Skip to content

Fix {name:Type} hints being dropped when an earlier brace is not a type hint - #511

Open
polyglotAI-bot wants to merge 1 commit into
mainfrom
polyglot/cs-parameter-hint-colon-bound
Open

Fix {name:Type} hints being dropped when an earlier brace is not a type hint#511
polyglotAI-bot wants to merge 1 commit into
mainfrom
polyglot/cs-parameter-hint-colon-bound

Conversation

@polyglotAI-bot

@polyglotAI-bot polyglotAI-bot commented Aug 3, 2026

Copy link
Copy Markdown
Collaborator

Description

Fixes #510.

SqlParameterTypeExtractor.TryExtractParameter located the name/type separator with an unbounded sql.IndexOf(':', startIndex + 1), and the type scan ran to the first } anywhere in the query. A { that is not a type hint — {name} with no type, an unterminated {name:Type, or a brace the outer scanner does not skip — therefore latched onto the colon (or closing brace) of a later parameter: the extractor recorded a garbage parameter name and advanced the scan past that later parameter, so its genuine hint was silently dropped and the parameter fell back to CLR-type inference. That is observable data loss, e.g. the query SELECT 1 AS `x{y`, {dt:DateTime64(3, 'UTC')} resolved dt as DateTime('UTC'), truncating the sub-second part. The method's own doc comment already promised that {name} without a type is simply "not included".

The fix bounds both scans to the parameter's own braces: the name must be a single run of identifier characters (ASCII word characters plus $), optionally surrounded by whitespace, and the type scan stops at an opening brace. When a brace does not hold a hint, TryExtractParameter returns no match and the caller advances one character, so any following hint is still scanned. The accepted name grammar was checked against ClickHouse 26.5: { a : Int32 }, {$p_1:Int32} and {1a:Int32} are accepted by the server, while {a.b:Int32}, {a-b:Int32}, {a b:Int32} and a { inside a type definition are syntax errors.

This is a separate root cause from #508 and is not addressed by #509 — the two touch neighbouring code in the same file, so whichever merges second will need a trivial rebase.

Changes

  • ClickHouse.Driver/ADO/Parameters/SqlParameterTypeExtractor.cs: bound the separator search to the parameter's own name (identifier run, optional surrounding whitespace); stop the type scan at {; add an IsParameterNameChar helper.
  • CHANGELOG.md / RELEASENOTES.md: bug-fix entry.

Test

  • SqlParameterTypeExtractorTests: parametrized ExtractTypeHints_BraceWithoutTypeHintPrecedingHint_HintStillExtracted (10 cases: {a}, { }, a colon in a following comment, a non-identifier name, an unterminated brace, an unterminated {a:Int32, a brace inside a quoted identifier) asserts the later hint is still extracted and no garbage key is produced; ExtractTypeHints_ParameterWithoutType_NotIncluded pins the documented {name} contract; ExtractTypeHints_NameThatIsNotAnIdentifier_NotIncluded pins the server-invalid names; ExtractTypeHints_UnusualButValidParameterName_ReturnsType is the contrast case that names which are valid server-side ($p_1, 1a, a newline before the colon) still yield their hint.
  • ParameterCollectionTests.ResolveTypeNames_HintPrecededByBraceWithoutType_UsesHint: covers the live client resolution path (ClickHouseParameterCollection.ResolveTypeNames, what ClickHouseClient.PostSqlQueryAsync calls) and fails on main with DateTime('UTC') instead of DateTime64(3, 'UTC').
  • All 15 added cases fail on main and pass with the fix; --filter "FullyQualifiedName~Parameter|FullyQualifiedName~SQL" is green (4105 passed) against a live ClickHouse 26.5 server. No existing test was modified.

Pre-PR validation gate

  • Deterministic repro confirmed
  • Root cause documented above
  • Fix targets the root cause
  • Test fails without fix, passes with fix
  • No existing tests broken or weakened
  • Convention compliance verified per AGENTS.md (test naming, TestCase parametrization, CHANGELOG + RELEASENOTES, no public API change)

TryExtractParameter searched for the name/type separator with an unbounded
IndexOf(':'), and the type scan ran to the first '}' anywhere. A '{' that is
not a type hint therefore latched onto a later parameter's colon, produced a
garbage parameter name, and advanced past that parameter, silently dropping
its real hint (which then fell back to CLR-type inference).

The name is now required to be a single identifier run, optionally surrounded
by whitespace, and the type scan stops at an opening brace.

Fixes: #510
Copilot AI review requested due to automatic review settings August 3, 2026 22:40

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a correctness bug in the ADO parameter type-hint scanner ({name:Type}) where a preceding { that is not a type hint (e.g., {name} or an unterminated {name:Type) could cause the extractor to latch onto a later parameter’s :/} and silently drop the real hint—leading to incorrect type resolution and potential data loss (e.g., DateTime64 truncation).

Changes:

  • Tighten {name:Type} parsing so the : separator search is bounded to a single identifier-like name (with optional surrounding whitespace), preventing later hints from being skipped.
  • Stop the type scan when encountering a new { (treating the current parameter as unterminated rather than consuming the next parameter).
  • Add targeted unit tests (extractor-level + ClickHouseParameterCollection.ResolveTypeNames path) and document the fix in CHANGELOG.md / RELEASENOTES.md.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated no comments.

Show a summary per file
File Description
ClickHouse.Driver/ADO/Parameters/SqlParameterTypeExtractor.cs Bounds name/type scanning to the current brace pair and enforces identifier-like parameter names to prevent dropped hints/garbage keys.
ClickHouse.Driver.Tests/ADO/SqlParameterTypeExtractorTests.cs Adds parametrized regression coverage for braces that are not type hints and for valid/invalid parameter-name shapes.
ClickHouse.Driver.Tests/ParameterCollectionTests.cs Adds a regression test for the real resolution pipeline (ResolveTypeNames) to ensure the later hint is honored.
CHANGELOG.md Adds an Unreleased bug-fix entry for issue #510.
RELEASENOTES.md Adds the same Unreleased bug-fix entry for issue #510.

@codecov

codecov Bot commented Aug 3, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 5 out of 5 changed files in this pull request and generated no new comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SqlParameterTypeExtractor: a brace without a type hint swallows the colon of the next parameter, silently dropping its type hint

2 participants