1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-07 02:42:48 +03:00

Eliminate the use of callbacks during schema initialization. (CVS 1242)

FossilOrigin-Name: af5c2be4aed1c50f69eb9634cf051a26263dcf51
This commit is contained in:
drh
2004-02-14 23:05:52 +00:00
parent 8a6ac0adbc
commit 1d85d93158
6 changed files with 109 additions and 98 deletions

View File

@@ -1,5 +1,5 @@
C Fix\sproblems\swith\smalloc-failure\shandling.\s(CVS\s1241) C Eliminate\sthe\suse\sof\scallbacks\sduring\sschema\sinitialization.\s(CVS\s1242)
D 2004-02-14T17:35:07 D 2004-02-14T23:05:53
F Makefile.in cfd75c46b335881999333a9e4b982fa8491f200b F Makefile.in cfd75c46b335881999333a9e4b982fa8491f200b
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@@ -26,7 +26,7 @@ F src/auth.c c59ad0dab501888f8b1fccc25e2f5965d2265116
F src/btree.c 0a40efb01fa3a431a16d8604f603431d8c9cebfa F src/btree.c 0a40efb01fa3a431a16d8604f603431d8c9cebfa
F src/btree.h 41cb3ff6ebc3f6da2d0a074e39ff8c7a2287469f F src/btree.h 41cb3ff6ebc3f6da2d0a074e39ff8c7a2287469f
F src/btree_rb.c 32b2cb4285c0fbd53b89de021637b63d52257e54 F src/btree_rb.c 32b2cb4285c0fbd53b89de021637b63d52257e54
F src/build.c 94fdf4d8abe56f957a519d139b0e49a92cbfb242 F src/build.c f8cef53c4e11a102a0d33000ba5f108a1fb48ac9
F src/copy.c 9e47975ea96751c658bcf1a0c4f0bb7c6ee61e73 F src/copy.c 9e47975ea96751c658bcf1a0c4f0bb7c6ee61e73
F src/date.c c9d2bfd40b1c95f8f97d53a5eba981d7167c7b61 F src/date.c c9d2bfd40b1c95f8f97d53a5eba981d7167c7b61
F src/delete.c 0778fe05df0a1d62ac27fd1a3dba237c186ff4d1 F src/delete.c 0778fe05df0a1d62ac27fd1a3dba237c186ff4d1
@@ -36,7 +36,7 @@ F src/func.c cbc5edd10c82a5193b9ca0726873328be445e6c1
F src/hash.c 9b56ef3b291e25168f630d5643a4264ec011c70e F src/hash.c 9b56ef3b291e25168f630d5643a4264ec011c70e
F src/hash.h 3247573ab95b9dd90bcca0307a75d9a16da1ccc7 F src/hash.h 3247573ab95b9dd90bcca0307a75d9a16da1ccc7
F src/insert.c 01f66866f35c986eab4a57373ca689a3255ef2df F src/insert.c 01f66866f35c986eab4a57373ca689a3255ef2df
F src/main.c 1e4647001f9015c00bb2285b6b155a09980f4d93 F src/main.c e803d6cc6d57e85e12e61a04768f14ff644a4180
F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565 F src/md5.c fe4f9c9c6f71dfc26af8da63e4d04489b1430565
F src/os.c f5fc4954725b2fcd852979f2746085fe8ca27710 F src/os.c f5fc4954725b2fcd852979f2746085fe8ca27710
F src/os.h 250a3789be609adfee5c5aa20137ce8683276f24 F src/os.h 250a3789be609adfee5c5aa20137ce8683276f24
@@ -49,7 +49,7 @@ F src/random.c 775913e0b7fbd6295d21f12a7bd35b46387c44b2
F src/select.c 7cbd9cca5294399657da9e2d6c441add4610fb18 F src/select.c 7cbd9cca5294399657da9e2d6c441add4610fb18
F src/shell.c c3d3404fa82bb0808444fda9884d1bb572fd18b9 F src/shell.c c3d3404fa82bb0808444fda9884d1bb572fd18b9
F src/sqlite.h.in 64f016cd5ce190643a0f47760188fdf4e0b2227e F src/sqlite.h.in 64f016cd5ce190643a0f47760188fdf4e0b2227e
F src/sqliteInt.h c45fbae6278407111d7a00aa9280ddc0f51344ad F src/sqliteInt.h 3b64ff750133c656badcedd7cf7e1e425e4aa693
F src/table.c d845cb101b5afc1f7fea083c99e3d2fa7998d895 F src/table.c d845cb101b5afc1f7fea083c99e3d2fa7998d895
F src/tclsqlite.c b84dafe3a8532ff534c36e96bd38880e4b9cedf3 F src/tclsqlite.c b84dafe3a8532ff534c36e96bd38880e4b9cedf3
F src/test1.c 56e9a156df3ad5e4e98df776776e963effc727f7 F src/test1.c 56e9a156df3ad5e4e98df776776e963effc727f7
@@ -57,7 +57,7 @@ F src/test2.c 75819b0f2c63c6a0fd6995445881f2eb94036996
F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5 F src/test3.c 30985ebdfaf3ee1462a9b0652d3efbdc8d9798f5
F src/test4.c dcbbbb382626fd466a7c46907f74db35fc8bad64 F src/test4.c dcbbbb382626fd466a7c46907f74db35fc8bad64
F src/tokenize.c 8c95dcd2620b18dc0db1cdc97f9e111d11e55fe0 F src/tokenize.c 8c95dcd2620b18dc0db1cdc97f9e111d11e55fe0
F src/trigger.c ce83e017b407d046e909d05373d7f8ee70f9f7f9 F src/trigger.c c647a442427fb8c1cd761eb03b1710c9d5675a8b
F src/update.c 24260b4fda00c9726d27699a0561d53c0dccc397 F src/update.c 24260b4fda00c9726d27699a0561d53c0dccc397
F src/util.c 64995b5949a5d377629ffd2598747bc771cade1e F src/util.c 64995b5949a5d377629ffd2598747bc771cade1e
F src/vacuum.c d9e80c2b36ee1f623dbf1bdf3cedad24a23f87ac F src/vacuum.c d9e80c2b36ee1f623dbf1bdf3cedad24a23f87ac
@@ -184,7 +184,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
P 9771ad1e811e02e10bb738550fbea447749083c5 P 398bc294c839368e7fa75a97ba8cc8d1639f9436
R 2dd38e1847aebff09cd4368ba627e231 R 2c93489f2ccfbeec94078a6113e1dd06
U drh U drh
Z c4bcf89beb16b0907aa99e04bfa67229 Z 914d3c303ed4bd19601ee7fa1346d33f

