コード例 #1
0
ファイル: Walker+Resolve.cs プロジェクト: BclEx/GpuStructs
        static void ResolveAlias(Parse parse, ExprList list, int colId, Expr expr, string type, int subqueries)
        {
            Debug.Assert(colId >= 0 && colId < list.Exprs);
            Expr orig = list.Ids[colId].Expr; // The iCol-th column of the result set
            Debug.Assert(orig != null);
            Debug.Assert((orig.Flags & EP.Resolved) != 0);
            Context ctx = parse.Ctx; // The database connection
            Expr dup = Expr.Dup(ctx, orig, 0); // Copy of pOrig
            if (orig.OP != TK.COLUMN && (type.Length == 0 || type[0] != 'G'))
            {
                IncrAggFunctionDepth(dup, subqueries);
                dup = Expr.PExpr_(parse, TK.AS, dup, null, null);
                if (dup == null) return;
                if (list.Ids[colId].Alias == 0)
                    list.Ids[colId].Alias = (ushort)(++parse.Alias.length);
                dup.TableId = list.Ids[colId].Alias;
            }
            if (expr.OP == TK.COLLATE)
                dup = Expr.AddCollateString(parse, dup, expr.u.Token);

            // Before calling sqlite3ExprDelete(), set the EP_Static flag. This prevents ExprDelete() from deleting the Expr structure itself,
            // allowing it to be repopulated by the memcpy() on the following line.
            E.ExprSetProperty(expr, EP.Static);
            Expr.Delete(ctx, ref expr);
            expr.memcpy(dup);
            if (!E.ExprHasProperty(expr, EP.IntValue) && expr.u.Token != null)
            {
                Debug.Assert((dup.Flags & (EP.Reduced | EP.TokenOnly)) == 0);
                dup.u.Token = expr.u.Token;
                dup.Flags2 |= EP2.MallocedToken;
            }
            C._tagfree(ctx, ref dup);
        }
コード例 #2
0
ファイル: Backup.cs プロジェクト: BclEx/GpuStructs
        public Backup Next;             // Next backup associated with source pager

        static Btree FindBtree(Context errorCtx, Context ctx, string dbName)
        {
            int i = Parse.FindDbName(ctx, dbName);
            if (i == 1)
            {
                RC rc = 0;
                Parse parse = new Parse();
                if (parse == null)
                {
                    Main.Error(errorCtx, RC.NOMEM, "out of memory");
                    rc = RC.NOMEM;
                }
                else
                {
                    parse.Ctx = ctx;
                    if (parse.OpenTempDatabase() != 0)
                    {
                        Main.Error(errorCtx, parse.RC, "%s", parse.ErrMsg);
                        rc = RC.ERROR;
                    }
                    C._tagfree(errorCtx, ref parse.ErrMsg);
                }
                if (rc != 0)
                    return null;
            }

            if (i < 0)
            {
                Main.Error(errorCtx, RC.ERROR, "unknown database %s", dbName);
                return null;
            }
            return ctx.DBs[i].Bt;
        }
コード例 #3
0
ファイル: Trigger.cs プロジェクト: BclEx/GpuStructs
 public static Trigger List(Parse parse, Table table)
 {
     Schema tmpSchema = parse.Ctx.DBs[1].Schema;
     Trigger list = null; // List of triggers to return
     if (parse.DisableTriggers)
         return null;
     if (tmpSchema != table.Schema)
     {
         Debug.Assert(Btree.SchemaMutexHeld(parse.Ctx, 0, tmpSchema));
         for (HashElem p = tmpSchema.TriggerHash.First; p != null; p = p.Next)
         {
             Trigger trig = (Trigger)p.Data;
             if (trig.TabSchema == table.Schema && string.Equals(trig.Table, table.Name, StringComparison.InvariantCultureIgnoreCase))
             {
                 trig.Next = (list != null ? list : table.Triggers);
                 list = trig;
             }
         }
     }
     return (list != null ? list : table.Triggers);
 }
コード例 #4
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 public static Select New(Parse parse, ExprList list, SrcList src, Expr where_, ExprList groupBy, Expr having, ExprList orderBy, SF selFlags, Expr limit, Expr offset)
 {
     Context ctx = parse.Ctx;
     Select newSelect = new Select();
     Debug.Assert(ctx.MallocFailed || offset == null || limit != null); // OFFSET implies LIMIT
     // Select standin;
     if (newSelect == null)
     {
         Debug.Assert(ctx.MallocFailed);
         //newSelect = standin;
         //_memset(newSelect, 0, sizeof(newSelect));
     }
     if (list == null)
         list = Expr.ListAppend(parse, null, Expr.Expr_(ctx, TK.ALL, null));
     newSelect.EList = list;
     if (src == null) src = new SrcList();
     newSelect.Src = src;
     newSelect.Where = where_;
     newSelect.GroupBy = groupBy;
     newSelect.Having = having;
     newSelect.OrderBy = orderBy;
     newSelect.SelFlags = selFlags;
     newSelect.OP = TK.SELECT;
     newSelect.Limit = limit;
     newSelect.Offset = offset;
     Debug.Assert(offset == null || limit != null);
     newSelect.AddrOpenEphms[0] = (OP) - 1;
     newSelect.AddrOpenEphms[1] = (OP) - 1;
     newSelect.AddrOpenEphms[2] = (OP) - 1;
     if (ctx.MallocFailed)
     {
         ClearSelect(ctx, newSelect);
         //if (newSelect != standin) C._tagfree(ctx, ref newSelect);
         newSelect = null;
     }
     else
         Debug.Assert(newSelect.Src != null || parse.Errs > 0);
     //Debug.Assert(newSelect != standin);
     return newSelect;
 }
コード例 #5
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
        static void GenerateSortTail(Parse parse, Select p, Vdbe v, int columns, SelectDest dest)
        {
            int addrBreak = v.MakeLabel(); // Jump here to exit loop
            int addrContinue = v.MakeLabel(); // Jump here for next cycle
            ExprList orderBy = p.OrderBy;
            SRT dest2 = dest.Dest;
            int parmId = dest.SDParmId;

            int tabId = orderBy.ECursor;
            int regRow = Expr.GetTempReg(parse);
            int pseudoTab = 0;
            int regRowid;
            if (dest2 == SRT.Output || dest2 == SRT.Coroutine)
            {
                pseudoTab = parse.Tabs++;
                v.AddOp3(OP.OpenPseudo, pseudoTab, regRow, columns);
                regRowid = 0;
            }
            else
                regRowid = Expr.GetTempReg(parse);
            int addr;
            if ((p.SelFlags & SF.UseSorter) != 0)
            {
                int regSortOut = ++parse.Mems;
                int ptab2 = parse.Tabs++;
                v.AddOp3(OP.OpenPseudo, ptab2, regSortOut, orderBy.Exprs + 2);
                addr = 1 + v.AddOp2(OP.SorterSort, tabId, addrBreak);
                CodeOffset(v, p, addrContinue);
                v.AddOp2(OP.SorterData, tabId, regSortOut);
                v.AddOp3(OP.Column, ptab2, orderBy.Exprs + 1, regRow);
                v.ChangeP5(Vdbe.OPFLAG.CLEARCACHE);
            }
            else
            {
                addr = 1 + v.AddOp2(OP.Sort, tabId, addrBreak);
                CodeOffset(v, p, addrContinue);
                v.AddOp3(OP.Column, tabId, orderBy.Exprs + 1, regRow);
            }
            switch (dest2)
            {
                case SRT.Table:
                case SRT.EphemTab:
                    {
                        C.ASSERTCOVERAGE(dest2 == SRT.Table);
                        C.ASSERTCOVERAGE(dest2 == SRT.EphemTab);
                        v.AddOp2(OP.NewRowid, parmId, regRowid);
                        v.AddOp3(OP.Insert, parmId, regRow, regRowid);
                        v.ChangeP5(Vdbe.OPFLAG.APPEND);
                        break;
                    }
#if !OMIT_SUBQUERY
                case SRT.Set:
                    {
                        Debug.Assert(columns == 1);
                        v.AddOp4(OP.MakeRecord, regRow, 1, regRowid, dest->AffSdst, 1);
                        Expr.CacheAffinityChange(parse, regRow, 1);
                        v.AddOp2(OP.IdxInsert, parmId, regRowid);
                        break;
                    }
                case SRT.Mem:
                    {
                        Debug.Assert(columns == 1);
                        Expr.CodeMove(parse, regRow, parmId, 1);
                        // The LIMIT clause will terminate the loop for us
                        break;
                    }
#endif
                default:
                    {
                        Debug.Assert(dest2 == SRT.Output || dest2 == SRT.Coroutine);
                        C.ASSERTCOVERAGE(dest2 == SRT.Output);
                        C.ASSERTCOVERAGE(dest2 == SRT.Coroutine);
                        for (int i = 0; i < columns; i++)
                        {
                            Debug.Assert(regRow != dest.SdstId + i);
                            v.AddOp3(OP.Column, pseudoTab, i, dest.SdstId + i);
                            if (i == 0)
                                v.ChangeP5(Vdbe.OPFLAG.CLEARCACHE);
                        }
                        if (dest2 == SRT.Output)
                        {
                            v.AddOp2(OP.ResultRow, dest.SdstId, columns);
                            Expr.CacheAffinityChange(parse, dest.SdstId, columns);
                        }
                        else
                            v.AddOp1(OP.Yield, dest.SDParmId);
                        break;
                    }
            }
            Expr.ReleaseTempReg(parse, regRow);
            Expr.ReleaseTempReg(parse, regRowid);

            // The bottom of the loop
            v.ResolveLabel(addrContinue);
            v.AddOp2(OP.Next, tabId, addr);
            v.ResolveLabel(addrBreak);
            if (dest2 == SRT.Output || dest2 == SRT.Coroutine)
                v.AddOp2(OP.Close, pseudoTab, 0);
        }
コード例 #6
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
        static void GenerateColumnNames(Parse parse, SrcList tabList, ExprList list)
        {
#if !OMIT_EXPLAIN
            // If this is an EXPLAIN, skip this step
            if (parse.Explain != 0)
                return;
#endif
            Vdbe v = parse.V;
            Context ctx = parse.Ctx;
            if (parse.ColNamesSet != 0 || C._NEVER(v == null) || ctx.MallocFailed) return;
            parse.ColNamesSet = 1;
            bool fullNames = ((ctx.Flags & Context.FLAG.FullColNames) != 0);
            bool shortNames = ((ctx.Flags & Context.FLAG.ShortColNames) != 0);
            v.SetNumCols(list.Exprs);
            for (int i = 0; i < list.Exprs; i++)
            {
                Expr p = list.Ids[i].Expr;
                if (C._NEVER(p == null)) continue;
                if (list.Ids[i].Name != null)
                {
                    string name = list.Ids[i].Name;
                    v.SetColName(i, COLNAME_NAME, name, C.DESTRUCTOR_TRANSIENT);
                }
                else if ((p.OP == TK.COLUMN || p.OP == TK.AGG_COLUMN) && tabList != null)
                {
                    int colId = p.ColumnIdx;
                    int j;
                    for (j = 0; C._ALWAYS(j < tabList.Srcs); j++)
                        if (tabList.Ids[j].Cursor == p.TableId) break;
                    Debug.Assert(j < tabList.Srcs);
                    Table table = tabList.Ids[j].Table;
                    if (colId < 0) colId = table.PKey;
                    Debug.Assert(colId == -1 || (colId >= 0 && colId < table.Cols.length));
                    string colName = (colId < 0 ? "rowid" : table.Cols[colId].Name);
                    if (!shortNames && !fullNames)
                        v.SetColName(i, COLNAME_NAME, list.Ids[i].Span, C.DESTRUCTOR_DYNAMIC);
                    else if (fullNames)
                    {
                        string name = C._mtagprintf(ctx, "%s.%s", table.Name, colName);
                        v.SetColName(i, COLNAME_NAME, name, C.DESTRUCTOR_DYNAMIC);
                    }
                    else
                        v.SetColName(i, COLNAME_NAME, colName, C.DESTRUCTOR_TRANSIENT);
                }
                else
                    v.SetColName(i, COLNAME_NAME, list.Ids[i].Span, C.DESTRUCTOR_TRANSIENT);
            }
            GenerateColumnTypes(parse, tabList, list);
        }
コード例 #7
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 static void CodeDistinct(Parse parse, int table, int addrRepeatId, int n, int memId)
 {
     Vdbe v = parse.V;
     int r1 = Expr.GetTempReg(parse);
     v.AddOp4Int(OP.Found, table, addrRepeatId, memId, n);
     v.AddOp3(OP.MakeRecord, memId, n, r1);
     v.AddOp2(OP.IdxInsert, table, r1);
     Expr.ReleaseTempReg(parse, r1);
 }
コード例 #8
0
ファイル: Walker+Resolve.cs プロジェクト: BclEx/GpuEx
        static WRC ResolveExprStep(Walker walker, Expr expr)
        {
            NameContext nc = walker.u.NC;

            Debug.Assert(nc != null);
            Parse parse = nc.Parse;

            Debug.Assert(parse == walker.Parse);

            if (E.ExprHasAnyProperty(expr, EP.Resolved))
            {
                return(WRC.Prune);
            }
            E.ExprSetProperty(expr, EP.Resolved);
#if !NDEBUG
            if (nc.SrcList != null && nc.SrcList.Allocs > 0)
            {
                SrcList srcList = nc.SrcList;
                for (int i = 0; i < nc.SrcList.Srcs; i++)
                {
                    Debug.Assert(srcList.Ids[i].Cursor >= 0 && srcList.Ids[i].Cursor < parse.Tabs);
                }
            }
#endif
            switch (expr.OP)
            {
#if ENABLE_UPDATE_DELETE_LIMIT && !OMIT_SUBQUERY
            // The special operator TK_ROW means use the rowid for the first column in the FROM clause.  This is used by the LIMIT and ORDER BY
            // clause processing on UPDATE and DELETE statements.
            case TK.ROW:
            {
                SrcList srcList = nc.SrcList;
                Debug.Assert(srcList != null && srcList.Srcs == 1);
                SrcList.SrcListItem item = srcList.Ids[0];
                expr.OP       = TK.COLUMN;
                expr.Table    = item.Table;
                expr.TableId  = item.Cursor;
                expr.ColumnId = -1;
                expr.Aff      = AFF.INTEGER;
                break;
            }
#endif

            case TK.ID:      // A lone identifier is the name of a column.
            {
                return(LookupName(parse, null, null, expr.u.Token, nc, expr));
            }

            case TK.DOT:     // A table name and column name: ID.ID Or a database, table and column: ID.ID.ID
            {
                string columnName;
                string tableName;
                string dbName;
                // if (srcList == nullptr) break;
                Expr right = expr.Right;
                if (right.OP == TK.ID)
                {
                    dbName     = null;
                    tableName  = expr.Left.u.Token;
                    columnName = right.u.Token;
                }
                else
                {
                    Debug.Assert(right.OP == TK.DOT);
                    dbName     = expr.Left.u.Token;
                    tableName  = right.Left.u.Token;
                    columnName = right.Right.u.Token;
                }
                return(LookupName(parse, dbName, tableName, columnName, nc, expr));
            }

            case TK.CONST_FUNC:
            case TK.FUNCTION:                                              // Resolve function names
            {
                ExprList   list         = expr.x.List;                     // The argument list
                int        n            = (list != null ? list.Exprs : 0); // Number of arguments
                bool       noSuchFunc   = false;                           // True if no such function exists
                bool       wrongNumArgs = false;                           // True if wrong number of arguments
                bool       isAgg        = false;                           // True if is an aggregate function
                TEXTENCODE encode       = E.CTXENCODE(parse.Ctx);          // The database encoding

                C.ASSERTCOVERAGE(expr.OP == TK.CONST_FUNC);
                Debug.Assert(!E.ExprHasProperty(expr, EP.xIsSelect));
                string  id       = expr.u.Token;                                                     // The function name.
                int     idLength = id.Length;                                                        // Number of characters in function name
                FuncDef def      = Callback.FindFunction(parse.Ctx, id, idLength, n, encode, false); // Information about the function
                if (def == null)
                {
                    def = Callback.FindFunction(parse.Ctx, id, idLength, -2, encode, false);
                    if (def == null)
                    {
                        noSuchFunc = true;
                    }
                    else
                    {
                        wrongNumArgs = true;
                    }
                }
                else
                {
                    isAgg = (def.Func == null);
                }
#if !OMIT_AUTHORIZATION
                if (def != null)
                {
                    ARC auth = Auth.Check(parse, AUTH.FUNCTION, null, def.Name, null);         // Authorization to use the function
                    if (auth != ARC.OK)
                    {
                        if (auth == ARC.DENY)
                        {
                            parse.ErrorMsg("not authorized to use function: %s", def.Name);
                            nc.Errs++;
                        }
                        expr.OP = TK.NULL;
                        return(WRC.Prune);
                    }
                }
#endif
                if (isAgg && (nc.NCFlags & NC.AllowAgg) == 0)
                {
                    parse.ErrorMsg("misuse of aggregate function %.*s()", idLength, id);
                    nc.Errs++;
                    isAgg = false;
                }
                else if (noSuchFunc && !ctx.Init.Busy)
                {
                    parse.ErrorMsg("no such function: %.*s", idLength, id);
                    nc.Errs++;
                }
                else if (wrongNumArgs)
                {
                    parse.ErrorMsg("wrong number of arguments to function %.*s()", idLength, id);
                    nc.Errs++;
                }
                if (isAgg)
                {
                    nc.NCFlags &= ~NC.AllowAgg;
                }
                walker.WalkExprList(list);
                if (isAgg)
                {
                    NameContext nc2 = nc;
                    expr.OP  = TK.AGG_FUNCTION;
                    expr.OP2 = 0;
                    while (nc2 != null && !expr.FunctionUsesThisSrc(nc2.SrcList))
                    {
                        expr.OP2++;
                        nc2 = nc2.Next;
                    }
                    if (nc2 != null)
                    {
                        nc2.NCFlags |= NC.HasAgg;
                    }
                    nc.NCFlags |= NC.AllowAgg;
                }
                // FIX ME:  Compute pExpr->affinity based on the expected return type of the function
                return(WRC.Prune);
            }

#if !OMIT_SUBQUERY
            case TK.SELECT:
            case TK.EXISTS:
            {
                C.ASSERTCOVERAGE(expr.OP == TK.EXISTS);
                goto case TK.IN;
            }
#endif
            case TK.IN:
            {
                C.ASSERTCOVERAGE(expr.OP == TK.IN);
                if (E.ExprHasProperty(expr, EP.xIsSelect))
                {
                    int refs = nc.Refs;
#if !OMIT_CHECK
                    if ((nc.NCFlags & NC.IsCheck) != 0)
                    {
                        parse.ErrorMsg("subqueries prohibited in CHECK constraints");
                    }
#endif
                    walker.WalkSelect(expr.x.Select);
                    Debug.Assert(nc.Refs >= refs);
                    if (refs != nc.Refs)
                    {
                        E.ExprSetProperty(expr, EP.VarSelect);
                    }
                }
                break;
            }

#if !OMIT_CHECK
            case TK.VARIABLE:
            {
                if ((nc.NCFlags & NC.IsCheck) != 0)
                {
                    parse.ErrorMsg("parameters prohibited in CHECK constraints");
                }

                break;
            }
#endif
            }
            return(parse.Errs != 0 || parse.Ctx.MallocFailed ? WRC.Abort : WRC.Continue);
        }
コード例 #9
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
        static void AddWhereTerm(Parse parse, SrcList src, int leftId, int colLeftId, int rightId, int colRightId, bool isOuterJoin, ref Expr where_)
        {
            Context ctx = parse.Ctx;
            Debug.Assert(leftId < rightId);
            Debug.Assert(src.Srcs > rightId);
            Debug.Assert(src.Ids[leftId].Table != null);
            Debug.Assert(src.Ids[rightId].Table != null);

            Expr e1 = Walker.CreateColumnExpr(ctx, src, leftId, colLeftId);
            Expr e2 = Walker.CreateColumnExpr(ctx, src, rightId, colRightId);

            Expr eq = Expr.PExpr_(parse, TK.EQ, e1, e2, null);
            if (eq != null && isOuterJoin)
            {
                E.ExprSetProperty(eq, EP.FromJoin);
                Debug.Assert(!E.ExprHasAnyProperty(eq, EP.TokenOnly | EP.Reduced));
                E.ExprSetIrreducible(eq);
                eq.RightJoinTable = (short)e2.TableId;
            }
            where_ = Expr.And(ctx, where_, eq);
        }
コード例 #10
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 static void PushOntoSorter(Parse parse, ExprList orderBy, Select select, int regData)
 {
     Vdbe v = parse.V;
     int exprs = orderBy.Exprs;
     int regBase = Expr.GetTempRange(parse, exprs + 2);
     int regRecord = Expr.GetTempReg(parse);
     Expr.CacheClear(parse);
     Expr.CodeExprList(parse, orderBy, regBase, false);
     v.AddOp2(OP.Sequence, orderBy.ECursor, regBase + exprs);
     Expr.CodeMove(parse, regData, regBase + exprs + 1, 1);
     v.AddOp3(OP.MakeRecord, regBase, exprs + 2, regRecord);
     v.AddOp2(OP.IdxInsert, orderBy.ECursor, regRecord);
     Expr.ReleaseTempReg(parse, regRecord);
     Expr.ReleaseTempRange(parse, regBase, exprs + 2);
     if (select.LimitId != 0)
     {
         int limitId = (select.OffsetId != 0 ? select.OffsetId + 1 : select.LimitId);
         int addr1 = v.AddOp1(OP.IfZero, limitId);
         v.AddOp2(OP.AddImm, limitId, -1);
         int addr2 = v.AddOp0(OP.Goto);
         v.JumpHere(addr1);
         v.AddOp1(OP.Last, orderBy.ECursor);
         v.AddOp1(OP.Delete, orderBy.ECursor);
         v.JumpHere(addr2);
     }
 }
コード例 #11
0
ファイル: Trigger.cs プロジェクト: BclEx/GpuStructs
        static int CodeTriggerProgram(Parse parse, TriggerStep stepList, OE orconf)
        {
            Vdbe v = parse.V;
            Context ctx = parse.Ctx;
            Debug.Assert(parse.TriggerTab != null && parse.Toplevel != null);
            Debug.Assert(stepList != null);
            Debug.Assert(v != null);
            for (TriggerStep step = stepList; step != null; step = step.Next)
            {
                // Figure out the ON CONFLICT policy that will be used for this step of the trigger program. If the statement that caused this trigger
                // to fire had an explicit ON CONFLICT, then use it. Otherwise, use the ON CONFLICT policy that was specified as part of the trigger
                // step statement. Example:
                //
                //   CREATE TRIGGER AFTER INSERT ON t1 BEGIN;
                //     INSERT OR REPLACE INTO t2 VALUES(new.a, new.b);
                //   END;
                //
                //   INSERT INTO t1 ... ;            -- insert into t2 uses REPLACE policy
                //   INSERT OR IGNORE INTO t1 ... ;  -- insert into t2 uses IGNORE policy
                parse.Orconf = (orconf == OE.Default ? step.Orconf : orconf);

                switch (step.OP)
                {
                    case TK.UPDATE:
                        Update(parse,
                          TargetSrcList(parse, step),
                          Expr.ListDup(ctx, step.ExprList, 0),
                          Expr.Dup(ctx, step.Where, 0),
                          parse.Orconf);
                        break;
                    case TK.INSERT:
                        Insert(parse,
                          TargetSrcList(parse, step),
                          Expr.ListDup(ctx, step.ExprList, 0),
                          Select.Dup(ctx, step.Select, 0),
                          Expr.IdListDup(ctx, step.IdList),
                          parse.Orconf);
                        break;
                    case TK.DELETE:
                        DeleteFrom(parse,
                          TargetSrcList(parse, step),
                          Expr.Dup(ctx, step.Where, 0));
                        break;
                    default:
                        Debug.Assert(step.OP == TK.SELECT);
                        SelectDest sDest = new SelectDest();
                        Select select = Expr.SelectDup(ctx, step.Select, 0);
                        Select.DestInit(sDest, SRT.Discard, 0);
                        Select.Select_(parse, select, ref sDest);
                        Select.Delete(ctx, ref select);
                        break;
                }
                if (step.OP != TK.SELECT)
                    v.AddOp0(OP.ResetCount);
            }
            return 0;
        }
