]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Change the SQLITE_MASTER format to version 2 in preparation for adding views. (CVS...
authordrh <drh@noemail.net>
Thu, 21 Feb 2002 12:01:27 +0000 (12:01 +0000)
committerdrh <drh@noemail.net>
Thu, 21 Feb 2002 12:01:27 +0000 (12:01 +0000)
FossilOrigin-Name: b2a9807fed544e83002366149b9a363759338c5d

manifest
manifest.uuid
src/build.c
src/main.c
src/select.c
src/sqliteInt.h
src/tokenize.c
src/vdbe.c
src/vdbe.h
test/table.test
www/changes.tcl

index 3345bc2b98a8eaa7fdc9322abb8870a4dcc4a924..92008934ab4bcf0cf3c9dd4dce721f1c3e469fc2 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Do\snot\sallow\sdot-commands\sto\soccur\sin\sthe\smiddle\sof\sa\sreal\sSQL\scommand.\s(CVS\s385)
-D 2002-02-21T02:25:03
+C Change\sthe\sSQLITE_MASTER\sformat\sto\sversion\s2\sin\spreparation\sfor\sadding\sviews.\s(CVS\s386)
+D 2002-02-21T12:01:27
 F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af
 F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834
 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0
@@ -21,13 +21,13 @@ F sqlite.1 2e2bb0529ef468ade9e4322bd609d0695fb9ded9
 F src/TODO af7f3cab0228e34149cf98e073aa83d45878e7e6
 F src/btree.c 495275fe14f3b718cf2f691dce979d4c0e1f8e5d
 F src/btree.h 8abeabfe6e0b1a990b64fa457592a6482f6674f3
-F src/build.c 088acf87a92b00edda1206ccafac3518660b1b3b
+F src/build.c 4e10d8e61971fe900317d00a98f49dd7ceb27c20
 F src/delete.c f8ad71be53cf18656b6573de65395852fe817f0c
 F src/expr.c 7aff65ea0732b07d36925087ad611019103ad69a
 F src/hash.c 8f7c740ef2eaaa8decfa8751f2be30680b123e46
 F src/hash.h d1ce47900c7325af5e41c4feb4855c4bf2b841e7
 F src/insert.c eae5aa2e9ac68c4d465e71b2ad34bcbb882979cf
-F src/main.c fada622b468c54fb211372f38a27ee636915e2ee
+F src/main.c abc0732d4caa676ff8337f278b01f1f1b57538f5
 F src/md5.c 52f677bfc590e09f71d07d7e327bd59da738d07c
 F src/os.c f6bc9b7ab530346bb7fef2ed39f2f1f214bc14ea
 F src/os.h a17596ecc7f38a228b83ecdb661fb03ce44726d6
@@ -36,22 +36,22 @@ F src/pager.h b28f004e2f5541dc60cc32db01bf80cf4d056283
 F src/parse.y b82278917959eefd05bd08c90e07a4fa5917ea51
 F src/printf.c 300a90554345751f26e1fc0c0333b90a66110a1d
 F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
-F src/select.c 282f37b2fdb9367f0230811e1cf7bba48665fb72
+F src/select.c f0cbfd2d9059e0f33837797ee326fbe964a35f09
 F src/shell.c cbf48bf0ca35c4e0d8a7d2a86f7724f52c525cd7
 F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
 F src/sqlite.h.in f57074c84a2c112a5093ba7a9d9636aa9cacc87c
-F src/sqliteInt.h e19efd5b1c6accfb3418cbb5c0e8c143fc1d18d7
+F src/sqliteInt.h 338cd586b9322105080a2a31122446e504ac1fc4
 F src/table.c c89698bd5bb4b8d14722d6ee7e9be014c383d24a
 F src/tclsqlite.c b9cf346e95291cb4c4f1bf5ac1d77db6b8ad023d
 F src/test1.c 33efd350dca27c52c58c553c04fd3a6a51f13c1f
 F src/test2.c d410dbd8a90faa466c3ab694fa0aa57f5a773aa6
 F src/test3.c 4e52fff8b01f08bd202f7633feda5639b7ba2b5e
 F src/threadtest.c 81f0598e0f031c1bd506af337fdc1b7e8dff263f
-F src/tokenize.c 9e98f94469694a763992860596137e78dbae0cc0
+F src/tokenize.c 777b734f9d06f5a9055b6808e5baec18936a4fd9
 F src/update.c 95459f94a061860bf8e5716b3426a5ba85c79103
 F src/util.c f31f3d6198a0d1296a16f5a6ceec423a932cbbf6
-F src/vdbe.c 18b6e9ed3bcdd76ae74d60a977a6d8a3a1b0f797
-F src/vdbe.h b4d35e159fbb80a74728b4a96e5b789fffce6f57
+F src/vdbe.c 44832d804e109248e9e2abd40daee5f8ac735450
+F src/vdbe.h 002bb8cf884034bea25a9fe901a9c5e9d29bc045
 F src/where.c f79bc3179379b46b131a67ab10713779368dceee
 F test/all.test 7a8a8a7a579ed2bb4d8976d55402f21eacd58049
 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578
@@ -89,7 +89,7 @@ F test/select5.test c2a6c4a003316ee42cbbd689eebef8fdce0db2ac
 F test/select6.test d9fb417d6cab75a072b547ba6303120f327fd6fd
 F test/sort.test 3b996ce7ca385f9cd559944ac0f4027a23aa546b
 F test/subselect.test 335d3dad8d585726c447dfee8d9c4f7383c76b78
-F test/table.test b8be4d3d3ff6b4858516fa274d38075ba06b5004
+F test/table.test 17b0b6eafa3faaee5545b7a94e6c1ff73f0880f3
 F test/tableapi.test 51d0c209aa6b1158cb952ec917c656d4ce66e9e4
 F test/tclsqlite.test ca8dd89b02ab68bd4540163c24551756a69f6783
 F test/temptable.test 0e9934283259a5e637eec756a7eefd6964c0f79b
@@ -110,7 +110,7 @@ F www/arch.fig d5f9752a4dbf242e9cfffffd3f5762b6c63b3bcf
 F www/arch.png 82ef36db1143828a7abc88b1e308a5f55d4336f4
 F www/arch.tcl 72a0c80e9054cc7025a50928d28d9c75c02c2b8b
 F www/c_interface.tcl 63efc40f09e2f0d8fea43d174103248b160fdf0e
-F www/changes.tcl e9ac5ffc030ad355fb5973bc2c68e622c3bc9ae2
+F www/changes.tcl 4aee975940a59d43736cdd4cd352c51e1e6426ba
 F www/conflict.tcl 81dd21f9a679e60aae049e9dd8ab53d59570cda2
 F www/crosscompile.tcl 3622ebbe518927a3854a12de51344673eb2dd060
 F www/download.tcl a6d75b8b117cd33dcb090bef7e80d7556d28ebe0
@@ -125,7 +125,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5
 F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279
 F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49
 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
-P 953928537c350e6c9df157553114c6d9d44712d5
-R 9ed6435fa0cf461ec879e5b28166d8d6
+P ffb00bf36a9a5851ea4a69f9c7dd7ce412553e3b
+R 827e990a5d306ede002baf12f96964e4
 U drh
-Z a1b5da6dd8cc3bb5ba9dca0ec016a36c
+Z 93dfb9234ed5554b3f3a0a3a7b0ddf3a
index 3a0aeeca6b3c242d6c00dc0af9d49b1884f0ea0c..c3c6ccb035c6e524e34b09af3d1f13397b858b6c 100644 (file)
@@ -1 +1 @@
-ffb00bf36a9a5851ea4a69f9c7dd7ce412553e3b
\ No newline at end of file
+b2a9807fed544e83002366149b9a363759338c5d
\ No newline at end of file
index afa4db7e5830ca5d876e3bd0d293991632ec42b7..3b4599c2d3d782e875b7ac274da30a2fe9321145 100644 (file)
@@ -25,7 +25,7 @@
 **     ROLLBACK
 **     PRAGMA
 **
-** $Id: build.c,v 1.77 2002/02/19 13:39:22 drh Exp $
+** $Id: build.c,v 1.78 2002/02/21 12:01:27 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -473,12 +473,25 @@ void sqliteStartTable(Parse *pParse, Token *pStart, Token *pName, int isTemp){
   pTable->isTemp = isTemp;
   if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
   pParse->pNewTable = pTable;
+
+  /* Begin generating the code that will insert the table record into
+  ** the SQLITE_MASTER table.  Note in particular that we must go ahead
+  ** and allocate the record number for the table entry now.  Before any
+  ** PRIMARY KEY or UNIQUE keywords are parsed.  Those keywords will cause
+  ** indices to be created and the table record must come before the 
+  ** indices.  Hence, the record number for the table must be allocated
+  ** now.
+  */
   if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){
     sqliteBeginWriteOperation(pParse);
     if( !isTemp ){
       sqliteVdbeAddOp(v, OP_SetCookie, db->file_format, 1);
       sqliteVdbeAddOp(v, OP_OpenWrite, 0, 2);
       sqliteVdbeChangeP3(v, -1, MASTER_NAME, P3_STATIC);
+      sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
+      sqliteVdbeAddOp(v, OP_Dup, 0, 0);
+      sqliteVdbeAddOp(v, OP_String, 0, 0);
+      sqliteVdbeAddOp(v, OP_PutIntKey, 0, 0);
     }
   }
 }
