summaryrefslogtreecommitdiff
path: root/ext/sqlite/libsqlite/src
diff options
context:
space:
mode:
authorIlia Alshanetsky <iliaa@php.net>2004-01-14 17:08:27 +0000
committerIlia Alshanetsky <iliaa@php.net>2004-01-14 17:08:27 +0000
commit6e350b553bedcfe4694a7118d8b44f80266201f4 (patch)
tree8be4ab1f00c7a24b19cacbd527d83b6ec61aa265 /ext/sqlite/libsqlite/src
parent49b698c67ed0f8408c54d0754672e552376b7554 (diff)
downloadphp-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.c19
-rw-r--r--ext/sqlite/libsqlite/src/date.c72
-rw-r--r--ext/sqlite/libsqlite/src/hash.c6
-rw-r--r--ext/sqlite/libsqlite/src/hash.h2
-rw-r--r--ext/sqlite/libsqlite/src/opcodes.c2
-rw-r--r--ext/sqlite/libsqlite/src/opcodes.h106
-rw-r--r--ext/sqlite/libsqlite/src/os.c256
-rw-r--r--ext/sqlite/libsqlite/src/os.h9
-rw-r--r--ext/sqlite/libsqlite/src/pager.c2
-rw-r--r--ext/sqlite/libsqlite/src/printf.c6
-rw-r--r--ext/sqlite/libsqlite/src/select.c13
-rw-r--r--ext/sqlite/libsqlite/src/sqliteInt.h9
-rw-r--r--ext/sqlite/libsqlite/src/tokenize.c246
-rw-r--r--ext/sqlite/libsqlite/src/util.c10
-rw-r--r--ext/sqlite/libsqlite/src/vdbe.c133
-rw-r--r--ext/sqlite/libsqlite/src/vdbeInt.h13
-rw-r--r--ext/sqlite/libsqlite/src/vdbeaux.c48
-rw-r--r--ext/sqlite/libsqlite/src/where.c40
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;