コード例 #12
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 public static JT JoinType(Parse parse, Token a, Token b, int null_4) { return JoinType(parse, a, b, null); }
コード例 #13
0
        static TriggerPrg CodeRowTrigger(Parse parse, Trigger trigger, Table table, OE orconf)
        {
            Parse   top = E.Parse_Toplevel(parse);
            Context ctx = parse.Ctx; // Database handle

            Debug.Assert(trigger.Name == null || table == TableOfTrigger(trigger));
            Debug.Assert(top.V != null);

            // Allocate the TriggerPrg and SubProgram objects. To ensure that they are freed if an error occurs, link them into the Parse.pTriggerPrg
            // list of the top-level Parse object sooner rather than later.
            TriggerPrg prg = new TriggerPrg(); // Value to return //: _tagalloc(ctx, sizeof(TriggerPrg), true);

            if (prg == null)
            {
                return(null);
            }
            prg.Next       = top.TriggerPrg;
            top.TriggerPrg = prg;
            Vdbe.SubProgram program;                       // Sub-vdbe for trigger program
            prg.Program = program = new Vdbe.SubProgram(); // sqlite3DbMallocZero( db, sizeof( SubProgram ) );
            if (program == null)
            {
                return(null);
            }
            top.V.LinkSubProgram(program);
            prg.Trigger     = trigger;
            prg.Orconf      = orconf;
            prg.Colmasks[0] = 0xffffffff;
            prg.Colmasks[1] = 0xffffffff;

            // Allocate and populate a new Parse context to use for coding the trigger sub-program.
            Parse subParse = new Parse(); // Parse context for sub-vdbe //: _scratchalloc(ctx, sizeof(Parse), true);

            if (subParse == null)
            {
                return(null);
            }
            NameContext sNC = new NameContext(); // Name context for sub-vdbe

            sNC.Parse            = subParse;
            subParse.Ctx         = ctx;
            subParse.TriggerTab  = table;
            subParse.Toplevel    = top;
            subParse.AuthContext = trigger.Name;
            subParse.TriggerOp   = trigger.OP;
            subParse.QueryLoops  = parse.QueryLoops;

            int  endTrigger = 0;                  // Label to jump to if WHEN is false
            Vdbe v          = subParse.GetVdbe(); // Temporary VM

            if (v != null)
            {
#if DEBUG
                v.Comment("Start: %s.%s (%s %s%s%s ON %s)",
                          trigger.Name, OnErrorText(orconf),
                          (trigger.TRtm == TRIGGER.BEFORE ? "BEFORE" : "AFTER"),
                          (trigger.OP == TK.UPDATE ? "UPDATE" : string.Empty),
                          (trigger.OP == TK.INSERT ? "INSERT" : string.Empty),
                          (trigger.OP == TK.DELETE ? "DELETE" : string.Empty),
                          table.Name);
#endif
#if !OMIT_TRACE
                v.ChangeP4(-1, C._mtagprintf(ctx, "-- TRIGGER %s", trigger.Name), Vdbe.P4T.DYNAMIC);
#endif

                // If one was specified, code the WHEN clause. If it evaluates to false (or NULL) the sub-vdbe is immediately halted by jumping to the
                // OP_Halt inserted at the end of the program.
                if (trigger.When != null)
                {
                    Expr when = Expr.Dup(ctx, trigger.When, 0); // Duplicate of trigger WHEN expression
                    if (ResolveExprNames(sNC, ref when) == RC.OK && !ctx.MallocFailed)
                    {
                        endTrigger = v.MakeLabel();
                        subParse.IfFalse(when, endTrigger, RC_JUMPIFNULL);
                    }
                    Expr.Delete(ctx, ref when);
                }

                // Code the trigger program into the sub-vdbe.
                CodeTriggerProgram(subParse, trigger.StepList, orconf);

                // Insert an OP_Halt at the end of the sub-program.
                if (endTrigger != 0)
                {
                    v.ResolveLabel(endTrigger);
                }
                v.AddOp0(Core.OP.Halt);
#if DEBUG
                v.Comment("End: %s.%s", trigger.Name, OnErrorText(orconf));
#endif
                TransferParseError(parse, subParse);
                if (!ctx.MallocFailed)
                {
                    program.Ops.data = v.TakeOpArray(ref program.Ops.length, ref top.MaxArgs);
                }
                program.Mems    = subParse.Mems;
                program.Csrs    = subParse.Tabs;
                program.Token   = trigger.GetHashCode();
                prg.Colmasks[0] = subParse.Oldmask;
                prg.Colmasks[1] = subParse.Newmask;
                Vdbe.Delete(v);
            }

            Debug.Assert(subParse.Ainc == null && subParse.ZombieTab == null);
            Debug.Assert(subParse.TriggerPrg == null && subParse.MaxArgs == 0);
            C._scratchfree(ctx, ref subParse);

            return(prg);
        }
コード例 #14
0
        static int CodeTriggerProgram(Parse parse, TriggerStep stepList, OE orconf)
        {
            Vdbe    v   = parse.V;
            Context ctx = parse.Ctx;

            Debug.Assert(parse.TriggerTab != null && parse.Toplevel != null);
            Debug.Assert(stepList != null);
            Debug.Assert(v != null);
            for (TriggerStep step = stepList; step != null; step = step.Next)
            {
                // Figure out the ON CONFLICT policy that will be used for this step of the trigger program. If the statement that caused this trigger
                // to fire had an explicit ON CONFLICT, then use it. Otherwise, use the ON CONFLICT policy that was specified as part of the trigger
                // step statement. Example:
                //
                //   CREATE TRIGGER AFTER INSERT ON t1 BEGIN;
                //     INSERT OR REPLACE INTO t2 VALUES(new.a, new.b);
                //   END;
                //
                //   INSERT INTO t1 ... ;            -- insert into t2 uses REPLACE policy
                //   INSERT OR IGNORE INTO t1 ... ;  -- insert into t2 uses IGNORE policy
                parse.Orconf = (orconf == OE.Default ? step.Orconf : orconf);

                switch (step.OP)
                {
                case TK.UPDATE:
                    Update(parse,
                           TargetSrcList(parse, step),
                           Expr.ListDup(ctx, step.ExprList, 0),
                           Expr.Dup(ctx, step.Where, 0),
                           parse.Orconf);
                    break;

                case TK.INSERT:
                    Insert(parse,
                           TargetSrcList(parse, step),
                           Expr.ListDup(ctx, step.ExprList, 0),
                           Select.Dup(ctx, step.Select, 0),
                           Expr.IdListDup(ctx, step.IdList),
                           parse.Orconf);
                    break;

                case TK.DELETE:
                    DeleteFrom(parse,
                               TargetSrcList(parse, step),
                               Expr.Dup(ctx, step.Where, 0));
                    break;

                default:
                    Debug.Assert(step.OP == TK.SELECT);
                    SelectDest sDest  = new SelectDest();
                    Select     select = Expr.SelectDup(ctx, step.Select, 0);
                    Select.DestInit(sDest, SRT.Discard, 0);
                    Select.Select_(parse, select, ref sDest);
                    Select.Delete(ctx, ref select);
                    break;
                }
                if (step.OP != TK.SELECT)
                {
                    v.AddOp0(OP.ResetCount);
                }
            }
            return(0);
        }
コード例 #15
0
ファイル: Walker+Resolve.cs プロジェクト: BclEx/GpuEx
        static WRC ResolveSelectStep(Walker walker, Select p)
        {
            Debug.Assert(p != null);
            if ((p.SelFlags & SF.Resolved) != 0)
            {
                return(WRC.Prune);
            }
            NameContext outerNC = walker.u.NC;  // Context that contains this SELECT
            Parse       parse   = walker.Parse; // Parsing context
            Context     ctx     = parse.Ctx;    // Database connection

            // Normally sqlite3SelectExpand() will be called first and will have already expanded this SELECT.  However, if this is a subquery within
            // an expression, sqlite3ResolveExprNames() will be called without a prior call to sqlite3SelectExpand().  When that happens, let
            // sqlite3SelectPrep() do all of the processing for this SELECT. sqlite3SelectPrep() will invoke both sqlite3SelectExpand() and
            // this routine in the correct order.
            if ((p.SelFlags & SF.Expanded) == 0)
            {
                p.Prep(parse, outerNC);
                return(parse.Errs != 0 || ctx.MallocFailed ? WRC.Abort : WRC.Prune);
            }

            bool        isCompound = (p.Prior != null); // True if p is a compound select
            int         compounds  = 0;                 // Number of compound terms processed so far
            Select      leftmost   = p;                 // Left-most of SELECT of a compound
            int         i;
            NameContext nc;                             // Name context of this SELECT

            while (p != null)
            {
                Debug.Assert((p.SelFlags & SF.Expanded) != 0);
                Debug.Assert((p.SelFlags & SF.Resolved) == 0);
                p.SelFlags |= SF.Resolved;

                // Resolve the expressions in the LIMIT and OFFSET clauses. These are not allowed to refer to any names, so pass an empty NameContext.
                nc       = new NameContext(); //: _memset(&nc, 0, sizeof(nc));
                nc.Parse = parse;
                if (Walker.ResolveExprNames(nc, ref p.Limit) || Walker.ResolveExprNames(nc, ref p.Offset))
                {
                    return(WRC.Abort);
                }

                // Recursively resolve names in all subqueries
                SrcList.SrcListItem item;
                for (i = 0; i < p.Src.Srcs; i++)
                {
                    item = p.Src.Ids[i];
                    if (item.Select != null)
                    {
                        NameContext nc2;              // Used to iterate name contexts
                        int         refs         = 0; // Refcount for pOuterNC and outer contexts
                        string      savedContext = parse.AuthContext;

                        // Count the total number of references to pOuterNC and all of its parent contexts. After resolving references to expressions in
                        // pItem->pSelect, check if this value has changed. If so, then SELECT statement pItem->pSelect must be correlated. Set the
                        // pItem->isCorrelated flag if this is the case.
                        for (nc2 = outerNC; nc2 != null; nc2 = nc2.Next)
                        {
                            refs += nc2.Refs;
                        }

                        if (item.Name != null)
                        {
                            parse.AuthContext = item.Name;
                        }
                        Walker.ResolveSelectNames(parse, item.Select, outerNC);
                        parse.AuthContext = savedContext;
                        if (parse.Errs != 0 || ctx.MallocFailed)
                        {
                            return(WRC.Abort);
                        }

                        for (nc2 = outerNC; nc2 != null; nc2 = nc2.Next)
                        {
                            refs -= nc2.Refs;
                        }
                        Debug.Assert(!item.IsCorrelated && refs <= 0);
                        item.IsCorrelated = (refs != 0);
                    }
                }

                // Set up the local name-context to pass to sqlite3ResolveExprNames() to resolve the result-set expression list.
                nc.NCFlags = NC.AllowAgg;
                nc.SrcList = p.Src;
                nc.Next    = outerNC;

                // Resolve names in the result set.
                ExprList list = p.EList; // Result set expression list
                Debug.Assert(list != null);
                for (i = 0; i < list.Exprs; i++)
                {
                    Expr expr = list.Ids[i].Expr;
                    if (Walker.ResolveExprNames(nc, ref expr))
                    {
                        return(WRC.Abort);
                    }
                }

                // If there are no aggregate functions in the result-set, and no GROUP BY expression, do not allow aggregates in any of the other expressions.
                Debug.Assert((p.SelFlags & SF.Aggregate) == 0);
                ExprList groupBy = p.GroupBy; // The GROUP BY clause
                if (groupBy != null || (nc.NCFlags & NC.HasAgg) != 0)
                {
                    p.SelFlags |= SF.Aggregate;
                }
                else
                {
                    nc.NCFlags &= ~NC.AllowAgg;
                }

                // If a HAVING clause is present, then there must be a GROUP BY clause.
                if (p.Having != null && groupBy == null)
                {
                    parse.ErrorMsg("a GROUP BY clause is required before HAVING");
                    return(WRC.Abort);
                }

                // Add the expression list to the name-context before parsing the other expressions in the SELECT statement. This is so that
                // expressions in the WHERE clause (etc.) can refer to expressions by aliases in the result set.
                //
                // Minor point: If this is the case, then the expression will be re-evaluated for each reference to it.
                nc.EList = p.EList;
                if (Walker.ResolveExprNames(nc, ref p.Where) || Walker.ResolveExprNames(nc, ref p.Having))
                {
                    return(WRC.Abort);
                }

                // The ORDER BY and GROUP BY clauses may not refer to terms in outer queries
                nc.Next     = null;
                nc.NCFlags |= NC.AllowAgg;

                // Process the ORDER BY clause for singleton SELECT statements. The ORDER BY clause for compounds SELECT statements is handled
                // below, after all of the result-sets for all of the elements of the compound have been resolved.
                if (!isCompound && Walker.ResolveOrderGroupBy(nc, p, p.OrderBy, "ORDER"))
                {
                    return(WRC.Abort);
                }
                if (ctx.MallocFailed)
                {
                    return(WRC.Abort);
                }

                // Resolve the GROUP BY clause.  At the same time, make sure the GROUP BY clause does not contain aggregate functions.
                if (groupBy != null)
                {
                    if (Walker.ResolveOrderGroupBy(nc, p, groupBy, "GROUP") || ctx.MallocFailed)
                    {
                        return(WRC.Abort);
                    }
                    ExprList.ExprListItem item2;
                    for (i = 0; i < groupBy.Exprs; i++)
                    {
                        item2 = groupBy.Ids[i];
                        if (E.ExprHasProperty(item2.Expr, EP.Agg))
                        {
                            parse.ErrorMsg("aggregate functions are not allowed in the GROUP BY clause");
                            return(WRC.Abort);
                        }
                    }
                }

                // Advance to the next term of the compound
                p = p.Prior;
                compounds++;
            }

            // Resolve the ORDER BY on a compound SELECT after all terms of the compound have been resolved.
            return(isCompound && ResolveCompoundOrderBy(parse, leftmost) != 0 ? WRC.Abort : WRC.Prune);
        }
