예제 #1
0
        private Expression SimplifyTerm(Expression expression)
        {
            if (expression is FunctionExpression) {
                FunctionExpression functionExp = (FunctionExpression) expression;

                // Get the function name
                string functionName = functionExp.Name;
                // If the function is an object comparator,
                if (IsSimpleComparison(functionName)) {
                    // First try and simplify,
                    Expression p1 = SimplifyTerm((Expression) functionExp.Parameters[0]);
                    Expression p2 = SimplifyTerm((Expression) functionExp.Parameters[1]);
                    // Is one of the terms is a fetchvar and the other is static, then
                    // we can make a selectable range set function.
                    Variable v1 = AsVariable(p1);
                    Variable v2 = AsVariable(p2);
                    SqlObject[] r1 = EvaluateExpression(p1);
                    SqlObject[] r2 = EvaluateExpression(p2);

                    Variable v;
                    SqlObject[] ob;
                    string rangeOp;
                    if (v1 != null && r2 != null) {
                        v = v1;
                        ob = r2;
                        rangeOp = functionName;
                    } else if (v2 != null && r1 != null) {
                        // We need to reverse the operator in this case
                        v = v2;
                        ob = r1;
                        rangeOp = ReverseSimpleComparison(functionName);
                    } else {
                        // if both are static, evaluate and return the operation
                        FunctionExpression new_fun = new FunctionExpression(functionName, new Expression[] { p1, p2 });
                        if (r1 != null && r2 != null)
                            return new FetchStaticExpression(EvaluateExpression(new_fun));

                        // Can't simplify
                        return new_fun;
                    }

                    // Make the range set,
                    SelectableRange rangeSet = SelectableRange.Full;
                    rangeSet = rangeSet.Intersect(SelectableRange.GetOperatorFromFunction(rangeOp), ob);
                    FunctionExpression funExp = new FunctionExpression("range_set");
                    funExp.Parameters.Add(new FetchVariableExpression(v));
                    funExp.Parameters.Add(rangeSet);
                    funExp.SetArgument("full_range_object", ob);
                    return funExp;
                }

                if (IsSimpleLogical(functionName)) {
                    // either and/or
                    // If it's a logical operation
                    Expression p1 = SimplifyTerm((Expression) functionExp.Parameters[0]);
                    Expression p2 = SimplifyTerm((Expression) functionExp.Parameters[1]);
                    // Can we combine the terms?
                    Variable v1 = GetSingleVariable(p1);
                    Variable v2 = GetSingleVariable(p2);

                    // If one of the terms is a range set
                    bool success;
                    Expression otherTerm = null;
                    if (v1 != null) {
                        Variable v = v1;
                        FunctionExpression rangeSetTerm = (FunctionExpression) p1;
                        otherTerm = p2;
                        success = AttemptRangeSetMerge(v, rangeSetTerm, otherTerm, functionName);
                    } else if (v2 != null) {
                        Variable v = v2;
                        FunctionExpression rangeSetTerm = (FunctionExpression) p2;
                        otherTerm = p1;
                        success = AttemptRangeSetMerge(v, rangeSetTerm, otherTerm, functionName);
                    } else {
                        // Neither left or right is a 'range_set'
                        success = false;
                    }

                    // Try and merge the range set term with the other term
                    // If it was a success, then we return the other term,
                    if (success)
                        return otherTerm;

                    // Otherwise, look for a static term,

                    // If one of the terms is a static,
                    SqlObject[] r1 = EvaluateExpression(p1);
                    SqlObject[] r2 = EvaluateExpression(p2);
                    SqlObject[] staticVal = null;
                    Expression nonStaticVal = null;
                    if (r1 != null && r2 != null) {
                        // Both are static, so evaluate and return
                        FunctionExpression newFun = new FunctionExpression(functionName, new Expression[] {p1, p2});
                        return new FetchStaticExpression(EvaluateExpression(newFun));
                    }
                    if (r1 != null) {
                        staticVal = r1;
                        nonStaticVal = p2;
                    } else if (r2 != null) {
                        staticVal = r2;
                        nonStaticVal = p1;
                    }
                    // If one of the sides is static,
                    if (staticVal != null) {
                        // If it's a single value,
                        if (staticVal.Length == 1) {
                            SqlObject tv = staticVal[0];
                            if (tv.Type.IsBoolean) {
                                bool? valb = tv.Value.ToBoolean();
                                if (valb != null) {
                                    // If it's true
                                    if (valb == true)
                                        return functionName.Equals("or") ? new FetchStaticExpression(staticVal) : nonStaticVal;

                                    // If it's false
                                    if (valb == false)
                                        return functionName.Equals("or") ? nonStaticVal : new FetchStaticExpression(staticVal);
                                }
                            }
                        } else {
                            // If it's not true of false
                            return functionName.Equals("or") ? nonStaticVal : new FetchStaticExpression(SqlObject.MakeNull(SqlType.GetSqlType(typeof(bool))));
                        }
                    }

                    // Ok, neither side static,

                    // If one of the sides is a range_set, then we search the other side
                    // of the tree for a potential term to merge with.

                    return new FunctionExpression(functionName, new Expression[] {p1, p2});
                }

                // Perhaps we can simplify a static operation?
                // Simplify the terms of the functions arguments,
                int sz = functionExp.Parameters.Count;
                object[] newParams = new object[sz];
                bool allStaticParams = true;
                for (int i = 0; i < sz; ++i) {
                    object ob = functionExp.Parameters[i];
                    if (ob != null && ob is Expression) {
                        Expression paramExp = (Expression)ob;
                        paramExp = SimplifyTerm(paramExp);
                        newParams[i] = paramExp;
                        if (!(paramExp is FetchStaticExpression))
                            allStaticParams = false;
                    } else {
                        newParams[i] = ob;
                    }
                }

                // If the function graph is static, evaluate it and return the fetch
                // static operation
                FunctionExpression funcExp = new FunctionExpression(functionName);
                for (int i = 0; i < sz; ++i) {
                    funcExp.Parameters.Add(newParams[i]);
                }
                if (allStaticParams &&
                    IsSimpleEvaluable(functionName)) {
                    return new FetchStaticExpression(EvaluateExpression(funcExp));
                }

                return funcExp;
            }
            return expression;
        }