I have a PostgreSQL 10 script for which I would like to declare variables once at the beginning and then use them throughout the script (with possible transactions).
I know I can do:
DO $$
DECLARE test float := 0.1 ;
BEGIN
< do whatever here>
END $$
but that makes me declare the variables each time I have a BEGIN / END block.
-
I ended modifying my script and have a long DO-BEGIN-END section. Not what I wanted but it works.Darth Kangooroo– Darth Kangooroo2018εΉ΄08ζ13ζ₯ 09:02:39 +00:00Commented Aug 13, 2018 at 9:02
2 Answers 2
There are no global variables per se in Postgres. But we have "customized options" that can be stretched for the purpose.
SET myvars.test TO '0.1';
Persists for the duration of the session (not just transaction). Use with:
SELECT current_setting('myvars.test')::float;
Be aware that values are stored as text
. So you may need to cast as demonstrated.
To avoid exceptions when referencing an unset variable and get NULL
instead:
SELECT current_setting('myvars.test', true)::float;
See:
There are a number of other workarounds, too:
If your script will be loaded via psql
, you can \set
variable in psql
scripts:
\set myvar myvalue
select :'myvar' as myval;
These variables can also be set when invoking psql
, by using the --variable/-v/--set
option.
It is nowadays also possible to have the customized options mentioned by @erwin-brandstetter persist across database settings. These can be set on the database, role or database+role level:
ALTER DATABASE mydb
SET app.settings.bla = 1::text;
ALTER ROLE myrole
IN DATABASE mydb
SET app.settings.bla = 2::text;
Do note that if you work with database-level settings, these will be set as session defaults when the user connects to that database, but can be overridden for that session (or a transaction).
If you wish to enforce a database se, you can do so by going directly to the pg_db_role_setting
system catalog, as done by this function from my pg_safer_settings
extension (copied here with my explicit permission π):
create function pg_db_setting(pg_setting_name$ text, pg_role$ regrole = 0)
returns text
stable
-- security definer
return (
select
regexp_replace(expanded_settings.raw_setting, E'^[^=]+=', '')
from
pg_catalog.pg_db_role_setting
inner join
pg_catalog.pg_database
on pg_database.oid = pg_db_role_setting.setdatabase
cross join lateral
unnest(pg_db_role_setting.setconfig) as expanded_settings(raw_setting)
where
pg_database.datname = current_database()
and pg_db_role_setting.setrole = coalesce(
pg_role,γγ«
0 -- 0 means "not role-specific"
)
and expanded_settings.raw_setting like pg_setting_name$ || '=%'
limit 1
);
Here's an example to illustrate the difference between the semantics of the pg_catalog.current_setting()
function and my pg_db_role_setting()
function:
CREATE DATABASE mydb;
CONNECT TO mydb
CREATE ROLE myrole;
ALTER DATABASE mydb
SET app.settings.bla = 1::text;
ALTER ROLE myrole
IN DATABASE mydb
SET app.settings.bla = 2::text;
SET ROLE myrole;
SET app.settings.bla TO 3::text;
SELECT current_setting('app.settings.bla', true); -- '3'
SELECT pg_db_role_setting('app.settings.bla'); -- '1'
SELECT pg_db_role_setting('app.settings.bla', current_user); -- '2'