Annotation of embedaddon/sqlite3/src/attach.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>