]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add a new column in the SQLITE_MASTER table to record the root page
authordrh <drh@noemail.net>
Mon, 17 Sep 2001 20:25:58 +0000 (20:25 +0000)
committerdrh <drh@noemail.net>
Mon, 17 Sep 2001 20:25:58 +0000 (20:25 +0000)
number of primary key indices. (CVS 252)

FossilOrigin-Name: 602ea4f9f641070592c788ce22859b849739b42e

Makefile.in
manifest
manifest.uuid
src/build.c
src/main.c
src/os.c [new file with mode: 0644]
src/os.h [new file with mode: 0644]
src/sqliteInt.h
test/index.test

index 68b8a3be09fa371632142e593891e7fb624b6ad3..912b905ebe9de9b2c365a8c713f0816a9f6c25fe 100644 (file)
@@ -74,6 +74,7 @@ SRC = \
   $(TOP)/src/expr.c \
   $(TOP)/src/insert.c \
   $(TOP)/src/main.c \
+  $(TOP)/src/os.c \
   $(TOP)/src/pager.c \
   $(TOP)/src/pager.h \
   $(TOP)/src/parse.y \
index b3776fe0e47b9887a2c7492cb8d12d2c10a66541..2a055b3cce21fceed15f67e287ae5da2b5f7f3f7 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,6 +1,6 @@
-C Version\sto\s2.0.0\s(CVS\s251)
-D 2001-09-16T13:36:41
-F Makefile.in 81e1c96b0d148042d851b40cbd3e26ecc5472aa6
+C Add\sa\snew\scolumn\sin\sthe\sSQLITE_MASTER\stable\sto\srecord\sthe\sroot\spage\nnumber\sof\sprimary\skey\sindices.\s(CVS\s252)
+D 2001-09-17T20:25:58
+F Makefile.in a7053596881af6f2590a816ad4eb8fbbf20724a7
 F README 51f6a4e7408b34afa5bc1c0485f61b6a4efb6958
 F VERSION 3861a21803fcd9eb92a403027b0da2bb7add4de1
 F configure aad857a97ca28a584228869186eb4cd7dbebbb3a x
@@ -10,12 +10,14 @@ F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac
 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
 F src/btree.c 39da79b5a656870aa3ab72d40374fb38bd1bd12d
 F src/btree.h fcb08daab59fd81023204ac71955233e218443c2
-F src/build.c c311b8d11bfd44a9b260c1a53946e2e091138e23
+F src/build.c 072d6cf5b894c47d3fb8c11580eaa1a24528bca8
 F src/delete.c ca7ca9bf8b613730821c4a755030d1a020b5e067
 F src/expr.c 343a515a4abaf60e9e26c7412aa8c43fd3eae97d
 F src/insert.c b34860ea58525754f18bde652f74161295ca2455
-F src/main.c 1523c790c243f886271e0c45eaa487951793cd46
+F src/main.c 71ca839b90869c8c13db52fd08b0d0e80dae3288
 F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
+F src/os.c 2e0daeca8a8c75f122d41f894698f5e1b258b69c
+F src/os.h 3b21772e76df0f3998c5a968a2a0d23b9d4551fe
 F src/pager.c 3871a5d34808b703e2d8ae2799fda208aa204051
 F src/pager.h a0d4c5ae271914aa07b62aee0707997d6932b6ca
 F src/parse.y 2bcf47bb8e6afd8bc10aebd555fa07b73905bee4
@@ -25,7 +27,7 @@ F src/select.c 7d90a6464906419fde96c0707a4cf4f3280db318
 F src/shell.c 8e573138074e0b9526fca59b3eac22bdf18ecc03
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in 689401a6cfb4c2344e67d80fa6bb0d74c87e6e31
-F src/sqliteInt.h 2e118ca917aa1b91932f9b9b6f36128218c73963
+F src/sqliteInt.h 667126497697d58a114d9db492f38c99eadb36d7
 F src/table.c abd0adbe0fee39d995287b3bcccd908d174dfcac
 F src/tclsqlite.c 04a35d04f06046acc3944121dc6c36717f7f36d5
 F src/test1.c 3892caa5372789a6d17329dd595724e1f06cb6de