@@ -657,10 +670,11 @@ static void changeCookie(sqlite *db){
 */
 static int identLength(const char *z){
   int n;
-  for(n=2; *z; n++, z++){
-    if( *z=='\'' ){ n++; }
+  int needQuote = 0;
+  for(n=0; *z; n++, z++){
+    if( *z=='\'' ){ n++; needQuote=1; }
   }
-  return n;
+  return n + needQuote*2;
 }
 
 /*
@@ -668,14 +682,19 @@ static int identLength(const char *z){
 ** quote characters as needed.
 */
 static void identPut(char *z, int *pIdx, char *zIdent){
-  int i, j;
+  int i, j, needQuote;
   i = *pIdx;
-  z[i++] = '\'';
+  for(j=0; zIdent[j]; j++){
+    if( !isalnum(zIdent[j]) && zIdent[j]!='_' ) break;
+  }
+  needQuote =  zIdent[j]!=0 || isdigit(zIdent[0])
+                  || sqliteKeywordCode(zIdent, j)!=TK_ID;
+  if( needQuote ) z[i++] = '\'';
   for(j=0; zIdent[j]; j++){
     z[i++] = zIdent[j];
     if( zIdent[j]=='\'' ) z[i++] = '\'';
   }
-  z[i++] = '\'';
+  if( needQuote ) z[i++] = '\'';
   z[i] = 0;
   *pIdx = i;
 }
@@ -769,6 +788,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
   */
   if( pSelect ){
     Table *pSelTab = sqliteResultSetOfSelect(pParse, 0, pSelect);
+    if( pSelTab==0 ) return;
     assert( p->aCol==0 );
     p->nCol = pSelTab->nCol;
     p->aCol = pSelTab->aCol;
@@ -788,7 +808,8 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
   }
 
   /* If not initializing, then create a record for the new table
-  ** in the SQLITE_MASTER table of the database.
+  ** in the SQLITE_MASTER table of the database.  The record number
+  ** for the new table entry should already be on the stack.
   **
   ** If this is a TEMPORARY table, then just create the table.  Do not
   ** make an entry in SQLITE_MASTER.
@@ -803,7 +824,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
     sqliteVdbeChangeP3(v, addr, (char *)&p->tnum, P3_POINTER);
     p->tnum = 0;
     if( !p->isTemp ){
-      sqliteVdbeAddOp(v, OP_NewRecno, 0, 0);
+      sqliteVdbeAddOp(v, OP_Pull, 1, 0);
       sqliteVdbeAddOp(v, OP_String, 0, 0);
       sqliteVdbeChangeP3(v, -1, "table", P3_STATIC);
       sqliteVdbeAddOp(v, OP_String, 0, 0);
index 553f7468343cf3338adc8cecc2baa2e4a79d7fa5..4969f3551fc36ec8c432d813406c49998020852a 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.60 2002/02/19 22:42:05 drh Exp $
+** $Id: main.c,v 1.61 2002/02/21 12:01:27 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -51,13 +51,14 @@ static int sqliteOpenCb(void *pDb, int argc, char **argv, char **azColName){
       db->next_cookie = db->schema_cookie;
       break;
     }
+    case 'v':
     case 'i':
-    case 't': {  /* CREATE TABLE  and CREATE INDEX statements */
+    case 't': {  /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */
       if( argv[3] && argv[3][0] ){
-        /* Call the parser to process a CREATE TABLE or CREATE INDEX statement.
+        /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
         ** But because sParse.initFlag is set to 1, no VDBE code is generated
         ** or executed.  All the parser does is build the internal data
-        ** structures that describe the table or index.
+        ** structures that describe the table, index, or view.
         */
         memset(&sParse, 0, sizeof(sParse));
         sParse.db = db;
@@ -149,10 +150,15 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
   ** was created to fulfill a PRIMARY KEY or UNIQUE constraint on a table,
   ** then the "sql" column is NULL.
   **
-  ** If the "type" column has the value "meta", then the "sql" column
-  ** contains extra information about the database, such as the
-  ** file format version number.  All meta information must be processed
-  ** before any tables or indices are constructed.
+  ** In format 1, entries in the sqlite_master table are in a random
+  ** order.  Two passes must be made through the table to initialize
+  ** internal data structures.  The first pass reads table definitions
+  ** and the second pass read index definitions.  Having two passes
+  ** insures that indices appear after their tables.
+  **
+  ** In format 2, entries appear in chronological order.  Only a single
+  ** pass needs to be made through the table since everything will be
+  ** in the write order.  VIEWs may only occur in format 2.
   **
   ** The following program invokes its callback on the SQL for each
   ** table then goes back and invokes the callback on the
@@ -161,38 +167,70 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
   ** database scheme.
   */
   static VdbeOp initProg[] = {
+    /* Send the file format to the callback routine
+    */
     { OP_Open,       0, 2,  0},
     { OP_String,     0, 0,  "file-format"},
     { OP_String,     0, 0,  0},
     { OP_String,     0, 0,  0},
     { OP_ReadCookie, 0, 1,  0},
     { OP_Callback,   4, 0,  0},
+
+    /* Send the initial schema cookie to the callback
+    */
     { OP_String,     0, 0,  "schema_cookie"},
     { OP_String,     0, 0,  0},
     { OP_String,     0, 0,  0},
     { OP_ReadCookie, 0, 0,  0},
     { OP_Callback,   4, 0,  0},
-    { OP_Rewind,     0, 31, 0},
-    { OP_Column,     0, 0,  0},           /* 12 */
+
+    /* Check the file format.  If the format number is 2 or more,
+    ** then do a single pass through the SQLITE_MASTER table.  For
+    ** a format number of less than 2, jump forward to a different
+    ** algorithm that makes two passes through the SQLITE_MASTER table,
+    ** once for tables and a second time for indices.
+    */
+    { OP_ReadCookie, 0, 1,  0},
+    { OP_Integer,    2, 0,  0},
+    { OP_Lt,         0, 23, 0},
+
+    /* This is the code for doing a single scan through the SQLITE_MASTER
+    ** table.  This code runs for format 2 and greater.
+    */
+    { OP_Rewind,     0, 21, 0},
+    { OP_Column,     0, 0,  0},           /* 15 */
+    { OP_Column,     0, 1,  0},
+    { OP_Column,     0, 3,  0},
+    { OP_Column,     0, 4,  0},
+    { OP_Callback,   4, 0,  0},
+    { OP_Next,       0, 15, 0},
+    { OP_Close,      0, 0,  0},           /* 21 */
+    { OP_Halt,       0, 0,  0},
+
+    /* This is the code for doing two passes through SQLITE_MASTER.  This
+    ** code runs for file format 1.
+    */
+    { OP_Rewind,     0, 43, 0},           /* 23 */
+    { OP_Column,     0, 0,  0},           /* 24 */
     { OP_String,     0, 0,  "table"},
-    { OP_Ne,         0, 20, 0},
+    { OP_Ne,         0, 32, 0},
     { OP_Column,     0, 0,  0},
     { OP_Column,     0, 1,  0},
     { OP_Column,     0, 3,  0},
     { OP_Column,     0, 4,  0},
     { OP_Callback,   4, 0,  0},
-    { OP_Next,       0, 12, 0},           /* 20 */
-    { OP_Rewind,     0, 31, 0},           /* 21 */
-    { OP_Column,     0, 0,  0},           /* 22 */
+    { OP_Next,       0, 24, 0},           /* 32 */
+    { OP_Rewind,     0, 43, 0},           /* 33 */
+    { OP_Column,     0, 0,  0},           /* 34 */
     { OP_String,     0, 0,  "index"},
-    { OP_Ne,         0, 30, 0},
+    { OP_Ne,         0, 42, 0},
     { OP_Column,     0, 0,  0},
     { OP_Column,     0, 1,  0},
     { OP_Column,     0, 3,  0},
     { OP_Column,     0, 4,  0},
     { OP_Callback,   4, 0,  0},
-    { OP_Next,       0, 22, 0},           /* 30 */
-    { OP_Close,      0, 0,  0},           /* 31 */
+    { OP_Next,       0, 34, 0},           /* 42 */
+    { OP_Close,      0, 0,  0},           /* 43 */
     { OP_Halt,       0, 0,  0},
   };
 
@@ -209,9 +247,9 @@ static int sqliteInit(sqlite *db, char **pzErrMsg){
                       db->pBusyArg, db->xBusyCallback);
   sqliteVdbeDelete(vdbe);
   if( rc==SQLITE_OK && db->nTable==0 ){
-    db->file_format = FILE_FORMAT;
+    db->file_format = 2;
   }
-  if( rc==SQLITE_OK && db->file_format>FILE_FORMAT ){
+  if( rc==SQLITE_OK && db->file_format>2 ){
     sqliteSetString(pzErrMsg, "unsupported file format", 0);
     rc = SQLITE_ERROR;
   }
index ef6cd216e82700eaa8f17029e9ac99550e9efa95..6183275793734792df917dfdb129c9bb30c07ab3 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.63 2002/02/19 22:42:05 drh Exp $
+** $Id: select.c,v 1.64 2002/02/21 12:01:27 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -760,7 +760,10 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
   pTab = p->pSrc->a[0].pTab;
 
   /* If we get to here, it means the query is of the correct form.
-  ** Check to make sure we have an index.
+  ** Check to make sure we have an index and make pIdx point to the
+  ** appropriate index.  If the min() or max() is on an INTEGER PRIMARY
+  ** key column, no index is necessary so set pIdx to NULL.  If no
+  ** usable index is found, return 0.
   */
   if( iCol<0 ){
     pIdx = 0;
@@ -772,7 +775,7 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
     if( pIdx==0 ) return 0;
   }
 
-  /* Identify column names if we will be using in the callback.  This
+  /* Identify column names if we will be using the callback.  This
   ** step is skipped if the output is going to a table or a memory cell.
   */
   v = sqliteGetVdbe(pParse);
@@ -781,7 +784,10 @@ static int simpleMinMaxQuery(Parse *pParse, Select *p, int eDest, int iParm){
     generateColumnNames(pParse, p->pSrc, p->pEList);
   }
 
-  /* Begin generating code
+  /* Generating code to find the min or the max.  Basically all we have
+  ** to do is find the first or the last entry in the chosen index.  If
+  ** the min() or max() is on the INTEGER PRIMARY KEY, then find the first
+  ** or last entry in the main table.
   */
   if( !pParse->schemaVerified && (pParse->db->flags & SQLITE_InTrans)==0 ){
     sqliteVdbeAddOp(v, OP_VerifyCookie, pParse->db->schema_cookie, 0);
index 302a2b4949c7da54abd27ffa260f1336306c0cc7..2eece76f9d032c703f0d5aaf95414b8077c0127b 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.88 2002/02/19 22:42:05 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.89 2002/02/21 12:01:27 drh Exp $
 */
 #include "sqlite.h"
 #include "hash.h"
 #define MAX_PAGES   100
 #define TEMP_PAGES   25
 
-/*
-** File format version number
-*/
-#define FILE_FORMAT 1
-
 /*
 ** Integers of known sizes.  These typedefs might change for architectures
 ** where the sizes very.  Preprocessor macros are available so that the
@@ -555,6 +550,7 @@ void sqliteRealToSortable(double r, char *);
 void sqliteSetString(char **, const char *, ...);
 void sqliteSetNString(char **, ...);
 void sqliteDequote(char*);
+int sqliteKeywordCode(const char*, int);
 int sqliteRunParser(Parse*, const char*, char **);
 void sqliteExec(Parse*);
 Expr *sqliteExpr(int, Expr*, Expr*, Token*);
index 18e23685677ec7cc9c6c99d3009365559ee697b6..cd44b1517e482ce3d202b40fd7613b0c78f0e3e2 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.36 2002/02/17 00:30:36 drh Exp $
+** $Id: tokenize.c,v 1.37 2002/02/21 12:01:27 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -116,7 +116,7 @@ static Keyword *apHashTable[KEY_HASH_SIZE];
 ** keyword.  If it is a keyword, the token code of that keyword is 
 ** returned.  If the input is not a keyword, TK_ID is returned.
 */
-static int sqliteKeywordCode(const char *z, int n){
+int sqliteKeywordCode(const char *z, int n){
   int h;
   Keyword *p;
   if( aKeywordTable[0].len==0 ){
index f9f08850462496dfcff14d452cde565b58fc92b8..acacaa91d3dfbe975352a99e2c7c1effbbf41600 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.120 2002/02/19 22:42:05 drh Exp $
+** $Id: vdbe.c,v 1.121 2002/02/21 12:01:27 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -72,6 +72,7 @@ struct Cursor {
   Bool keyAsData;       /* The OP_Column command works on key instead of data */
   Bool atFirst;         /* True if pointing to first entry */
   Bool useRandomRowid;  /* Generate new record numbers semi-randomly */
+  Bool nullRow;         /* True if pointing to a row with no data */
   Btree *pBt;           /* Separate file holding temporary table */
 };
 typedef struct Cursor Cursor;
@@ -867,30 +868,30 @@ static char *zOpName[] = { 0,
   "Close",             "MoveTo",            "NewRecno",          "PutIntKey",
   "PutStrKey",         "Distinct",          "Found",             "NotFound",
   "IsUnique",          "NotExists",         "Delete",            "Column",
-  "KeyAsData",         "Recno",             "FullKey",           "Last",
-  "Rewind",            "Next",              "Destroy",           "Clear",
-  "CreateIndex",       "CreateTable",       "IntegrityCk",       "IdxPut",
-  "IdxDelete",         "IdxRecno",          "IdxGT",             "IdxGE",
-  "MemLoad",           "MemStore",          "ListWrite",         "ListRewind",
-  "ListRead",          "ListReset",         "SortPut",           "SortMakeRec",
-  "SortMakeKey",       "Sort",              "SortNext",          "SortCallback",
-  "SortReset",         "FileOpen",          "FileRead",          "FileColumn",
-  "AggReset",          "AggFocus",          "AggIncr",           "AggNext",
-  "AggSet",            "AggGet",            "SetInsert",         "SetFound",
-  "SetNotFound",       "MakeRecord",        "MakeKey",           "MakeIdxKey",
-  "IncrKey",           "Goto",              "If",                "Halt",
-  "ColumnCount",       "ColumnName",        "Callback",          "NullCallback",
-  "Integer",           "String",            "Pop",               "Dup",
-  "Pull",              "Push",              "MustBeInt",         "Add",
-  "AddImm",            "Subtract",          "Multiply",          "Divide",
-  "Remainder",         "BitAnd",            "BitOr",             "BitNot",
-  "ShiftLeft",         "ShiftRight",        "AbsValue",          "Precision",
-  "Min",               "Max",               "Like",              "Glob",
-  "Eq",                "Ne",                "Lt",                "Le",
-  "Gt",                "Ge",                "IsNull",            "NotNull",
-  "Negative",          "And",               "Or",                "Not",
-  "Concat",            "Noop",              "Strlen",            "Substr",
-  "Limit",           
+  "KeyAsData",         "Recno",             "FullKey",           "NullRow",
+  "Last",              "Rewind",            "Next",              "Destroy",
+  "Clear",             "CreateIndex",       "CreateTable",       "IntegrityCk",
+  "IdxPut",            "IdxDelete",         "IdxRecno",          "IdxGT",
+  "IdxGE",             "MemLoad",           "MemStore",          "ListWrite",
+  "ListRewind",        "ListRead",          "ListReset",         "SortPut",
+  "SortMakeRec",       "SortMakeKey",       "Sort",              "SortNext",
+  "SortCallback",      "SortReset",         "FileOpen",          "FileRead",
+  "FileColumn",        "AggReset",          "AggFocus",          "AggIncr",
+  "AggNext",           "AggSet",            "AggGet",            "SetInsert",
+  "SetFound",          "SetNotFound",       "MakeRecord",        "MakeKey",
+  "MakeIdxKey",        "IncrKey",           "Goto",              "If",
+  "Halt",              "ColumnCount",       "ColumnName",        "Callback",
+  "NullCallback",      "Integer",           "String",            "Pop",
+  "Dup",               "Pull",              "Push",              "MustBeInt",
+  "Add",               "AddImm",            "Subtract",          "Multiply",
+  "Divide",            "Remainder",         "BitAnd",            "BitOr",
+  "BitNot",            "ShiftLeft",         "ShiftRight",        "AbsValue",
+  "Precision",         "Min",               "Max",               "Like",
+  "Glob",              "Eq",                "Ne",                "Lt",
+  "Le",                "Gt",                "Ge",                "IsNull",
+  "NotNull",           "Negative",          "And",               "Or",
+  "Not",               "Concat",            "Noop",              "Strlen",
+  "Substr",            "Limit",           
 };
 
 /*
@@ -2591,6 +2592,7 @@ case OP_Open: {
   }
   cleanupCursor(&p->aCsr[i]);
   memset(&p->aCsr[i], 0, sizeof(Cursor));
+  p->aCsr[i].nullRow = 1;
   do{
     rc = sqliteBtreeCursor(pX, p2, wrFlag, &p->aCsr[i].pCursor);
     switch( rc ){
@@ -2648,6 +2650,7 @@ case OP_OpenTemp: {
   pCx = &p->aCsr[i];
   cleanupCursor(pCx);
   memset(pCx, 0, sizeof(*pCx));
+  pCx->nullRow = 1;
   rc = sqliteBtreeOpen(0, 0, TEMP_PAGES, &pCx->pBt);
   if( rc==SQLITE_OK ){
     rc = sqliteBtreeBeginTrans(pCx->pBt);
@@ -2708,6 +2711,7 @@ case OP_MoveTo: {
       sqliteBtreeMoveto(pC->pCursor, zStack[tos], aStack[tos].n, &res);
       pC->recnoIsValid = 0;
     }
+    pC->nullRow = 0;
     sqlite_search_count++;
     if( res<0 ){
       sqliteBtreeNext(pC->pCursor, &res);
@@ -2892,8 +2896,12 @@ case OP_NotExists: {
     assert( aStack[tos].flags & STK_Int );
     iKey = intToKey(aStack[tos].i);
     rx = sqliteBtreeMoveto(pCrsr, (char*)&iKey, sizeof(int), &res);
+    p->aCsr[i].lastRecno = aStack[tos].i;
+    p->aCsr[i].recnoIsValid = res==0;
+    p->aCsr[i].nullRow = 0;
     if( rx!=SQLITE_OK || res!=0 ){
-       pc = pOp->p2 - 1;
+      pc = pOp->p2 - 1;
+      p->aCsr[i].recnoIsValid = 0;
     }
   }
   POPSTACK;
@@ -2982,6 +2990,7 @@ case OP_NewRecno: {
         goto abort_due_to_error;
       }
     }
+    pC->recnoIsValid = 0;
   }
   VERIFY( NeedStack(p, p->tos+1); )
   p->tos++;
@@ -3044,6 +3053,7 @@ case OP_PutStrKey: {
     }
     rc = sqliteBtreeInsert(p->aCsr[i].pCursor, zKey, nKey,
                         zStack[tos], aStack[tos].n);
+    p->aCsr[i].recnoIsValid = 0;
   }
   POPSTACK;
   POPSTACK;
@@ -3113,7 +3123,9 @@ case OP_Column: {
     ** is coming from the key or the data of the record.
     */
     pCrsr = pC->pCursor;
-    if( pC->keyAsData ){
+    if( pC->nullRow ){
+      payloadSize = 0;
+    }else if( pC->keyAsData ){
       sqliteBtreeKeySize(pCrsr, &payloadSize);
       xRead = sqliteBtreeKey;
     }else{
@@ -3199,6 +3211,9 @@ case OP_Recno: {
     int v;
     if( p->aCsr[i].recnoIsValid ){
       v = p->aCsr[i].lastRecno;
+    }else if( p->aCsr[i].nullRow ){
+      aStack[tos].flags = STK_Null;
+      break;
     }else{
       sqliteBtreeKey(pCrsr, 0, sizeof(u32), (char*)&v);
       v = keyToInt(v);
@@ -3248,6 +3263,22 @@ case OP_FullKey: {
   break;
 }
 
+/* Opcode: NullRow P1 * *
+**
+** Move the cursor P1 to a null row.  Any OP_Column operations
+** that occur while the cursor is on the null row will always push 
+** a NULL onto the stack.
+*/
+case OP_NullRow: {
+  int i = pOp->p1;
+  BtCursor *pCrsr;
+
+  if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
+    p->aCsr[i].nullRow = 1;
+  }
+  break;
+}
+
 /* Opcode: Last P1 P2 *
 **
 ** The next use of the Recno or Column or Next instruction for P1 
@@ -3263,7 +3294,7 @@ case OP_Last: {
   if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
     int res;
     sqliteBtreeLast(pCrsr, &res);
-    p->aCsr[i].atFirst = res==0;
+    p->aCsr[i].nullRow = res;
     if( res && pOp->p2>0 ){
       pc = pOp->p2 - 1;
     }
@@ -3287,6 +3318,7 @@ case OP_Rewind: {
     int res;
     sqliteBtreeFirst(pCrsr, &res);
     p->aCsr[i].atFirst = res==0;
+    p->aCsr[i].nullRow = res;
     if( res && pOp->p2>0 ){
       pc = pOp->p2 - 1;
     }
@@ -3308,6 +3340,7 @@ case OP_Next: {
   if( VERIFY( i>=0 && i<p->nCursor && ) (pCrsr = p->aCsr[i].pCursor)!=0 ){
     int res;
     rc = sqliteBtreeNext(pCrsr, &res);
+    p->aCsr[i].nullRow = res;
     if( res==0 ){
       pc = pOp->p2 - 1;
       sqlite_search_count++;
index 2f10d591f8660f871469c608fd1df0835ddacbcf..4bde7b342cbb7ba856b351169ae2904ae0044112 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.43 2002/02/19 15:00:08 drh Exp $
+** $Id: vdbe.h,v 1.44 2002/02/21 12:01:28 drh Exp $
 */
 #ifndef _SQLITE_VDBE_H_
 #define _SQLITE_VDBE_H_
@@ -97,113 +97,114 @@ typedef struct VdbeOp VdbeOp;
 #define OP_KeyAsData          25
 #define OP_Recno              26
 #define OP_FullKey            27
-#define OP_Last               28
-#define OP_Rewind             29
-#define OP_Next               30
-
-#define OP_Destroy            31
-#define OP_Clear              32
-#define OP_CreateIndex        33
-#define OP_CreateTable        34
-#define OP_IntegrityCk        35
-
-#define OP_IdxPut             36
-#define OP_IdxDelete          37
-#define OP_IdxRecno           38
-#define OP_IdxGT              39
-#define OP_IdxGE              40
-
-#define OP_MemLoad            41
-#define OP_MemStore           42
-
-#define OP_ListWrite          43
-#define OP_ListRewind         44
-#define OP_ListRead           45
-#define OP_ListReset          46
-
-#define OP_SortPut            47
-#define OP_SortMakeRec        48
-#define OP_SortMakeKey        49
-#define OP_Sort               50
-#define OP_SortNext           51
-#define OP_SortCallback       52
-#define OP_SortReset          53
-
-#define OP_FileOpen           54
-#define OP_FileRead           55
-#define OP_FileColumn         56
-
-#define OP_AggReset           57
-#define OP_AggFocus           58
-#define OP_AggIncr            59
-#define OP_AggNext            60
-#define OP_AggSet             61
-#define OP_AggGet             62
-
-#define OP_SetInsert          63
-#define OP_SetFound           64
-#define OP_SetNotFound        65
-
-#define OP_MakeRecord         66
-#define OP_MakeKey            67
-#define OP_MakeIdxKey         68
-#define OP_IncrKey            69
-
-#define OP_Goto               70
-#define OP_If                 71
-#define OP_Halt               72
-
-#define OP_ColumnCount        73
-#define OP_ColumnName         74
-#define OP_Callback           75
-#define OP_NullCallback       76
-
-#define OP_Integer            77
-#define OP_String             78
-#define OP_Pop                79
-#define OP_Dup                80
-#define OP_Pull               81
-#define OP_Push               82
-#define OP_MustBeInt          83
-
-#define OP_Add                84
-#define OP_AddImm             85
-#define OP_Subtract           86
-#define OP_Multiply           87
-#define OP_Divide             88
-#define OP_Remainder          89
-#define OP_BitAnd             90
-#define OP_BitOr              91
-#define OP_BitNot             92
-#define OP_ShiftLeft          93
-#define OP_ShiftRight         94
-#define OP_AbsValue           95
-#define OP_Precision          96
-#define OP_Min                97
-#define OP_Max                98
-#define OP_Like               99
-#define OP_Glob              100
-#define OP_Eq                101
-#define OP_Ne                102
-#define OP_Lt                103
-#define OP_Le                104
-#define OP_Gt                105
-#define OP_Ge                106
-#define OP_IsNull            107
-#define OP_NotNull           108
-#define OP_Negative          109
-#define OP_And               110
-#define OP_Or                111
-#define OP_Not               112
-#define OP_Concat            113
-#define OP_Noop              114
-
-#define OP_Strlen            115
-#define OP_Substr            116
-
-#define OP_Limit             117
-
-#define OP_MAX               117
+#define OP_NullRow            28
+#define OP_Last               29
+#define OP_Rewind             30
+#define OP_Next               31
+
+#define OP_Destroy            32
+#define OP_Clear              33
+#define OP_CreateIndex        34
+#define OP_CreateTable        35
+#define OP_IntegrityCk        36
+
+#define OP_IdxPut             37
+#define OP_IdxDelete          38
+#define OP_IdxRecno           39
+#define OP_IdxGT              40
+#define OP_IdxGE              41
+
+#define OP_MemLoad            42
+#define OP_MemStore           43
+
+#define OP_ListWrite          44
+#define OP_ListRewind         45
+#define OP_ListRead           46
+#define OP_ListReset          47
+
+#define OP_SortPut            48
+#define OP_SortMakeRec        49
+#define OP_SortMakeKey        50
+#define OP_Sort               51
+#define OP_SortNext           52
+#define OP_SortCallback       53
+#define OP_SortReset          54
+
+#define OP_FileOpen           55
+#define OP_FileRead           56
+#define OP_FileColumn         57
+
+#define OP_AggReset           58
+#define OP_AggFocus           59
+#define OP_AggIncr            60
+#define OP_AggNext            61
+#define OP_AggSet             62
+#define OP_AggGet             63
+
+#define OP_SetInsert          64
+#define OP_SetFound           65
+#define OP_SetNotFound        66
+
+#define OP_MakeRecord         67
+#define OP_MakeKey            68
+#define OP_MakeIdxKey         69
+#define OP_IncrKey            70
+
+#define OP_Goto               71
+#define OP_If                 72
+#define OP_Halt               73
+
+#define OP_ColumnCount        74
+#define OP_ColumnName         75
+#define OP_Callback           76
+#define OP_NullCallback       77
+
+#define OP_Integer            78
+#define OP_String             79
+#define OP_Pop                80
+#define OP_Dup                81
+#define OP_Pull               82
+#define OP_Push               83
+#define OP_MustBeInt          84
+
+#define OP_Add                85
+#define OP_AddImm             86
+#define OP_Subtract           87
+#define OP_Multiply           88
+#define OP_Divide             89
+#define OP_Remainder          90
+#define OP_BitAnd             91
+#define OP_BitOr              92
+#define OP_BitNot             93
+#define OP_ShiftLeft          94
+#define OP_ShiftRight         95
+#define OP_AbsValue           96
+#define OP_Precision          97
+#define OP_Min                98
+#define OP_Max                99
+#define OP_Like              100
+#define OP_Glob              101
+#define OP_Eq                102
+#define OP_Ne                103
+#define OP_Lt                104
+#define OP_Le                105
+#define OP_Gt                106
+#define OP_Ge                107
+#define OP_IsNull            108
+#define OP_NotNull           109
+#define OP_Negative          110
+#define OP_And               111
+#define OP_Or                112
+#define OP_Not               113
+#define OP_Concat            114
+#define OP_Noop              115
+
+#define OP_Strlen            116
+#define OP_Substr            117
+
+#define OP_Limit             118
+
+#define OP_MAX               118
 
 /*
 ** Prototypes for the VDBE interface.  See comments on the implementation
index cfe64c60159985b6bf8989cd5227b648616b7ba0..4d3931dd6b1c2114f2dcd96abfda6b059649bc7a 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.14 2002/02/18 18:30:33 drh Exp $
+# $Id: table.test,v 1.15 2002/02/21 12:01:28 drh Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -282,8 +282,8 @@ do_test table-7.1 {
       desc text,
       asc text,
       explain int,
-      vacuum boolean,
-      delimiters varchar(10),
+      [14_vac] boolean,
+      fuzzy_dog_12 varchar(10),
       begin blob,
       end clob
     )
@@ -300,7 +300,7 @@ do_test table-7.3 {
   execsql2 {
     SELECT * FROM weird;
   }
-} {desc a asc b explain 9 vacuum 0 delimiters xyz begin hi end y'all}
+} {desc a asc b explain 9 14_vac 0 fuzzy_dog_12 xyz begin hi end y'all}
 
 # Try out the CREATE TABLE AS syntax
 #
@@ -309,7 +309,20 @@ do_test table-8.1 {
     CREATE TABLE t2 AS SELECT * FROM weird;
     SELECT * FROM t2;
   }
-} {desc a asc b explain 9 vacuum 0 delimiters xyz begin hi end y'all}
+} {desc a asc b explain 9 14_vac 0 fuzzy_dog_12 xyz begin hi end y'all}
+do_test table-8.1.1 {
+  execsql {
+    SELECT sql FROM sqlite_master WHERE name='t2';
+  }
+} {{CREATE TABLE t2(
+  'desc',
+  'asc',
+  'explain',
+  '14_vac',
+  fuzzy_dog_12,
+  'begin',
+  'end'
+)}}
 do_test table-8.2 {
   execsql {
     CREATE TABLE 't3''xyz'(a,b,c);
@@ -319,10 +332,15 @@ do_test table-8.2 {
 } {1 2 3}
 do_test table-8.3 {
   execsql2 {
-    CREATE TABLE [t4'abc] AS SELECT count(*), min(a), max(b+c) FROM [t3'xyz];
+    CREATE TABLE [t4'abc] AS SELECT count(*) as cnt, max(b+c) FROM [t3'xyz];
     SELECT * FROM [t4'abc];
   }
-} {count(*) 1 min(a) 1 max(b+c) 5}
+} {cnt 1 max(b+c) 5}
+do_test table-8.3.1 {
+  execsql {
+    SELECT sql FROM sqlite_master WHERE name='t4''abc'
+  }
+} {{CREATE TABLE 't4''abc'(cnt,'max(b+c)')}}
 do_test table-8.4 {
   execsql2 {
     CREATE TEMPORARY TABLE t5 AS SELECT count(*) AS [y'all] FROM [t3'xyz];
@@ -335,16 +353,21 @@ do_test table-8.5 {
   execsql2 {
     SELECT * FROM [t4'abc];
   }
-} {count(*) 1 min(a) 1 max(b+c) 5}
+} {cnt 1 max(b+c) 5}
 do_test table-8.6 {
   execsql2 {
     SELECT * FROM t2;
   }
-} {desc a asc b explain 9 vacuum 0 delimiters xyz begin hi end y'all}
+} {desc a asc b explain 9 14_vac 0 fuzzy_dog_12 xyz begin hi end y'all}
 do_test table-8.7 {
   catchsql {
     SELECT * FROM t5;
   }
 } {1 {no such table: t5}}
+do_test table-8.8 {
+  catchsql {
+    CREATE TABLE t5 AS SELECT * FROM no_such_table;
+  }
+} {1 {no such table: no_such_table}}
 
 finish_test
index 10a59b90792a188abad1e5db2c9191d12e64637b..64e5dcd7d9b71d9ea9a97f3a939a76a5656119f0 100644 (file)
@@ -23,6 +23,8 @@ chng {2002 Feb * (2.3.4)} {
 <li>SELECT min() or max() of an indexed column with no WHERE or GROUP BY
     clause is handled as a special case which avoids a complete table scan.</li>
 <li>Automatically generated ROWIDs are now sequential.</li>
+<li>Do not allow dot-commands of the command-line shell to occur in the
+    middle of a real SQL command.</li>
 }
 
 chng {2002 Feb 18 (2.3.3)} {