From: drh Date: Fri, 12 Nov 2004 03:56:15 +0000 (+0000) Subject: Autoincrement code installed. Simple smoke-testing only. No regression X-Git-Tag: version-3.1.0~167 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=2958a4e6a550b306c3958cbe0e7a8aa5f011718d;p=thirdparty%2Fsqlite.git Autoincrement code installed. Simple smoke-testing only. No regression tests developed yet. (CVS 2091) FossilOrigin-Name: 8fde833c812b91c5a574208a70b5f92b9d4b0a87 --- diff --git a/manifest b/manifest index b8be8edcb9..75021c5d08 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Website\supdates.\s(CVS\s2090) -D 2004-11-11T19:32:40 +C Autoincrement\scode\sinstalled.\s\sSimple\ssmoke-testing\sonly.\s\sNo\sregression\ntests\sdeveloped\syet.\s(CVS\s2091) +D 2004-11-12T03:56:15 F Makefile.in c4d2416860f472a1e3393714d0372074197565df F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -31,14 +31,14 @@ F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689 F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea F src/btree.c 9fd74df65bad768a441afefc3b73174d45b85d5b F src/btree.h 861e40b759a195ba63819740e484390012cf81ab -F src/build.c 27e3cc9e5d5187fa6f23d2e60b76e82c4bc0e7b0 +F src/build.c 6d1687c66138af18e210981465ee342fe36985d3 F src/date.c 4fd4e90b3880dacd67305e96330940dc243ffc10 F src/delete.c f0af21a1ede15524a5edd59fe10ef486283a1ee9 -F src/expr.c 5f9afecf27e048b8f3627b5a9be3136bc1d9bdf1 +F src/expr.c 4ee3e47358c92a919062255b14057a7a8f641e01 F src/func.c 600e506bccf7648df8ad03efb417560d0f7ad4c1 F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5 F src/hash.h 1b0c445e1c89ff2aaad9b4605ba61375af001e84 -F src/insert.c 8bd40dc5a8e470cba5b9b14211fa88ea0350d2fa +F src/insert.c e80b009f9ef2864bbaaaae836286f56125a180f6 F src/legacy.c d58ea507bce885298a2c8c3cbb0f4bff5d47830b F src/main.c c7dc54c62c86cab8b2e2883aef607c179eefa611 F src/md5.c 7ae1c39044b95de2f62e066f47bb1deb880a1070 @@ -54,14 +54,14 @@ F src/os_win.c 9482dfc92f289b68205bb2c9315757c7e3946bfb F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b F src/pager.c ee88fcecb081e3635c281bc09d604e934429e2f5 F src/pager.h 9eba8c53dd91eae7f3f90743b2ee242da02a9862 -F src/parse.y 02e0d88a6d465f6fd5ea79a200a8c23c92a877dc +F src/parse.y 91a01b5f1170a574b4b9f19871b32bd0f00923a9 F src/pragma.c bb1c76dae9911b9312997b353c1e316fa603a0c6 F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 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 701cbd435750eb854032eaa42e9a12499934e6ce +F src/sqliteInt.h 0fdf2b0cf6f2db12c4abefad0f1085268d911f74 F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c 0302e3f42f015d132d1291f3388c06e86c24a008 F src/test1.c e80e070fe794cdc204ec144ce03bd7b27dab4946 @@ -69,13 +69,13 @@ F src/test2.c b11fa244fff02190707dd0879987c37c75e61fc8 F src/test3.c 6f1ec93e13632a004b527049535079eda84c459d F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df F src/test5.c b001fa7f1b9e2dc5c2331de62fc641b5ab2bd7a1 -F src/tokenize.c c48221284e729be067237a8cfd7848fb62ee4a92 +F src/tokenize.c 4dc14256d80d25da622d506bfe3b817153b97032 F src/trigger.c f9a0a8d3a87238de1a934eeb7d0b6b1f13e6a55b F src/update.c 3cc67f6053495152e82a6a48c93ed331218e936e F src/utf.c f4f83acd73389090e32d6589d307fc55d794c7ed F src/util.c 005fdf2d008f3429d081766ad6098fdd86d8d8e6 F src/vacuum.c ecb4a2c6f1ac5cc9b394dc64d3bb14ca650c4f60 -F src/vdbe.c 8bc549adf596ee792facd229ee7f7bfc0b690ad4 +F src/vdbe.c 0fd9437a288b19681856ef3f803bfde6858567f1 F src/vdbe.h 067ca8d6750ba4f69a50284765e5883dee860181 F src/vdbeInt.h 6017100adff362b8dfa37a69e3f1431f084bfa5b F src/vdbeapi.c 3965bf4678ae32c05f73550c1b5be3268f9f3006 @@ -255,7 +255,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25 F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c -P d28d1d68e5104726e6088361dfa7bf2cdd9985c7 -R d5f119c36b99dc5061fef0d1b11f7246 +P 60fb0cef093b9827ac2d36b8a94e37f4b79dd2ea +R ab6b6f9534118088586ec8c53a8170c1 U drh -Z f55195d01ac4ebd4d023505baea63851 +Z 72c9d0289de8ee06d1a20ab843f47f3d diff --git a/manifest.uuid b/manifest.uuid index bfd84589ed..9a2824f59e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -60fb0cef093b9827ac2d36b8a94e37f4b79dd2ea \ No newline at end of file +8fde833c812b91c5a574208a70b5f92b9d4b0a87 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 9dc6db2014..ead40ec42a 100644 --- a/src/build.c +++ b/src/build.c @@ -22,7 +22,7 @@ ** COMMIT ** ROLLBACK ** -** $Id: build.c,v 1.275 2004/11/10 11:55:12 danielk1977 Exp $ +** $Id: build.c,v 1.276 2004/11/12 03:56:15 drh Exp $ */ #include "sqliteInt.h" #include @@ -321,6 +321,7 @@ void sqlite3ResetInternalSchema(sqlite3 *db, int iDb){ sqlite3DeleteTable(db, pTab); } sqlite3HashClear(&temp1); + pDb->pSeqTab = 0; DbClearProperty(db, i, DB_SchemaLoaded); if( iDb>0 ) return; } @@ -517,12 +518,15 @@ void sqlite3OpenMasterTable(Vdbe *v, int iDb){ int findDb(sqlite3 *db, Token *pName){ int i; Db *pDb; + char *zName = sqlite3NameFromToken(pName); + int n = strlen(zName); for(pDb=db->aDb, i=0; inDb; i++, pDb++){ - if( pName->n==strlen(pDb->zName) && - 0==sqlite3StrNICmp(pDb->zName, pName->z, pName->n) ){ + if( n==strlen(pDb->zName) && 0==sqlite3StrICmp(pDb->zName, zName) ){ + sqliteFree(zName); return i; } } + sqliteFree(zName); return -1; } @@ -720,7 +724,6 @@ void sqlite3StartTable( */ #ifndef SQLITE_OMIT_AUTOINCREMENT if( strcmp(zName, "sqlite_sequence")==0 ){ - assert( db->aDb[iDb].pSeqTab==0 ); db->aDb[iDb].pSeqTab = pTable; } #endif @@ -1452,13 +1455,34 @@ void sqlite3EndTable(Parse *pParse, Token *pEnd, Select *pSelect){ zStmt ); sqliteFree(zStmt); + sqlite3ChangeCookie(db, v, p->iDb); + +#ifndef SQLITE_OMIT_AUTOINCREMENT + /* Check to see if we need to create an sqlite_sequence table for + ** keeping track of autoincrement keys. + */ + if( p->autoInc ){ + Db *pDb = &db->aDb[p->iDb]; + if( pDb->pSeqTab==0 ){ + sqlite3NestedParse(pParse, + "CREATE TABLE %Q.sqlite_sequence AS SELECT %Q AS name, 0 AS seq;", + pDb->zName, p->zName + ); + }else{ + sqlite3NestedParse(pParse, + "INSERT INTO %Q.sqlite_sequence VALUES(%Q,0)", + pDb->zName, p->zName + ); + } + } +#endif /* Reparse everything to update our internal data structures */ - sqlite3ChangeCookie(db, v, p->iDb); sqlite3VdbeOp3(v, OP_ParseSchema, p->iDb, 0, sqlite3MPrintf("tbl_name='%q'",p->zName), P3_DYNAMIC); } + /* Add the table to the in-memory representation of the database. */ if( db->init.busy && pParse->nErr==0 ){ @@ -1807,7 +1831,9 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){ v = sqlite3GetVdbe(pParse); if( v ){ Trigger *pTrigger; - sqlite3BeginWriteOperation(pParse, 0, pTab->iDb); + int iDb = pTab->iDb; + Db *pDb = &db->aDb[iDb]; + sqlite3BeginWriteOperation(pParse, 0, iDb); /* Drop all triggers associated with the table being dropped. Code ** is generated to remove entries from sqlite_master and/or @@ -1815,7 +1841,7 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){ */ pTrigger = pTab->pTrigger; while( pTrigger ){ - assert( pTrigger->iDb==pTab->iDb || pTrigger->iDb==1 ); + assert( pTrigger->iDb==iDb || pTrigger->iDb==1 ); sqlite3DropTriggerPtr(pParse, pTrigger, 1); pTrigger = pTrigger->pNext; } @@ -1829,11 +1855,25 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){ */ sqlite3NestedParse(pParse, "DELETE FROM %Q.%s WHERE tbl_name=%Q and type!='trigger'", - db->aDb[pTab->iDb].zName, SCHEMA_TABLE(pTab->iDb), pTab->zName); + pDb->zName, SCHEMA_TABLE(iDb), pTab->zName); if( !isView ){ destroyTable(pParse, pTab); } - sqlite3VdbeOp3(v, OP_DropTable, pTab->iDb, 0, pTab->zName, 0); + +#ifndef SQLITE_OMIT_AUTOINCREMENT + /* Remove any entries of the sqlite_sequence table associated with + ** the table being dropped */ + if( pTab->autoInc ){ + sqlite3NestedParse(pParse, + "DELETE FROM %s.sqlite_sequence WHERE name=%Q", + pDb->zName, pTab->zName + ); + } +#endif + + /* Remove the table entry from SQLite's internal schema + */ + sqlite3VdbeOp3(v, OP_DropTable, iDb, 0, pTab->zName, 0); } sqliteViewResetAll(db, iDb); diff --git a/src/expr.c b/src/expr.c index ea6054e44f..7567d849d5 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.169 2004/11/09 12:44:38 danielk1977 Exp $ +** $Id: expr.c,v 1.170 2004/11/12 03:56:15 drh Exp $ */ #include "sqliteInt.h" #include @@ -202,7 +202,8 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, Token *pToken){ ** When doing a nested parse, you can include terms in an expression ** that look like this: #0 #1 #2 ... These terms refer to elements ** on the stack. "#0" (or just "#") means the top of the stack. -** "#1" means the next down on the stack. And so forth. +** "#1" means the next down on the stack. And so forth. #-1 means +** memory location 0. #-2 means memory location 1. And so forth. ** ** This routine is called by the parser to deal with on of those terms. ** It immediately generates code to store the value in a memory location. @@ -220,9 +221,13 @@ Expr *sqlite3RegisterExpr(Parse *pParse, Token *pToken){ } p = sqlite3Expr(TK_REGISTER, 0, 0, pToken); depth = atoi(&pToken->z[1]); - p->iTable = pParse->nMem++; - sqlite3VdbeAddOp(v, OP_Dup, depth, 0); - sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1); + if( depth>=0 ){ + p->iTable = pParse->nMem++; + sqlite3VdbeAddOp(v, OP_Dup, depth, 0); + sqlite3VdbeAddOp(v, OP_MemStore, p->iTable, 1); + }else{ + p->iTable = -1-depth; + } return p; } diff --git a/src/insert.c b/src/insert.c index 209198180c..a701e1bf66 100644 --- a/src/insert.c +++ b/src/insert.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle INSERT statements in SQLite. ** -** $Id: insert.c,v 1.124 2004/11/09 12:44:38 danielk1977 Exp $ +** $Id: insert.c,v 1.125 2004/11/12 03:56:15 drh Exp $ */ #include "sqliteInt.h" @@ -189,6 +189,8 @@ void sqlite3Insert( int iInsertBlock = 0; /* Address of the subroutine used to insert data */ int iCntMem = 0; /* Memory cell used for the row counter */ int newIdx = -1; /* Cursor for the NEW table */ + Db *pDb; /* The database containing table being inserted into */ + int counterMem = 0; /* Memory cell holding AUTOINCREMENT counter */ #ifndef SQLITE_OMIT_TRIGGER int isView; /* True if attempting to insert into a view */ @@ -210,7 +212,8 @@ void sqlite3Insert( goto insert_cleanup; } assert( pTab->iDbnDb ); - zDb = db->aDb[pTab->iDb].zName; + pDb = &db->aDb[pTab->iDb]; + zDb = pDb->zName; if( sqlite3AuthCheck(pParse, SQLITE_INSERT, pTab->zName, 0, zDb) ){ goto insert_cleanup; } @@ -270,6 +273,21 @@ void sqlite3Insert( newIdx = pParse->nTab++; } +#ifndef SQLITE_OMIT_AUTOINCREMENT + /* If this is an AUTOINCREMENT table, look up the sequence number in the + ** sqlite_sequence table and store it in a memory cell. Create a new + ** sqlite_sequence table entry if one does not already exist. + */ + if( pTab->autoInc ){ + counterMem = ++pParse->nMem; + assert( counterMem>0 ); /* Must be so for OP_NewRecno to work right */ + sqlite3NestedParse(pParse, + "SELECT seq FROM %Q.sqlite_sequence WHERE name=%Q INTO %d", + pDb->zName, pTab->zName, counterMem + ); + } +#endif /* SQLITE_OMIT_AUTOINCREMENT */ + /* Figure out how many columns of data are supplied. If the data ** is coming from a SELECT statement, then this step also generates ** all the code to implement the SELECT statement and invoke a subroutine @@ -545,11 +563,16 @@ void sqlite3Insert( */ sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); - sqlite3VdbeAddOp(v, OP_NewRecno, base, 0); + sqlite3VdbeAddOp(v, OP_NewRecno, base, counterMem); sqlite3VdbeAddOp(v, OP_MustBeInt, 0, 0); }else{ sqlite3VdbeAddOp(v, OP_NewRecno, base, 0); } +#ifndef SQLITE_OMIT_AUTOINCREMENT + if( pTab->autoInc ){ + sqlite3VdbeAddOp(v, OP_MemMax, counterMem, 0); + } +#endif /* SQLITE_OMIT_AUTOINCREMENT */ /* Push onto the stack, data for all columns of the new entry, beginning ** with the first column. @@ -633,6 +656,17 @@ void sqlite3Insert( } } +#ifndef SQLITE_OMIT_AUTOINCREMENT + /* Update the sqlite_sequence table + */ + if( pTab->autoInc ){ + sqlite3NestedParse(pParse, + "UPDATE %Q.sqlite_sequence SET seq=#-%d WHERE name=%Q", + pDb->zName, counterMem+1, pTab->zName + ); + } +#endif + /* ** Return the number of rows inserted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not diff --git a/src/parse.y b/src/parse.y index 7225257e59..c8ebc76e1c 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.152 2004/11/09 16:13:33 danielk1977 Exp $ +** @(#) $Id: parse.y,v 1.153 2004/11/12 03:56:15 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -150,7 +150,7 @@ id(A) ::= ID(X). {A = X;} %ifdef SQLITE_OMIT_COMPOUND_SELECT EXCEPT INTERSECT UNION %endif - REINDEX RENAME AUTOINCR CDATE CTIME CTIMESTAMP ALTER + REINDEX RENAME CDATE CTIME CTIMESTAMP ALTER . // Define operator precedence early so that this is the first occurance @@ -230,8 +230,8 @@ 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;} +autoinc(X) ::= . {X = 0;} +autoinc(X) ::= AUTOINCR. {X = 1;} // The next group of rules parses the arguments to a REFERENCES clause // that determine if the referential integrity checking is deferred or @@ -320,6 +320,21 @@ cmd ::= select(X). { sqlite3SelectDelete(X); } +%ifndef SQLITE_OMIT_AUTOINCREMENT +// The INTO clause after a select only works in nested mode. It causes +// the result of the SELECT to be stored in a memory register of the +// virtual machine. +// +cmd ::= select(X) INTO INTEGER(M). { + if( pParse->nested ){ + sqlite3Select(pParse, X, SRT_Mem, atoi(M.z), 0, 0, 0, 0); + }else{ + sqlite3ErrorMsg(pParse, "near \"INTO\": syntax error"); + } + sqlite3SelectDelete(X); +} +%endif // SQLITE_OMIT_AUTOINCREMENT + %type select {Select*} %destructor select {sqlite3SelectDelete($$);} %type oneselect {Select*} diff --git a/src/sqliteInt.h b/src/sqliteInt.h index c780b190e3..50f7f61a41 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.337 2004/11/10 15:27:38 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.338 2004/11/12 03:56:15 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1457,5 +1457,6 @@ sqlite3_value *sqlite3GetTransientValue(sqlite3*db); extern const unsigned char sqlite3UpperToLower[]; void sqlite3RootPageMoved(Db*, int, int); void sqlite3Reindex(Parse*, Token*, Token*); +void sqlite3NestedParse(Parse*, const char*, ...); #endif diff --git a/src/tokenize.c b/src/tokenize.c index 46dcc76338..9cda93948a 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -15,7 +15,7 @@ ** individual tokens and sends those tokens one-by-one over to the ** parser for analysis. ** -** $Id: tokenize.c,v 1.95 2004/11/05 05:10:29 drh Exp $ +** $Id: tokenize.c,v 1.96 2004/11/12 03:56:15 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -178,7 +178,7 @@ static int sqliteGetToken(const unsigned char *z, int *tokenType){ return 1; } case '#': { - for(i=1; isdigit(z[i]); i++){} + for(i=1; isdigit(z[i]) || (i==1 && z[1]=='-'); i++){} *tokenType = TK_REGISTER; return i; } @@ -409,7 +409,7 @@ abort_parse: pParse->zErrMsg = 0; if( !nErr ) nErr++; } - if( pParse->pVdbe && pParse->nErr>0 ){ + if( pParse->pVdbe && pParse->nErr>0 && pParse->nested==0 ){ sqlite3VdbeDelete(pParse->pVdbe); pParse->pVdbe = 0; } diff --git a/src/vdbe.c b/src/vdbe.c index b00d410e51..0f4210e3c0 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.425 2004/11/10 11:55:13 danielk1977 Exp $ +** $Id: vdbe.c,v 1.426 2004/11/12 03:56:15 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -2822,7 +2822,7 @@ case OP_NotExists: { ** ** 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 +** than this value. When this value reaches its maximum, 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.