Expr() public method

public Expr ( Parser, yyq ) : System
yyq Parser,
return System
Example #1
0
        static void UpdateVirtualTable(Parse parse, SrcList src, Table table, ExprList changes, Expr rowid, int[] xrefs, Expr where_, int onError)
        {
            int        i;
            Context    ctx    = parse.Ctx; // Database connection
            VTable     vtable = VTable.GetVTable(ctx, table);
            SelectDest dest   = new SelectDest();

            // Construct the SELECT statement that will find the new values for all updated rows.
            ExprList list = ExprList.Append(parse, 0, Expr.Expr(ctx, TK.ID, "_rowid_")); // The result set of the SELECT statement

            if (rowid != null)
            {
                list = ExprList.Append(parse, list, Expr.Dup(ctx, rowid, 0));
            }
            Debug.Assert(table.PKey < 0);
            for (i = 0; i < table.Cols.length; i++)
            {
                Expr expr = (xrefs[i] >= 0 ? Expr.Dup(ctx, changes.Ids[xrefs[i]].Expr, 0) : Expr.Expr(ctx, TK.ID, table.Cols[i].Name)); // Temporary expression
                list = ExprList.Append(parse, list, expr);
            }
            Select select = Select.New(parse, list, src, where_, null, null, null, 0, null, null); // The SELECT statement

            // Create the ephemeral table into which the update results will be stored.
            Vdbe v = parse.V; // Virtual machine under construction

            Debug.Assert(v != null);
            int ephemTab = parse.Tabs++; // Table holding the result of the SELECT

            v.AddOp2(OP.OpenEphemeral, ephemTab, table.Cols.length + 1 + (rowid != null ? 1 : 0));
            v.ChangeP5(BTREE_UNORDERED);

            // fill the ephemeral table
            Select.DestInit(dest, SRT.Table, ephemTab);
            Select.Select(parse, select, ref dest);

            // Generate code to scan the ephemeral table and call VUpdate.
            int regId = ++parse.Mems;// First register in set passed to OP_VUpdate

            parse.Mems += table.Cols.length + 1;
            int addr = v.AddOp2(OP.Rewind, ephemTab, 0); // Address of top of loop

            v.AddOp3(OP.Column, ephemTab, 0, regId);
            v.AddOp3(OP.Column, ephemTab, (rowid != null ? 1 : 0), regId + 1);
            for (i = 0; i < table.nCol; i++)
            {
                v.AddOp3(OP.Column, ephemTab, i + 1 + (rowid != null ? 1 : 0), regId + 2 + i);
            }
            sqlite3VtabMakeWritable(parse, table);
            v.AddOp4(OP_VUpdate, 0, table.Cols.length + 2, regId, vtable, P4_VTAB);
            v.ChangeP5((byte)(onError == OE_Default ? OE_Abort : onError));
            parse.MayAbort();
            v.AddOp2(OP.Next, ephemTab, addr + 1);
            v.JumpHere(addr);
            v.AddOp2(OP.Close, ephemTab, 0);

            // Cleanup
            Select.Delete(ctx, ref select);
        }
Example #2
0
        static Trigger FKActionTrigger(Parse parse, Table table, FKey fkey, ExprList changes)
        {
            Context ctx      = parse.Ctx;                 // Database handle
            int     actionId = (changes != null ? 1 : 0); // 1 for UPDATE, 0 for DELETE
            OE      action   = fkey.Actions[actionId];    // One of OE_None, OE_Cascade etc.
            Trigger trigger  = fkey.Triggers[actionId];   // Trigger definition to return

            if (action != OE.None && trigger == null)
            {
                Index index = null; // Parent key index for this FK
                int[] cols  = null; // child table cols . parent key cols
                if (LocateFkeyIndex(parse, table, fkey, out index, out cols) != 0)
                {
                    return(null);
                }
                Debug.Assert(cols != null || fkey.Cols.length == 1);

                Expr     where_ = null; // WHERE clause of trigger step
                Expr     when   = null; // WHEN clause for the trigger
                ExprList list   = null; // Changes list if ON UPDATE CASCADE
                for (int i = 0; i < fkey.Cols.length; i++)
                {
                    Token oldToken = new Token("old", 3);                         // Literal "old" token
                    Token newToken = new Token("new", 3);                         // Literal "new" token

                    int fromColId = (cols != null ? cols[i] : fkey.Cols[0].From); // Idx of column in child table
                    Debug.Assert(fromColId >= 0);
                    Token fromCol = new Token();                                  // Name of column in child table
                    Token toCol   = new Token();                                  // Name of column in parent table
                    toCol.data     = (index != null ? table.Cols[index.Columns[i]].Name : "oid");
                    fromCol.data   = fkey.From.Cols[fromColId].Name;
                    toCol.length   = (uint)toCol.data.Length;
                    fromCol.length = (uint)fromCol.data.Length;

                    // Create the expression "OLD.zToCol = zFromCol". It is important that the "OLD.zToCol" term is on the LHS of the = operator, so
                    // that the affinity and collation sequence associated with the parent table are used for the comparison.
                    Expr eq = Expr.PExpr(parse, TK.EQ,
                                         Expr.PExpr(parse, TK.DOT,
                                                    Expr.PExpr(parse, TK.ID, null, null, oldToken),
                                                    Expr.PExpr(parse, TK.ID, null, null, toCol)
                                                    , 0),
                                         Expr.PExpr(parse, TK.ID, null, null, fromCol)
                                         , 0); // tFromCol = OLD.tToCol
                    where_ = Expr.And(ctx, where_, eq);

                    // For ON UPDATE, construct the next term of the WHEN clause. The final WHEN clause will be like this:
                    //
                    //    WHEN NOT(old.col1 IS new.col1 AND ... AND old.colN IS new.colN)
                    if (changes != null)
                    {
                        eq = Expr.PExpr(parse, TK.IS,
                                        Expr.PExpr(parse, TK.DOT,
                                                   Expr.PExpr(parse, TK.ID, null, null, oldToken),
                                                   Expr.PExpr(parse, TK.ID, null, null, toCol),
                                                   0),
                                        Expr.PExpr(parse, TK.DOT,
                                                   Expr.PExpr(parse, TK.ID, null, null, newToken),
                                                   Expr.PExpr(parse, TK.ID, null, null, toCol),
                                                   0),
                                        0);
                        when = Expr.And(ctx, when, eq);
                    }

                    if (action != OE.Restrict && (action != OE.Cascade || changes != null))
                    {
                        Expr newExpr;
                        if (action == OE.Cascade)
                        {
                            newExpr = Expr.PExpr(parse, TK.DOT,
                                                 Expr.PExpr(parse, TK.ID, null, null, newToken),
                                                 Expr.PExpr(parse, TK.ID, null, null, toCol)
                                                 , 0);
                        }
                        else if (action == OE.SetDflt)
                        {
                            Expr dfltExpr = fkey.From.Cols[fromColId].Dflt;
                            if (dfltExpr != null)
                            {
                                newExpr = Expr.Dup(ctx, dfltExpr, 0);
                            }
                            else
                            {
                                newExpr = Expr.PExpr(parse, TK.NULL, 0, 0, 0);
                            }
                        }
                        else
                        {
                            newExpr = Expr.PExpr(parse, TK.NULL, 0, 0, 0);
                        }
                        list = Expr.ListAppend(parse, list, newExpr);
                        Expr.ListSetName(parse, list, fromCol, 0);
                    }
                }
                C._tagfree(ctx, ref cols);

                string fromName       = fkey.From.Name;  // Name of child table
                int    fromNameLength = fromName.Length; // Length in bytes of zFrom

                Select select = null;                    // If RESTRICT, "SELECT RAISE(...)"
                if (action == OE.Restrict)
                {
                    Token from = new Token();
                    from.data   = fromName;
                    from.length = fromNameLength;
                    Expr raise = Expr.Expr(ctx, TK.RAISE, "foreign key constraint failed");
                    if (raise != null)
                    {
                        raise.Affinity = OE.Abort;
                    }
                    select = Select.New(parse,
                                        Expr.ListAppend(parse, 0, raise),
                                        SrcListAppend(ctx, 0, from, null),
                                        where_,
                                        null, null, null, 0, null, null);
                    where_ = null;
                }

                // Disable lookaside memory allocation
                bool enableLookaside = ctx.Lookaside.Enabled; // Copy of ctx->lookaside.bEnabled
                ctx.Lookaside.Enabled = false;

                trigger = new Trigger();
                //: trigger = (Trigger *)_tagalloc(ctx,
                //:    sizeof(Trigger) + // Trigger
                //:    sizeof(TriggerStep) + // Single step in trigger program
                //:    fromNameLength + 1 // Space for pStep->target.z
                //:    , true);
                TriggerStep step = null; // First (only) step of trigger program
                if (trigger != null)
                {
                    step               = trigger.StepList = new TriggerStep(); //: (TriggerStep)trigger[1];
                    step.Target.data   = fromName;                             //: (char *)&step[1];
                    step.Target.length = fromNameLength;
                    //: _memcpy((const char *)step->Target.data, fromName, fromNameLength);

                    step.Where    = Expr.Dup(ctx, where_, EXPRDUP_REDUCE);
                    step.ExprList = Expr.ListDup(ctx, list, EXPRDUP_REDUCE);
                    step.Select   = Select.Dup(ctx, select, EXPRDUP_REDUCE);
                    if (when != null)
                    {
                        when         = Expr.PExpr(parse, TK.NOT, when, 0, 0);
                        trigger.When = Expr.Dup(ctx, when, EXPRDUP_REDUCE);
                    }
                }

                // Re-enable the lookaside buffer, if it was disabled earlier.
                ctx.Lookaside.Enabled = enableLookaside;

                Expr.Delete(ctx, ref where_);
                Expr.Delete(ctx, ref when);
                Expr.ListDelete(ctx, ref list);
                Select.Delete(ctx, ref select);
                if (ctx.MallocFailed)
                {
                    FKTriggerDelete(ctx, trigger);
                    return(null);
                }

                switch (action)
                {
                case OE.Restrict:
                    step.OP = TK.SELECT;
                    break;

                case OE.Cascade:
                    if (changes == null)
                    {
                        step.OP = TK.DELETE;
                        break;
                    }
                    goto default;

                default:
                    step.OP = TK.UPDATE;
                    break;
                }
                step.Trigger            = trigger;
                trigger.Schema          = table.Schema;
                trigger.TabSchema       = table.Schema;
                fkey.Triggers[actionId] = trigger;
                trigger.OP = (TK)(changes != null ? TK.UPDATE : TK.DELETE);
            }

            return(trigger);
        }
