mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-07 02:42:48 +03:00
The ATTACH and DETACH statements are now coded but are still mostly untested. (CVS 890)
FossilOrigin-Name: c7c5e927a54f0fbc2ca625754787aff4d9c4eff1
This commit is contained in:
20
manifest
20
manifest
@@ -1,5 +1,5 @@
|
||||
C Remove\sthe\sexperimental\ssqlite_open_aux_file()\sAPI.\s\sIt\swill\ssoon\sbe\sreplaced\nby\sATTACH\sand\sDETACH\sSQL\scommands.\s(CVS\s1732)
|
||||
D 2003-03-30T19:17:03
|
||||
C The\sATTACH\sand\sDETACH\sstatements\sare\snow\scoded\sbut\sare\sstill\smostly\suntested.\s(CVS\s890)
|
||||
D 2003-03-31T00:30:48
|
||||
F Makefile.in 3c4ba24253e61c954d67adbbb4245e7117c5357e
|
||||
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
|
||||
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
|
||||
@@ -22,7 +22,7 @@ F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2
|
||||
F src/auth.c f37bfc9451b8c1fa52f34adff474560018892729
|
||||
F src/btree.c dba4d12945228dd7e94de7da0e1d8638b70d99f2
|
||||
F src/btree.h 8209bfadf5845d4fdaa60f471bb360f894cd4095
|
||||
F src/build.c afe256e29f62733d8d8816c220eb822a6317a444
|
||||
F src/build.c e56df7b1ccf923e75707953181c91380134253be
|
||||
F src/delete.c 923497248e0ff9097a595c6333ec6d67fe6650b5
|
||||
F src/encode.c faf03741efe921755ec371cf4a6984536de00042
|
||||
F src/expr.c eae205a27ec45232f234f281f8827c3be58b303d
|
||||
@@ -30,20 +30,20 @@ F src/func.c 882c3ed5a02be18cd904715c7ec62947a34a3605
|
||||
F src/hash.c 4fc39feb7b7711f6495ee9f2159559bedb043e1f
|
||||
F src/hash.h cd0433998bc1a3759d244e1637fe5a3c13b53bf8
|
||||
F src/insert.c 95e7ab3fb51909351273a6c6f8aa831201130ce7
|
||||
F src/main.c df729d604e3055b8081e3d4348983dfd30d2835d
|
||||
F src/main.c 6d9a38491fdc40c041df64a7399244c364481a09
|
||||
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
|
||||
F src/os.c dfed46091f69cd2d1e601f8a214d41344f2b00b6
|
||||
F src/os.h aa52f0c9da321ff6134d19f2ca959e18e33615d0
|
||||
F src/pager.c dd1dfa4d929a58b44175f3117360ff1553671173
|
||||
F src/pager.h 97d9a8cc5103750efd8037d71ebfb41849ef2f2f
|
||||
F src/parse.y 243cfc277d0e5ce87086c015e717dec98d6648a7
|
||||
F src/parse.y 3be47fa18323aa2e3364fc42bf7a6ba5b3cc0a81
|
||||
F src/printf.c fc5fdef6e92ad205005263661fe9716f55a49f3e
|
||||
F src/random.c 19e8e00fe0df32a742f115773f57651be327cabe
|
||||
F src/select.c afdc06d4606d14ab5793ef480206def6b02a2f19
|
||||
F src/shell.c c13ff46e905a59eb1c7dbea7c1850f8f115e6395
|
||||
F src/shell.tcl 27ecbd63dd88396ad16d81ab44f73e6c0ea9d20e
|
||||
F src/sqlite.h.in 91f94c73514477ffef54aaa452f7fcb62fc59d1e
|
||||
F src/sqliteInt.h 5335f694cba9f07538cf8207aab11d48e0b9a2f8
|
||||
F src/sqlite.h.in be3e56214fecc73d72195ca62d8a3d6663602ff4
|
||||
F src/sqliteInt.h b86c03c496bdc9ff543a12a1d88766fbcf28cd0c
|
||||
F src/table.c eed2098c9b577aa17f8abe89313a9c4413f57d63
|
||||
F src/tclsqlite.c 4cb0ffa863123ae037db359849a231ff5cebfed4
|
||||
F src/test1.c 7ad4e6308dde0bf5a0f0775ce20cb2ec37a328f8
|
||||
@@ -155,7 +155,7 @@ F www/speed.tcl cb4c10a722614aea76d2c51f32ee43400d5951be
|
||||
F www/sqlite.tcl ae3dcfb077e53833b59d4fcc94d8a12c50a44098
|
||||
F www/tclsqlite.tcl 1db15abeb446aad0caf0b95b8b9579720e4ea331
|
||||
F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218
|
||||
P b6d6e07f3a5cb493f2cf0675bc6061c5afe5c078
|
||||
R 359232b433a24865017ceb4c15ffe33b
|
||||
P 0a358844e40020557c1aeea5779b194670350930
|
||||
R b07af9b76a439a5b405050fd15558aa2
|
||||
U drh
|
||||
Z b46b224b9a3ce8983137da5d0635bd02
|
||||
Z 8c6d8642908a4e47e8f8d0600ce4a4a6
|
||||
|
@@ -1 +1 @@
|
||||
0a358844e40020557c1aeea5779b194670350930
|
||||
c7c5e927a54f0fbc2ca625754787aff4d9c4eff1
|
167
src/build.c
167
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);
|
||||
}
|
||||
|
171
src/main.c
171
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 );
|
||||
|
12
src/parse.y
12
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);
|
||||
}
|
||||
|
@@ -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 */
|
||||
|
||||
|
@@ -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*);
|
||||
|
Reference in New Issue
Block a user