Add IPv6 support, AUTH_METHOD_NONE, and custom curl options#248
Merged
isublimity merged 10 commits intomasterfrom Apr 4, 2026
Merged
Add IPv6 support, AUTH_METHOD_NONE, and custom curl options#248isublimity merged 10 commits intomasterfrom
isublimity merged 10 commits intomasterfrom
Conversation
- IPv6: getUri() wraps bare IPv6 addresses in brackets (e.g. [::1]:8123) - AUTH_METHOD_NONE (0): skip authentication for trusted/proxy setups - curl_options: pass arbitrary CURLOPT_* via config or setCurlOptions() - CurlerRequest::option() made public for curl option injection - Tests: IPv6UriTest, AuthMethodNoneTest, CurlOptionsTest Inspired by PR #239, reimplemented with proper IPv6 detection and tests. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Fixes #247 — streamRead() and streamWrite() accept key-value bindings, not a string array. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…eader statistics() now falls back to the X-ClickHouse-Summary HTTP header when the response body has no statistics (INSERT/write queries). New summary() method provides direct access to the header data. Fixes #233 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
docker-compose now runs two ClickHouse instances: - clickhouse-21 (port 8123) — v21.9 for backward compat - clickhouse-latest (port 8124) — v26.3.3.20 Run tests against either: CLICKHOUSE_PORT=8123 ./vendor/bin/phpunit # v21.9 CLICKHOUSE_PORT=8124 ./vendor/bin/phpunit # v26.3 Known ClickHouse 26.3 behavioral changes (not library bugs): - JSON returns numbers as native types, not strings (UInt64Test) - Temporary tables work without session (SessionsTest) - Mid-stream errors return 500 instead of 200 (StatementTest) - Different compression ratios (GzipInsert/InsertCSV size assertions) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Two separate PHPUnit configs:
- phpunit-ch21.xml (port 8123) — all original tests, 107 tests
- phpunit-ch26.xml (port 8124) — shared tests + CH26-adapted tests, 93 tests
CH26-specific tests in tests/ClickHouse26/ adapt for behavioral changes:
- Modern MergeTree syntax (ORDER BY instead of deprecated args)
- JSON returns native numeric types instead of strings (UInt64)
- Temporary tables work without sessions
- Mid-stream errors return HTTP 500 instead of 200
- No hardcoded compressed data sizes
Run: ./vendor/bin/phpunit -c phpunit-ch21.xml # ClickHouse 21.9
./vendor/bin/phpunit -c phpunit-ch26.xml # ClickHouse 26.3
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Five major initiatives planned:
1. Native Query Parameters ({name:Type} server-side binding)
2. Full ClickHouse type support (60+ types in 4 phases)
3. Structured exceptions (CH error name, query ID)
4. PHPStan level 1 → max (incremental)
5. Per-query settings override in select()/write()
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…rams, PHPStan 5
P0: Per-query settings override
- select(), selectAsync(), write() accept optional $querySettings array
- Per-query settings merge with global (per-query takes priority)
- Global settings remain unchanged after query
P0: Structured exceptions
- DatabaseException::fromClickHouse() factory with exception name + query ID
- Parse CH 22+ error format: (EXCEPTION_NAME) (version ...)
- Extract X-ClickHouse-Query-Id from response header
- getClickHouseExceptionName(), getQueryId() accessors
P1: Native Query Parameters
- selectWithParams() / writeWithParams() — server-side typed binding
- SQL uses {name:Type}, values passed as param_name in URL
- Supports: int, float, string, bool, null, DateTime, array
- SQL injection impossible at protocol level
P1: PHPStan level 1 → 5
- Raised from level 1 to level 5
- Baseline for 60 pre-existing errors (mostly curl layer type hints)
- All new code must pass level 5
Tests: 126 (CH21) + 112 (CH26) = all passing
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
#234 Fix: hasErrorClickhouse no longer json_decode() large responses - Bodies > 4KB: check only tail for ClickHouse error patterns - Bodies <= 4KB: validate JSON as before (preserves #223 fix) - Prevents OOM when streaming large JSON resultsets #166 Feature: Generator-based row iteration - Statement::rowsGenerator() — yields rows from already-fetched data - Client::selectGenerator() — streams from CH via JSONEachRow, yields one row at a time without loading full resultset into memory - Supports bindings and per-query settings #176 Feature: GitHub Actions CI (replaces Travis CI) - Matrix: PHP 8.0-8.4 x ClickHouse 21.9 + 26.3 - PHPStan and PHPCS jobs - Docker services for both CH versions Tests: 135 (CH21) + 121 (CH26) = all passing, PHPStan clean Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New types in src/Type/: - Int64, Decimal — large numeric types (string-based, no overflow) - UUID — UUID values for insert and native params - IPv4, IPv6 — IP address types - DateTime64 — sub-second precision, fromString() and fromDateTime() - Date32 — extended date range - MapType — Map(K, V) composite type - TupleType — Tuple(T1, T2, ...) composite type All types implement Type interface, work with: - insert() via ValueFormatter pipeline - selectWithParams() via convertParamValue() - Bindings via getValue() #191 Fix: progressFunction now works for write/insert operations - Added wait_end_of_query=1 setting when progressFunction is enabled - Required for ClickHouse to send progress headers during writes Tests: 158 (CH21) + 144 (CH26) = all passing, PHPStan clean Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
New docs in doc/:
- types.md — all 9 type classes with examples (insert, bindings, native params)
- native-params.md — server-side {name:Type} parameters
- per-query-settings.md — $querySettings override for select/write
- generators.md — selectGenerator() and rowsGenerator() for large results
- progress.md — progressFunction for SELECT and INSERT
- exceptions.md — structured exceptions with error codes and names
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.
Summary
getUri()correctly wraps bare IPv6 addresses in brackets (e.g.http://[::1]:8123), distinguishing IPv6 fromhost:portby counting colonsCURLOPT_*via$connectParams['curl_options']array orHttp::setCurlOptions()Reimplements the ideas from #239 with proper IPv6 detection and full test coverage.
Test plan
IPv6UriTest— 8 cases: IPv6 with/without port, already bracketed, IPv4, hostname:port, hostname/pathAuthMethodNoneTest— constant value, presence in AUTH_METHODS_LIST, client constructionCurlOptionsTest— options via config and viasetCurlOptions()🤖 Generated with Claude Code