/* ** Compile a single statement of SQL into a virtual machine. Return one ** of the SQLITE_ success/failure codes. Also write an error message into ** memory obtained from malloc() and make *pzErrMsg point to that message. */ int sqlite_compile( sqlite *db, /* The database on which the SQL executes */ const char *zSql, /* The SQL to be executed */ const char **pzTail, /* OUT: Next statement after the first */ sqlite_vm **ppVm, /* OUT: The virtual machine */ char **pzErrMsg /* OUT: Write error messages here */ ){ Parse sParse; if( pzErrMsg ) *pzErrMsg = 0; if( sqliteSafetyOn(db) ) goto exec_misuse; if( !db->init.busy ){ if( (db->flags & SQLITE_Initialized)==0 ){ int rc, cnt = 1; while( (rc = sqliteInit(db, pzErrMsg))==SQLITE_BUSY && db->xBusyCallback && db->xBusyCallback(db->pBusyArg, "", cnt++)!=0 ){} if( rc!=SQLITE_OK ){ sqliteStrRealloc(pzErrMsg); sqliteSafetyOff(db); return rc; } if( pzErrMsg ){ sqliteFree(*pzErrMsg); *pzErrMsg = 0; } } if( db->file_format<3 ){ sqliteSafetyOff(db); sqliteSetString(pzErrMsg, "obsolete database file format", (char*)0); return SQLITE_ERROR; } } assert( (db->flags & SQLITE_Initialized)!=0 || db->init.busy ); if( db->pVdbe==0 ){ db->nChange = 0; } memset(&sParse, 0, sizeof(sParse)); sParse.db = db; sqliteRunParser(&sParse, zSql, pzErrMsg); if( db->xTrace && !db->init.busy ){ /* Trace only the statment that was compiled. ** Make a copy of that part of the SQL string since zSQL is const ** and we must pass a zero terminated string to the trace function ** The copy is unnecessary if the tail pointer is pointing at the ** beginnig or end of the SQL string. */ if( sParse.zTail && sParse.zTail!=zSql && *sParse.zTail ){ char *tmpSql = sqliteStrNDup(zSql, sParse.zTail - zSql); if( tmpSql ){ db->xTrace(db->pTraceArg, tmpSql); free(tmpSql); }else{ /* If a memory error occurred during the copy, ** trace entire SQL string and fall through to the ** sqlite_malloc_failed test to report the error. */ db->xTrace(db->pTraceArg, zSql); } }else{ db->xTrace(db->pTraceArg, zSql); } } if( sqlite_malloc_failed ){ sqliteSetString(pzErrMsg, "out of memory", (char*)0); sParse.rc = SQLITE_NOMEM; sqliteRollbackAll(db); sqliteResetInternalSchema(db, 0); db->flags &= ~SQLITE_InTrans; } if( sParse.rc==SQLITE_DONE ) sParse.rc = SQLITE_OK; if( sParse.rc!=SQLITE_OK && pzErrMsg && *pzErrMsg==0 ){ sqliteSetString(pzErrMsg, sqlite_error_string(sParse.rc), (char*)0); } sqliteStrRealloc(pzErrMsg); if( sParse.rc==SQLITE_SCHEMA ){ sqliteResetInternalSchema(db, 0); } assert( ppVm ); *ppVm = (sqlite_vm*)sParse.pVdbe; if( pzTail ) *pzTail = sParse.zTail; if( sqliteSafetyOff(db) ) goto exec_misuse; return sParse.rc; exec_misuse: if( pzErrMsg ){ *pzErrMsg = 0; sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0); sqliteStrRealloc(pzErrMsg); } return SQLITE_MISUSE; }
/* ** This routine is called by the parser to process an ATTACH statement: ** ** ATTACH DATABASE filename AS dbname ** ** The pFilename and pDbname arguments are the tokens that define the ** filename and dbname in the ATTACH statement. */ void sqliteAttach(Parse *pParse, Token *pFilename, Token *pDbname, Token *pKey){ Db *aNew; int rc, i; char *zFile, *zName; sqlite *db; Vdbe *v; v = sqliteGetVdbe(pParse); sqliteVdbeAddOp(v, OP_Halt, 0, 0); if( pParse->explain ) return; db = pParse->db; if( db->file_format<4 ){ sqliteErrorMsg(pParse, "cannot attach auxiliary databases to an " "older format master database", 0); pParse->rc = SQLITE_ERROR; return; } if( db->nDb>=MAX_ATTACHED+2 ){ sqliteErrorMsg(pParse, "too many attached databases - max %d", MAX_ATTACHED); pParse->rc = SQLITE_ERROR; return; } zFile = 0; sqliteSetNString(&zFile, pFilename->z, pFilename->n, 0); if( zFile==0 ) return; sqliteDequote(zFile); #ifndef SQLITE_OMIT_AUTHORIZATION if( sqliteAuthCheck(pParse, SQLITE_ATTACH, zFile, 0, 0)!=SQLITE_OK ){ sqliteFree(zFile); return; } #endif /* SQLITE_OMIT_AUTHORIZATION */ zName = 0; sqliteSetNString(&zName, pDbname->z, pDbname->n, 0); if( zName==0 ) return; sqliteDequote(zName); for(i=0; i<db->nDb; i++){ if( db->aDb[i].zName && sqliteStrICmp(db->aDb[i].zName, zName)==0 ){ sqliteErrorMsg(pParse, "database %z is already in use", zName); pParse->rc = SQLITE_ERROR; sqliteFree(zFile); return; } } if( db->aDb==db->aDbStatic ){ aNew = sqliteMalloc( sizeof(db->aDb[0])*3 ); if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ aNew = sqliteRealloc(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)); sqliteHashInit(&aNew->tblHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&aNew->idxHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&aNew->trigHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&aNew->aFKey, SQLITE_HASH_STRING, 1); aNew->zName = zName; rc = sqliteBtreeFactory(db, zFile, 0, MAX_PAGES, &aNew->pBt); if( rc ){ sqliteErrorMsg(pParse, "unable to open database: %s", zFile); } #if SQLITE_HAS_CODEC { extern int sqliteCodecAttach(sqlite*, int, void*, int); char *zKey = 0; int nKey; if( pKey && pKey->z && pKey->n ){ sqliteSetNString(&zKey, pKey->z, pKey->n, 0); sqliteDequote(zKey); nKey = strlen(zKey); }else{ zKey = 0; nKey = 0; } sqliteCodecAttach(db, db->nDb-1, zKey, nKey); } #endif sqliteFree(zFile); db->flags &= ~SQLITE_Initialized; if( pParse->nErr ) return; if( rc==SQLITE_OK ){ rc = sqliteInit(pParse->db, &pParse->zErrMsg); } if( rc ){ int i = db->nDb - 1; assert( i>=2 ); if( db->aDb[i].pBt ){ sqliteBtreeClose(db->aDb[i].pBt); db->aDb[i].pBt = 0; } sqliteResetInternalSchema(db, 0); pParse->nErr++; pParse->rc = SQLITE_ERROR; } }
/* ** Open a new SQLite database. Construct an "sqlite" structure to define ** the state of this database and return a pointer to that structure. ** ** An attempt is made to initialize the in-memory data structures that ** hold the database schema. But if this fails (because the schema file ** is locked) then that step is deferred until the first call to ** sqlite_exec(). */ sqlite *sqlite_open(const char *zFilename, int mode, char **pzErrMsg){ sqlite *db; int rc, i; /* Allocate the sqlite data structure */ db = sqliteMalloc( sizeof(sqlite) ); if( pzErrMsg ) *pzErrMsg = 0; if( db==0 ) goto no_mem_on_open; db->onError = OE_Default; db->priorNewRowid = 0; db->magic = SQLITE_MAGIC_BUSY; db->nDb = 2; db->aDb = db->aDbStatic; /* db->flags |= SQLITE_ShortColNames; */ sqliteHashInit(&db->aFunc, SQLITE_HASH_STRING, 1); for(i=0; i<db->nDb; i++){ sqliteHashInit(&db->aDb[i].tblHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&db->aDb[i].idxHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&db->aDb[i].trigHash, SQLITE_HASH_STRING, 0); sqliteHashInit(&db->aDb[i].aFKey, SQLITE_HASH_STRING, 1); } /* Open the backend database driver */ if( zFilename[0]==':' && strcmp(zFilename,":memory:")==0 ){ db->temp_store = 2; } rc = sqliteBtreeFactory(db, zFilename, 0, MAX_PAGES, &db->aDb[0].pBt); if( rc!=SQLITE_OK ){ switch( rc ){ default: { sqliteSetString(pzErrMsg, "unable to open database: ", zFilename, (char*)0); } } sqliteFree(db); sqliteStrRealloc(pzErrMsg); return 0; } db->aDb[0].zName = "main"; db->aDb[1].zName = "temp"; /* Attempt to read the schema */ sqliteRegisterBuiltinFunctions(db); rc = sqliteInit(db, pzErrMsg); db->magic = SQLITE_MAGIC_OPEN; if( sqlite_malloc_failed ){ sqlite_close(db); goto no_mem_on_open; }else if( rc!=SQLITE_OK && rc!=SQLITE_BUSY ){ sqlite_close(db); sqliteStrRealloc(pzErrMsg); return 0; }else if( pzErrMsg ){ sqliteFree(*pzErrMsg); *pzErrMsg = 0; } /* Return a pointer to the newly opened database structure */ return db; no_mem_on_open: sqliteSetString(pzErrMsg, "out of memory", (char*)0); sqliteStrRealloc(pzErrMsg); return 0; }