public override ExpressionNode VisitCaseExpression(CaseExpression expression) { _xmlWriter.WriteStartElement("caseExpression"); WriteTypeAttribute(expression.ExpressionType); if (expression.InputExpression != null) { WriteAstNode("inputExpression", expression.InputExpression); } for (int i = 0; i < expression.WhenExpressions.Length; i++) { _xmlWriter.WriteStartElement("whenThenPair"); _xmlWriter.WriteAttributeString("index", XmlConvert.ToString(i)); WriteAstNode("whenExpression", expression.WhenExpressions[i]); WriteAstNode("thenExpression", expression.ThenExpressions[i]); _xmlWriter.WriteEndElement(); } if (expression.ElseExpression != null) { WriteAstNode("elseExpression", expression.ElseExpression); } _xmlWriter.WriteEndElement(); return(expression); }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { if (expression.InputExpression == null) { _writer.Write("CASE"); } else { _writer.Write("CASE "); Visit(expression.InputExpression); } for (int i = 0; i < expression.WhenExpressions.Length && i < expression.ThenExpressions.Length; i++) { _writer.Write(" WHEN "); Visit(expression.WhenExpressions[i]); _writer.Write(" THEN "); Visit(expression.ThenExpressions[i]); } if (expression.ElseExpression != null) { _writer.Write(" ELSE "); Visit(expression.ElseExpression); } _writer.Write(" END"); return(expression); }
public override AstElement Clone(Dictionary <AstElement, AstElement> alreadyClonedElements) { CaseExpression result = new CaseExpression(); if (_inputExpression != null) { result.InputExpression = (ExpressionNode)_inputExpression.Clone(alreadyClonedElements); } if (_elseExpression != null) { result.ElseExpression = (ExpressionNode)_elseExpression.Clone(alreadyClonedElements); } result.WhenExpressions = new ExpressionNode[_whenExpressions.Length]; for (int i = 0; i < _whenExpressions.Length; i++) { result.WhenExpressions[i] = (ExpressionNode)_whenExpressions[i].Clone(alreadyClonedElements); } result.ThenExpressions = new ExpressionNode[_thenExpressions.Length]; for (int i = 0; i < _thenExpressions.Length; i++) { result.ThenExpressions[i] = (ExpressionNode)_thenExpressions[i].Clone(alreadyClonedElements); } result.ResultType = _resultType; return(result); }
public override ExpressionNode VisitNullIfExpression(NullIfExpression expression) { // First visit all expressions base.VisitNullIfExpression(expression); // Since a NULLIF expression can be expressed using a CASE expression we convert // them to simplify the evaluation and optimization engine. // // NULLIF(expression1, expression1) is equivalent to this CASE expression: // // CASE // WHEN expression1 = expression2 THEN NULL // ELSE expression1 // END CaseExpression caseExpression = new CaseExpression(); caseExpression.WhenExpressions = new ExpressionNode[1]; caseExpression.ThenExpressions = new ExpressionNode[1]; caseExpression.WhenExpressions[0] = new BinaryExpression(BinaryOperator.Equal, expression.LeftExpression, expression.RightExpression); caseExpression.ThenExpressions[0] = LiteralExpression.FromNull(); caseExpression.ElseExpression = expression.LeftExpression; return(VisitExpression(caseExpression)); }
public override ExpressionNode VisitCoalesceExpression(CoalesceExpression expression) { // First visit all expressions base.VisitCoalesceExpression(expression); // Since a COALESCE expression can be expressed using a CASE expression we convert // them to simplify the evaluation and optimization engine. // // COALESCE(expression1,...,expressionN) is equivalent to this CASE expression: // // CASE // WHEN (expression1 IS NOT NULL) THEN expression1 // ... // WHEN (expressionN IS NOT NULL) THEN expressionN // END CaseExpression caseExpression = new CaseExpression(); caseExpression.WhenExpressions = new ExpressionNode[expression.Expressions.Length]; caseExpression.ThenExpressions = new ExpressionNode[expression.Expressions.Length]; for (int i = 0; i < expression.Expressions.Length; i++) { ExpressionNode whenPart = expression.Expressions[i]; ExpressionNode thenPart = (ExpressionNode)whenPart.Clone(); caseExpression.WhenExpressions[i] = new IsNullExpression(true, whenPart); caseExpression.ThenExpressions[i] = thenPart; } return(VisitExpression(caseExpression)); }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { // NOTE: It is assumed that simple case expressions are already transformed into // searched case expressions, i.e. // CASE // WHEN Pred1 THEN Expr1 ... // WHEN PredN THEN ExprN // [ELSE ElseExpr] // END List <ExpressionNode> processedWhenExpressions = new List <ExpressionNode>(); for (int i = 0; i < expression.WhenExpressions.Length; i++) { SetWhenPassthru(processedWhenExpressions); expression.WhenExpressions[i] = VisitExpression(expression.WhenExpressions[i]); processedWhenExpressions.Add(expression.WhenExpressions[i]); SetThenPassthru(processedWhenExpressions); expression.ThenExpressions[i] = VisitExpression(expression.ThenExpressions[i]); } if (expression.ElseExpression != null) { SetWhenPassthru(processedWhenExpressions); expression.ElseExpression = VisitExpression(expression.ElseExpression); } _currentPassthruPredicate = null; return(expression); }
private static bool VisitCaseExpression(CaseExpression node1, CaseExpression node2) { if (node2 == null) { return(false); } if (node1.InputExpression != null) { if (!Visit(node1.InputExpression, node2.InputExpression)) { return(false); } } if (node1.WhenExpressions.Length != node2.WhenExpressions.Length || node1.ThenExpressions.Length != node2.ThenExpressions.Length) { return(false); } for (int i = 0; i < node1.WhenExpressions.Length; i++) { if (!Visit(node1.WhenExpressions[i], node2.WhenExpressions[i])) { return(false); } } for (int i = 0; i < node1.ThenExpressions.Length; i++) { if (!Visit(node1.ThenExpressions[i], node2.ThenExpressions[i])) { return(false); } } if (node1.ElseExpression != null) { if (!Visit(node1.ElseExpression, node2.ElseExpression)) { return(false); } } return(true); }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { // NOTE: Must be searched CASE. The normalizer should have replaced it. Label finishLabel = _ilEmitContext.ILGenerator.DefineLabel(); Label[] caseLabels = new Label[expression.WhenExpressions.Length + 1]; for (int i = 0; i < expression.WhenExpressions.Length; i++) { caseLabels[i] = _ilEmitContext.ILGenerator.DefineLabel(); } Label elseLabel = _ilEmitContext.ILGenerator.DefineLabel(); caseLabels[expression.WhenExpressions.Length] = elseLabel; for (int i = 0; i < expression.WhenExpressions.Length; i++) { _ilEmitContext.ILGenerator.MarkLabel(caseLabels[i]); int whenLocalIndex = DeclareLocal(); Visit(expression.WhenExpressions[i]); _ilEmitContext.ILGenerator.Emit(OpCodes.Stloc, whenLocalIndex); _ilEmitContext.ILGenerator.Emit(OpCodes.Ldloc, whenLocalIndex); _ilEmitContext.ILGenerator.Emit(OpCodes.Brfalse, caseLabels[i + 1]); _ilEmitContext.ILGenerator.Emit(OpCodes.Ldloc, whenLocalIndex); _ilEmitContext.ILGenerator.Emit(OpCodes.Unbox_Any, typeof(bool)); _ilEmitContext.ILGenerator.Emit(OpCodes.Brfalse, caseLabels[i + 1]); Visit(expression.ThenExpressions[i]); _ilEmitContext.ILGenerator.Emit(OpCodes.Br, finishLabel); } _ilEmitContext.ILGenerator.MarkLabel(elseLabel); if (expression.ElseExpression != null) { Visit(expression.ElseExpression); } else { _ilEmitContext.ILGenerator.Emit(OpCodes.Ldnull); } _ilEmitContext.ILGenerator.MarkLabel(finishLabel); return(expression); }
public override AstElement Clone(Dictionary<AstElement, AstElement> alreadyClonedElements) { CaseExpression result = new CaseExpression(); if (_inputExpression != null) result.InputExpression = (ExpressionNode)_inputExpression.Clone(alreadyClonedElements); if (_elseExpression != null) result.ElseExpression = (ExpressionNode)_elseExpression.Clone(alreadyClonedElements); result.WhenExpressions = new ExpressionNode[_whenExpressions.Length]; for (int i = 0; i < _whenExpressions.Length; i++) result.WhenExpressions[i] = (ExpressionNode)_whenExpressions[i].Clone(alreadyClonedElements); result.ThenExpressions = new ExpressionNode[_thenExpressions.Length]; for (int i = 0; i < _thenExpressions.Length; i++) result.ThenExpressions[i] = (ExpressionNode)_thenExpressions[i].Clone(alreadyClonedElements); result.ResultType = _resultType; return result; }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { // Replace simple CASE by searched CASE, i.e. // // replace // // CASE InputExpr // WHEN Expr1 THEN ThenExpr1 ... // WHEN ExprN THEN ThenExprN // [ELSE ElseExpr] // END // // by // // CASE // WHEN InputExpr = Expr1 THEN ThenExpr1 ... // WHEN InputExpr = ExprN THEN ThenExprN // [ELSE ElseExpr] // END if (expression.InputExpression != null) { for (int i = 0; i < expression.WhenExpressions.Length; i++) { BinaryExpression binaryExpression = new BinaryExpression(); binaryExpression.Op = BinaryOperator.Equal; binaryExpression.Left = (ExpressionNode)expression.InputExpression.Clone(); binaryExpression.Right = expression.WhenExpressions[i]; expression.WhenExpressions[i] = binaryExpression; } expression.InputExpression = null; } return(base.VisitCaseExpression(expression)); }
public virtual ExpressionNode VisitCaseExpression(CaseExpression expression) { if (expression.InputExpression != null) { expression.InputExpression = VisitExpression(expression.InputExpression); } for (int i = 0; i < expression.WhenExpressions.Length; i++) { expression.WhenExpressions[i] = VisitExpression(expression.WhenExpressions[i]); } for (int i = 0; i < expression.ThenExpressions.Length; i++) { expression.ThenExpressions[i] = VisitExpression(expression.ThenExpressions[i]); } if (expression.ElseExpression != null) { expression.ElseExpression = VisitExpression(expression.ElseExpression); } return(expression); }
private static bool VisitCaseExpression(CaseExpression node1, CaseExpression node2) { if (node2 == null) return false; if (node1.InputExpression != null) if (!Visit(node1.InputExpression, node2.InputExpression)) return false; if (node1.WhenExpressions.Length != node2.WhenExpressions.Length || node1.ThenExpressions.Length != node2.ThenExpressions.Length) return false; for (int i = 0; i < node1.WhenExpressions.Length; i++) if (!Visit(node1.WhenExpressions[i], node2.WhenExpressions[i])) return false; for (int i = 0; i < node1.ThenExpressions.Length; i++) if (!Visit(node1.ThenExpressions[i], node2.ThenExpressions[i])) return false; if (node1.ElseExpression != null) if (!Visit(node1.ElseExpression, node2.ElseExpression)) return false; return true; }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { // NOTE: It is assumed that simple case expressions are already transformed into // searched case expressions, i.e. // CASE // WHEN Pred1 THEN Expr1 ... // WHEN PredN THEN ExprN // [ELSE ElseExpr] // END List<ExpressionNode> processedWhenExpressions = new List<ExpressionNode>(); for (int i = 0; i < expression.WhenExpressions.Length; i++) { SetWhenPassthru(processedWhenExpressions); expression.WhenExpressions[i] = VisitExpression(expression.WhenExpressions[i]); processedWhenExpressions.Add(expression.WhenExpressions[i]); SetThenPassthru(processedWhenExpressions); expression.ThenExpressions[i] = VisitExpression(expression.ThenExpressions[i]); } if (expression.ElseExpression != null) { SetWhenPassthru(processedWhenExpressions); expression.ElseExpression = VisitExpression(expression.ElseExpression); } _currentPassthruPredicate = null; return expression; }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { if (expression.InputExpression == null) { _writer.Write("CASE"); } else { _writer.Write("CASE "); Visit(expression.InputExpression); } for (int i = 0; i < expression.WhenExpressions.Length && i < expression.ThenExpressions.Length; i++) { _writer.Write(" WHEN "); Visit(expression.WhenExpressions[i]); _writer.Write(" THEN "); Visit(expression.ThenExpressions[i]); } if (expression.ElseExpression != null) { _writer.Write(" ELSE "); Visit(expression.ElseExpression); } _writer.Write(" END"); return expression; }
private static AlgebraNode AlgebrizeRecursiveCte(CommonTableBinding commonTableBinding) { // It is a recursive query. // // Create row buffer entry that is used to guard the recursion and the primary table spool // that spools the results needed by nested recursion calls. ExpressionBuilder expressionBuilder = new ExpressionBuilder(); StackedTableSpoolAlgebraNode primaryTableSpool = new StackedTableSpoolAlgebraNode(); RowBufferEntry anchorRecursionLevel; RowBufferEntry[] anchorOutput; AlgebraNode anchorNode; #region Anchor member { // Emit anchor member. AlgebraNode algebrizedAnchor = Convert(commonTableBinding.AnchorMember); // Emit compute scalar that initializes the recursion level to 0. anchorRecursionLevel = new RowBufferEntry(typeof(int)); ComputedValueDefinition computedValueDefinition1 = new ComputedValueDefinition(); computedValueDefinition1.Target = anchorRecursionLevel; computedValueDefinition1.Expression = LiteralExpression.FromInt32(0); ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode(); computeScalarAlgebraNode.Input = algebrizedAnchor; computeScalarAlgebraNode.DefinedValues = new ComputedValueDefinition[] { computedValueDefinition1 }; anchorOutput = algebrizedAnchor.OutputList; anchorNode = computeScalarAlgebraNode; } #endregion RowBufferEntry incrementedRecursionLevel; RowBufferEntry[] tableSpoolOutput; AlgebraNode tableSpoolNode; #region Table spool { // Emit table spool reference. RowBufferEntry recursionLevelRefEntry = new RowBufferEntry(typeof(int)); tableSpoolOutput = new RowBufferEntry[anchorOutput.Length]; for (int i = 0; i < tableSpoolOutput.Length; i++) tableSpoolOutput[i] = new RowBufferEntry(anchorOutput[i].DataType); StackedTableSpoolRefAlgebraNode tableSpoolReference = new StackedTableSpoolRefAlgebraNode(); tableSpoolReference.PrimarySpool = primaryTableSpool; tableSpoolReference.DefinedValues = ArrayHelpers.JoinArrays(new RowBufferEntry[] { recursionLevelRefEntry }, tableSpoolOutput); // Emit compute scalar that increases the recursion level by one and renames // columns from the spool to the CTE column buffer entries. expressionBuilder.Push(new RowBufferEntryExpression(recursionLevelRefEntry)); expressionBuilder.Push(LiteralExpression.FromInt32(1)); expressionBuilder.PushBinary(BinaryOperator.Add); incrementedRecursionLevel = new RowBufferEntry(typeof(int)); ComputedValueDefinition incremenedRecLevelValueDefinition = new ComputedValueDefinition(); incremenedRecLevelValueDefinition.Target = incrementedRecursionLevel; incremenedRecLevelValueDefinition.Expression = expressionBuilder.Pop(); CteColumnMappingFinder cteColumnMappingFinder = new CteColumnMappingFinder(commonTableBinding, tableSpoolOutput); foreach (QueryNode recursiveMember in commonTableBinding.RecursiveMembers) cteColumnMappingFinder.Visit(recursiveMember); CteColumnMapping[] cteColumnMappings = cteColumnMappingFinder.GetMappings(); List<ComputedValueDefinition> definedValues = new List<ComputedValueDefinition>(); definedValues.Add(incremenedRecLevelValueDefinition); foreach (CteColumnMapping cteColumnMapping in cteColumnMappings) { ComputedValueDefinition definedValue = new ComputedValueDefinition(); definedValue.Target = cteColumnMapping.VirtualBufferEntry; definedValue.Expression = new RowBufferEntryExpression(cteColumnMapping.SpoolBufferEntry); definedValues.Add(definedValue); } ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode(); computeScalarAlgebraNode.Input = tableSpoolReference; computeScalarAlgebraNode.DefinedValues = definedValues.ToArray(); tableSpoolNode = computeScalarAlgebraNode; } #endregion RowBufferEntry[] recursiveOutput; AlgebraNode recursiveNode; #region Recursive member(s) { // Emit all recursive parts. The join conditions to the recursive part are replaced by simple filters // in the nested Convert() call. ConcatAlgebraNode concatAlgebraNode = new ConcatAlgebraNode(); concatAlgebraNode.Inputs = new AlgebraNode[commonTableBinding.RecursiveMembers.Length]; for (int i = 0; i < commonTableBinding.RecursiveMembers.Length; i++) concatAlgebraNode.Inputs[i] = Convert(commonTableBinding, commonTableBinding.RecursiveMembers[i]); concatAlgebraNode.DefinedValues = new UnitedValueDefinition[anchorOutput.Length]; for (int i = 0; i < anchorOutput.Length; i++) { List<RowBufferEntry> dependencies = new List<RowBufferEntry>(); foreach (ResultAlgebraNode algebrizedRecursivePart in concatAlgebraNode.Inputs) dependencies.Add(algebrizedRecursivePart.OutputList[i]); concatAlgebraNode.DefinedValues[i] = new UnitedValueDefinition(); concatAlgebraNode.DefinedValues[i].Target = new RowBufferEntry(anchorOutput[i].DataType); concatAlgebraNode.DefinedValues[i].DependendEntries = dependencies.ToArray(); } // Calculate the recursive output. recursiveOutput = new RowBufferEntry[concatAlgebraNode.DefinedValues.Length]; for (int i = 0; i < concatAlgebraNode.DefinedValues.Length; i++) recursiveOutput[i] = concatAlgebraNode.DefinedValues[i].Target; // Emit cross join JoinAlgebraNode crossJoinNode = new JoinAlgebraNode(); crossJoinNode.Left = tableSpoolNode; crossJoinNode.Right = concatAlgebraNode; // Emit assert that ensures that the recursion level is <= 100. expressionBuilder.Push(new RowBufferEntryExpression(incrementedRecursionLevel)); expressionBuilder.Push(LiteralExpression.FromInt32(100)); expressionBuilder.PushBinary(BinaryOperator.Greater); CaseExpression caseExpression = new CaseExpression(); caseExpression.WhenExpressions = new ExpressionNode[1]; caseExpression.WhenExpressions[0] = expressionBuilder.Pop(); caseExpression.ThenExpressions = new ExpressionNode[1]; caseExpression.ThenExpressions[0] = LiteralExpression.FromInt32(0); AssertAlgebraNode assertAlgebraNode = new AssertAlgebraNode(); assertAlgebraNode.Input = crossJoinNode; assertAlgebraNode.AssertionType = AssertionType.BelowRecursionLimit; assertAlgebraNode.Predicate = caseExpression; recursiveNode = assertAlgebraNode; } #endregion RowBufferEntry[] algebrizedOutput; AlgebraNode algebrizedCte; #region Combination { // Create concat node to combine anchor and recursive part. ConcatAlgebraNode concatAlgebraNode = new ConcatAlgebraNode(); concatAlgebraNode.Inputs = new AlgebraNode[2]; concatAlgebraNode.Inputs[0] = anchorNode; concatAlgebraNode.Inputs[1] = recursiveNode; concatAlgebraNode.DefinedValues = new UnitedValueDefinition[anchorOutput.Length + 1]; concatAlgebraNode.DefinedValues[0] = new UnitedValueDefinition(); concatAlgebraNode.DefinedValues[0].Target = new RowBufferEntry(anchorRecursionLevel.DataType); concatAlgebraNode.DefinedValues[0].DependendEntries = new RowBufferEntry[] { anchorRecursionLevel, incrementedRecursionLevel }; for (int i = 0; i < anchorOutput.Length; i++) { concatAlgebraNode.DefinedValues[i + 1] = new UnitedValueDefinition(); concatAlgebraNode.DefinedValues[i + 1].Target = new RowBufferEntry(anchorOutput[i].DataType); concatAlgebraNode.DefinedValues[i + 1].DependendEntries = new RowBufferEntry[] { anchorOutput[i], recursiveOutput[i] }; } algebrizedOutput = new RowBufferEntry[concatAlgebraNode.DefinedValues.Length]; for (int i = 0; i < concatAlgebraNode.DefinedValues.Length; i++) algebrizedOutput[i] = concatAlgebraNode.DefinedValues[i].Target; // Assign the combination as the input to the primray spool primaryTableSpool.Input = concatAlgebraNode; // The primary spool represents the result of the "inlined" CTE. algebrizedCte = primaryTableSpool; } #endregion algebrizedCte.OutputList = algebrizedOutput; return algebrizedCte; }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { base.VisitCaseExpression(expression); // NOTE: It must be a searched CASE. The normalizer should have normalized it already. // // Remove all WHEN expressions that are allays FALSE or NULL. // AND // Cut off all WHENs trailing an expression that is always true. List<ExpressionNode> whenExpressions = new List<ExpressionNode>(); List<ExpressionNode> thenExpressions = new List<ExpressionNode>(); for (int i = 0; i < expression.WhenExpressions.Length; i++) { if (AstUtil.IsNull(expression.WhenExpressions[i])) { // A WHEN expression is always null. continue; } ConstantExpression whenAsBooleanConstant = expression.WhenExpressions[i] as ConstantExpression; if (whenAsBooleanConstant != null) { if (!whenAsBooleanConstant.AsBoolean) { // A WHEN expression is always false. // // We remove this part from the case expression by not adding to // whenExpressions and thenExpressions. continue; } else { // A WHEN expression is always true. // // We replace the ELSE expression by the THEN expression and // cut off the rest. expression.ElseExpression = expression.ThenExpressions[i]; break; } } whenExpressions.Add(expression.WhenExpressions[i]); thenExpressions.Add(expression.ThenExpressions[i]); } if (whenExpressions.Count == 0) { // This means the first WHEN expression was always false // or all WHEN expressions are either FALSE or NULL. // // We replace the case expression by the else expression // or by NULL. if (expression.ElseExpression != null) return expression.ElseExpression; return LiteralExpression.FromTypedNull(expression.ExpressionType); } expression.WhenExpressions = whenExpressions.ToArray(); expression.ThenExpressions = thenExpressions.ToArray(); return expression; }
private ExpressionNode ParsePrimaryExpression() { switch (_token.Id) { case TokenId.NULL: NextToken(); return LiteralExpression.FromNull(); case TokenId.TRUE: case TokenId.FALSE: return ParseBooleanLiteral(); case TokenId.Date: return ParseDateLiteral(); case TokenId.Number: return ParseNumberLiteral(); case TokenId.String: return LiteralExpression.FromString(ParseString()); case TokenId.EXISTS: { ExistsSubselect result = new ExistsSubselect(); NextToken(); Match(TokenId.LeftParentheses); result.Query = ParseQuery(); Match(TokenId.RightParentheses); return result; } case TokenId.ParameterMarker: { _rangeRecorder.Begin(); NextToken(); Identifier name = ParseIdentifier(); SourceRange nameSourceRange = _rangeRecorder.End(); ParameterExpression result = new ParameterExpression(); result.Name = name; result.NameSourceRange = nameSourceRange; return result; } case TokenId.CAST: { NextToken(); CastExpression castExpression = new CastExpression(); Match(TokenId.LeftParentheses); castExpression.Expression = ParseExpression(); Match(TokenId.AS); castExpression.TypeReference = ParseTypeReference(); Match(TokenId.RightParentheses); return castExpression; } case TokenId.CASE: { NextToken(); CaseExpression caseExpression = new CaseExpression(); if (_token.Id != TokenId.WHEN && _token.Id != TokenId.ELSE && _token.Id != TokenId.END) caseExpression.InputExpression = ParseExpression(); List<ExpressionNode> whenExpressionList = new List<ExpressionNode>(); List<ExpressionNode> expressionList = new List<ExpressionNode>(); if (_token.Id != TokenId.WHEN) { Match(TokenId.WHEN); } else { while (_token.Id == TokenId.WHEN) { NextToken(); whenExpressionList.Add(ParseExpression()); Match(TokenId.THEN); expressionList.Add(ParseExpression()); } } caseExpression.WhenExpressions = whenExpressionList.ToArray(); caseExpression.ThenExpressions = expressionList.ToArray(); if (_token.Id == TokenId.ELSE) { NextToken(); caseExpression.ElseExpression = ParseExpression(); } Match(TokenId.END); return caseExpression; } case TokenId.COALESCE: { NextToken(); CoalesceExpression coalesceExpression = new CoalesceExpression(); coalesceExpression.Expressions = ParseExpressionList(); return coalesceExpression; } case TokenId.NULLIF: { NextToken(); NullIfExpression nullIfExpression = new NullIfExpression(); Match(TokenId.LeftParentheses); nullIfExpression.LeftExpression = ParseExpression(); Match(TokenId.Comma); nullIfExpression.RightExpression = ParseExpression(); Match(TokenId.RightParentheses); return nullIfExpression; } case TokenId.Identifier: { _rangeRecorder.Begin(); Identifier name = ParseIdentifier(); SourceRange nameSourceRange = _rangeRecorder.End(); if (_token.Id != TokenId.LeftParentheses) { NameExpression result = new NameExpression(); result.Name = name; result.NameSourceRange = nameSourceRange; return result; } else { bool hasAsteriskModifier; ExpressionNode[] args; if (_lookahead.Id != TokenId.Multiply) { hasAsteriskModifier = false; args = ParseExpressionList(); } else { NextToken(); NextToken(); Match(TokenId.RightParentheses); hasAsteriskModifier = true; args = new ExpressionNode[0]; } FunctionInvocationExpression result = new FunctionInvocationExpression(); result.Name = name; result.NameSourceRange = nameSourceRange; result.Arguments = args; result.HasAsteriskModifier = hasAsteriskModifier; return result; } } case TokenId.LeftParentheses: { NextToken(); ExpressionNode expr; if (_token.Id != TokenId.SELECT) { expr = ParseExpression(); } else { SingleRowSubselect singleRowSubselect = new SingleRowSubselect(); singleRowSubselect.Query = ParseQuery(); expr = singleRowSubselect; } Match(TokenId.RightParentheses); return expr; } default: { _errorReporter.SimpleExpressionExpected(_token.Range, _token.Text); return LiteralExpression.FromNull(); } } }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { // Replace simple CASE by searched CASE, i.e. // // replace // // CASE InputExpr // WHEN Expr1 THEN ThenExpr1 ... // WHEN ExprN THEN ThenExprN // [ELSE ElseExpr] // END // // by // // CASE // WHEN InputExpr = Expr1 THEN ThenExpr1 ... // WHEN InputExpr = ExprN THEN ThenExprN // [ELSE ElseExpr] // END if (expression.InputExpression != null) { for (int i = 0; i < expression.WhenExpressions.Length; i++) { BinaryExpression binaryExpression = new BinaryExpression(); binaryExpression.Op = BinaryOperator.Equal; binaryExpression.Left = (ExpressionNode) expression.InputExpression.Clone(); binaryExpression.Right = expression.WhenExpressions[i]; expression.WhenExpressions[i] = binaryExpression; } expression.InputExpression = null; } return base.VisitCaseExpression(expression); }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { // NOTE: Must be searched CASE. The normalizer should have replaced it. Label finishLabel = _ilEmitContext.ILGenerator.DefineLabel(); Label[] caseLabels = new Label[expression.WhenExpressions.Length + 1]; for (int i = 0; i < expression.WhenExpressions.Length; i++) caseLabels[i] = _ilEmitContext.ILGenerator.DefineLabel(); Label elseLabel = _ilEmitContext.ILGenerator.DefineLabel(); caseLabels[expression.WhenExpressions.Length] = elseLabel; for (int i = 0; i < expression.WhenExpressions.Length; i++) { _ilEmitContext.ILGenerator.MarkLabel(caseLabels[i]); int whenLocalIndex = DeclareLocal(); Visit(expression.WhenExpressions[i]); _ilEmitContext.ILGenerator.Emit(OpCodes.Stloc, whenLocalIndex); _ilEmitContext.ILGenerator.Emit(OpCodes.Ldloc, whenLocalIndex); _ilEmitContext.ILGenerator.Emit(OpCodes.Brfalse, caseLabels[i + 1]); _ilEmitContext.ILGenerator.Emit(OpCodes.Ldloc, whenLocalIndex); _ilEmitContext.ILGenerator.Emit(OpCodes.Unbox_Any, typeof (bool)); _ilEmitContext.ILGenerator.Emit(OpCodes.Brfalse, caseLabels[i + 1]); Visit(expression.ThenExpressions[i]); _ilEmitContext.ILGenerator.Emit(OpCodes.Br, finishLabel); } _ilEmitContext.ILGenerator.MarkLabel(elseLabel); if (expression.ElseExpression != null) Visit(expression.ElseExpression); else _ilEmitContext.ILGenerator.Emit(OpCodes.Ldnull); _ilEmitContext.ILGenerator.MarkLabel(finishLabel); return expression; }
public override ExpressionNode VisitCoalesceExpression(CoalesceExpression expression) { // First visit all expressions base.VisitCoalesceExpression(expression); // Since a COALESCE expression can be expressed using a CASE expression we convert // them to simplify the evaluation and optimization engine. // // COALESCE(expression1,...,expressionN) is equivalent to this CASE expression: // // CASE // WHEN (expression1 IS NOT NULL) THEN expression1 // ... // WHEN (expressionN IS NOT NULL) THEN expressionN // END CaseExpression caseExpression = new CaseExpression(); caseExpression.WhenExpressions = new ExpressionNode[expression.Expressions.Length]; caseExpression.ThenExpressions = new ExpressionNode[expression.Expressions.Length]; for (int i = 0; i < expression.Expressions.Length; i++) { ExpressionNode whenPart = expression.Expressions[i]; ExpressionNode thenPart = (ExpressionNode) whenPart.Clone(); caseExpression.WhenExpressions[i] = new IsNullExpression(true, whenPart); caseExpression.ThenExpressions[i] = thenPart; } return VisitExpression(caseExpression); }
public override ExpressionNode VisitNullIfExpression(NullIfExpression expression) { // First visit all expressions base.VisitNullIfExpression (expression); // Since a NULLIF expression can be expressed using a CASE expression we convert // them to simplify the evaluation and optimization engine. // // NULLIF(expression1, expression1) is equivalent to this CASE expression: // // CASE // WHEN expression1 = expression2 THEN NULL // ELSE expression1 // END CaseExpression caseExpression = new CaseExpression(); caseExpression.WhenExpressions = new ExpressionNode[1]; caseExpression.ThenExpressions = new ExpressionNode[1]; caseExpression.WhenExpressions[0] = new BinaryExpression(BinaryOperator.Equal, expression.LeftExpression, expression.RightExpression); caseExpression.ThenExpressions[0] = LiteralExpression.FromNull(); caseExpression.ElseExpression = expression.LeftExpression; return VisitExpression(caseExpression); }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { _xmlWriter.WriteStartElement("caseExpression"); WriteTypeAttribute(expression.ExpressionType); if (expression.InputExpression != null) WriteAstNode("inputExpression", expression.InputExpression); for (int i = 0; i < expression.WhenExpressions.Length; i++) { _xmlWriter.WriteStartElement("whenThenPair"); _xmlWriter.WriteAttributeString("index", XmlConvert.ToString(i)); WriteAstNode("whenExpression", expression.WhenExpressions[i]); WriteAstNode("thenExpression", expression.ThenExpressions[i]); _xmlWriter.WriteEndElement(); } if (expression.ElseExpression != null) WriteAstNode("elseExpression", expression.ElseExpression); _xmlWriter.WriteEndElement(); return expression; }
private static ResultAlgebraNode CreateAssertedSubquery(ResultAlgebraNode inputNode) { if (AstUtil.WillProduceAtMostOneRow(inputNode)) { return(inputNode); } RowBufferEntry inputEntry = inputNode.OutputList[0]; AggregatedValueDefinition countDefinedValue = new AggregatedValueDefinition(); countDefinedValue.Aggregate = new CountAggregateBinding("COUNT"); countDefinedValue.Aggregator = countDefinedValue.Aggregate.CreateAggregator(typeof(int)); countDefinedValue.Argument = LiteralExpression.FromInt32(0); RowBufferEntry countDefinedValueEntry = new RowBufferEntry(countDefinedValue.Aggregator.ReturnType); countDefinedValue.Target = countDefinedValueEntry; RowBufferEntryExpression anyAggregateArgument = new RowBufferEntryExpression(); anyAggregateArgument.RowBufferEntry = inputEntry; AggregatedValueDefinition anyDefinedValue = new AggregatedValueDefinition(); anyDefinedValue.Aggregate = new FirstAggregateBinding("ANY"); anyDefinedValue.Aggregator = anyDefinedValue.Aggregate.CreateAggregator(inputEntry.DataType); anyDefinedValue.Argument = anyAggregateArgument; RowBufferEntry anyDefinedValueEntry = new RowBufferEntry(inputEntry.DataType); anyDefinedValue.Target = anyDefinedValueEntry; AggregateAlgebraNode aggregateAlgebraNode = new AggregateAlgebraNode(); aggregateAlgebraNode.Input = inputNode.Input; aggregateAlgebraNode.DefinedValues = new AggregatedValueDefinition[] { countDefinedValue, anyDefinedValue }; // CASE WHEN SubqueryCount > 1 THEN 0 ELSE NULL END ExpressionBuilder expressionBuilder = new ExpressionBuilder(); expressionBuilder.Push(new RowBufferEntryExpression(countDefinedValueEntry)); expressionBuilder.Push(LiteralExpression.FromInt32(1)); expressionBuilder.PushBinary(BinaryOperator.Greater); ExpressionNode whenExpression = expressionBuilder.Pop(); ExpressionNode thenExpression = LiteralExpression.FromInt32(0); CaseExpression caseExpression = new CaseExpression(); caseExpression.WhenExpressions = new ExpressionNode[] { whenExpression }; caseExpression.ThenExpressions = new ExpressionNode[] { thenExpression }; expressionBuilder.Push(caseExpression); ExpressionNode predicate = expressionBuilder.Pop(); AssertAlgebraNode assertAlgebraNode = new AssertAlgebraNode(); assertAlgebraNode.Input = aggregateAlgebraNode; assertAlgebraNode.Predicate = predicate; assertAlgebraNode.AssertionType = AssertionType.MaxOneRow; ResultAlgebraNode resultAlgebraNode = new ResultAlgebraNode(); resultAlgebraNode.Input = assertAlgebraNode; resultAlgebraNode.OutputList = new RowBufferEntry[] { anyDefinedValueEntry }; resultAlgebraNode.ColumnNames = inputNode.ColumnNames; return(resultAlgebraNode); }
private static ResultAlgebraNode CreateAssertedSubquery(ResultAlgebraNode inputNode) { if (AstUtil.WillProduceAtMostOneRow(inputNode)) return inputNode; RowBufferEntry inputEntry = inputNode.OutputList[0]; AggregatedValueDefinition countDefinedValue = new AggregatedValueDefinition(); countDefinedValue.Aggregate = new CountAggregateBinding("COUNT"); countDefinedValue.Aggregator = countDefinedValue.Aggregate.CreateAggregator(typeof(int)); countDefinedValue.Argument = LiteralExpression.FromInt32(0); RowBufferEntry countDefinedValueEntry = new RowBufferEntry(countDefinedValue.Aggregator.ReturnType); countDefinedValue.Target = countDefinedValueEntry; RowBufferEntryExpression anyAggregateArgument = new RowBufferEntryExpression(); anyAggregateArgument.RowBufferEntry = inputEntry; AggregatedValueDefinition anyDefinedValue = new AggregatedValueDefinition(); anyDefinedValue.Aggregate = new FirstAggregateBinding("ANY"); anyDefinedValue.Aggregator = anyDefinedValue.Aggregate.CreateAggregator(inputEntry.DataType); anyDefinedValue.Argument = anyAggregateArgument; RowBufferEntry anyDefinedValueEntry = new RowBufferEntry(inputEntry.DataType); anyDefinedValue.Target = anyDefinedValueEntry; AggregateAlgebraNode aggregateAlgebraNode = new AggregateAlgebraNode(); aggregateAlgebraNode.Input = inputNode.Input; aggregateAlgebraNode.DefinedValues = new AggregatedValueDefinition[] { countDefinedValue, anyDefinedValue }; // CASE WHEN SubqueryCount > 1 THEN 0 ELSE NULL END ExpressionBuilder expressionBuilder = new ExpressionBuilder(); expressionBuilder.Push(new RowBufferEntryExpression(countDefinedValueEntry)); expressionBuilder.Push(LiteralExpression.FromInt32(1)); expressionBuilder.PushBinary(BinaryOperator.Greater); ExpressionNode whenExpression = expressionBuilder.Pop(); ExpressionNode thenExpression = LiteralExpression.FromInt32(0); CaseExpression caseExpression = new CaseExpression(); caseExpression.WhenExpressions = new ExpressionNode[] { whenExpression }; caseExpression.ThenExpressions = new ExpressionNode[] { thenExpression }; expressionBuilder.Push(caseExpression); ExpressionNode predicate = expressionBuilder.Pop(); AssertAlgebraNode assertAlgebraNode = new AssertAlgebraNode(); assertAlgebraNode.Input = aggregateAlgebraNode; assertAlgebraNode.Predicate = predicate; assertAlgebraNode.AssertionType = AssertionType.MaxOneRow; ResultAlgebraNode resultAlgebraNode = new ResultAlgebraNode(); resultAlgebraNode.Input = assertAlgebraNode; resultAlgebraNode.OutputList = new RowBufferEntry[] { anyDefinedValueEntry }; resultAlgebraNode.ColumnNames = inputNode.ColumnNames; return resultAlgebraNode; }
public virtual ExpressionNode VisitCaseExpression(CaseExpression expression) { if (expression.InputExpression != null) expression.InputExpression = VisitExpression(expression.InputExpression); for (int i = 0; i < expression.WhenExpressions.Length; i++) expression.WhenExpressions[i] = VisitExpression(expression.WhenExpressions[i]); for (int i = 0; i < expression.ThenExpressions.Length; i++) expression.ThenExpressions[i] = VisitExpression(expression.ThenExpressions[i]); if (expression.ElseExpression != null) expression.ElseExpression = VisitExpression(expression.ElseExpression); return expression; }
private ExpressionNode ParsePrimaryExpression() { switch (_token.Id) { case TokenId.NULL: NextToken(); return(LiteralExpression.FromNull()); case TokenId.TRUE: case TokenId.FALSE: return(ParseBooleanLiteral()); case TokenId.Date: return(ParseDateLiteral()); case TokenId.Number: return(ParseNumberLiteral()); case TokenId.String: return(LiteralExpression.FromString(ParseString())); case TokenId.EXISTS: { ExistsSubselect result = new ExistsSubselect(); NextToken(); Match(TokenId.LeftParentheses); result.Query = ParseQuery(); Match(TokenId.RightParentheses); return(result); } case TokenId.ParameterMarker: { _rangeRecorder.Begin(); NextToken(); Identifier name = ParseIdentifier(); SourceRange nameSourceRange = _rangeRecorder.End(); ParameterExpression result = new ParameterExpression(); result.Name = name; result.NameSourceRange = nameSourceRange; return(result); } case TokenId.CAST: { NextToken(); CastExpression castExpression = new CastExpression(); Match(TokenId.LeftParentheses); castExpression.Expression = ParseExpression(); Match(TokenId.AS); castExpression.TypeReference = ParseTypeReference(); Match(TokenId.RightParentheses); return(castExpression); } case TokenId.CASE: { NextToken(); CaseExpression caseExpression = new CaseExpression(); if (_token.Id != TokenId.WHEN && _token.Id != TokenId.ELSE && _token.Id != TokenId.END) { caseExpression.InputExpression = ParseExpression(); } List <ExpressionNode> whenExpressionList = new List <ExpressionNode>(); List <ExpressionNode> expressionList = new List <ExpressionNode>(); if (_token.Id != TokenId.WHEN) { Match(TokenId.WHEN); } else { while (_token.Id == TokenId.WHEN) { NextToken(); whenExpressionList.Add(ParseExpression()); Match(TokenId.THEN); expressionList.Add(ParseExpression()); } } caseExpression.WhenExpressions = whenExpressionList.ToArray(); caseExpression.ThenExpressions = expressionList.ToArray(); if (_token.Id == TokenId.ELSE) { NextToken(); caseExpression.ElseExpression = ParseExpression(); } Match(TokenId.END); return(caseExpression); } case TokenId.COALESCE: { NextToken(); CoalesceExpression coalesceExpression = new CoalesceExpression(); coalesceExpression.Expressions = ParseExpressionList(); return(coalesceExpression); } case TokenId.NULLIF: { NextToken(); NullIfExpression nullIfExpression = new NullIfExpression(); Match(TokenId.LeftParentheses); nullIfExpression.LeftExpression = ParseExpression(); Match(TokenId.Comma); nullIfExpression.RightExpression = ParseExpression(); Match(TokenId.RightParentheses); return(nullIfExpression); } case TokenId.Identifier: { _rangeRecorder.Begin(); Identifier name = ParseIdentifier(); SourceRange nameSourceRange = _rangeRecorder.End(); if (_token.Id != TokenId.LeftParentheses) { NameExpression result = new NameExpression(); result.Name = name; result.NameSourceRange = nameSourceRange; return(result); } else { bool hasAsteriskModifier; ExpressionNode[] args; if (_lookahead.Id != TokenId.Multiply) { hasAsteriskModifier = false; args = ParseExpressionList(); } else { NextToken(); NextToken(); Match(TokenId.RightParentheses); hasAsteriskModifier = true; args = new ExpressionNode[0]; } FunctionInvocationExpression result = new FunctionInvocationExpression(); result.Name = name; result.NameSourceRange = nameSourceRange; result.Arguments = args; result.HasAsteriskModifier = hasAsteriskModifier; return(result); } } case TokenId.LeftParentheses: { NextToken(); ExpressionNode expr; if (_token.Id != TokenId.SELECT) { expr = ParseExpression(); } else { SingleRowSubselect singleRowSubselect = new SingleRowSubselect(); singleRowSubselect.Query = ParseQuery(); expr = singleRowSubselect; } Match(TokenId.RightParentheses); return(expr); } default: { _errorReporter.SimpleExpressionExpected(_token.Range, _token.Text); return(LiteralExpression.FromNull()); } } }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { base.VisitCaseExpression(expression); // NOTE: It must be a searched CASE. The normalizer should have normalized it already. // // Remove all WHEN expressions that are allays FALSE or NULL. // AND // Cut off all WHENs trailing an expression that is always true. List <ExpressionNode> whenExpressions = new List <ExpressionNode>(); List <ExpressionNode> thenExpressions = new List <ExpressionNode>(); for (int i = 0; i < expression.WhenExpressions.Length; i++) { if (AstUtil.IsNull(expression.WhenExpressions[i])) { // A WHEN expression is always null. continue; } ConstantExpression whenAsBooleanConstant = expression.WhenExpressions[i] as ConstantExpression; if (whenAsBooleanConstant != null) { if (!whenAsBooleanConstant.AsBoolean) { // A WHEN expression is always false. // // We remove this part from the case expression by not adding to // whenExpressions and thenExpressions. continue; } else { // A WHEN expression is always true. // // We replace the ELSE expression by the THEN expression and // cut off the rest. expression.ElseExpression = expression.ThenExpressions[i]; break; } } whenExpressions.Add(expression.WhenExpressions[i]); thenExpressions.Add(expression.ThenExpressions[i]); } if (whenExpressions.Count == 0) { // This means the first WHEN expression was always false // or all WHEN expressions are either FALSE or NULL. // // We replace the case expression by the else expression // or by NULL. if (expression.ElseExpression != null) { return(expression.ElseExpression); } return(LiteralExpression.FromTypedNull(expression.ExpressionType)); } expression.WhenExpressions = whenExpressions.ToArray(); expression.ThenExpressions = thenExpressions.ToArray(); return(expression); }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { // Ensure all nested expressions are fully resolved. base.VisitCaseExpression(expression); for (int i = 0; i < expression.WhenExpressions.Length; i++) { if (expression.WhenExpressions[i].ExpressionType == null || expression.ThenExpressions[i].ExpressionType == null) return expression; } if (expression.ElseExpression != null && expression.ElseExpression.ExpressionType == null) return expression; // Ok, all nested expressions could be fully resolved. Lets validate the CASE expression. // The semantic of CASE says that if no expression incl. ELSE does match the result is NULL. // So having an ELSE expression that returns NULL is quite redundant. LiteralExpression elseAsLiteral = expression.ElseExpression as LiteralExpression; if (elseAsLiteral != null && elseAsLiteral.IsNullValue) expression.ElseExpression = null; // All WHEN expressions must evaluate to bool. foreach (ExpressionNode whenExpression in expression.WhenExpressions) { if (whenExpression.ExpressionType != typeof(bool) && whenExpression.ExpressionType != typeof(DBNull)) _errorReporter.WhenMustEvaluateToBoolIfCaseInputIsOmitted(whenExpression); } // Check that all result expression incl. else share a common type. // // To do this and to support good error reporting we first try to find // the best common type. Any needed conversions or type errors are // ignored. Type commonResultType = expression.ThenExpressions[0].ExpressionType; for (int i = 1; i < expression.ThenExpressions.Length; i++) { commonResultType = _binder.ChooseBetterTypeConversion(commonResultType, expression.ThenExpressions[i].ExpressionType); } if (expression.ElseExpression != null) commonResultType = _binder.ChooseBetterTypeConversion(expression.ElseExpression.ExpressionType, commonResultType); // Now we know that commonResultType is the best type for all result expressions. // Insert cast nodes for all expressions that have a different type but are // implicit convertible and report errors for all expressions that not convertible. if (expression.ElseExpression != null) { expression.ElseExpression = _binder.ConvertExpressionIfRequired(expression.ElseExpression, commonResultType); } for (int i = 0; i < expression.ThenExpressions.Length; i++) { expression.ThenExpressions[i] = _binder.ConvertExpressionIfRequired(expression.ThenExpressions[i], commonResultType); } expression.ResultType = commonResultType; return expression; }
private static AlgebraNode AlgebrizeRecursiveCte(CommonTableBinding commonTableBinding) { // It is a recursive query. // // Create row buffer entry that is used to guard the recursion and the primary table spool // that spools the results needed by nested recursion calls. ExpressionBuilder expressionBuilder = new ExpressionBuilder(); StackedTableSpoolAlgebraNode primaryTableSpool = new StackedTableSpoolAlgebraNode(); RowBufferEntry anchorRecursionLevel; RowBufferEntry[] anchorOutput; AlgebraNode anchorNode; #region Anchor member { // Emit anchor member. AlgebraNode algebrizedAnchor = Convert(commonTableBinding.AnchorMember); // Emit compute scalar that initializes the recursion level to 0. anchorRecursionLevel = new RowBufferEntry(typeof(int)); ComputedValueDefinition computedValueDefinition1 = new ComputedValueDefinition(); computedValueDefinition1.Target = anchorRecursionLevel; computedValueDefinition1.Expression = LiteralExpression.FromInt32(0); ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode(); computeScalarAlgebraNode.Input = algebrizedAnchor; computeScalarAlgebraNode.DefinedValues = new ComputedValueDefinition[] { computedValueDefinition1 }; anchorOutput = algebrizedAnchor.OutputList; anchorNode = computeScalarAlgebraNode; } #endregion RowBufferEntry incrementedRecursionLevel; RowBufferEntry[] tableSpoolOutput; AlgebraNode tableSpoolNode; #region Table spool { // Emit table spool reference. RowBufferEntry recursionLevelRefEntry = new RowBufferEntry(typeof(int)); tableSpoolOutput = new RowBufferEntry[anchorOutput.Length]; for (int i = 0; i < tableSpoolOutput.Length; i++) { tableSpoolOutput[i] = new RowBufferEntry(anchorOutput[i].DataType); } StackedTableSpoolRefAlgebraNode tableSpoolReference = new StackedTableSpoolRefAlgebraNode(); tableSpoolReference.PrimarySpool = primaryTableSpool; tableSpoolReference.DefinedValues = ArrayHelpers.JoinArrays(new RowBufferEntry[] { recursionLevelRefEntry }, tableSpoolOutput); // Emit compute scalar that increases the recursion level by one and renames // columns from the spool to the CTE column buffer entries. expressionBuilder.Push(new RowBufferEntryExpression(recursionLevelRefEntry)); expressionBuilder.Push(LiteralExpression.FromInt32(1)); expressionBuilder.PushBinary(BinaryOperator.Add); incrementedRecursionLevel = new RowBufferEntry(typeof(int)); ComputedValueDefinition incremenedRecLevelValueDefinition = new ComputedValueDefinition(); incremenedRecLevelValueDefinition.Target = incrementedRecursionLevel; incremenedRecLevelValueDefinition.Expression = expressionBuilder.Pop(); CteColumnMappingFinder cteColumnMappingFinder = new CteColumnMappingFinder(commonTableBinding, tableSpoolOutput); foreach (QueryNode recursiveMember in commonTableBinding.RecursiveMembers) { cteColumnMappingFinder.Visit(recursiveMember); } CteColumnMapping[] cteColumnMappings = cteColumnMappingFinder.GetMappings(); List <ComputedValueDefinition> definedValues = new List <ComputedValueDefinition>(); definedValues.Add(incremenedRecLevelValueDefinition); foreach (CteColumnMapping cteColumnMapping in cteColumnMappings) { ComputedValueDefinition definedValue = new ComputedValueDefinition(); definedValue.Target = cteColumnMapping.VirtualBufferEntry; definedValue.Expression = new RowBufferEntryExpression(cteColumnMapping.SpoolBufferEntry); definedValues.Add(definedValue); } ComputeScalarAlgebraNode computeScalarAlgebraNode = new ComputeScalarAlgebraNode(); computeScalarAlgebraNode.Input = tableSpoolReference; computeScalarAlgebraNode.DefinedValues = definedValues.ToArray(); tableSpoolNode = computeScalarAlgebraNode; } #endregion RowBufferEntry[] recursiveOutput; AlgebraNode recursiveNode; #region Recursive member(s) { // Emit all recursive parts. The join conditions to the recursive part are replaced by simple filters // in the nested Convert() call. ConcatAlgebraNode concatAlgebraNode = new ConcatAlgebraNode(); concatAlgebraNode.Inputs = new AlgebraNode[commonTableBinding.RecursiveMembers.Length]; for (int i = 0; i < commonTableBinding.RecursiveMembers.Length; i++) { concatAlgebraNode.Inputs[i] = Convert(commonTableBinding, commonTableBinding.RecursiveMembers[i]); } concatAlgebraNode.DefinedValues = new UnitedValueDefinition[anchorOutput.Length]; for (int i = 0; i < anchorOutput.Length; i++) { List <RowBufferEntry> dependencies = new List <RowBufferEntry>(); foreach (ResultAlgebraNode algebrizedRecursivePart in concatAlgebraNode.Inputs) { dependencies.Add(algebrizedRecursivePart.OutputList[i]); } concatAlgebraNode.DefinedValues[i] = new UnitedValueDefinition(); concatAlgebraNode.DefinedValues[i].Target = new RowBufferEntry(anchorOutput[i].DataType); concatAlgebraNode.DefinedValues[i].DependendEntries = dependencies.ToArray(); } // Calculate the recursive output. recursiveOutput = new RowBufferEntry[concatAlgebraNode.DefinedValues.Length]; for (int i = 0; i < concatAlgebraNode.DefinedValues.Length; i++) { recursiveOutput[i] = concatAlgebraNode.DefinedValues[i].Target; } // Emit cross join JoinAlgebraNode crossJoinNode = new JoinAlgebraNode(); crossJoinNode.Left = tableSpoolNode; crossJoinNode.Right = concatAlgebraNode; // Emit assert that ensures that the recursion level is <= 100. expressionBuilder.Push(new RowBufferEntryExpression(incrementedRecursionLevel)); expressionBuilder.Push(LiteralExpression.FromInt32(100)); expressionBuilder.PushBinary(BinaryOperator.Greater); CaseExpression caseExpression = new CaseExpression(); caseExpression.WhenExpressions = new ExpressionNode[1]; caseExpression.WhenExpressions[0] = expressionBuilder.Pop(); caseExpression.ThenExpressions = new ExpressionNode[1]; caseExpression.ThenExpressions[0] = LiteralExpression.FromInt32(0); AssertAlgebraNode assertAlgebraNode = new AssertAlgebraNode(); assertAlgebraNode.Input = crossJoinNode; assertAlgebraNode.AssertionType = AssertionType.BelowRecursionLimit; assertAlgebraNode.Predicate = caseExpression; recursiveNode = assertAlgebraNode; } #endregion RowBufferEntry[] algebrizedOutput; AlgebraNode algebrizedCte; #region Combination { // Create concat node to combine anchor and recursive part. ConcatAlgebraNode concatAlgebraNode = new ConcatAlgebraNode(); concatAlgebraNode.Inputs = new AlgebraNode[2]; concatAlgebraNode.Inputs[0] = anchorNode; concatAlgebraNode.Inputs[1] = recursiveNode; concatAlgebraNode.DefinedValues = new UnitedValueDefinition[anchorOutput.Length + 1]; concatAlgebraNode.DefinedValues[0] = new UnitedValueDefinition(); concatAlgebraNode.DefinedValues[0].Target = new RowBufferEntry(anchorRecursionLevel.DataType); concatAlgebraNode.DefinedValues[0].DependendEntries = new RowBufferEntry[] { anchorRecursionLevel, incrementedRecursionLevel }; for (int i = 0; i < anchorOutput.Length; i++) { concatAlgebraNode.DefinedValues[i + 1] = new UnitedValueDefinition(); concatAlgebraNode.DefinedValues[i + 1].Target = new RowBufferEntry(anchorOutput[i].DataType); concatAlgebraNode.DefinedValues[i + 1].DependendEntries = new RowBufferEntry[] { anchorOutput[i], recursiveOutput[i] }; } algebrizedOutput = new RowBufferEntry[concatAlgebraNode.DefinedValues.Length]; for (int i = 0; i < concatAlgebraNode.DefinedValues.Length; i++) { algebrizedOutput[i] = concatAlgebraNode.DefinedValues[i].Target; } // Assign the combination as the input to the primray spool primaryTableSpool.Input = concatAlgebraNode; // The primary spool represents the result of the "inlined" CTE. algebrizedCte = primaryTableSpool; } #endregion algebrizedCte.OutputList = algebrizedOutput; return(algebrizedCte); }
public override ExpressionNode VisitCaseExpression(CaseExpression expression) { // Ensure all nested expressions are fully resolved. base.VisitCaseExpression(expression); for (int i = 0; i < expression.WhenExpressions.Length; i++) { if (expression.WhenExpressions[i].ExpressionType == null || expression.ThenExpressions[i].ExpressionType == null) { return(expression); } } if (expression.ElseExpression != null && expression.ElseExpression.ExpressionType == null) { return(expression); } // Ok, all nested expressions could be fully resolved. Lets validate the CASE expression. // The semantic of CASE says that if no expression incl. ELSE does match the result is NULL. // So having an ELSE expression that returns NULL is quite redundant. LiteralExpression elseAsLiteral = expression.ElseExpression as LiteralExpression; if (elseAsLiteral != null && elseAsLiteral.IsNullValue) { expression.ElseExpression = null; } // All WHEN expressions must evaluate to bool. foreach (ExpressionNode whenExpression in expression.WhenExpressions) { if (whenExpression.ExpressionType != typeof(bool) && whenExpression.ExpressionType != typeof(DBNull)) { _errorReporter.WhenMustEvaluateToBoolIfCaseInputIsOmitted(whenExpression); } } // Check that all result expression incl. else share a common type. // // To do this and to support good error reporting we first try to find // the best common type. Any needed conversions or type errors are // ignored. Type commonResultType = expression.ThenExpressions[0].ExpressionType; for (int i = 1; i < expression.ThenExpressions.Length; i++) { commonResultType = _binder.ChooseBetterTypeConversion(commonResultType, expression.ThenExpressions[i].ExpressionType); } if (expression.ElseExpression != null) { commonResultType = _binder.ChooseBetterTypeConversion(expression.ElseExpression.ExpressionType, commonResultType); } // Now we know that commonResultType is the best type for all result expressions. // Insert cast nodes for all expressions that have a different type but are // implicit convertible and report errors for all expressions that not convertible. if (expression.ElseExpression != null) { expression.ElseExpression = _binder.ConvertExpressionIfRequired(expression.ElseExpression, commonResultType); } for (int i = 0; i < expression.ThenExpressions.Length; i++) { expression.ThenExpressions[i] = _binder.ConvertExpressionIfRequired(expression.ThenExpressions[i], commonResultType); } expression.ResultType = commonResultType; return(expression); }