diff options
author | Ilia Alshanetsky <iliaa@php.net> | 2004-01-14 17:08:27 +0000 |
---|---|---|
committer | Ilia Alshanetsky <iliaa@php.net> | 2004-01-14 17:08:27 +0000 |
commit | 6e350b553bedcfe4694a7118d8b44f80266201f4 (patch) | |
tree | 8be4ab1f00c7a24b19cacbd527d83b6ec61aa265 /ext/sqlite/libsqlite/src | |
parent | 49b698c67ed0f8408c54d0754672e552376b7554 (diff) | |
download | php-git-6e350b553bedcfe4694a7118d8b44f80266201f4.tar.gz |
Upgraded bundled libsqlite to 2.8.11 (fixed critical bug of *NIX systems).
Diffstat (limited to 'ext/sqlite/libsqlite/src')
-rw-r--r-- | ext/sqlite/libsqlite/src/btree_rb.c | 19 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/date.c | 72 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/hash.c | 6 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/hash.h | 2 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/opcodes.c | 2 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/opcodes.h | 106 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/os.c | 256 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/os.h | 9 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/pager.c | 2 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/printf.c | 6 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/select.c | 13 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/sqliteInt.h | 9 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/tokenize.c | 246 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/util.c | 10 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/vdbe.c | 133 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/vdbeInt.h | 13 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/vdbeaux.c | 48 | ||||
-rw-r--r-- | ext/sqlite/libsqlite/src/where.c | 40 |
18 files changed, 646 insertions, 346 deletions
diff --git a/ext/sqlite/libsqlite/src/btree_rb.c b/ext/sqlite/libsqlite/src/btree_rb.c index 928c4e977c..49009be830 100644 --- a/ext/sqlite/libsqlite/src/btree_rb.c +++ b/ext/sqlite/libsqlite/src/btree_rb.c @@ -618,10 +618,12 @@ int sqliteRbtreeOpen( ){ Rbtree **ppRbtree = (Rbtree**)ppBtree; *ppRbtree = (Rbtree *)sqliteMalloc(sizeof(Rbtree)); + if( sqlite_malloc_failed ) goto open_no_mem; sqliteHashInit(&(*ppRbtree)->tblHash, SQLITE_HASH_INT, 0); /* Create a binary tree for the SQLITE_MASTER table at location 2 */ btreeCreateTable(*ppRbtree, 2); + if( sqlite_malloc_failed ) goto open_no_mem; (*ppRbtree)->next_idx = 3; (*ppRbtree)->pOps = &sqliteRbtreeOps; /* Set file type to 4; this is so that "attach ':memory:' as ...." does not @@ -630,6 +632,10 @@ int sqliteRbtreeOpen( (*ppRbtree)->aMetaData[2] = 4; return SQLITE_OK; + +open_no_mem: + *ppBtree = 0; + return SQLITE_NOMEM; } /* @@ -642,11 +648,13 @@ static int memRbtreeCreateTable(Rbtree* tree, int* n) *n = tree->next_idx++; btreeCreateTable(tree, *n); + if( sqlite_malloc_failed ) return SQLITE_NOMEM; /* Set up the rollback structure (if we are not doing this as part of a * rollback) */ if( tree->eTransState != TRANS_ROLLBACK ){ BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp)); + if( pRollbackOp==0 ) return SQLITE_NOMEM; pRollbackOp->eOp = ROLLBACK_DROP; pRollbackOp->iTab = *n; btreeLogRollbackOp(tree, pRollbackOp); @@ -671,6 +679,7 @@ static int memRbtreeDropTable(Rbtree* tree, int n) if( tree->eTransState != TRANS_ROLLBACK ){ BtRollbackOp *pRollbackOp = sqliteMalloc(sizeof(BtRollbackOp)); + if( pRollbackOp==0 ) return SQLITE_NOMEM; pRollbackOp->eOp = ROLLBACK_CREATE; pRollbackOp->iTab = n; btreeLogRollbackOp(tree, pRollbackOp); @@ -712,6 +721,7 @@ static int memRbtreeCursor( RbtCursor *pCur; assert(tree); pCur = *ppCur = sqliteMalloc(sizeof(RbtCursor)); + if( sqlite_malloc_failed ) return SQLITE_NOMEM; pCur->pTree = sqliteHashFind(&tree->tblHash, 0, iTable); pCur->pRbtree = tree; pCur->iTree = iTable; @@ -755,6 +765,7 @@ static int memRbtreeInsert( /* Take a copy of the input data now, in case we need it for the * replace case */ pData = sqliteMallocRaw(nData); + if( sqlite_malloc_failed ) return SQLITE_NOMEM; memcpy(pData, pDataInput, nData); /* Move the cursor to a node near the key to be inserted. If the key already @@ -771,8 +782,10 @@ static int memRbtreeInsert( memRbtreeMoveto( pCur, pKey, nKey, &match); if( match ){ BtRbNode *pNode = sqliteMalloc(sizeof(BtRbNode)); + if( pNode==0 ) return SQLITE_NOMEM; pNode->nKey = nKey; pNode->pKey = sqliteMallocRaw(nKey); + if( sqlite_malloc_failed ) return SQLITE_NOMEM; memcpy(pNode->pKey, pKey, nKey); pNode->nData = nData; pNode->pData = pData; @@ -804,10 +817,12 @@ static int memRbtreeInsert( /* Set up a rollback-op in case we have to roll this operation back */ if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){ BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) ); + if( pOp==0 ) return SQLITE_NOMEM; pOp->eOp = ROLLBACK_DELETE; pOp->iTab = pCur->iTree; pOp->nKey = pNode->nKey; pOp->pKey = sqliteMallocRaw( pOp->nKey ); + if( sqlite_malloc_failed ) return SQLITE_NOMEM; memcpy( pOp->pKey, pNode->pKey, pOp->nKey ); btreeLogRollbackOp(pCur->pRbtree, pOp); } @@ -819,9 +834,11 @@ static int memRbtreeInsert( /* Set up a rollback-op in case we have to roll this operation back */ if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){ BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) ); + if( pOp==0 ) return SQLITE_NOMEM; pOp->iTab = pCur->iTree; pOp->nKey = pCur->pNode->nKey; pOp->pKey = sqliteMallocRaw( pOp->nKey ); + if( sqlite_malloc_failed ) return SQLITE_NOMEM; memcpy( pOp->pKey, pCur->pNode->pKey, pOp->nKey ); pOp->nData = pCur->pNode->nData; pOp->pData = pCur->pNode->pData; @@ -924,6 +941,7 @@ static int memRbtreeDelete(RbtCursor* pCur) * deletion */ if( pCur->pRbtree->eTransState != TRANS_ROLLBACK ){ BtRollbackOp *pOp = sqliteMalloc( sizeof(BtRollbackOp) ); + if( pOp==0 ) return SQLITE_NOMEM; pOp->iTab = pCur->iTree; pOp->nKey = pZ->nKey; pOp->pKey = pZ->pKey; @@ -1029,6 +1047,7 @@ static int memRbtreeClearTable(Rbtree* tree, int n) sqliteFree( pNode->pData ); }else{ BtRollbackOp *pRollbackOp = sqliteMallocRaw(sizeof(BtRollbackOp)); + if( pRollbackOp==0 ) return SQLITE_NOMEM; pRollbackOp->eOp = ROLLBACK_INSERT; pRollbackOp->iTab = n; pRollbackOp->nKey = pNode->nKey; diff --git a/ext/sqlite/libsqlite/src/date.c b/ext/sqlite/libsqlite/src/date.c index 9a0df401ba..64fc3bccdf 100644 --- a/ext/sqlite/libsqlite/src/date.c +++ b/ext/sqlite/libsqlite/src/date.c @@ -221,7 +221,7 @@ static void computeJD(DateTime *p){ M = p->M; D = p->D; }else{ - Y = 2000; + Y = 2000; /* If no YMD specified, assume 2000-Jan-01 */ M = 1; D = 1; } @@ -369,6 +369,23 @@ static void computeHMS(DateTime *p){ } /* +** Compute both YMD and HMS +*/ +static void computeYMD_HMS(DateTime *p){ + computeYMD(p); + computeHMS(p); +} + +/* +** Clear the YMD and HMS and the TZ +*/ +static void clearYMD_HMS_TZ(DateTime *p){ + p->validYMD = 0; + p->validHMS = 0; + p->validTZ = 0; +} + +/* ** Compute the difference (in days) between localtime and UTC (a.k.a. GMT) ** for the time value p where p is in UTC. */ @@ -376,9 +393,8 @@ static double localtimeOffset(DateTime *p){ DateTime x, y; time_t t; struct tm *pTm; - computeYMD(p); - computeHMS(p); x = *p; + computeYMD_HMS(&x); if( x.Y<1971 || x.Y>=2038 ){ x.Y = 2000; x.M = 1; @@ -408,9 +424,6 @@ static double localtimeOffset(DateTime *p){ y.validJD = 0; y.validTZ = 0; computeJD(&y); - /* printf("x=%d-%02d-%02d %02d:%02d:%02d\n",x.Y,x.M,x.D,x.h,x.m,(int)x.s); */ - /* printf("y=%d-%02d-%02d %02d:%02d:%02d\n",y.Y,y.M,y.D,y.h,y.m,(int)y.s); */ - /* printf("diff=%.17g\n", y.rJD - x.rJD); */ return y.rJD - x.rJD; } @@ -454,9 +467,7 @@ static int parseModifier(const char *zMod, DateTime *p){ if( strcmp(z, "localtime")==0 ){ computeJD(p); p->rJD += localtimeOffset(p); - p->validYMD = 0; - p->validHMS = 0; - p->validTZ = 0; + clearYMD_HMS_TZ(p); rc = 0; } break; @@ -470,22 +481,15 @@ static int parseModifier(const char *zMod, DateTime *p){ */ if( strcmp(z, "unixepoch")==0 && p->validJD ){ p->rJD = p->rJD/86400.0 + 2440587.5; - p->validYMD = 0; - p->validHMS = 0; - p->validTZ = 0; + clearYMD_HMS_TZ(p); rc = 0; }else if( strcmp(z, "utc")==0 ){ double c1; computeJD(p); c1 = localtimeOffset(p); p->rJD -= c1; - p->validYMD = 0; - p->validHMS = 0; - p->validTZ = 0; + clearYMD_HMS_TZ(p); p->rJD += c1 - localtimeOffset(p); - p->validYMD = 0; - p->validHMS = 0; - p->validTZ = 0; rc = 0; } break; @@ -494,16 +498,14 @@ static int parseModifier(const char *zMod, DateTime *p){ /* ** weekday N ** - ** Move the date to the beginning of the next occurrance of + ** Move the date to the same time on the next occurrance of ** weekday N where 0==Sunday, 1==Monday, and so forth. If the - ** date is already on the appropriate weekday, this is equivalent - ** to "start of day". + ** date is already on the appropriate weekday, this is a no-op. */ if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0 && (n=r)==r && n>=0 && r<7 ){ int Z; - computeYMD(p); - p->validHMS = 0; + computeYMD_HMS(p); p->validTZ = 0; p->validJD = 0; computeJD(p); @@ -511,8 +513,7 @@ static int parseModifier(const char *zMod, DateTime *p){ Z %= 7; if( Z>n ) Z -= 7; p->rJD += n - Z; - p->validYMD = 0; - p->validHMS = 0; + clearYMD_HMS_TZ(p); rc = 0; } break; @@ -570,17 +571,14 @@ static int parseModifier(const char *zMod, DateTime *p){ if( n==3 && strcmp(z,"day")==0 ){ p->rJD += r; }else if( n==4 && strcmp(z,"hour")==0 ){ - computeJD(p); p->rJD += r/24.0; }else if( n==6 && strcmp(z,"minute")==0 ){ - computeJD(p); p->rJD += r/(24.0*60.0); }else if( n==6 && strcmp(z,"second")==0 ){ - computeJD(p); p->rJD += r/(24.0*60.0*60.0); }else if( n==5 && strcmp(z,"month")==0 ){ int x, y; - computeYMD(p); + computeYMD_HMS(p); p->M += r; x = p->M>0 ? (p->M-1)/12 : (p->M-12)/12; p->Y += x; @@ -592,16 +590,14 @@ static int parseModifier(const char *zMod, DateTime *p){ p->rJD += (r - y)*30.0; } }else if( n==4 && strcmp(z,"year")==0 ){ - computeYMD(p); + computeYMD_HMS(p); p->Y += r; p->validJD = 0; computeJD(p); }else{ rc = 1; } - p->validYMD = 0; - p->validHMS = 0; - p->validTZ = 0; + clearYMD_HMS_TZ(p); break; } default: { @@ -655,8 +651,7 @@ static void datetimeFunc(sqlite_func *context, int argc, const char **argv){ DateTime x; if( isDate(argc, argv, &x)==0 ){ char zBuf[100]; - computeYMD(&x); - computeHMS(&x); + computeYMD_HMS(&x); sprintf(zBuf, "%04d-%02d-%02d %02d:%02d:%02d",x.Y, x.M, x.D, x.h, x.m, (int)(x.s)); sqlite_set_result_string(context, zBuf, -1); @@ -759,8 +754,7 @@ static void strftimeFunc(sqlite_func *context, int argc, const char **argv){ if( z==0 ) return; } computeJD(&x); - computeYMD(&x); - computeHMS(&x); + computeYMD_HMS(&x); for(i=j=0; zFmt[i]; i++){ if( zFmt[i]!='%' ){ z[j++] = zFmt[i]; @@ -798,11 +792,11 @@ static void strftimeFunc(sqlite_func *context, int argc, const char **argv){ case 'm': sprintf(&z[j],"%02d",x.M); j+=2; break; case 'M': sprintf(&z[j],"%02d",x.m); j+=2; break; case 's': { - sprintf(&z[j],"%d",(int)((x.rJD-2440587.5)*86400.0)); + sprintf(&z[j],"%d",(int)((x.rJD-2440587.5)*86400.0 + 0.5)); j += strlen(&z[j]); break; } - case 'S': sprintf(&z[j],"%02d",(int)x.s); j+=2; break; + case 'S': sprintf(&z[j],"%02d",(int)(x.s+0.5)); j+=2; break; case 'w': z[j++] = (((int)(x.rJD+1.5)) % 7) + '0'; break; case 'Y': sprintf(&z[j],"%04d",x.Y); j+=strlen(&z[j]); break; case '%': z[j++] = '%'; break; diff --git a/ext/sqlite/libsqlite/src/hash.c b/ext/sqlite/libsqlite/src/hash.c index aa3bb81c44..77be2807b2 100644 --- a/ext/sqlite/libsqlite/src/hash.c +++ b/ext/sqlite/libsqlite/src/hash.c @@ -75,6 +75,7 @@ static int intCompare(const void *pKey1, int n1, const void *pKey2, int n2){ return n2 - n1; } +#if 0 /* NOT USED */ /* ** Hash and comparison functions when the mode is SQLITE_HASH_POINTER */ @@ -87,6 +88,7 @@ static int ptrCompare(const void *pKey1, int n1, const void *pKey2, int n2){ if( pKey1<pKey2 ) return -1; return 1; } +#endif /* ** Hash and comparison functions when the mode is SQLITE_HASH_STRING @@ -130,7 +132,7 @@ static int binCompare(const void *pKey1, int n1, const void *pKey2, int n2){ static int (*hashFunction(int keyClass))(const void*,int){ switch( keyClass ){ case SQLITE_HASH_INT: return &intHash; - case SQLITE_HASH_POINTER: return &ptrHash; + /* case SQLITE_HASH_POINTER: return &ptrHash; // NOT USED */ case SQLITE_HASH_STRING: return &strHash; case SQLITE_HASH_BINARY: return &binHash;; default: break; @@ -147,7 +149,7 @@ static int (*hashFunction(int keyClass))(const void*,int){ static int (*compareFunction(int keyClass))(const void*,int,const void*,int){ switch( keyClass ){ case SQLITE_HASH_INT: return &intCompare; - case SQLITE_HASH_POINTER: return &ptrCompare; + /* case SQLITE_HASH_POINTER: return &ptrCompare; // NOT USED */ case SQLITE_HASH_STRING: return &strCompare; case SQLITE_HASH_BINARY: return &binCompare; default: break; diff --git a/ext/sqlite/libsqlite/src/hash.h b/ext/sqlite/libsqlite/src/hash.h index 053fa70cad..5f6335e1c8 100644 --- a/ext/sqlite/libsqlite/src/hash.h +++ b/ext/sqlite/libsqlite/src/hash.h @@ -71,7 +71,7 @@ struct HashElem { ** if the copyKey parameter to HashInit is 1. */ #define SQLITE_HASH_INT 1 -#define SQLITE_HASH_POINTER 2 +/* #define SQLITE_HASH_POINTER 2 // NOT USED */ #define SQLITE_HASH_STRING 3 #define SQLITE_HASH_BINARY 4 diff --git a/ext/sqlite/libsqlite/src/opcodes.c b/ext/sqlite/libsqlite/src/opcodes.c index 8fcd8bdafe..59061b7c0a 100644 --- a/ext/sqlite/libsqlite/src/opcodes.c +++ b/ext/sqlite/libsqlite/src/opcodes.c @@ -79,6 +79,7 @@ char *sqliteOpcodeNames[] = { "???", "PutStrKey", "Delete", "KeyAsData", + "RowKey", "RowData", "Column", "Recno", @@ -94,6 +95,7 @@ char *sqliteOpcodeNames[] = { "???", "IdxLT", "IdxGT", "IdxGE", + "IdxIsNull", "Destroy", "Clear", "CreateIndex", diff --git a/ext/sqlite/libsqlite/src/opcodes.h b/ext/sqlite/libsqlite/src/opcodes.h index ea9de3f5f5..ac274022d1 100644 --- a/ext/sqlite/libsqlite/src/opcodes.h +++ b/ext/sqlite/libsqlite/src/opcodes.h @@ -78,55 +78,57 @@ #define OP_PutStrKey 77 #define OP_Delete 78 #define OP_KeyAsData 79 -#define OP_RowData 80 -#define OP_Column 81 -#define OP_Recno 82 -#define OP_FullKey 83 -#define OP_NullRow 84 -#define OP_Last 85 -#define OP_Rewind 86 -#define OP_Prev 87 -#define OP_Next 88 -#define OP_IdxPut 89 -#define OP_IdxDelete 90 -#define OP_IdxRecno 91 -#define OP_IdxLT 92 -#define OP_IdxGT 93 -#define OP_IdxGE 94 -#define OP_Destroy 95 -#define OP_Clear 96 -#define OP_CreateIndex 97 -#define OP_CreateTable 98 -#define OP_IntegrityCk 99 -#define OP_ListWrite 100 -#define OP_ListRewind 101 -#define OP_ListRead 102 -#define OP_ListReset 103 -#define OP_ListPush 104 -#define OP_ListPop 105 -#define OP_SortPut 106 -#define OP_SortMakeRec 107 -#define OP_SortMakeKey 108 -#define OP_Sort 109 -#define OP_SortNext 110 -#define OP_SortCallback 111 -#define OP_SortReset 112 -#define OP_FileOpen 113 -#define OP_FileRead 114 -#define OP_FileColumn 115 -#define OP_MemStore 116 -#define OP_MemLoad 117 -#define OP_MemIncr 118 -#define OP_AggReset 119 -#define OP_AggInit 120 -#define OP_AggFunc 121 -#define OP_AggFocus 122 -#define OP_AggSet 123 -#define OP_AggGet 124 -#define OP_AggNext 125 -#define OP_SetInsert 126 -#define OP_SetFound 127 -#define OP_SetNotFound 128 -#define OP_SetFirst 129 -#define OP_SetNext 130 -#define OP_Vacuum 131 +#define OP_RowKey 80 +#define OP_RowData 81 +#define OP_Column 82 +#define OP_Recno 83 +#define OP_FullKey 84 +#define OP_NullRow 85 +#define OP_Last 86 +#define OP_Rewind 87 +#define OP_Prev 88 +#define OP_Next 89 +#define OP_IdxPut 90 +#define OP_IdxDelete 91 +#define OP_IdxRecno 92 +#define OP_IdxLT 93 +#define OP_IdxGT 94 +#define OP_IdxGE 95 +#define OP_IdxIsNull 96 +#define OP_Destroy 97 +#define OP_Clear 98 +#define OP_CreateIndex 99 +#define OP_CreateTable 100 +#define OP_IntegrityCk 101 +#define OP_ListWrite 102 +#define OP_ListRewind 103 +#define OP_ListRead 104 +#define OP_ListReset 105 +#define OP_ListPush 106 +#define OP_ListPop 107 +#define OP_SortPut 108 +#define OP_SortMakeRec 109 +#define OP_SortMakeKey 110 +#define OP_Sort 111 +#define OP_SortNext 112 +#define OP_SortCallback 113 +#define OP_SortReset 114 +#define OP_FileOpen 115 +#define OP_FileRead 116 +#define OP_FileColumn 117 +#define OP_MemStore 118 +#define OP_MemLoad 119 +#define OP_MemIncr 120 +#define OP_AggReset 121 +#define OP_AggInit 122 +#define OP_AggFunc 123 +#define OP_AggFocus 124 +#define OP_AggSet 125 +#define OP_AggGet 126 +#define OP_AggNext 127 +#define OP_SetInsert 128 +#define OP_SetFound 129 +#define OP_SetNotFound 130 +#define OP_SetFirst 131 +#define OP_SetNext 132 +#define OP_Vacuum 133 diff --git a/ext/sqlite/libsqlite/src/os.c b/ext/sqlite/libsqlite/src/os.c index 61eb21bf89..2c57078305 100644 --- a/ext/sqlite/libsqlite/src/os.c +++ b/ext/sqlite/libsqlite/src/os.c @@ -164,6 +164,39 @@ static unsigned int elapse; ** structure. The fcntl() system call is only invoked to set a ** POSIX lock if the internal lock structure transitions between ** a locked and an unlocked state. +** +** 2004-Jan-11: +** More recent discoveries about POSIX advisory locks. (The more +** I discover, the more I realize the a POSIX advisory locks are +** an abomination.) +** +** If you close a file descriptor that points to a file that has locks, +** all locks on that file that are owned by the current process are +** released. To work around this problem, each OsFile structure contains +** a pointer to an openCnt structure. There is one openCnt structure +** per open inode, which means that multiple OsFiles can point to a single +** openCnt. When an attempt is made to close an OsFile, if there are +** other OsFiles open on the same inode that are holding locks, the call +** to close() the file descriptor is deferred until all of the locks clear. +** The openCnt structure keeps a list of file descriptors that need to +** be closed and that list is walked (and cleared) when the last lock +** clears. +** +** First, under Linux threads, because each thread has a separate +** process ID, lock operations in one thread do not override locks +** to the same file in other threads. Linux threads behave like +** separate processes in this respect. But, if you close a file +** descriptor in linux threads, all locks are cleared, even locks +** on other threads and even though the other threads have different +** process IDs. Linux threads is inconsistent in this respect. +** (I'm beginning to think that linux threads is an abomination too.) +** The consequence of this all is that the hash table for the lockInfo +** structure has to include the process id as part of its key because +** locks in different threads are treated as distinct. But the +** openCnt structure should not include the process id in its +** key because close() clears lock on all threads, not just the current +** thread. Were it not for this goofiness in linux threads, we could +** combine the lockInfo and openCnt structures into a single structure. */ /* @@ -180,69 +213,147 @@ struct lockKey { }; /* -** An instance of the following structure is allocated for each inode. +** An instance of the following structure is allocated for each open +** inode on each thread with a different process ID. (Threads have +** different process IDs on linux, but not on most other unixes.) +** ** A single inode can have multiple file descriptors, so each OsFile ** structure contains a pointer to an instance of this object and this ** object keeps a count of the number of OsFiles pointing to it. */ struct lockInfo { struct lockKey key; /* The lookup key */ - int cnt; /* 0: unlocked. -1: write lock. 1...: read lock. */ + int cnt; /* 0: unlocked. -1: write lock. 1...: read lock. */ + int nRef; /* Number of pointers to this structure */ +}; + +/* +** An instance of the following structure serves as the key used +** to locate a particular openCnt structure given its inode. This +** is the same as the lockKey except that the process ID is omitted. +*/ +struct openKey { + dev_t dev; /* Device number */ + ino_t ino; /* Inode number */ +}; + +/* +** An instance of the following structure is allocated for each open +** inode. This structure keeps track of the number of locks on that +** inode. If a close is attempted against an inode that is holding +** locks, the close is deferred until all locks clear by adding the +** file descriptor to be closed to the pending list. +*/ +struct openCnt { + struct openKey key; /* The lookup key */ int nRef; /* Number of pointers to this structure */ + int nLock; /* Number of outstanding locks */ + int nPending; /* Number of pending close() operations */ + int *aPending; /* Malloced space holding fd's awaiting a close() */ }; /* -** This hash table maps inodes (in the form of lockKey structures) into -** pointers to lockInfo structures. +** These hash table maps inodes and process IDs into lockInfo and openCnt +** structures. Access to these hash tables must be protected by a mutex. */ static Hash lockHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 }; +static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 }; + +/* +** Release a lockInfo structure previously allocated by findLockInfo(). +*/ +static void releaseLockInfo(struct lockInfo *pLock){ + pLock->nRef--; + if( pLock->nRef==0 ){ + sqliteHashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0); + sqliteFree(pLock); + } +} /* -** Given a file descriptor, locate a lockInfo structure that describes -** that file descriptor. Create a new one if necessary. NULL might -** be returned if malloc() fails. +** Release a openCnt structure previously allocated by findLockInfo(). +*/ +static void releaseOpenCnt(struct openCnt *pOpen){ + pOpen->nRef--; + if( pOpen->nRef==0 ){ + sqliteHashInsert(&openHash, &pOpen->key, sizeof(pOpen->key), 0); + sqliteFree(pOpen->aPending); + sqliteFree(pOpen); + } +} + +/* +** Given a file descriptor, locate lockInfo and openCnt structures that +** describes that file descriptor. Create a new ones if necessary. The +** return values might be unset if an error occurs. +** +** Return the number of errors. */ -static struct lockInfo *findLockInfo(int fd){ +int findLockInfo( + int fd, /* The file descriptor used in the key */ + struct lockInfo **ppLock, /* Return the lockInfo structure here */ + struct openCnt **ppOpen /* Return the openCnt structure here */ +){ int rc; - struct lockKey key; + struct lockKey key1; + struct openKey key2; struct stat statbuf; - struct lockInfo *pInfo; + struct lockInfo *pLock; + struct openCnt *pOpen; rc = fstat(fd, &statbuf); - if( rc!=0 ) return 0; - memset(&key, 0, sizeof(key)); - key.dev = statbuf.st_dev; - key.ino = statbuf.st_ino; - key.pid = getpid(); - pInfo = (struct lockInfo*)sqliteHashFind(&lockHash, &key, sizeof(key)); - if( pInfo==0 ){ + if( rc!=0 ) return 1; + memset(&key1, 0, sizeof(key1)); + key1.dev = statbuf.st_dev; + key1.ino = statbuf.st_ino; + key1.pid = getpid(); + memset(&key2, 0, sizeof(key2)); + key2.dev = statbuf.st_dev; + key2.ino = statbuf.st_ino; + pLock = (struct lockInfo*)sqliteHashFind(&lockHash, &key1, sizeof(key1)); + if( pLock==0 ){ struct lockInfo *pOld; - pInfo = sqliteMalloc( sizeof(*pInfo) ); - if( pInfo==0 ) return 0; - pInfo->key = key; - pInfo->nRef = 1; - pInfo->cnt = 0; - pOld = sqliteHashInsert(&lockHash, &pInfo->key, sizeof(key), pInfo); + pLock = sqliteMallocRaw( sizeof(*pLock) ); + if( pLock==0 ) return 1; + pLock->key = key1; + pLock->nRef = 1; + pLock->cnt = 0; + pOld = sqliteHashInsert(&lockHash, &pLock->key, sizeof(key1), pLock); if( pOld!=0 ){ - assert( pOld==pInfo ); - sqliteFree(pInfo); - pInfo = 0; + assert( pOld==pLock ); + sqliteFree(pLock); + return 1; } }else{ - pInfo->nRef++; + pLock->nRef++; } - return pInfo; -} - -/* -** Release a lockInfo structure previously allocated by findLockInfo(). -*/ -static void releaseLockInfo(struct lockInfo *pInfo){ - pInfo->nRef--; - if( pInfo->nRef==0 ){ - sqliteHashInsert(&lockHash, &pInfo->key, sizeof(pInfo->key), 0); - sqliteFree(pInfo); + *ppLock = pLock; + pOpen = (struct openCnt*)sqliteHashFind(&openHash, &key2, sizeof(key2)); + if( pOpen==0 ){ + struct openCnt *pOld; + pOpen = sqliteMallocRaw( sizeof(*pOpen) ); + if( pOpen==0 ){ + releaseLockInfo(pLock); + return 1; + } + pOpen->key = key2; + pOpen->nRef = 1; + pOpen->nLock = 0; + pOpen->nPending = 0; + pOpen->aPending = 0; + pOld = sqliteHashInsert(&openHash, &pOpen->key, sizeof(key2), pOpen); + if( pOld!=0 ){ + assert( pOld==pOpen ); + sqliteFree(pOpen); + releaseLockInfo(pLock); + return 1; + } + }else{ + pOpen->nRef++; } + *ppOpen = pOpen; + return 0; } + #endif /** POSIX advisory lock work-around **/ /* @@ -349,6 +460,7 @@ int sqliteOsOpenReadWrite( int *pReadonly ){ #if OS_UNIX + int rc; id->dirfd = -1; id->fd = open(zFilename, O_RDWR|O_CREAT|O_LARGEFILE|O_BINARY, 0644); if( id->fd<0 ){ @@ -361,9 +473,9 @@ int sqliteOsOpenReadWrite( *pReadonly = 0; } sqliteOsEnterMutex(); - id->pLock = findLockInfo(id->fd); + rc = findLockInfo(id->fd, &id->pLock, &id->pOpen); sqliteOsLeaveMutex(); - if( id->pLock==0 ){ + if( rc ){ close(id->fd); return SQLITE_NOMEM; } @@ -471,6 +583,7 @@ int sqliteOsOpenReadWrite( */ int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ #if OS_UNIX + int rc; if( access(zFilename, 0)==0 ){ return SQLITE_CANTOPEN; } @@ -481,9 +594,9 @@ int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ return SQLITE_CANTOPEN; } sqliteOsEnterMutex(); - id->pLock = findLockInfo(id->fd); + rc = findLockInfo(id->fd, &id->pLock, &id->pOpen); sqliteOsLeaveMutex(); - if( id->pLock==0 ){ + if( rc ){ close(id->fd); unlink(zFilename); return SQLITE_NOMEM; @@ -561,15 +674,16 @@ int sqliteOsOpenExclusive(const char *zFilename, OsFile *id, int delFlag){ */ int sqliteOsOpenReadOnly(const char *zFilename, OsFile *id){ #if OS_UNIX + int rc; id->dirfd = -1; id->fd = open(zFilename, O_RDONLY|O_LARGEFILE|O_BINARY); if( id->fd<0 ){ return SQLITE_CANTOPEN; } sqliteOsEnterMutex(); - id->pLock = findLockInfo(id->fd); + rc = findLockInfo(id->fd, &id->pLock, &id->pOpen); sqliteOsLeaveMutex(); - if( id->pLock==0 ){ + if( rc ){ close(id->fd); return SQLITE_NOMEM; } @@ -763,15 +877,36 @@ int sqliteOsTempFileName(char *zBuf){ } /* -** Close a file +** Close a file. */ int sqliteOsClose(OsFile *id){ #if OS_UNIX - close(id->fd); + sqliteOsUnlock(id); if( id->dirfd>=0 ) close(id->dirfd); id->dirfd = -1; sqliteOsEnterMutex(); + if( id->pOpen->nLock ){ + /* If there are outstanding locks, do not actually close the file just + ** yet because that would clear those locks. Instead, add the file + ** descriptor to pOpen->aPending. It will be automatically closed when + ** the last lock is cleared. + */ + int *aNew; + struct openCnt *pOpen = id->pOpen; + pOpen->nPending++; + aNew = sqliteRealloc( pOpen->aPending, pOpen->nPending*sizeof(int) ); + if( aNew==0 ){ + /* If a malloc fails, just leak the file descriptor */ + }else{ + pOpen->aPending = aNew; + pOpen->aPending[pOpen->nPending-1] = id->fd; + } + }else{ + /* There are no outstanding locks so we can close the file immediately */ + close(id->fd); + } releaseLockInfo(id->pLock); + releaseOpenCnt(id->pOpen); sqliteOsLeaveMutex(); TRACE2("CLOSE %-3d\n", id->fd); OpenCounter(-1); @@ -1159,6 +1294,7 @@ int sqliteOsReadLock(OsFile *id){ if( !id->locked ){ id->pLock->cnt++; id->locked = 1; + id->pOpen->nLock++; } rc = SQLITE_OK; }else if( id->locked || id->pLock->cnt==0 ){ @@ -1172,8 +1308,11 @@ int sqliteOsReadLock(OsFile *id){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; }else{ rc = SQLITE_OK; + if( !id->locked ){ + id->pOpen->nLock++; + id->locked = 1; + } id->pLock->cnt = 1; - id->locked = 1; } }else{ rc = SQLITE_BUSY; @@ -1276,8 +1415,11 @@ int sqliteOsWriteLock(OsFile *id){ rc = (errno==EINVAL) ? SQLITE_NOLFS : SQLITE_BUSY; }else{ rc = SQLITE_OK; + if( !id->locked ){ + id->pOpen->nLock++; + id->locked = 1; + } id->pLock->cnt = -1; - id->locked = 1; } }else{ rc = SQLITE_BUSY; @@ -1391,6 +1533,24 @@ int sqliteOsUnlock(OsFile *id){ id->pLock->cnt = 0; } } + if( rc==SQLITE_OK ){ + /* Decrement the count of locks against this same file. When the + ** count reaches zero, close any other file descriptors whose close + ** was deferred because of outstanding locks. + */ + struct openCnt *pOpen = id->pOpen; + pOpen->nLock--; + assert( pOpen->nLock>=0 ); + if( pOpen->nLock==0 && pOpen->nPending>0 ){ + int i; + for(i=0; i<pOpen->nPending; i++){ + close(pOpen->aPending[i]); + } + sqliteFree(pOpen->aPending); + pOpen->nPending = 0; + pOpen->aPending = 0; + } + } sqliteOsLeaveMutex(); id->locked = 0; return rc; diff --git a/ext/sqlite/libsqlite/src/os.h b/ext/sqlite/libsqlite/src/os.h index b415a48cf4..681f831b66 100644 --- a/ext/sqlite/libsqlite/src/os.h +++ b/ext/sqlite/libsqlite/src/os.h @@ -103,10 +103,11 @@ # include <unistd.h> typedef struct OsFile OsFile; struct OsFile { - struct lockInfo *pLock; /* Information about locks on this inode */ - int fd; /* The file descriptor */ - int locked; /* True if this user holds the lock */ - int dirfd; /* File descriptor for the directory */ + struct openCnt *pOpen; /* Info about all open fd's on this inode */ + struct lockInfo *pLock; /* Info about locks on this inode */ + int fd; /* The file descriptor */ + int locked; /* True if this instance holds the lock */ + int dirfd; /* File descriptor for the directory */ }; # define SQLITE_TEMPNAME_SIZE 200 # if defined(HAVE_USLEEP) && HAVE_USLEEP diff --git a/ext/sqlite/libsqlite/src/pager.c b/ext/sqlite/libsqlite/src/pager.c index 2ef87195f9..f593862104 100644 --- a/ext/sqlite/libsqlite/src/pager.c +++ b/ext/sqlite/libsqlite/src/pager.c @@ -594,7 +594,7 @@ static int pager_playback(Pager *pPager, int useJournalSize){ goto end_playback; } if( format>=JOURNAL_FORMAT_3 ){ - rc = read32bits(format, &pPager->jfd, &nRec); + rc = read32bits(format, &pPager->jfd, (u32*)&nRec); if( rc ) goto end_playback; rc = read32bits(format, &pPager->jfd, &pPager->cksumInit); if( rc ) goto end_playback; diff --git a/ext/sqlite/libsqlite/src/printf.c b/ext/sqlite/libsqlite/src/printf.c index e32487e6f4..a8af91434e 100644 --- a/ext/sqlite/libsqlite/src/printf.c +++ b/ext/sqlite/libsqlite/src/printf.c @@ -139,9 +139,9 @@ static et_info fmtinfo[] = { ** 16 (the number of significant digits in a 64-bit float) '0' is ** always returned. */ -static int et_getdigit(double *val, int *cnt){ +static int et_getdigit(LONGDOUBLE_TYPE *val, int *cnt){ int digit; - double d; + LONGDOUBLE_TYPE d; if( (*cnt)++ >= 16 ) return '0'; digit = (int)*val; d = digit; @@ -202,7 +202,7 @@ static int vxprintf( int flag_long; /* True if "l" flag is present */ int flag_center; /* True if "=" flag is present */ unsigned long longvalue; /* Value for integer types */ - double realvalue; /* Value for real types */ + LONGDOUBLE_TYPE realvalue; /* Value for real types */ et_info *infop; /* Pointer to the appropriate info structure */ char buf[etBUFSIZE]; /* Conversion buffer */ char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ diff --git a/ext/sqlite/libsqlite/src/select.c b/ext/sqlite/libsqlite/src/select.c index c0aa4ecfeb..c7525b3b6b 100644 --- a/ext/sqlite/libsqlite/src/select.c +++ b/ext/sqlite/libsqlite/src/select.c @@ -479,16 +479,19 @@ static int selectInnerLoop( ** item into the set table with bogus data. */ case SRT_Set: { - int lbl = sqliteVdbeMakeLabel(v); + int addr1 = sqliteVdbeCurrentAddr(v); + int addr2; assert( nColumn==1 ); - sqliteVdbeAddOp(v, OP_IsNull, -1, lbl); + sqliteVdbeAddOp(v, OP_NotNull, -1, addr1+3); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + addr2 = sqliteVdbeAddOp(v, OP_Goto, 0, 0); if( pOrderBy ){ pushOntoSorter(pParse, v, pOrderBy); }else{ sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); } - sqliteVdbeResolveLabel(v, lbl); + sqliteVdbeChangeP2(v, addr2, sqliteVdbeCurrentAddr(v)); break; } @@ -588,7 +591,9 @@ static void generateSortTail( } case SRT_Set: { assert( nColumn==1 ); - sqliteVdbeAddOp(v, OP_IsNull, -1, sqliteVdbeCurrentAddr(v)+3); + sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3); + sqliteVdbeAddOp(v, OP_Pop, 1, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); break; diff --git a/ext/sqlite/libsqlite/src/sqliteInt.h b/ext/sqlite/libsqlite/src/sqliteInt.h index a4f8b27ad0..04a90dccf2 100644 --- a/ext/sqlite/libsqlite/src/sqliteInt.h +++ b/ext/sqlite/libsqlite/src/sqliteInt.h @@ -120,6 +120,15 @@ typedef INTPTR_TYPE ptr; /* Big enough to hold a pointer */ typedef unsigned INTPTR_TYPE uptr; /* Big enough to hold a pointer */ /* +** Most C compilers these days recognize "long double", don't they? +** Just in case we encounter one that does not, we will create a macro +** for long double so that it can be easily changed to just "double". +*/ +#ifndef LONGDOUBLE_TYPE +# define LONGDOUBLE_TYPE long double +#endif + +/* ** This macro casts a pointer to an integer. Useful for doing ** pointer arithmetic. */ diff --git a/ext/sqlite/libsqlite/src/tokenize.c b/ext/sqlite/libsqlite/src/tokenize.c index 34ecd49776..ddf014f8fe 100644 --- a/ext/sqlite/libsqlite/src/tokenize.c +++ b/ext/sqlite/libsqlite/src/tokenize.c @@ -29,122 +29,122 @@ typedef struct Keyword Keyword; struct Keyword { char *zName; /* The keyword name */ - u16 len; /* Number of characters in the keyword */ - u16 tokenType; /* The token value for this keyword */ - Keyword *pNext; /* Next keyword with the same hash */ + u8 tokenType; /* Token value for this keyword */ + u8 len; /* Length of this keyword */ + u8 iNext; /* Index in aKeywordTable[] of next with same hash */ }; /* ** These are the keywords */ static Keyword aKeywordTable[] = { - { "ABORT", 0, TK_ABORT, 0 }, - { "AFTER", 0, TK_AFTER, 0 }, - { "ALL", 0, TK_ALL, 0 }, - { "AND", 0, TK_AND, 0 }, - { "AS", 0, TK_AS, 0 }, - { "ASC", 0, TK_ASC, 0 }, - { "ATTACH", 0, TK_ATTACH, 0 }, - { "BEFORE", 0, TK_BEFORE, 0 }, - { "BEGIN", 0, TK_BEGIN, 0 }, - { "BETWEEN", 0, TK_BETWEEN, 0 }, - { "BY", 0, TK_BY, 0 }, - { "CASCADE", 0, TK_CASCADE, 0 }, - { "CASE", 0, TK_CASE, 0 }, - { "CHECK", 0, TK_CHECK, 0 }, - { "CLUSTER", 0, TK_CLUSTER, 0 }, - { "COLLATE", 0, TK_COLLATE, 0 }, - { "COMMIT", 0, TK_COMMIT, 0 }, - { "CONFLICT", 0, TK_CONFLICT, 0 }, - { "CONSTRAINT", 0, TK_CONSTRAINT, 0 }, - { "COPY", 0, TK_COPY, 0 }, - { "CREATE", 0, TK_CREATE, 0 }, - { "CROSS", 0, TK_JOIN_KW, 0 }, - { "DATABASE", 0, TK_DATABASE, 0 }, - { "DEFAULT", 0, TK_DEFAULT, 0 }, - { "DEFERRED", 0, TK_DEFERRED, 0 }, - { "DEFERRABLE", 0, TK_DEFERRABLE, 0 }, - { "DELETE", 0, TK_DELETE, 0 }, - { "DELIMITERS", 0, TK_DELIMITERS, 0 }, - { "DESC", 0, TK_DESC, 0 }, - { "DETACH", 0, TK_DETACH, 0 }, - { "DISTINCT", 0, TK_DISTINCT, 0 }, - { "DROP", 0, TK_DROP, 0 }, - { "END", 0, TK_END, 0 }, - { "EACH", 0, TK_EACH, 0 }, - { "ELSE", 0, TK_ELSE, 0 }, - { "EXCEPT", 0, TK_EXCEPT, 0 }, - { "EXPLAIN", 0, TK_EXPLAIN, 0 }, - { "FAIL", 0, TK_FAIL, 0 }, - { "FOR", 0, TK_FOR, 0 }, - { "FOREIGN", 0, TK_FOREIGN, 0 }, - { "FROM", 0, TK_FROM, 0 }, - { "FULL", 0, TK_JOIN_KW, 0 }, - { "GLOB", 0, TK_GLOB, 0 }, - { "GROUP", 0, TK_GROUP, 0 }, - { "HAVING", 0, TK_HAVING, 0 }, - { "IGNORE", 0, TK_IGNORE, 0 }, - { "IMMEDIATE", 0, TK_IMMEDIATE, 0 }, - { "IN", 0, TK_IN, 0 }, - { "INDEX", 0, TK_INDEX, 0 }, - { "INITIALLY", 0, TK_INITIALLY, 0 }, - { "INNER", 0, TK_JOIN_KW, 0 }, - { "INSERT", 0, TK_INSERT, 0 }, - { "INSTEAD", 0, TK_INSTEAD, 0 }, - { "INTERSECT", 0, TK_INTERSECT, 0 }, - { "INTO", 0, TK_INTO, 0 }, - { "IS", 0, TK_IS, 0 }, - { "ISNULL", 0, TK_ISNULL, 0 }, - { "JOIN", 0, TK_JOIN, 0 }, - { "KEY", 0, TK_KEY, 0 }, - { "LEFT", 0, TK_JOIN_KW, 0 }, - { "LIKE", 0, TK_LIKE, 0 }, - { "LIMIT", 0, TK_LIMIT, 0 }, - { "MATCH", 0, TK_MATCH, 0 }, - { "NATURAL", 0, TK_JOIN_KW, 0 }, - { "NOT", 0, TK_NOT, 0 }, - { "NOTNULL", 0, TK_NOTNULL, 0 }, - { "NULL", 0, TK_NULL, 0 }, - { "OF", 0, TK_OF, 0 }, - { "OFFSET", 0, TK_OFFSET, 0 }, - { "ON", 0, TK_ON, 0 }, - { "OR", 0, TK_OR, 0 }, - { "ORDER", 0, TK_ORDER, 0 }, - { "OUTER", 0, TK_JOIN_KW, 0 }, - { "PRAGMA", 0, TK_PRAGMA, 0 }, - { "PRIMARY", 0, TK_PRIMARY, 0 }, - { "RAISE", 0, TK_RAISE, 0 }, - { "REFERENCES", 0, TK_REFERENCES, 0 }, - { "REPLACE", 0, TK_REPLACE, 0 }, - { "RESTRICT", 0, TK_RESTRICT, 0 }, - { "RIGHT", 0, TK_JOIN_KW, 0 }, - { "ROLLBACK", 0, TK_ROLLBACK, 0 }, - { "ROW", 0, TK_ROW, 0 }, - { "SELECT", 0, TK_SELECT, 0 }, - { "SET", 0, TK_SET, 0 }, - { "STATEMENT", 0, TK_STATEMENT, 0 }, - { "TABLE", 0, TK_TABLE, 0 }, - { "TEMP", 0, TK_TEMP, 0 }, - { "TEMPORARY", 0, TK_TEMP, 0 }, - { "THEN", 0, TK_THEN, 0 }, - { "TRANSACTION", 0, TK_TRANSACTION, 0 }, - { "TRIGGER", 0, TK_TRIGGER, 0 }, - { "UNION", 0, TK_UNION, 0 }, - { "UNIQUE", 0, TK_UNIQUE, 0 }, - { "UPDATE", 0, TK_UPDATE, 0 }, - { "USING", 0, TK_USING, 0 }, - { "VACUUM", 0, TK_VACUUM, 0 }, - { "VALUES", 0, TK_VALUES, 0 }, - { "VIEW", 0, TK_VIEW, 0 }, - { "WHEN", 0, TK_WHEN, 0 }, - { "WHERE", 0, TK_WHERE, 0 }, + { "ABORT", TK_ABORT, }, + { "AFTER", TK_AFTER, }, + { "ALL", TK_ALL, }, + { "AND", TK_AND, }, + { "AS", TK_AS, }, + { "ASC", TK_ASC, }, + { "ATTACH", TK_ATTACH, }, + { "BEFORE", TK_BEFORE, }, + { "BEGIN", TK_BEGIN, }, + { "BETWEEN", TK_BETWEEN, }, + { "BY", TK_BY, }, + { "CASCADE", TK_CASCADE, }, + { "CASE", TK_CASE, }, + { "CHECK", TK_CHECK, }, + { "CLUSTER", TK_CLUSTER, }, + { "COLLATE", TK_COLLATE, }, + { "COMMIT", TK_COMMIT, }, + { "CONFLICT", TK_CONFLICT, }, + { "CONSTRAINT", TK_CONSTRAINT, }, + { "COPY", TK_COPY, }, + { "CREATE", TK_CREATE, }, + { "CROSS", TK_JOIN_KW, }, + { "DATABASE", TK_DATABASE, }, + { "DEFAULT", TK_DEFAULT, }, + { "DEFERRED", TK_DEFERRED, }, + { "DEFERRABLE", TK_DEFERRABLE, }, + { "DELETE", TK_DELETE, }, + { "DELIMITERS", TK_DELIMITERS, }, + { "DESC", TK_DESC, }, + { "DETACH", TK_DETACH, }, + { "DISTINCT", TK_DISTINCT, }, + { "DROP", TK_DROP, }, + { "END", TK_END, }, + { "EACH", TK_EACH, }, + { "ELSE", TK_ELSE, }, + { "EXCEPT", TK_EXCEPT, }, + { "EXPLAIN", TK_EXPLAIN, }, + { "FAIL", TK_FAIL, }, + { "FOR", TK_FOR, }, + { "FOREIGN", TK_FOREIGN, }, + { "FROM", TK_FROM, }, + { "FULL", TK_JOIN_KW, }, + { "GLOB", TK_GLOB, }, + { "GROUP", TK_GROUP, }, + { "HAVING", TK_HAVING, }, + { "IGNORE", TK_IGNORE, }, + { "IMMEDIATE", TK_IMMEDIATE, }, + { "IN", TK_IN, }, + { "INDEX", TK_INDEX, }, + { "INITIALLY", TK_INITIALLY, }, + { "INNER", TK_JOIN_KW, }, + { "INSERT", TK_INSERT, }, + { "INSTEAD", TK_INSTEAD, }, + { "INTERSECT", TK_INTERSECT, }, + { "INTO", TK_INTO, }, + { "IS", TK_IS, }, + { "ISNULL", TK_ISNULL, }, + { "JOIN", TK_JOIN, }, + { "KEY", TK_KEY, }, + { "LEFT", TK_JOIN_KW, }, + { "LIKE", TK_LIKE, }, + { "LIMIT", TK_LIMIT, }, + { "MATCH", TK_MATCH, }, + { "NATURAL", TK_JOIN_KW, }, + { "NOT", TK_NOT, }, + { "NOTNULL", TK_NOTNULL, }, + { "NULL", TK_NULL, }, + { "OF", TK_OF, }, + { "OFFSET", TK_OFFSET, }, + { "ON", TK_ON, }, + { "OR", TK_OR, }, + { "ORDER", TK_ORDER, }, + { "OUTER", TK_JOIN_KW, }, + { "PRAGMA", TK_PRAGMA, }, + { "PRIMARY", TK_PRIMARY, }, + { "RAISE", TK_RAISE, }, + { "REFERENCES", TK_REFERENCES, }, + { "REPLACE", TK_REPLACE, }, + { "RESTRICT", TK_RESTRICT, }, + { "RIGHT", TK_JOIN_KW, }, + { "ROLLBACK", TK_ROLLBACK, }, + { "ROW", TK_ROW, }, + { "SELECT", TK_SELECT, }, + { "SET", TK_SET, }, + { "STATEMENT", TK_STATEMENT, }, + { "TABLE", TK_TABLE, }, + { "TEMP", TK_TEMP, }, + { "TEMPORARY", TK_TEMP, }, + { "THEN", TK_THEN, }, + { "TRANSACTION", TK_TRANSACTION, }, + { "TRIGGER", TK_TRIGGER, }, + { "UNION", TK_UNION, }, + { "UNIQUE", TK_UNIQUE, }, + { "UPDATE", TK_UPDATE, }, + { "USING", TK_USING, }, + { "VACUUM", TK_VACUUM, }, + { "VALUES", TK_VALUES, }, + { "VIEW", TK_VIEW, }, + { "WHEN", TK_WHEN, }, + { "WHERE", TK_WHERE, }, }; /* ** This is the hash table */ -#define KEY_HASH_SIZE 71 -static Keyword *apHashTable[KEY_HASH_SIZE]; +#define KEY_HASH_SIZE 101 +static u8 aiHashTable[KEY_HASH_SIZE]; /* @@ -153,29 +153,29 @@ static Keyword *apHashTable[KEY_HASH_SIZE]; ** returned. If the input is not a keyword, TK_ID is returned. */ int sqliteKeywordCode(const char *z, int n){ - int h; + int h, i; Keyword *p; static char needInit = 1; if( needInit ){ /* Initialize the keyword hash table */ sqliteOsEnterMutex(); if( needInit ){ - int i; - int n; - n = sizeof(aKeywordTable)/sizeof(aKeywordTable[0]); - for(i=0; i<n; i++){ + int nk; + nk = sizeof(aKeywordTable)/sizeof(aKeywordTable[0]); + for(i=0; i<nk; i++){ aKeywordTable[i].len = strlen(aKeywordTable[i].zName); h = sqliteHashNoCase(aKeywordTable[i].zName, aKeywordTable[i].len); h %= KEY_HASH_SIZE; - aKeywordTable[i].pNext = apHashTable[h]; - apHashTable[h] = &aKeywordTable[i]; + aKeywordTable[i].iNext = aiHashTable[h]; + aiHashTable[h] = i+1; } needInit = 0; } sqliteOsLeaveMutex(); } h = sqliteHashNoCase(z, n) % KEY_HASH_SIZE; - for(p=apHashTable[h]; p; p=p->pNext){ + for(i=aiHashTable[h]; i; i=p->iNext){ + p = &aKeywordTable[i-1]; if( p->len==n && sqliteStrNICmp(p->zName, z, n)==0 ){ return p->tokenType; } @@ -185,8 +185,12 @@ int sqliteKeywordCode(const char *z, int n){ /* -** If X is a character that can be used in an identifier then -** isIdChar[X] will be 1. Otherwise isIdChar[X] will be 0. +** If X is a character that can be used in an identifier and +** X&0x80==0 then isIdChar[X] will be 1. If X&0x80==0x80 then +** X is always an identifier character. (Hence all UTF-8 +** characters can be part of an identifier). isIdChar[X] will +** be 0 for every character in the lower 128 ASCII characters +** that cannot be used as part of an identifier. ** ** In this implementation, an identifier can be a string of ** alphabetic characters, digits, and "_" plus any character @@ -204,14 +208,6 @@ static const char isIdChar[] = { 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 1, /* 5x */ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 6x */ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, /* 7x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 8x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* 9x */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ax */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Bx */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Cx */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Dx */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Ex */ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, /* Fx */ }; @@ -380,10 +376,10 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){ return 1; } default: { - if( !isIdChar[*z] ){ + if( (*z&0x80)==0 && !isIdChar[*z] ){ break; } - for(i=1; isIdChar[z[i]]; i++){} + for(i=1; (z[i]&0x80)!=0 || isIdChar[z[i]]; i++){} *tokenType = sqliteKeywordCode((char*)z, i); return i; } diff --git a/ext/sqlite/libsqlite/src/util.c b/ext/sqlite/libsqlite/src/util.c index 2e8f5aa2af..2e896ee8b6 100644 --- a/ext/sqlite/libsqlite/src/util.c +++ b/ext/sqlite/libsqlite/src/util.c @@ -252,7 +252,7 @@ char *sqliteStrNDup_(const char *z, int n, char *zFile, int line){ void *sqliteMalloc(int n){ void *p; if( (p = malloc(n))==0 ){ - sqlite_malloc_failed++; + if( n>0 ) sqlite_malloc_failed++; }else{ memset(p, 0, n); } @@ -266,7 +266,7 @@ void *sqliteMalloc(int n){ void *sqliteMallocRaw(int n){ void *p; if( (p = malloc(n))==0 ){ - sqlite_malloc_failed++; + if( n>0 ) sqlite_malloc_failed++; } return p; } @@ -664,7 +664,7 @@ int sqliteIsNumber(const char *z){ */ double sqliteAtoF(const char *z){ int sign = 1; - double v1 = 0.0; + LONGDOUBLE_TYPE v1 = 0.0; if( *z=='-' ){ sign = -1; z++; @@ -676,7 +676,7 @@ double sqliteAtoF(const char *z){ z++; } if( *z=='.' ){ - double divisor = 1.0; + LONGDOUBLE_TYPE divisor = 1.0; z++; while( isdigit(*z) ){ v1 = v1*10.0 + (*z - '0'); @@ -688,7 +688,7 @@ double sqliteAtoF(const char *z){ if( *z=='e' || *z=='E' ){ int esign = 1; int eval = 0; - double scale = 1.0; + LONGDOUBLE_TYPE scale = 1.0; z++; if( *z=='-' ){ esign = -1; diff --git a/ext/sqlite/libsqlite/src/vdbe.c b/ext/sqlite/libsqlite/src/vdbe.c index bd080f37d3..b0dd210049 100644 --- a/ext/sqlite/libsqlite/src/vdbe.c +++ b/ext/sqlite/libsqlite/src/vdbe.c @@ -363,42 +363,6 @@ static Sorter *Merge(Sorter *pLeft, Sorter *pRight){ } /* -** Convert an integer in between the native integer format and -** the bigEndian format used as the record number for tables. -** -** The bigEndian format (most significant byte first) is used for -** record numbers so that records will sort into the correct order -** even though memcmp() is used to compare the keys. On machines -** whose native integer format is little endian (ex: i486) the -** order of bytes is reversed. On native big-endian machines -** (ex: Alpha, Sparc, Motorola) the byte order is the same. -** -** This function is its own inverse. In other words -** -** X == byteSwap(byteSwap(X)) -*/ -static int byteSwap(int x){ - union { - char zBuf[sizeof(int)]; - int i; - } ux; - ux.zBuf[3] = x&0xff; - ux.zBuf[2] = (x>>8)&0xff; - ux.zBuf[1] = (x>>16)&0xff; - ux.zBuf[0] = (x>>24)&0xff; - return ux.i; -} - -/* -** When converting from the native format to the key format and back -** again, in addition to changing the byte order we invert the high-order -** bit of the most significant byte. This causes negative numbers to -** sort before positive numbers in the memcmp() function. -*/ -#define keyToInt(X) (byteSwap(X) ^ 0x80000000) -#define intToKey(X) (byteSwap((X) ^ 0x80000000)) - -/* ** Code contained within the VERIFY() macro is not needed for correct ** execution. It is there only to catch errors. So when we compile ** with NDEBUG=1, the VERIFY() code is omitted. @@ -1157,7 +1121,9 @@ case OP_Function: { ctx.z = 0; ctx.isError = 0; ctx.isStep = 0; + if( sqliteSafetyOff(db) ) goto abort_due_to_misuse; (*ctx.pFunc->xFunc)(&ctx, n, (const char**)&zStack[p->tos-n+1]); + if( sqliteSafetyOn(db) ) goto abort_due_to_misuse; sqliteVdbePopStack(p, n); p->tos++; aStack[p->tos] = ctx.s; @@ -1831,8 +1797,8 @@ case OP_IfNot: { /* Opcode: IsNull P1 P2 * ** ** If any of the top abs(P1) values on the stack are NULL, then jump -** to P2. The stack is popped P1 times if P1>0. If P1<0 then all values -** are left unchanged on the stack. +** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack +** unchanged. */ case OP_IsNull: { int i, cnt; @@ -1851,14 +1817,18 @@ case OP_IsNull: { /* Opcode: NotNull P1 P2 * ** -** Jump to P2 if the top value on the stack is not NULL. Pop the -** stack if P1 is greater than zero. If P1 is less than or equal to -** zero then leave the value on the stack. +** Jump to P2 if the top P1 values on the stack are all not NULL. Pop the +** stack if P1 times if P1 is greater than zero. If P1 is less than +** zero then leave the stack unchanged. */ case OP_NotNull: { - VERIFY( if( p->tos<0 ) goto not_enough_stack; ) - if( (aStack[p->tos].flags & STK_Null)==0 ) pc = pOp->p2-1; - if( pOp->p1>0 ){ POPSTACK; } + int i, cnt; + cnt = pOp->p1; + if( cnt<0 ) cnt = -cnt; + VERIFY( if( p->tos+1-cnt<0 ) goto not_enough_stack; ) + for(i=0; i<cnt && (aStack[p->tos-i].flags & STK_Null)==0; i++){} + if( i>=cnt ) pc = pOp->p2-1; + if( pOp->p1>0 ) sqliteVdbePopStack(p, cnt); break; } @@ -2597,8 +2567,15 @@ case OP_MoveTo: { pC = &p->aCsr[i]; if( pC->pCursor!=0 ){ int res, oc; + pC->nullRow = 0; if( aStack[tos].flags & STK_Int ){ int iKey = intToKey(aStack[tos].i); + if( pOp->p2==0 && pOp->opcode==OP_MoveTo ){ + pC->movetoTarget = iKey; + pC->deferredMoveto = 1; + POPSTACK; + break; + } sqliteBtreeMoveto(pC->pCursor, (char*)&iKey, sizeof(int), &res); pC->lastRecno = aStack[tos].i; pC->recnoIsValid = res==0; @@ -2607,7 +2584,7 @@ case OP_MoveTo: { sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res); pC->recnoIsValid = 0; } - pC->nullRow = 0; + pC->deferredMoveto = 0; sqlite_search_count++; oc = pOp->opcode; if( oc==OP_MoveTo && res<0 ){ @@ -2682,6 +2659,7 @@ case OP_Found: { Stringify(p, tos); rx = sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res); alreadyExists = rx==SQLITE_OK && res==0; + pC->deferredMoveto = 0; } if( pOp->opcode==OP_Found ){ if( alreadyExists ) pc = pOp->p2 - 1; @@ -2743,6 +2721,7 @@ case OP_IsUnique: { /* Search for an entry in P1 where all but the last four bytes match K. ** If there is no such entry, jump immediately to P2. */ + assert( p->aCsr[i].deferredMoveto==0 ); rc = sqliteBtreeMoveto(pCrsr, zKey, nKey-4, &res); if( rc!=SQLITE_OK ) goto abort_due_to_error; if( res<0 ){ @@ -2911,6 +2890,7 @@ case OP_NewRecno: { } } pC->recnoIsValid = 0; + pC->deferredMoveto = 0; } p->tos++; aStack[p->tos].i = v; @@ -2993,6 +2973,7 @@ case OP_PutStrKey: { zStack[tos], aStack[tos].n); } pC->recnoIsValid = 0; + pC->deferredMoveto = 0; } POPSTACK; POPSTACK; @@ -3019,6 +3000,7 @@ case OP_Delete: { assert( i>=0 && i<p->nCursor ); pC = &p->aCsr[i]; if( pC->pCursor!=0 ){ + sqliteVdbeCursorMoveto(pC); rc = sqliteBtreeDelete(pC->pCursor); pC->nextRowidValid = 0; } @@ -3049,6 +3031,16 @@ case OP_KeyAsData: { ** If the cursor is not pointing to a valid row, a NULL is pushed ** onto the stack. */ +/* Opcode: RowKey P1 * * +** +** Push onto the stack the complete row key for cursor P1. +** There is no interpretation of the key. It is just copied +** onto the stack exactly as it is found in the database file. +** +** If the cursor is not pointing to a valid row, a NULL is pushed +** onto the stack. +*/ +case OP_RowKey: case OP_RowData: { int i = pOp->p1; int tos = ++p->tos; @@ -3061,10 +3053,11 @@ case OP_RowData: { aStack[tos].flags = STK_Null; }else if( pC->pCursor!=0 ){ BtCursor *pCrsr = pC->pCursor; + sqliteVdbeCursorMoveto(pC); if( pC->nullRow ){ aStack[tos].flags = STK_Null; break; - }else if( pC->keyAsData ){ + }else if( pC->keyAsData || pOp->opcode==OP_RowKey ){ sqliteBtreeKeySize(pCrsr, &n); }else{ sqliteBtreeDataSize(pCrsr, &n); @@ -3079,7 +3072,7 @@ case OP_RowData: { aStack[tos].flags = STK_Str | STK_Dyn; zStack[tos] = z; } - if( pC->keyAsData ){ + if( pC->keyAsData || pOp->opcode==OP_RowKey ){ sqliteBtreeKey(pCrsr, 0, n, zStack[tos]); }else{ sqliteBtreeData(pCrsr, 0, n, zStack[tos]); @@ -3131,6 +3124,7 @@ case OP_Column: { zRec = zStack[tos+i]; payloadSize = aStack[tos+i].n; }else if( (pC = &p->aCsr[i])->pCursor!=0 ){ + sqliteVdbeCursorMoveto(pC); zRec = 0; pCrsr = pC->pCursor; if( pC->nullRow ){ @@ -3237,7 +3231,9 @@ case OP_Recno: { int v; assert( i>=0 && i<p->nCursor ); - if( (pC = &p->aCsr[i])->recnoIsValid ){ + pC = &p->aCsr[i]; + sqliteVdbeCursorMoveto(pC); + if( pC->recnoIsValid ){ v = pC->lastRecno; }else if( pC->pseudoTable ){ v = keyToInt(pC->iKey); @@ -3276,6 +3272,7 @@ case OP_FullKey: { int amt; char *z; + sqliteVdbeCursorMoveto(&p->aCsr[i]); sqliteBtreeKeySize(pCrsr, &amt); if( amt<=0 ){ rc = SQLITE_CORRUPT; @@ -3329,7 +3326,8 @@ case OP_Last: { if( (pCrsr = pC->pCursor)!=0 ){ int res; rc = sqliteBtreeLast(pCrsr, &res); - p->aCsr[i].nullRow = res; + pC->nullRow = res; + pC->deferredMoveto = 0; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } @@ -3359,6 +3357,7 @@ case OP_Rewind: { rc = sqliteBtreeFirst(pCrsr, &res); pC->atFirst = res==0; pC->nullRow = res; + pC->deferredMoveto = 0; if( res && pOp->p2>0 ){ pc = pOp->p2 - 1; } @@ -3397,6 +3396,7 @@ case OP_Next: { if( pC->nullRow ){ res = 1; }else{ + assert( pC->deferredMoveto==0 ); rc = pOp->opcode==OP_Next ? sqliteBtreeNext(pCrsr, &res) : sqliteBtreePrevious(pCrsr, &res); pC->nullRow = res; @@ -3458,6 +3458,7 @@ case OP_IdxPut: { } } rc = sqliteBtreeInsert(pCrsr, zKey, nKey, "", 0); + assert( p->aCsr[i].deferredMoveto==0 ); } POPSTACK; break; @@ -3479,6 +3480,7 @@ case OP_IdxDelete: { if( rx==SQLITE_OK && res==0 ){ rc = sqliteBtreeDelete(pCrsr); } + assert( p->aCsr[i].deferredMoveto==0 ); } POPSTACK; break; @@ -3501,6 +3503,7 @@ case OP_IdxRecno: { if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){ int v; int sz; + assert( p->aCsr[i].deferredMoveto==0 ); sqliteBtreeKeySize(pCrsr, &sz); if( sz<sizeof(u32) ){ aStack[tos].flags = STK_Null; @@ -3550,6 +3553,7 @@ case OP_IdxGE: { int res, rc; Stringify(p, tos); + assert( p->aCsr[i].deferredMoveto==0 ); rc = sqliteBtreeKeyCompare(pCrsr, zStack[tos], aStack[tos].n, 4, &res); if( rc!=SQLITE_OK ){ break; @@ -3567,6 +3571,37 @@ case OP_IdxGE: { break; } +/* Opcode: IdxIsNull P1 P2 * +** +** The top of the stack contains an index entry such as might be generated +** by the MakeIdxKey opcode. This routine looks at the first P1 fields of +** that key. If any of the first P1 fields are NULL, then a jump is made +** to address P2. Otherwise we fall straight through. +** +** The index entry is always popped from the stack. +*/ +case OP_IdxIsNull: { + int i = pOp->p1; + int tos = p->tos; + int k, n; + const char *z; + + assert( tos>=0 ); + assert( aStack[tos].flags & STK_Str ); + z = zStack[tos]; + n = aStack[tos].n; + for(k=0; k<n && i>0; i--){ + if( z[k]=='a' ){ + pc = pOp->p2-1; + break; + } + while( k<n && z[k] ){ k++; } + k++; + } + POPSTACK; + break; +} + /* Opcode: Destroy P1 P2 * ** ** Delete an entire database table or index whose root page in the database diff --git a/ext/sqlite/libsqlite/src/vdbeInt.h b/ext/sqlite/libsqlite/src/vdbeInt.h index d168387cd2..d58523ad28 100644 --- a/ext/sqlite/libsqlite/src/vdbeInt.h +++ b/ext/sqlite/libsqlite/src/vdbeInt.h @@ -17,6 +17,15 @@ */ /* +** When converting from the native format to the key format and back +** again, in addition to changing the byte order we invert the high-order +** bit of the most significant byte. This causes negative numbers to +** sort before positive numbers in the memcmp() function. +*/ +#define keyToInt(X) (sqliteVdbeByteSwap(X) ^ 0x80000000) +#define intToKey(X) (sqliteVdbeByteSwap((X) ^ 0x80000000)) + +/* ** The makefile scans this source file and creates the following ** array of string constants which are the names of all VDBE opcodes. ** This array is defined in a separate source code file named opcode.c @@ -62,6 +71,8 @@ struct Cursor { Bool nullRow; /* True if pointing to a row with no data */ Bool nextRowidValid; /* True if the nextRowid field is valid */ Bool pseudoTable; /* This is a NEW or OLD pseudo-tables of a trigger */ + Bool deferredMoveto; /* A call to sqliteBtreeMoveto() is needed */ + int movetoTarget; /* Argument to the deferred sqliteBtreeMoveto() */ Btree *pBt; /* Separate file holding temporary table */ int nData; /* Number of bytes in pData */ char *pData; /* Data for a NEW or OLD pseudo-table */ @@ -294,6 +305,8 @@ void sqliteVdbeSorterReset(Vdbe*); void sqliteVdbeAggReset(Agg*); void sqliteVdbeKeylistFree(Keylist*); void sqliteVdbePopStack(Vdbe*,int); +int sqliteVdbeCursorMoveto(Cursor*); +int sqliteVdbeByteSwap(int); #if !defined(NDEBUG) || defined(VDBE_PROFILE) void sqliteVdbePrintOp(FILE*, int, Op*); #endif diff --git a/ext/sqlite/libsqlite/src/vdbeaux.c b/ext/sqlite/libsqlite/src/vdbeaux.c index c08db5c088..6249a29f0b 100644 --- a/ext/sqlite/libsqlite/src/vdbeaux.c +++ b/ext/sqlite/libsqlite/src/vdbeaux.c @@ -992,3 +992,51 @@ void sqliteVdbeDelete(Vdbe *p){ p->magic = VDBE_MAGIC_DEAD; sqliteFree(p); } + +/* +** Convert an integer in between the native integer format and +** the bigEndian format used as the record number for tables. +** +** The bigEndian format (most significant byte first) is used for +** record numbers so that records will sort into the correct order +** even though memcmp() is used to compare the keys. On machines +** whose native integer format is little endian (ex: i486) the +** order of bytes is reversed. On native big-endian machines +** (ex: Alpha, Sparc, Motorola) the byte order is the same. +** +** This function is its own inverse. In other words +** +** X == byteSwap(byteSwap(X)) +*/ +int sqliteVdbeByteSwap(int x){ + union { + char zBuf[sizeof(int)]; + int i; + } ux; + ux.zBuf[3] = x&0xff; + ux.zBuf[2] = (x>>8)&0xff; + ux.zBuf[1] = (x>>16)&0xff; + ux.zBuf[0] = (x>>24)&0xff; + return ux.i; +} + +/* +** If a MoveTo operation is pending on the given cursor, then do that +** MoveTo now. Return an error code. If no MoveTo is pending, this +** routine does nothing and returns SQLITE_OK. +*/ +int sqliteVdbeCursorMoveto(Cursor *p){ + if( p->deferredMoveto ){ + int res; + extern int sqlite_search_count; + sqliteBtreeMoveto(p->pCursor, (char*)&p->movetoTarget, sizeof(int), &res); + p->lastRecno = keyToInt(p->movetoTarget); + p->recnoIsValid = res==0; + if( res<0 ){ + sqliteBtreeNext(p->pCursor, &res); + } + sqlite_search_count++; + p->deferredMoveto = 0; + } + return SQLITE_OK; +} diff --git a/ext/sqlite/libsqlite/src/where.c b/ext/sqlite/libsqlite/src/where.c index 32bc432d35..11358e413c 100644 --- a/ext/sqlite/libsqlite/src/where.c +++ b/ext/sqlite/libsqlite/src/where.c @@ -764,7 +764,7 @@ WhereInfo *sqliteWhereBegin( ){ if( pX->op==TK_EQ ){ sqliteExprCode(pParse, pX->pRight); - /* aExpr[k].p = 0; // See ticket #461 */ + aExpr[k].p = 0; break; } if( pX->op==TK_IN && nColumn==1 ){ @@ -781,7 +781,7 @@ WhereInfo *sqliteWhereBegin( pLevel->inOp = OP_Next; pLevel->inP1 = pX->iTable; } - /* aExpr[k].p = 0; // See ticket #461 */ + aExpr[k].p = 0; break; } } @@ -791,13 +791,16 @@ WhereInfo *sqliteWhereBegin( && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j] ){ sqliteExprCode(pParse, aExpr[k].p->pLeft); - /* aExpr[k].p = 0; // See ticket #461 */ + aExpr[k].p = 0; break; } } } pLevel->iMem = pParse->nMem++; cont = pLevel->cont = sqliteVdbeMakeLabel(v); + sqliteVdbeAddOp(v, OP_NotNull, -nColumn, sqliteVdbeCurrentAddr(v)+3); + sqliteVdbeAddOp(v, OP_Pop, nColumn, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, brk); sqliteVdbeAddOp(v, OP_MakeKey, nColumn, 0); sqliteAddIdxKeyType(v, pIdx); if( nColumn==pIdx->nColumn || pLevel->bRev ){ @@ -815,16 +818,17 @@ WhereInfo *sqliteWhereBegin( sqliteVdbeAddOp(v, OP_MoveLt, pLevel->iCur, brk); start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); sqliteVdbeAddOp(v, OP_IdxLT, pLevel->iCur, brk); - sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0); pLevel->op = OP_Prev; }else{ /* Scan in the forward order */ sqliteVdbeAddOp(v, OP_MoveTo, pLevel->iCur, brk); start = sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk); - sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0); pLevel->op = OP_Next; } + sqliteVdbeAddOp(v, OP_RowKey, pLevel->iCur, 0); + sqliteVdbeAddOp(v, OP_IdxIsNull, nColumn, cont); + sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0); if( i==pTabList->nSrc-1 && pushKey ){ haveKey = 1; }else{ @@ -933,7 +937,7 @@ WhereInfo *sqliteWhereBegin( && aExpr[k].p->pLeft->iColumn==pIdx->aiColumn[j] ){ sqliteExprCode(pParse, aExpr[k].p->pRight); - /* aExpr[k].p = 0; // See ticket #461 */ + aExpr[k].p = 0; break; } if( aExpr[k].idxRight==iCur @@ -942,7 +946,7 @@ WhereInfo *sqliteWhereBegin( && aExpr[k].p->pRight->iColumn==pIdx->aiColumn[j] ){ sqliteExprCode(pParse, aExpr[k].p->pLeft); - /* aExpr[k].p = 0; // See ticket #461 */ + aExpr[k].p = 0; break; } } @@ -979,7 +983,7 @@ WhereInfo *sqliteWhereBegin( ){ sqliteExprCode(pParse, pExpr->pRight); leFlag = pExpr->op==TK_LE; - /* aExpr[k].p = 0; // See ticket #461 */ + aExpr[k].p = 0; break; } if( aExpr[k].idxRight==iCur @@ -989,7 +993,7 @@ WhereInfo *sqliteWhereBegin( ){ sqliteExprCode(pParse, pExpr->pLeft); leFlag = pExpr->op==TK_GE; - /* aExpr[k].p = 0; // See ticket #461 */ + aExpr[k].p = 0; break; } } @@ -999,8 +1003,12 @@ WhereInfo *sqliteWhereBegin( leFlag = 1; } if( testOp!=OP_Noop ){ + int nCol = nEqColumn + (score & 1); pLevel->iMem = pParse->nMem++; - sqliteVdbeAddOp(v, OP_MakeKey, nEqColumn + (score & 1), 0); + sqliteVdbeAddOp(v, OP_NotNull, -nCol, sqliteVdbeCurrentAddr(v)+3); + sqliteVdbeAddOp(v, OP_Pop, nCol, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, brk); + sqliteVdbeAddOp(v, OP_MakeKey, nCol, 0); sqliteAddIdxKeyType(v, pIdx); if( leFlag ){ sqliteVdbeAddOp(v, OP_IncrKey, 0, 0); @@ -1034,7 +1042,7 @@ WhereInfo *sqliteWhereBegin( ){ sqliteExprCode(pParse, pExpr->pRight); geFlag = pExpr->op==TK_GE; - /* aExpr[k].p = 0; // See ticket #461 */ + aExpr[k].p = 0; break; } if( aExpr[k].idxRight==iCur @@ -1044,7 +1052,7 @@ WhereInfo *sqliteWhereBegin( ){ sqliteExprCode(pParse, pExpr->pLeft); geFlag = pExpr->op==TK_LE; - /* aExpr[k].p = 0; // See ticket #461 */ + aExpr[k].p = 0; break; } } @@ -1052,7 +1060,11 @@ WhereInfo *sqliteWhereBegin( geFlag = 1; } if( nEqColumn>0 || (score&2)!=0 ){ - sqliteVdbeAddOp(v, OP_MakeKey, nEqColumn + ((score&2)!=0), 0); + int nCol = nEqColumn + ((score&2)!=0); + sqliteVdbeAddOp(v, OP_NotNull, -nCol, sqliteVdbeCurrentAddr(v)+3); + sqliteVdbeAddOp(v, OP_Pop, nCol, 0); + sqliteVdbeAddOp(v, OP_Goto, 0, brk); + sqliteVdbeAddOp(v, OP_MakeKey, nCol, 0); sqliteAddIdxKeyType(v, pIdx); if( !geFlag ){ sqliteVdbeAddOp(v, OP_IncrKey, 0, 0); @@ -1079,6 +1091,8 @@ WhereInfo *sqliteWhereBegin( sqliteVdbeAddOp(v, OP_MemLoad, pLevel->iMem, 0); sqliteVdbeAddOp(v, testOp, pLevel->iCur, brk); } + sqliteVdbeAddOp(v, OP_RowKey, pLevel->iCur, 0); + sqliteVdbeAddOp(v, OP_IdxIsNull, nEqColumn + (score & 1), cont); sqliteVdbeAddOp(v, OP_IdxRecno, pLevel->iCur, 0); if( i==pTabList->nSrc-1 && pushKey ){ haveKey = 1; |