From 401d670639f6acc78601d95e7bd3949bcd625ddb Mon Sep 17 00:00:00 2001 From: Joseph Doherty Date: Mon, 10 Aug 2026 08:03:13 -0400 Subject: [PATCH] docs(sql-dialect): record the browse consequence of Oracle's ALL_USERS schema list (Driver.Sql.Dialect-003) ListSchemasSql has two consumers and the remarks only justified the divergence from the catalog gate's viewpoint. SqlBrowseSession.RootAsync renders every row as an expandable schema, so an Oracle browse offers every database user. The narrower ALL_TABLES/ALL_VIEWS query is named, along with why it is not taken here: it narrows the gate too, and that is a poll-path behaviour change only a real Oracle server can gate. --- .../OracleDialect.cs | 24 +++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/OracleDialect.cs b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/OracleDialect.cs index 9bfa6ae9..8ffc1003 100644 --- a/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/OracleDialect.cs +++ b/src/Drivers/ZB.MOM.WW.OtOpcUa.Driver.Sql.Dialect/OracleDialect.cs @@ -141,10 +141,26 @@ public sealed class OracleDialect : ISqlDialect /// user), aliased to the TABLE_SCHEMA column name the catalog readers project by. /// /// - /// Broader than the SQL Server dialect's DISTINCT TABLE_SCHEMA FROM INFORMATION_SCHEMA.TABLES, - /// which lists only schemas that own an object: ALL_USERS includes empty ones. Harmless here — - /// the list is used to resolve an authored schema name to the catalog's own spelling, and a schema - /// holding no tables simply resolves and then matches no relation. + /// Broader than the SQL Server dialect's DISTINCT TABLE_SCHEMA FROM + /// INFORMATION_SCHEMA.TABLES, which lists only schemas that own an object: ALL_USERS + /// includes empty ones. Harmless for the catalog gate — the list is used to resolve an authored + /// schema name to the catalog's own spelling, and a schema holding no tables simply resolves and then + /// matches no relation. + /// ⚠️ It is NOT harmless for the browse tree, and that is a known, accepted trade rather than + /// an oversight (Driver.Sql.Dialect-003). This query has two consumers, and only the gate wants the + /// broad list: SqlBrowseSession.RootAsync renders every row as an expandable schema folder, so + /// on a real Oracle estate the operator is offered every database user — hundreds of them, + /// nearly all empty, with nothing in the tree distinguishing the ones that hold a relation until each + /// is expanded. + /// The narrower query is + /// SELECT DISTINCT owner FROM ALL_TABLES UNION SELECT DISTINCT owner FROM ALL_VIEWS, which + /// would match what the other two dialects list and what the browse tree wants. It is deliberately not + /// taken here because it also narrows the gate: a tag naming an empty schema today resolves and + /// then fails at the table level, and afterwards would fail at the schema level with a different + /// message — a behaviour change on the poll path that can only be validated against a real Oracle + /// server (OracleReadTests), never offline, for the same reason the p_ bind-prefix defect + /// was invisible until it ran. Make the swap when an Oracle estate is available to gate it on, and + /// change both consumers' expectations in the same commit. /// public string ListSchemasSql => "SELECT username AS TABLE_SCHEMA FROM ALL_USERS ORDER BY username";