]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Store the root page of the PRIMARY KEY index for a WITHOUT ROWID table in
authordrh <drh@noemail.net>
Sat, 2 Nov 2013 14:37:18 +0000 (14:37 +0000)
committerdrh <drh@noemail.net>
Sat, 2 Nov 2013 14:37:18 +0000 (14:37 +0000)
the sqlite_master entry for the main table and omit the sqlite_master entry
for the PRIMARY KEY.

FossilOrigin-Name: b7544bb280f1c1c55135a9b35aeb85604fef94a3

manifest
manifest.uuid
src/build.c
src/prepare.c
src/sqliteInt.h
src/tokenize.c
test/corrupt2.test

index cd6383f16f530bd86e0da991868e5de9a93fccca..c01b546d054a589a99179fbbf33420ca43cdbbac 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Import\sthe\ssqlite3_analyzer\sfixes\sfrom\strunk.
-D 2013-11-02T11:43:05.572
+C Store\sthe\sroot\spage\sof\sthe\sPRIMARY\sKEY\sindex\sfor\sa\sWITHOUT\sROWID\stable\sin\nthe\ssqlite_master\sentry\sfor\sthe\smain\stable\sand\somit\sthe\ssqlite_master\sentry\nfor\sthe\sPRIMARY\sKEY.
+D 2013-11-02T14:37:18.563
 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 bc63356abffdde0271f8d7667bad32e0566debe1
+F src/build.c 38d6d7396213a5320ce6e822145b671e3e2653eb
 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 ff1a98998d2038bc9c770326986b7c4728de4973
-F src/prepare.c ea231a8450eef356490b09481db9fe51a6a59c32
+F src/prepare.c fa6988589f39af8504a61731614cd4f6ae71554f
 F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
 F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
 F src/resolve.c e729889b2c7a680ba4aa7296efa72c09369956d8
@@ -223,7 +223,7 @@ F src/shell.c 03d8d9b4052430343ff30d646334621f980f1202
 F src/sqlite.h.in 547a44dd4ff4d975e92a645ea2d609e543a83d0f
 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
-F src/sqliteInt.h bc4588b0d2eac8429d102609af6cfad583bfb41f
+F src/sqliteInt.h 7cc1b32804563f26cf44a4a48ad370490c8f737c
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -273,7 +273,7 @@ F src/test_thread.c 1e133a40b50e9c035b00174035b846e7eef481cb
 F src/test_vfs.c e72f555ef7a59080f898fcf1a233deb9eb704ea9
 F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
-F src/tokenize.c 70061085a51f2f4fc15ece94f32c03bcb78e63b2
+F src/tokenize.c ec4c1a62b890bf1dbcdb966399e140b904c700a4
 F src/trigger.c 53d6b5d50b3b23d4fcd0a36504feb5cff9aed716
 F src/update.c 94d63d3e06b09df3618655a841dc95d5b9466dc6
 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
@@ -387,7 +387,7 @@ F test/colname.test 08948a4809d22817e0e5de89c7c0a8bd90cb551b
 F test/conflict.test 0b3922d2304a14a47e3ccd61bbd6824327af659b
 F test/contrib01.test 2a1cbc0f2f48955d7d073f725765da6fbceda6b4
 F test/corrupt.test 4aabd06cff3fe759e3e658bcc17b71789710665e
-F test/corrupt2.test b8174976fab5bc000e58539ceb3bb9f31b4813f8
+F test/corrupt2.test 9c0ab4becd50e9050bc1ebb8675456a4e5587bf0
 F test/corrupt3.test 889d7cdb811800303aa722d7813fe8a4299cf726
 F test/corrupt4.test b963f9e01e0f92d15c76fb0747876fd4b96dc30a
 F test/corrupt5.test c23da7bfb20917cc7fdbb13ee25c7cc4e9fffeff
@@ -1128,7 +1128,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 302a81390f039fc23eeb8510e95b9d9fa0b41edd 42a11e7464ab1d97d603c7409f10710ad4f1f542
-R 3792eebb99bae3c39c82ab2be948da7e
+P ac711459ff243e787ea5e9c01720dff75a5eda9b
+R ae34f785e9853a53b0aaa3951983c6d8
 U drh
