From 9b83d468855434ae8e86a4d62bf2d8fad44ef88c Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Tue, 7 May 2024 19:33:54 +0100 Subject: [PATCH] Standardised exception on JSON path errors --- MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsError.cs | 5 +++++ MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs | 3 ++- MarkMpn.Sql4Cds.Engine/JsonPath.cs | 22 ++++++++++++++----- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsError.cs b/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsError.cs index 6ae6c459..14b57687 100644 --- a/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsError.cs +++ b/MarkMpn.Sql4Cds.Engine/Ado/Sql4CdsError.cs @@ -387,6 +387,11 @@ internal static Sql4CdsError JsonNotArrayOrObject(TSqlFragment fragment) return Create(13611, fragment); } + internal static Sql4CdsError JsonPathFormatError(char c, int index) + { + return Create(13607, null, Collation.USEnglish.ToSqlString(c.ToString()), (SqlInt32)index); + } + internal static Sql4CdsError XQueryMissingVariable(string name) { return Create(9501, null, (SqlInt32)name.Length, Collation.USEnglish.ToSqlString(name)); diff --git a/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs b/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs index f9fae527..3bc8ae59 100644 --- a/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs +++ b/MarkMpn.Sql4Cds.Engine/ExpressionFunctions.cs @@ -1181,7 +1181,7 @@ public static SqlString FormatMessage(SqlString message, ExpressionExecutionCont if (message.IsNull) return SqlString.Null; - var regex = new Regex("%(?[-+0# ])?(?([0-9]+|\\*))?(\\.(?([0-9]+|\\*)))?(?h|l)?(?[diosuxX]|I64d|S_MSG)"); + var regex = new Regex("%(?[-+0# ])?(?([0-9]+|\\*))?(\\.(?([0-9]+|\\*)))?(?h|l)?(?[diosuxXc]|I64d|S_MSG)"); var paramIndex = 0; T GetValue() @@ -1290,6 +1290,7 @@ T GetValue() case "s": case "S_MSG": + case "c": var strValue = GetValue(); if (strValue.IsNull) diff --git a/MarkMpn.Sql4Cds.Engine/JsonPath.cs b/MarkMpn.Sql4Cds.Engine/JsonPath.cs index a500733c..384866fc 100644 --- a/MarkMpn.Sql4Cds.Engine/JsonPath.cs +++ b/MarkMpn.Sql4Cds.Engine/JsonPath.cs @@ -77,7 +77,7 @@ private static JsonPathPart[] Parse(string expression, out JsonPathMode mode) i++; if (i == expression.Length) - throw new JsonException($"Invalid JSON path - missing property name after '.' at end of '{expression}'"); + throw new JsonPathException(Sql4CdsError.JsonPathFormatError(expression[i], i + 1)); if (expression[i] == '"') { @@ -130,7 +130,7 @@ private static JsonPathPart[] Parse(string expression, out JsonPathMode mode) else { // Error - throw new JsonException($"Invalid JSON path - invalid property name at index {i} of '{expression}'"); + throw new JsonPathException(Sql4CdsError.JsonPathFormatError(expression[i], i + 1)); } } else if (expression[i] == '[') @@ -139,12 +139,12 @@ private static JsonPathPart[] Parse(string expression, out JsonPathMode mode) var end = expression.IndexOf(']', i); if (end == -1) - throw new JsonException($"Invalid JSON path - missing closing bracket for indexer at index {i} of '{expression}'"); + throw new JsonPathException(Sql4CdsError.JsonPathFormatError('.', expression.Length)); var indexStr = expression.Substring(i + 1, end - i - 1); if (!UInt32.TryParse(indexStr, out var index)) - throw new JsonException($"Invalid JSON path - invalid indexer at index {i} of '{expression}'"); + throw new JsonPathException(Sql4CdsError.JsonPathFormatError(expression[i+1], i + 2)); parts.Add(new ArrayElementJsonPathPart(index)); i = end ; @@ -152,7 +152,7 @@ private static JsonPathPart[] Parse(string expression, out JsonPathMode mode) else { // Error - throw new JsonException($"JSON path is not properly formatted. Unexpected character '{expression[i]}' is found at position {i}"); + throw new JsonPathException(Sql4CdsError.JsonPathFormatError(expression[i], i + 1)); } } @@ -275,4 +275,16 @@ enum JsonPathMode Lax, Strict } + + class JsonPathException : ApplicationException, ISql4CdsErrorException + { + private readonly Sql4CdsError[] _errors; + + public JsonPathException(Sql4CdsError error) : base(error.Message) + { + _errors = new[] { error }; + } + + public IReadOnlyList Errors => _errors; + } }