コード例 #16
0
ファイル: Walker+Resolve.cs プロジェクト: BclEx/GpuEx
        static int ResolveCompoundOrderBy(Parse parse, Select select)
        {
            ExprList orderBy = select.OrderBy;

            if (orderBy == null)
            {
                return(0);
            }
            Context ctx = parse.Ctx;

#if true || MAX_COLUMN
            if (orderBy.Exprs > ctx.Limits[(int)LIMIT.COLUMN])
            {
                parse.ErrorMsg("too many terms in ORDER BY clause");
                return(1);
            }
#endif
            int i;
            for (i = 0; i < orderBy.Exprs; i++)
            {
                orderBy.Ids[i].Done = false;
            }
            select.Next = null;
            while (select.Prior != null)
            {
                select.Prior.Next = select;
                select            = select.Prior;
            }
            bool moreToDo = true;
            while (select != null && moreToDo)
            {
                moreToDo = false;
                ExprList list = select.EList;
                Debug.Assert(list != null);
                ExprList.ExprListItem item;
                for (i = 0; i < orderBy.Exprs; i++)
                {
                    item = orderBy.Ids[i];

                    Expr pDup;
                    if (item.Done)
                    {
                        continue;
                    }
                    Expr expr  = item.Expr;
                    int  colId = -1;
                    if (expr.IsInteger(ref colId))
                    {
                        if (colId <= 0 || colId > list.Exprs)
                        {
                            ResolveOutOfRangeError(parse, "ORDER", i + 1, list.Exprs);
                            return(1);
                        }
                    }
                    else
                    {
                        colId = ResolveAsName(parse, list, expr);
                        if (colId == 0)
                        {
                            Expr dupExpr = Expr.Dup(ctx, expr, 0);
                            if (!ctx.MallocFailed)
                            {
                                Debug.Assert(dupExpr != null);
                                colId = ResolveOrderByTermToExprList(parse, select, dupExpr);
                            }
                            Expr.Delete(ctx, ref dupExpr);
                        }
                    }
                    if (colId > 0)
                    {
                        // Convert the ORDER BY term into an integer column number iCol, taking care to preserve the COLLATE clause if it exists
                        Expr newExpr = Expr.Expr_(ctx, TK.INTEGER, null);
                        if (newExpr == null)
                        {
                            return(1);
                        }
                        newExpr.Flags |= EP.IntValue;
                        newExpr.u.I    = colId;
                        if (item.Expr == expr)
                        {
                            item.Expr = newExpr;
                        }
                        else
                        {
                            Debug.Assert(item.Expr.OP == TK.COLLATE);
                            Debug.Assert(item.Expr.Left == expr);
                            item.Expr.Left = newExpr;
                        }
                        Expr.Delete(ctx, ref expr);
                        item.OrderByCol = (ushort)colId;
                        item.Done       = true;
                    }
                    else
                    {
                        moreToDo = true;
                    }
                }
                select = select.Next;
            }
            for (i = 0; i < orderBy.Exprs; i++)
            {
                if (!orderBy.Ids[i].Done)
                {
                    parse.ErrorMsg("%r ORDER BY term does not match any column in the result set", i + 1);
                    return(1);
                }
            }
            return(0);
        }
コード例 #17
0
ファイル: Walker+Resolve.cs プロジェクト: BclEx/GpuEx
 static void ResolveOutOfRangeError(Parse parse, string typeName, int i, int max)
 {
     parse.ErrorMsg("%r %s BY term out of range - should be between 1 and %d", i, typeName, max);
 }
コード例 #18
0
        public static void BeginTrigger(Parse parse, Token name1, Token name2, TK trTm, TK op, IdList columns, SrcList tableName, Expr when, bool isTemp, int noErr)
        {
            Context ctx = parse.Ctx;     // The database connection

            Debug.Assert(name1 != null); // pName1.z might be NULL, but not pName1 itself
            Debug.Assert(name2 != null);
            Debug.Assert(op == TK.INSERT || op == TK.UPDATE || op == TK.DELETE);
            Debug.Assert(op > 0 && op < (TK)0xff);
            Trigger trigger = null; // The new trigger

            int   db;               // The database to store the trigger in
            Token name = null;      // The unqualified db name

            if (isTemp)
            {
                // If TEMP was specified, then the trigger name may not be qualified.
                if (name2.length > 0)
                {
                    parse.ErrorMsg("temporary trigger may not have qualified name");
                    goto trigger_cleanup;
                }
                db   = 1;
                name = name1;
            }
            else
            {
                // Figure out the db that the the trigger will be created in
                db = parse.TwoPartName(name1, name2, ref name);
                if (db < 0)
                {
                    goto trigger_cleanup;
                }
            }
            if (tableName == null || ctx.MallocFailed)
            {
                goto trigger_cleanup;
            }

            // A long-standing parser bug is that this syntax was allowed:
            //    CREATE TRIGGER attached.demo AFTER INSERT ON attached.tab ....
            //                                                 ^^^^^^^^
            // To maintain backwards compatibility, ignore the database name on pTableName if we are reparsing our of SQLITE_MASTER.
            if (ctx.Init.Busy && db != 1)
            {
                C._tagfree(ctx, ref tableName.Ids[0].Database);
                tableName.Ids[0].Database = null;
            }

            // If the trigger name was unqualified, and the table is a temp table, then set iDb to 1 to create the trigger in the temporary database.
            // If sqlite3SrcListLookup() returns 0, indicating the table does not exist, the error is caught by the block below.
            //? if (tableName == null) goto trigger_cleanup;
            Table table = Delete.SrcListLookup(parse, tableName); // Table that the trigger fires off of

            if (ctx.Init.Busy == null && name2.length == 0 && table != null && table.Schema == ctx.DBs[1].Schema)
            {
                db = 1;
            }

            // Ensure the table name matches database name and that the table exists
            if (ctx.MallocFailed)
            {
                goto trigger_cleanup;
            }
            Debug.Assert(tableName.Srcs == 1);
            DbFixer sFix = new DbFixer(); // State vector for the DB fixer

            if (sFix.FixInit(parse, db, "trigger", name) && sFix.FixSrcList(tableName))
            {
                goto trigger_cleanup;
            }
            table = Delete.SrcListLookup(parse, tableName);
            if (table == null)
            {
                // The table does not exist.
                if (ctx.Init.DB == 1)
                {
                    // Ticket #3810.
                    // Normally, whenever a table is dropped, all associated triggers are dropped too.  But if a TEMP trigger is created on a non-TEMP table
                    // and the table is dropped by a different database connection, the trigger is not visible to the database connection that does the
                    // drop so the trigger cannot be dropped.  This results in an "orphaned trigger" - a trigger whose associated table is missing.
                    ctx.Init.OrphanTrigger = true;
                }
                goto trigger_cleanup;
            }
            if (E.IsVirtual(table))
            {
                parse.ErrorMsg("cannot create triggers on virtual tables");
                goto trigger_cleanup;
            }

            // Check that the trigger name is not reserved and that no trigger of the specified name exists
            string nameAsString = Parse.NameFromToken(ctx, name);

            if (nameAsString == null || parse.CheckObjectName(nameAsString) != RC.OK)
            {
                goto trigger_cleanup;
            }
            Debug.Assert(Btree.SchemaMutexHeld(ctx, db, null));
            if (ctx.DBs[db].Schema.TriggerHash.Find(nameAsString, nameAsString.Length, (Trigger)null) != null)
            {
                if (noErr == 0)
                {
                    parse.ErrorMsg("trigger %T already exists", name);
                }
                else
                {
                    Debug.Assert(!ctx.Init.Busy);
                    parse.CodeVerifySchema(db);
                }
                goto trigger_cleanup;
            }

            // Do not create a trigger on a system table
            if (table.Name.StartsWith("sqlite_", StringComparison.InvariantCultureIgnoreCase))
            {
                parse.ErrorMsg("cannot create trigger on system table");
                parse.Errs++;
                goto trigger_cleanup;
            }

            // INSTEAD of triggers are only for views and views only support INSTEAD of triggers.
            if (table.Select != null && trTm != TK.INSTEAD)
            {
                parse.ErrorMsg("cannot create %s trigger on view: %S", (trTm == TK.BEFORE ? "BEFORE" : "AFTER"), tableName, 0);
                goto trigger_cleanup;
            }
            if (table.Select == null && trTm == TK.INSTEAD)
            {
                parse.ErrorMsg("cannot create INSTEAD OF trigger on table: %S", tableName, 0);
                goto trigger_cleanup;
            }

#if !OMIT_AUTHORIZATION
            {
                int    tabDb      = Prepare.SchemaToIndex(ctx, table.Schema); // Index of the database holding pTab
                AUTH   code       = AUTH.CREATE_TRIGGER;
                string dbName     = ctx.DBs[tabDb].Name;
                string dbTrigName = (isTemp ? ctx.DBs[1].Name : dbName);
                if (tabDb == 1 || isTemp)
                {
                    code = AUTH.CREATE_TEMP_TRIGGER;
                }
                if (Auth.Check(parse, code, nameAsString, table.Name, dbTrigName) != 0 || Auth.Check(parse, AUTH.INSERT, E.SCHEMA_TABLE(tabDb), 0, dbName))
                {
                    goto trigger_cleanup;
                }
            }
#endif

            // INSTEAD OF triggers can only appear on views and BEFORE triggers cannot appear on views.  So we might as well translate every
            // INSTEAD OF trigger into a BEFORE trigger.  It simplifies code elsewhere.
            if (trTm == TK.INSTEAD)
            {
                trTm = TK.BEFORE;
            }

            // Build the Trigger object
            trigger = new Trigger(); //: (Trigger *)_tagalloc(db, sizeof(Trigger), true);
            if (trigger == null)
            {
                goto trigger_cleanup;
            }
            trigger.Name      = name;
            trigger.Table     = tableName.Ids[0].Name; //: _tagstrdup(ctx, tableName->Ids[0].Name);
            trigger.Schema    = ctx.DBs[db].Schema;
            trigger.TabSchema = table.Schema;
            trigger.OP        = op;
            trigger.TRtm      = (trTm == TK.BEFORE ? TRIGGER.BEFORE : TRIGGER.AFTER);
            trigger.When      = Expr.Dup(db, when, E.EXPRDUP_REDUCE);
            trigger.Columns   = Expr.IdListDup(ctx, columns);
            Debug.Assert(parse.NewTrigger == null);
            parse.NewTrigger = trigger;

trigger_cleanup:
            C._tagfree(ctx, ref name);
            Expr.SrcListDelete(ctx, ref tableName);
            Expr.IdListDelete(ctx, ref columns);
            Expr.Delete(ctx, ref when);
            if (parse.NewTrigger == null)
            {
                DeleteTrigger(ctx, ref trigger);
            }
            else
            {
                Debug.Assert(parse.NewTrigger == trigger);
            }
        }
