CREATE TYPE error_data AS( sqlstate text , message text , hint text , detail text , context text , schema_name text , table_name text , column_name text , constraint_name text , type_name text ); CREATE FUNCTION error_data( sqlstate text = '' , message text = '' , hint text = '' , detail text = '' , context text = '' , schema_name text = '' , table_name text = '' , column_name text = '' , constraint_name text = '' , type_name text = '' ) RETURNS error_data LANGUAGE sql IMMUTABLE SET search_path FROM CURRENT AS $$ SELECT row( sqlstate , message , hint , detail , context , schema_name , table_name , column_name , constraint_name , type_name )::error_data $$; -- Note that context is intentionally ommitted CREATE OR REPLACE FUNCTION raise( message text , level text = 'EXCEPTION' , sqlstate text = NULL , hint text = NULL , detail text = NULL , schema_name text = NULL , table_name text = NULL , column_name text = NULL , constraint_name text = NULL , type_name text = NULL ) RETURNS void LANGUAGE plpgsql AS $body$ DECLARE sql text; conds text[]; BEGIN sql = $sql$CREATE OR REPLACE FUNCTION pg_temp.raise_error_internal() RETURNS void LANGUAGE plpgsql AS $raise_function$ BEGIN RAISE $sql$ || level; IF sqlstate IS NOT NULL THEN sql := sql || format(' SQLSTATE %L', sqlstate); END IF; IF nullif(message, '') IS NOT NULL THEN conds := conds || array[format('MESSAGE = %L', message)]; END IF; IF nullif(hint, '') IS NOT NULL THEN conds := conds || array[format('HINT = %L', hint)]; END IF; IF nullif(detail, '') IS NOT NULL THEN conds := conds || array[format('DETAIL = %L', detail)]; END IF; IF nullif(schema_name, '') IS NOT NULL THEN conds := conds || array[format('SCHEMA = %L', schema_name)]; END IF; IF nullif(table_name, '') IS NOT NULL THEN conds := conds || array[format('TABLE = %L', table_name)]; END IF; IF nullif(column_name, '') IS NOT NULL THEN conds := conds || array[format('COLUMN = %L', column_name)]; END IF; IF nullif(constraint_name, '') IS NOT NULL THEN conds := conds || array[format('CONSTRAINT = %L', constraint_name)]; END IF; IF nullif(type_name, '') IS NOT NULL THEN conds := conds || array[format('DATATYPE = %L', type_name)]; END IF; IF conds IS NOT NULL THEN sql := sql || E'\n USING\n' || array_to_string(conds, E'\n , '); END IF; sql := sql || $$ ; END$raise_function$;$$; EXECUTE sql; -- Wrap the call in a handler to remove the temp function from the context stack BEGIN PERFORM pg_temp.raise_error_internal(); EXCEPTION WHEN OTHERS OR QUERY_CANCELED -- GE95: OR ASSERT_FAILURE THEN RAISE; END; END $body$; CREATE OR REPLACE FUNCTION raise( error error_data , level text = 'EXCEPTION' ) RETURNS void LANGUAGE sql SET search_path FROM CURRENT AS $$ SELECT raise( error.message , level , error.sqlstate , error.hint , error.detail , error.schema_name , error.table_name , error.column_name , error.constraint_name , error.type_name ); $$; CREATE OR REPLACE FUNCTION try( code text , OUT row_count int , OUT error error_data ) RETURNS record LANGUAGE plpgsql AS $body$ BEGIN EXECUTE code; -- NOTE: FOUND dosent' work with EXECUTE GET DIAGNOSTICS try.row_count = ROW_COUNT; EXCEPTION WHEN OTHERS THEN GET STACKED DIAGNOSTICS error.sqlstate = RETURNED_SQLSTATE , error.message = MESSAGE_TEXT , error.detail = PG_EXCEPTION_DETAIL , error.hint = PG_EXCEPTION_HINT , error.context = PG_EXCEPTION_CONTEXT , error.column_name = COLUMN_NAME , error.constraint_name = CONSTRAINT_NAME , error.type_name = PG_DATATYPE_NAME , error.table_name = TABLE_NAME , error.schema_name = SCHEMA_NAME ; END $body$; CREATE OR REPLACE FUNCTION try_cursor( query text , cursor_name text DEFAULT NULL , OUT result refcursor , OUT error error_data ) RETURNS record LANGUAGE plpgsql AS $body$ BEGIN IF cursor_name IS NOT NULL THEN result := cursor_name; END IF; OPEN result FOR EXECUTE query; EXCEPTION WHEN OTHERS THEN GET STACKED DIAGNOSTICS error.sqlstate = RETURNED_SQLSTATE , error.message = MESSAGE_TEXT , error.detail = PG_EXCEPTION_DETAIL , error.hint = PG_EXCEPTION_HINT , error.context = PG_EXCEPTION_CONTEXT , error.column_name = COLUMN_NAME , error.constraint_name = CONSTRAINT_NAME , error.type_name = PG_DATATYPE_NAME , error.table_name = TABLE_NAME , error.schema_name = SCHEMA_NAME ; END $body$; CREATE OR REPLACE FUNCTION try_into( code text , INOUT result anyelement , strict boolean DEFAULT false , OUT error error_data ) RETURNS record LANGUAGE plpgsql AS $body$ BEGIN IF strict IS TRUE THEN EXECUTE code INTO STRICT result; ELSE EXECUTE code INTO result; END IF; EXCEPTION WHEN OTHERS THEN GET STACKED DIAGNOSTICS error.sqlstate = RETURNED_SQLSTATE , error.message = MESSAGE_TEXT , error.detail = PG_EXCEPTION_DETAIL , error.hint = PG_EXCEPTION_HINT , error.context = PG_EXCEPTION_CONTEXT , error.column_name = COLUMN_NAME , error.constraint_name = CONSTRAINT_NAME , error.type_name = PG_DATATYPE_NAME , error.table_name = TABLE_NAME , error.schema_name = SCHEMA_NAME ; END $body$; -- vi: expandtab ts=2 sw=2