]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fixed the support of UNIQUE and PRIMARY KEY. (CVS 268)
authordrh <drh@noemail.net>
Thu, 27 Sep 2001 15:11:53 +0000 (15:11 +0000)
committerdrh <drh@noemail.net>
Thu, 27 Sep 2001 15:11:53 +0000 (15:11 +0000)
FossilOrigin-Name: 116fdad06868acf6aca9e75c2c3497c0511a42c3

13 files changed:
manifest
manifest.uuid
src/build.c
src/main.c
src/parse.y
src/shell.c
src/sqliteInt.h
src/vdbe.c
src/vdbe.h
test/index.test
test/table.test
test/tester.tcl
test/unique.test [new file with mode: 0644]

index f36f581880685f3d9857a464370458c5bb87279b..173f3c521c048f598ae3ef3da53cdb7500bab831 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Added\sbasic\ssupport\sfor\senforcement\sof\sUNIQUE\son\sindices\sand\sprimary\nkeys.\s\sSupport\sfor\saddition\sconstraints\sis\sto\sfollow.\s(CVS\s267)
-D 2001-09-27T03:22:33
+C Fixed\sthe\ssupport\sof\sUNIQUE\sand\sPRIMARY\sKEY.\s(CVS\s268)
+D 2001-09-27T15:11:54
 F Makefile.in fe9d96d6a7b04b3000a24692c2a3761840bbbf97
 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
 F VERSION 17fadc361fb942d644f92116388409c937c9fa79
@@ -10,26 +10,26 @@ F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
 F src/btree.c a4a88dfef2072cedfdac09f3a51b7d70b017b9b4
 F src/btree.h 57d653ef5137b91f2a068aaf71a2905468dd2cb7
-F src/build.c 501c96f8224f1dd6c87c53c1ca7de62c3a98d5bb
+F src/build.c 64a7325c1471087ada81588d6ace6d294b28cd1d
 F src/delete.c 81002d889aae874decf507627207c5d1b3599dc2
 F src/expr.c 343a515a4abaf60e9e26c7412aa8c43fd3eae97d
 F src/hash.c bf36fb4cba114015123b0050f137d2c4553778a1
 F src/hash.h 5f6e7c04c46ed015ab4e01797c2049b4af5b006d
 F src/insert.c 0552c2a4b5fd359e9ed5d1e314d5e89093802c8e
-F src/main.c 00ff61d82189ad23fe2f2e6c355951f514cb1b5c
+F src/main.c 87cabd64c99af66ba95f06a7dcd870eec65d89af
 F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
 F src/os.c 45376582c41dc8829330816d56b8e9e6cd1b7972
 F src/os.h 0f478e2fef5ec1612f94b59b163d4807d4c77d6d
 F src/pager.c 0fe02b63a89d8eebb42ad30529d0c7cc918ecb94
 F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
-F src/parse.y a136e0a24ce434e52c79a7eaa669cf9c8249e4db
+F src/parse.y 7a61488cb52da8b3da094aadb391b42d59a25602
 F src/printf.c b1e22a47be8cdf707815647239991e08e8cb69f9
 F src/random.c 708a23f69f40d6f2ae5ce1a04e6a4055d4a6ecec
 F src/select.c 7d90a6464906419fde96c0707a4cf4f3280db318
-F src/shell.c 8e573138074e0b9526fca59b3eac22bdf18ecc03
+F src/shell.c 977ec6b6479c8b8b6e05323d5026a6f4bd73aa54
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 08151912b382ded315b5c8fc6288d9d7a9332aa4
-F src/sqliteInt.h 35f42e624f11924a56a5501e30a670e1b92f62bb
+F src/sqliteInt.h 3ead85324704b79b2ae6799d6af3e5fd710756d9
 F src/table.c abd0adbe0fee39d995287b3bcccd908d174dfcac
 F src/tclsqlite.c 04a35d04f06046acc3944121dc6c36717f7f36d5
 F src/test1.c e4b31f62ea71963cbae44338acf477a04fc8fc49
@@ -38,8 +38,8 @@ F src/test3.c 4a0d7b882fdae731dbb759f512ad867122452f96
 F src/tokenize.c 2ab07b85fde38d8fa2b4e73417b93e94f9cf8f5f
 F src/update.c 0449af173b5f2f0b26e2f0e4545ee0e0429763cb
 F src/util.c 4da3be37d0fd3c640d2d3033503768afdc8e5387
-F src/vdbe.c d3cf685bd9c823445a4b4a57f7cb01718169f464
-F src/vdbe.h dc1d441494ba560a1ff464e1c56beb8ca03844fc
+F src/vdbe.c 173892798e1698605fafb24d29e26e3a5644ddf5
+F src/vdbe.h c543a58f52fb654c90dd31d0d0c31309f4d838de
 F src/where.c cce952b6a2459ac2296e3432876a4252d2fe3b87
 F test/all.test a2320eb40b462f25bd3e33115b1cabf3791450dd
 F test/bigrow.test a35f2de9948b24e427fb292c35947795efe182d0
@@ -50,7 +50,7 @@ F test/delete.test 5ebb114582457428b3e0e30b21b477fedcb85609
 F test/expr.test b3475005ea19d53bf8c4573fb6e4a4498be5b434
 F test/func.test dfee65686b8ba06071c2f007243a25c96ce82cf2
 F test/in.test 9323681388be301dc73f370b4cd62c5a33f79d1e
-F test/index.test e43e952b482c2afe938f1f31b71e2b33d43893a9
+F test/index.test 6076f29d09a4f26a2efa38b03b8cc338b8662f0e
 F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11
 F test/insert2.test 252d7130d8cc20f649b31a4f503cd87e660abda8
 F test/lock.test a9641cdc282214563a2fb0233735b09cc2fdd8f2
