diff --git a/manifest b/manifest index c352386d74..d952a56739 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C All\stests\spass\swhen\sSQLITE_OMIT_INTEGRITY_CHECK\sis\sdefined.\s(CVS\s2055) -D 2004-11-04T14:47:12 +C Incremental\scheck-in\sof\schanges\sthat\swill\sultimately\slead\sto\sa\nworking\sautoincrement.\s(CVS\s2056) +D 2004-11-05T00:43:12 F Makefile.in c4d2416860f472a1e3393714d0372074197565df F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -29,11 +29,11 @@ F sqlite3.def dbaeb20c153e1d366e8f421b55a573f5dfc00863 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689 F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea -F src/btree.c a3e45d54eb1a81698f609693c22df382dfbf9151 +F src/btree.c 1b172b9d58608eeba1022e858fedce351c7090f5 F src/btree.h 3166388fa58c5594d8064d38b43440d79da38fb6 -F src/build.c 1bf89a574108cbb03aed722f0ce97cf54469717d +F src/build.c e72d6f76373998063cd85d592e7a402b8e24b721 F src/date.c 34bdb0082db7ec2a83ef00063f7b44e61ee19dad -F src/delete.c 52980e594e69e80374fb928fe611d5f75ca4e390 +F src/delete.c 832adc6fe1c07b7e28e1b4c1038d2b06f7397dd4 F src/expr.c 3a43e508a3dc213703808bbcbb17633b88b57d17 F src/func.c 600e506bccf7648df8ad03efb417560d0f7ad4c1 F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5 @@ -54,19 +54,19 @@ F src/os_win.c 9482dfc92f289b68205bb2c9315757c7e3946bfb F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c a43e2a392be51966129e9afb18b81551c9f222b8 F src/pager.h cbe4ba356d9dd3f30260f322b3dc77408164df14 -F src/parse.y 4a27450611ed2b8c359078e04daf93c50b1d22dd +F src/parse.y e7f4e87a2ad14ccf5b8adcf1019fb8a355964579 F src/pragma.c 44e192eb5928157bdb015926f858a7c6e3ef6c98 F src/printf.c 7a92adc00b758cd5ce087dae80181a8bbdb70ed2 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c 156990c636102bb6b8de85e7ff3396a62568476b F src/shell.c 55adda3cf3c1cc2f6c1919aac17b2318f9c2a96f F src/sqlite.h.in 4f97b5907acfd2a5068cb0cec9d5178816734db7 -F src/sqliteInt.h 8b93c9d7b7343b9013ffb73cbd2cb6ea4f546c62 +F src/sqliteInt.h 126ec1947a91438a388112f3d282f625f7f73a0a F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c 0302e3f42f015d132d1291f3388c06e86c24a008 F src/test1.c df1d1ca2c40cafefb9a29860f072c4d0fee1a7b5 F src/test2.c b11fa244fff02190707dd0879987c37c75e61fc8 -F src/test3.c fdae1ed48add4b5df60f59a7c22e9d0b34265b55 +F src/test3.c de9edf178c02707cd37fd80b54e4c2ea77251cc0 F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df F src/test5.c b001fa7f1b9e2dc5c2331de62fc641b5ab2bd7a1 F src/tokenize.c bf9de9689b3bb813d65784bf54472804bf9595e6 @@ -75,7 +75,7 @@ F src/update.c 7b17b281d600bf3e220b3c5718e0883442dee722 F src/utf.c f4f83acd73389090e32d6589d307fc55d794c7ed F src/util.c 005fdf2d008f3429d081766ad6098fdd86d8d8e6 F src/vacuum.c ecb4a2c6f1ac5cc9b394dc64d3bb14ca650c4f60 -F src/vdbe.c cf7eb35b5a649c11345c5f85ad7b1511253431cc +F src/vdbe.c b324acdaff3b1f21cd369bbb0df30e1c3fa828f4 F src/vdbe.h 067ca8d6750ba4f69a50284765e5883dee860181 F src/vdbeInt.h 6017100adff362b8dfa37a69e3f1431f084bfa5b F src/vdbeapi.c 3965bf4678ae32c05f73550c1b5be3268f9f3006 @@ -252,7 +252,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c -P 1da361fae82d420be63c53f8e3efaccac24f348a -R 91d65eb4622d90500501298966d2317c +P 158a2d16a8630e3b5892120f6ea68f2b0dc47eb3 +R 7e671e2bcee0e6583c9f1a1b858bd032 U drh -Z aa82f4ff31655559fe92ab11f9dd6086 +Z 257ce5d18cf67227ffb08447220e1214 diff --git a/manifest.uuid b/manifest.uuid index 74c7122a9d..7a52f9be87 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -158a2d16a8630e3b5892120f6ea68f2b0dc47eb3 \ No newline at end of file +10c3d88305e404b9e4cc4eef0b8e5dc7864a5937 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index a91b234f8f..3b53e7dbc8 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.204 2004/11/04 14:30:05 danielk1977 Exp $ +** $Id: btree.c,v 1.205 2004/11/05 00:43:12 drh Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -4412,6 +4412,18 @@ int sqlite3BtreeClearTable(Btree *pBt, int iTable){ ** ** This routine will fail with SQLITE_LOCKED if there are any open ** cursors on the table. +** +** If AUTOVACUUM is enabled and the page at iTable is not the last +** root page in the database file, then the last root page +** in the database file is moved into the slot formerly occupied by +** iTable and that last slot formerly occupied by the last root page +** is added to the freelist instead of iTable. In this say, all +** root pages are kept at the beginning of the database file, which +** is necessary for AUTOVACUUM to work right. *piMoved is set to the +** page number that used to be the last root page in the file before +** the move. If no page gets moved, *piMoved is set to 0. +** The last root page is recorded in meta[3] and the value of +** meta[3] is updated by this procedure. */ int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){ int rc; @@ -4434,7 +4446,7 @@ int sqlite3BtreeDropTable(Btree *pBt, int iTable, int *piMoved){ rc = sqlite3BtreeClearTable(pBt, iTable); if( rc ) return rc; - if( piMoved ) *piMoved = 0; + *piMoved = 0; if( iTable>1 ){ #ifdef SQLITE_OMIT_AUTOVACUUM @@ -4521,8 +4533,9 @@ int sqlite3BtreeGetMeta(Btree *pBt, int idx, u32 *pMeta){ *pMeta = get4byte(&pP1[36 + idx*4]); sqlite3pager_unref(pP1); - /* The current implementation is unable to handle writes to an autovacuumed - ** database. So make such a database readonly. */ + /* If autovacuumed is disabled in the implementation but we are + ** trying to access an autovacuumed database, then make the + ** database readonly. */ #ifdef SQLITE_OMIT_AUTOVACUUM if( idx==4 && *pMeta>0 ) pBt->readOnly = 1; #endif diff --git a/src/build.c b/src/build.c index b88f7de8ee..23c2fbeefd 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.260 2004/11/04 14:47:12 drh Exp $ +** $Id: build.c,v 1.261 2004/11/05 00:43:12 drh Exp $ */ #include "sqliteInt.h" #include @@ -54,6 +54,7 @@ void sqlite3FinishCoding(Parse *pParse){ Vdbe *v; if( sqlite3_malloc_failed ) return; + if( pParse->nested ) return; /* Begin by generating some termination code at the end of the ** vdbe program @@ -112,6 +113,35 @@ void sqlite3FinishCoding(Parse *pParse){ pParse->cookieGoto = 0; } +/* +** Run the parser and code generator recursively in order to generate +** code for the SQL statement given onto the end of the pParse context +** currently under construction. When the parser is run recursively +** this way, the final OP_Halt is not appended and other initialization +** and finalization steps are omitted because those are handling by the +** outermost parser. +** +** Not everything is nestable. This facility is designed to permit +** INSERT, UPDATE, and DELETE operations against SQLITE_MASTER. Use +** care if you decide to try to use this routine for some other purpose. +*/ +void sqlite3NestedParse(Parse *pParse, const char *zFormat, ...){ + va_list ap; + char *zSql; + int rc; + Parse savedState; + if( pParse->nErr ) return; + assert( pParse->nested<10 ); /* Nesting should only be of limited depth */ + va_start(ap, zFormat); + zSql = sqlite3VMPrintf(zFormat, ap); + va_end(ap); + pParse->nested++; + savedState = *pParse; + rc = sqlite3RunParser(pParse, zSql, 0); + sqliteFree(zSql); + pParse->nested--; +} + /* ** Locate the in-memory structure that describes a particular database ** table given the name of that table and (optionally) the name of the @@ -836,7 +866,12 @@ void sqlite3AddDefaultValue(Parse *pParse, Token *pVal, int minusFlag){ ** If the key is not an INTEGER PRIMARY KEY, then create a unique ** index for the key. No index is created for INTEGER PRIMARY KEYs. */ -void sqlite3AddPrimaryKey(Parse *pParse, ExprList *pList, int onError){ +void sqlite3AddPrimaryKey( + Parse *pParse, /* Parsing context */ + ExprList *pList, /* List of field names to be indexed */ + int onError, /* What to do with a uniqueness conflict */ + int autoInc /* True if the AUTOINCREMENT keyword is present */ +){ Table *pTab = pParse->pNewTable; char *zType = 0; int iCol = -1, i; @@ -867,6 +902,10 @@ void sqlite3AddPrimaryKey(Parse *pParse, ExprList *pList, int onError){ if( zType && sqlite3StrICmp(zType, "INTEGER")==0 ){ pTab->iPKey = iCol; pTab->keyConf = onError; + pTab->autoInc = autoInc; + }else if( autoInc ){ + sqlite3ErrorMsg(pParse, "AUTOINCREMENT is only allowed on an " + "INTEGER PRIMARY KEY"); }else{ sqlite3CreateIndex(pParse, 0, 0, 0, pList, onError, 0, 0); pList = 0; diff --git a/src/delete.c b/src/delete.c index a476c4fded..17448ae211 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** -** $Id: delete.c,v 1.85 2004/11/04 04:42:28 drh Exp $ +** $Id: delete.c,v 1.86 2004/11/05 00:43:12 drh Exp $ */ #include "sqliteInt.h" @@ -38,7 +38,8 @@ Table *sqlite3SrcListLookup(Parse *pParse, SrcList *pSrc){ ** writable return 0; */ int sqlite3IsReadOnly(Parse *pParse, Table *pTab, int viewOk){ - if( pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0 ){ + if( pTab->readOnly && (pParse->db->flags & SQLITE_WriteSchema)==0 + && pParse->nested==0 ){ sqlite3ErrorMsg(pParse, "table %s may not be modified", pTab->zName); return 1; } diff --git a/src/parse.y b/src/parse.y index bce3dbfc5a..90e4b1394f 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.147 2004/11/03 13:59:05 drh Exp $ +** @(#) $Id: parse.y,v 1.148 2004/11/05 00:43:12 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -213,7 +213,8 @@ carg ::= DEFAULT NULL. // ccons ::= NULL onconf. ccons ::= NOT NULL onconf(R). {sqlite3AddNotNull(pParse, R);} -ccons ::= PRIMARY KEY sortorder onconf(R). {sqlite3AddPrimaryKey(pParse,0,R);} +ccons ::= PRIMARY KEY sortorder onconf(R) autoinc(I). + {sqlite3AddPrimaryKey(pParse,0,R,I);} ccons ::= UNIQUE onconf(R). {sqlite3CreateIndex(pParse,0,0,0,0,R,0,0);} ccons ::= CHECK LP expr RP onconf. ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R). @@ -221,6 +222,11 @@ ccons ::= REFERENCES nm(T) idxlist_opt(TA) refargs(R). ccons ::= defer_subclause(D). {sqlite3DeferForeignKey(pParse,D);} ccons ::= COLLATE id(C). {sqlite3AddCollateType(pParse, C.z, C.n);} +// The optional AUTOINCREMENT keyword +%type autoinc {int} +autoinc(X) ::= . {X = 0;} +autoinc(X) ::= AUTOINC. {X = 1;} + // The next group of rules parses the arguments to a REFERENCES clause // that determine if the referential integrity checking is deferred or // or immediate and which determine what action to take if a ref-integ @@ -256,8 +262,8 @@ conslist ::= conslist COMMA tcons. conslist ::= conslist tcons. conslist ::= tcons. tcons ::= CONSTRAINT nm. -tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R). - {sqlite3AddPrimaryKey(pParse,X,R);} +tcons ::= PRIMARY KEY LP idxlist(X) RP onconf(R) autoinc(I). + {sqlite3AddPrimaryKey(pParse,X,R,I);} tcons ::= UNIQUE LP idxlist(X) RP onconf(R). {sqlite3CreateIndex(pParse,0,0,0,X,R,0,0);} tcons ::= CHECK expr onconf. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 9244476c82..b8b924cd87 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.330 2004/11/04 14:30:05 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.331 2004/11/05 00:43:12 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -573,6 +573,7 @@ struct Table { u8 isTransient; /* True if automatically deleted when VDBE finishes */ u8 hasPrimKey; /* True if there exists a primary key */ u8 keyConf; /* What to do in case of uniqueness conflict on iPKey */ + u8 autoInc; /* True if the integer primary key is autoincrement */ Trigger *pTrigger; /* List of SQL triggers on this table */ FKey *pFKey; /* Linked list of all foreign keys in this table */ char *zColAff; /* String defining the affinity of each column */ @@ -1010,6 +1011,7 @@ struct Parse { u8 useAgg; /* If true, extract field values from the aggregator ** while generating expressions. Normally false */ u8 checkSchema; /* Causes schema cookie check after an error */ + u8 nested; /* Number of nested calls to the parser/code generator */ int nErr; /* Number of errors seen */ int nTab; /* Number of previously allocated VDBE cursors */ int nMem; /* Number of memory cells used so far */ @@ -1254,7 +1256,7 @@ void sqlite3OpenMasterTable(Vdbe *v, int); void sqlite3StartTable(Parse*,Token*,Token*,Token*,int,int); void sqlite3AddColumn(Parse*,Token*); void sqlite3AddNotNull(Parse*, int); -void sqlite3AddPrimaryKey(Parse*, ExprList*, int); +void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int); void sqlite3AddColumnType(Parse*,Token*,Token*); void sqlite3AddDefaultValue(Parse*,Token*,int); void sqlite3AddCollateType(Parse*, const char*, int); @@ -1298,6 +1300,7 @@ void sqlite3ExprCode(Parse*, Expr*); int sqlite3ExprCodeExprList(Parse*, ExprList*); void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); +void sqlite3NextedParse(Parse*, const char*, ...); Table *sqlite3FindTable(sqlite3*,const char*, const char*); Table *sqlite3LocateTable(Parse*,const char*, const char*); Index *sqlite3FindIndex(sqlite3*,const char*, const char*); diff --git a/src/test3.c b/src/test3.c index 9c8b566874..da7ce0e7d3 100644 --- a/src/test3.c +++ b/src/test3.c @@ -13,7 +13,7 @@ ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test3.c,v 1.55 2004/11/04 14:47:12 drh Exp $ +** $Id: test3.c,v 1.56 2004/11/05 00:43:12 drh Exp $ */ #include "sqliteInt.h" #include "pager.h" @@ -315,6 +315,7 @@ static int btree_drop_table( Btree *pBt; int iTable; int rc; + int notUsed1; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " ID TABLENUM\"", 0); @@ -322,7 +323,7 @@ static int btree_drop_table( } pBt = sqlite3TextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; - rc = sqlite3BtreeDropTable(pBt, iTable, 0); + rc = sqlite3BtreeDropTable(pBt, iTable, ¬Used1); if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, errorName(rc), 0); return TCL_ERROR; diff --git a/src/vdbe.c b/src/vdbe.c index 9e4ef43b4e..bb2106c2f1 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.423 2004/11/04 14:30:06 danielk1977 Exp $ +** $Id: vdbe.c,v 1.424 2004/11/05 00:43:12 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -2813,12 +2813,19 @@ case OP_NotExists: { break; } -/* Opcode: NewRecno P1 * * +/* Opcode: NewRecno P1 P2 * ** ** Get a new integer record number used as the key to a table. ** The record number is not previously used as a key in the database ** table that cursor P1 points to. The new record number is pushed ** onto the stack. +** +** If P2>0 then P2 is a memory cell that holds the largest previously +** generated record number. No new record numbers are allowed to be less +** than this value. When this value reaches 0x7fffffff, a SQLITE_FULL +** error is generated. The P2 memory cell is updated with the generated +** record number. This P2 mechanism is used to help implement the +** AUTOINCREMENT feature. */ case OP_NewRecno: { int i = pOp->p1; @@ -2882,6 +2889,24 @@ case OP_NewRecno: { } } } + +#ifndef SQLITE_OMIT_AUTOINCREMENT + if( pOp->p2 ){ + Mem *pMem; + assert( pOp->p2>0 && pOp->p2nMem ); /* P2 is a valid memory cell */ + pMem = &p->aMem[pOp->p2]; + assert( (pMem->flags & MEM_Int)!=0 ); /* mem(P2) holds an integer */ + if( pMem->i==0x7fffffffffffffff || pC->useRandomRowid ){ + rc = SQLITE_FULL; + goto abort_due_to_error; + } + if( vi+1 ){ + v = pMem->i + 1; + } + pMem->i = v; + } +#endif + if( v<0x7fffffffffffffff ){ pC->nextRowidValid = 1; pC->nextRowid = v+1; @@ -2890,6 +2915,7 @@ case OP_NewRecno: { } } if( pC->useRandomRowid ){ + assert( pOp->p2==0 ); /* SQLITE_FULL must have occurred prior to this */ v = db->priorNewRowid; cnt = 0; do{ @@ -3607,15 +3633,24 @@ case OP_IdxIsNull: { ** P2==1 then the table to be clear is in the auxiliary database file ** that is used to store tables create using CREATE TEMPORARY TABLE. ** +** If AUTOVACUUM is enabled then it is possible that another root page +** might be moved into the newly deleted root page in order to keep all +** root pages contiguous at the beginning of the database. The former +** value of the root page that moved - its value before the move occurred - +** is pushed onto the stack. If no page movement was required (because +** the table being dropped was already the last one in the database) then +** a zero is pushed onto the stack. If AUTOVACUUM is disabled at +** then a zero is pushed onto the stack. +** ** See also: Clear */ case OP_Destroy: { int iMoved; rc = sqlite3BtreeDropTable(db->aDb[pOp->p2].pBt, pOp->p1, &iMoved); -#ifndef SQLITE_OMIT_AUTOVACUUM pTos++; pTos->flags = MEM_Int; pTos->i = iMoved; +#ifndef SQLITE_OMIT_AUTOVACUUM if( iMoved!=0 ){ sqlite3RootPageMoved(&db->aDb[pOp->p2], iMoved, pOp->p1); } @@ -4071,6 +4106,30 @@ case OP_MemLoad: { break; } +#ifndef SQLITE_OMIT_AUTOINCREMENT +/* Opcode: MemMax P1 * * +** +** Set the value of memory cell P1 to the maximum of its current value +** and the value on the top of the stack. The stack is unchanged. +** +** This instruction throws an error if the memory cell is not initially +** an integer. +*/ +case OP_MemMax: { + int i = pOp->p1; + Mem *pMem; + assert( pTos>=p->aStack ); + assert( i>=0 && inMem ); + pMem = &p->aMem[i]; + assert( pMem->flags==MEM_Int ); + Integerify(pTos); + if( pMem->ii){ + pMem->i = pTos->i; + } + break; +} +#endif /* SQLITE_OMIT_AUTOINCREMENT */ + /* Opcode: MemIncr P1 P2 * ** ** Increment the integer valued memory cell P1 by 1. If P2 is not zero