xref: /illumos-gate/usr/src/lib/libsqlite/src/attach.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
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,v 1.10.2.1 2004/05/07 01:46:01 drh Exp $
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 */
sqliteAttach(Parse * pParse,Token * pFilename,Token * pDbname,Token * pKey)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 */
sqliteDetach(Parse * pParse,Token * pDbname)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 */
sqliteFixInit(DbFixer * pFix,Parse * pParse,int iDb,const char * zType,const Token * pName)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 */
sqliteFixSrcList(DbFixer * pFix,SrcList * pList)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 }
sqliteFixSelect(DbFixer * pFix,Select * pSelect)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 }
sqliteFixExpr(DbFixer * pFix,Expr * pExpr)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 }
sqliteFixExprList(DbFixer * pFix,ExprList * pList)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 }
sqliteFixTriggerStep(DbFixer * pFix,TriggerStep * pStep)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 }
312