diff --git a/ext/fts1/fts1.c b/ext/fts1/fts1.c index d5429ff320..482cf759ba 100644 --- a/ext/fts1/fts1.c +++ b/ext/fts1/fts1.c @@ -3335,8 +3335,11 @@ int sqlite3Fts1Init(sqlite3 *db){ } #if !SQLITE_CORE -int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, - const sqlite3_api_routines *pApi){ +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_fts1_init(sqlite3 *db, char **pzErrMsg, + const sqlite3_api_routines *pApi){ SQLITE_EXTENSION_INIT2(pApi) return sqlite3Fts1Init(db); } diff --git a/ext/fts1/fulltext.c b/ext/fts1/fulltext.c index e6034ba023..313ff303e1 100644 --- a/ext/fts1/fulltext.c +++ b/ext/fts1/fulltext.c @@ -852,8 +852,14 @@ static void fulltext_vtab_destroy(fulltext_vtab *v){ ** 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){ +static int fulltextConnect( + sqlite3 *db, + void *pAux, + int argc, + const char * const *argv, + sqlite3_vtab **ppVTab, + char **pzErr +){ int rc; fulltext_vtab *v; sqlite3_tokenizer_module *m = NULL; @@ -898,8 +904,14 @@ static int fulltextConnect(sqlite3 *db, void *pAux, int argc, char **argv, return SQLITE_OK; } -static int fulltextCreate(sqlite3 *db, void *pAux, int argc, char **argv, - sqlite3_vtab **ppVTab){ +static int fulltextCreate( + sqlite3 *db, + void *pAux, + int argc, + const char * const *argv, + sqlite3_vtab **ppVTab, + char **pzErr +){ int rc; assert( argc>=3 ); @@ -934,7 +946,7 @@ static int fulltextCreate(sqlite3 *db, void *pAux, int argc, char **argv, "create index %_index on %_term(term, first)"); if( rc!=SQLITE_OK ) return rc; - return fulltextConnect(db, pAux, argc, argv, ppVTab); + return fulltextConnect(db, pAux, argc, argv, ppVTab, pzErr); } /* Decide how to handle an SQL query. @@ -1488,8 +1500,11 @@ int fulltext_init(sqlite3 *db){ } #if !SQLITE_CORE -int sqlite3_extension_init(sqlite3 *db, char **pzErrMsg, - const sqlite3_api_routines *pApi){ +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_fulltext_init(sqlite3 *db, char **pzErrMsg, + const sqlite3_api_routines *pApi){ SQLITE_EXTENSION_INIT2(pApi) return fulltext_init(db); } diff --git a/ext/fts2/fts2.c b/ext/fts2/fts2.c index f008ce6dc0..0405fb7b1e 100644 --- a/ext/fts2/fts2.c +++ b/ext/fts2/fts2.c @@ -6844,7 +6844,10 @@ int sqlite3Fts2Init(sqlite3 *db){ } #if !SQLITE_CORE -int sqlite3_extension_init( +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_fts2_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi diff --git a/ext/fts2/fts2_hash.c b/ext/fts2/fts2_hash.c index f22fcc91df..3596dcf0b8 100644 --- a/ext/fts2/fts2_hash.c +++ b/ext/fts2/fts2_hash.c @@ -30,6 +30,8 @@ #include #include "sqlite3.h" +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT3 #include "fts2_hash.h" /* diff --git a/ext/fts2/fts2_porter.c b/ext/fts2/fts2_porter.c index 16620b9353..881baf7100 100644 --- a/ext/fts2/fts2_porter.c +++ b/ext/fts2/fts2_porter.c @@ -30,6 +30,9 @@ #include #include +#include "sqlite3.h" +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT3 #include "fts2_tokenizer.h" /* diff --git a/ext/fts2/fts2_tokenizer.c b/ext/fts2/fts2_tokenizer.c index a93790c801..a3d6a6312a 100644 --- a/ext/fts2/fts2_tokenizer.c +++ b/ext/fts2/fts2_tokenizer.c @@ -28,7 +28,7 @@ #include "sqlite3.h" #include "sqlite3ext.h" -SQLITE_EXTENSION_INIT1 +SQLITE_EXTENSION_INIT3 #include "fts2_hash.h" #include "fts2_tokenizer.h" diff --git a/ext/fts2/fts2_tokenizer1.c b/ext/fts2/fts2_tokenizer1.c index 7e13366910..fe4f9eb4b5 100644 --- a/ext/fts2/fts2_tokenizer1.c +++ b/ext/fts2/fts2_tokenizer1.c @@ -30,6 +30,9 @@ #include #include +#include "sqlite3.h" +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT3 #include "fts2_tokenizer.h" typedef struct simple_tokenizer { diff --git a/ext/fts3/fts3.c b/ext/fts3/fts3.c index 0719fbd5fd..0f7c38e571 100644 --- a/ext/fts3/fts3.c +++ b/ext/fts3/fts3.c @@ -1095,7 +1095,7 @@ static int fts3InitVtab( nByte = sizeof(const char *) * (argc-2); aCol = (const char **)sqlite3_malloc(nByte); if( aCol ){ - memset(aCol, 0, nByte); + memset((void*)aCol, 0, nByte); azNotindexed = (char **)sqlite3_malloc(nByte); } if( azNotindexed ){ @@ -1346,7 +1346,7 @@ static int fts3InitVtab( /* Fill in the abNotindexed array */ for(iCol=0; iColazColumn[iCol]); + int n = (int)strlen(p->azColumn[iCol]); for(i=0; iazColumn[iCol], zNot, n) ){ @@ -5376,7 +5376,10 @@ int sqlite3Fts3Corrupt(){ /* ** Initialize API pointer table, if required. */ -int sqlite3_extension_init( +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_fts3_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi diff --git a/ext/fts3/fts3Int.h b/ext/fts3/fts3Int.h index 59beae5938..f399d89038 100644 --- a/ext/fts3/fts3Int.h +++ b/ext/fts3/fts3Int.h @@ -32,7 +32,7 @@ /* If not building as part of the core, include sqlite3ext.h. */ #ifndef SQLITE_CORE # include "sqlite3ext.h" -extern const sqlite3_api_routines *sqlite3_api; +SQLITE_EXTENSION_INIT3 #endif #include "sqlite3.h" diff --git a/ext/icu/icu.c b/ext/icu/icu.c index 74f4ae77c2..1ce1e0c806 100644 --- a/ext/icu/icu.c +++ b/ext/icu/icu.c @@ -488,7 +488,10 @@ int sqlite3IcuInit(sqlite3 *db){ } #if !SQLITE_CORE -int sqlite3_extension_init( +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_icu_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi diff --git a/ext/misc/ieee754.c b/ext/misc/ieee754.c index 436b11e0c5..f143893885 100644 --- a/ext/misc/ieee754.c +++ b/ext/misc/ieee754.c @@ -18,11 +18,11 @@ ** ** In the first form, the value X should be a floating-point number. ** The function will return a string of the form 'ieee754(Y,Z)' where -** Y and Z are integers such that X==Y*pow(w.0,Z). +** Y and Z are integers such that X==Y*pow(2,Z). ** ** In the second form, Y and Z are integers which are the mantissa and ** base-2 exponent of a new floating point number. The function returns -** a floating-point value equal to Y*pow(2.0,Z). +** a floating-point value equal to Y*pow(2,Z). ** ** Examples: ** diff --git a/ext/misc/nextchar.c b/ext/misc/nextchar.c index e063043e04..6dcbd2dbc3 100644 --- a/ext/misc/nextchar.c +++ b/ext/misc/nextchar.c @@ -10,12 +10,22 @@ ** ****************************************************************************** ** -** This file contains code to implement the next_char(A,T,F,W) SQL function. +** This file contains code to implement the next_char(A,T,F,W,C) SQL function. ** -** The next_char(A,T,F,H) function finds all valid "next" characters for -** string A given the vocabulary in T.F. The T.F field should be indexed. -** If the W value exists and is a non-empty string, then it is an SQL -** expression that limits the entries in T.F that will be considered. +** The next_char(A,T,F,W,C) function finds all valid "next" characters for +** string A given the vocabulary in T.F. If the W value exists and is a +** non-empty string, then it is an SQL expression that limits the entries +** in T.F that will be considered. If C exists and is a non-empty string, +** then it is the name of the collating sequence to use for comparison. If +** +** Only the first three arguments are required. If the C parameter is +** omitted or is NULL or is an empty string, then the default collating +** sequence of T.F is used for comparision. If the W parameter is omitted +** or is NULL or is an empty string, then no filtering of the output is +** done. +** +** The T.F column should be indexed using collation C or else this routine +** will be quite slow. ** ** For example, suppose an application has a dictionary like this: ** @@ -184,6 +194,9 @@ static void nextCharFunc( const unsigned char *zTable = sqlite3_value_text(argv[1]); const unsigned char *zField = sqlite3_value_text(argv[2]); const unsigned char *zWhere; + const unsigned char *zCollName; + char *zWhereClause = 0; + char *zColl = 0; char *zSql; int rc; @@ -192,25 +205,41 @@ static void nextCharFunc( c.zPrefix = sqlite3_value_text(argv[0]); c.nPrefix = sqlite3_value_bytes(argv[0]); if( zTable==0 || zField==0 || c.zPrefix==0 ) return; - if( argc<4 - || (zWhere = sqlite3_value_text(argv[3]))==0 - || zWhere[0]==0 + if( argc>=4 + && (zWhere = sqlite3_value_text(argv[3]))!=0 + && zWhere[0]!=0 ){ - zSql = sqlite3_mprintf( - "SELECT \"%w\" FROM \"%w\"" - " WHERE \"%w\">=(?1 || ?2)" - " AND \"%w\"<=(?1 || char(1114111))" /* 1114111 == 0x10ffff */ - " ORDER BY 1 ASC LIMIT 1", - zField, zTable, zField, zField); + zWhereClause = sqlite3_mprintf("AND (%s)", zWhere); + if( zWhereClause==0 ){ + sqlite3_result_error_nomem(context); + return; + } }else{ - zSql = sqlite3_mprintf( - "SELECT \"%w\" FROM \"%w\"" - " WHERE \"%w\">=(?1 || ?2)" - " AND \"%w\"<=(?1 || char(1114111))" /* 1114111 == 0x10ffff */ - " AND (%s)" - " ORDER BY 1 ASC LIMIT 1", - zField, zTable, zField, zField, zWhere); + zWhereClause = ""; } + if( argc>=5 + && (zCollName = sqlite3_value_text(argv[4]))!=0 + && zCollName[0]!=0 + ){ + zColl = sqlite3_mprintf("collate \"%w\"", zCollName); + if( zColl==0 ){ + sqlite3_result_error_nomem(context); + if( zWhereClause[0] ) sqlite3_free(zWhereClause); + return; + } + }else{ + zColl = ""; + } + zSql = sqlite3_mprintf( + "SELECT \"%w\" FROM \"%w\"" + " WHERE \"%w\">=(?1 || ?2) %s" + " AND \"%w\"<=(?1 || char(1114111)) %s" /* 1114111 == 0x10ffff */ + " %s" + " ORDER BY 1 %s ASC LIMIT 1", + zField, zTable, zField, zColl, zField, zColl, zWhereClause, zColl + ); + if( zWhereClause[0] ) sqlite3_free(zWhereClause); + if( zColl[0] ) sqlite3_free(zColl); if( zSql==0 ){ sqlite3_result_error_nomem(context); return; @@ -261,5 +290,9 @@ int sqlite3_nextchar_init( rc = sqlite3_create_function(db, "next_char", 4, SQLITE_UTF8, 0, nextCharFunc, 0, 0); } + if( rc==SQLITE_OK ){ + rc = sqlite3_create_function(db, "next_char", 5, SQLITE_UTF8, 0, + nextCharFunc, 0, 0); + } return rc; } diff --git a/ext/misc/percentile.c b/ext/misc/percentile.c index 40ef151f60..74a4c9d12b 100644 --- a/ext/misc/percentile.c +++ b/ext/misc/percentile.c @@ -190,7 +190,7 @@ static void percentFinal(sqlite3_context *pCtx){ if( p->nUsed ){ qsort(p->a, p->nUsed, sizeof(double), doubleCmp); ix = (p->rPct-1.0)*(p->nUsed-1)*0.01; - i1 = ix; + i1 = (unsigned)ix; i2 = ix==(double)i1 || i1==p->nUsed-1 ? i1 : i1+1; v1 = p->a[i1]; v2 = p->a[i2]; diff --git a/ext/misc/vtshim.c b/ext/misc/vtshim.c new file mode 100644 index 0000000000..9e1e495e33 --- /dev/null +++ b/ext/misc/vtshim.c @@ -0,0 +1,547 @@ +/* +** 2013-06-12 +** +** 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. +** +************************************************************************* +** +** A shim that sits between the SQLite virtual table interface and +** runtimes with garbage collector based memory management. +*/ +#include "sqlite3ext.h" +SQLITE_EXTENSION_INIT1 +#include +#include + +#ifndef SQLITE_OMIT_VIRTUALTABLE + +/* Forward references */ +typedef struct vtshim_aux vtshim_aux; +typedef struct vtshim_vtab vtshim_vtab; +typedef struct vtshim_cursor vtshim_cursor; + + +/* The vtshim_aux argument is the auxiliary parameter that is passed +** into sqlite3_create_module_v2(). +*/ +struct vtshim_aux { + void *pChildAux; /* pAux for child virtual tables */ + void (*xChildDestroy)(void*); /* Destructor for pChildAux */ + sqlite3_module *pMod; /* Methods for child virtual tables */ + sqlite3 *db; /* The database to which we are attached */ + char *zName; /* Name of the module */ + int bDisposed; /* True if disposed */ + vtshim_vtab *pAllVtab; /* List of all vtshim_vtab objects */ + sqlite3_module sSelf; /* Methods used by this shim */ +}; + +/* A vtshim virtual table object */ +struct vtshim_vtab { + sqlite3_vtab base; /* Base class - must be first */ + sqlite3_vtab *pChild; /* Child virtual table */ + vtshim_aux *pAux; /* Pointer to vtshim_aux object */ + vtshim_cursor *pAllCur; /* List of all cursors */ + vtshim_vtab **ppPrev; /* Previous on list */ + vtshim_vtab *pNext; /* Next on list */ +}; + +/* A vtshim cursor object */ +struct vtshim_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + sqlite3_vtab_cursor *pChild; /* Cursor generated by the managed subclass */ + vtshim_cursor **ppPrev; /* Previous on list of all cursors */ + vtshim_cursor *pNext; /* Next on list of all cursors */ +}; + +/* Macro used to copy the child vtable error message to outer vtable */ +#define VTSHIM_COPY_ERRMSG() \ + do { \ + sqlite3_free(pVtab->base.zErrMsg); \ + pVtab->base.zErrMsg = sqlite3_mprintf("%s", pVtab->pChild->zErrMsg); \ + } while (0) + +/* Methods for the vtshim module */ +static int vtshimCreate( + sqlite3 *db, + void *ppAux, + int argc, + const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + vtshim_aux *pAux = (vtshim_aux*)ppAux; + vtshim_vtab *pNew; + int rc; + + assert( db==pAux->db ); + if( pAux->bDisposed ){ + if( pzErr ){ + *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"", + pAux->zName); + } + return SQLITE_ERROR; + } + pNew = sqlite3_malloc( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + rc = pAux->pMod->xCreate(db, pAux->pChildAux, argc, argv, + &pNew->pChild, pzErr); + if( rc ){ + sqlite3_free(pNew); + *ppVtab = 0; + } + pNew->pAux = pAux; + pNew->ppPrev = &pAux->pAllVtab; + pNew->pNext = pAux->pAllVtab; + if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext; + pAux->pAllVtab = pNew; + return rc; +} + +static int vtshimConnect( + sqlite3 *db, + void *ppAux, + int argc, + const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + vtshim_aux *pAux = (vtshim_aux*)ppAux; + vtshim_vtab *pNew; + int rc; + + assert( db==pAux->db ); + if( pAux->bDisposed ){ + if( pzErr ){ + *pzErr = sqlite3_mprintf("virtual table was disposed: \"%s\"", + pAux->zName); + } + return SQLITE_ERROR; + } + pNew = sqlite3_malloc( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + rc = pAux->pMod->xConnect(db, pAux->pChildAux, argc, argv, + &pNew->pChild, pzErr); + if( rc ){ + sqlite3_free(pNew); + *ppVtab = 0; + } + pNew->pAux = pAux; + pNew->ppPrev = &pAux->pAllVtab; + pNew->pNext = pAux->pAllVtab; + if( pAux->pAllVtab ) pAux->pAllVtab->ppPrev = &pNew->pNext; + pAux->pAllVtab = pNew; + return rc; +} + +static int vtshimBestIndex( + sqlite3_vtab *pBase, + sqlite3_index_info *pIdxInfo +){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xBestIndex(pVtab->pChild, pIdxInfo); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimDisconnect(sqlite3_vtab *pBase){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc = SQLITE_OK; + if( !pAux->bDisposed ){ + rc = pAux->pMod->xDisconnect(pVtab->pChild); + } + if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev; + *pVtab->ppPrev = pVtab->pNext; + sqlite3_free(pVtab); + return rc; +} + +static int vtshimDestroy(sqlite3_vtab *pBase){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc = SQLITE_OK; + if( !pAux->bDisposed ){ + rc = pAux->pMod->xDestroy(pVtab->pChild); + } + if( pVtab->pNext ) pVtab->pNext->ppPrev = pVtab->ppPrev; + *pVtab->ppPrev = pVtab->pNext; + sqlite3_free(pVtab); + return rc; +} + +static int vtshimOpen(sqlite3_vtab *pBase, sqlite3_vtab_cursor **ppCursor){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + vtshim_cursor *pCur; + int rc; + *ppCursor = 0; + if( pAux->bDisposed ) return SQLITE_ERROR; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + rc = pAux->pMod->xOpen(pVtab->pChild, &pCur->pChild); + if( rc ){ + sqlite3_free(pCur); + VTSHIM_COPY_ERRMSG(); + return rc; + } + pCur->pChild->pVtab = pVtab->pChild; + *ppCursor = &pCur->base; + pCur->ppPrev = &pVtab->pAllCur; + if( pVtab->pAllCur ) pVtab->pAllCur->ppPrev = &pCur->pNext; + pCur->pNext = pVtab->pAllCur; + pVtab->pAllCur = pCur; + return SQLITE_OK; +} + +static int vtshimClose(sqlite3_vtab_cursor *pX){ + vtshim_cursor *pCur = (vtshim_cursor*)pX; + vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab; + vtshim_aux *pAux = pVtab->pAux; + int rc = SQLITE_OK; + if( !pAux->bDisposed ){ + rc = pAux->pMod->xClose(pCur->pChild); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + } + if( pCur->pNext ) pCur->pNext->ppPrev = pCur->ppPrev; + *pCur->ppPrev = pCur->pNext; + sqlite3_free(pCur); + return rc; +} + +static int vtshimFilter( + sqlite3_vtab_cursor *pX, + int idxNum, + const char *idxStr, + int argc, + sqlite3_value **argv +){ + vtshim_cursor *pCur = (vtshim_cursor*)pX; + vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xFilter(pCur->pChild, idxNum, idxStr, argc, argv); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimNext(sqlite3_vtab_cursor *pX){ + vtshim_cursor *pCur = (vtshim_cursor*)pX; + vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xNext(pCur->pChild); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimEof(sqlite3_vtab_cursor *pX){ + vtshim_cursor *pCur = (vtshim_cursor*)pX; + vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return 1; + rc = pAux->pMod->xEof(pCur->pChild); + VTSHIM_COPY_ERRMSG(); + return rc; +} + +static int vtshimColumn(sqlite3_vtab_cursor *pX, sqlite3_context *ctx, int i){ + vtshim_cursor *pCur = (vtshim_cursor*)pX; + vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xColumn(pCur->pChild, ctx, i); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimRowid(sqlite3_vtab_cursor *pX, sqlite3_int64 *pRowid){ + vtshim_cursor *pCur = (vtshim_cursor*)pX; + vtshim_vtab *pVtab = (vtshim_vtab*)pCur->base.pVtab; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xRowid(pCur->pChild, pRowid); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimUpdate( + sqlite3_vtab *pBase, + int argc, + sqlite3_value **argv, + sqlite3_int64 *pRowid +){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xUpdate(pVtab->pChild, argc, argv, pRowid); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimBegin(sqlite3_vtab *pBase){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xBegin(pVtab->pChild); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimSync(sqlite3_vtab *pBase){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xSync(pVtab->pChild); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimCommit(sqlite3_vtab *pBase){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xCommit(pVtab->pChild); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimRollback(sqlite3_vtab *pBase){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xRollback(pVtab->pChild); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimFindFunction( + sqlite3_vtab *pBase, + int nArg, + const char *zName, + void (**pxFunc)(sqlite3_context*,int,sqlite3_value**), + void **ppArg +){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return 0; + rc = pAux->pMod->xFindFunction(pVtab->pChild, nArg, zName, pxFunc, ppArg); + VTSHIM_COPY_ERRMSG(); + return rc; +} + +static int vtshimRename(sqlite3_vtab *pBase, const char *zNewName){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xRename(pVtab->pChild, zNewName); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimSavepoint(sqlite3_vtab *pBase, int n){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xSavepoint(pVtab->pChild, n); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimRelease(sqlite3_vtab *pBase, int n){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xRelease(pVtab->pChild, n); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +static int vtshimRollbackTo(sqlite3_vtab *pBase, int n){ + vtshim_vtab *pVtab = (vtshim_vtab*)pBase; + vtshim_aux *pAux = pVtab->pAux; + int rc; + if( pAux->bDisposed ) return SQLITE_ERROR; + rc = pAux->pMod->xRollbackTo(pVtab->pChild, n); + if( rc!=SQLITE_OK ){ + VTSHIM_COPY_ERRMSG(); + } + return rc; +} + +/* The destructor function for a disposible module */ +static void vtshimAuxDestructor(void *pXAux){ + vtshim_aux *pAux = (vtshim_aux*)pXAux; + assert( pAux->pAllVtab==0 ); + if( !pAux->bDisposed && pAux->xChildDestroy ){ + pAux->xChildDestroy(pAux->pChildAux); + } + sqlite3_free(pAux->zName); + sqlite3_free(pAux->pMod); + sqlite3_free(pAux); +} + +static int vtshimCopyModule( + const sqlite3_module *pMod, /* Source module to be copied */ + sqlite3_module **ppMod /* Destination for copied module */ +){ + sqlite3_module *p; + if( !pMod || !ppMod ) return SQLITE_ERROR; + p = sqlite3_malloc( sizeof(*p) ); + if( p==0 ) return SQLITE_NOMEM; + memcpy(p, pMod, sizeof(*p)); + *ppMod = p; + return SQLITE_OK; +} + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void *sqlite3_create_disposable_module( + sqlite3 *db, /* SQLite connection to register module with */ + const char *zName, /* Name of the module */ + const sqlite3_module *p, /* Methods for the module */ + void *pClientData, /* Client data for xCreate/xConnect */ + void(*xDestroy)(void*) /* Module destructor function */ +){ + vtshim_aux *pAux; + sqlite3_module *pMod; + int rc; + pAux = sqlite3_malloc( sizeof(*pAux) ); + if( pAux==0 ){ + if( xDestroy ) xDestroy(pClientData); + return 0; + } + rc = vtshimCopyModule(p, &pMod); + if( rc!=SQLITE_OK ){ + sqlite3_free(pAux); + return 0; + } + pAux->pChildAux = pClientData; + pAux->xChildDestroy = xDestroy; + pAux->pMod = pMod; + pAux->db = db; + pAux->zName = sqlite3_mprintf("%s", zName); + pAux->bDisposed = 0; + pAux->pAllVtab = 0; + pAux->sSelf.iVersion = p->iVersion<=2 ? p->iVersion : 2; + pAux->sSelf.xCreate = p->xCreate ? vtshimCreate : 0; + pAux->sSelf.xConnect = p->xConnect ? vtshimConnect : 0; + pAux->sSelf.xBestIndex = p->xBestIndex ? vtshimBestIndex : 0; + pAux->sSelf.xDisconnect = p->xDisconnect ? vtshimDisconnect : 0; + pAux->sSelf.xDestroy = p->xDestroy ? vtshimDestroy : 0; + pAux->sSelf.xOpen = p->xOpen ? vtshimOpen : 0; + pAux->sSelf.xClose = p->xClose ? vtshimClose : 0; + pAux->sSelf.xFilter = p->xFilter ? vtshimFilter : 0; + pAux->sSelf.xNext = p->xNext ? vtshimNext : 0; + pAux->sSelf.xEof = p->xEof ? vtshimEof : 0; + pAux->sSelf.xColumn = p->xColumn ? vtshimColumn : 0; + pAux->sSelf.xRowid = p->xRowid ? vtshimRowid : 0; + pAux->sSelf.xUpdate = p->xUpdate ? vtshimUpdate : 0; + pAux->sSelf.xBegin = p->xBegin ? vtshimBegin : 0; + pAux->sSelf.xSync = p->xSync ? vtshimSync : 0; + pAux->sSelf.xCommit = p->xCommit ? vtshimCommit : 0; + pAux->sSelf.xRollback = p->xRollback ? vtshimRollback : 0; + pAux->sSelf.xFindFunction = p->xFindFunction ? vtshimFindFunction : 0; + pAux->sSelf.xRename = p->xRename ? vtshimRename : 0; + if( p->iVersion>=2 ){ + pAux->sSelf.xSavepoint = p->xSavepoint ? vtshimSavepoint : 0; + pAux->sSelf.xRelease = p->xRelease ? vtshimRelease : 0; + pAux->sSelf.xRollbackTo = p->xRollbackTo ? vtshimRollbackTo : 0; + }else{ + pAux->sSelf.xSavepoint = 0; + pAux->sSelf.xRelease = 0; + pAux->sSelf.xRollbackTo = 0; + } + rc = sqlite3_create_module_v2(db, zName, &pAux->sSelf, + pAux, vtshimAuxDestructor); + return rc==SQLITE_OK ? (void*)pAux : 0; +} + +#ifdef _WIN32 +__declspec(dllexport) +#endif +void sqlite3_dispose_module(void *pX){ + vtshim_aux *pAux = (vtshim_aux*)pX; + if( !pAux->bDisposed ){ + vtshim_vtab *pVtab; + vtshim_cursor *pCur; + for(pVtab=pAux->pAllVtab; pVtab; pVtab=pVtab->pNext){ + for(pCur=pVtab->pAllCur; pCur; pCur=pCur->pNext){ + pAux->pMod->xClose(pCur->pChild); + } + pAux->pMod->xDisconnect(pVtab->pChild); + } + pAux->bDisposed = 1; + if( pAux->xChildDestroy ) pAux->xChildDestroy(pAux->pChildAux); + } +} + + +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_vtshim_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + SQLITE_EXTENSION_INIT2(pApi); + return SQLITE_OK; +} diff --git a/ext/rtree/rtree.c b/ext/rtree/rtree.c index 16a316f400..815a8993e4 100644 --- a/ext/rtree/rtree.c +++ b/ext/rtree/rtree.c @@ -3350,7 +3350,10 @@ int sqlite3_rtree_geometry_callback( } #if !SQLITE_CORE -int sqlite3_extension_init( +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_rtree_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi diff --git a/manifest b/manifest index 05a751b481..66bca82b2d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sbug\spreventing\ssome\sFK\sconstraint\schecking\sfrom\sbeing\sdeferred\suntil\sthe\send\sof\schangeset\sapplication. -D 2013-07-04T15:22:53.953 +C Pull\sin\sall\sthe\slatest\schanges\sfrom\strunk. +D 2013-07-09T13:05:49.248 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in aff38bc64c582dd147f18739532198372587b0f0 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -51,36 +51,36 @@ F ext/async/sqlite3async.h f489b080af7e72aec0e1ee6f1d98ab6cf2e4dcef F ext/fts1/README.txt 20ac73b006a70bcfd80069bdaf59214b6cf1db5e F ext/fts1/ft_hash.c 3927bd880e65329bdc6f506555b228b28924921b F ext/fts1/ft_hash.h 06df7bba40dadd19597aa400a875dbc2fed705ea -F ext/fts1/fts1.c 3e7b253e61aab0bb1fea808c7a0ce36c19432acc +F ext/fts1/fts1.c f7739dc37500a613cc0dab8fc04d1b5577d02998 F ext/fts1/fts1.h 6060b8f62c1d925ea8356cb1a6598073eb9159a6 F ext/fts1/fts1_hash.c 3196cee866edbebb1c0521e21672e6d599965114 F ext/fts1/fts1_hash.h e7f0d761353996a8175eda351104acfde23afcb0 F ext/fts1/fts1_porter.c b1c7304b8988ba3f764a147cdd32043b4913ea7b F ext/fts1/fts1_tokenizer.h fdea722c38a9f82ed921642981234f666e47919c F ext/fts1/fts1_tokenizer1.c fd00d1fe4dc30dfc5c64cba695ce34f4af20d2fa -F ext/fts1/fulltext.c d935e600d87bc86b7d64f55c7520ea41d6034c5c +F ext/fts1/fulltext.c 37698e1909584f6d8ea67d1485e3ad39dbf42d19 F ext/fts1/fulltext.h 08525a47852d1d62a0be81d3fc3fe2d23b094efd F ext/fts1/simple_tokenizer.c 1844d72f7194c3fd3d7e4173053911bf0661b70d F ext/fts1/tokenizer.h 0c53421b832366d20d720d21ea3e1f6e66a36ef9 F ext/fts2/README.tokenizers 21e3684ea5a095b55d70f6878b4ce6af5932dfb7 F ext/fts2/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts2/fts2.c b48cc0bb657c0a421f4067b79aa0354bd16a046d +F ext/fts2/fts2.c 72c816a9ae448049fbbe8f18a85698765fc7956c F ext/fts2/fts2.h da5f76c65163301d1068a971fd32f4119e3c95fa -F ext/fts2/fts2_hash.c 2689e42e1107ea67207f725cf69cf8972d00cf93 +F ext/fts2/fts2_hash.c 011a1d32de45bb1b519a1fd0048e857d6a843558 F ext/fts2/fts2_hash.h 1824b99dfd8d0225facbdb26a2c87289b2e7dcf8 F ext/fts2/fts2_icu.c 51c5cd3c04954badd329fa738c95fcdb717b5188 -F ext/fts2/fts2_porter.c 747056987951f743e955c8479f1df21a565720fe -F ext/fts2/fts2_tokenizer.c a86d08c9634fabfa237c8f379008de2e11248d36 +F ext/fts2/fts2_porter.c 2cd4a507bf3c3085fe66f59b0f2a325f65aaacf5 +F ext/fts2/fts2_tokenizer.c 3dbe8058e97afb55fff3ea844120ce3208b114cc F ext/fts2/fts2_tokenizer.h 27a1a99ca2d615cf7e142839b8d79e8751b4529e -F ext/fts2/fts2_tokenizer1.c 0123d21078e053bd98fd6186c5c6dc6d67969f2e +F ext/fts2/fts2_tokenizer1.c 07e223eecb483d448313b5f1553a4f299a7fb7a1 F ext/fts2/mkfts2amal.tcl 974d5d438cb3f7c4a652639262f82418c1e4cff0 F ext/fts3/README.content fdc666a70d5257a64fee209f97cf89e0e6e32b51 F ext/fts3/README.syntax a19711dc5458c20734b8e485e75fb1981ec2427a F ext/fts3/README.tokenizers e0a8b81383ea60d0334d274fadf305ea14a8c314 F ext/fts3/README.txt 8c18f41574404623b76917b9da66fcb0ab38328d -F ext/fts3/fts3.c 6dbb5c424144465782d5bf0d23be89907c972454 +F ext/fts3/fts3.c 0d6311cd433ea30c9e941b93bfeac2f9e6937980 F ext/fts3/fts3.h 3a10a0af180d502cecc50df77b1b22df142817fe -F ext/fts3/fts3Int.h a50cd231e906da818f00f0a81845bbf7bbeba002 +F ext/fts3/fts3Int.h c7a451661c2d9b2440b2008c3f63ce06f13181d6 F ext/fts3/fts3_aux.c b02632f6dd0e375ce97870206d914ea6d8df5ccd F ext/fts3/fts3_expr.c f8eb1046063ba342c7114eba175cabb31c4a64e7 F ext/fts3/fts3_hash.c 8dd2d06b66c72c628c2732555a32bc0943114914 @@ -104,20 +104,21 @@ F ext/fts3/unicode/CaseFolding.txt 8c678ca52ecc95e16bc7afc2dbf6fc9ffa05db8c F ext/fts3/unicode/UnicodeData.txt cd07314edb62d49fde34debdaf92fa2aa69011e7 F ext/fts3/unicode/mkunicode.tcl dc6f268eb526710e2c6e496c372471d773d0c368 F ext/icu/README.txt d9fbbad0c2f647c3fdf715fc9fd64af53aedfc43 -F ext/icu/icu.c 7538f98eab2854cf17fa5f7797bffa6c76e3863b +F ext/icu/icu.c d415ccf984defeb9df2c0e1afcfaa2f6dc05eacb F ext/icu/sqliteicu.h 728867a802baa5a96de7495e9689a8e01715ef37 F ext/misc/amatch.c eae8454cd9dcb287b2a3ec2e65a865a4ac5f0d06 F ext/misc/closure.c 997c20ddf35f85ab399f4a02a557a9baa822ec32 F ext/misc/fuzzer.c 136533c53cfce0957f0b48fa11dba27e21c5c01d -F ext/misc/ieee754.c 2565ce373d842977efe0922dc50b8a41b3289556 -F ext/misc/nextchar.c 1131e2b36116ffc6fe6b2e3464bfdace27978b1e -F ext/misc/percentile.c 4fb5e46c4312b0be74e8e497ac18f805f0e3e6c5 +F ext/misc/ieee754.c b0362167289170627659e84173f5d2e8fee8566e +F ext/misc/nextchar.c 80ba262d23238efcfcb3d72d71aa4513098e26a6 +F ext/misc/percentile.c bcbee3c061b884eccb80e21651daaae8e1e43c63 F ext/misc/regexp.c c25c65fe775f5d9801fb8573e36ebe73f2c0c2e0 F ext/misc/rot13.c 1ac6f95f99b575907b9b09c81a349114cf9be45a F ext/misc/spellfix.c 6d7ce6105a4b7729f6c44ccdf1ab7e80d9707c02 +F ext/misc/vtshim.c 5fb6be7fe37659a8cbd1e16982d74cceacbc4543 F ext/misc/wholenumber.c 784b12543d60702ebdd47da936e278aa03076212 F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/rtree.c 757abea591d4ff67c0ff4e8f9776aeda86b18c14 +F ext/rtree/rtree.c db516d7e59a14c92df10b552789509f2b632df3a F ext/rtree/rtree.h 834dbcb82dc85b2481cde6a07cdadfddc99e9b9e F ext/rtree/rtree1.test cf679265ecafff494a768ac9c2f43a70915a6290 F ext/rtree/rtree2.test acbb3a4ce0f4fbc2c304d2b4b784cfa161856bba @@ -154,7 +155,7 @@ F magic.txt f2b23a6bde8f1c6e86b957e4d94eab0add520b0d F main.mk f045701c66fec66208bc35d79de372340916e81e F mkdll.sh 7d09b23c05d56532e9d44a50868eb4b12ff4f74a F mkextu.sh 416f9b7089d80e5590a29692c9d9280a10dbad9f -F mkextw.sh 4123480947681d9b434a5e7b1ee08135abe409ac +F mkextw.sh d2a981497b404d6498f5ff3e3b1f3816bdfcb338 F mkopcodec.awk f6fccee29e68493bfd90a2e0466ede5fa94dd2fc F mkopcodeh.awk 29b84656502eee5f444c3147f331ee686956ab0e F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 @@ -175,7 +176,7 @@ F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 F src/backup.c 43b348822db3e4cef48b2ae5a445fbeb6c73a165 F src/bitvec.c 19a4ba637bd85f8f63fc8c9bae5ade9fb05ec1cb F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c 7fba377c29573adfc6091832e27ee1fcbefb51d0 +F src/btree.c 3f7bbfd72efb1cbf6a49515c376a031767ec930a F src/btree.h 6fa8a3ff2483d0bb64a9f0105a8cedeac9e00cca F src/btreeInt.h eecc84f02375b2bb7a44abbcbbe3747dde73edb2 F src/build.c 42239cfd95533e4aacf4d58b4724c8f858de5ced @@ -197,7 +198,7 @@ F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b F src/loadext.c c48f7f3f170e502fe0cc20748e03c6e0b5a016c2 -F src/main.c 893986530b7ea4607643675babf08888cb63e48e +F src/main.c a27560235a8e0e3f1a94aaca30189431bf61e776 F src/malloc.c fe085aa851b666b7c375c1ff957643dc20a04bf6 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c 437c7c4af964895d4650f29881df63535caaa1fa @@ -216,7 +217,7 @@ F src/os.h 4a46270a64e9193af4a0aaa3bc2c66dc07c29b3f F src/os_common.h 92815ed65f805560b66166e3583470ff94478f04 F src/os_unix.c 9eafa5458cf2ff684ddccff82c9bb113c7cad847 F src/os_win.c 074cb2b9bca6a1c2bd72acf04666cdc554bfaa9b -F src/pager.c 79df56da9dd49aceaa4cac207484a9a82cba40ae +F src/pager.c 5d2f7475260a8588f9c441bb309d2b7eaa7ded3b F src/pager.h 5cb78b8e1adfd5451e600be7719f5a99d87ac3b1 F src/parse.y 9acfcc83ddbf0cf82f0ed9582ccf0ad6c366ff37 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346 @@ -224,21 +225,21 @@ F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222 F src/pcache1.c d23d07716de96c7c0c2503ec5051a4384c3fb938 F src/pragma.c 057f5b1343c9a79e3e6c0c542a3a08b85849ee61 F src/prepare.c 2306be166bbeddf454e18bf8b21dba8388d05328 -F src/printf.c bff529ed47657098c55c9910b9c69b1b3b1a1353 +F src/printf.c 41c49dac366a3a411190001a8ab495fa8887974e F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50 F src/resolve.c 89f9003e8316ee3a172795459efc2a0274e1d5a8 F src/rowset.c 64655f1a627c9c212d9ab497899e7424a34222e0 F src/select.c 91b62654caf8dfe292fb8882715e575d34ad3874 -F src/shell.c a02544af6697c5782d29ec3204616f35ed9e8458 -F src/sqlite.h.in 0693f95792b64cca4d1780c082d7b96fd32aa1c3 +F src/shell.c c8cd06e6b66250a3ea0149c4edec30de14f57b6f +F src/sqlite.h.in fb8adf7852fb92e410de422b5569923327bf8a2c F src/sqlite3.rc fea433eb0a59f4c9393c8e6d76a6e2596b1fe0c0 -F src/sqlite3ext.h d936f797812c28b81b26ed18345baf8db28a21a5 -F src/sqliteInt.h 5a005fde923b3755fa3184e60028c582a8efe01d +F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc +F src/sqliteInt.h a83b0cef30022c46a19e6ace1f668b7833935eed F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d F src/status.c bedc37ec1a6bb9399944024d63f4c769971955a9 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e F src/tclsqlite.c e0eaf3a78eca2ef650abb67b6571cc86abcb5f87 -F src/test1.c 06bd01f7795bbef4aaf59d3b9fe5b3131a6ef642 +F src/test1.c 870fc648a48cb6d6808393174f7ebe82b8c840fa F src/test2.c 7355101c085304b90024f2261e056cdff13c6c35 F src/test3.c 1c0e5d6f080b8e33c1ce8b3078e7013fdbcd560c F src/test4.c 9b32d22f5f150abe23c1830e2057c4037c45b3df @@ -272,7 +273,7 @@ F src/test_pcache.c a5cd24730cb43c5b18629043314548c9169abb00 F src/test_quota.c 30c64f0ef84734f2231a686df41ed882b0c59bc0 F src/test_quota.h 8761e463b25e75ebc078bd67d70e39b9c817a0cb F src/test_rtree.c 1d764c352b5348bb2869ff5f54aff8eadcb96041 -F src/test_schema.c 8c06ef9ddb240c7a0fcd31bc221a6a2aade58bf0 +F src/test_schema.c cd12a2223c3a394f4d07bb93bdf6d344c5c121b6 F src/test_server.c 2f99eb2837dfa06a4aacf24af24c6affdf66a84f F src/test_sqllog.c c1c1bbedbcaf82b93d83e4f9dd990e62476a680e F src/test_stat.c d1569c7a4839f13e80187e2c26b2ab4da2d03935 @@ -280,29 +281,29 @@ F src/test_superlock.c 2b97936ca127d13962c3605dbc9a4ef269c424cd F src/test_syscall.c 16dbe79fb320fadb5acd7a0a59f49e52ab2d2091 F src/test_tclvar.c f4dc67d5f780707210d6bb0eb6016a431c04c7fa F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb -F src/test_vfs.c 8e6087a8b3dcc260282074b0efba14b76311120c +F src/test_vfs.c 12d9931f65acde64961523b6f420ba7cd057fbd7 F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 -F src/tokenize.c 1e86210d3976717a19238ea7b047fac481fe8c12 +F src/tokenize.c e0e8fd3cb90a88451f6b6425726c84747b6b20d7 F src/trigger.c 5c0ea9b8755e7c5e1a700f3e27ac4f8d92dd221e F src/update.c 19daebf6a0a67af5524913e93498d08388792128 F src/utf.c 8d819e2e5104a430fc2005f018db14347c95a38f F src/util.c f566b5138099a2df8533b190d0dcc74b7dfbe0c9 -F src/vacuum.c ddf21cc9577c4cb459d08bee9863a78ec000c5bb -F src/vdbe.c e1782e46404dd5aeb26d49e2180be6efcb6a2334 +F src/vacuum.c d9c5759f4c5a438bb43c2086f72c5d2edabc36c8 +F src/vdbe.c 7e1654d4ac01f017aad8088a1225e514b2aef5cf F src/vdbe.h 1223e2548e0970cf96f573ff6b99f804a36ad683 -F src/vdbeInt.h 1ca0f9ae9e9c28823647749edb767ea9ef2176d1 -F src/vdbeapi.c c45805f7acd2a07444b3d3b63853eb96545ec5f0 -F src/vdbeaux.c 2e82e249a0b72e9c2b63d16ec7801a966ff6a182 +F src/vdbeInt.h 11feb11eb49d8b312741011d30d91c9c50b59de0 +F src/vdbeapi.c bb28ee14bae43579b33d88e0d916a1657255a866 +F src/vdbeaux.c 84f5fb7cb2f62fd8b8a37b96ac929221cc77d317 F src/vdbeblob.c 1268e0bcb8e21fa32520b0fc376e1bcdfaa0c642 F src/vdbemem.c 833005f1cbbf447289f1973dba2a0c2228c7b8ab F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017 -F src/vdbetrace.c 18cc59cb475e6115129bfde224367d13a35a7d13 +F src/vdbetrace.c e7ec40e1999ff3c6414424365d5941178966dcbc F src/vtab.c b05e5f1f4902461ba9f5fc49bb7eb7c3a0741a83 -F src/wal.c 436bfceb141b9423c45119e68e444358ee0ed35d +F src/wal.c 7dc3966ef98b74422267e7e6e46e07ff6c6eb1b4 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 4fa43583d0a84b48f93b1e88f11adf2065be4e73 -F src/where.c 9bcfcb4ec6a14dd0111bf287bee02be88d5709f9 +F src/where.c f5201334501cd23a39315cab479c0dcce0990701 F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/aggerror.test a867e273ef9e3d7919f03ef4f0e8c0d2767944f2 F test/aggnested.test 45c0201e28045ad38a530b5a144b73cd4aa2cfd6 @@ -335,7 +336,7 @@ F test/auth.test 4a4c3b034fff7750513520defa910f376c96ab49 F test/auth2.test a2a371aa6df15f8b0c8109b33d3d7f0f73e4c9aa F test/auth3.test a4755e6a2a2fea547ffe63c874eb569e60a28eb5 F test/autoinc.test bd30d372d00045252f6c2e41b5f41455e1975acf -F test/autoindex1.test 314f12f87667861ac965c41587f9df82c42fff65 +F test/autoindex1.test d4dfe14001dfcb74cfbd7107f45a79fc1ab6183e F test/autovacuum.test 9f22a7733f39c56ef6a5665d10145ac25d8cb574 F test/autovacuum_ioerr2.test 8a367b224183ad801e0e24dcb7d1501f45f244b4 F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 @@ -360,7 +361,7 @@ F test/boundary1.tcl 6421b2d920d8b09539503a8673339d32f7609eb1 F test/boundary1.test 66d7f4706ccdb42d58eafdb081de07b0eb42d77b F test/boundary2.tcl e34ef4e930cf1083150d4d2c603e146bd3b76bcb F test/boundary2.test 9ae758d7dab7e882c8b6cc4a6a10278385bff8fa -F test/boundary3.tcl 8901d6a503d0bf64251dd81cc74e5ad3add4b119 +F test/boundary3.tcl 23361e108a125dca9c4080c2feb884fe54d69243 F test/boundary3.test 56ef82096b4329aca2be74fa1e2b0f762ea0eb45 F test/boundary4.tcl 0bb4b1a94f4fc5ae59b79b9a2b7a140c405e2983 F test/boundary4.test 89e02fa66397b8a325d5eb102b5806f961f8ec4b @@ -371,7 +372,7 @@ F test/capi2.test e8b18cc61090b6e5e388f54d6b125d711d1b265a F test/capi3.test 56ab450125ead38846cbae7e5b6a216686c3cffa F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4 F test/capi3c.test 93d24621c9ff84da9da060f30431e0453db1cdb0 -F test/capi3d.test 17b57ca28be3e37e14c2ba8f787d292d84b724a1 +F test/capi3d.test 6d0fc0a86d73f42dd19a7d8b7761ab9bc02277d0 F test/capi3e.test ad90088b18b0367125ff2d4b5400153fd2f99aab F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3 F test/check.test 2eb93611139a7dfaed3be80067c7dc5ceb5fb287 @@ -438,7 +439,7 @@ F test/e_createtable.test ddf3b2e4506e0813f46b69ccf55757c5570cc181 F test/e_delete.test 89aa84d3d1bd284a0689ede04bce10226a5aeaa5 F test/e_droptrigger.test afd5c4d27dec607f5997a66bf7e2498a082cb235 F test/e_dropview.test 583411e470458c5d76148542cfb5a5fa84c8f93e -F test/e_expr.test 5489424d3d9a452ac3701cdf4b680ae31a157894 +F test/e_expr.test 2a599f40f37ee9e853c4396c28ff13c2c50f6628 F test/e_fkey.test 17cfb40002d165299681f39aac0cb5890c359935 F test/e_fts3.test 5c02288842e4f941896fd44afdef564dd5fc1459 F test/e_insert.test d5331cc95e101af2508159fc98b6801631659ffe @@ -675,7 +676,7 @@ F test/manydb.test 28385ae2087967aa05c38624cec7d96ec74feb3e F test/mem5.test c6460fba403c5703141348cd90de1c294188c68f F test/memdb.test db5260330676de007be8530d6ecc7c9ab2b06ad3 F test/memleak.test 10b9c6c57e19fc68c32941495e9ba1c50123f6e2 -F test/memsubsys1.test a8f9e37567453a5d1d9d37ec102d4d88ab6be33f +F test/memsubsys1.test f97cfd0b30e85c2f1ed16d642e7ac58006be84b2 F test/memsubsys2.test 3a1c1a9de48e5726faa85108b02459fae8cb9ee9 F test/minmax.test 42fbad0e81afaa6e0de41c960329f2b2c3526efd F test/minmax2.test b44bae787fc7b227597b01b0ca5575c7cb54d3bc @@ -691,7 +692,8 @@ F test/misc7.test 50c02c35ef7924c246eb3d8d71dfbf90ba352f8f F test/misuse.test ba4fb5d1a6101d1c171ea38b3c613d0661c83054 F test/mmap1.test 93d167b328255cbe6679fe1e1a23be1b1197d07b F test/mmap2.test 9d6dd9ddb4ad2379f29cc78f38ce1e63ed418022 -F test/mmap3.test 01728252af6f9bcf708169d7b794b7597c69ac44 +F test/mmap3.test c92273e16eb8d23c1d55c9815b446bb72ef0512e +F test/mmapfault.test 97507ee06172df99057dbf1c40294eabd82cbb13 F test/multiplex.test e08cc7177bd6d85990ee1d71100bb6c684c02256 F test/multiplex2.test 580ca5817c7edbe4cc68fa150609c9473393003a F test/multiplex3.test d228f59eac91839a977eac19f21d053f03e4d101 @@ -719,9 +721,9 @@ F test/pagerfault2.test caf4c7facb914fd3b03a17b31ae2b180c8d6ca1f F test/pagerfault3.test 1003fcda009bf48a8e22a516e193b6ef0dd1bbd8 F test/pageropt.test 6b8f6a123a5572c195ad4ae40f2987007923bbd6 F test/pagesize.test 1dd51367e752e742f58e861e65ed7390603827a0 -F test/pcache.test 065aa286e722ab24f2e51792c1f093bf60656b16 +F test/pcache.test b09104b03160aca0d968d99e8cd2c5b1921a993d F test/pcache2.test a83efe2dec0d392f814bfc998def1d1833942025 -F test/percentile.test 4614301e38398df7fdd5f28f4ed8f272b328251b +F test/percentile.test b98fc868d71eb5619d42a1702e9ab91718cbed54 F test/permutations.test 742b8005bb3c782797a20beccdbe213ef52531fb F test/pragma.test 5e7de6c32a5d764f09437d2025f07e4917b9e178 F test/pragma2.test 3a55f82b954242c642f8342b17dffc8b47472947 @@ -767,7 +769,7 @@ F test/select5.test e758b8ef94f69b111df4cb819008856655dcd535 F test/select6.test e76bd10a56988f15726c097a5d5a7966fe82d3b2 F test/select7.test dad6f00f0d49728a879d6eb6451d4752db0b0abe F test/select8.test 391de11bdd52339c30580dabbbbe97e3e9a3c79d -F test/select9.test c0ca3cd87a8ebb04de2cb1402c77df55d911a0ea +F test/select9.test aebc2bb0c3bc44606125033cbcaac2c8d1f33a95 F test/selectA.test 99cf21df033b93033ea4f34aba14a500f48f04fe F test/selectB.test 954e4e49cf1f896d61794e440669e03a27ceea25 F test/selectC.test 871fb55d884d3de5943c4057ebd22c2459e71977 @@ -786,11 +788,11 @@ F test/shared9.test 5f2a8f79b4d6c7d107a01ffa1ed05ae7e6333e21 F test/sharedA.test 0cdf1a76dfa00e6beee66af5b534b1e8df2720f5 F test/shared_err.test 0079c05c97d88cfa03989b7c20a8b266983087aa F test/sharedlock.test 927a4b6da11978c82b857dbdb20a932aad732123 -F test/shell1.test 4a2f57952719972c6f862134463f8712e953c038 +F test/shell1.test 928547277d385038c696428e9d791cbbad098974 F test/shell2.test 037d6ad16e873354195d30bb2dc4b5321788154a F test/shell3.test 9196c42772d575685e722c92b4b39053c6ebba59 F test/shell4.test aa4eef8118b412d1a01477a53426ece169ea86a9 -F test/shell5.test fa2188bbb13fe2d183fd04a5f7b512650c35ef5d +F test/shell5.test 946e620a41b64f90d45dcf91c36e8d408d435cfd F test/shortread1.test bb591ef20f0fd9ed26d0d12e80eee6d7ac8897a3 F test/shrink.test 8c70f62b6e8eb4d54533de6d65bd06b1b9a17868 F test/sidedelete.test f0ad71abe6233e3b153100f3b8d679b19a488329 @@ -805,7 +807,7 @@ F test/speed3.test d32043614c08c53eafdc80f33191d5bd9b920523 F test/speed4.test abc0ad3399dcf9703abed2fff8705e4f8e416715 F test/speed4p.explain 6b5f104ebeb34a038b2f714150f51d01143e59aa F test/speed4p.test 0e51908951677de5a969b723e03a27a1c45db38b -F test/spellfix.test bea537caf587df30d430c2c6a8fe9f64b8712834 +F test/spellfix.test 38246facf7d9d7eeb8a57d7497cf7ce73ce5785d F test/sqllimits1.test b1aae27cc98eceb845e7f7adf918561256e31298 F test/stat.test be8d477306006ec696bc86757cfb34bec79447ce F test/stmt.test 25d64e3dbf9a3ce89558667d7f39d966fe2a71b9 @@ -861,6 +863,7 @@ F test/tkt-7bbfb7d442.test 7b2cd79c7a17ae6750e75ec1a7846712a69c9d18 F test/tkt-80ba201079.test 105a721e6aad0ae3c5946d7615d1e4d03f6145b8 F test/tkt-80e031a00f.test 9a154173461a4dbe2de49cda73963e04842d52f7 F test/tkt-8454a207b9.test c583a9f814a82a2b5ba95207f55001c9f0cd816c +F test/tkt-868145d012.test a5f941107ece6a64410ca4755c6329b7eb57a356 F test/tkt-91e2e8ba6f.test 08c4f94ae07696b05c9b822da0b4e5337a2f54c5 F test/tkt-94c04eaadb.test fa9c71192f7e2ea2d51bf078bc34e8da6088bf71 F test/tkt-9d68c883.test 458f7d82a523d7644b54b497c986378a7d8c8b67 @@ -971,7 +974,7 @@ F test/trace2.test e7a988fdd982cdec62f1f1f34b0360e6476d01a0 F test/trans.test 6e1b4c6a42dba31bd65f8fa5e61a2708e08ddde6 F test/trans2.test d5337e61de45e66b1fcbf9db833fa8c82e624b22 F test/trans3.test 373ac5183cc56be69f48ae44090e7f672939f732 -F test/transitive1.test d04aa9023e425d6f2d4aa61dd81ee9e102f89062 +F test/transitive1.test 0ee69546d6fa20e577a4a706d7daa01c7eba9239 F test/trigger1.test dc47573ac79ffe0ee3eecaa517d70d8dacbccd03 F test/trigger2.test 834187beafd1db383af0c659cfa49b0576832816 F test/trigger3.test aa640bb2bbb03edd5ff69c055117ea088f121945 @@ -1025,7 +1028,7 @@ F test/wal2.test d4b470f13c87f6d8268b004380afa04c3c67cb90 F test/wal3.test b22eb662bcbc148c5f6d956eaf94b047f7afe9c0 F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c F test/wal5.test 8f888b50f66b78821e61ed0e233ded5de378224b -F test/wal6.test 2e3bc767d9c2ce35c47106148d43fcbd072a93b3 +F test/wal6.test 527581f5527bf9c24394991e2be83000aace5f9e F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd F test/wal8.test 75c42e1bc4545c277fed212f8fc9b7723cd02216 F test/wal9.test 378e76a9ad09cd9bee06c172ad3547b0129a6750 @@ -1046,8 +1049,8 @@ F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417 F test/walslow.test e7be6d9888f83aa5d3d3c7c08aa9b5c28b93609a F test/walthread.test de8dbaf6d9e41481c460ba31ca61e163d7348f8e F test/where.test da54153a4c1571ea1b95659e5bec8119edf786aa -F test/where2.test dcf0ffafe0de55051c1373835a5a57aee6b50094 -F test/where3.test 157071521ceabc06bfd4d37106e4270a8956364d +F test/where2.test d712de0ea9a2c3de7b34b0b1e75172556fef5b24 +F test/where3.test a0682ba3dc8c8f46ffcc95a3d9f58c4327fc129f F test/where4.test e9b9e2f2f98f00379e6031db6a6fca29bae782a2 F test/where5.test fdf66f96d29a064b63eb543e28da4dfdccd81ad2 F test/where6.test 5da5a98cec820d488e82708301b96cb8c18a258b @@ -1062,6 +1065,7 @@ F test/whereD.test 6c2feb79ef1f68381b07f39017fe5f9b96da8d62 F test/whereE.test b3a055eef928c992b0a33198a7b8dc10eea5ad2f F test/whereF.test 136a7301512d72a08a272806c8767066311b7bc1 F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31 +F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688 F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd @@ -1111,7 +1115,7 @@ F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/wherecosttest.c f407dc4c79786982a475261866a161cd007947ae F tool/win/sqlite.vsix 97894c2790eda7b5bce3cc79cb2a8ec2fde9b3ac -P 1d44e5d3c2b1dc958442f9114a960b256e002ed3 -R 28f75ac347bd281672cb0a8d27d3f6b3 -U dan -Z 01296a7a6fdc241a613ea24758428ad2 +P 1452defb8cfcc489230314dd1e0425feba46c49d 1e39f85077f1f2b96c3a656c5b6334bafb005908 +R 996effd12b4e262519df6f6e538dae74 +U drh +Z 08707dac307041af534ddfd35863fca1 diff --git a/manifest.uuid b/manifest.uuid index 44d88b34c0..d864f435a3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1452defb8cfcc489230314dd1e0425feba46c49d \ No newline at end of file +af3ca4c6e557e6bc92584586b5a97d9be41b0b82 \ No newline at end of file diff --git a/mkextw.sh b/mkextw.sh index 2d1b6d1335..909a126c38 100644 --- a/mkextw.sh +++ b/mkextw.sh @@ -11,7 +11,7 @@ CMD="$CC -c fts2amal.c" echo $CMD $CMD echo 'EXPORTS' >fts2.def -echo 'sqlite3_extension_init' >>fts2.def +echo 'sqlite3_fts2_init' >>fts2.def i386-mingw32msvc-dllwrap \ --def fts2.def -v --export-all \ --driver-name i386-mingw32msvc-gcc \ diff --git a/src/btree.c b/src/btree.c index f6e564628f..9b78378791 100644 --- a/src/btree.c +++ b/src/btree.c @@ -3273,12 +3273,13 @@ int sqlite3BtreeCommitPhaseOne(Btree *p, const char *zMaster){ */ static void btreeEndTransaction(Btree *p){ BtShared *pBt = p->pBt; + sqlite3 *db = p->db; assert( sqlite3BtreeHoldsMutex(p) ); #ifndef SQLITE_OMIT_AUTOVACUUM pBt->bDoTruncate = 0; #endif - if( p->inTrans>TRANS_NONE && p->db->activeVdbeCnt>1 ){ + if( p->inTrans>TRANS_NONE && db->nVdbeRead>1 ){ /* If there are other active statements that belong to this database ** handle, downgrade to a read-only transaction. The other statements ** may still be reading from the database. */ diff --git a/src/main.c b/src/main.c index df158b9186..ad9422b486 100644 --- a/src/main.c +++ b/src/main.c @@ -1065,6 +1065,7 @@ const char *sqlite3ErrName(int rc){ case SQLITE_ABORT_ROLLBACK: zName = "SQLITE_ABORT_ROLLBACK"; break; case SQLITE_BUSY: zName = "SQLITE_BUSY"; break; case SQLITE_BUSY_RECOVERY: zName = "SQLITE_BUSY_RECOVERY"; break; + case SQLITE_BUSY_SNAPSHOT: zName = "SQLITE_BUSY_SNAPSHOT"; break; case SQLITE_LOCKED: zName = "SQLITE_LOCKED"; break; case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break; case SQLITE_NOMEM: zName = "SQLITE_NOMEM"; break; @@ -1138,6 +1139,7 @@ const char *sqlite3ErrName(int rc){ case SQLITE_NOTICE_RECOVER_ROLLBACK: zName = "SQLITE_NOTICE_RECOVER_ROLLBACK"; break; case SQLITE_WARNING: zName = "SQLITE_WARNING"; break; + case SQLITE_WARNING_AUTOINDEX: zName = "SQLITE_WARNING_AUTOINDEX"; break; case SQLITE_DONE: zName = "SQLITE_DONE"; break; } } @@ -1396,7 +1398,7 @@ int sqlite3CreateFunc( */ p = sqlite3FindFunction(db, zFunctionName, nName, nArg, (u8)enc, 0); if( p && p->iPrefEnc==enc && p->nArg==nArg ){ - if( db->activeVdbeCnt ){ + if( db->nVdbeActive ){ sqlite3Error(db, SQLITE_BUSY, "unable to delete/modify user-function due to active statements"); assert( !db->mallocFailed ); @@ -1998,7 +2000,7 @@ static int createCollation( */ pColl = sqlite3FindCollSeq(db, (u8)enc2, zName, 0); if( pColl && pColl->xCmp ){ - if( db->activeVdbeCnt ){ + if( db->nVdbeActive ){ sqlite3Error(db, SQLITE_BUSY, "unable to delete/modify collation sequence due to active statements"); return SQLITE_BUSY; @@ -2473,7 +2475,10 @@ static int openDatabase( db->nextAutovac = -1; db->szMmap = sqlite3GlobalConfig.szMmap; db->nextPagesize = 0; - db->flags |= SQLITE_ShortColNames | SQLITE_AutoIndex | SQLITE_EnableTrigger + db->flags |= SQLITE_ShortColNames | SQLITE_EnableTrigger +#if !defined(SQLITE_DEAULT_AUTOMATIC_INDEX) || SQLITE_DEFAULT_AUTOMATIC_INDEX + | SQLITE_AutoIndex +#endif #if SQLITE_DEFAULT_FILE_FORMAT<4 | SQLITE_LegacyFileFmt #endif diff --git a/src/pager.c b/src/pager.c index 645cc3d9a0..b208228968 100644 --- a/src/pager.c +++ b/src/pager.c @@ -1812,6 +1812,7 @@ static void pager_unlock(Pager *pPager){ pPager->changeCountDone = pPager->tempFile; pPager->eState = PAGER_OPEN; pPager->errCode = SQLITE_OK; + if( USEFETCH(pPager) ) sqlite3OsUnfetch(pPager->fd, 0, 0); } pPager->journalOff = 0; @@ -3378,10 +3379,10 @@ void sqlite3PagerSetCachesize(Pager *pPager, int mxPage){ static void pagerFixMaplimit(Pager *pPager){ #if SQLITE_MAX_MMAP_SIZE>0 sqlite3_file *fd = pPager->fd; - if( isOpen(fd) ){ + if( isOpen(fd) && fd->pMethods->iVersion>=3 ){ sqlite3_int64 sz; - pPager->bUseFetch = (fd->pMethods->iVersion>=3) && pPager->szMmap>0; sz = pPager->szMmap; + pPager->bUseFetch = (sz>0); sqlite3OsFileControlHint(pPager->fd, SQLITE_FCNTL_MMAP_SIZE, &sz); } #endif diff --git a/src/printf.c b/src/printf.c index 8d37d633b2..67649b269b 100644 --- a/src/printf.c +++ b/src/printf.c @@ -468,8 +468,8 @@ void sqlite3VXPrintf( }else{ e2 = exp; } - if( e2+precision+width > etBUFSIZE - 15 ){ - bufpt = zExtra = sqlite3Malloc( e2+precision+width+15 ); + if( MAX(e2,0)+precision+width > etBUFSIZE - 15 ){ + bufpt = zExtra = sqlite3Malloc( MAX(e2,0)+precision+width+15 ); if( bufpt==0 ){ pAccum->mallocFailed = 1; return; diff --git a/src/shell.c b/src/shell.c index 9a8a906944..79548fa1e4 100644 --- a/src/shell.c +++ b/src/shell.c @@ -67,7 +67,7 @@ #undef popen #define popen(a,b) _popen((a),(b)) #undef pclose -#define pclose(x) _pclose(x) +#define pclose _pclose #else /* Make sure isatty() has a prototype. */ @@ -1492,6 +1492,7 @@ static void open_db(struct callback_data *p){ ** \t -> tab ** \n -> newline ** \r -> carriage return +** \" -> " ** \NNN -> ascii character NNN in octal ** \\ -> backslash */ @@ -1507,6 +1508,8 @@ static void resolve_backslashes(char *z){ c = '\t'; }else if( c=='r' ){ c = '\r'; + }else if( c=='\\' ){ + c = '\\'; }else if( c>='0' && c<='7' ){ c -= '0'; if( z[i+1]>='0' && z[i+1]<='7' ){ @@ -1650,6 +1653,107 @@ static void test_breakpoint(void){ nCall++; } +/* +** An object used to read a CSV file +*/ +typedef struct CSVReader CSVReader; +struct CSVReader { + const char *zFile; /* Name of the input file */ + FILE *in; /* Read the CSV text from this input stream */ + char *z; /* Accumulated text for a field */ + int n; /* Number of bytes in z */ + int nAlloc; /* Space allocated for z[] */ + int nLine; /* Current line number */ + int cTerm; /* Character that terminated the most recent field */ + int cSeparator; /* The separator character. (Usually ",") */ +}; + +/* Append a single byte to z[] */ +static void csv_append_char(CSVReader *p, int c){ + if( p->n+1>=p->nAlloc ){ + p->nAlloc += p->nAlloc + 100; + p->z = sqlite3_realloc(p->z, p->nAlloc); + if( p->z==0 ){ + fprintf(stderr, "out of memory\n"); + exit(1); + } + } + p->z[p->n++] = (char)c; +} + +/* Read a single field of CSV text. Compatible with rfc4180 and extended +** with the option of having a separator other than ",". +** +** + Input comes from p->in. +** + Store results in p->z of length p->n. Space to hold p->z comes +** from sqlite3_malloc(). +** + Use p->cSep as the separator. The default is ",". +** + Keep track of the line number in p->nLine. +** + Store the character that terminates the field in p->cTerm. Store +** EOF on end-of-file. +** + Report syntax errors on stderr +*/ +static char *csv_read_one_field(CSVReader *p){ + int c, pc; + int cSep = p->cSeparator; + p->n = 0; + c = fgetc(p->in); + if( c==EOF || seenInterrupt ){ + p->cTerm = EOF; + return 0; + } + if( c=='"' ){ + int startLine = p->nLine; + int cQuote = c; + pc = 0; + while( 1 ){ + c = fgetc(p->in); + if( c=='\n' ) p->nLine++; + if( c==cQuote ){ + if( pc==cQuote ){ + pc = 0; + continue; + } + } + if( (c==cSep && pc==cQuote) + || (c=='\n' && pc==cQuote) + || (c=='\n' && pc=='\r' && p->n>2 && p->z[p->n-2]==cQuote) + || (c==EOF && pc==cQuote) + ){ + do{ p->n--; }while( p->z[p->n]!=cQuote ); + p->z[p->n] = 0; + p->cTerm = c; + break; + } + if( pc==cQuote && c!='\r' ){ + fprintf(stderr, "%s:%d: unescaped %c character\n", + p->zFile, p->nLine, cQuote); + } + if( c==EOF ){ + fprintf(stderr, "%s:%d: unterminated %c-quoted field\n", + p->zFile, startLine, cQuote); + p->z[p->n] = 0; + p->cTerm = EOF; + break; + } + csv_append_char(p, c); + pc = c; + } + }else{ + while( c!=EOF && c!=cSep && c!='\n' ){ + csv_append_char(p, c); + c = fgetc(p->in); + } + if( c=='\n' ){ + p->nLine++; + if( p->n>1 && p->z[p->n-1]=='\r' ) p->n--; + } + p->z[p->n] = 0; + p->cTerm = c; + } + return p->z; +} + /* ** If an input line begins with "." then invoke this routine to ** process that line. @@ -1671,7 +1775,10 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( zLine[i]=='\'' || zLine[i]=='"' ){ int delim = zLine[i++]; azArg[nArg++] = &zLine[i]; - while( zLine[i] && zLine[i]!=delim ){ i++; } + while( zLine[i] && zLine[i]!=delim ){ + if( zLine[i]=='\\' && delim=='"' && zLine[i+1]!=0 ) i++; + i++; + } if( zLine[i]==delim ){ zLine[i++] = 0; } @@ -1888,48 +1995,97 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( c=='i' && strncmp(azArg[0], "import", n)==0 && nArg==3 ){ char *zTable = azArg[2]; /* Insert data into this table */ - char *zFile = azArg[1]; /* The file from which to extract data */ + char *zFile = azArg[1]; /* Name of file to extra content from */ sqlite3_stmt *pStmt = NULL; /* A statement */ int nCol; /* Number of columns in the table */ int nByte; /* Number of bytes in an SQL string */ int i, j; /* Loop counters */ int nSep; /* Number of bytes in p->separator[] */ char *zSql; /* An SQL statement */ - char *zLine; /* A single line of input from the file */ - char **azCol; /* zLine[] broken up into columns */ - char *zCommit; /* How to commit changes */ - FILE *in; /* The input file */ - int lineno = 0; /* Line number of input file */ + CSVReader sCsv; /* Reader context */ + int (*xCloser)(FILE*); /* Procedure to close th3 connection */ + seenInterrupt = 0; + memset(&sCsv, 0, sizeof(sCsv)); open_db(p); nSep = strlen30(p->separator); if( nSep==0 ){ fprintf(stderr, "Error: non-null separator required for import\n"); return 1; } + if( nSep>1 ){ + fprintf(stderr, "Error: multi-character separators not allowed" + " for import\n"); + return 1; + } + sCsv.zFile = zFile; + sCsv.nLine = 1; + if( sCsv.zFile[0]=='|' ){ + sCsv.in = popen(sCsv.zFile+1, "r"); + sCsv.zFile = ""; + xCloser = pclose; + }else{ + sCsv.in = fopen(sCsv.zFile, "rb"); + xCloser = fclose; + } + if( sCsv.in==0 ){ + fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); + return 1; + } + sCsv.cSeparator = p->separator[0]; zSql = sqlite3_mprintf("SELECT * FROM %s", zTable); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); + xCloser(sCsv.in); return 1; } nByte = strlen30(zSql); rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); + if( rc && sqlite3_strglob("no such table: *", sqlite3_errmsg(db))==0 ){ + char *zCreate = sqlite3_mprintf("CREATE TABLE %s", zTable); + char cSep = '('; + while( csv_read_one_field(&sCsv) ){ + zCreate = sqlite3_mprintf("%z%c\n \"%s\" TEXT", zCreate, cSep, sCsv.z); + cSep = ','; + if( sCsv.cTerm!=sCsv.cSeparator ) break; + } + if( cSep=='(' ){ + sqlite3_free(zCreate); + sqlite3_free(sCsv.z); + xCloser(sCsv.in); + fprintf(stderr,"%s: empty file\n", sCsv.zFile); + return 1; + } + zCreate = sqlite3_mprintf("%z\n)", zCreate); + rc = sqlite3_exec(p->db, zCreate, 0, 0, 0); + sqlite3_free(zCreate); + if( rc ){ + fprintf(stderr, "CREATE TABLE %s(...) failed: %s\n", zTable, + sqlite3_errmsg(db)); + sqlite3_free(sCsv.z); + xCloser(sCsv.in); + return 1; + } + rc = sqlite3_prepare(p->db, zSql, -1, &pStmt, 0); + } sqlite3_free(zSql); if( rc ){ if (pStmt) sqlite3_finalize(pStmt); fprintf(stderr,"Error: %s\n", sqlite3_errmsg(db)); + xCloser(sCsv.in); return 1; } nCol = sqlite3_column_count(pStmt); sqlite3_finalize(pStmt); pStmt = 0; if( nCol==0 ) return 0; /* no columns, no error */ - zSql = malloc( nByte + 20 + nCol*2 ); + zSql = sqlite3_malloc( nByte*2 + 20 + nCol*2 ); if( zSql==0 ){ fprintf(stderr, "Error: out of memory\n"); + xCloser(sCsv.in); return 1; } - sqlite3_snprintf(nByte+20, zSql, "INSERT INTO %s VALUES(?", zTable); + sqlite3_snprintf(nByte+20, zSql, "INSERT INTO \"%w\" VALUES(?", zTable); j = strlen30(zSql); for(i=1; idb, zSql, -1, &pStmt, 0); - free(zSql); + sqlite3_free(zSql); if( rc ){ fprintf(stderr, "Error: %s\n", sqlite3_errmsg(db)); if (pStmt) sqlite3_finalize(pStmt); + xCloser(sCsv.in); return 1; } - in = fopen(zFile, "rb"); - if( in==0 ){ - fprintf(stderr, "Error: cannot open \"%s\"\n", zFile); - sqlite3_finalize(pStmt); - return 1; - } - azCol = malloc( sizeof(azCol[0])*(nCol+1) ); - if( azCol==0 ){ - fprintf(stderr, "Error: out of memory\n"); - fclose(in); - sqlite3_finalize(pStmt); - return 1; - } - sqlite3_exec(p->db, "BEGIN", 0, 0, 0); - zCommit = "COMMIT"; - while( (zLine = local_getline(0, in, 1))!=0 ){ - char *z, c; - int inQuote = 0; - lineno++; - azCol[0] = zLine; - for(i=0, z=zLine; (c = *z)!=0; z++){ - if( c=='"' ) inQuote = !inQuote; - if( c=='\n' ) lineno++; - if( !inQuote && c==p->separator[0] && strncmp(z,p->separator,nSep)==0 ){ - *z = 0; - i++; - if( i=nCol ){ + sqlite3_step(pStmt); + rc = sqlite3_reset(pStmt); + if( rc!=SQLITE_OK ){ + fprintf(stderr, "%s:%d: INSERT failed: %s\n", sCsv.zFile, startLine, + sqlite3_errmsg(db)); + } + } + }while( sCsv.cTerm!=EOF ); + + xCloser(sCsv.in); + sqlite3_free(sCsv.z); sqlite3_finalize(pStmt); - sqlite3_exec(p->db, zCommit, 0, 0, 0); + sqlite3_exec(p->db, "COMMIT", 0, 0, 0); }else if( c=='i' && strncmp(azArg[0], "indices", n)==0 && nArg<3 ){ @@ -2332,6 +2459,7 @@ static int do_meta_command(char *zLine, struct callback_data *p){ } }else +#ifdef SQLITE_DEBUG /* Undocumented commands for internal testing. Subject to change ** without notice. */ if( c=='s' && n>=10 && strncmp(azArg[0], "selftest-", 9)==0 ){ @@ -2345,11 +2473,14 @@ static int do_meta_command(char *zLine, struct callback_data *p){ if( strncmp(azArg[0]+9, "integer", n-9)==0 ){ int i; sqlite3_int64 v; for(i=1; iout, "%s: %lld 0x%llx\n", azArg[i], v, v); + sqlite3_snprintf(sizeof(zBuf), zBuf, "%s: %lld 0x%llx\n", azArg[i], v, v); + fprintf(p->out, "%s", zBuf); } } }else +#endif if( c=='s' && strncmp(azArg[0], "separator", n)==0 && nArg==2 ){ sqlite3_snprintf(sizeof(p->separator), p->separator, diff --git a/src/sqlite.h.in b/src/sqlite.h.in index f02e568f38..24ccb8d39d 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -475,6 +475,7 @@ int sqlite3_exec( #define SQLITE_IOERR_MMAP (SQLITE_IOERR | (24<<8)) #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) +#define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) #define SQLITE_CANTOPEN_NOTEMPDIR (SQLITE_CANTOPEN | (1<<8)) #define SQLITE_CANTOPEN_ISDIR (SQLITE_CANTOPEN | (2<<8)) #define SQLITE_CANTOPEN_FULLPATH (SQLITE_CANTOPEN | (3<<8)) @@ -494,6 +495,7 @@ int sqlite3_exec( #define SQLITE_CONSTRAINT_VTAB (SQLITE_CONSTRAINT | (9<<8)) #define SQLITE_NOTICE_RECOVER_WAL (SQLITE_NOTICE | (1<<8)) #define SQLITE_NOTICE_RECOVER_ROLLBACK (SQLITE_NOTICE | (2<<8)) +#define SQLITE_WARNING_AUTOINDEX (SQLITE_WARNING | (1<<8)) /* ** CAPI3REF: Flags For File Open Operations diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 928bb3bad9..ecf93f62f6 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -474,11 +474,14 @@ struct sqlite3_api_routines { ** extension */ # define SQLITE_EXTENSION_INIT1 const sqlite3_api_routines *sqlite3_api=0; # define SQLITE_EXTENSION_INIT2(v) sqlite3_api=v; +# define SQLITE_EXTENSION_INIT3 \ + extern const sqlite3_api_routines *sqlite3_api; #else /* This case when the file is being statically linked into the ** application */ # define SQLITE_EXTENSION_INIT1 /*no-op*/ # define SQLITE_EXTENSION_INIT2(v) (void)v; /* unused parameter */ +# define SQLITE_EXTENSION_INIT3 /*no-op*/ #endif #endif /* _SQLITE3EXT_H_ */ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index dd65c51d90..228d34fc59 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -898,9 +898,10 @@ struct sqlite3 { u8 busy; /* TRUE if currently initializing */ u8 orphanTrigger; /* Last statement is orphaned TEMP trigger */ } init; - int activeVdbeCnt; /* Number of VDBEs currently executing */ - int writeVdbeCnt; /* Number of active VDBEs that are writing */ - int vdbeExecCnt; /* Number of nested calls to VdbeExec() */ + int nVdbeActive; /* Number of VDBEs currently running */ + int nVdbeRead; /* Number of active VDBEs that read or write */ + int nVdbeWrite; /* Number of active VDBEs that read and write */ + int nVdbeExec; /* Number of nested calls to VdbeExec() */ int nExtension; /* Number of loaded extensions */ void **aExtension; /* Array of shared library handles */ void (*xTrace)(void*,const char*); /* Trace function */ @@ -1035,6 +1036,7 @@ struct sqlite3 { #define SQLITE_SubqCoroutine 0x0100 /* Evaluate subqueries as coroutines */ #define SQLITE_Transitive 0x0200 /* Transitive constraints */ #define SQLITE_OmitNoopJoin 0x0400 /* Omit unused tables in joins */ +#define SQLITE_Stat3 0x0800 /* Use the SQLITE_STAT3 table */ #define SQLITE_AllOpts 0xffff /* All optimizations */ /* diff --git a/src/test1.c b/src/test1.c index 58cfd2ca54..9c38b11a6d 100644 --- a/src/test1.c +++ b/src/test1.c @@ -5959,15 +5959,20 @@ static int optimization_control( const char *zOptName; int mask; } aOpt[] = { - { "all", SQLITE_AllOpts }, - { "query-flattener", SQLITE_QueryFlattener }, - { "column-cache", SQLITE_ColumnCache }, - { "groupby-order", SQLITE_GroupByOrder }, - { "factor-constants", SQLITE_FactorOutConst }, - { "real-as-int", SQLITE_IdxRealAsInt }, - { "distinct-opt", SQLITE_DistinctOpt }, - { "cover-idx-scan", SQLITE_CoverIdxScan }, - { "order-by-idx-join",SQLITE_OrderByIdxJoin }, + { "all", SQLITE_AllOpts }, + { "none", 0 }, + { "query-flattener", SQLITE_QueryFlattener }, + { "column-cache", SQLITE_ColumnCache }, + { "groupby-order", SQLITE_GroupByOrder }, + { "factor-constants", SQLITE_FactorOutConst }, + { "real-as-int", SQLITE_IdxRealAsInt }, + { "distinct-opt", SQLITE_DistinctOpt }, + { "cover-idx-scan", SQLITE_CoverIdxScan }, + { "order-by-idx-join", SQLITE_OrderByIdxJoin }, + { "transitive", SQLITE_Transitive }, + { "subquery-coroutine", SQLITE_SubqCoroutine }, + { "omit-noop-join", SQLITE_OmitNoopJoin }, + { "stat3", SQLITE_Stat3 }, }; if( objc!=4 ){ @@ -5988,7 +5993,7 @@ static int optimization_control( Tcl_AppendResult(interp, "unknown optimization - should be one of:", (char*)0); for(i=0; iiVersion = pVfs->iVersion; + pMethods->iVersion = pFd->pReal->pMethods->iVersion; + if( pMethods->iVersion>pVfs->iVersion ){ + pMethods->iVersion = pVfs->iVersion; + } if( pVfs->iVersion>1 && ((Testvfs *)pVfs->pAppData)->isNoshm ){ pMethods->xShmUnmap = 0; pMethods->xShmLock = 0; @@ -993,6 +1001,21 @@ static int tvfsShmUnmap( return rc; } +static int tvfsFetch( + sqlite3_file *pFile, + sqlite3_int64 iOfst, + int iAmt, + void **pp +){ + TestvfsFd *pFd = tvfsGetFd(pFile); + return sqlite3OsFetch(pFd->pReal, iOfst, iAmt, pp); +} + +static int tvfsUnfetch(sqlite3_file *pFile, sqlite3_int64 iOfst, void *p){ + TestvfsFd *pFd = tvfsGetFd(pFile); + return sqlite3OsUnfetch(pFd->pReal, iOfst, p); +} + static int testvfs_obj_cmd( ClientData cd, Tcl_Interp *interp, @@ -1343,7 +1366,7 @@ static int testvfs_cmd( Tcl_Obj *CONST objv[] ){ static sqlite3_vfs tvfs_vfs = { - 2, /* iVersion */ + 3, /* iVersion */ 0, /* szOsFile */ 0, /* mxPathname */ 0, /* pNext */ @@ -1369,6 +1392,9 @@ static int testvfs_cmd( tvfsCurrentTime, /* xCurrentTime */ 0, /* xGetLastError */ 0, /* xCurrentTimeInt64 */ + 0, /* xSetSystemCall */ + 0, /* xGetSystemCall */ + 0, /* xNextSystemCall */ }; Testvfs *p; /* New object */ @@ -1382,7 +1408,7 @@ static int testvfs_cmd( int isDefault = 0; /* True if -default is passed */ int szOsFile = 0; /* Value passed to -szosfile */ int mxPathname = -1; /* Value passed to -mxpathname */ - int iVersion = 2; /* Value passed to -iversion */ + int iVersion = 3; /* Value passed to -iversion */ if( objc<2 || 0!=(objc%2) ) goto bad_args; for(i=2; iaLimit[SQLITE_LIMIT_SQL_LENGTH]; - if( db->activeVdbeCnt==0 ){ + if( db->nVdbeActive==0 ){ db->u1.isInterrupted = 0; } pParse->rc = SQLITE_OK; diff --git a/src/vacuum.c b/src/vacuum.c index 4afb2cca64..4ba09fd4d9 100644 --- a/src/vacuum.c +++ b/src/vacuum.c @@ -111,7 +111,7 @@ int sqlite3RunVacuum(char **pzErrMsg, sqlite3 *db){ sqlite3SetString(pzErrMsg, db, "cannot VACUUM from within a transaction"); return SQLITE_ERROR; } - if( db->activeVdbeCnt>1 ){ + if( db->nVdbeActive>1 ){ sqlite3SetString(pzErrMsg, db,"cannot VACUUM - SQL statements in progress"); return SQLITE_ERROR; } diff --git a/src/vdbe.c b/src/vdbe.c index 5330c48b5f..e5a40b7993 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -589,6 +589,7 @@ int sqlite3VdbeExec( goto no_mem; } assert( p->rc==SQLITE_OK || p->rc==SQLITE_BUSY ); + assert( p->bIsReader || p->readOnly!=0 ); p->rc = SQLITE_OK; assert( p->explain==0 ); p->pResultSet = 0; @@ -2695,9 +2696,10 @@ case OP_Savepoint: { assert( p1==SAVEPOINT_BEGIN||p1==SAVEPOINT_RELEASE||p1==SAVEPOINT_ROLLBACK ); assert( db->pSavepoint || db->isTransactionSavepoint==0 ); assert( checkSavepointCount(db) ); + assert( p->bIsReader ); if( p1==SAVEPOINT_BEGIN ){ - if( db->writeVdbeCnt>0 ){ + if( db->nVdbeWrite>0 ){ /* A new savepoint cannot be created if there are active write ** statements (i.e. open read/write incremental blob handles). */ @@ -2755,7 +2757,7 @@ case OP_Savepoint: { if( !pSavepoint ){ sqlite3SetString(&p->zErrMsg, db, "no such savepoint: %s", zName); rc = SQLITE_ERROR; - }else if( db->writeVdbeCnt>0 && p1==SAVEPOINT_RELEASE ){ + }else if( db->nVdbeWrite>0 && p1==SAVEPOINT_RELEASE ){ /* It is not possible to release (commit) a savepoint if there are ** active write statements. */ @@ -2857,10 +2859,11 @@ case OP_AutoCommit: { turnOnAC = desiredAutoCommit && !db->autoCommit; assert( desiredAutoCommit==1 || desiredAutoCommit==0 ); assert( desiredAutoCommit==1 || iRollback==0 ); - assert( db->activeVdbeCnt>0 ); /* At least this one VM is active */ + assert( db->nVdbeActive>0 ); /* At least this one VM is active */ + assert( p->bIsReader ); #if 0 - if( turnOnAC && iRollback && db->activeVdbeCnt>1 ){ + if( turnOnAC && iRollback && db->nVdbeActive>1 ){ /* If this instruction implements a ROLLBACK and other VMs are ** still running, and a transaction is active, return an error indicating ** that the other VMs must complete first. @@ -2870,7 +2873,7 @@ case OP_AutoCommit: { rc = SQLITE_BUSY; }else #endif - if( turnOnAC && !iRollback && db->writeVdbeCnt>0 ){ + if( turnOnAC && !iRollback && db->nVdbeWrite>0 ){ /* If this instruction implements a COMMIT and other VMs are writing ** return an error indicating that the other VMs must complete first. */ @@ -2946,6 +2949,8 @@ case OP_AutoCommit: { case OP_Transaction: { Btree *pBt; + assert( p->bIsReader ); + assert( p->readOnly==0 || pOp->p2==0 ); assert( pOp->p1>=0 && pOp->p1nDb ); assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); pBt = db->aDb[pOp->p1].pBt; @@ -2962,7 +2967,7 @@ case OP_Transaction: { } if( pOp->p2 && p->usesStmtJournal - && (db->autoCommit==0 || db->activeVdbeCnt>1) + && (db->autoCommit==0 || db->nVdbeRead>1) ){ assert( sqlite3BtreeIsInTrans(pBt) ); if( p->iStatement==0 ){ @@ -3003,6 +3008,7 @@ case OP_ReadCookie: { /* out2-prerelease */ int iDb; int iCookie; + assert( p->bIsReader ); iDb = pOp->p1; iCookie = pOp->p3; assert( pOp->p3p2p1>=0 && pOp->p1nDb ); assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); @@ -3080,6 +3087,7 @@ case OP_VerifyCookie: { assert( pOp->p1>=0 && pOp->p1nDb ); assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); assert( sqlite3SchemaMutexHeld(db, pOp->p1, 0) ); + assert( p->bIsReader ); pBt = db->aDb[pOp->p1].pBt; if( pBt ){ sqlite3BtreeGetMeta(pBt, BTREE_SCHEMA_VERSION, (u32 *)&iMeta); @@ -3175,6 +3183,8 @@ case OP_OpenWrite: { assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR))==pOp->p5 ); assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 ); + assert( p->bIsReader ); + assert( pOp->opcode==OP_OpenRead || p->readOnly==0 ); if( p->expired ){ rc = SQLITE_ABORT; @@ -4787,15 +4797,18 @@ case OP_Destroy: { /* out2-prerelease */ Vdbe *pVdbe; int iDb; + assert( p->readOnly==0 ); #ifndef SQLITE_OMIT_VIRTUALTABLE iCnt = 0; for(pVdbe=db->pVdbe; pVdbe; pVdbe = pVdbe->pNext){ - if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 ){ + if( pVdbe->magic==VDBE_MAGIC_RUN && pVdbe->bIsReader + && pVdbe->inVtabMethod<2 && pVdbe->pc>=0 + ){ iCnt++; } } #else - iCnt = db->activeVdbeCnt; + iCnt = db->nVdbeRead; #endif pOut->flags = MEM_Null; if( iCnt>1 ){ @@ -4842,6 +4855,7 @@ case OP_Clear: { int nChange; nChange = 0; + assert( p->readOnly==0 ); assert( (p->btreeMask & (((yDbMask)1)<p2))!=0 ); rc = sqlite3BtreeClearTable( db->aDb[pOp->p2].pBt, pOp->p1, (pOp->p3 ? &nChange : 0) @@ -4888,6 +4902,7 @@ case OP_CreateTable: { /* out2-prerelease */ pgno = 0; assert( pOp->p1>=0 && pOp->p1nDb ); assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( p->readOnly==0 ); pDb = &db->aDb[pOp->p1]; assert( pDb->pBt!=0 ); if( pOp->opcode==OP_CreateTable ){ @@ -5035,7 +5050,8 @@ case OP_IntegrityCk: { int nErr; /* Number of errors reported */ char *z; /* Text of the error report */ Mem *pnErr; /* Register keeping track of errors remaining */ - + + assert( p->bIsReader ); nRoot = pOp->p2; assert( nRoot>0 ); aRoot = sqlite3DbMallocRaw(db, sizeof(int)*(nRoot+1) ); @@ -5543,6 +5559,7 @@ case OP_Checkpoint: { int aRes[3]; /* Results */ Mem *pMem; /* Write results here */ + assert( p->readOnly==0 ); aRes[0] = 0; aRes[1] = aRes[2] = -1; assert( pOp->p2==SQLITE_CHECKPOINT_PASSIVE @@ -5592,6 +5609,7 @@ case OP_JournalMode: { /* out2-prerelease */ || eNew==PAGER_JOURNALMODE_QUERY ); assert( pOp->p1>=0 && pOp->p1nDb ); + assert( p->readOnly==0 ); pBt = db->aDb[pOp->p1].pBt; pPager = sqlite3BtreePager(pBt); @@ -5615,7 +5633,7 @@ case OP_JournalMode: { /* out2-prerelease */ if( (eNew!=eOld) && (eOld==PAGER_JOURNALMODE_WAL || eNew==PAGER_JOURNALMODE_WAL) ){ - if( !db->autoCommit || db->activeVdbeCnt>1 ){ + if( !db->autoCommit || db->nVdbeRead>1 ){ rc = SQLITE_ERROR; sqlite3SetString(&p->zErrMsg, db, "cannot change %s wal mode from within a transaction", @@ -5674,6 +5692,7 @@ case OP_JournalMode: { /* out2-prerelease */ ** a transaction. */ case OP_Vacuum: { + assert( p->readOnly==0 ); rc = sqlite3RunVacuum(&p->zErrMsg, db); break; } @@ -5691,6 +5710,7 @@ case OP_IncrVacuum: { /* jump */ assert( pOp->p1>=0 && pOp->p1nDb ); assert( (p->btreeMask & (((yDbMask)1)<p1))!=0 ); + assert( p->readOnly==0 ); pBt = db->aDb[pOp->p1].pBt; rc = sqlite3BtreeIncrVacuum(pBt); if( rc==SQLITE_DONE ){ @@ -5809,6 +5829,7 @@ case OP_VOpen: { sqlite3_vtab *pVtab; sqlite3_module *pModule; + assert( p->bIsReader ); pCur = 0; pVtabCursor = 0; pVtab = pOp->p4.pVtab->pVtab; @@ -6025,6 +6046,7 @@ case OP_VRename: { pName = &aMem[pOp->p1]; assert( pVtab->pModule->xRename ); assert( memIsValid(pName) ); + assert( p->readOnly==0 ); REGISTER_TRACE(pOp->p1, pName); assert( pName->flags & MEM_Str ); testcase( pName->enc==SQLITE_UTF8 ); @@ -6076,6 +6098,7 @@ case OP_VUpdate: { assert( pOp->p2==1 || pOp->p5==OE_Fail || pOp->p5==OE_Rollback || pOp->p5==OE_Abort || pOp->p5==OE_Ignore || pOp->p5==OE_Replace ); + assert( p->readOnly==0 ); pVtab = pOp->p4.pVtab->pVtab; pModule = (sqlite3_module *)pVtab->pModule; nArg = pOp->p2; diff --git a/src/vdbeInt.h b/src/vdbeInt.h index aec4b422b6..dee4ca68d3 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -337,7 +337,8 @@ struct Vdbe { bft expired:1; /* True if the VM needs to be recompiled */ bft runOnlyOnce:1; /* Automatically expire on reset */ bft usesStmtJournal:1; /* True if uses a statement journal */ - bft readOnly:1; /* True for read-only statements */ + bft readOnly:1; /* True for statements that do not write */ + bft bIsReader:1; /* True for statements that read */ bft isPrepareV2:1; /* True if prepared with prepare_v2() */ bft doingRerun:1; /* True if rerunning after an auto-reprepare */ int nChange; /* Number of db changes made since last reset */ diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 6fb45edb84..b97faaf404 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -382,11 +382,11 @@ static int sqlite3Step(Vdbe *p){ ** reset the interrupt flag. This prevents a call to sqlite3_interrupt ** from interrupting a statement that has not yet started. */ - if( db->activeVdbeCnt==0 ){ + if( db->nVdbeActive==0 ){ db->u1.isInterrupted = 0; } - assert( db->writeVdbeCnt>0 || db->autoCommit==0 + assert( db->nVdbeWrite>0 || db->autoCommit==0 || (db->nDeferredCons==0 && db->nDeferredImmCons==0) ); @@ -396,8 +396,9 @@ static int sqlite3Step(Vdbe *p){ } #endif - db->activeVdbeCnt++; - if( p->readOnly==0 ) db->writeVdbeCnt++; + db->nVdbeActive++; + if( p->readOnly==0 ) db->nVdbeWrite++; + if( p->bIsReader ) db->nVdbeRead++; p->pc = 0; } #ifndef SQLITE_OMIT_EXPLAIN @@ -406,9 +407,9 @@ static int sqlite3Step(Vdbe *p){ }else #endif /* SQLITE_OMIT_EXPLAIN */ { - db->vdbeExecCnt++; + db->nVdbeExec++; rc = sqlite3VdbeExec(p); - db->vdbeExecCnt--; + db->nVdbeExec--; } #ifndef SQLITE_OMIT_TRACE diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 88561ecb06..5ba51dce60 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -404,14 +404,26 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ Op *pOp; int *aLabel = p->aLabel; p->readOnly = 1; + p->bIsReader = 0; for(pOp=p->aOp, i=p->nOp-1; i>=0; i--, pOp++){ u8 opcode = pOp->opcode; pOp->opflags = sqlite3OpcodeProperty[opcode]; if( opcode==OP_Function || opcode==OP_AggStep ){ if( pOp->p5>nMaxArgs ) nMaxArgs = pOp->p5; - }else if( (opcode==OP_Transaction && pOp->p2!=0) || opcode==OP_Vacuum ){ + }else if( opcode==OP_Transaction ){ + if( pOp->p2!=0 ) p->readOnly = 0; + p->bIsReader = 1; + }else if( opcode==OP_AutoCommit || opcode==OP_Savepoint ){ + p->bIsReader = 1; + }else if( opcode==OP_Vacuum + || opcode==OP_JournalMode +#ifndef SQLITE_OMIT_WAL + || opcode==OP_Checkpoint +#endif + ){ p->readOnly = 0; + p->bIsReader = 1; #ifndef SQLITE_OMIT_VIRTUALTABLE }else if( opcode==OP_VUpdate ){ if( pOp->p2>nMaxArgs ) nMaxArgs = pOp->p2; @@ -437,8 +449,8 @@ static void resolveP2Values(Vdbe *p, int *pMaxFuncArgs){ } sqlite3DbFree(p->db, p->aLabel); p->aLabel = 0; - *pMaxFuncArgs = nMaxArgs; + assert( p->bIsReader!=0 || p->btreeMask==0 ); } /* @@ -1964,7 +1976,7 @@ static int vdbeCommit(sqlite3 *db, Vdbe *p){ } /* -** This routine checks that the sqlite3.activeVdbeCnt count variable +** This routine checks that the sqlite3.nVdbeActive count variable ** matches the number of vdbe's in the list sqlite3.pVdbe that are ** currently active. An assertion fails if the two counts do not match. ** This is an internal self-check only - it is not an essential processing @@ -1977,16 +1989,19 @@ static void checkActiveVdbeCnt(sqlite3 *db){ Vdbe *p; int cnt = 0; int nWrite = 0; + int nRead = 0; p = db->pVdbe; while( p ){ if( p->magic==VDBE_MAGIC_RUN && p->pc>=0 ){ cnt++; if( p->readOnly==0 ) nWrite++; + if( p->bIsReader ) nRead++; } p = p->pNext; } - assert( cnt==db->activeVdbeCnt ); - assert( nWrite==db->writeVdbeCnt ); + assert( cnt==db->nVdbeActive ); + assert( nWrite==db->nVdbeWrite ); + assert( nRead==db->nVdbeRead ); } #else #define checkActiveVdbeCnt(x) @@ -2125,8 +2140,9 @@ int sqlite3VdbeHalt(Vdbe *p){ } checkActiveVdbeCnt(db); - /* No commit or rollback needed if the program never started */ - if( p->pc>=0 ){ + /* No commit or rollback needed if the program never started or if the + ** SQL statement does not read or write a database file. */ + if( p->pc>=0 && p->bIsReader ){ int mrc; /* Primary error code from p->rc */ int eStatementOp = 0; int isSpecialError; /* Set to true if a 'special' error */ @@ -2179,7 +2195,7 @@ int sqlite3VdbeHalt(Vdbe *p){ */ if( !sqlite3VtabInSync(db) && db->autoCommit - && db->writeVdbeCnt==(p->readOnly==0) + && db->nVdbeWrite==(p->readOnly==0) ){ if( p->rc==SQLITE_OK || (p->errorAction==OE_Fail && !isSpecialError) ){ rc = sqlite3VdbeCheckFk(p, 1); @@ -2262,11 +2278,12 @@ int sqlite3VdbeHalt(Vdbe *p){ /* We have successfully halted and closed the VM. Record this fact. */ if( p->pc>=0 ){ - db->activeVdbeCnt--; - if( !p->readOnly ){ - db->writeVdbeCnt--; - } - assert( db->activeVdbeCnt>=db->writeVdbeCnt ); + db->nVdbeActive--; + if( !p->readOnly ) db->nVdbeWrite--; + if( p->bIsReader ) db->nVdbeRead--; + assert( db->nVdbeActive>=db->nVdbeRead ); + assert( db->nVdbeRead>=db->nVdbeWrite ); + assert( db->nVdbeWrite>=0 ); } p->magic = VDBE_MAGIC_HALT; checkActiveVdbeCnt(db); @@ -2282,7 +2299,7 @@ int sqlite3VdbeHalt(Vdbe *p){ sqlite3ConnectionUnlocked(db); } - assert( db->activeVdbeCnt>0 || db->autoCommit==0 || db->nStatement==0 ); + assert( db->nVdbeActive>0 || db->autoCommit==0 || db->nStatement==0 ); return (p->rc==SQLITE_BUSY ? SQLITE_BUSY : SQLITE_OK); } diff --git a/src/vdbetrace.c b/src/vdbetrace.c index 356277e8d2..0a767261f0 100644 --- a/src/vdbetrace.c +++ b/src/vdbetrace.c @@ -47,9 +47,9 @@ static int findNextHostParameter(const char *zSql, int *pnToken){ /* ** This function returns a pointer to a nul-terminated string in memory -** obtained from sqlite3DbMalloc(). If sqlite3.vdbeExecCnt is 1, then the +** obtained from sqlite3DbMalloc(). If sqlite3.nVdbeExec is 1, then the ** string contains a copy of zRawSql but with host parameters expanded to -** their current bindings. Or, if sqlite3.vdbeExecCnt is greater than 1, +** their current bindings. Or, if sqlite3.nVdbeExec is greater than 1, ** then the returned string holds a copy of zRawSql with "-- " prepended ** to each line of text. ** @@ -87,7 +87,7 @@ char *sqlite3VdbeExpandSql( sqlite3StrAccumInit(&out, zBase, sizeof(zBase), db->aLimit[SQLITE_LIMIT_LENGTH]); out.db = db; - if( db->vdbeExecCnt>1 ){ + if( db->nVdbeExec>1 ){ while( *zRawSql ){ const char *zStart = zRawSql; while( *(zRawSql++)!='\n' && *zRawSql ); diff --git a/src/wal.c b/src/wal.c index e642ea2105..f413920648 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2463,7 +2463,7 @@ int sqlite3WalBeginWriteTransaction(Wal *pWal){ if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){ walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1); pWal->writeLock = 0; - rc = SQLITE_BUSY; + rc = SQLITE_BUSY_SNAPSHOT; } return rc; diff --git a/src/where.c b/src/where.c index e20f2b3018..e18e88623f 100644 --- a/src/where.c +++ b/src/where.c @@ -159,7 +159,7 @@ static int whereLoopResize(sqlite3*, WhereLoop*, int); ** Each instance of this object holds a sequence of WhereLoop objects ** that implement some or all of a query plan. ** -** Think of each WhereLoop objects as a node in a graph, which arcs +** Think of each WhereLoop object as a node in a graph with arcs ** showing dependences and costs for travelling between nodes. (That is ** not a completely accurate description because WhereLoop costs are a ** vector, not a scalar, and because dependences are many-to-one, not @@ -429,7 +429,7 @@ struct WhereInfo { ** The particular combination of bits in each WhereLoop help to ** determine the algorithm that WhereLoop represents. */ -#define WHERE_COLUMN_EQ 0x00000001 /* x=EXPR or x IN (...) or x IS NULL */ +#define WHERE_COLUMN_EQ 0x00000001 /* x=EXPR */ #define WHERE_COLUMN_RANGE 0x00000002 /* xEXPR */ #define WHERE_COLUMN_IN 0x00000004 /* x IN (...) */ #define WHERE_COLUMN_NULL 0x00000008 /* x IS NULL */ @@ -444,7 +444,7 @@ struct WhereInfo { #define WHERE_IN_ABLE 0x00000800 /* Able to support an IN operator */ #define WHERE_ONEROW 0x00001000 /* Selects no more than one row */ #define WHERE_MULTI_OR 0x00002000 /* OR using multiple indices */ -#define WHERE_TEMP_INDEX 0x00004000 /* Uses an ephemeral index */ +#define WHERE_AUTO_INDEX 0x00004000 /* Uses an ephemeral index */ /* Convert a WhereCost value (10 times log2(X)) into its integer value X. @@ -822,7 +822,7 @@ static u16 operatorMask(int op){ ** established when the pScan object was initialized by whereScanInit(). ** Return NULL if there are no more matching WhereTerms. */ -WhereTerm *whereScanNext(WhereScan *pScan){ +static WhereTerm *whereScanNext(WhereScan *pScan){ int iCur; /* The cursor on the LHS of the term */ int iColumn; /* The column on the LHS of the term. -1 for IPK */ Expr *pX; /* An expression being tested */ @@ -909,7 +909,7 @@ WhereTerm *whereScanNext(WhereScan *pScan){ ** If X is not the INTEGER PRIMARY KEY then X must be compatible with ** index pIdx. */ -WhereTerm *whereScanInit( +static WhereTerm *whereScanInit( WhereScan *pScan, /* The WhereScan object being initialized */ WhereClause *pWC, /* The WHERE clause to be scanned */ int iCur, /* Cursor to scan for */ @@ -1738,6 +1738,7 @@ static void exprAnalyze( if( pExpr->op==TK_NOTNULL && pExpr->pLeft->op==TK_COLUMN && pExpr->pLeft->iColumn>=0 + && OptimizationEnabled(db, SQLITE_Stat3) ){ Expr *pNewExpr; Expr *pLeft = pExpr->pLeft; @@ -2041,6 +2042,7 @@ static void constructAutomaticIndex( WhereLoop *pLoop; /* The Loop object */ Bitmask idxCols; /* Bitmap of columns used for indexing */ Bitmask extraCols; /* Bitmap of additional columns */ + u8 sentWarning = 0; /* True if a warnning has been issued */ /* Generate code to skip over the creation and initialization of the ** transient index on 2nd and subsequent iterations of the loop. */ @@ -2061,6 +2063,12 @@ static void constructAutomaticIndex( Bitmask cMask = iCol>=BMS ? MASKBIT(BMS-1) : MASKBIT(iCol); testcase( iCol==BMS ); testcase( iCol==BMS-1 ); + if( !sentWarning ){ + sqlite3_log(SQLITE_WARNING_AUTOINDEX, + "automatic index on %s(%s)", pTable->zName, + pTable->aCol[iCol].zName); + sentWarning = 1; + } if( (idxCols & cMask)==0 ){ if( whereLoopResize(pParse->db, pLoop, nColumn+1) ) return; pLoop->aLTerm[nColumn++] = pTerm; @@ -2071,7 +2079,7 @@ static void constructAutomaticIndex( assert( nColumn>0 ); pLoop->u.btree.nEq = pLoop->nLTerm = nColumn; pLoop->wsFlags = WHERE_COLUMN_EQ | WHERE_IDX_ONLY | WHERE_INDEXED - | WHERE_TEMP_INDEX; + | WHERE_AUTO_INDEX; /* Count the number of additional columns needed to create a ** covering index. A "covering index" is an index that contains all @@ -2571,7 +2579,7 @@ static int whereRangeScanEst( #ifdef SQLITE_ENABLE_STAT3 - if( nEq==0 && p->nSample ){ + if( nEq==0 && p->nSample && OptimizationEnabled(pParse->db, SQLITE_Stat3) ){ sqlite3_value *pRangeVal; tRowcnt iLower = 0; tRowcnt iUpper = p->aiRowEst[0]; @@ -3117,13 +3125,12 @@ static void explainOneScan( && ALWAYS(pLoop->u.btree.pIndex!=0) ){ char *zWhere = explainIndexRange(db, pLoop, pItem->pTab); - zMsg = sqlite3MAppendf(db, zMsg, "%s USING %s%sINDEX%s%s%s", zMsg, - ((flags & WHERE_TEMP_INDEX)?"AUTOMATIC ":""), - ((flags & WHERE_IDX_ONLY)?"COVERING ":""), - ((flags & WHERE_TEMP_INDEX)?"":" "), - ((flags & WHERE_TEMP_INDEX)?"": pLoop->u.btree.pIndex->zName), - zWhere - ); + zMsg = sqlite3MAppendf(db, zMsg, + ((flags & WHERE_AUTO_INDEX) ? + "%s USING AUTOMATIC %sINDEX%.0s%s" : + "%s USING %sINDEX %s%s"), + zMsg, ((flags & WHERE_IDX_ONLY) ? "COVERING " : ""), + pLoop->u.btree.pIndex->zName, zWhere); sqlite3DbFree(db, zWhere); }else if( (flags & WHERE_IPK)!=0 && (flags & WHERE_CONSTRAINT)!=0 ){ zMsg = sqlite3MAppendf(db, zMsg, "%s USING INTEGER PRIMARY KEY", zMsg); @@ -3328,10 +3335,11 @@ static Bitmask codeOneLoopStart( assert( TK_LT==TK_GT+2 ); /* ... of the TK_xx values... */ assert( TK_GE==TK_GT+3 ); /* ... is correcct. */ + assert( (pStart->wtFlags & TERM_VNULL)==0 ); testcase( pStart->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ pX = pStart->pExpr; assert( pX!=0 ); - assert( pStart->leftCursor==iCur ); + testcase( pStart->leftCursor!=iCur ); /* transitive constraints */ r1 = sqlite3ExprCodeTemp(pParse, pX->pRight, &rTemp); sqlite3VdbeAddOp3(v, aMoveOp[pX->op-TK_GT], iCur, addrBrk, r1); VdbeComment((v, "pk")); @@ -3345,7 +3353,8 @@ static Bitmask codeOneLoopStart( Expr *pX; pX = pEnd->pExpr; assert( pX!=0 ); - assert( pEnd->leftCursor==iCur ); + assert( (pEnd->wtFlags & TERM_VNULL)==0 ); + testcase( pEnd->leftCursor!=iCur ); /* Transitive constraints */ testcase( pEnd->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */ memEndValue = ++pParse->nMem; sqlite3ExprCode(pParse, pX->pRight, memEndValue); @@ -3794,7 +3803,7 @@ static Bitmask codeOneLoopStart( ** be available. */ pSubLoop = pSubWInfo->a[0].pWLoop; - assert( (pSubLoop->wsFlags & WHERE_TEMP_INDEX)==0 ); + assert( (pSubLoop->wsFlags & WHERE_AUTO_INDEX)==0 ); if( (pSubLoop->wsFlags & WHERE_INDEXED)!=0 && (ii==0 || pSubLoop->u.btree.pIndex==pCov) ){ @@ -3880,6 +3889,7 @@ static Bitmask codeOneLoopStart( if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue; if( pTerm->eOperator!=(WO_EQUIV|WO_EQ) ) continue; if( pTerm->leftCursor!=iCur ) continue; + if( pLevel->iLeftJoin ) continue; pE = pTerm->pExpr; assert( !ExprHasProperty(pE, EP_FromJoin) ); assert( (pTerm->prereqRight & newNotReady)!=0 ); @@ -3976,12 +3986,12 @@ static void whereLoopInit(WhereLoop *p){ ** Clear the WhereLoop.u union. Leave WhereLoop.pLTerm intact. */ static void whereLoopClearUnion(sqlite3 *db, WhereLoop *p){ - if( p->wsFlags & (WHERE_VIRTUALTABLE|WHERE_TEMP_INDEX) ){ + if( p->wsFlags & (WHERE_VIRTUALTABLE|WHERE_AUTO_INDEX) ){ if( (p->wsFlags & WHERE_VIRTUALTABLE)!=0 && p->u.vtab.needFree ){ sqlite3_free(p->u.vtab.idxStr); p->u.vtab.needFree = 0; p->u.vtab.idxStr = 0; - }else if( (p->wsFlags & WHERE_TEMP_INDEX)!=0 && p->u.btree.pIndex!=0 ){ + }else if( (p->wsFlags & WHERE_AUTO_INDEX)!=0 && p->u.btree.pIndex!=0 ){ sqlite3DbFree(db, p->u.btree.pIndex->zColAff); sqlite3DbFree(db, p->u.btree.pIndex); p->u.btree.pIndex = 0; @@ -4024,7 +4034,7 @@ static int whereLoopXfer(sqlite3 *db, WhereLoop *pTo, WhereLoop *pFrom){ memcpy(pTo->aLTerm, pFrom->aLTerm, pTo->nLTerm*sizeof(pTo->aLTerm[0])); if( pFrom->wsFlags & WHERE_VIRTUALTABLE ){ pFrom->u.vtab.needFree = 0; - }else if( (pFrom->wsFlags & WHERE_TEMP_INDEX)!=0 ){ + }else if( (pFrom->wsFlags & WHERE_AUTO_INDEX)!=0 ){ pFrom->u.btree.pIndex = 0; } return SQLITE_OK; @@ -4274,6 +4284,11 @@ static int whereLoopAddBtreeIndex( for(; rc==SQLITE_OK && pTerm!=0; pTerm = whereScanNext(&scan)){ int nIn = 0; if( pTerm->prereqRight & pNew->maskSelf ) continue; +#ifdef SQLITE_ENABLE_STAT3 + if( (pTerm->wtFlags & TERM_VNULL)!=0 && pSrc->pTab->aCol[iCol].notNull ){ + continue; /* skip IS NOT NULL constraints on a NOT NULL column */ + } +#endif pNew->wsFlags = saved_wsFlags; pNew->u.btree.nEq = saved_nEq; pNew->nLTerm = saved_nLTerm; @@ -4336,7 +4351,8 @@ static int whereLoopAddBtreeIndex( pNew->nOut = saved_nOut>rDiv+10 ? saved_nOut - rDiv : 10; } #ifdef SQLITE_ENABLE_STAT3 - if( pNew->u.btree.nEq==1 && pProbe->nSample ){ + if( pNew->u.btree.nEq==1 && pProbe->nSample + && OptimizationEnabled(db, SQLITE_Stat3) ){ tRowcnt nOut = 0; if( (pTerm->eOperator & (WO_EQ|WO_ISNULL))!=0 ){ testcase( pTerm->eOperator & WO_EQ ); @@ -4420,7 +4436,7 @@ static Bitmask columnsInIndex(Index *pIdx){ /* -** Add all WhereLoop objects a single table of the join were the table +** Add all WhereLoop objects for a single table of the join where the table ** is idenfied by pBuilder->pNew->iTab. That table is guaranteed to be ** a b-tree table, not a virtual table. */ @@ -4496,13 +4512,16 @@ static int whereLoopAddBtree( pNew->nLTerm = 1; pNew->aLTerm[0] = pTerm; /* TUNING: One-time cost for computing the automatic index is - ** approximately 6*N*log2(N) where N is the number of rows in + ** approximately 7*N*log2(N) where N is the number of rows in ** the table being indexed. */ - pNew->rSetup = rLogSize + rSize + 26; assert( 26==whereCost(6) ); - /* TUNING: Each index lookup yields 10 rows in the table */ - pNew->nOut = 33; assert( 33==whereCost(10) ); + pNew->rSetup = rLogSize + rSize + 28; assert( 28==whereCost(7) ); + /* TUNING: Each index lookup yields 20 rows in the table. This + ** is more than the usual guess of 10 rows, since we have no way + ** of knowning how selective the index will ultimately be. It would + ** not be unreasonable to make this value much larger. */ + pNew->nOut = 43; assert( 43==whereCost(20) ); pNew->rRun = whereCostAdd(rLogSize,pNew->nOut); - pNew->wsFlags = WHERE_TEMP_INDEX; + pNew->wsFlags = WHERE_AUTO_INDEX; pNew->prereq = mExtra | pTerm->prereqRight; rc = whereLoopInsert(pBuilder, pNew); } @@ -4881,12 +4900,19 @@ static int whereLoopAddAll(WhereLoopBuilder *pBuilder){ /* ** Examine a WherePath (with the addition of the extra WhereLoop of the 5th ** parameters) to see if it outputs rows in the requested ORDER BY -** (or GROUP BY) without requiring a separate source operation. Return: +** (or GROUP BY) without requiring a separate sort operation. Return: ** ** 0: ORDER BY is not satisfied. Sorting required ** 1: ORDER BY is satisfied. Omit sorting ** -1: Unknown at this time ** +** Note that processing for WHERE_GROUPBY and WHERE_DISTINCTBY is not as +** strict. With GROUP BY and DISTINCT the only requirement is that +** equivalent rows appear immediately adjacent to one another. GROUP BY +** and DISTINT do not require rows to appear in any particular order as long +** as equivelent rows are grouped together. Thus for GROUP BY and DISTINCT +** the pOrderBy terms can be matched in any order. With ORDER BY, the +** pOrderBy terms must be matched in strict left-to-right order. */ static int wherePathSatisfiesOrderBy( WhereInfo *pWInfo, /* The WHERE clause */ @@ -5134,7 +5160,7 @@ static const char *wherePathName(WherePath *pPath, int nLoop, WhereLoop *pLast){ /* -** Given the list of WhereLoop objects on pWInfo->pLoops, this routine +** Given the list of WhereLoop objects at pWInfo->pLoops, this routine ** attempts to find the lowest cost path that visits each WhereLoop ** once. This path is then loaded into the pWInfo->a[].pWLoop fields. ** @@ -5551,7 +5577,8 @@ static int whereShortCut(WhereLoopBuilder *pBuilder){ ** ** ORDER BY CLAUSE PROCESSING ** -** pOrderBy is a pointer to the ORDER BY clause of a SELECT statement, +** pOrderBy is a pointer to the ORDER BY clause (or the GROUP BY clause +** if the WHERE_GROUPBY flag is set in wctrlFlags) of a SELECT statement ** if there is one. If there is no ORDER BY clause or if this routine ** is called from an UPDATE or DELETE statement, then pOrderBy is NULL. */ @@ -5643,6 +5670,7 @@ WhereInfo *sqlite3WhereBegin( whereClauseInit(&pWInfo->sWC, pWInfo); sqlite3ExprCodeConstants(pParse, pWhere); whereSplit(&pWInfo->sWC, pWhere, TK_AND); /* IMP: R-15842-53296 */ + sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ /* Special case: a WHERE clause that is constant. Evaluate the ** expression and either jump over all of the code or fall thru. @@ -5796,6 +5824,7 @@ WhereInfo *sqlite3WhereBegin( Bitmask tabUsed = exprListTableUsage(pMaskSet, pResultSet); if( pOrderBy ) tabUsed |= exprListTableUsage(pMaskSet, pOrderBy); while( pWInfo->nLevel>=2 ){ + WhereTerm *pTerm, *pEnd; pLoop = pWInfo->a[pWInfo->nLevel-1].pWLoop; if( (pWInfo->pTabList->a[pLoop->iTab].jointype & JT_LEFT)==0 ) break; if( (wctrlFlags & WHERE_WANT_DISTINCT)==0 @@ -5804,6 +5833,15 @@ WhereInfo *sqlite3WhereBegin( break; } if( (tabUsed & pLoop->maskSelf)!=0 ) break; + pEnd = sWLB.pWC->a + sWLB.pWC->nTerm; + for(pTerm=sWLB.pWC->a; pTermprereqAll & pLoop->maskSelf)!=0 + && !ExprHasProperty(pTerm->pExpr, EP_FromJoin) + ){ + break; + } + } + if( pTerm drop loop %c not used\n", pLoop->cId)); pWInfo->nLevel--; nTabList--; @@ -5827,13 +5865,11 @@ WhereInfo *sqlite3WhereBegin( /* Open all tables in the pTabList and any indices selected for ** searching those tables. */ - sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ notReady = ~(Bitmask)0; for(ii=0, pLevel=pWInfo->a; iia[pLevel->iFrom]; pTab = pTabItem->pTab; @@ -5869,7 +5905,7 @@ WhereInfo *sqlite3WhereBegin( sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName); } #ifndef SQLITE_OMIT_AUTOMATIC_INDEX - if( (pLoop->wsFlags & WHERE_TEMP_INDEX)!=0 ){ + if( (pLoop->wsFlags & WHERE_AUTO_INDEX)!=0 ){ constructAutomaticIndex(pParse, &pWInfo->sWC, pTabItem, notReady, pLevel); }else #endif @@ -5992,7 +6028,7 @@ void sqlite3WhereEnd(WhereInfo *pWInfo){ if( !pWInfo->okOnePass && (ws & WHERE_IDX_ONLY)==0 ){ sqlite3VdbeAddOp1(v, OP_Close, pTabItem->iCursor); } - if( (ws & WHERE_INDEXED)!=0 && (ws & (WHERE_IPK|WHERE_TEMP_INDEX))==0 ){ + if( (ws & WHERE_INDEXED)!=0 && (ws & (WHERE_IPK|WHERE_AUTO_INDEX))==0 ){ sqlite3VdbeAddOp1(v, OP_Close, pLevel->iIdxCur); } } diff --git a/test/autoindex1.test b/test/autoindex1.test index f8f1d9e7c0..0e5032b9b9 100644 --- a/test/autoindex1.test +++ b/test/autoindex1.test @@ -23,6 +23,14 @@ ifcapable {!autoindex} { return } +# Setup for logging +db close +sqlite3_shutdown +test_sqlite3_log [list lappend ::log] +set ::log [list] +sqlite3 db test.db + + # With automatic index turned off, we do a full scan of the T2 table do_test autoindex1-100 { db eval { @@ -60,6 +68,15 @@ do_test autoindex1-111 { do_test autoindex1-112 { db status autoindex } {7} +do_test autoindex1-113 { + set ::log +} {SQLITE_WARNING_AUTOINDEX {automatic index on t2(c)}} + +db close +sqlite3_shutdown +test_sqlite3_log +sqlite3_initialize +sqlite3 db test.db # The same test as above, but this time the T2 query is a subquery rather # than a join. @@ -94,9 +111,15 @@ do_test autoindex1-212 { # Modify the second table of the join while the join is in progress # +do_execsql_test autoindex1-299 { + UPDATE sqlite_stat1 SET stat='10000' WHERE tbl='t2'; + ANALYZE sqlite_master; + EXPLAIN QUERY PLAN + SELECT b, d FROM t1 CROSS JOIN t2 ON (c=a); +} {/AUTOMATIC COVERING INDEX/} do_test autoindex1-300 { set r {} - db eval {SELECT b, d FROM t1 JOIN t2 ON (c=a)} { + db eval {SELECT b, d FROM t1 CROSS JOIN t2 ON (c=a)} { lappend r $b $d db eval {UPDATE t2 SET d=d+1} } diff --git a/test/boundary3.tcl b/test/boundary3.tcl index ac3bf0ad94..5fc26d6113 100644 --- a/test/boundary3.tcl +++ b/test/boundary3.tcl @@ -13,7 +13,6 @@ puts {# 2008 December 11 # This file is automatically generated from a separate TCL script. # This file seeks to exercise integer boundary values. # -# $Id: boundary3.tcl,v 1.3 2009/01/02 15:45:48 shane Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -40,16 +39,16 @@ foreach x { } { set x [expr {wide($x)}] set boundarynum($x) 1 - set boundarynum([expr {$x+1}]) 1 - set boundarynum([expr {-($x+1)}]) 1 - set boundarynum([expr {-($x+2)}]) 1 - set boundarynum([expr {$x+$x+1}]) 1 - set boundarynum([expr {$x+$x+2}]) 1 + set boundarynum([expr {wide($x+1)}]) 1 + set boundarynum([expr {wide(-($x+1))}]) 1 + set boundarynum([expr {wide(-($x+2))}]) 1 + set boundarynum([expr {wide($x+$x+1)}]) 1 + set boundarynum([expr {wide($x+$x+2)}]) 1 } set x [expr {wide(127)}] for {set i 1} {$i<=9} {incr i} { set boundarynum($x) 1 - set boundarynum([expr {$x+1}]) 1 + set boundarynum([expr {wide($x+1)}]) 1 set x [expr {wide($x*128 + 127)}] } @@ -116,7 +115,7 @@ foreach r $nums1 { incr a set t1ra($r) $a set t1ar($a) $r - set x [format %08x%08x [expr {wide($r)>>32}] $r] + set x [format %016x [expr {wide($r)}]] set t1rx($r) $x set t1xr($x) $r puts " INSERT INTO t1(oid,a,x) VALUES($r,$a,'$x');" @@ -158,7 +157,7 @@ foreach r $nums3 { set r5 $r.5 set r0 $r.0 - if {abs($r)<9.22337203685477580800e+18} { + if {abs($r)<0x7FFFFFFFFFFFFFFF || $r==-9223372036854775808} { set x $t1rx($r) set a $t1ra($r) puts "do_test $tname-2.$i.1 \173" diff --git a/test/capi3d.test b/test/capi3d.test index 746ec20b25..ed3765b051 100644 --- a/test/capi3d.test +++ b/test/capi3d.test @@ -108,6 +108,13 @@ db eval {CREATE TABLE t1(x)} test_is_readonly capi3d-2.3 {INSERT INTO t1 VALUES(5)} 0 test_is_readonly capi3d-2.4 {UPDATE t1 SET x=x+1 WHERE x<0} 0 test_is_readonly capi3d-2.5 {SELECT * FROM t1} 1 +ifcapable wal { + test_is_readonly capi3d-2.6 {PRAGMA journal_mode=WAL} 0 + test_is_readonly capi3d-2.7 {PRAGMA wal_checkpoint} 0 +} +test_is_readonly capi3d-2.8 {PRAGMA application_id=1234} 0 +test_is_readonly capi3d-2.9 {VACUUM} 0 +test_is_readonly capi3d-2.10 {PRAGMA integrity_check} 1 do_test capi3-2.99 { sqlite3_stmt_readonly 0 } 1 diff --git a/test/e_expr.test b/test/e_expr.test index 74d0c40712..744044d821 100644 --- a/test/e_expr.test +++ b/test/e_expr.test @@ -1294,7 +1294,7 @@ proc rev {str} { set ret } proc reverse {lhs rhs} { - string compare [rev $lhs] [ref $rhs] + string compare [rev $lhs] [rev $rhs] } db collate reverse reverse do_execsql_test e_expr-23.1.1 { @@ -1317,7 +1317,7 @@ do_execsql_test e_expr-23.1.4 { } {B} do_execsql_test e_expr-23.1.5 { SELECT CASE b WHEN a THEN 'A' ELSE 'B' END FROM t1 -} {A} +} {B} do_execsql_test e_expr-23.1.6 { SELECT CASE 55 WHEN '55' THEN 'A' ELSE 'B' END } {B} diff --git a/test/memsubsys1.test b/test/memsubsys1.test index e14a1b3c2c..76b79d00f6 100644 --- a/test/memsubsys1.test +++ b/test/memsubsys1.test @@ -94,7 +94,7 @@ sqlite3_shutdown sqlite3_config_pagecache [expr 1024+$xtra_size] 20 sqlite3_initialize reset_highwater_marks -build_test_db memsubsys1-2 {PRAGMA page_size=1024} +build_test_db memsubsys1-2 {PRAGMA page_size=1024; PRAGMA mmap_size=0} #show_memstats set MEMORY_MANAGEMENT $sqlite_options(memorymanage) ifcapable !malloc_usable_size { diff --git a/test/mmap3.test b/test/mmap3.test index d2b347eb3e..07b5152968 100644 --- a/test/mmap3.test +++ b/test/mmap3.test @@ -12,7 +12,7 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -ifcapable !mmap { +ifcapable !mmap||!vtab { finish_test return } diff --git a/test/mmapfault.test b/test/mmapfault.test new file mode 100644 index 0000000000..248b5bad08 --- /dev/null +++ b/test/mmapfault.test @@ -0,0 +1,77 @@ +# 2013-05-23 +# +# 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. +# +#*********************************************************************** +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +source $testdir/malloc_common.tcl +ifcapable !mmap { + finish_test + return +} +set testprefix mmapfault + +set a_string_counter 1 +proc a_string {n} { + global a_string_counter + incr a_string_counter + string range [string repeat "${a_string_counter}." $n] 1 $n +} +db func a_string a_string + +do_test 1-pre { + execsql { + CREATE TABLE t1(a UNIQUE, b UNIQUE); + INSERT INTO t1 VALUES(a_string(200), a_string(300)); + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + } + faultsim_save_and_close +} {} + + +do_faultsim_test 1 -prep { + faultsim_restore_and_reopen + db func a_string a_string + breakpoint + execsql { + PRAGMA mmap_size = 1000000; + PRAGMA cache_size = 5; + BEGIN; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + INSERT INTO t1 SELECT a_string(200), a_string(300) FROM t1; + } +} -body { + execsql { INSERT INTO t1 VALUES(a_string(200), a_string(300)) } +} -test { + faultsim_test_result {0 {}} + + if {[sqlite3_get_autocommit db]} { + sqlite3 db2 test.db + set nRow [db2 one {SELECT count(*) FROM t1}] + if {$nRow!=4} { error "Database content appears incorrect (1)" } + db2 close + } + + execsql { INSERT INTO t1 VALUES(a_string(201), a_string(301)) } + set nRow [db one {SELECT count(*) FROM t1}] + if {$nRow!=5 && $nRow!=66 && $nRow!=65} { + error "Database content appears incorrect (2) ($nRow)" + } + + catch { execsql COMMIT } +} + + + +finish_test diff --git a/test/pcache.test b/test/pcache.test index 5dc3059c44..0766fce088 100644 --- a/test/pcache.test +++ b/test/pcache.test @@ -44,6 +44,7 @@ do_test pcache-1.2 { execsql { PRAGMA cache_size=12; PRAGMA auto_vacuum=0; + PRAGMA mmap_size=0; } pcache_stats } {current 1 max 12 min 10 recyclable 1} diff --git a/test/percentile.test b/test/percentile.test index 29947b9dee..9d471dfcde 100644 --- a/test/percentile.test +++ b/test/percentile.test @@ -180,28 +180,30 @@ do_test percentile-1.21 { # Million-row Inputs # -do_test percentile-2.0 { - load_static_extension db wholenumber - execsql { - CREATE VIRTUAL TABLE nums USING wholenumber; - CREATE TABLE t3(x); - INSERT INTO t3 SELECT value-1 FROM nums WHERE value BETWEEN 1 AND 500000; - INSERT INTO t3 SELECT value*10 FROM nums - WHERE value BETWEEN 500000 AND 999999; - SELECT count(*) FROM t3; - } -} {1000000} -foreach {in out} { - 0 0.0 - 100 9999990.0 - 50 2749999.5 - 10 99999.9 -} { - do_test percentile-2.1.$in { +ifcapable vtab { + do_test percentile-2.0 { + load_static_extension db wholenumber execsql { - SELECT percentile(x, $in) from t3; + CREATE VIRTUAL TABLE nums USING wholenumber; + CREATE TABLE t3(x); + INSERT INTO t3 SELECT value-1 FROM nums WHERE value BETWEEN 1 AND 500000; + INSERT INTO t3 SELECT value*10 FROM nums + WHERE value BETWEEN 500000 AND 999999; + SELECT count(*) FROM t3; } - } $out + } {1000000} + foreach {in out} { + 0 0.0 + 100 9999990.0 + 50 2749999.5 + 10 99999.9 + } { + do_test percentile-2.1.$in { + execsql { + SELECT percentile(x, $in) from t3; + } + } $out + } } finish_test diff --git a/test/select9.test b/test/select9.test index 9f54014cf9..4c42236dc8 100644 --- a/test/select9.test +++ b/test/select9.test @@ -450,5 +450,23 @@ do_test select9-5.3 { } } {/SCAN TABLE/} ;# Full table scan if the "+x" prevents index usage. +# 2013-07-09: Ticket [490a4b7235624298]: +# "WHERE 0" on the first element of a UNION causes an assertion fault +# +do_execsql_test select9-6.1 { + CREATE TABLE t61(a); + CREATE TABLE t62(b); + INSERT INTO t61 VALUES(111); + INSERT INTO t62 VALUES(222); + SELECT a FROM t61 WHERE 0 UNION SELECT b FROM t62; +} {222} +do_execsql_test select9-6.2 { + SELECT a FROM t61 WHERE 0 UNION ALL SELECT b FROM t62; +} {222} +do_execsql_test select9-6.3 { + SELECT a FROM t61 UNION SELECT b FROM t62 WHERE 0; +} {111} + + finish_test diff --git a/test/shell1.test b/test/shell1.test index c60f3af702..25fb330de0 100644 --- a/test/shell1.test +++ b/test/shell1.test @@ -397,9 +397,9 @@ do_test shell1-3.11.1 { do_test shell1-3.11.2 { catchcmd "test.db" ".import FOO" } {1 {Error: unknown command or invalid arguments: "import". Enter ".help" for help}} -do_test shell1-3.11.2 { - catchcmd "test.db" ".import FOO BAR" -} {1 {Error: no such table: BAR}} +#do_test shell1-3.11.2 { +# catchcmd "test.db" ".import FOO BAR" +#} {1 {Error: no such table: BAR}} do_test shell1-3.11.3 { # too many arguments catchcmd "test.db" ".import FOO BAR BAD" @@ -710,6 +710,15 @@ do_test shell1-3-29.1 { catchcmd "test.db" ".print this is a test" } {0 {this is a test}} +# dot-command argument quoting +do_test shell1-3-30.1 { + catchcmd {test.db} {.print "this\"is'a\055test" 'this\"is\\a\055test'} +} {0 {this"is'a-test this\"is\\a\055test}} +do_test shell1-3-31.1 { + catchcmd {test.db} {.print "this\nis\ta\\test" 'this\nis\ta\\test'} +} [list 0 "this\nis\ta\\test this\\nis\\ta\\\\test"] + + # Test the output of the ".dump" command # do_test shell1-4.1 { diff --git a/test/shell5.test b/test/shell5.test index d90cedf949..6256b281bb 100644 --- a/test/shell5.test +++ b/test/shell5.test @@ -45,9 +45,9 @@ do_test shell5-1.1.1 { do_test shell5-1.1.2 { catchcmd "test.db" ".import FOO" } {1 {Error: unknown command or invalid arguments: "import". Enter ".help" for help}} -do_test shell5-1.1.2 { - catchcmd "test.db" ".import FOO BAR" -} {1 {Error: no such table: BAR}} +#do_test shell5-1.1.2 { +# catchcmd "test.db" ".import FOO BAR" +#} {1 {Error: no such table: BAR}} do_test shell5-1.1.3 { # too many arguments catchcmd "test.db" ".import FOO BAR BAD" @@ -101,7 +101,7 @@ do_test shell5-1.4.3 { puts $in "1" close $in set res [catchcmd "test.db" {.import shell5.csv t1}] -} {1 {Error: shell5.csv line 1: expected 2 columns of data but found 1}} +} {1 {shell5.csv:1: expected 2 columns but found 1 - filling the rest with NULL}} # import file with 1 row, 3 columns (expecting 2 cols) do_test shell5-1.4.4 { @@ -109,14 +109,15 @@ do_test shell5-1.4.4 { puts $in "1|2|3" close $in set res [catchcmd "test.db" {.import shell5.csv t1}] -} {1 {Error: shell5.csv line 1: expected 2 columns of data but found 3}} +} {1 {shell5.csv:1: expected 2 columns but found 3 - extras ignored}} # import file with 1 row, 2 columns do_test shell5-1.4.5 { set in [open shell5.csv w] puts $in "1|2" close $in - set res [catchcmd "test.db" {.import shell5.csv t1 + set res [catchcmd "test.db" {DELETE FROM t1; +.import shell5.csv t1 SELECT COUNT(*) FROM t1;}] } {0 1} @@ -197,15 +198,15 @@ SELECT length(b) FROM t1 WHERE a='8';}] # This is limited by SQLITE_MAX_VARIABLE_NUMBER, which defaults to 999. set cols 999 do_test shell5-1.6.1 { - set sql {CREATE TABLE t2(} set data {} for {set i 1} {$i<$cols} {incr i} { - append sql "c$i," + append data "c$i|" + } + append data "c$cols\n"; + for {set i 1} {$i<$cols} {incr i} { append data "$i|" } - append sql "c$cols);" append data "$cols" - catchcmd "test.db" $sql set in [open shell5.csv w] puts $in $data close $in @@ -214,16 +215,31 @@ SELECT COUNT(*) FROM t2;}] } {0 1} # try importing a large number of rows -set rows 999999 +set rows 9999 do_test shell5-1.7.1 { set in [open shell5.csv w] + puts $in a for {set i 1} {$i<=$rows} {incr i} { puts $in $i } close $in - set res [catchcmd "test.db" {CREATE TABLE t3(a); + set res [catchcmd "test.db" {.mode csv .import shell5.csv t3 SELECT COUNT(*) FROM t3;}] } [list 0 $rows] +# Inport from a pipe. (Unix only, as it requires "awk") +if {$tcl_platform(platform)=="unix"} { + do_test shell5-1.8 { + file delete -force test.db + catchcmd test.db {.mode csv +.import "|awk 'END{print \"x,y\";for(i=1;i<=5;i++){print i \",this is \" i}}'" t1 +SELECT * FROM t1;} + } {0 {1,"this is 1" +2,"this is 2" +3,"this is 3" +4,"this is 4" +5,"this is 5"}} +} + finish_test diff --git a/test/spellfix.test b/test/spellfix.test index dfa487a1b0..17ce70540e 100644 --- a/test/spellfix.test +++ b/test/spellfix.test @@ -105,6 +105,22 @@ do_test 1.14 { catchsql {SELECT next_char('','xyzzy','a')} } {1 {no such table: xyzzy}} +do_execsql_test 1.20 { + CREATE TABLE vocab2(w TEXT); + CREATE INDEX vocab2w ON vocab2(w COLLATE nocase); + INSERT INTO vocab2 VALUES('abc'), ('ABD'), ('aBe'), ('AbF'); + SELECT next_char('ab', 'vocab2', 'w', null, 'nocase'); +} {cDeF} +do_execsql_test 1.21 { + SELECT next_char('ab','vocab2','w',null,null); +} {c} +do_execsql_test 1.22 { + SELECT next_char('AB','vocab2','w',null,'NOCASE'); +} {cDeF} +do_execsql_test 1.23 { + SELECT next_char('ab','vocab2','w',null,'binary'); +} {c} + do_execsql_test 2.1 { CREATE VIRTUAL TABLE t2 USING spellfix1; INSERT INTO t2 (word, soundslike) VALUES('school', 'skuul'); diff --git a/test/tkt-868145d012.test b/test/tkt-868145d012.test new file mode 100644 index 0000000000..145d159e54 --- /dev/null +++ b/test/tkt-868145d012.test @@ -0,0 +1,64 @@ +# 2013 March 05 +# +# 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 implements regression tests for SQLite library. Specifically, +# it tests that ticket [868145d012a1] is fixed. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +do_execsql_test tkt-868145d012.100 { + CREATE TABLE p ( + id INTEGER PRIMARY KEY, + uid VARCHAR(36), + t INTEGER + ); + + CREATE TABLE pa ( + id INTEGER PRIMARY KEY, + a_uid VARCHAR(36) + ); + + CREATE TABLE a ( + id INTEGER PRIMARY KEY, + uid VARCHAR(36), + t INTEGER + ); + + INSERT INTO pa VALUES(1,'1234'); + INSERT INTO pa VALUES(2,'2345'); + INSERT INTO p VALUES(3,'1234',97); + INSERT INTO p VALUES(4,'1234',98); + INSERT INTO a VALUES(5,'1234',98); + INSERT INTO a VALUES(6,'1234',99); +} {} +do_execsql_test tkt-868145d012.110 { + SELECT DISTINCT pa.id, p.id, a.id + FROM + pa + LEFT JOIN p ON p.uid='1234' + LEFT JOIN a ON a.uid=pa.a_uid + WHERE + a.t=p.t + ; +} {1 4 5} +do_execsql_test tkt-868145d012.120 { + SELECT DISTINCT pa.id, p.id, a.id + FROM + pa + LEFT JOIN p ON p.uid='1234' + LEFT JOIN a ON a.uid=pa.a_uid AND a.t=p.t + ORDER BY 1, 2, 3 + ; +} {1 3 {} 1 4 5 2 3 {} 2 4 {}} + + +finish_test diff --git a/test/transitive1.test b/test/transitive1.test index ff81af6421..4cf439bb45 100644 --- a/test/transitive1.test +++ b/test/transitive1.test @@ -47,4 +47,59 @@ do_execsql_test transitive1-220 { SELECT * FROM t2 WHERE a=b AND c=b AND c<=20 ORDER BY +a; } {20 20 20 100 100 100} +# Test cases for ticket [[d805526eae253103] 2013-07-08 +# "Incorrect join result or assertion fault due to transitive constraints" +# +do_execsql_test transitive1-300 { + CREATE TABLE t301(w INTEGER PRIMARY KEY, x); + CREATE TABLE t302(y INTEGER UNIQUE, z); + INSERT INTO t301 VALUES(1,2),(3,4),(5,6); + INSERT INTO t302 VALUES(1,3),(3,6),(5,7); + SELECT * + FROM t301 CROSS JOIN t302 + WHERE w=y AND y IS NOT NULL + ORDER BY +w; +} {1 2 1 3 3 4 3 6 5 6 5 7} +do_execsql_test transitive1-301 { + SELECT * + FROM t301 CROSS JOIN t302 + WHERE w=y AND y IS NOT NULL + ORDER BY w; +} {1 2 1 3 3 4 3 6 5 6 5 7} +do_execsql_test transitive1-310 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y>1 + ORDER BY +w +} {3 4 3 6 5 6 5 7} +do_execsql_test transitive1-311 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y>1 + ORDER BY w +} {3 4 3 6 5 6 5 7} +do_execsql_test transitive1-312 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y>1 + ORDER BY w DESC +} {5 6 5 7 3 4 3 6} +do_execsql_test transitive1-320 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y BETWEEN 2 AND 4; +} {3 4 3 6} +do_execsql_test transitive1-331 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y BETWEEN 1 AND 4 + ORDER BY w; +} {1 2 1 3 3 4 3 6} +do_execsql_test transitive1-332 { + SELECT * + FROM t301 CROSS JOIN t302 ON w=y + WHERE y BETWEEN 1 AND 4 + ORDER BY w DESC; +} {3 4 3 6 1 2 1 3} + finish_test diff --git a/test/wal6.test b/test/wal6.test index ec31bb8b0f..2498907ea9 100644 --- a/test/wal6.test +++ b/test/wal6.test @@ -14,6 +14,7 @@ # set testdir [file dirname $argv0] +set testprefix wal6 source $testdir/tester.tcl source $testdir/lock_common.tcl source $testdir/wal_common.tcl @@ -29,18 +30,18 @@ forcedelete test.db set all_journal_modes {delete persist truncate memory off} foreach jmode $all_journal_modes { - do_test wal6-1.0.$jmode { + do_test wal6-1.0.$jmode { sqlite3 db test.db execsql "PRAGMA journal_mode = $jmode;" - } $jmode + } $jmode - do_test wal6-1.1.$jmode { - execsql { - CREATE TABLE t1(a INTEGER PRIMARY KEY, b); - INSERT INTO t1 VALUES(1,2); - SELECT * FROM t1; - } - } {1 2} + do_test wal6-1.1.$jmode { + execsql { + CREATE TABLE t1(a INTEGER PRIMARY KEY, b); + INSERT INTO t1 VALUES(1,2); + SELECT * FROM t1; + } + } {1 2} # Under Windows, you'll get an error trying to delete # a file this is already opened. Close the first connection @@ -51,31 +52,146 @@ if {$tcl_platform(platform)=="windows"} { } } - do_test wal6-1.2.$jmode { - sqlite3 db2 test.db - execsql { - PRAGMA journal_mode=WAL; - INSERT INTO t1 VALUES(3,4); - SELECT * FROM t1 ORDER BY a; - } db2 - } {wal 1 2 3 4} + do_test wal6-1.2.$jmode { + sqlite3 db2 test.db + execsql { + PRAGMA journal_mode=WAL; + INSERT INTO t1 VALUES(3,4); + SELECT * FROM t1 ORDER BY a; + } db2 + } {wal 1 2 3 4} if {$tcl_platform(platform)=="windows"} { if {$jmode=="persist" || $jmode=="truncate"} { - sqlite3 db test.db + sqlite3 db test.db } } - do_test wal6-1.3.$jmode { - execsql { - SELECT * FROM t1 ORDER BY a; - } - } {1 2 3 4} + do_test wal6-1.3.$jmode { + execsql { + SELECT * FROM t1 ORDER BY a; + } + } {1 2 3 4} - db close - db2 close + db close + db2 close forcedelete test.db } +#------------------------------------------------------------------------- +# Test that SQLITE_BUSY_SNAPSHOT is returned as expected. +# +reset_db +sqlite3 db2 test.db + +do_execsql_test 2.1 { + PRAGMA journal_mode = WAL; + CREATE TABLE t1(a PRIMARY KEY, b TEXT); + INSERT INTO t1 VALUES(1, 'one'); + INSERT INTO t1 VALUES(2, 'two'); + BEGIN; + SELECT * FROM t1; +} {wal 1 one 2 two} + +do_test 2.2 { + execsql { + SELECT * FROM t1; + INSERT INTO t1 VALUES(3, 'three'); + } db2 +} {1 one 2 two} + +do_catchsql_test 2.3 { + INSERT INTO t1 VALUES('x', 'x') +} {1 {database is locked}} + +do_test 2.4 { + list [sqlite3_errcode db] [sqlite3_extended_errcode db] +} {SQLITE_BUSY SQLITE_BUSY_SNAPSHOT} + +do_execsql_test 2.5 { + SELECT * FROM t1; + COMMIT; + INSERT INTO t1 VALUES('x', 'x') +} {1 one 2 two} + +proc test3 {prefix} { + do_test $prefix.1 { + execsql { SELECT count(*) FROM t1 } + } {0} + do_test $prefix.2 { + execsql { INSERT INTO t1 VALUES('x', 'x') } db2 + } {} + do_test $prefix.3 { + execsql { INSERT INTO t1 VALUES('y', 'y') } + } {} + do_test $prefix.4 { + execsql { SELECT count(*) FROM t1 } + } {2} +} + +do_execsql_test 2.6.1 { DELETE FROM t1 } +test3 2.6.2 + +db func test3 test3 +do_execsql_test 2.6.3 { DELETE FROM t1 } +db eval {SELECT test3('2.6.4')} + +do_test 2.x { + db2 close +} {} + +#------------------------------------------------------------------------- +# Check that if BEGIN IMMEDIATE fails, it does not leave the user with +# an open read-transaction (unless one was already open before the BEGIN +# IMMEDIATE). Even if there are other active VMs. +# + +proc test4 {prefix} { + do_test $prefix.1 { + catchsql { BEGIN IMMEDIATE } + } {1 {database is locked}} + + do_test $prefix.2 { + execsql { COMMIT } db2 + } {} + + do_test $prefix.3 { + execsql { BEGIN IMMEDIATE } + } {} + do_test $prefix.4 { + execsql { COMMIT } + } {} +} + +reset_db +sqlite3 db2 test.db +do_execsql_test 3.1 { + PRAGMA journal_mode = WAL; + CREATE TABLE ab(a PRIMARY KEY, b); +} {wal} + +do_test 3.2.1 { + execsql { + BEGIN; + INSERT INTO ab VALUES(1, 2); + } db2 +} {} +test4 3.2.2 + +db func test4 test4 +do_test 3.3.1 { + execsql { + BEGIN; + INSERT INTO ab VALUES(3, 4); + } db2 +} {} + +db eval {SELECT test4('3.3.2')} + +do_test 3.x { + db2 close +} {} + finish_test + diff --git a/test/where2.test b/test/where2.test index e57192d85c..3d4dfc9126 100644 --- a/test/where2.test +++ b/test/where2.test @@ -307,6 +307,8 @@ do_test where2-6.6 { } } [list 1 0 4 4 2 1 9 10 sort a i1w b $::idx] +if {[permutation] != "no_optimization"} { + # Ticket #2249. Make sure the OR optimization is not attempted if # comparisons between columns of different affinities are needed. # @@ -474,6 +476,8 @@ do_test where2-7.4 { } } {1 2 3 2 3 nosort} +} ;# if {[permutation] != "no_optimization"} + # Ticket #1807. Using IN constrains on multiple columns of # a multi-column index. # diff --git a/test/where3.test b/test/where3.test index a5137173f2..72ae98b6c6 100644 --- a/test/where3.test +++ b/test/where3.test @@ -436,5 +436,48 @@ foreach predicate { } {1 w-one x-one y-one z-one 9 w-nine x-nine y-nine z-nine} } +do_execsql_test where3-7-setup { + CREATE TABLE t71(x1 INTEGER PRIMARY KEY, y1); + CREATE TABLE t72(x2 INTEGER PRIMARY KEY, y2); + CREATE TABLE t73(x3, y3); + CREATE TABLE t74(x4, y4); + INSERT INTO t71 VALUES(123,234); + INSERT INTO t72 VALUES(234,345); + INSERT INTO t73 VALUES(123,234); + INSERT INTO t74 VALUES(234,345); + INSERT INTO t74 VALUES(234,678); +} {} +foreach disabled_opt {none omit-noop-join all} { + optimization_control db all 1 + optimization_control db $disabled_opt 0 + do_execsql_test where3-7.$disabled_opt.1 { + SELECT x1 FROM t71 LEFT JOIN t72 ON x2=y1; + } {123} + do_execsql_test where3-7.$disabled_opt.2 { + SELECT x1 FROM t71 LEFT JOIN t72 ON x2=y1 WHERE y2 IS NULL; + } {} + do_execsql_test where3-7.$disabled_opt.3 { + SELECT x1 FROM t71 LEFT JOIN t72 ON x2=y1 WHERE y2 IS NOT NULL; + } {123} + do_execsql_test where3-7.$disabled_opt.4 { + SELECT x1 FROM t71 LEFT JOIN t72 ON x2=y1 AND y2 IS NULL; + } {123} + do_execsql_test where3-7.$disabled_opt.5 { + SELECT x1 FROM t71 LEFT JOIN t72 ON x2=y1 AND y2 IS NOT NULL; + } {123} + do_execsql_test where3-7.$disabled_opt.6 { + SELECT x3 FROM t73 LEFT JOIN t72 ON x2=y3; + } {123} + do_execsql_test where3-7.$disabled_opt.7 { + SELECT DISTINCT x3 FROM t73 LEFT JOIN t72 ON x2=y3; + } {123} + do_execsql_test where3-7.$disabled_opt.8 { + SELECT x3 FROM t73 LEFT JOIN t74 ON x4=y3; + } {123 123} + do_execsql_test where3-7.$disabled_opt.9 { + SELECT DISTINCT x3 FROM t73 LEFT JOIN t74 ON x4=y3; + } {123} +} + finish_test diff --git a/test/wild001.test b/test/wild001.test new file mode 100644 index 0000000000..7fe1404294 --- /dev/null +++ b/test/wild001.test @@ -0,0 +1,311 @@ +# 2013-07-01 +# +# 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 a test case from content taken "from the wild". In this +# particular instance, the query was provided with permission by +# Elan Feingold on 2013-06-27. His message on the SQLite mailing list +# on that date reads: +# +#------------------------------------------------------------------------------ +# > Can you send (1) the schema (2) the query that is giving problems, and (3) +# > the content of the sqlite_stat1 table after you have run ANALYZE? If you +# > can combine all of the above into a script, that would be great! +# > +# > If you send (1..3) above and you give us written permission to include the +# > query in our test suite, that would be off-the-chain terrific. +# +# Please find items 1..3 in this file: http://www.plexapp.com/elan/sqlite_bug.txt +# +# You have our permission to include the query in your test suite. +# +# Thanks for an amazing product. +#----------------------------------------------------------------------------- +# +# This test case merely creates the schema and populates SQLITE_STAT1 and +# SQLITE_STAT3 then runs an EXPLAIN QUERY PLAN to ensure that the right plan +# is discovered. This test case may need to be adjusted for future revisions +# of the query planner manage to select a better query plan. The query plan +# shown here is known to be very fast with the original data. +# +# This test should work the same with and without SQLITE_ENABLE_STAT3 +# +############################################################################### + +set testdir [file dirname $argv0] +source $testdir/tester.tcl + +ifcapable !stat3 { + finish_test + return +} + +do_execsql_test wild001.01 { + CREATE TABLE "items" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "secid" integer, "parent_id" integer, "metadata_type" integer, "guid" varchar(255), "media_item_count" integer, "title" varchar(255), "title_sort" varchar(255) COLLATE NOCASE, "original_title" varchar(255), "studio" varchar(255), "rating" float, "rating_count" integer, "tagline" varchar(255), "summary" text, "trivia" text, "quotes" text, "content_rating" varchar(255), "content_rating_age" integer, "index" integer, "absolute_index" integer, "duration" integer, "user_thumb_url" varchar(255), "user_art_url" varchar(255), "user_banner_url" varchar(255), "user_music_url" varchar(255), "user_fields" varchar(255), "tags_genre" varchar(255), "tags_collection" varchar(255), "tags_director" varchar(255), "tags_writer" varchar(255), "tags_star" varchar(255), "originally_available_at" datetime, "available_at" datetime, "expires_at" datetime, "refreshed_at" datetime, "year" integer, "added_at" datetime, "created_at" datetime, "updated_at" datetime, "deleted_at" datetime, "tags_country" varchar(255), "extra_data" varchar(255), "hash" varchar(255)); + CREATE INDEX "i_secid" ON "items" ("secid" ); + CREATE INDEX "i_parent_id" ON "items" ("parent_id" ); + CREATE INDEX "i_created_at" ON "items" ("created_at" ); + CREATE INDEX "i_index" ON "items" ("index" ); + CREATE INDEX "i_title" ON "items" ("title" ); + CREATE INDEX "i_title_sort" ON "items" ("title_sort" ); + CREATE INDEX "i_guid" ON "items" ("guid" ); + CREATE INDEX "i_metadata_type" ON "items" ("metadata_type" ); + CREATE INDEX "i_deleted_at" ON "items" ("deleted_at" ); + CREATE INDEX "i_secid_ex1" ON "items" ("secid", "metadata_type", "added_at" ); + CREATE INDEX "i_hash" ON "items" ("hash" ); + CREATE TABLE "settings" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "account_id" integer, "guid" varchar(255), "rating" float, "view_offset" integer, "view_count" integer, "last_viewed_at" datetime, "created_at" datetime, "updated_at" datetime); + CREATE INDEX "s_account_id" ON "settings" ("account_id" ); + CREATE INDEX "s_guid" ON "settings" ("guid" ); + ANALYZE; + INSERT INTO sqlite_stat1 VALUES('settings','s_guid','4740 1'); + INSERT INTO sqlite_stat1 VALUES('settings','s_account_id','4740 4740'); + INSERT INTO sqlite_stat1 VALUES('items','i_hash','27316 2'); + INSERT INTO sqlite_stat1 VALUES('items','i_secid_ex1','27316 6829 4553 3'); + INSERT INTO sqlite_stat1 VALUES('items','i_deleted_at','27316 27316'); + INSERT INTO sqlite_stat1 VALUES('items','i_metadata_type','27316 6829'); + INSERT INTO sqlite_stat1 VALUES('items','i_guid','27316 2'); + INSERT INTO sqlite_stat1 VALUES('items','i_title_sort','27316 2'); + INSERT INTO sqlite_stat1 VALUES('items','i_title','27316 2'); + INSERT INTO sqlite_stat1 VALUES('items','i_index','27316 144'); + INSERT INTO sqlite_stat1 VALUES('items','i_created_at','27316 2'); + INSERT INTO sqlite_stat1 VALUES('items','i_parent_id','27316 15'); + INSERT INTO sqlite_stat1 VALUES('items','i_secid','27316 6829'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,150,150,'com.plexapp.agents.thetvdb://153021/2/9?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,198,198,'com.plexapp.agents.thetvdb://194031/1/10?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,526,526,'com.plexapp.agents.thetvdb://71256/12/92?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,923,923,'com.plexapp.agents.thetvdb://71256/15/16?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1008,1008,'com.plexapp.agents.thetvdb://71256/15/93?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1053,1053,'com.plexapp.agents.thetvdb://71256/16/21?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1068,1068,'com.plexapp.agents.thetvdb://71256/16/35?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1235,1235,'com.plexapp.agents.thetvdb://71256/17/44?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1255,1255,'com.plexapp.agents.thetvdb://71256/17/62?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1573,1573,'com.plexapp.agents.thetvdb://71663/20/9?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,1580,1580,'com.plexapp.agents.thetvdb://71663/21/16?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2000,2000,'com.plexapp.agents.thetvdb://73141/9/8?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2107,2107,'com.plexapp.agents.thetvdb://73244/6/17?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2256,2256,'com.plexapp.agents.thetvdb://74845/4/7?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2408,2408,'com.plexapp.agents.thetvdb://75978/2/21?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2634,2634,'com.plexapp.agents.thetvdb://79126/1/1?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,2962,2962,'com.plexapp.agents.thetvdb://79274/3/94?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3160,3160,'com.plexapp.agents.thetvdb://79274/5/129?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3161,3161,'com.plexapp.agents.thetvdb://79274/5/12?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3688,3688,'com.plexapp.agents.thetvdb://79274/8/62?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,3714,3714,'com.plexapp.agents.thetvdb://79274/8/86?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,4002,4002,'com.plexapp.agents.thetvdb://79590/13/17?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,4215,4215,'com.plexapp.agents.thetvdb://80727/3/6?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_guid',1,4381,4381,'com.plexapp.agents.thetvdb://83462/3/24?lang=en'); + INSERT INTO sqlite_stat3 VALUES('settings','s_account_id',4740,0,0,1); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,1879,1879,'1113f632ccd52ec8b8d7ca3d6d56da4701e48018'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,2721,2721,'1936154b97bb5567163edaebc2806830ae419ccf'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,3035,3035,'1c122331d4b7bfa0dc2c003ab5fb4f7152b9987a'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,3393,3393,'1f81bdbc9acc3321dc592b1a109ca075731b549a'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,6071,6070,'393cf7713efb4519c7a3d1d5403f0d945d15a16a'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,7462,7461,'4677dd37011f8bd9ae7fbbdd3af6dcd8a5b4ab2d'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,8435,8434,'4ffa339485334e81a5e12e03a63b6508d76401cf'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,8716,8714,'52a093852e6599dd5004857b7ff5b5b82c7cdb25'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,9107,9104,'561183e39f866d97ec728e9ff16ac4ad01466111'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,10942,10939,'66e99b72e29610f49499ae09ee04a376210d1f08'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,12143,12139,'71f0602427e173dc2c551535f73fdb6885fe4302'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,14962,14958,'8ca8e4dfba696019830c19ab8a32c7ece9d8534b'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,15179,15174,'8ebf1a5cf33f8ada1fc5853ac06ac4d7e074f825'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,15375,15370,'908bc211bebdf21c79d2d2b54ebaa442ac1f5cae'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,18215,18210,'ab29e4e18ec5a14fef95aa713d69e31c045a22c1'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,18615,18610,'ae84c008cc0c338bf4f28d798a88575746452f6d'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,18649,18644,'aec7c901353e115aa5307e94018ba7507bec3a45'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,19517,19512,'b75025fbf2e9c504e3c1197ff1b69250402a31f8'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,21251,21245,'c7d32f0e3a8f3a0a3dbd00833833d2ccee62f0fd'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,23616,23610,'dd5ff61479a9bd4100de802515d9dcf72d46f07a'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,24287,24280,'e3db00034301b7555419d4ef6f64769298d5845e'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,24949,24942,'ea336abd197ecd7013854a25a4f4eb9dea7927c6'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',1,25574,25567,'f018ea5182ec3f32768ca1c3cefbf3ad160ec20b'); + INSERT INTO sqlite_stat3 VALUES('items','i_hash',2,26139,26132,'f53709a8d81c12cb0f4f8d58004a25dd063de67c'); + INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',25167,0,0,2); + INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',736,25167,1,3); + INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',15,25903,2,4); + INSERT INTO sqlite_stat3 VALUES('items','i_secid_ex1',1398,25918,3,5); + INSERT INTO sqlite_stat3 VALUES('items','i_deleted_at',27316,0,0,NULL); + INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',2149,0,0,1); + INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',411,2149,1,2); + INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',1440,2560,2,3); + INSERT INTO sqlite_stat3 VALUES('items','i_metadata_type',23316,4000,3,4); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,215,215,'com.plexapp.agents.imdb://tt0065702?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,711,711,'com.plexapp.agents.imdb://tt0198781?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,987,986,'com.plexapp.agents.imdb://tt0454876?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1004,1002,'com.plexapp.agents.imdb://tt0464154?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1056,1053,'com.plexapp.agents.imdb://tt0499549?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1120,1116,'com.plexapp.agents.imdb://tt0903624?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1250,1245,'com.plexapp.agents.imdb://tt1268799?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1270,1264,'com.plexapp.agents.imdb://tt1320261?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',2,1376,1369,'com.plexapp.agents.imdb://tt1772341?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,3035,3027,'com.plexapp.agents.thetvdb://153021/3/14?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,6071,6063,'com.plexapp.agents.thetvdb://71173/1/18?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,6342,6334,'com.plexapp.agents.thetvdb://71256/13/4?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,9107,9099,'com.plexapp.agents.thetvdb://72389/2/19?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,11740,11732,'com.plexapp.agents.thetvdb://73893/2/13?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,12143,12135,'com.plexapp.agents.thetvdb://73976/4/23?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,15179,15171,'com.plexapp.agents.thetvdb://75897/16/12?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,17408,17400,'com.plexapp.agents.thetvdb://76808/2/16?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,17984,17976,'com.plexapp.agents.thetvdb://77068/1/16?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,18215,18207,'com.plexapp.agents.thetvdb://77259/1/1?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,21251,21243,'com.plexapp.agents.thetvdb://78957/8/2?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,24287,24279,'com.plexapp.agents.thetvdb://80337/5/8?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,25513,25505,'com.plexapp.agents.thetvdb://82226/6?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,25548,25540,'com.plexapp.agents.thetvdb://82339/2/10?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_guid',1,26770,26762,'com.plexapp.agents.thetvdb://86901/1/3?lang=en'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1524,0,0,''); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',2,3034,1391,'Attack of the Giant Squid'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',51,4742,2895,'Brad Sherwood'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',11,4912,2996,'Brian Williams'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',39,5847,3857,'Chip Esten'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,6071,4015,'Chuck Versus the DeLorean'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',12,7625,5436,'Denny Siegel'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',30,8924,6618,'Episode 1'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',29,9015,6629,'Episode 2'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',32,9082,6643,'Episode 3'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',28,9135,6654,'Episode 4'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',26,9183,6665,'Episode 5'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',27,9229,6677,'Episode 6'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',22,9266,6688,'Episode 7'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',20,9298,6699,'Episode 8'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',55,11750,8817,'Greg Proops'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,12143,9120,'Hardware Jungle'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',33,14712,11435,'Kathy Greenwood'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',3,15179,11840,'Last Call'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,18215,14601,'Nature or Nurture?'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',12,18241,14623,'Neil DeGrasse Tyson'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',68,19918,16144,'Pilot'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',7,21251,17298,'Reza Aslan'); + INSERT INTO sqlite_stat3 VALUES('items','i_title_sort',1,24287,20035,'Technoviking'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1524,0,0,''); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,3035,1429,'Anderson Can''t Dance'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',51,4782,2991,'Brad Sherwood'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',11,4936,3079,'Brian Williams'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',39,5694,3783,'Chip Esten'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,6071,4100,'Clive Warren'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',12,7144,5078,'Denny Siegel'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',30,8249,6097,'Episode 1'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',29,8340,6108,'Episode 2'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',32,8407,6122,'Episode 3'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',28,8460,6133,'Episode 4'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',26,8508,6144,'Episode 5'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',27,8554,6156,'Episode 6'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',22,8591,6167,'Episode 7'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',20,8623,6178,'Episode 8'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,9107,6537,'Fat Albert and the Cosby Kids'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',55,10539,7843,'Greg Proops'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,12143,9276,'Iron Age Remains'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',33,13118,10143,'Kathy Greenwood'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,15179,11972,'Mink'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',68,17411,14035,'Pilot'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',2,18214,14727,'Reflections'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',4,21250,17481,'The Apartment'); + INSERT INTO sqlite_stat3 VALUES('items','i_title',1,24287,20283,'The Simpsons Already Did It'); + INSERT INTO sqlite_stat3 VALUES('items','i_index',4315,95,2,1); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1553,4410,3,2); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1485,5963,4,3); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1414,7448,5,4); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1367,8862,6,5); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1328,10229,7,6); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1161,11557,8,7); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1108,12718,9,8); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1033,13826,10,9); + INSERT INTO sqlite_stat3 VALUES('items','i_index',1014,14859,11,10); + INSERT INTO sqlite_stat3 VALUES('items','i_index',929,15873,12,11); + INSERT INTO sqlite_stat3 VALUES('items','i_index',906,16802,13,12); + INSERT INTO sqlite_stat3 VALUES('items','i_index',844,17708,14,13); + INSERT INTO sqlite_stat3 VALUES('items','i_index',690,18552,15,14); + INSERT INTO sqlite_stat3 VALUES('items','i_index',655,19242,16,15); + INSERT INTO sqlite_stat3 VALUES('items','i_index',625,19897,17,16); + INSERT INTO sqlite_stat3 VALUES('items','i_index',579,20522,18,17); + INSERT INTO sqlite_stat3 VALUES('items','i_index',555,21101,19,18); + INSERT INTO sqlite_stat3 VALUES('items','i_index',526,21656,20,19); + INSERT INTO sqlite_stat3 VALUES('items','i_index',501,22182,21,20); + INSERT INTO sqlite_stat3 VALUES('items','i_index',459,22683,22,21); + INSERT INTO sqlite_stat3 VALUES('items','i_index',439,23142,23,22); + INSERT INTO sqlite_stat3 VALUES('items','i_index',315,23581,24,23); + INSERT INTO sqlite_stat3 VALUES('items','i_index',192,24177,26,25); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1851,0,0,NULL); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',373,1857,2,'2011-10-22 14:54:39'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',595,2230,3,'2011-10-22 14:54:41'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',337,2825,4,'2011-10-22 14:54:43'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',361,3378,8,'2011-10-22 14:54:54'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',160,3739,9,'2011-10-22 14:54:56'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',315,4000,11,'2011-10-22 14:54:59'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',321,4334,13,'2011-10-22 14:55:02'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1292,4723,16,'2011-10-22 14:55:06'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',161,6015,17,'2011-10-22 14:55:07'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1,9107,2677,'2012-09-04 18:07:50'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',313,9717,3270,'2012-10-18 16:50:21'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',450,10030,3271,'2012-10-18 16:50:22'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',389,10668,3275,'2012-10-18 16:50:26'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',796,11057,3276,'2012-10-18 16:51:06'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',161,12041,3280,'2012-10-19 19:52:37'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',135,13281,4186,'2013-02-19 00:56:10'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1063,13416,4187,'2013-02-19 00:56:11'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',797,14479,4188,'2013-02-19 00:56:13'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',147,15276,4189,'2013-02-19 00:56:15'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',346,15423,4190,'2013-02-19 00:56:16'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1,18215,6436,'2013-05-05 14:09:54'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',2,21251,8122,'2013-05-24 15:25:45'); + INSERT INTO sqlite_stat3 VALUES('items','i_created_at',1,24287,11116,'2013-05-26 14:17:39'); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',2560,0,0,NULL); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',18,3022,31,2350); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',10,6068,285,8150); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',158,6346,315,8949); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',34,9094,562,18831); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',20,12139,794,22838); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',134,14033,886,24739); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',159,14167,887,24740); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,14326,888,24741); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,14487,889,24742); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',124,14648,890,24743); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',157,14772,891,24744); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',126,15043,894,24747); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',40,15169,895,24748); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,15243,898,24753); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',138,15404,899,24754); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',160,15542,900,24755); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,15702,901,24756); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',161,15863,902,24757); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',124,16024,903,24758); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',155,16148,904,24759); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',26,18208,1043,29704); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',2,21251,1282,32952); + INSERT INTO sqlite_stat3 VALUES('items','i_parent_id',13,24279,1583,36068); + INSERT INTO sqlite_stat3 VALUES('items','i_secid',25167,0,0,2); + INSERT INTO sqlite_stat3 VALUES('items','i_secid',736,25167,1,3); + INSERT INTO sqlite_stat3 VALUES('items','i_secid',15,25903,2,4); + INSERT INTO sqlite_stat3 VALUES('items','i_secid',1398,25918,3,5); + ANALYZE sqlite_master; + + explain query plan + select items.title + from items + join items as child on child.parent_id=items.id + join items as grandchild on grandchild.parent_id=child.id + join settings + on settings.guid=grandchild.guid + and settings.account_id=1 + where items.metadata_type=2 + and items.secid=2 + and settings.last_viewed_at is not null + group by items.id + order by settings.last_viewed_at desc + limit 10; +} [list \ + 0 0 3 {SEARCH TABLE settings USING INDEX s_account_id (account_id=?)} \ + 0 1 2 {SEARCH TABLE items AS grandchild USING INDEX i_guid (guid=?)} \ + 0 2 1 {SEARCH TABLE items AS child USING INTEGER PRIMARY KEY (rowid=?)} \ + 0 3 0 {SEARCH TABLE items USING INTEGER PRIMARY KEY (rowid=?)} \ + 0 0 0 {USE TEMP B-TREE FOR GROUP BY} \ + 0 0 0 {USE TEMP B-TREE FOR ORDER BY}] + + +finish_test