I've got some code like this, using an extension :
DO $$
BEGIN
-- If table is versioned, use table_version API to add column
IF EXISTS (
SELECT 1
FROM pg_catalog.pg_proc
JOIN pg_catalog.pg_namespace ON pg_namespace.oid = pg_proc.pronamespace
WHERE pg_proc.proname = 'ver_is_table_versioned'
AND pg_namespace.nspname = 'table_version'
) THEN
IF table_version.ver_is_table_versioned('my_schema', 'my_table') THEN
PERFORM table_version.ver_versioned_table_add_column(
'my_schema',
'my_table',
'my_column',
'CHAR(1)'
);
RETURN;
ELSE
ALTER TABLE my_schema.my_table ADD COLUMN my_column CHAR(1);
END IF;
END IF;
-- Otherwise ALTER TABLE directly
ALTER TABLE my_schema.my_table ADD COLUMN my_column CHAR(1);
END;
$$
How can I avoid duplicating the ALTER TABLE
statement? I can't use IF EXISTS(…) AND table_version.ver_is_table_versioned(…)
, because that is eagerly evaluated, and results in a
schema "table_version" does not exist
error if the extension is not installed.
Postgres execute function if exists does not answer my question.
Throwing a custom exception when table_version.ver_is_table_versioned(…)
is false and catching both that and undefined_function
to run the fallback code is a possibility, but pretty horrible in terms of complexity.
Drop the ALTER TABLE
inside of the condition block and let the final statement execute unconditionally unless the versioning exists.
DO $$
BEGIN
-- If table is versioned, use table_version API to add column
IF EXISTS (
SELECT 1
FROM pg_catalog.pg_proc
JOIN pg_catalog.pg_namespace ON pg_namespace.oid = pg_proc.pronamespace
WHERE pg_proc.proname = 'ver_is_table_versioned'
AND pg_namespace.nspname = 'table_version'
) THEN
IF table_version.ver_is_table_versioned('my_schema', 'my_table') THEN
PERFORM table_version.ver_versioned_table_add_column(
'my_schema',
'my_table',
'my_column',
'CHAR(1)'
);
RETURN;
END IF;
END IF;
-- Otherwise ALTER TABLE directly
ALTER TABLE my_schema.my_table ADD COLUMN my_column CHAR(1);
END;
$$