@@ -45,7 +47,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 9a03f1944916b0583486f87c60571f2dee2b5d29
+F test/index.test e43e952b482c2afe938f1f31b71e2b33d43893a9
 F test/insert.test a5c122aa726f1cef6f07d6767e8fd6f220994c11
 F test/insert2.test 252d7130d8cc20f649b31a4f503cd87e660abda8
 F test/lock.test 5b4d969ab92c88f8dc10d1b870a2e5fe51ee7f5f
@@ -93,7 +95,7 @@ F www/opcode.tcl cb3a1abf8b7b9be9f3a228d097d6bf8b742c2b6f
 F www/sqlite.tcl cb0d23d8f061a80543928755ec7775da6e4f362f
 F www/tclsqlite.tcl 06f81c401f79a04f2c5ebfb97e7c176225c0aef2
 F www/vdbe.tcl 0c8aaa529dd216ccbf7daaabd80985e413d5f9ad
-P 4e926efe2b59adfec4086eb1d2ba830238facb4c
-R b664d11dd53bb094e12afd54030b7627
+P c67f6db681784f8511ccf208cde1c29d9ee73742
+R ec078dd1e4ad61f2004b7bba1a6425b5
 U drh
-Z ae4e84a6e126186214dee2d7ef388846
+Z 211dfb1506c70a3bba4b90be9db7543f
index 101fc59c9599a8d5bc1f1c8e4d93032c91a4d747..d6ba36ff653c3fe6b838f9248dcfcab147bf9109 100644 (file)
@@ -1 +1 @@
-c67f6db681784f8511ccf208cde1c29d9ee73742
\ No newline at end of file
+602ea4f9f641070592c788ce22859b849739b42e
\ No newline at end of file
index b6a5074ec57305bd1ddbd4af0153a03e5a7a8bbd..cb93215d09efbc42587f598a50ffd55df25a45e7 100644 (file)
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.36 2001/09/16 00:13:26 drh Exp $
+** $Id: build.c,v 1.37 2001/09/17 20:25:58 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -504,50 +504,59 @@ void sqliteEndTable(Parse *pParse, Token *pEnd){
 
   /* If the initFlag is 1 it means we are reading the SQL off the
   ** "sqlite_master" table on the disk.  So do not write to the disk
-  ** again.  Extract the table number from the pParse->newTnum field.
+  ** again.  Extract the root page number for the table from the 
+  ** pParse->newTnum field.  (The page number should have been put
+  ** there by the sqliteOpenCb routine.)  If the table has a primary
+  ** key, the root page of the index associated with the primary key
+  ** should be in pParse->newKnum.
   */
   if( pParse->initFlag ){
     p->tnum = pParse->newTnum;
+    if( p->pIndex ){
+      p->pIndex->tnum = pParse->newKnum;
+    }
   }
 
-  /* If not initializing, then create the table on disk.
+  /* If not initializing, then create a record for the new table
+  ** in the SQLITE_MASTER table of the database.
   */
   if( !pParse->initFlag ){
-    static VdbeOp addTable[] = {
-      { OP_Open,        0, 2, MASTER_NAME},
-      { OP_NewRecno,    0, 0, 0},
-      { OP_String,      0, 0, "table"     },
-      { OP_String,      0, 0, 0},            /* 3 */
-      { OP_CreateTable, 0, 0, 0},
-      { OP_String,      0, 0, 0},            /* 5 */
-      { OP_String,      0, 0, 0},            /* 6 */
-      { OP_MakeRecord,  5, 0, 0},
-      { OP_Put,         0, 0, 0},
-      { OP_SetCookie,   0, 0, 0},            /* 9 */
-    };
     int n, base;
     Vdbe *v;
 
     v = sqliteGetVdbe(pParse);
     if( v==0 ) return;
     n = (int)pEnd->z - (int)pParse->sFirstToken.z + 1;
-    base = sqliteVdbeAddOpList(v, ArraySize(addTable), addTable);
-    sqliteVdbeChangeP3(v, base+3, p->zName, 0);
+    sqliteVdbeAddOp(v, OP_Open, 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);
-    sqliteVdbeChangeP3(v, base+5, p->zName, 0);
-    sqliteVdbeChangeP3(v, base+6, pParse->sFirstToken.z, n);
-    changeCookie(db);
-    sqliteVdbeChangeP1(v, base+9, db->next_cookie);
-    sqliteVdbeAddOp(v, OP_Close, 0, 0, 0, 0);
     if( p->pIndex ){
       /* If the table has a primary key, create an index in the database
-      ** for that key. */
+      ** 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);
+    sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 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);
     }
