From 8e227875dd62e0e036bdc51fed6536d7e3c231b8 Mon Sep 17 00:00:00 2001 From: danielk1977 Date: Mon, 7 Jun 2004 07:52:17 +0000 Subject: [PATCH] Add pragma to set/get text encoding. Also fix an obscure problem where a temp trigger could be accidently dropped. (CVS 1537) FossilOrigin-Name: 983221b038813c5a7892564896e39597c223c4c3 --- manifest | 28 +++++++------- manifest.uuid | 2 +- src/attach.c | 4 +- src/build.c | 62 ++++++++++++++---------------- src/main.c | 98 +++++++++++++++++++---------------------------- src/pragma.c | 85 +++++++++++++++++++++++++++++++++++++++- src/sqliteInt.h | 3 +- src/trigger.c | 13 +++---- test/attach3.test | 26 ++++++++++++- test/enc2.test | 15 ++++---- 10 files changed, 211 insertions(+), 125 deletions(-) diff --git a/manifest b/manifest index 0fb31e9891..84c236d7e2 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Progress\stowards\sgetting\slocking\sto\swork\son\swindows.\s(CVS\s1536) -D 2004-06-07T01:52:14 +C Add\spragma\sto\sset/get\stext\sencoding.\sAlso\sfix\san\sobscure\sproblem\swhere\sa\ntemp\strigger\scould\sbe\saccidently\sdropped.\s(CVS\s1537) +D 2004-06-07T07:52:18 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -23,11 +23,11 @@ F spec.template a38492f1c1dd349fc24cb0565e08afc53045304b F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea F sqlite.def fc4f5734786fe4743cfe2aa98eb2da4b089edb5f F sqlite.pc.in 30552343140c53304c2a658c080fbe810cd09ca2 -F src/attach.c c315c58cb16fd6e913b3bfa6412aedecb4567fa5 +F src/attach.c e76e4590ec5dd389e5646b171881b5243a6ef391 F src/auth.c 5c2f0bea4729c98c2be3b69d6b466fc51448fe79 F src/btree.c 3f0c22ab8c0c000ee5de4ad875836c111c4191c6 F src/btree.h 589427ac13bb544d298cd99726e2572a6fe4bdaa -F src/build.c e12e602f06e37a0fbcb49af17cba68ad85e101b6 +F src/build.c 92144f30d30fa00cb21c9c9e51de49cfb948d113 F src/date.c 8e6fa3173386fb29fdef012ee08a853c1e9908b2 F src/delete.c b30f08250c9ed53a25a13c7c04599c1e8753992d F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 @@ -37,7 +37,7 @@ F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb F src/insert.c 4268d9e3959cc845ea243fb4ec7507269404dad9 F src/legacy.c ad23746f15f67e34577621b1875f639c94839e1f -F src/main.c 2e4d37f0f8f31694b79823a530ea4b52c8e1a7fd +F src/main.c d34e173296473c9626f2560a0c86e694fc8e5a2b F src/md5.c 4302e84ae516c616bb079c4e6d038c0addb33481 F src/os.h 4e480eb92737ebcdd1e1136bdbf5cd22223bd1b4 F src/os_common.h 7b0f4ae0d9f66888f90ab28f126b42bfefe0bbd4 @@ -50,13 +50,13 @@ F src/os_win.h 004eec47b1780fcaf07420ddc2072294b698d48c F src/pager.c 944f6b071279887574081281f27bb2af88b42905 F src/pager.h 0c7b5ac45c69e690c45d160d03bdc8fbd2d4657b F src/parse.y 27c1ce09f9d309be91f9e537df2fb00892990af4 -F src/pragma.c 1b58d852b84b36a8b84e2245dd29b63c377414ec +F src/pragma.c 54b4d67fa81fd38b911aa3325348dcae9ceac5a4 F src/printf.c 77ee9ec6dbf1b7512b17d63ccf8322ea9466278b F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c 02d711160100ef3a730060f7cfb5bc85fde06d72 F src/shell.c 79af86d39b2149c7f16219fcbe636e7c2da9df8e F src/sqlite.h.in 4705697dd7213f322d59ffc69b48b8ac32b23373 -F src/sqliteInt.h 306256532411cc7b9019b82d3697c534a322e2a7 +F src/sqliteInt.h 845d2a3ffdb9a9050a1b55044d4856227b649b84 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 F src/tclsqlite.c 3db6b868bd844bfb71720c8e573f4c9b0d536bd5 F src/test1.c 4a3cc1b628a29f24c0a43227a035d0f2a96eb634 @@ -65,7 +65,7 @@ F src/test3.c beafd0ccf7b9ae784744be1b1e66ffe8f64c25da F src/test4.c caf675e443460ec76b04d78e1688986c17c82cec F src/test5.c 44178ce85c3afd2004ab4eeb5cfd7487116ce366 F src/tokenize.c 183c5d7da11affab5d70d903d33409c8c0ce6c5b -F src/trigger.c 04b2c310d0d056b213609cab6df5fff03d5eaf88 +F src/trigger.c 532daca4972bbf1165bdeecf48d9949eee8c24c0 F src/update.c 259f06e7b22c684b2d3dda54a18185892d6e9573 F src/utf.c c2c8e445bfea724f3502609d6389fe66651f02ab F src/util.c 8b3680271111bcdf5b395916b08b9a6684e0e73d @@ -80,7 +80,7 @@ F src/where.c 444a7c3a8b1eb7bba072e489af628555d21d92a4 F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test 1635022d7e1d95dc92fe381cc62f9bf25cb29d73 F test/attach2.test e98aab312722d05fc1837bf103baeebc582c64f8 -F test/attach3.test d384ac2e59f305743f73aec4b3d97b36fa5c6975 +F test/attach3.test 8259ab833b5dcdf4acd75d9653f42f703ce2e013 F test/auth.test 95809b8f6a9bec18b94d28cafd03fe27d2f8a9e9 F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 @@ -99,7 +99,7 @@ F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 F test/date.test aed5030482ebc02bd8d386c6c86a29f694ab068d F test/delete.test ddb1d4e172a01c0165804f82f81df556fb48a856 F test/enc.test a55481d45ff493804e8d88357feb4642fc50a6b2 -F test/enc2.test 8ab83839b73ce3a571b1396379f2f8ae3c895d74 +F test/enc2.test a46170cc3a3fdc3e8647abf8eebca584886cf611 F test/expr.test 521588701dae8cf5aa2b8a18c5c897711f754332 F test/fkey1.test d65c824459916249bee501532d6154ddab0b5db7 F test/func.test 9816fbed0a5e87e00f4fc88b4cdcd638abc524c4 @@ -215,7 +215,7 @@ F www/support.tcl 1801397edd271cc39a2aadd54e701184b5181248 F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 30b81507fc404355751705c6f9856c178249eff1 -R f549135a3da153baeae9af57b4d41e2b -U drh -Z 564efee24b8b93a5d228cb5bc9c253cb +P 4f7c0961ad6cb7082bf7716f0c7ca16a8742c039 +R ec69eb8a9c750d8d0b48358a8267ec3f +U danielk1977 +Z 53de26870eaceb80255c757bed464dd0 diff --git a/manifest.uuid b/manifest.uuid index e8d06e14df..1b432f643f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4f7c0961ad6cb7082bf7716f0c7ca16a8742c039 \ No newline at end of file +983221b038813c5a7892564896e39597c223c4c3 \ No newline at end of file diff --git a/src/attach.c b/src/attach.c index 89c3b3b574..46f2226475 100644 --- a/src/attach.c +++ b/src/attach.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the ATTACH and DETACH commands. ** -** $Id: attach.c,v 1.12 2004/05/11 07:11:52 danielk1977 Exp $ +** $Id: attach.c,v 1.13 2004/06/07 07:52:18 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -105,7 +105,7 @@ void sqlite3Attach(Parse *pParse, Token *pFilename, Token *pDbname, Token *pKey) db->flags &= ~SQLITE_Initialized; if( pParse->nErr ) return; if( rc==SQLITE_OK ){ - rc = sqlite3Init(pParse->db, &pParse->zErrMsg); + rc = sqlite3ReadSchema(pParse->db); } if( rc ){ int i = db->nDb - 1; diff --git a/src/build.c b/src/build.c index 30f8d04b9e..a0cd3b589c 100644 --- a/src/build.c +++ b/src/build.c @@ -23,7 +23,7 @@ ** ROLLBACK ** PRAGMA ** -** $Id: build.c,v 1.206 2004/06/03 16:08:41 danielk1977 Exp $ +** $Id: build.c,v 1.207 2004/06/07 07:52:18 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -38,6 +38,7 @@ void sqlite3BeginParse(Parse *pParse, int explainFlag){ sqlite *db = pParse->db; int i; pParse->explain = explainFlag; +#if 0 if((db->flags & SQLITE_Initialized)==0 && db->init.busy==0 ){ int rc = sqlite3Init(db, &pParse->zErrMsg); if( rc!=SQLITE_OK ){ @@ -45,6 +46,7 @@ void sqlite3BeginParse(Parse *pParse, int explainFlag){ pParse->nErr++; } } +#endif for(i=0; inDb; i++){ DbClearProperty(db, i, DB_Locked); if( !db->aDb[i].inTrans ){ @@ -105,7 +107,8 @@ void sqlite3Exec(Parse *pParse){ Table *sqlite3FindTable(sqlite *db, const char *zName, const char *zDatabase){ Table *p = 0; int i; - for(i=0; inDb; i++){ + int rc = sqlite3ReadSchema(db); + for(i=0; rc==SQLITE_OK && inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDatabase!=0 && sqlite3StrICmp(zDatabase, db->aDb[j].zName) ) continue; p = sqlite3HashFind(&db->aDb[j].tblHash, zName, strlen(zName)+1); @@ -157,7 +160,8 @@ Table *sqlite3LocateTable(Parse *pParse, const char *zName, const char *zDbase){ Index *sqlite3FindIndex(sqlite *db, const char *zName, const char *zDb){ Index *p = 0; int i; - for(i=0; inDb; i++){ + int rc = sqlite3ReadSchema(db); + for(i=0; rc==SQLITE_OK && inDb; i++){ int j = (i<2) ? i^1 : i; /* Search TEMP before MAIN */ if( zDb && sqlite3StrICmp(zDb, db->aDb[j].zName) ) continue; p = sqlite3HashFind(&db->aDb[j].idxHash, zName, strlen(zName)+1); @@ -931,16 +935,6 @@ void sqlite3ChangeCookie(sqlite *db, Vdbe *v, int iDb){ db->flags |= SQLITE_InternChanges; sqlite3VdbeAddOp(v, OP_Integer, *pSchemaCookie, 0); sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0); -/* - if( db->next_cookie==db->aDb[0].schema_cookie ){ - unsigned char r; - sqlite3Randomness(1, &r); - db->next_cookie = db->aDb[0].schema_cookie + r + 1; - db->flags |= SQLITE_InternChanges; - sqlite3VdbeAddOp(v, OP_Integer, db->next_cookie, 0); - sqlite3VdbeAddOp(v, OP_SetCookie, iDb, 0); - } -*/ } /* @@ -1404,22 +1398,28 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){ v = sqlite3GetVdbe(pParse); if( v ){ static VdbeOpList dropTable[] = { - { OP_Rewind, 0, ADDR(10), 0}, - { OP_String8, 0, 0, 0}, /* 1 */ + { OP_Rewind, 0, ADDR(13), 0}, + { OP_String8, 0, 0, 0}, /* 1 */ { OP_MemStore, 1, 1, 0}, { OP_MemLoad, 1, 0, 0}, /* 3 */ - { OP_Column, 0, 2, 0}, - { OP_Ne, 0, ADDR(9), 0}, + { OP_Column, 0, 2, 0}, /* sqlite_master.tbl_name */ + { OP_Ne, 0, ADDR(12), 0}, + { OP_String8, 0, 0, "trigger"}, + { OP_Column, 0, 2, 0}, /* sqlite_master.type */ + { OP_Eq, 0, ADDR(12), 0}, { OP_Delete, 0, 0, 0}, - { OP_Rewind, 0, ADDR(10), 0}, + { OP_Rewind, 0, ADDR(13), 0}, { OP_Goto, 0, ADDR(3), 0}, - { OP_Next, 0, ADDR(3), 0}, /* 9 */ + { OP_Next, 0, ADDR(3), 0}, /* 12 */ }; Index *pIdx; Trigger *pTrigger; sqlite3BeginWriteOperation(pParse, 0, pTab->iDb); - /* Drop all triggers associated with the table being dropped */ + /* Drop all triggers associated with the table being dropped. Code + ** is generated to remove entries from sqlite_master and/or + ** sqlite_temp_master if required. + */ pTrigger = pTab->pTrigger; while( pTrigger ){ assert( pTrigger->iDb==pTab->iDb || pTrigger->iDb==1 ); @@ -1431,21 +1431,17 @@ void sqlite3DropTable(Parse *pParse, SrcList *pName, int isView){ } } - /* Drop all SQLITE_MASTER entries that refer to the table */ + /* Drop all SQLITE_MASTER table and index entries that refer to the + ** table. The program name loops through the master table and deletes + ** every row that refers to a table of the same name as the one being + ** dropped. Triggers are handled seperately because a trigger can be + ** created in the temp database that refers to a table in another + ** database. + */ sqlite3OpenMasterTable(v, pTab->iDb); base = sqlite3VdbeAddOpList(v, ArraySize(dropTable), dropTable); sqlite3VdbeChangeP3(v, base+1, pTab->zName, 0); - - /* Drop all SQLITE_TEMP_MASTER entries that refer to the table */ - if( pTab->iDb!=1 ){ - sqlite3OpenMasterTable(v, 1); - base = sqlite3VdbeAddOpList(v, ArraySize(dropTable), dropTable); - sqlite3VdbeChangeP3(v, base+1, pTab->zName, 0); - } - - if( pTab->iDb!=1 ){ /* Temp database has no schema cookie */ - sqlite3ChangeCookie(db, v, pTab->iDb); - } + sqlite3ChangeCookie(db, v, pTab->iDb); sqlite3VdbeAddOp(v, OP_Close, 0, 0); if( !isView ){ sqlite3VdbeAddOp(v, OP_Destroy, pTab->tnum, pTab->iDb); @@ -2262,7 +2258,7 @@ void sqlite3BeginWriteOperation(Parse *pParse, int setStatement, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); if( v==0 ) return; sqlite3VdbeAddOp(v, OP_Transaction, iDb, 1); - if( iDb!=1 && (iDb>63 || !(pParse->cookieMask & ((u64)1<63 || !(pParse->cookieMask & ((u64)1<aDb[iDb].schema_cookie); pParse->cookieMask |= ((u64)1<init.busy ){ + if( (db->flags & SQLITE_Initialized)==0 ){ + rc = sqlite3Init(db, &zErrMsg); + } + } + assert( (db->flags & SQLITE_Initialized)!=0 || db->init.busy ); + + sqlite3Error(db, rc, zErrMsg); + if( zErrMsg ){ + sqliteFree(zErrMsg); + } + return rc; +} + /* ** The version of the library */ @@ -845,21 +863,6 @@ int sqlite3_prepare( goto prepare_out; } - if( !db->init.busy ){ - if( (db->flags & SQLITE_Initialized)==0 ){ - int cnt = 1; - rc = sqlite3Init(db, &zErrMsg); - if( rc!=SQLITE_OK ){ - goto prepare_out; - } - if( zErrMsg ){ - sqliteFree(zErrMsg); - zErrMsg = 0; - } - } - } - assert( (db->flags & SQLITE_Initialized)!=0 || db->init.busy ); - if( db->pVdbe==0 ){ db->nChange = 0; } memset(&sParse, 0, sizeof(sParse)); sParse.db = db; @@ -974,27 +977,12 @@ int sqlite3_prepare16( */ static int openDatabase( const char *zFilename, /* Database filename UTF-8 encoded */ - sqlite3 **ppDb, /* OUT: Returned database handle */ - const char **options, /* Null terminated list of db options, or null */ - u8 def_enc /* One of TEXT_Utf8, TEXT_Utf16le or TEXT_Utf16be */ + sqlite3 **ppDb /* OUT: Returned database handle */ ){ sqlite3 *db; int rc, i; char *zErrMsg = 0; -#ifdef SQLITE_TEST - for(i=0; options && options[i]; i++){ - char const *zOpt = options[i]; - if( 0==sqlite3StrICmp(zOpt, "-utf8") ){ - def_enc = TEXT_Utf8; - }else if( 0==sqlite3StrICmp(zOpt, "-utf16le") ){ - def_enc = TEXT_Utf16le; - }else if( 0==sqlite3StrICmp(zOpt, "-utf16be") ){ - def_enc = TEXT_Utf16be; - } - } -#endif - /* Allocate the sqlite data structure */ db = sqliteMalloc( sizeof(sqlite) ); if( db==0 ) goto opendb_out; @@ -1002,7 +990,7 @@ static int openDatabase( db->magic = SQLITE_MAGIC_BUSY; db->nDb = 2; db->aDb = db->aDbStatic; - db->enc = def_enc; + db->enc = TEXT_Utf8; db->autoCommit = 1; /* db->flags |= SQLITE_ShortColNames; */ sqlite3HashInit(&db->aFunc, SQLITE_HASH_STRING, 0); @@ -1030,20 +1018,18 @@ static int openDatabase( db->aDb[0].zName = "main"; db->aDb[1].zName = "temp"; - /* Attempt to read the schema */ + /* Register all built-in functions, but do not attempt to read the + ** database schema yet. This is delayed until the first time the database + ** is accessed. + */ sqlite3RegisterBuiltinFunctions(db); - rc = sqlite3Init(db, &zErrMsg); - if( sqlite3_malloc_failed ){ - sqlite3_close(db); - db = 0; - goto opendb_out; - }else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ - sqlite3Error(db, rc, "%s", zErrMsg, 0); - db->magic = SQLITE_MAGIC_CLOSED; - }else{ + if( rc==SQLITE_OK ){ db->magic = SQLITE_MAGIC_OPEN; + }else{ + sqlite3Error(db, rc, "%s", zErrMsg, 0); + if( zErrMsg ) sqliteFree(zErrMsg); + db->magic = SQLITE_MAGIC_CLOSED; } - if( zErrMsg ) sqliteFree(zErrMsg); opendb_out: *ppDb = db; @@ -1058,7 +1044,7 @@ int sqlite3_open( sqlite3 **ppDb, const char **options ){ - return openDatabase(zFilename, ppDb, options, TEXT_Utf8); + return openDatabase(zFilename, ppDb); } /* @@ -1079,16 +1065,12 @@ int sqlite3_open16( *ppDb = 0; return SQLITE_NOMEM; } - - /* FIX ME: Also need to translate the option strings */ - - if( SQLITE_BIGENDIAN ){ - rc = openDatabase(zFilename8, ppDb, options, TEXT_Utf16be); - }else{ - rc = openDatabase(zFilename8, ppDb, options, TEXT_Utf16le); + rc = openDatabase(zFilename8, ppDb); + if( rc==SQLITE_OK && *ppDb ){ + sqlite3_exec(*ppDb, "PRAGMA encoding = 'UTF-16'", 0, 0, 0); } - sqliteFree(zFilename8); + return rc; } diff --git a/src/pragma.c b/src/pragma.c index 8df5cd381a..85bb495fdc 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -11,7 +11,7 @@ ************************************************************************* ** This file contains code used to implement the PRAGMA command. ** -** $Id: pragma.c,v 1.36 2004/06/03 16:08:42 danielk1977 Exp $ +** $Id: pragma.c,v 1.37 2004/06/07 07:52:18 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -203,6 +203,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ { OP_Callback, 1, 0, 0}, }; int addr; + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; if( pRight->z==pLeft->z ){ sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, "cache_size", P3_STATIC); @@ -242,6 +243,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ static VdbeOpList getCacheSize[] = { { OP_Callback, 1, 0, 0}, }; + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; if( pRight->z==pLeft->z ){ int size = db->cache_size;; if( size<0 ) size = -size; @@ -292,6 +294,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ { OP_Callback, 1, 0, 0} }; int addr; + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; if( pRight->z==pLeft->z ){ sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, "synchronous", P3_STATIC); @@ -335,6 +338,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ static VdbeOpList getSync[] = { { OP_Callback, 1, 0, 0}, }; + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; if( pRight->z==pLeft->z ){ sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, "synchronous", P3_STATIC); @@ -367,6 +371,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ if( sqlite3StrICmp(zLeft, "table_info")==0 ){ Table *pTab; + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; pTab = sqlite3FindTable(db, zRight, 0); if( pTab ){ int i; @@ -395,6 +400,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ if( sqlite3StrICmp(zLeft, "index_info")==0 ){ Index *pIdx; Table *pTab; + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; pIdx = sqlite3FindIndex(db, zRight, 0); if( pIdx ){ int i; @@ -417,6 +423,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ if( sqlite3StrICmp(zLeft, "index_list")==0 ){ Index *pIdx; Table *pTab; + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; pTab = sqlite3FindTable(db, zRight, 0); if( pTab ){ v = sqlite3GetVdbe(pParse); @@ -442,6 +449,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ if( sqlite3StrICmp(zLeft, "foreign_key_list")==0 ){ FKey *pFK; Table *pTab; + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; pTab = sqlite3FindTable(db, zRight, 0); if( pTab ){ v = sqlite3GetVdbe(pParse); @@ -474,6 +482,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ if( sqlite3StrICmp(zLeft, "database_list")==0 ){ int i; + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; sqlite3VdbeSetNumCols(v, 3); sqlite3VdbeSetColName(v, 0, "seq", P3_STATIC); sqlite3VdbeSetColName(v, 1, "name", P3_STATIC); @@ -505,6 +514,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ static VdbeOpList getTmpDbLoc[] = { { OP_Callback, 1, 0, 0}, }; + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; if( pRight->z==pLeft->z ){ sqlite3VdbeAddOp(v, OP_Integer, db->temp_store, 0); sqlite3VdbeSetNumCols(v, 1); @@ -530,6 +540,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ static VdbeOpList getTmpDbLoc[] = { { OP_ReadCookie, 0, 5, 0}, { OP_Callback, 1, 0, 0}}; + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; if( pRight->z==pLeft->z ){ sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, "temp_store", P3_STATIC); @@ -545,6 +556,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ #ifndef NDEBUG if( sqlite3StrICmp(zLeft, "parser_trace")==0 ){ extern void sqlite3ParserTrace(FILE*, char *); + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; if( getBoolean(zRight) ){ sqlite3ParserTrace(stdout, "parser: "); }else{ @@ -577,6 +589,7 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ }; /* Initialize the VDBE program */ + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; sqlite3VdbeSetNumCols(v, 1); sqlite3VdbeSetColName(v, 0, "integrity_check", P3_STATIC); sqlite3VdbeAddOpList(v, ArraySize(initCode), initCode); @@ -680,6 +693,76 @@ void sqlite3Pragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){ addr = sqlite3VdbeAddOpList(v, ArraySize(endCode), endCode); sqlite3VdbeChangeP2(v, addr+2, addr+ArraySize(endCode)); }else + /* + ** PRAGMA encoding + ** PRAGMA encoding = "utf-8"|"utf-16"|"utf-16le"|"utf-16be" + ** + ** In it's first form, this pragma returns the encoding of the main + ** database. If the database is not initialized, it is initialized now. + ** + ** The second form of this pragma is a no-op if the main database file + ** has not already been initialized. In this case it sets the default + ** encoding that will be used for the main database file if a new file + ** is created. If an existing main database file is opened, then the + ** default text encoding for the existing database is used. + ** + ** In all cases new databases created using the ATTACH command are + ** created to use the same default text encoding as the main database. If + ** the main database has not been initialized and/or created when ATTACH + ** is executed, this is done before the ATTACH operation. + ** + ** In the second form this pragma sets the text encoding to be used in + ** new database files created using this database handle. It is only + ** useful if invoked immediately after the main database i + */ + if( sqlite3StrICmp(zLeft, "encoding")==0 ){ + struct EncName { + char *zName; + u8 enc; + } encnames[] = { + { "UTF-8", TEXT_Utf8 }, + { "UTF-16le", TEXT_Utf16le }, + { "UTF-16be", TEXT_Utf16be }, + { "UTF-16", TEXT_Utf16 }, + { "UTF8", TEXT_Utf8 }, + { "UTF16le", TEXT_Utf16le }, + { "UTF16be", TEXT_Utf16be }, + { "UTF16", TEXT_Utf16 }, + { 0, 0 } + }; + struct EncName *pEnc; + if( pRight->z==pLeft->z ){ /* "PRAGMA encoding" */ + if( SQLITE_OK!=sqlite3ReadSchema(pParse->db) ) return; + sqlite3VdbeSetNumCols(v, 1); + sqlite3VdbeSetColName(v, 0, "encoding", P3_STATIC); + sqlite3VdbeAddOp(v, OP_String8, 0, 0); + for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ + if( pEnc->enc==pParse->db->enc ){ + sqlite3VdbeChangeP3(v, -1, pEnc->zName, P3_STATIC); + break; + } + } + sqlite3VdbeAddOp(v, OP_Callback, 1, 0); + }else{ /* "PRAGMA encoding = XXX" */ + /* Only change the value of sqlite.enc if the database handle is not + ** initialized. If the main database exists, the new sqlite.enc value + ** will be overwritten when the schema is next loaded. If it does not + ** already exists, it will be created to use the new encoding value. + */ + if( !(pParse->db->flags&SQLITE_Initialized) ){ + for(pEnc=&encnames[0]; pEnc->zName; pEnc++){ + if( 0==sqlite3StrICmp(zRight, pEnc->zName) ){ + pParse->db->enc = pEnc->enc; + break; + } + } + if( !pEnc->zName ){ + sqlite3Error(pParse->db, SQLITE_ERROR, + "Unsupported encoding: %s", zRight); + } + } + } + }else {} sqliteFree(zLeft); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index ba9231158a..bc73f021d2 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.270 2004/06/07 01:52:14 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.271 2004/06/07 07:52:18 danielk1977 Exp $ */ #include "config.h" #include "sqlite3.h" @@ -1374,3 +1374,4 @@ void *sqlite3HexToBlob(const char *z); int sqlite3TwoPartName(Parse *, Token *, Token *, Token **); const char *sqlite3ErrStr(int); int sqlite3ReadUniChar(const char *zStr, int *pOffset, u8 *pEnc, int fold); +int sqlite3ReadSchema(sqlite *db); diff --git a/src/trigger.c b/src/trigger.c index 20f71b57de..b40ae7d2fe 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -421,6 +421,8 @@ void sqlite3DropTrigger(Parse *pParse, SrcList *pName){ sqlite *db = pParse->db; if( sqlite3_malloc_failed ) goto drop_trigger_cleanup; + if( SQLITE_OK!=sqlite3ReadSchema(db) ) goto drop_trigger_cleanup; + assert( pName->nSrc==1 ); zDb = pName->a[0].zDatabase; zName = pName->a[0].zName; @@ -470,7 +472,7 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){ /* Generate code to destroy the database record of the trigger. */ - if( pTable!=0 && !nested && (v = sqlite3GetVdbe(pParse))!=0 ){ + if( pTable!=0 && (v = sqlite3GetVdbe(pParse))!=0 ){ int base; static VdbeOpList dropTrigger[] = { { OP_Rewind, 0, ADDR(9), 0}, @@ -488,16 +490,13 @@ void sqlite3DropTriggerPtr(Parse *pParse, Trigger *pTrigger, int nested){ sqlite3OpenMasterTable(v, pTrigger->iDb); base = sqlite3VdbeAddOpList(v, ArraySize(dropTrigger), dropTrigger); sqlite3VdbeChangeP3(v, base+1, pTrigger->name, 0); - if( pTrigger->iDb!=1 ){ - sqlite3ChangeCookie(db, v, pTrigger->iDb); - } + sqlite3ChangeCookie(db, v, pTrigger->iDb); sqlite3VdbeAddOp(v, OP_Close, 0, 0); - sqlite3EndWriteOperation(pParse); } /* - * If this is not an "explain", then delete the trigger structure. - */ + ** If this is not an "explain", then delete the trigger structure. + */ if( !pParse->explain ){ const char *zName = pTrigger->name; int nName = strlen(zName); diff --git a/test/attach3.test b/test/attach3.test index a0f6696b2e..f6d9a536b3 100644 --- a/test/attach3.test +++ b/test/attach3.test @@ -12,7 +12,7 @@ # focus of this script is testing the ATTACH and DETACH commands # and schema changes to attached databases. # -# $Id: attach3.test,v 1.5 2004/05/29 10:23:20 danielk1977 Exp $ +# $Id: attach3.test,v 1.6 2004/06/07 07:52:19 danielk1977 Exp $ # @@ -188,6 +188,30 @@ do_test attach3-8.2 { } } {} +# Try to trick SQLite into dropping the wrong temp trigger. +do_test attach3-9.0 { + execsql { + CREATE TABLE main.t4(a, b, c); + CREATE TABLE aux.t4(a, b, c); + CREATE TEMP TRIGGER tst_trigger BEFORE INSERT ON aux.t4 BEGIN + SELECT 'hello world'; + END; + SELECT count(*) FROM sqlite_temp_master; + } +} {1} +do_test attach3-9.1 { + execsql { + DROP TABLE main.t4; + SELECT count(*) FROM sqlite_temp_master; + } +} {1} +do_test attach3-9.2 { + execsql { + DROP TABLE aux.t4; + SELECT count(*) FROM sqlite_temp_master; + } +} {0} + finish_test diff --git a/test/enc2.test b/test/enc2.test index 9e56bdc474..5c1f35511b 100644 --- a/test/enc2.test +++ b/test/enc2.test @@ -13,7 +13,7 @@ # various suported unicode encodings (UTF-8, UTF-16, UTF-16le and # UTF-16be). # -# $Id: enc2.test,v 1.4 2004/05/27 17:22:56 drh Exp $ +# $Id: enc2.test,v 1.5 2004/06/07 07:52:19 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -45,7 +45,7 @@ set dbcontents { # database, and that it is possible to retreive values in # various text encodings. # -proc run_test_script {t} { +proc run_test_script {t enc} { # Open the database and pull out a (the) row. do_test $t.1 { @@ -102,22 +102,23 @@ do_test $t.9 { sqlite3_finalize $STMT } SQLITE_OK -do_test $t.99 { - db close -} {} +do_test $t.10 { + db eval {PRAGMA encoding} +} $enc } # The three unicode encodings understood by SQLite. -set encodings [list -utf8 -utf16be -utf16le] +set encodings [list UTF-8 UTF-16le UTF-16be] set i 1 foreach enc $encodings { file delete -force test.db sqlite db test.db $enc + db eval "PRAGMA encoding = \"$enc\"" execsql $dbcontents db close - run_test_script enc2-$i + run_test_script enc2-$i $enc incr i }