Example #1
0
        // during type coerse, we may have to change el/er type. Consider this case:
        //  el+er where el= 2.5 double, er = 10 decimal
        // their result is decimal as decimal has higher precedence so we have to
        // convert el to decimal to avoid later operator+ suprise.
        //
        public static ColumnType CoerseType(string op, Expr el, Expr er)
        {
            ColumnType result = null;
            ColumnType l      = el.type_;
            ColumnType r      = er.type_;

            if (l.Equals(r))
            {
                return(l);
            }
            else
            {
                Type coertype = TypeBase.HigherPrecedence(l, r);

                // these types needs precision etc further handling
                if (coertype == typeof(NumericType))
                {
                    if (l is DoubleType && r is NumericType rnum)
                    {
                        result   = new NumericType(rnum.len_, rnum.scale_);
                        el.type_ = result;
                        if (el is ConstExpr ell)
                        {
                            ell.val_ = Convert.ToDecimal(ell.val_);
                        }
                    }
                    else if (r is DoubleType && l is NumericType lnum)
                    {
                        result   = new NumericType(lnum.len_, lnum.scale_);
                        er.type_ = result;
                        if (er is ConstExpr erl)
                        {
                            erl.val_ = Convert.ToDecimal(erl.val_);
                        }
                    }
                    else if (l is NumericType || r is NumericType)
                    {
                        // FIXME: this is a rough calculation
                        int prec = 0, scale = 0;
                        if (l is NumericType ln)
                        {
                            prec = ln.len_; scale = ln.scale_;
                        }
                        if (r is NumericType rn)
                        {
                            prec  = Math.Max(rn.len_, prec);
                            scale = Math.Max(rn.scale_, scale);
                        }
                        result = new NumericType(prec, scale);
                    }
                }
                else if (TypeBase.IsStringType(l) && TypeBase.IsStringType(r))
                {
                    result = new VarCharType(Int32.MaxValue);
                }
                else
                {
                    result = (ColumnType)Activator.CreateInstance(coertype);
                }
            }

            Debug.Assert(result != null);
            return(result);
        }
Example #2
0
        public override Expr Normalize()
        {
            // all children get normalized first
            for (int i = 0; i < children_.Count; ++i)
            {
                Expr x = children_[i];
                children_[i] = x.Normalize();
            }

            Expr      l   = lchild_();
            Expr      r   = rchild_();
            ConstExpr lce = (l is ConstExpr) ? (ConstExpr)l : null;
            ConstExpr rce = (r is ConstExpr) ? (ConstExpr)r : null;

            switch (op_)
            {
            case "+":
            case "-":
            case "*":
            case "/":
            case ">":
            case ">=":
            case "<":
            case "<=":
            case "||":
            case "=":
            case "<>":
            case "!=":
            case " and ":
            case " or ":
            case "is":
            case "is not":
                if ((lce != null && lce.val_ is null) || (rce != null && rce.val_ is null))
                {
                    if (IsRelOp())
                    {
                        // needs to be TRUE or FALSE
                        if ((op_ == "is") || (op_ == "is not") || (lce != null && TypeBase.IsNumberType(l.type_)) || (rce != null && TypeBase.IsNumberType(r.type_)))
                        {
                            return(SimplifyRelop());
                        }
                    }

                    // NULL simplification: if operator is not relational, X op NULL is NULL
                    if (lce != null && lce.val_ is null)
                    {
                        return(lce);
                    }

                    if (rce != null && rce.IsNull())
                    {
                        return(rce);
                    }
                }

                if (lce != null && rce != null)
                {
                    // Simplify Constants: children are not non null constants, evaluate them.
                    Value val = Exec(null, null);
                    return(ConstExpr.MakeConst(val, type_, outputName_));
                }

                if (lce != null && rce == null && isPlainSwappableConstOp())
                {
                    SwapSide();
                }

                if ((lce != null || rce != null) && (IsArithIdentity(lce, rce)))
                {
                    return(SimplifyArithmetic(lce, rce));
                }

                if (IsLogicalOp())
                {
                    return(SimplifyLogic());
                }

                if (IsRelOp())
                {
                    return(SimplifyRelop());
                }

                // arithmetic operators?
                if (l is BinExpr le && le.children_[1].IsConst() && (rce != null) &&
                    isCommutativeConstOp() && le.isCommutativeConstOp() && TypeBase.SameArithType(l.type_, r.type_))
                {
                    /*
                     * Here root is distributive operator (only * in this context) left is Commutative
                     * operator, +, or * right is constant, furthermore, left's right is a constant
                     * (becuase we swapped cosntant to be on the right).
                     * if be == + and l == +: add left's right value to root's right value,
                     * make  left's left as left of root
                     *
                     * if be == * and l == +: create a expr node as left (x + 10), create (5 * 10)
                     * as right, change operator to +
                     * In either case left and right's children must be nulled out
                     * and since we are going bottom up, this doesn't create any problem.
                     *
                     * Here is a pictorial description:
                     *                         *         root           +
                     *              old left  / \ old right   new left / \  new right
                     *                       /   \                    /   \
                     *                      +     10        =>       *     50
                     *  left of old left   / \                      / \
                     *                    /   \ ROL         LNL    /   \ RNL (right of New Left)
                     *                   x     5                  x     10
                     */

                    /*
                     * Simple case: when current and left are same operators, distributive
                     * opeartion and node creation is uncessary.
                     */
                    if ((op_ == "+" && le.op_ == "+") || (op_ == "*" && le.op_ == "*"))
                    {
                        /* create new right node as constant. */
                        Expr tmpexp = Clone();
                        tmpexp.children_[0] = le.children_[1];
                        tmpexp.children_[1] = r;
                        tmpexp.type_        = r.type_;

                        Value val;
                        bool  wasConst = tmpexp.TryEvalConst(out val);
                        Expr  newr     = ConstExpr.MakeConst(val, tmpexp.type_, r.outputName_);

                        // new left is old left's left child
                        // of left will be right of the root.
                        children_[0] = l.children_[0];

                        // new right is the new constant node
                        children_[1] = newr;
                    }
                    else
                    if (op_ == "*" && le.rchild_() is ConstExpr lrc && (le.op_ == "+" || le.op_ == "-"))
                    {
                        /*
                         * case of (a + const1) * const2  => (a * const2) + (const1 * const2))
                         * make a newe left node to house (a * const2)
                         *
                         *                          *                    +
                         *                         / \                  / \
                         *                        /   \                /   \
                         *                       +     c2     =>      *   c1 * c2
                         *                      / \                  / \
                         *                     /   \                /   \
                         *                    X     c1             X     c2
                         *
                         */

                        /* make a const expr node to evaluate const1 * const 2 */
                        Expr tmpexp = Clone();
                        tmpexp.children_[0] = lrc;      // right of left is const
                        tmpexp.children_[1] = r;        // our right is const
                        tmpexp.type_        = r.type_;

                        Value val;
                        tmpexp.TryEvalConst(out val);

                        // set c2 as the value of right child of our left
                        lrc.val_ = rce.val_;

                        // val is c1 * c2, set it as the value of our right child
                        rce.val_ = val;

                        /* swap the operators */
                        string op = op_;
                        op_    = le.op_;
                        le.op_ = op;
                    }
                    /* we can't do any thing about + at the top and * as left child. */
                }

                return(this);
            }

            return(this);
        }