Adding table column query capability to support ODBC. (CVS 278)
FossilOrigin-Name: b63b3f3684a3d584ef99f54cde76b6c483bbfef7
diff --git a/src/btree.c b/src/btree.c
index 471cd0c..761ccac 100644
--- a/src/btree.c
+++ b/src/btree.c
@@ -9,7 +9,7 @@
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.32 2001/10/02 13:01:49 drh Exp $
+** $Id: btree.c,v 1.33 2001/10/06 16:33:02 drh Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
@@ -595,6 +595,10 @@
** Actually, this routine just sets up the internal data structures
** for accessing the database. We do not open the database file
** until the first page is loaded.
+**
+** zFilename is the name of the database file. If zFilename is NULL
+** a new database with a random name is created. The database will be
+** destroyed when sqliteBtreeClose() is called.
*/
int sqliteBtreeOpen(
const char *zFilename, /* Name of the file containing the BTree database */
diff --git a/src/build.c b/src/build.c
index 70f0c7e..e8d213b 100644
--- a/src/build.c
+++ b/src/build.c
@@ -25,7 +25,7 @@
** ROLLBACK
** PRAGMA
**
-** $Id: build.c,v 1.43 2001/09/27 15:11:54 drh Exp $
+** $Id: build.c,v 1.44 2001/10/06 16:33:03 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -203,6 +203,7 @@
for(i=0; i<pTable->nCol; i++){
sqliteFree(pTable->aCol[i].zName);
sqliteFree(pTable->aCol[i].zDflt);
+ sqliteFree(pTable->aCol[i].zType);
}
for(pIndex = pTable->pIndex; pIndex; pIndex=pNext){
pNext = pIndex->pNext;
@@ -335,7 +336,7 @@
** after seeing tokens "CREATE" and "TABLE" and the table name. The
** pStart token is the CREATE and pName is the table name.
**
-** The new table is constructed in files of the pParse structure. As
+** The new table is constructed in fields of the pParse structure. As
** more of the CREATE TABLE statement is parsed, additional action
** routines are called to build up more of the table.
*/
@@ -407,6 +408,48 @@
}
/*
+** This routine is called by the parser while in the middle of
+** parsing a CREATE TABLE statement. A "NOT NULL" constraint has
+** been seen on a column. This routine sets the notNull flag on
+** the column currently under construction.
+*/
+void sqliteAddNotNull(Parse *pParse){
+ Table *p;
+ int i;
+ if( (p = pParse->pNewTable)==0 ) return;
+ i = p->nCol-1;
+ p->aCol[i].notNull = 1;
+}
+
+/*
+** This routine is called by the parser while in the middle of
+** parsing a CREATE TABLE statement. The pFirst token is the first
+** token in the sequence of tokens that describe the type of the
+** column currently under construction. pLast is the last token
+** in the sequence. Use this information to construct a string
+** that contains the typename of the column and store that string
+** in zType.
+*/
+void sqliteAddColumnType(Parse *pParse, Token *pFirst, Token *pLast){
+ Table *p;
+ int i, j;
+ int n;
+ char *z, **pz;
+ if( (p = pParse->pNewTable)==0 ) return;
+ i = p->nCol-1;
+ pz = &p->aCol[i].zType;
+ n = pLast->n + ((int)pLast->z) - (int)pFirst->z;
+ sqliteSetNString(pz, pFirst->z, n, 0);
+ z = *pz;
+ for(i=j=0; z[i]; i++){
+ int c = z[i];
+ if( isspace(c) ) continue;
+ z[j++] = c;
+ }
+ z[j] = 0;
+}
+
+/*
** The given token is the default value for the last column added to
** the table currently under construction. If "minusFlag" is true, it
** means the value token was preceded by a minus sign.
@@ -486,9 +529,7 @@
** "sqlite_master" table on the disk. So do not write to the disk
** 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.
+ ** there by the sqliteOpenCb routine.)
*/
if( pParse->initFlag ){
p->tnum = pParse->newTnum;
@@ -618,11 +659,12 @@
** and pTable is the name of the table that is to be indexed. Both will
** 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.
+** as the table to be indexed. pParse->pNewTable is a table that is
+** currently being constructed by a CREATE TABLE statement.
**
-** pList is a list of columns to be indexed. pList will be NULL if the
-** most recently added column of the table is the primary key or has
-** the UNIQUE constraint.
+** pList is a list of columns to be indexed. pList will be NULL if this
+** is a primary key or unique-constraint on the most recent column added
+** to the table currently under construction.
*/
void sqliteCreateIndex(
Parse *pParse, /* All information about this parse */
@@ -763,10 +805,9 @@
** we don't want to recreate it.
**
** If pTable==0 it means this index is generated as a primary key
- ** 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
+ ** or UNIQUE constraint of a CREATE TABLE statement. Since the table
+ ** has just been created, it contains no data and the index initialization
+ ** step can be skipped.
*/
else if( pParse->initFlag==0 ){
int n;
@@ -796,12 +837,10 @@
sqliteVdbeAddOp(v, OP_Dup, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_OpenWrite, 1, 0, 0, 0);
}
+ addr = sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
if( pStart && pEnd ){
n = (int)pEnd->z - (int)pStart->z + 1;
- 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_MakeRecord, 5, 0, 0, 0);
sqliteVdbeAddOp(v, OP_Put, 0, 0, 0, 0);
@@ -1262,6 +1301,68 @@
}
}else
+ if( sqliteStrICmp(zLeft, "full_column_names")==0 ){
+ if( getBoolean(zRight) ){
+ db->flags |= SQLITE_FullColNames;
+ }else{
+ db->flags &= ~SQLITE_FullColNames;
+ }
+ }else
+
+ if( sqliteStrICmp(zLeft, "table_info")==0 ){
+ Table *pTab;
+ Vdbe *v;
+ pTab = sqliteFindTable(db, zRight);
+ if( pTab ) v = sqliteGetVdbe(pParse);
+ if( pTab && v ){
+ static VdbeOp tableInfoPreface[] = {
+ { OP_ColumnCount, 5, 0, 0},
+ { OP_ColumnName, 0, 0, "cid"},
+ { OP_ColumnName, 1, 0, "name"},
+ { OP_ColumnName, 2, 0, "type"},
+ { OP_ColumnName, 3, 0, "notnull"},
+ { OP_ColumnName, 4, 0, "dflt_value"},
+ };
+ int i;
+ sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
+ for(i=0; i<pTab->nCol; i++){
+ sqliteVdbeAddOp(v, OP_Integer, i, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_String, 0, 0, pTab->aCol[i].zName, 0);
+ sqliteVdbeAddOp(v, OP_String, 0, 0,
+ pTab->aCol[i].zType ? pTab->aCol[i].zType : "text", 0);
+ sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_String, 0, 0, pTab->aCol[i].zDflt, 0);
+ sqliteVdbeAddOp(v, OP_Callback, 5, 0, 0, 0);
+ }
+ }
+ }else
+
+ if( sqliteStrICmp(zLeft, "index_info")==0 ){
+ Index *pIdx;
+ Table *pTab;
+ Vdbe *v;
+ pIdx = sqliteFindIndex(db, zRight);
+ if( pIdx ) v = sqliteGetVdbe(pParse);
+ if( pIdx && v ){
+ static VdbeOp tableInfoPreface[] = {
+ { OP_ColumnCount, 3, 0, 0},
+ { OP_ColumnName, 0, 0, "seqno"},
+ { OP_ColumnName, 1, 0, "cid"},
+ { OP_ColumnName, 2, 0, "name"},
+ };
+ int i;
+ pTab = pIdx->pTable;
+ sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
+ for(i=0; i<pIdx->nColumn; i++){
+ sqliteVdbeAddOp(v, OP_Integer, i, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_Integer, pIdx->aiColumn[i], 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_String, 0, 0,
+ pTab->aCol[pIdx->aiColumn[i]].zName, 0);
+ sqliteVdbeAddOp(v, OP_Callback, 3, 0, 0, 0);
+ }
+ }
+ }else
+
#ifndef NDEBUG
if( sqliteStrICmp(zLeft, "parser_trace")==0 ){
extern void sqliteParserTrace(FILE*, char *);
diff --git a/src/expr.c b/src/expr.c
index 7710743..0bf7472 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -12,7 +12,7 @@
** This file contains routines used for analyzing expressions and
** for generating VDBE code that evaluates expressions in SQLite.
**
-** $Id: expr.c,v 1.28 2001/09/16 00:13:27 drh Exp $
+** $Id: expr.c,v 1.29 2001/10/06 16:33:03 drh Exp $
*/
#include "sqliteInt.h"
@@ -526,7 +526,7 @@
break;
}
case TK_NULL: {
- sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
break;
}
case TK_AND:
diff --git a/src/insert.c b/src/insert.c
index 1c209be..9529a1f 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -12,7 +12,7 @@
** This file contains C code routines that are called by the parser
** to handle INSERT statements in SQLite.
**
-** $Id: insert.c,v 1.20 2001/09/27 03:22:33 drh Exp $
+** $Id: insert.c,v 1.21 2001/10/06 16:33:03 drh Exp $
*/
#include "sqliteInt.h"
@@ -186,12 +186,7 @@
}
}
if( pColumn && j>=pColumn->nId ){
- char *zDflt = pTab->aCol[i].zDflt;
- if( zDflt==0 ){
- sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
- }else{
- sqliteVdbeAddOp(v, OP_String, 0, 0, zDflt, 0);
- }
+ sqliteVdbeAddOp(v, OP_String, 0, 0, pTab->aCol[i].zDflt, 0);
}else if( srcTab>=0 ){
sqliteVdbeAddOp(v, OP_Column, srcTab, i, 0, 0);
}else{
@@ -218,12 +213,7 @@
}
}
if( pColumn && j>=pColumn->nId ){
- char *zDflt = pTab->aCol[idx].zDflt;
- if( zDflt==0 ){
- sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
- }else{
- sqliteVdbeAddOp(v, OP_String, 0, 0, zDflt, 0);
- }
+ sqliteVdbeAddOp(v, OP_String, 0, 0, pTab->aCol[idx].zDflt, 0);
}else if( srcTab>=0 ){
sqliteVdbeAddOp(v, OP_Column, srcTab, idx, 0, 0);
}else{
diff --git a/src/main.c b/src/main.c
index 5fcc32c..d96aad9 100644
--- a/src/main.c
+++ b/src/main.c
@@ -14,14 +14,16 @@
** other files are for internal use by SQLite and should not be
** accessed by users of the library.
**
-** $Id: main.c,v 1.42 2001/09/27 15:11:54 drh Exp $
+** $Id: main.c,v 1.43 2001/10/06 16:33:03 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
/*
** This is the callback routine for the code that initializes the
-** database. Each callback contains the following information:
+** database. See sqliteInit() below for additional information.
+**
+** Each callback contains the following information:
**
** argv[0] = "meta" or "table" or "index"
** argv[1] = table or index name or meta statement type.
@@ -34,8 +36,9 @@
Parse sParse;
int nErr = 0;
-/* TODO: Do some validity checks on all fields. In particular,
-** make sure fields do not contain NULLs. */
+ /* TODO: Do some validity checks on all fields. In particular,
+ ** make sure fields do not contain NULLs. Otherwise we might core
+ ** when attempting to initialize from a corrupt database file. */
assert( argc==4 );
switch( argv[0][0] ){
@@ -51,12 +54,23 @@
case 'i':
case 't': { /* CREATE TABLE and CREATE INDEX statements */
if( argv[3] && argv[3][0] ){
+ /* Call the parser to process a CREATE TABLE or CREATE INDEX statement.
+ ** 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.
+ */
memset(&sParse, 0, sizeof(sParse));
sParse.db = db;
sParse.initFlag = 1;
sParse.newTnum = atoi(argv[2]);
nErr = sqliteRunParser(&sParse, argv[3], 0);
}else{
+ /* If the SQL column is blank it means this is an index that
+ ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
+ ** constraint or a CREATE TABLE. The index should have already
+ ** been created when we processed the CREATE TABLE. All we have
+ ** to do here is record the root page.
+ */
Index *pIndex = sqliteFindIndex(db, argv[1]);
if( pIndex==0 || pIndex->tnum!=0 ){
nErr++;
@@ -123,9 +137,12 @@
** The "tbl_name" is the name of the associated table. For tables,
** the tbl_name column is always the same as name. For indices, the
** tbl_name column contains the name of the table that the index
- ** indexes. Finally, the "sql" column contains the complete text of
- ** the CREATE TABLE or CREATE INDEX statement that originally created
- ** the table or index.
+ ** indexes. The "rootpage" column holds the number of the root page
+ ** for the b-tree for the table or index. Finally, the "sql" column
+ ** contains the complete text of the CREATE TABLE or CREATE INDEX
+ ** statement that originally created the table or index. If an index
+ ** 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
@@ -175,7 +192,7 @@
{ OP_Goto, 0, 24, 0},
{ OP_String, 0, 0, "meta"}, /* 34 */
{ OP_String, 0, 0, "schema-cookie"},
- { OP_Null, 0, 0, 0},
+ { OP_String, 0, 0, 0},
{ OP_ReadCookie,0,0, 0},
{ OP_Callback, 4, 0, 0},
{ OP_Close, 0, 0, 0},
@@ -183,7 +200,7 @@
};
/* Create a virtual machine to run the initialization program. Run
- ** the program. The delete the virtual machine.
+ ** the program. Then delete the virtual machine.
*/
vdbe = sqliteVdbeCreate(db);
if( vdbe==0 ){
diff --git a/src/pager.c b/src/pager.c
index 6f60301..6bb71ef 100644
--- a/src/pager.c
+++ b/src/pager.c
@@ -18,7 +18,7 @@
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.24 2001/09/20 01:44:43 drh Exp $
+** @(#) $Id: pager.c,v 1.25 2001/10/06 16:33:03 drh Exp $
*/
#include "sqliteInt.h"
#include "pager.h"
@@ -377,6 +377,10 @@
** The file to be cached need not exist. The file is not locked until
** the first call to sqlitepager_get() and is only held open until the
** last page is released using sqlitepager_unref().
+**
+** If zFilename is NULL then a random temporary file is created and used
+** as the file to be cached. The file will be deleted automatically when
+** it is closed.
*/
int sqlitepager_open(
Pager **ppPager, /* Return the Pager structure here */
diff --git a/src/parse.y b/src/parse.y
index d64c56b..56e6af7 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,7 +14,7 @@
** the parser. Lemon will also generate a header file containing
** numeric codes for all of the tokens.
**
-** @(#) $Id: parse.y,v 1.33 2001/10/01 14:29:23 drh Exp $
+** @(#) $Id: parse.y,v 1.34 2001/10/06 16:33:03 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -49,9 +49,7 @@
ecmd ::= .
explain ::= EXPLAIN. {pParse->explain = 1;}
-// Begin and end transactions. Transaction support is sparse.
-// Some backends support only COMMIT and not ROLLBACK. There can
-// be only a single active transaction at a time.
+///////////////////// Begin and end transactions. ////////////////////////////
//
cmd ::= BEGIN trans_opt. {sqliteBeginTransaction(pParse);}
trans_opt ::= .
@@ -61,7 +59,7 @@
cmd ::= END trans_opt. {sqliteCommitTransaction(pParse);}
cmd ::= ROLLBACK trans_opt. {sqliteRollbackTransaction(pParse);}
-// The first form of a command is a CREATE TABLE statement.
+///////////////////// The CREATE TABLE statement ////////////////////////////
//
cmd ::= create_table create_table_args.
create_table ::= CREATE(X) TABLE ids(Y). {sqliteStartTable(pParse,&X,&Y);}
@@ -79,7 +77,8 @@
// An IDENTIFIER can be a generic identifier, or one of several
// keywords. Any non-standard keyword can also be an identifier.
-// We also make DESC and identifier since it comes up so often.
+// We also make DESC and identifier since it comes up so often (as
+// an abbreviation of "description").
//
%type id {Token}
id(A) ::= DESC(X). {A = X;}
@@ -99,11 +98,14 @@
ids(A) ::= id(X). {A = X;}
ids(A) ::= STRING(X). {A = X;}
-type ::= typename.
-type ::= typename LP signed RP.
-type ::= typename LP signed COMMA signed RP.
-typename ::= ids.
-typename ::= typename ids.
+type ::= .
+type ::= typename(X). {sqliteAddColumnType(pParse,&X,&X);}
+type ::= typename(X) LP signed RP(Y). {sqliteAddColumnType(pParse,&X,&Y);}
+type ::= typename(X) LP signed COMMA signed RP(Y).
+ {sqliteAddColumnType(pParse,&X,&Y);}
+%type typename {Token}
+typename(A) ::= ids(X). {A = X;}
+typename(A) ::= typename(X) ids. {A = X;}
signed ::= INTEGER.
signed ::= PLUS INTEGER.
signed ::= MINUS INTEGER.
@@ -121,15 +123,16 @@
carg ::= DEFAULT MINUS FLOAT(X). {sqliteAddDefaultValue(pParse,&X,1);}
carg ::= DEFAULT NULL.
-// In addition to the type name, we also care about the primary key.
+// In addition to the type name, we also care about the primary key and
+// UNIQUE constraints.
//
-ccons ::= NOT NULL.
+ccons ::= NOT NULL. {sqliteAddNotNull(pParse);}
ccons ::= PRIMARY KEY sortorder. {sqliteCreateIndex(pParse,0,0,0,1,0,0);}
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
-// key.
+// key and UNIQUE. Both create indices.
//
conslist_opt ::= .
conslist_opt ::= COMMA conslist.
@@ -140,14 +143,12 @@
tcons ::= PRIMARY KEY LP idxlist(X) RP. {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
tcons ::= UNIQUE LP idxlist(X) RP. {sqliteCreateIndex(pParse,0,0,X,1,0,0);}
tcons ::= CHECK expr.
-// idlist ::= idlist COMMA ids.
-// idlist ::= ids.
-// The next command format is dropping tables.
+////////////////////////// The DROP TABLE /////////////////////////////////////
//
cmd ::= DROP TABLE ids(X). {sqliteDropTable(pParse,&X);}
-// The select statement
+//////////////////////// The SELECT statement /////////////////////////////////
//
cmd ::= select(X). {
sqliteSelect(pParse, X, SRT_Callback, 0);
@@ -253,7 +254,8 @@
having_opt(A) ::= . {A = 0;}
having_opt(A) ::= HAVING expr(X). {A = X;}
-
+/////////////////////////// The DELETE statement /////////////////////////////
+//
cmd ::= DELETE FROM ids(X) where_opt(Y).
{sqliteDeleteFrom(pParse, &X, Y);}
@@ -266,6 +268,8 @@
%type setlist {ExprList*}
%destructor setlist {sqliteExprListDelete($$);}
+////////////////////////// The UPDATE command ////////////////////////////////
+//
cmd ::= UPDATE ids(X) SET setlist(Y) where_opt(Z).
{sqliteUpdate(pParse,&X,Y,Z);}
@@ -273,6 +277,8 @@
{A = sqliteExprListAppend(Z,Y,&X);}
setlist(A) ::= ids(X) EQ expr(Y). {A = sqliteExprListAppend(0,Y,&X);}
+////////////////////////// The INSERT command /////////////////////////////////
+//
cmd ::= INSERT INTO ids(X) inscollist_opt(F) VALUES LP itemlist(Y) RP.
{sqliteInsert(pParse, &X, Y, 0, F);}
cmd ::= INSERT INTO ids(X) inscollist_opt(F) select(S).
@@ -311,6 +317,8 @@
inscollist(A) ::= inscollist(X) COMMA ids(Y). {A = sqliteIdListAppend(X,&Y);}
inscollist(A) ::= ids(Y). {A = sqliteIdListAppend(0,&Y);}
+/////////////////////////// Expression Processing /////////////////////////////
+//
%left OR.
%left AND.
%right NOT.
@@ -452,7 +460,8 @@
expritem(A) ::= expr(X). {A = X;}
expritem(A) ::= . {A = 0;}
-
+///////////////////////////// The CREATE INDEX command ///////////////////////
+//
cmd ::= CREATE(S) uniqueflag(U) INDEX ids(X) ON ids(Y) LP idxlist(Z) RP(E).
{sqliteCreateIndex(pParse, &X, &Y, Z, U, &S, &E);}
@@ -470,20 +479,31 @@
{A = sqliteIdListAppend(0,&Y);}
idxitem(A) ::= ids(X). {A = X;}
+///////////////////////////// The CREATE INDEX command ///////////////////////
+//
+
cmd ::= DROP INDEX ids(X). {sqliteDropIndex(pParse, &X);}
+
+///////////////////////////// The DROP INDEX command /////////////////////////
+//
cmd ::= COPY ids(X) FROM ids(Y) USING DELIMITERS STRING(Z).
{sqliteCopy(pParse,&X,&Y,&Z);}
cmd ::= COPY ids(X) FROM ids(Y).
{sqliteCopy(pParse,&X,&Y,0);}
+///////////////////////////// The VACUUM command /////////////////////////////
+//
cmd ::= VACUUM. {sqliteVacuum(pParse,0);}
cmd ::= VACUUM ids(X). {sqliteVacuum(pParse,&X);}
+///////////////////////////// The PRAGMA command /////////////////////////////
+//
cmd ::= PRAGMA ids(X) EQ ids(Y). {sqlitePragma(pParse,&X,&Y,0);}
cmd ::= PRAGMA ids(X) EQ ON(Y). {sqlitePragma(pParse,&X,&Y,0);}
cmd ::= PRAGMA ids(X) EQ plus_num(Y). {sqlitePragma(pParse,&X,&Y,0);}
cmd ::= PRAGMA ids(X) EQ minus_num(Y). {sqlitePragma(pParse,&X,&Y,1);}
+cmd ::= PRAGMA ids(X) LP ids(Y) RP. {sqlitePragma(pParse,&X,&Y,0);}
plus_num(A) ::= plus_opt number(X). {A = X;}
minus_num(A) ::= MINUS number(X). {A = X;}
number(A) ::= INTEGER(X). {A = X;}
diff --git a/src/select.c b/src/select.c
index 7b9c479..ab1cc5a 100644
--- a/src/select.c
+++ b/src/select.c
@@ -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.37 2001/09/16 00:13:27 drh Exp $
+** $Id: select.c,v 1.38 2001/10/06 16:33:03 drh Exp $
*/
#include "sqliteInt.h"
@@ -250,7 +250,7 @@
sprintf(zName, "column%d", i+1);
sqliteVdbeAddOp(v, OP_ColumnName, i, 0, zName, 0);
}else{
- if( pTabList->nId>1 ){
+ if( pTabList->nId>1 || (pParse->db->flags & SQLITE_FullColNames)!=0 ){
char *zName = 0;
Table *pTab = pTabList->a[p->iTable].pTab;
char *zTab;
@@ -861,7 +861,7 @@
/* Initialize the memory cell to NULL
*/
if( eDest==SRT_Mem ){
- sqliteVdbeAddOp(v, OP_Null, 0, 0, 0, 0);
+ sqliteVdbeAddOp(v, OP_String, 0, 0, 0, 0);
sqliteVdbeAddOp(v, OP_MemStore, iParm, 0, 0, 0);
}
diff --git a/src/shell.c b/src/shell.c
index a9f34e1..726dd92 100644
--- a/src/shell.c
+++ b/src/shell.c
@@ -12,13 +12,12 @@
** This file contains code to implement the "sqlite" command line
** utility for accessing SQLite databases.
**
-** $Id: shell.c,v 1.35 2001/10/01 14:29:23 drh Exp $
+** $Id: shell.c,v 1.36 2001/10/06 16:33:03 drh Exp $
*/
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "sqlite.h"
-#include <unistd.h>
#include <ctype.h>
#ifdef OS_UNIX
# include <signal.h>
@@ -603,8 +602,6 @@
}else if( strncmp(azArg[1],"html",n2)==0 ){
p->mode = MODE_Html;
}else if( strncmp(azArg[1],"insert",n2)==0 ){
- char *zTab;
- int k, n;
p->mode = MODE_Insert;
if( nArg>=3 ){
set_table_name(p, azArg[2]);
@@ -908,6 +905,7 @@
exit(1);
}
}else{
+ extern int isatty();
if( isatty(0) ){
printf(
"SQLite version %s\n"
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 9056ed4..4bf2fdd 100644
--- a/src/sqlite.h.in
+++ b/src/sqlite.h.in
@@ -12,7 +12,7 @@
** This header file defines the interface that the SQLite library
** presents to client programs.
**
-** @(#) $Id: sqlite.h.in,v 1.20 2001/09/27 03:22:33 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.21 2001/10/06 16:33:03 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
@@ -24,6 +24,13 @@
#define SQLITE_VERSION "--VERS--"
/*
+** Make sure we can call this stuff from C++.
+*/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
** The version string is also compiled into the library so that a program
** can check to make sure that the lib*.a file and the *.h file are from
** the same version.
@@ -342,4 +349,8 @@
va_list ap /* Arguments to the format string */
);
+#ifdef __cplusplus
+} /* End of the 'extern "C"' block */
+#endif
+
#endif /* _SQLITE_H_ */
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 5d1d743..59f0a25 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.56 2001/09/27 15:11:54 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.57 2001/10/06 16:33:03 drh Exp $
*/
#include "sqlite.h"
#include "hash.h"
@@ -164,6 +164,7 @@
#define SQLITE_Interrupt 0x00000004 /* Cancel current operation */
#define SQLITE_InTrans 0x00000008 /* True if in a transaction */
#define SQLITE_InternChanges 0x00000010 /* Uncommitted Hash table changes */
+#define SQLITE_FullColNames 0x00000020 /* Show full column names on SELECT */
/*
** Current file format version
@@ -177,6 +178,7 @@
struct Column {
char *zName; /* Name of this column */
char *zDflt; /* Default value of this column */
+ char *zType; /* Data type for this column */
int notNull; /* True if there is a NOT NULL constraint */
};
@@ -423,6 +425,8 @@
void sqliteRollbackInternalChanges(sqlite*);
void sqliteStartTable(Parse*,Token*,Token*);
void sqliteAddColumn(Parse*,Token*);
+void sqliteAddNotNull(Parse*);
+void sqliteAddColumnType(Parse*,Token*,Token*);
void sqliteAddDefaultValue(Parse*,Token*,int);
void sqliteEndTable(Parse*,Token*);
void sqliteDropTable(Parse*, Token*);
diff --git a/src/tokenize.c b/src/tokenize.c
index 53ebbbf..619ae6e 100644
--- a/src/tokenize.c
+++ b/src/tokenize.c
@@ -15,7 +15,7 @@
** individual tokens and sends those tokens one-by-one over to the
** parser for analysis.
**
-** $Id: tokenize.c,v 1.23 2001/09/23 02:35:53 drh Exp $
+** $Id: tokenize.c,v 1.24 2001/10/06 16:33:03 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -333,7 +333,6 @@
}
switch( tokenType ){
case TK_SPACE:
- break;
case TK_COMMENT: {
break;
}
diff --git a/src/vdbe.c b/src/vdbe.c
index 546b7bf..0e2614b 100644
--- a/src/vdbe.c
+++ b/src/vdbe.c
@@ -30,11 +30,10 @@
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
-** $Id: vdbe.c,v 1.79 2001/09/27 15:11:54 drh Exp $
+** $Id: vdbe.c,v 1.80 2001/10/06 16:33:03 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
-#include <unistd.h>
/*
** SQL is translated into a sequence of instructions to be
@@ -1084,20 +1083,26 @@
/* Opcode: String * * P3
**
-** The string value P3 is pushed onto the stack.
+** The string value P3 is pushed onto the stack. If P3==0 then a
+** NULL is pushed onto the stack.
*/
case OP_String: {
int i = ++p->tos;
char *z;
VERIFY( if( NeedStack(p, p->tos) ) goto no_mem; )
z = pOp->p3;
- if( z==0 ) z = "";
- zStack[i] = z;
- aStack[i].n = strlen(z) + 1;
- aStack[i].flags = STK_Str;
+ if( z==0 ){
+ zStack[i] = 0;
+ aStack[i].flags = STK_Null;
+ }else{
+ zStack[i] = z;
+ aStack[i].n = strlen(z) + 1;
+ aStack[i].flags = STK_Str;
+ }
break;
}
+#if 0 /* NOT USED */
/* Opcode: Null * * *
**
** Push a NULL value onto the stack.
@@ -1109,6 +1114,7 @@
aStack[i].flags = STK_Null;
break;
}
+#endif
/* Opcode: Pop P1 * *
**