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 | */
|
---|
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 | }
|
---|