Skip to content

fix(bind): treat []byte as String and time.Duration as Time - #1945

Open
sankalpsthakur wants to merge 2 commits into
ClickHouse:mainfrom
sankalpsthakur:fix/1942-bind-byte-duration
Open

fix(bind): treat []byte as String and time.Duration as Time#1945
sankalpsthakur wants to merge 2 commits into
ClickHouse:mainfrom
sankalpsthakur:fix/1942-bind-byte-duration

Conversation

@sankalpsthakur

@sankalpsthakur sankalpsthakur commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes client-side parameter binding for two Go types that previously fell through to unusable SQL literals in formatValue (bind.go):

  1. []byte — was rendered via reflect.Slice as Array(UInt8) ([65, 0, 66]). Now quoted as a ClickHouse String literal with the same escaping as string (\, ', and NUL as \0).
  2. time.Duration / *time.Duration — matched fmt.Stringer and produced Go’s duration form ('14h30m0s'). Now rendered as a Time/Time64-parseable HH:MM:SS[.frac] literal. time.Duration is the driver’s own ScanType for Time/Time64.

Fixes #1942

Checklist

Tests

go test -count=1 -run 'TestBindDuration|TestBindBytes|TestFormatDuration|TestFormatValueModes|TestBind' .
go test -count=1 .

AI disclosure

AI assistance was used to locate the formatValue fallthrough and draft the unit tests. The change was reviewed, kept minimal to the bind path, and verified with the package unit tests above.

AI/LLM disclosure

  • AI coding tools (including Grok and/or Codex agent-assisted editing) were used to help draft or modify code and this PR description.
  • I reviewed the complete change, understand the reasoning, and ran the reported local tests before submitting.
  • This submission is original work of authorship under the project CLA / contributor terms; AI output was not pasted unreviewed.

Client-side formatValue had no cases for []byte or time.Duration, so
[]byte fell through to reflect.Slice (Array(UInt8)) and Duration hit
fmt.Stringer (Go's "14h30m0s"). Both are unusable against String and
Time/Time64 columns respectively.

- Quote []byte like string (escape \, ', and NUL as \0)
- Format time.Duration / *time.Duration as HH:MM:SS[.frac]
- Unit tests for bind + formatDuration

Fixes ClickHouse#1942

AI assistance: used for locating formatValue fallthrough and drafting
the bind tests; change reviewed and verified with go test.
Comment thread bind.go Outdated
}
fracStr := fmt.Sprintf("%09d", frac.Nanoseconds())
fracStr = strings.TrimRight(fracStr, "0")
return fmt.Sprintf("%s%02d:%02d:%02d.%s", sign, hours, mins, secs, fracStr)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

add single quotes as formatTime puts them - API should be consistent.

@sankalpsthakur sankalpsthakur Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 8393cdc, please take another look.

Comment thread bind.go Outdated
return formatTime(tz, scale, *v)
case time.Duration:
// Must precede fmt.Stringer: Duration.String() is Go's "14h30m0s".
return quote(formatDuration(v)), nil

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

formatDuration should return quoted string like formatTime does

@sankalpsthakur sankalpsthakur Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 8393cdc, please take another look.

Comment thread bind_test.go

// TestBindDuration checks that time.Duration (the ScanType for ClickHouse
// Time/Time64) binds as a Time-parseable literal, not Go's duration string.
func TestBindDuration(t *testing.T) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

add tests with Time64 with different precision.

@sankalpsthakur sankalpsthakur Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Addressed in 8393cdc, please take another look.

…recision tests

Address review feedback from chernser:
- formatDuration now returns quoted string like formatTime, including single quotes
  in the return value for API consistency.
- Add TestBindDuration_Time64Precision covering Time/Time64 with
  different precisions (seconds, milli, micro, nano) and composite types.

Fixes ClickHouse#1942

Signed-off-by: Sankalp Thakur <sankalphimself@gmail.com>
@sankalpsthakur

sankalpsthakur commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Hi @chernser, addressed the three threads in 8393cdc. Made formatDuration return the quoted literal like formatTime does, so call sites just use it directly. Added Time64 precision tests covering Time and Time64 variants and composites. Go tests for bind pass. Please take another look.

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.

bind: []byte is bound as Array(UInt8) and time.Duration as a Go duration string, so binary and Time values cannot be bound as parameters

2 participants