Repository navigation
Fix query-engine crash, name collisions, DELETE semantics and parser panics - #132
austin-barrington wants to merge 1 commit into
Conversation
…ons, DELETE, parser panics - A WHERE clause with a few thousand OR terms overflowed the stack in the InfluxQL parser (one recursion level per term); chDB's signal handler took the fault and shut the query engine down while /health stayed 200. AND/OR chains now parse into balanced trees, expression and subquery nesting are bounded, and /health fails once chDB reports a fatal error. - Names that sanitise to the same table or column (cpu.load / cpu_load, db a + rp b_c / db a_b + rp c, non-ASCII names, field a.b / a_b) shared storage. The client write path now refuses a new colliding name with a 400 before the WAL; existing tables keep their names. - DELETE and DROP SERIES stored a tombstone every later query applied, so points written afterwards were hidden too, and one naming an unknown column broke the measurement for good. They now delete the rows (ALTER TABLE ... DELETE, tags as series lookups) after the WAL flushes, and refuse fields and unknown names. DROP MEASUREMENT clears legacy tombstones, and the ingest schema cache starts over after a drop, so a measurement written again keeps its fields. - Lone ', " and / no longer panic the parser, and a number followed by a multi-byte character no longer panics the lexer (now a linear scan).
PR SummaryMedium Risk Overview DELETE and DROP SERIES stop relying on query-time tombstones for the common case. Predicates are built for fact-table Client writes are rejected with Reviewed by Cursor Bugbot for commit 7ea9643. Configure here. |
Bugbot couldn't run - usage limit reachedBugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit. A user or team admin can review and increase usage limits in the Cursor dashboard. (requestId: ab99e927-83e6-402a-b6c1-f9098ce25642) |
Fixes the four bugs from the 0.9.4-beta review. Each was reproduced first and now has a regression test.
1. A long WHERE clause took the query engine down
SELECT ... WHERE a OR b OR ...with a few thousand terms overflowed the stack in our InfluxQL parser, which recursed once per term and was quadratic. chDB's SIGSEGV handler caught the fault and shut its engine down, so every later query failed and flushes stalled, while/healthkept answering 200. Any tenant on a shared pool could do this./healthand/health/readyreturn 503 once chDB reports "shutting down due to a fatal error", so Kubernetes restarts the node.2. Different names shared one table or column
sanitise_identmaps every character outside[A-Za-z0-9_]to_and joinsdb_rp_measurement. As a result, these pairs shared storage, and writes to one name overwrote the other:cpu.loadandcpu_load;温度and湿度;awith retention policyb_c, and databasea_bwith policyc;cpu_seriesandcpu's series table;a.banda_b.Table names are unchanged, because renaming would orphan existing data. Instead, the client write path (single-node and cluster ingestion, line protocol and columnar) refuses a new name that maps onto storage another name owns, with a 400
NameCollision, before the WAL. Replication and shard transfers don't check, since they carry writes that were already accepted. Keys that already collide in stored data stay writable.3. DELETE / DROP SERIES hid later writes and could break a measurement for good
Both commands stored a tombstone that every later query applied. That had three effects:
DELETE FROM cpu WHERE tim0 < 0failed every later query oncpu.DELETE FROM cpuwith noWHEREdid nothing.Changes:
ALTER TABLE ... DELETE(mutations_sync = 2). Each tag comparison becomes aseries_id IN (SELECT ... FROM <series>)lookup.MetadataPort::drop_generationnow resets that cache, and the name guard, after any drop.4. Parser panics
',"or/(WHERE host = ',SELECT ",FROM /,GROUP BY /) panicked the parser.5温panicked the lexer. The lexer's duration scan is now one linear pass; it used to re-parse the input once per byte.Found while fixing, not changed here
delete_series_matchingignores its predicate and removes all series metadata for the measurement. It is used by DROP SERIES and by replicated DELETEs.DROP SERIES WHERE ...withoutFROMdeletes no rows on non-sharded nodes.ingest_seqis the WAL sequence plus a row offset, so it isn't monotonic across WAL entries.Tests
cargo fmt --check,cargo clippy --all-targets -D warnings,cargo test --lib(825), every integration binary with--no-fail-fast(compat 245, sharding, raft, e2e, …), and the CLI tests all pass locally.Cargo.lockis unchanged.