DELETED ext/fts1/ft_hash.c Index: ext/fts1/ft_hash.c ================================================================== --- ext/fts1/ft_hash.c +++ /dev/null @@ -1,404 +0,0 @@ -/* -** 2001 September 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This is the implementation of generic hash-tables used in SQLite. -** We've modified it slightly to serve as a standalone hash table -** implementation for the full-text indexing module. -*/ -#include -#include -#include - -#include "ft_hash.h" - -void *malloc_and_zero(int n){ - void *p = malloc(n); - if( p ){ - memset(p, 0, n); - } - return p; -} - -/* Turn bulk memory into a hash table object by initializing the -** fields of the Hash structure. -** -** "pNew" is a pointer to the hash table that is to be initialized. -** keyClass is one of the constants HASH_INT, HASH_POINTER, -** HASH_BINARY, or HASH_STRING. The value of keyClass -** determines what kind of key the hash table will use. "copyKey" is -** true if the hash table should make its own private copy of keys and -** false if it should just use the supplied pointer. CopyKey only makes -** sense for HASH_STRING and HASH_BINARY and is ignored -** for other key classes. -*/ -void HashInit(Hash *pNew, int keyClass, int copyKey){ - assert( pNew!=0 ); - assert( keyClass>=HASH_STRING && keyClass<=HASH_BINARY ); - pNew->keyClass = keyClass; -#if 0 - if( keyClass==HASH_POINTER || keyClass==HASH_INT ) copyKey = 0; -#endif - pNew->copyKey = copyKey; - pNew->first = 0; - pNew->count = 0; - pNew->htsize = 0; - pNew->ht = 0; - pNew->xMalloc = malloc_and_zero; - pNew->xFree = free; -} - -/* Remove all entries from a hash table. Reclaim all memory. -** Call this routine to delete a hash table or to reset a hash table -** to the empty state. -*/ -void HashClear(Hash *pH){ - HashElem *elem; /* For looping over all elements of the table */ - - assert( pH!=0 ); - elem = pH->first; - pH->first = 0; - if( pH->ht ) pH->xFree(pH->ht); - pH->ht = 0; - pH->htsize = 0; - while( elem ){ - HashElem *next_elem = elem->next; - if( pH->copyKey && elem->pKey ){ - pH->xFree(elem->pKey); - } - pH->xFree(elem); - elem = next_elem; - } - pH->count = 0; -} - -#if 0 /* NOT USED */ -/* -** Hash and comparison functions when the mode is HASH_INT -*/ -static int intHash(const void *pKey, int nKey){ - return nKey ^ (nKey<<8) ^ (nKey>>8); -} -static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){ - return n2 - n1; -} -#endif - -#if 0 /* NOT USED */ -/* -** Hash and comparison functions when the mode is HASH_POINTER -*/ -static int ptrHash(const void *pKey, int nKey){ - uptr x = Addr(pKey); - return x ^ (x<<8) ^ (x>>8); -} -static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){ - if( pKey1==pKey2 ) return 0; - if( pKey1 0 ){ - h = (h<<3) ^ h ^ *z++; - nKey--; - } - return h & 0x7fffffff; -} -static int strCompare(const void *pKey1, int n1, const void *pKey2, int n2){ - if( n1!=n2 ) return 1; - return strncmp((const char*)pKey1,(const char*)pKey2,n1); -} - -/* -** Hash and comparison functions when the mode is HASH_BINARY -*/ -static int binHash(const void *pKey, int nKey){ - int h = 0; - const char *z = (const char *)pKey; - while( nKey-- > 0 ){ - h = (h<<3) ^ h ^ *(z++); - } - return h & 0x7fffffff; -} -static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){ - if( n1!=n2 ) return 1; - return memcmp(pKey1,pKey2,n1); -} - -/* -** Return a pointer to the appropriate hash function given the key class. -** -** The C syntax in this function definition may be unfamilar to some -** programmers, so we provide the following additional explanation: -** -** The name of the function is "hashFunction". The function takes a -** single parameter "keyClass". The return value of hashFunction() -** is a pointer to another function. Specifically, the return value -** of hashFunction() is a pointer to a function that takes two parameters -** with types "const void*" and "int" and returns an "int". -*/ -static int (*hashFunction(int keyClass))(const void*,int){ -#if 0 /* HASH_INT and HASH_POINTER are never used */ - switch( keyClass ){ - case HASH_INT: return &intHash; - case HASH_POINTER: return &ptrHash; - case HASH_STRING: return &strHash; - case HASH_BINARY: return &binHash;; - default: break; - } - return 0; -#else - if( keyClass==HASH_STRING ){ - return &strHash; - }else{ - assert( keyClass==HASH_BINARY ); - return &binHash; - } -#endif -} - -/* -** Return a pointer to the appropriate hash function given the key class. -** -** For help in interpreted the obscure C code in the function definition, -** see the header comment on the previous function. -*/ -static int (*compareFunction(int keyClass))(const void*,int,const void*,int){ -#if 0 /* HASH_INT and HASH_POINTER are never used */ - switch( keyClass ){ - case HASH_INT: return &intCompare; - case HASH_POINTER: return &ptrCompare; - case HASH_STRING: return &strCompare; - case HASH_BINARY: return &binCompare; - default: break; - } - return 0; -#else - if( keyClass==HASH_STRING ){ - return &strCompare; - }else{ - assert( keyClass==HASH_BINARY ); - return &binCompare; - } -#endif -} - -/* Link an element into the hash table -*/ -static void insertElement( - Hash *pH, /* The complete hash table */ - struct _ht *pEntry, /* The entry into which pNew is inserted */ - HashElem *pNew /* The element to be inserted */ -){ - HashElem *pHead; /* First element already in pEntry */ - pHead = pEntry->chain; - if( pHead ){ - pNew->next = pHead; - pNew->prev = pHead->prev; - if( pHead->prev ){ pHead->prev->next = pNew; } - else { pH->first = pNew; } - pHead->prev = pNew; - }else{ - pNew->next = pH->first; - if( pH->first ){ pH->first->prev = pNew; } - pNew->prev = 0; - pH->first = pNew; - } - pEntry->count++; - pEntry->chain = pNew; -} - - -/* Resize the hash table so that it cantains "new_size" buckets. -** "new_size" must be a power of 2. The hash table might fail -** to resize if sqliteMalloc() fails. -*/ -static void rehash(Hash *pH, int new_size){ - struct _ht *new_ht; /* The new hash table */ - HashElem *elem, *next_elem; /* For looping over existing elements */ - int (*xHash)(const void*,int); /* The hash function */ - - assert( (new_size & (new_size-1))==0 ); - new_ht = (struct _ht *)pH->xMalloc( new_size*sizeof(struct _ht) ); - if( new_ht==0 ) return; - if( pH->ht ) pH->xFree(pH->ht); - pH->ht = new_ht; - pH->htsize = new_size; - xHash = hashFunction(pH->keyClass); - for(elem=pH->first, pH->first=0; elem; elem = next_elem){ - int h = (*xHash)(elem->pKey, elem->nKey) & (new_size-1); - next_elem = elem->next; - insertElement(pH, &new_ht[h], elem); - } -} - -/* This function (for internal use only) locates an element in an -** hash table that matches the given key. The hash for this key has -** already been computed and is passed as the 4th parameter. -*/ -static HashElem *findElementGivenHash( - const Hash *pH, /* The pH to be searched */ - const void *pKey, /* The key we are searching for */ - int nKey, - int h /* The hash for this key. */ -){ - HashElem *elem; /* Used to loop thru the element list */ - int count; /* Number of elements left to test */ - int (*xCompare)(const void*,int,const void*,int); /* comparison function */ - - if( pH->ht ){ - struct _ht *pEntry = &pH->ht[h]; - elem = pEntry->chain; - count = pEntry->count; - xCompare = compareFunction(pH->keyClass); - while( count-- && elem ){ - if( (*xCompare)(elem->pKey,elem->nKey,pKey,nKey)==0 ){ - return elem; - } - elem = elem->next; - } - } - return 0; -} - -/* Remove a single entry from the hash table given a pointer to that -** element and a hash on the element's key. -*/ -static void removeElementGivenHash( - Hash *pH, /* The pH containing "elem" */ - HashElem* elem, /* The element to be removed from the pH */ - int h /* Hash value for the element */ -){ - struct _ht *pEntry; - if( elem->prev ){ - elem->prev->next = elem->next; - }else{ - pH->first = elem->next; - } - if( elem->next ){ - elem->next->prev = elem->prev; - } - pEntry = &pH->ht[h]; - if( pEntry->chain==elem ){ - pEntry->chain = elem->next; - } - pEntry->count--; - if( pEntry->count<=0 ){ - pEntry->chain = 0; - } - if( pH->copyKey && elem->pKey ){ - pH->xFree(elem->pKey); - } - pH->xFree( elem ); - pH->count--; - if( pH->count<=0 ){ - assert( pH->first==0 ); - assert( pH->count==0 ); - HashClear(pH); - } -} - -/* Attempt to locate an element of the hash table pH with a key -** that matches pKey,nKey. Return the data for this element if it is -** found, or NULL if there is no match. -*/ -void *HashFind(const Hash *pH, const void *pKey, int nKey){ - int h; /* A hash on key */ - HashElem *elem; /* The element that matches key */ - int (*xHash)(const void*,int); /* The hash function */ - - if( pH==0 || pH->ht==0 ) return 0; - xHash = hashFunction(pH->keyClass); - assert( xHash!=0 ); - h = (*xHash)(pKey,nKey); - assert( (pH->htsize & (pH->htsize-1))==0 ); - elem = findElementGivenHash(pH,pKey,nKey, h & (pH->htsize-1)); - return elem ? elem->data : 0; -} - -/* Insert an element into the hash table pH. The key is pKey,nKey -** and the data is "data". -** -** If no element exists with a matching key, then a new -** element is created. A copy of the key is made if the copyKey -** flag is set. NULL is returned. -** -** If another element already exists with the same key, then the -** new data replaces the old data and the old data is returned. -** The key is not copied in this instance. If a malloc fails, then -** the new data is returned and the hash table is unchanged. -** -** If the "data" parameter to this function is NULL, then the -** element corresponding to "key" is removed from the hash table. -*/ -void *HashInsert(Hash *pH, const void *pKey, int nKey, void *data){ - int hraw; /* Raw hash value of the key */ - int h; /* the hash of the key modulo hash table size */ - HashElem *elem; /* Used to loop thru the element list */ - HashElem *new_elem; /* New element added to the pH */ - int (*xHash)(const void*,int); /* The hash function */ - - assert( pH!=0 ); - xHash = hashFunction(pH->keyClass); - assert( xHash!=0 ); - hraw = (*xHash)(pKey, nKey); - assert( (pH->htsize & (pH->htsize-1))==0 ); - h = hraw & (pH->htsize-1); - elem = findElementGivenHash(pH,pKey,nKey,h); - if( elem ){ - void *old_data = elem->data; - if( data==0 ){ - removeElementGivenHash(pH,elem,h); - }else{ - elem->data = data; - } - return old_data; - } - if( data==0 ) return 0; - new_elem = (HashElem*)pH->xMalloc( sizeof(HashElem) ); - if( new_elem==0 ) return data; - if( pH->copyKey && pKey!=0 ){ - new_elem->pKey = pH->xMalloc( nKey ); - if( new_elem->pKey==0 ){ - pH->xFree(new_elem); - return data; - } - memcpy((void*)new_elem->pKey, pKey, nKey); - }else{ - new_elem->pKey = (void*)pKey; - } - new_elem->nKey = nKey; - pH->count++; - if( pH->htsize==0 ){ - rehash(pH,8); - if( pH->htsize==0 ){ - pH->count = 0; - pH->xFree(new_elem); - return data; - } - } - if( pH->count > pH->htsize ){ - rehash(pH,pH->htsize*2); - } - assert( pH->htsize>0 ); - assert( (pH->htsize & (pH->htsize-1))==0 ); - h = hraw & (pH->htsize-1); - insertElement(pH, &pH->ht[h], new_elem); - new_elem->data = data; - return 0; -} DELETED ext/fts1/ft_hash.h Index: ext/fts1/ft_hash.h ================================================================== --- ext/fts1/ft_hash.h +++ /dev/null @@ -1,111 +0,0 @@ -/* -** 2001 September 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This is the header file for the generic hash-table implemenation -** used in SQLite. We've modified it slightly to serve as a standalone -** hash table implementation for the full-text indexing module. -** -*/ -#ifndef _HASH_H_ -#define _HASH_H_ - -/* Forward declarations of structures. */ -typedef struct Hash Hash; -typedef struct HashElem HashElem; - -/* A complete hash table is an instance of the following structure. -** The internals of this structure are intended to be opaque -- client -** code should not attempt to access or modify the fields of this structure -** directly. Change this structure only by using the routines below. -** However, many of the "procedures" and "functions" for modifying and -** accessing this structure are really macros, so we can't really make -** this structure opaque. -*/ -struct Hash { - char keyClass; /* HASH_INT, _POINTER, _STRING, _BINARY */ - char copyKey; /* True if copy of key made on insert */ - int count; /* Number of entries in this table */ - HashElem *first; /* The first element of the array */ - void *(*xMalloc)(int); /* malloc() function to use */ - void (*xFree)(void *); /* free() function to use */ - int htsize; /* Number of buckets in the hash table */ - struct _ht { /* the hash table */ - int count; /* Number of entries with this hash */ - HashElem *chain; /* Pointer to first entry with this hash */ - } *ht; -}; - -/* Each element in the hash table is an instance of the following -** structure. All elements are stored on a single doubly-linked list. -** -** Again, this structure is intended to be opaque, but it can't really -** be opaque because it is used by macros. -*/ -struct HashElem { - HashElem *next, *prev; /* Next and previous elements in the table */ - void *data; /* Data associated with this element */ - void *pKey; int nKey; /* Key associated with this element */ -}; - -/* -** There are 4 different modes of operation for a hash table: -** -** HASH_INT nKey is used as the key and pKey is ignored. -** -** HASH_POINTER pKey is used as the key and nKey is ignored. -** -** HASH_STRING pKey points to a string that is nKey bytes long -** (including the null-terminator, if any). Case -** is respected in comparisons. -** -** HASH_BINARY pKey points to binary data nKey bytes long. -** memcmp() is used to compare keys. -** -** A copy of the key is made for HASH_STRING and HASH_BINARY -** if the copyKey parameter to HashInit is 1. -*/ -/* #define HASH_INT 1 // NOT USED */ -/* #define HASH_POINTER 2 // NOT USED */ -#define HASH_STRING 3 -#define HASH_BINARY 4 - -/* -** Access routines. To delete, insert a NULL pointer. -*/ -void HashInit(Hash*, int keytype, int copyKey); -void *HashInsert(Hash*, const void *pKey, int nKey, void *pData); -void *HashFind(const Hash*, const void *pKey, int nKey); -void HashClear(Hash*); - -/* -** Macros for looping over all elements of a hash table. The idiom is -** like this: -** -** Hash h; -** HashElem *p; -** ... -** for(p=HashFirst(&h); p; p=HashNext(p)){ -** SomeStructure *pData = HashData(p); -** // do something with pData -** } -*/ -#define HashFirst(H) ((H)->first) -#define HashNext(E) ((E)->next) -#define HashData(E) ((E)->data) -#define HashKey(E) ((E)->pKey) -#define HashKeysize(E) ((E)->nKey) - -/* -** Number of entries in a hash table -*/ -#define HashCount(H) ((H)->count) - -#endif /* _HASH_H_ */ DELETED ext/fts1/fulltext.c Index: ext/fts1/fulltext.c ================================================================== --- ext/fts1/fulltext.c +++ /dev/null @@ -1,1496 +0,0 @@ -/* The author disclaims copyright to this source code. - * - * This is an SQLite module implementing full-text search. - */ - -#include -#if !defined(__APPLE__) -#include -#else -#include -#endif -#include -#include -#include - -#include "fulltext.h" -#include "ft_hash.h" -#include "tokenizer.h" -#include "sqlite3.h" -#include "sqlite3ext.h" -SQLITE_EXTENSION_INIT1 - -/* utility functions */ - -/* We encode variable-length integers in little-endian order using seven bits - * per byte as follows: -** -** KEY: -** A = 0xxxxxxx 7 bits of data and one flag bit -** B = 1xxxxxxx 7 bits of data and one flag bit -** -** 7 bits - A -** 14 bits - BA -** 21 bits - BBA -** and so on. -*/ - -/* We may need up to VARINT_MAX bytes to store an encoded 64-bit integer. */ -#define VARINT_MAX 10 - -/* Write a 64-bit variable-length integer to memory starting at p[0]. - * The length of data written will be between 1 and VARINT_MAX bytes. - * The number of bytes written is returned. */ -static int putVarint(char *p, sqlite_int64 v){ - unsigned char *q = (unsigned char *) p; - sqlite_uint64 vu = v; - do{ - *q++ = (unsigned char) ((vu & 0x7f) | 0x80); - vu >>= 7; - }while( vu!=0 ); - q[-1] &= 0x7f; /* turn off high bit in final byte */ - assert( q - (unsigned char *)p <= VARINT_MAX ); - return (int) (q - (unsigned char *)p); -} - -/* Read a 64-bit variable-length integer from memory starting at p[0]. - * Return the number of bytes read, or 0 on error. - * The value is stored in *v. */ -static int getVarint(const char *p, sqlite_int64 *v){ - const unsigned char *q = (const unsigned char *) p; - sqlite_uint64 x = 0, y = 1; - while( (*q & 0x80) == 0x80 ){ - x += y * (*q++ & 0x7f); - y <<= 7; - if( q - (unsigned char *)p >= VARINT_MAX ){ /* bad data */ - assert( 0 ); - return 0; - } - } - x += y * (*q++); - *v = (sqlite_int64) x; - return (int) (q - (unsigned char *)p); -} - -static int getVarint32(const char *p, int *pi){ - sqlite_int64 i; - int ret = getVarint(p, &i); - *pi = (int) i; - assert( *pi==i ); - return ret; -} - -/*** Document lists *** - * - * A document list holds a sorted list of varint-encoded document IDs. - * - * A doclist with type DL_POSITIONS_OFFSETS is stored like this: - * - * array { - * varint docid; - * array { - * varint position; (delta from previous position plus 1, or 0 for end) - * varint startOffset; (delta from previous startOffset) - * varint endOffset; (delta from startOffset) - * } - * } - * - * Here, array { X } means zero or more occurrences of X, adjacent in memory. - * - * A doclist with type DL_POSITIONS is like the above, but holds only docids - * and positions without offset information. - * - * A doclist with type DL_DOCIDS is like the above, but holds only docids - * without positions or offset information. - * - * On disk, every document list has positions and offsets, so we don't bother - * to serialize a doclist's type. - * - * We don't yet delta-encode document IDs; doing so will probably be a - * modest win. - * - * NOTE(shess) I've thought of a slightly (1%) better offset encoding. - * After the first offset, estimate the next offset by using the - * current token position and the previous token position and offset, - * offset to handle some variance. So the estimate would be - * (iPosition*w->iStartOffset/w->iPosition-64), which is delta-encoded - * as normal. Offsets more than 64 chars from the estimate are - * encoded as the delta to the previous start offset + 128. An - * additional tiny increment can be gained by using the end offset of - * the previous token to make the estimate a tiny bit more precise. -*/ - -typedef enum DocListType { - DL_DOCIDS, /* docids only */ - DL_POSITIONS, /* docids + positions */ - DL_POSITIONS_OFFSETS /* docids + positions + offsets */ -} DocListType; - -typedef struct DocList { - char *pData; - int nData; - DocListType iType; - int iLastPos; /* the last position written */ - int iLastOffset; /* the last start offset written */ -} DocList; - -/* Initialize a new DocList to hold the given data. */ -static void docListInit(DocList *d, DocListType iType, - const char *pData, int nData){ - d->nData = nData; - if( nData>0 ){ - d->pData = malloc(nData); - memcpy(d->pData, pData, nData); - } else { - d->pData = NULL; - } - d->iType = iType; - d->iLastPos = 0; - d->iLastOffset = 0; -} - -/* Create a new dynamically-allocated DocList. */ -static DocList *docListNew(DocListType iType){ - DocList *d = (DocList *) malloc(sizeof(DocList)); - docListInit(d, iType, 0, 0); - return d; -} - -static void docListDestroy(DocList *d){ - free(d->pData); -#ifndef NDEBUG - memset(d, 0x55, sizeof(*d)); -#endif -} - -static void docListDelete(DocList *d){ - docListDestroy(d); - free(d); -} - -static char *docListEnd(DocList *d){ - return d->pData + d->nData; -} - -/* Append a varint to a DocList's data. */ -static void appendVarint(DocList *d, sqlite_int64 i){ - char c[VARINT_MAX]; - int n = putVarint(c, i); - d->pData = realloc(d->pData, d->nData + n); - memcpy(d->pData + d->nData, c, n); - d->nData += n; -} - -static void docListAddDocid(DocList *d, sqlite_int64 iDocid){ - appendVarint(d, iDocid); - d->iLastPos = 0; -} - -/* Add a position to the last position list in a doclist. */ -static void docListAddPos(DocList *d, int iPos){ - assert( d->iType>=DL_POSITIONS ); - appendVarint(d, iPos-d->iLastPos+1); - d->iLastPos = iPos; -} - -static void docListAddPosOffset(DocList *d, int iPos, - int iStartOffset, int iEndOffset){ - assert( d->iType==DL_POSITIONS_OFFSETS ); - docListAddPos(d, iPos); - appendVarint(d, iStartOffset-d->iLastOffset); - d->iLastOffset = iStartOffset; - appendVarint(d, iEndOffset-iStartOffset); -} - -/* Terminate the last position list in the given doclist. */ -static void docListAddEndPos(DocList *d){ - appendVarint(d, 0); -} - -typedef struct DocListReader { - DocList *pDoclist; - char *p; - int iLastPos; /* the last position read */ -} DocListReader; - -static void readerInit(DocListReader *r, DocList *pDoclist){ - r->pDoclist = pDoclist; - if( pDoclist!=NULL ){ - r->p = pDoclist->pData; - } - r->iLastPos = 0; -} - -static int readerAtEnd(DocListReader *pReader){ - return pReader->p >= docListEnd(pReader->pDoclist); -} - -/* Peek at the next docid without advancing the read pointer. */ -static sqlite_int64 peekDocid(DocListReader *pReader){ - sqlite_int64 ret; - assert( !readerAtEnd(pReader) ); - getVarint(pReader->p, &ret); - return ret; -} - -/* Read the next docid. */ -static sqlite_int64 readDocid(DocListReader *pReader){ - sqlite_int64 ret; - assert( !readerAtEnd(pReader) ); - pReader->p += getVarint(pReader->p, &ret); - pReader->iLastPos = 0; - return ret; -} - -/* Read the next position from a position list. - * Returns the position, or -1 at the end of the list. */ -static int readPosition(DocListReader *pReader){ - int i; - int iType = pReader->pDoclist->iType; - assert( iType>=DL_POSITIONS ); - assert( !readerAtEnd(pReader) ); - - pReader->p += getVarint32(pReader->p, &i); - if( i==0 ){ - pReader->iLastPos = -1; - return -1; - } - pReader->iLastPos += ((int) i)-1; - if( iType>=DL_POSITIONS_OFFSETS ){ - /* Skip over offsets, ignoring them for now. */ - int iStart, iEnd; - pReader->p += getVarint32(pReader->p, &iStart); - pReader->p += getVarint32(pReader->p, &iEnd); - } - return pReader->iLastPos; -} - -/* Skip past the end of a position list. */ -static void skipPositionList(DocListReader *pReader){ - while( readPosition(pReader)!=-1 ) - ; -} - -/* Skip over a docid, including its position list if the doclist has - * positions. */ -static void skipDocument(DocListReader *pReader){ - readDocid(pReader); - if( pReader->pDoclist->iType >= DL_POSITIONS ){ - skipPositionList(pReader); - } -} - -static sqlite_int64 firstDocid(DocList *d){ - DocListReader r; - readerInit(&r, d); - return readDocid(&r); -} - -/* Doclist multi-tool. Pass pUpdate==NULL to delete the indicated docid; - * otherwise pUpdate, which must contain only the single docid [iDocid], is - * inserted (if not present) or updated (if already present). */ -static int docListUpdate(DocList *d, sqlite_int64 iDocid, DocList *pUpdate){ - int modified = 0; - DocListReader reader; - char *p; - - if( pUpdate!=NULL ){ - assert( d->iType==pUpdate->iType); - assert( iDocid==firstDocid(pUpdate) ); - } - - readerInit(&reader, d); - while( !readerAtEnd(&reader) && peekDocid(&reader)nData -= (reader.p - p); - modified = 1; - } - - /* Insert if indicated. */ - if( pUpdate!=NULL ){ - int iDoclist = p-d->pData; - docListAddEndPos(pUpdate); - - d->pData = realloc(d->pData, d->nData+pUpdate->nData); - p = d->pData + iDoclist; - - memmove(p+pUpdate->nData, p, docListEnd(d) - p); - memcpy(p, pUpdate->pData, pUpdate->nData); - d->nData += pUpdate->nData; - modified = 1; - } - - return modified; -} - -/* Split the second half of doclist d into a separate doclist d2. Returns 1 - * if successful, or 0 if d contains a single document and hence can't be - * split. */ -static int docListSplit(DocList *d, DocList *d2){ - const char *pSplitPoint = d->pData + d->nData / 2; - DocListReader reader; - - readerInit(&reader, d); - while( reader.piType, reader.p, docListEnd(d) - reader.p); - d->nData = reader.p - d->pData; - d->pData = realloc(d->pData, d->nData); - return 1; -} - -/* A DocListMerge computes the AND of an in-memory DocList [in] and a chunked - * on-disk doclist, resulting in another in-memory DocList [out]. [in] - * and [out] may or may not store position information according to the - * caller's wishes. The on-disk doclist always comes with positions. - * - * The caller must read each chunk of the on-disk doclist in succession and - * pass it to mergeBlock(). - * - * If [in] has positions, then the merge output contains only documents with - * matching positions in the two input doclists. If [in] does not have - * positions, then the merge output contains all documents common to the two - * input doclists. - * - * If [in] is NULL, then the on-disk doclist is copied to [out] directly. - * - * A merge is performed using an integer [iOffset] provided by the caller. - * [iOffset] is subtracted from each position in the on-disk doclist for the - * purpose of position comparison; this is helpful in implementing phrase - * searches. - * - * A DocListMerge is not yet able to propagate offsets through query - * processing; we should add that capability soon. -*/ -typedef struct DocListMerge { - DocListReader in; - DocList *pOut; - int iOffset; -} DocListMerge; - -static void mergeInit(DocListMerge *m, - DocList *pIn, int iOffset, DocList *pOut){ - readerInit(&m->in, pIn); - m->pOut = pOut; - m->iOffset = iOffset; - - /* can't handle offsets yet */ - assert( pIn==NULL || pIn->iType <= DL_POSITIONS ); - assert( pOut->iType <= DL_POSITIONS ); -} - -/* A helper function for mergeBlock(), below. Merge the position lists - * pointed to by m->in and pBlockReader. - * If the merge matches, write [iDocid] to m->pOut; if m->pOut - * has positions then write all matching positions as well. */ -static void mergePosList(DocListMerge *m, sqlite_int64 iDocid, - DocListReader *pBlockReader){ - int block_pos = readPosition(pBlockReader); - int in_pos = readPosition(&m->in); - int match = 0; - while( block_pos!=-1 || in_pos!=-1 ){ - if( block_pos-m->iOffset==in_pos ){ - if( !match ){ - docListAddDocid(m->pOut, iDocid); - match = 1; - } - if( m->pOut->iType >= DL_POSITIONS ){ - docListAddPos(m->pOut, in_pos); - } - block_pos = readPosition(pBlockReader); - in_pos = readPosition(&m->in); - } else if( in_pos==-1 || (block_pos!=-1 && block_pos-m->iOffsetin); - } - } - if( m->pOut->iType >= DL_POSITIONS && match ){ - docListAddEndPos(m->pOut); - } -} - -/* Merge one block of an on-disk doclist into a DocListMerge. */ -static void mergeBlock(DocListMerge *m, DocList *pBlock){ - DocListReader blockReader; - assert( pBlock->iType >= DL_POSITIONS ); - readerInit(&blockReader, pBlock); - while( !readerAtEnd(&blockReader) ){ - sqlite_int64 iDocid = readDocid(&blockReader); - if( m->in.pDoclist!=NULL ){ - while( 1 ){ - if( readerAtEnd(&m->in) ) return; /* nothing more to merge */ - if( peekDocid(&m->in)>=iDocid ) break; - skipDocument(&m->in); - } - if( peekDocid(&m->in)>iDocid ){ /* [pIn] has no match with iDocid */ - skipPositionList(&blockReader); /* skip this docid in the block */ - continue; - } - readDocid(&m->in); - } - /* We have a document match. */ - if( m->in.pDoclist==NULL || m->in.pDoclist->iType < DL_POSITIONS ){ - /* We don't need to do a poslist merge. */ - docListAddDocid(m->pOut, iDocid); - if( m->pOut->iType >= DL_POSITIONS ){ - /* Copy all positions to the output doclist. */ - while( 1 ){ - int pos = readPosition(&blockReader); - if( pos==-1 ) break; - docListAddPos(m->pOut, pos); - } - docListAddEndPos(m->pOut); - } else skipPositionList(&blockReader); - continue; - } - mergePosList(m, iDocid, &blockReader); - } -} - -static char *string_dup_n(const char *s, int n){ - char *str = malloc(n + 1); - memcpy(str, s, n); - str[n] = '\0'; - return str; -} - -/* Duplicate a string; the caller must free() the returned string. - * (We don't use strdup() since it's not part of the standard C library and - * may not be available everywhere.) */ -static char *string_dup(const char *s){ - return string_dup_n(s, strlen(s)); -} - -/* Format a string, replacing each occurrence of the % character with - * zName. This may be more convenient than sqlite_mprintf() - * when one string is used repeatedly in a format string. - * The caller must free() the returned string. */ -static char *string_format(const char *zFormat, const char *zName){ - const char *p; - size_t len = 0; - size_t nName = strlen(zName); - char *result; - char *r; - - /* first compute length needed */ - for(p = zFormat ; *p ; ++p){ - len += (*p=='%' ? nName : 1); - } - len += 1; /* for null terminator */ - - r = result = malloc(len); - for(p = zFormat; *p; ++p){ - if( *p=='%' ){ - memcpy(r, zName, nName); - r += nName; - } else { - *r++ = *p; - } - } - *r++ = '\0'; - assert( r == result + len ); - return result; -} - -static int sql_exec(sqlite3 *db, const char *zName, const char *zFormat){ - char *zCommand = string_format(zFormat, zName); - int rc = sqlite3_exec(db, zCommand, NULL, 0, NULL); - free(zCommand); - return rc; -} - -static int sql_prepare(sqlite3 *db, const char *zName, sqlite3_stmt **ppStmt, - const char *zFormat){ - char *zCommand = string_format(zFormat, zName); - int rc = sqlite3_prepare(db, zCommand, -1, ppStmt, NULL); - free(zCommand); - return rc; -} - -/* end utility functions */ - -#define QUERY_GENERIC 0 -#define QUERY_FULLTEXT 1 - -#define CHUNK_MAX 1024 - -typedef enum fulltext_statement { - CONTENT_INSERT_STMT, - CONTENT_SELECT_STMT, - CONTENT_DELETE_STMT, - - TERM_SELECT_STMT, - TERM_CHUNK_SELECT_STMT, - TERM_INSERT_STMT, - TERM_UPDATE_STMT, - TERM_DELETE_STMT, - - MAX_STMT /* Always at end! */ -} fulltext_statement; - -/* These must exactly match the enum above. */ -/* TODO(adam): Is there some risk that a statement (in particular, -** pTermSelectStmt) will be used in two cursors at once, e.g. if a -** query joins a virtual table to itself? If so perhaps we should -** move some of these to the cursor object. -*/ -static const char *fulltext_zStatement[MAX_STMT] = { - /* CONTENT_INSERT */ "insert into %_content (rowid, content) values (?, ?)", - /* CONTENT_SELECT */ "select content from %_content where rowid = ?", - /* CONTENT_DELETE */ "delete from %_content where rowid = ?", - - /* TERM_SELECT */ - "select rowid, doclist from %_term where term = ? and first = ?", - /* TERM_CHUNK_SELECT */ - "select max(first) from %_term where term = ? and first <= ?", - /* TERM_INSERT */ - "insert into %_term (term, first, doclist) values (?, ?, ?)", - /* TERM_UPDATE */ "update %_term set doclist = ? where rowid = ?", - /* TERM_DELETE */ "delete from %_term where rowid = ?", -}; - -typedef struct fulltext_vtab { - sqlite3_vtab base; - sqlite3 *db; - const char *zName; /* virtual table name */ - sqlite3_tokenizer *pTokenizer; /* tokenizer for inserts and queries */ - - /* Precompiled statements which we keep as long as the table is - ** open. - */ - sqlite3_stmt *pFulltextStatements[MAX_STMT]; -} fulltext_vtab; - -typedef struct fulltext_cursor { - sqlite3_vtab_cursor base; - int iCursorType; /* QUERY_GENERIC or QUERY_FULLTEXT */ - - sqlite3_stmt *pStmt; - - int eof; - - /* The following is used only when iCursorType == QUERY_FULLTEXT. */ - DocListReader result; -} fulltext_cursor; - -static struct fulltext_vtab *cursor_vtab(fulltext_cursor *c){ - return (fulltext_vtab *) c->base.pVtab; -} - -static sqlite3_module fulltextModule; /* forward declaration */ - -/* Puts a freshly-prepared statement determined by iStmt in *ppStmt. -** If the indicated statement has never been prepared, it is prepared -** and cached, otherwise the cached version is reset. -*/ -static int sql_get_statement(fulltext_vtab *v, fulltext_statement iStmt, - sqlite3_stmt **ppStmt){ - assert( iStmtpFulltextStatements[iStmt]==NULL ){ - int rc = sql_prepare(v->db, v->zName, &v->pFulltextStatements[iStmt], - fulltext_zStatement[iStmt]); - if( rc!=SQLITE_OK ) return rc; - } else { - int rc = sqlite3_reset(v->pFulltextStatements[iStmt]); - if( rc!=SQLITE_OK ) return rc; - } - - *ppStmt = v->pFulltextStatements[iStmt]; - return SQLITE_OK; -} - -/* Step the indicated statement, handling errors SQLITE_BUSY (by -** retrying) and SQLITE_SCHEMA (by re-preparing and transferring -** bindings to the new statement). -** TODO(adam): We should extend this function so that it can work with -** statements declared locally, not only globally cached statements. -*/ -static int sql_step_statement(fulltext_vtab *v, fulltext_statement iStmt, - sqlite3_stmt **ppStmt){ - int rc; - sqlite3_stmt *s = *ppStmt; - assert( iStmtpFulltextStatements[iStmt] ); - - while( (rc=sqlite3_step(s))!=SQLITE_DONE && rc!=SQLITE_ROW ){ - sqlite3_stmt *pNewStmt; - - if( rc==SQLITE_BUSY ) continue; - if( rc!=SQLITE_ERROR ) return rc; - - rc = sqlite3_reset(s); - if( rc!=SQLITE_SCHEMA ) return SQLITE_ERROR; - - v->pFulltextStatements[iStmt] = NULL; /* Still in s */ - rc = sql_get_statement(v, iStmt, &pNewStmt); - if( rc!=SQLITE_OK ) goto err; - *ppStmt = pNewStmt; - - rc = sqlite3_transfer_bindings(s, pNewStmt); - if( rc!=SQLITE_OK ) goto err; - - rc = sqlite3_finalize(s); - if( rc!=SQLITE_OK ) return rc; - s = pNewStmt; - } - return rc; - - err: - sqlite3_finalize(s); - return rc; -} - -/* Like sql_step_statement(), but convert SQLITE_DONE to SQLITE_OK. -** Useful for statements like UPDATE, where we expect no results. -*/ -static int sql_single_step_statement(fulltext_vtab *v, - fulltext_statement iStmt, - sqlite3_stmt **ppStmt){ - int rc = sql_step_statement(v, iStmt, ppStmt); - return (rc==SQLITE_DONE) ? SQLITE_OK : rc; -} - -/* insert into %_content (rowid, content) values ([rowid], [zContent]) */ -static int content_insert(fulltext_vtab *v, sqlite3_value *rowid, - const char *zContent, int nContent){ - sqlite3_stmt *s; - int rc = sql_get_statement(v, CONTENT_INSERT_STMT, &s); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_value(s, 1, rowid); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_text(s, 2, zContent, nContent, SQLITE_STATIC); - if( rc!=SQLITE_OK ) return rc; - - return sql_single_step_statement(v, CONTENT_INSERT_STMT, &s); -} - -/* select content from %_content where rowid = [iRow] - * The caller must delete the returned string. */ -static int content_select(fulltext_vtab *v, sqlite_int64 iRow, - char **pzContent){ - sqlite3_stmt *s; - int rc = sql_get_statement(v, CONTENT_SELECT_STMT, &s); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_int64(s, 1, iRow); - if( rc!=SQLITE_OK ) return rc; - - rc = sql_step_statement(v, CONTENT_SELECT_STMT, &s); - if( rc!=SQLITE_ROW ) return rc; - - *pzContent = string_dup((const char *)sqlite3_column_text(s, 0)); - - /* We expect only one row. We must execute another sqlite3_step() - * to complete the iteration; otherwise the table will remain locked. */ - rc = sqlite3_step(s); - if( rc==SQLITE_DONE ) return SQLITE_OK; - - free(*pzContent); - return rc; -} - -/* delete from %_content where rowid = [iRow ] */ -static int content_delete(fulltext_vtab *v, sqlite_int64 iRow){ - sqlite3_stmt *s; - int rc = sql_get_statement(v, CONTENT_DELETE_STMT, &s); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_int64(s, 1, iRow); - if( rc!=SQLITE_OK ) return rc; - - return sql_single_step_statement(v, CONTENT_DELETE_STMT, &s); -} - -/* select rowid, doclist from %_term where term = [zTerm] and first = [iFirst] - * If found, returns SQLITE_OK; the caller must free the returned doclist. - * If no rows found, returns SQLITE_ERROR. */ -static int term_select(fulltext_vtab *v, const char *zTerm, int nTerm, - sqlite_int64 iFirst, - sqlite_int64 *rowid, - DocList *out){ - sqlite3_stmt *s; - int rc = sql_get_statement(v, TERM_SELECT_STMT, &s); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_text(s, 1, zTerm, nTerm, SQLITE_TRANSIENT); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_int64(s, 2, iFirst); - if( rc!=SQLITE_OK ) return rc; - - rc = sql_step_statement(v, TERM_SELECT_STMT, &s); - if( rc!=SQLITE_ROW ) return rc==SQLITE_DONE ? SQLITE_ERROR : rc; - - *rowid = sqlite3_column_int64(s, 0); - docListInit(out, DL_POSITIONS_OFFSETS, - sqlite3_column_blob(s, 1), sqlite3_column_bytes(s, 1)); - - /* We expect only one row. We must execute another sqlite3_step() - * to complete the iteration; otherwise the table will remain locked. */ - rc = sqlite3_step(s); - return rc==SQLITE_DONE ? SQLITE_OK : rc; -} - -/* select max(first) from %_term where term = [zTerm] and first <= [iFirst] - * If found, returns SQLITE_ROW and result in *piResult; if the query returns - * NULL (meaning no row found) returns SQLITE_DONE. - */ -static int term_chunk_select(fulltext_vtab *v, const char *zTerm, int nTerm, - sqlite_int64 iFirst, sqlite_int64 *piResult){ - sqlite3_stmt *s; - int rc = sql_get_statement(v, TERM_CHUNK_SELECT_STMT, &s); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_text(s, 1, zTerm, nTerm, SQLITE_STATIC); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_int64(s, 2, iFirst); - if( rc!=SQLITE_OK ) return rc; - - rc = sql_step_statement(v, TERM_CHUNK_SELECT_STMT, &s); - if( rc!=SQLITE_ROW ) return rc==SQLITE_DONE ? SQLITE_ERROR : rc; - - switch( sqlite3_column_type(s, 0) ){ - case SQLITE_NULL: - rc = SQLITE_DONE; - break; - case SQLITE_INTEGER: - *piResult = sqlite3_column_int64(s, 0); - break; - default: - return SQLITE_ERROR; - } - /* We expect only one row. We must execute another sqlite3_step() - * to complete the iteration; otherwise the table will remain locked. */ - if( sqlite3_step(s) != SQLITE_DONE ) return SQLITE_ERROR; - return rc; -} - -/* insert into %_term (term, first, doclist) - values ([zTerm], [iFirst], [doclist]) */ -static int term_insert(fulltext_vtab *v, const char *zTerm, int nTerm, - sqlite_int64 iFirst, DocList *doclist){ - sqlite3_stmt *s; - int rc = sql_get_statement(v, TERM_INSERT_STMT, &s); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_text(s, 1, zTerm, nTerm, SQLITE_STATIC); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_int64(s, 2, iFirst); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_blob(s, 3, doclist->pData, doclist->nData, SQLITE_STATIC); - if( rc!=SQLITE_OK ) return rc; - - return sql_single_step_statement(v, TERM_INSERT_STMT, &s); -} - -/* update %_term set doclist = [doclist] where rowid = [rowid] */ -static int term_update(fulltext_vtab *v, sqlite_int64 rowid, - DocList *doclist){ - sqlite3_stmt *s; - int rc = sql_get_statement(v, TERM_UPDATE_STMT, &s); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_blob(s, 1, doclist->pData, doclist->nData, - SQLITE_STATIC); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_int64(s, 2, rowid); - if( rc!=SQLITE_OK ) return rc; - - return sql_single_step_statement(v, TERM_UPDATE_STMT, &s); -} - -static int term_delete(fulltext_vtab *v, sqlite_int64 rowid){ - sqlite3_stmt *s; - int rc = sql_get_statement(v, TERM_DELETE_STMT, &s); - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_int64(s, 1, rowid); - if( rc!=SQLITE_OK ) return rc; - - return sql_single_step_statement(v, TERM_DELETE_STMT, &s); -} - -static void fulltext_vtab_destroy(fulltext_vtab *v){ - int iStmt; - - for( iStmt=0; iStmtpFulltextStatements[iStmt]!=NULL ){ - sqlite3_finalize(v->pFulltextStatements[iStmt]); - v->pFulltextStatements[iStmt] = NULL; - } - } - - if( v->pTokenizer!=NULL ){ - v->pTokenizer->pModule->xDestroy(v->pTokenizer); - v->pTokenizer = NULL; - } - - free((void *) v->zName); - free(v); -} - -/* Current interface: -** argv[0] - module name -** argv[1] - database name -** argv[2] - table name -** argv[3] - tokenizer name (optional, a sensible default is provided) -** argv[4..] - passed to tokenizer (optional based on tokenizer) -**/ -static int fulltextConnect(sqlite3 *db, void *pAux, int argc, char **argv, - sqlite3_vtab **ppVTab){ - int rc; - fulltext_vtab *v; - sqlite3_tokenizer_module *m = NULL; - - assert( argc>=3 ); - v = (fulltext_vtab *) malloc(sizeof(fulltext_vtab)); - /* sqlite will initialize v->base */ - v->db = db; - v->zName = string_dup(argv[2]); - v->pTokenizer = NULL; - - if( argc==3 ){ - get_simple_tokenizer_module(&m); - } else { - /* TODO(shess) For now, add new tokenizers as else if clauses. */ - if( !strcmp(argv[3], "simple") ){ - get_simple_tokenizer_module(&m); - } else { - assert( "unrecognized tokenizer"==NULL ); - } - } - - /* TODO(shess) Since tokenization impacts the index, the parameters - ** to the tokenizer need to be identical when a persistent virtual - ** table is re-created. One solution would be a meta-table to track - ** such information in the database. Then we could verify that the - ** information is identical on subsequent creates. - */ - /* TODO(shess) Why isn't argv already (const char **)? */ - rc = m->xCreate(argc-3, (const char **) (argv+3), &v->pTokenizer); - if( rc!=SQLITE_OK ) return rc; - v->pTokenizer->pModule = m; - - /* TODO: verify the existence of backing tables foo_content, foo_term */ - - rc = sqlite3_declare_vtab(db, "create table x(content text)"); - if( rc!=SQLITE_OK ) return rc; - - memset(v->pFulltextStatements, 0, sizeof(v->pFulltextStatements)); - - *ppVTab = &v->base; - return SQLITE_OK; -} - -static int fulltextCreate(sqlite3 *db, void *pAux, int argc, char **argv, - sqlite3_vtab **ppVTab){ - int rc; - assert( argc>=3 ); - - /* The %_content table holds the text of each full-text item, with - ** the rowid used as the docid. - ** - ** The %_term table maps each term to a document list blob - ** containing elements sorted by ascending docid, each element - ** encoded as: - ** - ** docid varint-encoded - ** token count varint-encoded - ** "count" token elements (poslist): - ** position varint-encoded as delta from previous position - ** start offset varint-encoded as delta from previous start offset - ** end offset varint-encoded as delta from start offset - ** - ** Additionally, doclist blobs can be chunked into multiple rows, - ** using "first" to order the blobs. "first" is simply the first - ** docid in the blob. - */ - /* - ** NOTE(shess) That last sentence is incorrect in the face of - ** deletion, which can leave a doclist that doesn't contain the - ** first from that row. I _believe_ this does not matter to the - ** operation of the system, but it might be reasonable to update - ** appropriately in case this assumption becomes more important. - */ - rc = sql_exec(db, argv[2], - "create table %_content(content text);" - "create table %_term(term text, first integer, doclist blob);" - "create index %_index on %_term(term, first)"); - if( rc!=SQLITE_OK ) return rc; - - return fulltextConnect(db, pAux, argc, argv, ppVTab); -} - -/* Decide how to handle an SQL query. - * At the moment, MATCH queries can include implicit boolean ANDs; we - * haven't implemented phrase searches or OR yet. */ -static int fulltextBestIndex(sqlite3_vtab *pVTab, sqlite3_index_info *pInfo){ - int i; - - for(i=0; inConstraint; ++i){ - const struct sqlite3_index_constraint *pConstraint; - pConstraint = &pInfo->aConstraint[i]; - if( pConstraint->iColumn==0 && - pConstraint->op==SQLITE_INDEX_CONSTRAINT_MATCH && - pConstraint->usable ){ /* a full-text search */ - pInfo->aConstraintUsage[i].argvIndex = 1; - pInfo->aConstraintUsage[i].omit = 1; - pInfo->idxNum = QUERY_FULLTEXT; - pInfo->estimatedCost = 1.0; /* an arbitrary value for now */ - return SQLITE_OK; - } - } - pInfo->idxNum = QUERY_GENERIC; - return SQLITE_OK; -} - -static int fulltextDisconnect(sqlite3_vtab *pVTab){ - fulltext_vtab_destroy((fulltext_vtab *)pVTab); - return SQLITE_OK; -} - -static int fulltextDestroy(sqlite3_vtab *pVTab){ - fulltext_vtab *v = (fulltext_vtab *)pVTab; - - int rc = sql_exec(v->db, v->zName, - "drop table %_content; drop table %_term"); - if( rc!=SQLITE_OK ) return rc; - - fulltext_vtab_destroy((fulltext_vtab *)pVTab); - return SQLITE_OK; -} - -static int fulltextOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ - fulltext_cursor *c; - - c = (fulltext_cursor *) calloc(sizeof(fulltext_cursor), 1); - /* sqlite will initialize c->base */ - *ppCursor = &c->base; - - return SQLITE_OK; -} - -static int fulltextClose(sqlite3_vtab_cursor *pCursor){ - fulltext_cursor *c = (fulltext_cursor *) pCursor; - sqlite3_finalize(c->pStmt); - if( c->result.pDoclist!=NULL ){ - docListDelete(c->result.pDoclist); - } - free(c); - return SQLITE_OK; -} - -static int fulltextNext(sqlite3_vtab_cursor *pCursor){ - fulltext_cursor *c = (fulltext_cursor *) pCursor; - sqlite_int64 iDocid; - int rc; - - switch( c->iCursorType ){ - case QUERY_GENERIC: - /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ - rc = sqlite3_step(c->pStmt); - switch( rc ){ - case SQLITE_ROW: - c->eof = 0; - return SQLITE_OK; - case SQLITE_DONE: - c->eof = 1; - return SQLITE_OK; - default: - c->eof = 1; - return rc; - } - case QUERY_FULLTEXT: - rc = sqlite3_reset(c->pStmt); - if( rc!=SQLITE_OK ) return rc; - - if( readerAtEnd(&c->result)){ - c->eof = 1; - return SQLITE_OK; - } - iDocid = readDocid(&c->result); - rc = sqlite3_bind_int64(c->pStmt, 1, iDocid); - if( rc!=SQLITE_OK ) return rc; - /* TODO(shess) Handle SQLITE_SCHEMA AND SQLITE_BUSY. */ - rc = sqlite3_step(c->pStmt); - if( rc==SQLITE_ROW ){ /* the case we expect */ - c->eof = 0; - return SQLITE_OK; - } - /* an error occurred; abort */ - return rc==SQLITE_DONE ? SQLITE_ERROR : rc; - default: - assert( 0 ); - return SQLITE_ERROR; /* not reached */ - } -} - -static int term_select_doclist(fulltext_vtab *v, const char *pTerm, int nTerm, - sqlite3_stmt **ppStmt){ - int rc; - if( *ppStmt ){ - rc = sqlite3_reset(*ppStmt); - } else { - rc = sql_prepare(v->db, v->zName, ppStmt, - "select doclist from %_term where term = ? order by first"); - } - if( rc!=SQLITE_OK ) return rc; - - rc = sqlite3_bind_text(*ppStmt, 1, pTerm, nTerm, SQLITE_TRANSIENT); - if( rc!=SQLITE_OK ) return rc; - - return sqlite3_step(*ppStmt); /* TODO(adamd): handle schema error */ -} - -/* Read the posting list for [zTerm]; AND it with the doclist [in] to - * produce the doclist [out], using the given offset [iOffset] for phrase - * matching. - * (*pSelect) is used to hold an SQLite statement used inside this function; - * the caller should initialize *pSelect to NULL before the first call. - */ -static int query_merge(fulltext_vtab *v, sqlite3_stmt **pSelect, - const char *zTerm, - DocList *pIn, int iOffset, DocList *out){ - int rc; - DocListMerge merge; - - if( pIn!=NULL && !pIn->nData ){ - /* If [pIn] is already empty, there's no point in reading the - * posting list to AND it in; return immediately. */ - return SQLITE_OK; - } - - rc = term_select_doclist(v, zTerm, -1, pSelect); - if( rc!=SQLITE_ROW && rc!=SQLITE_DONE ) return rc; - - mergeInit(&merge, pIn, iOffset, out); - while( rc==SQLITE_ROW ){ - DocList block; - docListInit(&block, DL_POSITIONS_OFFSETS, - sqlite3_column_blob(*pSelect, 0), - sqlite3_column_bytes(*pSelect, 0)); - mergeBlock(&merge, &block); - docListDestroy(&block); - - rc = sqlite3_step(*pSelect); - if( rc!=SQLITE_ROW && rc!=SQLITE_DONE ){ - return rc; - } - } - - return SQLITE_OK; -} - -typedef struct QueryTerm { - int is_phrase; /* true if this term begins a new phrase */ - const char *zTerm; -} QueryTerm; - -/* A parsed query. - * - * As an example, parsing the query ["four score" years "new nation"] will - * yield a Query with 5 terms: - * "four", is_phrase = 1 - * "score", is_phrase = 0 - * "years", is_phrase = 1 - * "new", is_phrase = 1 - * "nation", is_phrase = 0 - */ -typedef struct Query { - int nTerms; - QueryTerm *pTerm; -} Query; - -static void query_add(Query *q, int is_phrase, const char *zTerm){ - QueryTerm *t; - ++q->nTerms; - q->pTerm = realloc(q->pTerm, q->nTerms * sizeof(q->pTerm[0])); - t = &q->pTerm[q->nTerms - 1]; - t->is_phrase = is_phrase; - t->zTerm = zTerm; -} - -static void query_free(Query *q){ - int i; - for(i = 0; i < q->nTerms; ++i){ - free((void *) q->pTerm[i].zTerm); - } - free(q->pTerm); -} - -static int tokenize_segment(sqlite3_tokenizer *pTokenizer, - const char *zQuery, int in_phrase, - Query *pQuery){ - sqlite3_tokenizer_module *pModule = pTokenizer->pModule; - sqlite3_tokenizer_cursor *pCursor; - int is_first = 1; - - int rc = pModule->xOpen(pTokenizer, zQuery, -1, &pCursor); - if( rc!=SQLITE_OK ) return rc; - pCursor->pTokenizer = pTokenizer; - - while( 1 ){ - const char *zToken; - int nToken, iStartOffset, iEndOffset, dummy_pos; - - rc = pModule->xNext(pCursor, - &zToken, &nToken, - &iStartOffset, &iEndOffset, - &dummy_pos); - if( rc!=SQLITE_OK ) break; - query_add(pQuery, !in_phrase || is_first, string_dup_n(zToken, nToken)); - is_first = 0; - } - - return pModule->xClose(pCursor); -} - -/* Parse a query string, yielding a Query object. */ -static int parse_query(fulltext_vtab *v, const char *zQuery, Query *pQuery){ - char *zQuery1 = string_dup(zQuery); - int in_phrase = 0; - char *s = zQuery1; - pQuery->nTerms = 0; - pQuery->pTerm = NULL; - - while( *s ){ - char *t = s; - while( *t ){ - if( *t=='"' ){ - *t++ = '\0'; - break; - } - ++t; - } - if( *s ){ - tokenize_segment(v->pTokenizer, s, in_phrase, pQuery); - } - s = t; - in_phrase = !in_phrase; - } - - free(zQuery1); - return SQLITE_OK; -} - -/* Perform a full-text query; return a list of documents in [pResult]. */ -static int fulltext_query(fulltext_vtab *v, const char *zQuery, - DocList **pResult){ - Query q; - int phrase_start = -1; - int i; - sqlite3_stmt *pSelect = NULL; - DocList *d = NULL; - - int rc = parse_query(v, zQuery, &q); - if( rc!=SQLITE_OK ) return rc; - - /* Merge terms. */ - for(i = 0 ; i < q.nTerms ; ++i){ - /* In each merge step, we need to generate positions whenever we're - * processing a phrase which hasn't ended yet. */ - int need_positions = iiCursorType = idxNum; - switch( idxNum ){ - case QUERY_GENERIC: - zStatement = "select rowid, content from %_content"; - break; - - case QUERY_FULLTEXT: /* full-text search */ - { - const char *zQuery = (const char *)sqlite3_value_text(argv[0]); - DocList *pResult; - assert( argc==1 ); - rc = fulltext_query(v, zQuery, &pResult); - if( rc!=SQLITE_OK ) return rc; - readerInit(&c->result, pResult); - zStatement = "select rowid, content from %_content where rowid = ?"; - break; - } - - default: - assert( 0 ); - } - - rc = sql_prepare(v->db, v->zName, &c->pStmt, zStatement); - if( rc!=SQLITE_OK ) return rc; - - return fulltextNext(pCursor); -} - -static int fulltextEof(sqlite3_vtab_cursor *pCursor){ - fulltext_cursor *c = (fulltext_cursor *) pCursor; - return c->eof; -} - -static int fulltextColumn(sqlite3_vtab_cursor *pCursor, - sqlite3_context *pContext, int idxCol){ - fulltext_cursor *c = (fulltext_cursor *) pCursor; - const char *s; - - assert( idxCol==0 ); - s = (const char *) sqlite3_column_text(c->pStmt, 1); - sqlite3_result_text(pContext, s, -1, SQLITE_TRANSIENT); - - return SQLITE_OK; -} - -static int fulltextRowid(sqlite3_vtab_cursor *pCursor, sqlite_int64 *pRowid){ - fulltext_cursor *c = (fulltext_cursor *) pCursor; - - *pRowid = sqlite3_column_int64(c->pStmt, 0); - return SQLITE_OK; -} - -/* Build a hash table containing all terms in zText. */ -static int build_terms(Hash *terms, sqlite3_tokenizer *pTokenizer, - const char *zText, sqlite_int64 iDocid){ - sqlite3_tokenizer_cursor *pCursor; - const char *pToken; - int nTokenBytes; - int iStartOffset, iEndOffset, iPosition; - - int rc = pTokenizer->pModule->xOpen(pTokenizer, zText, -1, &pCursor); - if( rc!=SQLITE_OK ) return rc; - - pCursor->pTokenizer = pTokenizer; - HashInit(terms, HASH_STRING, 1); - while( SQLITE_OK==pTokenizer->pModule->xNext(pCursor, - &pToken, &nTokenBytes, - &iStartOffset, &iEndOffset, - &iPosition) ){ - DocList *p; - - /* Positions can't be negative; we use -1 as a terminator internally. */ - if( iPosition<0 ) { - rc = SQLITE_ERROR; - goto err; - } - - p = HashFind(terms, pToken, nTokenBytes); - if( p==NULL ){ - p = docListNew(DL_POSITIONS_OFFSETS); - docListAddDocid(p, iDocid); - HashInsert(terms, pToken, nTokenBytes, p); - } - docListAddPosOffset(p, iPosition, iStartOffset, iEndOffset); - } - -err: - /* TODO(shess) Check return? Should this be able to cause errors at - ** this point? Actually, same question about sqlite3_finalize(), - ** though one could argue that failure there means that the data is - ** not durable. *ponder* - */ - pTokenizer->pModule->xClose(pCursor); - return rc; -} -/* Update the %_terms table to map the term [zTerm] to the given rowid. */ -static int index_insert_term(fulltext_vtab *v, const char *zTerm, int nTerm, - sqlite_int64 iDocid, DocList *p){ - sqlite_int64 iFirst; - sqlite_int64 iIndexRow; - DocList doclist; - - int rc = term_chunk_select(v, zTerm, nTerm, iDocid, &iFirst); - if( rc==SQLITE_DONE ){ - docListInit(&doclist, DL_POSITIONS_OFFSETS, 0, 0); - if( docListUpdate(&doclist, iDocid, p) ){ - rc = term_insert(v, zTerm, nTerm, iDocid, &doclist); - docListDestroy(&doclist); - return rc; - } - return SQLITE_OK; - } - if( rc!=SQLITE_ROW ) return SQLITE_ERROR; - - /* This word is in the index; add this document ID to its blob. */ - - rc = term_select(v, zTerm, nTerm, iFirst, &iIndexRow, &doclist); - if( rc!=SQLITE_OK ) return rc; - - if( docListUpdate(&doclist, iDocid, p) ){ - /* If the blob is too big, split it in half. */ - if( doclist.nData>CHUNK_MAX ){ - DocList half; - if( docListSplit(&doclist, &half) ){ - rc = term_insert(v, zTerm, nTerm, firstDocid(&half), &half); - docListDestroy(&half); - if( rc!=SQLITE_OK ) goto err; - } - } - rc = term_update(v, iIndexRow, &doclist); - } - -err: - docListDestroy(&doclist); - return rc; -} - -/* Insert a row into the full-text index; set *piRowid to be the ID of the - * new row. */ -static int index_insert(fulltext_vtab *v, - sqlite3_value *pRequestRowid, const char *zText, - sqlite_int64 *piRowid){ - Hash terms; /* maps term string -> PosList */ - HashElem *e; - - int rc = content_insert(v, pRequestRowid, zText, -1); - if( rc!=SQLITE_OK ) return rc; - *piRowid = sqlite3_last_insert_rowid(v->db); - - if( !zText ) return SQLITE_OK; /* nothing to index */ - - rc = build_terms(&terms, v->pTokenizer, zText, *piRowid); - if( rc!=SQLITE_OK ) return rc; - - for(e=HashFirst(&terms); e; e=HashNext(e)){ - DocList *p = HashData(e); - rc = index_insert_term(v, HashKey(e), HashKeysize(e), *piRowid, p); - if( rc!=SQLITE_OK ) break; - } - - for(e=HashFirst(&terms); e; e=HashNext(e)){ - DocList *p = HashData(e); - docListDelete(p); - } - HashClear(&terms); - return rc; -} - -static int index_delete_term(fulltext_vtab *v, const char *zTerm, int nTerm, - sqlite_int64 iDocid){ - sqlite_int64 iFirst; - sqlite_int64 iIndexRow; - DocList doclist; - - int rc = term_chunk_select(v, zTerm, nTerm, iDocid, &iFirst); - if( rc!=SQLITE_ROW ) return SQLITE_ERROR; - - rc = term_select(v, zTerm, nTerm, iFirst, &iIndexRow, &doclist); - if( rc!=SQLITE_OK ) return rc; - - if( docListUpdate(&doclist, iDocid, NULL) ){ - if( doclist.nData>0 ){ - rc = term_update(v, iIndexRow, &doclist); - } else { /* empty posting list */ - rc = term_delete(v, iIndexRow); - } - } - docListDestroy(&doclist); - return rc; -} - -/* Delete a row from the full-text index. */ -static int index_delete(fulltext_vtab *v, sqlite_int64 iRow){ - char *zText; - Hash terms; - HashElem *e; - - int rc = content_select(v, iRow, &zText); - if( rc!=SQLITE_OK ) return rc; - - rc = build_terms(&terms, v->pTokenizer, zText, iRow); - free(zText); - if( rc!=SQLITE_OK ) return rc; - - for(e=HashFirst(&terms); e; e=HashNext(e)){ - rc = index_delete_term(v, HashKey(e), HashKeysize(e), iRow); - if( rc!=SQLITE_OK ) break; - } - for(e=HashFirst(&terms); e; e=HashNext(e)){ - DocList *p = HashData(e); - docListDelete(p); - } - HashClear(&terms); - - return content_delete(v, iRow); -} - -static int fulltextUpdate(sqlite3_vtab *pVtab, int nArg, sqlite3_value **ppArg, - sqlite_int64 *pRowid){ - fulltext_vtab *v = (fulltext_vtab *) pVtab; - - if( nArg<2 ){ - return index_delete(v, sqlite3_value_int64(ppArg[0])); - } - - if( sqlite3_value_type(ppArg[0]) != SQLITE_NULL ){ - return SQLITE_ERROR; /* an update; not yet supported */ - } - - assert( nArg==3 ); /* ppArg[1] = rowid, ppArg[2] = content */ - return index_insert(v, ppArg[1], - (const char *)sqlite3_value_text(ppArg[2]), pRowid); -} - -static sqlite3_module fulltextModule = { - 0, - fulltextCreate, - fulltextConnect, - fulltextBestIndex, - fulltextDisconnect, - fulltextDestroy, - fulltextOpen, - fulltextClose, - fulltextFilter, - fulltextNext, - fulltextEof, - fulltextColumn, - fulltextRowid, - fulltextUpdate -}; - -int fulltext_init(sqlite3 *db){ - return sqlite3_create_module(db, "fulltext", &fulltextModule, 0); -} - -#if !SQLITE_CORE -int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, - const sqlite3_api_routines *pApi){ - SQLITE_EXTENSION_INIT2(pApi) - return fulltext_init(db); -} -#endif DELETED ext/fts1/fulltext.h Index: ext/fts1/fulltext.h ================================================================== --- ext/fts1/fulltext.h +++ /dev/null @@ -1,11 +0,0 @@ -#include "sqlite3.h" - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -int fulltext_init(sqlite3 *db); - -#ifdef __cplusplus -} /* extern "C" */ -#endif /* __cplusplus */ DELETED ext/fts1/simple_tokenizer.c Index: ext/fts1/simple_tokenizer.c ================================================================== --- ext/fts1/simple_tokenizer.c +++ /dev/null @@ -1,174 +0,0 @@ -/* -** The author disclaims copyright to this source code. -** -************************************************************************* -** Implementation of the "simple" full-text-search tokenizer. -*/ - -#include -#if !defined(__APPLE__) -#include -#else -#include -#endif -#include -#include -#include - -#include "tokenizer.h" - -/* Duplicate a string; the caller must free() the returned string. - * (We don't use strdup() since it's not part of the standard C library and - * may not be available everywhere.) */ -/* TODO(shess) Copied from fulltext.c, consider util.c for such -** things. */ -static char *string_dup(const char *s){ - char *str = malloc(strlen(s) + 1); - strcpy(str, s); - return str; -} - -typedef struct simple_tokenizer { - sqlite3_tokenizer base; - const char *zDelim; /* token delimiters */ -} simple_tokenizer; - -typedef struct simple_tokenizer_cursor { - sqlite3_tokenizer_cursor base; - const char *pInput; /* input we are tokenizing */ - int nBytes; /* size of the input */ - const char *pCurrent; /* current position in pInput */ - int iToken; /* index of next token to be returned */ - char *zToken; /* storage for current token */ - int nTokenBytes; /* actual size of current token */ - int nTokenAllocated; /* space allocated to zToken buffer */ -} simple_tokenizer_cursor; - -static sqlite3_tokenizer_module simpleTokenizerModule;/* forward declaration */ - -static int simpleCreate( - int argc, const char **argv, - sqlite3_tokenizer **ppTokenizer -){ - simple_tokenizer *t; - - t = (simple_tokenizer *) malloc(sizeof(simple_tokenizer)); - /* TODO(shess) Delimiters need to remain the same from run to run, - ** else we need to reindex. One solution would be a meta-table to - ** track such information in the database, then we'd only want this - ** information on the initial create. - */ - if( argc>1 ){ - t->zDelim = string_dup(argv[1]); - } else { - /* Build a string excluding alphanumeric ASCII characters */ - char zDelim[0x80]; /* nul-terminated, so nul not a member */ - int i, j; - for(i=1, j=0; i<0x80; i++){ - if( !isalnum(i) ){ - zDelim[j++] = i; - } - } - zDelim[j++] = '\0'; - assert( j<=sizeof(zDelim) ); - t->zDelim = string_dup(zDelim); - } - - *ppTokenizer = &t->base; - return SQLITE_OK; -} - -static int simpleDestroy(sqlite3_tokenizer *pTokenizer){ - simple_tokenizer *t = (simple_tokenizer *) pTokenizer; - - free((void *) t->zDelim); - free(t); - - return SQLITE_OK; -} - -static int simpleOpen( - sqlite3_tokenizer *pTokenizer, - const char *pInput, int nBytes, - sqlite3_tokenizer_cursor **ppCursor -){ - simple_tokenizer_cursor *c; - - c = (simple_tokenizer_cursor *) malloc(sizeof(simple_tokenizer_cursor)); - c->pInput = pInput; - c->nBytes = nBytes<0 ? (int) strlen(pInput) : nBytes; - c->pCurrent = c->pInput; /* start tokenizing at the beginning */ - c->iToken = 0; - c->zToken = NULL; /* no space allocated, yet. */ - c->nTokenBytes = 0; - c->nTokenAllocated = 0; - - *ppCursor = &c->base; - return SQLITE_OK; -} - -static int simpleClose(sqlite3_tokenizer_cursor *pCursor){ - simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; - - if( NULL!=c->zToken ){ - free(c->zToken); - } - free(c); - - return SQLITE_OK; -} - -static int simpleNext( - sqlite3_tokenizer_cursor *pCursor, - const char **ppToken, int *pnBytes, - int *piStartOffset, int *piEndOffset, int *piPosition -){ - simple_tokenizer_cursor *c = (simple_tokenizer_cursor *) pCursor; - simple_tokenizer *t = (simple_tokenizer *) pCursor->pTokenizer; - int ii; - - while( c->pCurrent-c->pInputnBytes ){ - int n = (int) strcspn(c->pCurrent, t->zDelim); - if( n>0 ){ - if( n+1>c->nTokenAllocated ){ - c->zToken = realloc(c->zToken, n+1); - } - for(ii=0; iipCurrent[ii]; - c->zToken[ii] = (unsigned char)ch<0x80 ? tolower(ch) : ch; - } - c->zToken[n] = '\0'; - *ppToken = c->zToken; - *pnBytes = n; - *piStartOffset = (int) (c->pCurrent-c->pInput); - *piEndOffset = *piStartOffset+n; - *piPosition = c->iToken++; - c->pCurrent += n + 1; - - return SQLITE_OK; - } - c->pCurrent += n + 1; - /* TODO(shess) could strspn() to skip delimiters en masse. Needs - ** to happen in two places, though, which is annoying. - */ - } - return SQLITE_DONE; -} - -static sqlite3_tokenizer_module simpleTokenizerModule = { - 0, - simpleCreate, - simpleDestroy, - simpleOpen, - simpleClose, - simpleNext, -}; - -void get_simple_tokenizer_module( - sqlite3_tokenizer_module **ppModule -){ - *ppModule = &simpleTokenizerModule; -} DELETED ext/fts1/tokenizer.h Index: ext/fts1/tokenizer.h ================================================================== --- ext/fts1/tokenizer.h +++ /dev/null @@ -1,89 +0,0 @@ -/* -** 2006 July 10 -** -** The author disclaims copyright to this source code. -** -************************************************************************* -** Defines the interface to tokenizers used by fulltext-search. There -** are three basic components: -** -** sqlite3_tokenizer_module is a singleton defining the tokenizer -** interface functions. This is essentially the class structure for -** tokenizers. -** -** sqlite3_tokenizer is used to define a particular tokenizer, perhaps -** including customization information defined at creation time. -** -** sqlite3_tokenizer_cursor is generated by a tokenizer to generate -** tokens from a particular input. -*/ -#ifndef _TOKENIZER_H_ -#define _TOKENIZER_H_ - -/* TODO(shess) Only used for SQLITE_OK and SQLITE_DONE at this time. -** If tokenizers are to be allowed to call sqlite3_*() functions, then -** we will need a way to register the API consistently. -*/ -#include "sqlite3.h" - -/* -** Structures used by the tokenizer interface. -*/ -typedef struct sqlite3_tokenizer sqlite3_tokenizer; -typedef struct sqlite3_tokenizer_cursor sqlite3_tokenizer_cursor; -typedef struct sqlite3_tokenizer_module sqlite3_tokenizer_module; - -struct sqlite3_tokenizer_module { - int iVersion; /* currently 0 */ - - /* - ** Create and destroy a tokenizer. argc/argv are passed down from - ** the fulltext virtual table creation to allow customization. - */ - int (*xCreate)(int argc, const char **argv, - sqlite3_tokenizer **ppTokenizer); - int (*xDestroy)(sqlite3_tokenizer *pTokenizer); - - /* - ** Tokenize a particular input. Call xOpen() to prepare to - ** tokenize, xNext() repeatedly until it returns SQLITE_DONE, then - ** xClose() to free any internal state. The pInput passed to - ** xOpen() must exist until the cursor is closed. The ppToken - ** result from xNext() is only valid until the next call to xNext() - ** or until xClose() is called. - */ - /* TODO(shess) current implementation requires pInput to be - ** nul-terminated. This should either be fixed, or pInput/nBytes - ** should be converted to zInput. - */ - int (*xOpen)(sqlite3_tokenizer *pTokenizer, - const char *pInput, int nBytes, - sqlite3_tokenizer_cursor **ppCursor); - int (*xClose)(sqlite3_tokenizer_cursor *pCursor); - int (*xNext)(sqlite3_tokenizer_cursor *pCursor, - const char **ppToken, int *pnBytes, - int *piStartOffset, int *piEndOffset, int *piPosition); -}; - -struct sqlite3_tokenizer { - sqlite3_tokenizer_module *pModule; /* The module for this tokenizer */ - /* Tokenizer implementations will typically add additional fields */ -}; - -struct sqlite3_tokenizer_cursor { - sqlite3_tokenizer *pTokenizer; /* Tokenizer for this cursor. */ - /* Tokenizer implementations will typically add additional fields */ -}; - -/* -** Get the module for a tokenizer which generates tokens based on a -** set of non-token characters. The default is to break tokens at any -** non-alnum character, though the set of delimiters can also be -** specified by the first argv argument to xCreate(). -*/ -/* TODO(shess) This doesn't belong here. Need some sort of -** registration process. -*/ -void get_simple_tokenizer_module(sqlite3_tokenizer_module **ppModule); - -#endif /* _TOKENIZER_H_ */ DELETED sqlite3.def Index: sqlite3.def ================================================================== --- sqlite3.def +++ /dev/null @@ -1,105 +0,0 @@ -EXPORTS -sqlite3_aggregate_context -sqlite3_aggregate_count -sqlite3_bind_blob -sqlite3_bind_double -sqlite3_bind_int -sqlite3_bind_int64 -sqlite3_bind_null -sqlite3_bind_parameter_count -sqlite3_bind_parameter_index -sqlite3_bind_parameter_name -sqlite3_bind_text -sqlite3_bind_text16 -sqlite3_busy_handler -sqlite3_busy_timeout -sqlite3_changes -sqlite3_close -sqlite3_collation_needed -sqlite3_collation_needed16 -sqlite3_column_blob -sqlite3_column_bytes -sqlite3_column_bytes16 -sqlite3_column_count -sqlite3_column_decltype -sqlite3_column_decltype16 -sqlite3_column_double -sqlite3_column_int -sqlite3_column_int64 -sqlite3_column_name -sqlite3_column_name16 -sqlite3_column_text -sqlite3_column_text16 -sqlite3_column_type -sqlite3_commit_hook -sqlite3_complete -sqlite3_complete16 -sqlite3_create_collation -sqlite3_create_collation16 -sqlite3_create_function -sqlite3_create_function16 -sqlite3_data_count -sqlite3_db_handle -sqlite3_enable_load_extension -sqlite3_enable_shared_cache -sqlite3_errcode -sqlite3_errmsg -sqlite3_errmsg16 -sqlite3_exec -sqlite3_expired -sqlite3_finalize -sqlite3_free -sqlite3_free_table -sqlite3_get_autocommit -sqlite3_get_auxdata -sqlite3_get_table -sqlite3_global_recover -sqlite3_interrupt -sqlite3_last_insert_rowid -sqlite3_libversion -sqlite3_libversion_number -sqlite3_load_extension -sqlite3_malloc -sqlite3_mprintf -sqlite3_open -sqlite3_open16 -sqlite3_prepare -sqlite3_prepare16 -sqlite3_progress_handler -sqlite3_realloc -sqlite3_reset -sqlite3_result_blob -sqlite3_result_double -sqlite3_result_error -sqlite3_result_error16 -sqlite3_result_int -sqlite3_result_int64 -sqlite3_result_null -sqlite3_result_text -sqlite3_result_text16 -sqlite3_result_text16be -sqlite3_result_text16le -sqlite3_result_value -sqlite3_rollback_hook -sqlite3_set_authorizer -sqlite3_set_auxdata -sqlite3_snprintf -sqlite3_step -sqlite3_thread_cleanup -sqlite3_total_changes -sqlite3_trace -sqlite3_transfer_bindings -sqlite3_update_hook -sqlite3_user_data -sqlite3_value_blob -sqlite3_value_bytes -sqlite3_value_bytes16 -sqlite3_value_double -sqlite3_value_int -sqlite3_value_int64 -sqlite3_value_text -sqlite3_value_text16 -sqlite3_value_text16be -sqlite3_value_text16le -sqlite3_value_type -sqlite3_vmprintf Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -7,11 +7,11 @@ ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.358 2007/04/24 17:35:59 drh Exp $ +** $Id: btree.c,v 1.358.2.1 2007/08/14 13:20:27 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: @@ -5134,11 +5134,10 @@ goto end_shallow_balance; } } } #endif - if( rc!=SQLITE_OK ) goto end_shallow_balance; releasePage(pChild); } end_shallow_balance: sqliteFree(apCell); return rc; DELETED src/experimental.c Index: src/experimental.c ================================================================== --- src/experimental.c +++ /dev/null @@ -1,37 +0,0 @@ -/* -** 2005 January 20 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -** This file contains C code routines that are not a part of the official -** SQLite API. These routines are unsupported. -** -** $Id: experimental.c,v 1.4 2006/01/31 20:49:13 drh Exp $ -*/ -#include "sqliteInt.h" -#include "os.h" - -/* -** Set all the parameters in the compiled SQL statement to NULL. -*/ -int sqlite3_clear_bindings(sqlite3_stmt *pStmt){ - int i; - int rc = SQLITE_OK; - for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){ - rc = sqlite3_bind_null(pStmt, i); - } - return rc; -} - -/* -** Sleep for a little while. Return the amount of time slept. -*/ -int sqlite3_sleep(int ms){ - return sqlite3OsSleep(ms); -} DELETED src/md5.c Index: src/md5.c ================================================================== --- src/md5.c +++ /dev/null @@ -1,387 +0,0 @@ -/* -** SQLite uses this code for testing only. It is not a part of -** the SQLite library. This file implements two new TCL commands -** "md5" and "md5file" that compute md5 checksums on arbitrary text -** and on complete files. These commands are used by the "testfixture" -** program to help verify the correct operation of the SQLite library. -** -** The original use of these TCL commands was to test the ROLLBACK -** feature of SQLite. First compute the MD5-checksum of the database. -** Then make some changes but rollback the changes rather than commit -** them. Compute a second MD5-checksum of the file and verify that the -** two checksums are the same. Such is the original use of this code. -** New uses may have been added since this comment was written. -*/ -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest. This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - */ -#include -#include -#include "sqlite3.h" - -/* - * If compiled on a machine that doesn't have a 32-bit integer, - * you just set "uint32" to the appropriate datatype for an - * unsigned 32-bit integer. For example: - * - * cc -Duint32='unsigned long' md5.c - * - */ -#ifndef uint32 -# define uint32 unsigned int -#endif - -struct Context { - uint32 buf[4]; - uint32 bits[2]; - unsigned char in[64]; -}; -typedef char MD5Context[88]; - -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse (unsigned char *buf, unsigned longs){ - uint32 t; - do { - t = (uint32)((unsigned)buf[3]<<8 | buf[2]) << 16 | - ((unsigned)buf[1]<<8 | buf[0]); - *(uint32 *)buf = t; - buf += 4; - } while (--longs); -} -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm. */ -#define MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data. MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void MD5Transform(uint32 buf[4], const uint32 in[16]){ - register uint32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); - MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); - MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); - MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); - MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); - MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); - MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); - MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); - MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); - MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); - MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); - MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); - MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); - MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); - MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); - MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); - - MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); - MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); - MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); - MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); - MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); - MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); - MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); - MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); - MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); - MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); - MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); - MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); - MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); - MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); - MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); - MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); - - MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); - MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); - MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); - MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); - MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); - MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); - MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); - MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); - MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); - MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); - MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); - MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); - MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); - MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); - MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); - MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); - - MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); - MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); - MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); - MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); - MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); - MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); - MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); - MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); - MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); - MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); - MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); - MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); - MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); - MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); - MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); - MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} - -/* - * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious - * initialization constants. - */ -static void MD5Init(MD5Context *pCtx){ - struct Context *ctx = (struct Context *)pCtx; - ctx->buf[0] = 0x67452301; - ctx->buf[1] = 0xefcdab89; - ctx->buf[2] = 0x98badcfe; - ctx->buf[3] = 0x10325476; - ctx->bits[0] = 0; - ctx->bits[1] = 0; -} - -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -static -void MD5Update(MD5Context *pCtx, const unsigned char *buf, unsigned int len){ - struct Context *ctx = (struct Context *)pCtx; - uint32 t; - - /* Update bitcount */ - - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((uint32)len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - - /* Handle any leading odd-sized chunks */ - - if ( t ) { - unsigned char *p = (unsigned char *)ctx->in + t; - - t = 64-t; - if (len < t) { - memcpy(p, buf, len); - return; - } - memcpy(p, buf, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - buf += t; - len -= t; - } - - /* Process data in 64-byte chunks */ - - while (len >= 64) { - memcpy(ctx->in, buf, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - buf += 64; - len -= 64; - } - - /* Handle any remaining bytes of data. */ - - memcpy(ctx->in, buf, len); -} - -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -static void MD5Final(unsigned char digest[16], MD5Context *pCtx){ - struct Context *ctx = (struct Context *)pCtx; - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80. This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - memset(p, 0, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (uint32 *)ctx->in); - - /* Now fill the next block with 56 bytes */ - memset(ctx->in, 0, 56); - } else { - /* Pad block to 56 bytes */ - memset(p, 0, count-8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((uint32 *)ctx->in)[ 14 ] = ctx->bits[0]; - ((uint32 *)ctx->in)[ 15 ] = ctx->bits[1]; - - MD5Transform(ctx->buf, (uint32 *)ctx->in); - byteReverse((unsigned char *)ctx->buf, 4); - memcpy(digest, ctx->buf, 16); - memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */ -} - -/* -** Convert a digest into base-16. digest should be declared as -** "unsigned char digest[16]" in the calling function. The MD5 -** digest is stored in the first 16 bytes. zBuf should -** be "char zBuf[33]". -*/ -static void DigestToBase16(unsigned char *digest, char *zBuf){ - static char const zEncode[] = "0123456789abcdef"; - int i, j; - - for(j=i=0; i<16; i++){ - int a = digest[i]; - zBuf[j++] = zEncode[(a>>4)&0xf]; - zBuf[j++] = zEncode[a & 0xf]; - } - zBuf[j] = 0; -} - -/* -** A TCL command for md5. The argument is the text to be hashed. The -** Result is the hash in base64. -*/ -static int md5_cmd(void*cd, Tcl_Interp *interp, int argc, const char **argv){ - MD5Context ctx; - unsigned char digest[16]; - - if( argc!=2 ){ - Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], - " TEXT\"", 0); - return TCL_ERROR; - } - MD5Init(&ctx); - MD5Update(&ctx, (unsigned char*)argv[1], (unsigned)strlen(argv[1])); - MD5Final(digest, &ctx); - DigestToBase16(digest, interp->result); - return TCL_OK; -} - -/* -** A TCL command to take the md5 hash of a file. The argument is the -** name of the file. -*/ -static int md5file_cmd(void*cd, Tcl_Interp*interp, int argc, const char **argv){ - FILE *in; - MD5Context ctx; - unsigned char digest[16]; - char zBuf[10240]; - - if( argc!=2 ){ - Tcl_AppendResult(interp,"wrong # args: should be \"", argv[0], - " FILENAME\"", 0); - return TCL_ERROR; - } - in = fopen(argv[1],"rb"); - if( in==0 ){ - Tcl_AppendResult(interp,"unable to open file \"", argv[1], - "\" for reading", 0); - return TCL_ERROR; - } - MD5Init(&ctx); - for(;;){ - int n; - n = fread(zBuf, 1, sizeof(zBuf), in); - if( n<=0 ) break; - MD5Update(&ctx, (unsigned char*)zBuf, (unsigned)n); - } - fclose(in); - MD5Final(digest, &ctx); - DigestToBase16(digest, interp->result); - return TCL_OK; -} - -/* -** Register the two TCL commands above with the TCL interpreter. -*/ -int Md5_Init(Tcl_Interp *interp){ - Tcl_CreateCommand(interp, "md5", (Tcl_CmdProc*)md5_cmd, 0, 0); - Tcl_CreateCommand(interp, "md5file", (Tcl_CmdProc*)md5file_cmd, 0, 0); - return TCL_OK; -} - -/* -** During testing, the special md5sum() aggregate function is available. -** inside SQLite. The following routines implement that function. -*/ -static void md5step(sqlite3_context *context, int argc, sqlite3_value **argv){ - MD5Context *p; - int i; - if( argc<1 ) return; - p = sqlite3_aggregate_context(context, sizeof(*p)); - if( p==0 ) return; - if( sqlite3_aggregate_count(context)==1 ){ - MD5Init(p); - } - for(i=0; in ){ - n = strlen(zPath); - } - r = 0; - if( iCrashDelay>0 && strncmp(zPath, zCrashFile, n)==0 ){ - iCrashDelay--; - if( iCrashDelay<=0 ){ - r = 1; - } - } - sqlite3OsLeaveMutex(); - return r; -} - - -static OsTestFile *pAllFiles = 0; - -/* -** Initialise the os_test.c specific fields of pFile. -*/ -static void initFile(OsFile *id, char const *zName){ - OsTestFile *pFile = (OsTestFile *) - sqliteMalloc(sizeof(OsTestFile) + strlen(zName)+1); - pFile->nMaxWrite = 0; - pFile->nBlk = 0; - pFile->apBlk = 0; - pFile->zName = (char *)(&pFile[1]); - strcpy(pFile->zName, zName); - *id = pFile; - pFile->pNext = pAllFiles; - pAllFiles = pFile; -} - -/* -** Undo the work done by initFile. Delete the OsTestFile structure -** and unlink the structure from the pAllFiles list. -*/ -static void closeFile(OsFile *id){ - OsTestFile *pFile = *id; - if( pFile==pAllFiles ){ - pAllFiles = pFile->pNext; - }else{ - OsTestFile *p; - for(p=pAllFiles; p->pNext!=pFile; p=p->pNext ){ - assert( p ); - } - p->pNext = pFile->pNext; - } - sqliteFree(pFile); - *id = 0; -} - -/* -** Return the current seek offset from the start of the file. This -** is unix-only code. -*/ -static i64 osTell(OsTestFile *pFile){ - return lseek(pFile->fd.h, 0, SEEK_CUR); -} - -/* -** Load block 'blk' into the cache of pFile. -*/ -static int cacheBlock(OsTestFile *pFile, int blk){ - if( blk>=pFile->nBlk ){ - int n = ((pFile->nBlk * 2) + 100 + blk); - /* if( pFile->nBlk==0 ){ printf("DIRTY %s\n", pFile->zName); } */ - pFile->apBlk = (u8 **)sqliteRealloc(pFile->apBlk, n * sizeof(u8*)); - if( !pFile->apBlk ) return SQLITE_NOMEM; - memset(&pFile->apBlk[pFile->nBlk], 0, (n - pFile->nBlk)*sizeof(u8*)); - pFile->nBlk = n; - } - - if( !pFile->apBlk[blk] ){ - i64 filesize; - int rc; - - u8 *p = sqliteMalloc(BLOCKSIZE); - if( !p ) return SQLITE_NOMEM; - pFile->apBlk[blk] = p; - - rc = sqlite3RealFileSize(&pFile->fd, &filesize); - if( rc!=SQLITE_OK ) return rc; - - if( BLOCK_OFFSET(blk)fd, blk*BLOCKSIZE); - if( BLOCK_OFFSET(blk+1)>filesize ){ - len = filesize - BLOCK_OFFSET(blk); - } - if( rc!=SQLITE_OK ) return rc; - rc = sqlite3RealRead(&pFile->fd, p, len); - if( rc!=SQLITE_OK ) return rc; - } - } - - return SQLITE_OK; -} - -/* #define TRACE_WRITECACHE */ - -/* -** Write the cache of pFile to disk. If crash is non-zero, randomly -** skip blocks when writing. The cache is deleted before returning. -*/ -static int writeCache2(OsTestFile *pFile, int crash){ - int i; - int nMax = pFile->nMaxWrite; - i64 offset; - int rc = SQLITE_OK; - - offset = osTell(pFile); - for(i=0; inBlk; i++){ - u8 *p = pFile->apBlk[i]; - if( p ){ - int skip = 0; - int trash = 0; - if( crash ){ - char random; - sqlite3Randomness(1, &random); - if( random & 0x01 ){ - if( random & 0x02 ){ - trash = 1; -#ifdef TRACE_WRITECACHE -printf("Trashing block %d of %s\n", i, pFile->zName); -#endif - }else{ - skip = 1; -#ifdef TRACE_WRITECACHE -printf("Skiping block %d of %s\n", i, pFile->zName); -#endif - } - }else{ -#ifdef TRACE_WRITECACHE -printf("Writing block %d of %s\n", i, pFile->zName); -#endif - } - } - if( rc==SQLITE_OK ){ - rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i)); - } - if( rc==SQLITE_OK && !skip ){ - int len = BLOCKSIZE; - if( BLOCK_OFFSET(i+1)>nMax ){ - len = nMax-BLOCK_OFFSET(i); - } - if( len>0 ){ - if( trash ){ - sqlite3Randomness(len, p); - } - rc = sqlite3RealWrite(&pFile->fd, p, len); - } - } - sqliteFree(p); - } - } - sqliteFree(pFile->apBlk); - pFile->nBlk = 0; - pFile->apBlk = 0; - pFile->nMaxWrite = 0; - - if( rc==SQLITE_OK ){ - rc = sqlite3RealSeek(&pFile->fd, offset); - } - return rc; -} - -/* -** Write the cache to disk. -*/ -static int writeCache(OsTestFile *pFile){ - if( pFile->apBlk ){ - int c = crashRequired(pFile->zName); - if( c ){ - OsTestFile *p; -#ifdef TRACE_WRITECACHE - printf("\nCrash during sync of %s\n", pFile->zName); -#endif - for(p=pAllFiles; p; p=p->pNext){ - writeCache2(p, 1); - } - exit(-1); - }else{ - return writeCache2(pFile, 0); - } - } - return SQLITE_OK; -} - -/* -** Close the file. -*/ -int sqlite3OsClose(OsFile *id){ - if( !(*id) ) return SQLITE_OK; - if( (*id)->fd.isOpen ){ - /* printf("CLOSE %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */ - writeCache(*id); - sqlite3RealClose(&(*id)->fd); - } - closeFile(id); - return SQLITE_OK; -} - -int sqlite3OsRead(OsFile *id, void *pBuf, int amt){ - i64 offset; /* The current offset from the start of the file */ - i64 end; /* The byte just past the last byte read */ - int blk; /* Block number the read starts on */ - int i; - u8 *zCsr; - int rc = SQLITE_OK; - OsTestFile *pFile = *id; - - offset = osTell(pFile); - end = offset+amt; - blk = (offset/BLOCKSIZE); - - zCsr = (u8 *)pBuf; - for(i=blk; i*BLOCKSIZE end ){ - len = len - (BLOCK_OFFSET(i+1)-end); - } - - if( inBlk && pFile->apBlk[i]){ - u8 *pBlk = pFile->apBlk[i]; - memcpy(zCsr, &pBlk[off], len); - }else{ - rc = sqlite3RealSeek(&pFile->fd, BLOCK_OFFSET(i) + off); - if( rc!=SQLITE_OK ) return rc; - rc = sqlite3RealRead(&pFile->fd, zCsr, len); - if( rc!=SQLITE_OK ) return rc; - } - - zCsr += len; - } - assert( zCsr==&((u8 *)pBuf)[amt] ); - - rc = sqlite3RealSeek(&pFile->fd, end); - return rc; -} - -int sqlite3OsWrite(OsFile *id, const void *pBuf, int amt){ - i64 offset; /* The current offset from the start of the file */ - i64 end; /* The byte just past the last byte written */ - int blk; /* Block number the write starts on */ - int i; - const u8 *zCsr; - int rc = SQLITE_OK; - OsTestFile *pFile = *id; - - offset = osTell(pFile); - end = offset+amt; - blk = (offset/BLOCKSIZE); - - zCsr = (u8 *)pBuf; - for(i=blk; i*BLOCKSIZEapBlk[i]; - assert( pBlk ); - - if( BLOCK_OFFSET(i) < offset ){ - off = offset-BLOCK_OFFSET(i); - } - len = BLOCKSIZE - off; - if( BLOCK_OFFSET(i+1) > end ){ - len = len - (BLOCK_OFFSET(i+1)-end); - } - memcpy(&pBlk[off], zCsr, len); - zCsr += len; - } - if( pFile->nMaxWritenMaxWrite = end; - } - assert( zCsr==&((u8 *)pBuf)[amt] ); - - rc = sqlite3RealSeek(&pFile->fd, end); - return rc; -} - -/* -** Sync the file. First flush the write-cache to disk, then call the -** real sync() function. -*/ -int sqlite3OsSync(OsFile *id, int dataOnly){ - int rc; - /* printf("SYNC %s (%d blocks)\n", (*id)->zName, (*id)->nBlk); */ - rc = writeCache(*id); - if( rc!=SQLITE_OK ) return rc; - rc = sqlite3RealSync(&(*id)->fd, dataOnly); - return rc; -} - -/* -** Truncate the file. Set the internal OsFile.nMaxWrite variable to the new -** file size to ensure that nothing in the write-cache past this point -** is written to disk. -*/ -int sqlite3OsTruncate(OsFile *id, i64 nByte){ - (*id)->nMaxWrite = nByte; - return sqlite3RealTruncate(&(*id)->fd, nByte); -} - -/* -** Return the size of the file. If the cache contains a write that extended -** the file, then return this size instead of the on-disk size. -*/ -int sqlite3OsFileSize(OsFile *id, i64 *pSize){ - int rc = sqlite3RealFileSize(&(*id)->fd, pSize); - if( rc==SQLITE_OK && pSize && *pSize<(*id)->nMaxWrite ){ - *pSize = (*id)->nMaxWrite; - } - return rc; -} - -/* -** The three functions used to open files. All that is required is to -** initialise the os_test.c specific fields and then call the corresponding -** os_unix.c function to really open the file. -*/ -int sqlite3OsOpenReadWrite(const char *zFilename, OsFile *id, int *pReadonly){ - initFile(id, zFilename); - return sqlite3RealOpenReadWrite(zFilename, &(*id)->fd, pReadonly); -} -int sqlite3OsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ - initFile(id, zFilename); - return sqlite3RealOpenExclusive(zFilename, &(*id)->fd, delFlag); -} -int sqlite3OsOpenReadOnly(const char *zFilename, OsFile *id){ - initFile(id, zFilename); - return sqlite3RealOpenReadOnly(zFilename, &(*id)->fd); -} - -/* -** These six function calls are passed straight through to the os_unix.c -** backend. -*/ -int sqlite3OsSeek(OsFile *id, i64 offset){ - return sqlite3RealSeek(&(*id)->fd, offset); -} -int sqlite3OsCheckReservedLock(OsFile *id){ - return sqlite3RealCheckReservedLock(&(*id)->fd); -} -int sqlite3OsLock(OsFile *id, int locktype){ - return sqlite3RealLock(&(*id)->fd, locktype); -} -int sqlite3OsUnlock(OsFile *id, int locktype){ - return sqlite3RealUnlock(&(*id)->fd, locktype); -} -int sqlite3OsOpenDirectory(const char *zDirname, OsFile *id){ - return sqlite3RealOpenDirectory(zDirname, &(*id)->fd); -} - -#endif /* OS_TEST */ DELETED src/os_test.h Index: src/os_test.h ================================================================== --- src/os_test.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -** 2004 May 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -*/ -#ifndef _SQLITE_OS_TEST_H_ -#define _SQLITE_OS_TEST_H_ - -#define OsFile OsRealFile -#define OS_UNIX 1 -#include "os_unix.h" -#undef OS_UNIX -#undef OsFile -#undef SET_FULLSYNC - -/* Include sqliteInt.h now to get the type u8. */ -#include "sqliteInt.h" - -typedef struct OsTestFile* OsFile; -typedef struct OsTestFile OsTestFile; -struct OsTestFile { - u8 **apBlk; /* Array of blocks that have been written to. */ - int nBlk; /* Size of apBlock. */ - int nMaxWrite; /* Largest offset written to. */ - char *zName; /* File name */ - OsRealFile fd; - OsTestFile *pNext; -}; - -void sqlite3SetCrashParams(int iDelay, char const *zFile); - -#endif /* _SQLITE_OS_UNIX_H_ */ DELETED src/os_unix.h Index: src/os_unix.h ================================================================== --- src/os_unix.h +++ /dev/null @@ -1,116 +0,0 @@ -/* -** 2004 May 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This header file defined OS-specific features for Unix. -*/ -#ifndef _SQLITE_OS_UNIX_H_ -#define _SQLITE_OS_UNIX_H_ - -/* -** Helpful hint: To get this to compile on HP/UX, add -D_INCLUDE_POSIX_SOURCE -** to the compiler command line. -*/ - -/* -** These #defines should enable >2GB file support on Posix if the -** underlying operating system supports it. If the OS lacks -** large file support, or if the OS is windows, these should be no-ops. -** -** Large file support can be disabled using the -DSQLITE_DISABLE_LFS switch -** on the compiler command line. This is necessary if you are compiling -** on a recent machine (ex: RedHat 7.2) but you want your code to work -** on an older machine (ex: RedHat 6.0). If you compile on RedHat 7.2 -** without this option, LFS is enable. But LFS does not exist in the kernel -** in RedHat 6.0, so the code won't work. Hence, for maximum binary -** portability you should omit LFS. -** -** Similar is true for MacOS. LFS is only supported on MacOS 9 and later. -*/ -#ifndef SQLITE_DISABLE_LFS -# define _LARGE_FILE 1 -# ifndef _FILE_OFFSET_BITS -# define _FILE_OFFSET_BITS 64 -# endif -# define _LARGEFILE_SOURCE 1 -#endif - -/* -** standard include files. -*/ -#include -#include -#include -#include - -/* -** Macros used to determine whether or not to use threads. The -** SQLITE_UNIX_THREADS macro is defined if we are synchronizing for -** Posix threads and SQLITE_W32_THREADS is defined if we are -** synchronizing using Win32 threads. -*/ -#if defined(THREADSAFE) && THREADSAFE -# include -# define SQLITE_UNIX_THREADS 1 -#endif - -/* -** The OsFile structure is a operating-system independing representation -** of an open file handle. It is defined differently for each architecture. -** -** This is the definition for Unix. -** -** OsFile.locktype takes one of the values SHARED_LOCK, RESERVED_LOCK, -** PENDING_LOCK or EXCLUSIVE_LOCK. -*/ -typedef struct OsFile OsFile; -struct OsFile { - struct Pager *pPager; /* The pager that owns this OsFile. Might be 0 */ - struct openCnt *pOpen; /* Info about all open fd's on this inode */ - struct lockInfo *pLock; /* Info about locks on this inode */ - int h; /* The file descriptor */ - unsigned char locktype; /* The type of lock held on this fd */ - unsigned char isOpen; /* True if needs to be closed */ - unsigned char fullSync; /* Use F_FULLSYNC if available */ - int dirfd; /* File descriptor for the directory */ -#ifdef SQLITE_UNIX_THREADS - pthread_t tid; /* The thread authorized to use this OsFile */ -#endif -}; - -/* -** A macro to set the OsFile.fullSync flag, if it exists. -*/ -#define SET_FULLSYNC(x,y) ((x).fullSync = (y)) - -/* -** Maximum number of characters in a temporary file name -*/ -#define SQLITE_TEMPNAME_SIZE 200 - -/* -** Minimum interval supported by sqlite3OsSleep(). -*/ -#if defined(HAVE_USLEEP) && HAVE_USLEEP -# define SQLITE_MIN_SLEEP_MS 1 -#else -# define SQLITE_MIN_SLEEP_MS 1000 -#endif - -/* -** Default permissions when creating a new file -*/ -#ifndef SQLITE_DEFAULT_FILE_PERMISSIONS -# define SQLITE_DEFAULT_FILE_PERMISSIONS 0644 -#endif - - -#endif /* _SQLITE_OS_UNIX_H_ */ DELETED src/os_win.h Index: src/os_win.h ================================================================== --- src/os_win.h +++ /dev/null @@ -1,40 +0,0 @@ -/* -** 2004 May 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This header file defines OS-specific features for Win32 -*/ -#ifndef _SQLITE_OS_WIN_H_ -#define _SQLITE_OS_WIN_H_ - -#include -#include - -/* -** The OsFile structure is a operating-system independing representation -** of an open file handle. It is defined differently for each architecture. -** -** This is the definition for Win32. -*/ -typedef struct OsFile OsFile; -struct OsFile { - HANDLE h; /* Handle for accessing the file */ - unsigned char locktype; /* Type of lock currently held on this file */ - unsigned char isOpen; /* True if needs to be closed */ - short sharedLockByte; /* Randomly chosen byte used as a shared lock */ -}; - - -#define SQLITE_TEMPNAME_SIZE (MAX_PATH+50) -#define SQLITE_MIN_SLEEP_MS 1 - - -#endif /* _SQLITE_OS_WIN_H_ */ Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -16,11 +16,11 @@ ** is separate from the database file. The pager also implements file ** locking to prevent two processes from writing the same database ** file simultaneously, or one process from reading the database while ** another is writing. ** -** @(#) $Id: pager.c,v 1.329 2007/04/16 15:02:19 drh Exp $ +** @(#) $Id: pager.c,v 1.329.2.1 2007/08/14 13:20:28 drh Exp $ */ #ifndef SQLITE_OMIT_DISKIO #include "sqliteInt.h" #include "os.h" #include "pager.h" @@ -504,11 +504,15 @@ ** the error becomes persistent. All subsequent API calls on this Pager ** will immediately return the same error code. */ static int pager_error(Pager *pPager, int rc){ int rc2 = rc & 0xff; - assert( pPager->errCode==SQLITE_FULL || pPager->errCode==SQLITE_OK ); + assert( + pPager->errCode==SQLITE_FULL || + pPager->errCode==SQLITE_OK || + (pPager->errCode & 0xff)==SQLITE_IOERR + ); if( rc2==SQLITE_FULL || rc2==SQLITE_IOERR || rc2==SQLITE_CORRUPT ){ @@ -1083,29 +1087,33 @@ assert( pPager->state==PAGER_RESERVED || pPager->state>=PAGER_EXCLUSIVE ); /* If the pager is in RESERVED state, then there must be a copy of this ** page in the pager cache. In this case just update the pager cache, ** not the database file. The page is left marked dirty in this case. + ** + ** If a malloc() or I/O error occurs during a Movepage() call then the + ** page might not be in cache. So the condition described in the + ** above paragraph is not assertable. ** ** If in EXCLUSIVE state, then we update the pager cache if it exists ** and the main file. The page is then marked not dirty. ** ** Ticket #1171: The statement journal might contain page content that is ** different from the page content at the start of the transaction. ** This occurs when a page is changed prior to the start of a statement ** then changed again within the statement. When rolling back such a ** statement we must not write to the original database unless we know - ** for certain that original page contents are in the main rollback - ** journal. Otherwise, if a full ROLLBACK occurs after the statement - ** rollback the full ROLLBACK will not restore the page to its original - ** content. Two conditions must be met before writing to the database - ** files. (1) the database must be locked. (2) we know that the original - ** page content is in the main journal either because the page is not in - ** cache or else it is marked as needSync==0. + ** for certain that original page contents are synced into the main rollback + ** journal. Otherwise, a power loss might leave modified data in the + ** database file without an entry in the rollback journal that can + ** restore the database to its original form. Two conditions must be + ** met before writing to the database files. (1) the database must be + ** locked. (2) we know that the original page content is fully synced + ** in the main journal either because the page is not in cache or else + ** the page is marked as needSync==0. */ pPg = pager_lookup(pPager, pgno); - assert( pPager->state>=PAGER_EXCLUSIVE || pPg!=0 ); PAGERTRACE3("PLAYBACK %d page %d\n", PAGERID(pPager), pgno); if( pPager->state>=PAGER_EXCLUSIVE && (pPg==0 || pPg->needSync==0) ){ rc = sqlite3OsSeek(pPager->fd, (pgno-1)*(i64)pPager->pageSize); if( rc==SQLITE_OK ){ rc = sqlite3OsWrite(pPager->fd, aData, pPager->pageSize); @@ -1362,14 +1370,19 @@ assert( pPager->journalOff==JOURNAL_HDR_SZ(pPager) ); nRec = (szJ - JOURNAL_HDR_SZ(pPager))/JOURNAL_PG_SZ(pPager); } /* If nRec is 0 and this rollback is of a transaction created by this - ** process. In this case the rest of the journal file consists of - ** journalled copies of pages that need to be read back into the cache. + ** process and if this is the final header in the journal, then it means + ** that this part of the journal was being filled but has not yet been + ** synced to disk. Compute the number of pages based on the remaining + ** size of the file. + ** + ** The third term of the test was added to fix ticket #2565. */ - if( nRec==0 && !isHot ){ + if( nRec==0 && !isHot && + pPager->journalHdr+JOURNAL_HDR_SZ(pPager)==pPager->journalOff ){ nRec = (szJ - pPager->journalOff) / JOURNAL_PG_SZ(pPager); } /* If this is the first header read from the journal, truncate the ** database file back to it's original size. @@ -2645,11 +2658,11 @@ }else{ for( pTmp=pPager->pAll; pTmp->pNextAll!=pPg; pTmp=pTmp->pNextAll ){} pTmp->pNextAll = pPg->pNextAll; } nReleased += sqliteAllocSize(pPg); - IOTRACE(("PGFREE %p %d\n", pPager, pPg->pgno)); + IOTRACE(("PGFREE %p %d *\n", pPager, pPg->pgno)); PAGER_INCR(sqlite3_pager_pgfree_count); sqliteFree(pPg); } if( rc!=SQLITE_OK ){ @@ -2657,11 +2670,15 @@ ** journal in pager_recycle(). The error is not returned to the ** caller of this function. Instead, set the Pager.errCode variable. ** The error will be returned to the user (or users, in the case ** of a shared pager cache) of the pager for which the error occured. */ - assert( (rc&0xff)==SQLITE_IOERR || rc==SQLITE_FULL ); + assert( + (rc&0xff)==SQLITE_IOERR || + rc==SQLITE_FULL || + rc==SQLITE_BUSY + ); assert( pPager->state>=PAGER_RESERVED ); pager_error(pPager, rc); } } } @@ -4159,28 +4176,28 @@ } #endif #ifndef SQLITE_OMIT_AUTOVACUUM /* -** Move the page identified by pData to location pgno in the file. -** -** There must be no references to the current page pgno. If current page -** pgno is not already in the rollback journal, it is not written there by -** by this routine. The same applies to the page pData refers to on entry to -** this routine. -** -** References to the page refered to by pData remain valid. Updating any -** meta-data associated with page pData (i.e. data stored in the nExtra bytes +** Move the page pPg to location pgno in the file. +** +** There must be no references to the page previously located at +** pgno (which we call pPgOld) though that page is allowed to be +** in cache. If the page previous located at pgno is not already +** in the rollback journal, it is not put there by by this routine. +** +** References to the page pPg remain valid. Updating any +** meta-data associated with pPg (i.e. data stored in the nExtra bytes ** allocated along with the page) is the responsibility of the caller. ** ** A transaction must be active when this routine is called. It used to be ** required that a statement transaction was not active, but this restriction ** has been removed (CREATE INDEX needs to move a page when a statement ** transaction is active). */ int sqlite3PagerMovepage(Pager *pPager, DbPage *pPg, Pgno pgno){ - PgHdr *pPgOld; + PgHdr *pPgOld; /* The page being overwritten. */ int h; Pgno needSyncPgno = 0; assert( pPg->nRef>0 ); @@ -4201,21 +4218,27 @@ /* If the cache contains a page with page-number pgno, remove it ** from it's hash chain. Also, if the PgHdr.needSync was set for ** page pgno before the 'move' operation, it needs to be retained ** for the page moved there. */ + pPg->needSync = 0; pPgOld = pager_lookup(pPager, pgno); if( pPgOld ){ assert( pPgOld->nRef==0 ); unlinkHashChain(pPager, pPgOld); makeClean(pPgOld); - if( pPgOld->needSync ){ - assert( pPgOld->inJournal ); - pPg->inJournal = 1; - pPg->needSync = 1; - assert( pPager->needSync ); - } + pPg->needSync = pPgOld->needSync; + }else{ + pPg->needSync = 0; + } + if( pPager->aInJournal && (int)pgno<=pPager->origDbSize ){ + pPg->inJournal = (pPager->aInJournal[pgno/8] & (1<<(pgno&7)))!=0; + }else if( (int)pgno>=pPager->origDbSize ){ + pPg->inJournal = 1; + }else{ + pPg->inJournal = 0; + assert( pPg->needSync==0 ); } /* Change the page number for pPg and insert it into the new hash-chain. */ assert( pgno!=0 ); pPg->pgno = pgno; DELETED src/server.c Index: src/server.c ================================================================== --- src/server.c +++ /dev/null @@ -1,485 +0,0 @@ -/* -** 2006 January 07 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -****************************************************************************** -** -** This file contains demonstration code. Nothing in this file gets compiled -** or linked into the SQLite library unless you use a non-standard option: -** -** -DSQLITE_SERVER=1 -** -** The configure script will never generate a Makefile with the option -** above. You will need to manually modify the Makefile if you want to -** include any of the code from this file in your project. Or, at your -** option, you may copy and paste the code from this file and -** thereby avoiding a recompile of SQLite. -** -** -** This source file demonstrates how to use SQLite to create an SQL database -** server thread in a multiple-threaded program. One or more client threads -** send messages to the server thread and the server thread processes those -** messages in the order received and returns the results to the client. -** -** One might ask: "Why bother? Why not just let each thread connect -** to the database directly?" There are a several of reasons to -** prefer the client/server approach. -** -** (1) Some systems (ex: Redhat9) have broken threading implementations -** that prevent SQLite database connections from being used in -** a thread different from the one where they were created. With -** the client/server approach, all database connections are created -** and used within the server thread. Client calls to the database -** can be made from multiple threads (though not at the same time!) -** -** (2) Beginning with SQLite version 3.3.0, when two or more -** connections to the same database occur within the same thread, -** they can optionally share their database cache. This reduces -** I/O and memory requirements. Cache shared is controlled using -** the sqlite3_enable_shared_cache() API. -** -** (3) Database connections on a shared cache use table-level locking -** instead of file-level locking for improved concurrency. -** -** (4) Database connections on a shared cache can by optionally -** set to READ UNCOMMITTED isolation. (The default isolation for -** SQLite is SERIALIZABLE.) When this occurs, readers will -** never be blocked by a writer and writers will not be -** blocked by readers. There can still only be a single writer -** at a time, but multiple readers can simultaneously exist with -** that writer. This is a huge increase in concurrency. -** -** To summarize the rational for using a client/server approach: prior -** to SQLite version 3.3.0 it probably was not worth the trouble. But -** with SQLite version 3.3.0 and beyond you can get significant performance -** and concurrency improvements and memory usage reductions by going -** client/server. -** -** Note: The extra features of version 3.3.0 described by points (2) -** through (4) above are only available if you compile without the -** option -DSQLITE_OMIT_SHARED_CACHE. -** -** Here is how the client/server approach works: The database server -** thread is started on this procedure: -** -** void *sqlite3_server(void *NotUsed); -** -** The sqlite_server procedure runs as long as the g.serverHalt variable -** is false. A mutex is used to make sure no more than one server runs -** at a time. The server waits for messages to arrive on a message -** queue and processes the messages in order. -** -** Two convenience routines are provided for starting and stopping the -** server thread: -** -** void sqlite3_server_start(void); -** void sqlite3_server_stop(void); -** -** Both of the convenience routines return immediately. Neither will -** ever give an error. If a server is already started or already halted, -** then the routines are effectively no-ops. -** -** Clients use the following interfaces: -** -** sqlite3_client_open -** sqlite3_client_prepare -** sqlite3_client_step -** sqlite3_client_reset -** sqlite3_client_finalize -** sqlite3_client_close -** -** These interfaces work exactly like the standard core SQLite interfaces -** having the same names without the "_client_" infix. Many other SQLite -** interfaces can be used directly without having to send messages to the -** server as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined. -** The following interfaces fall into this second category: -** -** sqlite3_bind_* -** sqlite3_changes -** sqlite3_clear_bindings -** sqlite3_column_* -** sqlite3_complete -** sqlite3_create_collation -** sqlite3_create_function -** sqlite3_data_count -** sqlite3_db_handle -** sqlite3_errcode -** sqlite3_errmsg -** sqlite3_last_insert_rowid -** sqlite3_total_changes -** sqlite3_transfer_bindings -** -** A single SQLite connection (an sqlite3* object) or an SQLite statement -** (an sqlite3_stmt* object) should only be passed to a single interface -** function at a time. The connections and statements can be passed from -** any thread to any of the functions listed in the second group above as -** long as the same connection is not in use by two threads at once and -** as long as SQLITE_ENABLE_MEMORY_MANAGEMENT is not defined. Additional -** information about the SQLITE_ENABLE_MEMORY_MANAGEMENT constraint is -** below. -** -** The busy handler for all database connections should remain turned -** off. That means that any lock contention will cause the associated -** sqlite3_client_step() call to return immediately with an SQLITE_BUSY -** error code. If a busy handler is enabled and lock contention occurs, -** then the entire server thread will block. This will cause not only -** the requesting client to block but every other database client as -** well. It is possible to enhance the code below so that lock -** contention will cause the message to be placed back on the top of -** the queue to be tried again later. But such enhanced processing is -** not included here, in order to keep the example simple. -** -** This example code assumes the use of pthreads. Pthreads -** implementations are available for windows. (See, for example -** http://sourceware.org/pthreads-win32/announcement.html.) Or, you -** can translate the locking and thread synchronization code to use -** windows primitives easily enough. The details are left as an -** exercise to the reader. -** -**** Restrictions Associated With SQLITE_ENABLE_MEMORY_MANAGEMENT **** -** -** If you compile with SQLITE_ENABLE_MEMORY_MANAGEMENT defined, then -** SQLite includes code that tracks how much memory is being used by -** each thread. These memory counts can become confused if memory -** is allocated by one thread and then freed by another. For that -** reason, when SQLITE_ENABLE_MEMORY_MANAGEMENT is used, all operations -** that might allocate or free memory should be performanced in the same -** thread that originally created the database connection. In that case, -** many of the operations that are listed above as safe to be performed -** in separate threads would need to be sent over to the server to be -** done there. If SQLITE_ENABLE_MEMORY_MANAGEMENT is defined, then -** the following functions can be used safely from different threads -** without messing up the allocation counts: -** -** sqlite3_bind_parameter_name -** sqlite3_bind_parameter_index -** sqlite3_changes -** sqlite3_column_blob -** sqlite3_column_count -** sqlite3_complete -** sqlite3_data_count -** sqlite3_db_handle -** sqlite3_errcode -** sqlite3_errmsg -** sqlite3_last_insert_rowid -** sqlite3_total_changes -** -** The remaining functions are not thread-safe when memory management -** is enabled. So one would have to define some new interface routines -** along the following lines: -** -** sqlite3_client_bind_* -** sqlite3_client_clear_bindings -** sqlite3_client_column_* -** sqlite3_client_create_collation -** sqlite3_client_create_function -** sqlite3_client_transfer_bindings -** -** The example code in this file is intended for use with memory -** management turned off. So the implementation of these additional -** client interfaces is left as an exercise to the reader. -** -** It may seem surprising to the reader that the list of safe functions -** above does not include things like sqlite3_bind_int() or -** sqlite3_column_int(). But those routines might, in fact, allocate -** or deallocate memory. In the case of sqlite3_bind_int(), if the -** parameter was previously bound to a string that string might need -** to be deallocated before the new integer value is inserted. In -** the case of sqlite3_column_int(), the value of the column might be -** a UTF-16 string which will need to be converted to UTF-8 then into -** an integer. -*/ - -/* -** Only compile the code in this file on UNIX with a THREADSAFE build -** and only if the SQLITE_SERVER macro is defined. -*/ -#ifdef SQLITE_SERVER -#if defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE - -/* -** We require only pthreads and the public interface of SQLite. -*/ -#include -#include "sqlite3.h" - -/* -** Messages are passed from client to server and back again as -** instances of the following structure. -*/ -typedef struct SqlMessage SqlMessage; -struct SqlMessage { - int op; /* Opcode for the message */ - sqlite3 *pDb; /* The SQLite connection */ - sqlite3_stmt *pStmt; /* A specific statement */ - int errCode; /* Error code returned */ - const char *zIn; /* Input filename or SQL statement */ - int nByte; /* Size of the zIn parameter for prepare() */ - const char *zOut; /* Tail of the SQL statement */ - SqlMessage *pNext; /* Next message in the queue */ - SqlMessage *pPrev; /* Previous message in the queue */ - pthread_mutex_t clientMutex; /* Hold this mutex to access the message */ - pthread_cond_t clientWakeup; /* Signal to wake up the client */ -}; - -/* -** Legal values for SqlMessage.op -*/ -#define MSG_Open 1 /* sqlite3_open(zIn, &pDb) */ -#define MSG_Prepare 2 /* sqlite3_prepare(pDb, zIn, nByte, &pStmt, &zOut) */ -#define MSG_Step 3 /* sqlite3_step(pStmt) */ -#define MSG_Reset 4 /* sqlite3_reset(pStmt) */ -#define MSG_Finalize 5 /* sqlite3_finalize(pStmt) */ -#define MSG_Close 6 /* sqlite3_close(pDb) */ -#define MSG_Done 7 /* Server has finished with this message */ - - -/* -** State information about the server is stored in a static variable -** named "g" as follows: -*/ -static struct ServerState { - pthread_mutex_t queueMutex; /* Hold this mutex to access the msg queue */ - pthread_mutex_t serverMutex; /* Held by the server while it is running */ - pthread_cond_t serverWakeup; /* Signal this condvar to wake up the server */ - volatile int serverHalt; /* Server halts itself when true */ - SqlMessage *pQueueHead; /* Head of the message queue */ - SqlMessage *pQueueTail; /* Tail of the message queue */ -} g = { - PTHREAD_MUTEX_INITIALIZER, - PTHREAD_MUTEX_INITIALIZER, - PTHREAD_COND_INITIALIZER, -}; - -/* -** Send a message to the server. Block until we get a reply. -** -** The mutex and condition variable in the message are uninitialized -** when this routine is called. This routine takes care of -** initializing them and destroying them when it has finished. -*/ -static void sendToServer(SqlMessage *pMsg){ - /* Initialize the mutex and condition variable on the message - */ - pthread_mutex_init(&pMsg->clientMutex, 0); - pthread_cond_init(&pMsg->clientWakeup, 0); - - /* Add the message to the head of the server's message queue. - */ - pthread_mutex_lock(&g.queueMutex); - pMsg->pNext = g.pQueueHead; - if( g.pQueueHead==0 ){ - g.pQueueTail = pMsg; - }else{ - g.pQueueHead->pPrev = pMsg; - } - pMsg->pPrev = 0; - g.pQueueHead = pMsg; - pthread_mutex_unlock(&g.queueMutex); - - /* Signal the server that the new message has be queued, then - ** block waiting for the server to process the message. - */ - pthread_mutex_lock(&pMsg->clientMutex); - pthread_cond_signal(&g.serverWakeup); - while( pMsg->op!=MSG_Done ){ - pthread_cond_wait(&pMsg->clientWakeup, &pMsg->clientMutex); - } - pthread_mutex_unlock(&pMsg->clientMutex); - - /* Destroy the mutex and condition variable of the message. - */ - pthread_mutex_destroy(&pMsg->clientMutex); - pthread_cond_destroy(&pMsg->clientWakeup); -} - -/* -** The following 6 routines are client-side implementations of the -** core SQLite interfaces: -** -** sqlite3_open -** sqlite3_prepare -** sqlite3_step -** sqlite3_reset -** sqlite3_finalize -** sqlite3_close -** -** Clients should use the following client-side routines instead of -** the core routines above. -** -** sqlite3_client_open -** sqlite3_client_prepare -** sqlite3_client_step -** sqlite3_client_reset -** sqlite3_client_finalize -** sqlite3_client_close -** -** Each of these routines creates a message for the desired operation, -** sends that message to the server, waits for the server to process -** then message and return a response. -*/ -int sqlite3_client_open(const char *zDatabaseName, sqlite3 **ppDb){ - SqlMessage msg; - msg.op = MSG_Open; - msg.zIn = zDatabaseName; - sendToServer(&msg); - *ppDb = msg.pDb; - return msg.errCode; -} -int sqlite3_client_prepare( - sqlite3 *pDb, - const char *zSql, - int nByte, - sqlite3_stmt **ppStmt, - const char **pzTail -){ - SqlMessage msg; - msg.op = MSG_Prepare; - msg.pDb = pDb; - msg.zIn = zSql; - msg.nByte = nByte; - sendToServer(&msg); - *ppStmt = msg.pStmt; - if( pzTail ) *pzTail = msg.zOut; - return msg.errCode; -} -int sqlite3_client_step(sqlite3_stmt *pStmt){ - SqlMessage msg; - msg.op = MSG_Step; - msg.pStmt = pStmt; - sendToServer(&msg); - return msg.errCode; -} -int sqlite3_client_reset(sqlite3_stmt *pStmt){ - SqlMessage msg; - msg.op = MSG_Reset; - msg.pStmt = pStmt; - sendToServer(&msg); - return msg.errCode; -} -int sqlite3_client_finalize(sqlite3_stmt *pStmt){ - SqlMessage msg; - msg.op = MSG_Finalize; - msg.pStmt = pStmt; - sendToServer(&msg); - return msg.errCode; -} -int sqlite3_client_close(sqlite3 *pDb){ - SqlMessage msg; - msg.op = MSG_Close; - msg.pDb = pDb; - sendToServer(&msg); - return msg.errCode; -} - -/* -** This routine implements the server. To start the server, first -** make sure g.serverHalt is false, then create a new detached thread -** on this procedure. See the sqlite3_server_start() routine below -** for an example. This procedure loops until g.serverHalt becomes -** true. -*/ -void *sqlite3_server(void *NotUsed){ - sqlite3_enable_shared_cache(1); - if( pthread_mutex_trylock(&g.serverMutex) ){ - sqlite3_enable_shared_cache(0); - return 0; /* Another server is already running */ - } - while( !g.serverHalt ){ - SqlMessage *pMsg; - - /* Remove the last message from the message queue. - */ - pthread_mutex_lock(&g.queueMutex); - while( g.pQueueTail==0 && g.serverHalt==0 ){ - pthread_cond_wait(&g.serverWakeup, &g.queueMutex); - } - pMsg = g.pQueueTail; - if( pMsg ){ - if( pMsg->pPrev ){ - pMsg->pPrev->pNext = 0; - }else{ - g.pQueueHead = 0; - } - g.pQueueTail = pMsg->pPrev; - } - pthread_mutex_unlock(&g.queueMutex); - if( pMsg==0 ) break; - - /* Process the message just removed - */ - pthread_mutex_lock(&pMsg->clientMutex); - switch( pMsg->op ){ - case MSG_Open: { - pMsg->errCode = sqlite3_open(pMsg->zIn, &pMsg->pDb); - break; - } - case MSG_Prepare: { - pMsg->errCode = sqlite3_prepare(pMsg->pDb, pMsg->zIn, pMsg->nByte, - &pMsg->pStmt, &pMsg->zOut); - break; - } - case MSG_Step: { - pMsg->errCode = sqlite3_step(pMsg->pStmt); - break; - } - case MSG_Reset: { - pMsg->errCode = sqlite3_reset(pMsg->pStmt); - break; - } - case MSG_Finalize: { - pMsg->errCode = sqlite3_finalize(pMsg->pStmt); - break; - } - case MSG_Close: { - pMsg->errCode = sqlite3_close(pMsg->pDb); - break; - } - } - - /* Signal the client that the message has been processed. - */ - pMsg->op = MSG_Done; - pthread_mutex_unlock(&pMsg->clientMutex); - pthread_cond_signal(&pMsg->clientWakeup); - } - pthread_mutex_unlock(&g.serverMutex); - sqlite3_thread_cleanup(); - return 0; -} - -/* -** Start a server thread if one is not already running. If there -** is aleady a server thread running, the new thread will quickly -** die and this routine is effectively a no-op. -*/ -void sqlite3_server_start(void){ - pthread_t x; - int rc; - g.serverHalt = 0; - rc = pthread_create(&x, 0, sqlite3_server, 0); - if( rc==0 ){ - pthread_detach(x); - } -} - -/* -** If a server thread is running, then stop it. If no server is -** running, this routine is effectively a no-op. -** -** This routine returns immediately without waiting for the server -** thread to stop. But be assured that the server will eventually stop. -*/ -void sqlite3_server_stop(void){ - g.serverHalt = 1; - pthread_cond_broadcast(&g.serverWakeup); -} - -#endif /* defined(OS_UNIX) && OS_UNIX && defined(THREADSAFE) && THREADSAFE */ -#endif /* defined(SQLITE_SERVER) */ Index: test/attach2.test ================================================================== --- test/attach2.test +++ test/attach2.test @@ -10,11 +10,11 @@ #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is testing the ATTACH and DETACH commands # and related functionality. # -# $Id: attach2.test,v 1.35 2006/01/03 00:33:50 drh Exp $ +# $Id: attach2.test,v 1.35.4.1 2007/08/14 13:20:28 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -209,10 +209,19 @@ } db2 } {1 {database is locked}} lock_status 4.4.1 db {main shared temp closed file2 unlocked} lock_status 4.4.2 db2 {main unlocked temp closed file2 unlocked} + +# We have to make sure that the cache_size and the soft_heap_limit +# are large enough to hold the entire change in memory. If either +# is set too small, then changes will spill to the database, forcing +# a reserved lock to promote to exclusive. That will mess up our +# test results. + +set soft_limit [sqlite3_soft_heap_limit 0] + do_test attach2-4.5 { # Handle 'db2' reserves file2. execsql {BEGIN} db2 execsql {INSERT INTO file2.t1 VALUES(1, 2)} db2 @@ -312,10 +321,11 @@ } {1 2 1 2} db close db2 close file delete -force test2.db +sqlite3_soft_heap_limit $soft_limit # These tests - attach2-5.* - check that the master journal file is deleted # correctly when a multi-file transaction is committed or rolled back. # # Update: It's not actually created if a rollback occurs, so that test Index: test/capi3b.test ================================================================== --- test/capi3b.test +++ test/capi3b.test @@ -11,16 +11,24 @@ # This file implements regression tests for SQLite library. The # focus of this script testing the callback-free C/C++ API and in # particular the behavior of sqlite3_step() when trying to commit # with lock contention. # -# $Id: capi3b.test,v 1.3 2006/01/03 00:33:50 drh Exp $ +# $Id: capi3b.test,v 1.3.4.1 2007/08/14 13:20:28 drh Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl + +# These tests depend on the pager holding changes in cache +# until it is time to commit. But that won't happen if the +# soft-heap-limit is set too low. So disable the soft heap limit +# for the duration of this test. +# +sqlite3_soft_heap_limit 0 + set DB [sqlite3_connection_pointer db] sqlite3 db2 test.db set DB2 [sqlite3_connection_pointer db2] @@ -130,6 +138,8 @@ sqlite3_finalize $VM2 execsql {SELECT * FROM t1} } {1 2 3 4} catch {db2 close} + +sqlite3_soft_heap_limit $soft_limit finish_test DELETED test/crashtest1.c Index: test/crashtest1.c ================================================================== --- test/crashtest1.c +++ /dev/null @@ -1,96 +0,0 @@ -/* -** This program tests the ability of SQLite database to recover from a crash. -** This program runs under Unix only, but the results are applicable to all -** systems. -** -** The main process first constructs a test database, then starts creating -** subprocesses that write to that database. Each subprocess is killed off, -** without a chance to clean up its database connection, after a random -** delay. This killing of the subprocesses simulates a crash or power -** failure. The next subprocess to open the database should rollback -** whatever operation was in process at the time of the simulated crash. -** -** If any problems are encountered, an error is reported and the test stops. -** If no problems are seen after a large number of tests, we assume that -** the rollback mechanism is working. -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include "sqlite.h" - -static void do_some_sql(int parent){ - char *zErr; - int rc = SQLITE_OK; - sqlite *db; - int cnt = 0; - static char zBig[] = - "-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - "-abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - if( access("./test.db-journal",0)==0 ){ - /*printf("pid %d: journal exists. rollback will be required\n",getpid());*/ unlink("test.db-saved"); - system("cp test.db test.db-saved"); - unlink("test.db-journal-saved"); - system("cp test.db-journal test.db-journal-saved"); - } - db = sqlite_open("./test.db", 0, &zErr); - if( db==0 ){ - printf("ERROR: %s\n", zErr); - if( strcmp(zErr,"database disk image is malformed")==0 ){ - kill(parent, SIGKILL); - } - exit(1); - } - srand(getpid()); - while( rc==SQLITE_OK ){ - cnt++; - rc = sqlite_exec_printf(db, - "INSERT INTO t1 VALUES(%d,'%d%s')", 0, 0, &zErr, - rand(), rand(), zBig); - } - if( rc!=SQLITE_OK ){ - printf("ERROR #%d: %s\n", rc, zErr); - if( rc==SQLITE_CORRUPT ){ - kill(parent, SIGKILL); - } - } - printf("pid %d: cnt=%d\n", getpid(), cnt); -} - - -int main(int argc, char **argv){ - int i; - sqlite *db; - char *zErr; - int status; - int parent = getpid(); - - unlink("test.db"); - unlink("test.db-journal"); - db = sqlite_open("test.db", 0, &zErr); - if( db==0 ){ - printf("Cannot initialize: %s\n", zErr); - return 1; - } - sqlite_exec(db, "CREATE TABLE t1(a,b)", 0, 0, 0); - sqlite_close(db); - for(i=0; i<10000; i++){ - int pid = fork(); - if( pid==0 ){ - sched_yield(); - do_some_sql(parent); - return 0; - } - printf("test %d, pid=%d\n", i, pid); - usleep(rand()%10000 + 1000); - kill(pid, SIGKILL); - waitpid(pid, &status, 0); - } - return 0; -} Index: test/tester.tcl ================================================================== --- test/tester.tcl +++ test/tester.tcl @@ -9,11 +9,11 @@ # #*********************************************************************** # This file implements some common TCL routines used for regression # testing the SQLite library # -# $Id: tester.tcl,v 1.79 2007/04/19 12:30:54 drh Exp $ +# $Id: tester.tcl,v 1.79.2.1 2007/08/14 13:20:28 drh Exp $ # Make sure tclsqlite3 was compiled correctly. Abort now with an # error message if not. # if {[sqlite3 -tcl-uses-utf]} { @@ -41,10 +41,30 @@ } set tcl_precision 15 set sqlite_pending_byte 0x0010000 +# +# Check the command-line arguments for a default soft-heap-limit. +# Store this default value in the global variable ::soft_limit and +# update the soft-heap-limit each time this script is run. In that +# way if an individual test file changes the soft-heap-limit, it +# will be reset at the start of the next test file. +# +if {![info exists soft_limit]} { + set soft_limit 0 + for {set i 0} {$i<[llength $argv]} {incr i} { + if {[regexp {^--soft-heap-limit=(.+)$} [lindex $argv $i] all value]} { + if {$value!="off"} { + set soft_limit $value + } + set argv [lreplace $argv $i $i] + } + } +} +sqlite3_soft_heap_limit $soft_limit + # Use the pager codec if it is available # if {[sqlite3 -has-codec] && [info command sqlite_orig]==""} { rename sqlite3 sqlite_orig proc sqlite3 {args} { @@ -176,10 +196,18 @@ pp_check_for_leaks } sqlite3 db {} # sqlite3_clear_tsd_memdebug db close + set heaplimit [sqlite3_soft_heap_limit] + if {$heaplimit!=$::soft_limit} { + puts "soft-heap-limit changed by this script\ + from $::soft_limit to $heaplimit" + } elseif {$heaplimit!="" && $heaplimit>0} { + puts "soft-heap-limit set to $heaplimit" + } + sqlite3_soft_heap_limit 0 if {$::sqlite3_tsd_count} { puts "Thread-specific data leak: $::sqlite3_tsd_count instances" incr nErr } else { puts "Thread-specific data deallocated properly" DELETED www/capi3ref.tcl Index: www/capi3ref.tcl ================================================================== --- www/capi3ref.tcl +++ /dev/null @@ -1,1796 +0,0 @@ -set rcsid {$Id: capi3ref.tcl,v 1.55 2007/04/16 15:35:24 drh Exp $} -source common.tcl -header {C/C++ Interface For SQLite Version 3} -puts { -