コード例 #19
0
ファイル: Trigger.cs プロジェクト: BclEx/GpuStructs
 static void TransferParseError(Parse to, Parse from)
 {
     Debug.Assert(from.ErrMsg == null || from.Errs != 0);
     Debug.Assert(to.ErrMsg== null || to.Errs != 0);
     if (to.Errs == 0)
     {
         to.ErrMsg = from.ErrMsg;
         to.Errs = from.Errs;
     }
     else
         C._tagfree(from.Ctx, ref from.ErrMsg);
 }
コード例 #20
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 public Table ResultSetOfSelect(Parse parse)
 {
     Context ctx = parse.Ctx;
     Context.FLAG savedFlags = ctx.Flags;
     ctx.Flags &= ~Context.FLAG.FullColNames;
     ctx.Flags |= Context.FLAG.ShortColNames;
     Select select = this;
     select.Prep(parse, null);
     if (parse.Errs != 0) return null;
     while (select.Prior != null) select = select.Prior;
     ctx.Flags = savedFlags;
     Table table = new Table();
     if (table == null)
         return null;
     // The sqlite3ResultSetOfSelect() is only used n contexts where lookaside is disabled
     Debug.Assert(!ctx.Lookaside.Enabled);
     table.Refs = 1;
     table.Name = null;
     table.RowEst = 1000000;
     SelectColumnsFromExprList(parse, select.EList, ref table.Cols.length, ref table.Cols.data);
     SelectAddColumnTypeAndCollation(parse, table.Cols.length, table.Cols.data, select);
     table.PKey = -1;
     if (ctx.MallocFailed)
     {
         Parse.DeleteTable(ctx, ref table);
         return null;
     }
     return table;
 }
コード例 #21
0
ファイル: Trigger.cs プロジェクト: BclEx/GpuStructs
        static TriggerPrg CodeRowTrigger(Parse parse, Trigger trigger, Table table, OE orconf)
        {
            Parse top = E.Parse_Toplevel(parse);
            Context ctx = parse.Ctx; // Database handle

            Debug.Assert(trigger.Name == null || table == TableOfTrigger(trigger));
            Debug.Assert(top.V != null);

            // Allocate the TriggerPrg and SubProgram objects. To ensure that they are freed if an error occurs, link them into the Parse.pTriggerPrg 
            // list of the top-level Parse object sooner rather than later.
            TriggerPrg prg = new TriggerPrg(); // Value to return //: _tagalloc(ctx, sizeof(TriggerPrg), true);
            if (prg == null) return null;
            prg.Next = top.TriggerPrg;
            top.TriggerPrg = prg;
            Vdbe.SubProgram program; // Sub-vdbe for trigger program
            prg.Program = program = new Vdbe.SubProgram();// sqlite3DbMallocZero( db, sizeof( SubProgram ) );
            if (program == null) return null;
            top.V.LinkSubProgram(program);
            prg.Trigger = trigger;
            prg.Orconf = orconf;
            prg.Colmasks[0] = 0xffffffff;
            prg.Colmasks[1] = 0xffffffff;

            // Allocate and populate a new Parse context to use for coding the trigger sub-program.
            Parse subParse = new Parse(); // Parse context for sub-vdbe //: _stackalloc(ctx, sizeof(Parse), true);
            if (subParse == null) return null;
            NameContext sNC = new NameContext(); // Name context for sub-vdbe
            sNC.Parse = subParse;
            subParse.Ctx = ctx;
            subParse.TriggerTab = table;
            subParse.Toplevel = top;
            subParse.AuthContext = trigger.Name;
            subParse.TriggerOp = trigger.OP;
            subParse.QueryLoops = parse.QueryLoops;

            int endTrigger = 0; // Label to jump to if WHEN is false
            Vdbe v = subParse.GetVdbe(); // Temporary VM
            if (v != null)
            {
#if DEBUG
                v.Comment("Start: %s.%s (%s %s%s%s ON %s)",
                    trigger.Name, OnErrorText(orconf),
                    (trigger.TRtm == TRIGGER.BEFORE ? "BEFORE" : "AFTER"),
                    (trigger.OP == TK.UPDATE ? "UPDATE" : string.Empty),
                    (trigger.OP == TK.INSERT ? "INSERT" : string.Empty),
                    (trigger.OP == TK.DELETE ? "DELETE" : string.Empty),
                    table.Name);
#endif
#if !OMIT_TRACE
                v.ChangeP4(-1, C._mtagprintf(ctx, "-- TRIGGER %s", trigger.Name), Vdbe.P4T.DYNAMIC);
#endif

                // If one was specified, code the WHEN clause. If it evaluates to false (or NULL) the sub-vdbe is immediately halted by jumping to the 
                // OP_Halt inserted at the end of the program.
                if (trigger.When != null)
                {
                    Expr when = Expr.Dup(ctx, trigger.When, 0); // Duplicate of trigger WHEN expression
                    if (ResolveExprNames(sNC, ref when) == RC.OK && !ctx.MallocFailed)
                    {
                        endTrigger = v.MakeLabel();
                        subParse.IfFalse(when, endTrigger, RC_JUMPIFNULL);
                    }
                    Expr.Delete(ctx, ref when);
                }

                // Code the trigger program into the sub-vdbe.
                CodeTriggerProgram(subParse, trigger.StepList, orconf);

                // Insert an OP_Halt at the end of the sub-program.
                if (endTrigger != 0)
                    v.ResolveLabel(endTrigger);
                v.AddOp0(Core.OP.Halt);
#if DEBUG
                v.Comment("End: %s.%s", trigger.Name, OnErrorText(orconf));
#endif
                TransferParseError(parse, subParse);
                if (!ctx.MallocFailed)
                    program.Ops.data = v.TakeOpArray(ref program.Ops.length, ref top.MaxArgs);
                program.Mems = subParse.Mems;
                program.Csrs = subParse.Tabs;
                program.Token = trigger.GetHashCode();
                prg.Colmasks[0] = subParse.Oldmask;
                prg.Colmasks[1] = subParse.Newmask;
                Vdbe.Delete(v);
            }

            Debug.Assert(subParse.Ainc == null && subParse.ZombieTab == null);
            Debug.Assert(subParse.TriggerPrg == null && subParse.MaxArgs == 0);
            C._stackfree(ctx, ref subParse);

            return prg;
        }
コード例 #22
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 public static JT JoinType(Parse parse, Token a, Token b, Token c)
 {
     Token[] alls = new Token[3];
     alls[0] = a;
     alls[1] = b;
     alls[2] = c;
     JT jointype = 0;
     for (int i = 0; i < 3 && alls[i] != null; i++)
     {
         Token p = alls[i];
         int j;
         for (j = 0; j < _keywords.Length; j++)
         {
             if (p.length == _keywords[j].Chars && p.data.StartsWith(_keyTexts.Substring(_keywords[j].I, _keywords[j].Chars), StringComparison.OrdinalIgnoreCase))
             {
                 jointype |= _keywords[j].Code;
                 break;
             }
         }
         C.ASSERTCOVERAGE(j == 0 || j == 1 || j == 2 || j == 3 || j == 4 || j == 5 || j == 6);
         if (j >= _keywords.Length)
         {
             jointype |= JT.ERROR;
             break;
         }
     }
     if ((jointype & (JT.INNER | JT.OUTER)) == (JT.INNER | JT.OUTER) || (jointype & JT.ERROR) != 0)
     {
         string sp = " ";
         Debug.Assert(b != null);
         if (c == null) sp = "";
         parse.ErrorMsg("unknown or unsupported join type: %T %T%s%T", a, b, sp, c);
         jointype = JT.INNER;
     }
     else if ((jointype & JT.OUTER) != 0 && (jointype & (JT.LEFT | JT.RIGHT)) != JT.LEFT)
     {
         parse.ErrorMsg("RIGHT and FULL OUTER JOINs are not currently supported");
         jointype = JT.INNER;
     }
     return jointype;
 }
コード例 #23
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 static bool CheckForMultiColumnSelectError(Parse parse, SelectDest dest, int exprs)
 {
     SRT dest2 = dest.Dest;
     if (exprs > 1 && (dest2 == SRT.Mem || dest2 == SRT.Set))
     {
         parse.ErrorMsg("only a single result allowed for a SELECT that is part of an expression");
         return true;
     }
     return false;
 }
コード例 #24
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
        public bool ProcessJoin(Parse parse)
        {
            SrcList src = Src; // All tables in the FROM clause
            SrcList.SrcListItem left; // Left table being joined
            SrcList.SrcListItem right; // Right table being joined
            int j;
            for (int i = 0; i < src.Srcs - 1; i++)
            {
                left = src.Ids[i];
                right = src.Ids[i + 1];
                Table leftTable = left.Table;
                Table rightTable = right.Table;

                if (C._NEVER(leftTable == null || rightTable == null)) continue;
                bool isOuter = ((right.Jointype & JT.OUTER) != 0);

                // When the NATURAL keyword is present, add WHERE clause terms for every column that the two tables have in common.
                if ((right.Jointype & JT.NATURAL) != 0)
                {
                    if (right.On != null || right.Using != null)
                    {
                        parse.ErrorMsg("a NATURAL join may not have an ON or USING clause");
                        return true;
                    }
                    for (j = 0; j < rightTable.Cols.length; j++)
                    {
                        string name = rightTable.Cols[j].Name; // Name of column in the right table
                        int leftId = 0; // Matching left table
                        int leftColId = 0;  // Matching column in the left table
                        if (TableAndColumnIndex(src, i + 1, name, ref leftId, ref leftColId))
                            AddWhereTerm(parse, src, leftId, leftColId, i + 1, j, isOuter, ref Where);
                    }
                }

                // Disallow both ON and USING clauses in the same join
                if (right.On != null && right.Using != null)
                {
                    parse.ErrorMsg("cannot have both ON and USING clauses in the same join");
                    return true;
                }

                // Add the ON clause to the end of the WHERE clause, connected by
                if (right.On != null)
                {
                    if (isOuter) SetJoinExpr(right.On, right.Cursor);
                    Where = Expr.And(parse.Ctx, Where, right.On);
                    right.On = null;
                }

                // Create extra terms on the WHERE clause for each column named in the USING clause.  Example: If the two tables to be joined are 
                // A and B and the USING clause names X, Y, and Z, then add this to the WHERE clause:    A.X=B.X AND A.Y=B.Y AND A.Z=B.Z
                // Report an error if any column mentioned in the USING clause is not contained in both tables to be joined.
                if (right.Using != null)
                {
                    IdList list = right.Using;
                    for (j = 0; j < list.Ids.length; j++)
                    {
                        string name = list.Ids[j].Name; // Name of the term in the USING clause
                        int leftId = 0; // Table on the left with matching column name
                        int leftColId = 0; // Column number of matching column on the left
                        int rightColId = ColumnIndex(rightTable, name); // Column number of matching column on the right
                        if (rightColId < 0 || TableAndColumnIndex(src, i + 1, name, ref leftId, ref leftColId))
                        {
                            parse.ErrorMsg("cannot join using column %s - column not present in both tables", name);
                            return true;
                        }
                        AddWhereTerm(parse, src, leftId, leftColId, i + 1, rightColId, isOuter, ref Where);
                    }
                }
            }
            return true;
        }
