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