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
7 changes: 7 additions & 0 deletions HISTORY.asc
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
STABLE
------
=== Adopt the `stable` pseudo-version between releases

=== Add `0.2.0--0.2.1` update script
`ALTER EXTENSION trunklet UPDATE` now works from 0.2.0. Previously there was no update path from 0.2.0.

0.3.3
-----
=== Add `ignore_missing_functions` agument to `template_language__remove()`
Expand Down
278 changes: 278 additions & 0 deletions sql/trunklet--0.2.0--0.2.1.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
/*
* Using temp objects will result in the extension being dropped after session
* end. Create a real schema and then explicitly drop it instead.
*/
CREATE SCHEMA __trunklet;

CREATE TABLE __trunklet.old_settings AS
SELECT name, setting
FROM pg_catalog.pg_settings
WHERE name IN ('client_min_messages', 'search_path')
;
SET client_min_messages = warning;
SET search_path = pg_catalog;

CREATE OR REPLACE FUNCTION _trunklet.template__get(
template_id _trunklet.template.template_id%TYPE
, loose boolean DEFAULT false
) RETURNS _trunklet.template LANGUAGE plpgsql AS $body$
DECLARE
r _trunklet.template;
BEGIN
SELECT * INTO STRICT r
FROM _trunklet.template t
WHERE t.template_id = template__get.template_id
;

RETURN r;
EXCEPTION
WHEN no_data_found THEN
IF loose THEN
RETURN NULL;
ELSE
RAISE EXCEPTION 'template not found'
USING ERRCODE = 'no_data_found'
, DETAIL = format( 'template id %s', template_id )
;
END IF;
END
$body$;
REVOKE ALL ON FUNCTION _trunklet.template__get(
template_id _trunklet.template.template_id%TYPE
, loose boolean
) FROM public;

CREATE OR REPLACE FUNCTION trunklet.process_language(
language_name _trunklet.language.language_name%TYPE
, template text
, parameters anyelement
) RETURNS text LANGUAGE plpgsql

-- !!!!!!!
SECURITY DEFINER SET search_path = pg_catalog
-- !!!!!!!

AS $body$
DECLARE
/*
* !!!!! SECURITY DEFINER !!!!!
*/

r_language _trunklet.language;
sql text;
v_return text;
BEGIN
-- Can't do this during DECLARE (0A000: default value for row or record variable is not supported)
r_language := _trunklet.language__get( language_name );

/*
* !!!!! SECURITY DEFINER !!!!!
*/
PERFORM _trunklet.verify_type( language_name, r_language.template_type, pg_catalog.pg_typeof(template), 'template' );
PERFORM _trunklet.verify_type( language_name, r_language.parameter_type, pg_catalog.pg_typeof(parameters), 'parameter' );

sql := format(
'SELECT _trunklet_functions.%s( CAST($1 AS %s), CAST($2 AS %s) )'
, _trunklet.function_name( r_language.language_id, 'process' )
, r_language.template_type
, r_language.parameter_type
);
RAISE DEBUG E'execute %\nUSING %, %', sql, template, parameters;
EXECUTE sql INTO STRICT v_return USING template, parameters;
RAISE DEBUG '% returned %', sql, v_return;

RETURN v_return;
END
$body$;

CREATE OR REPLACE FUNCTION trunklet.process(
template_id _trunklet.template.template_id%TYPE
, parameters anyelement
) RETURNS text LANGUAGE SQL
-- !!!
SECURITY DEFINER SET search_path = pg_catalog
-- !!!
AS $body$
SELECT trunklet.process_language(
-- language_id comes from template__get() below
(_trunklet.language__get(language_id)).language_name
, template
, parameters
)
FROM _trunklet.template__get( template_id )
$body$;
CREATE OR REPLACE FUNCTION trunklet.process(
template_name _trunklet.template.template_name%TYPE
, template_version _trunklet.template.template_version%TYPE
, parameters anyelement
) RETURNS text LANGUAGE SQL
-- !!!
SECURITY DEFINER SET search_path = pg_catalog
-- !!!
AS $body$
SELECT trunklet.process_language(
-- language_id comes from template__get() below
(_trunklet.language__get(language_id)).language_name
, template
, parameters
)
FROM _trunklet.template__get( template_name, template_version )
$body$;
CREATE OR REPLACE FUNCTION trunklet.process(
template_name _trunklet.template.template_name%TYPE
, parameters anyelement
) RETURNS text LANGUAGE SQL AS $body$
SELECT trunklet.process( template_name, 1, parameters )
$body$;


/*
* trunklet.execute_into()
*/
CREATE OR REPLACE FUNCTION trunklet.execute_into__language(
language_name _trunklet.language.language_name%TYPE
, template text
, parameters anyelement
) RETURNS anyelement LANGUAGE plpgsql AS $body$
DECLARE
sql CONSTANT text := trunklet.process_language(language_name, template, parameters);

r record;
BEGIN
-- Define the structure of r
EXECUTE format('SELECT NULL::%s AS out', pg_typeof(parameters)) INTO STRICT r;

RAISE DEBUG E'execute %', sql;
EXECUTE sql INTO STRICT r.out;
RAISE DEBUG '% returned %', sql, r.out;

RETURN r.out;
END
$body$;
CREATE OR REPLACE FUNCTION trunklet.execute_into(
template_id _trunklet.template.template_id%TYPE
, parameters anyelement
) RETURNS anyelement LANGUAGE plpgsql AS $body$
DECLARE
sql CONSTANT text := trunklet.process(template_id, parameters);

r record;
BEGIN
-- Define the structure of r
EXECUTE format('SELECT NULL::%s AS out', pg_typeof(parameters)) INTO STRICT r;

RAISE DEBUG E'execute %', sql;
EXECUTE sql INTO STRICT r.out;
RAISE DEBUG '% returned %', sql, r.out;

RETURN r.out;
END
$body$;
CREATE OR REPLACE FUNCTION trunklet.execute_into(
template_name _trunklet.template.template_name%TYPE
, template_version _trunklet.template.template_version%TYPE
, parameters anyelement
) RETURNS anyelement LANGUAGE plpgsql AS $body$
DECLARE
sql CONSTANT text := trunklet.process(template_name, template_version, parameters);

r record;
BEGIN
-- Define the structure of r
EXECUTE format('SELECT NULL::%s AS out', pg_typeof(parameters)) INTO STRICT r;

RAISE DEBUG E'execute %', sql;
EXECUTE sql INTO STRICT r.out;
RAISE DEBUG '% returned %', sql, r.out;

RETURN r.out;
END
$body$;
CREATE OR REPLACE FUNCTION trunklet.execute_into(
template_name _trunklet.template.template_name%TYPE
, parameters anyelement
) RETURNS anyelement LANGUAGE SQL AS $body$
SELECT trunklet.execute_into( template_name, 1, parameters )
$body$;





/*
* trunklet.execute_text()
*/
CREATE OR REPLACE FUNCTION trunklet.execute_text__language(
language_name _trunklet.language.language_name%TYPE
, template text
, parameters anyelement
) RETURNS text LANGUAGE plpgsql AS $body$
DECLARE
sql CONSTANT text := trunklet.process_language(language_name, template, parameters);

out text;
BEGIN
RAISE DEBUG E'execute %', sql;
EXECUTE sql INTO STRICT out;
RAISE DEBUG '% returned %', sql, out;

RETURN out;
END
$body$;
CREATE OR REPLACE FUNCTION trunklet.execute_text(
template_id _trunklet.template.template_id%TYPE
, parameters anyelement
) RETURNS anyelement LANGUAGE plpgsql AS $body$
DECLARE
sql CONSTANT text := trunklet.process(template_id, parameters);

out text;
BEGIN
RAISE DEBUG E'execute %', sql;
EXECUTE sql INTO STRICT out;
RAISE DEBUG '% returned %', sql, out;

RETURN out;
END
$body$;
CREATE OR REPLACE FUNCTION trunklet.execute_text(
template_name _trunklet.template.template_name%TYPE
, template_version _trunklet.template.template_version%TYPE
, parameters anyelement
) RETURNS anyelement LANGUAGE plpgsql AS $body$
DECLARE
sql CONSTANT text := trunklet.process(template_name, template_version, parameters);

out text;
BEGIN
RAISE DEBUG E'execute %', sql;
EXECUTE sql INTO STRICT out;
RAISE DEBUG '% returned %', sql, out;

RETURN out;
END
$body$;
CREATE OR REPLACE FUNCTION trunklet.execute_text(
template_name _trunklet.template.template_name%TYPE
, parameters anyelement
) RETURNS anyelement LANGUAGE SQL AS $body$
SELECT trunklet.execute_text( template_name, 1, parameters )
$body$;





SELECT _trunklet.exec(
format(
'SET %I = %L'
, name
, setting
)
)
FROM __trunklet.old_settings
;
DROP TABLE __trunklet.old_settings;
DROP SCHEMA __trunklet;

-- vi: expandtab sw=2 ts=2
Loading
Loading