コード例 #25
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 static KeyInfo KeyInfoFromExprList(Parse parse, ExprList list)
 {
     Context ctx = parse.Ctx;
     int exprs = list.Exprs;
     KeyInfo info = new KeyInfo();
     if (info != null)
     {
         info.SortOrders = new SO[exprs];
         info.Colls = new CollSeq[exprs];
         info.Fields = (ushort)exprs;
         info.Encode = E.CTXENCODE(ctx);
         info.Ctx = ctx;
         int i;
         ExprList.ExprListItem item;
         for (i = 0; i < exprs; i++)
         {
             item = list.Ids[i];
             CollSeq coll = item.Expr.CollSeq(parse);
             if (coll == null)
                 coll = ctx.DefaultColl;
             info.Colls[i] = coll;
             info.SortOrders[i] = item.SortOrder;
         }
     }
     return info;
 }
コード例 #26
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 public static Select New(Parse parse, int dummy1, SrcList src, int dummy2, int dummy3, int dummy4, int dummy5, SF selFlags, int dummy6, int dummy7) { return New(parse, null, src, null, null, null, null, selFlags, null, null); }
コード例 #27
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 static void ExplainComposite(Parse parse, TK op, int sub1Id, int sub2Id, bool useTmp)
 {
     Debug.Assert(op == TK.UNION || op == TK.EXCEPT || op == TK.INTERSECT || op == TK.ALL);
     if (parse.Explain == 2)
     {
         Vdbe v = parse.V;
         string msg = C._mtagprintf(parse.Ctx, "COMPOUND SUBQUERIES %d AND %d %s(%s)", sub1Id, sub2Id, (useTmp ? "USING TEMP B-TREE " : ""), SelectOpName(op));
         v.AddOp4(OP.Explain, parse.SelectId, 0, 0, msg, Vdbe.P4T.DYNAMIC);
     }
 }
コード例 #28
0
ファイル: Trigger.cs プロジェクト: BclEx/GpuStructs
        static TriggerPrg GetRowTrigger(Parse parse, Trigger trigger, Table table, OE orconf)
        {
            Parse root = E.Parse_Toplevel(parse);
            Debug.Assert(trigger.Name == null || table == TableOfTrigger(trigger));

            // It may be that this trigger has already been coded (or is in the process of being coded). If this is the case, then an entry with
            // a matching TriggerPrg.pTrigger field will be present somewhere in the Parse.pTriggerPrg list. Search for such an entry.
            TriggerPrg prg;
            for (prg = root.TriggerPrg; prg != null && (prg.Trigger != trigger || prg.Orconf != orconf); prg = prg.Next) ;
            // If an existing TriggerPrg could not be located, create a new one.
            if (prg == null)
                prg = CodeRowTrigger(parse, trigger, table, orconf);
            return prg;
        }
コード例 #29
0
ファイル: Walker+Resolve.cs プロジェクト: BclEx/GpuEx
        static WRC LookupName(Parse parse, string dbName, string tableName, string colName, NameContext nc, Expr expr)
        {
            int     cnt       = 0;            // Number of matching column names
            int     cntTab    = 0;            // Number of matching table names
            int     subquerys = 0;            // How many levels of subquery
            Context ctx       = parse.Ctx;    // The database connection

            SrcList.SrcListItem item;         // Use for looping over pSrcList items
            SrcList.SrcListItem match = null; // The matching pSrcList item
            NameContext         topNC = nc;   // First namecontext in the list
            Schema schema = null;             // Schema of the expression
            bool   isTrigger = false;
            int    i, j;

            Debug.Assert(nc != null);      // the name context cannot be NULL.
            Debug.Assert(colName != null); // The Z in X.Y.Z cannot be NULL
            Debug.Assert(!E.ExprHasAnyProperty(expr, EP.TokenOnly | EP.Reduced));

            // Initialize the node to no-match
            expr.TableId = -1;
            expr.Table   = null;
            E.ExprSetIrreducible(expr);

            // Translate the schema name in zDb into a pointer to the corresponding schema.  If not found, pSchema will remain NULL and nothing will match
            // resulting in an appropriate error message toward the end of this routine
            if (dbName != null)
            {
                for (i = 0; i < ctx.DBs.length; i++)
                {
                    Debug.Assert(ctx.DBs[i].Name != null);
                    if (string.Compare(ctx.DBs[i].Name, dbName) == 0)
                    {
                        schema = ctx.DBs[i].Schema;
                        break;
                    }
                }
            }

            // Start at the inner-most context and move outward until a match is found
            while (nc != null && cnt == 0)
            {
                ExprList list;
                SrcList  srcList = nc.SrcList;
                if (srcList != null)
                {
                    for (i = 0; i < srcList.Srcs; i++)
                    {
                        item = srcList.Ids[i];
                        Table table = item.Table;
                        Debug.Assert(table != null && table.Name != null);
                        Debug.Assert(table.Cols.length > 0);
                        if (item.Select != null && (item.Select.SelFlags & SF.NestedFrom) != 0)
                        {
                            bool hit = false;
                            list = item.Select.EList;
                            for (j = 0; j < list.Exprs; j++)
                            {
                                if (Walker.MatchSpanName(list.Ids[j].Span, colName, tableName, dbName))
                                {
                                    cnt++;
                                    cntTab        = 2;
                                    match         = item;
                                    expr.ColumnId = j;
                                    hit           = true;
                                }
                            }
                            if (hit || table == null)
                            {
                                continue;
                            }
                        }
                        if (dbName != null && table.Schema != schema)
                        {
                            continue;
                        }
                        if (tableName != null)
                        {
                            string tableName2 = (item.Alias != null ? item.Alias : table.Name);
                            Debug.Assert(tableName2 != null);
                            if (!string.Equals(tableName2, tableName, StringComparison.OrdinalIgnoreCase))
                            {
                                continue;
                            }
                        }
                        if (cntTab++ == 0)
                        {
                            match = item;
                        }
                        Column col;
                        for (j = 0; j < table.Cols.length; j++)
                        {
                            col = table.Cols[j];
                            if (string.Equals(col.Name, colName, StringComparison.InvariantCultureIgnoreCase))
                            {
                                // If there has been exactly one prior match and this match is for the right-hand table of a NATURAL JOIN or is in a
                                // USING clause, then skip this match.
                                if (cnt == 1)
                                {
                                    if ((item.Jointype & JT.NATURAL) != 0)
                                    {
                                        continue;
                                    }
                                    if (NameInUsingClause(item.Using, colName))
                                    {
                                        continue;
                                    }
                                }
                                cnt++;
                                match = item;
                                // Substitute the rowid (column -1) for the INTEGER PRIMARY KEY
                                expr.ColumnId = (j == table.PKey ? -1 : (short)j);
                                break;
                            }
                        }
                    }
                    if (match != null)
                    {
                        expr.TableId = match.Cursor;
                        expr.Table   = match.Table;
                        schema       = expr.Table.Schema;
                    }
                }

#if !OMIT_TRIGGER
                // If we have not already resolved the name, then maybe it is a new.* or old.* trigger argument reference
                if (dbName == null && tableName != null && cnt == 0 && parse.TriggerTab != null)
                {
                    TK    op    = parse.TriggerOp;
                    Table table = null;
                    Debug.Assert(op == TK.DELETE || op == TK.UPDATE || op == TK.INSERT);
                    if (op != TK.DELETE && string.Equals("new", tableName, StringComparison.InvariantCultureIgnoreCase))
                    {
                        expr.TableId = 1;
                        table        = parse.TriggerTab;
                    }
                    else if (op != TK.INSERT && string.Equals("old", tableName, StringComparison.InvariantCultureIgnoreCase))
                    {
                        expr.TableId = 0;
                        table        = parse.TriggerTab;
                    }
                    if (table != null)
                    {
                        int colId;
                        schema = table.Schema;
                        cntTab++;
                        for (colId = 0; colId < table.Cols.length; colId++)
                        {
                            Column col = table.Cols[colId];
                            if (string.Equals(col.Name, colName, StringComparison.InvariantCultureIgnoreCase))
                            {
                                if (colId == table.PKey)
                                {
                                    colId = -1;
                                }
                                break;
                            }
                        }
                        if (colId >= table.Cols.length && Expr.IsRowid(colName))
                        {
                            colId = -1; // IMP: R-44911-55124
                        }
                        if (colId < table.Cols.length)
                        {
                            cnt++;
                            if (colId < 0)
                            {
                                expr.Aff = AFF.INTEGER;
                            }
                            else if (expr.TableId == 0)
                            {
                                C.ASSERTCOVERAGE(colId == 31);
                                C.ASSERTCOVERAGE(colId == 32);
                                parse.Oldmask |= (colId >= 32 ? 0xffffffff : (((uint)1) << colId));
                            }
                            else
                            {
                                C.ASSERTCOVERAGE(colId == 31);
                                C.ASSERTCOVERAGE(colId == 32);
                                parse.Newmask |= (colId >= 32 ? 0xffffffff : (((uint)1) << colId));
                            }
                            expr.ColumnId = (short)colId;
                            expr.Table    = table;
                            isTrigger     = true;
                        }
                    }
                }
#endif

                // Perhaps the name is a reference to the ROWID
                if (cnt == 0 && cntTab == 1 && Expr.IsRowid(colName))
                {
                    cnt           = 1;
                    expr.ColumnId = -1; // IMP: R-44911-55124
                    expr.Aff      = AFF.INTEGER;
                }

                // If the input is of the form Z (not Y.Z or X.Y.Z) then the name Z might refer to an result-set alias.  This happens, for example, when
                // we are resolving names in the WHERE clause of the following command:
                //
                //     SELECT a+b AS x FROM table WHERE x<10;
                //
                // In cases like this, replace pExpr with a copy of the expression that forms the result set entry ("a+b" in the example) and return immediately.
                // Note that the expression in the result set should have already been resolved by the time the WHERE clause is resolved.
                if (cnt == 0 && (list = nc.EList) != null && tableName == null)
                {
                    for (j = 0; j < list.Exprs; j++)
                    {
                        string asName = list.Ids[j].Name;
                        if (asName != null && string.Equals(asName, colName, StringComparison.InvariantCultureIgnoreCase))
                        {
                            Debug.Assert(expr.Left == null && expr.Right == null);
                            Debug.Assert(expr.x.List == null);
                            Debug.Assert(expr.x.Select == null);
                            Expr orig = list.Ids[j].Expr;
                            if ((nc.NCFlags & NC.AllowAgg) == 0 && E.ExprHasProperty(orig, EP.Agg))
                            {
                                parse.ErrorMsg("misuse of aliased aggregate %s", asName);
                                return(WRC.Abort);
                            }
                            ResolveAlias(parse, list, j, expr, "", subquerys);
                            cnt   = 1;
                            match = null;
                            Debug.Assert(tableName == null && dbName == null);
                            goto lookupname_end;
                        }
                    }
                }

                // Advance to the next name context.  The loop will exit when either we have a match (cnt>0) or when we run out of name contexts.
                if (cnt == 0)
                {
                    nc = nc.Next;
                    subquerys++;
                }
            }

            // If X and Y are NULL (in other words if only the column name Z is supplied) and the value of Z is enclosed in double-quotes, then
            // Z is a string literal if it doesn't match any column names.  In that case, we need to return right away and not make any changes to
            // pExpr.
            //
            // Because no reference was made to outer contexts, the pNC->nRef fields are not changed in any context.
            if (cnt == 0 && tableName == null && E.ExprHasProperty(expr, EP.DblQuoted))
            {
                expr.OP    = TK.STRING;
                expr.Table = null;
                return(WRC.Prune);
            }

            // cnt==0 means there was not match.  cnt>1 means there were two or more matches.  Either way, we have an error.
            if (cnt != 1)
            {
                string err = (cnt == 0 ? "no such column" : "ambiguous column name");
                if (dbName != null)
                {
                    parse.ErrorMsg("%s: %s.%s.%s", err, dbName, tableName, colName);
                }
                else if (tableName != null)
                {
                    parse.ErrorMsg("%s: %s.%s", err, tableName, colName);
                }
                else
                {
                    parse.ErrorMsg("%s: %s", err, colName);
                }
                parse.CheckSchema = 1;
                topNC.Errs++;
            }

            // If a column from a table in pSrcList is referenced, then record this fact in the pSrcList.a[].colUsed bitmask.  Column 0 causes
            // bit 0 to be set.  Column 1 sets bit 1.  And so forth.  If the column number is greater than the number of bits in the bitmask
            // then set the high-order bit of the bitmask.
            if (expr.ColumnId >= 0 && match != null)
            {
                int n = expr.ColumnId;
                C.ASSERTCOVERAGE(n == BMS - 1);
                if (n >= BMS)
                {
                    n = BMS - 1;
                }
                Debug.Assert(match.Cursor == expr.TableId);
                match.ColUsed |= ((Bitmask)1) << n;
            }

            // Clean up and return
            Expr.Delete(ctx, ref expr.Left);
            expr.Left = null;
            Expr.Delete(ctx, ref expr.Right);
            expr.Right = null;
            expr.OP    = (isTrigger ? TK.TRIGGER : TK.COLUMN);
lookupname_end:
            if (cnt == 1)
            {
                Debug.Assert(nc != null);
                Auth.Read(parse, expr, schema, nc.SrcList);
                // Increment the nRef value on all name contexts from TopNC up to the point where the name matched.
                for (; ;)
                {
                    Debug.Assert(topNC != null);
                    topNC.Refs++;
                    if (topNC == nc)
                    {
                        break;
                    }
                    topNC = topNC.Next;
                }
                return(WRC.Prune);
            }
            return(WRC.Abort);
        }
