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 ATTACH and DETACH commands. |
13 | */ |
14 | #include "sqliteInt.h" |
15 | |
16 | #ifndef SQLITE_OMIT_ATTACH |
17 | /* |
18 | ** Resolve an expression that was part of an ATTACH or DETACH statement. This |
19 | ** is slightly different from resolving a normal SQL expression, because simple |
20 | ** identifiers are treated as strings, not possible column names or aliases. |
21 | ** |
22 | ** i.e. if the parser sees: |
23 | ** |
24 | ** ATTACH DATABASE abc AS def |
25 | ** |
26 | ** it treats the two expressions as literal strings 'abc' and 'def' instead of |
27 | ** looking for columns of the same name. |
28 | ** |
29 | ** This only applies to the root node of pExpr, so the statement: |
30 | ** |
31 | ** ATTACH DATABASE abc||def AS 'db2' |
32 | ** |
33 | ** will fail because neither abc or def can be resolved. |
34 | */ |
35 | static int resolveAttachExpr(NameContext *pName, Expr *pExpr) |
36 | { |
37 | int rc = SQLITE_OK; |
38 | if( pExpr ){ |
39 | if( pExpr->op!=TK_ID ){ |
40 | rc = sqlite3ResolveExprNames(pName, pExpr); |
41 | }else{ |
42 | pExpr->op = TK_STRING; |
43 | } |
44 | } |
45 | return rc; |
46 | } |
47 | |
48 | /* |
49 | ** Return true if zName points to a name that may be used to refer to |
50 | ** database iDb attached to handle db. |
51 | */ |
52 | int sqlite3DbIsNamed(sqlite3 *db, int iDb, const char *zName){ |
53 | return ( |
54 | sqlite3StrICmp(db->aDb[iDb].zDbSName, zName)==0 |
55 | || (iDb==0 && sqlite3StrICmp("main" , zName)==0) |
56 | ); |
57 | } |
58 | |
59 | /* |
60 | ** An SQL user-function registered to do the work of an ATTACH statement. The |
61 | ** three arguments to the function come directly from an attach statement: |
62 | ** |
63 | ** ATTACH DATABASE x AS y KEY z |
64 | ** |
65 | ** SELECT sqlite_attach(x, y, z) |
66 | ** |
67 | ** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the |
68 | ** third argument. |
69 | ** |
70 | ** If the db->init.reopenMemdb flags is set, then instead of attaching a |
71 | ** new database, close the database on db->init.iDb and reopen it as an |
72 | ** empty MemDB. |
73 | */ |
74 | static void attachFunc( |
75 | sqlite3_context *context, |
76 | int NotUsed, |
77 | sqlite3_value **argv |
78 | ){ |
79 | int i; |
80 | int rc = 0; |
81 | sqlite3 *db = sqlite3_context_db_handle(context); |
82 | const char *zName; |
83 | const char *zFile; |
84 | char *zPath = 0; |
85 | char *zErr = 0; |
86 | unsigned int flags; |
87 | Db *aNew; /* New array of Db pointers */ |
88 | Db *pNew; /* Db object for the newly attached database */ |
89 | char *zErrDyn = 0; |
90 | sqlite3_vfs *pVfs; |
91 | |
92 | UNUSED_PARAMETER(NotUsed); |
93 | zFile = (const char *)sqlite3_value_text(argv[0]); |
94 | zName = (const char *)sqlite3_value_text(argv[1]); |
95 | if( zFile==0 ) zFile = "" ; |
96 | if( zName==0 ) zName = "" ; |
97 | |
98 | #ifndef SQLITE_OMIT_DESERIALIZE |
99 | # define REOPEN_AS_MEMDB(db) (db->init.reopenMemdb) |
100 | #else |
101 | # define REOPEN_AS_MEMDB(db) (0) |
102 | #endif |
103 | |
104 | if( REOPEN_AS_MEMDB(db) ){ |
105 | /* This is not a real ATTACH. Instead, this routine is being called |
106 | ** from sqlite3_deserialize() to close database db->init.iDb and |
107 | ** reopen it as a MemDB */ |
108 | pVfs = sqlite3_vfs_find("memdb" ); |
109 | if( pVfs==0 ) return; |
110 | pNew = &db->aDb[db->init.iDb]; |
111 | if( pNew->pBt ) sqlite3BtreeClose(pNew->pBt); |
112 | pNew->pBt = 0; |
113 | pNew->pSchema = 0; |
114 | rc = sqlite3BtreeOpen(pVfs, "x\0" , db, &pNew->pBt, 0, SQLITE_OPEN_MAIN_DB); |
115 | }else{ |
116 | /* This is a real ATTACH |
117 | ** |
118 | ** Check for the following errors: |
119 | ** |
120 | ** * Too many attached databases, |
121 | ** * Transaction currently open |
122 | ** * Specified database name already being used. |
123 | */ |
124 | if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){ |
125 | zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d" , |
126 | db->aLimit[SQLITE_LIMIT_ATTACHED] |
127 | ); |
128 | goto attach_error; |
129 | } |
130 | for(i=0; i<db->nDb; i++){ |
131 | assert( zName ); |
132 | if( sqlite3DbIsNamed(db, i, zName) ){ |
133 | zErrDyn = sqlite3MPrintf(db, "database %s is already in use" , zName); |
134 | goto attach_error; |
135 | } |
136 | } |
137 | |
138 | /* Allocate the new entry in the db->aDb[] array and initialize the schema |
139 | ** hash tables. |
140 | */ |
141 | if( db->aDb==db->aDbStatic ){ |
142 | aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 ); |
143 | if( aNew==0 ) return; |
144 | memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); |
145 | }else{ |
146 | aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); |
147 | if( aNew==0 ) return; |
148 | } |
149 | db->aDb = aNew; |
150 | pNew = &db->aDb[db->nDb]; |
151 | memset(pNew, 0, sizeof(*pNew)); |
152 | |
153 | /* Open the database file. If the btree is successfully opened, use |
154 | ** it to obtain the database schema. At this point the schema may |
155 | ** or may not be initialized. |
156 | */ |
157 | flags = db->openFlags; |
158 | rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); |
159 | if( rc!=SQLITE_OK ){ |
160 | if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); |
161 | sqlite3_result_error(context, zErr, -1); |
162 | sqlite3_free(zErr); |
163 | return; |
164 | } |
165 | assert( pVfs ); |
166 | flags |= SQLITE_OPEN_MAIN_DB; |
167 | rc = sqlite3BtreeOpen(pVfs, zPath, db, &pNew->pBt, 0, flags); |
168 | db->nDb++; |
169 | pNew->zDbSName = sqlite3DbStrDup(db, zName); |
170 | } |
171 | db->noSharedCache = 0; |
172 | if( rc==SQLITE_CONSTRAINT ){ |
173 | rc = SQLITE_ERROR; |
174 | zErrDyn = sqlite3MPrintf(db, "database is already attached" ); |
175 | }else if( rc==SQLITE_OK ){ |
176 | Pager *; |
177 | pNew->pSchema = sqlite3SchemaGet(db, pNew->pBt); |
178 | if( !pNew->pSchema ){ |
179 | rc = SQLITE_NOMEM_BKPT; |
180 | }else if( pNew->pSchema->file_format && pNew->pSchema->enc!=ENC(db) ){ |
181 | zErrDyn = sqlite3MPrintf(db, |
182 | "attached databases must use the same text encoding as main database" ); |
183 | rc = SQLITE_ERROR; |
184 | } |
185 | sqlite3BtreeEnter(pNew->pBt); |
186 | pPager = sqlite3BtreePager(pNew->pBt); |
187 | sqlite3PagerLockingMode(pPager, db->dfltLockMode); |
188 | sqlite3BtreeSecureDelete(pNew->pBt, |
189 | sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) ); |
190 | #ifndef SQLITE_OMIT_PAGER_PRAGMAS |
191 | sqlite3BtreeSetPagerFlags(pNew->pBt, |
192 | PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK)); |
193 | #endif |
194 | sqlite3BtreeLeave(pNew->pBt); |
195 | } |
196 | pNew->safety_level = SQLITE_DEFAULT_SYNCHRONOUS+1; |
197 | if( rc==SQLITE_OK && pNew->zDbSName==0 ){ |
198 | rc = SQLITE_NOMEM_BKPT; |
199 | } |
200 | sqlite3_free_filename( zPath ); |
201 | |
202 | /* If the file was opened successfully, read the schema for the new database. |
203 | ** If this fails, or if opening the file failed, then close the file and |
204 | ** remove the entry from the db->aDb[] array. i.e. put everything back the |
205 | ** way we found it. |
206 | */ |
207 | if( rc==SQLITE_OK ){ |
208 | sqlite3BtreeEnterAll(db); |
209 | db->init.iDb = 0; |
210 | db->mDbFlags &= ~(DBFLAG_SchemaKnownOk); |
211 | if( !REOPEN_AS_MEMDB(db) ){ |
212 | rc = sqlite3Init(db, &zErrDyn); |
213 | } |
214 | sqlite3BtreeLeaveAll(db); |
215 | assert( zErrDyn==0 || rc!=SQLITE_OK ); |
216 | } |
217 | #ifdef SQLITE_USER_AUTHENTICATION |
218 | if( rc==SQLITE_OK && !REOPEN_AS_MEMDB(db) ){ |
219 | u8 newAuth = 0; |
220 | rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); |
221 | if( newAuth<db->auth.authLevel ){ |
222 | rc = SQLITE_AUTH_USER; |
223 | } |
224 | } |
225 | #endif |
226 | if( rc ){ |
227 | if( !REOPEN_AS_MEMDB(db) ){ |
228 | int iDb = db->nDb - 1; |
229 | assert( iDb>=2 ); |
230 | if( db->aDb[iDb].pBt ){ |
231 | sqlite3BtreeClose(db->aDb[iDb].pBt); |
232 | db->aDb[iDb].pBt = 0; |
233 | db->aDb[iDb].pSchema = 0; |
234 | } |
235 | sqlite3ResetAllSchemasOfConnection(db); |
236 | db->nDb = iDb; |
237 | if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ |
238 | sqlite3OomFault(db); |
239 | sqlite3DbFree(db, zErrDyn); |
240 | zErrDyn = sqlite3MPrintf(db, "out of memory" ); |
241 | }else if( zErrDyn==0 ){ |
242 | zErrDyn = sqlite3MPrintf(db, "unable to open database: %s" , zFile); |
243 | } |
244 | } |
245 | goto attach_error; |
246 | } |
247 | |
248 | return; |
249 | |
250 | attach_error: |
251 | /* Return an error if we get here */ |
252 | if( zErrDyn ){ |
253 | sqlite3_result_error(context, zErrDyn, -1); |
254 | sqlite3DbFree(db, zErrDyn); |
255 | } |
256 | if( rc ) sqlite3_result_error_code(context, rc); |
257 | } |
258 | |
259 | /* |
260 | ** An SQL user-function registered to do the work of an DETACH statement. The |
261 | ** three arguments to the function come directly from a detach statement: |
262 | ** |
263 | ** DETACH DATABASE x |
264 | ** |
265 | ** SELECT sqlite_detach(x) |
266 | */ |
267 | static void detachFunc( |
268 | sqlite3_context *context, |
269 | int NotUsed, |
270 | sqlite3_value **argv |
271 | ){ |
272 | const char *zName = (const char *)sqlite3_value_text(argv[0]); |
273 | sqlite3 *db = sqlite3_context_db_handle(context); |
274 | int i; |
275 | Db *pDb = 0; |
276 | HashElem *pEntry; |
277 | char zErr[128]; |
278 | |
279 | UNUSED_PARAMETER(NotUsed); |
280 | |
281 | if( zName==0 ) zName = "" ; |
282 | for(i=0; i<db->nDb; i++){ |
283 | pDb = &db->aDb[i]; |
284 | if( pDb->pBt==0 ) continue; |
285 | if( sqlite3DbIsNamed(db, i, zName) ) break; |
286 | } |
287 | |
288 | if( i>=db->nDb ){ |
289 | sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s" , zName); |
290 | goto detach_error; |
291 | } |
292 | if( i<2 ){ |
293 | sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s" , zName); |
294 | goto detach_error; |
295 | } |
296 | if( sqlite3BtreeTxnState(pDb->pBt)!=SQLITE_TXN_NONE |
297 | || sqlite3BtreeIsInBackup(pDb->pBt) |
298 | ){ |
299 | sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked" , zName); |
300 | goto detach_error; |
301 | } |
302 | |
303 | /* If any TEMP triggers reference the schema being detached, move those |
304 | ** triggers to reference the TEMP schema itself. */ |
305 | assert( db->aDb[1].pSchema ); |
306 | pEntry = sqliteHashFirst(&db->aDb[1].pSchema->trigHash); |
307 | while( pEntry ){ |
308 | Trigger *pTrig = (Trigger*)sqliteHashData(pEntry); |
309 | if( pTrig->pTabSchema==pDb->pSchema ){ |
310 | pTrig->pTabSchema = pTrig->pSchema; |
311 | } |
312 | pEntry = sqliteHashNext(pEntry); |
313 | } |
314 | |
315 | sqlite3BtreeClose(pDb->pBt); |
316 | pDb->pBt = 0; |
317 | pDb->pSchema = 0; |
318 | sqlite3CollapseDatabaseArray(db); |
319 | return; |
320 | |
321 | detach_error: |
322 | sqlite3_result_error(context, zErr, -1); |
323 | } |
324 | |
325 | /* |
326 | ** This procedure generates VDBE code for a single invocation of either the |
327 | ** sqlite_detach() or sqlite_attach() SQL user functions. |
328 | */ |
329 | static void codeAttach( |
330 | Parse *pParse, /* The parser context */ |
331 | int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */ |
332 | FuncDef const *pFunc,/* FuncDef wrapper for detachFunc() or attachFunc() */ |
333 | Expr *pAuthArg, /* Expression to pass to authorization callback */ |
334 | Expr *pFilename, /* Name of database file */ |
335 | Expr *pDbname, /* Name of the database to use internally */ |
336 | Expr *pKey /* Database key for encryption extension */ |
337 | ){ |
338 | int rc; |
339 | NameContext sName; |
340 | Vdbe *v; |
341 | sqlite3* db = pParse->db; |
342 | int regArgs; |
343 | |
344 | if( pParse->nErr ) goto attach_end; |
345 | memset(&sName, 0, sizeof(NameContext)); |
346 | sName.pParse = pParse; |
347 | |
348 | if( |
349 | SQLITE_OK!=resolveAttachExpr(&sName, pFilename) || |
350 | SQLITE_OK!=resolveAttachExpr(&sName, pDbname) || |
351 | SQLITE_OK!=resolveAttachExpr(&sName, pKey) |
352 | ){ |
353 | goto attach_end; |
354 | } |
355 | |
356 | #ifndef SQLITE_OMIT_AUTHORIZATION |
357 | if( ALWAYS(pAuthArg) ){ |
358 | char *zAuthArg; |
359 | if( pAuthArg->op==TK_STRING ){ |
360 | assert( !ExprHasProperty(pAuthArg, EP_IntValue) ); |
361 | zAuthArg = pAuthArg->u.zToken; |
362 | }else{ |
363 | zAuthArg = 0; |
364 | } |
365 | rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0); |
366 | if(rc!=SQLITE_OK ){ |
367 | goto attach_end; |
368 | } |
369 | } |
370 | #endif /* SQLITE_OMIT_AUTHORIZATION */ |
371 | |
372 | |
373 | v = sqlite3GetVdbe(pParse); |
374 | regArgs = sqlite3GetTempRange(pParse, 4); |
375 | sqlite3ExprCode(pParse, pFilename, regArgs); |
376 | sqlite3ExprCode(pParse, pDbname, regArgs+1); |
377 | sqlite3ExprCode(pParse, pKey, regArgs+2); |
378 | |
379 | assert( v || db->mallocFailed ); |
380 | if( v ){ |
381 | sqlite3VdbeAddFunctionCall(pParse, 0, regArgs+3-pFunc->nArg, regArgs+3, |
382 | pFunc->nArg, pFunc, 0); |
383 | /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this |
384 | ** statement only). For DETACH, set it to false (expire all existing |
385 | ** statements). |
386 | */ |
387 | sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH)); |
388 | } |
389 | |
390 | attach_end: |
391 | sqlite3ExprDelete(db, pFilename); |
392 | sqlite3ExprDelete(db, pDbname); |
393 | sqlite3ExprDelete(db, pKey); |
394 | } |
395 | |
396 | /* |
397 | ** Called by the parser to compile a DETACH statement. |
398 | ** |
399 | ** DETACH pDbname |
400 | */ |
401 | void sqlite3Detach(Parse *pParse, Expr *pDbname){ |
402 | static const FuncDef detach_func = { |
403 | 1, /* nArg */ |
404 | SQLITE_UTF8, /* funcFlags */ |
405 | 0, /* pUserData */ |
406 | 0, /* pNext */ |
407 | detachFunc, /* xSFunc */ |
408 | 0, /* xFinalize */ |
409 | 0, 0, /* xValue, xInverse */ |
410 | "sqlite_detach" , /* zName */ |
411 | {0} |
412 | }; |
413 | codeAttach(pParse, SQLITE_DETACH, &detach_func, pDbname, 0, 0, pDbname); |
414 | } |
415 | |
416 | /* |
417 | ** Called by the parser to compile an ATTACH statement. |
418 | ** |
419 | ** ATTACH p AS pDbname KEY pKey |
420 | */ |
421 | void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){ |
422 | static const FuncDef attach_func = { |
423 | 3, /* nArg */ |
424 | SQLITE_UTF8, /* funcFlags */ |
425 | 0, /* pUserData */ |
426 | 0, /* pNext */ |
427 | attachFunc, /* xSFunc */ |
428 | 0, /* xFinalize */ |
429 | 0, 0, /* xValue, xInverse */ |
430 | "sqlite_attach" , /* zName */ |
431 | {0} |
432 | }; |
433 | codeAttach(pParse, SQLITE_ATTACH, &attach_func, p, p, pDbname, pKey); |
434 | } |
435 | #endif /* SQLITE_OMIT_ATTACH */ |
436 | |
437 | /* |
438 | ** Expression callback used by sqlite3FixAAAA() routines. |
439 | */ |
440 | static int fixExprCb(Walker *p, Expr *pExpr){ |
441 | DbFixer *pFix = p->u.pFix; |
442 | if( !pFix->bTemp ) ExprSetProperty(pExpr, EP_FromDDL); |
443 | if( pExpr->op==TK_VARIABLE ){ |
444 | if( pFix->pParse->db->init.busy ){ |
445 | pExpr->op = TK_NULL; |
446 | }else{ |
447 | sqlite3ErrorMsg(pFix->pParse, "%s cannot use variables" , pFix->zType); |
448 | return WRC_Abort; |
449 | } |
450 | } |
451 | return WRC_Continue; |
452 | } |
453 | |
454 | /* |
455 | ** Select callback used by sqlite3FixAAAA() routines. |
456 | */ |
457 | static int fixSelectCb(Walker *p, Select *pSelect){ |
458 | DbFixer *pFix = p->u.pFix; |
459 | int i; |
460 | SrcItem *pItem; |
461 | sqlite3 *db = pFix->pParse->db; |
462 | int iDb = sqlite3FindDbName(db, pFix->zDb); |
463 | SrcList *pList = pSelect->pSrc; |
464 | |
465 | if( NEVER(pList==0) ) return WRC_Continue; |
466 | for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ |
467 | if( pFix->bTemp==0 ){ |
468 | if( pItem->zDatabase ){ |
469 | if( iDb!=sqlite3FindDbName(db, pItem->zDatabase) ){ |
470 | sqlite3ErrorMsg(pFix->pParse, |
471 | "%s %T cannot reference objects in database %s" , |
472 | pFix->zType, pFix->pName, pItem->zDatabase); |
473 | return WRC_Abort; |
474 | } |
475 | sqlite3DbFree(db, pItem->zDatabase); |
476 | pItem->zDatabase = 0; |
477 | pItem->fg.notCte = 1; |
478 | } |
479 | pItem->pSchema = pFix->pSchema; |
480 | pItem->fg.fromDDL = 1; |
481 | } |
482 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) |
483 | if( pList->a[i].fg.isUsing==0 |
484 | && sqlite3WalkExpr(&pFix->w, pList->a[i].u3.pOn) |
485 | ){ |
486 | return WRC_Abort; |
487 | } |
488 | #endif |
489 | } |
490 | if( pSelect->pWith ){ |
491 | for(i=0; i<pSelect->pWith->nCte; i++){ |
492 | if( sqlite3WalkSelect(p, pSelect->pWith->a[i].pSelect) ){ |
493 | return WRC_Abort; |
494 | } |
495 | } |
496 | } |
497 | return WRC_Continue; |
498 | } |
499 | |
500 | /* |
501 | ** Initialize a DbFixer structure. This routine must be called prior |
502 | ** to passing the structure to one of the sqliteFixAAAA() routines below. |
503 | */ |
504 | void sqlite3FixInit( |
505 | DbFixer *pFix, /* The fixer to be initialized */ |
506 | Parse *pParse, /* Error messages will be written here */ |
507 | int iDb, /* This is the database that must be used */ |
508 | const char *zType, /* "view", "trigger", or "index" */ |
509 | const Token *pName /* Name of the view, trigger, or index */ |
510 | ){ |
511 | sqlite3 *db = pParse->db; |
512 | assert( db->nDb>iDb ); |
513 | pFix->pParse = pParse; |
514 | pFix->zDb = db->aDb[iDb].zDbSName; |
515 | pFix->pSchema = db->aDb[iDb].pSchema; |
516 | pFix->zType = zType; |
517 | pFix->pName = pName; |
518 | pFix->bTemp = (iDb==1); |
519 | pFix->w.pParse = pParse; |
520 | pFix->w.xExprCallback = fixExprCb; |
521 | pFix->w.xSelectCallback = fixSelectCb; |
522 | pFix->w.xSelectCallback2 = sqlite3WalkWinDefnDummyCallback; |
523 | pFix->w.walkerDepth = 0; |
524 | pFix->w.eCode = 0; |
525 | pFix->w.u.pFix = pFix; |
526 | } |
527 | |
528 | /* |
529 | ** The following set of routines walk through the parse tree and assign |
530 | ** a specific database to all table references where the database name |
531 | ** was left unspecified in the original SQL statement. The pFix structure |
532 | ** must have been initialized by a prior call to sqlite3FixInit(). |
533 | ** |
534 | ** These routines are used to make sure that an index, trigger, or |
535 | ** view in one database does not refer to objects in a different database. |
536 | ** (Exception: indices, triggers, and views in the TEMP database are |
537 | ** allowed to refer to anything.) If a reference is explicitly made |
538 | ** to an object in a different database, an error message is added to |
539 | ** pParse->zErrMsg and these routines return non-zero. If everything |
540 | ** checks out, these routines return 0. |
541 | */ |
542 | int sqlite3FixSrcList( |
543 | DbFixer *pFix, /* Context of the fixation */ |
544 | SrcList *pList /* The Source list to check and modify */ |
545 | ){ |
546 | int res = 0; |
547 | if( pList ){ |
548 | Select s; |
549 | memset(&s, 0, sizeof(s)); |
550 | s.pSrc = pList; |
551 | res = sqlite3WalkSelect(&pFix->w, &s); |
552 | } |
553 | return res; |
554 | } |
555 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) |
556 | int sqlite3FixSelect( |
557 | DbFixer *pFix, /* Context of the fixation */ |
558 | Select *pSelect /* The SELECT statement to be fixed to one database */ |
559 | ){ |
560 | return sqlite3WalkSelect(&pFix->w, pSelect); |
561 | } |
562 | int sqlite3FixExpr( |
563 | DbFixer *pFix, /* Context of the fixation */ |
564 | Expr *pExpr /* The expression to be fixed to one database */ |
565 | ){ |
566 | return sqlite3WalkExpr(&pFix->w, pExpr); |
567 | } |
568 | #endif |
569 | |
570 | #ifndef SQLITE_OMIT_TRIGGER |
571 | int sqlite3FixTriggerStep( |
572 | DbFixer *pFix, /* Context of the fixation */ |
573 | TriggerStep *pStep /* The trigger step be fixed to one database */ |
574 | ){ |
575 | while( pStep ){ |
576 | if( sqlite3WalkSelect(&pFix->w, pStep->pSelect) |
577 | || sqlite3WalkExpr(&pFix->w, pStep->pWhere) |
578 | || sqlite3WalkExprList(&pFix->w, pStep->pExprList) |
579 | || sqlite3FixSrcList(pFix, pStep->pFrom) |
580 | ){ |
581 | return 1; |
582 | } |
583 | #ifndef SQLITE_OMIT_UPSERT |
584 | { |
585 | Upsert *pUp; |
586 | for(pUp=pStep->pUpsert; pUp; pUp=pUp->pNextUpsert){ |
587 | if( sqlite3WalkExprList(&pFix->w, pUp->pUpsertTarget) |
588 | || sqlite3WalkExpr(&pFix->w, pUp->pUpsertTargetWhere) |
589 | || sqlite3WalkExprList(&pFix->w, pUp->pUpsertSet) |
590 | || sqlite3WalkExpr(&pFix->w, pUp->pUpsertWhere) |
591 | ){ |
592 | return 1; |
593 | } |
594 | } |
595 | } |
596 | #endif |
597 | pStep = pStep->pNext; |
598 | } |
599 | |
600 | return 0; |
601 | } |
602 | #endif |
603 | |