Example #3
0
        static void FKScanChildren(Parse parse, SrcList src, Table table, Index index, FKey fkey, int[] cols, int regDataId, int incr)
        {
            Context ctx    = parse.Ctx; // Database handle
            Vdbe    v      = parse.GetVdbe();
            Expr    where_ = null;      // WHERE clause to scan with

            Debug.Assert(index == null || index.Table == table);
            int fkIfZero = 0; // Address of OP_FkIfZero

            if (incr < 0)
            {
                fkIfZero = v.AddOp2(OP.FkIfZero, fkey.IsDeferred, 0);
            }

            // Create an Expr object representing an SQL expression like:
            //
            //   <parent-key1> = <child-key1> AND <parent-key2> = <child-key2> ...
            //
            // The collation sequence used for the comparison should be that of the parent key columns. The affinity of the parent key column should
            // be applied to each child key value before the comparison takes place.
            for (int i = 0; i < fkey.Cols.length; i++)
            {
                int  col;                                      // Index of column in child table
                Expr left = Expr.Expr(ctx, TK.REGISTER, null); // Value from parent table row
                if (left != null)
                {
                    // Set the collation sequence and affinity of the LHS of each TK_EQ expression to the parent key column defaults.
                    if (index != null)
                    {
                        col = index.Columns[i];
                        Column colObj = table.Cols[col];
                        if (table.PKey == col)
                        {
                            col = -1;
                        }
                        left.TableId = regDataId + col + 1;
                        left.Aff     = colObj.Affinity;
                        string collName = colObj.Coll;
                        if (collName == null)
                        {
                            collName = ctx.DefaultColl.Name;
                        }
                        left = Expr.AddCollateString(parse, left, collName);
                    }
                    else
                    {
                        left.TableId = regDataId;
                        left.Aff     = AFF.INTEGER;
                    }
                }
                col = (cols != null ? cols[i] : fkey.Cols[0].From);
                Debug.Assert(col >= 0);
                string colName = fkey.From.Cols[col].Name;                 // Name of column in child table
                Expr   right   = Expr.Expr(ctx, TK.ID, colName);           // Column ref to child table
                Expr   eq      = Expr.PExpr(parse, TK.EQ, left, right, 0); // Expression (pLeft = pRight)
                where_ = Expr.And(ctx, where_, eq);
            }

            // If the child table is the same as the parent table, and this scan is taking place as part of a DELETE operation (operation D.2), omit the
            // row being deleted from the scan by adding ($rowid != rowid) to the WHERE clause, where $rowid is the rowid of the row being deleted.
            if (table == fkey.From && incr > 0)
            {
                Expr left  = Expr.Expr(ctx, TK.REGISTER, null); // Value from parent table row
                Expr right = Expr.Expr(ctx, TK.COLUMN, null);   // Column ref to child table
                if (left != null && right != null)
                {
                    left.TableId   = regDataId;
                    left.Aff       = AFF.INTEGER;
                    right.TableId  = src.Ids[0].Cursor;
                    right.ColumnId = -1;
                }
                Expr eq = Expr.PExpr(parse, TK.NE, left, right, 0); // Expression (pLeft = pRight)
                where_ = Expr.And(ctx, where_, eq);
            }

            // Resolve the references in the WHERE clause.
            NameContext nameContext;                 // Context used to resolve WHERE clause

            nameContext         = new NameContext(); // memset( &sNameContext, 0, sizeof( NameContext ) );
            nameContext.SrcList = src;
            nameContext.Parse   = parse;
            ResolveExprNames(nameContext, ref where_);

            // Create VDBE to loop through the entries in src that match the WHERE clause. If the constraint is not deferred, throw an exception for
            // each row found. Otherwise, for deferred constraints, increment the deferred constraint counter by incr for each row selected.
            ExprList  dummy     = null;
            WhereInfo whereInfo = Where.Begin(parse, src, where_, ref dummy, 0); // Context used by sqlite3WhereXXX()

            if (incr > 0 && !fkey.IsDeferred)
            {
                E.Parse_Toplevel(parse).MayAbort = true;
            }
            v.AddOp2(OP.FkCounter, fkey.IsDeferred, incr);
            if (whereInfo != null)
            {
                Where.End(whereInfo);
            }

            // Clean up the WHERE clause constructed above.
            Expr.Delete(ctx, ref where_);
            if (fkIfZero != 0)
            {
                v.JumpHere(fkIfZero);
            }
        }