@@ -69,11 +69,12 @@ F test/select4.test 29a2ffb187f3d8b6ca42a0a6b619e9cabe12e228
 F test/select5.test 00a240e3311b6c4ff0f27a252ad33811211fa8d8
 F test/sort.test 462c1161eee1abaa7cc93990e0b34d5fdb70ce19
 F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78
-F test/table.test 52fdca1632580fb638c7b7dd14f4d37ecc09f994
+F test/table.test 3ef4254d62ece31a3872ab11cdaec846f6fa8fd1
 F test/tableapi.test 162840153191a91a7dce6395f2334f9aef713b37
 F test/tclsqlite.test a57bb478d7e9f0b2c927f92e161f391e2896631a
-F test/tester.tcl 957cd92fe8645b829da175d94b7ddb7ea68dac39
+F test/tester.tcl c7ddeebc14cc841abb37134cd5d40c1e3ad367c1
 F test/trans.test 855337b8a178c73c433fcf8ee88e4b2f5efff0d9
+F test/unique.test 23056f0705755bc503ff543e79b79a5c91d35850
 F test/update.test b320ea22899e80b32b4d21c54591eb7a6ba4d6bd
 F test/vacuum.test 8acf8669f3b627e54149b25165b034aa06c2432e
 F test/where.test 43d5ac94da3f3722375307f948884dc79b326a91
@@ -99,7 +100,7 @@ F www/speed.tcl 91b53f9403a62bb322dc1f85a81531309bcfb41c
 F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
 F www/tclsqlite.tcl 13d50723f583888fc80ae1a38247c0ab415066fa
 F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
-P 0e9cfcd53e16f96fc181def1d0b2d0ea7f7df73f
-R d903e186383659ad85dc50397b26ad49
+P 34c42967f3d52dfb65d9f31db4f6995d098ec1f7
+R 738ff05ebc1672d0941631329247a92e
 U drh
-Z 4633481d5649b488b3df47e886de0708
+Z b9a4ce432fac1a7969450da73881d616
index 01640a35211f282144e9b9bde1e5ca8e5858595c..35300e0adc97e7d047555828f2b00ee5fa3babae 100644 (file)
@@ -1 +1 @@
-34c42967f3d52dfb65d9f31db4f6995d098ec1f7
\ No newline at end of file
+116fdad06868acf6aca9e75c2c3497c0511a42c3
\ No newline at end of file
index 84e612ac41d1d4b69bc8abbe6f1fc61a8c060c39..70f0c7e2d3c84fc127070cf40088274056487637 100644 (file)
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.42 2001/09/27 03:22:33 drh Exp $
+** $Id: build.c,v 1.43 2001/09/27 15:11:54 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -343,6 +343,7 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
   Table *pTable;
   char *zName;
   sqlite *db = pParse->db;
+  Vdbe *v;
 
   pParse->sFirstToken = *pStart;
   zName = sqliteTableNameFromToken(pName);
@@ -370,13 +371,13 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName){
   pTable->pIndex = 0;
   if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
   pParse->pNewTable = pTable;
-  if( !pParse->initFlag && (db->flags & SQLITE_InTrans)==0 ){
-    Vdbe *v = sqliteGetVdbe(pParse);
-    if( v ){
+  if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){
+    if( (db->flags & SQLITE_InTrans)==0 ){
       sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
       sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
       pParse->schemaVerified = 1;
     }
+    sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0);
   }
 }
 
@@ -491,47 +492,28 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
   */
   if( pParse->initFlag ){
     p->tnum = pParse->newTnum;
-    if( p->pIndex ){
-      p->pIndex->tnum = pParse->newKnum;
-    }
   }
 
   /* If not initializing, then create a record for the new table
   ** in the SQLITE_MASTER table of the database.
   */
   if( !pParse->initFlag ){
-    int n, base;
+    int n, addr;
     Vdbe *v;
 
     v = sqliteGetVdbe(pParse);
     if( v==0 ) return;
     n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1;
-    sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0);
     sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0);
     sqliteVdbeAddOp(v, OP_String, 0, 0, "table", 0);
     sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0);
     sqliteVdbeAddOp(v, OP_String, 0, 0, p->zName, 0);
-    sqliteVdbeAddOp(v, OP_CreateTable, 0, 0, 0, 0);
-    sqliteVdbeTableRootAddr(v, &p->tnum);
-    if( p->pIndex ){
-      /* If the table has a primary key, create an index in the database
-      ** for that key and record the root page of the index in the "knum"
-      ** column of of the SQLITE_MASTER table.
-      */
-      Index *pIndex = p->pIndex;
-      assert( pIndex->pNext==0 );
-      assert( pIndex->tnum==0 );
-      sqliteVdbeAddOp(v, OP_CreateIndex, 0, 0, 0, 0),
-      sqliteVdbeIndexRootAddr(v, &pIndex->tnum);
-    }else{
-      /* If the table does not have a primary key, the "knum" column is 
-      ** fill with a NULL value.
-      */
-      sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
-    }
-    base = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
-    sqliteVdbeChangeP3(v, base, pParse->sFirstToken.z, n);
-    sqliteVdbeAddOp(v, OP_MakeRecord, 6, 0, 0, 0);
+    addr = sqliteVdbeAddOp(v, OP_CreateTable, 0, 0, 0, 0);
+    sqliteVdbeChangeP3(v, addr, (char *)&p->tnum, -1);
+    p->tnum = 0;
+    addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
+    sqliteVdbeChangeP3(v, addr, pParse->sFirstToken.z, n);
+    sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0);
     sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
     changeCookie(db);
     sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0);
