[205] | 1 | /*
|
---|
| 2 | ** 2003 April 6
|
---|
| 3 | **
|
---|
| 4 | ** The author disclaims copyright to this source code. In place of
|
---|
| 5 | ** a legal notice, here is a blessing:
|
---|
| 6 | **
|
---|
| 7 | ** May you do good and not evil.
|
---|
| 8 | ** May you find forgiveness for yourself and forgive others.
|
---|
| 9 | ** May you share freely, never taking more than you give.
|
---|
| 10 | **
|
---|
| 11 | *************************************************************************
|
---|
| 12 | ** This file contains code used to implement the PRAGMA command.
|
---|
| 13 | **
|
---|
| 14 | ** $Id: pragma.c,v 1.19 2004/04/23 17:04:45 drh Exp $
|
---|
| 15 | */
|
---|
| 16 | #include "sqliteInt.h"
|
---|
| 17 | #include <ctype.h>
|
---|
| 18 |
|
---|
| 19 | /*
|
---|
| 20 | ** Interpret the given string as a boolean value.
|
---|
| 21 | */
|
---|
| 22 | static int getBoolean(const char *z){
|
---|
| 23 | static char *azTrue[] = { "yes", "on", "true" };
|
---|
| 24 | int i;
|
---|
| 25 | if( z[0]==0 ) return 0;
|
---|
| 26 | if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
|
---|
| 27 | return atoi(z);
|
---|
| 28 | }
|
---|
| 29 | for(i=0; i<sizeof(azTrue)/sizeof(azTrue[0]); i++){
|
---|
| 30 | if( sqliteStrICmp(z,azTrue[i])==0 ) return 1;
|
---|
| 31 | }
|
---|
| 32 | return 0;
|
---|
| 33 | }
|
---|
| 34 |
|
---|
| 35 | /*
|
---|
| 36 | ** Interpret the given string as a safety level. Return 0 for OFF,
|
---|
| 37 | ** 1 for ON or NORMAL and 2 for FULL. Return 1 for an empty or
|
---|
| 38 | ** unrecognized string argument.
|
---|
| 39 | **
|
---|
| 40 | ** Note that the values returned are one less that the values that
|
---|
| 41 | ** should be passed into sqliteBtreeSetSafetyLevel(). The is done
|
---|
| 42 | ** to support legacy SQL code. The safety level used to be boolean
|
---|
| 43 | ** and older scripts may have used numbers 0 for OFF and 1 for ON.
|
---|
| 44 | */
|
---|
| 45 | static int getSafetyLevel(char *z){
|
---|
| 46 | static const struct {
|
---|
| 47 | const char *zWord;
|
---|
| 48 | int val;
|
---|
| 49 | } aKey[] = {
|
---|
| 50 | { "no", 0 },
|
---|
| 51 | { "off", 0 },
|
---|
| 52 | { "false", 0 },
|
---|
| 53 | { "yes", 1 },
|
---|
| 54 | { "on", 1 },
|
---|
| 55 | { "true", 1 },
|
---|
| 56 | { "full", 2 },
|
---|
| 57 | };
|
---|
| 58 | int i;
|
---|
| 59 | if( z[0]==0 ) return 1;
|
---|
| 60 | if( isdigit(z[0]) || (z[0]=='-' && isdigit(z[1])) ){
|
---|
| 61 | return atoi(z);
|
---|
| 62 | }
|
---|
| 63 | for(i=0; i<sizeof(aKey)/sizeof(aKey[0]); i++){
|
---|
| 64 | if( sqliteStrICmp(z,aKey[i].zWord)==0 ) return aKey[i].val;
|
---|
| 65 | }
|
---|
| 66 | return 1;
|
---|
| 67 | }
|
---|
| 68 |
|
---|
| 69 | /*
|
---|
| 70 | ** Interpret the given string as a temp db location. Return 1 for file
|
---|
| 71 | ** backed temporary databases, 2 for the Red-Black tree in memory database
|
---|
| 72 | ** and 0 to use the compile-time default.
|
---|
| 73 | */
|
---|
| 74 | static int getTempStore(const char *z){
|
---|
| 75 | if( z[0]>='0' && z[0]<='2' ){
|
---|
| 76 | return z[0] - '0';
|
---|
| 77 | }else if( sqliteStrICmp(z, "file")==0 ){
|
---|
| 78 | return 1;
|
---|
| 79 | }else if( sqliteStrICmp(z, "memory")==0 ){
|
---|
| 80 | return 2;
|
---|
| 81 | }else{
|
---|
| 82 | return 0;
|
---|
| 83 | }
|
---|
| 84 | }
|
---|
| 85 |
|
---|
| 86 | /*
|
---|
| 87 | ** If the TEMP database is open, close it and mark the database schema
|
---|
| 88 | ** as needing reloading. This must be done when using the TEMP_STORE
|
---|
| 89 | ** or DEFAULT_TEMP_STORE pragmas.
|
---|
| 90 | */
|
---|
| 91 | static int changeTempStorage(Parse *pParse, const char *zStorageType){
|
---|
| 92 | int ts = getTempStore(zStorageType);
|
---|
| 93 | sqlite *db = pParse->db;
|
---|
| 94 | if( db->temp_store==ts ) return SQLITE_OK;
|
---|
| 95 | if( db->aDb[1].pBt!=0 ){
|
---|
| 96 | if( db->flags & SQLITE_InTrans ){
|
---|
| 97 | sqliteErrorMsg(pParse, "temporary storage cannot be changed "
|
---|
| 98 | "from within a transaction");
|
---|
| 99 | return SQLITE_ERROR;
|
---|
| 100 | }
|
---|
| 101 | sqliteBtreeClose(db->aDb[1].pBt);
|
---|
| 102 | db->aDb[1].pBt = 0;
|
---|
| 103 | sqliteResetInternalSchema(db, 0);
|
---|
| 104 | }
|
---|
| 105 | db->temp_store = ts;
|
---|
| 106 | return SQLITE_OK;
|
---|
| 107 | }
|
---|
| 108 |
|
---|
| 109 | /*
|
---|
| 110 | ** Check to see if zRight and zLeft refer to a pragma that queries
|
---|
| 111 | ** or changes one of the flags in db->flags. Return 1 if so and 0 if not.
|
---|
| 112 | ** Also, implement the pragma.
|
---|
| 113 | */
|
---|
| 114 | static int flagPragma(Parse *pParse, const char *zLeft, const char *zRight){
|
---|
| 115 | static const struct {
|
---|
| 116 | const char *zName; /* Name of the pragma */
|
---|
| 117 | int mask; /* Mask for the db->flags value */
|
---|
| 118 | } aPragma[] = {
|
---|
| 119 | { "vdbe_trace", SQLITE_VdbeTrace },
|
---|
| 120 | { "full_column_names", SQLITE_FullColNames },
|
---|
| 121 | { "short_column_names", SQLITE_ShortColNames },
|
---|
| 122 | { "show_datatypes", SQLITE_ReportTypes },
|
---|
| 123 | { "count_changes", SQLITE_CountRows },
|
---|
| 124 | { "empty_result_callbacks", SQLITE_NullCallback },
|
---|
| 125 | };
|
---|
| 126 | int i;
|
---|
| 127 | for(i=0; i<sizeof(aPragma)/sizeof(aPragma[0]); i++){
|
---|
| 128 | if( sqliteStrICmp(zLeft, aPragma[i].zName)==0 ){
|
---|
| 129 | sqlite *db = pParse->db;
|
---|
| 130 | Vdbe *v;
|
---|
| 131 | if( strcmp(zLeft,zRight)==0 && (v = sqliteGetVdbe(pParse))!=0 ){
|
---|
| 132 | sqliteVdbeOp3(v, OP_ColumnName, 0, 1, aPragma[i].zName, P3_STATIC);
|
---|
| 133 | sqliteVdbeOp3(v, OP_ColumnName, 1, 0, "boolean", P3_STATIC);
|
---|
| 134 | sqliteVdbeCode(v, OP_Integer, (db->flags & aPragma[i].mask)!=0, 0,
|
---|
| 135 | OP_Callback, 1, 0,
|
---|
| 136 | 0);
|
---|
| 137 | }else if( getBoolean(zRight) ){
|
---|
| 138 | db->flags |= aPragma[i].mask;
|
---|
| 139 | }else{
|
---|
| 140 | db->flags &= ~aPragma[i].mask;
|
---|
| 141 | }
|
---|
| 142 | return 1;
|
---|
| 143 | }
|
---|
| 144 | }
|
---|
| 145 | return 0;
|
---|
| 146 | }
|
---|
| 147 |
|
---|
| 148 | /*
|
---|
| 149 | ** Process a pragma statement.
|
---|
| 150 | **
|
---|
| 151 | ** Pragmas are of this form:
|
---|
| 152 | **
|
---|
| 153 | ** PRAGMA id = value
|
---|
| 154 | **
|
---|
| 155 | ** The identifier might also be a string. The value is a string, and
|
---|
| 156 | ** identifier, or a number. If minusFlag is true, then the value is
|
---|
| 157 | ** a number that was preceded by a minus sign.
|
---|
| 158 | */
|
---|
| 159 | void sqlitePragma(Parse *pParse, Token *pLeft, Token *pRight, int minusFlag){
|
---|
| 160 | char *zLeft = 0;
|
---|
| 161 | char *zRight = 0;
|
---|
| 162 | sqlite *db = pParse->db;
|
---|
| 163 | Vdbe *v = sqliteGetVdbe(pParse);
|
---|
| 164 | if( v==0 ) return;
|
---|
| 165 |
|
---|
| 166 | zLeft = sqliteStrNDup(pLeft->z, pLeft->n);
|
---|
| 167 | sqliteDequote(zLeft);
|
---|
| 168 | if( minusFlag ){
|
---|
| 169 | zRight = 0;
|
---|
| 170 | sqliteSetNString(&zRight, "-", 1, pRight->z, pRight->n, 0);
|
---|
| 171 | }else{
|
---|
| 172 | zRight = sqliteStrNDup(pRight->z, pRight->n);
|
---|
| 173 | sqliteDequote(zRight);
|
---|
| 174 | }
|
---|
| 175 | if( sqliteAuthCheck(pParse, SQLITE_PRAGMA, zLeft, zRight, 0) ){
|
---|
| 176 | sqliteFree(zLeft);
|
---|
| 177 | sqliteFree(zRight);
|
---|
| 178 | return;
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | /*
|
---|
| 182 | ** PRAGMA default_cache_size
|
---|
| 183 | ** PRAGMA default_cache_size=N
|
---|
| 184 | **
|
---|
| 185 | ** The first form reports the current persistent setting for the
|
---|
| 186 | ** page cache size. The value returned is the maximum number of
|
---|
| 187 | ** pages in the page cache. The second form sets both the current
|
---|
| 188 | ** page cache size value and the persistent page cache size value
|
---|
| 189 | ** stored in the database file.
|
---|
| 190 | **
|
---|
| 191 | ** The default cache size is stored in meta-value 2 of page 1 of the
|
---|
| 192 | ** database file. The cache size is actually the absolute value of
|
---|
| 193 | ** this memory location. The sign of meta-value 2 determines the
|
---|
| 194 | ** synchronous setting. A negative value means synchronous is off
|
---|
| 195 | ** and a positive value means synchronous is on.
|
---|
| 196 | */
|
---|
| 197 | if( sqliteStrICmp(zLeft,"default_cache_size")==0 ){
|
---|
| 198 | static VdbeOpList getCacheSize[] = {
|
---|
| 199 | { OP_ReadCookie, 0, 2, 0},
|
---|
| 200 | { OP_AbsValue, 0, 0, 0},
|
---|
| 201 | { OP_Dup, 0, 0, 0},
|
---|
| 202 | { OP_Integer, 0, 0, 0},
|
---|
| 203 | { OP_Ne, 0, 6, 0},
|
---|
| 204 | { OP_Integer, 0, 0, 0}, /* 5 */
|
---|
| 205 | { OP_ColumnName, 0, 1, "cache_size"},
|
---|
| 206 | { OP_Callback, 1, 0, 0},
|
---|
| 207 | };
|
---|
| 208 | int addr;
|
---|
| 209 | if( pRight->z==pLeft->z ){
|
---|
| 210 | addr = sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
|
---|
| 211 | sqliteVdbeChangeP1(v, addr+5, MAX_PAGES);
|
---|
| 212 | }else{
|
---|
| 213 | int size = atoi(zRight);
|
---|
| 214 | if( size<0 ) size = -size;
|
---|
| 215 | sqliteBeginWriteOperation(pParse, 0, 0);
|
---|
| 216 | sqliteVdbeAddOp(v, OP_Integer, size, 0);
|
---|
| 217 | sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
|
---|
| 218 | addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
|
---|
| 219 | sqliteVdbeAddOp(v, OP_Ge, 0, addr+3);
|
---|
| 220 | sqliteVdbeAddOp(v, OP_Negative, 0, 0);
|
---|
| 221 | sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
|
---|
| 222 | sqliteEndWriteOperation(pParse);
|
---|
| 223 | db->cache_size = db->cache_size<0 ? -size : size;
|
---|
| 224 | sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
---|
| 225 | }
|
---|
| 226 | }else
|
---|
| 227 |
|
---|
| 228 | /*
|
---|
| 229 | ** PRAGMA cache_size
|
---|
| 230 | ** PRAGMA cache_size=N
|
---|
| 231 | **
|
---|
| 232 | ** The first form reports the current local setting for the
|
---|
| 233 | ** page cache size. The local setting can be different from
|
---|
| 234 | ** the persistent cache size value that is stored in the database
|
---|
| 235 | ** file itself. The value returned is the maximum number of
|
---|
| 236 | ** pages in the page cache. The second form sets the local
|
---|
| 237 | ** page cache size value. It does not change the persistent
|
---|
| 238 | ** cache size stored on the disk so the cache size will revert
|
---|
| 239 | ** to its default value when the database is closed and reopened.
|
---|
| 240 | ** N should be a positive integer.
|
---|
| 241 | */
|
---|
| 242 | if( sqliteStrICmp(zLeft,"cache_size")==0 ){
|
---|
| 243 | static VdbeOpList getCacheSize[] = {
|
---|
| 244 | { OP_ColumnName, 0, 1, "cache_size"},
|
---|
| 245 | { OP_Callback, 1, 0, 0},
|
---|
| 246 | };
|
---|
| 247 | if( pRight->z==pLeft->z ){
|
---|
| 248 | int size = db->cache_size;;
|
---|
| 249 | if( size<0 ) size = -size;
|
---|
| 250 | sqliteVdbeAddOp(v, OP_Integer, size, 0);
|
---|
| 251 | sqliteVdbeAddOpList(v, ArraySize(getCacheSize), getCacheSize);
|
---|
| 252 | }else{
|
---|
| 253 | int size = atoi(zRight);
|
---|
| 254 | if( size<0 ) size = -size;
|
---|
| 255 | if( db->cache_size<0 ) size = -size;
|
---|
| 256 | db->cache_size = size;
|
---|
| 257 | sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
---|
| 258 | }
|
---|
| 259 | }else
|
---|
| 260 |
|
---|
| 261 | /*
|
---|
| 262 | ** PRAGMA default_synchronous
|
---|
| 263 | ** PRAGMA default_synchronous=ON|OFF|NORMAL|FULL
|
---|
| 264 | **
|
---|
| 265 | ** The first form returns the persistent value of the "synchronous" setting
|
---|
| 266 | ** that is stored in the database. This is the synchronous setting that
|
---|
| 267 | ** is used whenever the database is opened unless overridden by a separate
|
---|
| 268 | ** "synchronous" pragma. The second form changes the persistent and the
|
---|
| 269 | ** local synchronous setting to the value given.
|
---|
| 270 | **
|
---|
| 271 | ** If synchronous is OFF, SQLite does not attempt any fsync() systems calls
|
---|
| 272 | ** to make sure data is committed to disk. Write operations are very fast,
|
---|
| 273 | ** but a power failure can leave the database in an inconsistent state.
|
---|
| 274 | ** If synchronous is ON or NORMAL, SQLite will do an fsync() system call to
|
---|
| 275 | ** make sure data is being written to disk. The risk of corruption due to
|
---|
| 276 | ** a power loss in this mode is negligible but non-zero. If synchronous
|
---|
| 277 | ** is FULL, extra fsync()s occur to reduce the risk of corruption to near
|
---|
| 278 | ** zero, but with a write performance penalty. The default mode is NORMAL.
|
---|
| 279 | */
|
---|
| 280 | if( sqliteStrICmp(zLeft,"default_synchronous")==0 ){
|
---|
| 281 | static VdbeOpList getSync[] = {
|
---|
| 282 | { OP_ColumnName, 0, 1, "synchronous"},
|
---|
| 283 | { OP_ReadCookie, 0, 3, 0},
|
---|
| 284 | { OP_Dup, 0, 0, 0},
|
---|
| 285 | { OP_If, 0, 0, 0}, /* 3 */
|
---|
| 286 | { OP_ReadCookie, 0, 2, 0},
|
---|
| 287 | { OP_Integer, 0, 0, 0},
|
---|
| 288 | { OP_Lt, 0, 5, 0},
|
---|
| 289 | { OP_AddImm, 1, 0, 0},
|
---|
| 290 | { OP_Callback, 1, 0, 0},
|
---|
| 291 | { OP_Halt, 0, 0, 0},
|
---|
| 292 | { OP_AddImm, -1, 0, 0}, /* 10 */
|
---|
| 293 | { OP_Callback, 1, 0, 0}
|
---|
| 294 | };
|
---|
| 295 | if( pRight->z==pLeft->z ){
|
---|
| 296 | int addr = sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
|
---|
| 297 | sqliteVdbeChangeP2(v, addr+3, addr+10);
|
---|
| 298 | }else{
|
---|
| 299 | int addr;
|
---|
| 300 | int size = db->cache_size;
|
---|
| 301 | if( size<0 ) size = -size;
|
---|
| 302 | sqliteBeginWriteOperation(pParse, 0, 0);
|
---|
| 303 | sqliteVdbeAddOp(v, OP_ReadCookie, 0, 2);
|
---|
| 304 | sqliteVdbeAddOp(v, OP_Dup, 0, 0);
|
---|
| 305 | addr = sqliteVdbeAddOp(v, OP_Integer, 0, 0);
|
---|
| 306 | sqliteVdbeAddOp(v, OP_Ne, 0, addr+3);
|
---|
| 307 | sqliteVdbeAddOp(v, OP_AddImm, MAX_PAGES, 0);
|
---|
| 308 | sqliteVdbeAddOp(v, OP_AbsValue, 0, 0);
|
---|
| 309 | db->safety_level = getSafetyLevel(zRight)+1;
|
---|
| 310 | if( db->safety_level==1 ){
|
---|
| 311 | sqliteVdbeAddOp(v, OP_Negative, 0, 0);
|
---|
| 312 | size = -size;
|
---|
| 313 | }
|
---|
| 314 | sqliteVdbeAddOp(v, OP_SetCookie, 0, 2);
|
---|
| 315 | sqliteVdbeAddOp(v, OP_Integer, db->safety_level, 0);
|
---|
| 316 | sqliteVdbeAddOp(v, OP_SetCookie, 0, 3);
|
---|
| 317 | sqliteEndWriteOperation(pParse);
|
---|
| 318 | db->cache_size = size;
|
---|
| 319 | sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
---|
| 320 | sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
|
---|
| 321 | }
|
---|
| 322 | }else
|
---|
| 323 |
|
---|
| 324 | /*
|
---|
| 325 | ** PRAGMA synchronous
|
---|
| 326 | ** PRAGMA synchronous=OFF|ON|NORMAL|FULL
|
---|
| 327 | **
|
---|
| 328 | ** Return or set the local value of the synchronous flag. Changing
|
---|
| 329 | ** the local value does not make changes to the disk file and the
|
---|
| 330 | ** default value will be restored the next time the database is
|
---|
| 331 | ** opened.
|
---|
| 332 | */
|
---|
| 333 | if( sqliteStrICmp(zLeft,"synchronous")==0 ){
|
---|
| 334 | static VdbeOpList getSync[] = {
|
---|
| 335 | { OP_ColumnName, 0, 1, "synchronous"},
|
---|
| 336 | { OP_Callback, 1, 0, 0},
|
---|
| 337 | };
|
---|
| 338 | if( pRight->z==pLeft->z ){
|
---|
| 339 | sqliteVdbeAddOp(v, OP_Integer, db->safety_level-1, 0);
|
---|
| 340 | sqliteVdbeAddOpList(v, ArraySize(getSync), getSync);
|
---|
| 341 | }else{
|
---|
| 342 | int size = db->cache_size;
|
---|
| 343 | if( size<0 ) size = -size;
|
---|
| 344 | db->safety_level = getSafetyLevel(zRight)+1;
|
---|
| 345 | if( db->safety_level==1 ) size = -size;
|
---|
| 346 | db->cache_size = size;
|
---|
| 347 | sqliteBtreeSetCacheSize(db->aDb[0].pBt, db->cache_size);
|
---|
| 348 | sqliteBtreeSetSafetyLevel(db->aDb[0].pBt, db->safety_level);
|
---|
| 349 | }
|
---|
| 350 | }else
|
---|
| 351 |
|
---|
| 352 | #ifndef NDEBUG
|
---|
| 353 | if( sqliteStrICmp(zLeft, "trigger_overhead_test")==0 ){
|
---|
| 354 | if( getBoolean(zRight) ){
|
---|
| 355 | always_code_trigger_setup = 1;
|
---|
| 356 | }else{
|
---|
| 357 | always_code_trigger_setup = 0;
|
---|
| 358 | }
|
---|
| 359 | }else
|
---|
| 360 | #endif
|
---|
| 361 |
|
---|
| 362 | if( flagPragma(pParse, zLeft, zRight) ){
|
---|
| 363 | /* The flagPragma() call also generates any necessary code */
|
---|
| 364 | }else
|
---|
| 365 |
|
---|
| 366 | if( sqliteStrICmp(zLeft, "table_info")==0 ){
|
---|
| 367 | Table *pTab;
|
---|
| 368 | pTab = sqliteFindTable(db, zRight, 0);
|
---|
| 369 | if( pTab ){
|
---|
| 370 | static VdbeOpList tableInfoPreface[] = {
|
---|
| 371 | { OP_ColumnName, 0, 0, "cid"},
|
---|
| 372 | { OP_ColumnName, 1, 0, "name"},
|
---|
| 373 | { OP_ColumnName, 2, 0, "type"},
|
---|
| 374 | { OP_ColumnName, 3, 0, "notnull"},
|
---|
| 375 | { OP_ColumnName, 4, 0, "dflt_value"},
|
---|
| 376 | { OP_ColumnName, 5, 1, "pk"},
|
---|
| 377 | };
|
---|
| 378 | int i;
|
---|
| 379 | sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
|
---|
| 380 | sqliteViewGetColumnNames(pParse, pTab);
|
---|
| 381 | for(i=0; i<pTab->nCol; i++){
|
---|
| 382 | sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
---|
| 383 | sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[i].zName, 0);
|
---|
| 384 | sqliteVdbeOp3(v, OP_String, 0, 0,
|
---|
| 385 | pTab->aCol[i].zType ? pTab->aCol[i].zType : "numeric", 0);
|
---|
| 386 | sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].notNull, 0);
|
---|
| 387 | sqliteVdbeOp3(v, OP_String, 0, 0,
|
---|
| 388 | pTab->aCol[i].zDflt, P3_STATIC);
|
---|
| 389 | sqliteVdbeAddOp(v, OP_Integer, pTab->aCol[i].isPrimKey, 0);
|
---|
| 390 | sqliteVdbeAddOp(v, OP_Callback, 6, 0);
|
---|
| 391 | }
|
---|
| 392 | }
|
---|
| 393 | }else
|
---|
| 394 |
|
---|
| 395 | if( sqliteStrICmp(zLeft, "index_info")==0 ){
|
---|
| 396 | Index *pIdx;
|
---|
| 397 | Table *pTab;
|
---|
| 398 | pIdx = sqliteFindIndex(db, zRight, 0);
|
---|
| 399 | if( pIdx ){
|
---|
| 400 | static VdbeOpList tableInfoPreface[] = {
|
---|
| 401 | { OP_ColumnName, 0, 0, "seqno"},
|
---|
| 402 | { OP_ColumnName, 1, 0, "cid"},
|
---|
| 403 | { OP_ColumnName, 2, 1, "name"},
|
---|
| 404 | };
|
---|
| 405 | int i;
|
---|
| 406 | pTab = pIdx->pTable;
|
---|
| 407 | sqliteVdbeAddOpList(v, ArraySize(tableInfoPreface), tableInfoPreface);
|
---|
| 408 | for(i=0; i<pIdx->nColumn; i++){
|
---|
| 409 | int cnum = pIdx->aiColumn[i];
|
---|
| 410 | sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
---|
| 411 | sqliteVdbeAddOp(v, OP_Integer, cnum, 0);
|
---|
| 412 | assert( pTab->nCol>cnum );
|
---|
| 413 | sqliteVdbeOp3(v, OP_String, 0, 0, pTab->aCol[cnum].zName, 0);
|
---|
| 414 | sqliteVdbeAddOp(v, OP_Callback, 3, 0);
|
---|
| 415 | }
|
---|
| 416 | }
|
---|
| 417 | }else
|
---|
| 418 |
|
---|
| 419 | if( sqliteStrICmp(zLeft, "index_list")==0 ){
|
---|
| 420 | Index *pIdx;
|
---|
| 421 | Table *pTab;
|
---|
| 422 | pTab = sqliteFindTable(db, zRight, 0);
|
---|
| 423 | if( pTab ){
|
---|
| 424 | v = sqliteGetVdbe(pParse);
|
---|
| 425 | pIdx = pTab->pIndex;
|
---|
| 426 | }
|
---|
| 427 | if( pTab && pIdx ){
|
---|
| 428 | int i = 0;
|
---|
| 429 | static VdbeOpList indexListPreface[] = {
|
---|
| 430 | { OP_ColumnName, 0, 0, "seq"},
|
---|
| 431 | { OP_ColumnName, 1, 0, "name"},
|
---|
| 432 | { OP_ColumnName, 2, 1, "unique"},
|
---|
| 433 | };
|
---|
| 434 |
|
---|
| 435 | sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
|
---|
| 436 | while(pIdx){
|
---|
| 437 | sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
---|
| 438 | sqliteVdbeOp3(v, OP_String, 0, 0, pIdx->zName, 0);
|
---|
| 439 | sqliteVdbeAddOp(v, OP_Integer, pIdx->onError!=OE_None, 0);
|
---|
| 440 | sqliteVdbeAddOp(v, OP_Callback, 3, 0);
|
---|
| 441 | ++i;
|
---|
| 442 | pIdx = pIdx->pNext;
|
---|
| 443 | }
|
---|
| 444 | }
|
---|
| 445 | }else
|
---|
| 446 |
|
---|
| 447 | if( sqliteStrICmp(zLeft, "foreign_key_list")==0 ){
|
---|
| 448 | FKey *pFK;
|
---|
| 449 | Table *pTab;
|
---|
| 450 | pTab = sqliteFindTable(db, zRight, 0);
|
---|
| 451 | if( pTab ){
|
---|
| 452 | v = sqliteGetVdbe(pParse);
|
---|
| 453 | pFK = pTab->pFKey;
|
---|
| 454 | }
|
---|
| 455 | if( pTab && pFK ){
|
---|
| 456 | int i = 0;
|
---|
| 457 | static VdbeOpList indexListPreface[] = {
|
---|
| 458 | { OP_ColumnName, 0, 0, "id"},
|
---|
| 459 | { OP_ColumnName, 1, 0, "seq"},
|
---|
| 460 | { OP_ColumnName, 2, 0, "table"},
|
---|
| 461 | { OP_ColumnName, 3, 0, "from"},
|
---|
| 462 | { OP_ColumnName, 4, 1, "to"},
|
---|
| 463 | };
|
---|
| 464 |
|
---|
| 465 | sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
|
---|
| 466 | while(pFK){
|
---|
| 467 | int j;
|
---|
| 468 | for(j=0; j<pFK->nCol; j++){
|
---|
| 469 | sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
---|
| 470 | sqliteVdbeAddOp(v, OP_Integer, j, 0);
|
---|
| 471 | sqliteVdbeOp3(v, OP_String, 0, 0, pFK->zTo, 0);
|
---|
| 472 | sqliteVdbeOp3(v, OP_String, 0, 0,
|
---|
| 473 | pTab->aCol[pFK->aCol[j].iFrom].zName, 0);
|
---|
| 474 | sqliteVdbeOp3(v, OP_String, 0, 0, pFK->aCol[j].zCol, 0);
|
---|
| 475 | sqliteVdbeAddOp(v, OP_Callback, 5, 0);
|
---|
| 476 | }
|
---|
| 477 | ++i;
|
---|
| 478 | pFK = pFK->pNextFrom;
|
---|
| 479 | }
|
---|
| 480 | }
|
---|
| 481 | }else
|
---|
| 482 |
|
---|
| 483 | if( sqliteStrICmp(zLeft, "database_list")==0 ){
|
---|
| 484 | int i;
|
---|
| 485 | static VdbeOpList indexListPreface[] = {
|
---|
| 486 | { OP_ColumnName, 0, 0, "seq"},
|
---|
| 487 | { OP_ColumnName, 1, 0, "name"},
|
---|
| 488 | { OP_ColumnName, 2, 1, "file"},
|
---|
| 489 | };
|
---|
| 490 |
|
---|
| 491 | sqliteVdbeAddOpList(v, ArraySize(indexListPreface), indexListPreface);
|
---|
| 492 | for(i=0; i<db->nDb; i++){
|
---|
| 493 | if( db->aDb[i].pBt==0 ) continue;
|
---|
| 494 | assert( db->aDb[i].zName!=0 );
|
---|
| 495 | sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
---|
| 496 | sqliteVdbeOp3(v, OP_String, 0, 0, db->aDb[i].zName, 0);
|
---|
| 497 | sqliteVdbeOp3(v, OP_String, 0, 0,
|
---|
| 498 | sqliteBtreeGetFilename(db->aDb[i].pBt), 0);
|
---|
| 499 | sqliteVdbeAddOp(v, OP_Callback, 3, 0);
|
---|
| 500 | }
|
---|
| 501 | }else
|
---|
| 502 |
|
---|
| 503 |
|
---|
| 504 | /*
|
---|
| 505 | ** PRAGMA temp_store
|
---|
| 506 | ** PRAGMA temp_store = "default"|"memory"|"file"
|
---|
| 507 | **
|
---|
| 508 | ** Return or set the local value of the temp_store flag. Changing
|
---|
| 509 | ** the local value does not make changes to the disk file and the default
|
---|
| 510 | ** value will be restored the next time the database is opened.
|
---|
| 511 | **
|
---|
| 512 | ** Note that it is possible for the library compile-time options to
|
---|
| 513 | ** override this setting
|
---|
| 514 | */
|
---|
| 515 | if( sqliteStrICmp(zLeft, "temp_store")==0 ){
|
---|
| 516 | static VdbeOpList getTmpDbLoc[] = {
|
---|
| 517 | { OP_ColumnName, 0, 1, "temp_store"},
|
---|
| 518 | { OP_Callback, 1, 0, 0},
|
---|
| 519 | };
|
---|
| 520 | if( pRight->z==pLeft->z ){
|
---|
| 521 | sqliteVdbeAddOp(v, OP_Integer, db->temp_store, 0);
|
---|
| 522 | sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
|
---|
| 523 | }else{
|
---|
| 524 | changeTempStorage(pParse, zRight);
|
---|
| 525 | }
|
---|
| 526 | }else
|
---|
| 527 |
|
---|
| 528 | /*
|
---|
| 529 | ** PRAGMA default_temp_store
|
---|
| 530 | ** PRAGMA default_temp_store = "default"|"memory"|"file"
|
---|
| 531 | **
|
---|
| 532 | ** Return or set the value of the persistent temp_store flag. Any
|
---|
| 533 | ** change does not take effect until the next time the database is
|
---|
| 534 | ** opened.
|
---|
| 535 | **
|
---|
| 536 | ** Note that it is possible for the library compile-time options to
|
---|
| 537 | ** override this setting
|
---|
| 538 | */
|
---|
| 539 | if( sqliteStrICmp(zLeft, "default_temp_store")==0 ){
|
---|
| 540 | static VdbeOpList getTmpDbLoc[] = {
|
---|
| 541 | { OP_ColumnName, 0, 1, "temp_store"},
|
---|
| 542 | { OP_ReadCookie, 0, 5, 0},
|
---|
| 543 | { OP_Callback, 1, 0, 0}};
|
---|
| 544 | if( pRight->z==pLeft->z ){
|
---|
| 545 | sqliteVdbeAddOpList(v, ArraySize(getTmpDbLoc), getTmpDbLoc);
|
---|
| 546 | }else{
|
---|
| 547 | sqliteBeginWriteOperation(pParse, 0, 0);
|
---|
| 548 | sqliteVdbeAddOp(v, OP_Integer, getTempStore(zRight), 0);
|
---|
| 549 | sqliteVdbeAddOp(v, OP_SetCookie, 0, 5);
|
---|
| 550 | sqliteEndWriteOperation(pParse);
|
---|
| 551 | }
|
---|
| 552 | }else
|
---|
| 553 |
|
---|
| 554 | #ifndef NDEBUG
|
---|
| 555 | if( sqliteStrICmp(zLeft, "parser_trace")==0 ){
|
---|
| 556 | extern void sqliteParserTrace(FILE*, char *);
|
---|
| 557 | if( getBoolean(zRight) ){
|
---|
| 558 | sqliteParserTrace(stdout, "parser: ");
|
---|
| 559 | }else{
|
---|
| 560 | sqliteParserTrace(0, 0);
|
---|
| 561 | }
|
---|
| 562 | }else
|
---|
| 563 | #endif
|
---|
| 564 |
|
---|
| 565 | if( sqliteStrICmp(zLeft, "integrity_check")==0 ){
|
---|
| 566 | int i, j, addr;
|
---|
| 567 |
|
---|
| 568 | /* Code that initializes the integrity check program. Set the
|
---|
| 569 | ** error count 0
|
---|
| 570 | */
|
---|
| 571 | static VdbeOpList initCode[] = {
|
---|
| 572 | { OP_Integer, 0, 0, 0},
|
---|
| 573 | { OP_MemStore, 0, 1, 0},
|
---|
| 574 | { OP_ColumnName, 0, 1, "integrity_check"},
|
---|
| 575 | };
|
---|
| 576 |
|
---|
| 577 | /* Code to do an BTree integrity check on a single database file.
|
---|
| 578 | */
|
---|
| 579 | static VdbeOpList checkDb[] = {
|
---|
| 580 | { OP_SetInsert, 0, 0, "2"},
|
---|
| 581 | { OP_Integer, 0, 0, 0}, /* 1 */
|
---|
| 582 | { OP_OpenRead, 0, 2, 0},
|
---|
| 583 | { OP_Rewind, 0, 7, 0}, /* 3 */
|
---|
| 584 | { OP_Column, 0, 3, 0}, /* 4 */
|
---|
| 585 | { OP_SetInsert, 0, 0, 0},
|
---|
| 586 | { OP_Next, 0, 4, 0}, /* 6 */
|
---|
| 587 | { OP_IntegrityCk, 0, 0, 0}, /* 7 */
|
---|
| 588 | { OP_Dup, 0, 1, 0},
|
---|
| 589 | { OP_String, 0, 0, "ok"},
|
---|
| 590 | { OP_StrEq, 0, 12, 0}, /* 10 */
|
---|
| 591 | { OP_MemIncr, 0, 0, 0},
|
---|
| 592 | { OP_String, 0, 0, "*** in database "},
|
---|
| 593 | { OP_String, 0, 0, 0}, /* 13 */
|
---|
| 594 | { OP_String, 0, 0, " ***\n"},
|
---|
| 595 | { OP_Pull, 3, 0, 0},
|
---|
| 596 | { OP_Concat, 4, 1, 0},
|
---|
| 597 | { OP_Callback, 1, 0, 0},
|
---|
| 598 | };
|
---|
| 599 |
|
---|
| 600 | /* Code that appears at the end of the integrity check. If no error
|
---|
| 601 | ** messages have been generated, output OK. Otherwise output the
|
---|
| 602 | ** error message
|
---|
| 603 | */
|
---|
| 604 | static VdbeOpList endCode[] = {
|
---|
| 605 | { OP_MemLoad, 0, 0, 0},
|
---|
| 606 | { OP_Integer, 0, 0, 0},
|
---|
| 607 | { OP_Ne, 0, 0, 0}, /* 2 */
|
---|
| 608 | { OP_String, 0, 0, "ok"},
|
---|
| 609 | { OP_Callback, 1, 0, 0},
|
---|
| 610 | };
|
---|
| 611 |
|
---|
| 612 | /* Initialize the VDBE program */
|
---|
| 613 | sqliteVdbeAddOpList(v, ArraySize(initCode), initCode);
|
---|
| 614 |
|
---|
| 615 | /* Do an integrity check on each database file */
|
---|
| 616 | for(i=0; i<db->nDb; i++){
|
---|
| 617 | HashElem *x;
|
---|
| 618 |
|
---|
| 619 | /* Do an integrity check of the B-Tree
|
---|
| 620 | */
|
---|
| 621 | addr = sqliteVdbeAddOpList(v, ArraySize(checkDb), checkDb);
|
---|
| 622 | sqliteVdbeChangeP1(v, addr+1, i);
|
---|
| 623 | sqliteVdbeChangeP2(v, addr+3, addr+7);
|
---|
| 624 | sqliteVdbeChangeP2(v, addr+6, addr+4);
|
---|
| 625 | sqliteVdbeChangeP2(v, addr+7, i);
|
---|
| 626 | sqliteVdbeChangeP2(v, addr+10, addr+ArraySize(checkDb));
|
---|
| 627 | sqliteVdbeChangeP3(v, addr+13, db->aDb[i].zName, P3_STATIC);
|
---|
| 628 |
|
---|
| 629 | /* Make sure all the indices are constructed correctly.
|
---|
| 630 | */
|
---|
| 631 | sqliteCodeVerifySchema(pParse, i);
|
---|
| 632 | for(x=sqliteHashFirst(&db->aDb[i].tblHash); x; x=sqliteHashNext(x)){
|
---|
| 633 | Table *pTab = sqliteHashData(x);
|
---|
| 634 | Index *pIdx;
|
---|
| 635 | int loopTop;
|
---|
| 636 |
|
---|
| 637 | if( pTab->pIndex==0 ) continue;
|
---|
| 638 | sqliteVdbeAddOp(v, OP_Integer, i, 0);
|
---|
| 639 | sqliteVdbeOp3(v, OP_OpenRead, 1, pTab->tnum, pTab->zName, 0);
|
---|
| 640 | for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
---|
| 641 | if( pIdx->tnum==0 ) continue;
|
---|
| 642 | sqliteVdbeAddOp(v, OP_Integer, pIdx->iDb, 0);
|
---|
| 643 | sqliteVdbeOp3(v, OP_OpenRead, j+2, pIdx->tnum, pIdx->zName, 0);
|
---|
| 644 | }
|
---|
| 645 | sqliteVdbeAddOp(v, OP_Integer, 0, 0);
|
---|
| 646 | sqliteVdbeAddOp(v, OP_MemStore, 1, 1);
|
---|
| 647 | loopTop = sqliteVdbeAddOp(v, OP_Rewind, 1, 0);
|
---|
| 648 | sqliteVdbeAddOp(v, OP_MemIncr, 1, 0);
|
---|
| 649 | for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
---|
| 650 | int k, jmp2;
|
---|
| 651 | static VdbeOpList idxErr[] = {
|
---|
| 652 | { OP_MemIncr, 0, 0, 0},
|
---|
| 653 | { OP_String, 0, 0, "rowid "},
|
---|
| 654 | { OP_Recno, 1, 0, 0},
|
---|
| 655 | { OP_String, 0, 0, " missing from index "},
|
---|
| 656 | { OP_String, 0, 0, 0}, /* 4 */
|
---|
| 657 | { OP_Concat, 4, 0, 0},
|
---|
| 658 | { OP_Callback, 1, 0, 0},
|
---|
| 659 | };
|
---|
| 660 | sqliteVdbeAddOp(v, OP_Recno, 1, 0);
|
---|
| 661 | for(k=0; k<pIdx->nColumn; k++){
|
---|
| 662 | int idx = pIdx->aiColumn[k];
|
---|
| 663 | if( idx==pTab->iPKey ){
|
---|
| 664 | sqliteVdbeAddOp(v, OP_Recno, 1, 0);
|
---|
| 665 | }else{
|
---|
| 666 | sqliteVdbeAddOp(v, OP_Column, 1, idx);
|
---|
| 667 | }
|
---|
| 668 | }
|
---|
| 669 | sqliteVdbeAddOp(v, OP_MakeIdxKey, pIdx->nColumn, 0);
|
---|
| 670 | if( db->file_format>=4 ) sqliteAddIdxKeyType(v, pIdx);
|
---|
| 671 | jmp2 = sqliteVdbeAddOp(v, OP_Found, j+2, 0);
|
---|
| 672 | addr = sqliteVdbeAddOpList(v, ArraySize(idxErr), idxErr);
|
---|
| 673 | sqliteVdbeChangeP3(v, addr+4, pIdx->zName, P3_STATIC);
|
---|
| 674 | sqliteVdbeChangeP2(v, jmp2, sqliteVdbeCurrentAddr(v));
|
---|
| 675 | }
|
---|
| 676 | sqliteVdbeAddOp(v, OP_Next, 1, loopTop+1);
|
---|
| 677 | sqliteVdbeChangeP2(v, loopTop, sqliteVdbeCurrentAddr(v));
|
---|
| 678 | for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
|
---|
| 679 | static VdbeOpList cntIdx[] = {
|
---|
| 680 | { OP_Integer, 0, 0, 0},
|
---|
| 681 | { OP_MemStore, 2, 1, 0},
|
---|
| 682 | { OP_Rewind, 0, 0, 0}, /* 2 */
|
---|
| 683 | { OP_MemIncr, 2, 0, 0},
|
---|
| 684 | { OP_Next, 0, 0, 0}, /* 4 */
|
---|
| 685 | { OP_MemLoad, 1, 0, 0},
|
---|
| 686 | { OP_MemLoad, 2, 0, 0},
|
---|
| 687 | { OP_Eq, 0, 0, 0}, /* 7 */
|
---|
| 688 | { OP_MemIncr, 0, 0, 0},
|
---|
| 689 | { OP_String, 0, 0, "wrong # of entries in index "},
|
---|
| 690 | { OP_String, 0, 0, 0}, /* 10 */
|
---|
| 691 | { OP_Concat, 2, 0, 0},
|
---|
| 692 | { OP_Callback, 1, 0, 0},
|
---|
| 693 | };
|
---|
| 694 | if( pIdx->tnum==0 ) continue;
|
---|
| 695 | addr = sqliteVdbeAddOpList(v, ArraySize(cntIdx), cntIdx);
|
---|
| 696 | sqliteVdbeChangeP1(v, addr+2, j+2);
|
---|
| 697 | sqliteVdbeChangeP2(v, addr+2, addr+5);
|
---|
| 698 | sqliteVdbeChangeP1(v, addr+4, j+2);
|
---|
| 699 | sqliteVdbeChangeP2(v, addr+4, addr+3);
|
---|
| 700 | sqliteVdbeChangeP2(v, addr+7, addr+ArraySize(cntIdx));
|
---|
| 701 | sqliteVdbeChangeP3(v, addr+10, pIdx->zName, P3_STATIC);
|
---|
| 702 | }
|
---|
| 703 | }
|
---|
| 704 | }
|
---|
| 705 | addr = sqliteVdbeAddOpList(v, ArraySize(endCode), endCode);
|
---|
| 706 | sqliteVdbeChangeP2(v, addr+2, addr+ArraySize(endCode));
|
---|
| 707 | }else
|
---|
| 708 |
|
---|
| 709 | {}
|
---|
| 710 | sqliteFree(zLeft);
|
---|
| 711 | sqliteFree(zRight);
|
---|
| 712 | }
|
---|