📄 attach.c
字号:
/*** 2003 April 6**** The author disclaims copyright to this source code. In place of** a legal notice, here is a blessing:**** May you do good and not evil.** May you find forgiveness for yourself and forgive others.** May you share freely, never taking more than you give.***************************************************************************** This file contains code used to implement the ATTACH and DETACH commands.**** $Id: attach.c,v 1.78 2008/08/20 16:35:10 drh Exp $*/#include "sqliteInt.h"#ifndef SQLITE_OMIT_ATTACH/*** Resolve an expression that was part of an ATTACH or DETACH statement. This** is slightly different from resolving a normal SQL expression, because simple** identifiers are treated as strings, not possible column names or aliases.**** i.e. if the parser sees:**** ATTACH DATABASE abc AS def**** it treats the two expressions as literal strings 'abc' and 'def' instead of** looking for columns of the same name.**** This only applies to the root node of pExpr, so the statement:**** ATTACH DATABASE abc||def AS 'db2'**** will fail because neither abc or def can be resolved.*/static int resolveAttachExpr(NameContext *pName, Expr *pExpr){ int rc = SQLITE_OK; if( pExpr ){ if( pExpr->op!=TK_ID ){ rc = sqlite3ResolveExprNames(pName, pExpr); if( rc==SQLITE_OK && !sqlite3ExprIsConstant(pExpr) ){ sqlite3ErrorMsg(pName->pParse, "invalid name: \"%T\"", &pExpr->span); return SQLITE_ERROR; } }else{ pExpr->op = TK_STRING; } } return rc;}/*** An SQL user-function registered to do the work of an ATTACH statement. The** three arguments to the function come directly from an attach statement:**** ATTACH DATABASE x AS y KEY z**** SELECT sqlite_attach(x, y, z)**** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the** third argument.*/static void attachFunc( sqlite3_context *context, int argc, sqlite3_value **argv){ int i; int rc = 0; sqlite3 *db = sqlite3_context_db_handle(context); const char *zName; const char *zFile; Db *aNew; char *zErrDyn = 0; char zErr[128]; zFile = (const char *)sqlite3_value_text(argv[0]); zName = (const char *)sqlite3_value_text(argv[1]); if( zFile==0 ) zFile = ""; if( zName==0 ) zName = ""; /* Check for the following errors: ** ** * Too many attached databases, ** * Transaction currently open ** * Specified database name already being used. */ if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){ sqlite3_snprintf( sizeof(zErr), zErr, "too many attached databases - max %d", db->aLimit[SQLITE_LIMIT_ATTACHED] ); goto attach_error; } if( !db->autoCommit ){ sqlite3_snprintf(sizeof(zErr), zErr, "cannot ATTACH database within transaction"); goto attach_error; } for(i=0; i<db->nDb; i++){ char *z = db->aDb[i].zName; if( z && zName && sqlite3StrICmp(z, zName)==0 ){ sqlite3_snprintf(sizeof(zErr), zErr, "database %s is already in use", zName); goto attach_error; } } /* Allocate the new entry in the db->aDb[] array and initialise the schema ** hash tables. */ if( db->aDb==db->aDbStatic ){ aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 ); if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); if( aNew==0 ) return; } db->aDb = aNew; aNew = &db->aDb[db->nDb++]; memset(aNew, 0, sizeof(*aNew)); /* Open the database file. If the btree is successfully opened, use ** it to obtain the database schema. At this point the schema may ** or may not be initialised. */ rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE, db->openFlags | SQLITE_OPEN_MAIN_DB, &aNew->pBt); if( rc==SQLITE_OK ){ Pager *pPager; aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt); if( !aNew->pSchema ){ rc = SQLITE_NOMEM; }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ sqlite3_snprintf(sizeof(zErr), zErr, "attached databases must use the same text encoding as main database"); goto attach_error; } pPager = sqlite3BtreePager(aNew->pBt); sqlite3PagerLockingMode(pPager, db->dfltLockMode); sqlite3PagerJournalMode(pPager, db->dfltJournalMode); } aNew->zName = sqlite3DbStrDup(db, zName); aNew->safety_level = 3;#if SQLITE_HAS_CODEC { extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); int nKey; char *zKey; int t = sqlite3_value_type(argv[2]); switch( t ){ case SQLITE_INTEGER: case SQLITE_FLOAT: zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); rc = SQLITE_ERROR; break; case SQLITE_TEXT: case SQLITE_BLOB: nKey = sqlite3_value_bytes(argv[2]); zKey = (char *)sqlite3_value_blob(argv[2]); sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); break; case SQLITE_NULL: /* No key specified. Use the key from the main database */ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); break; } }#endif /* If the file was opened successfully, read the schema for the new database. ** If this fails, or if opening the file failed, then close the file and ** remove the entry from the db->aDb[] array. i.e. put everything back the way ** we found it. */ if( rc==SQLITE_OK ){ (void)sqlite3SafetyOn(db); sqlite3BtreeEnterAll(db); rc = sqlite3Init(db, &zErrDyn); sqlite3BtreeLeaveAll(db); (void)sqlite3SafetyOff(db); } if( rc ){ int iDb = db->nDb - 1; assert( iDb>=2 ); if( db->aDb[iDb].pBt ){ sqlite3BtreeClose(db->aDb[iDb].pBt); db->aDb[iDb].pBt = 0; db->aDb[iDb].pSchema = 0; } sqlite3ResetInternalSchema(db, 0); db->nDb = iDb; if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ db->mallocFailed = 1; sqlite3_snprintf(sizeof(zErr),zErr, "out of memory"); }else{ sqlite3_snprintf(sizeof(zErr),zErr, "unable to open database: %s", zFile); } goto attach_error; } return;attach_error: /* Return an error if we get here */ if( zErrDyn ){ sqlite3_result_error(context, zErrDyn, -1); sqlite3DbFree(db, zErrDyn); }else{ zErr[sizeof(zErr)-1] = 0; sqlite3_result_error(context, zErr, -1); } if( rc ) sqlite3_result_error_code(context, rc);}/*** An SQL user-function registered to do the work of an DETACH statement. The** three arguments to the function come directly from a detach statement:**** DETACH DATABASE x**** SELECT sqlite_detach(x)*/static void detachFunc( sqlite3_context *context, int argc, sqlite3_value **argv){ const char *zName = (const char *)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); int i; Db *pDb = 0; char zErr[128]; if( zName==0 ) zName = ""; for(i=0; i<db->nDb; i++){ pDb = &db->aDb[i]; if( pDb->pBt==0 ) continue; if( sqlite3StrICmp(pDb->zName, zName)==0 ) break; } if( i>=db->nDb ){ sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName); goto detach_error; } if( i<2 ){ sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName); goto detach_error; } if( !db->autoCommit ){ sqlite3_snprintf(sizeof(zErr), zErr, "cannot DETACH database within transaction"); goto detach_error; }
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -