Fail loudly on corrupt Durofut envelopes (follow-up to #331) - #328
Conversation
|
Root cause confirmed: the serde_json 128-level deserialization recursion limit, and the node counts in #327 pin it exactly. cc @pinodeca Analysis pinned to Mechanism
match serde_json::from_str::<Durofut>(s) {
Ok(d) if VALID_NODE_TYPES.contains(&d.node_type.as_str()) => d,
_ => Durofut {
node_type: "SQL".to_string(),
query: Some(s.to_string()),
..Default::default()
},
}The The counts are the proofThe chain does not stop at the collapse. After a collapse the handle is
Both failing data points land to the unit with no fudge factor. No length cap, varlena limit, or truncation produces a 127-periodic pattern — which is also why the counts looked like "not a clean function of the requested depth" in the original report. Other candidate boundaries were checked and ruled out: Two things the issue understatesThis is not
On this PRThe guard is placed correctly. Putting it inside Three things worth weighing:
Sibling fallbacks of the same class, untouched here
Happy to send a PR for whichever direction the maintainers prefer — the documented-ceiling variant or the unbounded-depth variant. |
Avoid serde recursion limits when composing deeply nested workflow graphs. Store Durofut children as opaque JSON values and deserialize one graph level at a time. Preserve the existing wire format and require child values to remain JSON objects. Validate graph depth before explain traversal, preserve PostgreSQL resource errors during Durofut normalization, and keep fresh-install and upgrade SQL definitions aligned. Add regression coverage for all composers, depth boundaries, operator paths, wire compatibility, and 200-step workflow execution. Fixes #327 Supersedes #328
4b7575d to
3268833
Compare
PR #331 fixed deep graph composition (#327) structurally but left two silent-corruption arms flagged in review: - Durofut::ensure() swallowed any unparseable JSON envelope into a raw SQL node, including the new deserialize_raw_object rejection of non-object children. Fail loudly instead, keying off the parse error plus a generic-JSON node_type probe (robust to serialized field order) rather than a prefix sniff. - collect_nodes() in df.explain() panicked via .expect() on an undeserializable child; align it to pgrx::error! like insert_nodes() so it raises a clean PostgreSQL error. Add regression tests: loud failure on a corrupt envelope, envelope detection independent of field order, and a deep JOIN chain locking in the shared opaque-child path.
3268833 to
40fe0a3
Compare
Summary
Narrow follow-up to #331 (which fixed #327). #331 fixed deep graph composition structurally, but a review flagged two remaining silent-corruption arms; this PR closes them.
Durofut::ensure()now fails loudly when a JSON object carrying anode_typefails to deserialize (e.g. the newdeserialize_raw_objectrejection of a non-object child) instead of silently wrapping the raw envelope as a SQL node that only errors at execution time. Detection keys off the parseErrplus a generic-JSONnode_typeprobe, so it is robust to serialized field order (avoids the field-order-coupled prefix sniff from this PR's original approach).collect_nodes()indf.explain()no longer panics via.expect()on an undeserializable child; it raises a clean PostgreSQL error viapgrx::error!, consistent withinsert_nodes()indf.start().Tests
df.seq.Validation
cargo build --features pg17cargo clippy --features pg17 -- -D warningscargo fmt -p pg_durable -- --check./scripts/test-unit.sh(267 passed, 16 ignored)