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
47 changes: 44 additions & 3 deletions ir/inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -915,7 +915,7 @@ func (i *Inspector) buildFunctions(ctx context.Context, schema *IR, targetSchema

// Parse parameters from the complete signature provided by pg_get_function_arguments()
// This signature includes all parameter information including modes, names, types, and defaults
parameters := i.parseParametersFromSignature(signature)
parameters := i.parseParametersFromSignature(signature, schemaName)

function := &Function{
Schema: schemaName,
Expand Down Expand Up @@ -1006,7 +1006,7 @@ func splitParameterString(signature string) []string {
// parseParametersFromSignature parses function signature string into Parameter structs
// Example signature: "order_id integer, discount_percent numeric DEFAULT 0"
// Or with modes: "IN order_id integer, OUT result integer"
func (i *Inspector) parseParametersFromSignature(signature string) []*Parameter {
func (i *Inspector) parseParametersFromSignature(signature string, routineSchema string) []*Parameter {
if signature == "" {
return nil
}
Expand Down Expand Up @@ -1060,13 +1060,54 @@ func (i *Inspector) parseParametersFromSignature(signature string) []*Parameter
param.DataType = remainingParts[0]
}

// Normalize type by stripping schema prefix if it matches the routine's schema
// This ensures consistent comparison between database and source SQL representations
param.DataType = i.stripSameSchemaPrefix(param.DataType, routineSchema)

parameters = append(parameters, param)
position++
}

return parameters
}

// stripSameSchemaPrefix removes schema qualification from a type name if the schema
// matches the routine's schema. This normalizes PostgreSQL's behavior of returning
// schema-qualified type names (e.g., "public.order_status") to unqualified names
// (e.g., "order_status") when the type is in the same schema as the function/procedure.
//
// Cross-schema type references are preserved (e.g., "utils.priority_level" stays qualified
// when the function is in the "public" schema).
//
// This ensures consistent comparison between database inspection (which may return qualified
// names) and source SQL (which typically uses unqualified names for same-schema types).
func (i *Inspector) stripSameSchemaPrefix(typeName, routineSchema string) string {
if typeName == "" || routineSchema == "" {
return typeName
}

// Remove quotes from schema name for comparison
unquotedSchema := routineSchema
if strings.HasPrefix(routineSchema, `"`) && strings.HasSuffix(routineSchema, `"`) {
unquotedSchema = routineSchema[1 : len(routineSchema)-1]
}

// Handle quoted schema prefix: "schema".typename
quotedPrefix := fmt.Sprintf(`"%s".`, unquotedSchema)
if strings.HasPrefix(typeName, quotedPrefix) {
return typeName[len(quotedPrefix):]
}

// Handle unquoted schema prefix: schema.typename
unquotedPrefix := unquotedSchema + "."
if strings.HasPrefix(typeName, unquotedPrefix) {
return typeName[len(unquotedPrefix):]
}

// No matching prefix - return as-is (could be cross-schema type or already unqualified)
return typeName
}

// lookupTypeNameFromOID converts PostgreSQL type OID to type name
func (i *Inspector) lookupTypeNameFromOID(oid int64) string {
// Common type OID mappings (can be extended as needed)
Expand Down Expand Up @@ -1119,7 +1160,7 @@ func (i *Inspector) buildProcedures(ctx context.Context, schema *IR, targetSchem
dbSchema := schema.getOrCreateSchema(schemaName)

// Parse parameters from signature (same approach as functions)
parameters := i.parseParametersFromSignature(signature)
parameters := i.parseParametersFromSignature(signature, schemaName)

procedure := &Procedure{
Schema: schemaName,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
CREATE OR REPLACE FUNCTION process_order(
order_id integer,
discount_percent numeric DEFAULT 0
discount_percent numeric DEFAULT 0,
status order_status DEFAULT 'pending',
priority utils.priority_level DEFAULT 'medium'
)
RETURNS numeric
LANGUAGE plpgsql
Expand All @@ -12,6 +14,7 @@ DECLARE
tax_rate numeric := 0.08;
BEGIN
-- Different logic: calculate with tax instead of just discount
-- Status and priority parameters are available but not used in this simplified version
SELECT price INTO base_price FROM products WHERE id = order_id;
RETURN base_price * (1 - discount_percent / 100) * (1 + tax_rate);
END;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
CREATE TYPE order_status AS ENUM ('pending', 'processing', 'completed', 'cancelled');

CREATE FUNCTION process_order(
order_id integer,
discount_percent numeric DEFAULT 0
discount_percent numeric DEFAULT 0,
status order_status DEFAULT 'pending',
priority utils.priority_level DEFAULT 'medium'
)
RETURNS numeric
LANGUAGE plpgsql
Expand All @@ -12,6 +16,7 @@ DECLARE
tax_rate numeric := 0.08;
BEGIN
-- Different logic: calculate with tax instead of just discount
-- Status and priority parameters are available but not used in this simplified version
SELECT price INTO base_price FROM products WHERE id = order_id;
RETURN base_price * (1 - discount_percent / 100) * (1 + tax_rate);
END;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
CREATE TYPE order_status AS ENUM ('pending', 'processing', 'completed', 'cancelled');

CREATE FUNCTION process_order(
order_id integer,
discount_percent numeric DEFAULT 0
discount_percent numeric DEFAULT 0,
status order_status DEFAULT 'pending',
priority utils.priority_level DEFAULT 'medium'
)
RETURNS numeric
LANGUAGE plpgsql
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
{
"version": "1.0.0",
"pgschema_version": "1.4.0",
"pgschema_version": "1.4.1",
"created_at": "1970-01-01T00:00:00Z",
"source_fingerprint": {
"hash": "60f55cc9364a4c46fec3d3c3b819f5507eea75c2667985f2a9c1a2954f786e4e"
"hash": "6d0c7bd072cf940b17ecae1b64566b63a06bd9cd0aaf2c69a12af2fe77ae6d47"
},
"groups": [
{
"steps": [
{
"sql": "CREATE OR REPLACE FUNCTION process_order(\n order_id integer,\n discount_percent numeric DEFAULT 0\n)\nRETURNS numeric\nLANGUAGE plpgsql\nSECURITY INVOKER\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 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',\n priority utils.priority_level DEFAULT 'medium'\n)\nRETURNS numeric\nLANGUAGE plpgsql\nSECURITY INVOKER\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"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
CREATE OR REPLACE FUNCTION process_order(
order_id integer,
discount_percent numeric DEFAULT 0
discount_percent numeric DEFAULT 0,
status order_status DEFAULT 'pending',
priority utils.priority_level DEFAULT 'medium'
)
RETURNS numeric
LANGUAGE plpgsql
Expand All @@ -12,6 +14,7 @@ DECLARE
tax_rate numeric := 0.08;
BEGIN
-- Different logic: calculate with tax instead of just discount
-- Status and priority parameters are available but not used in this simplified version
SELECT price INTO base_price FROM products WHERE id = order_id;
RETURN base_price * (1 - discount_percent / 100) * (1 + tax_rate);
END;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ DDL to be executed:

CREATE OR REPLACE FUNCTION process_order(
order_id integer,
discount_percent numeric DEFAULT 0
discount_percent numeric DEFAULT 0,
status order_status DEFAULT 'pending',
priority utils.priority_level DEFAULT 'medium'
)
RETURNS numeric
LANGUAGE plpgsql
Expand All @@ -23,6 +25,7 @@ DECLARE
tax_rate numeric := 0.08;
BEGIN
-- Different logic: calculate with tax instead of just discount
-- Status and priority parameters are available but not used in this simplified version
SELECT price INTO base_price FROM products WHERE id = order_id;
RETURN base_price * (1 - discount_percent / 100) * (1 + tax_rate);
END;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
-- Create utils schema with a custom type for cross-schema testing
CREATE SCHEMA IF NOT EXISTS utils;

CREATE TYPE utils.priority_level AS ENUM ('low', 'medium', 'high', 'critical');