mirror of
https://github.com/sqlite/sqlite.git
synced 2025-11-05 04:30:38 +03:00
Store the root page of the PRIMARY KEY index for a WITHOUT ROWID table in
the sqlite_master entry for the main table and omit the sqlite_master entry for the PRIMARY KEY. FossilOrigin-Name: b7544bb280f1c1c55135a9b35aeb85604fef94a3
This commit is contained in:
20
manifest
20
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
|
||||
|
||||
@@ -1 +1 @@
|
||||
ac711459ff243e787ea5e9c01720dff75a5eda9b
|
||||
b7544bb280f1c1c55135a9b35aeb85604fef94a3
|
||||
71
src/build.c
71
src/build.c
@@ -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.
|
||||
**
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user