Upgraded bundled libsqlite to 2.8.11 (fixed critical bug of *NIX systems).

This commit is contained in:
Ilia Alshanetsky 2004-01-14 17:08:27 +00:00
parent 49b698c67e
commit 6e350b553b
20 changed files with 655 additions and 355 deletions

2
NEWS
View File

@ -1,7 +1,7 @@
PHP NEWS
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 2004, PHP 5 RC1
- Upgraded SQLite library to version 2.8.9. (Ilia, Wez)
- Upgraded SQLite library to version 2.8.11. (Ilia, Wez)
- Fixed var_export() to show public, protected and private modifiers properly.
(Derick)
- Fixed problems with longlong values in mysqli. (Georg)

View File

@ -1 +1 @@
2.8.9
2.8.11

View File

@ -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;

View File

@ -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;
}
@ -368,6 +368,23 @@ static void computeHMS(DateTime *p){
p->validHMS = 1;
}
/*
** 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;

View File

@ -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;

View File

@ -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

View File

@ -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",

View File

@ -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

View File

@ -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 };
/*
** 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.
*/
static struct lockInfo *findLockInfo(int fd){
int rc;
struct lockKey key;
struct stat statbuf;
struct lockInfo *pInfo;
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 ){
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);
if( pOld!=0 ){
assert( pOld==pInfo );
sqliteFree(pInfo);
pInfo = 0;
}
}else{
pInfo->nRef++;
}
return pInfo;
}
static Hash openHash = { SQLITE_HASH_BINARY, 0, 0, 0, 0, 0 };
/*
** 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);
static void releaseLockInfo(struct lockInfo *pLock){
pLock->nRef--;
if( pLock->nRef==0 ){
sqliteHashInsert(&lockHash, &pLock->key, sizeof(pLock->key), 0);
sqliteFree(pLock);
}
}
/*
** 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.
*/
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 key1;
struct openKey key2;
struct stat statbuf;
struct lockInfo *pLock;
struct openCnt *pOpen;
rc = fstat(fd, &statbuf);
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;
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==pLock );
sqliteFree(pLock);
return 1;
}
}else{
pLock->nRef++;
}
*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;

View File

@ -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

View File

@ -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;

View File

@ -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'. */

View File

@ -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;

View File

@ -119,6 +119,15 @@ typedef UINT8_TYPE u8; /* 1-byte unsigned integer */
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.

View File

@ -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;
}

View File

@ -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;

View File

@ -362,42 +362,6 @@ static Sorter *Merge(Sorter *pLeft, Sorter *pRight){
return sHead.pNext;
}
/*
** 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
@ -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

View File

@ -16,6 +16,15 @@
** this header information was factored out.
*/
/*
** 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.
@ -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

View File

@ -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;
}

View File

@ -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;