@@ -634,11 +616,13 @@ void sqliteDropTable(Parse *pParse, Token *pName){
 /*
 ** Create a new index for an SQL table.  pIndex is the name of the index 
 ** and pTable is the name of the table that is to be indexed.  Both will 
-** be NULL for a primary key.  In that case, use pParse->pNewTable as the 
-** table to be indexed.
+** be NULL for a primary key or an index that is created to satisfy a
+** UNIQUE constraint.  If pTable and pIndex are NULL, use pParse->pNewTable
+** as the table to be indexed.
 **
 ** pList is a list of columns to be indexed.  pList will be NULL if the
-** most recently added column of the table is labeled as the primary key.
+** most recently added column of the table is the primary key or has
+** the UNIQUE constraint.
 */
 void sqliteCreateIndex(
   Parse *pParse,   /* All information about this parse */
@@ -679,8 +663,8 @@ void sqliteCreateIndex(
   /*
   ** Find the name of the index.  Make sure there is not already another
   ** index or table with the same name.  If pName==0 it means that we are
-  ** dealing with a primary key, which has no name, so this step can be
-  ** skipped.
+  ** dealing with a primary key or UNIQUE constraint.  We have to invent our
+  ** own name.
   */
   if( pName ){
     zName = sqliteTableNameFromToken(pName);
@@ -698,8 +682,13 @@ void sqliteCreateIndex(
       goto exit_create_index;
     }
   }else{
+    char zBuf[30];
+    int n;
+    Index *pLoop;
+    for(pLoop=pTab->pIndex, n=1; pLoop; pLoop=pLoop->pNext, n++){}
+    sprintf(zBuf,"%d)",n);
     zName = 0;
-    sqliteSetString(&zName, pTab->zName, " (primary key)", 0);
+    sqliteSetString(&zName, "(", pTab->zName, " autoindex ", zBuf, 0);
     if( zName==0 ) goto exit_create_index;
   }
 
@@ -746,16 +735,12 @@ void sqliteCreateIndex(
   }
 
   /* Link the new Index structure to its table and to the other
-  ** in-memory database structures.  Note that primary key indices
-  ** do not appear in the index hash table.
+  ** in-memory database structures. 
   */
-  if( pParse->explain==0 ){
-    if( pName!=0 ){
-      char *zName = pIndex->zName;;
-      sqliteHashInsert(&db->idxHash, zName, strlen(zName)+1, pIndex);
-    }
-    pIndex->pNext = pTab->pIndex;
-    pTab->pIndex = pIndex;
+  pIndex->pNext = pTab->pIndex;
+  pTab->pIndex = pIndex;
+  if( !pParse->explain ){
+    sqliteHashInsert(&db->idxHash, pIndex->zName, strlen(zName)+1, pIndex);
     db->flags |= SQLITE_InternChanges;
   }
 
@@ -763,7 +748,7 @@ void sqliteCreateIndex(
   ** "sqlite_master" table on the disk.  So do not write to the disk
   ** again.  Extract the table number from the pParse->newTnum field.
   */
-  if( pParse->initFlag ){
+  if( pParse->initFlag && pTable!=0 ){
     pIndex->tnum = pParse->newTnum;
   }
 
@@ -778,79 +763,75 @@ void sqliteCreateIndex(
   ** we don't want to recreate it.
   **
   ** If pTable==0 it means this index is generated as a primary key
-  ** and those does not have a CREATE INDEX statement to add to the
-  ** master table.  Also, since primary keys are created at the same
-  ** time as tables, the table will be empty so there is no need to
-  ** initialize the index.  Hence, skip all the code generation if
-  ** pTable==0.
+  ** or UNIQUE constraint of a CREATE TABLE statement.  The code generator
+  ** for CREATE TABLE will have already opened cursor 0 for writing to
+  ** the sqlite_master table and will take care of closing that cursor
+  ** for us in the end.  So those steps are skipped when pTable==0
   */
-  else if( pParse->initFlag==0 && pTable!=0 ){
-    static VdbeOp addTable[] = {
-      { OP_OpenWrite,   2, 2, MASTER_NAME},
-      { OP_NewRecno,    2, 0, 0},
-      { OP_String,      0, 0, "index"},
-      { OP_String,      0, 0, 0},  /* 3 */
-      { OP_String,      0, 0, 0},  /* 4 */
-      { OP_CreateIndex, 1, 0, 0},
-      { OP_Dup,         0, 0, 0},
-      { OP_OpenWrite,   1, 0, 0},  /* 7 */
-      { OP_Null,        0, 0, 0},
-      { OP_String,      0, 0, 0},  /* 9 */
-      { OP_MakeRecord,  6, 0, 0},
-      { OP_Put,         2, 0, 0},
-      { OP_SetCookie,   0, 0, 0},  /* 12 */
-      { OP_Close,       2, 0, 0},
-    };
+  else if( pParse->initFlag==0 ){
     int n;
-    Vdbe *v = pParse->pVdbe;
+    Vdbe *v;
     int lbl1, lbl2;
     int i;
+    int addr;
 
     v = sqliteGetVdbe(pParse);
     if( v==0 ) goto exit_create_index;
-    if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){
-      sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
-      sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
-      pParse->schemaVerified = 1;
+    if( pTable!=0 ){
+      if( (db->flags & SQLITE_InTrans)==0 ){
+        sqliteVdbeAddOp(v, OP_Transaction, 0, 0, 0, 0);
+        sqliteVdbeAddOp(v, OP_VerifyCookie, db->schema_cookie, 0, 0, 0);
+        pParse->schemaVerified = 1;
+      }
+      sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2, MASTER_NAME, 0);
+    }
+    sqliteVdbeAddOp(v, OP_NewRecno, 0, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_String, 0, 0, "index", 0);
+    sqliteVdbeAddOp(v, OP_String, 0, 0, pIndex->zName, 0);
+    sqliteVdbeAddOp(v, OP_String, 0, 0, pTab->zName, 0);
+    addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, 0, 0, 0);
+    sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, -1);
+    pIndex->tnum = 0;
+    if( pTable ){
+      sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0, 0, 0);
     }
     if( pStart && pEnd ){
-      int base;
       n = (int)pEnd->z - (int)pStart->z + 1;
-      base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
-      sqliteVdbeChangeP3(v, base+3, pIndex->zName, 0);
-      sqliteVdbeChangeP3(v, base+4, pTab->zName, 0);
-      sqliteVdbeIndexRootAddr(v, &pIndex->tnum);
-      sqliteVdbeChangeP3(v, base+7, pIndex->zName, 0);
-      sqliteVdbeChangeP3(v, base+9, pStart->z, n);
-      changeCookie(db);
-      sqliteVdbeChangeP1(v, base+12, db->next_cookie);
+      addr = sqliteVdbeAddOp(v, OP_String, 0, 0, "", 0);
+      sqliteVdbeChangeP3(v, addr, pStart->z, n);
+    }else{
+      sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
     }
-    sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0);
-    lbl1 = sqliteVdbeMakeLabel(v);
-    lbl2 = sqliteVdbeMakeLabel(v);
-    sqliteVdbeAddOp(v, OP_Rewind, 0, 0, 0, 0);
-    sqliteVdbeAddOp(v, OP_Next, 0, lbl2, 0, lbl1);
-    sqliteVdbeAddOp(v, OP_Recno, 0, 0, 0, 0);
-    for(i=0; i<pIndex->nColumn; i++){
-      sqliteVdbeAddOp(v, OP_Column, 0, pIndex->aiColumn[i], 0, 0);
+    sqliteVdbeAddOp(v, OP_MakeRecord, 5, 0, 0, 0);
+    sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
+    if( pTable ){
+      sqliteVdbeAddOp(v, OP_Open, 2, pTab->tnum, pTab->zName, 0);
+      lbl1 = sqliteVdbeMakeLabel(v);
+      lbl2 = sqliteVdbeMakeLabel(v);
+      sqliteVdbeAddOp(v, OP_Rewind, 2, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_Next, 2, lbl2, 0, lbl1);
+      sqliteVdbeAddOp(v, OP_Recno, 2, 0, 0, 0);
+      for(i=0; i<pIndex->nColumn; i++){
+        sqliteVdbeAddOp(v, OP_Column, 2, pIndex->aiColumn[i], 0, 0);
+      }
+      sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_PutIdx, 1, pIndex->isUnique, 0, 0);
+      sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0);
+      sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2);
+      sqliteVdbeAddOp(v, OP_Close, 2, 0, 0, 0);
     }
-    sqliteVdbeAddOp(v, OP_MakeIdxKey, pIndex->nColumn, 0, 0, 0);
-    sqliteVdbeAddOp(v, OP_PutIdx, 1, pIndex->isUnique, 0, 0);
-    sqliteVdbeAddOp(v, OP_Goto, 0, lbl1, 0, 0);
-    sqliteVdbeAddOp(v, OP_Noop, 0, 0, 0, lbl2);
     sqliteVdbeAddOp(v, OP_Close, 1, 0, 0, 0);
-    sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
-    if( pTable!=0 && (db->flags & SQLITE_InTrans)==0 ){
-      sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
+    if( pTable!=0 ){
+      changeCookie(db);
+      sqliteVdbeAddOp(v, OP_SetCookie, db->next_cookie, 0, 0, 0);
+      sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
+      if( (db->flags & SQLITE_InTrans)==0 ){
+        sqliteVdbeAddOp(v, OP_Commit, 0, 0, 0, 0);
+      }
     }
   }
 
-  /* Reclaim memory on an EXPLAIN call.
-  */
-  if( pParse->explain ){
-    sqliteFree(pIndex);
-  }
-
   /* Clean up before exiting */
 exit_create_index:
   sqliteIdListDelete(pList);
index bfdbaf9ee92b25d189627b39dcd1de3cb2ec3064..5fcc32ccccc3c90bbc182a4db2dfdca282e29eda 100644 (file)
@@ -14,7 +14,7 @@
 ** other files are for internal use by SQLite and should not be
 ** accessed by users of the library.
 **
-** $Id: main.c,v 1.41 2001/09/23 20:17:55 drh Exp $
+** $Id: main.c,v 1.42 2001/09/27 15:11:54 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -26,8 +26,7 @@
 **     argv[0] = "meta" or "table" or "index"
 **     argv[1] = table or index name or meta statement type.
 **     argv[2] = root page number for table or index.  NULL for meta.
-**     argv[3] = root page number of primary key for tables or NULL.
-**     argv[4] = SQL create statement for the table or index
+**     argv[3] = SQL create statement for the table or index
 **
 */
 static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
@@ -38,25 +37,33 @@ static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
 /* TODO: Do some validity checks on all fields.  In particular,
 ** make sure fields do not contain NULLs. */
 
-  assert( argc==5 );
+  assert( argc==4 );
   switch( argv[0][0] ){
     case 'm': {  /* Meta information */
       if( strcmp(argv[1],"file-format")==0 ){
-        db->file_format = atoi(argv[4]);
+        db->file_format = atoi(argv[3]);
       }else if( strcmp(argv[1],"schema-cookie")==0 ){
-        db->schema_cookie = atoi(argv[4]);
+        db->schema_cookie = atoi(argv[3]);
         db->next_cookie = db->schema_cookie;
       }
       break;
     }
     case 'i':
     case 't': {  /* CREATE TABLE  and CREATE INDEX statements */
-      memset(&sParse, 0, sizeof(sParse));
-      sParse.db = db;
-      sParse.initFlag = 1;
-      sParse.newTnum = atoi(argv[2]);
-      sParse.newKnum = argv[3] ? atoi(argv[3]) : 0;
-      nErr = sqliteRunParser(&sParse, argv[4], 0);
+      if( argv[3] && argv[3][0] ){
+        memset(&sParse, 0, sizeof(sParse));
+        sParse.db = db;
+        sParse.initFlag = 1;
+        sParse.newTnum = atoi(argv[2]);
+        nErr = sqliteRunParser(&sParse, argv[3], 0);
+      }else{
+        Index *pIndex = sqliteFindIndex(db, argv[1]);
+        if( pIndex==0 || pIndex->tnum!=0 ){
+          nErr++;
+        }else{
+          pIndex->tnum = atoi(argv[2]);
+        }
+      }
       break;
     }
     default: {
@@ -92,8 +99,7 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
      "  type text,\n"
      "  name text,\n"
      "  tbl_name text,\n"
-     "  tnum integer,\n"
-     "  knum integer,\n"
+     "  rootpage integer,\n"
      "  sql text\n"
      ")"
   ;
@@ -107,8 +113,7 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
   **        type       text,    --  Either "table" or "index" or "meta"
   **        name       text,    --  Name of table or index
   **        tbl_name   text,    --  Associated table 
-  **        tnum       integer, --  The integer page number of root page
-  **        knum       integer, --  Root page of primary key, or NULL
+  **        rootpage   integer, --  The integer page number of root page
   **        sql        text     --  The CREATE statement for this object
   **    );
   **
@@ -136,47 +141,43 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
   static VdbeOp initProg[] = {
     { OP_Open,     0, 2,  0},
     { OP_Rewind,   0, 0,  0},
-    { OP_Next,     0, 13, 0},           /* 2 */
+    { OP_Next,     0, 12, 0},           /* 2 */
     { OP_Column,   0, 0,  0},
     { OP_String,   0, 0,  "meta"},
     { OP_Ne,       0, 2,  0},
     { OP_Column,   0, 0,  0},
     { OP_Column,   0, 1,  0},
     { OP_Column,   0, 3,  0},
-    { OP_Null,     0, 0,  0},
-    { OP_Column,   0, 5,  0},
-    { OP_Callback, 5, 0,  0},
+    { OP_Column,   0, 4,  0},
+    { OP_Callback, 4, 0,  0},
     { OP_Goto,     0, 2,  0},
-    { OP_Rewind,   0, 0,  0},           /* 13 */
-    { OP_Next,     0, 25, 0},           /* 14 */
+    { OP_Rewind,   0, 0,  0},           /* 12 */
+    { OP_Next,     0, 23, 0},           /* 13 */
     { OP_Column,   0, 0,  0},
     { OP_String,   0, 0,  "table"},
-    { OP_Ne,       0, 14, 0},
+    { OP_Ne,       0, 13, 0},
     { OP_Column,   0, 0,  0},
     { OP_Column,   0, 1,  0},
     { OP_Column,   0, 3,  0},
     { OP_Column,   0, 4,  0},
-    { OP_Column,   0, 5,  0},
-    { OP_Callback, 5, 0,  0},
-    { OP_Goto,     0, 14, 0},
-    { OP_Rewind,   0, 0,  0},           /* 25 */
-    { OP_Next,     0, 37, 0},           /* 26 */
+    { OP_Callback, 4, 0,  0},
+    { OP_Goto,     0, 13, 0},
+    { OP_Rewind,   0, 0,  0},           /* 23 */
+    { OP_Next,     0, 34, 0},           /* 24 */
     { OP_Column,   0, 0,  0},
     { OP_String,   0, 0,  "index"},
-    { OP_Ne,       0, 26, 0},
+    { OP_Ne,       0, 24, 0},
     { OP_Column,   0, 0,  0},
     { OP_Column,   0, 1,  0},
     { OP_Column,   0, 3,  0},
-    { OP_Null,     0, 0,  0},
-    { OP_Column,   0, 5,  0},
-    { OP_Callback, 5, 0,  0},
-    { OP_Goto,     0, 26, 0},
-    { OP_String,   0, 0,  "meta"},      /* 37 */
+    { OP_Column,   0, 4,  0},
+    { OP_Callback, 4, 0,  0},
+    { OP_Goto,     0, 24, 0},
+    { OP_String,   0, 0,  "meta"},      /* 34 */
     { OP_String,   0, 0,  "schema-cookie"},
     { OP_Null,     0, 0,  0},
-    { OP_Null,     0, 0,  0},
     { OP_ReadCookie,0,0,  0},
-    { OP_Callback, 5, 0,  0},
+    { OP_Callback, 4, 0,  0},
     { OP_Close,    0, 0,  0},
     { OP_Halt,     0, 0,  0},
   };
@@ -203,10 +204,9 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
     azArg[0] = "table";
     azArg[1] = MASTER_NAME;
     azArg[2] = "2";
-    azArg[3] = 0;
-    azArg[4] = master_schema;
-    azArg[5] = 0;
-    sqliteOpenCb(db, 5, azArg, 0);
+    azArg[3] = master_schema;
+    azArg[4] = 0;
+    sqliteOpenCb(db, 4, azArg, 0);
     pTab = sqliteFindTable(db, MASTER_NAME);
     if( pTab ){
       pTab->readOnly = 1;
index e07054ca5845d7760b227a5510c88d8f0884b7e7..b5519895de7c5d736148643fc8edf3c88e725abb 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.31 2001/09/27 03:22:33 drh Exp $
+** @(#) $Id: parse.y,v 1.32 2001/09/27 15:11:54 drh Exp $
 */
 %token_prefix TK_
 %token_type {Token}
@@ -125,7 +125,7 @@ carg ::= DEFAULT NULL.
 //
 ccons ::= NOT NULL.
 ccons ::= PRIMARY KEY sortorder.     {sqliteCreateIndex(pParse,0,0,0,1,0,0);}
-ccons ::= UNIQUE.
+ccons ::= UNIQUE.                    {sqliteCreateIndex(pParse,0,0,0,1,0,0);}
 ccons ::= CHECK LP expr RP.
 
 // For the time being, the only constraint we care about is the primary
@@ -138,10 +138,10 @@ conslist ::= conslist tcons.
 conslist ::= tcons.
 tcons ::= CONSTRAINT ids.
 tcons ::= PRIMARY KEY LP idxlist(X) RP. {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
-tcons ::= UNIQUE LP idlist RP.
+tcons ::= UNIQUE LP idxlist(X) RP.      {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
 tcons ::= CHECK expr.
-idlist ::= idlist COMMA ids.
-idlist ::= ids.
+// idlist ::= idlist COMMA ids.
+// idlist ::= ids.
 
 // The next command format is dropping tables.
 //
index 59c5f6a0c57ef50713aca9a51cb3ce4789191be5..e93f284e476291c677b4fe5e7fad604a918d17ca 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains code to implement the "sqlite" command line
 ** utility for accessing SQLite databases.
 **
-** $Id: shell.c,v 1.33 2001/09/16 00:13:27 drh Exp $
+** $Id: shell.c,v 1.34 2001/09/27 15:11:54 drh Exp $
 */
 #include <stdlib.h>
 #include <string.h>
@@ -648,6 +648,7 @@ static void do_meta_command(char *zLine, sqlite *db, struct callback_data *p){
                       "  type text,\n"
                       "  name text,\n"
                       "  tbl_name text,\n"
+                      "  rootpage integer,\n"
                       "  sql text\n"
                       ")";
         new_argv[1] = 0;
index 40323e4de837534073e92e0b6af1bc6243c521bc..5d1d7438fb4a13959f72cdf707ce1d318dd62dfa 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.55 2001/09/27 03:22:33 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.56 2001/09/27 15:11:54 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
@@ -444,6 +444,7 @@ void sqliteExprCode(Parse*, Expr*);
 void sqliteExprIfTrue(Parse*, Expr*, int);
 void sqliteExprIfFalse(Parse*, Expr*, int);
 Table *sqliteFindTable(sqlite*,char*);
+Index *sqliteFindIndex(sqlite*,char*);
 void sqliteCopy(Parse*, Token*, Token*, Token*);
 void sqliteVacuum(Parse*, Token*);
 int sqliteGlobCompare(const unsigned char*,const unsigned char*);
index 49a1eb55cd8b30368b09808e8e7bf506656d1291..546b7bf86f5bb92316c48c36a377c116ec62d0d1 100644 (file)
@@ -30,7 +30,7 @@
 ** But other routines are also provided to help in building up
 ** a program instruction by instruction.
 **
-** $Id: vdbe.c,v 1.78 2001/09/27 03:22:34 drh Exp $
+** $Id: vdbe.c,v 1.79 2001/09/27 15:11:54 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -202,8 +202,6 @@ struct Vdbe {
   Agg agg;            /* Aggregate information */
   int nSet;           /* Number of sets allocated */
   Set *aSet;          /* An array of sets */
-  int *pTableRoot;    /* Write root page no. for new tables to this addr */
-  int *pIndexRoot;    /* Write root page no. for new indices to this addr */
   int nFetch;         /* Number of OP_Fetch instructions executed */
 };
 
@@ -226,24 +224,6 @@ void sqliteVdbeTrace(Vdbe *p, FILE *trace){
   p->trace = trace;
 }
 
-/*
-** Cause the next OP_CreateTable or OP_CreateIndex instruction that executes
-** to write the page number of the root page for the new table or index it
-** creates into the memory location *pAddr.
-**
-** The pointer to the place to write the page number is cleared after
-** the OP_Create* statement.  If OP_Create* is executed and the pointer
-** is NULL, an error results.  Hence the address can only be used once.
-** If the root address fields are set but OP_Create* operations never
-** execute, that too is an error.
-*/
-void sqliteVdbeTableRootAddr(Vdbe *p, int *pAddr){
-  p->pTableRoot = pAddr;
-}
-void sqliteVdbeIndexRootAddr(Vdbe *p, int *pAddr){
-  p->pIndexRoot = pAddr;
-}
-
 /*
 ** Add a new instruction to the list of instructions current in the
 ** VDBE.  Return the address of the new instruction.
@@ -288,6 +268,7 @@ int sqliteVdbeAddOp(Vdbe *p, int op, int p1, int p2, const char *p3, int lbl){
   p->aOp[i].p2 = p2;
   if( p3 && p3[0] ){
     p->aOp[i].p3 = sqliteStrDup(p3);
+    p->aOp[i].p3dyn = 1;
   }else{
     p->aOp[i].p3 = 0;
   }
@@ -367,10 +348,28 @@ void sqliteVdbeChangeP1(Vdbe *p, int addr, int val){
 ** This routine is useful when a large program is loaded from a
 ** static array using sqliteVdbeAddOpList but we want to make a
 ** few minor changes to the program.
+**
+** If n>=0 then the P3 operand is dynamic, meaning that a copy of
+** the string is made into memory obtained from sqliteMalloc().
+** A value of n==0 means copy bytes of zP3 up to and including the
+** first null byte.  If n>0 then copy n+1 bytes of zP3.
+**
+** If n<0 then zP3 is assumed to be a pointer to a static string.
+** P3 is made to point directly to this string without any copying.
 */
-void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
+void sqliteVdbeChangeP3(Vdbe *p, int addr, char *zP3, int n){
   if( p && addr>=0 && p->nOp>addr && zP3 ){
-    sqliteSetNString(&p->aOp[addr].p3, zP3, n, 0);
+    Op *pOp = &p->aOp[addr];
+    if( pOp->p3 && pOp->p3dyn ){
+      sqliteFree(pOp->p3);
+    }
+    if( n<0 ){
+      pOp->p3 = zP3;
+      pOp->p3dyn = 0;
+    }else{
+      sqliteSetNString(&p->aOp[addr].p3, zP3, n, 0);
+      pOp->p3dyn = 1;
+    }
   }
 }
 
@@ -384,10 +383,15 @@ void sqliteVdbeChangeP3(Vdbe *p, int addr, const char *zP3, int n){
 ** resolve to be a single actual quote character within the string.
 */
 void sqliteVdbeDequoteP3(Vdbe *p, int addr){
-  char *z;
+  Op *pOp;
   if( addr<0 || addr>=p->nOp ) return;
-  z = p->aOp[addr].p3;
-  if( z ) sqliteDequote(z);
+  pOp = &p->aOp[addr];
+  if( pOp->p3==0 || pOp->p3[0]==0 ) return;
+  if( !pOp->p3dyn ){
+    pOp->p3 = sqliteStrDup(pOp->p3);
+    pOp->p3dyn = 1;
+  }
+  if( pOp->p3 ) sqliteDequote(pOp->p3);
 }
 
 /*
@@ -398,8 +402,14 @@ void sqliteVdbeDequoteP3(Vdbe *p, int addr){
 void sqliteVdbeCompressSpace(Vdbe *p, int addr){
   char *z;
   int i, j;
+  Op *pOp;
   if( addr<0 || addr>=p->nOp ) return;
-  z = p->aOp[addr].p3;
+  pOp = &p->aOp[addr];
+  if( !pOp->p3dyn ){
+    pOp->p3 = sqliteStrDup(pOp->p3);
+    pOp->p3dyn = 1;
+  }
+  z = pOp->p3;
   if( z==0 ) return;
   i = j = 0;
   while( isspace(z[i]) ){ i++; }
@@ -747,8 +757,6 @@ static void Cleanup(Vdbe *p){
   sqliteFree(p->aSet);
   p->aSet = 0;
   p->nSet = 0;
-  p->pTableRoot = 0;
-  p->pIndexRoot = 0;
 }
 
 /*
@@ -763,7 +771,9 @@ void sqliteVdbeDelete(Vdbe *p){
     p->nOp = 0;
   }
   for(i=0; i<p->nOp; i++){
-    sqliteFree(p->aOp[i].p3);
+    if( p->aOp[i].p3dyn ){
+      sqliteFree(p->aOp[i].p3);
+    }
   }
   sqliteFree(p->aOp);
   sqliteFree(p->aLabel);
@@ -2618,7 +2628,7 @@ case OP_BeginIdx: {
     if( Stringify(p, tos) ) goto no_mem;
     if( pCrsr->zKey ) sqliteFree(pCrsr->zKey);
     pCrsr->nKey = aStack[tos].n;
-    pCrsr->zKey = sqliteMalloc( pCrsr->nKey );
+    pCrsr->zKey = sqliteMalloc( pCrsr->nKey+1 );
     if( pCrsr->zKey==0 ) goto no_mem;
     memcpy(pCrsr->zKey, zStack[tos], aStack[tos].n);
     pCrsr->zKey[aStack[tos].n] = 0;
@@ -2774,17 +2784,15 @@ case OP_Clear: {
   break;
 }
 
-/* Opcode: CreateTable * * *
+/* Opcode: CreateTable * * P3
 **
 ** Allocate a new table in the main database file.  Push the page number
 ** for the root page of the new table onto the stack.
 **
-** The root page number is also written to a memory location which has
-** be set up by the parser.  The difference between CreateTable and
-** CreateIndex is that each writes its root page number into a different
-** memory location.  This writing of the page number into a memory location
-** is used by the SQL parser to record the page number in its internal
-** data structures.
+** The root page number is also written to a memory location that P3
+** points to.  This is the mechanism is used to write the root page
+** number into the parser's internal data structures that describe the
+** new table.
 **
 ** See also: CreateIndex
 */
@@ -2792,31 +2800,26 @@ case OP_CreateTable: {
   int i = ++p->tos;
   int pgno;
   VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
-  if( p->pTableRoot==0 ){
-    rc = SQLITE_INTERNAL;
-    goto abort_due_to_error;
-  }
+  assert( pOp->p3!=0 && pOp->p3dyn==0 );
   rc = sqliteBtreeCreateTable(pBt, &pgno);
   if( rc==SQLITE_OK ){
     aStack[i].i = pgno;
     aStack[i].flags = STK_Int;
-    *p->pTableRoot = pgno;
-    p->pTableRoot = 0;
+    *(u32*)pOp->p3 = pgno;
+    pOp->p3 = 0;
   }
   break;
 }
 
-/* Opcode: CreateIndex P1 * *
+/* Opcode: CreateIndex * * P3
 **
 ** Allocate a new Index in the main database file.  Push the page number
 ** for the root page of the new table onto the stack.
 **
-** The root page number is also written to a memory location which has
-** be set up by the parser.  The difference between CreateTable and
-** CreateIndex is that each writes its root page number into a different
-** memory location.  This writing of the page number into a memory location
-** is used by the SQL parser to record the page number in its internal
-** data structures.
+** The root page number is also written to a memory location that P3
+** points to.  This is the mechanism is used to write the root page
+** number into the parser's internal data structures that describe the
+** new index.
 **
 ** See also: CreateTable
 */
@@ -2824,16 +2827,13 @@ case OP_CreateIndex: {
   int i = ++p->tos;
   int pgno;
   VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
-  if( p->pIndexRoot==0 ){
-    rc = SQLITE_INTERNAL;
-    goto abort_due_to_error;
-  }
+  assert( pOp->p3!=0 && pOp->p3dyn==0 );
   rc = sqliteBtreeCreateTable(pBt, &pgno);
   if( rc==SQLITE_OK ){
     aStack[i].i = pgno;
     aStack[i].flags = STK_Int;
-    *p->pIndexRoot = pgno;
-    p->pIndexRoot = 0;
+    *(u32*)pOp->p3 = pgno;
+    pOp->p3 = 0;
   }
   break;
 }
@@ -3865,10 +3865,6 @@ default: {
 
 cleanup:
   Cleanup(p);
-  if( (p->pTableRoot || p->pIndexRoot) && rc==SQLITE_OK ){
-    rc = SQLITE_INTERNAL;
-    sqliteSetString(pzErrMsg, "table or index root page not set", 0);
-  }
   if( rc!=SQLITE_OK ){
     closeAllCursors(p);
     sqliteBtreeRollback(pBt);
index c1975bd172ebb61cbfd8fb5a7fcf51ced5f072cd..211d6ede5b390e55a68916bc1d3fe4c02bacf288 100644 (file)
@@ -15,7 +15,7 @@
 ** or VDBE.  The VDBE implements an abstract machine that runs a
 ** simple program to access and modify the underlying database.
 **
-** $Id: vdbe.h,v 1.24 2001/09/23 02:35:53 drh Exp $
+** $Id: vdbe.h,v 1.25 2001/09/27 15:11:55 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -38,6 +38,7 @@ struct VdbeOp {
   int p1;             /* First operand */
   int p2;             /* Second parameter (often the jump destination) */
   char *p3;           /* Third parameter */
+  int p3dyn;          /* True if p3 is malloced.  False if it is static */
 };
 typedef struct VdbeOp VdbeOp;
 
@@ -187,12 +188,10 @@ typedef struct VdbeOp VdbeOp;
 */
 Vdbe *sqliteVdbeCreate(sqlite*);
 void sqliteVdbeCreateCallback(Vdbe*, int*);
-void sqliteVdbeTableRootAddr(Vdbe*, int*);
-void sqliteVdbeIndexRootAddr(Vdbe*, int*);
 int sqliteVdbeAddOp(Vdbe*,int,int,int,const char*,int);
 int sqliteVdbeAddOpList(Vdbe*, int nOp, VdbeOp const *aOp);
 void sqliteVdbeChangeP1(Vdbe*, int addr, int P1);
-void sqliteVdbeChangeP3(Vdbe*, int addr, const char *zP1, int N);
+void sqliteVdbeChangeP3(Vdbe*, int addr, char *zP1, int N);
 void sqliteVdbeDequoteP3(Vdbe*, int addr);
 int sqliteVdbeMakeLabel(Vdbe*);
 void sqliteVdbeDelete(Vdbe*);
index b0d385bd15b1792bc3f946ce6c4d2e3520450407..f61d42de255a85e279959d3e4ae53faa72660354 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the CREATE INDEX statement.
 #
-# $Id: index.test,v 1.13 2001/09/17 20:25:58 drh Exp $
+# $Id: index.test,v 1.14 2001/09/27 15:11:55 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -203,9 +203,11 @@ do_test index-7.2 {
   execsql {SELECT f1 FROM test1 WHERE f2=65536}
 } {16}
 do_test index-7.3 {
-  set code [execsql {EXPLAIN SELECT f1 FROM test1 WHERE f2=65536}]
-  expr {[lsearch $code {test1 (primary key)}]>0}
-} {1}
+  execsql {
+    SELECT name FROM sqlite_master 
+    WHERE type='index' AND tbl_name='test1'
+  }
+} {{(test1 autoindex 1)}}
 do_test index-7.4 {
   execsql {DROP table test1}
   execsql {SELECT name FROM sqlite_master WHERE type!='meta'}
index 5e06e64b716a5a498f2ae1da900193053bc8a5ff..9c41c1fcc964a94a44509db7275cab370565c458 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this file is testing the CREATE TABLE statement.
 #
-# $Id: table.test,v 1.12 2001/09/16 00:13:28 drh Exp $
+# $Id: table.test,v 1.13 2001/09/27 15:11:55 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -163,7 +163,7 @@ set big_table \
 )}
 do_test table-3.1 {
   execsql $big_table
-  execsql {SELECT sql FROM sqlite_master WHERE type!='meta'}
+  execsql {SELECT sql FROM sqlite_master WHERE type=='table'}
 } \{$big_table\}
 do_test table-3.2 {
   set v [catch {execsql {CREATE TABLE BIG(xyz foo)}} msg]
index 18e887040f8248d23a90b62a7c5b658b34f7bdc6..582c3c00dbd3e3b2e65246310de0650d45302259 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements some common TCL routines used for regression
 # testing the SQLite library
 #
-# $Id: tester.tcl,v 1.19 2001/09/20 01:44:43 drh Exp $
+# $Id: tester.tcl,v 1.20 2001/09/27 15:11:55 drh Exp $
 
 # Make sure tclsqlite was compiled correctly.  Abort now with an
 # error message if not.
@@ -174,6 +174,15 @@ proc execsql {sql {db db}} {
   return [$db eval $sql]
 }
 
+# Execute SQL and catch exceptions.
+#
+proc catchsql {sql {db db}} {
+  # puts "SQL = $sql"
+  set r [catch {$db eval $sql} msg]
+  lappend r $msg
+  return $r
+}
+
 # Another procedure to execute SQL.  This one includes the field
 # names in the returned list.
 #
diff --git a/test/unique.test b/test/unique.test
new file mode 100644 (file)
index 0000000..e2eb697
--- /dev/null
@@ -0,0 +1,33 @@
+# 2001 September 27
+#
+# The author disclaims copyright to this source code.  In place of
+# a legal notice, here is a blessing:
+#
+#    May you do good and not evil.
+#    May you find forgiveness for yourself and forgive others.
+#    May you share freely, never taking more than you give.
+#
+#***********************************************************************
+# This file implements regression tests for SQLite library.  The
+# focus of this file is testing the CREATE UNIQUE INDEX statement,
+# and primary keys, and the UNIQUE constraint on table columns
+#
+# $Id: unique.test,v 1.1 2001/09/27 15:11:55 drh Exp $
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# Try to create a table with two primary keys.
+# (This is allowed in SQLite even that it is not valid SQL)
+#
+do_test unique-1.1 {
+  catchsql {
+    CREATE TABLE t1(
+       a int PRIMARY KEY,
+       b int PRIMARY KEY,
+       c text
+    );
+  }
+} {0 {}}
+
+finish_test