]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Schemalint changes: Avoid creating candidate indexes if a compatible index exists...
authordan <dan@noemail.net>
Wed, 17 Feb 2016 20:06:12 +0000 (20:06 +0000)
committerdan <dan@noemail.net>
Wed, 17 Feb 2016 20:06:12 +0000 (20:06 +0000)
FossilOrigin-Name: cf0f7eeb4f6490b1e3f05b45e83b87cd64640846

manifest
manifest.uuid
src/shell_indexes.c

index f1eaa8735a7332ea954e5f55d17a96bab04a9b50..ff57fedd263511a3106c3db5247b6e216a37c420 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Fix\sfurther\sissues\sin\sschemalint.
-D 2016-02-16T18:37:37.844
+C Schemalint\schanges:\sAvoid\screating\scandidate\sindexes\sif\sa\scompatible\sindex\sexists.\sDo\snot\squote\sidentifiers\sthat\sdo\snot\srequire\sit.
+D 2016-02-17T20:06:12.566
 F Makefile.in dac2776c84e0d533b158a9af6e57e05c4a6b19f3
 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
 F Makefile.msc b0493f10caddb8adf992a4e6f1943141fc7c6816
@@ -350,7 +350,7 @@ F src/resolve.c 9f7ce3a3c087afb7597b7c916c99126ff3f12f0c
 F src/rowset.c 9fe4b3ad7cc00944386bb600233d8f523de07a6e
 F src/select.c ff80004a9a6ece891a8d9327a88e7b6e2588ee6d
 F src/shell.c 2cde87e03712204231167c4a6c61b0eb5129e105
-F src/shell_indexes.c 27d3b064078066c9a284a93149c4a151821f55bf
+F src/shell_indexes.c 6cc207072469f1ded8c3bb9de1d4b6590a28abb8
 F src/sqlite.h.in c7db059d3b810b70b83d9ed1436fa813eba22462
 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8
 F src/sqlite3ext.h dfbe62ffd95b99afe2140d8c35b180d11924072d
@@ -1430,7 +1430,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b
 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f
-P 58d4cf26e15f90463148bec63d6ab514ffbbae60
-R f221e3cac7f52c2c660e427ee329aa03
+P 73a7f010937828c5195a198604f976e8458cef73
+R 3a9a4af7276c9c00e5b2666c0bfe324e
 U dan
-Z 8b18cd934aae857f866e3f00c12cba6f
+Z 82976e1002963ffa4a1c502f357a9ae9
index 4b3aa263c2a28b2601f1b350e46c9b050621741e..2e9ca33ba0d8ab724febd9d2153ce982f65ed56a 100644 (file)
@@ -1 +1 @@
-73a7f010937828c5195a198604f976e8458cef73
\ No newline at end of file
+cf0f7eeb4f6490b1e3f05b45e83b87cd64640846
\ No newline at end of file
index 33f872efd7d2b1b91fc513fcdf5f912cc35720fa..54b59cd421fd651e395734f95d753999f7494746 100644 (file)
@@ -33,6 +33,7 @@ struct IdxConstraint {
   int bRange;                     /* True for range, false for eq */
   int iCol;                       /* Constrained table column */
   i64 depmask;                    /* Dependency mask */
+  int bFlag;                      /* Used by idxFindCompatible() */
   IdxConstraint *pNext;           /* Next constraint in pEq or pRange list */
   IdxConstraint *pLink;           /* See above */
 };