-Z 67feff5a16da3f8a7e3efdb5ed709f00
+Z 71ade7b873cbec3da5d0aa4bb763c9f6
index f638e5858c069a3816ea8af4ad53423ec6560d35..2764a20dcaae4981b43d6f18ed800a4db8394962 100644 (file)
@@ -1 +1 @@
-ac711459ff243e787ea5e9c01720dff75a5eda9b
\ No newline at end of file
+b7544bb280f1c1c55135a9b35aeb85604fef94a3
\ No newline at end of file
index 16b0f4840cec3569e14c693e3789cc0b96c57f8a..666d1b8ba875860b39bdbda42aae2dba38adbb78 100644 (file)
@@ -1275,11 +1275,14 @@ void sqlite3AddPrimaryKey(
        "INTEGER PRIMARY KEY");
 #endif
   }else{
+    Vdbe *v = pParse->pVdbe;
     Index *p;
+    if( v ) pParse->addrSkipPK = sqlite3VdbeAddOp0(v, OP_Noop);
     p = sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0,
                            0, sortOrder, 0);
     if( p ){
       p->autoIndex = 2;
+      if( v ) sqlite3VdbeJumpHere(v, pParse->addrSkipPK);
     }
     pList = 0;
   }
@@ -1590,13 +1593,27 @@ static int hasColumn(const i16 *aiCol, int nCol, int x){
 }
 
 /*
-** 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.
+** This routine runs at the end of parsing a CREATE TABLE statement that
+** has a WITHOUT ROWID clause.  The job of this routine is to convert both
+** internal schema data structures and the generated VDBE code so that they
+** are appropriate for a WITHOUT ROWID table instead of a rowid table.
+** Changes include:
 **
-**     (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
+**     (1)  Convert the OP_CreateTable into an OP_CreateIndex.  There is
+**          no rowid btree for a WITHOUT ROWID.  Instead, the canonical
+**          data storage is a covering index btree.
+**     (2)  Bypass the creation of the sqlite_master table entry
+**          for the PRIMARY KEY as the the primary key index is now
+**          identified by the sqlite_master table entry of the table itself.
+**     (3)  Set the Index.tnum of the PRIMARY KEY Index object in the
+**          schema to the rootpage from the main table.
+**     (4)  Set all columns of the PRIMARY KEY schema object to be NOT NULL.
+**     (5)  Add all table columns to the PRIMARY KEY Index object
+**          so that the PRIMARY KEY is a covering index.  The surplus
+**          columns are part of KeyInfo.nXField and are not used for
+**          sorting or lookup or uniqueness checks.
+**     (6)  Replace the rowid tail on all automatically generated UNIQUE
+**          indices with the PRIMARY KEY columns.
 */
 static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
   Index *pIdx;
@@ -1604,15 +1621,23 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
   int nPk;
   int i, j;
   sqlite3 *db = pParse->db;
+  Vdbe *v = pParse->pVdbe;
 
   /* 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.
+  ** root-page for the table into a OP_CreateIndex opcode.  The index
+  ** created will become the PRIMARY KEY index.
   */
   if( pParse->addrCrTab ){
-    sqlite3VdbeGetOp(pParse->pVdbe, pParse->addrCrTab)->opcode = OP_Null;
+    assert( v );
+    sqlite3VdbeGetOp(v, pParse->addrCrTab)->opcode = OP_CreateIndex;
+  }
+
+  /* Bypass the creation of the PRIMARY KEY btree and the sqlite_master
+  ** table entry.
+  */
+  if( pParse->addrSkipPK ){
+    assert( v );
+    sqlite3VdbeGetOp(v, pParse->addrSkipPK)->opcode = OP_Goto;
   }
 
   /* Locate the PRIMARY KEY index.  Or, if this table was originally
@@ -1641,6 +1666,9 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){
   }
   pPk->uniqNotNull = 1;
 
+  /* The root page of the PRIMARY KEY is the table root page */
+  pPk->tnum = pTab->tnum;
+
   /* Update the in-memory representation of all UNIQUE indices by converting
   ** the final rowid column into one or more columns of the PRIMARY KEY.
   */
