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 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); }
static RC BindText(Vdbe p, int i, string z, int n, Action <string> del, TEXTENCODE encoding) { RC rc = VdbeUnbind(p, i); if (rc == RC.OK) { if (z != null) { Mem var = p.Vars[i - 1]; rc = MemSetStr(var, z, n, encoding, del); if (rc == RC.OK && encoding != 0) { rc = ChangeEncoding(var, E.CTXENCODE(p.Ctx)); } SysEx.Error(p.Ctx, rc, 0); rc = SysEx.ApiExit(p.Ctx, rc); } MutexEx.Leave(p.Ctx.Mutex); } else if (del != null) { del(z); } 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 void Result_ErrorCode(FuncContext fctx, RC errCode) { fctx.IsError = errCode; if ((fctx.S.Flags & MEM.Null) != 0) { SetResultStrOrError(fctx, SysEx.ErrStr(errCode), -1, TEXTENCODE.UTF8, DESTRUCTOR_STATIC); } }
static bool VdbeSafetyNotNull(Vdbe p) { if (p == null) { SysEx.LOG(RC.MISUSE, "API called with NULL prepared statement"); return(true); } return(VdbeSafety(p)); }
static bool VdbeSafety(Vdbe p) { if (p.Ctx == null) { SysEx.LOG(RC.MISUSE, "API called with finalized prepared statement"); return(true); } return(false); }
static void ColumnMallocFailure(Vdbe p) { // If malloc() failed during an encoding conversion within an sqlite3_column_XXX API, then set the return code of the statement to // RC_NOMEM. The next call to _step() (if any) will return RC_ERROR and _finalize() will return NOMEM. if (p != null) { p.RC_ = SysEx.ApiExit(p.Ctx, p.RC_); MutexEx.Leave(p.Ctx.Mutex); } }
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 bool Complete16(string sql) { RC rc = RC.NOMEM; #if !OMIT_AUTOINIT rc = SysEx.Initialize(); if (rc != RC.OK) { return(rc); } #endif Mem val = sqlite3ValueNew(0); sqlite3ValueSetStr(val, -1, sql, TEXTENCODE.UTF16NATIVE, DESTRUCTOR.STATIC); string sql8 = sqlite3ValueText(val, TEXTENCODE.UTF8); rc = (sql8 != null ? (RC)Complete(sql8) : RC.NOMEM);
public static RC Reset(Vdbe p) { if (p == null) { return(RC.OK); } #if THREADSAFE MutexEx mutex = p.Ctx.Mutex; #endif MutexEx.Enter(mutex); RC rc = p.Reset(); p.Rewind(); Debug.Assert((rc & (RC)p.Ctx.ErrMask) == rc); rc = SysEx.ApiExit(p.Ctx, rc); MutexEx.Leave(mutex); return(rc); }
static void CorruptSchema(InitData data, string obj, string extra) { Context ctx = data.Ctx; if (!ctx.MallocFailed && (ctx.Flags & Context.FLAG.RecoveryMode) == 0) { if (obj == null) { obj = "?"; } C._setstring(ref data.ErrMsg, ctx, "malformed database schema (%s)", obj); if (extra == null) { data.ErrMsg = C._mtagappendf(ctx, data.ErrMsg, "%s - %s", data.ErrMsg, extra); } data.RC = (ctx.MallocFailed ? RC.NOMEM : SysEx.CORRUPT_BKPT()); } }
static RC walIndexPage(Wal wal, Pid id, ref object idOut) { // Enlarge the pWal->apWiData[] array if required if (wal.WiData.Length <= id) { var bytes = (int)(1 * (id + 1)); var newWiData = SysEx.Realloc <object>(1, wal.WiData, bytes); if (newWiData != null) { idOut = null; return(RC.NOMEM); } Array.Clear(newWiData, wal.WiData.Length, (int)(id + 1 - wal.WiData.Length)); wal.WiData = newWiData; } // Request a pointer to the required page from the VFS var rc = RC.OK; if (wal.WiData[id] == null) { if (wal.ExclusiveMode_ == Wal.MODE.HEAPMEMORY) { wal.WiData[id] = C._alloc <Pid>(4, WALINDEX_PGSZ, true); if (wal.WiData[id] != null) { rc = RC.NOMEM; } } else { rc = wal.DBFile.ShmMap((int)id, WALINDEX_PGSZ, (int)wal.WriteLock, wal.WiData, (int)id); if (rc == RC.READONLY) { wal.ReadOnly_ |= READONLY.SHM_RDONLY; rc = RC.OK; } } } idOut = wal.WiData[id]; Debug.Assert(id == 0 || idOut != null || rc != RC.OK); return(rc); }
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); }
static Mem ColumnMem(Vdbe p, int i) { Mem r; if (p != null && p.ResultSet != null && i < p.ResColumns && i >= 0) { MutexEx.Enter(p.Ctx.Mutex); r = p.ResultSet[i]; } else { if (p != null && C._ALWAYS(p.Ctx != null)) { MutexEx.Enter(p.Ctx.Mutex); SysEx.Error(p.Ctx, RC.RANGE, 0); } r = _nullMem; } return(r); }
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 RC Step() { RC rc = RC.OK; // Result from sqlite3Step() RC rc2 = RC.OK; // Result from sqlite3Reprepare() int cnt = 0; // Counter to prevent infinite loop of reprepares Context ctx = Ctx; // The database connection MutexEx.Enter(ctx.Mutex); DoingRerun = false; while ((rc = Step2()) == RC.SCHEMA && cnt++ < MAX_SCHEMA_RETRY && (rc2 = rc = Reprepare()) == RC.OK) { Reset(this); DoingRerun = true; Debug.Assert(!Expired); } if (rc2 != RC.OK && C._ALWAYS(IsPrepareV2) && C._ALWAYS(ctx.Err != null)) { // This case occurs after failing to recompile an sql statement. The error message from the SQL compiler has already been loaded // into the database handle. This block copies the error message from the database handle into the statement and sets the statement // program counter to 0 to ensure that when the statement is finalized or reset the parser error message is available via // sqlite3_errmsg() and sqlite3_errcode(). string err = Value_Text(ctx.Err); C._tagfree(ctx, ref ErrMsg); if (!ctx.MallocFailed) { ErrMsg = err; RC_ = rc2; } else { ErrMsg = null; RC_ = rc = RC.NOMEM; } } rc = SysEx.ApiExit(ctx, rc); MutexEx.Leave(ctx.Mutex); return(rc); }
public static RC Prepare_(Context ctx, string sql, int bytes, bool isPrepareV2, Vdbe reprepare, ref Vdbe stmtOut, ref string tailOut) { stmtOut = null; tailOut = null; string errMsg = null; // Error message RC rc = RC.OK; int i; // Allocate the parsing context Parse parse = new Parse(); // Parsing context if (parse == null) { rc = RC.NOMEM; goto end_prepare; } parse.Reprepare = reprepare; parse.LastToken.data = null; //: C#? Debug.Assert(tailOut == null); Debug.Assert(!ctx.MallocFailed); Debug.Assert(MutexEx.Held(ctx.Mutex)); // Check to verify that it is possible to get a read lock on all database schemas. The inability to get a read lock indicates that // some other database connection is holding a write-lock, which in turn means that the other connection has made uncommitted changes // to the schema. // // Were we to proceed and prepare the statement against the uncommitted schema changes and if those schema changes are subsequently rolled // back and different changes are made in their place, then when this prepared statement goes to run the schema cookie would fail to detect // the schema change. Disaster would follow. // // This thread is currently holding mutexes on all Btrees (because of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it // is not possible for another thread to start a new schema change while this routine is running. Hence, we do not need to hold // locks on the schema, we just need to make sure nobody else is holding them. // // Note that setting READ_UNCOMMITTED overrides most lock detection, but it does *not* override schema lock detection, so this all still // works even if READ_UNCOMMITTED is set. for (i = 0; i < ctx.DBs.length; i++) { Btree bt = ctx.DBs[i].Bt; if (bt != null) { Debug.Assert(bt.HoldsMutex()); rc = bt.SchemaLocked(); if (rc != 0) { string dbName = ctx.DBs[i].Name; sqlite3Error(ctx, rc, "database schema is locked: %s", dbName); C.ASSERTCOVERAGE((ctx.Flags & Context.FLAG.ReadUncommitted) != 0); goto end_prepare; } } } VTable.UnlockList(ctx); parse.Ctx = ctx; parse.QueryLoops = (double)1; if (bytes >= 0 && (bytes == 0 || sql[bytes - 1] != 0)) { int maxLen = ctx.aLimit[SQLITE_LIMIT_SQL_LENGTH]; C.ASSERTCOVERAGE(bytes == maxLen); C.ASSERTCOVERAGE(bytes == maxLen + 1); if (bytes > maxLen) { sqlite3Error(ctx, RC.TOOBIG, "statement too long"); rc = SysEx.ApiExit(ctx, RC.TOOBIG); goto end_prepare; } string sqlCopy = sql.Substring(0, bytes); if (sqlCopy != null) { parse.RunParser(sqlCopy, ref errMsg); C._tagfree(ctx, ref sqlCopy); parse.Tail = null; //: &sql[parse->Tail - sqlCopy]; } else { parse.Tail = null; //: &sql[bytes]; } } else { parse.RunParser(sql, ref errMsg); } Debug.Assert((int)parse.QueryLoops == 1); if (ctx.MallocFailed) { parse.RC = RC.NOMEM; } if (parse.RC == RC.DONE) { parse.RC = RC.OK; } if (parse.CheckSchema != 0) { SchemaIsValid(parse); } if (ctx.MallocFailed) { parse.RC = RC.NOMEM; } tailOut = (parse.Tail == null ? null : parse.Tail.ToString()); rc = parse.RC; Vdbe v = parse.V; #if !OMIT_EXPLAIN if (rc == RC.OK && parse.V != null && parse.Explain != 0) { int first, max; if (parse.Explain == 2) { v.SetNumCols(4); first = 8; max = 12; } else { v.SetNumCols(8); first = 0; max = 8; } for (i = first; i < max; i++) { v.SetColName(i - first, COLNAME_NAME, _colName[i], C.DESTRUCTOR_STATIC); } } #endif Debug.Assert(!ctx.Init.Busy || !isPrepareV2); if (!ctx.Init.Busy) { Vdbe.SetSql(v, sql, (int)(sql.Length - (parse.Tail == null ? 0 : parse.Tail.Length)), isPrepareV2); } if (v != null && (rc != RC.OK || ctx.MallocFailed)) { v.Finalize(); Debug.Assert(stmtOut == null); } else { stmtOut = v; } if (errMsg != null) { sqlite3Error(ctx, rc, "%s", errMsg); C._tagfree(ctx, ref errMsg); } else { sqlite3Error(ctx, rc, null); } // Delete any TriggerPrg structures allocated while parsing this statement. while (parse.TriggerPrg != null) { TriggerPrg t = parse.TriggerPrg; parse.TriggerPrg = t.Next; C._tagfree(ctx, ref t); } end_prepare: //sqlite3StackFree( db, pParse ); rc = SysEx.ApiExit(ctx, rc); Debug.Assert((RC)((int)rc & ctx.ErrMask) == rc); return(rc); }
public RC Fetch(Pid id, bool createFlag, out PgHdr pageOut) { Debug.Assert(id > 0); // If the pluggable cache (sqlite3_pcache*) has not been allocated, allocate it now. if (Cache == null && createFlag) { var p = _pcache.Create(SizePage, SizeExtra + 0, Purgeable); p.Cachesize(get_CacheSize()); Cache = p; } ICachePage page = null; var create = (createFlag ? 1 : 0) * (1 + ((!Purgeable || Dirty == null) ? 1 : 0)); if (Cache != null) { page = Cache.Fetch(id, create > 0); } if (page == null && create == 1) { // Find a dirty page to write-out and recycle. First try to find a page that does not require a journal-sync (one with PGHDR_NEED_SYNC // cleared), but if that is not possible settle for any other unreferenced dirty page. #if EXPENSIVE_ASSERT CheckSynced(this); #endif PgHdr pg; for (pg = Synced; pg != null && (pg.Refs != 0 || (pg.Flags & PgHdr.PGHDR.NEED_SYNC) != 0); pg = pg.DirtyPrev) { ; } Synced = pg; if (pg == null) { for (pg = DirtyTail; pg != null && pg.Refs != 0; pg = pg.DirtyPrev) { ; } } if (pg != null) { #if LOG_CACHE_SPILL SysEx.Log(RC.FULL, "spill page %d making room for %d - cache used: %d/%d", pg.ID, id, _pcache->Pagecount(Cache), NumberOfCachePages(this)); #endif var rc = Stress(StressArg, pg); if (rc != RC.OK && rc != RC.BUSY) { pageOut = null; return(rc); } } page = Cache.Fetch(id, true); } PgHdr pgHdr = null; if (page != null) { //pgHdr = page.Extra; if (page.Data == null) { //page.Page = page; page.Data = C._alloc(SizePage); //page.Extra = this; page.Cache = this; page.ID = id; } Debug.Assert(page.Cache == Cache); Debug.Assert(page.ID == id); //Debug.Assert(page.Data == page.Buffer); //Debug.Assert(page.Extra == this); if (page.Refs == 0) { Refs++; } page.Refs++; if (id == 1) { Page1 = pgHdr; } } pageOut = pgHdr; return(pgHdr == null && create != 0 ? RC.NOMEM : RC.OK); }
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); }
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 int RunParser(string sql, ref string errMsg) { Debug.Assert(errMsg != null); Debug.Assert(NewTable == null); Debug.Assert(NewTrigger == null); Debug.Assert(VarsSeen == 0); Debug.Assert(Vars.length == 0); Debug.Assert(Vars.data == null); Context ctx = Ctx; // The database connection int maxSqlLength = ctx.Limits[(int)LIMIT.SQL_LENGTH]; // Max length of an SQL string if (ctx.ActiveVdbeCnt == 0) { ctx.u1.IsInterrupted = false; } RC = RC.OK; Tail = new StringBuilder(sql); yyParser engine = Parser_Alloc(); // The LEMON-generated LALR(1) parser if (engine == null) { ctx.MallocFailed = true; return((int)RC.NOMEM); } bool enableLookaside = ctx.Lookaside.Enabled; // Saved value of db->lookaside.bEnabled if (ctx.Lookaside.Start != 0) { ctx.Lookaside.Enabled = true; } int errs = 0; // Number of errors encountered TK tokenType = 0; // type of the next token TK lastTokenParsed = 0; // type of the previous token int i = 0; while (/* !ctx.MallocFailed && */ i < sql.Length) { Debug.Assert(i >= 0); LastToken.data = sql.Substring(i); LastToken.length = (uint)GetToken(sql, i, ref tokenType); i += (int)LastToken.length; if (i > maxSqlLength) { RC = RC.TOOBIG; break; } switch (tokenType) { case TK.SPACE: { if (ctx.u1.IsInterrupted) { ErrorMsg("interrupt"); RC = RC.INTERRUPT; goto abort_parse; } break; } case TK.ILLEGAL: { C._tagfree(ctx, ref errMsg); errMsg = SysEx.Mprintf(ctx, "unrecognized token: \"%T\"", (object)LastToken); errs++; goto abort_parse; } case TK.SEMI: { //Tail = new StringBuilder(sql.Substring(i, sql.Length - i)); goto default; } default: { Parser(engine, tokenType, LastToken, this); lastTokenParsed = tokenType; if (RC != RC.OK) { goto abort_parse; } break; } } } abort_parse: Tail = new StringBuilder(sql.Length <= i ? string.Empty : sql.Substring(i, sql.Length - i)); if (sql.Length >= i && errs == 0 && RC == RC.OK) { if (lastTokenParsed != TK.SEMI) { Parser(engine, TK.SEMI, LastToken, this); } Parser(engine, 0, LastToken, this); } #if YYTRACKMAXSTACKDEPTH sqlite3StatusSet(SQLITE_STATUS_PARSER_STACK, sqlite3ParserStackPeak(engine)); #endif Parser_Free(engine, null); ctx.Lookaside.Enabled = enableLookaside; //if (ctx.MallocFailed) // RC = RC.NOMEM; if (RC != RC.OK && RC != RC.DONE && string.IsNullOrEmpty(ErrMsg)) { SetString(ref ErrMsg, ctx, ErrStr(RC)); } if (ErrMsg != null) { errMsg = ErrMsg; SysEx.LOG(RC, "%s", errMsg); ErrMsg = string.Empty; errs++; } if (V != null && Errs > 0 && Nested == 0) { Vdbe.Delete(ref V); V = null; } #if !OMIT_SHARED_CACHE if (Nested == 0) { C._tagfree(ctx, ref TableLocks.data); TableLocks.data = null; TableLocks.length = 0; } #endif #if !OMIT_VIRTUALTABLE VTableLocks.data = null; #endif if (!E.INDECLARE_VTABLE(this)) { // If the pParse.declareVtab flag is set, do not delete any table structure built up in pParse.pNewTable. The calling code (see vtab.c) // will take responsibility for freeing the Table structure. DeleteTable(ctx, ref NewTable); } #if !OMIT_TRIGGER DeleteTrigger(ctx, ref NewTrigger); #endif //for (i = Vars.length - 1; i >= 0; i--) // C._tagfree(ctx, ref Vars.data[i]); C._tagfree(ctx, ref Vars.data); C._tagfree(ctx, ref Alias.data); while (Ainc != null) { AutoincInfo p = Ainc; Ainc = p.Next; C._tagfree(ctx, ref p); } while (ZombieTab != null) { Table p = ZombieTab; ZombieTab = p.NextZombie; DeleteTable(ctx, ref p); } if (errs > 0 && RC == RC.OK) { RC = RC.ERROR; } return(errs); }
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); }