Local and remote (src_uri) replication, initial copy options, partitioned tables, and table_config JSON parameters.
This is the multi-page printable view of this section. .
SQL Procedures, Views & Configuration Reference
- 1: Create Columnstore Table
- 2: Query Columnstore Table & Supported Query Shapes
- 3: Apache Iceberg v2 & Object Storage Configuration
- 4: Query Your Data Lake in Postgres
This section provides the complete reference for all SQL procedures, catalog inspection functions, table access methods, and PostgreSQL GUC configuration parameters exposed by pg_mooncake (v0.3.0).
SQL Procedures & Functions (mooncake schema)
| Object | Signature | Description |
|---|---|---|
mooncake.create_table |
CALL mooncake.create_table(dst text, src text, src_uri text DEFAULT NULL, table_config json DEFAULT NULL) |
Creates a read-only USING mooncake columnstore mirror table (dst) replicating from local or remote (src_uri) PostgreSQL table (src). |
mooncake.create_snapshot |
CALL mooncake.create_snapshot(dst text) |
Waits for Moonlink to reach the current PostgreSQL WAL write LSN, flushes buffered Arrow data to Parquet, and writes a new Apache Iceberg v2 metadata snapshot. |
mooncake.optimize_table |
CALL mooncake.optimize_table(dst text, mode text) |
Runs compaction and deletion-vector reconciliation on dst (mode can be 'full' or 'minor'). |
mooncake.list_tables |
SELECT * FROM mooncake.list_tables() |
Set-returning function returning (table text, commit_lsn pg_lsn, flush_lsn pg_lsn, iceberg_warehouse_location text) for every active Moonlink table in the current database. |
mooncake.load_files |
CALL mooncake.load_files(dst text, files text[]) |
Unimplemented in v0.3.0; explicitly raises SQLSTATE 0A000 (FEATURE_NOT_SUPPORTED) instead of silently returning as a no-op. |
mooncake.list_tables() Output Columns
| Column | Type | Description |
|---|---|---|
table |
text |
Schema-qualified name of the columnstore mirror table (e.g. public.orders_analytics). |
commit_lsn |
pg_lsn |
Latest PostgreSQL WAL LSN ingested into Moonlink’s in-memory Arrow buffer. |
flush_lsn |
pg_lsn |
Latest PostgreSQL WAL LSN flushed to durable Parquet / Iceberg snapshot storage. |
iceberg_warehouse_location |
text |
Local filesystem directory ($PGDATA/pg_mooncake/...) or cloud URI (s3://...) containing the Apache Iceberg v2 metadata and Parquet data files. |
Table Access Method & Event Triggers
- Table Access Method (
USING mooncake): Created automatically bymooncake.create_tableand registered withpg_duckdb 1.2.0viaRegisterDuckdbTableAm("mooncake"). - Drop Cleanup Trigger (
mooncake_drop_trigger): AnON sql_dropevent trigger (mooncake_drop_trigger_func) automatically unregisters the table from Moonlink and cleans up its logical replication subscription when you executeDROP TABLE <dst>;.
GUC Configuration Parameters
| Parameter | Type | Default | Context | Description |
|---|---|---|---|---|
mooncake.default_bucket |
string |
'' (local $PGDATA/pg_mooncake) |
USERSET / SUSET |
Default object storage bucket URI (e.g. 's3://my-bucket/warehouse') where newly created Mooncake tables write Parquet files and Apache Iceberg v2 metadata. |
mooncake.extension_repository |
string |
$(pg_config --sharedir)/extension/pg_mooncake |
SUSET |
Local filesystem path containing the bundled v2.0.0/<platform>/mooncake.duckdb_extension binary loaded into pg_duckdb. |
mooncake.enable_local_cache |
bool |
true |
SUSET |
Enables local disk caching when writing to cloud object storage. |
duckdb.allow_community_extensions |
bool |
false (must set true) |
SUSET |
Required by pg_duckdb so pg_mooncake can load the mooncake DuckDB storage extension. |
duckdb.allow_unsigned_extensions |
bool |
false (must set true) |
SUSET |
Required so pg_duckdb can load the locally built mooncake.duckdb_extension binary from mooncake.extension_repository. |
duckdb.max_memory |
string |
4GB (or 80% RAM) |
SUSET |
Maximum memory allocated to the embedded DuckDB 2.0 analytical execution engine. |
duckdb.threads |
int |
-1 (all cores) |
SUSET |
Number of worker threads used by DuckDB 2.0 for vectorized query execution. |
Detailed Reference Guides
Supported analytical query shapes, aggregations, joins with Postgres heap tables, and exposing DuckDB functions in SQL.
Configure S3 and Cloudflare R2 secrets, materialize Iceberg v2 snapshots, and query Mooncake tables from external engines.
Scan external Parquet, CSV, JSON, Iceberg, Delta Lake, and HuggingFace datasets directly inside PostgreSQL.
1 - Create Columnstore Table
In pg_mooncake, columnstore tables are created as real-time mirrors of existing PostgreSQL rowstore (heap or partitioned) tables using the mooncake.create_table procedure.
Procedure Signature
| Parameter | Type | Default | Description |
|---|---|---|---|
dst |
text |
(Required) | Name of the destination columnstore mirror table to create (supports schema.table, defaults to public if unqualified). |
src |
text |
(Required) | Name of the source PostgreSQL rowstore or partitioned table to replicate from (supports schema.table). |
src_uri |
text |
NULL |
Connection URI (postgresql://user:pass@host:port/dbname) of a remote PostgreSQL instance when replicating from an external database. When NULL, replicates from the current local database. |
table_config |
json |
NULL |
Optional JSON object configuring Moonlink storage and ingestion settings (such as write_buffer_size or initial data copy behavior). |
src_uri (Not source_uri)Earlier upstream documentation contained a typo showing source_uri => 'postgresql://...'. The actual parameter name in pg_mooncake’s SQL definition (src/functions.rs) is src_uri. Always use src_uri => 'postgresql://...' when calling mooncake.create_table with named arguments.
1. Mirror a Table in the Same Database
When src_uri is omitted (or NULL), pg_mooncake replicates directly from src in the current database:
What happens when CALL mooncake.create_table('orders_analytics', 'orders') runs:
pg_mooncakeinspects the columns ofordersand createsCREATE TABLE orders_analytics (...) USING mooncake.- If
ordersdoes not have a primary key,pg_mooncakerunsALTER TABLE orders REPLICA IDENTITY FULL(and inv0.3.0, automatically appliesREPLICA IDENTITY FULLto all existing leaf partitions ifordersis partitioned). moonlinkcreates a logical replication slot (pgoutput), copies all existing rows fromorders, and begins streaming ongoingINSERT,UPDATE, andDELETEchanges in real time.
2. Mirror a Table from a Remote PostgreSQL Instance (src_uri)
You can run pg_mooncake on a dedicated analytical PostgreSQL node and mirror tables from a remote production PostgreSQL database (including self-hosted PostgreSQL, AWS RDS, Aurora, Supabase, or Neon):
Requirements on the remote source database:
wal_level = logicalmust be enabled.- The user in
src_urimust haveREPLICATIONprivileges andSELECTpermission onsrc. - If
srchas no primary key,REPLICA IDENTITY FULLmust be set onsrc.
3. Mirror a Partitioned Table
mooncake.create_table supports declarative PostgreSQL partitioned tables (PARTITION BY RANGE, LIST, or HASH). Specify the root partitioned table as src:
create_tableIn pg_mooncake 0.3.0, mooncake.create_table automatically sets REPLICA IDENTITY FULL on all partitions that exist at the time the mirror is created. If you attach or create a new partition later (CREATE TABLE events_2026_12 PARTITION OF events ...) and the partitioned table does not have a primary key, run ALTER TABLE events_2026_12 REPLICA IDENTITY FULL; before executing UPDATE or DELETE statements on that partition.
4. Advanced table_config Options
You can pass a JSON object via table_config to customize Moonlink’s per-table behavior (TableConfig in moonlink_backend/src/table_config.rs), including append-only optimization, background compaction flags, and custom filesystem / S3 / GCS storage backends for Iceberg data and WAL:
| JSON Path | Type | Default | Description |
|---|---|---|---|
mooncake.append_only |
bool |
false (or true if no PK/replica identity) |
When true, treats the table as append-only and skips building primary-key hash indexes. |
mooncake.skip_index_merge |
bool |
false |
When true, disables background Puffin hash-index LSM compaction. |
mooncake.skip_data_compaction |
bool |
false |
When true, disables background Parquet data file compaction. |
iceberg.storage_config |
object |
{"fs": {"root_directory": "$PGDATA/pg_mooncake"}} |
Storage backend (fs, s3, or gcs) for Apache Iceberg v2 metadata and Parquet data files. |
wal.storage_config |
object |
{"fs": {"root_directory": "$PGDATA/pg_mooncake"}} |
Storage backend (fs, s3, or gcs) for Moonlink’s internal WAL segments. |
5. Dropping a Columnstore Mirror Table
To remove a columnstore mirror table and automatically clean up its Moonlink metadata and logical replication slot, simply run DROP TABLE:
2 - Query Columnstore Table & Supported Query Shapes
Columnstore mirror tables created with CALL mooncake.create_table(dst, src) are queried using standard PostgreSQL SELECT syntax. Behind the scenes, pg_mooncake and pg_duckdb 1.2.0 translate and route analytical scans to the embedded DuckDB v2.0.0 vectorized execution engine.
How Queries Work
When you query a USING mooncake table:
- LSN Synchronization:
duckdb_mooncakechecks PostgreSQL’s current WAL write LSN and waits formoonlinkto ingest all committed transactions up to that LSN. - Segment Elimination: DuckDB 2.0 inspects multi-file Parquet column min/max statistics to skip files and row groups that cannot match your
WHEREpredicates. - Zero-Copy Hybrid Scan: Flushed Parquet files, Roaring Bitmap deletion vectors, and the in-memory Apache Arrow write buffer are scanned in parallel across DuckDB worker threads (
duckdb.threads).
You can verify that DuckDB is executing your query by running EXPLAIN:
Analytical Query Shapes (Recommended)
Columnstore tables excel at analytical workloads that scan large numbers of rows across a subset of columns, often delivering 10× to 1000× speedups over heap tables.
1. Multi-Dimensional Aggregations
2. High-Selectivity Filtering & Top-N Ranking
3. Time-Series Rollups & Window Functions
4. Hybrid Joins with Regular PostgreSQL Heap Tables
You can join a USING mooncake columnstore mirror directly with regular PostgreSQL rowstore tables (such as dimension tables or lookup tables):
Operational Point Lookups (Use the Rowstore Table)
While pg_mooncake supports arbitrary SELECT queries, single-row point lookups (WHERE id = 12345) and tiny index range scans should be routed to your source rowstore table, where PostgreSQL’s B-tree indexes provide sub-millisecond lookup latency.
Query Translation & DuckDB Functions
Because queries on USING mooncake tables are executed by DuckDB (pg_duckdb), certain PostgreSQL-specific functions that lack a direct DuckDB equivalent (such as to_char(), certain regexp_* overloads, or specific jsonb_* operators) may require DuckDB-compatible expressions.
Exposing DuckDB Functions in PostgreSQL
You can expose native DuckDB analytical functions (such as time_bucket) inside PostgreSQL by defining a placeholder PL/pgSQL function with the matching signature. When a query targets a columnstore table, pg_duckdb intercepts the call and executes DuckDB’s native vectorized implementation:
3 - Apache Iceberg v2 & Object Storage Configuration
Every columnstore mirror table in pg_mooncake (v0.3.0) is backed by moonlink, which writes data as standard Parquet files and maintains Apache Iceberg v2 table metadata.
By default, Moonlink writes files to the local filesystem under $PGDATA/pg_mooncake/. You can configure pg_mooncake to write directly to Amazon S3, Cloudflare R2, MinIO, or Google Cloud Storage (GCS) so external engines (DuckDB, Apache Spark, Trino, Snowflake, PyIceberg) can query your PostgreSQL tables directly from object storage.
1. Configure Object Storage Credentials (duckdb.secrets)
pg_mooncake reads object storage credentials from pg_duckdb’s duckdb.secrets table and passes them to both Moonlink and DuckDB.
Amazon S3
Cloudflare R2 / S3-Compatible (MinIO)
2. Configure Table Storage (table_config & mooncake.default_bucket)
In pg_mooncake v0.3.0, you can configure S3 / R2 / GCS storage directly in the table_config JSON parameter of mooncake.create_table (or set mooncake.default_bucket as documented in upstream v0.1/v0.2 guides):
3. Materialize an Apache Iceberg v2 Snapshot
While in-database queries on orders_analytics automatically read both flushed Parquet files and Moonlink’s in-memory Arrow write buffer, external Iceberg readers only see data that has been flushed into an Iceberg metadata snapshot.
To force-flush all committed rows up to the current PostgreSQL WAL LSN and write a new v*.metadata.json file:
v0.3.0 (moonlink v0.0.1)In pg_mooncake 0.3.0, CALL mooncake.create_snapshot('orders_analytics') completes immediately even if the database WAL has advanced due to writes on other, unrelated tables since the last write to orders.
4. Locate the Iceberg Warehouse & Query Externally
Use mooncake.list_tables() to inspect the commit LSN, flushed LSN, and exact iceberg_warehouse_location:
Example output:
Querying from External DuckDB / PyIceberg / Spark
Inside the iceberg_warehouse_location directory, Moonlink writes standard Apache Iceberg v2 metadata (metadata/v1.metadata.json, v2.metadata.json, etc.):
5. Compacting Files (mooncake.optimize_table)
To compact small Parquet files and reconcile Roaring Bitmap deletion vectors into clean base files:
4 - Query Your Data Lake in Postgres
Because pg_mooncake (v0.3.0) embeds DuckDB v2.0.0 via pg_duckdb 1.2.0, you can query external files in your data lake (local disk, S3, Cloudflare R2, GCS, HTTP, or HuggingFace hf:// datasets) directly from PostgreSQL without loading them into heap tables first.
Supported External Formats
- Apache Parquet (
duckdb.read_parquet) - CSV / TSV (
duckdb.read_csv) - JSON / NDJSON (
duckdb.read_json) - Apache Iceberg (
duckdb.iceberg_scan) - Delta Lake (
duckdb.delta_scan)
v0.2 / v0.3 (duckdb.*) vs Legacy v0.1 (mooncake.*) FunctionsIn pg_mooncake v0.2 and v0.3.0, external file readers are provided directly by pg_duckdb (duckdb.read_parquet, duckdb.read_csv, duckdb.iceberg_scan, duckdb.delta_scan). For the legacy v0.1 mooncake.read_parquet syntax, see v0.1 Query External Files.
1. Querying Parquet Files (duckdb.read_parquet)
Use duckdb.read_parquet and specify the expected output columns in the AS (...) clause:
You can also query Hive-partitioned directory structures:
2. Querying CSV Files (duckdb.read_csv)
3. Querying External Iceberg & Delta Lake Tables
First install and load the iceberg or delta DuckDB extension via duckdb.install_extension:
4. Joining External Files with PostgreSQL Tables
You can join external Parquet, Iceberg, or Delta Lake datasets directly with regular PostgreSQL heap tables or USING mooncake columnstore mirrors in a single SQL query:
5. Querying HuggingFace Datasets (hf://)
DuckDB supports reading public HuggingFace datasets directly via the hf://datasets/<org>/<repo>/<path> URI scheme: