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
77 changes: 5 additions & 72 deletions pgpm/core/src/migrate/sql/procedures.sql
Original file line number Diff line number Diff line change
Expand Up @@ -53,17 +53,6 @@ CREATE PROCEDURE pgpm_migrate.deploy(
LANGUAGE plpgsql AS $$
DECLARE
v_change_id TEXT;
-- Error diagnostic variables
v_sqlstate TEXT;
v_message TEXT;
v_detail TEXT;
v_hint TEXT;
v_context TEXT;
v_schema_name TEXT;
v_table_name TEXT;
v_column_name TEXT;
v_constraint_name TEXT;
v_datatype_name TEXT;
BEGIN
-- Ensure package exists
CALL pgpm_migrate.register_package(p_package);
Expand Down Expand Up @@ -108,30 +97,8 @@ BEGIN
BEGIN
EXECUTE p_deploy_sql;
EXCEPTION WHEN OTHERS THEN
-- Capture all error diagnostics to preserve them in the re-raised exception
GET STACKED DIAGNOSTICS
v_sqlstate = RETURNED_SQLSTATE,
v_message = MESSAGE_TEXT,
v_detail = PG_EXCEPTION_DETAIL,
v_hint = PG_EXCEPTION_HINT,
v_context = PG_EXCEPTION_CONTEXT,
v_schema_name = SCHEMA_NAME,
v_table_name = TABLE_NAME,
v_column_name = COLUMN_NAME,
v_constraint_name = CONSTRAINT_NAME,
v_datatype_name = PG_DATATYPE_NAME;

-- Re-raise with all captured diagnostics preserved
RAISE EXCEPTION USING
ERRCODE = v_sqlstate,
MESSAGE = v_message,
DETAIL = v_detail,
HINT = v_hint,
SCHEMA = v_schema_name,
TABLE = v_table_name,
COLUMN = v_column_name,
CONSTRAINT = v_constraint_name,
DATATYPE = v_datatype_name;
-- Re-raise the original exception to preserve full context including SQL statement
RAISE;
END;
END IF;

Expand All @@ -158,18 +125,6 @@ CREATE PROCEDURE pgpm_migrate.revert(
p_revert_sql TEXT
)
LANGUAGE plpgsql AS $$
DECLARE
-- Error diagnostic variables
v_sqlstate TEXT;
v_message TEXT;
v_detail TEXT;
v_hint TEXT;
v_context TEXT;
v_schema_name TEXT;
v_table_name TEXT;
v_column_name TEXT;
v_constraint_name TEXT;
v_datatype_name TEXT;
BEGIN
-- Check if deployed
IF NOT pgpm_migrate.is_deployed(p_package, p_change_name) THEN
Expand Down Expand Up @@ -211,34 +166,12 @@ BEGIN
END;
END IF;

-- Execute revert with error diagnostics preservation
-- Execute revert
BEGIN
EXECUTE p_revert_sql;
EXCEPTION WHEN OTHERS THEN
-- Capture all error diagnostics to preserve them in the re-raised exception
GET STACKED DIAGNOSTICS
v_sqlstate = RETURNED_SQLSTATE,
v_message = MESSAGE_TEXT,
v_detail = PG_EXCEPTION_DETAIL,
v_hint = PG_EXCEPTION_HINT,
v_context = PG_EXCEPTION_CONTEXT,
v_schema_name = SCHEMA_NAME,
v_table_name = TABLE_NAME,
v_column_name = COLUMN_NAME,
v_constraint_name = CONSTRAINT_NAME,
v_datatype_name = PG_DATATYPE_NAME;

-- Re-raise with all captured diagnostics preserved
RAISE EXCEPTION USING
ERRCODE = v_sqlstate,
MESSAGE = v_message,
DETAIL = v_detail,
HINT = v_hint,
SCHEMA = v_schema_name,
TABLE = v_table_name,
COLUMN = v_column_name,
CONSTRAINT = v_constraint_name,
DATATYPE = v_datatype_name;
-- Re-raise the original exception to preserve full context including SQL statement
RAISE;
END;

-- Remove from deployed
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,17 @@ PL/pgSQL function pgpm_migrate.deploy(text,text,text,text[],text,boolean) line 4
}
`;

exports[`PGPM Migration Error Messages Constraint Violation in Migration snapshot: constraint violation in migration: error message 1`] = `"duplicate key value violates unique constraint "test_snapshot_products_sku_key""`;
exports[`PGPM Migration Error Messages Constraint Violation in Migration snapshot: constraint violation in migration: error message 1`] = `
"duplicate key value violates unique constraint "test_snapshot_products_sku_key"
Detail: Key (sku)=(PROD-001) already exists.
Where: SQL statement "
INSERT INTO test_snapshot_products (sku) VALUES ('PROD-001');
"
PL/pgSQL function pgpm_migrate.deploy(text,text,text,text[],text,boolean) line 46 at EXECUTE
Schema: public
Table: test_snapshot_products
Constraint: test_snapshot_products_sku_key"
`;

exports[`PGPM Migration Error Messages JSON Type Mismatch in Migration snapshot: JSON type mismatch error in migration: error fields 1`] = `
{
Expand All @@ -36,7 +46,16 @@ PL/pgSQL function pgpm_migrate.deploy(text,text,text,text[],text,boolean) line 4
}
`;

exports[`PGPM Migration Error Messages JSON Type Mismatch in Migration snapshot: JSON type mismatch error in migration: error message 1`] = `"invalid input syntax for type json"`;
exports[`PGPM Migration Error Messages JSON Type Mismatch in Migration snapshot: JSON type mismatch error in migration: error message 1`] = `
"invalid input syntax for type json
Detail: Token "not_valid_json" is invalid.
Where: JSON data, line 1: not_valid_json
PL/pgSQL function pgpm_migrate.deploy(text,text,text,text[],text,boolean) line 46 at EXECUTE
Internal Query:
INSERT INTO test_migration_config (name, settings) VALUES ('test', 'not_valid_json');

