]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Autoincrement code installed. Simple smoke-testing only. No regression
authordrh <drh@noemail.net>
Fri, 12 Nov 2004 03:56:15 +0000 (03:56 +0000)
committerdrh <drh@noemail.net>
Fri, 12 Nov 2004 03:56:15 +0000 (03:56 +0000)
tests developed yet. (CVS 2091)

FossilOrigin-Name: 8fde833c812b91c5a574208a70b5f92b9d4b0a87

manifest
manifest.uuid
src/build.c
src/expr.c
src/insert.c
src/parse.y
src/sqliteInt.h
src/tokenize.c
src/vdbe.c

index b8be8edcb974e2c4a6b7bc88559543f94635a8c2..75021c5d0837ea42a957f636c1f5fad3c9b85462 100644 (file)
--- 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
index bfd84589edcca1934bcc63719a83580344cf8909..9a2824f59e42a66a6b391baba1ef0e86df775085 100644 (file)
@@ -1 +1 @@
-60fb0cef093b9827ac2d36b8a94e37f4b79dd2ea
\ No newline at end of file
+8fde833c812b91c5a574208a70b5f92b9d4b0a87
\ No newline at end of file
index 9dc6db201431033d49dc049fa770b2fe830ac2e6..ead40ec42ac054d8148342a2d89d2b7e7ad5d9b0 100644 (file)
@@ -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 <ctype.h>
@@ -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; i<db->nDb; 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);
 
index ea6054e44f4543651c02d2e494ff9ac394517f90..7567d849d558f4b8945d80606105898b01acd632 100644 (file)
@@ -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 <ctype.h>
@@ -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;
 }
 
index 209198180c20ccfab98348b7ea66ebf153d0b0ab..a701e1bf6694e99b069a5bfd281c29f566248738 100644 (file)
@@ -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->iDb<db->nDb );
-  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
index 7225257e593235c43ea184c828a20144853c6a78..c8ebc76e1c73807fccc61fafbfa41bb65a8b50de 100644 (file)
@@ -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*}
index c780b190e3ae0eb39a5c9064c7f9be093ea83f3e..50f7f61a41cafbd4f1c59b5033f53b784ca8a158 100644 (file)
@@ -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
index 46dcc76338a7479e875412fd8c6b5a5fffc90abb..9cda93948aa6986cdcf690bde5722f3af163b27a 100644 (file)
@@ -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;
   }
index b00d410e51b5b2b69db43b8f3a6a6f39ee600674..0f4210e3c0fbd18861897457cb3faf0e503a3877 100644 (file)
@@ -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.