Our external Parquet support reads local files only. Parquet is usually not on a local
file system, so the feature currently works where the data mostly is not.
Measured on author/main
$ grep -ril "s3\|libcurl\|http" src/*.c src/*.h
src/columnar_parquet_reader.c
The single match is pg_sub_s32_overflow, so there is no object-store code, no HTTP
client and no credential handling anywhere in the tree. The FDW accepts two options,
path and partition_columns, and path is a local path or a glob over one.
Why this is a prerequisite rather than a nice-to-have
Apache Iceberg exists largely because Hive-style tables behaved badly on S3, and several
of its design choices only make sense there. Files are immutable because object stores do
not support in-place modification. A snapshot lists its files explicitly so a reader never
has to list a directory, which on an object store is slow. A commit is an atomic swap of
the metadata pointer, and because object stores have no atomic rename, the catalog exists
to provide that swap.
So #388 depends on this. An Iceberg reader without object storage can read a table
somebody copied to local disk, and not a table as deployed.
The existing note understates the work
design/PHASE_G_EXTERNAL_PARQUET_PLAN.md records the decision:
File access scope: DECIDED (2026-07-23) -- local filesystem first. Object storage
(S3 and S3-compatible such as MinIO, plus GCS/Azure) is a future todo behind the same
path/URL option: an s3://bucket/key path resolves through an object-store reader
while /path/file.parquet reads the local FS. The scan core is unchanged either way
because both just hand it bytes.
The first half is right and the reader really is agnostic. The last sentence is the part
to argue with. A local read is a microsecond-scale pread. An S3 read is a network round
trip of tens of milliseconds. Treating the two as interchangeable byte sources produces
something that works and is unusably slow.
What actually differs:
- Ranged GETs. Read the footer, then only the column chunks the projection needs.
Parquet's footer-at-the-end layout suits this, but the reader has to ask for byte
ranges rather than stream a file.
- Concurrency. Latency per request dominates, so chunk fetches want to be in flight
together. The local path never needed that.
- Retries and backoff. Transient failure is normal, not exceptional.
- Caching. Refetching a footer per query is wasteful in a way it never was locally.
- Credentials. FDW options land in
pg_foreign_server in plain text, readable by
anyone who can select from it. That is a design question before it is a coding one.
Suggested shape
- A byte-source abstraction behind the reader with the local path as the first
implementation, so the seam is proven before any network code exists.
- An S3 and S3-compatible implementation with ranged GETs, retries and concurrency.
MinIO makes this testable in CI without a cloud account.
- Credentials, deliberately, with the plaintext problem addressed rather than inherited.
- GCS and Azure after the seam has carried one implementation.
Steps 1 and 2 are the ones that decide whether this is viable.
Not in scope here
Writing to object storage is a separate issue, because multipart upload and its failure
semantics are a different problem from ranged reads.
Our external Parquet support reads local files only. Parquet is usually not on a local
file system, so the feature currently works where the data mostly is not.
Measured on
author/mainThe single match is
pg_sub_s32_overflow, so there is no object-store code, no HTTPclient and no credential handling anywhere in the tree. The FDW accepts two options,
pathandpartition_columns, andpathis a local path or a glob over one.Why this is a prerequisite rather than a nice-to-have
Apache Iceberg exists largely because Hive-style tables behaved badly on S3, and several
of its design choices only make sense there. Files are immutable because object stores do
not support in-place modification. A snapshot lists its files explicitly so a reader never
has to list a directory, which on an object store is slow. A commit is an atomic swap of
the metadata pointer, and because object stores have no atomic rename, the catalog exists
to provide that swap.
So #388 depends on this. An Iceberg reader without object storage can read a table
somebody copied to local disk, and not a table as deployed.
The existing note understates the work
design/PHASE_G_EXTERNAL_PARQUET_PLAN.mdrecords the decision:The first half is right and the reader really is agnostic. The last sentence is the part
to argue with. A local read is a microsecond-scale
pread. An S3 read is a network roundtrip of tens of milliseconds. Treating the two as interchangeable byte sources produces
something that works and is unusably slow.
What actually differs:
Parquet's footer-at-the-end layout suits this, but the reader has to ask for byte
ranges rather than stream a file.
together. The local path never needed that.
pg_foreign_serverin plain text, readable byanyone who can select from it. That is a design question before it is a coding one.
Suggested shape
implementation, so the seam is proven before any network code exists.
MinIO makes this testable in CI without a cloud account.
Steps 1 and 2 are the ones that decide whether this is viable.
Not in scope here
Writing to object storage is a separate issue, because multipart upload and its failure
semantics are a different problem from ranged reads.