コード例 #30
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
        static void SelectInnerLoop(Parse parse, Select p, ExprList list, int srcTable, int columns, ExprList orderBy, DistinctCtx distinct, SelectDest dest, int continueId, int breakId)
        {
            Vdbe v = parse.V;

            Debug.Assert(v != null);
            if (C._NEVER(v == null)) return;
            Debug.Assert(list != null);
            WHERE_DISTINCT hasDistinct = (distinct != null ? distinct.TnctType : WHERE_DISTINCT.NOOP); // True if the DISTINCT keyword is present
            if (orderBy == null && hasDistinct == (WHERE_DISTINCT)0)
                CodeOffset(v, p, continueId);

            // Pull the requested columns.
            int resultCols = (columns > 0 ? columns : list.Exprs); // Number of result columns
            if (dest.Sdsts == 0)
            {
                dest.SdstId = parse.Mems + 1;
                dest.Sdsts = resultCols;
                parse.Mems += resultCols;
            }
            else
                Debug.Assert(dest.Sdsts == resultCols);
            int regResult = dest.SdstId; // Start of memory holding result set
            SRT dest2 = dest.Dest; // How to dispose of results
            int i;
            if (columns > 0)
                for (i = 0; i < columns; i++)
                    v.AddOp3(OP.Column, srcTable, i, regResult + i);
            else if (dest2 != SRT.Exists)
            {
                // If the destination is an EXISTS(...) expression, the actual values returned by the SELECT are not required.
                Expr.CacheClear(parse);
                Expr.CodeExprList(parse, list, regResult, dest2 == SRT.Output);
            }
            columns = resultCols;

            // If the DISTINCT keyword was present on the SELECT statement and this row has been seen before, then do not make this row part of the result.
            if (hasDistinct != 0)
            {
                Debug.Assert(list != null);
                Debug.Assert(list.Exprs == columns);
                switch (distinct.TnctType)
                {
                    case WHERE_DISTINCT.ORDERED:
                        {
                            // Allocate space for the previous row
                            int regPrev = parse.Mems + 1; // Previous row content
                            parse.Mems += columns;

                            // Change the OP_OpenEphemeral coded earlier to an OP_Null sets the MEM_Cleared bit on the first register of the
                            // previous value.  This will cause the OP_Ne below to always fail on the first iteration of the loop even if the first
                            // row is all NULLs.
                            v.ChangeToNoop(distinct.AddrTnct);
                            Vdbe.VdbeOp op = v.GetOp(distinct.AddrTnct); // No longer required OpenEphemeral instr.
                            op.Opcode = OP.Null;
                            op.P1 = 1;
                            op.P2 = regPrev;

                            int jumpId = v.CurrentAddr() + columns; // Jump destination
                            for (i = 0; i < columns; i++)
                            {
                                CollSeq coll = list.Ids[i].Expr.CollSeq(parse);
                                if (i < columns - 1)
                                    v.AddOp3(OP.Ne, regResult + i, jumpId, regPrev + i);
                                else
                                    v.AddOp3(OP.Eq, regResult + i, continueId, regPrev + i);
                                v.ChangeP4(-1, coll, Vdbe.P4T.COLLSEQ);
                                v.ChangeP5(AFF.BIT_NULLEQ);
                            }
                            Debug.Assert(v.CurrentAddr() == jumpId);
                            v.AddOp3(OP.Copy, regResult, regPrev, columns - 1);
                            break;
                        }
                    case WHERE_DISTINCT.UNIQUE:
                        {
                            v.ChangeToNoop(distinct.AddrTnct);
                            break;
                        }
                    default:
                        {
                            Debug.Assert(distinct.TnctType == WHERE_DISTINCT.UNORDERED);
                            CodeDistinct(parse, distinct.TableTnct, continueId, columns, regResult);
                            break;
                        }
                }
                if (orderBy != null)
                    CodeOffset(v, p, continueId);
            }

            int paramId = dest.SDParmId; // First argument to disposal method
            switch (dest2)
            {
#if !OMIT_COMPOUND_SELECT
                case SRT.Union:
                    {
                        // In this mode, write each query result to the key of the temporary table iParm.
                        int r1 = Expr.GetTempReg(parse);
                        v.AddOp3(OP.MakeRecord, regResult, columns, r1);
                        v.AddOp2(OP.IdxInsert, paramId, r1);
                        Expr.ReleaseTempReg(parse, r1);
                        break;
                    }
                case SRT.Except:
                    {
                        // Construct a record from the query result, but instead of saving that record, use it as a key to delete elements from
                        // the temporary table iParm.
                        v.AddOp3(OP.IdxDelete, paramId, regResult, columns);
                        break;
                    }
#endif
                case SRT.Table:
                case SRT.EphemTab:
                    {
                        // Store the result as data using a unique key.
                        int r1 = Expr.GetTempReg(parse);
                        C.ASSERTCOVERAGE(dest2 == SRT.Table);
                        C.ASSERTCOVERAGE(dest2 == SRT.EphemTab);
                        v.AddOp3(OP.MakeRecord, regResult, columns, r1);
                        if (orderBy != null)
                            PushOntoSorter(parse, orderBy, p, r1);
                        else
                        {
                            int r2 = Expr.GetTempReg(parse);
                            v.AddOp2(OP.NewRowid, paramId, r2);
                            v.AddOp3(OP.Insert, paramId, r1, r2);
                            v.ChangeP5(Vdbe.OPFLAG.APPEND);
                            Expr.ReleaseTempReg(parse, r2);
                        }
                        Expr.ReleaseTempReg(parse, r1);
                        break;
                    }
#if !OMIT_SUBQUERY
                case SRT.Set:
                    {
                        // If we are creating a set for an "expr IN (SELECT ...)" construct, then there should be a single item on the stack.  Write this
                        // item into the set table with bogus data.
                        Debug.Assert(columns == 1);
                        dest.AffSdst = list.Ids[0].Expr.CompareAffinity(dest.AffSdst);
                        // At first glance you would think we could optimize out the ORDER BY in this case since the order of entries in the set
                        // does not matter.  But there might be a LIMIT clause, in which case the order does matter
                        if (orderBy != null)
                            PushOntoSorter(parse, orderBy, p, regResult);
                        else
                        {
                            int r1 = Expr.GetTempReg(parse);
                            v.AddOp4(OP.MakeRecord, regResult, 1, r1, dest.AffSdst, 1);
                            Expr.CacheAffinityChange(parse, regResult, 1);
                            v.AddOp2(OP.IdxInsert, paramId, r1);
                            Expr.ReleaseTempReg(parse, r1);
                        }
                        break;
                    }
                case SRT.Exists:
                    {
                        // If any row exist in the result set, record that fact and abort.
                        v.AddOp2(OP.Integer, 1, paramId);
                        // The LIMIT clause will terminate the loop for us
                        break;
                    }
                case SRT.Mem:
                    {
                        // If this is a scalar select that is part of an expression, then store the results in the appropriate memory cell and break out
                        // of the scan loop.
                        Debug.Assert(columns == 1);
                        if (orderBy != null)
                            PushOntoSorter(parse, orderBy, p, regResult);
                        else
                            Expr.CodeMove(parse, regResult, paramId, 1);
                        // The LIMIT clause will jump out of the loop for us
                        break;
                    }
#endif
                case SRT.Coroutine:
                case SRT.Output:
                    {
                        // Send the data to the callback function or to a subroutine.  In the case of a subroutine, the subroutine itself is responsible for
                        // popping the data from the stack.
                        C.ASSERTCOVERAGE(dest2 == SRT.Coroutine);
                        C.ASSERTCOVERAGE(dest2 == SRT.Output);
                        if (orderBy != null)
                        {
                            int r1 = Expr.GetTempReg(parse);
                            v.AddOp3(OP.MakeRecord, regResult, columns, r1);
                            PushOntoSorter(parse, orderBy, p, r1);
                            Expr.ReleaseTempReg(parse, r1);
                        }
                        else if (dest2 == SRT.Coroutine)
                            v.AddOp1(OP.Yield, dest.SDParmId);
                        else
                        {
                            v.AddOp2(OP.ResultRow, regResult, columns);
                            Expr.CacheAffinityChange(parse, regResult, columns);
                        }
                        break;
                    }
#if !OMIT_TRIGGER
                default:
                    {
                        // Discard the results.  This is used for SELECT statements inside the body of a TRIGGER.  The purpose of such selects is to call
                        // user-defined functions that have side effects.  We do not care about the actual results of the select.
                        Debug.Assert(dest2 == SRT.Discard);
                        break;
                    }
#endif
            }

            // Jump to the end of the loop if the LIMIT is reached.  Except, if there is a sorter, in which case the sorter has already limited the output for us.
            if (orderBy == null && p.LimitId != 0)
                v.AddOp3(OP.IfZero, p.LimitId, breakId, -1);
        }