Internal Position: 69"
`;

exports[`PGPM Migration Error Messages Nested EXECUTE Migration Errors snapshot: nested EXECUTE migration error: error fields 1`] = `
{
Expand All @@ -60,4 +79,17 @@ PL/pgSQL function pgpm_migrate.deploy(text,text,text,text[],text,boolean) line 4
}
`;

exports[`PGPM Migration Error Messages Nested EXECUTE Migration Errors snapshot: nested EXECUTE migration error: error message 1`] = `"relation "nonexistent_migration_table_xyz" does not exist"`;
exports[`PGPM Migration Error Messages Nested EXECUTE Migration Errors snapshot: nested EXECUTE migration error: error message 1`] = `
"relation "nonexistent_migration_table_xyz" does not exist
Where: PL/pgSQL function inline_code_block line 3 at EXECUTE
SQL statement "
DO $$
BEGIN
EXECUTE 'INSERT INTO nonexistent_migration_table_xyz (col) VALUES (1)';
END;
$$;
"
PL/pgSQL function pgpm_migrate.deploy(text,text,text,text[],text,boolean) line 46 at EXECUTE
Internal Query: INSERT INTO nonexistent_migration_table_xyz (col) VALUES (1)
Internal Position: 13"
`;
2 changes: 1 addition & 1 deletion postgres/pgsql-test/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ export * from './connect';
export * from './manager';
export * from './seed';
export * from './test-client';
export { snapshot } from './utils';
export { snapshot, getErrorCode } from './utils';
21 changes: 20 additions & 1 deletion postgres/pgsql-test/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,26 @@ export {
type PgErrorContext
};

const uuidRegexp = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
/**
* Extract the error code from an error message.
*
* Enhanced error messages from PgTestClient include additional context on subsequent lines
* (Where, Query, Values, etc.). This function returns only the first line, which contains
* the actual error code raised by PostgreSQL.
*
* @param message - The error message (may contain multiple lines with debug context)
* @returns The first line of the error message (the error code)
*
* @example
* // Error message with enhanced context:
* // "NONEXISTENT_TYPE\nWhere: PL/pgSQL function...\nQuery: INSERT INTO..."
* getErrorCode(err.message) // => "NONEXISTENT_TYPE"
*/
export function getErrorCode(message: string): string {
return message.split('\n')[0];
}

const uuidRegexp= /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;

// ID hash map for tracking ID relationships in snapshots
// Values can be numbers (e.g., 1 -> [ID-1]) or strings (e.g., 'user2' -> [ID-user2])
Expand Down