Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
271 commits
Select commit Hold shift + click to select a range
342ed49
test(egress): live EXEC_DONE coverage for CREATE / INSERT / DROP
bluestreak01 Apr 26, 2026
94ca980
feat(egress): CREDIT flow control sender
bluestreak01 Apr 26, 2026
e85f9ea
feat(egress): connect-time failover with target routing
bluestreak01 Apr 26, 2026
2147636
test(egress): live DOUBLE_ARRAY coverage (1-D / 2-D / nulls)
bluestreak01 Apr 26, 2026
1f74233
test(egress): live edge-case coverage across every column type
bluestreak01 Apr 26, 2026
ee5fbef
chore(egress): fix CI fmt + clippy warnings
bluestreak01 Apr 26, 2026
fa99a7a
fix(egress): drop dev-dep ureq rustls feature to avoid crypto provide…
bluestreak01 Apr 26, 2026
1916117
ci: install JDK 25 for QuestDB master compile job
bluestreak01 Apr 26, 2026
8ec0a85
perf(egress): zero-copy decode of RESULT_BATCH payloads
bluestreak01 Apr 26, 2026
1163d43
perf(egress): tighter SYMBOL + VARCHAR decode hot paths
bluestreak01 Apr 26, 2026
0962e1c
fix(egress): cursor lifecycle correctness + PR review fixes
bluestreak01 Apr 27, 2026
3042790
egress failover
glasstiger Apr 29, 2026
add65af
no offsets array for NullVarchar and NullBinary
glasstiger Apr 29, 2026
73d29dd
support bracketed-IPv6 form
glasstiger Apr 29, 2026
7bc545f
clippy fix
glasstiger Apr 29, 2026
611705e
toml file fix
glasstiger Apr 29, 2026
ba92060
is_null not to panic on length-mismatched bitmap
glasstiger Apr 29, 2026
bb5c995
fix Bind::Null
glasstiger Apr 29, 2026
9a9b1a2
mark VarcharColumn::new unsafe fn
glasstiger Apr 29, 2026
847d238
cancel() fixes
glasstiger Apr 29, 2026
83b27ec
Decimal scale validation
glasstiger Apr 29, 2026
6398c1a
visibility changes
glasstiger Apr 29, 2026
a93e6d6
more tests
glasstiger Apr 29, 2026
edcf6ec
fix code formatting
glasstiger Apr 29, 2026
d073a9e
fix row count in failover example
glasstiger Apr 29, 2026
f35687f
TLS and authentication
glasstiger Apr 29, 2026
5f842bd
fix warning
glasstiger Apr 29, 2026
264552f
address coderabbit comments
glasstiger Apr 30, 2026
d13520f
ingress: warning fixes
glasstiger May 1, 2026
303f395
C and C++ clients
glasstiger May 1, 2026
fa90f88
fix build on CI
glasstiger May 1, 2026
19a6d4f
replace ‘__int128’, ISO C++ does not support
glasstiger May 1, 2026
840c072
fix Windows build
glasstiger May 1, 2026
0a0df26
fix formatting
glasstiger May 1, 2026
369545c
fix clippy issues
glasstiger May 1, 2026
ea70ae2
fix Windows build
glasstiger May 1, 2026
5293af8
address code review comments
glasstiger May 1, 2026
ae1a40d
fix code formatting
glasstiger May 1, 2026
1c88d37
address code review comments
glasstiger May 1, 2026
b675e70
address code review comments
glasstiger May 1, 2026
4d52f45
address code review comments
glasstiger May 1, 2026
1f4b61a
address code review comments
glasstiger May 1, 2026
a962ef8
address code review comments
glasstiger May 1, 2026
079215b
fix code formatting
glasstiger May 1, 2026
72be895
NULL guards
glasstiger May 2, 2026
c06e99b
hardening of non-nullable type decoding
glasstiger May 5, 2026
939f299
zero-copy write path
glasstiger May 5, 2026
0a3762a
comply with egress spec
glasstiger May 5, 2026
ca83b71
python egress failover integration tests
glasstiger May 6, 2026
7328dfa
mirror Java client's caps
glasstiger May 6, 2026
375f50f
use catch_unwind consistently
glasstiger May 6, 2026
30b4d0e
NULL-handle guard for FFI entry points whose contract disallows NULL
glasstiger May 6, 2026
41348e8
simplify code
glasstiger May 6, 2026
441619f
address code review comments
glasstiger May 6, 2026
24bdd05
_query_execute nulls caller's pointer
glasstiger May 7, 2026
c6c1a24
Bind::Null now takes a SimpleNullKind enum
glasstiger May 7, 2026
a6b7757
Upfront capacity check of delta_count in symbol dict
glasstiger May 7, 2026
c975041
reduce visibility in column.rs
glasstiger May 7, 2026
4145fa0
fix: Validity::is_null masks short bitmaps with a silent default
glasstiger May 7, 2026
237931a
add #[non_exhaustive] to enums to make them future-proof
glasstiger May 7, 2026
12916cf
doc improvements
glasstiger May 7, 2026
6e7b20b
fix: line_reader_error_code enum members not explicitly numbered
glasstiger May 7, 2026
e817617
code formatting
glasstiger May 7, 2026
859aefd
reject control characters in username
glasstiger May 7, 2026
8ec72db
fix TLS secret leak
glasstiger May 7, 2026
66c37b7
reject unbracketed ipv6
glasstiger May 7, 2026
3e652a9
improve doc
glasstiger May 7, 2026
a71e9ae
make insecure-skip-verify opt-in in C/C++ clients, default is off
glasstiger May 7, 2026
54b7c64
fix: PEM-file root load silently produces an empty trust store on a f…
glasstiger May 7, 2026
1ec4fb5
fix: ColumnView and Validity lack #[non_exhaustive]
glasstiger May 7, 2026
034c437
fix: _server_version returns false on NULL handle without setting *er…
glasstiger May 7, 2026
ded9590
code formatting
glasstiger May 7, 2026
09518eb
fix: Cursor::add_credit does not honour the failover contract
glasstiger May 7, 2026
a027807
fix: ReaderConfig field mutability bypasses parse-time validation
glasstiger May 7, 2026
3bd0f56
fix: Drop for Cursor does not send CANCEL before closing
glasstiger May 7, 2026
fdedf64
Mock-server malformed-frame tests
glasstiger May 7, 2026
adbf290
fix: validate_content_encoding accepts unknown zstd parameters
glasstiger May 7, 2026
70d8c1e
improve decimal128 FFI parameter naming
glasstiger May 7, 2026
e717c8a
improved auth error message
glasstiger May 7, 2026
8b865b3
code formatting
glasstiger May 7, 2026
25ece00
future-proofing result batch decoding against panic
glasstiger May 7, 2026
2f3a6c3
improve error test coverage
glasstiger May 7, 2026
5595fe0
run the new C++ test binaries on CI
glasstiger May 7, 2026
efc5eda
fix doc
glasstiger May 7, 2026
8b6a772
fix: decode_gorilla_temporal rejects non_null < 3 instead of decoding…
glasstiger May 7, 2026
94bd2d1
column view cache
glasstiger May 7, 2026
9fa9f98
bytes as optional dependency
glasstiger May 7, 2026
8e330c5
more tests
glasstiger May 8, 2026
8ff9776
CI lint to cover system_test
glasstiger May 8, 2026
447e347
auth header tests
glasstiger May 8, 2026
52a51b0
ZSTD tests
glasstiger May 8, 2026
e72d310
TLS tests
glasstiger May 8, 2026
b68db2f
code formatting, clippy
glasstiger May 8, 2026
b17d00d
fix test
glasstiger May 8, 2026
a4558b7
fix: _query_new and _query_execute allocate outside catch_unwind
glasstiger May 8, 2026
215f138
centralise err_out null-check
glasstiger May 11, 2026
b8143eb
reject dim = 0
glasstiger May 11, 2026
c24ef82
optimise ZSTD allocations
glasstiger May 11, 2026
fbfef33
rename bind_uuid_bytes to bind_uuid for consistency
glasstiger May 11, 2026
d326f73
fix doc
glasstiger May 11, 2026
74abacb
unify rust and C/C++ from_env()/from_conf() APIs
glasstiger May 11, 2026
3ee882e
fix: Bind::Geohash silently truncates value beyond precision_bits
glasstiger May 11, 2026
beb201c
fix: Cursor::cancel() writes credit-nudge before installing drain tim…
glasstiger May 11, 2026
9823002
CAP_ZONE capability bit / SERVER_INFO.zone_id and decoder fixes
glasstiger May 11, 2026
6339a1b
host health tracker
glasstiger May 11, 2026
39f432d
new config options
glasstiger May 11, 2026
f4d4dca
full-jitter backoff
glasstiger May 11, 2026
4d1ab19
relax param check of X-QWP-Content-Encoding
glasstiger May 11, 2026
ed658f0
fix: post-upgrade SERVER_INFO read has no timeout
glasstiger May 11, 2026
759dc23
rethrow AuthError during initial connect
glasstiger May 11, 2026
5eadbe9
fix FFI
glasstiger May 11, 2026
9791dc9
code formatting
glasstiger May 11, 2026
62f5dbb
fixing tests
glasstiger May 11, 2026
5d25740
code formatting
glasstiger May 11, 2026
0195892
optional server info in error
glasstiger May 11, 2026
a14c349
fix: line_reader_cursor_free docstring contradicts Cursor::Drop behavior
glasstiger May 11, 2026
96d92f7
fix: line_reader_cursor_column_name is the only column-side getter wi…
glasstiger May 11, 2026
e681e55
fix: UnsafeCell<Reader> aliasing docstring overstates SB-soundness
glasstiger May 11, 2026
a47a72a
fix: Hot-path code missing #[inline] across crate boundaries
glasstiger May 11, 2026
070b0ff
fix: decode_result_batch allocates Vec<ColumnKind> per batch
glasstiger May 11, 2026
9c668d4
fix: decode_gorilla_temporal densifies in two passes
glasstiger May 11, 2026
7617a62
fix: _cursor_credit_granted_total thread-safety docstring contradicts…
glasstiger May 11, 2026
3b67a57
fix: terminate_with_close doesn't release the FD
glasstiger May 11, 2026
42b162b
fix: Cursor::cancel +1-byte credit nudge violates the documented cred…
glasstiger May 11, 2026
5eebed5
fix: TLS coverage of non-default tls_ca modes is config-only
glasstiger May 11, 2026
4787275
fix: No live-server auth smoke
glasstiger May 11, 2026
a7be72e
fix: No regression test pins the Drop-sends-CANCEL fix (commit 3bd0f56)
glasstiger May 11, 2026
3fe53c9
fix: No live test for Cursor::add_credit server-pause / failover / te…
glasstiger May 11, 2026
d455a9a
fix: C-only smoke test does not cover cursor lifecycle
glasstiger May 11, 2026
3038957
fix: remove unused error types
glasstiger May 11, 2026
fdcc4de
fix: ZSTD decompressed buffer is a fresh allocation per batch
glasstiger May 11, 2026
a4ba0c9
fix: count_nulls is byte-by-byte popcount
glasstiger May 11, 2026
95f4629
fix: FLAG_ZSTD rejection path (when client built without compression-…
glasstiger May 11, 2026
b248c2a
fix: decode_gorilla_temporal_round_trip is parameterised over only Ti…
glasstiger May 11, 2026
bb78879
fix: reserve_then_close_addr() uses let-OS-pick-then-close
glasstiger May 11, 2026
da6dc03
fix: 144 public items in egress/ lack rustdoc. Top-level pub use re-e…
glasstiger May 11, 2026
d212d3a
fix: Perf claim without an anchoring benchmark
glasstiger May 11, 2026
2ba2c1d
fix: panic_guard on every per-row column getter pays an unwind frame …
glasstiger May 11, 2026
7ba7425
code formatting
glasstiger May 11, 2026
e60690c
fix clippy errors
glasstiger May 11, 2026
af21edb
fix flaky tests
glasstiger May 11, 2026
1324bf0
fix: CRLF/control-byte rejection bypassed by post-parse field mutation
glasstiger May 11, 2026
b35a635
fix: Failover replay can silently restart already-terminal streams
glasstiger May 11, 2026
cff44ff
fix: addr=host:0 accepted
glasstiger May 11, 2026
2aed932
fix: Content-Encoding codec name is case-sensitive
glasstiger May 11, 2026
4fc2384
fix: apply_delta_from_bytes uses raw subtraction
glasstiger May 11, 2026
f8c24d4
increase test coverage
glasstiger May 11, 2026
6253ed7
fix: FFI cursor getters dereference NULL cursor argument
glasstiger May 11, 2026
dbb3423
fix: naming inconsistency across Rust/C++: query vs prepare
glasstiger May 11, 2026
a0dcbc7
fix: Public structs with all-pub fields and no #[non_exhaustive]
glasstiger May 11, 2026
791abde
fix: compression doc
glasstiger May 11, 2026
fa424fa
fix: ReaderQuery, Cursor, BatchView lack #[must_use]
glasstiger May 11, 2026
392aff0
doc update
glasstiger May 11, 2026
c6d78b5
code formatting
glasstiger May 11, 2026
7c83866
fix build
glasstiger May 12, 2026
da9a138
fix clippy issue
glasstiger May 12, 2026
c3dc020
fix failover test
glasstiger May 12, 2026
41cd2db
fix clippy issue
glasstiger May 12, 2026
c29d80d
log a warning when a ProtocolError triggers failover
glasstiger May 12, 2026
4ce6546
fix: request_id patch offset is hardcoded; layout invariant only chec…
glasstiger May 12, 2026
8ef50e7
add CONTRIBUTING.md
glasstiger May 12, 2026
e74f084
doc improvements
glasstiger May 12, 2026
dc03ca3
failover_max_duration_ms is now a true per-Execute budget
glasstiger May 12, 2026
fd7aee8
server role constants
glasstiger May 12, 2026
e6732b2
compression_level connect-string key (default 3, range [1, 22])
glasstiger May 12, 2026
27ff0cb
fix: Cursor::add_credit bypasses the silent-duplicate failover guard
glasstiger May 12, 2026
a8cd612
query() -> prepare()
glasstiger May 12, 2026
366da9d
code formatting
glasstiger May 12, 2026
c9aa3fd
more tests
glasstiger May 12, 2026
3e4b9d8
code formatting
glasstiger May 12, 2026
7e8b98d
fix tests
glasstiger May 12, 2026
86a1e1b
add test: INSERT with bind variables
glasstiger May 14, 2026
fc645bf
code formatting
glasstiger May 14, 2026
dd31f20
replace tungstenite with custom WebSocket client
bluestreak01 May 14, 2026
a1c2677
code formatting
glasstiger May 15, 2026
4ceae24
code formatting, clippy
glasstiger May 15, 2026
ac57742
fix: ReaderQuery::error is dead code
glasstiger May 15, 2026
607d0c3
fix: SchemaColumn lacks #[non_exhaustive]
glasstiger May 15, 2026
415c480
doc improvement: consolidate "Phase 1" comments
glasstiger May 15, 2026
889d26b
fix: exec_done_for_ddl_and_insert doesn't pin op_type
glasstiger May 15, 2026
c29f548
egress read bench
glasstiger May 15, 2026
8e6dba3
qwp:: -> ws::
glasstiger May 15, 2026
787ca39
code formatting
glasstiger May 15, 2026
4a77e26
qwp:: -> ws::
glasstiger May 15, 2026
829a68b
fix: C++reader::operator=(reader&&)silently leaks the old reader if a…
glasstiger May 15, 2026
6f27b29
ReaderConfig::validate() to re-check the tls_verify=unsafe_off featur…
glasstiger May 15, 2026
639c40e
improved error message at failover exhaustion
glasstiger May 15, 2026
b6eabd2
fix: decode_varlen manual u32 push loop
glasstiger May 15, 2026
7a5df8c
update review-pr skill
glasstiger May 15, 2026
1894529
code formatting
glasstiger May 15, 2026
2b99ea7
test(egress): port QWP egress fuzz suite from Java OSS questdb (#142)
jovfer May 16, 2026
c686a9d
Merge remote-tracking branch 'origin/main' into vi_egress
bluestreak01 May 17, 2026
42b76a8
chore(deps): bump rustls / aws-lc / bytes / rand / ring to clear Depe…
bluestreak01 May 17, 2026
ba4eb04
fix(ci): disable set -x around ##vso echoes on hetzner-incus jobs
bluestreak01 May 17, 2026
c8bd13c
fix(qwp_ws): apply reconnect budget to TestQwpWsFuzz initial connect
bluestreak01 May 17, 2026
6cf0760
fix(ffi): reject overflowing line_sender_buffer_reserve up front
bluestreak01 May 17, 2026
c0db892
feat(qwp_ws): reconnect_* knobs imply initial_connect_retry=sync
bluestreak01 May 17, 2026
242ecd2
test(qwp_ws): cover gaps in reconnect-implies-initial-retry promotion
bluestreak01 May 17, 2026
6379be0
fix(egress): default zstd compression level to 1
bluestreak01 May 17, 2026
c50e347
refactor(ws): consolidate RFC 6455 plumbing into shared questdb::ws m…
bluestreak01 May 17, 2026
f3f1bf0
perf(ws): SIMD apply_mask on aarch64 (NEON) and x86_64 (AVX2/SSE2)
bluestreak01 May 17, 2026
c9c8494
perf(egress): bump WS recv buffer 1 MiB -> 4 MiB
bluestreak01 May 17, 2026
ec07d82
hardening(ws): bound recv-buffer growth + fallible handshake allocs
bluestreak01 May 17, 2026
c1e7706
release: bump to 7.0.0 + multi-host addr / init_buf_size in egress & QWP
bluestreak01 May 17, 2026
252cf12
docs(ws): tighten SAFETY note on the recv-buffer uninit cast
bluestreak01 May 17, 2026
a0d1af7
test(ingress/tcp): red test for SIGPIPE on closed-peer flush
bluestreak01 May 17, 2026
132be12
test(ingress/tcp): fix clippy under -D warnings
bluestreak01 May 17, 2026
d38bd69
revert: drop SIGPIPE ingress test — bug doesn't manifest via Sender
bluestreak01 May 17, 2026
4ffaab5
refactor(ingress/ws): drop panics from write_frame_to_buf
bluestreak01 May 17, 2026
8c3e683
api(ingress): mark Protocol #[non_exhaustive] + FFI unknown sentinel
bluestreak01 May 17, 2026
7239e5d
cleanup: drop dead FFI catch_unwind + mac mock SIGPIPE + tracker doc
bluestreak01 May 17, 2026
be18def
feat(qwp/tls): accept tls_roots_password (JKS + PKCS#12) on QWP
bluestreak01 May 17, 2026
e5717ad
cleanup: clear rustdoc + dead-code warnings across feature combos
bluestreak01 May 17, 2026
13d0888
test(fuzz): pre-create failover-fuzz tables with DEDUP UPSERT KEYS
bluestreak01 May 18, 2026
31f9d1e
feat(config): make connect string portable between ingress and egress
bluestreak01 May 18, 2026
17dcf12
test(ingress): drop tls_verify=on from plain-http portability test
bluestreak01 May 18, 2026
018b850
config(ingress): reject auto_flush_interval explicitly
bluestreak01 May 18, 2026
12705c8
test(common): retry JVM start on tcp-line port-bind race
jovfer May 18, 2026
8abbebc
test(common): replace JVM-start retry with a process-local startup mutex
jovfer May 18, 2026
48c7821
feat(ingress/http): add retry_max_backoff knob
bluestreak01 May 18, 2026
a05316a
Merge remote-tracking branch 'origin/main' into vi_egress
bluestreak01 May 18, 2026
37be473
fix(ingress/conf): gate retry_max_backoff_millis parser on sync-sende…
bluestreak01 May 18, 2026
e426923
fix ffi UB and some other reviews
kafka1991 May 19, 2026
03c18f3
ingress align specs
kafka1991 May 19, 2026
1dfce51
rename macros
kafka1991 May 19, 2026
815f7c1
cpptest add SANITIZE
kafka1991 May 19, 2026
3e196b7
use RelWithDebInfo
kafka1991 May 19, 2026
09e4c6f
fix(egress/ws): SIGPIPE-proof writes via per-platform NoSigpipeTcp wr…
bluestreak01 May 19, 2026
0fac196
test(egress): bind-ABI smoke + reader-migration concurrency regression
bluestreak01 May 19, 2026
2e3e71b
qwp-ws: expose lifetime totals and add qwp_sidecar driver binary
bluestreak01 May 19, 2026
83d7518
ci: trigger questdb-enterprise e2e for the c_client_rust sidecar
bluestreak01 May 19, 2026
5d4d971
ci: run enterprise-dispatch job on hetzner-incus
bluestreak01 May 19, 2026
45e9ef8
test(mock): emplace_back the Script actions so GCC 13 stops false-pos…
bluestreak01 May 19, 2026
af5d55a
ci: point enterprise dispatch at the questdb-enterprise ADO project
bluestreak01 May 19, 2026
809bff0
ci: dispatch via PAT instead of System.AccessToken
bluestreak01 May 19, 2026
9fbd32c
ci: empty commit to retest enterprise dispatch after PAT setup
bluestreak01 May 19, 2026
27890a5
feat(egress): add on_failover_progress lifecycle callback
bluestreak01 May 19, 2026
af212b5
c/cpp api refactor
kafka1991 May 20, 2026
61dcd4a
code reformat
kafka1991 May 20, 2026
f9a74d9
code review and fix linux/windows issue
kafka1991 May 20, 2026
2d4c580
fix failed ci
kafka1991 May 20, 2026
948cfc1
fix align issue
kafka1991 May 20, 2026
0e4cb86
add align issue comment
kafka1991 May 20, 2026
2e64492
fix align issue in test
kafka1991 May 20, 2026
da3cc98
continue on align issue
kafka1991 May 20, 2026
c765dd1
continue on align issue
kafka1991 May 20, 2026
e69108e
continue on align issue
kafka1991 May 20, 2026
8548972
pipelined reader
glasstiger May 20, 2026
23b2277
Merge branch 'vi_egress' into ia_pipelined_reader
glasstiger May 20, 2026
3441c73
improved doc
glasstiger May 20, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bumpversion.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[tool.bumpversion]
current_version = "6.1.0"
current_version = "7.0.0"
commit = false
tag = false

Expand Down
28 changes: 25 additions & 3 deletions .claude/skills/review-pr/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,20 @@ Group the callsites from 2.5b by execution context. Typical contexts in this cod

Every entry on this list must be reviewed in Step 3.

### 2.5e Build profile facts

**This sub-step runs at every level, including levels 0 and 1 where the rest of Step 2.5 is skipped.** A single `Cargo.toml` setting can flip the panic-safety story for the entire crate; agents must reason from the actual profile, not from defaults.

Read `questdb-rs/Cargo.toml` and `questdb-rs-ffi/Cargo.toml` and record, with file:line citations:

- **panic strategy** per profile (`[profile.release]`, `[profile.dev]`). If `panic = "abort"` in either, **every `catch_unwind` in that crate is a no-op for that profile** and every reachable panic is a process abort. Agents 2, 3, and 4 (and the level-0 inline review) must not credit `catch_unwind` as a panic guard under `panic = "abort"`. The only acceptable defense under abort-panic is proving no panic path exists.
- **overflow-checks** per profile. If `overflow-checks = false` in release (the default), integer overflow wraps silently in release builds instead of panicking — bugs that look like panics in test builds disappear into wrong values in production. State which mode applies.
- **`[profile.*.package.*]` overrides** if present — a per-dependency profile can reintroduce unwinding for one crate even when the workspace defaults to abort.
- **`#[global_allocator]`** if defined anywhere in the workspace. A custom allocator changes the OOM behavior (some abort, some unwind, some return null).
- **lto / codegen-units / strip** — informational; flag if they look unusual.

A review without this section is incomplete. State the panic mode in one line at the top of every Step 3 agent prompt so the agent reasons from the right premise.

## Step 3: Parallel review

Every agent receives:
Expand All @@ -141,6 +155,7 @@ Every agent receives:
- **Bugs at callsites outside the diff outrank bugs inside the diff.** A confirmed bug in a file the PR did not touch but that calls a changed symbol is a P0 finding.
- **"Looks correct in isolation" is not a valid conclusion.** Before clearing a changed symbol, the agent must walk the callsite inventory from 2.5b and explicitly state, per callsite, whether the new behavior is still correct there.
- **The diff is the entry point, not the scope.** If the change surface map shows the symbol is reachable from N other files, the review covers N+1 files.
- **Crate-wide settings affect untouched code.** A change to `Cargo.toml` (panic strategy, allocator, feature defaults, MSRV, profile overrides), a new `#[global_allocator]`, or a new `panic_handler` retroactively changes the safety story for every existing function in the crate — not just the diff. When `Cargo.toml`, build scripts, or workspace-level config files appear in the diff, the review covers the panic/allocation/overflow contract of the **entire affected crate**, not just the touched lines. The same applies when 2.5e records a profile fact (e.g. `panic = "abort"`) that invalidates existing safety patterns in untouched code.
- A single finding of the form "in `test_line_sender.cpp` the new behavior of `line_sender_buffer_column_f64` causes Y" is worth more than five findings inside the diff.

### Agents
Expand All @@ -160,7 +175,12 @@ Launch the following agents in parallel.
- **C++ exceptions escaping into C:** the C++ wrapper (`include/questdb/ingress/*.hpp`) is reachable from pure-C callers via inline forwarders. Any path where the wrapper can throw (`std::bad_alloc`, `std::system_error`, user-defined `throw`) and reach a C caller is undefined behavior. Verify wrapper functions called from C are `noexcept` or only invoked from C++ contexts.
- **SIGPIPE on broken sockets:** writing to a closed peer raises SIGPIPE by default on Linux/macOS, killing the process. Verify TCP/HTTP write paths set `MSG_NOSIGNAL` or mask SIGPIPE.

Every fallible operation must use `Result`/`Option` with proper error propagation. Every `extern "C"` function must wrap its body in `catch_unwind` or prove no panic path exists.
**Panic strategy is the foundation.** Before reasoning about any panic guard, look up the `panic` setting from Step 2.5e:

- **Under `panic = "abort"`**, `catch_unwind` is a no-op — it cannot catch anything because nothing unwinds. Every reachable panic is a process abort regardless of where the `catch_unwind` is placed. The only acceptable defense is *proving no panic path exists*: front-load every length check, replace `unwrap`/`expect`/indexing on wire-derived or caller-supplied values with `Result`-returning equivalents, validate before allocating, use `checked_*` arithmetic. A `catch_unwind` wrapper in this mode is misleading documentation, not a safety net — flag it if it gives the reader false confidence.
- **Under `panic = "unwind"`**, every `extern "C"` function must wrap its body in `catch_unwind` AND every `Drop` impl on the unwind path must be panic-free (double-panic aborts the process). Fallible operations must use `Result`/`Option` with proper error propagation.

State which panic mode applies in the agent's first sentence. Every panic-related finding must be evaluated under the actual mode, not the textbook one.

**Agent 3 — FFI boundary safety:** Check every `#[no_mangle]` / `extern "C"` function. Verify: NULL pointer checks on all pointer arguments, proper error propagation across the FFI boundary (no panics escaping into C), correct ownership transfer semantics (who allocates, who frees), buffer length validation, string encoding correctness (UTF-8 ↔ C strings, NUL handling), and that the C header (`include/questdb/ingress/line_sender.h`) and C++ wrapper (`include/questdb/ingress/line_sender.hpp` + the split `line_sender_core.hpp` / `line_sender_array.hpp` / `line_sender_decimal.hpp`) accurately reflect the Rust implementation. If `cbindgen.toml` is involved, verify generated output matches handwritten headers.

Expand Down Expand Up @@ -250,10 +270,12 @@ Review the diff for:
- All `unsafe` blocks have documented safety invariants
- No undefined behavior: dangling pointers, use-after-free, double-free, data races
- Proper `Send`/`Sync` bounds on public types
- No panics that can escape FFI boundaries (every `extern "C"` function uses `catch_unwind` or proves panics are impossible)
- No panics that can escape FFI boundaries — and the meaning of "escape" depends on the panic strategy (see Step 2.5e). Under `panic = "abort"`, `catch_unwind` is a no-op and *every* reachable panic is a fatal escape; the FFI function must prove no panic path exists. Under `panic = "unwind"`, every `extern "C"` function must wrap its body in `catch_unwind`.

### Crash surface
Anything that aborts the Rust side aborts the host process. Beyond panics, check for:
Anything that aborts the Rust side aborts the host process. The first check is the panic strategy itself — everything else is downstream of it.

- **Panic strategy** (from Step 2.5e): under `panic = "abort"`, the entire `catch_unwind` defense collapses — every panic across the entire crate is fatal. Verify the profile before crediting any panic guard. A finding that says "the panic at X is caught by `catch_unwind` at Y" is incorrect under abort-panic.
- Direct aborts: `std::process::abort()`, `libc::abort()`, `std::intrinsics::abort()`
- Allocation-failure aborts: any allocation sized by an untrusted length parameter must validate the bound before allocating (Rust's default allocator aborts on OOM)
- Stack overflow: unbounded recursion, recursive `Drop` impls, deeply nested untrusted input
Expand Down
4 changes: 4 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[submodule "questdb"]
path = questdb
url = https://github.com/questdb/questdb.git
branch = master
151 changes: 146 additions & 5 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
cmake_minimum_required(VERSION 3.15.0)
project(c-questdb-client VERSION 6.1.0)
project(c-questdb-client VERSION 7.0.0)

set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
Expand Down Expand Up @@ -31,20 +31,74 @@ option(
"Build shared library dependencies instead of static."
OFF)

# Opt in to the synchronous WebSocket egress reader (`line_reader_*`
# C/C++ surface). Pulls in the `tungstenite` + `zstd` Rust crates as
# transitive dependencies, so downstreams that only need the line
# sender can flip this OFF to keep the resulting library minimal.
# Defaults ON for the in-tree build because the `line_reader_*`
# examples and tests need it; external consumers who add this
# project via `add_subdirectory` should set
# `-DQUESTDB_ENABLE_READER=OFF` if they don't want the surface.
option(
QUESTDB_ENABLE_READER
"Enable the synchronous WebSocket egress reader (line_reader_* API). Adds tungstenite+zstd."
ON)

# When QUESTDB_TESTS_AND_EXAMPLES is enabled the reader-related
# examples and tests need the reader API present. Refusing to build
# in that combination is friendlier than producing a confusing link
# error from missing `line_reader_*` symbols.
if(QUESTDB_TESTS_AND_EXAMPLES AND NOT QUESTDB_ENABLE_READER)
message(FATAL_ERROR
"QUESTDB_TESTS_AND_EXAMPLES=ON requires QUESTDB_ENABLE_READER=ON: "
"the line_reader_* examples and tests would fail to link without it.")
endif()

# Compile in the `tls_verify=false` (sender) / `tls_verify=unsafe_off`
# (egress reader) escape hatch. ON by default to preserve the legacy
# behaviour of the shipped C ABI; security-conscious distributions can
# flip it OFF (`-DQUESTDB_ENABLE_INSECURE_SKIP_VERIFY=OFF`) to harden
# the resulting library — `line_sender_opts_tls_verify` then disappears
# from the symbol table and `tls_verify=unsafe_off` in a connect string
# is rejected at parse time.
option(
QUESTDB_ENABLE_INSECURE_SKIP_VERIFY
"Compile in support for tls_verify off. Allows downstream code to disable TLS certificate verification at runtime."
ON)

option(
QUESTDB_SANITIZE
"Build the C/C++ tests with -fsanitize=address,undefined."
OFF)

# Build static and dynamic lib written in Rust by invoking `cargo`.
# Imports `questdb_client` target.
add_subdirectory(corrosion)
corrosion_import_crate(
MANIFEST_PATH questdb-rs-ffi/Cargo.toml
LOCKED) # Use `Cargo.lock`
set(QUESTDB_CARGO_FEATURES "")
if(QUESTDB_ENABLE_READER)
list(APPEND QUESTDB_CARGO_FEATURES sync-reader-ws)
endif()
if(QUESTDB_ENABLE_INSECURE_SKIP_VERIFY)
list(APPEND QUESTDB_CARGO_FEATURES insecure-skip-verify)
endif()
if(QUESTDB_CARGO_FEATURES)
corrosion_import_crate(
MANIFEST_PATH questdb-rs-ffi/Cargo.toml
LOCKED
FEATURES ${QUESTDB_CARGO_FEATURES})
else()
corrosion_import_crate(
MANIFEST_PATH questdb-rs-ffi/Cargo.toml
LOCKED)
endif()
target_include_directories(
questdb_client INTERFACE
${CMAKE_CURRENT_SOURCE_DIR}/include)
if(WIN32)
set_target_properties(
questdb_client-shared
PROPERTIES
DEFINE_SYMBOL "LINESENDER_DYN_LIB")
DEFINE_SYMBOL "QUESTDB_CLIENT_DYN_LIB")
target_link_libraries(
questdb_client-shared
INTERFACE wsock32 ws2_32 ntdll crypt32 Secur32 Ncrypt)
Expand Down Expand Up @@ -82,6 +136,27 @@ function(set_compile_flags TARGET_NAME)
endif()
endfunction()

function(apply_sanitizers TARGET_NAME)
if(NOT QUESTDB_SANITIZE)
return()
endif()
if(MSVC)
message(WARNING
"QUESTDB_SANITIZE is not supported on MSVC (its ASan runtime is "
"not validated against the rustc-built library); skipping.")
else()
target_compile_options(
${TARGET_NAME} PRIVATE
-fsanitize=address,undefined
-fno-sanitize-recover=all
-fno-omit-frame-pointer
-g)
target_link_options(
${TARGET_NAME} PRIVATE
-fsanitize=address,undefined)
endif()
endfunction()

# Examples
function(compile_example TARGET_NAME)
list(POP_FRONT ARGV)
Expand Down Expand Up @@ -187,6 +262,24 @@ if (QUESTDB_TESTS_AND_EXAMPLES)
compile_example(
line_sender_cpp_example_decimal_binary
examples/line_sender_cpp_example_decimal_binary.cpp)
compile_example(
line_reader_c_example_from_conf
examples/line_reader_c_example_from_conf.c)
compile_example(
line_reader_cpp_example_from_conf
examples/line_reader_cpp_example_from_conf.cpp)
compile_example(
line_reader_c_example_with_binds
examples/line_reader_c_example_with_binds.c)
compile_example(
line_reader_cpp_example_with_binds
examples/line_reader_cpp_example_with_binds.cpp)
compile_example(
line_reader_cpp_example_columns
examples/line_reader_cpp_example_columns.cpp)
compile_example(
line_reader_c_example_columns
examples/line_reader_c_example_columns.c)

# Include Rust tests as part of the tests run
add_test(
Expand All @@ -207,16 +300,64 @@ if (QUESTDB_TESTS_AND_EXAMPLES)
${TARGET_NAME}
PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
set_compile_flags(${TARGET_NAME})
apply_sanitizers(${TARGET_NAME})
add_test(
NAME ${TARGET_NAME}
COMMAND ${TARGET_NAME})
if(QUESTDB_SANITIZE AND NOT MSVC)
# Leak detection is off: the Rust library is not instrumented and
# legitimately retains process-global allocations at exit, which
# LSan cannot tell apart from an FFI leak without a suppression
# file. ASan's use-after-free / out-of-bounds / double-free checks
# stay active.
set_tests_properties(
${TARGET_NAME} PROPERTIES
ENVIRONMENT
"ASAN_OPTIONS=detect_leaks=0;UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1")
endif()
endfunction()

compile_test(
test_line_sender
cpp_test/mock_server.cpp
cpp_test/test_line_sender.cpp)

# Live-broker integration tests for the egress reader. Skips per-test
# if no broker is reachable on QDB_LIVE_BROKER_HOST:QDB_LIVE_BROKER_HTTP_PORT
# (defaults: localhost:9000), so this test is safe to wire into ctest
# even on machines without a broker.
compile_test(
test_line_reader
cpp_test/test_line_reader.cpp)

# Broker-independent smoke test for the line_reader FFI. Targets a
# guaranteed-closed port (127.0.0.1:1) and asserts the FFI surfaces
# a non-NULL error that can be inspected and freed. Uses standard
# exit-code semantics so SIGSEGV / SIGABRT correctly fail the test
# (the previous WILL_FAIL-based smoke treated any non-zero exit as a
# pass, and inverted to a failure when QuestDB happened to be running
# on the developer's machine).
compile_test(
line_reader_c_smoke
cpp_test/smoke_line_reader.c)

# Broker-independent C++ tests for the line_reader FFI. Covers the
# error-handling surface, parser rejection paths, the connect-failure
# path against a closed port, NULL-idempotent free / close functions,
# `from_env`, and the C++ `line_reader_error` exception wrapper.
compile_test(
test_line_reader_offline
cpp_test/test_line_reader_offline.cpp)

# Mock-server-driven C++ tests for the line_reader FFI. Drives the
# reader against an in-process WebSocket + QWP1 mock so the
# column-getter / bind-encoding / server_info / error-code / stats
# surface that previously needed a live broker now runs in CI.
compile_test(
test_line_reader_mock
cpp_test/qwp_mock_server.cpp
cpp_test/test_line_reader_mock.cpp)

# System testing Python3 script.
# This will download the latest QuestDB instance from Github,
# thus will also require a Java 11 installation to run the tests.
Expand Down
Loading