private void VisitCallHelper(string functionName, ODataCallExpression node) { this.Write(functionName).Write("("); for (var i = 0; i < node.Arguments.Count; ++i) { this.Write(", ", @if: i > 0); this.Visit(node.Arguments[i]); } this.Write(")"); }
protected override void VisitCall(ODataCallExpression node) { // reference for different function syntax http://users.atw.hu/sqlnut/sqlnut2-chp-4-sect-4.html switch (node.Function) { case ODataFunction.Cast: this.Write("CAST(").Write(node.Arguments[0]); var toType = ((Type)((ODataConstantExpression)node.Arguments[1]).Value).ToODataExpressionType(); this.Write(" AS ").Write(this.syntaxProvider.GetSqlTypeName(toType)).Write(")"); break; case ODataFunction.Ceiling: this.VisitCallHelper(this.syntaxProvider.UseAbbreviatedCeilingFunction ? "CEIL" : "CEILING", node); break; case ODataFunction.Concat: this.Write("(").Write(node.Arguments[0]) .Write(" + ") .Write(node.Arguments[1]).Write(")"); break; case ODataFunction.Second: case ODataFunction.Minute: case ODataFunction.Hour: case ODataFunction.Day: case ODataFunction.Month: case ODataFunction.Year: this.syntaxProvider.RenderDatePartFunctionCall(node.Function, s => this.Write(s), () => this.Write(node.Arguments[0])); break; case ODataFunction.EndsWith: // endswith => (INDEXOF(needle, haystack) = LEN(haystack) - LEN(needle)) OR LEN(needle) = 0 var needleLengthExpression = ODataExpression.Call(ODataFunction.Length, new[] { node.Arguments[1] }); var endsWithExpression = ODataExpression.BinaryOp( ODataExpression.BinaryOp( ODataExpression.Call(ODataFunction.IndexOf, node.Arguments), ODataBinaryOp.Equal, ODataExpression.BinaryOp( ODataExpression.Call(ODataFunction.Length, new[] { node.Arguments[0] }), ODataBinaryOp.Subtract, needleLengthExpression ) ), ODataBinaryOp.Or, ODataExpression.BinaryOp( needleLengthExpression, ODataBinaryOp.Equal, ODataExpression.Constant(0) ) ); this.Visit(endsWithExpression); break; case ODataFunction.StartsWith: // startswith => INDEXOF(needle, haystack) = 0 var startsWithExpression = ODataExpression.BinaryOp( ODataExpression.Call(ODataFunction.IndexOf, node.Arguments), ODataBinaryOp.Equal, ODataExpression.Constant(0) ); this.Visit(startsWithExpression); break; case ODataFunction.SubstringOf: // substringof => INDEXOF(needle, haystack) >= 0 var substringOfExpression = ODataExpression.BinaryOp( ODataExpression.Call(ODataFunction.IndexOf, node.Arguments.Reverse()), ODataBinaryOp.GreaterThanOrEqual, ODataExpression.Constant(0) ); this.Visit(substringOfExpression); break; case ODataFunction.IndexOf: this.syntaxProvider.RenderIndexOfFunctionCall(s => this.Write(s), renderNeedleArgument: () => this.Write(node.Arguments[1]), renderHaystackArgument: () => this.Write(node.Arguments[0])); break; case ODataFunction.Floor: this.VisitCallHelper("FLOOR", node); break; case ODataFunction.Length: this.VisitCallHelper(this.syntaxProvider.StringLengthFunctionName, node); break; case ODataFunction.Replace: this.VisitCallHelper("REPLACE", node); break; case ODataFunction.Round: this.syntaxProvider.RenderRoundFunctionCall(s => this.Write(s), () => this.Write(node.Arguments[0])); break; case ODataFunction.Substring: this.syntaxProvider.RenderSubstringFunctionCall(s => this.Write(s), () => this.Write(node.Arguments[0]), () => this.Write(node.Arguments[1]), node.Arguments.Count > 2 ? new Action(() => this.Write(node.Arguments[2])) : null); break; case ODataFunction.ToLower: this.VisitCallHelper("LOWER", node); break; case ODataFunction.ToUpper: this.VisitCallHelper("UPPER", node); break; case ODataFunction.Trim: if (this.syntaxProvider.HasTwoSidedTrim) { this.VisitCallHelper("TRIM", node); } else { // call both LTRIM and RTRIM this.VisitCallHelper("LTRIM(RTRIM", node); this.Write(")"); } break; case ODataFunction.IsOf: throw new NotSupportedException(node.Function.ToString()); } }