monotone

monotone Mtn Source Tree

Root/sqlite/attach.c

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

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status