]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Build internal data structures appropriately for WITHOUT ROWID tables.
authordrh <drh@noemail.net>
Wed, 23 Oct 2013 00:32:58 +0000 (00:32 +0000)
committerdrh <drh@noemail.net>
Wed, 23 Oct 2013 00:32:58 +0000 (00:32 +0000)
FossilOrigin-Name: 35a3606071685aa5196951f4bdddb136589ea216

manifest
manifest.uuid
src/build.c
src/prepare.c
src/sqliteInt.h

index ecbd37a3e8b1701595847772b901145fc3ebd3ce..5d7cda4c7d2528fddd1dd9ef9989d3ea2ec97281 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C The\sIndex\sobject\snow\shas\snKeyCol\sand\snColumn.\s\snColumn\sis\sthe\stotal\snumber\nof\scolumns\sand\snKeyCol\sis\sthe\snumber\sof\skey\scolumns.\s\sCurrently\sthese\salways\ndiffer\sby\sone.\s\sRefactor\saiColumn[]\sto\sbe\sof\stype\si16\sinstead\sof\sint.
-D 2013-10-22T18:01:40.210
+C Build\sinternal\sdata\sstructures\sappropriately\sfor\sWITHOUT\sROWID\stables.
+D 2013-10-23T00:32:58.135
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -168,7 +168,7 @@ F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7
 F src/btree.c 509722ce305471b626d3401c0631a808fd33237b
 F src/btree.h bfe0e8c5759b4ec77b0d18390064a6ef3cdffaaf
 F src/btreeInt.h f038e818bfadf75afbd09819ed93c26a333d39e0
-F src/build.c c29b38fb05dcd6c17990b3d2f2e6cdd66b5c42b7
+F src/build.c fbc70ed499d86a5a004ea097e509175229826e8b
 F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
@@ -213,7 +213,7 @@ F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
 F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
 F src/pragma.c ab815d27690d24e87c953355a765edb546c47708
-F src/prepare.c fa6988589f39af8504a61731614cd4f6ae71554f
+F src/prepare.c b1a3393b6c71b270921451ac43072d0c46711575
 F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
 F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
 F src/resolve.c 572585a96bf282bb9c3d9e08785ec3cae21dc488
@@ -223,7 +223,7 @@ F src/shell.c 6f11f0e9ded63d48e306f2c6858c521e568a47bb
 F src/sqlite.h.in 547a44dd4ff4d975e92a645ea2d609e543a83d0f
 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
-F src/sqliteInt.h b365e0f5ae7e22a433be5d1595f62a9db66d11cc
+F src/sqliteInt.h a60fca7b3f2a8d5a69f4b49e63224b92140207cf
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -1127,7 +1127,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P 45efc94f9a8169433ffcb4aa35760551c55df4c4
-R 01cd56332e89d0bc92e41f690b42402c
+P a106ce86cd4afd1f81603826de77df1fb25e9ab5
+R 3388bfdb8db93d8349e384ecbd431368
 U drh
-Z 6297f61b2d795cc46624c31a3c77d60c
+Z b769ffc4c966dfcb9185c08b7ad2538c
index 48d7ab4e297a891702bbc9051c139280987cd56c..ec1d986007029ffe2e83b16d7049cbf25afaa32d 100644 (file)
@@ -1 +1 @@
-a106ce86cd4afd1f81603826de77df1fb25e9ab5
\ No newline at end of file
+35a3606071685aa5196951f4bdddb136589ea216
\ No newline at end of file
index 58950330ceda59b98381b0fe206344e6e0046f0f..091498fc5870abb8851b954a64464f5e6e7e7c80 100644 (file)
@@ -384,6 +384,7 @@ static void freeIndex(sqlite3 *db, Index *p){
 #endif
   sqlite3ExprDelete(db, p->pPartIdxWhere);
   sqlite3DbFree(db, p->zColAff);
+  if( p->isResized ) sqlite3DbFree(db, p->azColl);
   sqlite3DbFree(db, p);
 }
 
@@ -946,7 +947,8 @@ void sqlite3StartTable(
     }else
 #endif
     {
-      sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
+      assert( sqlite3VdbeCurrentAddr(v) < 100 );
+      pParse->addrCrTab = (u16)sqlite3VdbeAddOp2(v, OP_CreateTable, iDb, reg2);
     }
     sqlite3OpenMasterTable(pParse, iDb);
     sqlite3VdbeAddOp2(v, OP_NewRowid, 0, reg1);
