From 3ae08b5833664447099a0e2a5a5bad76f8a968ef Mon Sep 17 00:00:00 2001 From: Mark Carrington <31017244+MarkMpn@users.noreply.github.com> Date: Wed, 4 Dec 2024 08:24:23 +0000 Subject: [PATCH] Handle nested primary functions Fixes #598 --- .../AdoProviderTests.cs | 30 ++++++++++++++++++- .../ReplacePrimaryFunctionsVisitor.cs | 30 +++++++++++-------- 2 files changed, 47 insertions(+), 13 deletions(-) diff --git a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs index 35cff7b2..c860a443 100644 --- a/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs +++ b/MarkMpn.Sql4Cds.Engine.Tests/AdoProviderTests.cs @@ -2930,7 +2930,7 @@ public void ErrorOnTruncateGuid() } [TestMethod] - public void ErrorOnTruncateEntityReferenc() + public void ErrorOnTruncateEntityReference() { using (var con = new Sql4CdsConnection(_localDataSources)) using (var cmd = con.CreateCommand()) @@ -2951,5 +2951,33 @@ public void ErrorOnTruncateEntityReferenc() } } } + + [TestMethod] + public void NestedPrimaryFunctions() + { + using (var con = new Sql4CdsConnection(_localDataSources)) + using (var cmd = con.CreateCommand()) + { + cmd.CommandText = "INSERT INTO account (name) VALUES ('Data8')"; + cmd.ExecuteNonQuery(); + cmd.CommandText = "INSERT INTO account (name) VALUES (null)"; + cmd.ExecuteNonQuery(); + + cmd.CommandText = "SELECT name, MAX(IIF(name = 'Data8', COALESCE(turnover, -1), 0)) FROM account GROUP BY name"; + + using (var reader = cmd.ExecuteReader()) + { + Assert.IsTrue(reader.Read()); + Assert.IsTrue(reader.IsDBNull(0)); + Assert.AreEqual(0, reader.GetDecimal(1)); + + Assert.IsTrue(reader.Read()); + Assert.AreEqual("Data8", reader.GetString(0)); + Assert.AreEqual(-1, reader.GetDecimal(1)); + + Assert.IsFalse(reader.Read()); + } + } + } } } diff --git a/MarkMpn.Sql4Cds.Engine/Visitors/ReplacePrimaryFunctionsVisitor.cs b/MarkMpn.Sql4Cds.Engine/Visitors/ReplacePrimaryFunctionsVisitor.cs index e815d833..cffedff8 100644 --- a/MarkMpn.Sql4Cds.Engine/Visitors/ReplacePrimaryFunctionsVisitor.cs +++ b/MarkMpn.Sql4Cds.Engine/Visitors/ReplacePrimaryFunctionsVisitor.cs @@ -31,6 +31,7 @@ protected override ScalarExpression ReplaceExpression(ScalarExpression expressio ThenExpression = expr }); + caseExpr.Accept(this); return caseExpr; } @@ -42,13 +43,14 @@ protected override ScalarExpression ReplaceExpression(ScalarExpression expressio { new SearchedWhenClause { - WhenExpression = iif.Predicate, - ThenExpression = iif.ThenExpression + WhenExpression = iif.Predicate.Clone(), + ThenExpression = iif.ThenExpression.Clone() } }, - ElseExpression = iif.ElseExpression + ElseExpression = iif.ElseExpression.Clone() }; + caseExpr.Accept(this); return caseExpr; } @@ -60,8 +62,9 @@ protected override ScalarExpression ReplaceExpression(ScalarExpression expressio }; foreach (var param in left.Parameters) - leftFunc.Parameters.Add(param); + leftFunc.Parameters.Add(param.Clone()); + leftFunc.Accept(this); return leftFunc; } @@ -75,16 +78,17 @@ protected override ScalarExpression ReplaceExpression(ScalarExpression expressio { WhenExpression = new BooleanComparisonExpression { - ComparisonType = BooleanComparisonType.Equals, FirstExpression = nullif.FirstExpression.Clone(), - SecondExpression = nullif.SecondExpression + ComparisonType = BooleanComparisonType.Equals, + SecondExpression = nullif.SecondExpression.Clone() }, ThenExpression = new NullLiteral() } }, - ElseExpression = nullif.FirstExpression + ElseExpression = nullif.FirstExpression.Clone() }; + caseExpr.Accept(this); return caseExpr; } @@ -96,8 +100,9 @@ protected override ScalarExpression ReplaceExpression(ScalarExpression expressio }; foreach (var param in right.Parameters) - rightFunc.Parameters.Add(param); + rightFunc.Parameters.Add(param.Clone()); + rightFunc.Accept(this); return rightFunc; } @@ -126,9 +131,9 @@ protected override BooleanExpression ReplaceExpression(BooleanExpression express { FirstExpression = new BooleanComparisonExpression { - FirstExpression = between.FirstExpression, + FirstExpression = between.FirstExpression.Clone(), ComparisonType = between.TernaryExpressionType == BooleanTernaryExpressionType.Between ? BooleanComparisonType.GreaterThanOrEqualTo : BooleanComparisonType.LessThan, - SecondExpression = between.SecondExpression, + SecondExpression = between.SecondExpression.Clone(), FirstTokenIndex = between.FirstTokenIndex, LastTokenIndex = between.LastTokenIndex, @@ -137,9 +142,9 @@ protected override BooleanExpression ReplaceExpression(BooleanExpression express BinaryExpressionType = between.TernaryExpressionType == BooleanTernaryExpressionType.Between ? BooleanBinaryExpressionType.And : BooleanBinaryExpressionType.Or, SecondExpression = new BooleanComparisonExpression { - FirstExpression = between.FirstExpression, + FirstExpression = between.FirstExpression.Clone(), ComparisonType = between.TernaryExpressionType == BooleanTernaryExpressionType.Between ? BooleanComparisonType.LessThanOrEqualTo : BooleanComparisonType.GreaterThan, - SecondExpression = between.ThirdExpression, + SecondExpression = between.ThirdExpression.Clone(), FirstTokenIndex = between.FirstTokenIndex, LastTokenIndex = between.LastTokenIndex, @@ -156,6 +161,7 @@ protected override BooleanExpression ReplaceExpression(BooleanExpression express ScriptTokenStream = between.ScriptTokenStream }; + converted.Accept(this); return converted; }