Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions cmd/plan/plan.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"fmt"
"os"
"path/filepath"
"regexp"
"strings"

"github.com/pgplex/pgschema/cmd/util"
Expand Down Expand Up @@ -403,6 +404,12 @@ func processOutput(migrationPlan *plan.Plan, output outputSpec, cmd *cobra.Comma
// and fail when applied to the target database.
func normalizeSchemaNames(irData *ir.IR, fromSchema, toSchema string) {
replaceString := newSchemaStringReplacer(fromSchema, toSchema)
// stripQualifiers removes same-schema function/type qualifiers from expressions.
// After replaceString converts temp schema references to toSchema, expressions may
// contain "toSchema.func_name(" or "::toSchema.type" which are redundant same-schema
// qualifiers. The initial normalizeIR (run by the inspector) couldn't strip these
// because it ran with the temp schema name, not the target schema. See issue #283.
stripQualifiers := newSameSchemaQualifierStripper(toSchema)

// Normalize schema names in Schemas map
if schema, exists := irData.Schemas[fromSchema]; exists {
Expand All @@ -425,7 +432,7 @@ func normalizeSchemaNames(irData *ir.IR, fromSchema, toSchema string) {
if constraint.ReferencedSchema == fromSchema {
constraint.ReferencedSchema = toSchema
}
constraint.CheckClause = replaceString(constraint.CheckClause)
constraint.CheckClause = stripQualifiers(replaceString(constraint.CheckClause))
}

// Normalize schema references in table dependencies
Expand All @@ -446,10 +453,10 @@ func normalizeSchemaNames(irData *ir.IR, fromSchema, toSchema string) {
for _, column := range table.Columns {
column.DataType = replaceString(column.DataType)
if column.DefaultValue != nil {
*column.DefaultValue = replaceString(*column.DefaultValue)
*column.DefaultValue = stripQualifiers(replaceString(*column.DefaultValue))
}
if column.GeneratedExpr != nil {
*column.GeneratedExpr = replaceString(*column.GeneratedExpr)
*column.GeneratedExpr = stripQualifiers(replaceString(*column.GeneratedExpr))
}
}

Expand All @@ -467,16 +474,16 @@ func normalizeSchemaNames(irData *ir.IR, fromSchema, toSchema string) {
trigger.Schema = toSchema
}
trigger.Function = replaceString(trigger.Function)
trigger.Condition = replaceString(trigger.Condition)
trigger.Condition = stripQualifiers(replaceString(trigger.Condition))
}

// Normalize schema names in RLS policies
for _, policy := range table.Policies {
if policy.Schema == fromSchema {
policy.Schema = toSchema
}
policy.Using = replaceString(policy.Using)
policy.WithCheck = replaceString(policy.WithCheck)
policy.Using = stripQualifiers(replaceString(policy.Using))
policy.WithCheck = stripQualifiers(replaceString(policy.WithCheck))
}
}

Expand Down Expand Up @@ -627,6 +634,28 @@ func newSchemaStringReplacer(fromSchema, toSchema string) func(string) string {
}
}

// newSameSchemaQualifierStripper creates a function that strips redundant same-schema
// qualifiers from SQL expressions. After normalizeSchemaNames replaces temp schema names
// with the target schema, expressions may contain "schema.func_name(" or "::schema.type"
// where the qualifier matches the object's own schema. These are redundant and must be
// stripped to match how the target database's inspector would produce them. See issue #283.
func newSameSchemaQualifierStripper(schema string) func(string) string {
if schema == "" {
return func(s string) string { return s }
}
prefix := schema + "."
funcPattern := regexp.MustCompile(regexp.QuoteMeta(prefix) + `([a-zA-Z_][a-zA-Z0-9_]*)\(`)
typePattern := regexp.MustCompile(`::` + regexp.QuoteMeta(prefix))
return func(s string) string {
if s == "" || !strings.Contains(s, prefix) {
return s
}
s = funcPattern.ReplaceAllString(s, `${1}(`)
s = typePattern.ReplaceAllString(s, "::")
return s
}
}

// ResetFlags resets all global flag variables to their default values for testing
func ResetFlags() {
planHost = "localhost"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CREATE FUNCTION my_default_id() RETURNS uuid
LANGUAGE sql
AS $$ SELECT gen_random_uuid() $$;

CREATE TABLE items (
id uuid DEFAULT my_default_id() NOT NULL,
name text NOT NULL,
active boolean DEFAULT true NOT NULL,
CONSTRAINT items_pk PRIMARY KEY (id)
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
CREATE FUNCTION my_default_id() RETURNS uuid
LANGUAGE sql
AS $$ SELECT gen_random_uuid() $$;

CREATE TABLE items (
id uuid DEFAULT my_default_id() NOT NULL,
name text NOT NULL,
active boolean DEFAULT true NOT NULL,
CONSTRAINT items_pk PRIMARY KEY (id)
);
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"version": "1.0.0",
"pgschema_version": "1.7.0",
"created_at": "1970-01-01T00:00:00Z",
"source_fingerprint": {
"hash": "0915a8651243d1249ecffcf4938383a65f0a0fb644f189f372e3719f2a46f13f"
},
"groups": null
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
No changes detected.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"version": "1.0.0",
"pgschema_version": "1.6.2",
"pgschema_version": "1.7.0",
"created_at": "1970-01-01T00:00:00Z",
"source_fingerprint": {
"hash": "965b1131737c955e24c7f827c55bd78e4cb49a75adfd04229e0ba297376f5085"
Expand All @@ -21,7 +21,7 @@
"path": "public.calc_priority"
},
{
"sql": "CREATE TABLE IF NOT EXISTS article (\n id integer,\n title text NOT NULL,\n priority integer GENERATED ALWAYS AS (public.calc_priority()) STORED,\n CONSTRAINT article_pkey PRIMARY KEY (id)\n);",
"sql": "CREATE TABLE IF NOT EXISTS article (\n id integer,\n title text NOT NULL,\n priority integer GENERATED ALWAYS AS (calc_priority()) STORED,\n CONSTRAINT article_pkey PRIMARY KEY (id)\n);",
"type": "table",
"operation": "create",
"path": "public.article"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ $$;
CREATE TABLE IF NOT EXISTS article (
id integer,
title text NOT NULL,
priority integer GENERATED ALWAYS AS (public.calc_priority()) STORED,
priority integer GENERATED ALWAYS AS (calc_priority()) STORED,
CONSTRAINT article_pkey PRIMARY KEY (id)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ $$;
CREATE TABLE IF NOT EXISTS article (
id integer,
title text NOT NULL,
priority integer GENERATED ALWAYS AS (public.calc_priority()) STORED,
priority integer GENERATED ALWAYS AS (calc_priority()) STORED,
CONSTRAINT article_pkey PRIMARY KEY (id)
);

Expand Down