refactor(sql): promote the single-row limit onto ISqlDialect
Claude-Session: https://claude.ai/code/session_01GASWkNEi68FSCtvr6rLoEW
This commit is contained in:
@@ -6,9 +6,9 @@ namespace ZB.MOM.WW.OtOpcUa.Driver.Sql;
|
||||
|
||||
/// <summary>
|
||||
/// The provider seam (design §2.2). ADO.NET's <see cref="System.Data.Common"/> base types abstract
|
||||
/// connections, commands, parameters and readers; they do <b>not</b> abstract the two things that differ
|
||||
/// per backend — <b>identifier quoting</b> and the <b>metadata-catalog SQL</b>. Those live here, so no
|
||||
/// dialect assumption leaks into the reader, the poll planner, or the schema browser.
|
||||
/// connections, commands, parameters and readers; they do <b>not</b> abstract the three things that differ
|
||||
/// per backend — <b>identifier quoting</b>, the <b>metadata-catalog SQL</b>, and <b>row-limit syntax</b>.
|
||||
/// Those live here, so no dialect assumption leaks into the reader, the poll planner, or the schema browser.
|
||||
/// <para><b>This interface is the driver's SQL-injection boundary.</b> Every runtime <em>value</em> is
|
||||
/// bound as a <see cref="DbParameter"/> and never reaches a command text. Identifiers cannot be
|
||||
/// parameterized in SQL, so the few that must appear as text are sourced only from catalog-validated
|
||||
@@ -47,6 +47,41 @@ public interface ISqlDialect
|
||||
/// <summary>Cheapest statement that proves the connection is alive (<c>SELECT 1</c>; Oracle needs <c>FROM DUAL</c>).</summary>
|
||||
string LivenessSql { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The fragment that goes <b>immediately after <c>SELECT</c></b> to limit a statement to one row —
|
||||
/// T-SQL's <c>"TOP 1 "</c>. Empty for a dialect that spells the limit at the end of the statement (see
|
||||
/// <see cref="SingleRowLimitSuffix"/>).
|
||||
/// <para><b>Include the trailing space</b> when non-empty: the planner concatenates
|
||||
/// <c>"SELECT " + SingleRowLimitPrefix + columns</c> with no separator of its own, so an empty fragment
|
||||
/// must leave the statement byte-identical to an unlimited one.</para>
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para><b>Why a prefix/suffix pair rather than one <c>ApplyRowLimit(sql, n)</c> method.</b> The two
|
||||
/// spellings sit at opposite ends of the statement — SQL Server writes
|
||||
/// <c>SELECT TOP 1 … ORDER BY … DESC</c>, while SQLite/Postgres/MySQL write
|
||||
/// <c>SELECT … ORDER BY … DESC LIMIT 1</c>. A single method taking the SELECT list could only serve the
|
||||
/// prefix position; a single method taking the whole statement would move statement assembly out of the
|
||||
/// planner and into every dialect. Two fragments keep the planner the sole author of statement shape
|
||||
/// and let each dialect fill in the end it uses.</para>
|
||||
/// <para><b>Why "single row" rather than a row count.</b> The only limit v1 emits is the wide-row
|
||||
/// <c>topByTimestamp</c> selector's newest-row pick. Modelling an arbitrary <c>n</c> would be untested
|
||||
/// surface, and <c>FETCH FIRST</c>/<c>ROWNUM</c> dialects need more than a substituted number anyway.
|
||||
/// Widen this to a method when a feature actually needs <c>n > 1</c>.</para>
|
||||
/// </remarks>
|
||||
string SingleRowLimitPrefix { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The fragment appended to the <b>very end</b> of a statement to limit it to one row —
|
||||
/// <c>" LIMIT 1"</c> for SQLite/Postgres/MySQL. Empty for a dialect that limits after <c>SELECT</c>
|
||||
/// (see <see cref="SingleRowLimitPrefix"/>).
|
||||
/// <para><b>Include the leading space</b> when non-empty, for the same reason the prefix carries a
|
||||
/// trailing one: the planner appends it directly to the finished statement.</para>
|
||||
/// <para>Exactly one of the two fragments is non-empty in every dialect modelled so far, but the planner
|
||||
/// emits <b>both</b> unconditionally — a dialect needing both ends (or neither) is expressible without
|
||||
/// touching the call site.</para>
|
||||
/// </summary>
|
||||
string SingleRowLimitSuffix { get; }
|
||||
|
||||
/// <summary>Catalog query listing schemas — the browser's <c>RootAsync</c> level. Takes no parameters.</summary>
|
||||
string ListSchemasSql { get; }
|
||||
|
||||
|
||||
Reference in New Issue
Block a user