public static RC Config(Context ctx, VTABLECONFIG op, object arg1) { RC rc = RC.OK; MutexEx.Enter(ctx.Mutex); switch (op) { case VTABLECONFIG.CONSTRAINT: { VTableContext p = ctx.VTableCtx; if (p == null) { rc = SysEx.MISUSE_BKPT(); } else { Debug.Assert(p.Table == null || (p.Table.TabFlags & TF.Virtual) != 0); p.VTable.Constraint = (bool)arg1; } break; } default: rc = SysEx.MISUSE_BKPT(); break; } if (rc != RC.OK) { Main.Error(ctx, rc, null); } MutexEx.Leave(ctx.Mutex); return(rc); }
public static RC Prepare16(Context ctx, string sql, int bytes, bool isPrepareV2, out Vdbe stmtOut, out string tailOut) { // This function currently works by first transforming the UTF-16 encoded string to UTF-8, then invoking sqlite3_prepare(). The // tricky bit is figuring out the pointer to return in *pzTail. stmtOut = null; if (!sqlite3SafetyCheckOk(ctx)) { return(SysEx.MISUSE_BKPT()); } MutexEx.Enter(ctx.Mutex); RC rc = RC.OK; string tail8 = null; string sql8 = Vdbe.Utf16to8(ctx, sql, bytes, TEXTENCODE.UTF16NATIVE); if (sql8 != null) { rc = LockAndPrepare(ctx, sql8, -1, isPrepareV2, null, ref stmtOut, ref tail8); } if (tail8 != null && tailOut != null) { // If sqlite3_prepare returns a tail pointer, we calculate the equivalent pointer into the UTF-16 string by counting the unicode // characters between zSql8 and zTail8, and then returning a pointer the same number of characters into the UTF-16 string. Debugger.Break(); //: int charsParsed = Vdbe::Utf8CharLen(sql8, (int)(tail8 - sql8)); //: *tailOut = (uint8 *)sql + Vdbe::Utf16ByteLen(sql, charsParsed); } C._tagfree(ctx, ref sql8); rc = SysEx.ApiExit(ctx, rc); MutexEx.Leave(ctx.Mutex); return(rc); }
public static RC DeclareVTable(Context ctx, string createTableName) { MutexEx.Enter(ctx.Mutex); Table table; if (ctx.VTableCtx == null || (table = ctx.VTableCtx.Table) == null) { sqlite3Error(ctx, RC.MISUSE, null); MutexEx.Leave(ctx.Mutex); return(SysEx.MISUSE_BKPT()); } Debug.Assert((table.TabFlags & TF.Virtual) != 0); RC rc = RC.OK; Parse parse = new Parse(); //: _stackalloc(ctx, sizeof(Parse)); if (parse == null) { rc = RC.NOMEM; } else { parse.DeclareVTable = true; parse.Ctx = ctx; parse.QueryLoops = 1; string error = null; if (sqlite3RunParser(parse, createTableName, ref error) == RC.OK && parse.NewTable != null && !ctx.MallocFailed && parse.NewTable.Select == null && (parse.NewTable.TabFlags & TF.Virtual) == 0) { if (table.Cols.data == null) { table.Cols.data = parse.NewTable.Cols.data; table.Cols.length = parse.NewTable.Cols.length; parse.NewTable.Cols.length = 0; parse.NewTable.Cols.data = null; } ctx.VTableCtx.Table = null; } else { sqlite3Error(ctx, RC.ERROR, (error != null ? "%s" : null), error); C._tagfree(ctx, ref error); rc = RC.ERROR; } parse.DeclareVTable = false; if (parse.V != null) { parse.V.Finalize(); } Parse.DeleteTable(ctx, ref parse.NewTable); parse = null; //: C._stackfree(ctx, parse); } Debug.Assert(((int)rc & 0xff) == (int)rc); rc = SysEx.ApiExit(ctx, rc); MutexEx.Leave(ctx.Mutex); return(rc); }
public static RC Status(STATUS op, ref int current, ref int highwater, int resetFlag) { if (op < 0 || (int)op >= _stat.NowValue.Length) { return(SysEx.MISUSE_BKPT()); } current = _stat.NowValue[(int)op]; highwater = _stat.MaxValue[(int)op]; if (resetFlag != 0) { _stat.MaxValue[(int)op] = _stat.NowValue[(int)op]; } return(RC.OK); }
public static RC Finalize(Vdbe p) { if (p == null) { return(RC.OK); // IMPLEMENTATION-OF: R-57228-12904 Invoking sqlite3_finalize() on a NULL pointer is a harmless no-op. } Context ctx = p.Ctx; if (VdbeSafety(p)) { return(SysEx.MISUSE_BKPT()); } MutexEx.Enter(ctx.Mutex); RC rc = p.Finalize(); rc = SysEx.ApiExit(ctx, rc); DataEx.LeaveMutexAndCloseZombie(ctx); return(rc); }
public static RC LockAndPrepare(Context ctx, string sql, int bytes, bool isPrepareV2, Vdbe reprepare, ref Vdbe stmtOut, ref string tailOut) { if (!sqlite3SafetyCheckOk(ctx)) { stmtOut = null; tailOut = null; return(SysEx.MISUSE_BKPT()); } MutexEx.Enter(ctx.Mutex); Btree.EnterAll(ctx); RC rc = Prepare_(ctx, sql, bytes, isPrepareV2, reprepare, ref stmtOut, ref tailOut); if (rc == RC.SCHEMA) { stmtOut.Finalize(); rc = Prepare_(ctx, sql, bytes, isPrepareV2, reprepare, ref stmtOut, ref tailOut); } Btree.LeaveAll(ctx); MutexEx.Leave(ctx.Mutex); Debug.Assert(rc == RC.OK || stmtOut == null); return(rc); }
public static RC CreateModule(Context ctx, string name, ITableModule imodule, object aux, Action <object> destroy) { RC rc = RC.OK; MutexEx.Enter(ctx.Mutex); int nameLength = name.Length; if (ctx.Modules.Find(name, nameLength, (TableModule)null) != null) { rc = SysEx.MISUSE_BKPT(); } else { TableModule module = new TableModule(); //: _tagalloc(ctx, sizeof(TableModule) + nameLength + 1) if (module != null) { var nameCopy = name; module.Name = nameCopy; module.IModule = imodule; module.Aux = aux; module.Destroy = destroy; TableModule del = (TableModule)ctx.Modules.Insert(nameCopy, nameLength, module); Debug.Assert(del == null && del == module); if (del != null) { ctx.MallocFailed = true; C._tagfree(ctx, ref del); } } } rc = SysEx.ApiExit(ctx, rc); if (rc != RC.OK && destroy != null) { destroy(aux); } MutexEx.Leave(ctx.Mutex); return(rc); }
// Routines used to attach values to wildcards in a compiled SQL statement. static RC VdbeUnbind(Vdbe p, int i) { if (VdbeSafetyNotNull(p)) { return(SysEx.MISUSE_BKPT()); } MutexEx.Enter(p.Ctx.Mutex); if (p.Magic != VDBE_MAGIC_RUN || p.PC >= 0) { SysEx.Error(p.Ctx, RC.MISUSE, 0); MutexEx.Leave(p.Ctx.Mutex); SysEx.LOG(RC.MISUSE, "bind on a busy prepared statement: [%s]", p.Sql); return(SysEx.MISUSE_BKPT()); } if (i < 1 || i > p.Vars) { SysEx.Error(p.Ctx, RC.RANGE, 0); MutexEx.Leave(p.Ctx.Mutex); return(RC.RANGE); } i--; Mem var = p.Vars[i]; MemRelease(var); var.Flags = MEM.Null; SysEx.Error(p.Ctx, RC.OK, 0); // If the bit corresponding to this variable in Vdbe.expmask is set, then binding a new value to this variable invalidates the current query plan. // // IMPLEMENTATION-OF: R-48440-37595 If the specific value bound to host parameter in the WHERE clause might influence the choice of query plan // for a statement, then the statement will be automatically recompiled, as if there had been a schema change, on the first sqlite3_step() call // following any change to the bindings of that parameter. if (p.IsPrepareV2 && ((i < 32 && p.Expmask != 0 & ((uint)1 << i) != 0) || p.Expmask == 0xffffffff)) { p.Expired = true; } return(RC.OK); }
public static RC Exec(Context ctx, string sql, Func <object, int, string[], string[], bool> callback, object arg, ref string errmsg) { RC rc = RC.OK; // Return code if (!SafetyCheckOk(ctx)) { return(SysEx.MISUSE_BKPT()); } if (sql == null) { sql = string.Empty; } MutexEx.Enter(ctx.Mutex); Error(ctx, RC.OK, null); Vdbe stmt = null; // The current SQL statement int retrys = 0; // Number of retry attempts string[] colsNames = null; // Names of result columns while ((rc == RC.OK || (rc == RC.SCHEMA && (++retrys) < 2)) && sql.Length > 0) { stmt = null; string leftover = null; // Tail of unprocessed SQL rc = Prepare.Prepare_(ctx, sql, -1, ref stmt, ref leftover); Debug.Assert(rc == RC.OK || stmt == null); if (rc != RC.OK) { continue; } if (stmt == null) { sql = leftover; // this happens for a comment or white-space continue; } bool callbackIsInit = false; // True if callback data is initialized int cols = Vdbe.Column_Count(stmt); while (true) { rc = stmt.Step(); // Invoke the callback function if required int i; if (callback != null && (rc == RC.ROW || (rc == RC.DONE && !callbackIsInit && (ctx.Flags & Context.FLAG.NullCallback) != 0))) { if (!callbackIsInit) { colsNames = new string[cols]; if (colsNames == null) { goto exec_out; } for (i = 0; i < cols; i++) { colsNames[i] = Vdbe.Column_Name(stmt, i); // Vdbe::SetColName() installs column names as UTF8 strings so there is no way for sqlite3_column_name() to fail. Debug.Assert(colsNames[i] != null); } callbackIsInit = true; } string[] colsValues = null; if (rc == RC.ROW) { colsValues = new string[cols]; for (i = 0; i < cols; i++) { colsValues[i] = Vdbe.Column_Text(stmt, i); if (colsValues[i] == null && Vdbe.Column_Type(stmt, i) != TYPE.NULL) { ctx.MallocFailed = true; goto exec_out; } } } if (callback(arg, cols, colsValues, colsNames)) { rc = RC.ABORT; stmt.Finalize(); stmt = null; Error(ctx, RC.ABORT, null); goto exec_out; } } if (rc != RC.ROW) { rc = stmt.Finalize(); stmt = null; if (rc != RC.SCHEMA) { retrys = 0; if ((sql = leftover) != string.Empty) { int idx = 0; while (idx < sql.Length && char.IsWhiteSpace(sql[idx])) { idx++; } if (idx != 0) { sql = (idx < sql.Length ? sql.Substring(idx) : string.Empty); } } } break; } } C._tagfree(ctx, ref colsNames); colsNames = null; } exec_out: if (stmt != null) { stmt.Finalize(); } C._tagfree(ctx, ref colsNames); rc = ApiExit(ctx, rc); if (rc != RC.OK && C._ALWAYS(rc == ErrCode(ctx)) && errmsg != null) { errmsg = ErrMsg(ctx); } else if (errmsg != null) { errmsg = null; } Debug.Assert((rc & (RC)ctx.ErrMask) == rc); MutexEx.Leave(ctx.Mutex); return(rc); }
public static RC Config(CONFIG op, params object[] args) { // sqlite3_config() shall return SQLITE_MISUSE if it is invoked while the SQLite library is in use. if (_GlobalStatics.IsInit) { return(SysEx.MISUSE_BKPT()); } RC rc = RC.OK; switch (op) { #if THREADSAFE // Mutex configuration options are only available in a threadsafe compile. case CONFIG.SINGLETHREAD: { // Disable all mutexing _GlobalStatics.CoreMutex = false; _GlobalStatics.FullMutex = false; break; } case CONFIG.MULTITHREAD: { // Disable mutexing of database connections, Enable mutexing of core data structures _GlobalStatics.CoreMutex = true; _GlobalStatics.FullMutex = false; break; } case CONFIG.SERIALIZED: { // Enable all mutexing _GlobalStatics.CoreMutex = true; _GlobalStatics.FullMutex = true; break; } case CONFIG.MUTEX: { // Specify an alternative mutex implementation //_GlobalStatics.Mutex = (sqlite3_mutex_methods)args[0]; break; } case CONFIG.GETMUTEX: { // Retrieve the current mutex implementation //args[0] = _GlobalStatics.Mutex; break; } #endif case CONFIG.MALLOC: { // Specify an alternative malloc implementation //_GlobalStatics.m = *va_arg(args, sqlite3_mem_methods*); break; } case CONFIG.GETMALLOC: { // Retrieve the current malloc() implementation //if (_GlobalStatics.m.xMalloc==0) sqlite3MemSetDefault(); //args[0]= _GlobalStatics.m; break; } case CONFIG.MEMSTATUS: { // Enable or disable the malloc status collection _GlobalStatics.Memstat = (bool)args[0]; break; } case CONFIG.SCRATCH: { // Designate a buffer for scratch memory space _GlobalStatics.Scratch = (byte[][])args[0]; _GlobalStatics.ScratchSize = (int)args[1]; _GlobalStatics.Scratchs = (int)args[2]; break; } #if ENABLE_MEMSYS3 || ENABLE_MEMSYS5 case CONFIG_HEAP: { // Designate a buffer for heap memory space _GlobalStatics.Heap.data = va_arg(args, void *); _GlobalStatics.Heap.length = va_arg(args, int); _GlobalStatics.MinReq = va_arg(ap, int); if (_GlobalStatics.MinReq < 1) { _GlobalStatics.MinReq = 1; } else if (SysEx_GlobalStatics.MinReq > (1 << 12)) // cap min request size at 2^12 { _GlobalStatics.MinReq = (1 << 12); } if (!_GlobalStatics.Heap.data) { // If the heap pointer is NULL, then restore the malloc implementation back to NULL pointers too. This will cause the malloc to go back to its default implementation when sqlite3_initialize() is run. memset(&_GlobalStatics.m, 0, sizeof(_GlobalStatics.m)); } else // The heap pointer is not NULL, then install one of the mem5.c/mem3.c methods. If neither ENABLE_MEMSYS3 nor ENABLE_MEMSYS5 is defined, return an error. #if ENABLE_MEMSYS3 { _GlobalStatics.m = sqlite3MemGetMemsys3(); } #endif #if ENABLE_MEMSYS5 { _GlobalStatics.m = sqlite3MemGetMemsys5(); } #endif { break; } } #endif case CONFIG.LOOKASIDE: { _GlobalStatics.LookasideSize = (int)args[0]; _GlobalStatics.Lookasides = (int)args[1]; break; } case CONFIG.LOG: { // Record a pointer to the logger function and its first argument. The default is NULL. Logging is disabled if the function pointer is NULL. // MSVC is picky about pulling func ptrs from va lists. // http://support.microsoft.com/kb/47961 _GlobalStatics.Log = (Action <object, int, string>)args[0]; _GlobalStatics.LogArg = (object)args[1]; break; } case CONFIG.URI: { _GlobalStatics.OpenUri = (bool)args[0]; break; } #if ENABLE_SQLLOG case CONFIG.SQLLOG: { _GlobalStatics.Sqllog = (Action <object, TagBase, int, string>)args[0];; _GlobalStatics.SqllogArg = (object)args[1]; break; } #endif default: { rc = RC.ERROR; break; } } return(rc); }
public RC Step2() { if (Magic != VDBE_MAGIC_RUN) { // We used to require that sqlite3_reset() be called before retrying sqlite3_step() after any error or after SQLITE_DONE. But beginning // with version 3.7.0, we changed this so that sqlite3_reset() would be called automatically instead of throwing the SQLITE_MISUSE error. // This "automatic-reset" change is not technically an incompatibility, since any application that receives an SQLITE_MISUSE is broken by // definition. // // Nevertheless, some published applications that were originally written for version 3.6.23 or earlier do in fact depend on SQLITE_MISUSE // returns, and those were broken by the automatic-reset change. As a work-around, the SQLITE_OMIT_AUTORESET compile-time restores the // legacy behavior of returning SQLITE_MISUSE for cases where the previous sqlite3_step() returned something other than a SQLITE_LOCKED // or SQLITE_BUSY error. #if OMIT_AUTORESET if (RC == RC.BUSY || RC == RC.LOCKED) { Reset(this); } else { return(SysEx.MISUSE_BKPT()); } #else Reset(this); #endif } // Check that malloc() has not failed. If it has, return early. RC rc; Context ctx = Ctx; if (ctx.MallocFailed) { RC_ = RC.NOMEM; return(RC.NOMEM); } if (PC <= 0 && Expired) { RC_ = RC.SCHEMA; rc = RC.ERROR; goto end_of_step; } if (PC < 0) { // If there are no other statements currently running, then reset the interrupt flag. This prevents a call to sqlite3_interrupt // from interrupting a statement that has not yet started. if (ctx.ActiveVdbeCnt == 0) { ctx.u1.IsInterrupted = false; } Debug.Assert(ctx.WriteVdbeCnt > 0 || ctx.AutoCommit == 0 || ctx.DeferredCons == 0); #if !OMIT_TRACE if (ctx.Profile != null && !ctx.Init.Busy) { ctx.Vfs.CurrentTimeInt64(ref StartTime); } #endif ctx.ActiveVdbeCnt++; if (!ReadOnly) { ctx.WriteVdbeCnt++; } PC = 0; } #if !OMIT_EXPLAIN if (_explain) { rc = List(); } else #endif { ctx.VdbeExecCnt++; rc = Exec(); ctx.VdbeExecCnt--; } #if !OMIT_TRACE // Invoke the profile callback if there is one if (rc != RC.ROW && ctx.Profile != null && !ctx.Init.Busy && Sql != null) { long now = 0; ctx.Vfs.CurrentTimeInt64(ref now); ctx.Profile(ctx.ProfileArg, Sql, (now - StartTime) * 1000000); } #endif if (rc == RC.DONE) { Debug.Assert(RC_ == RC.OK); RC_ = DoWalCallbacks(ctx); if (RC_ != RC.OK) { rc = RC.ERROR; } } ctx.ErrCode = rc; if (SysEx.ApiExit(Ctx, RC_) == RC.NOMEM) { RC_ = RC.NOMEM; } end_of_step: // At this point local variable rc holds the value that should be returned if this statement was compiled using the legacy // sqlite3_prepare() interface. According to the docs, this can only be one of the values in the first assert() below. Variable p->rc // contains the value that would be returned if sqlite3_finalize() were called on statement p. Debug.Assert(rc == RC.ROW || rc == RC.DONE || rc == RC.ERROR || rc == RC.BUSY || rc == RC.MISUSE); Debug.Assert(RC_ != RC.ROW && RC_ != RC.DONE); // If this statement was prepared using sqlite3_prepare_v2(), and an error has occurred, then return the error code in p->rc to the // caller. Set the error code in the database handle to the same value. if (IsPrepareV2 && rc != RC.ROW && rc != RC.DONE) { rc = TransferError(); } return(rc & (RC)ctx.ErrMask); }