From 0cda5b1feb16230f45348c2de564c34f48696451 Mon Sep 17 00:00:00 2001 From: James Greenhill Date: Wed, 3 Dec 2025 18:00:16 -0800 Subject: [PATCH] Fix DuckLake ATTACH command format MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add AS ducklake alias to ATTACH statement - Remove unused DataPath config option - Update connection string examples to show full format 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- README.md | 14 +++++--------- duckgres.example.yaml | 15 ++++----------- main.go | 9 +-------- server/server.go | 15 +++++++-------- 4 files changed, 17 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 7e7091d8..d8727599 100644 --- a/README.md +++ b/README.md @@ -71,8 +71,7 @@ extensions: - httpfs ducklake: - metadata_store: "postgres:dbname=ducklake" - data_path: "s3://my-bucket/ducklake-data/" + metadata_store: "postgres:host=localhost user=ducklake password=secret dbname=ducklake" rate_limit: max_failed_attempts: 5 @@ -97,8 +96,7 @@ Run with config file: | `DUCKGRES_DATA_DIR` | Directory for DuckDB files | `./data` | | `DUCKGRES_CERT` | TLS certificate file | `./certs/server.crt` | | `DUCKGRES_KEY` | TLS private key file | `./certs/server.key` | -| `DUCKGRES_DUCKLAKE_METADATA_STORE` | DuckLake metadata store | - | -| `DUCKGRES_DUCKLAKE_DATA_PATH` | DuckLake data path | - | +| `DUCKGRES_DUCKLAKE_METADATA_STORE` | DuckLake metadata connection string | - | ### CLI Flags @@ -133,15 +131,13 @@ DuckLake provides a SQL-based lakehouse format. When configured, the DuckLake ca ```yaml ducklake: - # Metadata store (required to enable DuckLake catalog) - metadata_store: "postgres:host=localhost dbname=ducklake" - # Data path for table files - data_path: "s3://my-bucket/ducklake-data/" + # Full connection string for the DuckLake metadata database + metadata_store: "postgres:host=ducklake.example.com user=ducklake password=secret dbname=ducklake" ``` This runs the equivalent of: ```sql -ATTACH 'ducklake:postgres:host=localhost dbname=ducklake' (DATA_PATH 's3://my-bucket/ducklake-data/') +ATTACH 'ducklake:postgres:host=ducklake.example.com user=ducklake password=secret dbname=ducklake' AS ducklake; ``` See [DuckLake documentation](https://ducklake.select/docs/stable/duckdb/usage/connecting) for more details. diff --git a/duckgres.example.yaml b/duckgres.example.yaml index be19fddc..079bf4c6 100644 --- a/duckgres.example.yaml +++ b/duckgres.example.yaml @@ -32,18 +32,11 @@ extensions: # When configured, DuckLake catalog is automatically attached on connection # See: https://ducklake.select/docs/stable/duckdb/usage/connecting ducklake: - # Metadata store connection string (required to enable DuckLake) + # Full connection string for the DuckLake metadata database # Examples: - # - "postgres:dbname=ducklake" - # - "postgres:host=localhost dbname=ducklake user=postgres password=secret" - # - "sqlite:ducklake.db" - # metadata_store: "postgres:dbname=ducklake" - - # Data path for table data files (optional) - # Examples: - # - "s3://my-bucket/ducklake-data/" - # - "/local/path/to/data/" - # data_path: "s3://my-bucket/ducklake-data/" + # - "postgres:host=localhost user=ducklake password=secret dbname=ducklake" + # - "postgres:host=ducklake.example.com user=ducklake password=secret dbname=ducklake" + # metadata_store: "postgres:host=localhost user=ducklake password=secret dbname=ducklake" # Rate limiting configuration (optional - these are the defaults) rate_limit: diff --git a/main.go b/main.go index 40815449..07a73046 100644 --- a/main.go +++ b/main.go @@ -39,8 +39,7 @@ type RateLimitFileConfig struct { } type DuckLakeFileConfig struct { - MetadataStore string `yaml:"metadata_store"` // e.g., "postgres:dbname=ducklake" - DataPath string `yaml:"data_path"` // e.g., "s3://my-bucket/data/" + MetadataStore string `yaml:"metadata_store"` // e.g., "postgres:host=localhost user=ducklake password=secret dbname=ducklake" } // loadConfigFile loads configuration from a YAML file @@ -178,9 +177,6 @@ func main() { if fileCfg.DuckLake.MetadataStore != "" { cfg.DuckLake.MetadataStore = fileCfg.DuckLake.MetadataStore } - if fileCfg.DuckLake.DataPath != "" { - cfg.DuckLake.DataPath = fileCfg.DuckLake.DataPath - } } // Apply environment variables (override config file) @@ -204,9 +200,6 @@ func main() { if v := os.Getenv("DUCKGRES_DUCKLAKE_METADATA_STORE"); v != "" { cfg.DuckLake.MetadataStore = v } - if v := os.Getenv("DUCKGRES_DUCKLAKE_DATA_PATH"); v != "" { - cfg.DuckLake.DataPath = v - } // Apply CLI flags (highest priority) if *host != "" { diff --git a/server/server.go b/server/server.go index 22ece042..da17e061 100644 --- a/server/server.go +++ b/server/server.go @@ -37,10 +37,11 @@ type Config struct { ShutdownTimeout time.Duration } -// DuckLakeConfig configures DuckLake metadata store and data path +// DuckLakeConfig configures DuckLake catalog attachment type DuckLakeConfig struct { - MetadataStore string // e.g., "postgres:dbname=ducklake" or "sqlite:ducklake.db" - DataPath string // e.g., "s3://my-bucket/data/" or "/local/path" + // MetadataStore is the connection string for the DuckLake metadata database + // Format: "postgres:host= user= password= dbname=" + MetadataStore string } type Server struct { @@ -293,11 +294,9 @@ func (s *Server) attachDuckLake(db *sql.DB) error { } // Build the ATTACH statement - // Format: ATTACH 'ducklake:metadata_store' (DATA_PATH 'data_path') - attachStmt := fmt.Sprintf("ATTACH 'ducklake:%s'", s.cfg.DuckLake.MetadataStore) - if s.cfg.DuckLake.DataPath != "" { - attachStmt += fmt.Sprintf(" (DATA_PATH '%s')", s.cfg.DuckLake.DataPath) - } + // Format: ATTACH 'ducklake:' AS ducklake + // Example: ATTACH 'ducklake:postgres:host=localhost user=ducklake password=secret dbname=ducklake' AS ducklake + attachStmt := fmt.Sprintf("ATTACH 'ducklake:%s' AS ducklake", s.cfg.DuckLake.MetadataStore) if _, err := db.Exec(attachStmt); err != nil { return fmt.Errorf("failed to attach DuckLake: %w", err)