mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Upgraded SQLite 3 library to version 3.3.13
This commit is contained in:
parent
c6402df3a7
commit
03e5b080a3
21 changed files with 1588 additions and 1275 deletions
2
NEWS
2
NEWS
|
@ -4,7 +4,7 @@ PHP NEWS
|
|||
- Upgraded libraries bundled in the Windows distribution. (Edin)
|
||||
. c-client (imap) to version 2006e
|
||||
. libpq (PostgreSQL) to version 8.2.3
|
||||
- Upgraded SQLite 3 to version 3.3.12 (Ilia)
|
||||
- Upgraded SQLite 3 to version 3.3.13 (Ilia)
|
||||
- Upgraded PCRE to version 7.0 (Nuno)
|
||||
- Added --ri switch to CLI which allows to check extension information. (Marcus)
|
||||
- Added tidyNode::getParent() method (John, Nuno)
|
||||
|
|
|
@ -1 +1 @@
|
|||
3.3.12
|
||||
3.3.13
|
||||
|
|
|
@ -5890,6 +5890,7 @@ int sqlite3BtreePageDump(Btree *p, int pgno, int recursive){
|
|||
** aResult[7] = Header size in bytes
|
||||
** aResult[8] = Local payload size
|
||||
** aResult[9] = Parent page number
|
||||
** aResult[10]= Page number of the first overflow page
|
||||
**
|
||||
** This routine is used for testing and debugging only.
|
||||
*/
|
||||
|
@ -5938,6 +5939,11 @@ int sqlite3BtreeCursorInfo(BtCursor *pCur, int *aResult, int upCnt){
|
|||
}else{
|
||||
aResult[9] = pPage->pParent->pgno;
|
||||
}
|
||||
if( tmpCur.info.iOverflow ){
|
||||
aResult[10] = get4byte(&tmpCur.info.pCell[tmpCur.info.iOverflow]);
|
||||
}else{
|
||||
aResult[10] = 0;
|
||||
}
|
||||
releaseTempCursor(&tmpCur);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
|
|
@ -1222,6 +1222,10 @@ void sqlite3AddCollateType(Parse *pParse, const char *zType, int nType){
|
|||
** If no versions of the requested collations sequence are available, or
|
||||
** another error occurs, NULL is returned and an error message written into
|
||||
** pParse.
|
||||
**
|
||||
** This routine is a wrapper around sqlite3FindCollSeq(). This routine
|
||||
** invokes the collation factory if the named collation cannot be found
|
||||
** and generates an error message.
|
||||
*/
|
||||
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName){
|
||||
sqlite3 *db = pParse->db;
|
||||
|
@ -2457,7 +2461,7 @@ void sqlite3CreateIndex(
|
|||
const char *zColName = pListItem->zName;
|
||||
Column *pTabCol;
|
||||
int requestedSortOrder;
|
||||
char *zColl; /* Collation sequence */
|
||||
char *zColl; /* Collation sequence name */
|
||||
|
||||
for(j=0, pTabCol=pTab->aCol; j<pTab->nCol; j++, pTabCol++){
|
||||
if( sqlite3StrICmp(zColName, pTabCol->zName)==0 ) break;
|
||||
|
@ -2467,6 +2471,12 @@ void sqlite3CreateIndex(
|
|||
pTab->zName, zColName);
|
||||
goto exit_create_index;
|
||||
}
|
||||
/* TODO: Add a test to make sure that the same column is not named
|
||||
** more than once within the same index. Only the first instance of
|
||||
** the column will ever be used by the optimizer. Note that using the
|
||||
** same column more than once cannot be an error because that would
|
||||
** break backwards compatibility - it needs to be a warning.
|
||||
*/
|
||||
pIndex->aiColumn[i] = j;
|
||||
if( pListItem->pExpr ){
|
||||
assert( pListItem->pExpr->pColl );
|
||||
|
|
|
@ -195,6 +195,11 @@ static CollSeq *findCollSeqEntry(
|
|||
**
|
||||
** If the entry specified is not found and 'create' is true, then create a
|
||||
** new entry. Otherwise return NULL.
|
||||
**
|
||||
** A separate function sqlite3LocateCollSeq() is a wrapper around
|
||||
** this routine. sqlite3LocateCollSeq() invokes the collation factory
|
||||
** if necessary and generates an error message if the collating sequence
|
||||
** cannot be found.
|
||||
*/
|
||||
CollSeq *sqlite3FindCollSeq(
|
||||
sqlite3 *db,
|
||||
|
|
|
@ -106,7 +106,8 @@ void sqlite3DeleteFrom(
|
|||
AuthContext sContext; /* Authorization context */
|
||||
int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */
|
||||
NameContext sNC; /* Name context to resolve expressions in */
|
||||
int iDb;
|
||||
int iDb; /* Database number */
|
||||
int memCnt = 0; /* Memory cell used for change counting */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
int isView; /* True if attempting to delete from a view */
|
||||
|
@ -204,7 +205,8 @@ void sqlite3DeleteFrom(
|
|||
** we are counting rows.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
memCnt = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
|
||||
}
|
||||
|
||||
/* Special case: A DELETE without a WHERE clause deletes everything.
|
||||
|
@ -221,7 +223,7 @@ void sqlite3DeleteFrom(
|
|||
sqlite3OpenTable(pParse, iCur, iDb, pTab, OP_OpenRead);
|
||||
}
|
||||
sqlite3VdbeAddOp(v, OP_Rewind, iCur, sqlite3VdbeCurrentAddr(v)+2);
|
||||
addr2 = sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
addr2 = sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
|
||||
sqlite3VdbeAddOp(v, OP_Next, iCur, addr2);
|
||||
sqlite3VdbeResolveLabel(v, endOfLoop);
|
||||
sqlite3VdbeAddOp(v, OP_Close, iCur, 0);
|
||||
|
@ -251,7 +253,7 @@ void sqlite3DeleteFrom(
|
|||
sqlite3VdbeAddOp(v, IsVirtual(pTab) ? OP_VRowid : OP_Rowid, iCur, 0);
|
||||
sqlite3VdbeAddOp(v, OP_FifoWrite, 0, 0);
|
||||
if( db->flags & SQLITE_CountRows ){
|
||||
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
|
||||
}
|
||||
|
||||
/* End the database scan loop.
|
||||
|
@ -354,6 +356,7 @@ void sqlite3DeleteFrom(
|
|||
** invoke the callback function.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && pParse->nested==0 && !pParse->trigStack ){
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows deleted", P3_STATIC);
|
||||
|
|
|
@ -49,6 +49,24 @@ char sqlite3ExprAffinity(Expr *pExpr){
|
|||
return pExpr->affinity;
|
||||
}
|
||||
|
||||
/*
|
||||
** Set the collating sequence for expression pExpr to be the collating
|
||||
** sequence named by pToken. Return a pointer to the revised expression.
|
||||
** The collating sequence is marked as "explicit" using the EP_ExpCollate
|
||||
** flag. An explicit collating sequence will override implicit
|
||||
** collating sequences.
|
||||
*/
|
||||
Expr *sqlite3ExprSetColl(Parse *pParse, Expr *pExpr, Token *pName){
|
||||
CollSeq *pColl;
|
||||
if( pExpr==0 ) return 0;
|
||||
pColl = sqlite3LocateCollSeq(pParse, (char*)pName->z, pName->n);
|
||||
if( pColl ){
|
||||
pExpr->pColl = pColl;
|
||||
pExpr->flags |= EP_ExpCollate;
|
||||
}
|
||||
return pExpr;
|
||||
}
|
||||
|
||||
/*
|
||||
** Return the default collation sequence for the expression pExpr. If
|
||||
** there is no default collation type, return 0.
|
||||
|
@ -158,9 +176,20 @@ static int binaryCompareP1(Expr *pExpr1, Expr *pExpr2, int jumpIfNull){
|
|||
** type.
|
||||
*/
|
||||
static CollSeq* binaryCompareCollSeq(Parse *pParse, Expr *pLeft, Expr *pRight){
|
||||
CollSeq *pColl = sqlite3ExprCollSeq(pParse, pLeft);
|
||||
if( !pColl ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pRight);
|
||||
CollSeq *pColl;
|
||||
assert( pLeft );
|
||||
assert( pRight );
|
||||
if( pLeft->flags & EP_ExpCollate ){
|
||||
assert( pLeft->pColl );
|
||||
pColl = pLeft->pColl;
|
||||
}else if( pRight->flags & EP_ExpCollate ){
|
||||
assert( pRight->pColl );
|
||||
pColl = pRight->pColl;
|
||||
}else{
|
||||
pColl = sqlite3ExprCollSeq(pParse, pLeft);
|
||||
if( !pColl ){
|
||||
pColl = sqlite3ExprCollSeq(pParse, pRight);
|
||||
}
|
||||
}
|
||||
return pColl;
|
||||
}
|
||||
|
@ -205,8 +234,18 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
|
|||
if( pToken ){
|
||||
assert( pToken->dyn==0 );
|
||||
pNew->span = pNew->token = *pToken;
|
||||
}else if( pLeft && pRight ){
|
||||
sqlite3ExprSpan(pNew, &pLeft->span, &pRight->span);
|
||||
}else if( pLeft ){
|
||||
if( pRight ){
|
||||
sqlite3ExprSpan(pNew, &pLeft->span, &pRight->span);
|
||||
if( pRight->flags && EP_ExpCollate ){
|
||||
pNew->flags |= EP_ExpCollate;
|
||||
pNew->pColl = pRight->pColl;
|
||||
}
|
||||
}
|
||||
if( pLeft->flags && EP_ExpCollate ){
|
||||
pNew->flags |= EP_ExpCollate;
|
||||
pNew->pColl = pLeft->pColl;
|
||||
}
|
||||
}
|
||||
return pNew;
|
||||
}
|
||||
|
@ -890,7 +929,9 @@ static int lookupName(
|
|||
/* Substitute the rowid (column -1) for the INTEGER PRIMARY KEY */
|
||||
pExpr->iColumn = j==pTab->iPKey ? -1 : j;
|
||||
pExpr->affinity = pTab->aCol[j].affinity;
|
||||
pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
|
||||
if( (pExpr->flags & EP_ExpCollate)==0 ){
|
||||
pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
|
||||
}
|
||||
if( i<pSrcList->nSrc-1 ){
|
||||
if( pItem[1].jointype & JT_NATURAL ){
|
||||
/* If this match occurred in the left table of a natural join,
|
||||
|
@ -946,7 +987,9 @@ static int lookupName(
|
|||
cnt++;
|
||||
pExpr->iColumn = iCol==pTab->iPKey ? -1 : iCol;
|
||||
pExpr->affinity = pTab->aCol[iCol].affinity;
|
||||
pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
|
||||
if( (pExpr->flags & EP_ExpCollate)==0 ){
|
||||
pExpr->pColl = sqlite3FindCollSeq(db, ENC(db), zColl,-1, 0);
|
||||
}
|
||||
pExpr->pTab = pTab;
|
||||
break;
|
||||
}
|
||||
|
@ -1046,7 +1089,7 @@ static int lookupName(
|
|||
n = sizeof(Bitmask)*8-1;
|
||||
}
|
||||
assert( pMatch->iCursor==pExpr->iTable );
|
||||
pMatch->colUsed |= 1<<n;
|
||||
pMatch->colUsed |= ((Bitmask)1)<<n;
|
||||
}
|
||||
|
||||
lookupname_end:
|
||||
|
|
|
@ -271,6 +271,25 @@ static void randomFunc(
|
|||
sqlite3_result_int64(context, r);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of randomblob(N). Return a random blob
|
||||
** that is N bytes long.
|
||||
*/
|
||||
static void randomBlob(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int n;
|
||||
unsigned char *p;
|
||||
assert( argc==1 );
|
||||
n = sqlite3_value_int(argv[0]);
|
||||
if( n<1 ) n = 1;
|
||||
p = sqlite3_malloc(n);
|
||||
sqlite3Randomness(n, p);
|
||||
sqlite3_result_blob(context, (char*)p, n, sqlite3_free);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of the last_insert_rowid() SQL function. The return
|
||||
** value is the same as the sqlite3_last_insert_rowid() API function.
|
||||
|
@ -547,6 +566,12 @@ static void versionFunc(
|
|||
sqlite3_result_text(context, sqlite3_version, -1, SQLITE_STATIC);
|
||||
}
|
||||
|
||||
/* Array for converting from half-bytes (nybbles) into ASCII hex
|
||||
** digits. */
|
||||
static const char hexdigits[] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
|
||||
/*
|
||||
** EXPERIMENTAL - This is not an official function. The interface may
|
||||
|
@ -572,10 +597,6 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|||
break;
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
static const char hexdigits[] = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
char *zText = 0;
|
||||
int nBlob = sqlite3_value_bytes(argv[0]);
|
||||
char const *zBlob = sqlite3_value_blob(argv[0]);
|
||||
|
@ -621,11 +642,41 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** The hex() function. Interpret the argument as a blob. Return
|
||||
** a hexadecimal rendering as text.
|
||||
*/
|
||||
static void hexFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int i, n;
|
||||
const unsigned char *pBlob;
|
||||
char *zHex, *z;
|
||||
assert( argc==1 );
|
||||
pBlob = sqlite3_value_blob(argv[0]);
|
||||
n = sqlite3_value_bytes(argv[0]);
|
||||
z = zHex = sqlite3_malloc(n*2 + 1);
|
||||
if( zHex==0 ) return;
|
||||
for(i=0; i<n; i++, pBlob++){
|
||||
unsigned char c = *pBlob;
|
||||
*(z++) = hexdigits[(c>>4)&0xf];
|
||||
*(z++) = hexdigits[c&0xf];
|
||||
}
|
||||
*z = 0;
|
||||
sqlite3_result_text(context, zHex, n*2, sqlite3_free);
|
||||
}
|
||||
|
||||
#ifdef SQLITE_SOUNDEX
|
||||
/*
|
||||
** Compute the soundex encoding of a word.
|
||||
*/
|
||||
static void soundexFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
static void soundexFunc(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
char zResult[8];
|
||||
const u8 *zIn;
|
||||
int i, j;
|
||||
|
@ -1021,8 +1072,10 @@ void sqlite3RegisterBuiltinFunctions(sqlite3 *db){
|
|||
{ "coalesce", -1, 0, SQLITE_UTF8, 0, ifnullFunc },
|
||||
{ "coalesce", 0, 0, SQLITE_UTF8, 0, 0 },
|
||||
{ "coalesce", 1, 0, SQLITE_UTF8, 0, 0 },
|
||||
{ "hex", 1, 0, SQLITE_UTF8, 0, hexFunc },
|
||||
{ "ifnull", 2, 0, SQLITE_UTF8, 1, ifnullFunc },
|
||||
{ "random", -1, 0, SQLITE_UTF8, 0, randomFunc },
|
||||
{ "randomblob", 1, 0, SQLITE_UTF8, 0, randomBlob },
|
||||
{ "nullif", 2, 0, SQLITE_UTF8, 1, nullifFunc },
|
||||
{ "sqlite_version", 0, 0, SQLITE_UTF8, 0, versionFunc},
|
||||
{ "quote", 1, 0, SQLITE_UTF8, 0, quoteFunc },
|
||||
|
|
|
@ -28,9 +28,9 @@
|
|||
#define OP_NotNull 67 /* same as TK_NOTNULL */
|
||||
#define OP_Rowid 23
|
||||
#define OP_Real 126 /* same as TK_FLOAT */
|
||||
#define OP_String8 88 /* same as TK_STRING */
|
||||
#define OP_String8 89 /* same as TK_STRING */
|
||||
#define OP_And 62 /* same as TK_AND */
|
||||
#define OP_BitNot 87 /* same as TK_BITNOT */
|
||||
#define OP_BitNot 88 /* same as TK_BITNOT */
|
||||
#define OP_VFilter 24
|
||||
#define OP_NullRow 25
|
||||
#define OP_Noop 26
|
||||
|
@ -84,8 +84,8 @@
|
|||
#define OP_Halt 65
|
||||
#define OP_Expire 74
|
||||
#define OP_Or 61 /* same as TK_OR */
|
||||
#define OP_DropIndex 86
|
||||
#define OP_IdxInsert 89
|
||||
#define OP_DropIndex 85
|
||||
#define OP_IdxInsert 87
|
||||
#define OP_ShiftLeft 77 /* same as TK_LSHIFT */
|
||||
#define OP_FifoRead 90
|
||||
#define OP_Column 91
|
||||
|
@ -117,7 +117,7 @@
|
|||
#define OP_VOpen 114
|
||||
#define OP_AggFinal 115
|
||||
#define OP_OpenWrite 116
|
||||
#define OP_Negative 85 /* same as TK_UMINUS */
|
||||
#define OP_Negative 86 /* same as TK_UMINUS */
|
||||
#define OP_Le 71 /* same as TK_LE */
|
||||
#define OP_VNext 117
|
||||
#define OP_AbsValue 118
|
||||
|
@ -154,7 +154,7 @@
|
|||
#define NOPUSH_MASK_2 0xedaf
|
||||
#define NOPUSH_MASK_3 0xf1eb
|
||||
#define NOPUSH_MASK_4 0xfffe
|
||||
#define NOPUSH_MASK_5 0x62ef
|
||||
#define NOPUSH_MASK_5 0x61ef
|
||||
#define NOPUSH_MASK_6 0xbfcf
|
||||
#define NOPUSH_MASK_7 0x23bf
|
||||
#define NOPUSH_MASK_8 0xf87b
|
||||
|
|
|
@ -565,7 +565,7 @@ static sqlite3LockingStyle sqlite3TestLockingStyle(const char *filePath,
|
|||
lockInfo.l_whence = SEEK_SET;
|
||||
lockInfo.l_type = F_RDLCK;
|
||||
|
||||
if (fcntl(fd, F_GETLK, (int) &lockInfo) != -1) {
|
||||
if (fcntl(fd, F_GETLK, &lockInfo) != -1) {
|
||||
return posixLockingStyle;
|
||||
}
|
||||
|
||||
|
@ -1000,10 +1000,14 @@ int sqlite3UnixIsDirWritable(char *zBuf){
|
|||
*/
|
||||
static int seekAndRead(unixFile *id, void *pBuf, int cnt){
|
||||
int got;
|
||||
i64 newOffset;
|
||||
#ifdef USE_PREAD
|
||||
got = pread(id->h, pBuf, cnt, id->offset);
|
||||
#else
|
||||
lseek(id->h, id->offset, SEEK_SET);
|
||||
newOffset = lseek(id->h, id->offset, SEEK_SET);
|
||||
if( newOffset!=id->offset ){
|
||||
return -1;
|
||||
}
|
||||
got = read(id->h, pBuf, cnt);
|
||||
#endif
|
||||
if( got>0 ){
|
||||
|
@ -1043,10 +1047,14 @@ static int unixRead(OsFile *id, void *pBuf, int amt){
|
|||
*/
|
||||
static int seekAndWrite(unixFile *id, const void *pBuf, int cnt){
|
||||
int got;
|
||||
i64 newOffset;
|
||||
#ifdef USE_PREAD
|
||||
got = pwrite(id->h, pBuf, cnt, id->offset);
|
||||
#else
|
||||
lseek(id->h, id->offset, SEEK_SET);
|
||||
newOffset = lseek(id->h, id->offset, SEEK_SET);
|
||||
if( newOffset!=id->offset ){
|
||||
return -1;
|
||||
}
|
||||
got = write(id->h, pBuf, cnt);
|
||||
#endif
|
||||
if( got>0 ){
|
||||
|
@ -1160,13 +1168,26 @@ static int full_fsync(int fd, int fullSync, int dataOnly){
|
|||
#if HAVE_FULLFSYNC
|
||||
if( fullSync ){
|
||||
rc = fcntl(fd, F_FULLFSYNC, 0);
|
||||
}else
|
||||
#endif /* HAVE_FULLFSYNC */
|
||||
}else{
|
||||
rc = 1;
|
||||
}
|
||||
/* If the FULLFSYNC failed, fall back to attempting an fsync().
|
||||
* It shouldn't be possible for fullfsync to fail on the local
|
||||
* file system (on OSX), so failure indicates that FULLFSYNC
|
||||
* isn't supported for this file system. So, attempt an fsync
|
||||
* and (for now) ignore the overhead of a superfluous fcntl call.
|
||||
* It'd be better to detect fullfsync support once and avoid
|
||||
* the fcntl call every time sync is called.
|
||||
*/
|
||||
if( rc ) rc = fsync(fd);
|
||||
|
||||
#else
|
||||
if( dataOnly ){
|
||||
rc = fdatasync(fd);
|
||||
}else{
|
||||
rc = fsync(fd);
|
||||
}
|
||||
#endif /* HAVE_FULLFSYNC */
|
||||
#endif /* defined(SQLITE_NO_SYNC) */
|
||||
|
||||
return rc;
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -82,19 +82,19 @@
|
|||
#define TK_SLASH 82
|
||||
#define TK_REM 83
|
||||
#define TK_CONCAT 84
|
||||
#define TK_UMINUS 85
|
||||
#define TK_UPLUS 86
|
||||
#define TK_BITNOT 87
|
||||
#define TK_STRING 88
|
||||
#define TK_JOIN_KW 89
|
||||
#define TK_CONSTRAINT 90
|
||||
#define TK_DEFAULT 91
|
||||
#define TK_NULL 92
|
||||
#define TK_PRIMARY 93
|
||||
#define TK_UNIQUE 94
|
||||
#define TK_CHECK 95
|
||||
#define TK_REFERENCES 96
|
||||
#define TK_COLLATE 97
|
||||
#define TK_COLLATE 85
|
||||
#define TK_UMINUS 86
|
||||
#define TK_UPLUS 87
|
||||
#define TK_BITNOT 88
|
||||
#define TK_STRING 89
|
||||
#define TK_JOIN_KW 90
|
||||
#define TK_CONSTRAINT 91
|
||||
#define TK_DEFAULT 92
|
||||
#define TK_NULL 93
|
||||
#define TK_PRIMARY 94
|
||||
#define TK_UNIQUE 95
|
||||
#define TK_CHECK 96
|
||||
#define TK_REFERENCES 97
|
||||
#define TK_AUTOINCR 98
|
||||
#define TK_ON 99
|
||||
#define TK_DELETE 100
|
||||
|
|
|
@ -205,6 +205,7 @@ id(A) ::= ID(X). {A = X;}
|
|||
%left PLUS MINUS.
|
||||
%left STAR SLASH REM.
|
||||
%left CONCAT.
|
||||
%left COLLATE.
|
||||
%right UMINUS UPLUS BITNOT.
|
||||
|
||||
// And "ids" is an identifer-or-string.
|
||||
|
@ -515,24 +516,21 @@ using_opt(U) ::= . {U = 0;}
|
|||
|
||||
orderby_opt(A) ::= . {A = 0;}
|
||||
orderby_opt(A) ::= ORDER BY sortlist(X). {A = X;}
|
||||
sortlist(A) ::= sortlist(X) COMMA sortitem(Y) collate(C) sortorder(Z). {
|
||||
A = sqlite3ExprListAppend(X,Y,C.n>0?&C:0);
|
||||
sortlist(A) ::= sortlist(X) COMMA sortitem(Y) sortorder(Z). {
|
||||
A = sqlite3ExprListAppend(X,Y,0);
|
||||
if( A ) A->a[A->nExpr-1].sortOrder = Z;
|
||||
}
|
||||
sortlist(A) ::= sortitem(Y) collate(C) sortorder(Z). {
|
||||
A = sqlite3ExprListAppend(0,Y,C.n>0?&C:0);
|
||||
sortlist(A) ::= sortitem(Y) sortorder(Z). {
|
||||
A = sqlite3ExprListAppend(0,Y,0);
|
||||
if( A && A->a ) A->a[0].sortOrder = Z;
|
||||
}
|
||||
sortitem(A) ::= expr(X). {A = X;}
|
||||
|
||||
%type sortorder {int}
|
||||
%type collate {Token}
|
||||
|
||||
sortorder(A) ::= ASC. {A = SQLITE_SO_ASC;}
|
||||
sortorder(A) ::= DESC. {A = SQLITE_SO_DESC;}
|
||||
sortorder(A) ::= . {A = SQLITE_SO_ASC;}
|
||||
collate(C) ::= . {C.z = 0; C.n = 0;}
|
||||
collate(C) ::= COLLATE id(X). {C = X;}
|
||||
|
||||
%type groupby_opt {ExprList*}
|
||||
%destructor groupby_opt {sqlite3ExprListDelete($$);}
|
||||
|
@ -642,6 +640,9 @@ expr(A) ::= VARIABLE(X). {
|
|||
Expr *pExpr = A = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
|
||||
sqlite3ExprAssignVarNumber(pParse, pExpr);
|
||||
}
|
||||
expr(A) ::= expr(E) COLLATE id(C). {
|
||||
A = sqlite3ExprSetColl(pParse, E, &C);
|
||||
}
|
||||
%ifndef SQLITE_OMIT_CAST
|
||||
expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
|
||||
A = sqlite3Expr(TK_CAST, E, 0, &T);
|
||||
|
@ -877,6 +878,10 @@ idxlist(A) ::= idxitem(Y) collate(C) sortorder(Z). {
|
|||
}
|
||||
idxitem(A) ::= nm(X). {A = X;}
|
||||
|
||||
%type collate {Token}
|
||||
collate(C) ::= . {C.z = 0; C.n = 0;}
|
||||
collate(C) ::= COLLATE id(X). {C = X;}
|
||||
|
||||
|
||||
///////////////////////////// The DROP INDEX command /////////////////////////
|
||||
//
|
||||
|
|
|
@ -1950,10 +1950,9 @@ static int multiSelect(
|
|||
apColl = pKeyInfo->aColl;
|
||||
for(i=0; i<nOrderByExpr; i++, pOTerm++, apColl++, pSortOrder++){
|
||||
Expr *pExpr = pOTerm->pExpr;
|
||||
char *zName = pOTerm->zName;
|
||||
assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol );
|
||||
if( zName ){
|
||||
*apColl = sqlite3LocateCollSeq(pParse, zName, -1);
|
||||
if( (pExpr->flags & EP_ExpCollate) ){
|
||||
assert( pExpr->pColl!=0 );
|
||||
*apColl = pExpr->pColl;
|
||||
}else{
|
||||
*apColl = aCopy[pExpr->iColumn];
|
||||
}
|
||||
|
@ -2476,8 +2475,14 @@ static int processOrderGroupBy(
|
|||
Expr *pE = pOrderBy->a[i].pExpr;
|
||||
if( sqlite3ExprIsInteger(pE, &iCol) ){
|
||||
if( iCol>0 && iCol<=pEList->nExpr ){
|
||||
CollSeq *pColl = pE->pColl;
|
||||
int flags = pE->flags & EP_ExpCollate;
|
||||
sqlite3ExprDelete(pE);
|
||||
pE = pOrderBy->a[i].pExpr = sqlite3ExprDup(pEList->a[iCol-1].pExpr);
|
||||
if( pColl && flags ){
|
||||
pE->pColl = pColl;
|
||||
pE->flags |= flags;
|
||||
}
|
||||
}else{
|
||||
sqlite3ErrorMsg(pParse,
|
||||
"%s BY column number %d out of range - should be "
|
||||
|
@ -2912,23 +2917,15 @@ int sqlite3Select(
|
|||
}
|
||||
#endif
|
||||
|
||||
/* If there is an ORDER BY clause, resolve any collation sequences
|
||||
** names that have been explicitly specified and create a sorting index.
|
||||
**
|
||||
** This sorting index might end up being unused if the data can be
|
||||
/* If there is an ORDER BY clause, then this sorting
|
||||
** index might end up being unused if the data can be
|
||||
** extracted in pre-sorted order. If that is the case, then the
|
||||
** OP_OpenEphemeral instruction will be changed to an OP_Noop once
|
||||
** we figure out that the sorting index is not needed. The addrSortIndex
|
||||
** variable is used to facilitate that change.
|
||||
*/
|
||||
if( pOrderBy ){
|
||||
struct ExprList_item *pTerm;
|
||||
KeyInfo *pKeyInfo;
|
||||
for(i=0, pTerm=pOrderBy->a; i<pOrderBy->nExpr; i++, pTerm++){
|
||||
if( pTerm->zName ){
|
||||
pTerm->pExpr->pColl = sqlite3LocateCollSeq(pParse, pTerm->zName, -1);
|
||||
}
|
||||
}
|
||||
if( pParse->nErr ){
|
||||
goto select_end;
|
||||
}
|
||||
|
|
|
@ -1021,6 +1021,7 @@ struct Expr {
|
|||
#define EP_VarSelect 0x20 /* pSelect is correlated, not constant */
|
||||
#define EP_Dequoted 0x40 /* True if the string has been dequoted */
|
||||
#define EP_InfixFunc 0x80 /* True for an infix function: LIKE, GLOB, etc */
|
||||
#define EP_ExpCollate 0x100 /* Collating sequence specified explicitly */
|
||||
|
||||
/*
|
||||
** These macros can be used to test, set, or clear bits in the
|
||||
|
@ -1078,8 +1079,12 @@ struct IdList {
|
|||
|
||||
/*
|
||||
** The bitmask datatype defined below is used for various optimizations.
|
||||
**
|
||||
** Changing this from a 64-bit to a 32-bit type limits the number of
|
||||
** tables in a join to 32 instead of 64. But it also reduces the size
|
||||
** of the library by 738 bytes on ix86.
|
||||
*/
|
||||
typedef unsigned int Bitmask;
|
||||
typedef u64 Bitmask;
|
||||
|
||||
/*
|
||||
** The following structure describes the FROM clause of a SELECT statement.
|
||||
|
@ -1108,7 +1113,7 @@ struct SrcList {
|
|||
Select *pSelect; /* A SELECT statement used in place of a table name */
|
||||
u8 isPopulated; /* Temporary table associated with SELECT is populated */
|
||||
u8 jointype; /* Type of join between this able and the previous */
|
||||
i16 iCursor; /* The VDBE cursor number used to access this table */
|
||||
int iCursor; /* The VDBE cursor number used to access this table */
|
||||
Expr *pOn; /* The ON clause of a join */
|
||||
IdList *pUsing; /* The USING clause of a join */
|
||||
Bitmask colUsed; /* Bit N (1<<N) set if column N or pTab is used */
|
||||
|
@ -1773,6 +1778,7 @@ int sqlite3ReadSchema(Parse *pParse);
|
|||
CollSeq *sqlite3FindCollSeq(sqlite3*,u8 enc, const char *,int,int);
|
||||
CollSeq *sqlite3LocateCollSeq(Parse *pParse, const char *zName, int nName);
|
||||
CollSeq *sqlite3ExprCollSeq(Parse *pParse, Expr *pExpr);
|
||||
Expr *sqlite3ExprSetColl(Parse *pParse, Expr *, Token *);
|
||||
int sqlite3CheckCollSeq(Parse *, CollSeq *);
|
||||
int sqlite3CheckIndexCollSeq(Parse *, Index *);
|
||||
int sqlite3CheckObjectName(Parse *, const char *);
|
||||
|
|
|
@ -1055,7 +1055,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
return TCL_ERROR;
|
||||
}
|
||||
nByte = strlen(zSql);
|
||||
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
|
||||
rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
|
||||
sqlite3_free(zSql);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||
|
@ -1081,7 +1081,7 @@ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){
|
|||
}
|
||||
zSql[j++] = ')';
|
||||
zSql[j] = 0;
|
||||
rc = sqlite3_prepare(pDb->db, zSql, 0, &pStmt, 0);
|
||||
rc = sqlite3_prepare(pDb->db, zSql, -1, &pStmt, 0);
|
||||
free(zSql);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, "Error: ", sqlite3_errmsg(pDb->db), 0);
|
||||
|
|
|
@ -610,6 +610,46 @@ static void sqlite3ExecFunc(
|
|||
sqliteFree(x.z);
|
||||
}
|
||||
|
||||
/*
|
||||
** Implementation of tkt2213func(), a scalar function that takes exactly
|
||||
** one argument. It has two interesting features:
|
||||
**
|
||||
** * It calls sqlite3_value_text() 3 times on the argument sqlite3_value*.
|
||||
** If the three pointers returned are not the same an SQL error is raised.
|
||||
**
|
||||
** * Otherwise it returns a copy of the text representation of it's
|
||||
** argument in such a way as the VDBE representation is a Mem* cell
|
||||
** with the MEM_Term flag clear.
|
||||
**
|
||||
** Ticket #2213 can therefore be tested by evaluating the following
|
||||
** SQL expression:
|
||||
**
|
||||
** tkt2213func(tkt2213func('a string'));
|
||||
*/
|
||||
static void tkt2213Function(
|
||||
sqlite3_context *context,
|
||||
int argc,
|
||||
sqlite3_value **argv
|
||||
){
|
||||
int nText;
|
||||
unsigned char const *zText1;
|
||||
unsigned char const *zText2;
|
||||
unsigned char const *zText3;
|
||||
|
||||
nText = sqlite3_value_bytes(argv[0]);
|
||||
zText1 = sqlite3_value_text(argv[0]);
|
||||
zText2 = sqlite3_value_text(argv[0]);
|
||||
zText3 = sqlite3_value_text(argv[0]);
|
||||
|
||||
if( zText1!=zText2 || zText2!=zText3 ){
|
||||
sqlite3_result_error(context, "tkt2213 is not fixed", -1);
|
||||
}else{
|
||||
char *zCopy = (char *)sqlite3_malloc(nText);
|
||||
memcpy(zCopy, zText1, nText);
|
||||
sqlite3_result_text(context, zCopy, nText, sqlite3_free);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
** Usage: sqlite_test_create_function DB
|
||||
**
|
||||
|
@ -651,6 +691,10 @@ static int test_create_function(
|
|||
rc = sqlite3_create_function(db, "hex16", 1, SQLITE_ANY, 0,
|
||||
hex16Func, 0, 0);
|
||||
}
|
||||
if( rc==SQLITE_OK ){
|
||||
rc = sqlite3_create_function(db, "tkt2213func", 1, SQLITE_ANY, 0,
|
||||
tkt2213Function, 0, 0);
|
||||
}
|
||||
|
||||
#ifndef SQLITE_OMIT_UTF16
|
||||
/* Use the sqlite3_create_function16() API here. Mainly for fun, but also
|
||||
|
|
|
@ -577,7 +577,7 @@ static int btree_integrity_check(
|
|||
}
|
||||
pBt = sqlite3TextToPtr(argv[1]);
|
||||
nRoot = argc-2;
|
||||
aRoot = malloc( sizeof(int)*(argc-2) );
|
||||
aRoot = (int*)malloc( sizeof(int)*(argc-2) );
|
||||
for(i=0; i<argc-2; i++){
|
||||
if( Tcl_GetInt(interp, argv[i+2], &aRoot[i]) ) return TCL_ERROR;
|
||||
}
|
||||
|
@ -586,7 +586,7 @@ static int btree_integrity_check(
|
|||
#else
|
||||
zResult = 0;
|
||||
#endif
|
||||
free(aRoot);
|
||||
free((void*)aRoot);
|
||||
if( zResult ){
|
||||
Tcl_AppendResult(interp, zResult, 0);
|
||||
sqliteFree(zResult);
|
||||
|
@ -1186,6 +1186,7 @@ static int btree_payload_size(
|
|||
** aResult[7] = Header size in bytes
|
||||
** aResult[8] = Local payload size
|
||||
** aResult[9] = Parent page number
|
||||
** aResult[10]= Page number of the first overflow page
|
||||
*/
|
||||
static int btree_cursor_info(
|
||||
void *NotUsed,
|
||||
|
@ -1197,7 +1198,7 @@ static int btree_cursor_info(
|
|||
int rc;
|
||||
int i, j;
|
||||
int up;
|
||||
int aResult[10];
|
||||
int aResult[11];
|
||||
char zBuf[400];
|
||||
|
||||
if( argc!=2 && argc!=3 ){
|
||||
|
@ -1225,6 +1226,76 @@ static int btree_cursor_info(
|
|||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** Copied from btree.c:
|
||||
*/
|
||||
static u32 get4byte(unsigned char *p){
|
||||
return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
|
||||
}
|
||||
|
||||
/*
|
||||
** btree_ovfl_info BTREE CURSOR
|
||||
**
|
||||
** Given a cursor, return the sequence of pages number that form the
|
||||
** overflow pages for the data of the entry that the cursor is point
|
||||
** to.
|
||||
*/
|
||||
static int btree_ovfl_info(
|
||||
void *NotUsed,
|
||||
Tcl_Interp *interp, /* The TCL interpreter that invoked this command */
|
||||
int argc, /* Number of arguments */
|
||||
const char **argv /* Text of each argument */
|
||||
){
|
||||
Btree *pBt;
|
||||
BtCursor *pCur;
|
||||
Pager *pPager;
|
||||
int rc;
|
||||
int n;
|
||||
int dataSize;
|
||||
u32 pgno;
|
||||
void *pPage;
|
||||
int aResult[11];
|
||||
char zElem[100];
|
||||
Tcl_DString str;
|
||||
|
||||
if( argc!=3 ){
|
||||
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
|
||||
" BTREE CURSOR", 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pBt = sqlite3TextToPtr(argv[1]);
|
||||
pCur = sqlite3TextToPtr(argv[2]);
|
||||
if( (*(void**)pCur) != (void*)pBt ){
|
||||
Tcl_AppendResult(interp, "Cursor ", argv[2], " does not belong to btree ",
|
||||
argv[1], 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pPager = sqlite3BtreePager(pBt);
|
||||
rc = sqlite3BtreeCursorInfo(pCur, aResult, 0);
|
||||
if( rc ){
|
||||
Tcl_AppendResult(interp, errorName(rc), 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
dataSize = sqlite3BtreeGetPageSize(pBt) - sqlite3BtreeGetReserve(pBt);
|
||||
Tcl_DStringInit(&str);
|
||||
n = aResult[6] - aResult[8];
|
||||
n = (n + dataSize - 1)/dataSize;
|
||||
pgno = (u32)aResult[10];
|
||||
while( pgno && n-- ){
|
||||
sprintf(zElem, "%d", pgno);
|
||||
Tcl_DStringAppendElement(&str, zElem);
|
||||
if( sqlite3pager_get(pPager, pgno, &pPage)!=SQLITE_OK ){
|
||||
Tcl_DStringFree(&str);
|
||||
Tcl_AppendResult(interp, "unable to get page ", zElem, 0);
|
||||
return TCL_ERROR;
|
||||
}
|
||||
pgno = get4byte((unsigned char*)pPage);
|
||||
sqlite3pager_unref(pPage);
|
||||
}
|
||||
Tcl_DStringResult(interp, &str);
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
||||
/*
|
||||
** The command is provided for the purpose of setting breakpoints.
|
||||
** in regression test scripts.
|
||||
|
@ -1440,6 +1511,7 @@ int Sqlitetest3_Init(Tcl_Interp *interp){
|
|||
{ "btree_from_db", (Tcl_CmdProc*)btree_from_db },
|
||||
{ "btree_set_cache_size", (Tcl_CmdProc*)btree_set_cache_size },
|
||||
{ "btree_cursor_info", (Tcl_CmdProc*)btree_cursor_info },
|
||||
{ "btree_ovfl_info", (Tcl_CmdProc*)btree_ovfl_info },
|
||||
{ "btree_cursor_list", (Tcl_CmdProc*)btree_cursor_list },
|
||||
};
|
||||
int i;
|
||||
|
|
|
@ -103,6 +103,7 @@ void sqlite3Update(
|
|||
AuthContext sContext; /* The authorization context */
|
||||
NameContext sNC; /* The name-context to resolve expressions in */
|
||||
int iDb; /* Database containing the table being updated */
|
||||
int memCnt = 0; /* Memory cell used for counting rows changed */
|
||||
|
||||
#ifndef SQLITE_OMIT_TRIGGER
|
||||
int isView; /* Trying to update a view */
|
||||
|
@ -311,7 +312,8 @@ void sqlite3Update(
|
|||
/* Initialize the count of updated rows
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack ){
|
||||
sqlite3VdbeAddOp(v, OP_Integer, 0, 0);
|
||||
memCnt = pParse->nMem++;
|
||||
sqlite3VdbeAddOp(v, OP_MemInt, 0, memCnt);
|
||||
}
|
||||
|
||||
if( triggers_exist ){
|
||||
|
@ -469,7 +471,7 @@ void sqlite3Update(
|
|||
/* Increment the row counter
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack){
|
||||
sqlite3VdbeAddOp(v, OP_AddImm, 1, 0);
|
||||
sqlite3VdbeAddOp(v, OP_MemIncr, 1, memCnt);
|
||||
}
|
||||
|
||||
/* If there are triggers, close all the cursors after each iteration
|
||||
|
@ -514,6 +516,7 @@ void sqlite3Update(
|
|||
** invoke the callback function.
|
||||
*/
|
||||
if( db->flags & SQLITE_CountRows && !pParse->trigStack && pParse->nested==0 ){
|
||||
sqlite3VdbeAddOp(v, OP_MemLoad, memCnt, 0);
|
||||
sqlite3VdbeAddOp(v, OP_Callback, 1, 0);
|
||||
sqlite3VdbeSetNumCols(v, 1);
|
||||
sqlite3VdbeSetColName(v, 0, COLNAME_NAME, "rows updated", P3_STATIC);
|
||||
|
|
|
@ -137,6 +137,7 @@ int sqlite3VdbeMemNulTerminate(Mem *pMem){
|
|||
}
|
||||
pMem->xDel = 0;
|
||||
pMem->z = z;
|
||||
pMem->flags |= MEM_Term;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
}
|
||||
|
|
|
@ -43,6 +43,7 @@ int sqlite3_where_trace = 0;
|
|||
/* Forward reference
|
||||
*/
|
||||
typedef struct WhereClause WhereClause;
|
||||
typedef struct ExprMaskSet ExprMaskSet;
|
||||
|
||||
/*
|
||||
** The query generator uses an array of instances of this structure to
|
||||
|
@ -106,6 +107,7 @@ struct WhereTerm {
|
|||
*/
|
||||
struct WhereClause {
|
||||
Parse *pParse; /* The parser context */
|
||||
ExprMaskSet *pMaskSet; /* Mapping of table indices to bitmasks */
|
||||
int nTerm; /* Number of terms */
|
||||
int nSlot; /* Number of entries in a[] */
|
||||
WhereTerm *a; /* Each a[] describes a term of the WHERE cluase */
|
||||
|
@ -138,7 +140,6 @@ struct WhereClause {
|
|||
** numbers all get mapped into bit numbers that begin with 0 and contain
|
||||
** no gaps.
|
||||
*/
|
||||
typedef struct ExprMaskSet ExprMaskSet;
|
||||
struct ExprMaskSet {
|
||||
int n; /* Number of assigned cursor values */
|
||||
int ix[sizeof(Bitmask)*8]; /* Cursor assigned to each bit */
|
||||
|
@ -186,8 +187,13 @@ struct ExprMaskSet {
|
|||
/*
|
||||
** Initialize a preallocated WhereClause structure.
|
||||
*/
|
||||
static void whereClauseInit(WhereClause *pWC, Parse *pParse){
|
||||
static void whereClauseInit(
|
||||
WhereClause *pWC, /* The WhereClause to be initialized */
|
||||
Parse *pParse, /* The parsing context */
|
||||
ExprMaskSet *pMaskSet /* Mapping from table indices to bitmasks */
|
||||
){
|
||||
pWC->pParse = pParse;
|
||||
pWC->pMaskSet = pMaskSet;
|
||||
pWC->nTerm = 0;
|
||||
pWC->nSlot = ARRAYSIZE(pWC->aStatic);
|
||||
pWC->a = pWC->aStatic;
|
||||
|
@ -463,7 +469,7 @@ static WhereTerm *findTerm(
|
|||
}
|
||||
|
||||
/* Forward reference */
|
||||
static void exprAnalyze(SrcList*, ExprMaskSet*, WhereClause*, int);
|
||||
static void exprAnalyze(SrcList*, WhereClause*, int);
|
||||
|
||||
/*
|
||||
** Call exprAnalyze on all terms in a WHERE clause.
|
||||
|
@ -472,12 +478,11 @@ static void exprAnalyze(SrcList*, ExprMaskSet*, WhereClause*, int);
|
|||
*/
|
||||
static void exprAnalyzeAll(
|
||||
SrcList *pTabList, /* the FROM clause */
|
||||
ExprMaskSet *pMaskSet, /* table masks */
|
||||
WhereClause *pWC /* the WHERE clause to be analyzed */
|
||||
){
|
||||
int i;
|
||||
for(i=pWC->nTerm-1; i>=0; i--){
|
||||
exprAnalyze(pTabList, pMaskSet, pWC, i);
|
||||
exprAnalyze(pTabList, pWC, i);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -592,11 +597,11 @@ static void transferJoinMarkings(Expr *pDerived, Expr *pBase){
|
|||
*/
|
||||
static void exprAnalyze(
|
||||
SrcList *pSrc, /* the FROM clause */
|
||||
ExprMaskSet *pMaskSet, /* table masks */
|
||||
WhereClause *pWC, /* the WHERE clause */
|
||||
int idxTerm /* Index of the term to be analyzed */
|
||||
){
|
||||
WhereTerm *pTerm = &pWC->a[idxTerm];
|
||||
ExprMaskSet *pMaskSet = pWC->pMaskSet;
|
||||
Expr *pExpr = pTerm->pExpr;
|
||||
Bitmask prereqLeft;
|
||||
Bitmask prereqAll;
|
||||
|
@ -679,7 +684,7 @@ static void exprAnalyze(
|
|||
pNewExpr = sqlite3Expr(ops[i], sqlite3ExprDup(pExpr->pLeft),
|
||||
sqlite3ExprDup(pList->a[i].pExpr), 0);
|
||||
idxNew = whereClauseInsert(pWC, pNewExpr, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
exprAnalyze(pSrc, pMaskSet, pWC, idxNew);
|
||||
exprAnalyze(pSrc, pWC, idxNew);
|
||||
pTerm = &pWC->a[idxTerm];
|
||||
pWC->a[idxNew].iParent = idxTerm;
|
||||
}
|
||||
|
@ -708,9 +713,9 @@ static void exprAnalyze(
|
|||
WhereTerm *pOrTerm;
|
||||
|
||||
assert( (pTerm->flags & TERM_DYNAMIC)==0 );
|
||||
whereClauseInit(&sOr, pWC->pParse);
|
||||
whereClauseInit(&sOr, pWC->pParse, pMaskSet);
|
||||
whereSplit(&sOr, pExpr, TK_OR);
|
||||
exprAnalyzeAll(pSrc, pMaskSet, &sOr);
|
||||
exprAnalyzeAll(pSrc, &sOr);
|
||||
assert( sOr.nTerm>0 );
|
||||
j = 0;
|
||||
do{
|
||||
|
@ -750,7 +755,7 @@ static void exprAnalyze(
|
|||
transferJoinMarkings(pNew, pExpr);
|
||||
pNew->pList = pList;
|
||||
idxNew = whereClauseInsert(pWC, pNew, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
exprAnalyze(pSrc, pMaskSet, pWC, idxNew);
|
||||
exprAnalyze(pSrc, pWC, idxNew);
|
||||
pTerm = &pWC->a[idxTerm];
|
||||
pWC->a[idxNew].iParent = idxTerm;
|
||||
pTerm->nChild = 1;
|
||||
|
@ -787,10 +792,10 @@ or_not_possible:
|
|||
}
|
||||
pNewExpr1 = sqlite3Expr(TK_GE, sqlite3ExprDup(pLeft), pStr1, 0);
|
||||
idxNew1 = whereClauseInsert(pWC, pNewExpr1, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
exprAnalyze(pSrc, pMaskSet, pWC, idxNew1);
|
||||
exprAnalyze(pSrc, pWC, idxNew1);
|
||||
pNewExpr2 = sqlite3Expr(TK_LT, sqlite3ExprDup(pLeft), pStr2, 0);
|
||||
idxNew2 = whereClauseInsert(pWC, pNewExpr2, TERM_VIRTUAL|TERM_DYNAMIC);
|
||||
exprAnalyze(pSrc, pMaskSet, pWC, idxNew2);
|
||||
exprAnalyze(pSrc, pWC, idxNew2);
|
||||
pTerm = &pWC->a[idxTerm];
|
||||
if( isComplete ){
|
||||
pWC->a[idxNew1].iParent = idxTerm;
|
||||
|
@ -836,6 +841,25 @@ or_not_possible:
|
|||
#endif /* SQLITE_OMIT_VIRTUALTABLE */
|
||||
}
|
||||
|
||||
/*
|
||||
** Return TRUE if any of the expressions in pList->a[iFirst...] contain
|
||||
** a reference to any table other than the iBase table.
|
||||
*/
|
||||
static int referencesOtherTables(
|
||||
ExprList *pList, /* Search expressions in ths list */
|
||||
ExprMaskSet *pMaskSet, /* Mapping from tables to bitmaps */
|
||||
int iFirst, /* Be searching with the iFirst-th expression */
|
||||
int iBase /* Ignore references to this table */
|
||||
){
|
||||
Bitmask allowed = ~getMask(pMaskSet, iBase);
|
||||
while( iFirst<pList->nExpr ){
|
||||
if( (exprTableUsage(pMaskSet, pList->a[iFirst++].pExpr)&allowed)!=0 ){
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
** This routine decides if pIdx can be used to satisfy the ORDER BY
|
||||
|
@ -858,6 +882,7 @@ or_not_possible:
|
|||
*/
|
||||
static int isSortingIndex(
|
||||
Parse *pParse, /* Parsing context */
|
||||
ExprMaskSet *pMaskSet, /* Mapping from table indices to bitmaps */
|
||||
Index *pIdx, /* The index we are testing */
|
||||
int base, /* Cursor number for the table to be sorted */
|
||||
ExprList *pOrderBy, /* The ORDER BY clause */
|
||||
|
@ -894,7 +919,7 @@ static int isSortingIndex(
|
|||
if( pExpr->op!=TK_COLUMN || pExpr->iTable!=base ){
|
||||
/* Can not use an index sort on anything that is not a column in the
|
||||
** left-most table of the FROM clause */
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
pColl = sqlite3ExprCollSeq(pParse, pExpr);
|
||||
if( !pColl ){
|
||||
|
@ -941,11 +966,12 @@ static int isSortingIndex(
|
|||
}
|
||||
j++;
|
||||
pTerm++;
|
||||
if( iColumn<0 ){
|
||||
if( iColumn<0 && !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){
|
||||
/* If the indexed column is the primary key and everything matches
|
||||
** so far, then we are assured that the index can be used to sort
|
||||
** because the primary key is unique and so none of the other columns
|
||||
** will make any difference
|
||||
** so far and none of the ORDER BY terms to the right reference other
|
||||
** tables in the join, then we are assured that the index can be used
|
||||
** to sort because the primary key is unique and so none of the other
|
||||
** columns will make any difference
|
||||
*/
|
||||
j = nTerm;
|
||||
}
|
||||
|
@ -957,9 +983,12 @@ static int isSortingIndex(
|
|||
** this index can be used for sorting. */
|
||||
return 1;
|
||||
}
|
||||
if( j==pIdx->nColumn && pIdx->onError!=OE_None ){
|
||||
if( pIdx->onError!=OE_None && i==pIdx->nColumn
|
||||
&& !referencesOtherTables(pOrderBy, pMaskSet, j, base) ){
|
||||
/* All terms of this index match some prefix of the ORDER BY clause
|
||||
** and this index is UNIQUE, so this index can be used for sorting. */
|
||||
** and the index is UNIQUE and no terms on the tail of the ORDER BY
|
||||
** clause reference other tables in a join. If this is all true then
|
||||
** the order by clause is superfluous. */
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
|
@ -973,6 +1002,7 @@ static int isSortingIndex(
|
|||
static int sortableByRowid(
|
||||
int base, /* Cursor number for table to be sorted */
|
||||
ExprList *pOrderBy, /* The ORDER BY clause */
|
||||
ExprMaskSet *pMaskSet, /* Mapping from tables to bitmaps */
|
||||
int *pbRev /* Set to 1 if ORDER BY is DESC */
|
||||
){
|
||||
Expr *p;
|
||||
|
@ -980,7 +1010,8 @@ static int sortableByRowid(
|
|||
assert( pOrderBy!=0 );
|
||||
assert( pOrderBy->nExpr>0 );
|
||||
p = pOrderBy->a[0].pExpr;
|
||||
if( p->op==TK_COLUMN && p->iTable==base && p->iColumn==-1 ){
|
||||
if( p->op==TK_COLUMN && p->iTable==base && p->iColumn==-1
|
||||
&& !referencesOtherTables(pOrderBy, pMaskSet, 1, base) ){
|
||||
*pbRev = pOrderBy->a[0].sortOrder;
|
||||
return 1;
|
||||
}
|
||||
|
@ -1298,7 +1329,7 @@ static double bestIndex(
|
|||
*/
|
||||
if( pProbe==0 &&
|
||||
findTerm(pWC, iCur, -1, 0, WO_EQ|WO_IN|WO_LT|WO_LE|WO_GT|WO_GE,0)==0 &&
|
||||
(pOrderBy==0 || !sortableByRowid(iCur, pOrderBy, &rev)) ){
|
||||
(pOrderBy==0 || !sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev)) ){
|
||||
*pFlags = 0;
|
||||
*ppIndex = 0;
|
||||
*pnEq = 0;
|
||||
|
@ -1360,7 +1391,7 @@ static double bestIndex(
|
|||
/* If the table scan does not satisfy the ORDER BY clause, increase
|
||||
** the cost by NlogN to cover the expense of sorting. */
|
||||
if( pOrderBy ){
|
||||
if( sortableByRowid(iCur, pOrderBy, &rev) ){
|
||||
if( sortableByRowid(iCur, pOrderBy, pWC->pMaskSet, &rev) ){
|
||||
flags |= WHERE_ORDERBY|WHERE_ROWID_RANGE;
|
||||
if( rev ){
|
||||
flags |= WHERE_REVERSE;
|
||||
|
@ -1444,7 +1475,7 @@ static double bestIndex(
|
|||
*/
|
||||
if( pOrderBy ){
|
||||
if( (flags & WHERE_COLUMN_IN)==0 &&
|
||||
isSortingIndex(pParse,pProbe,iCur,pOrderBy,nEq,&rev) ){
|
||||
isSortingIndex(pParse,pWC->pMaskSet,pProbe,iCur,pOrderBy,nEq,&rev) ){
|
||||
if( flags==0 ){
|
||||
flags = WHERE_COLUMN_RANGE;
|
||||
}
|
||||
|
@ -1832,7 +1863,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
** subexpression is separated by an AND operator.
|
||||
*/
|
||||
initMaskSet(&maskSet);
|
||||
whereClauseInit(&wc, pParse);
|
||||
whereClauseInit(&wc, pParse, &maskSet);
|
||||
whereSplit(&wc, pWhere, TK_AND);
|
||||
|
||||
/* Allocate and initialize the WhereInfo structure that will become the
|
||||
|
@ -1863,7 +1894,7 @@ WhereInfo *sqlite3WhereBegin(
|
|||
for(i=0; i<pTabList->nSrc; i++){
|
||||
createMask(&maskSet, pTabList->a[i].iCursor);
|
||||
}
|
||||
exprAnalyzeAll(pTabList, &maskSet, &wc);
|
||||
exprAnalyzeAll(pTabList, &wc);
|
||||
if( sqlite3MallocFailed() ){
|
||||
goto whereBeginNoMem;
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue