Hi there!

I followed the discussion about the schema resolution, and I really think there is need for an early bound (at function definition time) version of CURRENT_SCHEMA (the first member of search_path)

Avoiding hard-coding of schema names, (and avoiding polluting the actual users schema) is hard.

My current code generates some plpgsql functions, which need some helper functions to construct fcolumn lists, query fragments, etc.

These helpers should live in the same schema, IMHO


It is not impossible: I ended up with the following kludge to refer to functions in the same schema as the calling function.

It involves an extra layer of dynamic SQL, which self-destructs after use. It is not pretty, but it works.

Example of such a nested dynamic function is attached. (the helper functions are not included, but they live in the same "compilation unit")

Cheers,

Adriaan van Kessel
        -- -------------------------------------------------
CREATE OR REPLACE FUNCTION disposable_factory ()
RETURNS text
VOLATILE
LANGUAGE plpgsql
AS
$WTF$
DECLARE
 _fmt text;
 _sql text;
BEGIN

_fmt = $FMT$
        -- "Factory function"
        -- Create a table-returning function for table "_fqn"
        -- with the same columns.
        -- But: restricted to the most recent, upto (and including)  asof_date.
        -- The function name is the table name, with '_asof' appended,
        -- and it is created in the same schema as the table.
        -- The generated function takes one argument _datum
        -- , with the same type as tbl.asof_date
        -- --------------------------------------------------------------------
CREATE OR REPLACE FUNCTION create_asof (_fqn text, asof_date text )
RETURNS text
VOLATILE
SECURITY INVOKER
LANGUAGE plpgsql
AS
$func$
DECLARE sql text;
        basepair text[];
        funcpair text[];
        fnc_name text;
        org_name text;
        allkeys text[];
        keys text[];
BEGIN

basepair := %1$s.split_name (_fqn);

funcpair[1] = basepair[1];
funcpair[2] = concat(basepair[2] , '_asof' );

org_name := %1$s.format_pair(basepair);
fnc_name := %1$s.format_pair(funcpair);

allkeys := %1$s.fetch_pk_array (basepair[1] , basepair[2] , asof_date );
keys := array_remove (allkeys, asof_date);

-- RAISE NOTICE 'Allkeys=%%' , all_keys[1];
-- RAISE NOTICE 'Keys=%%' , keys[1];

-- CREATE OR REPLACE FUNCTION %%1$s (IN _datum DATE DEFAULT now() ) -- name
sql := format ('
CREATE OR REPLACE FUNCTION %%1$s (IN _datum %%2$s DEFAULT now() ) -- fnc_name 
dtype
RETURNS SETOF %%3$s     -- orgtable
STABLE SECURITY INVOKER ROWS 300000
LANGUAGE sql
AS
$omg$
SELECT *                -- all columns
FROM %%3$s src          -- org table
WHERE %%4$s             -- date treshold
AND NOT EXISTS (
        SELECT * 
        FROM %%3$s nx   -- org table
        WHERE %%5$s     -- key fields
        AND %%6$s       -- date treshold
        AND %%7$s       -- gap
        )
        ;
$omg$ 
        ;'
        , fnc_name                                              -- 1 Function 
name
        , %1$s.fetch_typename(basepair[1], basepair[2], asof_date)              
-- 2 typeof Date field argument
        , org_name                                              -- 3 table name
        , %1$s.format_reference ('src', asof_date) || ' <= $1'  -- 4 source 
Date treshold
        , %1$s.format_equal_and_list ('nx', 'src', keys)                -- 5 
Same Keys
        , %1$s.format_reference ('nx', asof_date) || ' <= $1'   -- 6 nx Date 
treshold
        , %1$s.format_reference ('nx', asof_date) || ' > ' || 
%1$s.format_reference( 'src', asof_date)  -- 7 Gap Date
        );

-- RAISE NOTICE 'Pair= [%%,%%]' , basepair[1], basepair[2];
-- RAISE NOTICE 'Fnc=%%' , fnc_name;
-- RAISE NOTICE 'Sql=%%' , sql;
EXECUTE sql;
-- RETURN sql ;
RETURN fnc_name ;
END;
$func$;
$FMT$ ;

-- RAISE NOTICE '_Fmt=%' , _fmt;
_sql = format (_fmt, quote_ident(current_schema) );
-- RAISE NOTICE '_Sql=%', _sql;

EXECUTE _sql;
DROP FUNCTION disposable_factory (); -- suicide
-- return _sql;
return 'create_asof';
END;
$WTF$ ;

\echo SELECT disposable_factory();
SELECT disposable_factory();
-- \df create_asof

-- EOF

Reply via email to