diff options
Diffstat (limited to 'libraries/sqlite/win32/attach.c')
-rwxr-xr-x | libraries/sqlite/win32/attach.c | 521 |
1 files changed, 521 insertions, 0 deletions
diff --git a/libraries/sqlite/win32/attach.c b/libraries/sqlite/win32/attach.c new file mode 100755 index 0000000..2fb950f --- /dev/null +++ b/libraries/sqlite/win32/attach.c | |||
@@ -0,0 +1,521 @@ | |||
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 | ** $Id: attach.c,v 1.63 2007/10/03 08:46:44 danielk1977 Exp $ | ||
15 | */ | ||
16 | #include "sqliteInt.h" | ||
17 | |||
18 | #ifndef SQLITE_OMIT_ATTACH | ||
19 | /* | ||
20 | ** Resolve an expression that was part of an ATTACH or DETACH statement. This | ||
21 | ** is slightly different from resolving a normal SQL expression, because simple | ||
22 | ** identifiers are treated as strings, not possible column names or aliases. | ||
23 | ** | ||
24 | ** i.e. if the parser sees: | ||
25 | ** | ||
26 | ** ATTACH DATABASE abc AS def | ||
27 | ** | ||
28 | ** it treats the two expressions as literal strings 'abc' and 'def' instead of | ||
29 | ** looking for columns of the same name. | ||
30 | ** | ||
31 | ** This only applies to the root node of pExpr, so the statement: | ||
32 | ** | ||
33 | ** ATTACH DATABASE abc||def AS 'db2' | ||
34 | ** | ||
35 | ** will fail because neither abc or def can be resolved. | ||
36 | */ | ||
37 | static int resolveAttachExpr(NameContext *pName, Expr *pExpr) | ||
38 | { | ||
39 | int rc = SQLITE_OK; | ||
40 | if( pExpr ){ | ||
41 | if( pExpr->op!=TK_ID ){ | ||
42 | rc = sqlite3ExprResolveNames(pName, pExpr); | ||
43 | if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){ | ||
44 | sqlite3ErrorMsg(pName->pParse, "invalid name: \"%T\"", &pExpr->span); | ||
45 | return SQLITE_ERROR; | ||
46 | } | ||
47 | }else{ | ||
48 | pExpr->op = TK_STRING; | ||
49 | } | ||
50 | } | ||
51 | return rc; | ||
52 | } | ||
53 | |||
54 | /* | ||
55 | ** An SQL user-function registered to do the work of an ATTACH statement. The | ||
56 | ** three arguments to the function come directly from an attach statement: | ||
57 | ** | ||
58 | ** ATTACH DATABASE x AS y KEY z | ||
59 | ** | ||
60 | ** SELECT sqlite_attach(x, y, z) | ||
61 | ** | ||
62 | ** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the | ||
63 | ** third argument. | ||
64 | */ | ||
65 | static void attachFunc( | ||
66 | sqlite3_context *context, | ||
67 | int argc, | ||
68 | sqlite3_value **argv | ||
69 | ){ | ||
70 | int i; | ||
71 | int rc = 0; | ||
72 | sqlite3 *db = sqlite3_user_data(context); | ||
73 | const char *zName; | ||
74 | const char *zFile; | ||
75 | Db *aNew; | ||
76 | char *zErrDyn = 0; | ||
77 | char zErr[128]; | ||
78 | |||
79 | zFile = (const char *)sqlite3_value_text(argv[0]); | ||
80 | zName = (const char *)sqlite3_value_text(argv[1]); | ||
81 | if( zFile==0 ) zFile = ""; | ||
82 | if( zName==0 ) zName = ""; | ||
83 | |||
84 | /* Check for the following errors: | ||
85 | ** | ||
86 | ** * Too many attached databases, | ||
87 | ** * Transaction currently open | ||
88 | ** * Specified database name already being used. | ||
89 | */ | ||
90 | if( db->nDb>=SQLITE_MAX_ATTACHED+2 ){ | ||
91 | sqlite3_snprintf( | ||
92 | sizeof(zErr), zErr, "too many attached databases - max %d", | ||
93 | SQLITE_MAX_ATTACHED | ||
94 | ); | ||
95 | goto attach_error; | ||
96 | } | ||
97 | if( !db->autoCommit ){ | ||
98 | sqlite3_snprintf(sizeof(zErr), zErr, | ||
99 | "cannot ATTACH database within transaction"); | ||
100 | goto attach_error; | ||
101 | } | ||
102 | for(i=0; i<db->nDb; i++){ | ||
103 | char *z = db->aDb[i].zName; | ||
104 | if( z && zName && sqlite3StrICmp(z, zName)==0 ){ | ||
105 | sqlite3_snprintf(sizeof(zErr), zErr, | ||
106 | "database %s is already in use", zName); | ||
107 | goto attach_error; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | /* Allocate the new entry in the db->aDb[] array and initialise the schema | ||
112 | ** hash tables. | ||
113 | */ | ||
114 | if( db->aDb==db->aDbStatic ){ | ||
115 | aNew = sqlite3_malloc( sizeof(db->aDb[0])*3 ); | ||
116 | if( aNew==0 ){ | ||
117 | db->mallocFailed = 1; | ||
118 | return; | ||
119 | } | ||
120 | memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); | ||
121 | }else{ | ||
122 | aNew = sqlite3_realloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); | ||
123 | if( aNew==0 ){ | ||
124 | db->mallocFailed = 1; | ||
125 | return; | ||
126 | } | ||
127 | } | ||
128 | db->aDb = aNew; | ||
129 | aNew = &db->aDb[db->nDb++]; | ||
130 | memset(aNew, 0, sizeof(*aNew)); | ||
131 | |||
132 | /* Open the database file. If the btree is successfully opened, use | ||
133 | ** it to obtain the database schema. At this point the schema may | ||
134 | ** or may not be initialised. | ||
135 | */ | ||
136 | rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE, | ||
137 | db->openFlags | SQLITE_OPEN_MAIN_DB, | ||
138 | &aNew->pBt); | ||
139 | if( rc==SQLITE_OK ){ | ||
140 | aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt); | ||
141 | if( !aNew->pSchema ){ | ||
142 | rc = SQLITE_NOMEM; | ||
143 | }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ | ||
144 | sqlite3_snprintf(sizeof(zErr), zErr, | ||
145 | "attached databases must use the same text encoding as main database"); | ||
146 | goto attach_error; | ||
147 | } | ||
148 | sqlite3PagerLockingMode(sqlite3BtreePager(aNew->pBt), db->dfltLockMode); | ||
149 | } | ||
150 | aNew->zName = sqlite3DbStrDup(db, zName); | ||
151 | aNew->safety_level = 3; | ||
152 | |||
153 | #if SQLITE_HAS_CODEC | ||
154 | { | ||
155 | extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); | ||
156 | extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); | ||
157 | int nKey; | ||
158 | char *zKey; | ||
159 | int t = sqlite3_value_type(argv[2]); | ||
160 | switch( t ){ | ||
161 | case SQLITE_INTEGER: | ||
162 | case SQLITE_FLOAT: | ||
163 | zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); | ||
164 | rc = SQLITE_ERROR; | ||
165 | break; | ||
166 | |||
167 | case SQLITE_TEXT: | ||
168 | case SQLITE_BLOB: | ||
169 | nKey = sqlite3_value_bytes(argv[2]); | ||
170 | zKey = (char *)sqlite3_value_blob(argv[2]); | ||
171 | sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); | ||
172 | break; | ||
173 | |||
174 | case SQLITE_NULL: | ||
175 | /* No key specified. Use the key from the main database */ | ||
176 | sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); | ||
177 | sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); | ||
178 | break; | ||
179 | } | ||
180 | } | ||
181 | #endif | ||
182 | |||
183 | /* If the file was opened successfully, read the schema for the new database. | ||
184 | ** If this fails, or if opening the file failed, then close the file and | ||
185 | ** remove the entry from the db->aDb[] array. i.e. put everything back the way | ||
186 | ** we found it. | ||
187 | */ | ||
188 | if( rc==SQLITE_OK ){ | ||
189 | sqlite3SafetyOn(db); | ||
190 | rc = sqlite3Init(db, &zErrDyn); | ||
191 | sqlite3SafetyOff(db); | ||
192 | } | ||
193 | if( rc ){ | ||
194 | int iDb = db->nDb - 1; | ||
195 | assert( iDb>=2 ); | ||
196 | if( db->aDb[iDb].pBt ){ | ||
197 | sqlite3BtreeClose(db->aDb[iDb].pBt); | ||
198 | db->aDb[iDb].pBt = 0; | ||
199 | db->aDb[iDb].pSchema = 0; | ||
200 | } | ||
201 | sqlite3ResetInternalSchema(db, 0); | ||
202 | db->nDb = iDb; | ||
203 | if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ | ||
204 | db->mallocFailed = 1; | ||
205 | sqlite3_snprintf(sizeof(zErr),zErr, "out of memory"); | ||
206 | }else{ | ||
207 | sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile); | ||
208 | } | ||
209 | goto attach_error; | ||
210 | } | ||
211 | |||
212 | return; | ||
213 | |||
214 | attach_error: | ||
215 | /* Return an error if we get here */ | ||
216 | if( zErrDyn ){ | ||
217 | sqlite3_result_error(context, zErrDyn, -1); | ||
218 | sqlite3_free(zErrDyn); | ||
219 | }else{ | ||
220 | zErr[sizeof(zErr)-1] = 0; | ||
221 | sqlite3_result_error(context, zErr, -1); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | /* | ||
226 | ** An SQL user-function registered to do the work of an DETACH statement. The | ||
227 | ** three arguments to the function come directly from a detach statement: | ||
228 | ** | ||
229 | ** DETACH DATABASE x | ||
230 | ** | ||
231 | ** SELECT sqlite_detach(x) | ||
232 | */ | ||
233 | static void detachFunc( | ||
234 | sqlite3_context *context, | ||
235 | int argc, | ||
236 | sqlite3_value **argv | ||
237 | ){ | ||
238 | const char *zName = (const char *)sqlite3_value_text(argv[0]); | ||
239 | sqlite3 *db = sqlite3_user_data(context); | ||
240 | int i; | ||
241 | Db *pDb = 0; | ||
242 | char zErr[128]; | ||
243 | |||
244 | if( zName==0 ) zName = ""; | ||
245 | for(i=0; i<db->nDb; i++){ | ||
246 | pDb = &db->aDb[i]; | ||
247 | if( pDb->pBt==0 ) continue; | ||
248 | if( sqlite3StrICmp(pDb->zName, zName)==0 ) break; | ||
249 | } | ||
250 | |||
251 | if( i>=db->nDb ){ | ||
252 | sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName); | ||
253 | goto detach_error; | ||
254 | } | ||
255 | if( i<2 ){ | ||
256 | sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName); | ||
257 | goto detach_error; | ||
258 | } | ||
259 | if( !db->autoCommit ){ | ||
260 | sqlite3_snprintf(sizeof(zErr), zErr, | ||
261 | "cannot DETACH database within transaction"); | ||
262 | goto detach_error; | ||
263 | } | ||
264 | if( sqlite3BtreeIsInReadTrans(pDb->pBt) ){ | ||
265 | sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); | ||
266 | goto detach_error; | ||
267 | } | ||
268 | |||
269 | sqlite3BtreeClose(pDb->pBt); | ||
270 | pDb->pBt = 0; | ||
271 | pDb->pSchema = 0; | ||
272 | sqlite3ResetInternalSchema(db, 0); | ||
273 | return; | ||
274 | |||
275 | detach_error: | ||
276 | sqlite3_result_error(context, zErr, -1); | ||
277 | } | ||
278 | |||
279 | /* | ||
280 | ** This procedure generates VDBE code for a single invocation of either the | ||
281 | ** sqlite_detach() or sqlite_attach() SQL user functions. | ||
282 | */ | ||
283 | static void codeAttach( | ||
284 | Parse *pParse, /* The parser context */ | ||
285 | int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */ | ||
286 | const char *zFunc, /* Either "sqlite_attach" or "sqlite_detach */ | ||
287 | int nFunc, /* Number of args to pass to zFunc */ | ||
288 | Expr *pAuthArg, /* Expression to pass to authorization callback */ | ||
289 | Expr *pFilename, /* Name of database file */ | ||
290 | Expr *pDbname, /* Name of the database to use internally */ | ||
291 | Expr *pKey /* Database key for encryption extension */ | ||
292 | ){ | ||
293 | int rc; | ||
294 | NameContext sName; | ||
295 | Vdbe *v; | ||
296 | FuncDef *pFunc; | ||
297 | sqlite3* db = pParse->db; | ||
298 | |||
299 | #ifndef SQLITE_OMIT_AUTHORIZATION | ||
300 | assert( db->mallocFailed || pAuthArg ); | ||
301 | if( pAuthArg ){ | ||
302 | char *zAuthArg = sqlite3NameFromToken(db, &pAuthArg->span); | ||
303 | if( !zAuthArg ){ | ||
304 | goto attach_end; | ||
305 | } | ||
306 | rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0); | ||
307 | sqlite3_free(zAuthArg); | ||
308 | if(rc!=SQLITE_OK ){ | ||
309 | goto attach_end; | ||
310 | } | ||
311 | } | ||
312 | #endif /* SQLITE_OMIT_AUTHORIZATION */ | ||
313 | |||
314 | memset(&sName, 0, sizeof(NameContext)); | ||
315 | sName.pParse = pParse; | ||
316 | |||
317 | if( | ||
318 | SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) || | ||
319 | SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || | ||
320 | SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) | ||
321 | ){ | ||
322 | pParse->nErr++; | ||
323 | goto attach_end; | ||
324 | } | ||
325 | |||
326 | v = sqlite3GetVdbe(pParse); | ||
327 | sqlite3ExprCode(pParse, pFilename); | ||
328 | sqlite3ExprCode(pParse, pDbname); | ||
329 | sqlite3ExprCode(pParse, pKey); | ||
330 | |||
331 | assert( v || db->mallocFailed ); | ||
332 | if( v ){ | ||
333 | sqlite3VdbeAddOp(v, OP_Function, 0, nFunc); | ||
334 | pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); | ||
335 | sqlite3VdbeChangeP3(v, -1, (char *)pFunc, P3_FUNCDEF); | ||
336 | |||
337 | /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this | ||
338 | ** statement only). For DETACH, set it to false (expire all existing | ||
339 | ** statements). | ||
340 | */ | ||
341 | sqlite3VdbeAddOp(v, OP_Expire, (type==SQLITE_ATTACH), 0); | ||
342 | } | ||
343 | |||
344 | attach_end: | ||
345 | sqlite3ExprDelete(pFilename); | ||
346 | sqlite3ExprDelete(pDbname); | ||
347 | sqlite3ExprDelete(pKey); | ||
348 | } | ||
349 | |||
350 | /* | ||
351 | ** Called by the parser to compile a DETACH statement. | ||
352 | ** | ||
353 | ** DETACH pDbname | ||
354 | */ | ||
355 | void sqlite3Detach(Parse *pParse, Expr *pDbname){ | ||
356 | codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname); | ||
357 | } | ||
358 | |||
359 | /* | ||
360 | ** Called by the parser to compile an ATTACH statement. | ||
361 | ** | ||
362 | ** ATTACH p AS pDbname KEY pKey | ||
363 | */ | ||
364 | void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){ | ||
365 | codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey); | ||
366 | } | ||
367 | #endif /* SQLITE_OMIT_ATTACH */ | ||
368 | |||
369 | /* | ||
370 | ** Register the functions sqlite_attach and sqlite_detach. | ||
371 | */ | ||
372 | void sqlite3AttachFunctions(sqlite3 *db){ | ||
373 | #ifndef SQLITE_OMIT_ATTACH | ||
374 | static const int enc = SQLITE_UTF8; | ||
375 | sqlite3CreateFunc(db, "sqlite_attach", 3, enc, db, attachFunc, 0, 0); | ||
376 | sqlite3CreateFunc(db, "sqlite_detach", 1, enc, db, detachFunc, 0, 0); | ||
377 | #endif | ||
378 | } | ||
379 | |||
380 | /* | ||
381 | ** Initialize a DbFixer structure. This routine must be called prior | ||
382 | ** to passing the structure to one of the sqliteFixAAAA() routines below. | ||
383 | ** | ||
384 | ** The return value indicates whether or not fixation is required. TRUE | ||
385 | ** means we do need to fix the database references, FALSE means we do not. | ||
386 | */ | ||
387 | int sqlite3FixInit( | ||
388 | DbFixer *pFix, /* The fixer to be initialized */ | ||
389 | Parse *pParse, /* Error messages will be written here */ | ||
390 | int iDb, /* This is the database that must be used */ | ||
391 | const char *zType, /* "view", "trigger", or "index" */ | ||
392 | const Token *pName /* Name of the view, trigger, or index */ | ||
393 | ){ | ||
394 | sqlite3 *db; | ||
395 | |||
396 | if( iDb<0 || iDb==1 ) return 0; | ||
397 | db = pParse->db; | ||
398 | assert( db->nDb>iDb ); | ||
399 | pFix->pParse = pParse; | ||
400 | pFix->zDb = db->aDb[iDb].zName; | ||
401 | pFix->zType = zType; | ||
402 | pFix->pName = pName; | ||
403 | return 1; | ||
404 | } | ||
405 | |||
406 | /* | ||
407 | ** The following set of routines walk through the parse tree and assign | ||
408 | ** a specific database to all table references where the database name | ||
409 | ** was left unspecified in the original SQL statement. The pFix structure | ||
410 | ** must have been initialized by a prior call to sqlite3FixInit(). | ||
411 | ** | ||
412 | ** These routines are used to make sure that an index, trigger, or | ||
413 | ** view in one database does not refer to objects in a different database. | ||
414 | ** (Exception: indices, triggers, and views in the TEMP database are | ||
415 | ** allowed to refer to anything.) If a reference is explicitly made | ||
416 | ** to an object in a different database, an error message is added to | ||
417 | ** pParse->zErrMsg and these routines return non-zero. If everything | ||
418 | ** checks out, these routines return 0. | ||
419 | */ | ||
420 | int sqlite3FixSrcList( | ||
421 | DbFixer *pFix, /* Context of the fixation */ | ||
422 | SrcList *pList /* The Source list to check and modify */ | ||
423 | ){ | ||
424 | int i; | ||
425 | const char *zDb; | ||
426 | struct SrcList_item *pItem; | ||
427 | |||
428 | if( pList==0 ) return 0; | ||
429 | zDb = pFix->zDb; | ||
430 | for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ | ||
431 | if( pItem->zDatabase==0 ){ | ||
432 | pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb); | ||
433 | }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){ | ||
434 | sqlite3ErrorMsg(pFix->pParse, | ||
435 | "%s %T cannot reference objects in database %s", | ||
436 | pFix->zType, pFix->pName, pItem->zDatabase); | ||
437 | return 1; | ||
438 | } | ||
439 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) | ||
440 | if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1; | ||
441 | if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1; | ||
442 | #endif | ||
443 | } | ||
444 | return 0; | ||
445 | } | ||
446 | #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) | ||
447 | int sqlite3FixSelect( | ||
448 | DbFixer *pFix, /* Context of the fixation */ | ||
449 | Select *pSelect /* The SELECT statement to be fixed to one database */ | ||
450 | ){ | ||
451 | while( pSelect ){ | ||
452 | if( sqlite3FixExprList(pFix, pSelect->pEList) ){ | ||
453 | return 1; | ||
454 | } | ||
455 | if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){ | ||
456 | return 1; | ||
457 | } | ||
458 | if( sqlite3FixExpr(pFix, pSelect->pWhere) ){ | ||
459 | return 1; | ||
460 | } | ||
461 | if( sqlite3FixExpr(pFix, pSelect->pHaving) ){ | ||
462 | return 1; | ||
463 | } | ||
464 | pSelect = pSelect->pPrior; | ||
465 | } | ||
466 | return 0; | ||
467 | } | ||
468 | int sqlite3FixExpr( | ||
469 | DbFixer *pFix, /* Context of the fixation */ | ||
470 | Expr *pExpr /* The expression to be fixed to one database */ | ||
471 | ){ | ||
472 | while( pExpr ){ | ||
473 | if( sqlite3FixSelect(pFix, pExpr->pSelect) ){ | ||
474 | return 1; | ||
475 | } | ||
476 | if( sqlite3FixExprList(pFix, pExpr->pList) ){ | ||
477 | return 1; | ||
478 | } | ||
479 | if( sqlite3FixExpr(pFix, pExpr->pRight) ){ | ||
480 | return 1; | ||
481 | } | ||
482 | pExpr = pExpr->pLeft; | ||
483 | } | ||
484 | return 0; | ||
485 | } | ||
486 | int sqlite3FixExprList( | ||
487 | DbFixer *pFix, /* Context of the fixation */ | ||
488 | ExprList *pList /* The expression to be fixed to one database */ | ||
489 | ){ | ||
490 | int i; | ||
491 | struct ExprList_item *pItem; | ||
492 | if( pList==0 ) return 0; | ||
493 | for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){ | ||
494 | if( sqlite3FixExpr(pFix, pItem->pExpr) ){ | ||
495 | return 1; | ||
496 | } | ||
497 | } | ||
498 | return 0; | ||
499 | } | ||
500 | #endif | ||
501 | |||
502 | #ifndef SQLITE_OMIT_TRIGGER | ||
503 | int sqlite3FixTriggerStep( | ||
504 | DbFixer *pFix, /* Context of the fixation */ | ||
505 | TriggerStep *pStep /* The trigger step be fixed to one database */ | ||
506 | ){ | ||
507 | while( pStep ){ | ||
508 | if( sqlite3FixSelect(pFix, pStep->pSelect) ){ | ||
509 | return 1; | ||
510 | } | ||
511 | if( sqlite3FixExpr(pFix, pStep->pWhere) ){ | ||
512 | return 1; | ||
513 | } | ||
514 | if( sqlite3FixExprList(pFix, pStep->pExprList) ){ | ||
515 | return 1; | ||
516 | } | ||
517 | pStep = pStep->pNext; | ||
518 | } | ||
519 | return 0; | ||
520 | } | ||
521 | #endif | ||