Skip to content

fix: preserve all function SET clauses from pg_proc.proconfig - #529

Merged
tianzhou merged 2 commits into
mainfrom
fix/issue-526-function-set-config
Aug 5, 2026
Merged

fix: preserve all function SET clauses from pg_proc.proconfig#529
tianzhou merged 2 commits into
mainfrom
fix/issue-526-function-set-config

Conversation

@tianzhou

@tianzhou tianzhou commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes #526pgschema apply was silently dropping every function-local SET clause except search_path.

Root cause

The function IR had a single SearchPath field. The introspection SQL extracted only search_path from pg_proc.proconfig, and rendering emitted only SET search_path.

Changes

Layer Change
IR (ir/ir.go) Replaced SearchPath string with SetConfig []string — stores raw key=value entries
SQL (ir/queries/queries.sql) Changed subquery from WHERE cfg LIKE 'search_path=%' to COALESCE(p.proconfig, '{}')
Inspector (ir/inspector.go) Reads full SetConfig array
Diff (internal/diff/function.go) Renders all SET clauses in sorted order for deterministic output; compares slices with sort-based equality; non-search_path values are SQL-quoted via quoteString()
Plan (cmd/plan/plan.go) Schema-normalizes all SetConfig entries
Tests Added round-trip integration tests for: multi-SET, non-search_path-only, no-SET, and search_path-only functions

Rendering

  • search_path keeps existing special behavior (unquoted for multi-schema paths, '' for empty)
  • All other GUCs rendered as SET <key> = '<value>' via quoteString() (handles whitespace, embedded quotes)
  • Entries sorted alphabetically for deterministic output

Edge cases

  • Empty proconfig: COALESCE produces {}, handled gracefully
  • Order-insensitive comparison: setConfigEqual sorts before comparing
  • Values with spaces/quotes: quoteString wraps in single quotes and doubles internal quotes
  • replaceSchemaInSearchPath unaffected — it operates on raw SQL and only matches SET search_path

Copilot AI lite review requested due to automatic review settings August 5, 2026 04:29
@greptile-apps

greptile-apps Bot commented Aug 5, 2026

Copy link
Copy Markdown

Greptile Summary

This PR extends function introspection and IR comparison to preserve every pg_proc.proconfig entry rather than only search_path.

  • Replaces the function IR’s single search-path field with an order-insensitive SET configuration list.
  • Introspects, schema-normalizes, compares, and renders the complete configuration list.
  • Adds round-trip integration coverage for common SET combinations.
  • Adds transaction-capability metadata to serialized plan steps and compatibility handling for older plans.

Confidence Score: 4/5

The arbitrary function-setting renderer should be fixed before merging because valid values containing whitespace or other literal-sensitive characters generate invalid migration SQL.

Full proconfig preservation reaches the new renderer correctly, but the renderer treats catalog values as reusable SQL tokens, breaking valid function settings that require quoting.

Files Needing Attention: internal/diff/function.go

Important Files Changed

Filename Overview
internal/diff/function.go Renders and compares all function SET entries, but emits arbitrary non-search_path values without the SQL quoting required for literal-sensitive values.
ir/queries/queries.sql Replaces search_path-only extraction with the complete, non-null pg_proc.proconfig array.
ir/inspector.go Propagates the complete introspected configuration array into the function IR.
ir/ir.go Replaces SearchPath with a SetConfig slice representing raw key-value entries.
cmd/plan/plan.go Extends temporary-schema normalization across function configuration entries.
internal/plan/plan.go Serializes per-step transaction capability and reconstructs defaults when reading older plans.
cmd/issue_526_integration_test.go Adds round-trip coverage for common multi-SET, non-search_path, empty, and search_path-only functions.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart LR
  A["pg_proc.proconfig text[]"] --> B["Inspector: Function.SetConfig"]
  B --> C["Temporary-schema normalization"]
  C --> D["Order-insensitive function diff"]
  D --> E["CREATE FUNCTION renderer"]
  E --> F["SET key = value clauses"]
Loading

Reviews (1): Last reviewed commit: "fix: preserve all function SET clauses f..." | Re-trigger Greptile

Comment thread internal/diff/function.go Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes function-local configuration loss by preserving and re-rendering all pg_proc.proconfig entries (not just search_path) through the IR → diff/plan → apply pipeline, addressing issue #526 where pgschema apply could silently drop function SET clauses.

Changes:

  • Replaces Function.SearchPath with Function.SetConfig []string and updates introspection SQL to read the full proconfig array.
  • Updates function diff/rendering to compare SetConfig order-insensitively and emit deterministic SET clauses.
  • Adds an integration regression test for plan → apply → plan convergence with multiple (and edge-case) SET clauses.
  • Additionally introduces can_run_in_transaction in plan JSON steps and updates migrate fixtures accordingly.

Reviewed changes

