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