mirror of https://github.com/sqlite/sqlite
Modifications towards better vector IN(...) support on this branch. Not activated yet.
FossilOrigin-Name: 34e35c71b25b0aa2d8931040feb260a78cc48c49
This commit is contained in:
parent
709947a315
commit
cfbb5e82db
14
manifest
14
manifest
|
@ -1,5 +1,5 @@
|
||||||
C Merge\scomment\stypo\sfixes\sfrom\strunk.
|
C Modifications\stowards\sbetter\svector\sIN(...)\ssupport\son\sthis\sbranch.\sNot\sactivated\syet.
|
||||||
D 2016-07-10T19:35:45.597
|
D 2016-07-13T19:48:13.115
|
||||||
F Makefile.in 6c20d44f72d4564f11652b26291a214c8367e5db
|
F Makefile.in 6c20d44f72d4564f11652b26291a214c8367e5db
|
||||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||||
F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
|
F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
|
||||||
|
@ -337,7 +337,7 @@ F src/ctime.c 61949e83c4c36e37195a8398ebc752780b534d95
|
||||||
F src/date.c 1cc9fb516ec9932c6fd4d2a0d2f8bc4480145c39
|
F src/date.c 1cc9fb516ec9932c6fd4d2a0d2f8bc4480145c39
|
||||||
F src/dbstat.c 4f6f7f52b49beb9636ffbd517cfe44a402ba4ad0
|
F src/dbstat.c 4f6f7f52b49beb9636ffbd517cfe44a402ba4ad0
|
||||||
F src/delete.c 4aba4214a377ce8ddde2d2e609777bcc8235200f
|
F src/delete.c 4aba4214a377ce8ddde2d2e609777bcc8235200f
|
||||||
F src/expr.c 330854fe9fdea1d244abaef6d680f6b91df07cb4
|
F src/expr.c 939362d26f5e99a4802ae94ae6e47d4def72b8f3
|
||||||
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
|
||||||
F src/fkey.c bc4145347595b7770f9a598cff1c848302cf5413
|
F src/fkey.c bc4145347595b7770f9a598cff1c848302cf5413
|
||||||
F src/func.c 61a4114cf7004f10c542cfabbab9f2bcb9033045
|
F src/func.c 61a4114cf7004f10c542cfabbab9f2bcb9033045
|
||||||
|
@ -1507,7 +1507,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P b2204215b231202aef7a218411cc2ddaecf28f35 77c692a6704cd877ba35d0afb774ab9b46364d59
|
P 728c5aa436a5f55c86b019c415a2b71d1b0a8fd6
|
||||||
R 1a7620cc6269220b48a9fcbcbb9b68d1
|
R 6c0b20cb1573f5c43e78ae5a07a06597
|
||||||
U mistachkin
|
U dan
|
||||||
Z cf1dd7dc395b0586dda9fa40ccf71a27
|
Z 35590bc4128842477cd3208768d4edc0
|
||||||
|
|
|
@ -1 +1 @@
|
||||||
728c5aa436a5f55c86b019c415a2b71d1b0a8fd6
|
34e35c71b25b0aa2d8931040feb260a78cc48c49
|
101
src/expr.c
101
src/expr.c
|
@ -309,6 +309,12 @@ static int codeCompare(
|
||||||
return addr;
|
return addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
** If the expression passed as the only argument is of type TK_VECTOR
|
||||||
|
** return the number of expressions in the vector. Or, if the expression
|
||||||
|
** is a sub-select, return the number of columns in the sub-select. For
|
||||||
|
** any other type of expression, return 1.
|
||||||
|
*/
|
||||||
int sqlite3ExprVectorSize(Expr *pExpr){
|
int sqlite3ExprVectorSize(Expr *pExpr){
|
||||||
if( (pExpr->flags & EP_Vector)==0 ) return 1;
|
if( (pExpr->flags & EP_Vector)==0 ) return 1;
|
||||||
if( pExpr->flags & EP_xIsSelect ){
|
if( pExpr->flags & EP_xIsSelect ){
|
||||||
|
@ -318,7 +324,10 @@ int sqlite3ExprVectorSize(Expr *pExpr){
|
||||||
}
|
}
|
||||||
|
|
||||||
static Expr *exprVectorField(Expr *pVector, int i){
|
static Expr *exprVectorField(Expr *pVector, int i){
|
||||||
if( pVector->flags & EP_xIsSelect ){
|
if( (pVector->flags & EP_Vector)==0 ){
|
||||||
|
assert( i==0 );
|
||||||
|
return pVector;
|
||||||
|
}else if( pVector->flags & EP_xIsSelect ){
|
||||||
return pVector->x.pSelect->pEList->a[i].pExpr;
|
return pVector->x.pSelect->pEList->a[i].pExpr;
|
||||||
}
|
}
|
||||||
return pVector->x.pList->a[i].pExpr;
|
return pVector->x.pList->a[i].pExpr;
|
||||||
|
@ -1703,12 +1712,12 @@ int sqlite3IsRowid(const char *z){
|
||||||
** table, then return NULL.
|
** table, then return NULL.
|
||||||
*/
|
*/
|
||||||
#ifndef SQLITE_OMIT_SUBQUERY
|
#ifndef SQLITE_OMIT_SUBQUERY
|
||||||
static Select *isCandidateForInOpt(Expr *pX){
|
static Select *isCandidateForInOpt(Expr *pX, int bNullSensitive){
|
||||||
Select *p;
|
Select *p;
|
||||||
SrcList *pSrc;
|
SrcList *pSrc;
|
||||||
ExprList *pEList;
|
ExprList *pEList;
|
||||||
Expr *pRes;
|
|
||||||
Table *pTab;
|
Table *pTab;
|
||||||
|
int i;
|
||||||
if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */
|
if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0; /* Not a subquery */
|
||||||
if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */
|
if( ExprHasProperty(pX, EP_VarSelect) ) return 0; /* Correlated subq */
|
||||||
p = pX->x.pSelect;
|
p = pX->x.pSelect;
|
||||||
|
@ -1731,10 +1740,18 @@ static Select *isCandidateForInOpt(Expr *pX){
|
||||||
assert( pTab->pSelect==0 ); /* FROM clause is not a view */
|
assert( pTab->pSelect==0 ); /* FROM clause is not a view */
|
||||||
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
|
if( IsVirtual(pTab) ) return 0; /* FROM clause not a virtual table */
|
||||||
pEList = p->pEList;
|
pEList = p->pEList;
|
||||||
if( pEList->nExpr!=1 ) return 0; /* One column in the result set */
|
|
||||||
pRes = pEList->a[0].pExpr;
|
/* All SELECT results must be columns. If the SELECT returns more than
|
||||||
if( pRes->op!=TK_COLUMN ) return 0; /* Result is a column */
|
** one column and the bNullSensitive flag is set, all returned columns
|
||||||
|
** must be declared NOT NULL. */
|
||||||
|
for(i=0; i<pEList->nExpr; i++){
|
||||||
|
Expr *pRes = pEList->a[i].pExpr;
|
||||||
|
if( pRes->op!=TK_COLUMN ) return 0;
|
||||||
assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */
|
assert( pRes->iTable==pSrc->a[0].iCursor ); /* Not a correlated subquery */
|
||||||
|
if( pEList->nExpr>1 && bNullSensitive ){
|
||||||
|
if( pTab->aCol[pRes->iColumn].notNull==0 ) return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
#endif /* SQLITE_OMIT_SUBQUERY */
|
#endif /* SQLITE_OMIT_SUBQUERY */
|
||||||
|
@ -1867,19 +1884,17 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||||
** satisfy the query. This is preferable to generating a new
|
** satisfy the query. This is preferable to generating a new
|
||||||
** ephemeral table.
|
** ephemeral table.
|
||||||
*/
|
*/
|
||||||
if( pParse->nErr==0 && (p = isCandidateForInOpt(pX))!=0 ){
|
if( pParse->nErr==0 && (p = isCandidateForInOpt(pX, prRhsHasNull!=0))!=0 ){
|
||||||
sqlite3 *db = pParse->db; /* Database connection */
|
sqlite3 *db = pParse->db; /* Database connection */
|
||||||
Table *pTab; /* Table <table>. */
|
Table *pTab; /* Table <table>. */
|
||||||
Expr *pExpr; /* Expression <column> */
|
ExprList *pEList = p->pEList;
|
||||||
i16 iCol; /* Index of column <column> */
|
int nExpr = pEList->nExpr;
|
||||||
i16 iDb; /* Database idx for pTab */
|
i16 iDb; /* Database idx for pTab */
|
||||||
|
|
||||||
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
|
assert( p->pEList!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||||
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
|
assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||||
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
|
assert( p->pSrc!=0 ); /* Because of isCandidateForInOpt(p) */
|
||||||
pTab = p->pSrc->a[0].pTab;
|
pTab = p->pSrc->a[0].pTab;
|
||||||
pExpr = p->pEList->a[0].pExpr;
|
|
||||||
iCol = (i16)pExpr->iColumn;
|
|
||||||
|
|
||||||
/* Code an OP_Transaction and OP_TableLock for <table>. */
|
/* Code an OP_Transaction and OP_TableLock for <table>. */
|
||||||
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
|
||||||
|
@ -1891,7 +1906,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||||
** successful here.
|
** successful here.
|
||||||
*/
|
*/
|
||||||
assert(v);
|
assert(v);
|
||||||
if( iCol<0 ){
|
if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){
|
||||||
int iAddr = sqlite3CodeOnce(pParse);
|
int iAddr = sqlite3CodeOnce(pParse);
|
||||||
VdbeCoverage(v);
|
VdbeCoverage(v);
|
||||||
|
|
||||||
|
@ -1901,23 +1916,54 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||||
sqlite3VdbeJumpHere(v, iAddr);
|
sqlite3VdbeJumpHere(v, iAddr);
|
||||||
}else{
|
}else{
|
||||||
Index *pIdx; /* Iterator variable */
|
Index *pIdx; /* Iterator variable */
|
||||||
|
int affinity_ok = 1;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Check that the affinity that will be used to perform each
|
||||||
|
** comparison is the same as the affinity of each column. If
|
||||||
|
** it not, it is not possible to use any index. */
|
||||||
|
for(i=0; i<nExpr && affinity_ok; i++){
|
||||||
|
Expr *pLhs = exprVectorField(pX->pLeft, i);
|
||||||
|
int iCol = pEList->a[i].pExpr->iColumn;
|
||||||
|
char idxaff = pTab->aCol[iCol].affinity;
|
||||||
|
char cmpaff = sqlite3CompareAffinity(pLhs, idxaff);
|
||||||
|
switch( cmpaff ){
|
||||||
|
case SQLITE_AFF_BLOB:
|
||||||
|
break;
|
||||||
|
case SQLITE_AFF_TEXT:
|
||||||
|
affinity_ok = (idxaff==SQLITE_AFF_TEXT);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
affinity_ok = sqlite3IsNumericAffinity(idxaff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* The collation sequence used by the comparison. If an index is to
|
/* The collation sequence used by the comparison. If an index is to
|
||||||
** be used in place of a temp-table, it must be ordered according
|
** be used in place of a temp-table, it must be ordered according
|
||||||
** to this collation sequence. */
|
** to this collation sequence. */
|
||||||
CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pX->pLeft, pExpr);
|
|
||||||
|
|
||||||
/* Check that the affinity that will be used to perform the
|
|
||||||
** comparison is the same as the affinity of the column. If
|
|
||||||
** it is not, it is not possible to use any index.
|
|
||||||
*/
|
|
||||||
int affinity_ok = sqlite3IndexAffinityOk(pX, pTab->aCol[iCol].affinity);
|
|
||||||
|
|
||||||
for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
|
for(pIdx=pTab->pIndex; pIdx && eType==0 && affinity_ok; pIdx=pIdx->pNext){
|
||||||
if( (pIdx->aiColumn[0]==iCol)
|
if( pIdx->nKeyCol<nExpr ) continue;
|
||||||
&& sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
|
if( mustBeUnique && (pIdx->nKeyCol!=nExpr || !IsUniqueIndex(pIdx)) ){
|
||||||
&& (!mustBeUnique || (pIdx->nKeyCol==1 && IsUniqueIndex(pIdx)))
|
continue;
|
||||||
){
|
}
|
||||||
|
|
||||||
|
for(i=0; i<nExpr; i++){
|
||||||
|
Expr *pLhs = exprVectorField(pX->pLeft, i);
|
||||||
|
Expr *pRhs = pEList->a[i].pExpr;
|
||||||
|
CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs);
|
||||||
|
int j;
|
||||||
|
|
||||||
|
for(j=0; j<nExpr; j++){
|
||||||
|
if( pIdx->aiColumn[j]!=pRhs->iColumn ) continue;
|
||||||
|
assert( pIdx->azColl[j] );
|
||||||
|
if( sqlite3StrICmp(pReq->zName, pIdx->azColl[j])!=0 ) continue;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if( j==nExpr ) break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if( i==nExpr ){
|
||||||
int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
int iAddr = sqlite3CodeOnce(pParse); VdbeCoverage(v);
|
||||||
sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
|
sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
|
||||||
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
sqlite3VdbeSetP4KeyInfo(pParse, pIdx);
|
||||||
|
@ -1925,11 +1971,13 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||||
assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
|
assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 );
|
||||||
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
|
eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0];
|
||||||
|
|
||||||
if( prRhsHasNull && !pTab->aCol[iCol].notNull ){
|
if( prRhsHasNull && nExpr==1
|
||||||
|
&& !pTab->aCol[pEList->a[0].pExpr->iColumn].notNull
|
||||||
|
){
|
||||||
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
#ifdef SQLITE_ENABLE_COLUMN_USED_MASK
|
||||||
const i64 sOne = 1;
|
i64 mask = (1<<nExpr)-1;
|
||||||
sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed,
|
sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed,
|
||||||
iTab, 0, 0, (u8*)&sOne, P4_INT64);
|
iTab, 0, 0, (u8*)&mask, P4_INT64);
|
||||||
#endif
|
#endif
|
||||||
*prRhsHasNull = ++pParse->nMem;
|
*prRhsHasNull = ++pParse->nMem;
|
||||||
sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
|
sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
|
||||||
|
@ -1955,7 +2003,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
|
||||||
eType = IN_INDEX_NOOP;
|
eType = IN_INDEX_NOOP;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if( eType==0 ){
|
if( eType==0 ){
|
||||||
/* Could not find an existing table or index to use as the RHS b-tree.
|
/* Could not find an existing table or index to use as the RHS b-tree.
|
||||||
** We will have to generate an ephemeral table to do the job.
|
** We will have to generate an ephemeral table to do the job.
|
||||||
|
|
Loading…
Reference in New Issue