|
|
@@ -306,6 +306,10 @@
|
|
|
# define _GNU_SOURCE
|
|
|
#endif
|
|
|
|
|
|
+#if defined(__OpenBSD__) && !defined(_BSD_SOURCE)
|
|
|
+# define _BSD_SOURCE
|
|
|
+#endif
|
|
|
+
|
|
|
/*
|
|
|
** Include standard header files as necessary
|
|
|
*/
|
|
|
@@ -676,7 +680,7 @@ extern "C" {
|
|
|
*/
|
|
|
#define SQLITE_VERSION "3.7.16"
|
|
|
#define SQLITE_VERSION_NUMBER 3007016
|
|
|
-#define SQLITE_SOURCE_ID "2013-03-06 01:41:53 4f5f3aebe81c3cbe539db3e33ec38fa3de47e90b"
|
|
|
+#define SQLITE_SOURCE_ID "2013-03-20 12:04:29 5b22053f918d16f593227a432a5d5b4c195bb0b5"
|
|
|
|
|
|
/*
|
|
|
** CAPI3REF: Run-Time Library Version Numbers
|
|
|
@@ -865,7 +869,7 @@ typedef sqlite_uint64 sqlite3_uint64;
|
|
|
** [sqlite3_blob_close | close] all [BLOB handles], and
|
|
|
** [sqlite3_backup_finish | finish] all [sqlite3_backup] objects associated
|
|
|
** with the [sqlite3] object prior to attempting to close the object. ^If
|
|
|
-** sqlite3_close() is called on a [database connection] that still has
|
|
|
+** sqlite3_close_v2() is called on a [database connection] that still has
|
|
|
** outstanding [prepared statements], [BLOB handles], and/or
|
|
|
** [sqlite3_backup] objects then it returns SQLITE_OK but the deallocation
|
|
|
** of resources is deferred until all [prepared statements], [BLOB handles],
|
|
|
@@ -4596,7 +4600,8 @@ SQLITE_API SQLITE_DEPRECATED int sqlite3_expired(sqlite3_stmt*);
|
|
|
SQLITE_API SQLITE_DEPRECATED int sqlite3_transfer_bindings(sqlite3_stmt*, sqlite3_stmt*);
|
|
|
SQLITE_API SQLITE_DEPRECATED int sqlite3_global_recover(void);
|
|
|
SQLITE_API SQLITE_DEPRECATED void sqlite3_thread_cleanup(void);
|
|
|
-SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),void*,sqlite3_int64);
|
|
|
+SQLITE_API SQLITE_DEPRECATED int sqlite3_memory_alarm(void(*)(void*,sqlite3_int64,int),
|
|
|
+ void*,sqlite3_int64);
|
|
|
#endif
|
|
|
|
|
|
/*
|
|
|
@@ -4676,14 +4681,17 @@ SQLITE_API int sqlite3_value_numeric_type(sqlite3_value*);
|
|
|
** In those cases, sqlite3_aggregate_context() might be called for the
|
|
|
** first time from within xFinal().)^
|
|
|
**
|
|
|
-** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer if N is
|
|
|
-** less than or equal to zero or if a memory allocate error occurs.
|
|
|
+** ^The sqlite3_aggregate_context(C,N) routine returns a NULL pointer
|
|
|
+** when first called if N is less than or equal to zero or if a memory
|
|
|
+** allocate error occurs.
|
|
|
**
|
|
|
** ^(The amount of space allocated by sqlite3_aggregate_context(C,N) is
|
|
|
** determined by the N parameter on first successful call. Changing the
|
|
|
** value of N in subsequent call to sqlite3_aggregate_context() within
|
|
|
** the same aggregate function instance will not resize the memory
|
|
|
-** allocation.)^
|
|
|
+** allocation.)^ Within the xFinal callback, it is customary to set
|
|
|
+** N=0 in calls to sqlite3_aggregate_context(C,N) so that no
|
|
|
+** pointless memory allocations occur.
|
|
|
**
|
|
|
** ^SQLite automatically frees the memory allocated by
|
|
|
** sqlite3_aggregate_context() when the aggregate query concludes.
|
|
|
@@ -12393,7 +12401,8 @@ SQLITE_PRIVATE void sqlite3EndBenignMalloc(void);
|
|
|
|
|
|
#define IN_INDEX_ROWID 1
|
|
|
#define IN_INDEX_EPH 2
|
|
|
-#define IN_INDEX_INDEX 3
|
|
|
+#define IN_INDEX_INDEX_ASC 3
|
|
|
+#define IN_INDEX_INDEX_DESC 4
|
|
|
SQLITE_PRIVATE int sqlite3FindInIndex(Parse *, Expr *, int*);
|
|
|
|
|
|
#ifdef SQLITE_ENABLE_ATOMIC_WRITE
|
|
|
@@ -21514,7 +21523,7 @@ SQLITE_API int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
|
|
|
*/
|
|
|
SQLITE_PRIVATE int sqlite3AtoF(const char *z, sqlite_double *pResult, int length, u8 enc){
|
|
|
#ifndef SQLITE_OMIT_FLOATING_POINT
|
|
|
- int incr = (enc==SQLITE_UTF8?1:2);
|
|
|
+ int incr;
|
|
|
const char *zEnd = z + length;
|
|
|
/* sign * significand * (10 ^ (esign * exponent)) */
|
|
|
int sign = 1; /* sign of significand */
|
|
|
@@ -21525,10 +21534,22 @@ SQLITE_PRIVATE int sqlite3AtoF(const char *z, sqlite_double *pResult, int lengt
|
|
|
int eValid = 1; /* True exponent is either not used or is well-formed */
|
|
|
sqlite_double result;
|
|
|
int nDigits = 0;
|
|
|
+ int nonNum = 0;
|
|
|
|
|
|
+ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
|
|
|
*pResult = 0.0; /* Default return value, in case of an error */
|
|
|
|
|
|
- if( enc==SQLITE_UTF16BE ) z++;
|
|
|
+ if( enc==SQLITE_UTF8 ){
|
|
|
+ incr = 1;
|
|
|
+ }else{
|
|
|
+ int i;
|
|
|
+ incr = 2;
|
|
|
+ assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
|
|
+ for(i=3-enc; i<length && z[i]==0; i+=2){}
|
|
|
+ nonNum = i<length;
|
|
|
+ zEnd = z+i+enc-3;
|
|
|
+ z += (enc&1);
|
|
|
+ }
|
|
|
|
|
|
/* skip leading spaces */
|
|
|
while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
|
|
|
@@ -21661,7 +21682,7 @@ do_atof_calc:
|
|
|
*pResult = result;
|
|
|
|
|
|
/* return true if number and no extra non-whitespace chracters after */
|
|
|
- return z>=zEnd && nDigits>0 && eValid;
|
|
|
+ return z>=zEnd && nDigits>0 && eValid && nonNum==0;
|
|
|
#else
|
|
|
return !sqlite3Atoi64(z, pResult, length, enc);
|
|
|
#endif /* SQLITE_OMIT_FLOATING_POINT */
|
|
|
@@ -21710,21 +21731,33 @@ static int compare2pow63(const char *zNum, int incr){
|
|
|
** signed 64-bit integer, its negative -9223372036854665808 can be.
|
|
|
**
|
|
|
** If zNum is too big for a 64-bit integer and is not
|
|
|
-** 9223372036854665808 then return 1.
|
|
|
+** 9223372036854665808 or if zNum contains any non-numeric text,
|
|
|
+** then return 1.
|
|
|
**
|
|
|
** length is the number of bytes in the string (bytes, not characters).
|
|
|
** The string is not necessarily zero-terminated. The encoding is
|
|
|
** given by enc.
|
|
|
*/
|
|
|
SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
|
|
|
- int incr = (enc==SQLITE_UTF8?1:2);
|
|
|
+ int incr;
|
|
|
u64 u = 0;
|
|
|
int neg = 0; /* assume positive */
|
|
|
int i;
|
|
|
int c = 0;
|
|
|
+ int nonNum = 0;
|
|
|
const char *zStart;
|
|
|
const char *zEnd = zNum + length;
|
|
|
- if( enc==SQLITE_UTF16BE ) zNum++;
|
|
|
+ assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
|
|
|
+ if( enc==SQLITE_UTF8 ){
|
|
|
+ incr = 1;
|
|
|
+ }else{
|
|
|
+ incr = 2;
|
|
|
+ assert( SQLITE_UTF16LE==2 && SQLITE_UTF16BE==3 );
|
|
|
+ for(i=3-enc; i<length && zNum[i]==0; i+=2){}
|
|
|
+ nonNum = i<length;
|
|
|
+ zEnd = zNum+i+enc-3;
|
|
|
+ zNum += (enc&1);
|
|
|
+ }
|
|
|
while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
|
|
|
if( zNum<zEnd ){
|
|
|
if( *zNum=='-' ){
|
|
|
@@ -21749,7 +21782,7 @@ SQLITE_PRIVATE int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc
|
|
|
testcase( i==18 );
|
|
|
testcase( i==19 );
|
|
|
testcase( i==20 );
|
|
|
- if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr ){
|
|
|
+ if( (c+nonNum!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr ){
|
|
|
/* zNum is empty or contains non-numeric text or is longer
|
|
|
** than 19 digits (thus guaranteeing that it is too large) */
|
|
|
return 1;
|
|
|
@@ -48603,6 +48636,25 @@ int sqlite3BtreeTrace=1; /* True to enable tracing */
|
|
|
*/
|
|
|
#define get2byteNotZero(X) (((((int)get2byte(X))-1)&0xffff)+1)
|
|
|
|
|
|
+/*
|
|
|
+** Values passed as the 5th argument to allocateBtreePage()
|
|
|
+*/
|
|
|
+#define BTALLOC_ANY 0 /* Allocate any page */
|
|
|
+#define BTALLOC_EXACT 1 /* Allocate exact page if possible */
|
|
|
+#define BTALLOC_LE 2 /* Allocate any page <= the parameter */
|
|
|
+
|
|
|
+/*
|
|
|
+** Macro IfNotOmitAV(x) returns (x) if SQLITE_OMIT_AUTOVACUUM is not
|
|
|
+** defined, or 0 if it is. For example:
|
|
|
+**
|
|
|
+** bIncrVacuum = IfNotOmitAV(pBtShared->incrVacuum);
|
|
|
+*/
|
|
|
+#ifndef SQLITE_OMIT_AUTOVACUUM
|
|
|
+#define IfNotOmitAV(expr) (expr)
|
|
|
+#else
|
|
|
+#define IfNotOmitAV(expr) 0
|
|
|
+#endif
|
|
|
+
|
|
|
#ifndef SQLITE_OMIT_SHARED_CACHE
|
|
|
/*
|
|
|
** A list of BtShared objects that are eligible for participation
|
|
|
@@ -51155,7 +51207,7 @@ SQLITE_PRIVATE int sqlite3BtreeBeginTrans(Btree *p, int wrflag){
|
|
|
if( p->inTrans==TRANS_WRITE || (p->inTrans==TRANS_READ && !wrflag) ){
|
|
|
goto trans_begun;
|
|
|
}
|
|
|
- assert( pBt->bDoTruncate==0 );
|
|
|
+ assert( IfNotOmitAV(pBt->bDoTruncate)==0 );
|
|
|
|
|
|
/* Write transactions are not possible on a read-only database */
|
|
|
if( (pBt->btsFlags & BTS_READ_ONLY)!=0 && wrflag ){
|
|
|
@@ -51470,9 +51522,6 @@ static int relocatePage(
|
|
|
|
|
|
/* Forward declaration required by incrVacuumStep(). */
|
|
|
static int allocateBtreePage(BtShared *, MemPage **, Pgno *, Pgno, u8);
|
|
|
-#define BTALLOC_ANY 0 /* Allocate any page */
|
|
|
-#define BTALLOC_EXACT 1 /* Allocate exact page if possible */
|
|
|
-#define BTALLOC_LE 2 /* Allocate any page <= the parameter */
|
|
|
|
|
|
/*
|
|
|
** Perform a single step of an incremental-vacuum. If successful, return
|
|
|
@@ -53462,7 +53511,7 @@ static int allocateBtreePage(
|
|
|
Pgno mxPage; /* Total size of the database file */
|
|
|
|
|
|
assert( sqlite3_mutex_held(pBt->mutex) );
|
|
|
- assert( eMode==BTALLOC_ANY || (nearby>0 && pBt->autoVacuum) );
|
|
|
+ assert( eMode==BTALLOC_ANY || (nearby>0 && IfNotOmitAV(pBt->autoVacuum)) );
|
|
|
pPage1 = pBt->pPage1;
|
|
|
mxPage = btreePagecount(pBt);
|
|
|
n = get4byte(&pPage1->aData[36]);
|
|
|
@@ -53695,7 +53744,7 @@ static int allocateBtreePage(
|
|
|
** here are confined to those pages that lie between the end of the
|
|
|
** database image and the end of the database file.
|
|
|
*/
|
|
|
- int bNoContent = (0==pBt->bDoTruncate);
|
|
|
+ int bNoContent = (0==IfNotOmitAV(pBt->bDoTruncate));
|
|
|
|
|
|
rc = sqlite3PagerWrite(pBt->pPage1->pDbPage);
|
|
|
if( rc ) return rc;
|
|
|
@@ -57755,7 +57804,9 @@ copy_finished:
|
|
|
** between formats.
|
|
|
*/
|
|
|
SQLITE_PRIVATE int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){
|
|
|
+#ifndef SQLITE_OMIT_UTF16
|
|
|
int rc;
|
|
|
+#endif
|
|
|
assert( (pMem->flags&MEM_RowSet)==0 );
|
|
|
assert( desiredEnc==SQLITE_UTF8 || desiredEnc==SQLITE_UTF16LE
|
|
|
|| desiredEnc==SQLITE_UTF16BE );
|
|
|
@@ -75603,10 +75654,11 @@ SQLITE_PRIVATE int sqlite3CodeOnce(Parse *pParse){
|
|
|
**
|
|
|
** The returned value of this function indicates the b-tree type, as follows:
|
|
|
**
|
|
|
-** IN_INDEX_ROWID - The cursor was opened on a database table.
|
|
|
-** IN_INDEX_INDEX - The cursor was opened on a database index.
|
|
|
-** IN_INDEX_EPH - The cursor was opened on a specially created and
|
|
|
-** populated epheremal table.
|
|
|
+** IN_INDEX_ROWID - The cursor was opened on a database table.
|
|
|
+** IN_INDEX_INDEX_ASC - The cursor was opened on an ascending index.
|
|
|
+** IN_INDEX_INDEX_DESC - The cursor was opened on a descending index.
|
|
|
+** IN_INDEX_EPH - The cursor was opened on a specially created and
|
|
|
+** populated epheremal table.
|
|
|
**
|
|
|
** An existing b-tree might be used if the RHS expression pX is a simple
|
|
|
** subquery such as:
|
|
|
@@ -75729,7 +75781,8 @@ SQLITE_PRIVATE int sqlite3FindInIndex(Parse *pParse, Expr *pX, int *prNotFound){
|
|
|
sqlite3VdbeAddOp4(v, OP_OpenRead, iTab, pIdx->tnum, iDb,
|
|
|
pKey,P4_KEYINFO_HANDOFF);
|
|
|
VdbeComment((v, "%s", pIdx->zName));
|
|
|
- eType = IN_INDEX_INDEX;
|
|
|
+ assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
|
|
|
+ eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
|
|
|
|
|
|
sqlite3VdbeJumpHere(v, iAddr);
|
|
|
if( prNotFound && !pTab->aCol[iCol].notNull ){
|
|
|
@@ -85556,30 +85609,28 @@ SQLITE_PRIVATE void sqlite3MaterializeView(
|
|
|
int iCur /* Cursor number for ephemerial table */
|
|
|
){
|
|
|
SelectDest dest;
|
|
|
- Select *pDup;
|
|
|
+ Select *pSel;
|
|
|
+ SrcList *pFrom;
|
|
|
sqlite3 *db = pParse->db;
|
|
|
+ int iDb = sqlite3SchemaToIndex(db, pView->pSchema);
|
|
|
|
|
|
- pDup = sqlite3SelectDup(db, pView->pSelect, 0);
|
|
|
- if( pWhere ){
|
|
|
- SrcList *pFrom;
|
|
|
-
|
|
|
- pWhere = sqlite3ExprDup(db, pWhere, 0);
|
|
|
- pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
|
|
|
- if( pFrom ){
|
|
|
- assert( pFrom->nSrc==1 );
|
|
|
- pFrom->a[0].zAlias = sqlite3DbStrDup(db, pView->zName);
|
|
|
- pFrom->a[0].pSelect = pDup;
|
|
|
- assert( pFrom->a[0].pOn==0 );
|
|
|
- assert( pFrom->a[0].pUsing==0 );
|
|
|
- }else{
|
|
|
- sqlite3SelectDelete(db, pDup);
|
|
|
- }
|
|
|
- pDup = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
|
|
|
- if( pDup ) pDup->selFlags |= SF_Materialize;
|
|
|
+ pWhere = sqlite3ExprDup(db, pWhere, 0);
|
|
|
+ pFrom = sqlite3SrcListAppend(db, 0, 0, 0);
|
|
|
+
|
|
|
+ if( pFrom ){
|
|
|
+ assert( pFrom->nSrc==1 );
|
|
|
+ pFrom->a[0].zName = sqlite3DbStrDup(db, pView->zName);
|
|
|
+ pFrom->a[0].zDatabase = sqlite3DbStrDup(db, db->aDb[iDb].zName);
|
|
|
+ assert( pFrom->a[0].pOn==0 );
|
|
|
+ assert( pFrom->a[0].pUsing==0 );
|
|
|
}
|
|
|
+
|
|
|
+ pSel = sqlite3SelectNew(pParse, 0, pFrom, pWhere, 0, 0, 0, 0, 0, 0);
|
|
|
+ if( pSel ) pSel->selFlags |= SF_Materialize;
|
|
|
+
|
|
|
sqlite3SelectDestInit(&dest, SRT_EphemTab, iCur);
|
|
|
- sqlite3Select(pParse, pDup, &dest);
|
|
|
- sqlite3SelectDelete(db, pDup);
|
|
|
+ sqlite3Select(pParse, pSel, &dest);
|
|
|
+ sqlite3SelectDelete(db, pSel);
|
|
|
}
|
|
|
#endif /* !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER) */
|
|
|
|
|
|
@@ -87162,18 +87213,23 @@ static void charFunc(
|
|
|
x = sqlite3_value_int64(argv[i]);
|
|
|
if( x<0 || x>0x10ffff ) x = 0xfffd;
|
|
|
c = (unsigned)(x & 0x1fffff);
|
|
|
- if( c<=0xFFFF ){
|
|
|
- if( c>=0xd800 && c<=0xdfff ) c = 0xfffd;
|
|
|
- *zOut++ = (u8)(c&0x00FF);
|
|
|
- *zOut++ = (u8)((c>>8)&0x00FF);
|
|
|
+ if( c<0x00080 ){
|
|
|
+ *zOut++ = (u8)(c&0xFF);
|
|
|
+ }else if( c<0x00800 ){
|
|
|
+ *zOut++ = 0xC0 + (u8)((c>>6)&0x1F);
|
|
|
+ *zOut++ = 0x80 + (u8)(c & 0x3F);
|
|
|
+ }else if( c<0x10000 ){
|
|
|
+ *zOut++ = 0xE0 + (u8)((c>>12)&0x0F);
|
|
|
+ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F);
|
|
|
+ *zOut++ = 0x80 + (u8)(c & 0x3F);
|
|
|
}else{
|
|
|
- *zOut++ = (u8)(((c>>10)&0x003F) + (((c-0x10000)>>10)&0x00C0));
|
|
|
- *zOut++ = (u8)(0x00D8 + (((c-0x10000)>>18)&0x03));
|
|
|
- *zOut++ = (u8)(c&0x00FF);
|
|
|
- *zOut++ = (u8)(0x00DC + ((c>>8)&0x03));
|
|
|
- }
|
|
|
+ *zOut++ = 0xF0 + (u8)((c>>18) & 0x07);
|
|
|
+ *zOut++ = 0x80 + (u8)((c>>12) & 0x3F);
|
|
|
+ *zOut++ = 0x80 + (u8)((c>>6) & 0x3F);
|
|
|
+ *zOut++ = 0x80 + (u8)(c & 0x3F);
|
|
|
+ } \
|
|
|
}
|
|
|
- sqlite3_result_text16le(context, (char*)z, (int)(zOut-z), sqlite3_free);
|
|
|
+ sqlite3_result_text(context, (char*)z, (int)(zOut-z), sqlite3_free);
|
|
|
}
|
|
|
|
|
|
/*
|
|
|
@@ -93443,6 +93499,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
|
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
|
|
|
|
|
|
#ifndef SQLITE_OMIT_FOREIGN_KEY
|
|
|
+#ifndef SQLITE_OMIT_TRIGGER
|
|
|
if( sqlite3StrICmp(zLeft, "foreign_key_check")==0 ){
|
|
|
FKey *pFK; /* A foreign key constraint */
|
|
|
Table *pTab; /* Child table contain "REFERENCES" keyword */
|
|
|
@@ -93554,6 +93611,7 @@ SQLITE_PRIVATE void sqlite3Pragma(
|
|
|
sqlite3VdbeJumpHere(v, addrTop);
|
|
|
}
|
|
|
}else
|
|
|
+#endif /* !defined(SQLITE_OMIT_TRIGGER) */
|
|
|
#endif /* !defined(SQLITE_OMIT_FOREIGN_KEY) */
|
|
|
|
|
|
#ifndef NDEBUG
|
|
|
@@ -94350,11 +94408,15 @@ static int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg){
|
|
|
*/
|
|
|
if( meta[BTREE_TEXT_ENCODING-1] ){ /* text encoding */
|
|
|
if( iDb==0 ){
|
|
|
+#ifndef SQLITE_OMIT_UTF16
|
|
|
u8 encoding;
|
|
|
/* If opening the main database, set ENC(db). */
|
|
|
encoding = (u8)meta[BTREE_TEXT_ENCODING-1] & 3;
|
|
|
if( encoding==0 ) encoding = SQLITE_UTF8;
|
|
|
ENC(db) = encoding;
|
|
|
+#else
|
|
|
+ ENC(db) = SQLITE_UTF8;
|
|
|
+#endif
|
|
|
}else{
|
|
|
/* If opening an attached database, the encoding much match ENC(db) */
|
|
|
if( meta[BTREE_TEXT_ENCODING-1]!=ENC(db) ){
|
|
|
@@ -103831,9 +103893,8 @@ static u16 operatorMask(int op){
|
|
|
** then try for the one with no dependencies on <expr> - in other words where
|
|
|
** <expr> is a constant expression of some kind. Only return entries of
|
|
|
** the form "X <op> Y" where Y is a column in another table if no terms of
|
|
|
-** the form "X <op> <const-expr>" exist. Other than this priority, if there
|
|
|
-** are two or more terms that match, then the choice of which term to return
|
|
|
-** is arbitrary.
|
|
|
+** the form "X <op> <const-expr>" exist. If no terms with a constant RHS
|
|
|
+** exist, try to return a term that does not use WO_EQUIV.
|
|
|
*/
|
|
|
static WhereTerm *findTerm(
|
|
|
WhereClause *pWC, /* The WHERE clause to be searched */
|
|
|
@@ -103892,8 +103953,12 @@ static WhereTerm *findTerm(
|
|
|
continue;
|
|
|
}
|
|
|
}
|
|
|
- pResult = pTerm;
|
|
|
- if( pTerm->prereqRight==0 ) goto findTerm_success;
|
|
|
+ if( pTerm->prereqRight==0 ){
|
|
|
+ pResult = pTerm;
|
|
|
+ goto findTerm_success;
|
|
|
+ }else if( pResult==0 ){
|
|
|
+ pResult = pTerm;
|
|
|
+ }
|
|
|
}
|
|
|
if( (pTerm->eOperator & WO_EQUIV)!=0
|
|
|
&& nEquiv<ArraySize(aEquiv)
|
|
|
@@ -106960,7 +107025,8 @@ static void codeApplyAffinity(Parse *pParse, int base, int n, char *zAff){
|
|
|
static int codeEqualityTerm(
|
|
|
Parse *pParse, /* The parsing context */
|
|
|
WhereTerm *pTerm, /* The term of the WHERE clause to be coded */
|
|
|
- WhereLevel *pLevel, /* When level of the FROM clause we are working on */
|
|
|
+ WhereLevel *pLevel, /* The level of the FROM clause we are working on */
|
|
|
+ int iEq, /* Index of the equality term within this level */
|
|
|
int iTarget /* Attempt to leave results in this register */
|
|
|
){
|
|
|
Expr *pX = pTerm->pExpr;
|
|
|
@@ -106980,9 +107046,22 @@ static int codeEqualityTerm(
|
|
|
struct InLoop *pIn;
|
|
|
u8 bRev = (pLevel->plan.wsFlags & WHERE_REVERSE)!=0;
|
|
|
|
|
|
+ if( (pLevel->plan.wsFlags & WHERE_INDEXED)!=0
|
|
|
+ && pLevel->plan.u.pIdx->aSortOrder[iEq]
|
|
|
+ ){
|
|
|
+ testcase( iEq==0 );
|
|
|
+ testcase( iEq==pLevel->plan.u.pIdx->nColumn-1 );
|
|
|
+ testcase( iEq>0 && iEq+1<pLevel->plan.u.pIdx->nColumn );
|
|
|
+ testcase( bRev );
|
|
|
+ bRev = !bRev;
|
|
|
+ }
|
|
|
assert( pX->op==TK_IN );
|
|
|
iReg = iTarget;
|
|
|
eType = sqlite3FindInIndex(pParse, pX, 0);
|
|
|
+ if( eType==IN_INDEX_INDEX_DESC ){
|
|
|
+ testcase( bRev );
|
|
|
+ bRev = !bRev;
|
|
|
+ }
|
|
|
iTab = pX->iTable;
|
|
|
sqlite3VdbeAddOp2(v, bRev ? OP_Last : OP_Rewind, iTab, 0);
|
|
|
assert( pLevel->plan.wsFlags & WHERE_IN_ABLE );
|
|
|
@@ -107097,7 +107176,7 @@ static int codeAllEqualityTerms(
|
|
|
** Ex: CREATE INDEX i1 ON t1(a,b,a); SELECT * FROM t1 WHERE a=0 AND b=0; */
|
|
|
testcase( (pTerm->wtFlags & TERM_CODED)!=0 );
|
|
|
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
|
|
- r1 = codeEqualityTerm(pParse, pTerm, pLevel, regBase+j);
|
|
|
+ r1 = codeEqualityTerm(pParse, pTerm, pLevel, j, regBase+j);
|
|
|
if( r1!=regBase+j ){
|
|
|
if( nReg==1 ){
|
|
|
sqlite3ReleaseTempReg(pParse, regBase);
|
|
|
@@ -107374,7 +107453,7 @@ static Bitmask codeOneLoopStart(
|
|
|
int iTarget = iReg+j+1;
|
|
|
pTerm = &pWC->a[aConstraint[k].iTermOffset];
|
|
|
if( pTerm->eOperator & WO_IN ){
|
|
|
- codeEqualityTerm(pParse, pTerm, pLevel, iTarget);
|
|
|
+ codeEqualityTerm(pParse, pTerm, pLevel, k, iTarget);
|
|
|
addrNotFound = pLevel->addrNxt;
|
|
|
}else{
|
|
|
sqlite3ExprCode(pParse, pTerm->pExpr->pRight, iTarget);
|
|
|
@@ -107415,10 +107494,11 @@ static Bitmask codeOneLoopStart(
|
|
|
assert( pTerm->pExpr!=0 );
|
|
|
assert( omitTable==0 );
|
|
|
testcase( pTerm->wtFlags & TERM_VIRTUAL ); /* EV: R-30575-11662 */
|
|
|
- iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, iReleaseReg);
|
|
|
+ iRowidReg = codeEqualityTerm(pParse, pTerm, pLevel, 0, iReleaseReg);
|
|
|
addrNxt = pLevel->addrNxt;
|
|
|
sqlite3VdbeAddOp2(v, OP_MustBeInt, iRowidReg, addrNxt);
|
|
|
sqlite3VdbeAddOp3(v, OP_NotExists, iCur, addrNxt, iRowidReg);
|
|
|
+ sqlite3ExprCacheAffinityChange(pParse, iRowidReg, 1);
|
|
|
sqlite3ExprCacheStore(pParse, iCur, -1, iRowidReg);
|
|
|
VdbeComment((v, "pk"));
|
|
|
pLevel->op = OP_Noop;
|