@@ -604,7 +613,7 @@ void sqliteDropTable(Parse *pParse, Token *pName){
       { OP_String,     0, 0,        0}, /* 2 */
       { OP_Next,       0, ADDR(9),  0}, /* 3 */
       { OP_Dup,        0, 0,        0},
-      { OP_Column,     0, 3,        0},
+      { OP_Column,     0, 2,        0},
       { OP_Ne,         0, ADDR(3),  0},
       { OP_Delete,     0, 0,        0},
       { OP_Goto,       0, ADDR(3),  0},
@@ -672,8 +681,10 @@ void sqliteCreateIndex(
   ** Find the table that is to be indexed.  Return early if not found.
   */
   if( pTable!=0 ){
+    assert( pName!=0 );
     pTab =  sqliteTableFromToken(pParse, pTable);
   }else{
+    assert( pName==0 );
     pTab =  pParse->pNewTable;
   }
   if( pTab==0 || pParse->nErr ) goto exit_create_index;
@@ -686,26 +697,29 @@ void sqliteCreateIndex(
 
   /*
   ** Find the name of the index.  Make sure there is not already another
-  ** index or table with the same name.
+  ** 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.
   */
   if( pName ){
     zName = sqliteTableNameFromToken(pName);
+    if( zName==0 ) goto exit_create_index;
+    if( sqliteFindIndex(db, zName) ){
+      sqliteSetString(&pParse->zErrMsg, "index ", zName, 
+         " already exists", 0);
+      pParse->nErr++;
+      goto exit_create_index;
+    }
+    if( sqliteFindTable(db, zName) ){
+      sqliteSetString(&pParse->zErrMsg, "there is already a table named ",
+         zName, 0);
+      pParse->nErr++;
+      goto exit_create_index;
+    }
   }else{
     zName = 0;
-    sqliteSetString(&zName, pTab->zName, "__primary_key", 0);
-  }
-  if( zName==0 ) goto exit_create_index;
-  if( sqliteFindIndex(db, zName) ){
-    sqliteSetString(&pParse->zErrMsg, "index ", zName, 
-       " already exists", 0);
-    pParse->nErr++;
-    goto exit_create_index;
-  }
-  if( sqliteFindTable(db, zName) ){
-    sqliteSetString(&pParse->zErrMsg, "there is already a table named ",
-       zName, 0);
-    pParse->nErr++;
-    goto exit_create_index;
+    sqliteSetString(&zName, pTab->zName, " (primary key)", 0);
+    if( zName==0 ) goto exit_create_index;
   }
 
   /* If pList==0, it means this routine was called to make a primary
@@ -750,12 +764,15 @@ void sqliteCreateIndex(
   }
 
   /* Link the new Index structure to its table and to the other
-  ** in-memory database structures.
+  ** in-memory database structures.  Note that primary key indices
+  ** do not appear in the index hash table.
   */
   if( pParse->explain==0 ){
-    h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH;
-    pIndex->pHash = db->apIdxHash[h];
-    db->apIdxHash[h] = pIndex;
+    if( pName!=0 ){
+      h = sqliteHashNoCase(pIndex->zName, 0) % N_HASH;
+      pIndex->pHash = db->apIdxHash[h];
+      db->apIdxHash[h] = pIndex;
+    }
     pIndex->pNext = pTab->pIndex;
     pTab->pIndex = pIndex;
     db->flags |= SQLITE_InternChanges;
@@ -792,14 +809,15 @@ void sqliteCreateIndex(
       { 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_Open,        1, 0, 0},  /* 6 */
-      { OP_String,      0, 0, 0},  /* 7 */
-      { OP_String,      0, 0, 0},  /* 8 */
-      { OP_MakeRecord,  5, 0, 0},
+      { OP_Open,        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},  /* 11 */
+      { OP_SetCookie,   0, 0, 0},  /* 12 */
       { OP_Close,       2, 0, 0},
     };
     int n;
@@ -818,12 +836,12 @@ void sqliteCreateIndex(
       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+6, pIndex->zName, 0);
-      sqliteVdbeChangeP3(v, base+7, pTab->zName, 0);
-      sqliteVdbeChangeP3(v, base+8, pStart->z, n);
+      sqliteVdbeChangeP3(v, base+7, pIndex->zName, 0);
+      sqliteVdbeChangeP3(v, base+9, pStart->z, n);
       changeCookie(db);
-      sqliteVdbeChangeP1(v, base+11, db->next_cookie);
+      sqliteVdbeChangeP1(v, base+12, db->next_cookie);
     }
     sqliteVdbeAddOp(v, OP_Open, 0, pTab->tnum, pTab->zName, 0);
     lbl1 = sqliteVdbeMakeLabel(v);
index c882abf0cca43f6b20f775b8c559741e6f261296..e109d3fb93036a60b32f055d9625d8f516b9c7c3 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.37 2001/09/16 00:13:27 drh Exp $
+** $Id: main.c,v 1.38 2001/09/17 20:25:58 drh Exp $
 */
 #include "sqliteInt.h"
 #if defined(HAVE_USLEEP) && HAVE_USLEEP
 ** database.  Each callback contains the following information:
 **
 **     argv[0] = "meta" or "table" or "index"
-**     argv[1] = table or index name
-**     argv[2] = root page number for table or index
-**     argv[3] = SQL create statement for the 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
 **
 */
 static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
@@ -36,13 +37,16 @@ static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
   Parse sParse;
   int nErr = 0;
 
-  assert( argc==4 );
+/* TODO: Do some validity checks on all fields.  In particular,
+** make sure fields do not contain NULLs. */
+
+  assert( argc==5 );
   switch( argv[0][0] ){
     case 'm': {  /* Meta information */
       if( strcmp(argv[1],"file-format")==0 ){
-        db->file_format = atoi(argv[3]);
+        db->file_format = atoi(argv[4]);
       }else if( strcmp(argv[1],"schema-cookie")==0 ){
-        db->schema_cookie = atoi(argv[3]);
+        db->schema_cookie = atoi(argv[4]);
         db->next_cookie = db->schema_cookie;
       }
       break;
@@ -53,7 +57,8 @@ static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
       sParse.db = db;
       sParse.initFlag = 1;
       sParse.newTnum = atoi(argv[2]);
-      nErr = sqliteRunParser(&sParse, argv[3], 0);
+      sParse.newKnum = argv[3] ? atoi(argv[3]) : 0;
+      nErr = sqliteRunParser(&sParse, argv[4], 0);
       break;
     }
     default: {
@@ -88,8 +93,9 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
      "CREATE TABLE " MASTER_NAME " (\n"
      "  type text,\n"
      "  name text,\n"
-     "  tnum integer,\n"
      "  tbl_name text,\n"
+     "  tnum integer,\n"
+     "  knum integer,\n"
      "  sql text\n"
      ")"
   ;
@@ -102,8 +108,9 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
   **    CREATE TABLE sqlite_master (
   **        type       text,    --  Either "table" or "index" or "meta"
   **        name       text,    --  Name of table or index
-  **        tnum       integer, --  The integer page number of root page
   **        tbl_name   text,    --  Associated table 
+  **        tnum       integer, --  The integer page number of root page
+  **        knum       integer, --  Root page of primary key, or NULL
   **        sql        text     --  The CREATE statement for this object
   **    );
   **
@@ -131,43 +138,47 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
   static VdbeOp initProg[] = {
     { OP_Open,     0, 2,  0},
     { OP_Rewind,   0, 0,  0},
-    { OP_Next,     0, 12, 0},           /* 2 */
+    { OP_Next,     0, 13, 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, 2,  0},
-    { OP_Column,   0, 4,  0},
-    { OP_Callback, 4, 0,  0},
+    { OP_Column,   0, 3,  0},
+    { OP_Null,     0, 0,  0},
+    { OP_Column,   0, 5,  0},
+    { OP_Callback, 5, 0,  0},
     { OP_Goto,     0, 2,  0},
-    { OP_Rewind,   0, 0,  0},           /* 12 */
-    { OP_Next,     0, 23, 0},           /* 13 */
+    { OP_Rewind,   0, 0,  0},           /* 13 */
+    { OP_Next,     0, 25, 0},           /* 14 */
     { OP_Column,   0, 0,  0},
     { OP_String,   0, 0,  "table"},
-    { OP_Ne,       0, 13, 0},
+    { OP_Ne,       0, 14, 0},
     { OP_Column,   0, 0,  0},
     { OP_Column,   0, 1,  0},
-    { OP_Column,   0, 2,  0},
+    { OP_Column,   0, 3,  0},
     { OP_Column,   0, 4,  0},
-    { 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, 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_Column,   0, 0,  0},
     { OP_String,   0, 0,  "index"},
-    { OP_Ne,       0, 24, 0},
+    { OP_Ne,       0, 26, 0},
     { OP_Column,   0, 0,  0},
     { OP_Column,   0, 1,  0},
-    { OP_Column,   0, 2,  0},
-    { OP_Column,   0, 4,  0},
-    { OP_Callback, 4, 0,  0},
-    { OP_Goto,     0, 24, 0},
-    { OP_String,   0, 0,  "meta"},      /* 34 */
+    { 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_String,   0, 0,  "schema-cookie"},
-    { OP_String,   0, 0,  ""},
+    { OP_Null,     0, 0,  0},
+    { OP_Null,     0, 0,  0},
     { OP_ReadCookie,0,0,  0},
-    { OP_Callback, 4, 0,  0},
+    { OP_Callback, 5, 0,  0},
     { OP_Close,    0, 0,  0},
     { OP_Halt,     0, 0,  0},
   };
@@ -190,13 +201,14 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
   }
   if( rc==SQLITE_OK ){
     Table *pTab;
-    char *azArg[5];
+    char *azArg[6];
     azArg[0] = "table";
     azArg[1] = MASTER_NAME;
     azArg[2] = "2";
-    azArg[3] = master_schema;
-    azArg[4] = 0;
-    sqliteOpenCb(db, 4, azArg, 0);
+    azArg[3] = 0;
+    azArg[4] = master_schema;
+    azArg[5] = 0;
+    sqliteOpenCb(db, 5, azArg, 0);
     pTab = sqliteFindTable(db, MASTER_NAME);
     if( pTab ){
       pTab->readOnly = 1;
diff --git a/src/os.c b/src/os.c
new file mode 100644 (file)
index 0000000..eab3e6a
--- /dev/null
+++ b/src/os.c
@@ -0,0 +1,250 @@
+/*
+** 2001 September 16
+**
+** 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 contains code that is specific to particular operating
+** systems.  The purpose of this file is to provide a uniform abstract
+** on which the rest of SQLite can operate.
+*/
+#include "sqliteInt.h"
+#include "os.h"
+
+#if OS_UNIX
+# include <fcntl.h>
+# include <sys/stat.h>
+# include <unistd.h>
+# include <time.h>
+#endif
+#if OS_WIN
+# include <winbase.h>
+#endif
+
+
+/*
+** Attempt to open a file for both reading and writing.  If that
+** fails, try opening it read-only.  If the file does not exist,
+** try to create it.
+**
+** On success, a handle for the open file is written to *pResult
+** and *pReadonly is set to 0 if the file was opened for reading and
+** writing or 1 if the file was opened read-only.  The function returns
+** SQLITE_OK.
+**
+** On failure, the function returns SQLITE_CANTOPEN and leaves
+** *pResulst and *pReadonly unchanged.
+*/
+int sqliteOsOpenReadWrite(char *zFilename, OsFile *pResult, int *pReadonly){
+#if OS_UNIX
+  int fd = open(zFilename, O_RDWR|O_CREAT, 0644);
+  if( fd<0 ){
+    fd = open(zFilename, O_RDONLY);
+    if( fd<0 ){
+      return SQLITE_CANTOPEN; 
+    }
+    *pReadonly = 1;
+  }else{
+    *pReadonly = 0;
+  }
+  *pResult = fd;
+  return SQLITE_OK;
+#endif
+#if OS_WIN
+  HANDLE h = CreateFile(zFilename,
+     GENERIC_READ | GENERIC_WRITE,
+     FILE_SHARE_READ | FILE_SHARE_WRITE,
+     NULL,
+     OPEN_ALWAYS,
+     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+     NULL
+  );
+  if( h==INVALID_HANDLE_VALUE ){
+    HANDLE h = CreateFile(zFilename,
+       GENERIC_READ,
+       FILE_SHARE_READ,
+       NULL,
+       OPEN_ALWAYS,
+       FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+       NULL
+    );
+    if( h==INVALID_HANDLE_VALUE ){
+      return SQLITE_CANTOPEN;
+    }
+    *pReadonly = 1;
+  }else{
+    *pReadonly = 0;
+  }
+  *pResult = h;
+  return SQLITE_OK;
+#endif
+
+
+/*
+** Attempt to open a new file for exclusive access by this process.
+** The file will be opened for both reading and writing.  To avoid
+** a potential security problem, we do not allow the file to have
+** previously existed.  Nor do we allow the file to be a symbolic
+** link.
+**
+** On success, write the file handle into *pResult and return SQLITE_OK.
+**
+** On failure, return SQLITE_CANTOPEN.
+*/
+int sqliteOsOpenExclusive(char *zFilename, OsFile *pResult){
+#if OS_UNIX
+  struct stat buf;
+  time_t now;
+  int fd;
+  if( access(zFilename, 0)==0 ){
+    return SQLITE_CANTOPEN;
+  }
+#ifndef O_NOFOLLOW
+# define O_NOFOLLOW 0
+#endif
+  fd = open(zFilename, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, 0600);
+  if( fd<0 ){
+    return SQLITE_CANTOPEN;
+  }
+  *pResult = fd;
+  return SQLITE_OK;
+#endif
+#if OS_WIN
+  HANDLE h = CreateFile(zFilename,
+     GENERIC_READ | GENERIC_WRITE,
+     0,
+     NULL,
+     CREATE_ALWAYS,
+     FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+     NULL
+  );
+  if( h==INVALID_HANDLE_VALUE ){
+    return SQLITE_CANTOPEN;
+  }
+  *pResult = h;
+  return SQLITE_OK;
+#endif
+}
+
+/*
+** Create a temporary file name in zBuf.  zBuf must be big enough to
+** hold at least SQLITE_TEMPNAME_SIZE characters.
+*/
+int sqliteOsTempFileName(char *zBuf){
+#if OS_UNIX
+  static const char *azDirs[] = {
+     ".",
+     "/var/tmp",
+     "/usr/tmp",
+     "/tmp",
+  };
+  static char zChars[] =
+    "abcdefghijklmnopqrstuvwxyz"
+    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+    "0123456789";
+  int i, j;
+  struct stat buf;
+  char *zDir = ".";
+  for(i=0; i<sizeof(azDirs)/sizeof(azDirs[0]); i++){
+    if( stat(azDirs[i], &buf) ) continue;
+    if( !S_ISDIR(buf.st_mode) ) continue;
+    if( access(azDirs[i], 07) ) continue;
+    zDir = azDirs[i];
+    break;
+  }
+  do{
+    sprintf(zBuf, "%s/sqlite_", zDir);
+    j = strlen(zBuf);
+    for(i=0; i<15; i++){
+      int n = sqliteRandomByte() % sizeof(zChars);
+      zBuf[j++] = zChars[n];
+    }
+    zBuf[j] = 0;
+  }while( access(zBuf,0)==0 );
+#endif
+#if OS_WIN
+  int i, j;
+  HANDLE h;
+  char zTempPath[SQLITE_TEMPNAME_SIZE];
+  GetTempPath(SQLITE_TEMPNAME_SIZE-30, zTempPath);
+  for(;;){
+    sprintf(zBuf, "%s/sqlite_", zTempPath);
+    j = strlen(zBuf);
+    for(i=0; i<15; i++){
+      int n = sqliteRandomByte() % sizeof(zChars);
+      zBuf[j++] = zChars[n];
+    }
+    zBuf[j] = 0;
+    h = CreateFile(zBuf,
+      GENERIC_READ,
+      0,
+      NULL,
+      OPEN_EXISTING,
+      FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
+      NULL
+    );
+    if( h!=INVALID_FILE_HANDLE ){
+      CloseHandle(h);
+      continue;
+    }
+    break;
+  }
+#endif
+  return SQLITE_OK; 
+}
+
+/*
+** Close a file
+*/
+int sqliteOsClose(OsFile id){
+#if OS_UNIX
+  close(id);
+  return SQLITE_OK;
+#endif
+#if OS_WIN
+  CloseHandle(id);
+  return SQLITE_OK;
+#endif
+}
+
+/*
+** Read data from a file into a buffer
+*/
+
+/*
+** Write data from a buffer into a file
+*/
+/*
+** Move the read/write pointer in a file.
+*/
+/*
+** Make sure all writes to a particular file are committed to disk.
+*/
+/*
+** Truncate an open file to a specified size
+*/
+/*
+** Determine the current size of a file in bytes
+*/
+/*
+** Get a read or write lock on a file.
+*/
+/*
+** Release the read or write lock from a file.
+*/
+/*
+** Get information to seed the random number generator.
+*/
+/*
+** Sleep for a little while.
+*/
+
+
+
+#endif /* OS_WIN */
diff --git a/src/os.h b/src/os.h
new file mode 100644 (file)
index 0000000..b9055ac
--- /dev/null
+++ b/src/os.h
@@ -0,0 +1,50 @@
+/*
+** 2001 September 16
+**
+** 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 header file (together with is companion C source-code file
+** "os.c") attempt to abstract the underlying operating system so that
+** the SQLite library will work on both POSIX and windows systems.
+*/
+#ifndef _SQLITE_OS_H_
+#define _SQLITE_OS_H_
+
+/*
+** A handle for an open file is stored in an OsFile object.
+*/
+#if OS_UNIX
+  typedef int OsFile;
+# define SQLITE_TEMPNAME_SIZE 200
+#endif
+
+#if OS_WIN
+  typedef HANDLE OsFile;
+# define SQLITE_TEMPNAME_SIZE (MAX_PATH+1)
+#endif
+
+int sqliteOsOpenReadWrite(char*, OsFile*, int*);
+int sqliteOsOpenExclusive(char*, OsFile*);
+int sqliteOsTempFileName(char*);
+int sqliteOsClose(OsFile);
+int sqliteOsRead(OsFile, int amt, void*);
+int sqliteOsWrite(OsFile, int amt, void*);
+int sqliteOsSeek(OsFile, int offset);
+int sqliteOsSync(OsFile);
+int sqliteOsTruncate(OsFile, int size);
+int sqliteOsFileSize(OsFile, int *pSize);
+int sqliteOsLock(OsFile, int wrlock);
+int sqliteOsUnlock(OsFile);
+int sqliteOsRandomSeed(int amt, char*);
+int sqliteSleep(int ms);
+
+
+
+#endif /* _SQLITE_OS_H_ */
index 9ba03cb066a9204b93944f18e0ea48682bcfbabd..ba439951c9e00fa4ba238f9e894f01a4a2b1e030 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.51 2001/09/16 00:13:27 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.52 2001/09/17 20:25:58 drh Exp $
 */
 #include "sqlite.h"
 #include "vdbe.h"
@@ -366,6 +366,7 @@ struct Parse {
   int explain;         /* True if the EXPLAIN flag is found on the query */
   int initFlag;        /* True if reparsing CREATE TABLEs */
   int newTnum;         /* Table number to use when reparsing CREATE TABLEs */
+  int newKnum;         /* Primary key number when reparsing CREATE TABLEs */
   int nErr;            /* Number of errors seen */
   int nTab;            /* Number of previously allocated cursors */
   int nMem;            /* Number of memory cells used so far */
index 1da441297416575000a2c1f3b8ecd7bed970791e..b0d385bd15b1792bc3f946ce6c4d2e3520450407 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.12 2001/09/16 00:13:28 drh Exp $
+# $Id: index.test,v 1.13 2001/09/17 20:25:58 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -204,7 +204,7 @@ do_test index-7.2 {
 } {16}
 do_test index-7.3 {
   set code [execsql {EXPLAIN SELECT f1 FROM test1 WHERE f2=65536}]
-  expr {[lsearch $code test1__primary_key]>0}
+  expr {[lsearch $code {test1 (primary key)}]>0}
 } {1}
 do_test index-7.4 {
   execsql {DROP table test1}