From 831602f377b80938796fdc1bf38745712db063da Mon Sep 17 00:00:00 2001 From: tianzhou Date: Mon, 29 Dec 2025 00:03:31 -0800 Subject: [PATCH 1/2] fix: preserve interval type casts in function parameter defaults (#216) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Previously, pgschema stripped all type casts from string literals in function parameter defaults, including semantically required ones like '1 year'::interval. This caused generated SQL to fail with: "ERROR: operator is not unique: date + unknown" Changes: - Modified normalize.go to only strip truly redundant casts (text, varchar, char, json, jsonb) while preserving required ones (interval, date, custom enums, etc.) - Added temp schema prefix stripping in IR normalization to ensure idempotent comparisons between desired and current state - Extended stripSchemaPrefix() to handle type casts within expressions - Added stripTempSchemaPrefix() for temporary embedded postgres schemas - Updated test files to include interval parameter and preserve custom enum type casts Fixes #216 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- internal/diff/function.go | 9 ++++- internal/diff/table.go | 38 ++++++++++++++++++- ir/normalize.go | 38 ++++++++++++------- .../create_function/add_function/diff.sql | 3 +- .../diff/create_function/add_function/new.sql | 4 +- .../create_function/add_function/plan.json | 2 +- .../create_function/add_function/plan.sql | 3 +- .../create_function/add_function/plan.txt | 3 +- .../alter_function_same_signature/diff.sql | 4 +- .../alter_function_same_signature/new.sql | 4 +- .../alter_function_same_signature/plan.json | 4 +- .../alter_function_same_signature/plan.sql | 4 +- .../alter_function_same_signature/plan.txt | 4 +- .../diff.sql | 2 +- .../plan.json | 2 +- .../plan.sql | 2 +- .../plan.txt | 2 +- .../create_table/alter_column_types/diff.sql | 2 +- .../create_table/alter_column_types/plan.json | 2 +- .../create_table/alter_column_types/plan.sql | 2 +- .../create_table/alter_column_types/plan.txt | 2 +- testdata/diff/migrate/v5/diff.sql | 2 +- testdata/diff/migrate/v5/plan.json | 2 +- testdata/diff/migrate/v5/plan.sql | 2 +- testdata/diff/migrate/v5/plan.txt | 2 +- 25 files changed, 100 insertions(+), 44 deletions(-) diff --git a/internal/diff/function.go b/internal/diff/function.go index c3190b4b..b1c94305 100644 --- a/internal/diff/function.go +++ b/internal/diff/function.go @@ -287,8 +287,15 @@ func formatFunctionParameter(param *ir.Parameter, includeDefault bool, targetSch } // Add DEFAULT value if present and requested + // Strip schema prefix from default value type casts + // We strip both the target schema prefix and any temporary schema prefix (pgschema_tmp_*) if includeDefault && param.DefaultValue != nil { - part += " DEFAULT " + *param.DefaultValue + defaultVal := *param.DefaultValue + // Strip target schema prefix + defaultVal = stripSchemaPrefix(defaultVal, targetSchema) + // Also strip temporary embedded postgres schema prefixes (pgschema_tmp_*) + defaultVal = stripTempSchemaPrefix(defaultVal) + part += " DEFAULT " + defaultVal } return part diff --git a/internal/diff/table.go b/internal/diff/table.go index 0fb536af..8983a6b7 100644 --- a/internal/diff/table.go +++ b/internal/diff/table.go @@ -8,21 +8,55 @@ import ( "github.com/pgschema/pgschema/ir" ) -// stripSchemaPrefix removes the schema prefix from a type name if it matches the target schema +// stripSchemaPrefix removes the schema prefix from a type name if it matches the target schema. +// It handles both simple type names (e.g., "schema.typename") and type casts within expressions +// (e.g., "'value'::schema.typename" -> "'value'::typename"). func stripSchemaPrefix(typeName, targetSchema string) string { if typeName == "" || targetSchema == "" { return typeName } - // Check if the type has the target schema prefix + // Check if the type has the target schema prefix at the beginning prefix := targetSchema + "." if after, found := strings.CutPrefix(typeName, prefix); found { return after } + // Also handle type casts within expressions: ::schema.typename -> ::typename + // This is needed for function parameter default values like 'value'::schema.enum_type + castPrefix := "::" + targetSchema + "." + if strings.Contains(typeName, castPrefix) { + return strings.ReplaceAll(typeName, castPrefix, "::") + } + return typeName } +// stripTempSchemaPrefix removes temporary embedded postgres schema prefixes (pgschema_tmp_*). +// These are used internally during plan generation and should not appear in output DDL. +func stripTempSchemaPrefix(value string) string { + if value == "" { + return value + } + + // Pattern: ::pgschema_tmp_YYYYMMDD_HHMMSS_XXXXXXXX.typename -> ::typename + // We look for ::pgschema_tmp_ followed by anything until the next dot + idx := strings.Index(value, "::pgschema_tmp_") + if idx == -1 { + return value + } + + // Find the dot after pgschema_tmp_* + dotIdx := strings.Index(value[idx+15:], ".") + if dotIdx == -1 { + return value + } + + // Replace ::pgschema_tmp_XXX.typename with ::typename + prefix := value[idx : idx+15+dotIdx+1] // includes the trailing dot + return strings.ReplaceAll(value, prefix, "::") +} + // sortConstraintColumnsByPosition sorts constraint columns by their position func sortConstraintColumnsByPosition(columns []*ir.ConstraintColumn) []*ir.ConstraintColumn { sorted := make([]*ir.ConstraintColumn, len(columns)) diff --git a/ir/normalize.go b/ir/normalize.go index fe38972b..0d585293 100644 --- a/ir/normalize.go +++ b/ir/normalize.go @@ -134,6 +134,14 @@ func normalizeDefaultValue(value string, tableSchema string) string { // Handle type casting - remove explicit type casts that are semantically equivalent if strings.Contains(value, "::") { + // Strip temporary embedded postgres schema prefixes (pgschema_tmp_*) + // These are used internally during plan generation and should be normalized away + // Pattern: ::pgschema_tmp_YYYYMMDD_HHMMSS_XXXXXXXX.typename -> ::typename + if strings.Contains(value, "::pgschema_tmp_") { + re := regexp.MustCompile(`::pgschema_tmp_[^.]+\.`) + value = re.ReplaceAllString(value, "::") + } + // Handle NULL::type -> NULL // Example: NULL::text -> NULL re := regexp.MustCompile(`\bNULL::(?:[a-zA-Z_][\w\s.]*)(?:\[\])?`) @@ -146,22 +154,24 @@ func normalizeDefaultValue(value string, tableSchema string) string { re = regexp.MustCompile(`'(-?\d+(?:\.\d+)?)'::(?:integer|bigint|smallint|numeric|decimal|real|double precision|int2|int4|int8|float4|float8)`) value = re.ReplaceAllString(value, "$1") - // Handle string literals with type casts (including escaped quotes) - // Example: 'text'::text -> 'text' - // Example: 'O''Brien'::text -> 'O''Brien' - // Example: '{}'::jsonb -> '{}' - // Example: '{1,2,3}'::integer[] -> '{1,2,3}' - // Pattern explanation: - // '(?:[^']|'')*' - matches a quoted string literal, handling escaped quotes '' - // ::[a-zA-Z_][\w\s.]* - matches ::typename - // (?:\[\])? - optionally followed by [] for array types - re = regexp.MustCompile(`('(?:[^']|'')*')::(?:[a-zA-Z_][\w\s.]*)(?:\[\])?`) + // Handle string literals with ONLY truly redundant type casts + // Only remove casts where the literal is inherently the target type: + // Example: 'text'::text -> 'text' (string literal IS text) + // Example: 'O''Brien'::character varying -> 'O''Brien' + // Example: '{}'::text[] -> '{}' (empty array literal with text array cast) + // Example: '{}'::jsonb -> '{}' (JSON object literal - column type provides context) + // + // IMPORTANT: Do NOT remove semantically significant casts like: + // - '1 year'::interval (interval literals REQUIRE the cast) + // - 'value'::my_enum (custom type casts) + // - '2024-01-01'::date (date literals need the cast in expressions) + // + // Pattern matches redundant text/varchar/char/json casts (including arrays) + // Note: jsonb must come before json to avoid partial match + // Note: (?:\[\])* handles multi-dimensional arrays like text[][] + re = regexp.MustCompile(`('(?:[^']|'')*')::(text|character varying|character|bpchar|varchar|jsonb|json)(?:\[\])*`) value = re.ReplaceAllString(value, "$1") - // Handle date/timestamp literals with type casts - // Example: '2024-01-01'::date -> '2024-01-01' - // Already handled by the string literal pattern above - // Handle parenthesized expressions with type casts - remove outer parentheses // Example: (100)::bigint -> 100::bigint // Pattern captures the number and the type cast separately diff --git a/testdata/diff/create_function/add_function/diff.sql b/testdata/diff/create_function/add_function/diff.sql index b1bf99f6..84ab1350 100644 --- a/testdata/diff/create_function/add_function/diff.sql +++ b/testdata/diff/create_function/add_function/diff.sql @@ -28,7 +28,8 @@ CREATE OR REPLACE FUNCTION process_order( note varchar DEFAULT '', status text DEFAULT 'pending', apply_tax boolean DEFAULT true, - is_priority boolean DEFAULT false + is_priority boolean DEFAULT false, + expiry_date date DEFAULT (CURRENT_DATE + '1 year'::interval) ) RETURNS numeric LANGUAGE plpgsql diff --git a/testdata/diff/create_function/add_function/new.sql b/testdata/diff/create_function/add_function/new.sql index f6d6bbc8..d5f4177d 100644 --- a/testdata/diff/create_function/add_function/new.sql +++ b/testdata/diff/create_function/add_function/new.sql @@ -9,7 +9,9 @@ CREATE FUNCTION process_order( status text DEFAULT 'pending', -- Boolean defaults apply_tax boolean DEFAULT true, - is_priority boolean DEFAULT false + is_priority boolean DEFAULT false, + -- Interval default (reproduces issue #216) + expiry_date date DEFAULT (CURRENT_DATE + INTERVAL '1 year') ) RETURNS numeric LANGUAGE plpgsql diff --git a/testdata/diff/create_function/add_function/plan.json b/testdata/diff/create_function/add_function/plan.json index 0a075626..20778f44 100644 --- a/testdata/diff/create_function/add_function/plan.json +++ b/testdata/diff/create_function/add_function/plan.json @@ -21,7 +21,7 @@ "path": "public.mask_sensitive_data" }, { - "sql": "CREATE OR REPLACE FUNCTION process_order(\n order_id integer,\n discount_percent numeric DEFAULT 0,\n priority_level integer DEFAULT 1,\n note varchar DEFAULT '',\n status text DEFAULT 'pending',\n apply_tax boolean DEFAULT true,\n is_priority boolean DEFAULT false\n)\nRETURNS numeric\nLANGUAGE plpgsql\nVOLATILE\nSTRICT\nSECURITY DEFINER\nLEAKPROOF\nPARALLEL RESTRICTED\nAS $$\nDECLARE\n total numeric;\nBEGIN\n SELECT amount INTO total FROM orders WHERE id = order_id;\n RETURN total - (total * discount_percent / 100);\nEND;\n$$;", + "sql": "CREATE OR REPLACE FUNCTION process_order(\n order_id integer,\n discount_percent numeric DEFAULT 0,\n priority_level integer DEFAULT 1,\n note varchar DEFAULT '',\n status text DEFAULT 'pending',\n apply_tax boolean DEFAULT true,\n is_priority boolean DEFAULT false,\n expiry_date date DEFAULT (CURRENT_DATE + '1 year'::interval)\n)\nRETURNS numeric\nLANGUAGE plpgsql\nVOLATILE\nSTRICT\nSECURITY DEFINER\nLEAKPROOF\nPARALLEL RESTRICTED\nAS $$\nDECLARE\n total numeric;\nBEGIN\n SELECT amount INTO total FROM orders WHERE id = order_id;\n RETURN total - (total * discount_percent / 100);\nEND;\n$$;", "type": "function", "operation": "create", "path": "public.process_order" diff --git a/testdata/diff/create_function/add_function/plan.sql b/testdata/diff/create_function/add_function/plan.sql index b1bf99f6..84ab1350 100644 --- a/testdata/diff/create_function/add_function/plan.sql +++ b/testdata/diff/create_function/add_function/plan.sql @@ -28,7 +28,8 @@ CREATE OR REPLACE FUNCTION process_order( note varchar DEFAULT '', status text DEFAULT 'pending', apply_tax boolean DEFAULT true, - is_priority boolean DEFAULT false + is_priority boolean DEFAULT false, + expiry_date date DEFAULT (CURRENT_DATE + '1 year'::interval) ) RETURNS numeric LANGUAGE plpgsql diff --git a/testdata/diff/create_function/add_function/plan.txt b/testdata/diff/create_function/add_function/plan.txt index e8bed1ad..40b91823 100644 --- a/testdata/diff/create_function/add_function/plan.txt +++ b/testdata/diff/create_function/add_function/plan.txt @@ -41,7 +41,8 @@ CREATE OR REPLACE FUNCTION process_order( note varchar DEFAULT '', status text DEFAULT 'pending', apply_tax boolean DEFAULT true, - is_priority boolean DEFAULT false + is_priority boolean DEFAULT false, + expiry_date date DEFAULT (CURRENT_DATE + '1 year'::interval) ) RETURNS numeric LANGUAGE plpgsql diff --git a/testdata/diff/create_function/alter_function_same_signature/diff.sql b/testdata/diff/create_function/alter_function_same_signature/diff.sql index ee039c57..da4a0d01 100644 --- a/testdata/diff/create_function/alter_function_same_signature/diff.sql +++ b/testdata/diff/create_function/alter_function_same_signature/diff.sql @@ -1,8 +1,8 @@ CREATE OR REPLACE FUNCTION process_order( order_id integer, discount_percent numeric DEFAULT 0, - status order_status DEFAULT 'pending', - priority utils.priority_level DEFAULT 'medium' + status order_status DEFAULT 'pending'::order_status, + priority utils.priority_level DEFAULT 'medium'::utils.priority_level ) RETURNS numeric LANGUAGE plpgsql diff --git a/testdata/diff/create_function/alter_function_same_signature/new.sql b/testdata/diff/create_function/alter_function_same_signature/new.sql index 0ae75938..77862d68 100644 --- a/testdata/diff/create_function/alter_function_same_signature/new.sql +++ b/testdata/diff/create_function/alter_function_same_signature/new.sql @@ -3,8 +3,8 @@ CREATE TYPE order_status AS ENUM ('pending', 'processing', 'completed', 'cancell CREATE FUNCTION process_order( order_id integer, discount_percent numeric DEFAULT 0, - status order_status DEFAULT 'pending', - priority utils.priority_level DEFAULT 'medium' + status order_status DEFAULT 'pending'::order_status, + priority utils.priority_level DEFAULT 'medium'::utils.priority_level ) RETURNS numeric LANGUAGE plpgsql diff --git a/testdata/diff/create_function/alter_function_same_signature/plan.json b/testdata/diff/create_function/alter_function_same_signature/plan.json index 187dcd99..0b24193a 100644 --- a/testdata/diff/create_function/alter_function_same_signature/plan.json +++ b/testdata/diff/create_function/alter_function_same_signature/plan.json @@ -3,13 +3,13 @@ "pgschema_version": "1.5.1", "created_at": "1970-01-01T00:00:00Z", "source_fingerprint": { - "hash": "07aea23ff65a63da587c7fddf4fe417ec7e0cbddbff86a8775bb4bfc5d1b011f" + "hash": "fc335bb328a0b47f89b922eadc006adbeadd205c59890bb5523a57bb00e854b9" }, "groups": [ { "steps": [ { - "sql": "CREATE OR REPLACE FUNCTION process_order(\n order_id integer,\n discount_percent numeric DEFAULT 0,\n status order_status DEFAULT 'pending',\n priority utils.priority_level DEFAULT 'medium'\n)\nRETURNS numeric\nLANGUAGE plpgsql\nSTABLE\nAS $$\nDECLARE\n base_price numeric;\n tax_rate numeric := 0.08;\nBEGIN\n -- Different logic: calculate with tax instead of just discount\n -- Status and priority parameters are available but not used in this simplified version\n SELECT price INTO base_price FROM products WHERE id = order_id;\n RETURN base_price * (1 - discount_percent / 100) * (1 + tax_rate);\nEND;\n$$;", + "sql": "CREATE OR REPLACE FUNCTION process_order(\n order_id integer,\n discount_percent numeric DEFAULT 0,\n status order_status DEFAULT 'pending'::order_status,\n priority utils.priority_level DEFAULT 'medium'::utils.priority_level\n)\nRETURNS numeric\nLANGUAGE plpgsql\nSTABLE\nAS $$\nDECLARE\n base_price numeric;\n tax_rate numeric := 0.08;\nBEGIN\n -- Different logic: calculate with tax instead of just discount\n -- Status and priority parameters are available but not used in this simplified version\n SELECT price INTO base_price FROM products WHERE id = order_id;\n RETURN base_price * (1 - discount_percent / 100) * (1 + tax_rate);\nEND;\n$$;", "type": "function", "operation": "alter", "path": "public.process_order" diff --git a/testdata/diff/create_function/alter_function_same_signature/plan.sql b/testdata/diff/create_function/alter_function_same_signature/plan.sql index ee039c57..da4a0d01 100644 --- a/testdata/diff/create_function/alter_function_same_signature/plan.sql +++ b/testdata/diff/create_function/alter_function_same_signature/plan.sql @@ -1,8 +1,8 @@ CREATE OR REPLACE FUNCTION process_order( order_id integer, discount_percent numeric DEFAULT 0, - status order_status DEFAULT 'pending', - priority utils.priority_level DEFAULT 'medium' + status order_status DEFAULT 'pending'::order_status, + priority utils.priority_level DEFAULT 'medium'::utils.priority_level ) RETURNS numeric LANGUAGE plpgsql diff --git a/testdata/diff/create_function/alter_function_same_signature/plan.txt b/testdata/diff/create_function/alter_function_same_signature/plan.txt index 88e4ac1d..77eb4b5e 100644 --- a/testdata/diff/create_function/alter_function_same_signature/plan.txt +++ b/testdata/diff/create_function/alter_function_same_signature/plan.txt @@ -12,8 +12,8 @@ DDL to be executed: CREATE OR REPLACE FUNCTION process_order( order_id integer, discount_percent numeric DEFAULT 0, - status order_status DEFAULT 'pending', - priority utils.priority_level DEFAULT 'medium' + status order_status DEFAULT 'pending'::order_status, + priority utils.priority_level DEFAULT 'medium'::utils.priority_level ) RETURNS numeric LANGUAGE plpgsql diff --git a/testdata/diff/create_table/add_column_cross_schema_custom_type/diff.sql b/testdata/diff/create_table/add_column_cross_schema_custom_type/diff.sql index 46c3167f..f20f3c5c 100644 --- a/testdata/diff/create_table/add_column_cross_schema_custom_type/diff.sql +++ b/testdata/diff/create_table/add_column_cross_schema_custom_type/diff.sql @@ -1,4 +1,4 @@ ALTER TABLE users ADD COLUMN fqdn citext NOT NULL; ALTER TABLE users ADD COLUMN metadata utils.hstore; ALTER TABLE users ADD COLUMN description utils.custom_text; -ALTER TABLE users ADD COLUMN status utils.custom_enum DEFAULT 'active'; +ALTER TABLE users ADD COLUMN status utils.custom_enum DEFAULT 'active'::utils.custom_enum; diff --git a/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.json b/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.json index 3c2db265..532a468d 100644 --- a/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.json +++ b/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.json @@ -27,7 +27,7 @@ "path": "public.users.description" }, { - "sql": "ALTER TABLE users ADD COLUMN status utils.custom_enum DEFAULT 'active';", + "sql": "ALTER TABLE users ADD COLUMN status utils.custom_enum DEFAULT 'active'::utils.custom_enum;", "type": "table.column", "operation": "create", "path": "public.users.status" diff --git a/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.sql b/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.sql index abeb0560..3c30525f 100644 --- a/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.sql +++ b/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.sql @@ -4,4 +4,4 @@ ALTER TABLE users ADD COLUMN metadata utils.hstore; ALTER TABLE users ADD COLUMN description utils.custom_text; -ALTER TABLE users ADD COLUMN status utils.custom_enum DEFAULT 'active'; +ALTER TABLE users ADD COLUMN status utils.custom_enum DEFAULT 'active'::utils.custom_enum; diff --git a/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.txt b/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.txt index 0adce2a3..dc808eb3 100644 --- a/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.txt +++ b/testdata/diff/create_table/add_column_cross_schema_custom_type/plan.txt @@ -19,4 +19,4 @@ ALTER TABLE users ADD COLUMN metadata utils.hstore; ALTER TABLE users ADD COLUMN description utils.custom_text; -ALTER TABLE users ADD COLUMN status utils.custom_enum DEFAULT 'active'; +ALTER TABLE users ADD COLUMN status utils.custom_enum DEFAULT 'active'::utils.custom_enum; diff --git a/testdata/diff/create_table/alter_column_types/diff.sql b/testdata/diff/create_table/alter_column_types/diff.sql index 3254cd0a..45e5b66f 100644 --- a/testdata/diff/create_table/alter_column_types/diff.sql +++ b/testdata/diff/create_table/alter_column_types/diff.sql @@ -16,6 +16,6 @@ ALTER TABLE user_pending_permissions ALTER COLUMN status DROP DEFAULT; ALTER TABLE user_pending_permissions ALTER COLUMN status TYPE action_type USING status::action_type; -ALTER TABLE user_pending_permissions ALTER COLUMN status SET DEFAULT 'pending'; +ALTER TABLE user_pending_permissions ALTER COLUMN status SET DEFAULT 'pending'::action_type; ALTER TABLE user_pending_permissions ALTER COLUMN tags TYPE action_type[] USING tags::action_type[]; diff --git a/testdata/diff/create_table/alter_column_types/plan.json b/testdata/diff/create_table/alter_column_types/plan.json index 54d58932..ac67a2b0 100644 --- a/testdata/diff/create_table/alter_column_types/plan.json +++ b/testdata/diff/create_table/alter_column_types/plan.json @@ -51,7 +51,7 @@ "path": "public.user_pending_permissions.status" }, { - "sql": "ALTER TABLE user_pending_permissions ALTER COLUMN status SET DEFAULT 'pending';", + "sql": "ALTER TABLE user_pending_permissions ALTER COLUMN status SET DEFAULT 'pending'::action_type;", "type": "table.column", "operation": "alter", "path": "public.user_pending_permissions.status" diff --git a/testdata/diff/create_table/alter_column_types/plan.sql b/testdata/diff/create_table/alter_column_types/plan.sql index 3254cd0a..45e5b66f 100644 --- a/testdata/diff/create_table/alter_column_types/plan.sql +++ b/testdata/diff/create_table/alter_column_types/plan.sql @@ -16,6 +16,6 @@ ALTER TABLE user_pending_permissions ALTER COLUMN status DROP DEFAULT; ALTER TABLE user_pending_permissions ALTER COLUMN status TYPE action_type USING status::action_type; -ALTER TABLE user_pending_permissions ALTER COLUMN status SET DEFAULT 'pending'; +ALTER TABLE user_pending_permissions ALTER COLUMN status SET DEFAULT 'pending'::action_type; ALTER TABLE user_pending_permissions ALTER COLUMN tags TYPE action_type[] USING tags::action_type[]; diff --git a/testdata/diff/create_table/alter_column_types/plan.txt b/testdata/diff/create_table/alter_column_types/plan.txt index 41a78908..2c506dce 100644 --- a/testdata/diff/create_table/alter_column_types/plan.txt +++ b/testdata/diff/create_table/alter_column_types/plan.txt @@ -37,6 +37,6 @@ ALTER TABLE user_pending_permissions ALTER COLUMN status DROP DEFAULT; ALTER TABLE user_pending_permissions ALTER COLUMN status TYPE action_type USING status::action_type; -ALTER TABLE user_pending_permissions ALTER COLUMN status SET DEFAULT 'pending'; +ALTER TABLE user_pending_permissions ALTER COLUMN status SET DEFAULT 'pending'::action_type; ALTER TABLE user_pending_permissions ALTER COLUMN tags TYPE action_type[] USING tags::action_type[]; diff --git a/testdata/diff/migrate/v5/diff.sql b/testdata/diff/migrate/v5/diff.sql index 178b1412..059e4e6c 100644 --- a/testdata/diff/migrate/v5/diff.sql +++ b/testdata/diff/migrate/v5/diff.sql @@ -35,4 +35,4 @@ CREATE POLICY audit_insert_system ON audit FOR INSERT TO PUBLIC WITH CHECK (true CREATE POLICY audit_user_isolation ON audit TO PUBLIC USING (user_name = CURRENT_USER); -ALTER TABLE employee ADD COLUMN status employee_status DEFAULT 'active' NOT NULL; +ALTER TABLE employee ADD COLUMN status employee_status DEFAULT 'active'::employee_status NOT NULL; diff --git a/testdata/diff/migrate/v5/plan.json b/testdata/diff/migrate/v5/plan.json index eaab5eca..375c438c 100644 --- a/testdata/diff/migrate/v5/plan.json +++ b/testdata/diff/migrate/v5/plan.json @@ -75,7 +75,7 @@ "path": "public.audit.audit_user_isolation" }, { - "sql": "ALTER TABLE employee ADD COLUMN status employee_status DEFAULT 'active' NOT NULL;", + "sql": "ALTER TABLE employee ADD COLUMN status employee_status DEFAULT 'active'::employee_status NOT NULL;", "type": "table.column", "operation": "create", "path": "public.employee.status" diff --git a/testdata/diff/migrate/v5/plan.sql b/testdata/diff/migrate/v5/plan.sql index 178b1412..059e4e6c 100644 --- a/testdata/diff/migrate/v5/plan.sql +++ b/testdata/diff/migrate/v5/plan.sql @@ -35,4 +35,4 @@ CREATE POLICY audit_insert_system ON audit FOR INSERT TO PUBLIC WITH CHECK (true CREATE POLICY audit_user_isolation ON audit TO PUBLIC USING (user_name = CURRENT_USER); -ALTER TABLE employee ADD COLUMN status employee_status DEFAULT 'active' NOT NULL; +ALTER TABLE employee ADD COLUMN status employee_status DEFAULT 'active'::employee_status NOT NULL; diff --git a/testdata/diff/migrate/v5/plan.txt b/testdata/diff/migrate/v5/plan.txt index 90960853..3347fa8e 100644 --- a/testdata/diff/migrate/v5/plan.txt +++ b/testdata/diff/migrate/v5/plan.txt @@ -65,4 +65,4 @@ CREATE POLICY audit_insert_system ON audit FOR INSERT TO PUBLIC WITH CHECK (true CREATE POLICY audit_user_isolation ON audit TO PUBLIC USING (user_name = CURRENT_USER); -ALTER TABLE employee ADD COLUMN status employee_status DEFAULT 'active' NOT NULL; +ALTER TABLE employee ADD COLUMN status employee_status DEFAULT 'active'::employee_status NOT NULL; From fbb39a959dd65321346877e3d2e2ec214ce6d5b6 Mon Sep 17 00:00:00 2001 From: tianzhou Date: Mon, 29 Dec 2025 01:35:23 -0800 Subject: [PATCH 2/2] chore: update schema dump --- testdata/dump/bytebase/pgschema.sql | 2 +- testdata/dump/employee/pgschema.sql | 2 +- testdata/dump/issue_125_function_default/pgschema.sql | 4 ++-- testdata/dump/sakila/pgschema.sql | 4 ++-- testdata/dump/tenant/pgschema.sql | 8 ++++---- 5 files changed, 10 insertions(+), 10 deletions(-) diff --git a/testdata/dump/bytebase/pgschema.sql b/testdata/dump/bytebase/pgschema.sql index 027af93c..ec841933 100644 --- a/testdata/dump/bytebase/pgschema.sql +++ b/testdata/dump/bytebase/pgschema.sql @@ -3,7 +3,7 @@ -- -- Dumped from database version PostgreSQL 17.5 --- Dumped by pgschema version 1.4.0 +-- Dumped by pgschema version 1.5.1 -- diff --git a/testdata/dump/employee/pgschema.sql b/testdata/dump/employee/pgschema.sql index ef1b4d21..149f43a9 100644 --- a/testdata/dump/employee/pgschema.sql +++ b/testdata/dump/employee/pgschema.sql @@ -3,7 +3,7 @@ -- -- Dumped from database version PostgreSQL 18.0 --- Dumped by pgschema version 1.5.0 +-- Dumped by pgschema version 1.5.1 -- diff --git a/testdata/dump/issue_125_function_default/pgschema.sql b/testdata/dump/issue_125_function_default/pgschema.sql index 87604145..c17eed94 100644 --- a/testdata/dump/issue_125_function_default/pgschema.sql +++ b/testdata/dump/issue_125_function_default/pgschema.sql @@ -3,7 +3,7 @@ -- -- Dumped from database version PostgreSQL 18.0 --- Dumped by pgschema version 1.5.0 +-- Dumped by pgschema version 1.5.1 -- @@ -13,7 +13,7 @@ CREATE OR REPLACE FUNCTION test_complex_defaults( arr integer[] DEFAULT ARRAY[1, 2, 3], json_data jsonb DEFAULT '{"key": "value"}', - range_val int4range DEFAULT '[1,10)', + range_val int4range DEFAULT '[1,10)'::int4range, expr_default integer DEFAULT 40 ) RETURNS jsonb diff --git a/testdata/dump/sakila/pgschema.sql b/testdata/dump/sakila/pgschema.sql index c36912d1..74beae12 100644 --- a/testdata/dump/sakila/pgschema.sql +++ b/testdata/dump/sakila/pgschema.sql @@ -3,7 +3,7 @@ -- -- Dumped from database version PostgreSQL 17.5 --- Dumped by pgschema version 1.5.0 +-- Dumped by pgschema version 1.5.1 -- @@ -139,7 +139,7 @@ CREATE TABLE IF NOT EXISTS film ( rental_rate numeric(4,2) DEFAULT 4.99 NOT NULL, length smallint, replacement_cost numeric(5,2) DEFAULT 19.99 NOT NULL, - rating mpaa_rating DEFAULT 'G', + rating mpaa_rating DEFAULT 'G'::mpaa_rating, last_update timestamptz DEFAULT now() NOT NULL, special_features text[], fulltext tsvector NOT NULL, diff --git a/testdata/dump/tenant/pgschema.sql b/testdata/dump/tenant/pgschema.sql index 9f3ede3e..149fd428 100644 --- a/testdata/dump/tenant/pgschema.sql +++ b/testdata/dump/tenant/pgschema.sql @@ -3,7 +3,7 @@ -- -- Dumped from database version PostgreSQL 17.5 --- Dumped by pgschema version 1.5.0 +-- Dumped by pgschema version 1.5.1 -- @@ -64,8 +64,8 @@ CREATE TABLE IF NOT EXISTS users ( website varchar(255), user_code text DEFAULT util.generate_id(), domain text GENERATED ALWAYS AS (util.extract_domain((website)::text)) STORED, - role user_role DEFAULT 'user', - status status DEFAULT 'active', + role user_role DEFAULT 'user'::user_role, + status status DEFAULT 'active'::status, created_at timestamp DEFAULT now(), CONSTRAINT users_pkey PRIMARY KEY (id) ); @@ -85,7 +85,7 @@ CREATE TABLE IF NOT EXISTS posts ( title varchar(200) NOT NULL, content text, author_id integer, - status status DEFAULT 'active', + status status DEFAULT 'active'::status, created_at timestamp DEFAULT now(), CONSTRAINT posts_pkey PRIMARY KEY (id), CONSTRAINT posts_author_id_fkey FOREIGN KEY (author_id) REFERENCES users (id)