예제 #1
0
        private BoundExpression BindCoalesceExpression(CoalesceExpressionSyntax node)
        {
            // COALESCE(e1, e2, .. eN)
            //
            // ====>
            //
            // CASE
            //   WHEN e1 IS NOT NULL THEN e1
            //   ..
            //   WHEN e2 IS NOT NULL THEN e2
            //   ELSE
            //     eN
            // END

            var boundArguments = BindToCommonType(node.ArgumentList.Arguments);
            var caseLabelCount = node.ArgumentList.Arguments.Count - 1;
            var caseLabels     = new BoundCaseLabel[caseLabelCount];

            for (var i = 0; i < caseLabelCount; i++)
            {
                var argument              = node.ArgumentList.Arguments[i];
                var boundArgument         = boundArguments[i];
                var boundIsNullExpression = new BoundIsNullExpression(boundArgument);
                var boundIsNullNegation   = BindUnaryExpression(argument.Span, UnaryOperatorKind.LogicalNot, boundIsNullExpression);
                var caseLabel             = new BoundCaseLabel(boundIsNullNegation, boundArgument);
                caseLabels[i] = caseLabel;
            }

            var elseExpresion = boundArguments.Last();

            return(new BoundCaseExpression(caseLabels, elseExpresion));
        }
예제 #2
0
        private BoundExpression BindIsNullExpression(IsNullExpressionSyntax node)
        {
            var expression = BindExpression(node.Expression);
            var isNull     = new BoundIsNullExpression(expression);

            return(BindOptionalNegation(node.Span, node.NotKeyword, isNull));
        }
예제 #3
0
 protected virtual BoundExpression RewriteIsNullExpression(BoundIsNullExpression node)
 {
     return(node.Update(RewriteExpression(node.Expression)));
 }
예제 #4
0
 protected virtual void VisitIsNullExpression(BoundIsNullExpression node)
 {
     VisitExpression(node.Expression);
 }
예제 #5
0
        private BoundExpression BindAllAnySubselect(TextSpan diagnosticSpan, ExpressionSyntax leftNode, bool isAll, QuerySyntax queryNode, BinaryOperatorKind operatorKind)
        {
            // TODO: Ensure query has no ORDER BY unless TOP is also specified

            // First, let's bind the expression and the query

            var left       = BindExpression(leftNode);
            var boundQuery = BindSubquery(queryNode);

            // The right hand side of the binary expression is the first column of the query.

            if (boundQuery.OutputColumns.Length == 0)
            {
                var outputValue = ValueSlotFactory.CreateTemporary(typeof(bool));
                return(new BoundValueSlotExpression(outputValue));
            }

            if (boundQuery.OutputColumns.Length > 1)
            {
                Diagnostics.ReportTooManyExpressionsInSelectListOfSubquery(queryNode.Span);
            }

            var rightColumn = boundQuery.OutputColumns[0];
            var right       = new BoundValueSlotExpression(rightColumn.ValueSlot);

            // Now we need to bind the binary operator.
            //
            // To avoid cascading errors, we'll only validate the operator
            // if we could resolve both sides.

            if (left.Type.IsError() || right.Type.IsError())
            {
                return(new BoundErrorExpression());
            }

            var result = LookupBinaryOperator(operatorKind, left.Type, right.Type);

            if (result.Best == null)
            {
                if (result.Selected == null)
                {
                    Diagnostics.ReportCannotApplyBinaryOperator(diagnosticSpan, operatorKind, left.Type, right.Type);
                }
                else
                {
                    Diagnostics.ReportAmbiguousBinaryOperator(diagnosticSpan, operatorKind, left.Type, right.Type);
                }
            }

            // We may need to convert the arguments to the binary operator, so let's
            // bind them as arguments to the resolved operator.

            var convertedLeft  = BindArgument(left, result, 0);
            var convertedRight = BindArgument(right, result, 1);

            // If we need to convert the right side, then we musy insert a BoundComputeRelation
            // that produces a derived value.

            BoundRelation relation;

            if (convertedRight == right)
            {
                relation = boundQuery.Relation;
            }
            else
            {
                var outputValue     = ValueSlotFactory.CreateTemporary(convertedRight.Type);
                var outputValues    = new[] { outputValue };
                var computedValue   = new BoundComputedValue(convertedRight, outputValue);
                var computedValues  = new[] { computedValue };
                var computeRelation = new BoundComputeRelation(boundQuery.Relation, computedValues);
                relation       = new BoundProjectRelation(computeRelation, outputValues);
                convertedRight = new BoundValueSlotExpression(outputValue);
            }

            // In order to simplify later phases, we'll rewrite the the ALL/ANY subselect into
            // a regular EXISTS subselect. ANY is fairly straight forward:
            //
            //      left op ANY (SELECT right FROM ...)
            //
            //      ===>
            //
            //      EXISTS (SELECT * FROM ... WHERE left op right)
            //
            // ALL requires a bit more trickery as we need to handle NULL values in the negated
            // predicate correctly:
            //
            //      left op ALL (SELECT Column FROM ...)
            //
            //      ===>
            //
            //      NOT EXISTS (SELECT * FROM ... WHERE NOT (left op right) OR (left IS NULL) OR (right IS NULL))

            if (!isAll)
            {
                var condition = new BoundBinaryExpression(convertedLeft, operatorKind, result, convertedRight);
                var filter    = new BoundFilterRelation(relation, condition);
                return(new BoundExistsSubselect(filter));
            }
            else
            {
                var comparison        = new BoundBinaryExpression(convertedLeft, operatorKind, result, right);
                var negatedComparison = BindUnaryExpression(diagnosticSpan, UnaryOperatorKind.LogicalNot, comparison);
                var leftIsNull        = new BoundIsNullExpression(convertedLeft);
                var rightisNull       = new BoundIsNullExpression(right);
                var eitherSideIsNull  = BindBinaryExpression(diagnosticSpan, BinaryOperatorKind.LogicalOr, leftIsNull, rightisNull);
                var condition         = BindBinaryExpression(diagnosticSpan, BinaryOperatorKind.LogicalOr, negatedComparison, eitherSideIsNull);
                var filter            = new BoundFilterRelation(relation, condition);
                var existsSubselect   = new BoundExistsSubselect(filter);
                return(BindUnaryExpression(diagnosticSpan, UnaryOperatorKind.LogicalNot, existsSubselect));
            }
        }
예제 #6
0
 private static bool IsRejectingNull(BoundIsNullExpression expression, ValueSlot valueSlot)
 {
     return(!IsRejectingNull(expression.Expression, valueSlot));
 }