By Digoal
This article reviews PostgreSQL Dynamic Inline Code with examples.
Stored procedures at the database-side provide complex business logic processing. Combined with the ACID feature of the database, placing the logic in the database for processing can improve reliability and reduce the number of interactions on the client.
Such a database performs well in certain scenarios requiring high reliability, consistency in transactions, and long logic, namely, excessive interactions with the database.
However, version control for the stored procedures of databases is weak. So, are there any solutions for the convenient management of these stored procedures?
Here are a few examples.
For example, version control for the client can be achieved when the client submits stored procedure code with bound parameters at each request.
Input:
For example, run the following command:
do language plpgsql $__$
declare
x text := %L;
begin
raise notice '%%', x;
end;
$__$
hello digoal
Note: the client driver may not support parameter binding in inline code. The solution is to modify the client driver or encapsulate the function.
Format function constructs inline code with parameters as described on this page: https://www.postgresql.org/docs/12/functions-string.html#FUNCTIONS-STRING-FORMAT
For example, the following call is encapsulated in the function:
create or replace function dy1 (i text) returns void as $$
declare
v text;
begin
v := format($_$
do language plpgsql $__$
declare
x text := %L;
begin
raise notice '%%', x;
end;
$__$
$_$,
i
);
execute v;
end;
$$ language plpgsql strict;
可行
postgres=# select dy1('hello digoal');
psql: NOTICE: hello digoal
dy1
-----
(1 row)
An insert statement is contained in dynamic code. The dependent tables are as shown below:
drop table if exists c;
create table c (c1 int, c2 numeric, c3 timestamptz, c4 int[], c5 jsonb);
Create a dynamic function:
create or replace function dy2(inline text, VARIADIC para text[]) returns void as $$
declare
begin
case array_length(para,1)
when 1 then execute format(inline, para[1]);
when 2 then execute format(inline, para[1],para[2]);
when 3 then execute format(inline, para[1],para[2],para[3]);
when 4 then execute format(inline, para[1],para[2],para[3],para[4]);
when 5 then execute format(inline, para[1],para[2],para[3],para[4],para[5]);
else
raise exception 'must less then 5 parameters';
end case;
end;
$$ language plpgsql strict;
The input parameters are inline code and dynamic parameters.
select dy2(
$_$
do language plpgsql $$
declare
v1 int := %L;
v2 numeric := %L;
v3 timestamptz := %L;
v4 int[] := %L;
v5 jsonb := %L;
begin
insert into c values (v1,v2,v3,v4,v5);
raise notice '%%, %%, %%, %%, %%', v1,v2,v3,v4,v5;
end;
$$
$_$, -- inline code
'1', -- 动态参数1
'1.1', -- 动态参数2
now()::text, -- 动态参数3
'{1,2,3,4}', -- 动态参数4
'{"a":1,"b":{"k":"v"}}' -- 动态参数5
Results:
psql: NOTICE: 1, 1.1, 2019-08-25 23:35:58.200068+08, {1,2,3,4}, {"a": 1, "b": {"k": "v"}}
dy2
-----
(1 row)
postgres=# select * from c;
c1 | c2 | c3 | c4 | c5
----+-----+-------------------------------+-----------+---------------------------
1 | 1.1 | 2019-08-25 23:35:58.200068+08 | {1,2,3,4} | {"a": 1, "b": {"k": "v"}}
(1 row)
If possible, there is a simpler dynamic encapsulation, but it requires the client to use the format function of the database when calling.
create or replace function dy3(inline text) returns void as $$
declare
begin
execute inline;
end;
$$ language plpgsql strict;
When calling, the dynamic parameters should be included:
select dy3(
format(
$_$
do language plpgsql $$
declare
v1 int := %L;
v2 numeric := %L;
v3 timestamptz := %L;
v4 int[] := %L;
v5 jsonb := %L;
begin
perform v1,v2,v3,v4,v5;
insert into c values (v1,v2,v3,v4,v5);
raise notice '%%, %%, %%, %%, %%', v1,v2,v3,v4,v5;
end;
$$
$_$, -- inline code
'1', -- 动态参数1
'1.1', -- 动态参数2
now()::text, -- 动态参数3
'{1,2,3,4}', -- 动态参数4
'{"a":1,"b":{"k":"v"}}' -- 动态参数5
)
);
Results:
psql: NOTICE: 1, 1.1, 2019-08-25 23:36:19.065442+08, {1,2,3,4}, {"a": 1, "b": {"k": "v"}}
dy3
-----
(1 row)
postgres=# select * from c;
c1 | c2 | c3 | c4 | c5
----+-----+-------------------------------+-----------+---------------------------
1 | 1.1 | 2019-08-25 23:35:58.200068+08 | {1,2,3,4} | {"a": 1, "b": {"k": "v"}}
1 | 1.1 | 2019-08-25 23:36:19.065442+08 | {1,2,3,4} | {"a": 1, "b": {"k": "v"}}
(2 rows)
The content of the stored procedure can also be stored in a table with dynamic calls.
postgres=# create table tcode(id int primary key, code text);
CREATE TABLE
-- 插入一段inline code
postgres=# insert into tcode values (1, $_$
postgres$# do language plpgsql $$
postgres$# declare
postgres$# v1 int := %L;
postgres$# v2 numeric := %L;
postgres$# v3 timestamptz := %L;
postgres$# v4 int[] := %L;
postgres$# v5 jsonb := %L;
postgres$# begin
postgres$# insert into c values (v1,v2,v3,v4,v5);
postgres$# raise notice '%%, %%, %%, %%, %%', v1,v2,v3,v4,v5;
postgres$# end;
postgres$# $$
postgres$# $_$);
INSERT 0 1
Create a dynamic function that calls the inline code of the table.
create or replace function dy4(vid int, VARIADIC para text[]) returns void as $$
declare
inline text;
begin
select code into inline from tcode where id=vid;
case array_length(para,1)
when 1 then execute format(inline, para[1]);
when 2 then execute format(inline, para[1],para[2]);
when 3 then execute format(inline, para[1],para[2],para[3]);
when 4 then execute format(inline, para[1],para[2],para[3],para[4]);
when 5 then execute format(inline, para[1],para[2],para[3],para[4],para[5]);
else
raise exception 'must less then 5 parameters';
end case;
end;
$$ language plpgsql strict;
The call is listed below:
select dy4(1,
'1',
'1.1',
now()::text,
'{1,2,3,4}',
'{"a":1,"b":{"k":"v"}}'
);
Results:
psql: NOTICE: 1, 1.1, 2019-08-25 23:48:06.863258+08, {1,2,3,4}, {"a": 1, "b": {"k": "v"}}
dy4
-----
(1 row)
postgres=# select * from c;
c1 | c2 | c3 | c4 | c5
----+-----+-------------------------------+-----------+---------------------------
1 | 1.1 | 2019-08-25 23:35:58.200068+08 | {1,2,3,4} | {"a": 1, "b": {"k": "v"}}
1 | 1.1 | 2019-08-25 23:36:19.065442+08 | {1,2,3,4} | {"a": 1, "b": {"k": "v"}}
1 | 1.1 | 2019-08-25 23:48:06.863258+08 | {1,2,3,4} | {"a": 1, "b": {"k": "v"}}
(3 rows)
Note: Injection needs to be prevented for dynamic SQL.
Solution for the PostgreSQL Roaringbitmap UID Overflows Beyond Int4 (32 Bytes) – Offset
ApsaraDB - June 15, 2023
digoal - June 28, 2021
XianYu Tech - May 11, 2021
Apache Flink Community China - November 8, 2023
Alipay Technology - November 12, 2019
ApsaraDB - October 24, 2022
Alibaba Cloud PolarDB for PostgreSQL is an in-house relational database service 100% compatible with PostgreSQL and highly compatible with the Oracle syntax.
Learn MoreAn online MPP warehousing service based on the Greenplum Database open source program
Learn MoreA risk management solution that features real-time analysis and accurate identification and is suitable for all business scenarios.
Learn MoreAn on-demand database hosting service for PostgreSQL with automated monitoring, backup and disaster recovery capabilities
Learn MoreMore Posts by digoal