📄 attach.c
字号:
if( sqlite3BtreeIsInReadTrans(pDb->pBt) ){ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); goto detach_error; } sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; sqlite3ResetInternalSchema(db, 0); return;detach_error: sqlite3_result_error(context, zErr, -1);}/*** This procedure generates VDBE code for a single invocation of either the** sqlite_detach() or sqlite_attach() SQL user functions.*/static void codeAttach( Parse *pParse, /* The parser context */ int type, /* Either SQLITE_ATTACH or SQLITE_DETACH */ const char *zFunc, /* Either "sqlite_attach" or "sqlite_detach */ int nFunc, /* Number of args to pass to zFunc */ Expr *pAuthArg, /* Expression to pass to authorization callback */ Expr *pFilename, /* Name of database file */ Expr *pDbname, /* Name of the database to use internally */ Expr *pKey /* Database key for encryption extension */){ int rc; NameContext sName; Vdbe *v; FuncDef *pFunc; sqlite3* db = pParse->db; int regArgs;#ifndef SQLITE_OMIT_AUTHORIZATION assert( db->mallocFailed || pAuthArg ); if( pAuthArg ){ char *zAuthArg = sqlite3NameFromToken(db, &pAuthArg->span); if( !zAuthArg ){ goto attach_end; } rc = sqlite3AuthCheck(pParse, type, zAuthArg, 0, 0); sqlite3DbFree(db, zAuthArg); if(rc!=SQLITE_OK ){ goto attach_end; } }#endif /* SQLITE_OMIT_AUTHORIZATION */ memset(&sName, 0, sizeof(NameContext)); sName.pParse = pParse; if( SQLITE_OK!=(rc = resolveAttachExpr(&sName, pFilename)) || SQLITE_OK!=(rc = resolveAttachExpr(&sName, pDbname)) || SQLITE_OK!=(rc = resolveAttachExpr(&sName, pKey)) ){ pParse->nErr++; goto attach_end; } v = sqlite3GetVdbe(pParse); regArgs = sqlite3GetTempRange(pParse, 4); sqlite3ExprCode(pParse, pFilename, regArgs); sqlite3ExprCode(pParse, pDbname, regArgs+1); sqlite3ExprCode(pParse, pKey, regArgs+2); assert( v || db->mallocFailed ); if( v ){ sqlite3VdbeAddOp3(v, OP_Function, 0, regArgs+3-nFunc, regArgs+3); sqlite3VdbeChangeP5(v, nFunc); pFunc = sqlite3FindFunction(db, zFunc, strlen(zFunc), nFunc, SQLITE_UTF8,0); sqlite3VdbeChangeP4(v, -1, (char *)pFunc, P4_FUNCDEF); /* Code an OP_Expire. For an ATTACH statement, set P1 to true (expire this ** statement only). For DETACH, set it to false (expire all existing ** statements). */ sqlite3VdbeAddOp1(v, OP_Expire, (type==SQLITE_ATTACH)); } attach_end: sqlite3ExprDelete(db, pFilename); sqlite3ExprDelete(db, pDbname); sqlite3ExprDelete(db, pKey);}/*** Called by the parser to compile a DETACH statement.**** DETACH pDbname*/void sqlite3Detach(Parse *pParse, Expr *pDbname){ codeAttach(pParse, SQLITE_DETACH, "sqlite_detach", 1, pDbname, 0, 0, pDbname);}/*** Called by the parser to compile an ATTACH statement.**** ATTACH p AS pDbname KEY pKey*/void sqlite3Attach(Parse *pParse, Expr *p, Expr *pDbname, Expr *pKey){ codeAttach(pParse, SQLITE_ATTACH, "sqlite_attach", 3, p, p, pDbname, pKey);}#endif /* SQLITE_OMIT_ATTACH *//*** Register the functions sqlite_attach and sqlite_detach.*/void sqlite3AttachFunctions(sqlite3 *db){#ifndef SQLITE_OMIT_ATTACH static const int enc = SQLITE_UTF8; sqlite3CreateFunc(db, "sqlite_attach", 3, enc, 0, attachFunc, 0, 0); sqlite3CreateFunc(db, "sqlite_detach", 1, enc, 0, detachFunc, 0, 0);#endif}/*** Initialize a DbFixer structure. This routine must be called prior** to passing the structure to one of the sqliteFixAAAA() routines below.**** The return value indicates whether or not fixation is required. TRUE** means we do need to fix the database references, FALSE means we do not.*/int sqlite3FixInit( DbFixer *pFix, /* The fixer to be initialized */ Parse *pParse, /* Error messages will be written here */ int iDb, /* This is the database that must be used */ const char *zType, /* "view", "trigger", or "index" */ const Token *pName /* Name of the view, trigger, or index */){ sqlite3 *db; if( iDb<0 || iDb==1 ) return 0; db = pParse->db; assert( db->nDb>iDb ); pFix->pParse = pParse; pFix->zDb = db->aDb[iDb].zName; pFix->zType = zType; pFix->pName = pName; return 1;}/*** The following set of routines walk through the parse tree and assign** a specific database to all table references where the database name** was left unspecified in the original SQL statement. The pFix structure** must have been initialized by a prior call to sqlite3FixInit().**** These routines are used to make sure that an index, trigger, or** view in one database does not refer to objects in a different database.** (Exception: indices, triggers, and views in the TEMP database are** allowed to refer to anything.) If a reference is explicitly made** to an object in a different database, an error message is added to** pParse->zErrMsg and these routines return non-zero. If everything** checks out, these routines return 0.*/int sqlite3FixSrcList( DbFixer *pFix, /* Context of the fixation */ SrcList *pList /* The Source list to check and modify */){ int i; const char *zDb; struct SrcList_item *pItem; if( pList==0 ) return 0; zDb = pFix->zDb; for(i=0, pItem=pList->a; i<pList->nSrc; i++, pItem++){ if( pItem->zDatabase==0 ){ pItem->zDatabase = sqlite3DbStrDup(pFix->pParse->db, zDb); }else if( sqlite3StrICmp(pItem->zDatabase,zDb)!=0 ){ sqlite3ErrorMsg(pFix->pParse, "%s %T cannot reference objects in database %s", pFix->zType, pFix->pName, pItem->zDatabase); return 1; }#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER) if( sqlite3FixSelect(pFix, pItem->pSelect) ) return 1; if( sqlite3FixExpr(pFix, pItem->pOn) ) return 1;#endif } return 0;}#if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)int sqlite3FixSelect( DbFixer *pFix, /* Context of the fixation */ Select *pSelect /* The SELECT statement to be fixed to one database */){ while( pSelect ){ if( sqlite3FixExprList(pFix, pSelect->pEList) ){ return 1; } if( sqlite3FixSrcList(pFix, pSelect->pSrc) ){ return 1; } if( sqlite3FixExpr(pFix, pSelect->pWhere) ){ return 1; } if( sqlite3FixExpr(pFix, pSelect->pHaving) ){ return 1; } pSelect = pSelect->pPrior; } return 0;}int sqlite3FixExpr( DbFixer *pFix, /* Context of the fixation */ Expr *pExpr /* The expression to be fixed to one database */){ while( pExpr ){ if( sqlite3FixSelect(pFix, pExpr->pSelect) ){ return 1; } if( sqlite3FixExprList(pFix, pExpr->pList) ){ return 1; } if( sqlite3FixExpr(pFix, pExpr->pRight) ){ return 1; } pExpr = pExpr->pLeft; } return 0;}int sqlite3FixExprList( DbFixer *pFix, /* Context of the fixation */ ExprList *pList /* The expression to be fixed to one database */){ int i; struct ExprList_item *pItem; if( pList==0 ) return 0; for(i=0, pItem=pList->a; i<pList->nExpr; i++, pItem++){ if( sqlite3FixExpr(pFix, pItem->pExpr) ){ return 1; } } return 0;}#endif#ifndef SQLITE_OMIT_TRIGGERint sqlite3FixTriggerStep( DbFixer *pFix, /* Context of the fixation */ TriggerStep *pStep /* The trigger step be fixed to one database */){ while( pStep ){ if( sqlite3FixSelect(pFix, pStep->pSelect) ){ return 1; } if( sqlite3FixExpr(pFix, pStep->pWhere) ){ return 1; } if( sqlite3FixExprList(pFix, pStep->pExprList) ){ return 1; } pStep = pStep->pNext; } return 0;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -