Пример #1
0
        private Expression BindBinaryOperatorQueryNode(BinaryOperatorQueryNode binaryOperatorNode)
        {
            Expression left  = Bind(binaryOperatorNode.Left);
            Expression right = Bind(binaryOperatorNode.Right);

            // handle null propagation only if either of the operands can be null
            bool isNullPropagationRequired = _querySettings.HandleNullPropagation == HandleNullPropagationOption.True && (IsNullable(left.Type) || IsNullable(right.Type));

            if (isNullPropagationRequired)
            {
                // |----------------------------------------------------------------|
                // |SQL 3VL truth table.                                            |
                // |----------------------------------------------------------------|
                // |p       |    q      |    p OR q     |    p AND q    |    p = q  |
                // |----------------------------------------------------------------|
                // |True    |   True    |   True        |   True        |   True    |
                // |True    |   False   |   True        |   False       |   False   |
                // |True    |   NULL    |   True        |   NULL        |   NULL    |
                // |False   |   True    |   True        |   False       |   False   |
                // |False   |   False   |   False       |   False       |   True    |
                // |False   |   NULL    |   NULL        |   False       |   NULL    |
                // |NULL    |   True    |   True        |   NULL        |   NULL    |
                // |NULL    |   False   |   NULL        |   False       |   NULL    |
                // |NULL    |   NULL    |   Null        |   NULL        |   NULL    |
                // |--------|-----------|---------------|---------------|-----------|

                // before we start with null propagation, convert the operators to nullable if already not.
                left  = ToNullable(left);
                right = ToNullable(right);

                bool liftToNull = true;
                if (left == _nullConstant || right == _nullConstant)
                {
                    liftToNull = false;
                }

                // Expression trees do a very good job of handling the 3VL truth table if we pass liftToNull true.
                return(CreateBinaryExpression(binaryOperatorNode.OperatorKind, left, right, liftToNull: liftToNull));
            }
            else
            {
                return(CreateBinaryExpression(binaryOperatorNode.OperatorKind, left, right, liftToNull: false));
            }
        }
Пример #2
0
        private string BindOperator(BinaryOperatorQueryNode binaryOperatorNode)
        {
            var left = binaryOperatorNode.Left is ConstantQueryNode
                           ? MakeSparqlConstant((binaryOperatorNode.Left as ConstantQueryNode).Value)
                           : ProcessNode(binaryOperatorNode.Left);
            var right = binaryOperatorNode.Right is ConstantQueryNode
                            ? MakeSparqlConstant((binaryOperatorNode.Right as ConstantQueryNode).Value)
                            : ProcessNode(binaryOperatorNode.Right);

            if (left is VariableIdentifierBinding)
            {
                if (binaryOperatorNode.Right is ConstantQueryNode)
                {
                    var constantValue = (binaryOperatorNode.Right as ConstantQueryNode).Value.ToString();
                    var uri = (left as VariableIdentifierBinding).IdentifierPrefix + constantValue;
                    switch (binaryOperatorNode.OperatorKind)
                    {
                        case BinaryOperatorKind.Equal:
                            return String.Format("sameTerm(?{0}, <{1}>)",
                                                 (left as VariableIdentifierBinding).VariableName, uri);
                        case BinaryOperatorKind.NotEqual:
                            return String.Format("!(sameTerm(?{0}, <{1}>)",
                                                 (left as VariableIdentifierBinding).VariableName,
                                                 uri);
                        default:
                            throw new NotImplementedException("No support for operator " +
                                                              binaryOperatorNode.OperatorKind +
                                                              " over a resource identifier property.");
                    }
                }
                throw new NotImplementedException("Identifier properties can only be compared to a constant value");
            }

            switch (binaryOperatorNode.OperatorKind)
            {
                // Logical operators
                case BinaryOperatorKind.Equal:
                    return left + " = " + right;
                case BinaryOperatorKind.GreaterThan:
                    return left + " > " + right;
                case BinaryOperatorKind.LessThan:
                    return left + " < " + right;
                case BinaryOperatorKind.NotEqual:
                    return left + " != " + right;
                case BinaryOperatorKind.GreaterThanOrEqual:
                    return left + " >= " + right;
                case BinaryOperatorKind.LessThanOrEqual:
                    return left + " <= " + right;
                case BinaryOperatorKind.And:
                    return "(" + left + ") && (" + right + ")";
                case BinaryOperatorKind.Or:
                    return "(" + left + ") || (" + right + ")";
                // Arithmetic operators
                case BinaryOperatorKind.Add:
                    return "(" + left + " + " + right + ")";
                case BinaryOperatorKind.Subtract:
                    return "(" + left + " - " + right + ")";
                case BinaryOperatorKind.Multiply:
                    return "(" + left + " * " + right + ")";
                case BinaryOperatorKind.Divide:
                    return "(" + left + " / " + right + ")";
                case BinaryOperatorKind.Modulo:
                    throw new NotSupportedException("There is no SPARQL equivalent for the OData mod operator");
                default:
                    throw new NotImplementedException("No support for " + binaryOperatorNode.OperatorKind);
            }
        }
        /// <summary>
        /// Translates a binary operator node.
        /// </summary>
        /// <param name="binaryOperatorNode">The binary operator node to translate.</param>
        /// <returns>Expression which evaluates to the result of the binary operator.</returns>
        protected virtual Expression TranslateBinaryOperator(BinaryOperatorQueryNode binaryOperatorNode)
        {
            ExceptionUtils.CheckArgumentNotNull(binaryOperatorNode, "binaryOperatorNode");
            ExceptionUtils.CheckArgumentNotNull(binaryOperatorNode.Left, "binaryOperatorNode.Left");
            ExceptionUtils.CheckArgumentNotNull(binaryOperatorNode.Right, "binaryOperatorNode.Right");

            Expression left = this.Translate(binaryOperatorNode.Left);
            Expression right = this.Translate(binaryOperatorNode.Right);

            // If the operands both statically are null literals we optimize the operator to result in the 
            // null literal as well (per specification) because we otherwise cannot execute such an expression tree
            if (left == nullLiteralExpression && right == nullLiteralExpression)
            {
                // Equality operators have special rules if one (or both) operands are null
                if (binaryOperatorNode.OperatorKind == BinaryOperatorKind.Equal)
                {
                    return trueLiteralExpression;
                }
                else if (binaryOperatorNode.OperatorKind == BinaryOperatorKind.NotEqual)
                {
                    return falseLiteralExpression;
                }

                return nullLiteralExpression;
            }

            Debug.Assert(left != nullLiteralExpression && right != nullLiteralExpression, "None of the operands should be the untyped literal null expression at this point.");

            // throw if no type is available
            if (binaryOperatorNode.TypeReference == null)
            {
                throw new ODataException(Strings.QueryExpressionTranslator_SingleValueQueryNodeWithoutTypeReference(binaryOperatorNode.Kind));
            }

            // Deal with null propagation; after translating the operands to expressions one (or both) can have changed from a non-nullable type to a
            // nullable type if null propagation is enabled; compensate for that.
            if (this.nullPropagationRequired)
            {
                HandleBinaryOperatorNullPropagation(ref left, ref right);
            }
            else
            {
                Debug.Assert(left.Type == right.Type, "left.Type == right.Type");
            }

            // TODO: Deal with open properties
            // See RequestQueryParser.ExpressionParser.GenerateComparisonExpression for the actual complexity required for comparison operators
            switch (binaryOperatorNode.OperatorKind)
            {
                case BinaryOperatorKind.Or:
                    return Expression.OrElse(left, right);
                case BinaryOperatorKind.And:
                    return Expression.AndAlso(left, right);

                case BinaryOperatorKind.Equal:
                    if (left.Type == typeof(byte[]))
                    {
                        return Expression.Equal(left, right, false, DataServiceProviderMethods.AreByteArraysEqualMethodInfo);
                    }
                    else
                    {
                        return Expression.Equal(left, right);
                    }

                case BinaryOperatorKind.NotEqual:
                    if (left.Type == typeof(byte[]))
                    {
                        return Expression.NotEqual(left, right, false, DataServiceProviderMethods.AreByteArraysNotEqualMethodInfo);
                    }
                    else
                    {
                        return Expression.NotEqual(left, right);
                    }

                case BinaryOperatorKind.GreaterThan:
                    return CreateGreaterThanExpression(left, right);
                case BinaryOperatorKind.GreaterThanOrEqual:
                    return CreateGreaterThanOrEqualExpression(left, right);
                case BinaryOperatorKind.LessThan:
                    return CreateLessThanExpression(left, right);
                case BinaryOperatorKind.LessThanOrEqual:
                    return CreateLessThanOrEqualExpression(left, right);

                case BinaryOperatorKind.Add:
                    return Expression.Add(left, right);
                case BinaryOperatorKind.Subtract:
                    return Expression.Subtract(left, right);

                case BinaryOperatorKind.Multiply:
                    return Expression.Multiply(left, right);
                case BinaryOperatorKind.Divide:
                    return Expression.Divide(left, right);
                case BinaryOperatorKind.Modulo:
                    return Expression.Modulo(left, right);

                default:
                    throw new ODataException(Strings.General_InternalError(InternalErrorCodes.QueryExpressionTranslator_TranslateBinaryOperator_UnreachableCodepath));
            }
        }
