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