コード例 #31
0
ファイル: Trigger.cs プロジェクト: BclEx/GpuStructs
        public void CodeRowTriggerDirect(Parse parse, Table table, int reg, OE orconf, int ignoreJump)
        {
            Vdbe v = parse.GetVdbe(); // Main VM
            TriggerPrg prg = GetRowTrigger(parse, this, table, orconf);
            Debug.Assert(prg != null || parse.Errs != 0 || parse.Ctx.MallocFailed);

            // Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program is a pointer to the sub-vdbe containing the trigger program.
            if (prg != null)
            {
                bool recursive = (Name != null && (parse.Ctx.Flags & Context.FLAG.RecTriggers) == 0);
                v.AddOp3(Core.OP.Program, reg, ignoreJump, ++parse.Mems);
                v.ChangeP4(-1, prg.Program, Vdbe.P4T.SUBPROGRAM);
#if DEBUG
                v.Comment("Call: %s.%s", (!string.IsNullOrEmpty(p.Name) ? p.Name : "fkey"), OnErrorText(orconf));
#endif
                // Set the P5 operand of the OP_Program instruction to non-zero if recursive invocation of this trigger program is disallowed. Recursive
                // invocation is disallowed if (a) the sub-program is really a trigger, not a foreign key action, and (b) the flag to enable recursive triggers is clear.
                v.ChangeP5((int)(recursive ? 1 : 0));
            }
        }
コード例 #32
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 static void ExplainTempTable(Parse parse, string usage_)
 {
     if (parse.Explain == 2)
     {
         Vdbe v = parse.V;
         string msg = C._mtagprintf(parse.Ctx, "USE TEMP B-TREE FOR %s", usage_);
         v.AddOp4(OP.Explain, parse.SelectId, 0, 0, msg, Vdbe.P4T.DYNAMIC);
     }
 }
コード例 #33
0
ファイル: Trigger.cs プロジェクト: BclEx/GpuStructs
        public void CodeRowTrigger(Parse parse, TK op, ExprList changes, TRIGGER trtm, Table table, int reg, OE orconf, int ignoreJump)
        {
            Debug.Assert(op == TK.UPDATE || op == TK.INSERT || op == TK.DELETE);
            Debug.Assert(trtm == TRIGGER.BEFORE || trtm == TRIGGER.AFTER);
            Debug.Assert((op == TK.UPDATE) == (changes != null));

            for (Trigger p = this; p != null; p = p.Next)
            {
                // Sanity checking:  The schema for the trigger and for the table are always defined.  The trigger must be in the same schema as the table or else it must be a TEMP trigger.
                Debug.Assert(p.Schema != null);
                Debug.Assert(p.TabSchema != null);
                Debug.Assert(p.Schema == p.TabSchema || p.Schema == parse.Ctx.DBs[1].Schema);

                // Determine whether we should code this trigger
                if (p.OP == op && p.TRtm == trtm && CheckColumnOverlap(p.Columns, changes))
                    p.CodeRowTriggerDirect(parse, table, reg, orconf, ignoreJump);
            }
        }
コード例 #34
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 static void ExplainComposite(Parse v, int w, int x, int y, bool z) { }
コード例 #35
0
ファイル: Trigger.cs プロジェクト: BclEx/GpuStructs
 public uint TriggerColmask(Parse parse, ExprList changes, bool isNew, TRIGGER trtm, Table table, OE orconf)
 {
     TK op = (changes != null ? TK.UPDATE : TK.DELETE);
     int isNewId = (isNew ? 1 : 0);
     uint mask = 0;
     for (Trigger p = this; p != null; p = p.Next)
         if (p.OP == op && (trtm & p.TRtm) != 0 && CheckColumnOverlap(p.Columns, changes))
         {
             TriggerPrg prg = GetRowTrigger(parse, p, table, orconf);
             if (prg != null)
                 mask |= prg.Colmasks[isNewId];
         }
     return mask;
 }
コード例 #36
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
        static void GenerateColumnTypes(Parse parse, SrcList tabList, ExprList list)
        {
#if !OMIT_DECLTYPE
            Vdbe v = parse.V;
            NameContext sNC = new NameContext();
            sNC.SrcList = tabList;
            sNC.Parse = parse;
            for (int i = 0; i < list.Exprs; i++)
            {
                Expr p = list.Ids[i].Expr;
                string typeName;
#if ENABLE_COLUMN_METADATA
                string origDbName = null;
                string origTableName = null;
                string origColumnName = null;
                typeName = ColumnType(sNC, p, ref origDbName, ref origTableName, ref origColumnName);

                // The vdbe must make its own copy of the column-type and other column specific strings, in case the schema is reset before this
                // virtual machine is deleted.
                v.SetColName(i, COLNAME_DATABASE, origDbName, C.DESTRUCTOR_TRANSIENT);
                v.SetColName(i, COLNAME_TABLE, origTableName, C.DESTRUCTOR_TRANSIENT);
                v.SetColName(i, COLNAME_COLUMN, origColumnName, C.DESTRUCTOR_TRANSIENT);
#else
                string dummy1 = null;
                typeName = ColumnType(sNC, p, ref dummy1, ref dummy1, ref dummy1);
#endif
                v.SetColName(i, COLNAME_DECLTYPE, typeName, C.DESTRUCTOR_TRANSIENT);
            }
#endif
        }
コード例 #37
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
 static void SelectAddColumnTypeAndCollation(Parse parse, int colsLength, Column[] cols, Select select)
 {
     Context ctx = parse.Ctx;
     Debug.Assert(select != null);
     Debug.Assert((select.SelFlags & SF.Resolved) != 0);
     Debug.Assert(colsLength == select.EList.Exprs || ctx.MallocFailed);
     if (ctx.MallocFailed) return;
     NameContext sNC = new NameContext();
     sNC.SrcList = select.Src;
     ExprList.ExprListItem[] ids = select.EList.Ids;
     int i;
     Column col;
     for (i = 0; i < colsLength; i++)
     {
         col = cols[i];
         Expr p = ids[i].Expr;
         string dummy1 = null;
         col.Type = ColumnType(sNC, p, ref dummy1, ref dummy1, ref dummy1);
         col.Affinity = p.Affinity();
         if (col.Affinity == 0) col.Affinity = AFF.NONE;
         CollSeq coll = p.CollSeq(parse);
         if (coll != null)
             col.Coll = coll.Name;
     }
 }
コード例 #38
0
ファイル: Select.cs プロジェクト: BclEx/GpuStructs
        static RC SelectColumnsFromExprList(Parse parse, ExprList list, ref short colsLengthOut, ref Column[] colsOut)
        {
            Context ctx = parse.Ctx; // Database connection
            int j;

            int colsLength; // Number of columns in the result set
            Column[] cols; // For looping over result columns
            if (list != null)
            {
                colsLength = list.Exprs;
                cols = new Column[colsLength];
                C.ASSERTCOVERAGE(cols == null);
            }
            else
            {
                colsLength = 0;
                cols = null;
            }
            colsLengthOut = (short)colsLength;
            colsOut = cols;

            int i;
            Column col; // For looping over result columns
            for (i = 0; i < colsLength; i++)//, pCol++)
            {
                if (cols[i] == null) cols[i] = new Column();
                col = cols[i];
                // Get an appropriate name for the column
                Expr p = list.Ids[i].Expr; // Expression for a single result column
                string name; // Column name
                if (list.Ids[i].Name != null && (name = list.Ids[i].Name) != null) { }
                //: name = _tagstrdup(ctx, name); // If the column contains an "AS <name>" phrase, use <name> as the name 
                else
                {
                    Expr colExpr = p; // The expression that is the result column name

                    while (colExpr.OP == TK.DOT)
                    {
                        colExpr = colExpr.Right;
                        Debug.Assert(colExpr != null);
                    }
                    if (colExpr.OP == TK.COLUMN && C._ALWAYS(colExpr.Table != null))
                    {
                        // For columns use the column name name
                        int colId = colExpr.ColumnIdx;
                        Table table = colExpr.Table; // Table associated with this expression
                        if (colId < 0) colId = table.PKey;
                        name = C._mtagprintf(ctx, "%s", (colId >= 0 ? table.Cols[colId].Name : "rowid"));
                    }
                    else if (colExpr.OP == TK.ID)
                    {
                        Debug.Assert(!E.ExprHasProperty(colExpr, EP.IntValue));
                        name = C._mtagprintf(ctx, "%s", colExpr.u.Token);
                    }
                    else
                        name = C._mtagprintf(ctx, "%s", list.Ids[i].Span); // Use the original text of the column expression as its name
                }
                if (ctx.MallocFailed)
                {
                    C._tagfree(ctx, ref name);
                    break;
                }

                // Make sure the column name is unique.  If the name is not unique, append a integer to the name so that it becomes unique.
                int nameLength = name.Length; // Size of name in zName[]
                int cnt; // Index added to make the name unique
                for (j = cnt = 0; j < i; j++)
                {
                    if (string.Equals(cols[j].Name, name, StringComparison.OrdinalIgnoreCase))
                    {
                        name = name.Substring(0, nameLength);
                        string newName = C._mtagprintf(ctx, "%s:%d", name, ++cnt);
                        C._tagfree(ctx, ref name);
                        name = newName;
                        j = -1;
                        if (name == null) break;
                    }
                }
                col.Name = name;
            }
            if (ctx.MallocFailed)
            {
                for (j = 0; j < i; j++)
                    C._tagfree(ctx, ref cols[j].Name);
                C._tagfree(ctx, ref cols);
                colsOut = null;
                colsLengthOut = 0;
                return RC.NOMEM;
            }
            return RC.OK;
        }
コード例 #39
0
        public static void FinishTrigger(Parse parse, TriggerStep stepList, Token all)
        {
            Trigger trig      = parse.NewTrigger; // Trigger being finished
            Context ctx       = parse.Ctx;        // The database
            Token   nameToken = new Token();      // Trigger name for error reporting

            parse.NewTrigger = null;
            if (C._NEVER(parse.Errs != 0) || trig == null)
            {
                goto triggerfinish_cleanup;
            }
            string name = trig.Name;                                     // Name of trigger
            int    db   = Prepare.SchemaToIndex(parse.Ctx, trig.Schema); // Database containing the trigger

            trig.StepList = stepList;
            while (stepList != null)
            {
                stepList.Trig = trig;
                stepList      = stepList.Next;
            }
            nameToken.data   = trig.Name;
            nameToken.length = (uint)nameToken.data.Length;
            DbFixer sFix = new DbFixer(); // Fixer object

            if (sFix.FixInit(parse, db, "trigger", nameToken) && sFix.FixTriggerStep(trig.StepList))
            {
                goto triggerfinish_cleanup;
            }

            // if we are not initializing, build the sqlite_master entry
            if (ctx.Init.Busy)
            {
                // Make an entry in the sqlite_master table
                Vdbe v = parse.GetVdbe();
                if (v == null)
                {
                    goto triggerfinish_cleanup;
                }
                parse.BeginWriteOperation(0, db);
                string z = all.data.Substring(0, (int)all.length); //: _tagstrndup(ctx, (char *)all->data, all->length);
                parse.NestedParse("INSERT INTO %Q.%s VALUES('trigger',%Q,%Q,0,'CREATE TRIGGER %q')", ctx.DBs[db].Name, E.SCHEMA_TABLE(db), name, trig.Table, z);
                C._tagfree(ctx, ref z);
                parse.ChangeCookie(db);
                v.AddParseSchemaOp(db, C._mtagprintf(ctx, "type='trigger' AND name='%q'", name));
            }

            if (!ctx.Init.Busy)
            {
                Trigger link = trig;
                Debug.Assert(Btree.SchemaMutexHeld(ctx, db, null));
                trig = ctx.DBs[db].Schema.TriggerHash.Insert(name, name.Length, trig);
                if (trig != null)
                {
                    ctx.MallocFailed = true;
                }
                else if (link.Schema == link.TabSchema)
                {
                    int   tableLength = link.Table.Length;
                    Table table       = (Table)link.TabSchema.TableHash.Find(link.Table, tableLength, (Table)null);
                    Debug.Assert(table != null);
                    link.Next      = table.Triggers;
                    table.Triggers = link;
                }
            }

triggerfinish_cleanup:
            DeleteTrigger(ctx, ref trig);
            Debug.Assert(parse.NewTrigger == null);
            DeleteTriggerStep(ctx, ref stepList);
        }