@@ -1247,6 +1249,7 @@ void sqlite3AddPrimaryKey(
     pTab->keyConf = (u8)onError;
     assert( autoInc==0 || autoInc==1 );
     pTab->tabFlags |= autoInc*TF_Autoincrement;
+    if( pList ) pParse->iPkSortOrder = pList->a[0].sortOrder;
   }else if( autoInc ){
 #ifndef SQLITE_OMIT_AUTOINCREMENT
     sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an "
@@ -1506,6 +1509,31 @@ static char *createTableStmt(sqlite3 *db, Table *p){
   return zStmt;
 }
 
+/*
+** Resize an Index object to hold N columns total.  Return SQLITE_OK
+** on success and SQLITE_NOMEM on an OOM error.
+*/
+static int resizeIndexObject(sqlite3 *db, Index *pIdx, int N){
+  char *zExtra;
+  int nByte;
+  if( pIdx->nColumn>=N ) return SQLITE_OK;
+  assert( pIdx->isResized==0 );
+  nByte = (sizeof(char*) + sizeof(i16) + 1)*N;
+  zExtra = sqlite3DbMallocZero(db, nByte);
+  if( zExtra==0 ) return SQLITE_NOMEM;
+  memcpy(zExtra, pIdx->azColl, sizeof(char*)*pIdx->nColumn);
+  pIdx->azColl = (char**)zExtra;
+  zExtra += sizeof(char*)*N;
+  memcpy(zExtra, pIdx->aiColumn, sizeof(i16)*pIdx->nColumn);
+  pIdx->aiColumn = (i16*)zExtra;
+  zExtra += sizeof(i16)*N;
+  memcpy(zExtra, pIdx->aSortOrder, pIdx->nColumn);
+  pIdx->aSortOrder = (u8*)zExtra;
+  pIdx->nColumn = N;
+  pIdx->isResized = 1;
+  return SQLITE_OK;
+}
+
 /*
 ** Estimate the total row width for a table.
 */
@@ -1535,6 +1563,101 @@ static void estimateIndexWidth(Index *pIdx){
   pIdx->szIdxRow = sqlite3LogEst(wIndex*4);
 }
 
+/* Return true if value x is found any of the first nCol entries of aiCol[]
+*/
+static int hasColumn(const i16 *aiCol, int nCol, int x){
+  while( nCol-- > 0 ) if( x==*(aiCol++) ) return 1;
+  return 0;
+}
+
+/*
+** The table pTab has a WITHOUT ROWID clause at the end.  Go through and
+** make all the changes necessary to make this a WITHOUT ROWID table.
+**
+**     (1)  Convert the OP_CreateTable into an no-op.
+**     (2)  Make sure all table columns are part of the PRIMARY KEY
+**     (3)  Make sure all PRIMARY KEY columns are part of all UNIQUE
+**          indices
+*/
+static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
+  Index *pIdx;
+  Index *pPk;
+  int nPk;
+  int i, j;
+  sqlite3 *db = pParse->db;
+
+  /* Convert the OP_CreateTable opcode that would normally create the
+  ** root-page for the table into a OP_Null opcode.  This prevents the
+  ** allocation of the root-page (which would never been used, as all
+  ** content is stored in the primary-key index instead) and it causes
+  ** a NULL value in the sqlite_master.rootpage field of the schema.
+  */
+  if( pParse->addrCrTab ){
+    sqlite3VdbeGetOp(pParse->pVdbe, pParse->addrCrTab)->opcode = OP_Null;
+  }
+
+  /* Locate the PRIMARY KEY index.  Or, if this table was originally
+  ** an INTEGER PRIMARY KEY table, create a new PRIMARY KEY index. 
+  */
+  if( pTab->iPKey>=0 ){
+    ExprList *pList;
+    pList = sqlite3ExprListAppend(pParse, 0, 0);
+    if( pList==0 ) return;
+    pList->a[0].zName = sqlite3DbStrDup(pParse->db,
+                                        pTab->aCol[pTab->iPKey].zName);
+    pList->a[0].sortOrder = pParse->iPkSortOrder;
+    assert( pParse->pNewTable==pTab );
+    pPk = sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0);
+    if( pPk==0 ) return;
+    pTab->iPKey = -1;
+  }
+  for(pPk=pTab->pIndex; pPk && pPk->autoIndex<2; pPk=pPk->pNext){}
+  assert( pPk!=0 );
+  nPk = pPk->nKeyCol;
+
+  /* Update the in-memory representation of all UNIQUE indices by converting
+  ** the final rowid column into one or more columns of the PRIMARY KEY.
+  */
+  for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
+    int n;
+    if( pIdx->autoIndex==2 ) continue;
+    if( pIdx->nKeyCol==pTab->nCol ){
+      pIdx->nColumn = pTab->nCol;
+      continue;
+    }
+    for(i=n=0; i<nPk; i++){
+      if( !hasColumn(pIdx->aiColumn, pIdx->nKeyCol, pPk->aiColumn[i]) ) n++;
+    }
+    if( resizeIndexObject(db, pIdx, pIdx->nKeyCol+n) ) return;
+    for(i=0, j=pIdx->nKeyCol; i<nPk; i++){
+      if( !hasColumn(pIdx->aiColumn, j, pPk->aiColumn[i]) ){
+        assert( j<pPk->nColumn );
+        pIdx->aiColumn[j] = pPk->aiColumn[i];
+        pIdx->azColl[j] = pPk->azColl[i];
+        j++;
+      }
+    }
+    assert( pIdx->nColumn==j );
+    assert( pIdx->nKeyCol+n==j );
+  }
+
+  /* Add all table columns to the PRIMARY KEY index
+  */
+  if( nPk<pTab->nCol ){
+    if( resizeIndexObject(db, pPk, pTab->nCol) ) return;
+    for(i=0, j=nPk; i<pTab->nCol; i++){
+      if( !hasColumn(pPk->aiColumn, j, i) ){
+        assert( j<pPk->nColumn );
+        pPk->aiColumn[j] = i;
+        pPk->azColl[j] = "BINARY";
+        j++;
+      }
+    }
+    assert( pPk->nColumn==j );
+    assert( pTab->nCol==j );
+  }
+}
+
 /*
 ** This routine is called to report the final ")" that terminates
 ** a CREATE TABLE statement.
@@ -1578,8 +1701,10 @@ void sqlite3EndTable(
   if( tabOpts & TF_WithoutRowid ){
     if( (p->tabFlags & TF_HasPrimaryKey)==0 ){
       sqlite3ErrorMsg(pParse, "no PRIMARY KEY for table %s", p->zName);
+    }else{
+      p->tabFlags |= TF_WithoutRowid;
+      convertToWithoutRowidTable(pParse, p);
     }
-    p->tabFlags |= TF_WithoutRowid;
   }
 
   iDb = sqlite3SchemaToIndex(db, p->pSchema);
@@ -2585,7 +2710,6 @@ Index *sqlite3CreateIndex(
   char *zName = 0;     /* Name of the index */
   int nName;           /* Number of characters in zName */
   int i, j;