Copilot reviewed 12 out of 13 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
testdata/diff/migrate/v1/plan.json Updates expected plan JSON to include can_run_in_transaction.
testdata/diff/migrate/v2/plan.json Updates expected plan JSON to include can_run_in_transaction.
testdata/diff/migrate/v3/plan.json Updates expected plan JSON to include can_run_in_transaction.
testdata/diff/migrate/v4/plan.json Updates expected plan JSON to include can_run_in_transaction (including CONCURRENTLY=false cases).
testdata/diff/migrate/v5/plan.json Updates expected plan JSON to include can_run_in_transaction.
ir/queries/queries.sql Introspects full pg_proc.proconfig via COALESCE(p.proconfig, '{}') AS set_config.
ir/queries/queries.sql.go Regenerates sqlc output to return set_config []string and scan via pq.Array.
ir/ir.go Updates function IR to store SetConfig []string instead of SearchPath.
ir/inspector.go Populates Function.SetConfig from inspector query results.
internal/diff/function.go Renders and compares SetConfig deterministically; introduces setConfigEqual.
cmd/plan/plan.go Normalizes schema references inside SetConfig entries during plan generation.
internal/plan/plan.go Adds Step.CanRunInTransaction to plan JSON + backward-compat handling in FromJSON.
cmd/issue_526_integration_test.go Adds integration test ensuring SET clauses survive plan → apply → plan.
Files not reviewed (1)
  • ir/queries/queries.sql.go: Generated file
Suppressed comments (1)

internal/plan/plan.go:44

  • This PR is scoped/titled around preserving function SET clauses, but it also introduces a new can_run_in_transaction field in plan JSON and updates multiple migrate plan fixtures accordingly. That’s a public JSON format change and likely warrants either (a) being called out explicitly in the PR title/description, or (b) moving to a separate PR to keep the change focused.
// Step represents a single execution step with SQL and optional directive
type Step struct {
	SQL                 string     `json:"sql"`
	Directive           *Directive `json:"directive,omitempty"`
	CanRunInTransaction bool       `json:"can_run_in_transaction"`
	// Metadata for summary generation
	Type      string `json:"type,omitempty"`      // e.g., "table", "index"
	Operation string `json:"operation,omitempty"` // e.g., "create", "alter", "drop"
	Path      string `json:"path,omitempty"`      // e.g., "public.users"
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/diff/function.go
@tianzhou

tianzhou commented Aug 5, 2026

Copy link
Copy Markdown
Contributor Author

Fixed in e9f00e8: non-search_path SET values are now rendered through quoteString() so values like DateStyle=ISO, MDY become SET DateStyle = 'ISO, MDY'.

The existing quoteString utility in diff.go wraps values in single quotes and doubles any internal quotes — exactly what pg_dump does for the non-search_path case.

@tianzhou tianzhou left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in e9f00e8: the non-search_path SET values in generateFunctionSQL now go through quoteString().

Values like DateStyle=ISO, MDY now render as SET DateStyle = 'ISO, MDY'. The quoteString utility (already used elsewhere in diff.go for COMMENT ON) wraps the value in single quotes and doubles any internal single quotes — same approach pg_dump uses for the non-search_path case.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 12 out of 13 changed files in this pull request and generated 1 comment.

Files not reviewed (1)
  • ir/queries/queries.sql.go: Generated file

Comment thread internal/plan/plan.go Outdated
Previously, only search_path was extracted from pg_proc.proconfig and
preserved in the function IR. All other SET clauses (TimeZone, DateStyle,
statement_timeout, etc.) were silently dropped during introspection,
causing plan→apply→plan divergence and lost runtime semantics.

Changes:
- ir/ir.go: Replace Function.SearchPath (string) with SetConfig ([]string)
  containing raw 'key=value' entries from proconfig
- ir/queries/queries.sql: Replace search_path-only subquery with
  COALESCE(p.proconfig, '{}') to capture all entries
- ir/queries/queries.sql.go: Regenerated with sqlc
- ir/inspector.go: Read full SetConfig array instead of just SearchPath
- internal/diff/function.go: Render all SET clauses in sorted order,
  with special handling for search_path empty-string case; compare
  SetConfig slices in all three function diff helpers
- cmd/plan/plan.go: Schema-normalize all SetConfig entries
- cmd/issue_526_integration_test.go: Round-trip regression tests

Fixes #526
The proconfig array stores values without quotes (e.g. DateStyle=ISO, MDY),
but valid migration SQL requires them as quoted string literals
(e.g. SET DateStyle = 'ISO, MDY'). Non-search_path settings are now
rendered through quoteString() so whitespace and special characters
don't produce invalid SQL.
@tianzhou
tianzhou force-pushed the fix/issue-526-function-set-config branch from e9f00e8 to 210a0bb Compare August 5, 2026 05:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 6 out of 7 changed files in this pull request and generated no new comments.

Files not reviewed (1)
  • ir/queries/queries.sql.go: Generated file

@tianzhou
tianzhou merged commit 89d04c7 into main Aug 5, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Function SET clauses except search_path are dropped

2 participants