Skip to content

Compatibility Philosophy

Hardwood aims to read every file that Apache parquet-java reads, while in a few specific places applying stricter semantics than parquet-java does. Each of those divergences follows from the principle described below.

The principle: liberal on input, strict on semantics

Two goals are in tension, and Hardwood resolves them on different axes:

  • Read what's out there. Parquet files in the wild were written by many tools across many years (parquet-mr, Arrow, Spark, Hive, PyArrow) using legacy encodings, deprecated types, and annotations that newer specs dropped. Hardwood reads these transparently: most legacy list-encoding variants, INT96 timestamps, the legacy converted_type annotations that predate the modern logical-type union, NULL-typed columns, FLOAT16. The tolerance also extends forward: a logical-type annotation newer than Hardwood recognizes is ignored rather than rejected, and the column's physical type is exposed, so a file written by a tool that has adopted a future logical type still reads.
  • Don't silently produce wrong results. On the semantic side, where a behavior is a matter of correctness rather than file compatibility, Hardwood chooses the well-defined answer even when that diverges from parquet-java's historical behavior.

Where strictness surfaces

SQL three-valued logic for comparison predicates

Hardwood applies SQL three-valued logic to every comparison predicate, so notEq("x", v) returns no rows where x is null (see Null Handling). parquet-java treats null <> v as true and so includes null rows in notEq, which breaks the SQL identity not(gt(x, v)) ≡ ltEq(x, v) on null rows. Hardwood preserves that identity across all operators, including under not(...). The cost is that a user porting a notEq filter from parquet-java may see fewer rows; the benefit is that filter algebra behaves predictably and matches what a SQL engine would do.

Schema validation across multiple files

A reader spanning multiple files checks every column a read touches against the first file's schema, and throws SchemaIncompatibleException on a mismatch (see Reading Multiple Files). The match is by field path, never by position. A Parquet footer lists column chunks in the order of the schema's flattened leaves, so a column's ordinal belongs to the file that was written, not to the column; two files that declare the same columns in a different order describe the same data.

The drop-in compat module

The hardwood-parquet-java-compat module is an API-compatibility shim, not a behavioral clone: filters routed through it evaluate under Hardwood's semantics. See parquet-java Compatibility.

Further reading