Annotation of embedaddon/php/ext/sqlite/libsqlite/src/attach.c, revision 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: ** $Id: attach.c 195361 2005-09-07 15:11:33Z iliaa $
! 15: */
! 16: #include "sqliteInt.h"
! 17:
! 18: /*
! 19: ** This routine is called by the parser to process an ATTACH statement:
! 20: **
! 21: ** ATTACH DATABASE filename AS dbname
! 22: **
! 23: ** The pFilename and pDbname arguments are the tokens that define the
! 24: ** filename and dbname in the ATTACH statement.
! 25: */
! 26: void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname, Token *pKey){
! 27: Db *aNew;
! 28: int rc, i;
! 29: char *zFile, *zName;
! 30: sqlite *db;
! 31: Vdbe *v;
! 32:
! 33: v = sqliteGetVdbe(pParse);
! 34: sqliteVdbeAddOp(v, OP_Halt, 0, 0);
! 35: if( pParse->explain ) return;
! 36: db = pParse->db;
! 37: if( db->file_format<4 ){
! 38: sqliteErrorMsg(pParse, "cannot attach auxiliary databases to an "
! 39: "older format master database", 0);
! 40: pParse->rc = SQLITE_ERROR;
! 41: return;
! 42: }
! 43: if( db->nDb>=MAX_ATTACHED+2 ){
! 44: sqliteErrorMsg(pParse, "too many attached databases - max %d",
! 45: MAX_ATTACHED);
! 46: pParse->rc = SQLITE_ERROR;
! 47: return;
! 48: }
! 49:
! 50: zFile = 0;
! 51: sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0);
! 52: if( zFile==0 ) return;
! 53: sqliteDequote(zFile);
! 54: #ifndef SQLITE_OMIT_AUTHORIZATION
! 55: if( sqliteAuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){
! 56: sqliteFree(zFile);
! 57: return;
! 58: }
! 59: #endif /* SQLITE_OMIT_AUTHORIZATION */
! 60:
! 61: zName = 0;
! 62: sqliteSetNString(&zName, pDbname->z, pDbname->n, 0);
! 63: if( zName==0 ) return;
! 64: sqliteDequote(zName);
! 65: for(i=0; i<db->nDb; i++){
! 66: if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){
! 67: sqliteErrorMsg(pParse, "database %z is already in use", zName);
! 68: pParse->rc = SQLITE_ERROR;
! 69: sqliteFree(zFile);
! 70: return;
! 71: }
! 72: }
! 73:
! 74: if( db->aDb==db->aDbStatic ){
! 75: aNew = sqliteMalloc( sizeof(db->aDb[0])*3 );
! 76: if( aNew==0 ) return;
! 77: memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2);
! 78: }else{
! 79: aNew = sqliteRealloc(db->aDb, sizeof(db->aDb[0])*(db->nDb+1) );
! 80: if( aNew==0 ) return;
! 81: }
! 82: db->aDb = aNew;
! 83: aNew = &db->aDb[db->nDb++];
! 84: memset(aNew, 0, sizeof(*aNew));
! 85: sqliteHashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0);
! 86: sqliteHashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0);
! 87: sqliteHashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0);
! 88: sqliteHashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1);
! 89: aNew->zName = zName;
! 90: rc = sqliteBtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt);
! 91: if( rc ){
! 92: sqliteErrorMsg(pParse, "unable to open database: %s", zFile);
! 93: }
! 94: #if SQLITE_HAS_CODEC
! 95: {
! 96: extern int sqliteCodecAttach(sqlite*, int, void*, int);
! 97: char *zKey = 0;
! 98: int nKey;
! 99: if( pKey && pKey->z && pKey->n ){
! 100: sqliteSetNString(&zKey, pKey->z, pKey->n, 0);
! 101: sqliteDequote(zKey);
! 102: nKey = strlen(zKey);
! 103: }else{
! 104: zKey = 0;
! 105: nKey = 0;
! 106: }
! 107: sqliteCodecAttach(db, db->nDb-1, zKey, nKey);
! 108: }
! 109: #endif
! 110: sqliteFree(zFile);
! 111: db->flags &= ~SQLITE_Initialized;
! 112: if( pParse->nErr ) return;
! 113: if( rc==SQLITE_OK ){
! 114: rc = sqliteInit(pParse->db, &pParse->zErrMsg);
! 115: }
! 116: if( rc ){
! 117: int i = db->nDb - 1;
! 118: assert( i>=2 );
! 119: if( db->aDb[i].pBt ){
! 120: sqliteBtreeClose(db->aDb[i].pBt);
! 121: db->aDb[i].pBt = 0;
! 122: }
! 123: sqliteResetInternalSchema(db, 0);
! 124: pParse->nErr++;
! 125: pParse->rc = SQLITE_ERROR;
! 126: }
! 127: }
! 128:
! 129: /*
! 130: ** This routine is called by the parser to process a DETACH statement:
! 131: **
! 132: ** DETACH DATABASE dbname
! 133: **
! 134: ** The pDbname argument is the name of the database in the DETACH statement.
! 135: */
! 136: void sqliteDetach(Parse *pParse, Token *pDbname){
! 137: int i;
! 138: sqlite *db;
! 139: Vdbe *v;
! 140: Db *pDb;
! 141:
! 142: v = sqliteGetVdbe(pParse);
! 143: sqliteVdbeAddOp(v, OP_Halt, 0, 0);
! 144: if( pParse->explain ) return;
! 145: db = pParse->db;
! 146: for(i=0; i<db->nDb; i++){
! 147: pDb = &db->aDb[i];
! 148: if( pDb->pBt==0 || pDb->zName==0 ) continue;
! 149: if( strlen(pDb->zName)!=pDbname->n ) continue;
! 150: if( sqliteStrNICmp(pDb->zName, pDbname->z, pDbname->n)==0 ) break;
! 151: }
! 152: if( i>=db->nDb ){
! 153: sqliteErrorMsg(pParse, "no such database: %T", pDbname);
! 154: return;
! 155: }
! 156: if( i<2 ){
! 157: sqliteErrorMsg(pParse, "cannot detach database %T", pDbname);
! 158: return;
! 159: }
! 160: #ifndef SQLITE_OMIT_AUTHORIZATION
! 161: if( sqliteAuthCheck(pParse,SQLITE_DETACH,db->aDb[i].zName,0,0)!=SQLITE_OK ){
! 162: return;
! 163: }
! 164: #endif /* SQLITE_OMIT_AUTHORIZATION */
! 165: sqliteBtreeClose(pDb->pBt);
! 166: pDb->pBt = 0;
! 167: sqliteFree(pDb->zName);
! 168: sqliteResetInternalSchema(db, i);
! 169: if( pDb->pAux && pDb->xFreeAux ) pDb->xFreeAux(pDb->pAux);
! 170: db->nDb--;
! 171: if( i<db->nDb ){
! 172: db->aDb[i] = db->aDb[db->nDb];
! 173: memset(&db->aDb[db->nDb], 0, sizeof(db->aDb[0]));
! 174: sqliteResetInternalSchema(db, i);
! 175: }
! 176: }
! 177:
! 178: /*
! 179: ** Initialize a DbFixer structure. This routine must be called prior
! 180: ** to passing the structure to one of the sqliteFixAAAA() routines below.
! 181: **
! 182: ** The return value indicates whether or not fixation is required. TRUE
! 183: ** means we do need to fix the database references, FALSE means we do not.
! 184: */
! 185: int sqliteFixInit(
! 186: DbFixer *pFix, /* The fixer to be initialized */
! 187: Parse *pParse, /* Error messages will be written here */
! 188: int iDb, /* This is the database that must must be used */
! 189: const char *zType, /* "view", "trigger", or "index" */
! 190: const Token *pName /* Name of the view, trigger, or index */
! 191: ){
! 192: sqlite *db;
! 193:
! 194: if( iDb<0 || iDb==1 ) return 0;
! 195: db = pParse->db;
! 196: assert( db->nDb>iDb );
! 197: pFix->pParse = pParse;
! 198: pFix->zDb = db->aDb[iDb].zName;
! 199: pFix->zType = zType;
! 200: pFix->pName = pName;
! 201: return 1;
! 202: }
! 203:
! 204: /*
! 205: ** The following set of routines walk through the parse tree and assign
! 206: ** a specific database to all table references where the database name
! 207: ** was left unspecified in the original SQL statement. The pFix structure
! 208: ** must have been initialized by a prior call to sqliteFixInit().
! 209: **
! 210: ** These routines are used to make sure that an index, trigger, or
! 211: ** view in one database does not refer to objects in a different database.
! 212: ** (Exception: indices, triggers, and views in the TEMP database are
! 213: ** allowed to refer to anything.) If a reference is explicitly made
! 214: ** to an object in a different database, an error message is added to
! 215: ** pParse->zErrMsg and these routines return non-zero. If everything
! 216: ** checks out, these routines return 0.
! 217: */
! 218: int sqliteFixSrcList(
! 219: DbFixer *pFix, /* Context of the fixation */
! 220: SrcList *pList /* The Source list to check and modify */
! 221: ){
! 222: int i;
! 223: const char *zDb;
! 224:
! 225: if( pList==0 ) return 0;
! 226: zDb = pFix->zDb;
! 227: for(i=0; i<pList->nSrc; i++){
! 228: if( pList->a[i].zDatabase==0 ){
! 229: pList->a[i].zDatabase = sqliteStrDup(zDb);
! 230: }else if( sqliteStrICmp(pList->a[i].zDatabase,zDb)!=0 ){
! 231: sqliteErrorMsg(pFix->pParse,
! 232: "%s %z cannot reference objects in database %s",
! 233: pFix->zType, sqliteStrNDup(pFix->pName->z, pFix->pName->n),
! 234: pList->a[i].zDatabase);
! 235: return 1;
! 236: }
! 237: if( sqliteFixSelect(pFix, pList->a[i].pSelect) ) return 1;
! 238: if( sqliteFixExpr(pFix, pList->a[i].pOn) ) return 1;
! 239: }
! 240: return 0;
! 241: }
! 242: int sqliteFixSelect(
! 243: DbFixer *pFix, /* Context of the fixation */
! 244: Select *pSelect /* The SELECT statement to be fixed to one database */
! 245: ){
! 246: while( pSelect ){
! 247: if( sqliteFixExprList(pFix, pSelect->pEList) ){
! 248: return 1;
! 249: }
! 250: if( sqliteFixSrcList(pFix, pSelect->pSrc) ){
! 251: return 1;
! 252: }
! 253: if( sqliteFixExpr(pFix, pSelect->pWhere) ){
! 254: return 1;
! 255: }
! 256: if( sqliteFixExpr(pFix, pSelect->pHaving) ){
! 257: return 1;
! 258: }
! 259: pSelect = pSelect->pPrior;
! 260: }
! 261: return 0;
! 262: }
! 263: int sqliteFixExpr(
! 264: DbFixer *pFix, /* Context of the fixation */
! 265: Expr *pExpr /* The expression to be fixed to one database */
! 266: ){
! 267: while( pExpr ){
! 268: if( sqliteFixSelect(pFix, pExpr->pSelect) ){
! 269: return 1;
! 270: }
! 271: if( sqliteFixExprList(pFix, pExpr->pList) ){
! 272: return 1;
! 273: }
! 274: if( sqliteFixExpr(pFix, pExpr->pRight) ){
! 275: return 1;
! 276: }
! 277: pExpr = pExpr->pLeft;
! 278: }
! 279: return 0;
! 280: }
! 281: int sqliteFixExprList(
! 282: DbFixer *pFix, /* Context of the fixation */
! 283: ExprList *pList /* The expression to be fixed to one database */
! 284: ){
! 285: int i;
! 286: if( pList==0 ) return 0;
! 287: for(i=0; i<pList->nExpr; i++){
! 288: if( sqliteFixExpr(pFix, pList->a[i].pExpr) ){
! 289: return 1;
! 290: }
! 291: }
! 292: return 0;
! 293: }
! 294: int sqliteFixTriggerStep(
! 295: DbFixer *pFix, /* Context of the fixation */
! 296: TriggerStep *pStep /* The trigger step be fixed to one database */
! 297: ){
! 298: while( pStep ){
! 299: if( sqliteFixSelect(pFix, pStep->pSelect) ){
! 300: return 1;
! 301: }
! 302: if( sqliteFixExpr(pFix, pStep->pWhere) ){
! 303: return 1;
! 304: }
! 305: if( sqliteFixExprList(pFix, pStep->pExprList) ){
! 306: return 1;
! 307: }
! 308: pStep = pStep->pNext;
! 309: }
! 310: return 0;
! 311: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>