Пример #4
0
        private string BindOperator(BinaryOperatorQueryNode binaryOperatorNode)
        {
            var left = binaryOperatorNode.Left is ConstantQueryNode
                           ? MakeSparqlConstant((binaryOperatorNode.Left as ConstantQueryNode).Value)
                           : ProcessNode(binaryOperatorNode.Left);

            var right = binaryOperatorNode.Right is ConstantQueryNode
                            ? MakeSparqlConstant((binaryOperatorNode.Right as ConstantQueryNode).Value)
                            : ProcessNode(binaryOperatorNode.Right);

            if (left is VariableIdentifierBinding)
            {
                if (binaryOperatorNode.Right is ConstantQueryNode)
                {
                    var constantValue = (binaryOperatorNode.Right as ConstantQueryNode).Value.ToString();
                    var uri           = (left as VariableIdentifierBinding).IdentifierPrefix + constantValue;
                    switch (binaryOperatorNode.OperatorKind)
                    {
                    case BinaryOperatorKind.Equal:
                        return(String.Format("sameTerm(?{0}, <{1}>)",
                                             (left as VariableIdentifierBinding).VariableName, uri));

                    case BinaryOperatorKind.NotEqual:
                        return(String.Format("!(sameTerm(?{0}, <{1}>)",
                                             (left as VariableIdentifierBinding).VariableName,
                                             uri));

                    default:
                        throw new NotImplementedException("No support for operator " +
                                                          binaryOperatorNode.OperatorKind +
                                                          " over a resource identifier property.");
                    }
                }
                throw new NotImplementedException("Identifier properties can only be compared to a constant value");
            }

            switch (binaryOperatorNode.OperatorKind)
            {
            // Logical operators
            case BinaryOperatorKind.Equal:
                return(left + " = " + right);

            case BinaryOperatorKind.GreaterThan:
                return(left + " > " + right);

            case BinaryOperatorKind.LessThan:
                return(left + " < " + right);

            case BinaryOperatorKind.NotEqual:
                return(left + " != " + right);

            case BinaryOperatorKind.GreaterThanOrEqual:
                return(left + " >= " + right);

            case BinaryOperatorKind.LessThanOrEqual:
                return(left + " <= " + right);

            case BinaryOperatorKind.And:
                return("(" + left + ") && (" + right + ")");

            case BinaryOperatorKind.Or:
                return("(" + left + ") || (" + right + ")");

            // Arithmetic operators
            case BinaryOperatorKind.Add:
                return("(" + left + " + " + right + ")");

            case BinaryOperatorKind.Subtract:
                return("(" + left + " - " + right + ")");

            case BinaryOperatorKind.Multiply:
                return("(" + left + " * " + right + ")");

            case BinaryOperatorKind.Divide:
                return("(" + left + " / " + right + ")");

            case BinaryOperatorKind.Modulo:
                throw new NotSupportedException("There is no SPARQL equivalent for the OData mod operator");

            default:
                throw new NotImplementedException("No support for " + binaryOperatorNode.OperatorKind);
            }
        }