-  Token nullId;        /* Fake token for an empty ID list */
   DbFixer sFix;        /* For assigning database names to pTable */
   int sortOrderMask;   /* 1 to honor DESC in index.  0 to ignore. */
   sqlite3 *db = pParse->db;
@@ -2742,11 +2866,10 @@ Index *sqlite3CreateIndex(
   ** So create a fake list to simulate this.
   */
   if( pList==0 ){
-    nullId.z = pTab->aCol[pTab->nCol-1].zName;
-    nullId.n = sqlite3Strlen30((char*)nullId.z);
     pList = sqlite3ExprListAppend(pParse, 0, 0);
     if( pList==0 ) goto exit_create_index;
-    sqlite3ExprListSetName(pParse, pList, &nullId, 0);
+    pList->a[0].zName = sqlite3DbStrDup(pParse->db,
+                                        pTab->aCol[pTab->nCol-1].zName);
     pList->a[0].sortOrder = (u8)sortOrder;
   }
 
index cfc9c348551fe6191d106148da9f931bc8b8542f..542d0bf8b95f5ee5ecac27254c900cbbc8344992 100644 (file)
@@ -66,7 +66,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
   assert( iDb>=0 && iDb<db->nDb );
   if( argv==0 ) return 0;   /* Might happen if EMPTY_RESULT_CALLBACKS are on */
   if( argv[1]==0 ){
-    corruptSchema(pData, argv[0], 0);
+    /* NULL root page for a WITHOUT ROWID table */
   }else if( argv[2] && argv[2][0] ){
     /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
     ** But because db->init.busy is set to 1, no VDBE code is generated
index 4565e92a88660fede615b53f7a5dadab79987a82..8ff95e3613d36bfca145f009ab28ae1a9f62388a 100644 (file)
@@ -1594,6 +1594,7 @@ struct Index {
   unsigned autoIndex:2;    /* 1==UNIQUE, 2==PRIMARY KEY, 0==CREATE INDEX */
   unsigned bUnordered:1;   /* Use this index for == or IN queries only */
   unsigned uniqNotNull:1;  /* True if UNIQUE and NOT NULL for all columns */
+  unsigned isResized:1;    /* True if resizeIndexObject() has been called */
 #ifdef SQLITE_ENABLE_STAT3_OR_STAT4
   int nSample;             /* Number of elements in aSample[] */
   int nSampleCol;          /* Size of IndexSample.anEq[] and so on */
@@ -2284,6 +2285,8 @@ struct Parse {
 
   int nVar;                 /* Number of '?' variables seen in the SQL so far */
   int nzVar;                /* Number of available slots in azVar[] */
+  u8 addrCrTab;             /* Address of OP_CreateTable opcode */
+  u8 iPkSortOrder;          /* ASC or DESC for INTEGER PRIMARY KEY */
   u8 explain;               /* True if the EXPLAIN flag is found on the query */
 #ifndef SQLITE_OMIT_VIRTUALTABLE
   u8 declareVtab;           /* True if inside sqlite3_declare_vtab() */