Skip to content

Commit fe7aab6

Browse files
fuziontechclaude
andauthored
fix(controlplane): force DuckLake transpile mode in multitenant remote backend (#550)
Sessions on the multitenant control plane are always backed by DuckLake workers, but the per-org metadata store comes from configstore so the global server.Config.DuckLake.MetadataStore stays empty. The transpiler was gated on that field alone, so the DDL transform never registered in MTCP — meaning Fivetran's ALTER TABLE ... ADD PRIMARY KEY (and ON CONFLICT, DuckLake-aware pg_catalog/info_schema rewrites) flowed straight through to the worker, which rejects them with "Adding indexes or constraints is not supported in DuckLake". Add server.Config.AlwaysDuckLake and set it from the remote-backend control plane. Tests cover the bare ADD PRIMARY KEY / UNIQUE / FK forms (the existing test only exercised the named-constraint path). Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent b715b38 commit fe7aab6

4 files changed

Lines changed: 20 additions & 1 deletion

File tree

controlplane/control.go

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -375,6 +375,15 @@ func RunControlPlane(cfg ControlPlaneConfig) {
375375
cfg.K8s.SharedWarmTarget = k8sSharedWarmTarget
376376
}
377377

378+
// In remote (multitenant) mode the global DuckLake.MetadataStore is empty
379+
// because metadata stores are per-org (loaded from configstore), but every
380+
// worker is DuckLake-backed. Force the transpiler into DuckLake mode so
381+
// DDL stripping (e.g. ALTER TABLE ADD PRIMARY KEY → no-op) and the other
382+
// DuckLake-aware transforms still run.
383+
if cfg.WorkerBackend == "remote" {
384+
cfg.AlwaysDuckLake = true
385+
}
386+
378387
// Create a minimal server for cancel request routing
379388
srv := &server.Server{}
380389
server.InitMinimalServer(srv, cfg.Config, nil)

server/conn.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@ type clientConn struct {
188188
// newTranspiler creates a transpiler configured for this connection.
189189
func (c *clientConn) newTranspiler(convertPlaceholders bool) *transpiler.Transpiler {
190190
return transpiler.New(transpiler.Config{
191-
DuckLakeMode: c.server.cfg.DuckLake.MetadataStore != "",
191+
DuckLakeMode: c.server.cfg.DuckLake.MetadataStore != "" || c.server.cfg.AlwaysDuckLake,
192192
LogicalDatabaseName: c.database,
193193
PhysicalCatalogName: "ducklake",
194194
ConvertPlaceholders: convertPlaceholders,

server/server.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,13 @@ type Config struct {
225225
// DuckLake configuration
226226
DuckLake DuckLakeConfig
227227

228+
// AlwaysDuckLake forces the SQL transpiler into DuckLake mode for every
229+
// session even when the global DuckLake.MetadataStore is empty. The
230+
// multitenant control plane sets this because metadata stores are
231+
// per-org (loaded from configstore), so the global field stays empty
232+
// even though every worker is DuckLake-backed.
233+
AlwaysDuckLake bool
234+
228235
// Graceful shutdown timeout (default: 30s)
229236
ShutdownTimeout time.Duration
230237

transpiler/transpiler_test.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,9 @@ func TestTranspile_DDL_NoOps(t *testing.T) {
886886
{"GRANT", "GRANT SELECT ON users TO public", "GRANT"},
887887
{"REVOKE", "REVOKE SELECT ON users FROM public", "REVOKE"},
888888
{"ALTER TABLE ADD CONSTRAINT", "ALTER TABLE users ADD CONSTRAINT pk_users PRIMARY KEY (id)", "ALTER TABLE"},
889+
{"ALTER TABLE ADD PRIMARY KEY (Fivetran form)", `/*Fivetran*/ALTER TABLE "billing_public"."billing_usagereport" ADD PRIMARY KEY ("id")`, "ALTER TABLE"},
890+
{"ALTER TABLE ADD UNIQUE", "ALTER TABLE users ADD UNIQUE (email)", "ALTER TABLE"},
891+
{"ALTER TABLE ADD FOREIGN KEY", "ALTER TABLE orders ADD FOREIGN KEY (user_id) REFERENCES users(id)", "ALTER TABLE"},
889892
{"ALTER TABLE SET NOT NULL", "ALTER TABLE users ALTER COLUMN name SET NOT NULL", "ALTER TABLE"},
890893
{"ALTER TABLE DROP NOT NULL", "ALTER TABLE users ALTER COLUMN name DROP NOT NULL", "ALTER TABLE"},
891894
{"ALTER TABLE SET DEFAULT", "ALTER TABLE users ALTER COLUMN status SET DEFAULT 'active'", "ALTER TABLE"},

0 commit comments

Comments
 (0)