aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authordrh <drh@noemail.net>2003-03-31 00:30:47 +0000
committerdrh <drh@noemail.net>2003-03-31 00:30:47 +0000
commit1c2d84148a6bb2f8d231debd65bc09e948abf029 (patch)
tree8325c0588ab6b2109b752e55684776cd3fed9455 /src
parent180487389b1aaa61cd32b7d439cc2d0bd5e0dde2 (diff)
downloadsqlite-1c2d84148a6bb2f8d231debd65bc09e948abf029.tar.gz
sqlite-1c2d84148a6bb2f8d231debd65bc09e948abf029.zip
The ATTACH and DETACH statements are now coded but are still mostly untested. (CVS 890)
FossilOrigin-Name: c7c5e927a54f0fbc2ca625754787aff4d9c4eff1
Diffstat (limited to 'src')
-rw-r--r--src/build.c167
-rw-r--r--src/main.c171
-rw-r--r--src/parse.y12
-rw-r--r--src/sqlite.h.in3
-rw-r--r--src/sqliteInt.h8
5 files changed, 268 insertions, 93 deletions
diff --git a/src/build.c b/src/build.c
index 141d15f14..059c69be8 100644
--- a/src/build.c
+++ b/src/build.c
@@ -25,7 +25,7 @@
** ROLLBACK
** PRAGMA
**
-** $Id: build.c,v 1.136 2003/03/30 00:19:50 drh Exp $
+** $Id: build.c,v 1.137 2003/03/31 00:30:48 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -186,14 +186,20 @@ void sqliteUnlinkAndDeleteIndex(sqlite *db, Index *pIndex){
** database connection. This routine is called to reclaim memory
** before the connection closes. It is also called during a rollback
** if there were schema changes during the transaction.
+**
+** If iDb<=0 then reset the internal schema tables for all database
+** files. If iDb>=2 then reset the internal schema for only the
+** single file indicates.
*/
-void sqliteResetInternalSchema(sqlite *db){
+void sqliteResetInternalSchema(sqlite *db, int iDb){
HashElem *pElem;
Hash temp1;
Hash temp2;
- int i;
+ int i, j;
- for(i=0; i<db->nDb; i++){
+ assert( iDb>=0 && iDb<db->nDb );
+ db->flags &= ~SQLITE_Initialized;
+ for(i=iDb; i<db->nDb; i++){
Db *pDb = &db->aDb[i];
temp1 = pDb->tblHash;
temp2 = pDb->trigHash;
@@ -211,8 +217,35 @@ void sqliteResetInternalSchema(sqlite *db){
sqliteDeleteTable(db, pTab);
}
sqliteHashClear(&temp1);
+ db->aDb[i].flags &= ~SQLITE_Initialized;
+ if( iDb>0 ) return;
+ }
+ assert( iDb==0 );
+ db->flags &= ~SQLITE_InternChanges;
+
+ /* If one or more of the auxiliary database files has been closed,
+ ** then remove then from the auxiliary database list. We take the
+ ** opportunity to do this here since we have just deleted all of the
+ ** schema hash tables and therefore do not have to make any changes
+ ** to any of those tables.
+ */
+ for(i=j=2; i<db->nDb; i++){
+ if( db->aDb[i].pBt==0 ){
+ sqliteFree(db->aDb[i].zName);
+ db->aDb[i].zName = 0;
+ continue;
+ }
+ if( j<i ){
+ db->aDb[j++] = db->aDb[i];
+ }
+ }
+ memset(&db->aDb[j], 0, (db->nDb-j)*sizeof(db->aDb[j]));
+ db->nDb = j;
+ if( db->nDb<=2 && db->aDb!=db->aDbStatic ){
+ memcpy(db->aDbStatic, db->aDb, 2*sizeof(db->aDb[0]));
+ sqliteFree(db->aDb);
+ db->aDb = db->aDbStatic;
}
- db->flags &= ~(SQLITE_Initialized|SQLITE_InternChanges);
}
/*
@@ -222,7 +255,7 @@ void sqliteResetInternalSchema(sqlite *db){
*/
void sqliteRollbackInternalChanges(sqlite *db){
if( db->flags & SQLITE_InternChanges ){
- sqliteResetInternalSchema(db);
+ sqliteResetInternalSchema(db, 0);
}
}
@@ -366,6 +399,7 @@ void sqliteStartTable(
char *zName;
sqlite *db = pParse->db;
Vdbe *v;
+ int iDb;
pParse->sFirstToken = *pStart;
zName = sqliteTableNameFromToken(pName);
@@ -430,7 +464,8 @@ void sqliteStartTable(
** an existing temporary table, that is not an error.
*/
pTable = sqliteFindTable(db, zName, 0);
- if( pTable!=0 && (pTable->iDb==isTemp || !pParse->initFlag) ){
+ iDb = isTemp ? 1 : pParse->iDb;
+ if( pTable!=0 && (pTable->iDb==iDb || !pParse->initFlag) ){
sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n,
" already exists", 0, 0);
sqliteFree(zName);
@@ -455,7 +490,7 @@ void sqliteStartTable(
pTable->aCol = 0;
pTable->iPKey = -1;
pTable->pIndex = 0;
- pTable->iDb = isTemp ? 1 : pParse->iDb;
+ pTable->iDb = iDb;
if( pParse->pNewTable ) sqliteDeleteTable(db, pParse->pNewTable);
pParse->pNewTable = pTable;
@@ -1458,7 +1493,7 @@ void sqliteCreateIndex(
pParse->nErr++;
goto exit_create_index;
}
- if( !isTemp && pTab->iDb>=2 ){
+ if( !isTemp && pTab->iDb>=2 && pParse->initFlag==0 ){
sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
" may not have non-temporary indices added", 0);
pParse->nErr++;
@@ -1473,20 +1508,6 @@ void sqliteCreateIndex(
isTemp = 1;
}
-
-#if 0
- /* If this index is created while re-reading the schema from sqlite_master
- ** but the table associated with this index is a temporary table, it can
- ** only mean that the table that this index is really associated with is
- ** one whose name is hidden behind a temporary table with the same name.
- ** Since its table has been suppressed, we need to also suppress the
- ** index.
- */
- if( pParse->initFlag && !pParse->isTemp && pTab->iDb ){
- goto exit_create_index;
- }
-#endif
-
/*
** Find the name of the index. Make sure there is not already another
** index or table with the same name.
@@ -2151,7 +2172,7 @@ void sqliteCodeVerifySchema(Parse *pParse){
Vdbe *v = sqliteGetVdbe(pParse);
for(i=0; i<db->nDb; i++){
if( i==1 || db->aDb[i].pBt==0 ) continue;
- sqliteVdbeAddOp(v, OP_VerifyCookie, 0, db->aDb[i].schema_cookie);
+ sqliteVdbeAddOp(v, OP_VerifyCookie, i, db->aDb[i].schema_cookie);
}
pParse->schemaVerified = 1;
}
@@ -2641,3 +2662,101 @@ void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
sqliteFree(zLeft);
sqliteFree(zRight);
}
+
+/*
+** This routine is called by the parser to process an ATTACH statement:
+**
+** ATTACH DATABASE filename AS dbname
+**
+** The pFilename and pDbname arguments are the tokens that define the
+** filename and dbname in the ATTACH statement.
+*/
+void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname){
+ Db *aNew;
+ int rc, i;
+ char *zFile, *zName;
+ sqlite *db;
+
+ if( pParse->explain ) return;
+ db = pParse->db;
+ if( db->aDb==db->aDbStatic ){
+ aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
+ if( aNew==0 ) return;
+ memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
+ }else{
+ aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
+ if( aNew==0 ) return;
+ }
+ db->aDb = aNew;
+ aNew = &db->aDb[db->nDb++];
+ memset(aNew, 0, sizeof(*aNew));
+ sqliteHashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
+ sqliteHashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
+ sqliteHashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
+ sqliteHashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
+
+ zName = 0;
+ sqliteSetNString(&zName, pDbname->z, pDbname->n, 0);
+ if( zName==0 ) return;
+ sqliteDequote(zName);
+ for(i=0; i<db->nDb; i++){
+ if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){
+ sqliteSetString(&pParse->zErrMsg, "database \"", zName,
+ "\" already in use", 0);
+ sqliteFree(zName);
+ pParse->nErr++;
+ return;
+ }
+ }
+ aNew->zName = zName;
+ zFile = 0;
+ sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0);
+ if( zFile==0 ) return;
+ sqliteDequote(zFile);
+ rc = sqliteBtreeOpen(zFile, 0, MAX_PAGES, &aNew->pBt);
+ if( rc ){
+ sqliteSetString(&pParse->zErrMsg, "unable to open database: ", zFile, 0);
+ pParse->nErr++;
+ }
+ sqliteFree(zFile);
+ db->flags &= ~SQLITE_Initialized;
+ if( pParse->nErr ) return;
+ rc = sqliteInit(pParse->db, &pParse->zErrMsg);
+ if( rc ){
+ pParse->nErr++;
+ }
+}
+
+/*
+** This routine is called by the parser to process a DETACH statement:
+**
+** DETACH DATABASE dbname
+**
+** The pDbname argument is the name of the database in the DETACH statement.
+*/
+void sqliteDetach(Parse *pParse, Token *pDbname){
+ int i;
+ sqlite *db;
+
+ if( pParse->explain ) return;
+ db = pParse->db;
+ for(i=0; i<db->nDb; i++){
+ if( db->aDb[i].pBt==0 || db->aDb[i].zName==0 ) continue;
+ if( strlen(db->aDb[i].zName)!=pDbname->n ) continue;
+ if( sqliteStrNICmp(db->aDb[i].zName, pDbname->z, pDbname->n)==0 ) break;
+ }
+ if( i>=db->nDb ){
+ sqliteSetNString(&pParse->zErrMsg, "no such database: ", -1,
+ pDbname->z, pDbname->n, 0);
+ pParse->nErr++;
+ return;
+ }
+ if( i<2 ){
+ sqliteSetString(&pParse->zErrMsg, "cannot detached \"main\" or \"temp\"",0);
+ pParse->nErr++;
+ return;
+ }
+ sqliteBtreeClose(db->aDb[i].pBt);
+ db->aDb[i].pBt = 0;
+ sqliteResetInternalSchema(db, 0);
+}
diff --git a/src/main.c b/src/main.c
index ee1985fc2..aa4e4b3cf 100644
--- a/src/main.c
+++ b/src/main.c
@@ -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.118 2003/03/30 19:17:02 drh Exp $
+** $Id: main.c,v 1.119 2003/03/31 00:30:48 drh Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@@ -40,7 +40,8 @@ typedef struct {
** argv[1] = table or index name or meta statement type.
** argv[2] = root page number for table or index. NULL for meta.
** argv[3] = SQL text for a CREATE TABLE or CREATE INDEX statement.
-** argv[4] = "1" for temporary files, "0" for main database
+** argv[4] = "1" for temporary files, "0" for main database, "2" or more
+** for auxiliary database files.
**
*/
static
@@ -158,22 +159,19 @@ int upgrade_3_callback(void *pInit, int argc, char **argv, char **NotUsed){
/*
** Attempt to read the database schema and initialize internal
-** data structures. Return one of the SQLITE_ error codes to
+** data structures for a single database file. The index of the
+** database file is given by iDb. iDb==0 is used for the main
+** database. iDb==1 should never be used. iDb>=2 is used for
+** auxiliary databases. Return one of the SQLITE_ error codes to
** indicate success or failure.
-**
-** After the database is initialized, the SQLITE_Initialized
-** bit is set in the flags field of the sqlite structure. An
-** attempt is made to initialize the database as soon as it
-** is opened. If that fails (perhaps because another process
-** has the sqlite_master table locked) than another attempt
-** is made the first time the database is accessed.
*/
-int sqliteInit(sqlite *db, char **pzErrMsg){
+static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
int rc;
BtCursor *curMain;
int size;
Table *pTab;
char *azArg[6];
+ char zDbNum[30];
int meta[SQLITE_N_BTREE_META];
Parse sParse;
InitData initData;
@@ -228,13 +226,16 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
"WHERE type='index'";
+ assert( iDb>=0 && iDb!=1 && iDb<db->nDb );
+
/* Construct the schema tables: sqlite_master and sqlite_temp_master
*/
azArg[0] = "table";
azArg[1] = MASTER_NAME;
azArg[2] = "2";
azArg[3] = master_schema;
- azArg[4] = "0";
+ sprintf(zDbNum, "%d", iDb);
+ azArg[4] = zDbNum;
azArg[5] = 0;
initData.db = db;
initData.pzErrMsg = pzErrMsg;
@@ -243,59 +244,68 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
if( pTab ){
pTab->readOnly = 1;
}
- azArg[1] = TEMP_MASTER_NAME;
- azArg[3] = temp_master_schema;
- azArg[4] = "1";
- sqliteInitCallback(&initData, 5, azArg, 0);
- pTab = sqliteFindTable(db, TEMP_MASTER_NAME, "temp");
- if( pTab ){
- pTab->readOnly = 1;
+ if( iDb==0 ){
+ azArg[1] = TEMP_MASTER_NAME;
+ azArg[3] = temp_master_schema;
+ azArg[4] = "1";
+ sqliteInitCallback(&initData, 5, azArg, 0);
+ pTab = sqliteFindTable(db, TEMP_MASTER_NAME, "temp");
+ if( pTab ){
+ pTab->readOnly = 1;
+ }
}
/* Create a cursor to hold the database open
*/
- if( db->aDb[0].pBt==0 ) return SQLITE_OK;
- rc = sqliteBtreeCursor(db->aDb[0].pBt, 2, 0, &curMain);
+ if( db->aDb[iDb].pBt==0 ) return SQLITE_OK;
+ rc = sqliteBtreeCursor(db->aDb[iDb].pBt, 2, 0, &curMain);
if( rc ){
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
- sqliteResetInternalSchema(db);
return rc;
}
/* Get the database meta information
*/
- rc = sqliteBtreeGetMeta(db->aDb[0].pBt, meta);
+ rc = sqliteBtreeGetMeta(db->aDb[iDb].pBt, meta);
if( rc ){
sqliteSetString(pzErrMsg, sqlite_error_string(rc), 0);
- sqliteResetInternalSchema(db);
sqliteBtreeCloseCursor(curMain);
return rc;
}
- db->next_cookie = db->aDb[0].schema_cookie = meta[1];
- db->file_format = meta[2];
- size = meta[3];
- if( size==0 ){ size = MAX_PAGES; }
- db->cache_size = size;
- sqliteBtreeSetCacheSize(db->aDb[0].pBt, size);
- db->safety_level = meta[4];
- if( db->safety_level==0 ) db->safety_level = 2;
- sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
+ db->aDb[iDb].schema_cookie = meta[1];
+ if( iDb==0 ){
+ db->next_cookie = meta[1];
+ db->file_format = meta[2];
+ size = meta[3];
+ if( size==0 ){ size = MAX_PAGES; }
+ db->cache_size = size;
+ db->safety_level = meta[4];
+ if( db->safety_level==0 ) db->safety_level = 2;
- /*
- ** file_format==1 Version 2.1.0.
- ** file_format==2 Version 2.2.0. Add support for INTEGER PRIMARY KEY.
- ** file_format==3 Version 2.6.0. Fix empty-string index bug.
- ** file_format==4 Version 2.7.0. Add support for separate numeric and
- ** text datatypes.
- */
- if( db->file_format==0 ){
- /* This happens if the database was initially empty */
- db->file_format = 4;
- }else if( db->file_format>4 ){
- sqliteBtreeCloseCursor(curMain);
- sqliteSetString(pzErrMsg, "unsupported file format", 0);
- return SQLITE_ERROR;
+ /*
+ ** file_format==1 Version 2.1.0.
+ ** file_format==2 Version 2.2.0. Add support for INTEGER PRIMARY KEY.
+ ** file_format==3 Version 2.6.0. Fix empty-string index bug.
+ ** file_format==4 Version 2.7.0. Add support for separate numeric and
+ ** text datatypes.
+ */
+ if( db->file_format==0 ){
+ /* This happens if the database was initially empty */
+ db->file_format = 4;
+ }else if( db->file_format>4 ){
+ sqliteBtreeCloseCursor(curMain);
+ sqliteSetString(pzErrMsg, "unsupported file format", 0);
+ return SQLITE_ERROR;
+ }
+ }else if( db->file_format<4 || db->file_format!=meta[2] ){
+ sqliteSetString(pzErrMsg, "incompatible file format in auxiliary "
+ "database \"", db->aDb[iDb].zName, "\"", 0);
+ sqliteBtreeClose(db->aDb[iDb].pBt);
+ db->aDb[iDb].pBt = 0;
+ return SQLITE_FORMAT;
}
+ sqliteBtreeSetCacheSize(db->aDb[iDb].pBt, size);
+ sqliteBtreeSetSafetyLevel(db->aDb[iDb].pBt, meta[4]==0 ? 2 : meta[4]);
/* Read the schema information out of the schema tables
*/
@@ -305,24 +315,62 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
sParse.pArg = (void*)&initData;
sParse.initFlag = 1;
sParse.useCallback = 1;
- sqliteRunParser(&sParse,
- db->file_format>=2 ? init_script : older_init_script,
- pzErrMsg);
+ if( iDb==0 ){
+ sqliteRunParser(&sParse,
+ db->file_format>=2 ? init_script : older_init_script,
+ pzErrMsg);
+ }else{
+ char *zSql = 0;
+ sqliteSetString(&zSql,
+ "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
+ db->aDb[iDb].zName, "\".sqlite_master", 0);
+ sqliteRunParser(&sParse, zSql, pzErrMsg);
+ sqliteFree(zSql);
+ }
+ sqliteBtreeCloseCursor(curMain);
if( sqlite_malloc_failed ){
sqliteSetString(pzErrMsg, "out of memory", 0);
sParse.rc = SQLITE_NOMEM;
- sqliteBtreeRollback(db->aDb[0].pBt);
- sqliteResetInternalSchema(db);
+ sqliteResetInternalSchema(db, 0);
}
if( sParse.rc==SQLITE_OK ){
+ db->aDb[iDb].flags |= SQLITE_Initialized;
+ }else{
+ sqliteResetInternalSchema(db, iDb);
+ }
+ return sParse.rc;
+}
+
+/*
+** Initialize all database files - the main database file, the file
+** used to store temporary tables, and any additional database files
+** created using ATTACH statements. Return a success code. If an
+** error occurs, write an error message into *pzErrMsg.
+**
+** After the database is initialized, the SQLITE_Initialized
+** bit is set in the flags field of the sqlite structure. An
+** attempt is made to initialize the database as soon as it
+** is opened. If that fails (perhaps because another process
+** has the sqlite_master table locked) than another attempt
+** is made the first time the database is accessed.
+*/
+int sqliteInit(sqlite *db, char **pzErrMsg){
+ int i, rc;
+
+ assert( (db->flags & SQLITE_Initialized)==0 );
+ rc = SQLITE_OK;
+ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
+ if( db->aDb[i].flags & SQLITE_Initialized ) continue;
+ if( i==1 ) continue; /* Skip the temp database - initialized with 0 */
+ rc = sqliteInitOne(db, i, pzErrMsg);
+ }
+ if( rc==SQLITE_OK ){
db->flags |= SQLITE_Initialized;
sqliteCommitInternalChanges(db);
}else{
db->flags &= ~SQLITE_Initialized;
- sqliteResetInternalSchema(db);
}
- sqliteBtreeCloseCursor(curMain);
- return sParse.rc;
+ return rc;
}
/*
@@ -476,15 +524,16 @@ void sqlite_close(sqlite *db){
for(j=0; j<db->nDb; j++){
if( db->aDb[j].pBt ){
sqliteBtreeClose(db->aDb[j].pBt);
+ db->aDb[j].pBt = 0;
}
if( j>=2 ){
sqliteFree(db->aDb[j].zName);
+ db->aDb[j].zName = 0;
}
}
- if( db->aDb!=db->aDbStatic ){
- sqliteFree(db->aDb);
- }
- sqliteResetInternalSchema(db);
+ sqliteResetInternalSchema(db, 0);
+ assert( db->nDb<=2 );
+ assert( db->aDb==db->aDbStatic );
for(i=sqliteHashFirst(&db->aFunc); i; i=sqliteHashNext(i)){
FuncDef *pFunc, *pNext;
for(pFunc = (FuncDef*)sqliteHashData(i); pFunc; pFunc=pNext){
@@ -673,7 +722,7 @@ static int sqliteMain(
sqliteSetString(pzErrMsg, "out of memory", 0);
sParse.rc = SQLITE_NOMEM;
sqliteRollbackAll(db);
- sqliteResetInternalSchema(db);
+ sqliteResetInternalSchema(db, 0);
db->flags &= ~SQLITE_InTrans;
}
if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK;
@@ -682,7 +731,7 @@ static int sqliteMain(
}
sqliteStrRealloc(pzErrMsg);
if( sParse.rc==SQLITE_SCHEMA ){
- sqliteResetInternalSchema(db);
+ sqliteResetInternalSchema(db, 0);
}
if( sParse.useCallback==0 ){
assert( ppVm );
diff --git a/src/parse.y b/src/parse.y
index e1feb992f..605cc6cd7 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.93 2003/03/27 12:51:25 drh Exp $
+** @(#) $Id: parse.y,v 1.94 2003/03/31 00:30:48 drh Exp $
*/
%token_prefix TK_
%token_type {Token}
@@ -841,14 +841,18 @@ expr(A) ::= RAISE(X) LP FAIL COMMA nm(Z) RP(Y). {
//////////////////////// DROP TRIGGER statement //////////////////////////////
cmd ::= DROP TRIGGER nm(X) dbnm(D). {
- sqliteDropTrigger(pParse,sqliteSrcListAppend(0,&X,&D),0);
+ sqliteDropTrigger(pParse,sqliteSrcListAppend(0,&X,&D),0);
}
//////////////////////// ATTACH DATABASE file AS name /////////////////////////
-cmd ::= ATTACH database_kw_opt ids AS nm.
+cmd ::= ATTACH database_kw_opt ids(F) AS nm(D). {
+ sqliteAttach(pParse, &F, &D);
+}
database_kw_opt ::= DATABASE.
database_kw_opt ::= .
//////////////////////// DETACH DATABASE name /////////////////////////////////
-cmd ::= DETACH database_kw_opt nm.
+cmd ::= DETACH database_kw_opt nm(D). {
+ sqliteDetach(pParse, &D);
+}
diff --git a/src/sqlite.h.in b/src/sqlite.h.in
index 552f351b4..7b224ea52 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.42 2003/03/30 19:17:03 drh Exp $
+** @(#) $Id: sqlite.h.in,v 1.43 2003/03/31 00:30:49 drh Exp $
*/
#ifndef _SQLITE_H_
#define _SQLITE_H_
@@ -165,6 +165,7 @@ int sqlite_exec(
#define SQLITE_MISUSE 21 /* Library used incorrectly */
#define SQLITE_NOLFS 22 /* Uses OS features not supported on host */
#define SQLITE_AUTH 23 /* Authorization denied */
+#define SQLITE_FORMAT 24 /* Auxiliary database format error */
#define SQLITE_ROW 100 /* sqlite_step() has another row ready */
#define SQLITE_DONE 101 /* sqlite_step() has finished executing */
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index dcc325f75..bffef93a4 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
*************************************************************************
** Internal interface definitions for SQLite.
**
-** @(#) $Id: sqliteInt.h,v 1.166 2003/03/27 13:50:00 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.167 2003/03/31 00:30:49 drh Exp $
*/
#include "config.h"
#include "sqlite.h"
@@ -971,9 +971,9 @@ Expr *sqliteExprFunction(ExprList*, Token*);
void sqliteExprDelete(Expr*);
ExprList *sqliteExprListAppend(ExprList*,Expr*,Token*);
void sqliteExprListDelete(ExprList*);
-void sqlitePragma(Parse*,Token*,Token*,int);
-void sqliteResetInternalSchema(sqlite*);
int sqliteInit(sqlite*, char**);
+void sqlitePragma(Parse*,Token*,Token*,int);
+void sqliteResetInternalSchema(sqlite*, int);
void sqliteBeginParse(Parse*,int);
void sqliteRollbackInternalChanges(sqlite*);
void sqliteCommitInternalChanges(sqlite*);
@@ -1082,3 +1082,5 @@ void sqliteDeferForeignKey(Parse*, int);
# define sqliteAuthRead(a,b,c,d)
# define sqliteAuthCheck(a,b,c,d) SQLITE_OK
#endif
+void sqliteAttach(Parse*, Token*, Token*);
+void sqliteDetach(Parse*, Token*);