diff options
Diffstat (limited to 'ext/sqlite/libsqlite/src/attach.c')
-rw-r--r-- | ext/sqlite/libsqlite/src/attach.c | 183 |
1 files changed, 166 insertions, 17 deletions
diff --git a/ext/sqlite/libsqlite/src/attach.c b/ext/sqlite/libsqlite/src/attach.c index dd94c21182..5b57e29e16 100644 --- a/ext/sqlite/libsqlite/src/attach.c +++ b/ext/sqlite/libsqlite/src/attach.c @@ -43,6 +43,32 @@ void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname){ pParse->rc = SQLITE_ERROR; return; } + + zFile = 0; + sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0); + if( zFile==0 ) return; + sqliteDequote(zFile); +#ifndef SQLITE_OMIT_AUTHORIZATION + if( sqliteAuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){ + sqliteFree(zFile); + return; + } +#endif /* SQLITE_OMIT_AUTHORIZATION */ + + zName = 0; + sqliteSetNString(&zName, pDbname->z, pDbname->n, 0); + if( zName==0 ) return; + sqliteDequote(zName); + for(i=0; i<db->nDb; i++){ + if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){ + sqliteErrorMsg(pParse, "database %z is already in use", zName); + pParse->rc = SQLITE_ERROR; + sqliteFree(zFile); + sqliteFree(zName); + return; + } + } + if( db->aDb==db->aDbStatic ){ aNew = sqliteMalloc( sizeof(db->aDb[0])*3 ); if( aNew==0 ) return; @@ -58,24 +84,7 @@ void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname){ sqliteHashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1); - - zName = 0; - sqliteSetNString(&zName, pDbname->z, pDbname->n, 0); - if( zName==0 ) return; - sqliteDequote(zName); - for(i=0; i<db->nDb; i++){ - if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){ - sqliteErrorMsg(pParse, "database %z is already in use", zName); - db->nDb--; - pParse->rc = SQLITE_ERROR; - return; - } - } aNew->zName = zName; - zFile = 0; - sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0); - if( zFile==0 ) return; - sqliteDequote(zFile); rc = sqliteBtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt); if( rc ){ sqliteErrorMsg(pParse, "unable to open database: %s", zFile); @@ -117,6 +126,11 @@ void sqliteDetach(Parse *pParse, Token *pDbname){ sqliteErrorMsg(pParse, "cannot detach database %T", pDbname); return; } +#ifndef SQLITE_OMIT_AUTHORIZATION + if( sqliteAuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){ + return; + } +#endif /* SQLITE_OMIT_AUTHORIZATION */ sqliteBtreeClose(db->aDb[i].pBt); db->aDb[i].pBt = 0; sqliteFree(db->aDb[i].zName); @@ -128,3 +142,138 @@ void sqliteDetach(Parse *pParse, Token *pDbname){ sqliteResetInternalSchema(db, i); } } + +/* +** 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 sqliteFixInit( + DbFixer *pFix, /* The fixer to be initialized */ + Parse *pParse, /* Error messages will be written here */ + int iDb, /* This is the database that must must be used */ + const char *zType, /* "view", "trigger", or "index" */ + const Token *pName /* Name of the view, trigger, or index */ +){ + sqlite *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 sqliteFixInit(). +** +** 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 sqliteFixSrcList( + DbFixer *pFix, /* Context of the fixation */ + SrcList *pList /* The Source list to check and modify */ +){ + int i; + const char *zDb; + + if( pList==0 ) return 0; + zDb = pFix->zDb; + for(i=0; i<pList->nSrc; i++){ + if( pList->a[i].zDatabase==0 ){ + pList->a[i].zDatabase = sqliteStrDup(zDb); + }else if( sqliteStrICmp(pList->a[i].zDatabase,zDb)!=0 ){ + sqliteErrorMsg(pFix->pParse, + "%s %z cannot reference objects in database %s", + pFix->zType, sqliteStrNDup(pFix->pName->z, pFix->pName->n), + pList->a[i].zDatabase); + return 1; + } + if( sqliteFixSelect(pFix, pList->a[i].pSelect) ) return 1; + if( sqliteFixExpr(pFix, pList->a[i].pOn) ) return 1; + } + return 0; +} +int sqliteFixSelect( + DbFixer *pFix, /* Context of the fixation */ + Select *pSelect /* The SELECT statement to be fixed to one database */ +){ + while( pSelect ){ + if( sqliteFixExprList(pFix, pSelect->pEList) ){ + return 1; + } + if( sqliteFixSrcList(pFix, pSelect->pSrc) ){ + return 1; + } + if( sqliteFixExpr(pFix, pSelect->pWhere) ){ + return 1; + } + if( sqliteFixExpr(pFix, pSelect->pHaving) ){ + return 1; + } + pSelect = pSelect->pPrior; + } + return 0; +} +int sqliteFixExpr( + DbFixer *pFix, /* Context of the fixation */ + Expr *pExpr /* The expression to be fixed to one database */ +){ + while( pExpr ){ + if( sqliteFixSelect(pFix, pExpr->pSelect) ){ + return 1; + } + if( sqliteFixExprList(pFix, pExpr->pList) ){ + return 1; + } + if( sqliteFixExpr(pFix, pExpr->pRight) ){ + return 1; + } + pExpr = pExpr->pLeft; + } + return 0; +} +int sqliteFixExprList( + DbFixer *pFix, /* Context of the fixation */ + ExprList *pList /* The expression to be fixed to one database */ +){ + int i; + if( pList==0 ) return 0; + for(i=0; i<pList->nExpr; i++){ + if( sqliteFixExpr(pFix, pList->a[i].pExpr) ){ + return 1; + } + } + return 0; +} +int sqliteFixTriggerStep( + DbFixer *pFix, /* Context of the fixation */ + TriggerStep *pStep /* The trigger step be fixed to one database */ +){ + while( pStep ){ + if( sqliteFixSelect(pFix, pStep->pSelect) ){ + return 1; + } + if( sqliteFixExpr(pFix, pStep->pWhere) ){ + return 1; + } + if( sqliteFixExprList(pFix, pStep->pExprList) ){ + return 1; + } + pStep = pStep->pNext; + } + return 0; +} |