View File

@@ -1 +1 @@
398bc294c839368e7fa75a97ba8cc8d1639f9436 af5c2be4aed1c50f69eb9634cf051a26263dcf51

View File

@@ -23,7 +23,7 @@
** ROLLBACK ** ROLLBACK
** PRAGMA ** PRAGMA
** **
** $Id: build.c,v 1.168 2004/02/14 16:31:03 drh Exp $ ** $Id: build.c,v 1.169 2004/02/14 23:05:53 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include <ctype.h> #include <ctype.h>
@@ -38,7 +38,7 @@ void sqliteBeginParse(Parse *pParse, int explainFlag){
sqlite *db = pParse->db; sqlite *db = pParse->db;
int i; int i;
pParse->explain = explainFlag; pParse->explain = explainFlag;
if((db->flags & SQLITE_Initialized)==0 && pParse->initFlag==0 ){ if((db->flags & SQLITE_Initialized)==0 && db->init.busy==0 ){
int rc = sqliteInit(db, &pParse->zErrMsg); int rc = sqliteInit(db, &pParse->zErrMsg);
if( rc!=SQLITE_OK ){ if( rc!=SQLITE_OK ){
pParse->rc = rc; pParse->rc = rc;
@@ -471,7 +471,7 @@ void sqliteStartTable(
pParse->sFirstToken = *pStart; pParse->sFirstToken = *pStart;
zName = sqliteTableNameFromToken(pName); zName = sqliteTableNameFromToken(pName);
if( zName==0 ) return; if( zName==0 ) return;
if( pParse->iDb==1 ) isTemp = 1; if( db->init.iDb==1 ) isTemp = 1;
#ifndef SQLITE_OMIT_AUTHORIZATION #ifndef SQLITE_OMIT_AUTHORIZATION
assert( (isTemp & 1)==isTemp ); assert( (isTemp & 1)==isTemp );
{ {
@@ -532,8 +532,8 @@ void sqliteStartTable(
** an existing temporary table, that is not an error. ** an existing temporary table, that is not an error.
*/ */
pTable = sqliteFindTable(db, zName, 0); pTable = sqliteFindTable(db, zName, 0);
iDb = isTemp ? 1 : pParse->iDb; iDb = isTemp ? 1 : db->init.iDb;
if( pTable!=0 && (pTable->iDb==iDb || !pParse->initFlag) ){ if( pTable!=0 && (pTable->iDb==iDb || !db->init.busy) ){
sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n, sqliteSetNString(&pParse->zErrMsg, "table ", 0, pName->z, pName->n,
" already exists", 0, 0); " already exists", 0, 0);
sqliteFree(zName); sqliteFree(zName);
@@ -541,7 +541,7 @@ void sqliteStartTable(
return; return;
} }
if( (pIdx = sqliteFindIndex(db, zName, 0))!=0 && if( (pIdx = sqliteFindIndex(db, zName, 0))!=0 &&
(pIdx->iDb==0 || !pParse->initFlag) ){ (pIdx->iDb==0 || !db->init.busy) ){
sqliteSetString(&pParse->zErrMsg, "there is already an index named ", sqliteSetString(&pParse->zErrMsg, "there is already an index named ",
zName, (char*)0); zName, (char*)0);
sqliteFree(zName); sqliteFree(zName);
@@ -570,7 +570,7 @@ void sqliteStartTable(
** indices. Hence, the record number for the table must be allocated ** indices. Hence, the record number for the table must be allocated
** now. ** now.
*/ */
if( !pParse->initFlag && (v = sqliteGetVdbe(pParse))!=0 ){ if( !db->init.busy && (v = sqliteGetVdbe(pParse))!=0 ){
sqliteBeginWriteOperation(pParse, 0, isTemp); sqliteBeginWriteOperation(pParse, 0, isTemp);
if( !isTemp ){ if( !isTemp ){
sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0); sqliteVdbeAddOp(v, OP_Integer, db->file_format, 0);
@@ -927,8 +927,8 @@ static char *createTableStmt(Table *p){
** is added to the internal hash tables, assuming no errors have ** is added to the internal hash tables, assuming no errors have
** occurred. ** occurred.
** **
** An entry for the table is made in the master table on disk, ** An entry for the table is made in the master table on disk, unless
** unless this is a temporary table or initFlag==1. When initFlag==1, ** this is a temporary table or db->init.busy==1. When db->init.busy==1
** it means we are reading the sqlite_master table because we just ** it means we are reading the sqlite_master table because we just
** connected to the database or because the sqlite_master table has ** connected to the database or because the sqlite_master table has
** recently changes, so the entry for this table already exists in ** recently changes, so the entry for this table already exists in
@@ -961,14 +961,14 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
sqliteDeleteTable(0, pSelTab); sqliteDeleteTable(0, pSelTab);
} }
/* If the initFlag is 1 it means we are reading the SQL off the /* If the db->init.busy is 1 it means we are reading the SQL off the
** "sqlite_master" or "sqlite_temp_master" table on the disk. ** "sqlite_master" or "sqlite_temp_master" table on the disk.
** So do not write to the disk again. Extract the root page number ** So do not write to the disk again. Extract the root page number
** for the table from the pParse->newTnum field. (The page number ** for the table from the db->init.newTnum field. (The page number
** should have been put there by the sqliteOpenCb routine.) ** should have been put there by the sqliteOpenCb routine.)
*/ */
if( pParse->initFlag ){ if( db->init.busy ){
p->tnum = pParse->newTnum; p->tnum = db->init.newTnum;
} }
/* If not initializing, then create a record for the new table /* If not initializing, then create a record for the new table
@@ -978,7 +978,7 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
** If this is a TEMPORARY table, write the entry into the auxiliary ** If this is a TEMPORARY table, write the entry into the auxiliary
** file instead of into the main database file. ** file instead of into the main database file.
*/ */
if( !pParse->initFlag ){ if( !db->init.busy ){
int n; int n;
Vdbe *v; Vdbe *v;
@@ -1001,9 +1001,9 @@ void sqliteEndTable(Parse *pParse, Token *pEnd, Select *pSelect){
sqliteVdbeChangeP3(v, -1, "view", P3_STATIC); sqliteVdbeChangeP3(v, -1, "view", P3_STATIC);
} }
sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, p->zName, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, p->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, p->zName, 0);
sqliteVdbeAddOp(v, OP_Dup, 4, 0); sqliteVdbeAddOp(v, OP_Dup, 4, 0);
sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0);
if( pSelect ){ if( pSelect ){
@@ -1089,7 +1089,7 @@ void sqliteCreateView(
*/ */
p->pSelect = sqliteSelectDup(pSelect); p->pSelect = sqliteSelectDup(pSelect);
sqliteSelectDelete(pSelect); sqliteSelectDelete(pSelect);
if( !pParse->initFlag ){ if( !pParse->db->init.busy ){
sqliteViewGetColumnNames(pParse, p); sqliteViewGetColumnNames(pParse, p);
} }
@@ -1567,8 +1567,8 @@ void sqliteCreateIndex(
sqlite *db = pParse->db; sqlite *db = pParse->db;
if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index; if( pParse->nErr || sqlite_malloc_failed ) goto exit_create_index;
if( pParse->initFlag if( db->init.busy
&& sqliteFixInit(&sFix, pParse, pParse->iDb, "index", pName) && sqliteFixInit(&sFix, pParse, db->init.iDb, "index", pName)
&& sqliteFixSrcList(&sFix, pTable) && sqliteFixSrcList(&sFix, pTable)
){ ){
goto exit_create_index; goto exit_create_index;
@@ -1592,7 +1592,7 @@ void sqliteCreateIndex(
pParse->nErr++; pParse->nErr++;
goto exit_create_index; goto exit_create_index;
} }
if( pTab->iDb>=2 && pParse->initFlag==0 ){ if( pTab->iDb>=2 && db->init.busy==0 ){
sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName, sqliteSetString(&pParse->zErrMsg, "table ", pTab->zName,
" may not have indices added", (char*)0); " may not have indices added", (char*)0);
pParse->nErr++; pParse->nErr++;
@@ -1618,7 +1618,7 @@ void sqliteCreateIndex(
** dealing with a primary key or UNIQUE constraint. We have to invent our ** dealing with a primary key or UNIQUE constraint. We have to invent our
** own name. ** own name.
*/ */
if( pName && !pParse->initFlag ){ if( pName && !db->init.busy ){
Index *pISameName; /* Another index with the same name */ Index *pISameName; /* Another index with the same name */
Table *pTSameName; /* A table with same name as the index */ Table *pTSameName; /* A table with same name as the index */
zName = sqliteStrNDup(pName->z, pName->n); zName = sqliteStrNDup(pName->z, pName->n);
@@ -1654,7 +1654,7 @@ void sqliteCreateIndex(
{ {
const char *zDb = db->aDb[pTab->iDb].zName; const char *zDb = db->aDb[pTab->iDb].zName;
assert( pTab->iDb==pParse->iDb || isTemp ); assert( pTab->iDb==db->init.iDb || isTemp );
if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){ if( sqliteAuthCheck(pParse, SQLITE_INSERT, SCHEMA_TABLE(isTemp), 0, zDb) ){
goto exit_create_index; goto exit_create_index;
} }
@@ -1690,7 +1690,7 @@ void sqliteCreateIndex(
pIndex->nColumn = pList->nId; pIndex->nColumn = pList->nId;
pIndex->onError = onError; pIndex->onError = onError;
pIndex->autoIndex = pName==0; pIndex->autoIndex = pName==0;
pIndex->iDb = isTemp ? 1 : pParse->iDb; pIndex->iDb = isTemp ? 1 : db->init.iDb;
/* Scan the names of the columns of the table to be indexed and /* Scan the names of the columns of the table to be indexed and
** load the column indices into the Index structure. Report an error ** load the column indices into the Index structure. Report an error
@@ -1743,20 +1743,20 @@ void sqliteCreateIndex(
pOther->pNext = pIndex; pOther->pNext = pIndex;
} }
/* If the initFlag is 1 it means we are reading the SQL off the /* If the db->init.busy is 1 it means we are reading the SQL off the
** "sqlite_master" table on the disk. So do not write to the disk ** "sqlite_master" table on the disk. So do not write to the disk
** again. Extract the table number from the pParse->newTnum field. ** again. Extract the table number from the db->init.newTnum field.
*/ */
if( pParse->initFlag && pTable!=0 ){ if( db->init.busy && pTable!=0 ){
pIndex->tnum = pParse->newTnum; pIndex->tnum = db->init.newTnum;
} }
/* If the initFlag is 0 then create the index on disk. This /* If the db->init.busy is 0 then create the index on disk. This
** involves writing the index into the master table and filling in the ** involves writing the index into the master table and filling in the
** index with the current table contents. ** index with the current table contents.
** **
** The initFlag is 0 when the user first enters a CREATE INDEX ** The db->init.busy is 0 when the user first enters a CREATE INDEX
** command. The initFlag is 1 when a database is opened and ** command. db->init.busy is 1 when a database is opened and
** CREATE INDEX statements are read out of the master table. In ** CREATE INDEX statements are read out of the master table. In
** the latter case the index already exists on disk, which is why ** the latter case the index already exists on disk, which is why
** we don't want to recreate it. ** we don't want to recreate it.
@@ -1766,7 +1766,7 @@ void sqliteCreateIndex(
** has just been created, it contains no data and the index initialization ** has just been created, it contains no data and the index initialization
** step can be skipped. ** step can be skipped.
*/ */
else if( pParse->initFlag==0 ){ else if( db->init.busy==0 ){
int n; int n;
Vdbe *v; Vdbe *v;
int lbl1, lbl2; int lbl1, lbl2;
@@ -1785,7 +1785,7 @@ void sqliteCreateIndex(
sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pIndex->zName, strlen(pIndex->zName)); sqliteVdbeChangeP3(v, -1, pIndex->zName, strlen(pIndex->zName));
sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_String, 0, 0);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, 0);
addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, isTemp); addr = sqliteVdbeAddOp(v, OP_CreateIndex, 0, isTemp);
sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, P3_POINTER); sqliteVdbeChangeP3(v, addr, (char*)&pIndex->tnum, P3_POINTER);
pIndex->tnum = 0; pIndex->tnum = 0;
@@ -1804,7 +1804,7 @@ void sqliteCreateIndex(
if( pTable ){ if( pTable ){
sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqliteVdbeAddOp(v, OP_Integer, pTab->iDb, 0);
sqliteVdbeAddOp(v, OP_OpenRead, 2, pTab->tnum); sqliteVdbeAddOp(v, OP_OpenRead, 2, pTab->tnum);
sqliteVdbeChangeP3(v, -1, pTab->zName, P3_STATIC); sqliteVdbeChangeP3(v, -1, pTab->zName, 0);
lbl2 = sqliteVdbeMakeLabel(v); lbl2 = sqliteVdbeMakeLabel(v);
sqliteVdbeAddOp(v, OP_Rewind, 2, lbl2); sqliteVdbeAddOp(v, OP_Rewind, 2, lbl2);
lbl1 = sqliteVdbeAddOp(v, OP_Recno, 2, 0); lbl1 = sqliteVdbeAddOp(v, OP_Recno, 2, 0);

View File

@@ -14,7 +14,7 @@
** other files are for internal use by SQLite and should not be ** other files are for internal use by SQLite and should not be
** accessed by users of the library. ** accessed by users of the library.
** **
** $Id: main.c,v 1.153 2004/02/14 17:35:07 drh Exp $ ** $Id: main.c,v 1.154 2004/02/14 23:05:53 drh Exp $
*/ */
#include "sqliteInt.h" #include "sqliteInt.h"
#include "os.h" #include "os.h"
@@ -33,8 +33,9 @@ typedef struct {
** Fill the InitData structure with an error message that indicates ** Fill the InitData structure with an error message that indicates
** that the database is corrupt. ** that the database is corrupt.
*/ */
static void corruptSchema(InitData *pData){ static void corruptSchema(InitData *pData, const char *zExtra){
sqliteSetString(pData->pzErrMsg, "malformed database schema", (char*)0); sqliteSetString(pData->pzErrMsg, "malformed database schema",
zExtra!=0 && zExtra[0]!=0 ? " - " : (char*)0, zExtra, (char*)0);
} }
/* /*
@@ -54,36 +55,39 @@ static void corruptSchema(InitData *pData){
static static
int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
InitData *pData = (InitData*)pInit; InitData *pData = (InitData*)pInit;
Parse sParse;
int nErr = 0; int nErr = 0;
assert( argc==5 ); assert( argc==5 );
if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */ if( argv==0 ) return 0; /* Might happen if EMPTY_RESULT_CALLBACKS are on */
if( argv[0]==0 ){ if( argv[0]==0 ){
corruptSchema(pData); corruptSchema(pData, 0);
return 1; return 1;
} }
switch( argv[0][0] ){ switch( argv[0][0] ){
case 'v': case 'v':
case 'i': case 'i':
case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */ case 't': { /* CREATE TABLE, CREATE INDEX, or CREATE VIEW statements */
sqlite *db = pData->db;
if( argv[2]==0 || argv[4]==0 ){ if( argv[2]==0 || argv[4]==0 ){
corruptSchema(pData); corruptSchema(pData, 0);
return 1; return 1;
} }
if( argv[3] && argv[3][0] ){ if( argv[3] && argv[3][0] ){
/* Call the parser to process a CREATE TABLE, INDEX or VIEW. /* Call the parser to process a CREATE TABLE, INDEX or VIEW.
** But because sParse.initFlag is set to 1, no VDBE code is generated ** But because db->init.busy is set to 1, no VDBE code is generated
** or executed. All the parser does is build the internal data ** or executed. All the parser does is build the internal data
** structures that describe the table, index, or view. ** structures that describe the table, index, or view.
*/ */
memset(&sParse, 0, sizeof(sParse)); char *zErr;
sParse.db = pData->db; assert( db->init.busy );
sParse.initFlag = 1; db->init.iDb = atoi(argv[4]);
sParse.iDb = atoi(argv[4]); assert( db->init.iDb>=0 && db->init.iDb<db->nDb );
sParse.newTnum = atoi(argv[2]); db->init.newTnum = atoi(argv[2]);
sParse.useCallback = 1; if( sqlite_exec(db, argv[3], 0, 0, &zErr) ){
sqliteRunParser(&sParse, argv[3], pData->pzErrMsg); corruptSchema(pData, zErr);
sqlite_freemem(zErr);
}
db->init.iDb = 0;
}else{ }else{
/* If the SQL column is blank it means this is an index that /* 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 ** was created to be the PRIMARY KEY or to fulfill a UNIQUE
@@ -95,8 +99,8 @@ int sqliteInitCallback(void *pInit, int argc, char **argv, char **azColName){
Index *pIndex; Index *pIndex;
iDb = atoi(argv[4]); iDb = atoi(argv[4]);
assert( iDb>=0 && iDb<pData->db->nDb ); assert( iDb>=0 && iDb<db->nDb );
pIndex = sqliteFindIndex(pData->db, argv[1], pData->db->aDb[iDb].zName); pIndex = sqliteFindIndex(db, argv[1], db->aDb[iDb].zName);
if( pIndex==0 || pIndex->tnum!=0 ){ if( pIndex==0 || pIndex->tnum!=0 ){
/* This can occur if there exists an index on a TEMP table which /* This can occur if there exists an index on a TEMP table which
** has the same name as another index on a permanent index. Since ** has the same name as another index on a permanent index. Since
@@ -188,7 +192,6 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
char *azArg[6]; char *azArg[6];
char zDbNum[30]; char zDbNum[30];
int meta[SQLITE_N_BTREE_META]; int meta[SQLITE_N_BTREE_META];
Parse sParse;
InitData initData; InitData initData;
/* /*
@@ -245,6 +248,7 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
/* Construct the schema tables: sqlite_master and sqlite_temp_master /* Construct the schema tables: sqlite_master and sqlite_temp_master
*/ */
sqliteSafetyOff(db);
azArg[0] = "table"; azArg[0] = "table";
azArg[1] = MASTER_NAME; azArg[1] = MASTER_NAME;
azArg[2] = "2"; azArg[2] = "2";
@@ -269,6 +273,7 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
pTab->readOnly = 1; pTab->readOnly = 1;
} }
} }
sqliteSafetyOn(db);
/* Create a cursor to hold the database open /* Create a cursor to hold the database open
*/ */
@@ -330,31 +335,28 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
/* Read the schema information out of the schema tables /* Read the schema information out of the schema tables
*/ */
memset(&sParse, 0, sizeof(sParse)); assert( db->init.busy );
sParse.db = db; sqliteSafetyOff(db);
sParse.xCallback = sqliteInitCallback;
sParse.pArg = (void*)&initData;
sParse.initFlag = 1;
sParse.useCallback = 1;
if( iDb==0 ){ if( iDb==0 ){
sqliteRunParser(&sParse, rc = sqlite_exec(db,
db->file_format>=2 ? init_script : older_init_script, db->file_format>=2 ? init_script : older_init_script,
pzErrMsg); sqliteInitCallback, &initData, 0);
}else{ }else{
char *zSql = 0; char *zSql = 0;
sqliteSetString(&zSql, sqliteSetString(&zSql,
"SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"", "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"",
db->aDb[iDb].zName, "\".sqlite_master", (char*)0); db->aDb[iDb].zName, "\".sqlite_master", (char*)0);
sqliteRunParser(&sParse, zSql, pzErrMsg); rc = sqlite_exec(db, zSql, sqliteInitCallback, &initData, 0);
sqliteFree(zSql); sqliteFree(zSql);
} }
sqliteSafetyOn(db);
sqliteBtreeCloseCursor(curMain); sqliteBtreeCloseCursor(curMain);
if( sqlite_malloc_failed ){ if( sqlite_malloc_failed ){
sqliteSetString(pzErrMsg, "out of memory", (char*)0); sqliteSetString(pzErrMsg, "out of memory", (char*)0);
sParse.rc = SQLITE_NOMEM; rc = SQLITE_NOMEM;
sqliteResetInternalSchema(db, 0); sqliteResetInternalSchema(db, 0);
} }
if( sParse.rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
DbSetProperty(db, iDb, DB_SchemaLoaded); DbSetProperty(db, iDb, DB_SchemaLoaded);
if( iDb==0 ){ if( iDb==0 ){
DbSetProperty(db, 1, DB_SchemaLoaded); DbSetProperty(db, 1, DB_SchemaLoaded);
@@ -362,7 +364,7 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
}else{ }else{
sqliteResetInternalSchema(db, iDb); sqliteResetInternalSchema(db, iDb);
} }
return sParse.rc; return rc;
} }
/* /*
@@ -381,8 +383,10 @@ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){
int sqliteInit(sqlite *db, char **pzErrMsg){ int sqliteInit(sqlite *db, char **pzErrMsg){
int i, rc; int i, rc;
if( db->init.busy ) return SQLITE_OK;
assert( (db->flags & SQLITE_Initialized)==0 ); assert( (db->flags & SQLITE_Initialized)==0 );
rc = SQLITE_OK; rc = SQLITE_OK;
db->init.busy = 1;
for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ for(i=0; rc==SQLITE_OK && i<db->nDb; i++){
if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue; if( DbHasProperty(db, i, DB_SchemaLoaded) ) continue;
assert( i!=1 ); /* Should have been initialized together with 0 */ assert( i!=1 ); /* Should have been initialized together with 0 */
@@ -391,6 +395,7 @@ int sqliteInit(sqlite *db, char **pzErrMsg){
sqliteResetInternalSchema(db, i); sqliteResetInternalSchema(db, i);
} }
} }
db->init.busy = 0;
if( rc==SQLITE_OK ){ if( rc==SQLITE_OK ){
db->flags |= SQLITE_Initialized; db->flags |= SQLITE_Initialized;
sqliteCommitInternalChanges(db); sqliteCommitInternalChanges(db);
@@ -669,25 +674,29 @@ int sqlite_compile(
if( pzErrMsg ) *pzErrMsg = 0; if( pzErrMsg ) *pzErrMsg = 0;
if( sqliteSafetyOn(db) ) goto exec_misuse; if( sqliteSafetyOn(db) ) goto exec_misuse;
if( (db->flags & SQLITE_Initialized)==0 ){ if( !db->init.busy ){
int rc, cnt = 1; if( (db->flags & SQLITE_Initialized)==0 ){
while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY int rc, cnt = 1;
&& db->xBusyCallback && db->xBusyCallback(db->pBusyArg, "", cnt++)!=0 ){} while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY
if( rc!=SQLITE_OK ){ && db->xBusyCallback
sqliteStrRealloc(pzErrMsg); && db->xBusyCallback(db->pBusyArg, "", cnt++)!=0 ){}
if( rc!=SQLITE_OK ){
sqliteStrRealloc(pzErrMsg);
sqliteSafetyOff(db);
return rc;
}
if( pzErrMsg ){
sqliteFree(*pzErrMsg);
*pzErrMsg = 0;
}
}
if( db->file_format<3 ){
sqliteSafetyOff(db); sqliteSafetyOff(db);
return rc; sqliteSetString(pzErrMsg, "obsolete database file format", (char*)0);
} return SQLITE_ERROR;
if( pzErrMsg ){
sqliteFree(*pzErrMsg);
*pzErrMsg = 0;
} }
} }
if( db->file_format<3 ){ assert( (db->flags & SQLITE_Initialized)!=0 || db->init.busy );
sqliteSafetyOff(db);
sqliteSetString(pzErrMsg, "obsolete database file format", (char*)0);
return SQLITE_ERROR;
}
if( db->pVdbe==0 ){ db->nChange = 0; } if( db->pVdbe==0 ){ db->nChange = 0; }
memset(&sParse, 0, sizeof(sParse)); memset(&sParse, 0, sizeof(sParse));
sParse.db = db; sParse.db = db;

View File

@@ -11,7 +11,7 @@
************************************************************************* *************************************************************************
** Internal interface definitions for SQLite. ** Internal interface definitions for SQLite.
** **
** @(#) $Id: sqliteInt.h,v 1.211 2004/02/12 18:46:39 drh Exp $ ** @(#) $Id: sqliteInt.h,v 1.212 2004/02/14 23:05:53 drh Exp $
*/ */
#include "config.h" #include "config.h"
#include "sqlite.h" #include "sqlite.h"
@@ -318,9 +318,10 @@ struct sqlite {
u8 file_format; /* What file format version is this database? */ u8 file_format; /* What file format version is this database? */
u8 safety_level; /* How aggressive at synching data to disk */ u8 safety_level; /* How aggressive at synching data to disk */
u8 want_to_close; /* Close after all VDBEs are deallocated */ u8 want_to_close; /* Close after all VDBEs are deallocated */
u8 temp_store; /* 1=file, 2=memory, 0=compile-time default */
u8 onError; /* Default conflict algorithm */
int next_cookie; /* Next value of aDb[0].schema_cookie */ int next_cookie; /* Next value of aDb[0].schema_cookie */
int cache_size; /* Number of pages to use in the cache */ int cache_size; /* Number of pages to use in the cache */
int temp_store; /* 1=file, 2=memory, 0=compile-time default */
int nTable; /* Number of tables in the database */ int nTable; /* Number of tables in the database */
void *pBusyArg; /* 1st Argument to the busy callback */ void *pBusyArg; /* 1st Argument to the busy callback */
int (*xBusyCallback)(void *,const char*,int); /* The busy callback */ int (*xBusyCallback)(void *,const char*,int); /* The busy callback */
@@ -329,9 +330,13 @@ struct sqlite {
Hash aFunc; /* All functions that can be in SQL exprs */ Hash aFunc; /* All functions that can be in SQL exprs */
int lastRowid; /* ROWID of most recent insert */ int lastRowid; /* ROWID of most recent insert */
int priorNewRowid; /* Last randomly generated ROWID */ int priorNewRowid; /* Last randomly generated ROWID */
int onError; /* Default conflict algorithm */
int magic; /* Magic number for detect library misuse */ int magic; /* Magic number for detect library misuse */
int nChange; /* Number of rows changed */ int nChange; /* Number of rows changed */
struct sqliteInitInfo { /* Information used during initialization */
int iDb; /* When back is being initialized */
int newTnum; /* Rootpage of table being initialized */
u8 busy; /* TRUE if currently initializing */
} init;
struct Vdbe *pVdbe; /* List of active virtual machines */ struct Vdbe *pVdbe; /* List of active virtual machines */
void (*xTrace)(void*,const char*); /* Trace function */ void (*xTrace)(void*,const char*); /* Trace function */
void *pTraceArg; /* Argument to the trace function */ void *pTraceArg; /* Argument to the trace function */
@@ -878,13 +883,10 @@ struct Parse {
Vdbe *pVdbe; /* An engine for executing database bytecode */ Vdbe *pVdbe; /* An engine for executing database bytecode */
u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */ u8 colNamesSet; /* TRUE after OP_ColumnName has been issued to pVdbe */
u8 explain; /* True if the EXPLAIN flag is found on the query */ u8 explain; /* True if the EXPLAIN flag is found on the query */
u8 initFlag; /* True if reparsing CREATE TABLEs */
u8 nameClash; /* A permanent table name clashes with temp table name */ u8 nameClash; /* A permanent table name clashes with temp table name */
u8 useAgg; /* If true, extract field values from the aggregator u8 useAgg; /* If true, extract field values from the aggregator
** while generating expressions. Normally false */ ** while generating expressions. Normally false */
u8 iDb; /* Index of database whose schema is being parsed */
u8 useCallback; /* True if callbacks should be used to report results */ u8 useCallback; /* True if callbacks should be used to report results */
int newTnum; /* Table number to use when reparsing CREATE TABLEs */
int nErr; /* Number of errors seen */ int nErr; /* Number of errors seen */
int nTab; /* Number of previously allocated VDBE cursors */ int nTab; /* Number of previously allocated VDBE cursors */
int nMem; /* Number of memory cells used so far */ int nMem; /* Number of memory cells used so far */

View File

@@ -65,8 +65,8 @@ void sqliteBeginTrigger(
*/ */
if( sqlite_malloc_failed ) goto trigger_cleanup; if( sqlite_malloc_failed ) goto trigger_cleanup;
assert( pTableName->nSrc==1 ); assert( pTableName->nSrc==1 );
if( pParse->initFlag if( db->init.busy
&& sqliteFixInit(&sFix, pParse, pParse->iDb, "trigger", pName) && sqliteFixInit(&sFix, pParse, db->init.iDb, "trigger", pName)
&& sqliteFixSrcList(&sFix, pTableName) && sqliteFixSrcList(&sFix, pTableName)
){ ){
goto trigger_cleanup; goto trigger_cleanup;
@@ -76,7 +76,7 @@ void sqliteBeginTrigger(
goto trigger_cleanup; goto trigger_cleanup;
} }
iDb = isTemp ? 1 : tab->iDb; iDb = isTemp ? 1 : tab->iDb;
if( iDb>=2 && !pParse->initFlag ){ if( iDb>=2 && !db->init.busy ){
sqliteErrorMsg(pParse, "triggers may not be added to auxiliary " sqliteErrorMsg(pParse, "triggers may not be added to auxiliary "
"database %s", db->aDb[tab->iDb].zName); "database %s", db->aDb[tab->iDb].zName);
goto trigger_cleanup; goto trigger_cleanup;
@@ -181,7 +181,7 @@ void sqliteFinishTrigger(
/* if we are not initializing, and this trigger is not on a TEMP table, /* if we are not initializing, and this trigger is not on a TEMP table,
** build the sqlite_master entry ** build the sqlite_master entry
*/ */
if( !pParse->initFlag ){ if( !db->init.busy ){
static VdbeOp insertTrig[] = { static VdbeOp insertTrig[] = {
{ OP_NewRecno, 0, 0, 0 }, { OP_NewRecno, 0, 0, 0 },
{ OP_String, 0, 0, "trigger" }, { OP_String, 0, 0, "trigger" },