1da770253e
ISqlDialect gains ParameterMarker (the token in the SQL text), ParameterBindName
(the DbParameter.ParameterName) and ConfigureCommand (per-command provider setup,
where Oracle will set BindByName). SQL Server and the test SQLite dialect answer
"@"+name for both spellings and no-op the hook, so SQL Server behaviour is
byte-identical — every existing expected-SQL assertion passes untouched.
SqlGroupPlanner drops its hardcoded @k/@w consts and mints base names (k0..kN, w)
that the dialect spells; SqlQueryPlan carries the emitted markers AND the matching
bind names, so SqlPollReader keeps copying the plan's pairing rather than
re-deriving a provider convention (the two diverge on ODP.NET: ":k0" in the text,
bare "k0" on the parameter). SqlCatalogLoader and SqlBrowseSession bind
schema/table through the dialect, so their bind names cannot drift from the
markers in the dialect-owned catalog SQL. Every parameter-carrying command site
calls ConfigureCommand before its first parameter.
Controlled by a new test-only ColonMarkerDialect (":name" markers, bare bind
names) that really executes against the SQLite fixture. Each leg was falsified
against the pre-change behaviour: the planner emitted "@k0", the reader bound
":k0", and a hardcoded "@schema" in the loader failed catalog load outright.
39 lines
1.3 KiB
C#
39 lines
1.3 KiB
C#
using Shouldly;
|
|
using Xunit;
|
|
using ZB.MOM.WW.OtOpcUa.Driver.Sql.Contracts;
|
|
|
|
namespace ZB.MOM.WW.OtOpcUa.Driver.Sql.Tests;
|
|
|
|
public class SqlQueryPlanImmutabilityTests
|
|
{
|
|
// A plan is documented as cacheable across polls. If it stayed aliased to the planner's working
|
|
// List<T>, a consumer downcast could corrupt every later poll that reused it.
|
|
[Fact]
|
|
public void Plan_doesNotAliasTheCallersLists()
|
|
{
|
|
var names = new List<string> { "@k0" };
|
|
var bindNames = new List<string> { "@k0" };
|
|
var values = new List<object?> { "v" };
|
|
var members = new List<SqlTagDefinition>
|
|
{
|
|
new("raw", SqlTagModel.KeyValue, "t") { KeyColumn = "k", KeyValue = "v", ValueColumn = "c" },
|
|
};
|
|
var selected = new List<string> { "k", "c" };
|
|
|
|
var plan = new SqlQueryPlan(
|
|
SqlTagModel.KeyValue, "gk", "SELECT 1", names, bindNames, values, members, selected);
|
|
|
|
names.Add("@k1");
|
|
bindNames.Add("@k1");
|
|
values.Add("other");
|
|
members.Add(members[0]);
|
|
selected.Add("extra");
|
|
|
|
plan.ParameterNames.Count.ShouldBe(1);
|
|
plan.ParameterBindNames.Count.ShouldBe(1);
|
|
plan.Parameters.Count.ShouldBe(1);
|
|
plan.Members.Count.ShouldBe(1);
|
|
plan.SelectedColumns.Count.ShouldBe(2);
|
|
}
|
|
}
|