Update this branch with latest trunk changes.

FossilOrigin-Name: 0f66a093935100efd731e14aa63b57360ddd517c1ac97edd1ea9a9de95e1f3cc
This commit is contained in:
dan 2017-04-11 19:00:30 +00:00
commit 0e0f5edbb5
18 changed files with 240 additions and 94 deletions

View File

@ -785,7 +785,7 @@ static int jsonParseValue(JsonParse *pParse, u32 i){
j = i+1;
for(;;){
c = z[j];
if( c==0 ) return -1;
if( c<=0x1f ) return -1; /* Control characters not allowed in strings */
if( c=='\\' ){
c = z[++j];
if( c=='"' || c=='\\' || c=='/' || c=='b' || c=='f'

View File

@ -1,5 +1,5 @@
C Fix\sa\sformatting\sissue\sin\sthe\soutput\sof\sthe\ssqlite3_expert\sprogram.
D 2017-04-11T18:29:14.206
C Update\sthis\s\sbranch\swith\slatest\strunk\schanges.
D 2017-04-11T19:00:30.300
F Makefile.in 1cc758ce3374a32425e4d130c2fe7b026b20de5b8843243de75f087c0a2661fb
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
F Makefile.msc a4c0613a18663bda56d8cf76079ab6590a7c3602e54befb4bbdef76bcaa38b6a
@ -224,7 +224,7 @@ F ext/misc/eval.c f971962e92ebb8b0a4e6b62949463ee454d88fa2
F ext/misc/fileio.c d4171c815d6543a9edef8308aab2951413cd8d0f
F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25
F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c
F ext/misc/json1.c 312b4ddf4c7399dcbd2189f492e8ca92a872c2df7347473bfb38854f9d60c06a
F ext/misc/json1.c 70d49f69ce61e54a83a29e425e704ca3e7e42e6bd9a7cf3c112d0ad995f6560b
F ext/misc/memvfs.c e5225bc22e79dde6b28380f3a068ddf600683a33
F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342
F ext/misc/percentile.c 92699c8cd7d517ff610e6037e56506f8904dae2e
@ -351,7 +351,7 @@ F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
F src/btree.c 24ae5472bd0b53b4130ecdda389deb621af721d1fcb50890b878102b00bd10fa
F src/btree.h bf64dfeeddeebdb775a5eba0098bbc00d073290d
F src/btree.h 80f518c0788be6cec8d9f8e13bd8e380df299d2b5e4ac340dc887b0642647cfc
F src/btreeInt.h a392d353104b4add58b4a59cb185f5d5693dde832c565b77d8d4c343ed98f610
F src/build.c 4026a9c554b233e50c5e9ad46963e676cf54dd2306d952aa1eaa07a1bc9ce14f
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
@ -360,7 +360,7 @@ F src/ctime.c 47d91a25ad8f199a71a5b1b7b169d6dd0d6e98c5719eca801568798743d1161c
F src/date.c ee676e7694dfadbdd2fde1a258a71be8360ba5ae
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c
F src/expr.c 6bce2cbdd822963cf28e782938a96274cc37f18ac28dec7a4e35ccac09f66ce8
F src/expr.c f6572c7690fa619e85b1192b683ccc30cd123363415963c061ada3770b18f6a7
F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007
F src/fkey.c 2e9aabe1aee76273aff8a84ee92c464e095400ae
F src/func.c 9d52522cc8ae7f5cdadfe14594262f1618bc1f86083c4cd6da861b4cf5af6174
@ -407,12 +407,12 @@ F src/printf.c 8757834f1b54dae512fb25eb1acc8e94a0d15dd2290b58f2563f65973265adb2
F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384
F src/resolve.c 3e518b962d932a997fae373366880fc028c75706
F src/rowset.c 7b7e7e479212e65b723bf40128c7b36dc5afdfac
F src/select.c afcf31d8ed7c890328a31d3f350467ccd273af345b24562382b398d6d9cd0664
F src/select.c e6f9afd8a5ef35bd186e51a6bea6d3d46bc93a530f26a21fe8a0a43dbeca9415
F src/shell.c 70f4957b988572315e97c56941fdc81fd35907fee36b7b2e7be5ec4c7e9d065d
F src/sqlite.h.in 8ed51474c7a9edacbf328e2a6ce63de5cde8f50793c6063cb508f9de128e5a4c
F src/sqlite.h.in cf20591fa0eb09e435db647ab28b61159262cbebac69ddad3c8c01accfb6c856
F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
F src/sqlite3ext.h 58fd0676d3111d02e62e5a35992a7d3da5d3f88753acc174f2d37b774fbbdd28
F src/sqliteInt.h 36eec0868d25b50e64a05bc7355557a0aa9bd14330c16b7d7568520b2bf2bb4e
F src/sqliteInt.h 5bcafb7c36f7f8765ed1e7031b7eb5f5e84cfdfe5ea4b3af01178528bde259c8
F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b
F src/status.c a9e66593dfb28a9e746cba7153f84d49c1ddc4b1
F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34
@ -475,12 +475,12 @@ F src/utf.c 699001c79f28e48e9bcdf8a463da029ea660540c
F src/util.c ca8440ede81e155d15cff7c101654f60b55a9ae6
F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569
F src/vdbe.c 808fda3d50f544120d27c731449b524b4ec8f8b0f734b228831078f0ba53ecb9
F src/vdbe.h caa5346d52bae2a3c8c1dcfa60a7a4dc878a9e3865cb8239da55808b316c8158
F src/vdbeInt.h 5db089ce18c4feff8820ec6e4cac2d2c82e03d4b1d96f10a6e43832147b8dffe
F src/vdbe.h f7d1456e28875c2dcb964056589b5b7149ab7edf39edeca801596a39bb3d3848
F src/vdbeInt.h c070bc5c8b913bda0ceaa995cd4d939ded5e4fc96cf7c3c1c602d41b871f8ade
F src/vdbeapi.c 5b08d82592bcff4470601fe78aaabebd50837860
F src/vdbeaux.c 0ecacf8c7ca93e430b30819b8fc9b2c1ffe88202d1437e88c08a1f0b6159c58c
F src/vdbeaux.c 6b3f6ce909e206d4c918988b13b7fa687e92b4471d137e0f2a37edac80ec60be
F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9
F src/vdbemem.c 8bb4dd22837da969bfda25ef3f92d41aaad192328f89a0951290d5e26ad7dbc4
F src/vdbemem.c 3122f5a21064198c10ee1b4686937aab27d5395712d9af905b7fa1affc47a453
F src/vdbesort.c e72fe02a2121386ba767ede8942e9450878b8fc873abf3d1b6824485f092570c
F src/vdbetrace.c 41963d5376f0349842b5fc4aaaaacd7d9cdc0834
F src/vtab.c 007513c2ef52472fcdea6a741683d50662e82790
@ -488,10 +488,10 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9
F src/wal.c 40c543f0a2195d1b0dc88ef12142bea690009344
F src/wal.h 06b2a0b599cc0f53ea97f497cf8c6b758c999f71
F src/walker.c b71a992b413b3a022572eccf29ef4b4890223791
F src/where.c 613b1cac781b2725bb0a841d5c264ae9475380ee3063c3ce9c81814b03a83c20
F src/whereInt.h 2d50c2b74a33be44cb68fdecee30b4d93552f1f4
F src/wherecode.c 677e95413c472c0b413023b6b69a47f40fce1b04
F src/whereexpr.c 130cdd1a43af71b19755270fb1224874cf55158c
F src/where.c f5acfb6fbac65e7da7b0e718fa6c6e784dee37eb29dad6efd42880ca117e7277
F src/whereInt.h 7a21ef633e26acbf46df04add2eba6e0a2100c78dc5879049e93f981fc3344df
F src/wherecode.c 943e32e9dccd0af802e0683ae11071c8bd808364e5908a5fb66758bd404c8681
F src/whereexpr.c e913aaa7b73ffcce66abcea5f197e2c538d48b5df78d0b7bba8ff4d73cc2e745
F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2
F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd
F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d
@ -884,6 +884,7 @@ F test/index7.test 7feababe16f2091b229c22aff2bcc1d4d6b9d2bb
F test/index8.test bc2e3db70e8e62459aaa1bd7e4a9b39664f8f9d7
F test/indexedby.test 9c4cd331224e57f79fbf411ae245e6272d415985
F test/indexexpr1.test 038b3befa74e5a75126b6e9dd2ae5df61c1c7cf7
F test/indexexpr2.test bcf694ae72efaaeb97691b990b61e39bf233884e27b9cc6b845a1f0c6bc9f0bb
F test/indexfault.test 31d4ab9a7d2f6e9616933eb079722362a883eb1d
F test/init.test 15c823093fdabbf7b531fe22cf037134d09587a7
F test/insert.test 38742b5e9601c8f8d76e9b7555f7270288c2d371
@ -917,7 +918,7 @@ F test/jrnlmode.test 7864d59cf7f6e552b9b99ba0f38acd167edc10fa
F test/jrnlmode2.test 81610545a4e6ed239ea8fa661891893385e23a1d
F test/jrnlmode3.test 556b447a05be0e0963f4311e95ab1632b11c9eaa
F test/json101.test c0897616f32d95431f37fd291cb78742181980ac
F test/json102.test de1728e8ffde4a57cbc77b6815a60ccb82a6c759967be44e71952757e7d7947b
F test/json102.test eeb54efa221e50b74a2d6fb9259963b48d7414dca3ce2fdfdeed45cb28487bc1
F test/json103.test c5f6b85e69de05f6b3195f9f9d5ce9cd179099a0
F test/json104.test 877d5845f6303899b7889ea5dd1bea99076e3100574d5c536082245c5805dcaa
F test/keyword1.test 37ef6bba5d2ed5b07ecdd6810571de2956599dff
@ -1577,7 +1578,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
P 0c45c5eb9f0f171b8d7c5f0d2973f9f59915467506cdff1450f3e4b2134a01ca
R 33f15deae23049b95df8ad5185895aff
P cc8c3581060ffef02290b680183e6f6bc9837ba3550e74c8aaabdc7c45edc223 76cd611d41465fcec61c21520d55172cb236530f38386b7d4a5544ba87de2353
R 598dc6bf3b8d38f8068b443f6c7f3624
U dan
Z 2806083003fa51636f951574e2a01b7d
Z 7c38a019370c850a76053a951a01d320

View File

@ -1 +1 @@
cc8c3581060ffef02290b680183e6f6bc9837ba3550e74c8aaabdc7c45edc223
0f66a093935100efd731e14aa63b57360ddd517c1ac97edd1ea9a9de95e1f3cc

View File

@ -276,7 +276,7 @@ struct BtreePayload {
const void *pKey; /* Key content for indexes. NULL for tables */
sqlite3_int64 nKey; /* Size of pKey for indexes. PRIMARY KEY for tabs */
const void *pData; /* Data for tables. NULL for indexes */
struct Mem *aMem; /* First of nMem value in the unpacked pKey */
sqlite3_value *aMem; /* First of nMem value in the unpacked pKey */
u16 nMem; /* Number of aMem[] value. Might be zero */
int nData; /* Size of pData. 0 if none. */
int nZero; /* Extra zero data appended after pData,nData */

View File

@ -58,7 +58,7 @@ char sqlite3ExprAffinity(Expr *pExpr){
return sqlite3AffinityType(pExpr->u.zToken, 0);
}
#endif
if( op==TK_AGG_COLUMN || op==TK_COLUMN ){
if( (op==TK_AGG_COLUMN || op==TK_COLUMN) && pExpr->pTab ){
return sqlite3TableColumnAffinity(pExpr->pTab, pExpr->iColumn);
}
if( op==TK_SELECT_COLUMN ){
@ -3192,6 +3192,10 @@ void sqlite3ExprCodeGetColumnOfTable(
int iCol, /* Index of the column to extract */
int regOut /* Extract the value into this register */
){
if( pTab==0 ){
sqlite3VdbeAddOp3(v, OP_Column, iTabCur, iCol, regOut);
return;
}
if( iCol<0 || iCol==pTab->iPKey ){
sqlite3VdbeAddOp2(v, OP_Rowid, iTabCur, regOut);
}else{

View File

@ -112,14 +112,13 @@ Select *sqlite3SelectNew(
){
Select *pNew;
Select standin;
sqlite3 *db = pParse->db;
pNew = sqlite3DbMallocRawNN(db, sizeof(*pNew) );
pNew = sqlite3DbMallocRawNN(pParse->db, sizeof(*pNew) );
if( pNew==0 ){
assert( db->mallocFailed );
assert( pParse->db->mallocFailed );
pNew = &standin;
}
if( pEList==0 ){
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(db,TK_ASTERISK,0));
pEList = sqlite3ExprListAppend(pParse, 0, sqlite3Expr(pParse->db,TK_ASTERISK,0));
}
pNew->pEList = pEList;
pNew->op = TK_SELECT;
@ -132,7 +131,7 @@ Select *sqlite3SelectNew(
pNew->addrOpenEphm[0] = -1;
pNew->addrOpenEphm[1] = -1;
pNew->nSelectRow = 0;
if( pSrc==0 ) pSrc = sqlite3DbMallocZero(db, sizeof(*pSrc));
if( pSrc==0 ) pSrc = sqlite3DbMallocZero(pParse->db, sizeof(*pSrc));
pNew->pSrc = pSrc;
pNew->pWhere = pWhere;
pNew->pGroupBy = pGroupBy;
@ -143,9 +142,9 @@ Select *sqlite3SelectNew(
pNew->pLimit = pLimit;
pNew->pOffset = pOffset;
pNew->pWith = 0;
assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || db->mallocFailed!=0 );
if( db->mallocFailed ) {
clearSelect(db, pNew, pNew!=&standin);
assert( pOffset==0 || pLimit!=0 || pParse->nErr>0 || pParse->db->mallocFailed!=0 );
if( pParse->db->mallocFailed ) {
clearSelect(pParse->db, pNew, pNew!=&standin);
pNew = 0;
}else{
assert( pNew->pSrc!=0 || pParse->nErr>0 );
@ -1530,6 +1529,7 @@ static void generateColumnTypes(
NameContext sNC;
sNC.pSrcList = pTabList;
sNC.pParse = pParse;
sNC.pNext = 0;
for(i=0; i<pEList->nExpr; i++){
Expr *p = pEList->a[i].pExpr;
const char *zType;
@ -1554,6 +1554,19 @@ static void generateColumnTypes(
#endif /* !defined(SQLITE_OMIT_DECLTYPE) */
}
/*
** Return the Table objecct in the SrcList that has cursor iCursor.
** Or return NULL if no such Table object exists in the SrcList.
*/
static Table *tableWithCursor(SrcList *pList, int iCursor){
int j;
for(j=0; j<pList->nSrc; j++){
if( pList->a[j].iCursor==iCursor ) return pList->a[j].pTab;
}
return 0;
}
/*
** Generate code that will tell the VDBE the names of columns
** in the result set. This information is used to provide the
@ -1565,7 +1578,8 @@ static void generateColumnNames(
ExprList *pEList /* Expressions defining the result set */
){
Vdbe *v = pParse->pVdbe;
int i, j;
int i;
Table *pTab;
sqlite3 *db = pParse->db;
int fullNames, shortNames;
@ -1590,15 +1604,11 @@ static void generateColumnNames(
if( pEList->a[i].zName ){
char *zName = pEList->a[i].zName;
sqlite3VdbeSetColName(v, i, COLNAME_NAME, zName, SQLITE_TRANSIENT);
}else if( p->op==TK_COLUMN || p->op==TK_AGG_COLUMN ){
Table *pTab;
}else if( (p->op==TK_COLUMN || p->op==TK_AGG_COLUMN)
&& (pTab = tableWithCursor(pTabList, p->iTable))!=0
){
char *zCol;
int iCol = p->iColumn;
for(j=0; ALWAYS(j<pTabList->nSrc); j++){
if( pTabList->a[j].iCursor==p->iTable ) break;
}
assert( j<pTabList->nSrc );
pTab = pTabList->a[j].pTab;
if( iCol<0 ) iCol = pTab->iPKey;
assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) );
if( iCol<0 ){
@ -3147,7 +3157,7 @@ static void substSelect(Parse*, Select *, int, ExprList*, int);
** This routine is part of the flattening procedure. A subquery
** whose result set is defined by pEList appears as entry in the
** FROM clause of a SELECT such that the VDBE cursor assigned to that
** FORM clause entry is iTable. This routine make the necessary
** FORM clause entry is iTable. This routine makes the necessary
** changes to pExpr so that it refers directly to the source table
** of the subquery rather the result set of the subquery.
*/

View File

@ -3701,7 +3701,7 @@ int sqlite3_stmt_busy(sqlite3_stmt*);
** The [sqlite3_value_blob | sqlite3_value_type()] family of
** interfaces require protected sqlite3_value objects.
*/
typedef struct Mem sqlite3_value;
typedef struct sqlite3_value sqlite3_value;
/*
** CAPI3REF: SQL Function Context Object

View File

@ -3328,6 +3328,7 @@ struct Walker {
struct CCurHint *pCCurHint; /* Used by codeCursorHint() */
int *aiCol; /* array of column indexes */
struct IdxCover *pIdxCover; /* Check for index coverage */
struct IdxExprTrans *pIdxTrans; /* Convert indexed expr to column */
} u;
};

View File

@ -30,7 +30,7 @@ typedef struct Vdbe Vdbe;
** The names of the following types declared in vdbeInt.h are required
** for the VdbeOp definition.
*/
typedef struct Mem Mem;
typedef struct sqlite3_value Mem;
typedef struct SubProgram SubProgram;
/*

View File

@ -185,7 +185,7 @@ struct VdbeFrame {
** structures. Each Mem struct may cache multiple representations (string,
** integer etc.) of the same value.
*/
struct Mem {
struct sqlite3_value {
union MemValue {
double r; /* Real value used when MEM_Real is set in flags */
i64 i; /* Integer value used when MEM_Int is set in flags */

View File

@ -879,7 +879,7 @@ static void freeP4(sqlite3 *db, int p4type, void *p4){
static void vdbeFreeOpArray(sqlite3 *db, Op *aOp, int nOp){
if( aOp ){
Op *pOp;
for(pOp=aOp; pOp<&aOp[nOp]; pOp++){
for(pOp=&aOp[nOp-1]; pOp>=aOp; pOp--){
if( pOp->p4type ) freeP4(db, pOp->p4type, pOp->p4.p);
#ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
sqlite3DbFree(db, pOp->zComment);

View File

@ -125,26 +125,24 @@ SQLITE_NOINLINE int sqlite3VdbeMemGrow(Mem *pMem, int n, int bPreserve){
assert( pMem->szMalloc==0
|| pMem->szMalloc==sqlite3DbMallocSize(pMem->db, pMem->zMalloc) );
if( pMem->szMalloc<n ){
if( n<32 ) n = 32;
if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
bPreserve = 0;
}else{
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
}
if( pMem->zMalloc==0 ){
sqlite3VdbeMemSetNull(pMem);
pMem->z = 0;
pMem->szMalloc = 0;
return SQLITE_NOMEM_BKPT;
}else{
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
}
if( n<32 ) n = 32;
if( bPreserve && pMem->szMalloc>0 && pMem->z==pMem->zMalloc ){
pMem->z = pMem->zMalloc = sqlite3DbReallocOrFree(pMem->db, pMem->z, n);
bPreserve = 0;
}else{
if( pMem->szMalloc>0 ) sqlite3DbFreeNN(pMem->db, pMem->zMalloc);
pMem->zMalloc = sqlite3DbMallocRaw(pMem->db, n);
}
if( pMem->zMalloc==0 ){
sqlite3VdbeMemSetNull(pMem);
pMem->z = 0;
pMem->szMalloc = 0;
return SQLITE_NOMEM_BKPT;
}else{
pMem->szMalloc = sqlite3DbMallocSize(pMem->db, pMem->zMalloc);
}
if( bPreserve && pMem->z && pMem->z!=pMem->zMalloc ){
if( bPreserve && pMem->z && ALWAYS(pMem->z!=pMem->zMalloc) ){
memcpy(pMem->zMalloc, pMem->z, pMem->n);
}
if( (pMem->flags&MEM_Dyn)!=0 ){

View File

@ -4642,6 +4642,7 @@ WhereInfo *sqlite3WhereBegin(
pWInfo->pParse = pParse;
pWInfo->pTabList = pTabList;
pWInfo->pOrderBy = pOrderBy;
pWInfo->pWhere = pWhere;
pWInfo->pResultSet = pResultSet;
pWInfo->aiCurOnePass[0] = pWInfo->aiCurOnePass[1] = -1;
pWInfo->nLevel = nTabList;

View File

@ -417,6 +417,7 @@ struct WhereInfo {
SrcList *pTabList; /* List of tables in the join */
ExprList *pOrderBy; /* The ORDER BY clause or NULL */
ExprList *pResultSet; /* Result set of the query */
Expr *pWhere; /* The complete WHERE clause */
LogEst iLimit; /* LIMIT if wctrlFlags has WHERE_USE_LIMIT */
int aiCurOnePass[2]; /* OP_OpenWrite cursors for the ONEPASS opt */
int iContinue; /* Jump here to continue with next record */

View File

@ -1039,6 +1039,69 @@ static void codeExprOrVector(Parse *pParse, Expr *p, int iReg, int nReg){
}
}
/* An instance of the IdxExprTrans object carries information about a
** mapping from an expression on table columns into a column in an index
** down through the Walker.
*/
typedef struct IdxExprTrans {
Expr *pIdxExpr; /* The index expression */
int iTabCur; /* The cursor of the corresponding table */
int iIdxCur; /* The cursor for the index */
int iIdxCol; /* The column for the index */
} IdxExprTrans;
/* The walker node callback used to transform matching expressions into
** a reference to an index column for an index on an expression.
**
** If pExpr matches, then transform it into a reference to the index column
** that contains the value of pExpr.
*/
static int whereIndexExprTransNode(Walker *p, Expr *pExpr){
IdxExprTrans *pX = p->u.pIdxTrans;
if( sqlite3ExprCompare(pExpr, pX->pIdxExpr, pX->iTabCur)==0 ){
pExpr->op = TK_COLUMN;
pExpr->iTable = pX->iIdxCur;
pExpr->iColumn = pX->iIdxCol;
pExpr->pTab = 0;
return WRC_Prune;
}else{
return WRC_Continue;
}
}
/*
** For an indexes on expression X, locate every instance of expression X in pExpr
** and change that subexpression into a reference to the appropriate column of
** the index.
*/
static void whereIndexExprTrans(
Index *pIdx, /* The Index */
int iTabCur, /* Cursor of the table that is being indexed */
int iIdxCur, /* Cursor of the index itself */
WhereInfo *pWInfo /* Transform expressions in this WHERE clause */
){
int iIdxCol; /* Column number of the index */
ExprList *aColExpr; /* Expressions that are indexed */
Walker w;
IdxExprTrans x;
aColExpr = pIdx->aColExpr;
if( aColExpr==0 ) return; /* Not an index on expressions */
memset(&w, 0, sizeof(w));
w.xExprCallback = whereIndexExprTransNode;
w.u.pIdxTrans = &x;
x.iTabCur = iTabCur;
x.iIdxCur = iIdxCur;
for(iIdxCol=0; iIdxCol<aColExpr->nExpr; iIdxCol++){
if( pIdx->aiColumn[iIdxCol]!=XN_EXPR ) continue;
assert( aColExpr->a[iIdxCol].pExpr!=0 );
x.iIdxCol = iIdxCol;
x.pIdxExpr = aColExpr->a[iIdxCol].pExpr;
sqlite3WalkExpr(&w, pWInfo->pWhere);
sqlite3WalkExprList(&w, pWInfo->pOrderBy);
sqlite3WalkExprList(&w, pWInfo->pResultSet);
}
}
/*
** Generate code for the start of the iLevel-th loop in the WHERE clause
** implementation described by pWInfo.
@ -1620,6 +1683,13 @@ Bitmask sqlite3WhereCodeOneLoopStart(
iRowidReg, pPk->nKeyCol); VdbeCoverage(v);
}
/* If pIdx is an index on one or more expressions, then look through
** all the expressions in pWInfo and try to transform matching expressions
** into reference to index columns.
*/
whereIndexExprTrans(pIdx, iCur, iIdxCur, pWInfo);
/* Record the instruction used to terminate the loop. */
if( pLoop->wsFlags & WHERE_ONEROW ){
pLevel->op = OP_Noop;

View File

@ -830,8 +830,8 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
** Expression pExpr is one operand of a comparison operator that might
** be useful for indexing. This routine checks to see if pExpr appears
** in any index. Return TRUE (1) if pExpr is an indexed term and return
** FALSE (0) if not. If TRUE is returned, also set *piCur to the cursor
** number of the table that is indexed and *piColumn to the column number
** FALSE (0) if not. If TRUE is returned, also set aiCurCol[0] to the cursor
** number of the table that is indexed and aiCurCol[1] to the column number
** of the column that is indexed, or XN_EXPR (-2) if an expression is being
** indexed.
**
@ -839,18 +839,37 @@ static Bitmask exprSelectUsage(WhereMaskSet *pMaskSet, Select *pS){
** true even if that particular column is not indexed, because the column
** might be added to an automatic index later.
*/
static int exprMightBeIndexed(
static SQLITE_NOINLINE int exprMightBeIndexed2(
SrcList *pFrom, /* The FROM clause */
int op, /* The specific comparison operator */
Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
Expr *pExpr, /* An operand of a comparison operator */
int *piCur, /* Write the referenced table cursor number here */
int *piColumn /* Write the referenced table column number here */
int *aiCurCol, /* Write the referenced table cursor and column here */
Expr *pExpr /* An operand of a comparison operator */
){
Index *pIdx;
int i;
int iCur;
for(i=0; mPrereq>1; i++, mPrereq>>=1){}
iCur = pFrom->a[i].iCursor;
for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->aColExpr==0 ) continue;
for(i=0; i<pIdx->nKeyCol; i++){
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
aiCurCol[0] = iCur;
aiCurCol[1] = XN_EXPR;
return 1;
}
}
}
return 0;
}
static int exprMightBeIndexed(
SrcList *pFrom, /* The FROM clause */
Bitmask mPrereq, /* Bitmask of FROM clause terms referenced by pExpr */
int *aiCurCol, /* Write the referenced table cursor & column here */
Expr *pExpr, /* An operand of a comparison operator */
int op /* The specific comparison operator */
){
/* If this expression is a vector to the left or right of a
** inequality constraint (>, <, >= or <=), perform the processing
** on the first element of the vector. */
@ -862,26 +881,13 @@ static int exprMightBeIndexed(
}
if( pExpr->op==TK_COLUMN ){
*piCur = pExpr->iTable;
*piColumn = pExpr->iColumn;
aiCurCol[0] = pExpr->iTable;
aiCurCol[1] = pExpr->iColumn;
return 1;
}
if( mPrereq==0 ) return 0; /* No table references */
if( (mPrereq&(mPrereq-1))!=0 ) return 0; /* Refs more than one table */
for(i=0; mPrereq>1; i++, mPrereq>>=1){}
iCur = pFrom->a[i].iCursor;
for(pIdx=pFrom->a[i].pTab->pIndex; pIdx; pIdx=pIdx->pNext){
if( pIdx->aColExpr==0 ) continue;
for(i=0; i<pIdx->nKeyCol; i++){
if( pIdx->aiColumn[i]!=XN_EXPR ) continue;
if( sqlite3ExprCompareSkip(pExpr, pIdx->aColExpr->a[i].pExpr, iCur)==0 ){
*piCur = iCur;
*piColumn = XN_EXPR;
return 1;
}
}
}
return 0;
return exprMightBeIndexed2(pFrom,mPrereq,aiCurCol,pExpr);
}
/*
@ -961,7 +967,7 @@ static void exprAnalyze(
pTerm->iParent = -1;
pTerm->eOperator = 0;
if( allowedOp(op) ){
int iCur, iColumn;
int aiCurCol[2];
Expr *pLeft = sqlite3ExprSkipCollate(pExpr->pLeft);
Expr *pRight = sqlite3ExprSkipCollate(pExpr->pRight);
u16 opMask = (pTerm->prereqRight & prereqLeft)==0 ? WO_ALL : WO_EQUIV;
@ -972,14 +978,14 @@ static void exprAnalyze(
pLeft = pLeft->x.pList->a[pTerm->iField-1].pExpr;
}
if( exprMightBeIndexed(pSrc, op, prereqLeft, pLeft, &iCur, &iColumn) ){
pTerm->leftCursor = iCur;
pTerm->u.leftColumn = iColumn;
if( exprMightBeIndexed(pSrc, prereqLeft, aiCurCol, pLeft, op) ){
pTerm->leftCursor = aiCurCol[0];
pTerm->u.leftColumn = aiCurCol[1];
pTerm->eOperator = operatorMask(op) & opMask;
}
if( op==TK_IS ) pTerm->wtFlags |= TERM_IS;
if( pRight
&& exprMightBeIndexed(pSrc, op, pTerm->prereqRight, pRight, &iCur,&iColumn)
&& exprMightBeIndexed(pSrc, pTerm->prereqRight, aiCurCol, pRight, op)
){
WhereTerm *pNew;
Expr *pDup;
@ -1009,8 +1015,8 @@ static void exprAnalyze(
pNew = pTerm;
}
exprCommute(pParse, pDup);
pNew->leftCursor = iCur;
pNew->u.leftColumn = iColumn;
pNew->leftCursor = aiCurCol[0];
pNew->u.leftColumn = aiCurCol[1];
testcase( (prereqLeft | extraRight) != prereqLeft );
pNew->prereqRight = prereqLeft | extraRight;
pNew->prereqAll = prereqAll;

36
test/indexexpr2.test Normal file
View File

@ -0,0 +1,36 @@
# 2017 April 11
#
# The author disclaims copyright to this source code. In place of
# a legal notice, here is a blessing:
#
# May you do good and not evil.
# May you find forgiveness for yourself and forgive others.
# May you share freely, never taking more than you give.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix indexexpr2
do_execsql_test 1 {
CREATE TABLE t1(a, b);
INSERT INTO t1 VALUES(1, 'one');
INSERT INTO t1 VALUES(2, 'two');
INSERT INTO t1 VALUES(3, 'three');
CREATE INDEX i1 ON t1(b || 'x');
}
do_execsql_test 1.1 {
SELECT 'TWOX' == (b || 'x') FROM t1 WHERE (b || 'x')>'onex'
} {0 0}
do_execsql_test 1.2 {
SELECT 'TWOX' == (b || 'x') COLLATE nocase FROM t1 WHERE (b || 'x')>'onex'
} {0 1}
finish_test

View File

@ -319,4 +319,22 @@ do_execsql_test json102-1410 { SELECT json_valid('{"x":-01.5}') } 0
do_execsql_test json102-1411 { SELECT json_valid('{"x":00}') } 0
do_execsql_test json102-1412 { SELECT json_valid('{"x":-00}') } 0
#------------------------------------------------------------------------
# 2017-04-10 ticket 6c9b5514077fed34551f98e64c09a10dc2fc8e16
# JSON extension accepts strings containing control characters.
#
# The JSON spec requires that all control characters be escaped.
#
do_execsql_test json102-1500 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<0x20)
SELECT x FROM c WHERE json_valid(printf('{"a":"x%sz"}', char(x))) ORDER BY x;
} {32}
# All control characters are escaped
#
do_execsql_test json102-1501 {
WITH RECURSIVE c(x) AS (VALUES(1) UNION ALL SELECT x+1 FROM c WHERE x<0x1f)
SELECT sum(json_valid(json_quote('a'||char(x)||'z'))) FROM c ORDER BY x;
} {31}
finish_test