Add map_no_value.parquet (#63)
* add map_no_value.parquet
* fix wording
* add map with all null values, provide code to generate
* reduce file overhead
* close code block properly
diff --git a/data/README.md b/data/README.md
index 7875a2f..c96f2b6 100644
--- a/data/README.md
+++ b/data/README.md
@@ -55,6 +55,7 @@
| sort_columns.parquet | INT64 and BYTE_ARRAY columns with first column with nulls first and descending, second column with nulls last and ascending. This file contains two row groups with same data and sorting columns. |
| old_list_structure.parquet | Single LIST<LIST<INT32>> column with legacy two-level list structure. See [old_list_structure.md](old_list_structure.md) |
| repeated_primitive_no_list.parquet | REPEATED INT32 and BYTE_ARRAY fields without LIST annotation. See [note](#REPEATED-primitive-fields-with-no-LIST-annotation) |
+| map_no_value.parquet | MAP with null values, MAP with INT32 keys and no values, and LIST<INT32> column with same values as the MAP keys. See [map_no_value.md](map_no_value.md) |
TODO: Document what each file is in the table above.
diff --git a/data/map_no_value.md b/data/map_no_value.md
new file mode 100644
index 0000000..8e6c5a7
--- /dev/null
+++ b/data/map_no_value.md
@@ -0,0 +1,164 @@
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+`map_no_value.parquet` is generated with parquet-rs version 53.2.0
+using the following code:
+```
+ fn main() {
+ use crate::data_type::Int32Type;
+ use crate::file::properties::{EnabledStatistics, WriterProperties};
+ use crate::file::writer::SerializedFileWriter;
+ use crate::schema::parser::parse_message_type;
+ use std::sync::Arc;
+
+ let schema = "
+ message schema {
+ REQUIRED group my_map (MAP) {
+ REPEATED group key_value {
+ REQUIRED INT32 key;
+ OPTIONAL INT32 value;
+ }
+ }
+ REQUIRED group my_map_no_v (MAP) {
+ REPEATED group key_value {
+ REQUIRED INT32 key;
+ }
+ }
+ REQUIRED group my_list (LIST) {
+ REPEATED group list {
+ REQUIRED INT32 element;
+ }
+ }
+ }
+ ";
+ let schema = Arc::new(parse_message_type(schema).unwrap());
+
+ // Write Parquet file to buffer
+ let mut file = std::fs::File::create("/tmp/map_no_value.parquet").unwrap();
+ let props = Arc::new(
+ WriterProperties::builder()
+ .set_statistics_enabled(EnabledStatistics::None)
+ .build(),
+ );
+ let mut file_writer = SerializedFileWriter::new(&mut file, schema, props).unwrap();
+ let mut row_group_writer = file_writer.next_row_group().unwrap();
+
+ // Write column my_map.key_value.key
+ let mut column_writer = row_group_writer.next_column().unwrap().unwrap();
+ column_writer
+ .typed::<Int32Type>()
+ .write_batch(
+ &[1, 2, 3, 4, 5, 6, 7, 8, 9],
+ Some(&[1, 1, 1, 1, 1, 1, 1, 1, 1]),
+ Some(&[0, 1, 1, 0, 1, 1, 0, 1, 1]),
+ )
+ .unwrap();
+ column_writer.close().unwrap();
+
+ // Write column my_map.key_value.value
+ let mut column_writer = row_group_writer.next_column().unwrap().unwrap();
+ column_writer
+ .typed::<Int32Type>()
+ .write_batch(
+ &[],
+ Some(&[1, 1, 1, 1, 1, 1, 1, 1, 1]),
+ Some(&[0, 1, 1, 0, 1, 1, 0, 1, 1]),
+ )
+ .unwrap();
+ column_writer.close().unwrap();
+
+ // Write column my_map_no_v.key_value.key
+ let mut column_writer = row_group_writer.next_column().unwrap().unwrap();
+ column_writer
+ .typed::<Int32Type>()
+ .write_batch(
+ &[1, 2, 3, 4, 5, 6, 7, 8, 9],
+ Some(&[1, 1, 1, 1, 1, 1, 1, 1, 1]),
+ Some(&[0, 1, 1, 0, 1, 1, 0, 1, 1]),
+ )
+ .unwrap();
+ column_writer.close().unwrap();
+
+ // Write column my_list.list.element
+ let mut column_writer = row_group_writer.next_column().unwrap().unwrap();
+ column_writer
+ .typed::<Int32Type>()
+ .write_batch(
+ &[1, 2, 3, 4, 5, 6, 7, 8, 9],
+ Some(&[1, 1, 1, 1, 1, 1, 1, 1, 1]),
+ Some(&[0, 1, 1, 0, 1, 1, 0, 1, 1]),
+ )
+ .unwrap();
+ column_writer.close().unwrap();
+
+ // Finalize Parquet file
+ row_group_writer.close().unwrap();
+ file_writer.close().unwrap();
+ }
+```
+
+It contains a MAP with all null values, a second MAP without a `values` field, and
+an equivalent LIST repeating the MAP keys. The first column is 3 MAP rows:
+```
+{1 -> null, 2 -> null, 3 -> null}
+{4 -> null, 5 -> null, 6 -> null}
+{7 -> null, 8 -> null, 9 -> null}
+```
+
+The last two columns comprise 3 equivalent rows of `list<Integer>`:
+```
+[1, 2, 3]
+[4, 5, 6]
+[7, 8, 9]
+```
+
+Here is the file metadata printed by parquet-cli:
+```
+File path: map_no_value.parquet
+Created by: parquet-rs version 53.2.0
+Properties: (none)
+Schema:
+message schema {
+ required group my_map (MAP) {
+ repeated group key_value {
+ required int32 key;
+ optional int32 value;
+ }
+ }
+ required group my_map_no_v (MAP) {
+ repeated group key_value {
+ required int32 key;
+ }
+ }
+ required group my_list (LIST) {
+ repeated group list {
+ required int32 element;
+ }
+ }
+}
+
+
+Row group 0: count: 3 105.00 B records start: 4 total(compressed): 315 B total(uncompressed):315 B
+--------------------------------------------------------------------------------
+ type encodings count avg size nulls min / max
+my_map.key_value.key INT32 _ RR_ 9 10.00 B
+my_map.key_value.value INT32 _ RR_ 9 5.00 B
+my_map_no_v.key_value.key INT32 _ RR_ 9 10.00 B
+my_list.list.element INT32 _ RR_ 9 10.00 B
+```
diff --git a/data/map_no_value.parquet b/data/map_no_value.parquet
new file mode 100644
index 0000000..0cf996e
--- /dev/null
+++ b/data/map_no_value.parquet
Binary files differ