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)); }
private BoundExpression BindIsNullExpression(IsNullExpressionSyntax node) { var expression = BindExpression(node.Expression); var isNull = new BoundIsNullExpression(expression); return(BindOptionalNegation(node.Span, node.NotKeyword, isNull)); }
protected virtual BoundExpression RewriteIsNullExpression(BoundIsNullExpression node) { return(node.Update(RewriteExpression(node.Expression))); }
protected virtual void VisitIsNullExpression(BoundIsNullExpression node) { VisitExpression(node.Expression); }
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)); } }
private static bool IsRejectingNull(BoundIsNullExpression expression, ValueSlot valueSlot) { return(!IsRejectingNull(expression.Expression, valueSlot)); }