C/C++ Interface For SQLite Version 3

-} - -proc api {name prototype desc {notused x}} { - global apilist specialname - if {$name==""} { - regsub -all {sqlite3_[a-z0-9_]+\(} $prototype \ - {[lappend name [string trimright & (]]} x1 - subst $x1 - } else { - lappend specialname $name - } - lappend apilist [list $name $prototype $desc] -} - -api {extended-result-codes} { -#define SQLITE_IOERR_READ -#define SQLITE_IOERR_SHORT_READ -#define SQLITE_IOERR_WRITE -#define SQLITE_IOERR_FSYNC -#define SQLITE_IOERR_DIR_FSYNC -#define SQLITE_IOERR_TRUNCATE -#define SQLITE_IOERR_FSTAT -#define SQLITE_IOERR_UNLOCK -#define SQLITE_IOERR_RDLOCK -... -} { -In its default configuration, SQLite API routines return one of 26 integer -result codes described at result-codes. However, experience has shown that -many of these result codes are too course-grained. They do not provide as -much information about problems as users might like. In an effort to -address this, newer versions of SQLite (version 3.3.8 and later) include -support for additional result codes that provide more detailed information -about errors. The extended result codes are enabled (or disabled) for -each database -connection using the sqlite3_extended_result_codes() API. - -Some of the available extended result codes are listed above. -We expect the number of extended result codes will be expand -over time. Software that uses extended result codes should expect -to see new result codes in future releases of SQLite. - -The symbolic name for an extended result code always contains a related -primary result code as a prefix. Primary result codes contain a single -"_" character. Extended result codes contain two or more "_" characters. -The numeric value of an extended result code can be converted to its -corresponding primary result code by masking off the lower 8 bytes. - -A complete list of available extended result codes and -details about the meaning of the various extended result codes can be -found by consulting the C code, especially the sqlite3.h header -file and its antecedent sqlite.h.in. Additional information -is also available at the SQLite wiki: -http://www.sqlite.org/cvstrac/wiki?p=ExtendedResultCodes -} - - -api {result-codes} { -#define SQLITE_OK 0 /* Successful result */ -#define SQLITE_ERROR 1 /* SQL error or missing database */ -#define SQLITE_INTERNAL 2 /* An internal logic error in SQLite */ -#define SQLITE_PERM 3 /* Access permission denied */ -#define SQLITE_ABORT 4 /* Callback routine requested an abort */ -#define SQLITE_BUSY 5 /* The database file is locked */ -#define SQLITE_LOCKED 6 /* A table in the database is locked */ -#define SQLITE_NOMEM 7 /* A malloc() failed */ -#define SQLITE_READONLY 8 /* Attempt to write a readonly database */ -#define SQLITE_INTERRUPT 9 /* Operation terminated by sqlite_interrupt() */ -#define SQLITE_IOERR 10 /* Some kind of disk I/O error occurred */ -#define SQLITE_CORRUPT 11 /* The database disk image is malformed */ -#define SQLITE_NOTFOUND 12 /* (Internal Only) Table or record not found */ -#define SQLITE_FULL 13 /* Insertion failed because database is full */ -#define SQLITE_CANTOPEN 14 /* Unable to open the database file */ -#define SQLITE_PROTOCOL 15 /* Database lock protocol error */ -#define SQLITE_EMPTY 16 /* (Internal Only) Database table is empty */ -#define SQLITE_SCHEMA 17 /* The database schema changed */ -#define SQLITE_TOOBIG 18 /* Too much data for one row of a table */ -#define SQLITE_CONSTRAINT 19 /* Abort due to constraint violation */ -#define SQLITE_MISMATCH 20 /* Data type mismatch */ -#define SQLITE_MISUSE 21 /* Library used incorrectly */ -#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */ -#define SQLITE_AUTH 23 /* Authorization denied */ -#define SQLITE_ROW 100 /* sqlite_step() has another row ready */ -#define SQLITE_DONE 101 /* sqlite_step() has finished executing */ -} { -Many SQLite functions return an integer result code from the set shown -above in order to indicates success or failure. - -The result codes above are the only ones returned by SQLite in its -default configuration. However, the sqlite3_extended_result_codes() -API can be used to set a database connectoin to return more detailed -result codes. See the documentation on sqlite3_extended_result_codes() -or extended-result-codes for additional information. -} - -api {} { - int sqlite3_extended_result_codes(sqlite3*, int onoff); -} { -This routine enables or disabled extended-result-codes feature. -By default, SQLite API routines return one of only 26 integer -result codes described at result-codes. When extended result codes -are enabled by this routine, the repetoire of result codes can be -much larger and can (hopefully) provide more detailed information -about the cause of an error. - -The second argument is a boolean value that turns extended result -codes on and off. Extended result codes are off by default for -backwards compatibility with older versions of SQLite. -} - -api {} { - const char *sqlite3_libversion(void); -} { - Return a pointer to a string which contains the version number of - the library. The same string is available in the global - variable named "sqlite3_version". This interface is provided since - windows is unable to access global variables in DLLs. -} - -api {} { - void *sqlite3_aggregate_context(sqlite3_context*, int nBytes); -} { - Aggregate functions use this routine to allocate - a structure for storing their state. The first time this routine - is called for a particular aggregate, a new structure of size nBytes - is allocated, zeroed, and returned. On subsequent calls (for the - same aggregate instance) the same buffer is returned. The implementation - of the aggregate can use the returned buffer to accumulate data. - - The buffer is freed automatically by SQLite when the query that - invoked the aggregate function terminates. -} - -api {} { - int sqlite3_aggregate_count(sqlite3_context*); -} { - This function is deprecated. It continues to exist so as not to - break any legacy code that might happen to use it. But it should not - be used in any new code. - - In order to encourage people to not use this function, we are not going - to tell you what it does. -} - -api {} { - int sqlite3_bind_blob(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); - int sqlite3_bind_double(sqlite3_stmt*, int, double); - int sqlite3_bind_int(sqlite3_stmt*, int, int); - int sqlite3_bind_int64(sqlite3_stmt*, int, long long int); - int sqlite3_bind_null(sqlite3_stmt*, int); - int sqlite3_bind_text(sqlite3_stmt*, int, const char*, int n, void(*)(void*)); - int sqlite3_bind_text16(sqlite3_stmt*, int, const void*, int n, void(*)(void*)); - #define SQLITE_STATIC ((void(*)(void *))0) - #define SQLITE_TRANSIENT ((void(*)(void *))-1) -} { - In the SQL strings input to sqlite3_prepare_v2() and sqlite3_prepare16_v2(), - one or more literals can be replace by a parameter "?" or ":AAA" or - "@AAA" or "\$VVV" - where AAA is an alphanumeric identifier and VVV is a variable name according - to the syntax rules of the TCL programming language. - The values of these parameters (also called "host parameter names") - can be set using the sqlite3_bind_*() routines. - - The first argument to the sqlite3_bind_*() routines always is a pointer - to the sqlite3_stmt structure returned from sqlite3_prepare_v2(). The second - argument is the index of the parameter to be set. The first parameter has - an index of 1. When the same named parameter is used more than once, second - and subsequent - occurrences have the same index as the first occurrence. The index for - named parameters can be looked up using the - sqlite3_bind_parameter_name() API if desired. - - The third argument is the value to bind to the parameter. - - In those - routines that have a fourth argument, its value is the number of bytes - in the parameter. To be clear: the value is the number of bytes in the - string, not the number of characters. The number - of bytes does not include the zero-terminator at the end of strings. - If the fourth parameter is negative, the length of the string is - number of bytes up to the first zero terminator. - - The fifth argument to sqlite3_bind_blob(), sqlite3_bind_text(), and - sqlite3_bind_text16() is a destructor used to dispose of the BLOB or - text after SQLite has finished with it. If the fifth argument is the - special value SQLITE_STATIC, then the library assumes that the information - is in static, unmanaged space and does not need to be freed. If the - fifth argument has the value SQLITE_TRANSIENT, then SQLite makes its - own private copy of the data immediately, before the sqlite3_bind_*() - routine returns. - - The sqlite3_bind_*() routines must be called after - sqlite3_prepare_v2() or sqlite3_reset() and before sqlite3_step(). - Bindings are not cleared by the sqlite3_reset() routine. - Unbound parameters are interpreted as NULL. - - These routines return SQLITE_OK on success or an error code if - anything goes wrong. SQLITE_RANGE is returned if the parameter - index is out of range. SQLITE_NOMEM is returned if malloc fails. - SQLITE_MISUSE is returned if these routines are called on a virtual - machine that is the wrong state or which has already been finalized. -} - -api {} { - int sqlite3_bind_parameter_count(sqlite3_stmt*); -} { - Return the number of parameters in the precompiled statement given as - the argument. -} - -api {} { - const char *sqlite3_bind_parameter_name(sqlite3_stmt*, int n); -} { - Return the name of the n-th parameter in the precompiled statement. - Parameters of the form ":AAA" or "@AAA" or "\$VVV" have a name which is the - string ":AAA" or "\$VVV". In other words, the initial ":" or "$" or "@" - is included as part of the name. - Parameters of the form "?" have no name. - - The first bound parameter has an index of 1, not 0. - - If the value n is out of range or if the n-th parameter is nameless, - then NULL is returned. The returned string is always in the - UTF-8 encoding. -} - -api {} { - int sqlite3_bind_parameter_index(sqlite3_stmt*, const char *zName); -} { - Return the index of the parameter with the given name. - The name must match exactly. - If there is no parameter with the given name, return 0. - The string zName is always in the UTF-8 encoding. -} - -api {} { - int sqlite3_busy_handler(sqlite3*, int(*)(void*,int), void*); -} { - This routine identifies a callback function that might be invoked - whenever an attempt is made to open a database table - that another thread or process has locked. - If the busy callback is NULL, then SQLITE_BUSY is returned immediately - upon encountering the lock. - If the busy callback is not NULL, then the - callback will be invoked with two arguments. The - first argument to the handler is a copy of the void* pointer which - is the third argument to this routine. The second argument to - the handler is the number of times that the busy handler has - been invoked for this locking event. If the - busy callback returns 0, then no additional attempts are made to - access the database and SQLITE_BUSY is returned. - If the callback returns non-zero, then another attempt is made to open the - database for reading and the cycle repeats. - - The presence of a busy handler does not guarantee that - it will be invoked when there is lock contention. - If SQLite determines that invoking the busy handler could result in - a deadlock, it will return SQLITE_BUSY instead. - Consider a scenario where one process is holding a read lock that - it is trying to promote to a reserved lock and - a second process is holding a reserved lock that it is trying - to promote to an exclusive lock. The first process cannot proceed - because it is blocked by the second and the second process cannot - proceed because it is blocked by the first. If both processes - invoke the busy handlers, neither will make any progress. Therefore, - SQLite returns SQLITE_BUSY for the first process, hoping that this - will induce the first process to release its read lock and allow - the second process to proceed. - - The default busy callback is NULL. - - Sqlite is re-entrant, so the busy handler may start a new query. - (It is not clear why anyone would every want to do this, but it - is allowed, in theory.) But the busy handler may not close the - database. Closing the database from a busy handler will delete - data structures out from under the executing query and will - probably result in a coredump. - - There can only be a single busy handler defined for each database - connection. Setting a new busy handler clears any previous one. - Note that calling sqlite3_busy_timeout() will also set or clear - the busy handler. -} - -api {} { - int sqlite3_busy_timeout(sqlite3*, int ms); -} { - This routine sets a busy handler that sleeps for a while when a - table is locked. The handler will sleep multiple times until - at least "ms" milliseconds of sleeping have been done. After - "ms" milliseconds of sleeping, the handler returns 0 which - causes sqlite3_exec() to return SQLITE_BUSY. - - Calling this routine with an argument less than or equal to zero - turns off all busy handlers. - - There can only be a single busy handler for a particular database - connection. If another busy handler was defined - (using sqlite3_busy_handler()) prior to calling - this routine, that other busy handler is cleared. -} - -api {} { - int sqlite3_changes(sqlite3*); -} { - This function returns the number of database rows that were changed - (or inserted or deleted) by the most recently completed - INSERT, UPDATE, or DELETE - statement. Only changes that are directly specified by the INSERT, - UPDATE, or DELETE statement are counted. Auxiliary changes caused by - triggers are not counted. Use the sqlite3_total_changes() function - to find the total number of changes including changes caused by triggers. - - Within the body of a trigger, the sqlite3_changes() function does work - to report the number of rows that were changed for the most recently - completed INSERT, UPDATE, or DELETE statement within the trigger body. - - SQLite implements the command "DELETE FROM table" without a WHERE clause - by dropping and recreating the table. (This is much faster than going - through and deleting individual elements from the table.) Because of - this optimization, the change count for "DELETE FROM table" will be - zero regardless of the number of elements that were originally in the - table. To get an accurate count of the number of rows deleted, use - "DELETE FROM table WHERE 1" instead. -} - -api {} { - int sqlite3_total_changes(sqlite3*); -} { - This function returns the total number of database rows that have - be modified, inserted, or deleted since the database connection was - created using sqlite3_open(). All changes are counted, including - changes by triggers and changes to TEMP and auxiliary databases. - Except, changes to the SQLITE_MASTER table (caused by statements - such as CREATE TABLE) are not counted. Nor are changes counted when - an entire table is deleted using DROP TABLE. - - See also the sqlite3_changes() API. - - SQLite implements the command "DELETE FROM table" without a WHERE clause - by dropping and recreating the table. (This is much faster than going - through and deleting individual elements form the table.) Because of - this optimization, the change count for "DELETE FROM table" will be - zero regardless of the number of elements that were originally in the - table. To get an accurate count of the number of rows deleted, use - "DELETE FROM table WHERE 1" instead. -} - -api {} { - int sqlite3_close(sqlite3*); -} { - Call this function with a pointer to a structure that was previously - returned from sqlite3_open() or sqlite3_open16() - and the corresponding database will by closed. - - SQLITE_OK is returned if the close is successful. If there are - prepared statements that have not been finalized, then SQLITE_BUSY - is returned. SQLITE_ERROR might be returned if the argument is not - a valid connection pointer returned by sqlite3_open() or if the connection - pointer has been closed previously. -} - -api {} { -const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); -int sqlite3_column_bytes(sqlite3_stmt*, int iCol); -int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); -double sqlite3_column_double(sqlite3_stmt*, int iCol); -int sqlite3_column_int(sqlite3_stmt*, int iCol); -long long int sqlite3_column_int64(sqlite3_stmt*, int iCol); -const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); -const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); -int sqlite3_column_type(sqlite3_stmt*, int iCol); -#define SQLITE_INTEGER 1 -#define SQLITE_FLOAT 2 -#define SQLITE_TEXT 3 -#define SQLITE_BLOB 4 -#define SQLITE_NULL 5 -} { - These routines return information about the information - in a single column of the current result row of a query. In every - case the first argument is a pointer to the SQL statement that is being - executed (the sqlite_stmt* that was returned from sqlite3_prepare_v2()) and - the second argument is the index of the column for which information - should be returned. iCol is zero-indexed. The left-most column has an - index of 0. - - If the SQL statement is not currently point to a valid row, or if the - the column index is out of range, the result is undefined. - - If the result is a BLOB then the sqlite3_column_bytes() routine returns - the number of bytes in that BLOB. No type conversions occur. - If the result is a string (or a number since a number can be converted - into a string) then sqlite3_column_bytes() converts - the value into a UTF-8 string and returns - the number of bytes in the resulting string. The value returned does - not include the \\000 terminator at the end of the string. The - sqlite3_column_bytes16() routine converts the value into a UTF-16 - encoding and returns the number of bytes (not characters) in the - resulting string. The \\u0000 terminator is not included in this count. - - These routines attempt to convert the value where appropriate. For - example, if the internal representation is FLOAT and a text result - is requested, sprintf() is used internally to do the conversion - automatically. The following table details the conversions that - are applied: - -
- - - - - - - - - - - - - - - - - - -
Internal TypeRequested TypeConversion
NULL INTEGERResult is 0
NULL FLOAT Result is 0.0
NULL TEXT Result is NULL pointer
NULL BLOB Result is NULL pointer
INTEGER FLOAT Convert from integer to float
INTEGER TEXT ASCII rendering of the integer
INTEGER BLOB Same as for INTEGER->TEXT
FLOAT INTEGERConvert from float to integer
FLOAT TEXT ASCII rendering of the float
FLOAT BLOB Same as FLOAT->TEXT
TEXT INTEGERUse atoi()
TEXT FLOAT Use atof()
TEXT BLOB No change
BLOB INTEGERConvert to TEXT then use atoi()
BLOB FLOAT Convert to TEXT then use atof()
BLOB TEXT Add a \\000 terminator if needed
-
- - Note that when type conversions occur, pointers returned by prior - calls to sqlite3_column_blob(), sqlite3_column_text(), and/or - sqlite3_column_text16() may be invalidated. So, for example, if - you initially call sqlite3_column_text() and get back a pointer to - a UTF-8 string, then you call sqlite3_column_text16(), after the - call to sqlite3_column_text16() the pointer returned by the prior - call to sqlite3_column_text() will likely point to deallocated memory. - Attempting to use the original pointer might lead to heap corruption - or a segfault. Note also that calls to sqlite3_column_bytes() - and sqlite3_column_bytes16() can also cause type conversion that - and deallocate prior buffers. Use these routines carefully. -} - -api {} { -int sqlite3_column_count(sqlite3_stmt *pStmt); -} { - Return the number of columns in the result set returned by the prepared - SQL statement. This routine returns 0 if pStmt is an SQL statement - that does not return data (for example an UPDATE). - - See also sqlite3_data_count(). -} - -api {} { -const char *sqlite3_column_decltype(sqlite3_stmt *, int i); -const void *sqlite3_column_decltype16(sqlite3_stmt*,int); -} { - The first argument is a prepared SQL statement. If this statement - is a SELECT statement, the Nth column of the returned result set - of the SELECT is a table column then the declared type of the table - column is returned. If the Nth column of the result set is not a table - column, then a NULL pointer is returned. The returned string is - UTF-8 encoded for sqlite3_column_decltype() and UTF-16 encoded - for sqlite3_column_decltype16(). For example, in the database schema: - -
- CREATE TABLE t1(c1 INTEGER);
- 
- - And the following statement compiled: - -
- SELECT c1 + 1, c1 FROM t1;
- 
- - Then this routine would return the string "INTEGER" for the second - result column (i==1), and a NULL pointer for the first result column - (i==0). - - If the following statements were compiled then this routine would - return "INTEGER" for the first (only) result column. - -
- SELECT (SELECT c1) FROM t1;
- SELECT (SELECT c1 FROM t1);
- SELECT c1 FROM (SELECT c1 FROM t1);
- SELECT * FROM (SELECT c1 FROM t1);
- SELECT * FROM (SELECT * FROM t1);
- 
-} - -api {} { - int sqlite3_table_column_metadata( - sqlite3 *db, /* Connection handle */ - const char *zDbName, /* Database name or NULL */ - const char *zTableName, /* Table name */ - const char *zColumnName, /* Column name */ - char const **pzDataType, /* OUTPUT: Declared data type */ - char const **pzCollSeq, /* OUTPUT: Collation sequence name */ - int *pNotNull, /* OUTPUT: True if NOT NULL constraint exists */ - int *pPrimaryKey, /* OUTPUT: True if column part of PK */ - int *pAutoinc /* OUTPUT: True if colums is auto-increment */ - ); -} { - This routine is used to obtain meta information about a specific column of a - specific database table accessible using the connection handle passed as the - first function argument. - - The column is identified by the second, third and fourth parameters to - this function. The second parameter is either the name of the database - (i.e. "main", "temp" or an attached database) containing the specified - table or NULL. If it is NULL, then all attached databases are searched - for the table using the same algorithm as the database engine uses to - resolve unqualified table references. - - The third and fourth parameters to this function are the table and column - name of the desired column, respectively. Neither of these parameters - may be NULL. - - Meta information is returned by writing to the memory locations passed as - the 5th and subsequent parameters to this function. Any of these - arguments may be NULL, in which case the corresponding element of meta - information is ommitted. - -
- Parameter     Output Type      Description
- -----------------------------------
-   5th         const char*      Declared data type 
-   6th         const char*      Name of the columns default collation sequence 
-   7th         int              True if the column has a NOT NULL constraint
-   8th         int              True if the column is part of the PRIMARY KEY
-   9th         int              True if the column is AUTOINCREMENT
-
- - The memory pointed to by the character pointers returned for the - declaration type and collation sequence is valid only until the next - call to any sqlite API function. - - This function may load one or more schemas from database files. If an - error occurs during this process, or if the requested table or column - cannot be found, an SQLITE error code is returned and an error message - left in the database handle (to be retrieved using sqlite3_errmsg()). - Specifying an SQL view instead of a table as the third argument is also - considered an error. - - If the specified column is "rowid", "oid" or "_rowid_" and an - INTEGER PRIMARY KEY column has been explicitly declared, then the output - parameters are set for the explicitly declared column. If there is no - explicitly declared IPK column, then the data-type is "INTEGER", the - collation sequence "BINARY" and the primary-key flag is set. Both - the not-null and auto-increment flags are clear. - - This API is only available if the library was compiled with the - SQLITE_ENABLE_COLUMN_METADATA preprocessor symbol defined. -} - -api {} { -const char *sqlite3_column_database_name(sqlite3_stmt *pStmt, int N); -const void *sqlite3_column_database_name16(sqlite3_stmt *pStmt, int N); -} { -If the Nth column returned by statement pStmt is a column reference, -these functions may be used to access the name of the database (either -"main", "temp" or the name of an attached database) that contains -the column. If the Nth column is not a column reference, NULL is -returned. - -See the description of function sqlite3_column_decltype() for a -description of exactly which expressions are considered column references. - -Function sqlite3_column_database_name() returns a pointer to a UTF-8 -encoded string. sqlite3_column_database_name16() returns a pointer -to a UTF-16 encoded string. -} - -api {} { -const char *sqlite3_column_origin_name(sqlite3_stmt *pStmt, int N); -const void *sqlite3_column_origin_name16(sqlite3_stmt *pStmt, int N); -} { -If the Nth column returned by statement pStmt is a column reference, -these functions may be used to access the schema name of the referenced -column in the database schema. If the Nth column is not a column -reference, NULL is returned. - -See the description of function sqlite3_column_decltype() for a -description of exactly which expressions are considered column references. - -Function sqlite3_column_origin_name() returns a pointer to a UTF-8 -encoded string. sqlite3_column_origin_name16() returns a pointer -to a UTF-16 encoded string. -} - -api {} { -const char *sqlite3_column_table_name(sqlite3_stmt *pStmt, int N); -const void *sqlite3_column_table_name16(sqlite3_stmt *pStmt, int N); -} { -If the Nth column returned by statement pStmt is a column reference, -these functions may be used to access the name of the table that -contains the column. If the Nth column is not a column reference, -NULL is returned. - -See the description of function sqlite3_column_decltype() for a -description of exactly which expressions are considered column references. - -Function sqlite3_column_table_name() returns a pointer to a UTF-8 -encoded string. sqlite3_column_table_name16() returns a pointer -to a UTF-16 encoded string. -} - -api {} { -const char *sqlite3_column_name(sqlite3_stmt*,int); -const void *sqlite3_column_name16(sqlite3_stmt*,int); -} { - The first argument is a prepared SQL statement. This function returns - the column heading for the Nth column of that statement, where N is the - second function argument. The string returned is UTF-8 for - sqlite3_column_name() and UTF-16 for sqlite3_column_name16(). -} - -api {} { -void *sqlite3_commit_hook(sqlite3*, int(*xCallback)(void*), void *pArg); -} { - Experimental - - Register a callback function to be invoked whenever a new transaction - is committed. The pArg argument is passed through to the callback. - callback. If the callback function returns non-zero, then the commit - is converted into a rollback. - - If another function was previously registered, its pArg value is returned. - Otherwise NULL is returned. - - Registering a NULL function disables the callback. Only a single commit - hook callback can be registered at a time. -} - -api {} { -int sqlite3_complete(const char *sql); -int sqlite3_complete16(const void *sql); -} { - These functions return true if the given input string comprises - one or more complete SQL statements. - The argument must be a nul-terminated UTF-8 string for sqlite3_complete() - and a nul-terminated UTF-16 string for sqlite3_complete16(). - - These routines do not check to see if the SQL statement is well-formed. - They only check to see that the statement is terminated by a semicolon - that is not part of a string literal and is not inside - the body of a trigger. -} {} - -api {} { -int sqlite3_create_collation( - sqlite3*, - const char *zName, - int pref16, - void*, - int(*xCompare)(void*,int,const void*,int,const void*) -); -int sqlite3_create_collation16( - sqlite3*, - const char *zName, - int pref16, - void*, - int(*xCompare)(void*,int,const void*,int,const void*) -); -#define SQLITE_UTF8 1 -#define SQLITE_UTF16BE 2 -#define SQLITE_UTF16LE 3 -#define SQLITE_UTF16 4 -} { - These two functions are used to add new collation sequences to the - sqlite3 handle specified as the first argument. - - The name of the new collation sequence is specified as a UTF-8 string - for sqlite3_create_collation() and a UTF-16 string for - sqlite3_create_collation16(). In both cases the name is passed as the - second function argument. - - The third argument must be one of the constants SQLITE_UTF8, - SQLITE_UTF16LE or SQLITE_UTF16BE, indicating that the user-supplied - routine expects to be passed pointers to strings encoded using UTF-8, - UTF-16 little-endian or UTF-16 big-endian respectively. The - SQLITE_UTF16 constant indicates that text strings are expected in - UTF-16 in the native byte order of the host machine. - - A pointer to the user supplied routine must be passed as the fifth - argument. If it is NULL, this is the same as deleting the collation - sequence (so that SQLite cannot call it anymore). Each time the user - supplied function is invoked, it is passed a copy of the void* passed as - the fourth argument to sqlite3_create_collation() or - sqlite3_create_collation16() as its first argument. - - The remaining arguments to the user-supplied routine are two strings, - each represented by a [length, data] pair and encoded in the encoding - that was passed as the third argument when the collation sequence was - registered. The user routine should return negative, zero or positive if - the first string is less than, equal to, or greater than the second - string. i.e. (STRING1 - STRING2). -} - -api {} { -int sqlite3_collation_needed( - sqlite3*, - void*, - void(*)(void*,sqlite3*,int eTextRep,const char*) -); -int sqlite3_collation_needed16( - sqlite3*, - void*, - void(*)(void*,sqlite3*,int eTextRep,const void*) -); -} { - To avoid having to register all collation sequences before a database - can be used, a single callback function may be registered with the - database handle to be called whenever an undefined collation sequence is - required. - - If the function is registered using the sqlite3_collation_needed() API, - then it is passed the names of undefined collation sequences as strings - encoded in UTF-8. If sqlite3_collation_needed16() is used, the names - are passed as UTF-16 in machine native byte order. A call to either - function replaces any existing callback. - - When the user-function is invoked, the first argument passed is a copy - of the second argument to sqlite3_collation_needed() or - sqlite3_collation_needed16(). The second argument is the database - handle. The third argument is one of SQLITE_UTF8, SQLITE_UTF16BE or - SQLITE_UTF16LE, indicating the most desirable form of the collation - sequence function required. The fourth argument is the name of the - required collation sequence. - - The collation sequence is returned to SQLite by a collation-needed - callback using the sqlite3_create_collation() or - sqlite3_create_collation16() APIs, described above. -} - -api {} { -int sqlite3_create_function( - sqlite3 *, - const char *zFunctionName, - int nArg, - int eTextRep, - void *pUserData, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*) -); -int sqlite3_create_function16( - sqlite3*, - const void *zFunctionName, - int nArg, - int eTextRep, - void *pUserData, - void (*xFunc)(sqlite3_context*,int,sqlite3_value**), - void (*xStep)(sqlite3_context*,int,sqlite3_value**), - void (*xFinal)(sqlite3_context*) -); -#define SQLITE_UTF8 1 -#define SQLITE_UTF16 2 -#define SQLITE_UTF16BE 3 -#define SQLITE_UTF16LE 4 -#define SQLITE_ANY 5 -} { - These two functions are used to add SQL functions or aggregates - implemented in C. The - only difference between these two routines is that the second argument, the - name of the (scalar) function or aggregate, is encoded in UTF-8 for - sqlite3_create_function() and UTF-16 for sqlite3_create_function16(). - The length of the name is limited to 255 bytes, exclusive of the - zero-terminator. Note that the name length limit is in bytes, not - characters. Any attempt to create a function with a longer name - will result in an SQLITE_ERROR error. - - The first argument is the database handle that the new function or - aggregate is to be added to. If a single program uses more than one - database handle internally, then user functions or aggregates must - be added individually to each database handle with which they will be - used. - - The third argument is the number of arguments that the function or - aggregate takes. If this argument is -1 then the function or - aggregate may take any number of arguments. The maximum number - of arguments to a new SQL function is 127. A number larger than - 127 for the third argument results in an SQLITE_ERROR error. - - The fourth argument, eTextRep, specifies what type of text arguments - this function prefers to receive. Any function should be able to work - work with UTF-8, UTF-16le, or UTF-16be. But some implementations may be - more efficient with one representation than another. Users are allowed - to specify separate implementations for the same function which are called - depending on the text representation of the arguments. The the implementation - which provides the best match is used. If there is only a single - implementation which does not care what text representation is used, - then the fourth argument should be SQLITE_ANY. - - The fifth argument is an arbitrary pointer. The function implementations - can gain access to this pointer using the sqlite_user_data() API. - - The sixth, seventh and eighth argumens, xFunc, xStep and xFinal, are - pointers to user implemented C functions that implement the user - function or aggregate. A scalar function requires an implementation of - the xFunc callback only, NULL pointers should be passed as the xStep - and xFinal arguments. An aggregate function requires an implementation - of xStep and xFinal, and NULL should be passed for xFunc. To delete an - existing user function or aggregate, pass NULL for all three function - callbacks. Specifying an inconstant set of callback values, such as an - xFunc and an xFinal, or an xStep but no xFinal, results in an SQLITE_ERROR - return. -} - -api {} { -int sqlite3_data_count(sqlite3_stmt *pStmt); -} { - Return the number of values in the current row of the result set. - - After a call to sqlite3_step() that returns SQLITE_ROW, this routine - will return the same value as the sqlite3_column_count() function. - After sqlite3_step() has returned an SQLITE_DONE, SQLITE_BUSY or - error code, or before sqlite3_step() has been called on a - prepared SQL statement, this routine returns zero. -} - -api {} { -int sqlite3_errcode(sqlite3 *db); -} { - Return the error code for the most recent failed sqlite3_* API call associated - with sqlite3 handle 'db'. If a prior API call failed but the most recent - API call succeeded, the return value from this routine is undefined. - - Calls to many sqlite3_* functions set the error code and string returned - by sqlite3_errcode(), sqlite3_errmsg() and sqlite3_errmsg16() - (overwriting the previous values). Note that calls to sqlite3_errcode(), - sqlite3_errmsg() and sqlite3_errmsg16() themselves do not affect the - results of future invocations. Calls to API routines that do not return - an error code (examples: sqlite3_data_count() or sqlite3_mprintf()) do - not change the error code returned by this routine. - - Assuming no other intervening sqlite3_* API calls are made, the error - code returned by this function is associated with the same error as - the strings returned by sqlite3_errmsg() and sqlite3_errmsg16(). -} {} - -api {} { -const char *sqlite3_errmsg(sqlite3*); -const void *sqlite3_errmsg16(sqlite3*); -} { - Return a pointer to a UTF-8 encoded string (sqlite3_errmsg) - or a UTF-16 encoded string (sqlite3_errmsg16) describing in English the - error condition for the most recent sqlite3_* API call. The returned - string is always terminated by an 0x00 byte. - - The string "not an error" is returned when the most recent API call was - successful. -} - -api {} { -int sqlite3_exec( - sqlite3*, /* An open database */ - const char *sql, /* SQL to be executed */ - sqlite_callback, /* Callback function */ - void *, /* 1st argument to callback function */ - char **errmsg /* Error msg written here */ -); -} { - A function to executes one or more statements of SQL. - - If one or more of the SQL statements are queries, then - the callback function specified by the 3rd argument is - invoked once for each row of the query result. This callback - should normally return 0. If the callback returns a non-zero - value then the query is aborted, all subsequent SQL statements - are skipped and the sqlite3_exec() function returns the SQLITE_ABORT. - - The 1st argument is an arbitrary pointer that is passed - to the callback function as its first argument. - - The 2nd argument to the callback function is the number of - columns in the query result. The 3rd argument to the callback - is an array of strings holding the values for each column. - The 4th argument to the callback is an array of strings holding - the names of each column. - - The callback function may be NULL, even for queries. A NULL - callback is not an error. It just means that no callback - will be invoked. - - If an error occurs while parsing or evaluating the SQL (but - not while executing the callback) then an appropriate error - message is written into memory obtained from malloc() and - *errmsg is made to point to that message. The calling function - is responsible for freeing the memory that holds the error - message. Use sqlite3_free() for this. If errmsg==NULL, - then no error message is ever written. - - The return value is is SQLITE_OK if there are no errors and - some other return code if there is an error. The particular - return value depends on the type of error. - - If the query could not be executed because a database file is - locked or busy, then this function returns SQLITE_BUSY. (This - behavior can be modified somewhat using the sqlite3_busy_handler() - and sqlite3_busy_timeout() functions.) -} {} - -api {} { -int sqlite3_finalize(sqlite3_stmt *pStmt); -} { - The sqlite3_finalize() function is called to delete a prepared - SQL statement obtained by a previous call to sqlite3_prepare(), - sqlite3_prepare_v2(), sqlite3_prepare16(), or sqlite3_prepare16_v2(). - If the statement was executed successfully, or - not executed at all, then SQLITE_OK is returned. If execution of the - statement failed then an error code is returned. - - All prepared statements must finalized before sqlite3_close() is - called or else the close will fail with a return code of SQLITE_BUSY. - - This routine can be called at any point during the execution of the - virtual machine. If the virtual machine has not completed execution - when this routine is called, that is like encountering an error or - an interrupt. (See sqlite3_interrupt().) Incomplete updates may be - rolled back and transactions canceled, depending on the circumstances, - and the result code returned will be SQLITE_ABORT. -} - -api {} { -void *sqlite3_malloc(int); -void *sqlite3_realloc(void*, int); -void sqlite3_free(void*); -} { - These routines provide access to the memory allocator used by SQLite. - Depending on how SQLite has been compiled and the OS-layer backend, - the memory allocator used by SQLite might be the standard system - malloc()/realloc()/free(), or it might be something different. With - certain compile-time flags, SQLite will add wrapper logic around the - memory allocator to add memory leak and buffer overrun detection. The - OS layer might substitute a completely different memory allocator. - Use these APIs to be sure you are always using the correct memory - allocator. - - The sqlite3_free() API, not the standard free() from the system library, - should always be used to free the memory buffer returned by - sqlite3_mprintf() or sqlite3_vmprintf() and to free the error message - string returned by sqlite3_exec(). Using free() instead of sqlite3_free() - might accidentally work on some systems and build configurations but - will fail on others. - - Compatibility Note: Prior to version 3.4.0, the sqlite3_free API - was prototyped to take a char* parameter rather than - void*. Like this: -
-void sqlite3_free(char*);
-
- The change to using void* might cause warnings when - compiling older code against - newer libraries, but everything should still work correctly. -} - -api {} { -int sqlite3_get_table( - sqlite3*, /* An open database */ - const char *sql, /* SQL to be executed */ - char ***resultp, /* Result written to a char *[] that this points to */ - int *nrow, /* Number of result rows written here */ - int *ncolumn, /* Number of result columns written here */ - char **errmsg /* Error msg written here */ -); -void sqlite3_free_table(char **result); -} { - This next routine is really just a wrapper around sqlite3_exec(). - Instead of invoking a user-supplied callback for each row of the - result, this routine remembers each row of the result in memory - obtained from malloc(), then returns all of the result after the - query has finished. - - As an example, suppose the query result where this table: - -
-        Name        | Age
-        -----------------------
-        Alice       | 43
-        Bob         | 28
-        Cindy       | 21
- 
- - If the 3rd argument were &azResult then after the function returns - azResult will contain the following data: - -
-        azResult[0] = "Name";
-        azResult[1] = "Age";
-        azResult[2] = "Alice";
-        azResult[3] = "43";
-        azResult[4] = "Bob";
-        azResult[5] = "28";
-        azResult[6] = "Cindy";
-        azResult[7] = "21";
- 
- - Notice that there is an extra row of data containing the column - headers. But the *nrow return value is still 3. *ncolumn is - set to 2. In general, the number of values inserted into azResult - will be ((*nrow) + 1)*(*ncolumn). - - After the calling function has finished using the result, it should - pass the result data pointer to sqlite3_free_table() in order to - release the memory that was malloc-ed. Because of the way the - malloc() happens, the calling function must not try to call - malloc() directly. Only sqlite3_free_table() is able to release - the memory properly and safely. - - The return value of this routine is the same as from sqlite3_exec(). -} - -api {sqlite3_interrupt} { - void sqlite3_interrupt(sqlite3*); -} { - This function causes any pending database operation to abort and - return at its earliest opportunity. This routine is typically - called in response to a user action such as pressing "Cancel" - or Ctrl-C where the user wants a long query operation to halt - immediately. -} {} - -api {} { -long long int sqlite3_last_insert_rowid(sqlite3*); -} { - Each entry in an SQLite table has a unique integer key called the "rowid". - The rowid is always available as an undeclared column - named ROWID, OID, or _ROWID_. - If the table has a column of type INTEGER PRIMARY KEY then that column - is another an alias for the rowid. - - This routine - returns the rowid of the most recent INSERT into the database - from the database connection given in the first argument. If - no inserts have ever occurred on this database connection, zero - is returned. - - If an INSERT occurs within a trigger, then the rowid of the - inserted row is returned by this routine as long as the trigger - is running. But once the trigger terminates, the value returned - by this routine reverts to the last value inserted before the - trigger fired. -} {} - -api {} { -char *sqlite3_mprintf(const char*,...); -char *sqlite3_vmprintf(const char*, va_list); -} { - These routines are variants of the "sprintf()" from the - standard C library. The resulting string is written into memory - obtained from malloc() so that there is never a possibility of buffer - overflow. These routines also implement some additional formatting - options that are useful for constructing SQL statements. - - The strings returned by these routines should be freed by calling - sqlite3_free(). - - All of the usual printf formatting options apply. In addition, there - is a "%q" option. %q works like %s in that it substitutes a null-terminated - string from the argument list. But %q also doubles every '\\'' character. - %q is designed for use inside a string literal. By doubling each '\\'' - character it escapes that character and allows it to be inserted into - the string. - - For example, so some string variable contains text as follows: - -
-  char *zText = "It's a happy day!";
- 
- - One can use this text in an SQL statement as follows: - -
-  sqlite3_exec_printf(db, "INSERT INTO table VALUES('%q')",
-       callback1, 0, 0, zText);
-  
- - Because the %q format string is used, the '\\'' character in zText - is escaped and the SQL generated is as follows: - -
-  INSERT INTO table1 VALUES('It''s a happy day!')
- 
- - This is correct. Had we used %s instead of %q, the generated SQL - would have looked like this: - -
-  INSERT INTO table1 VALUES('It's a happy day!');
-  
- - This second example is an SQL syntax error. As a general rule you - should always use %q instead of %s when inserting text into a string - literal. -} {} - -api {} { -int sqlite3_open( - const char *filename, /* Database filename (UTF-8) */ - sqlite3 **ppDb /* OUT: SQLite db handle */ -); -int sqlite3_open16( - const void *filename, /* Database filename (UTF-16) */ - sqlite3 **ppDb /* OUT: SQLite db handle */ -); -} { - Open the sqlite database file "filename". The "filename" is UTF-8 - encoded for sqlite3_open() and UTF-16 encoded in the native byte order - for sqlite3_open16(). An sqlite3* handle is returned in *ppDb, even - if an error occurs. If the database is opened (or created) successfully, - then SQLITE_OK is returned. Otherwise an error code is returned. The - sqlite3_errmsg() or sqlite3_errmsg16() routines can be used to obtain - an English language description of the error. - - If the database file does not exist, then a new database will be created - as needed. - The encoding for the database will be UTF-8 if sqlite3_open() is called and - UTF-16 if sqlite3_open16 is used. - - Whether or not an error occurs when it is opened, resources associated - with the sqlite3* handle should be released by passing it to - sqlite3_close() when it is no longer required. - - The returned sqlite3* can only be used in the same thread in which it - was created. It is an error to call sqlite3_open() in one thread then - pass the resulting database handle off to another thread to use. This - restriction is due to goofy design decisions (bugs?) in the way some - threading implementations interact with file locks. - - Note to windows users: The encoding used for the filename argument - of sqlite3_open() must be UTF-8, not whatever codepage is currently - defined. Filenames containing international characters must be converted - to UTF-8 prior to passing them into sqlite3_open(). -} - -api {} { -int sqlite3_prepare_v2( - sqlite3 *db, /* Database handle */ - const char *zSql, /* SQL statement, UTF-8 encoded */ - int nBytes, /* Length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const char **pzTail /* OUT: Pointer to unused portion of zSql */ -); -int sqlite3_prepare16_v2( - sqlite3 *db, /* Database handle */ - const void *zSql, /* SQL statement, UTF-16 encoded */ - int nBytes, /* Length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const void **pzTail /* OUT: Pointer to unused portion of zSql */ -); - -/* Legacy Interfaces */ -int sqlite3_prepare( - sqlite3 *db, /* Database handle */ - const char *zSql, /* SQL statement, UTF-8 encoded */ - int nBytes, /* Length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const char **pzTail /* OUT: Pointer to unused portion of zSql */ -); -int sqlite3_prepare16( - sqlite3 *db, /* Database handle */ - const void *zSql, /* SQL statement, UTF-16 encoded */ - int nBytes, /* Length of zSql in bytes. */ - sqlite3_stmt **ppStmt, /* OUT: Statement handle */ - const void **pzTail /* OUT: Pointer to unused portion of zSql */ -); -} { - To execute an SQL query, it must first be compiled into a byte-code - program using one of these routines. - - The first argument "db" is an SQLite database handle. The second - argument "zSql" is the statement to be compiled, encoded as either - UTF-8 or UTF-16. The sqlite3_prepare_v2() - interfaces uses UTF-8 and sqlite3_prepare16_v2() - use UTF-16. If the next argument, "nBytes", is less - than zero, then zSql is read up to the first nul terminator. If - "nBytes" is not less than zero, then it is the length of the string zSql - in bytes (not characters). - - *pzTail is made to point to the first byte past the end of the first - SQL statement in zSql. This routine only compiles the first statement - in zSql, so *pzTail is left pointing to what remains uncompiled. - - *ppStmt is left pointing to a compiled SQL statement that can be - executed using sqlite3_step(). Or if there is an error, *ppStmt may be - set to NULL. If the input text contained no SQL (if the input is and - empty string or a comment) then *ppStmt is set to NULL. The calling - procedure is responsible for deleting this compiled SQL statement - using sqlite3_finalize() after it has finished with it. - - On success, SQLITE_OK is returned. Otherwise an error code is returned. - - The sqlite3_prepare_v2() and sqlite3_prepare16_v2() interfaces are - recommended for all new programs. The two older interfaces are retained - for backwards compatibility, but their use is discouraged. - In the "v2" interfaces, the prepared statement - that is returned (the sqlite3_stmt object) contains a copy of the original - SQL. This causes the sqlite3_step() interface to behave a differently in - two ways: - -
    -
  1. - If the database schema changes, instead of returning SQLITE_SCHEMA as it - always used to do, sqlite3_step() will automatically recompile the SQL - statement and try to run it again. If the schema has changed in a way - that makes the statement no longer valid, sqlite3_step() will still - return SQLITE_SCHEMA. But unlike the legacy behavior, SQLITE_SCHEMA is - now a fatal error. Calling sqlite3_prepare_v2() again will not make the - error go away. Note: use sqlite3_errmsg() to find the text of the parsing - error that results in an SQLITE_SCHEMA return. -
  2. - -
  3. - When an error occurs, - sqlite3_step() will return one of the detailed result-codes - like SQLITE_IOERR or SQLITE_FULL or SQLITE_SCHEMA directly. The - legacy behavior was that sqlite3_step() would only return a generic - SQLITE_ERROR code and you would have to make a second call to - sqlite3_reset() in order to find the underlying cause of the problem. - With the "v2" prepare interfaces, the underlying reason for the error is - returned directly. -
  4. -
-} - -api {} { -void sqlite3_progress_handler(sqlite3*, int, int(*)(void*), void*); -} { - Experimental - - This routine configures a callback function - the progress callback - that - is invoked periodically during long running calls to sqlite3_exec(), - sqlite3_step() and sqlite3_get_table(). - An example use for this API is to keep - a GUI updated during a large query. - - The progress callback is invoked once for every N virtual machine opcodes, - where N is the second argument to this function. The progress callback - itself is identified by the third argument to this function. The fourth - argument to this function is a void pointer passed to the progress callback - function each time it is invoked. - - If a call to sqlite3_exec(), sqlite3_step() or sqlite3_get_table() results - in less than N opcodes being executed, then the progress callback is not - invoked. - - To remove the progress callback altogether, pass NULL as the third - argument to this function. - - If the progress callback returns a result other than 0, then the current - query is immediately terminated and any database changes rolled back. If the - query was part of a larger transaction, then the transaction is not rolled - back and remains active. The sqlite3_exec() call returns SQLITE_ABORT. - -} - -api {} { -int sqlite3_reset(sqlite3_stmt *pStmt); -} { - The sqlite3_reset() function is called to reset a prepared SQL - statement obtained by a previous call to - sqlite3_prepare_v2() or - sqlite3_prepare16_v2() back to it's initial state, ready to be re-executed. - Any SQL statement variables that had values bound to them using - the sqlite3_bind_*() API retain their values. -} - -api {} { -void sqlite3_result_blob(sqlite3_context*, const void*, int n, void(*)(void*)); -void sqlite3_result_double(sqlite3_context*, double); -void sqlite3_result_error(sqlite3_context*, const char*, int); -void sqlite3_result_error16(sqlite3_context*, const void*, int); -void sqlite3_result_int(sqlite3_context*, int); -void sqlite3_result_int64(sqlite3_context*, long long int); -void sqlite3_result_null(sqlite3_context*); -void sqlite3_result_text(sqlite3_context*, const char*, int n, void(*)(void*)); -void sqlite3_result_text16(sqlite3_context*, const void*, int n, void(*)(void*)); -void sqlite3_result_text16be(sqlite3_context*, const void*, int n, void(*)(void*)); -void sqlite3_result_text16le(sqlite3_context*, const void*, int n, void(*)(void*)); -void sqlite3_result_value(sqlite3_context*, sqlite3_value*); -} { - User-defined functions invoke these routines in order to - set their return value. The sqlite3_result_value() routine is used - to return an exact copy of one of the arguments to the function. - - The operation of these routines is very similar to the operation of - sqlite3_bind_blob() and its cousins. Refer to the documentation there - for additional information. -} - -api {} { -int sqlite3_set_authorizer( - sqlite3*, - int (*xAuth)(void*,int,const char*,const char*,const char*,const char*), - void *pUserData -); -#define SQLITE_CREATE_INDEX 1 /* Index Name Table Name */ -#define SQLITE_CREATE_TABLE 2 /* Table Name NULL */ -#define SQLITE_CREATE_TEMP_INDEX 3 /* Index Name Table Name */ -#define SQLITE_CREATE_TEMP_TABLE 4 /* Table Name NULL */ -#define SQLITE_CREATE_TEMP_TRIGGER 5 /* Trigger Name Table Name */ -#define SQLITE_CREATE_TEMP_VIEW 6 /* View Name NULL */ -#define SQLITE_CREATE_TRIGGER 7 /* Trigger Name Table Name */ -#define SQLITE_CREATE_VIEW 8 /* View Name NULL */ -#define SQLITE_DELETE 9 /* Table Name NULL */ -#define SQLITE_DROP_INDEX 10 /* Index Name Table Name */ -#define SQLITE_DROP_TABLE 11 /* Table Name NULL */ -#define SQLITE_DROP_TEMP_INDEX 12 /* Index Name Table Name */ -#define SQLITE_DROP_TEMP_TABLE 13 /* Table Name NULL */ -#define SQLITE_DROP_TEMP_TRIGGER 14 /* Trigger Name Table Name */ -#define SQLITE_DROP_TEMP_VIEW 15 /* View Name NULL */ -#define SQLITE_DROP_TRIGGER 16 /* Trigger Name Table Name */ -#define SQLITE_DROP_VIEW 17 /* View Name NULL */ -#define SQLITE_INSERT 18 /* Table Name NULL */ -#define SQLITE_PRAGMA 19 /* Pragma Name 1st arg or NULL */ -#define SQLITE_READ 20 /* Table Name Column Name */ -#define SQLITE_SELECT 21 /* NULL NULL */ -#define SQLITE_TRANSACTION 22 /* NULL NULL */ -#define SQLITE_UPDATE 23 /* Table Name Column Name */ -#define SQLITE_ATTACH 24 /* Filename NULL */ -#define SQLITE_DETACH 25 /* Database Name NULL */ -#define SQLITE_ALTER_TABLE 26 /* Database Name Table Name */ -#define SQLITE_REINDEX 27 /* Index Name NULL */ -#define SQLITE_ANALYZE 28 /* Table Name NULL */ -#define SQLITE_CREATE_VTABLE 29 /* Table Name Module Name */ -#define SQLITE_DROP_VTABLE 30 /* Table Name Module Name */ -#define SQLITE_FUNCTION 31 /* Function Name NULL */ - -#define SQLITE_DENY 1 /* Abort the SQL statement with an error */ -#define SQLITE_IGNORE 2 /* Don't allow access, but don't generate an error */ -} { - This routine registers a callback with the SQLite library. The - callback is invoked by sqlite3_prepare_v2() to authorize various - operations against the database. The callback should - return SQLITE_OK if access is allowed, SQLITE_DENY if the entire - SQL statement should be aborted with an error and SQLITE_IGNORE - if the operation should be treated as a no-op. - - Each database connection have at most one authorizer registered - at a time one time. Each call - to sqlite3_set_authorizer() overrides the previous authorizer. - Setting the callback to NULL disables the authorizer. - - The second argument to the access authorization function will be one - of the defined constants shown. These values signify what kind of operation - is to be authorized. The 3rd and 4th arguments to the authorization - function will be arguments or NULL depending on which of the - codes is used as the second argument. For example, if the the - 2nd argument code is SQLITE_READ then the 3rd argument will be the name - of the table that is being read from and the 4th argument will be the - name of the column that is being read from. Or if the 2nd argument - is SQLITE_FUNCTION then the 3rd argument will be the name of the - function that is being invoked and the 4th argument will be NULL. - - The 5th argument is the name - of the database ("main", "temp", etc.) where applicable. The 6th argument - is the name of the inner-most trigger or view that is responsible for - the access attempt or NULL if this access attempt is directly from - input SQL code. - - The return value of the authorization callback function should be one of the - constants SQLITE_OK, SQLITE_DENY, or SQLITE_IGNORE. A return of - SQLITE_OK means that the operation is permitted and that - sqlite3_prepare_v2() can proceed as normal. - A return of SQLITE_DENY means that the sqlite3_prepare_v2() - should fail with an error. A return of SQLITE_IGNORE causes the - sqlite3_prepare_v2() to continue as normal but the requested - operation is silently converted into a no-op. A return of SQLITE_IGNORE - in response to an SQLITE_READ or SQLITE_FUNCTION causes the column - being read or the function being invoked to return a NULL. - - The intent of this routine is to allow applications to safely execute - user-entered SQL. An appropriate callback can deny the user-entered - SQL access certain operations (ex: anything that changes the database) - or to deny access to certain tables or columns within the database. - - SQLite is not reentrant through the authorization callback function. - The authorization callback function should not attempt to invoke - any other SQLite APIs for the same database connection. If the - authorization callback function invokes some other SQLite API, an - SQLITE_MISUSE error or a segmentation fault may result. -} - -api {} { -int sqlite3_step(sqlite3_stmt*); -} { - After an SQL query has been prepared with a call to either - sqlite3_prepare_v2() or sqlite3_prepare16_v2() or to one of - the legacy interfaces sqlite3_prepare() or sqlite3_prepare16(), - then this function must be - called one or more times to execute the statement. - - The details of the behavior of this sqlite3_step() interface depend - on whether the statement was prepared using the newer "v2" interface - sqlite3_prepare_v2() and sqlite3_prepare16_v2() or the older legacy - interface sqlite3_prepare() and sqlite3_prepare16(). The use of the - new "v2" interface is recommended for new applications but the legacy - interface will continue to be supported. - - In the lagacy interface, the return value will be either SQLITE_BUSY, - SQLITE_DONE, SQLITE_ROW, SQLITE_ERROR, or SQLITE_MISUSE. With the "v2" - interface, any of the other SQLite result-codes might be returned as - well. - - SQLITE_BUSY means that the database engine attempted to open - a locked database and there is no busy callback registered. - Call sqlite3_step() again to retry the open. - - SQLITE_DONE means that the statement has finished executing - successfully. sqlite3_step() should not be called again on this virtual - machine without first calling sqlite3_reset() to reset the virtual - machine back to its initial state. - - If the SQL statement being executed returns any data, then - SQLITE_ROW is returned each time a new row of data is ready - for processing by the caller. The values may be accessed using - the sqlite3_column_int(), sqlite3_column_text(), and similar functions. - sqlite3_step() is called again to retrieve the next row of data. - - SQLITE_ERROR means that a run-time error (such as a constraint - violation) has occurred. sqlite3_step() should not be called again on - the VM. More information may be found by calling sqlite3_errmsg(). - A more specific error code (example: SQLITE_INTERRUPT, SQLITE_SCHEMA, - SQLITE_CORRUPT, and so forth) can be obtained by calling - sqlite3_reset() on the prepared statement. In the "v2" interface, - the more specific error code is returned directly by sqlite3_step(). - - SQLITE_MISUSE means that the this routine was called inappropriately. - Perhaps it was called on a virtual machine that had already been - finalized or on one that had previously returned SQLITE_ERROR or - SQLITE_DONE. Or it could be the case that a database connection - is being used by a different thread than the one it was created it. - - Goofy Interface Alert: - In the legacy interface, - the sqlite3_step() API always returns a generic error code, - SQLITE_ERROR, following any error other than SQLITE_BUSY and SQLITE_MISUSE. - You must call sqlite3_reset() (or sqlite3_finalize()) in order to find - one of the specific result-codes that better describes the error. - We admit that this is a goofy design. The problem has been fixed - with the "v2" interface. If you prepare all of your SQL statements - using either sqlite3_prepare_v2() or sqlite3_prepare16_v2() instead - of the legacy sqlite3_prepare() and sqlite3_prepare16(), then the - more specific result-codes are returned directly by sqlite3_step(). - The use of the "v2" interface is recommended. -} - -api {} { -void *sqlite3_trace(sqlite3*, void(*xTrace)(void*,const char*), void*); -} { - Register a function that is called each time an SQL statement is evaluated. - The callback function is invoked on the first call to sqlite3_step() after - calls to sqlite3_prepare_v2() or sqlite3_reset(). - This function can be used (for example) to generate - a log file of all SQL executed against a database. This can be - useful when debugging an application that uses SQLite. -} - -api {} { -void *sqlite3_user_data(sqlite3_context*); -} { - The pUserData argument to the sqlite3_create_function() and - sqlite3_create_function16() routines used to register user functions - is available to the implementation of the function using this - call. -} - -api {} { -const void *sqlite3_value_blob(sqlite3_value*); -int sqlite3_value_bytes(sqlite3_value*); -int sqlite3_value_bytes16(sqlite3_value*); -double sqlite3_value_double(sqlite3_value*); -int sqlite3_value_int(sqlite3_value*); -long long int sqlite3_value_int64(sqlite3_value*); -const unsigned char *sqlite3_value_text(sqlite3_value*); -const void *sqlite3_value_text16(sqlite3_value*); -const void *sqlite3_value_text16be(sqlite3_value*); -const void *sqlite3_value_text16le(sqlite3_value*); -int sqlite3_value_type(sqlite3_value*); -} { - This group of routines returns information about arguments to - a user-defined function. Function implementations use these routines - to access their arguments. These routines are the same as the - sqlite3_column_... routines except that these routines take a single - sqlite3_value* pointer instead of an sqlite3_stmt* and an integer - column number. - - See the documentation under sqlite3_column_blob for additional - information. -} - -api {} { - int sqlite3_sleep(int); -} { - Sleep for a little while. The second parameter is the number of - miliseconds to sleep for. - - If the operating system does not support sleep requests with - milisecond time resolution, then the time will be rounded up to - the nearest second. The number of miliseconds of sleep actually - requested from the operating system is returned. -} - -api {} { - int sqlite3_expired(sqlite3_stmt*); -} { - Return TRUE (non-zero) if the statement supplied as an argument needs - to be recompiled. A statement needs to be recompiled whenever the - execution environment changes in a way that would alter the program - that sqlite3_prepare() generates. For example, if new functions or - collating sequences are registered or if an authorizer function is - added or changed. -} - -api {} { - int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*); -} { - Move all bindings from the first prepared statement over to the second. - This routine is useful, for example, if the first prepared statement - fails with an SQLITE_SCHEMA error. The same SQL can be prepared into - the second prepared statement then all of the bindings transfered over - to the second statement before the first statement is finalized. -} - -api {} { - int sqlite3_global_recover(); -} { - This function used to be involved in recovering from out-of-memory - errors. But as of SQLite version 3.3.0, out-of-memory recovery is - automatic and this routine now does nothing. THe interface is retained - to avoid link errors with legacy code. -} - -api {} { - int sqlite3_get_autocommit(sqlite3*); -} { - Test to see whether or not the database connection is in autocommit - mode. Return TRUE if it is and FALSE if not. Autocommit mode is on - by default. Autocommit is disabled by a BEGIN statement and reenabled - by the next COMMIT or ROLLBACK. -} - -api {} { - int sqlite3_clear_bindings(sqlite3_stmt*); -} { - Set all the parameters in the compiled SQL statement back to NULL. -} - -api {} { - sqlite3 *sqlite3_db_handle(sqlite3_stmt*); -} { - Return the sqlite3* database handle to which the prepared statement given - in the argument belongs. This is the same database handle that was - the first argument to the sqlite3_prepare() that was used to create - the statement in the first place. -} - -api {} { - void *sqlite3_update_hook( - sqlite3*, - void(*)(void *,int ,char const *,char const *,sqlite_int64), - void* - ); -} { - Register a callback function with the database connection identified by the - first argument to be invoked whenever a row is updated, inserted or deleted. - Any callback set by a previous call to this function for the same - database connection is overridden. - - The second argument is a pointer to the function to invoke when a - row is updated, inserted or deleted. The first argument to the callback is - a copy of the third argument to sqlite3_update_hook. The second callback - argument is one of SQLITE_INSERT, SQLITE_DELETE or SQLITE_UPDATE, depending - on the operation that caused the callback to be invoked. The third and - fourth arguments to the callback contain pointers to the database and - table name containing the affected row. The final callback parameter is - the rowid of the row. In the case of an update, this is the rowid after - the update takes place. - - The update hook is not invoked when internal system tables are - modified (i.e. sqlite_master and sqlite_sequence). - - If another function was previously registered, its pArg value is returned. - Otherwise NULL is returned. - - See also: sqlite3_commit_hook(), sqlite3_rollback_hook() -} - -api {} { - void *sqlite3_rollback_hook(sqlite3*, void(*)(void *), void*); -} { - Register a callback to be invoked whenever a transaction is rolled - back. - - The new callback function overrides any existing rollback-hook - callback. If there was an existing callback, then it's pArg value - (the third argument to sqlite3_rollback_hook() when it was registered) - is returned. Otherwise, NULL is returned. - - For the purposes of this API, a transaction is said to have been - rolled back if an explicit "ROLLBACK" statement is executed, or - an error or constraint causes an implicit rollback to occur. The - callback is not invoked if a transaction is automatically rolled - back because the database connection is closed. -} - -api {} { - int sqlite3_enable_shared_cache(int); -} { - This routine enables or disables the sharing of the database cache - and schema data structures between connections to the same database. - Sharing is enabled if the argument is true and disabled if the argument - is false. - - Cache sharing is enabled and disabled on a thread-by-thread basis. - Each call to this routine enables or disables cache sharing only for - connections created in the same thread in which this routine is called. - There is no mechanism for sharing cache between database connections - running in different threads. - - Sharing must be disabled prior to shutting down a thread or else - the thread will leak memory. Call this routine with an argument of - 0 to turn off sharing. Or use the sqlite3_thread_cleanup() API. - - This routine must not be called when any database connections - are active in the current thread. Enabling or disabling shared - cache while there are active database connections will result - in memory corruption. - - When the shared cache is enabled, the - following routines must always be called from the same thread: - sqlite3_open(), sqlite3_prepare_v2(), sqlite3_step(), sqlite3_reset(), - sqlite3_finalize(), and sqlite3_close(). - This is due to the fact that the shared cache makes use of - thread-specific storage so that it will be available for sharing - with other connections. - - Virtual tables cannot be used with a shared cache. When shared - cache is enabled, the sqlite3_create_module() API used to register - virtual tables will always return an error. - - This routine returns SQLITE_OK if shared cache was - enabled or disabled successfully. An error code is returned - otherwise. - - Shared cache is disabled by default for backward compatibility. -} - -api {} { - void sqlite3_thread_cleanup(void); -} { - This routine makes sure that all thread local storage used by SQLite - in the current thread has been deallocated. A thread can call this - routine prior to terminating in order to make sure there are no memory - leaks. - - This routine is not strictly necessary. If cache sharing has been - disabled using sqlite3_enable_shared_cache() and if all database - connections have been closed and if SQLITE_ENABLE_MEMORY_MANAGMENT is - on and all memory has been freed, then the thread local storage will - already have been automatically deallocated. This routine is provided - as a convenience to the program who just wants to make sure that there - are no leaks. -} - -api {} { - int sqlite3_release_memory(int N); -} { - This routine attempts to free at least N bytes of memory from the caches - of database connecions that were created in the same thread from which this - routine is called. The value returned is the number of bytes actually - freed. - - This routine is only available if memory management has been enabled - by compiling with the SQLITE_ENABLE_MEMORY_MANAGMENT macro. -} - -api {} { - void sqlite3_soft_heap_limit(int N); -} { - This routine sets the soft heap limit for the current thread to N. - If the total heap usage by SQLite in the current thread exceeds N, - then sqlite3_release_memory() is called to try to reduce the memory usage - below the soft limit. - - Prior to shutting down a thread sqlite3_soft_heap_limit() must be set to - zero (the default) or else the thread will leak memory. Alternatively, use - the sqlite3_thread_cleanup() API. - - A negative or zero value for N means that there is no soft heap limit and - sqlite3_release_memory() will only be called when memory is exhaused. - The default value for the soft heap limit is zero. - - SQLite makes a best effort to honor the soft heap limit. But if it - is unable to reduce memory usage below the soft limit, execution will - continue without error or notification. This is why the limit is - called a "soft" limit. It is advisory only. - - This routine is only available if memory management has been enabled - by compiling with the SQLITE_ENABLE_MEMORY_MANAGMENT macro. -} - -api {} { - void sqlite3_thread_cleanup(void); -} { - This routine ensures that a thread that has used SQLite in the past - has released any thread-local storage it might have allocated. - When the rest of the API is used properly, the cleanup of - thread-local storage should be completely automatic. You should - never really need to invoke this API. But it is provided to you - as a precaution and as a potential work-around for future - thread-releated memory-leaks. -} - -set n 0 -set i 0 -foreach item $apilist { - set namelist [lindex $item 0] - foreach name $namelist { - set n_to_name($n) $name - set n_to_idx($n) $i - set name_to_idx($name) $i - incr n - } - incr i -} -set i 0 -foreach name [lsort [array names name_to_idx]] { - set sname($i) $name - incr i -} -#parray n_to_name -#parray n_to_idx -#parray name_to_idx -#parray sname -incr n -1 -puts "
" -puts {} -set nrow [expr {($n+2)/3}] -set i 0 -for {set j 0} {$j<3} {incr j} { - if {$j>0} {puts {}} - puts {} -} -puts "
} - set limit [expr {$i+$nrow}] - puts {
    } - while {$i<$limit && $i<$n} { - set name $sname($i) - if {[regexp {^sqlite} $name]} {set display $name} {set display $name} - puts "
  • $display
  • " - incr i - } - puts {
" -puts "" -puts "
" - -proc resolve_name {ignore_list name} { - global name_to_idx - if {![info exists name_to_idx($name)] || [lsearch $ignore_list $name]>=0} { - return $name - } else { - return "$name" - } -} - -foreach name [lsort [array names name_to_idx]] { - set i $name_to_idx($name) - if {[info exists done($i)]} continue - set done($i) 1 - foreach {namelist prototype desc} [lindex $apilist $i] break - foreach name $namelist { - puts "" - } - puts "


" - puts "
"
-  regsub "^( *\n)+" $prototype {} p2
-  regsub "(\n *)+\$" $p2 {} p3
-  puts $p3
-  puts "
" - regsub -all {\[} $desc {\[} desc - regsub -all {sqlite3_[a-z0-9_]+} $desc "\[resolve_name $name &\]" d2 - foreach x $specialname { - regsub -all $x $d2 "\[resolve_name $name &\]" d2 - } - regsub -all "\n( *\n)+" [subst $d2] "

\n\n

" d3 - puts "

$d3

" -} - -puts "
" -footer $rcsid -puts "
"