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
Open
Fix {name:Type} hints being dropped when an earlier brace is not a type hint#511polyglotAI-bot wants to merge 1 commit into
polyglotAI-bot wants to merge 1 commit into
Conversation
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
polyglotAI-bot
requested review from
alex-clickhouse and
mzitnik
as code owners
August 3, 2026 22:40
Contributor
There was a problem hiding this comment.
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.ResolveTypeNamespath) and document the fix inCHANGELOG.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 Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fixes #510.
SqlParameterTypeExtractor.TryExtractParameterlocated the name/type separator with an unboundedsql.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 querySELECT 1 AS `x{y`, {dt:DateTime64(3, 'UTC')}resolveddtasDateTime('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,TryExtractParameterreturns 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 anIsParameterNameCharhelper.CHANGELOG.md/RELEASENOTES.md: bug-fix entry.Test
SqlParameterTypeExtractorTests: parametrizedExtractTypeHints_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_NotIncludedpins the documented{name}contract;ExtractTypeHints_NameThatIsNotAnIdentifier_NotIncludedpins the server-invalid names;ExtractTypeHints_UnusualButValidParameterName_ReturnsTypeis 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, whatClickHouseClient.PostSqlQueryAsynccalls) and fails onmainwithDateTime('UTC')instead ofDateTime64(3, 'UTC').mainand 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
TestCaseparametrization, CHANGELOG + RELEASENOTES, no public API change)