4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
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.
11 *************************************************************************
12 ** This file contains code used to implement the ATTACH and DETACH commands.
16 #include "sqliteInt.h"
19 ** This routine is called by the parser to process an ATTACH statement:
21 ** ATTACH DATABASE filename AS dbname
23 ** The pFilename and pDbname arguments are the tokens that define the
24 ** filename and dbname in the ATTACH statement.
27 Parse
*pParse
, /* The parser context */
28 Token
*pFilename
, /* Name of database file */
29 Token
*pDbname
, /* Name of the database to use internally */
30 int keyType
, /* 0: no key. 1: TEXT, 2: BLOB */
31 Token
*pKey
/* Text of the key for keytype 1 and 2 */
40 v
= sqlite3GetVdbe(pParse
);
42 sqlite3VdbeAddOp(v
, OP_Expire
, 1, 0);
43 sqlite3VdbeAddOp(v
, OP_Halt
, 0, 0);
44 if( pParse
->explain
) return;
46 if( db
->nDb
>=MAX_ATTACHED
+2 ){
47 sqlite3ErrorMsg(pParse
, "too many attached databases - max %d",
49 pParse
->rc
= SQLITE_ERROR
;
53 if( !db
->autoCommit
){
54 sqlite3ErrorMsg(pParse
, "cannot ATTACH database within transaction");
55 pParse
->rc
= SQLITE_ERROR
;
59 zFile
= sqlite3NameFromToken(pFilename
);
63 #ifndef SQLITE_OMIT_AUTHORIZATION
64 if( sqlite3AuthCheck(pParse
, SQLITE_ATTACH
, zFile
, 0, 0)!=SQLITE_OK
){
67 #endif /* SQLITE_OMIT_AUTHORIZATION */
69 zName
= sqlite3NameFromToken(pDbname
);
73 for(i
=0; i
<db
->nDb
; i
++){
74 char *z
= db
->aDb
[i
].zName
;
75 if( z
&& sqlite3StrICmp(z
, zName
)==0 ){
76 sqlite3ErrorMsg(pParse
, "database %s is already in use", zName
);
77 pParse
->rc
= SQLITE_ERROR
;
82 if( db
->aDb
==db
->aDbStatic
){
83 aNew
= sqliteMalloc( sizeof(db
->aDb
[0])*3 );
87 memcpy(aNew
, db
->aDb
, sizeof(db
->aDb
[0])*2);
89 aNew
= sqliteRealloc(db
->aDb
, sizeof(db
->aDb
[0])*(db
->nDb
+1) );
95 aNew
= &db
->aDb
[db
->nDb
++];
96 memset(aNew
, 0, sizeof(*aNew
));
97 sqlite3HashInit(&aNew
->tblHash
, SQLITE_HASH_STRING
, 0);
98 sqlite3HashInit(&aNew
->idxHash
, SQLITE_HASH_STRING
, 0);
99 sqlite3HashInit(&aNew
->trigHash
, SQLITE_HASH_STRING
, 0);
100 sqlite3HashInit(&aNew
->aFKey
, SQLITE_HASH_STRING
, 1);
103 aNew
->safety_level
= 3;
104 rc
= sqlite3BtreeFactory(db
, zFile
, 0, MAX_PAGES
, &aNew
->pBt
);
106 sqlite3ErrorMsg(pParse
, "unable to open database: %s", zFile
);
110 extern int sqlite3CodecAttach(sqlite3
*, int, void*, int);
114 /* No key specified. Use the key from the main database */
115 extern void sqlite3CodecGetKey(sqlite3
*, int, void**, int*);
116 sqlite3CodecGetKey(db
, 0, (void**)&zKey
, &nKey
);
117 }else if( keyType
==1 ){
118 /* Key specified as text */
119 zKey
= sqlite3NameFromToken(pKey
);
122 /* Key specified as a BLOB */
124 assert( keyType
==2 );
127 zTemp
= sqlite3NameFromToken(pKey
);
128 zKey
= sqlite3HexToBlob(zTemp
);
131 sqlite3CodecAttach(db
, db
->nDb
-1, zKey
, nKey
);
137 db
->flags
&= ~SQLITE_Initialized
;
138 if( pParse
->nErr
==0 && rc
==SQLITE_OK
){
139 rc
= sqlite3ReadSchema(pParse
);
144 if( db
->aDb
[i
].pBt
){
145 sqlite3BtreeClose(db
->aDb
[i
].pBt
);
148 sqlite3ResetInternalSchema(db
, 0);
149 if( 0==pParse
->nErr
){
151 pParse
->rc
= SQLITE_ERROR
;
161 ** This routine is called by the parser to process a DETACH statement:
163 ** DETACH DATABASE dbname
165 ** The pDbname argument is the name of the database in the DETACH statement.
167 void sqlite3Detach(Parse
*pParse
, Token
*pDbname
){
174 v
= sqlite3GetVdbe(pParse
);
176 sqlite3VdbeAddOp(v
, OP_Expire
, 0, 0);
177 sqlite3VdbeAddOp(v
, OP_Halt
, 0, 0);
178 if( pParse
->explain
) return;
180 zName
= sqlite3NameFromToken(pDbname
);
181 if( zName
==0 ) return;
182 for(i
=0; i
<db
->nDb
; i
++){
184 if( pDb
->pBt
==0 ) continue;
185 if( sqlite3StrICmp(pDb
->zName
, zName
)==0 ) break;
188 sqlite3ErrorMsg(pParse
, "no such database: %z", zName
);
192 sqlite3ErrorMsg(pParse
, "cannot detach database %z", zName
);
196 if( !db
->autoCommit
){
197 sqlite3ErrorMsg(pParse
, "cannot DETACH database within transaction");
198 pParse
->rc
= SQLITE_ERROR
;
201 #ifndef SQLITE_OMIT_AUTHORIZATION
202 if( sqlite3AuthCheck(pParse
,SQLITE_DETACH
,db
->aDb
[i
].zName
,0,0)!=SQLITE_OK
){
205 #endif /* SQLITE_OMIT_AUTHORIZATION */
206 sqlite3BtreeClose(pDb
->pBt
);
208 sqlite3ResetInternalSchema(db
, 0);
212 ** Initialize a DbFixer structure. This routine must be called prior
213 ** to passing the structure to one of the sqliteFixAAAA() routines below.
215 ** The return value indicates whether or not fixation is required. TRUE
216 ** means we do need to fix the database references, FALSE means we do not.
219 DbFixer
*pFix
, /* The fixer to be initialized */
220 Parse
*pParse
, /* Error messages will be written here */
221 int iDb
, /* This is the database that must be used */
222 const char *zType
, /* "view", "trigger", or "index" */
223 const Token
*pName
/* Name of the view, trigger, or index */
227 if( iDb
<0 || iDb
==1 ) return 0;
229 assert( db
->nDb
>iDb
);
230 pFix
->pParse
= pParse
;
231 pFix
->zDb
= db
->aDb
[iDb
].zName
;
238 ** The following set of routines walk through the parse tree and assign
239 ** a specific database to all table references where the database name
240 ** was left unspecified in the original SQL statement. The pFix structure
241 ** must have been initialized by a prior call to sqlite3FixInit().
243 ** These routines are used to make sure that an index, trigger, or
244 ** view in one database does not refer to objects in a different database.
245 ** (Exception: indices, triggers, and views in the TEMP database are
246 ** allowed to refer to anything.) If a reference is explicitly made
247 ** to an object in a different database, an error message is added to
248 ** pParse->zErrMsg and these routines return non-zero. If everything
249 ** checks out, these routines return 0.
251 int sqlite3FixSrcList(
252 DbFixer
*pFix
, /* Context of the fixation */
253 SrcList
*pList
/* The Source list to check and modify */
257 struct SrcList_item
*pItem
;
259 if( pList
==0 ) return 0;
261 for(i
=0, pItem
=pList
->a
; i
<pList
->nSrc
; i
++, pItem
++){
262 if( pItem
->zDatabase
==0 ){
263 pItem
->zDatabase
= sqliteStrDup(zDb
);
264 }else if( sqlite3StrICmp(pItem
->zDatabase
,zDb
)!=0 ){
265 sqlite3ErrorMsg(pFix
->pParse
,
266 "%s %T cannot reference objects in database %s",
267 pFix
->zType
, pFix
->pName
, pItem
->zDatabase
);
270 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
271 if( sqlite3FixSelect(pFix
, pItem
->pSelect
) ) return 1;
272 if( sqlite3FixExpr(pFix
, pItem
->pOn
) ) return 1;
277 #if !defined(SQLITE_OMIT_VIEW) || !defined(SQLITE_OMIT_TRIGGER)
278 int sqlite3FixSelect(
279 DbFixer
*pFix
, /* Context of the fixation */
280 Select
*pSelect
/* The SELECT statement to be fixed to one database */
283 if( sqlite3FixExprList(pFix
, pSelect
->pEList
) ){
286 if( sqlite3FixSrcList(pFix
, pSelect
->pSrc
) ){
289 if( sqlite3FixExpr(pFix
, pSelect
->pWhere
) ){
292 if( sqlite3FixExpr(pFix
, pSelect
->pHaving
) ){
295 pSelect
= pSelect
->pPrior
;
300 DbFixer
*pFix
, /* Context of the fixation */
301 Expr
*pExpr
/* The expression to be fixed to one database */
304 if( sqlite3FixSelect(pFix
, pExpr
->pSelect
) ){
307 if( sqlite3FixExprList(pFix
, pExpr
->pList
) ){
310 if( sqlite3FixExpr(pFix
, pExpr
->pRight
) ){
313 pExpr
= pExpr
->pLeft
;
317 int sqlite3FixExprList(
318 DbFixer
*pFix
, /* Context of the fixation */
319 ExprList
*pList
/* The expression to be fixed to one database */
322 struct ExprList_item
*pItem
;
323 if( pList
==0 ) return 0;
324 for(i
=0, pItem
=pList
->a
; i
<pList
->nExpr
; i
++, pItem
++){
325 if( sqlite3FixExpr(pFix
, pItem
->pExpr
) ){
333 #ifndef SQLITE_OMIT_TRIGGER
334 int sqlite3FixTriggerStep(
335 DbFixer
*pFix
, /* Context of the fixation */
336 TriggerStep
*pStep
/* The trigger step be fixed to one database */
339 if( sqlite3FixSelect(pFix
, pStep
->pSelect
) ){
342 if( sqlite3FixExpr(pFix
, pStep
->pWhere
) ){
345 if( sqlite3FixExprList(pFix
, pStep
->pExprList
) ){
348 pStep
= pStep
->pNext
;