Shape / inspect · All operations
Read a file's schema and metadata
A variant of List columns and types
Read a data file's schema, row groups, statistics, header or detected format without loading its data.
Status
- In arcform
Runs as a SQL step
arcform carries it as a
sql:step today.
The DuckDB step
Read a file's schema, row groups, statistics, header and detected format without loading its rows
It reads the orders table the proofs share. Create it first:
CREATE TABLE orders AS SELECT * FROM (VALUES
(1, 'Alice Ng', 'north', DATE '2026-01-03', 120.00, 'widget', 'a|b', '{"channel":"web","items":[1,2]}'),
(2, 'alice ng', 'north', DATE '2026-01-05', 80.50, 'gadget', 'b', '{"channel":"shop","items":[3]}'),
(3, 'Bob Okafor', 'south', DATE '2026-01-05', 300.00, 'widget', 'a|c', '{"channel":"web","items":[4,5,6]}'),
(4, 'Carla Díaz', 'east', DATE '2026-01-09', NULL, 'gizmo', NULL, '{"channel":"web","items":[]}'),
(5, 'Bob Okafor', 'south', DATE '2026-01-12', 45.25, 'gadget', 'c', '{"channel":"phone","items":[7]}'),
(6, 'Dev Patel', 'west', DATE '2026-01-12', 510.00, 'widget', 'a', '{"channel":"web","items":[8,9]}'),
(7, 'Carla Diaz', 'east', DATE '2026-01-20', 99.99, 'gizmo', 'b|c', '{"channel":"shop","items":[10]}'),
(8, 'Dev Patel', 'west', DATE '2026-02-02', 510.00, 'widget', 'a', '{"channel":"web","items":[8,9]}'),
(9, 'Eve Larsen', NULL, DATE '2026-02-03', 15.00, 'gadget', NULL, '{"channel":"web","items":[11]}'),
(10, 'Alice Ng', 'north', DATE '2026-02-10', 220.00, 'gizmo', 'a|b|c', '{"channel":"phone","items":[12,13]}')
) t(order_id, customer, region, order_date, amount, product, tags, meta);Then run the statement:
-- 5000 rows written as three row groups of at most 2048 rows
COPY (SELECT i AS id, 'row ' || i AS label FROM range(5000) t(i)) TO '<your_scratch_dir>/inspect_many.parquet' (FORMAT parquet, ROW_GROUP_SIZE 2048);
COPY (SELECT order_id, customer, order_date, amount FROM orders) TO '<your_scratch_dir>/inspect_orders.csv' (HEADER);
CREATE TEMP TABLE file_schema AS SELECT name, duckdb_type FROM parquet_schema('<your_scratch_dir>/inspect_many.parquet') WHERE num_children IS NULL;
CREATE TEMP TABLE file_info AS SELECT num_rows, num_row_groups FROM parquet_file_metadata('<your_scratch_dir>/inspect_many.parquet');
CREATE TEMP TABLE row_groups AS
SELECT row_group_id, stats_min::BIGINT AS id_min, stats_max::BIGINT AS id_max, num_values
FROM parquet_metadata('<your_scratch_dir>/inspect_many.parquet') WHERE path_in_schema = 'id';
CREATE TEMP TABLE csv_format AS
SELECT "Delimiter" AS delimiter, "HasHeader" AS has_header, [c.name FOR c IN "Columns"] AS column_names, [c.type FOR c IN "Columns"] AS column_types
FROM sniff_csv('<your_scratch_dir>/inspect_orders.csv');
SELECT * FROM file_schema;
SELECT * FROM file_info;
SELECT * FROM row_groups ORDER BY row_group_id;
SELECT * FROM csv_format;
SELECT CASE WHEN ((SELECT list((name, duckdb_type) ORDER BY name) FROM file_schema) = [('id', 'BIGINT'), ('label', 'VARCHAR')] AND (SELECT (num_rows, num_row_groups) FROM file_info) = (5000, 3) AND (SELECT list((id_min, id_max, num_values) ORDER BY row_group_id) FROM row_groups) = [(0, 2047, 2048), (2048, 4095, 2048), (4096, 4999, 904)] AND (SELECT (delimiter, has_header) FROM csv_format) = (',', true) AND (SELECT column_names FROM csv_format) = ['order_id', 'customer', 'order_date', 'amount'] AND (SELECT column_types FROM csv_format) = ['BIGINT', 'VARCHAR', 'DATE', 'DOUBLE']) THEN 'as expected' ELSE error('the Parquet footer was not 3 row groups over 5000 rows with their id ranges, or the CSV was not detected as comma-separated with a header and four typed columns') END AS verdict;Replace <your_scratch_dir> with a directory of your own that you can write to before running the statement.
- The statement writes
inspect_many.parquetandinspect_orders.csvitself, in<your_scratch_dir>. - It needs nothing installed beyond DuckDB itself.
- The statement checks its own result and raises an error when it is wrong: “the Parquet footer was not 3 row groups over 5000 rows with their id ranges, or the CSV was not detected as comma-separated with a header and four typed columns”.
- It passed on DuckDB
v2.0.0 (Cyanoptera) d54cbbe3df.
What other tools call it
Meridian's classification; an independent blind rating agreed on 95.7% of 324 rows (variant, version 3).
Apache DataFusion (1)
parquet_metadataread 2026-09-27Table function returning row-group and column metadata and statistics of a Parquet file
Apache Hop (1)
File metadataread 2026-09-27Scan a text file to detect its delimiter, enclosure, encoding and field types
Apache NiFi (2)
ExtractAvroMetadataread 2026-09-27Extract metadata from the header of an Avro data file
IdentifyMimeTyperead 2026-09-27Detect the MIME type of content and write it to the mime.type attribute
DuckDB (6)
parquet_bloom_proberead 2026-09-27parquet_bloom_probe table function
parquet_file_metadataread 2026-09-27parquet_file_metadata table function
parquet_full_metadataread 2026-09-27parquet_full_metadata table function
parquet_kv_metadataread 2026-09-27parquet_kv_metadata table function
parquet_metadataread 2026-09-27parquet_metadata table function
parquet_schemaread 2026-09-27parquet_schema table function
Pentaho Data Integration (1)
Read metadata from Copybookread 2026-09-27Read a COBOL copybook definition and emit its file and column descriptors as rows
Polars (3)
read_ipc_schemaread 2026-09-27Read the schema of an Arrow IPC file without its data
read_parquet_metadataread 2026-09-27Read the custom file-level metadata of a Parquet file without its data
read_parquet_schemaread 2026-09-27Read the schema of a Parquet file without its data
VisiData (1)
dive-metadataread 2026-09-23Open attribute metadata of the HDF5 object in current row
Background
In Apache Parquet, file metadata is written after the data, and readers are expected to read the file metadata first to find the column chunks they need.[1] In Polars, read_parquet_schema gets the schema of a Parquet file without reading data.[2] DuckDB's CSV sniffer infers how to read a CSV file, because CSV files are not self-describing and come in many different dialects.[3]
When to use it
In DuckDB, parquet_metadata supports glob patterns, to query metadata across multiple files in parallel.[4] In DuckDB, DESCRIBE is the easier way to find the column names and types of a Parquet file, while parquet_schema shows the schema as it is held in the file's metadata.[4] Use DESCRIBE when you want the columns as a query will see them, and parquet_schema when you want to see how the file itself records them. (Meridian's view)
In DuckDB, the CSV sniffer detects the dialect of the file, the type of each column and whether the file has a header row.[3] In DuckDB, CSV type detection works on a sample of the file, by default 20,480 rows.[3] In DuckDB, a file the reader cannot jump into, such as a .gz compressed CSV file or stdin, is sampled only from its beginning.[3] Treat the types sniffed from a CSV file as a guess from a sample, and fix them in the read once you have checked them against the whole file. (Meridian's view) In DuckDB, sniff_csv runs the CSV sniffer as a separate step and returns the detected properties as a table with a single row.[3] In DuckDB, the Prompt column of sniff_csv holds a SQL command with the configurations the sniffer detected.[3]
The method
In Apache Parquet, a file consists of one or more row groups, a row group contains exactly one column chunk per column, and column chunks contain one or more pages.[5] In Apache Parquet, the file metadata contains the start locations of all the column chunks.[1] Apache Parquet is designed to separate the metadata from the data, which allows columns to be split across files and one metadata file to reference several Parquet files.[1] The Apache Parquet project began as a joint effort between Twitter and Cloudera, and Apache Parquet 1.0 was released in July 2013.[6]
In DuckDB, parquet_file_metadata returns file-level metadata such as the format version and the encryption algorithm, and parquet_kv_metadata returns custom metadata held as key-value pairs.[4]
Sources
- [1]File Format | Parquetdocumentation
- [2]polars.read_parquet_schema — Polars documentationdocumentation
- [3]CSV Auto Detection – DuckDBdocumentation
- [4]Querying Parquet Metadata – DuckDBdocumentation
- [5]Concepts | Parquetdocumentation
- [6]Apache Parquet - Wikipediasecondary source