@@ -413,53 +414,20 @@ static int idxCreateTables(
   int rc = SQLITE_OK;
   IdxScan *pIter;
   for(pIter=pScan; pIter && rc==SQLITE_OK; pIter=pIter->pNextScan){
-    int nPk = 0;
-    char *zCols = 0;
-    char *zPk = 0;
-    char *zCreate = 0;
-    int iCol;
-
     rc = idxGetTableInfo(db, pIter, pzErrmsg);
-
-    for(iCol=0; rc==SQLITE_OK && iCol<pIter->pTable->nCol; iCol++){
-      IdxColumn *pCol = &pIter->pTable->aCol[iCol];
-      if( pCol->iPk>nPk ) nPk = pCol->iPk;
-      zCols = sqlite3_mprintf("%z%s%Q", zCols, (zCols?", ":""), pCol->zName);
-      if( zCols==0 ) rc = SQLITE_NOMEM;
-    }
-
-    for(iCol=1; rc==SQLITE_OK && iCol<=nPk; iCol++){
-      int j;
-      for(j=0; j<pIter->pTable->nCol; j++){
-        IdxColumn *pCol = &pIter->pTable->aCol[j];
-        if( pCol->iPk==iCol ){
-          zPk = sqlite3_mprintf("%z%s%Q", zPk, (zPk?", ":""), pCol->zName);
-          if( zPk==0 ) rc = SQLITE_NOMEM;
-          break;
-        }
-      }
-    }
-
     if( rc==SQLITE_OK ){
-      if( zPk ){
-        zCreate = sqlite3_mprintf("CREATE TABLE %Q(%s, PRIMARY KEY(%s))",
-            pIter->zTable, zCols, zPk
-        );
-      }else{
-        zCreate = sqlite3_mprintf("CREATE TABLE %Q(%s)", pIter->zTable, zCols);
+      int rc2;
+      sqlite3_stmt *pSql = 0;
+      rc = idxPrintfPrepareStmt(db, &pSql, pzErrmsg, 
+          "SELECT sql FROM sqlite_master WHERE tbl_name = %Q", pIter->zTable
+      );
+      while( rc==SQLITE_OK && SQLITE_ROW==sqlite3_step(pSql) ){
+        const char *zSql = (const char*)sqlite3_column_text(pSql, 0);
+        rc = sqlite3_exec(dbm, zSql, 0, 0, pzErrmsg);
       }
-      if( zCreate==0 ) rc = SQLITE_NOMEM;
+      rc2 = sqlite3_finalize(pSql);
+      if( rc==SQLITE_OK ) rc = rc2;
     }
-
-    if( rc==SQLITE_OK ){
-#if 0
-      printf("/* %s */\n", zCreate);
-#endif
-      rc = sqlite3_exec(dbm, zCreate, 0, 0, pzErrmsg);
-    }
-    sqlite3_free(zCols);
-    sqlite3_free(zPk);
-    sqlite3_free(zCreate);
   }
   return rc;
 }
@@ -501,6 +469,20 @@ static char *idxAppendText(int *pRc, char *zIn, const char *zFmt, ...){
   return zRet;
 }
 
+static int idxIdentifierRequiresQuotes(const char *zId){
+  int i;
+  for(i=0; zId[i]; i++){
+    if( !(zId[i]=='_')
+     && !(zId[i]>='0' && zId[i]<='9')
+     && !(zId[i]>='a' && zId[i]<='z')
+     && !(zId[i]>='A' && zId[i]<='Z')
+    ){
+      return 1;
+    }
+  }
+  return 0;
+}
+
 static char *idxAppendColDefn(
   int *pRc, 
   char *zIn, 
@@ -510,13 +492,100 @@ static char *idxAppendColDefn(
   char *zRet = zIn;
   IdxColumn *p = &pTab->aCol[pCons->iCol];
   if( zRet ) zRet = idxAppendText(pRc, zRet, ", ");
-  zRet = idxAppendText(pRc, zRet, "%Q", p->zName);
+
+  if( idxIdentifierRequiresQuotes(p->zName) ){
+    zRet = idxAppendText(pRc, zRet, "%Q", p->zName);
+  }else{
+    zRet = idxAppendText(pRc, zRet, "%s", p->zName);
+  }
+
   if( sqlite3_stricmp(p->zColl, pCons->zColl) ){
-    zRet = idxAppendText(pRc, zRet, " COLLATE %Q", pCons->zColl);
+    if( idxIdentifierRequiresQuotes(pCons->zColl) ){
+      zRet = idxAppendText(pRc, zRet, " COLLATE %Q", pCons->zColl);
+    }else{
+      zRet = idxAppendText(pRc, zRet, " COLLATE %s", pCons->zColl);
+    }
   }
   return zRet;
 }
 
+/*
+** Search database dbm for an index compatible with the one idxCreateFromCons()
+** would create from arguments pScan, pEq and pTail. If no error occurs and 
+** such an index is found, return non-zero. Or, if no such index is found,
+** return zero.
+**
+** If an error occurs, set *pRc to an SQLite error code and return zero.
+*/
+static int idxFindCompatible(
+  int *pRc,                       /* OUT: Error code */
+  sqlite3* dbm,                   /* Database to search */
+  IdxScan *pScan,                 /* Scan for table to search for index on */
+  IdxConstraint *pEq,             /* List of == constraints */
+  IdxConstraint *pTail            /* List of range constraints */
+){
+  const char *zTbl = pScan->zTable;
+  sqlite3_stmt *pIdxList = 0;
+  IdxConstraint *pIter;
+  int nEq = 0;                    /* Number of elements in pEq */
+  int rc, rc2;
+
+  /* Count the elements in list pEq */
+  for(pIter=pEq; pIter; pIter=pIter->pNext) nEq++;
+
+  rc = idxPrintfPrepareStmt(dbm, &pIdxList, 0, "PRAGMA index_list=%Q", zTbl);
+  while( rc==SQLITE_OK && sqlite3_step(pIdxList)==SQLITE_ROW ){
+    int bMatch = 1;
+    IdxConstraint *pT = pTail;
+    sqlite3_stmt *pInfo = 0;
+    const char *zIdx = (const char*)sqlite3_column_text(pIdxList, 1);
+
+    /* Zero the IdxConstraint.bFlag values in the pEq list */
+    for(pIter=pEq; pIter; pIter=pIter->pNext) pIter->bFlag = 0;
+
+    rc = idxPrintfPrepareStmt(dbm, &pInfo, 0, "PRAGMA index_xInfo=%Q", zIdx);
+    while( rc==SQLITE_OK && sqlite3_step(pInfo)==SQLITE_ROW ){
+      int iIdx = sqlite3_column_int(pInfo, 0);
+      int iCol = sqlite3_column_int(pInfo, 1);
+      const char *zColl = (const char*)sqlite3_column_text(pInfo, 4);
+
+      if( iIdx<nEq ){
+        for(pIter=pEq; pIter; pIter=pIter->pNext){
+          if( pIter->bFlag ) continue;
+          if( pIter->iCol!=iCol ) continue;
+          if( sqlite3_stricmp(pIter->zColl, zColl) ) continue;
+          pIter->bFlag = 1;
+          break;
+        }
+        if( pIter==0 ){
+          bMatch = 0;
+          break;
+        }
+      }else{
+        if( pT ){
+          if( pT->iCol!=iCol || sqlite3_stricmp(pT->zColl, zColl) ){
+            bMatch = 0;
+            break;
+          }
+          pT = pT->pLink;
+        }
+      }
+    }
+    rc2 = sqlite3_finalize(pInfo);
+    if( rc==SQLITE_OK ) rc = rc2;
+
+    if( rc==SQLITE_OK && bMatch ){
+      sqlite3_finalize(pIdxList);
+      return 1;
+    }
+  }
+  rc2 = sqlite3_finalize(pIdxList);
+  if( rc==SQLITE_OK ) rc = rc2;
+
+  *pRc = rc;
+  return 0;
+}
+
 static int idxCreateFromCons(
   sqlite3 *dbm,
   IdxScan *pScan,
@@ -524,12 +593,13 @@ static int idxCreateFromCons(
   IdxConstraint *pTail
 ){
   int rc = SQLITE_OK;
-  if( pEq || pTail ){
+  if( (pEq || pTail) && 0==idxFindCompatible(&rc, dbm, pScan, pEq, pTail) ){
     IdxTable *pTab = pScan->pTable;
     char *zCols = 0;
     char *zIdx = 0;
     IdxConstraint *pCons;
     int h = 0;
+    const char *zFmt;
 
     for(pCons=pEq; pCons; pCons=pCons->pLink){
       zCols = idxAppendColDefn(&rc, zCols, pTab, pCons);
@@ -545,9 +615,12 @@ static int idxCreateFromCons(
         h += ((h<<3) + zCols[i]);
       }
 
-      zIdx = sqlite3_mprintf("CREATE INDEX IF NOT EXISTS "
-          "'%q_idx_%08x' ON %Q(%s)", pScan->zTable, h, pScan->zTable, zCols
-      );
+      if( idxIdentifierRequiresQuotes(pScan->zTable) ){
+        zFmt = "CREATE INDEX '%q_idx_%08x' ON %Q(%s)";
+      }else{
+        zFmt = "CREATE INDEX %s_idx_%08x ON %s(%s)";
+      }
+      zIdx = sqlite3_mprintf(zFmt, pScan->zTable, h, pScan->zTable, zCols);
       if( !zIdx ){
         rc = SQLITE_NOMEM;
       }else{
@@ -665,6 +738,12 @@ static int idxCreateCandidates(
 }
 
 static void idxScanFree(IdxScan *pScan){
+  IdxScan *pIter;
+  IdxScan *pNext;
+  for(pIter=pScan; pIter; pIter=pNext){
+    pNext = pIter->pNextScan;
+
+  }
 }
 
 int idxFindIndexes(
@@ -796,12 +875,14 @@ int shellIndexesCommand(
     rc = idxCreateCandidates(dbm, ctx.pScan, pzErrmsg);
   }
 
-  /* Create candidate indexes within the in-memory database file */
+  /* Figure out which of the candidate indexes are preferred by the query
+  ** planner and report the results to the user.  */
   if( rc==SQLITE_OK ){
     rc = idxFindIndexes(dbm, zSql, xOut, pOutCtx, pzErrmsg);
   }
 
   idxScanFree(ctx.pScan);
+  sqlite3_finalize(ctx.pInsertMask);
   sqlite3_close(dbm);
   return rc;
 }