From d3365bc7514e248bf36e1655336bfa207431d415 Mon Sep 17 00:00:00 2001 From: Shannon Date: Tue, 23 Sep 2014 18:38:42 +1000 Subject: [PATCH] starts updating sqlexpressions to include sql params --- .../Persistence/PetaPocoSqlExtensions.cs | 2 +- .../Querying/BaseExpressionHelper.cs | 84 +++++---- .../Querying/ModelToSqlExpressionHelper.cs | 168 ++++++++++------- .../Querying/PocoToSqlExpressionHelper.cs | 176 +++++++++++------- .../Persistence/Querying/PetaPocoSqlTests.cs | 21 +++ 5 files changed, 283 insertions(+), 168 deletions(-) diff --git a/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs b/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs index c606c24a59..2814d455d1 100644 --- a/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs +++ b/src/Umbraco.Core/Persistence/PetaPocoSqlExtensions.cs @@ -26,7 +26,7 @@ namespace Umbraco.Core.Persistence var expresionist = new PocoToSqlExpressionHelper(); string whereExpression = expresionist.Visit(predicate); - return sql.Where(whereExpression); + return sql.Where(whereExpression, expresionist.GetSqlParameters()); } public static Sql OrderBy(this Sql sql, Expression> columnMember) diff --git a/src/Umbraco.Core/Persistence/Querying/BaseExpressionHelper.cs b/src/Umbraco.Core/Persistence/Querying/BaseExpressionHelper.cs index 1a087ad8d7..0fe28d085f 100644 --- a/src/Umbraco.Core/Persistence/Querying/BaseExpressionHelper.cs +++ b/src/Umbraco.Core/Persistence/Querying/BaseExpressionHelper.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; using System.Globalization; using Umbraco.Core.Persistence.SqlSyntax; @@ -9,6 +10,13 @@ namespace Umbraco.Core.Persistence.Querying /// internal class BaseExpressionHelper { + protected List SqlParameters = new List(); + + public object[] GetSqlParameters() + { + return SqlParameters.ToArray(); + } + protected string HandleStringComparison(string col, string val, string verb, TextColumnType columnType) { switch (verb) @@ -44,54 +52,54 @@ namespace Umbraco.Core.Persistence.Querying } } - public virtual string GetQuotedValue(object value, Type fieldType, Func escapeCallback = null, Func shouldQuoteCallback = null) - { - if (value == null) return "NULL"; + //public virtual string GetQuotedValue(object value, Type fieldType, Func escapeCallback = null, Func shouldQuoteCallback = null) + //{ + // if (value == null) return "NULL"; - if (escapeCallback == null) - { - escapeCallback = EscapeParam; - } - if (shouldQuoteCallback == null) - { - shouldQuoteCallback = ShouldQuoteValue; - } + // if (escapeCallback == null) + // { + // escapeCallback = EscapeParam; + // } + // if (shouldQuoteCallback == null) + // { + // shouldQuoteCallback = ShouldQuoteValue; + // } - if (!fieldType.UnderlyingSystemType.IsValueType && fieldType != typeof(string)) - { - //if (TypeSerializer.CanCreateFromString(fieldType)) - //{ - // return "'" + escapeCallback(TypeSerializer.SerializeToString(value)) + "'"; - //} + // if (!fieldType.UnderlyingSystemType.IsValueType && fieldType != typeof(string)) + // { + // //if (TypeSerializer.CanCreateFromString(fieldType)) + // //{ + // // return "'" + escapeCallback(TypeSerializer.SerializeToString(value)) + "'"; + // //} - throw new NotSupportedException( - string.Format("Property of type: {0} is not supported", fieldType.FullName)); - } + // throw new NotSupportedException( + // string.Format("Property of type: {0} is not supported", fieldType.FullName)); + // } - if (fieldType == typeof(int)) - return ((int)value).ToString(CultureInfo.InvariantCulture); + // if (fieldType == typeof(int)) + // return ((int)value).ToString(CultureInfo.InvariantCulture); - if (fieldType == typeof(float)) - return ((float)value).ToString(CultureInfo.InvariantCulture); + // if (fieldType == typeof(float)) + // return ((float)value).ToString(CultureInfo.InvariantCulture); - if (fieldType == typeof(double)) - return ((double)value).ToString(CultureInfo.InvariantCulture); + // if (fieldType == typeof(double)) + // return ((double)value).ToString(CultureInfo.InvariantCulture); - if (fieldType == typeof(decimal)) - return ((decimal)value).ToString(CultureInfo.InvariantCulture); + // if (fieldType == typeof(decimal)) + // return ((decimal)value).ToString(CultureInfo.InvariantCulture); - if (fieldType == typeof(DateTime)) - { - return "'" + escapeCallback(((DateTime)value).ToIsoString()) + "'"; - } + // if (fieldType == typeof(DateTime)) + // { + // return "'" + escapeCallback(((DateTime)value).ToIsoString()) + "'"; + // } - if (fieldType == typeof(bool)) - return ((bool)value) ? Convert.ToString(1, CultureInfo.InvariantCulture) : Convert.ToString(0, CultureInfo.InvariantCulture); + // if (fieldType == typeof(bool)) + // return ((bool)value) ? Convert.ToString(1, CultureInfo.InvariantCulture) : Convert.ToString(0, CultureInfo.InvariantCulture); - return shouldQuoteCallback(fieldType) - ? "'" + escapeCallback(value) + "'" - : value.ToString(); - } + // return shouldQuoteCallback(fieldType) + // ? "'" + escapeCallback(value) + "'" + // : value.ToString(); + //} public virtual string EscapeParam(object paramValue) { diff --git a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs index e3ff272cee..2e2308d5d0 100644 --- a/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs +++ b/src/Umbraco.Core/Persistence/Querying/ModelToSqlExpressionHelper.cs @@ -13,7 +13,7 @@ namespace Umbraco.Core.Persistence.Querying internal class ModelToSqlExpressionHelper : BaseExpressionHelper { private string sep = " "; - private BaseMapper _mapper; + private readonly BaseMapper _mapper; public ModelToSqlExpressionHelper() { @@ -88,7 +88,11 @@ namespace Umbraco.Core.Persistence.Querying if (m.Expression != null) { string r = VisitMemberAccess(m); - return string.Format("{0}={1}", r, GetQuotedTrueValue()); + + SqlParameters.Add(1); + return string.Format("{0}=@{1}", r, SqlParameters.Count - 1); + + //return string.Format("{0}={1}", r, GetQuotedTrueValue()); } } @@ -105,7 +109,11 @@ namespace Umbraco.Core.Persistence.Querying if (m != null && m.Expression != null) { string r = VisitMemberAccess(m); - left = string.Format("{0}={1}", r, GetQuotedTrueValue()); + + SqlParameters.Add(1); + left = string.Format("{0}=@{1}", r, SqlParameters.Count - 1); + + //left = string.Format("{0}={1}", r, GetQuotedTrueValue()); } else { @@ -115,7 +123,11 @@ namespace Umbraco.Core.Persistence.Querying if (m != null && m.Expression != null) { string r = VisitMemberAccess(m); - right = string.Format("{0}={1}", r, GetQuotedTrueValue()); + + SqlParameters.Add(1); + right = string.Format("{0}=@{1}", r, SqlParameters.Count - 1); + + //right = string.Format("{0}={1}", r, GetQuotedTrueValue()); } else { @@ -132,11 +144,11 @@ namespace Umbraco.Core.Persistence.Querying else if (operand == "<>" && right == "null") operand = "is not"; else if (operand == "=" || operand == "<>") { - if (IsTrueExpression(right)) right = GetQuotedTrueValue(); - else if (IsFalseExpression(right)) right = GetQuotedFalseValue(); + //if (IsTrueExpression(right)) right = GetQuotedTrueValue(); + //else if (IsFalseExpression(right)) right = GetQuotedFalseValue(); - if (IsTrueExpression(left)) left = GetQuotedTrueValue(); - else if (IsFalseExpression(left)) left = GetQuotedFalseValue(); + //if (IsTrueExpression(left)) left = GetQuotedTrueValue(); + //else if (IsFalseExpression(left)) left = GetQuotedFalseValue(); } @@ -168,7 +180,11 @@ namespace Umbraco.Core.Persistence.Querying var lambda = Expression.Lambda>(member); var getter = lambda.Compile(); object o = getter(); - return GetQuotedValue(o, o != null ? o.GetType() : null); + + SqlParameters.Add(o); + return string.Format("(@{0})", SqlParameters.Count - 1); + + //return GetQuotedValue(o, o != null ? o.GetType() : null); } @@ -181,7 +197,11 @@ namespace Umbraco.Core.Persistence.Querying { var getter = lambda.Compile(); object o = getter(); - return GetQuotedValue(o, o.GetType()); + + SqlParameters.Add(o); + return string.Format("(@{0})", SqlParameters.Count - 1); + + //return GetQuotedValue(o, o.GetType()); } catch (System.InvalidOperationException) { // FieldName ? @@ -205,26 +225,31 @@ namespace Umbraco.Core.Persistence.Querying { if (c.Value == null) return "null"; - if (c.Value is bool) - { - object o = GetQuotedValue(c.Value, c.Value.GetType()); - return string.Format("({0}={1})", GetQuotedTrueValue(), o); - } - return GetQuotedValue(c.Value, c.Value.GetType()); + + SqlParameters.Add(c.Value); + return string.Format("(@{0})", SqlParameters.Count - 1); + + //if (c.Value is bool) + //{ + // object o = GetQuotedValue(c.Value, c.Value.GetType()); + // return string.Format("({0}={1})", GetQuotedTrueValue(), o); + //} + //return GetQuotedValue(c.Value, c.Value.GetType()); } protected virtual string VisitUnary(UnaryExpression u) { - switch (u.NodeType) - { - case ExpressionType.Not: - string o = Visit(u.Operand); - if (IsFieldName(o)) o = o + "=" + GetQuotedValue(true, typeof(bool)); - return "NOT (" + o + ")"; - default: - return Visit(u.Operand); - } + //switch (u.NodeType) + //{ + // case ExpressionType.Not: + // string o = Visit(u.Operand); + // if (IsFieldName(o)) o = o + "=" + GetQuotedValue(true, typeof(bool)); + // return "NOT (" + o + ")"; + // default: + // return Visit(u.Operand); + //} + return Visit(u.Operand); } protected virtual string VisitMethodCall(MethodCallExpression m) @@ -316,18 +341,30 @@ namespace Umbraco.Core.Persistence.Querying { if (e.GetType().ToString() != "System.Collections.Generic.List`1[System.Object]") { + SqlParameters.Add(e); + sIn.AppendFormat("{0}{1}", sIn.Length > 0 ? "," : "", - GetQuotedValue(e, e.GetType())); + string.Format("@{0}", SqlParameters.Count - 1)); + + //sIn.AppendFormat("{0}{1}", + // sIn.Length > 0 ? "," : "", + // GetQuotedValue(e, e.GetType())); } else { var listArgs = e as IList; foreach (Object el in listArgs) { + SqlParameters.Add(el); + sIn.AppendFormat("{0}{1}", sIn.Length > 0 ? "," : "", - GetQuotedValue(el, el.GetType())); + string.Format("@{0}", SqlParameters.Count - 1)); + + //sIn.AppendFormat("{0}{1}", + // sIn.Length > 0 ? "," : "", + // GetQuotedValue(el, el.GetType())); } } } @@ -342,12 +379,15 @@ namespace Umbraco.Core.Persistence.Querying case "ToString": return r.ToString(); default: - var s2 = new StringBuilder(); - foreach (Object e in args) - { - s2.AppendFormat(",{0}", GetQuotedValue(e, e.GetType())); - } - return string.Format("{0}({1}{2})", m.Method.Name, r, s2.ToString()); + + return r.ToString(); + + //var s2 = new StringBuilder(); + //foreach (Object e in args) + //{ + // s2.AppendFormat(",{0}", GetQuotedValue(e, e.GetType())); + //} + //return string.Format("{0}({1}{2})", m.Method.Name, r, s2.ToString()); } } @@ -443,44 +483,44 @@ namespace Umbraco.Core.Persistence.Querying return string.Format("\"{0}\"", name); } - private string GetQuotedTrueValue() - { - return GetQuotedValue(true, typeof(bool)); - } + //private string GetQuotedTrueValue() + //{ + // return GetQuotedValue(true, typeof(bool)); + //} - private string GetQuotedFalseValue() - { - return GetQuotedValue(false, typeof(bool)); - } + //private string GetQuotedFalseValue() + //{ + // return GetQuotedValue(false, typeof(bool)); + //} - public virtual string GetQuotedValue(object value, Type fieldType) - { - return GetQuotedValue(value, fieldType, EscapeParam, ShouldQuoteValue); - } + //public virtual string GetQuotedValue(object value, Type fieldType) + //{ + // return GetQuotedValue(value, fieldType, EscapeParam, ShouldQuoteValue); + //} - private string GetTrueExpression() - { - object o = GetQuotedTrueValue(); - return string.Format("({0}={1})", o, o); - } + //private string GetTrueExpression() + //{ + // object o = GetQuotedTrueValue(); + // return string.Format("({0}={1})", o, o); + //} - private string GetFalseExpression() - { + //private string GetFalseExpression() + //{ - return string.Format("({0}={1})", - GetQuotedTrueValue(), - GetQuotedFalseValue()); - } + // return string.Format("({0}={1})", + // GetQuotedTrueValue(), + // GetQuotedFalseValue()); + //} - private bool IsTrueExpression(string exp) - { - return (exp == GetTrueExpression()); - } + //private bool IsTrueExpression(string exp) + //{ + // return (exp == GetTrueExpression()); + //} - private bool IsFalseExpression(string exp) - { - return (exp == GetFalseExpression()); - } + //private bool IsFalseExpression(string exp) + //{ + // return (exp == GetFalseExpression()); + //} protected bool IsFieldName(string quotedExp) { diff --git a/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs b/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs index 9a27cc8183..424ad62e28 100644 --- a/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs +++ b/src/Umbraco.Core/Persistence/Querying/PocoToSqlExpressionHelper.cs @@ -86,7 +86,11 @@ namespace Umbraco.Core.Persistence.Querying if (m.Expression != null) { string r = VisitMemberAccess(m); - return string.Format("{0}={1}", r, GetQuotedTrueValue()); + + SqlParameters.Add(1); + return string.Format("{0}=@{1}", r, 1); + + //return string.Format("{0}={1}", r, GetQuotedTrueValue()); } } @@ -103,7 +107,11 @@ namespace Umbraco.Core.Persistence.Querying if (m != null && m.Expression != null) { string r = VisitMemberAccess(m); - left = string.Format("{0}={1}", r, GetQuotedTrueValue()); + + SqlParameters.Add(1); + left = string.Format("{0}=@{1}", r, SqlParameters.Count - 1); + + //left = string.Format("{0}={1}", r, GetQuotedTrueValue()); } else { @@ -113,7 +121,11 @@ namespace Umbraco.Core.Persistence.Querying if (m != null && m.Expression != null) { string r = VisitMemberAccess(m); - right = string.Format("{0}={1}", r, GetQuotedTrueValue()); + + SqlParameters.Add(1); + right = string.Format("{0}=@{1}", r, SqlParameters.Count - 1); + + //right = string.Format("{0}={1}", r, GetQuotedTrueValue()); } else { @@ -130,11 +142,11 @@ namespace Umbraco.Core.Persistence.Querying else if (operand == "<>" && right == "null") operand = "is not"; else if (operand == "=" || operand == "<>") { - if (IsTrueExpression(right)) right = GetQuotedTrueValue(); - else if (IsFalseExpression(right)) right = GetQuotedFalseValue(); + //if (IsTrueExpression(right)) right = GetQuotedTrueValue(); + //else if (IsFalseExpression(right)) right = GetQuotedFalseValue(); - if (IsTrueExpression(left)) left = GetQuotedTrueValue(); - else if (IsFalseExpression(left)) left = GetQuotedFalseValue(); + //if (IsTrueExpression(left)) left = GetQuotedTrueValue(); + //else if (IsFalseExpression(left)) left = GetQuotedFalseValue(); } @@ -168,7 +180,11 @@ namespace Umbraco.Core.Persistence.Querying var lambda = Expression.Lambda>(member); var getter = lambda.Compile(); object o = getter(); - return GetQuotedValue(o, o != null ? o.GetType() : null); + + SqlParameters.Add(o); + return string.Format("(@{0})", SqlParameters.Count - 1); + + //return GetQuotedValue(o, o != null ? o.GetType() : null); } @@ -181,9 +197,13 @@ namespace Umbraco.Core.Persistence.Querying { var getter = lambda.Compile(); object o = getter(); - return GetQuotedValue(o, o.GetType()); + + SqlParameters.Add(o); + return string.Format("(@{0})", SqlParameters.Count - 1); + + //return GetQuotedValue(o, o.GetType()); } - catch (System.InvalidOperationException) + catch (InvalidOperationException) { // FieldName ? List exprs = VisitExpressionList(nex.Arguments); var r = new StringBuilder(); @@ -207,26 +227,37 @@ namespace Umbraco.Core.Persistence.Querying { if (c.Value == null) return "null"; - else if (c.Value.GetType() == typeof(bool)) - { - object o = GetQuotedValue(c.Value, c.Value.GetType()); - return string.Format("({0}={1})", GetQuotedTrueValue(), o); - } - else - return GetQuotedValue(c.Value, c.Value.GetType()); + + SqlParameters.Add(c.Value); + return string.Format("(@{0})", SqlParameters.Count - 1); + + //if (c.Value is bool) + //{ + // object o = GetQuotedValue(c.Value, c.Value.GetType()); + + // SqlParameters.Add(o); + + // return string.Format("({0}=@{1})", GetQuotedTrueValue(), SqlParameters.Count); + //} + //return GetQuotedValue(c.Value, c.Value.GetType()); } protected virtual string VisitUnary(UnaryExpression u) { - switch (u.NodeType) - { - case ExpressionType.Not: - string o = Visit(u.Operand); - if (IsFieldName(o)) o = o + "=" + GetQuotedValue(true, typeof(bool)); - return "NOT (" + o + ")"; - default: - return Visit(u.Operand); - } + //switch (u.NodeType) + //{ + // case ExpressionType.Not: + // string o = Visit(u.Operand); + + // if (IsFieldName(o)) + // o = o + "=" + GetQuotedValue(true, typeof(bool)); + + // return "NOT (" + o + ")"; + // default: + // return Visit(u.Operand); + //} + + return Visit(u.Operand); } @@ -323,18 +354,30 @@ namespace Umbraco.Core.Persistence.Querying { if (e.GetType().ToString() != "System.Collections.Generic.List`1[System.Object]") { + SqlParameters.Add(e); + sIn.AppendFormat("{0}{1}", sIn.Length > 0 ? "," : "", - GetQuotedValue(e, e.GetType())); + string.Format("@{0}", SqlParameters.Count - 1)); + + //sIn.AppendFormat("{0}{1}", + // sIn.Length > 0 ? "," : "", + // GetQuotedValue(e, e.GetType())); } else { var listArgs = e as IList; foreach (Object el in listArgs) { + SqlParameters.Add(el); + sIn.AppendFormat("{0}{1}", sIn.Length > 0 ? "," : "", - GetQuotedValue(el, el.GetType())); + string.Format("@{0}", SqlParameters.Count - 1)); + + //sIn.AppendFormat("{0}{1}", + // sIn.Length > 0 ? "," : "", + // GetQuotedValue(el, el.GetType())); } } } @@ -349,12 +392,15 @@ namespace Umbraco.Core.Persistence.Querying case "ToString": return r.ToString(); default: - var s2 = new StringBuilder(); - foreach (Object e in args) - { - s2.AppendFormat(",{0}", GetQuotedValue(e, e.GetType())); - } - return string.Format("{0}({1}{2})", m.Method.Name, r, s2.ToString()); + + return r.ToString(); + + //var s2 = new StringBuilder(); + //foreach (Object e in args) + //{ + // s2.AppendFormat(",{0}", GetQuotedValue(e, e.GetType())); + //} + //return string.Format("{0}({1}{2})", m.Method.Name, r, s2.ToString()); } } @@ -450,20 +496,20 @@ namespace Umbraco.Core.Persistence.Querying return string.Format("\"{0}\"", name); } - private string GetQuotedTrueValue() - { - return GetQuotedValue(true, typeof(bool)); - } + //private string GetQuotedTrueValue() + //{ + // return GetQuotedValue(true, typeof(bool)); + //} - private string GetQuotedFalseValue() - { - return GetQuotedValue(false, typeof(bool)); - } + //private string GetQuotedFalseValue() + //{ + // return GetQuotedValue(false, typeof(bool)); + //} - public virtual string GetQuotedValue(object value, Type fieldType) - { - return GetQuotedValue(value, fieldType, EscapeParam, ShouldQuoteValue); - } + //public virtual string GetQuotedValue(object value, Type fieldType) + //{ + // return GetQuotedValue(value, fieldType, EscapeParam, ShouldQuoteValue); + //} protected virtual string GetFieldName(Database.PocoData pocoData, string name) { @@ -473,29 +519,29 @@ namespace Umbraco.Core.Persistence.Querying SqlSyntaxContext.SqlSyntaxProvider.GetQuotedColumnName(column.Value.ColumnName)); } - private string GetTrueExpression() - { - object o = GetQuotedTrueValue(); - return string.Format("({0}={1})", o, o); - } + //private string GetTrueExpression() + //{ + // object o = GetQuotedTrueValue(); + // return string.Format("({0}={1})", o, o); + //} - private string GetFalseExpression() - { + //private string GetFalseExpression() + //{ - return string.Format("({0}={1})", - GetQuotedTrueValue(), - GetQuotedFalseValue()); - } + // return string.Format("({0}={1})", + // GetQuotedTrueValue(), + // GetQuotedFalseValue()); + //} - private bool IsTrueExpression(string exp) - { - return (exp == GetTrueExpression()); - } + //private bool IsTrueExpression(string exp) + //{ + // return (exp == GetTrueExpression()); + //} - private bool IsFalseExpression(string exp) - { - return (exp == GetFalseExpression()); - } + //private bool IsFalseExpression(string exp) + //{ + // return (exp == GetFalseExpression()); + //} protected bool IsFieldName(string quotedExp) { diff --git a/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs b/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs index 881e4af110..55531d112a 100644 --- a/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs +++ b/src/Umbraco.Tests/Persistence/Querying/PetaPocoSqlTests.cs @@ -13,6 +13,27 @@ namespace Umbraco.Tests.Persistence.Querying public class PetaPocoSqlTests : BaseUsingSqlCeSyntax { + [Test] + public void Generates_Sql_Parameter_Where_Clause_Single_Constant() + { + var sql = new Sql("SELECT *").From().Where(x => x.NodeId == 2); + + Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ([umbracoNode].[id] = (@0))", sql.SQL.Replace("\n", " ")); + Assert.AreEqual(1, sql.Arguments.Length); + Assert.AreEqual(2, sql.Arguments[0]); + } + + [Test] + public void Generates_Sql_Parameter_Where_Clause_And_Constant() + { + var sql = new Sql("SELECT *").From().Where(x => x.NodeId != 2 && x.NodeId != 3); + + Assert.AreEqual("SELECT * FROM [umbracoNode] WHERE ([umbracoNode].[id] <> (@0) AND [umbracoNode].[id] <> (@1))", sql.SQL.Replace("\n", " ")); + Assert.AreEqual(2, sql.Arguments.Length); + Assert.AreEqual(2, sql.Arguments[0]); + Assert.AreEqual(3, sql.Arguments[0]); + } + [Test] public void Can_Select_From_With_Type() {