This is an automated email from the ASF dual-hosted git repository.

alamb pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/parquet-testing.git


The following commit(s) were added to refs/heads/master by this push:
     new e7bea05  Add JSON and BSON logical type test files (#118)
e7bea05 is described below

commit e7bea05fa5bc18a032f3687e8a71128f14bb7331
Author: Neelesh Salian <[email protected]>
AuthorDate: Thu Aug 6 14:19:06 2026 -0700

    Add JSON and BSON logical type test files (#118)
---
 data/README.md    | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 data/bson.parquet | Bin 0 -> 412 bytes
 data/json.parquet | Bin 0 -> 402 bytes
 3 files changed, 107 insertions(+)

diff --git a/data/README.md b/data/README.md
index eb823e1..ea93558 100644
--- a/data/README.md
+++ b/data/README.md
@@ -63,6 +63,8 @@
 | int96_from_spark.parquet | Single column of (deprecated) int96 values that 
originated as Apache Spark microsecond-resolution timestamps. Some values are 
outside the range typically representable by 64-bit nanosecond-resolution 
timestamps. See [int96_from_spark.md](int96_from_spark.md) for details. |
 | int96_timestamp_order.parquet | Single `required int96` column written with 
the `INT96_TIMESTAMP_ORDER` column order ([parquet-format 
#584](https://github.com/apache/parquet-format/pull/584)). Values are chosen so 
a byte-wise comparison disagrees with the chronological order, so the min/max 
statistics (and column index) are only correct for a reader that honors the new 
order. See [int96_timestamp_order.md](int96_timestamp_order.md) for details. |
 | binary_truncated_min_max.parquet | A file containing six columns with exact, 
fully-truncated and partially-truncated max and min statistics and with the 
expected is_{min/max}_value_exact.  (see 
[note](Binary-truncated-min-and-max-statistics)).|
+| json.parquet | A single optional BYTE_ARRAY column annotated with the JSON 
logical type (also carries the legacy converted type JSON). Four rows: 
`{"a":1}`, `{"a":1,"b":null}` (null field value inside a non-null document), 
`[1,null,3]` (null element inside an array), and a NULL row. See 
[note](#json-and-bson-logical-types) below. |
+| bson.parquet | A single optional BYTE_ARRAY column annotated with the BSON 
logical type (also carries the legacy converted type BSON). Three rows: BSON 
`{"a":1}`, `{"a":1,"b":null}` (null field value inside a non-null document), 
and a NULL row. See [note](#json-and-bson-logical-types) below. |
 
 TODO: Document what each file is in the table above.
 
@@ -589,3 +591,108 @@ java -jar 
parquet-cli/target/parquet-cli-1.16.0-SNAPSHOT-runtime.jar cat /home/r
 {"utf8_full_truncation": "Julia Roberts", "binary_full_truncation": "Julia 
Roberts", "utf8_partial_truncation": "Julia Roberts", 
"binary_partial_truncation": "Julia Roberts", "utf8_no_truncation": "Julia 
Roberts", "binary_no_truncation": "Julia Roberts"}
 {"utf8_full_truncation": "Kevin Bacon", "binary_full_truncation": "Kevin 
Bacon", "utf8_partial_truncation": "🚀Kevin Bacon", "binary_partial_truncation": 
"ÿÿ\u0001\u0002", "utf8_no_truncation": "Ke", "binary_no_truncation": "Ke"}
 ```
+
+## JSON and BSON logical types
+
+`json.parquet` and `bson.parquet` each contain a single optional `BYTE_ARRAY`
+column annotated with the `JSON` and `BSON` logical types respectively (both 
also
+carry the equivalent legacy converted type). They give reader implementations a
+small fixture for the JSON/BSON annotations, which no other file in this repo
+exercises. The data is intentionally small and includes a NULL value, documents
+with a null field value, and (for JSON) a null array element.
+
+`json.parquet` (4 rows): `{"a":1}`, `{"a":1,"b":null}` (null field value in a
+non-null document), `[1,null,3]` (null element in an array), and one NULL row.
+
+`bson.parquet` (3 rows): BSON `{"a":1}` (`0c0000001061000100000000`),
+`{"a":1,"b":null}` (`0f000000106100010000000a620000`), and one NULL row.
+
+Both files are generated by parquet-mr 1.18.0-SNAPSHOT using the following 
code:
+
+`json.parquet`:
+
+```java
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.parquet.example.data.Group;
+import org.apache.parquet.example.data.simple.SimpleGroupFactory;
+import org.apache.parquet.hadoop.ParquetWriter;
+import org.apache.parquet.hadoop.example.ExampleParquetWriter;
+import org.apache.parquet.hadoop.example.GroupWriteSupport;
+import org.apache.parquet.hadoop.metadata.CompressionCodecName;
+import org.apache.parquet.schema.LogicalTypeAnnotation;
+import org.apache.parquet.schema.MessageType;
+import org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName;
+import org.apache.parquet.schema.Types;
+
+public class JsonFixture {
+  public static void main(String[] args) throws Exception {
+    MessageType schema = Types.buildMessage()
+        .optional(PrimitiveTypeName.BINARY)
+        .as(LogicalTypeAnnotation.jsonType())
+        .named("json_field")
+        .named("json_fixture");
+    Configuration conf = new Configuration();
+    GroupWriteSupport.setSchema(schema, conf);
+    SimpleGroupFactory factory = new SimpleGroupFactory(schema);
+    String[] docs = {"{\"a\":1}", "{\"a\":1,\"b\":null}", "[1,null,3]"};
+    try (ParquetWriter<Group> writer = ExampleParquetWriter.builder(new 
Path("json.parquet"))
+        .withConf(conf)
+        .withCompressionCodec(CompressionCodecName.UNCOMPRESSED)
+        .build()) {
+      for (String d : docs) {
+        writer.write(factory.newGroup().append("json_field", d));  // String 
-> UTF-8 BYTE_ARRAY
+      }
+      writer.write(factory.newGroup());  // optional field omitted -> NULL row
+    }
+  }
+}
+```
+
+`bson.parquet`:
+
+```java
+import org.apache.hadoop.conf.Configuration;
+import org.apache.hadoop.fs.Path;
+import org.apache.parquet.example.data.Group;
+import org.apache.parquet.example.data.simple.SimpleGroupFactory;
+import org.apache.parquet.hadoop.ParquetWriter;
+import org.apache.parquet.hadoop.example.ExampleParquetWriter;
+import org.apache.parquet.hadoop.example.GroupWriteSupport;
+import org.apache.parquet.hadoop.metadata.CompressionCodecName;
+import org.apache.parquet.io.api.Binary;
+import org.apache.parquet.schema.LogicalTypeAnnotation;
+import org.apache.parquet.schema.MessageType;
+import org.apache.parquet.schema.PrimitiveType.PrimitiveTypeName;
+import org.apache.parquet.schema.Types;
+
+public class BsonFixture {
+  public static void main(String[] args) throws Exception {
+    MessageType schema = Types.buildMessage()
+        .optional(PrimitiveTypeName.BINARY)
+        .as(LogicalTypeAnnotation.bsonType())
+        .named("bson_field")
+        .named("bson_fixture");
+    Configuration conf = new Configuration();
+    GroupWriteSupport.setSchema(schema, conf);
+    SimpleGroupFactory factory = new SimpleGroupFactory(schema);
+    byte[] doc1 = 
{0x0c,0x00,0x00,0x00,0x10,0x61,0x00,0x01,0x00,0x00,0x00,0x00};                 
// {"a":1}
+    byte[] doc2 = 
{0x0f,0x00,0x00,0x00,0x10,0x61,0x00,0x01,0x00,0x00,0x00,0x0a,0x62,0x00,0x00};  
// {"a":1,"b":null}
+    try (ParquetWriter<Group> writer = ExampleParquetWriter.builder(new 
Path("bson.parquet"))
+        .withConf(conf)
+        .withCompressionCodec(CompressionCodecName.UNCOMPRESSED)
+        .build()) {
+      writer.write(factory.newGroup().append("bson_field", 
Binary.fromConstantByteArray(doc1)));
+      writer.write(factory.newGroup().append("bson_field", 
Binary.fromConstantByteArray(doc2)));
+      writer.write(factory.newGroup());   // optional field omitted -> NULL row
+    }
+  }
+}
+```
+
+Column annotations read back with pyarrow (both files: `null_count` = 1):
+
+```
+json.parquet | physical: BYTE_ARRAY | logical: JSON | converted: JSON
+bson.parquet | physical: BYTE_ARRAY | logical: BSON | converted: BSON
+```
diff --git a/data/bson.parquet b/data/bson.parquet
new file mode 100644
index 0000000..5d97a9b
Binary files /dev/null and b/data/bson.parquet differ
diff --git a/data/json.parquet b/data/json.parquet
new file mode 100644
index 0000000..855ddcb
Binary files /dev/null and b/data/json.parquet differ

Reply via email to