예제 #1
0
        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
        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);
            }
        }