@@ -1723,6 +1751,17 @@ void sqlite3EndTable(
 
   assert( !db->init.busy || !pSelect );
 
+  /* If the db->init.busy is 1 it means we are reading the SQL off the
+  ** "sqlite_master" or "sqlite_temp_master" table on the disk.
+  ** So do not write to the disk again.  Extract the root page number
+  ** for the table from the db->init.newTnum field.  (The page number
+  ** should have been put there by the sqliteOpenCb routine.)
+  */
+  if( db->init.busy ){
+    p->tnum = db->init.newTnum;
+  }
+
+  /* Special processing for WITHOUT ROWID Tables */
   if( tabOpts & TF_WithoutRowid ){
     if( (p->tabFlags & TF_HasPrimaryKey)==0 ){
       sqlite3ErrorMsg(pParse, "no PRIMARY KEY for table %s", p->zName);
@@ -1748,16 +1787,6 @@ void sqlite3EndTable(
     estimateIndexWidth(pIdx);
   }
 
-  /* If the db->init.busy is 1 it means we are reading the SQL off the
-  ** "sqlite_master" or "sqlite_temp_master" table on the disk.
-  ** So do not write to the disk again.  Extract the root page number
-  ** for the table from the db->init.newTnum field.  (The page number
-  ** should have been put there by the sqliteOpenCb routine.)
-  */
-  if( db->init.busy ){
-    p->tnum = db->init.newTnum;
-  }
-
   /* If not initializing, then create a record for the new table
   ** in the SQLITE_MASTER table of the database.
   **
index 88a6b65288cdb82a8fbd21d6802d58e26f1621a4..cfc9c348551fe6191d106148da9f931bc8b8542f 100644 (file)
@@ -65,7 +65,9 @@ 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[2] && argv[2][0] ){
+  if( argv[1]==0 ){
+    corruptSchema(pData, argv[0], 0);
+  }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
     ** or executed.  All the parser does is build the internal data
@@ -77,7 +79,7 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
 
     assert( db->init.busy );
     db->init.iDb = iDb;
-    db->init.newTnum = argv[1] ? sqlite3Atoi(argv[1]) : 0;
+    db->init.newTnum = sqlite3Atoi(argv[1]);
     db->init.orphanTrigger = 0;
     TESTONLY(rcp = ) sqlite3_prepare(db, argv[2], -1, &pStmt, 0);
     rc = db->errCode;
@@ -116,10 +118,6 @@ int sqlite3InitCallback(void *pInit, int argc, char **argv, char **NotUsed){
       /* Do Nothing */;
     }else if( sqlite3GetInt32(argv[1], &pIndex->tnum)==0 ){
       corruptSchema(pData, argv[0], "invalid rootpage");
-    }else if( pIndex->autoIndex==2 
-     && (pIndex->pTable->tabFlags & TF_WithoutRowid)!=0
-    ){
-      pIndex->pTable->tnum = pIndex->tnum;
     }
   }
   return 0;
index 97b75f16b245f968e1a875410596378bb44b8d8b..8890cbeaf4d959b2c5548adf7c4cac2d40159c19 100644 (file)
@@ -2283,6 +2283,8 @@ struct Parse {
   /* Information used while coding trigger programs. */
   Parse *pToplevel;    /* Parse structure for main program (or NULL) */
   Table *pTriggerTab;  /* Table triggers are being coded for */
+  int addrCrTab;       /* Address of OP_CreateTable opcode on CREATE TABLE */
+  int addrSkipPK;      /* Address of instruction to skip PRIMARY KEY index */
   u32 nQueryLoop;      /* Est number of iterations of a query (10*log2(N)) */
   u32 oldmask;         /* Mask of old.* columns referenced */
   u32 newmask;         /* Mask of new.* columns referenced */
@@ -2295,7 +2297,6 @@ struct Parse {
 
   int nVar;                 /* Number of '?' variables seen in the SQL so far */
   int nzVar;                /* Number of available slots in azVar[] */
-  int 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
@@ -2310,7 +2311,6 @@ struct Parse {
 #endif
   char **azVar;             /* Pointers to names of parameters */
   Vdbe *pReprepare;         /* VM being reprepared (sqlite3Reprepare()) */
-  int *aAlias;              /* Register used to hold aliased result */
   const char *zTail;        /* All SQL text past the last semicolon parsed */
   Table *pNewTable;         /* A table being constructed by CREATE TABLE */
   Trigger *pNewTrigger;     /* Trigger under construct by a CREATE TRIGGER */
index d26157f7d232d8132d0a3612f0f504c04896e643..f27929ea5b44a4a98c409548fdea3585be2fa164 100644 (file)
@@ -506,7 +506,6 @@ abort_parse:
   sqlite3DeleteTrigger(db, pParse->pNewTrigger);
   for(i=pParse->nzVar-1; i>=0; i--) sqlite3DbFree(db, pParse->azVar[i]);
   sqlite3DbFree(db, pParse->azVar);
-  sqlite3DbFree(db, pParse->aAlias);
   while( pParse->pAinc ){
     AutoincInfo *p = pParse->pAinc;
     pParse->pAinc = p->pNext;
index f395a0ba9124a1e36859427fe39e63480391c07d..744a76ed04ac9b125177211e2e91850d0766137c 100644 (file)
@@ -466,11 +466,6 @@ corruption_test -sqlprep {
   } {1 {database disk image is malformed}}
 }
 
-# Since the introduction of WITHOUT ROWID tables, having a table entry in
-# the sqlite_master table with a NULL rootpage is no longer a sign of 
-# corruption.
-#
-if 0 {
 corruption_test -sqlprep {
   CREATE TABLE t1(a, b, c);
   CREATE TABLE t2(a, b, c);
@@ -484,7 +479,6 @@ corruption_test -sqlprep {
     sqlite3_errcode db
   } {SQLITE_CORRUPT}
 }
-} ;# Disabled rootpage==NULL corruption test
 
 corruption_test -sqlprep {
   PRAGMA auto_vacuum = incremental;