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); }
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); }
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 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); }
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 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); }
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 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); }