/* ** Usage: sqlite_bind VM IDX VALUE FLAGS ** ** Sets the value of the IDX-th occurance of "?" in the original SQL ** string. VALUE is the new value. If FLAGS=="null" then VALUE is ** ignored and the value is set to NULL. If FLAGS=="static" then ** the value is set to the value of a static variable named ** "sqlite_static_bind_value". If FLAGS=="normal" then a copy ** of the VALUE is made. */ static int test_bind( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite_vm *vm; int rc; int idx; if( argc!=5 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " VM IDX VALUE (null|static|normal)\"", 0); return TCL_ERROR; } if( getVmPointer(interp, argv[1], &vm) ) return TCL_ERROR; if( Tcl_GetInt(interp, argv[2], &idx) ) return TCL_ERROR; if( strcmp(argv[4],"null")==0 ){ rc = sqlite_bind(vm, idx, 0, 0, 0); }else if( strcmp(argv[4],"static")==0 ){ rc = sqlite_bind(vm, idx, sqlite_static_bind_value, -1, 0); }else if( strcmp(argv[4],"normal")==0 ){ rc = sqlite_bind(vm, idx, argv[3], -1, 1); }else{ Tcl_AppendResult(interp, "4th argument should be " "\"null\" or \"static\" or \"normal\"", 0); return TCL_ERROR; } if( rc ){ char zBuf[50]; sprintf(zBuf, "(%d) ", rc); Tcl_AppendResult(interp, zBuf, sqlite_error_string(rc), 0); return TCL_ERROR; } return TCL_OK; }
/* ** Give a listing of the program in the virtual machine. ** ** The interface is the same as sqliteVdbeExec(). But instead of ** running the code, it invokes the callback once for each instruction. ** This feature is used to implement "EXPLAIN". */ int sqliteVdbeList( Vdbe *p /* The VDBE */ ){ sqlite *db = p->db; int i; int rc = SQLITE_OK; static char *azColumnNames[] = { "addr", "opcode", "p1", "p2", "p3", "int", "text", "int", "int", "text", 0 }; assert( p->popStack==0 ); assert( p->explain ); p->azColName = azColumnNames; p->azResColumn = p->zArgv; for(i=0; i<5; i++) p->zArgv[i] = p->aStack[i].zShort; i = p->pc; if( i>=p->nOp ){ p->rc = SQLITE_OK; rc = SQLITE_DONE; }else if( db->flags & SQLITE_Interrupt ){ db->flags &= ~SQLITE_Interrupt; if( db->magic!=SQLITE_MAGIC_BUSY ){ p->rc = SQLITE_MISUSE; }else{ p->rc = SQLITE_INTERRUPT; } rc = SQLITE_ERROR; sqliteSetString(&p->zErrMsg, sqlite_error_string(p->rc), (char*)0); }else{ sprintf(p->zArgv[0],"%d",i); sprintf(p->zArgv[2],"%d", p->aOp[i].p1); sprintf(p->zArgv[3],"%d", p->aOp[i].p2); if( p->aOp[i].p3type==P3_POINTER ){ sprintf(p->aStack[4].zShort, "ptr(%#x)", (int)p->aOp[i].p3); p->zArgv[4] = p->aStack[4].zShort; }else{ p->zArgv[4] = p->aOp[i].p3; } p->zArgv[1] = sqliteOpcodeNames[p->aOp[i].opcode]; p->pc = i+1; p->azResColumn = p->zArgv; p->nResColumn = 5; p->rc = SQLITE_OK; rc = SQLITE_ROW; } return rc; }
/* ** Clean up and delete a VDBE after execution. Return an integer which is ** the result code. Write any error message text into *pzErrMsg. */ int sqliteVdbeFinalize(Vdbe *p, char **pzErrMsg){ int rc; sqlite *db; if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){ sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0); return SQLITE_MISUSE; } db = p->db; rc = sqliteVdbeReset(p, pzErrMsg); sqliteVdbeDelete(p); if( db->want_to_close && db->pVdbe==0 ){ sqlite_close(db); } if( rc==SQLITE_SCHEMA ){ sqliteResetInternalSchema(db, 0); } return rc; }
/* ** Invoke an SQL statement but ignore all the data in the result. Instead, ** return a list that consists of the datatypes of the various columns. ** ** This only works if "PRAGMA show_datatypes=on" has been executed against ** the database connection. */ static int sqlite_datatypes( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite *db; int rc; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB SQL", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; rc = sqlite_exec(db, argv[2], rememberDataTypes, interp, 0); if( rc!=0 && rc!=SQLITE_ABORT ){ Tcl_AppendResult(interp, sqlite_error_string(rc), 0); return TCL_ERROR; } return TCL_OK; }
/* ** Usage: sqlite_register_test_function DB NAME ** ** Register the test SQL function on the database DB under the name NAME. */ static int test_register_func( void *NotUsed, Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int argc, /* Number of arguments */ char **argv /* Text of each argument */ ){ sqlite *db; int rc; if( argc!=3 ){ Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0], " DB FUNCTION-NAME", 0); return TCL_ERROR; } if( getDbPointer(interp, argv[1], &db) ) return TCL_ERROR; rc = sqlite_create_function(db, argv[2], -1, testFunc, 0); if( rc!=0 ){ Tcl_AppendResult(interp, sqlite_error_string(rc), 0); return TCL_ERROR; } return TCL_OK; }
static int sqlite_odbx_bind( odbx_t* handle, const char* database, const char* who, const char* cred, int method ) { struct sconn* aux = handle->aux; if( aux == NULL ) { return -ODBX_ERR_PARAM; } if( method != ODBX_BIND_SIMPLE ) { return -ODBX_ERR_NOTSUP; } aux->errmsg = NULL; size_t flen = strlen( database ) + 1; if( ( aux->path = realloc( aux->path, aux->pathlen + flen + 1 ) ) == NULL ) { return -ODBX_ERR_NOMEM; } snprintf( aux->path + aux->pathlen, flen + 1, "%s", database ); /* The second parameter is currently unused. */ if( ( handle->generic = (void*) sqlite_open( aux->path, 0, NULL ) ) == NULL ) { aux->errno = SQLITE_CANTOPEN; aux->errmsg = (char*) dgettext( "opendbx", sqlite_odbx_errmsg[0] ); return -ODBX_ERR_BACKEND; } int err; if( ( err = sqlite_exec( (sqlite*) handle->generic, "PRAGMA empty_result_callbacks = ON;", NULL, NULL, NULL ) ) != SQLITE_OK ) { aux->errno = err; aux->errmsg = (char*) sqlite_error_string( err ); return -ODBX_ERR_BACKEND; } return ODBX_ERR_SUCCESS; }
/* ** Run the parser on the given SQL string. The parser structure is ** passed in. An SQLITE_ status code is returned. If an error occurs ** and pzErrMsg!=NULL then an error message might be written into ** memory obtained from malloc() and *pzErrMsg made to point to that ** error message. Or maybe not. */ int sqliteRunParser(Parse *pParse, const char *zSql, char **pzErrMsg){ int nErr = 0; int i; void *pEngine; int tokenType; int lastTokenParsed = -1; sqlite *db = pParse->db; extern void *sqliteParserAlloc(void*(*)(int)); extern void sqliteParserFree(void*, void(*)(void*)); extern int sqliteParser(void*, int, Token, Parse*); db->flags &= ~SQLITE_Interrupt; pParse->rc = SQLITE_OK; i = 0; pEngine = sqliteParserAlloc((void*(*)(int))malloc); if( pEngine==0 ){ sqliteSetString(pzErrMsg, "out of memory", (char*)0); return 1; } pParse->sLastToken.dyn = 0; pParse->zTail = zSql; while( sqlite_malloc_failed==0 && zSql[i]!=0 ){ assert( i>=0 ); pParse->sLastToken.z = &zSql[i]; assert( pParse->sLastToken.dyn==0 ); pParse->sLastToken.n = sqliteGetToken((unsigned char*)&zSql[i], &tokenType); i += pParse->sLastToken.n; switch( tokenType ){ case TK_SPACE: case TK_COMMENT: { if( (db->flags & SQLITE_Interrupt)!=0 ){ pParse->rc = SQLITE_INTERRUPT; sqliteSetString(pzErrMsg, "interrupt", (char*)0); goto abort_parse; } break; } case TK_ILLEGAL: { sqliteSetNString(pzErrMsg, "unrecognized token: \"", -1, pParse->sLastToken.z, pParse->sLastToken.n, "\"", 1, 0); nErr++; goto abort_parse; } case TK_SEMI: { pParse->zTail = &zSql[i]; /* Fall thru into the default case */ } default: { sqliteParser(pEngine, tokenType, pParse->sLastToken, pParse); lastTokenParsed = tokenType; if( pParse->rc!=SQLITE_OK ){ goto abort_parse; } break; } } } abort_parse: if( zSql[i]==0 && nErr==0 && pParse->rc==SQLITE_OK ){ if( lastTokenParsed!=TK_SEMI ){ sqliteParser(pEngine, TK_SEMI, pParse->sLastToken, pParse); pParse->zTail = &zSql[i]; } sqliteParser(pEngine, 0, pParse->sLastToken, pParse); } sqliteParserFree(pEngine, free); if( pParse->rc!=SQLITE_OK && pParse->rc!=SQLITE_DONE && pParse->zErrMsg==0 ){ sqliteSetString(&pParse->zErrMsg, sqlite_error_string(pParse->rc), (char*)0); } if( pParse->zErrMsg ){ if( pzErrMsg && *pzErrMsg==0 ){ *pzErrMsg = pParse->zErrMsg; }else{ sqliteFree(pParse->zErrMsg); } pParse->zErrMsg = 0; if( !nErr ) nErr++; } if( pParse->pVdbe && pParse->nErr>0 ){ sqliteVdbeDelete(pParse->pVdbe); pParse->pVdbe = 0; } if( pParse->pNewTable ){ sqliteDeleteTable(pParse->db, pParse->pNewTable); pParse->pNewTable = 0; } if( pParse->pNewTrigger ){ sqliteDeleteTrigger(pParse->pNewTrigger); pParse->pNewTrigger = 0; } if( nErr>0 && (pParse->rc==SQLITE_OK || pParse->rc==SQLITE_DONE) ){ pParse->rc = SQLITE_ERROR; } return nErr; }
/* ** The "sqlite" command below creates a new Tcl command for each ** connection it opens to an SQLite database. This routine is invoked ** whenever one of those connection-specific commands is executed ** in Tcl. For example, if you run Tcl code like this: ** ** sqlite db1 "my_database" ** db1 close ** ** The first command opens a connection to the "my_database" database ** and calls that connection "db1". The second command causes this ** subroutine to be invoked. */ static int DbObjCmd(void *cd, Tcl_Interp *interp, int objc,Tcl_Obj *const*objv){ SqliteDb *pDb = (SqliteDb*)cd; int choice; int rc = TCL_OK; static const char *DB_strs[] = { "authorizer", "busy", "changes", "close", "commit_hook", "complete", "errorcode", "eval", "function", "last_insert_rowid", "last_statement_changes", "onecolumn", "progress", "rekey", "timeout", "trace", 0 }; enum DB_enum { DB_AUTHORIZER, DB_BUSY, DB_CHANGES, DB_CLOSE, DB_COMMIT_HOOK, DB_COMPLETE, DB_ERRORCODE, DB_EVAL, DB_FUNCTION, DB_LAST_INSERT_ROWID, DB_LAST_STATEMENT_CHANGES, DB_ONECOLUMN, DB_PROGRESS, DB_REKEY, DB_TIMEOUT, DB_TRACE }; if( objc<2 ){ Tcl_WrongNumArgs(interp, 1, objv, "SUBCOMMAND ..."); return TCL_ERROR; } if( Tcl_GetIndexFromObj(interp, objv[1], DB_strs, "option", 0, &choice) ){ return TCL_ERROR; } switch( (enum DB_enum)choice ){ /* $db authorizer ?CALLBACK? ** ** Invoke the given callback to authorize each SQL operation as it is ** compiled. 5 arguments are appended to the callback before it is ** invoked: ** ** (1) The authorization type (ex: SQLITE_CREATE_TABLE, SQLITE_INSERT, ...) ** (2) First descriptive name (depends on authorization type) ** (3) Second descriptive name ** (4) Name of the database (ex: "main", "temp") ** (5) Name of trigger that is doing the access ** ** The callback should return on of the following strings: SQLITE_OK, ** SQLITE_IGNORE, or SQLITE_DENY. Any other return value is an error. ** ** If this method is invoked with no arguments, the current authorization ** callback string is returned. */ case DB_AUTHORIZER: { if( objc>3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); }else if( objc==2 ){ if( pDb->zAuth ){ Tcl_AppendResult(interp, pDb->zAuth, 0); } }else{ char *zAuth; int len; if( pDb->zAuth ){ Tcl_Free(pDb->zAuth); } zAuth = Tcl_GetStringFromObj(objv[2], &len); if( zAuth && len>0 ){ pDb->zAuth = Tcl_Alloc( len + 1 ); strcpy(pDb->zAuth, zAuth); }else{ pDb->zAuth = 0; } #ifndef SQLITE_OMIT_AUTHORIZATION if( pDb->zAuth ){ pDb->interp = interp; sqlite_set_authorizer(pDb->db, auth_callback, pDb); }else{ sqlite_set_authorizer(pDb->db, 0, 0); } #endif } break; } /* $db busy ?CALLBACK? ** ** Invoke the given callback if an SQL statement attempts to open ** a locked database file. */ case DB_BUSY: { if( objc>3 ){ Tcl_WrongNumArgs(interp, 2, objv, "CALLBACK"); return TCL_ERROR; }else if( objc==2 ){ if( pDb->zBusy ){ Tcl_AppendResult(interp, pDb->zBusy, 0); } }else{ char *zBusy; int len; if( pDb->zBusy ){ Tcl_Free(pDb->zBusy); } zBusy = Tcl_GetStringFromObj(objv[2], &len); if( zBusy && len>0 ){ pDb->zBusy = Tcl_Alloc( len + 1 ); strcpy(pDb->zBusy, zBusy); }else{ pDb->zBusy = 0; } if( pDb->zBusy ){ pDb->interp = interp; sqlite_busy_handler(pDb->db, DbBusyHandler, pDb); }else{ sqlite_busy_handler(pDb->db, 0, 0); } } break; } /* $db progress ?N CALLBACK? ** ** Invoke the given callback every N virtual machine opcodes while executing ** queries. */ case DB_PROGRESS: { if( objc==2 ){ if( pDb->zProgress ){ Tcl_AppendResult(interp, pDb->zProgress, 0); } }else if( objc==4 ){ char *zProgress; int len; int N; if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &N) ){ return TCL_ERROR; }; if( pDb->zProgress ){ Tcl_Free(pDb->zProgress); } zProgress = Tcl_GetStringFromObj(objv[3], &len); if( zProgress && len>0 ){ pDb->zProgress = Tcl_Alloc( len + 1 ); strcpy(pDb->zProgress, zProgress); }else{ pDb->zProgress = 0; } #ifndef SQLITE_OMIT_PROGRESS_CALLBACK if( pDb->zProgress ){ pDb->interp = interp; sqlite_progress_handler(pDb->db, N, DbProgressHandler, pDb); }else{ sqlite_progress_handler(pDb->db, 0, 0, 0); } #endif }else{ Tcl_WrongNumArgs(interp, 2, objv, "N CALLBACK"); return TCL_ERROR; } break; } /* ** $db changes ** ** Return the number of rows that were modified, inserted, or deleted by ** the most recent "eval". */ case DB_CHANGES: { Tcl_Obj *pResult; int nChange; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } nChange = sqlite_changes(pDb->db); pResult = Tcl_GetObjResult(interp); Tcl_SetIntObj(pResult, nChange); break; } /* ** $db last_statement_changes ** ** Return the number of rows that were modified, inserted, or deleted by ** the last statment to complete execution (excluding changes due to ** triggers) */ case DB_LAST_STATEMENT_CHANGES: { Tcl_Obj *pResult; int lsChange; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } lsChange = sqlite_last_statement_changes(pDb->db); pResult = Tcl_GetObjResult(interp); Tcl_SetIntObj(pResult, lsChange); break; } /* $db close ** ** Shutdown the database */ case DB_CLOSE: { Tcl_DeleteCommand(interp, Tcl_GetStringFromObj(objv[0], 0)); break; } /* $db commit_hook ?CALLBACK? ** ** Invoke the given callback just before committing every SQL transaction. ** If the callback throws an exception or returns non-zero, then the ** transaction is aborted. If CALLBACK is an empty string, the callback ** is disabled. */ case DB_COMMIT_HOOK: { if( objc>3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); }else if( objc==2 ){ if( pDb->zCommit ){ Tcl_AppendResult(interp, pDb->zCommit, 0); } }else{ char *zCommit; int len; if( pDb->zCommit ){ Tcl_Free(pDb->zCommit); } zCommit = Tcl_GetStringFromObj(objv[2], &len); if( zCommit && len>0 ){ pDb->zCommit = Tcl_Alloc( len + 1 ); strcpy(pDb->zCommit, zCommit); }else{ pDb->zCommit = 0; } if( pDb->zCommit ){ pDb->interp = interp; sqlite_commit_hook(pDb->db, DbCommitHandler, pDb); }else{ sqlite_commit_hook(pDb->db, 0, 0); } } break; } /* $db complete SQL ** ** Return TRUE if SQL is a complete SQL statement. Return FALSE if ** additional lines of input are needed. This is similar to the ** built-in "info complete" command of Tcl. */ case DB_COMPLETE: { Tcl_Obj *pResult; int isComplete; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "SQL"); return TCL_ERROR; } isComplete = sqlite_complete( Tcl_GetStringFromObj(objv[2], 0) ); pResult = Tcl_GetObjResult(interp); Tcl_SetBooleanObj(pResult, isComplete); break; } /* ** $db errorcode ** ** Return the numeric error code that was returned by the most recent ** call to sqlite_exec(). */ case DB_ERRORCODE: { Tcl_SetObjResult(interp, Tcl_NewIntObj(pDb->rc)); break; } /* ** $db eval $sql ?array { ...code... }? ** ** The SQL statement in $sql is evaluated. For each row, the values are ** placed in elements of the array named "array" and ...code... is executed. ** If "array" and "code" are omitted, then no callback is every invoked. ** If "array" is an empty string, then the values are placed in variables ** that have the same name as the fields extracted by the query. */ case DB_EVAL: { CallbackData cbData; char *zErrMsg; char *zSql; #ifdef UTF_TRANSLATION_NEEDED Tcl_DString dSql; int i; #endif if( objc!=5 && objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "SQL ?ARRAY-NAME CODE?"); return TCL_ERROR; } pDb->interp = interp; zSql = Tcl_GetStringFromObj(objv[2], 0); #ifdef UTF_TRANSLATION_NEEDED Tcl_DStringInit(&dSql); Tcl_UtfToExternalDString(NULL, zSql, -1, &dSql); zSql = Tcl_DStringValue(&dSql); #endif Tcl_IncrRefCount(objv[2]); if( objc==5 ){ cbData.interp = interp; cbData.once = 1; cbData.zArray = Tcl_GetStringFromObj(objv[3], 0); cbData.pCode = objv[4]; cbData.tcl_rc = TCL_OK; cbData.nColName = 0; cbData.azColName = 0; zErrMsg = 0; Tcl_IncrRefCount(objv[3]); Tcl_IncrRefCount(objv[4]); rc = sqlite_exec(pDb->db, zSql, DbEvalCallback, &cbData, &zErrMsg); Tcl_DecrRefCount(objv[4]); Tcl_DecrRefCount(objv[3]); if( cbData.tcl_rc==TCL_BREAK ){ cbData.tcl_rc = TCL_OK; } }else{ Tcl_Obj *pList = Tcl_NewObj(); cbData.tcl_rc = TCL_OK; rc = sqlite_exec(pDb->db, zSql, DbEvalCallback2, pList, &zErrMsg); Tcl_SetObjResult(interp, pList); } pDb->rc = rc; if( rc==SQLITE_ABORT ){ if( zErrMsg ) free(zErrMsg); rc = cbData.tcl_rc; }else if( zErrMsg ){ Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); free(zErrMsg); rc = TCL_ERROR; }else if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite_error_string(rc), 0); rc = TCL_ERROR; }else{ } Tcl_DecrRefCount(objv[2]); #ifdef UTF_TRANSLATION_NEEDED Tcl_DStringFree(&dSql); if( objc==5 && cbData.azColName ){ for(i=0; i<cbData.nColName; i++){ if( cbData.azColName[i] ) free(cbData.azColName[i]); } free(cbData.azColName); cbData.azColName = 0; } #endif return rc; } /* ** $db function NAME SCRIPT ** ** Create a new SQL function called NAME. Whenever that function is ** called, invoke SCRIPT to evaluate the function. */ case DB_FUNCTION: { SqlFunc *pFunc; char *zName; char *zScript; int nScript; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 2, objv, "NAME SCRIPT"); return TCL_ERROR; } zName = Tcl_GetStringFromObj(objv[2], 0); zScript = Tcl_GetStringFromObj(objv[3], &nScript); pFunc = (SqlFunc*)Tcl_Alloc( sizeof(*pFunc) + nScript + 1 ); if( pFunc==0 ) return TCL_ERROR; pFunc->interp = interp; pFunc->pNext = pDb->pFunc; pFunc->zScript = (char*)&pFunc[1]; strcpy(pFunc->zScript, zScript); sqlite_create_function(pDb->db, zName, -1, tclSqlFunc, pFunc); sqlite_function_type(pDb->db, zName, SQLITE_NUMERIC); break; } /* ** $db last_insert_rowid ** ** Return an integer which is the ROWID for the most recent insert. */ case DB_LAST_INSERT_ROWID: { Tcl_Obj *pResult; int rowid; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 2, objv, ""); return TCL_ERROR; } rowid = sqlite_last_insert_rowid(pDb->db); pResult = Tcl_GetObjResult(interp); Tcl_SetIntObj(pResult, rowid); break; } /* ** $db onecolumn SQL ** ** Return a single column from a single row of the given SQL query. */ case DB_ONECOLUMN: { char *zSql; char *zErrMsg = 0; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "SQL"); return TCL_ERROR; } zSql = Tcl_GetStringFromObj(objv[2], 0); rc = sqlite_exec(pDb->db, zSql, DbEvalCallback3, interp, &zErrMsg); if( rc==SQLITE_ABORT ){ rc = SQLITE_OK; }else if( zErrMsg ){ Tcl_SetResult(interp, zErrMsg, TCL_VOLATILE); free(zErrMsg); rc = TCL_ERROR; }else if( rc!=SQLITE_OK ){ Tcl_AppendResult(interp, sqlite_error_string(rc), 0); rc = TCL_ERROR; } break; } /* ** $db rekey KEY ** ** Change the encryption key on the currently open database. */ case DB_REKEY: { int nKey; void *pKey; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "KEY"); return TCL_ERROR; } pKey = Tcl_GetByteArrayFromObj(objv[2], &nKey); #ifdef SQLITE_HAS_CODEC rc = sqlite_rekey(pDb->db, pKey, nKey); if( rc ){ Tcl_AppendResult(interp, sqlite_error_string(rc), 0); rc = TCL_ERROR; } #endif break; } /* ** $db timeout MILLESECONDS ** ** Delay for the number of milliseconds specified when a file is locked. */ case DB_TIMEOUT: { int ms; if( objc!=3 ){ Tcl_WrongNumArgs(interp, 2, objv, "MILLISECONDS"); return TCL_ERROR; } if( Tcl_GetIntFromObj(interp, objv[2], &ms) ) return TCL_ERROR; sqlite_busy_timeout(pDb->db, ms); break; } /* $db trace ?CALLBACK? ** ** Make arrangements to invoke the CALLBACK routine for each SQL statement ** that is executed. The text of the SQL is appended to CALLBACK before ** it is executed. */ case DB_TRACE: { if( objc>3 ){ Tcl_WrongNumArgs(interp, 2, objv, "?CALLBACK?"); }else if( objc==2 ){ if( pDb->zTrace ){ Tcl_AppendResult(interp, pDb->zTrace, 0); } }else{ char *zTrace; int len; if( pDb->zTrace ){ Tcl_Free(pDb->zTrace); } zTrace = Tcl_GetStringFromObj(objv[2], &len); if( zTrace && len>0 ){ pDb->zTrace = Tcl_Alloc( len + 1 ); strcpy(pDb->zTrace, zTrace); }else{ pDb->zTrace = 0; } if( pDb->zTrace ){ pDb->interp = interp; sqlite_trace(pDb->db, DbTraceHandler, pDb); }else{ sqlite_trace(pDb->db, 0, 0); } } break; } } /* End of the SWITCH statement */ return rc; }
/* ** 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; }
/* ** Attempt to read the database schema and initialize internal ** data structures for a single database file. The index of the ** database file is given by iDb. iDb==0 is used for the main ** database. iDb==1 should never be used. iDb>=2 is used for ** auxiliary databases. Return one of the SQLITE_ error codes to ** indicate success or failure. */ static int sqliteInitOne(sqlite *db, int iDb, char **pzErrMsg){ int rc; BtCursor *curMain; int size; Table *pTab; char const *azArg[6]; char zDbNum[30]; int meta[SQLITE_N_BTREE_META]; InitData initData; char const *zMasterSchema; char const *zMasterName; char *zSql = 0; /* ** The master database table has a structure like this */ static char master_schema[] = "CREATE TABLE sqlite_master(\n" " type text,\n" " name text,\n" " tbl_name text,\n" " rootpage integer,\n" " sql text\n" ")" ; static char temp_master_schema[] = "CREATE TEMP TABLE sqlite_temp_master(\n" " type text,\n" " name text,\n" " tbl_name text,\n" " rootpage integer,\n" " sql text\n" ")" ; assert( iDb>=0 && iDb<db->nDb ); /* zMasterSchema and zInitScript are set to point at the master schema ** and initialisation script appropriate for the database being ** initialised. zMasterName is the name of the master table. */ if( iDb==1 ){ zMasterSchema = temp_master_schema; zMasterName = TEMP_MASTER_NAME; }else{ zMasterSchema = master_schema; zMasterName = MASTER_NAME; } /* Construct the schema table. */ sqliteSafetyOff(db); azArg[0] = "table"; azArg[1] = zMasterName; azArg[2] = "2"; azArg[3] = zMasterSchema; sprintf(zDbNum, "%d", iDb); azArg[4] = zDbNum; azArg[5] = 0; initData.db = db; initData.pzErrMsg = pzErrMsg; sqliteInitCallback(&initData, 5, (char **)azArg, 0); pTab = sqliteFindTable(db, zMasterName, db->aDb[iDb].zName); if( pTab ){ pTab->readOnly = 1; }else{ return SQLITE_NOMEM; } sqliteSafetyOn(db); /* Create a cursor to hold the database open */ if( db->aDb[iDb].pBt==0 ) return SQLITE_OK; rc = sqliteBtreeCursor(db->aDb[iDb].pBt, 2, 0, &curMain); if( rc ){ sqliteSetString(pzErrMsg, sqlite_error_string(rc), (char*)0); return rc; } /* Get the database meta information */ rc = sqliteBtreeGetMeta(db->aDb[iDb].pBt, meta); if( rc ){ sqliteSetString(pzErrMsg, sqlite_error_string(rc), (char*)0); sqliteBtreeCloseCursor(curMain); return rc; } db->aDb[iDb].schema_cookie = meta[1]; if( iDb==0 ){ db->next_cookie = meta[1]; db->file_format = meta[2]; size = meta[3]; if( size==0 ){ size = MAX_PAGES; } db->cache_size = size; db->safety_level = meta[4]; if( meta[6]>0 && meta[6]<=2 && db->temp_store==0 ){ db->temp_store = meta[6]; } if( db->safety_level==0 ) db->safety_level = 2; /* ** file_format==1 Version 2.1.0. ** file_format==2 Version 2.2.0. Add support for INTEGER PRIMARY KEY. ** file_format==3 Version 2.6.0. Fix empty-string index bug. ** file_format==4 Version 2.7.0. Add support for separate numeric and ** text datatypes. */ if( db->file_format==0 ){ /* This happens if the database was initially empty */ db->file_format = 4; }else if( db->file_format>4 ){ sqliteBtreeCloseCursor(curMain); sqliteSetString(pzErrMsg, "unsupported file format", (char*)0); return SQLITE_ERROR; } }else if( iDb!=1 && (db->file_format!=meta[2] || db->file_format<4) ){ assert( db->file_format>=4 ); if( meta[2]==0 ){ sqliteSetString(pzErrMsg, "cannot attach empty database: ", db->aDb[iDb].zName, (char*)0); }else{ sqliteSetString(pzErrMsg, "incompatible file format in auxiliary " "database: ", db->aDb[iDb].zName, (char*)0); } sqliteBtreeClose(db->aDb[iDb].pBt); db->aDb[iDb].pBt = 0; return SQLITE_FORMAT; } sqliteBtreeSetCacheSize(db->aDb[iDb].pBt, db->cache_size); sqliteBtreeSetSafetyLevel(db->aDb[iDb].pBt, meta[4]==0 ? 2 : meta[4]); /* Read the schema information out of the schema tables */ assert( db->init.busy ); sqliteSafetyOff(db); /* The following SQL will read the schema from the master tables. ** The first version works with SQLite file formats 2 or greater. ** The second version is for format 1 files. ** ** Beginning with file format 2, the rowid for new table entries ** (including entries in sqlite_master) is an increasing integer. ** So for file format 2 and later, we can play back sqlite_master ** and all the CREATE statements will appear in the right order. ** But with file format 1, table entries were random and so we ** have to make sure the CREATE TABLEs occur before their corresponding ** CREATE INDEXs. (We don't have to deal with CREATE VIEW or ** CREATE TRIGGER in file format 1 because those constructs did ** not exist then.) */ if( db->file_format>=2 ){ sqliteSetString(&zSql, "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"", db->aDb[iDb].zName, "\".", zMasterName, (char*)0); }else{ sqliteSetString(&zSql, "SELECT type, name, rootpage, sql, ", zDbNum, " FROM \"", db->aDb[iDb].zName, "\".", zMasterName, " WHERE type IN ('table', 'index')" " ORDER BY CASE type WHEN 'table' THEN 0 ELSE 1 END", (char*)0); } rc = sqlite_exec(db, zSql, sqliteInitCallback, &initData, 0); sqliteFree(zSql); sqliteSafetyOn(db); sqliteBtreeCloseCursor(curMain); if( sqlite_malloc_failed ){ sqliteSetString(pzErrMsg, "out of memory", (char*)0); rc = SQLITE_NOMEM; sqliteResetInternalSchema(db, 0); } if( rc==SQLITE_OK ){ DbSetProperty(db, iDb, DB_SchemaLoaded); }else{ sqliteResetInternalSchema(db, iDb); } return rc; }
/* ** Clean up a VDBE after execution but do not delete the VDBE just yet. ** Write any error messages into *pzErrMsg. Return the result code. ** ** After this routine is run, the VDBE should be ready to be executed ** again. */ int sqliteVdbeReset(Vdbe *p, char **pzErrMsg){ sqlite *db = p->db; int i; if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){ sqliteSetString(pzErrMsg, sqlite_error_string(SQLITE_MISUSE), (char*)0); return SQLITE_MISUSE; } if( p->zErrMsg ){ if( pzErrMsg && *pzErrMsg==0 ){ *pzErrMsg = p->zErrMsg; }else{ sqliteFree(p->zErrMsg); } p->zErrMsg = 0; }else if( p->rc ){ sqliteSetString(pzErrMsg, sqlite_error_string(p->rc), (char*)0); } Cleanup(p); if( p->rc!=SQLITE_OK ){ switch( p->errorAction ){ case OE_Abort: { if( !p->undoTransOnError ){ for(i=0; i<db->nDb; i++){ if( db->aDb[i].pBt ){ sqliteBtreeRollbackCkpt(db->aDb[i].pBt); } } break; } /* Fall through to ROLLBACK */ } case OE_Rollback: { sqliteRollbackAll(db); db->flags &= ~SQLITE_InTrans; db->onError = OE_Default; break; } default: { if( p->undoTransOnError ){ sqliteRollbackAll(db); db->flags &= ~SQLITE_InTrans; db->onError = OE_Default; } break; } } sqliteRollbackInternalChanges(db); } for(i=0; i<db->nDb; i++){ if( db->aDb[i].pBt && db->aDb[i].inTrans==2 ){ sqliteBtreeCommitCkpt(db->aDb[i].pBt); db->aDb[i].inTrans = 1; } } assert( p->pTos<&p->aStack[p->pc] || sqlite_malloc_failed==1 ); #ifdef VDBE_PROFILE { FILE *out = fopen("vdbe_profile.out", "a"); if( out ){ int i; fprintf(out, "---- "); for(i=0; i<p->nOp; i++){ fprintf(out, "%02x", p->aOp[i].opcode); } fprintf(out, "\n"); for(i=0; i<p->nOp; i++){ fprintf(out, "%6d %10lld %8lld ", p->aOp[i].cnt, p->aOp[i].cycles, p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0 ); sqliteVdbePrintOp(out, i, &p->aOp[i]); } fclose(out); } } #endif p->magic = VDBE_MAGIC_INIT; return p->rc; }
/* ** Read input from *in and process it. If *in==0 then input ** is interactive - the user is typing it it. Otherwise, input ** is coming from a file or device. A prompt is issued and history ** is saved only if input is interactive. An interrupt signal will ** cause this routine to exit immediately, unless input is interactive. */ static void process_input(struct callback_data *p, FILE *in){ char *zLine; char *zSql = 0; int nSql = 0; char *zErrMsg; int rc; while( fflush(p->out), (zLine = one_input_line(zSql, in))!=0 ){ if( seenInterrupt ){ if( in!=0 ) break; seenInterrupt = 0; } if( p->echoOn ) printf("%s\n", zLine); if( (zSql==0 || zSql[0]==0) && _all_whitespace(zLine) ) continue; if( zLine && zLine[0]=='.' && nSql==0 ){ int rc = do_meta_command(zLine, p); free(zLine); if( rc ) break; continue; } if( _is_command_terminator(zLine) ){ strcpy(zLine,";"); } if( zSql==0 ){ int i; for(i=0; zLine[i] && isspace(zLine[i]); i++){} if( zLine[i]!=0 ){ nSql = strlen(zLine); zSql = malloc( nSql+1 ); strcpy(zSql, zLine); } }else{ int len = strlen(zLine); zSql = realloc( zSql, nSql + len + 2 ); if( zSql==0 ){ fprintf(stderr,"%s: out of memory!\n", Argv0); exit(1); } strcpy(&zSql[nSql++], "\n"); strcpy(&zSql[nSql], zLine); nSql += len; } free(zLine); if( zSql && _ends_with_semicolon(zSql, nSql) && sqlite_complete(zSql) ){ p->cnt = 0; open_db(p); rc = sqlite_exec(p->db, zSql, callback, p, &zErrMsg); if( rc || zErrMsg ){ if( in!=0 && !p->echoOn ) printf("%s\n",zSql); if( zErrMsg!=0 ){ printf("SQL error: %s\n", zErrMsg); sqlite_freemem(zErrMsg); zErrMsg = 0; }else{ printf("SQL error: %s\n", sqlite_error_string(rc)); } } free(zSql); zSql = 0; nSql = 0; } } if( zSql ){ if( !_all_whitespace(zSql) ) printf("Incomplete SQL: %s\n", zSql); free(zSql); } }
static int sqlite_odbx_result( odbx_t* handle, odbx_result_t** result, struct timeval* timeout, unsigned long chunk ) { char** res; long ms = 0; int err, nrow, ncolumn; struct sres* sres; struct sconn* aux = (struct sconn*) handle->aux; if( handle->generic == NULL || aux == NULL ) { return -ODBX_ERR_PARAM; } aux->errmsg = NULL; if( aux->stmt == NULL ) { return ODBX_RES_DONE; /* no more results */ } if( timeout != NULL ) { ms = timeout->tv_sec * 1000 + timeout->tv_usec / 1000; } while( ( err = sqlite_get_table( (sqlite*) handle->generic, aux->stmt, &res, &nrow, &ncolumn, NULL ) ) == SQLITE_BUSY ) { if( ms <= 0 ) { return ODBX_RES_TIMEOUT; } /* Timeout */ sqlite_busy_timeout( (sqlite*) handle->generic, 100 ); ms -= 100; } free( aux->stmt ); aux->stmt = NULL; if( err != SQLITE_OK ) { aux->errno = err; aux->errmsg = (char*) sqlite_error_string( err ); return -ODBX_ERR_BACKEND; } if( ( *result = (odbx_result_t*) malloc( sizeof( struct odbx_result_t ) ) ) == NULL ) { return -ODBX_ERR_NOMEM; } if( ( sres = (struct sres*) malloc( sizeof( struct sres ) ) ) == NULL ) { free( *result ); *result = NULL; return -ODBX_ERR_NOMEM; } (*result)->generic = (void*) res; (*result)->aux = (void*) sres; sres->ncolumn = ncolumn; sres->nrow = nrow; sres->cur = -1; if( !ncolumn ) { return ODBX_RES_NOROWS; } /* empty or not SELECT like query */ return ODBX_RES_ROWS; /* result is available */ }