]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Modifications towards better vector IN(...) support on this branch. Not activated...
authordan <dan@noemail.net>
Wed, 13 Jul 2016 19:48:13 +0000 (19:48 +0000)
committerdan <dan@noemail.net>
Wed, 13 Jul 2016 19:48:13 +0000 (19:48 +0000)
FossilOrigin-Name: 34e35c71b25b0aa2d8931040feb260a78cc48c49

manifest
manifest.uuid
src/expr.c

index 43f53685aacf7bae808d9c0bff83e0bb974fe271..c71b40dd0dee7085be090f70cd3bc96786cb14c9 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Merge\scomment\stypo\sfixes\sfrom\strunk.
-D 2016-07-10T19:35:45.597
+C Modifications\stowards\sbetter\svector\sIN(...)\ssupport\son\sthis\sbranch.\sNot\sactivated\syet.
+D 2016-07-13T19:48:13.115
 F Makefile.in 6c20d44f72d4564f11652b26291a214c8367e5db
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc d66d0395c38571aab3804f8db0fa20707ae4609a
@@ -337,7 +337,7 @@ F src/ctime.c 61949e83c4c36e37195a8398ebc752780b534d95
 F src/date.c 1cc9fb516ec9932c6fd4d2a0d2f8bc4480145c39
 F src/dbstat.c 4f6f7f52b49beb9636ffbd517cfe44a402ba4ad0
 F src/delete.c 4aba4214a377ce8ddde2d2e609777bcc8235200f
-F src/expr.c 330854fe9fdea1d244abaef6d680f6b91df07cb4
+F src/expr.c 939362d26f5e99a4802ae94ae6e47d4def72b8f3
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c bc4145347595b7770f9a598cff1c848302cf5413
 F src/func.c 61a4114cf7004f10c542cfabbab9f2bcb9033045
@@ -1507,7 +1507,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 b2204215b231202aef7a218411cc2ddaecf28f35 77c692a6704cd877ba35d0afb774ab9b46364d59
-R 1a7620cc6269220b48a9fcbcbb9b68d1
-U mistachkin
-Z cf1dd7dc395b0586dda9fa40ccf71a27
+P 728c5aa436a5f55c86b019c415a2b71d1b0a8fd6
+R 6c0b20cb1573f5c43e78ae5a07a06597
+U dan
+Z 35590bc4128842477cd3208768d4edc0
index b148ca60430f07e53ccb38961c5655e7708ebaff..722c9bb7ccff202285be525f58cf240812406b41 100644 (file)
@@ -1 +1 @@
-728c5aa436a5f55c86b019c415a2b71d1b0a8fd6
\ No newline at end of file
+34e35c71b25b0aa2d8931040feb260a78cc48c49
\ No newline at end of file
index 7941c228fdd0005fac6a14ac72b0746c485fe5c0..c43c6c04dee9253b8efe10cf95818246326be4c9 100644 (file)
@@ -309,6 +309,12 @@ static int codeCompare(
   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){
   if( (pExpr->flags & EP_Vector)==0 ) return 1;
   if( pExpr->flags & EP_xIsSelect ){
@@ -318,7 +324,10 @@ int sqlite3ExprVectorSize(Expr *pExpr){
 }
 
 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.pList->a[i].pExpr;
@@ -1703,12 +1712,12 @@ int sqlite3IsRowid(const char *z){
 ** table, then return NULL.
 */
 #ifndef SQLITE_OMIT_SUBQUERY
-static Select *isCandidateForInOpt(Expr *pX){
+static Select *isCandidateForInOpt(Expr *pX, int bNullSensitive){
   Select *p;
   SrcList *pSrc;
   ExprList *pEList;
-  Expr *pRes;
   Table *pTab;
+  int i;
   if( !ExprHasProperty(pX, EP_xIsSelect) ) return 0;  /* Not a subquery */
   if( ExprHasProperty(pX, EP_VarSelect)  ) return 0;  /* Correlated subq */
   p = pX->x.pSelect;
@@ -1731,10 +1740,18 @@ static Select *isCandidateForInOpt(Expr *pX){
   assert( pTab->pSelect==0 );            /* FROM clause is not a view */
   if( IsVirtual(pTab) ) return 0;        /* FROM clause not a virtual table */
   pEList = p->pEList;
-  if( pEList->nExpr!=1 ) return 0;       /* One column in the result set */
-  pRes = pEList->a[0].pExpr;
-  if( pRes->op!=TK_COLUMN ) return 0;    /* Result is a column */
-  assert( pRes->iTable==pSrc->a[0].iCursor );  /* Not a correlated subquery */
+
+  /* All SELECT results must be columns. If the SELECT returns more than
+  ** 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 */
+    if( pEList->nExpr>1 && bNullSensitive ){
+      if( pTab->aCol[pRes->iColumn].notNull==0 ) return 0;
+    }
+  }
   return p;
 }
 #endif /* SQLITE_OMIT_SUBQUERY */
@@ -1867,20 +1884,18 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
   ** satisfy the query.  This is preferable to generating a new 
   ** 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 */
     Table *pTab;                           /* Table <table>. */
-    Expr *pExpr;                           /* Expression <column> */
-    i16 iCol;                              /* Index of column <column> */
+    ExprList *pEList = p->pEList;
+    int nExpr = pEList->nExpr;
     i16 iDb;                               /* Database idx for pTab */
 
     assert( p->pEList!=0 );             /* Because of isCandidateForInOpt(p) */
     assert( p->pEList->a[0].pExpr!=0 ); /* Because of isCandidateForInOpt(p) */
     assert( p->pSrc!=0 );               /* Because of isCandidateForInOpt(p) */
     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>. */
     iDb = sqlite3SchemaToIndex(db, pTab->pSchema);
     sqlite3CodeVerifySchema(pParse, iDb);
@@ -1891,7 +1906,7 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
     ** successful here.
     */
     assert(v);
-    if( iCol<0 ){
+    if( nExpr==1 && pEList->a[0].pExpr->iColumn<0 ){
       int iAddr = sqlite3CodeOnce(pParse);
       VdbeCoverage(v);
 
@@ -1901,23 +1916,54 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
       sqlite3VdbeJumpHere(v, iAddr);
     }else{
       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
       ** be used in place of a temp-table, it must be ordered according
       ** 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){
-        if( (pIdx->aiColumn[0]==iCol)
-         && sqlite3FindCollSeq(db, ENC(db), pIdx->azColl[0], 0)==pReq
-         && (!mustBeUnique || (pIdx->nKeyCol==1 && IsUniqueIndex(pIdx)))
-        ){
+        if( pIdx->nKeyCol<nExpr ) continue;
+        if( mustBeUnique && (pIdx->nKeyCol!=nExpr || !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);
           sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb);
           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 );
           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
-            const i64 sOne = 1;
+            i64 mask = (1<<nExpr)-1;
             sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, 
-                iTab, 0, 0, (u8*)&sOne, P4_INT64);
+                iTab, 0, 0, (u8*)&mask, P4_INT64);
 #endif
             *prRhsHasNull = ++pParse->nMem;
             sqlite3SetHasNullFlag(v, iTab, *prRhsHasNull);
@@ -1954,7 +2002,6 @@ int sqlite3FindInIndex(Parse *pParse, Expr *pX, u32 inFlags, int *prRhsHasNull){
   ){
     eType = IN_INDEX_NOOP;
   }
-     
 
   if( eType==0 ){
     /* Could not find an existing table or index to use as the RHS b-tree.