Skip to content

Commit e717a9a

Browse files
committed
SQL-standard function body
This adds support for writing CREATE FUNCTION and CREATE PROCEDURE statements for language SQL with a function body that conforms to the SQL standard and is portable to other implementations. Instead of the PostgreSQL-specific AS $$ string literal $$ syntax, this allows writing out the SQL statements making up the body unquoted, either as a single statement: CREATE FUNCTION add(a integer, b integer) RETURNS integer LANGUAGE SQL RETURN a + b; or as a block CREATE PROCEDURE insert_data(a integer, b integer) LANGUAGE SQL BEGIN ATOMIC INSERT INTO tbl VALUES (a); INSERT INTO tbl VALUES (b); END; The function body is parsed at function definition time and stored as expression nodes in a new pg_proc column prosqlbody. So at run time, no further parsing is required. However, this form does not support polymorphic arguments, because there is no more parse analysis done at call time. Dependencies between the function and the objects it uses are fully tracked. A new RETURN statement is introduced. This can only be used inside function bodies. Internally, it is treated much like a SELECT statement. psql needs some new intelligence to keep track of function body boundaries so that it doesn't send off statements when it sees semicolons that are inside a function body. Tested-by: Jaime Casanova <[email protected]> Reviewed-by: Julien Rouhaud <[email protected]> Discussion: https://www.postgresql.org/message-id/flat/[email protected]
1 parent 1e55e7d commit e717a9a

37 files changed

+1411
-212
lines changed

doc/src/sgml/catalogs.sgml

+10
Original file line numberDiff line numberDiff line change
@@ -6002,6 +6002,16 @@ SCRAM-SHA-256$<replaceable>&lt;iteration count&gt;</replaceable>:<replaceable>&l
60026002
</para></entry>
60036003
</row>
60046004

6005+
<row>
6006+
<entry role="catalog_table_entry"><para role="column_definition">
6007+
<structfield>prosqlbody</structfield> <type>pg_node_tree</type>
6008+
</para>
6009+
<para>
6010+
Pre-parsed SQL function body. This will be used for language SQL
6011+
functions if the body is not specified as a string constant.
6012+
</para></entry>
6013+
</row>
6014+
60056015
<row>
60066016
<entry role="catalog_table_entry"><para role="column_definition">
60076017
<structfield>proconfig</structfield> <type>text[]</type>

doc/src/sgml/ref/create_function.sgml

+113-12
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ CREATE [ OR REPLACE ] FUNCTION
3838
| SET <replaceable class="parameter">configuration_parameter</replaceable> { TO <replaceable class="parameter">value</replaceable> | = <replaceable class="parameter">value</replaceable> | FROM CURRENT }
3939
| AS '<replaceable class="parameter">definition</replaceable>'
4040
| AS '<replaceable class="parameter">obj_file</replaceable>', '<replaceable class="parameter">link_symbol</replaceable>'
41+
| <replaceable class="parameter">sql_body</replaceable>
4142
} ...
4243
</synopsis>
4344
</refsynopsisdiv>
@@ -262,7 +263,9 @@ CREATE [ OR REPLACE ] FUNCTION
262263
The name of the language that the function is implemented in.
263264
It can be <literal>sql</literal>, <literal>c</literal>,
264265
<literal>internal</literal>, or the name of a user-defined
265-
procedural language, e.g., <literal>plpgsql</literal>. Enclosing the
266+
procedural language, e.g., <literal>plpgsql</literal>. The default is
267+
<literal>sql</literal> if <replaceable
268+
class="parameter">sql_body</replaceable> is specified. Enclosing the
266269
name in single quotes is deprecated and requires matching case.
267270
</para>
268271
</listitem>
@@ -582,6 +585,44 @@ CREATE [ OR REPLACE ] FUNCTION
582585
</listitem>
583586
</varlistentry>
584587

588+
<varlistentry>
589+
<term><replaceable class="parameter">sql_body</replaceable></term>
590+
591+
<listitem>
592+
<para>
593+
The body of a <literal>LANGUAGE SQL</literal> function. This can
594+
either be a single statement
595+
<programlisting>
596+
RETURN <replaceable>expression</replaceable>
597+
</programlisting>
598+
or a block
599+
<programlisting>
600+
BEGIN ATOMIC
601+
<replaceable>statement</replaceable>;
602+
<replaceable>statement</replaceable>;
603+
...
604+
<replaceable>statement</replaceable>;
605+
END
606+
</programlisting>
607+
</para>
608+
609+
<para>
610+
This is similar to writing the text of the function body as a string
611+
constant (see <replaceable>definition</replaceable> above), but there
612+
are some differences: This form only works for <literal>LANGUAGE
613+
SQL</literal>, the string constant form works for all languages. This
614+
form is parsed at function definition time, the string constant form is
615+
parsed at execution time; therefore this form cannot support
616+
polymorphic argument types and other constructs that are not resolvable
617+
at function definition time. This form tracks dependencies between the
618+
function and objects used in the function body, so <literal>DROP
619+
... CASCADE</literal> will work correctly, whereas the form using
620+
string literals may leave dangling functions. Finally, this form is
621+
more compatible with the SQL standard and other SQL implementations.
622+
</para>
623+
</listitem>
624+
</varlistentry>
625+
585626
</variablelist>
586627
</refsect1>
587628

@@ -667,6 +708,15 @@ CREATE FUNCTION add(integer, integer) RETURNS integer
667708
LANGUAGE SQL
668709
IMMUTABLE
669710
RETURNS NULL ON NULL INPUT;
711+
</programlisting>
712+
The same function written in a more SQL-conforming style, using argument
713+
names and an unquoted body:
714+
<programlisting>
715+
CREATE FUNCTION add(a integer, b integer) RETURNS integer
716+
LANGUAGE SQL
717+
IMMUTABLE
718+
RETURNS NULL ON NULL INPUT
719+
RETURN a + b;
670720
</programlisting>
671721
</para>
672722

@@ -797,23 +847,74 @@ COMMIT;
797847
<title>Compatibility</title>
798848

799849
<para>
800-
A <command>CREATE FUNCTION</command> command is defined in the SQL standard.
801-
The <productname>PostgreSQL</productname> version is similar but
802-
not fully compatible. The attributes are not portable, neither are the
803-
different available languages.
850+
A <command>CREATE FUNCTION</command> command is defined in the SQL
851+
standard. The <productname>PostgreSQL</productname> implementation can be
852+
used in a compatible way but has many extensions. Conversely, the SQL
853+
standard specifies a number of optional features that are not implemented
854+
in <productname>PostgreSQL</productname>.
804855
</para>
805856

806857
<para>
807-
For compatibility with some other database systems,
808-
<replaceable class="parameter">argmode</replaceable> can be written
809-
either before or after <replaceable class="parameter">argname</replaceable>.
810-
But only the first way is standard-compliant.
858+
The following are important compatibility issues:
859+
860+
<itemizedlist>
861+
<listitem>
862+
<para>
863+
<literal>OR REPLACE</literal> is a PostgreSQL extension.
864+
</para>
865+
</listitem>
866+
867+
<listitem>
868+
<para>
869+
For compatibility with some other database systems, <replaceable
870+
class="parameter">argmode</replaceable> can be written either before or
871+
after <replaceable class="parameter">argname</replaceable>. But only
872+
the first way is standard-compliant.
873+
</para>
874+
</listitem>
875+
876+
<listitem>
877+
<para>
878+
For parameter defaults, the SQL standard specifies only the syntax with
879+
the <literal>DEFAULT</literal> key word. The syntax with
880+
<literal>=</literal> is used in T-SQL and Firebird.
881+
</para>
882+
</listitem>
883+
884+
<listitem>
885+
<para>
886+
The <literal>SETOF</literal> modifier is a PostgreSQL extension.
887+
</para>
888+
</listitem>
889+
890+
<listitem>
891+
<para>
892+
Only <literal>SQL</literal> is standardized as a language.
893+
</para>
894+
</listitem>
895+
896+
<listitem>
897+
<para>
898+
All other attributes except <literal>CALLED ON NULL INPUT</literal> and
899+
<literal>RETURNS NULL ON NULL INPUT</literal> are not standardized.
900+
</para>
901+
</listitem>
902+
903+
<listitem>
904+
<para>
905+
For the body of <literal>LANGUAGE SQL</literal> functions, the SQL
906+
standard only specifies the <replaceable>sql_body</replaceable> form.
907+
</para>
908+
</listitem>
909+
</itemizedlist>
811910
</para>
812911

813912
<para>
814-
For parameter defaults, the SQL standard specifies only the syntax with
815-
the <literal>DEFAULT</literal> key word. The syntax
816-
with <literal>=</literal> is used in T-SQL and Firebird.
913+
Simple <literal>LANGUAGE SQL</literal> functions can be written in a way
914+
that is both standard-conforming and portable to other implementations.
915+
More complex functions using advanced features, optimization attributes, or
916+
other languages will necessarily be specific to PostgreSQL in a significant
917+
way.
817918
</para>
818919
</refsect1>
819920

doc/src/sgml/ref/create_procedure.sgml

+56-5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ CREATE [ OR REPLACE ] PROCEDURE
2929
| SET <replaceable class="parameter">configuration_parameter</replaceable> { TO <replaceable class="parameter">value</replaceable> | = <replaceable class="parameter">value</replaceable> | FROM CURRENT }
3030
| AS '<replaceable class="parameter">definition</replaceable>'
3131
| AS '<replaceable class="parameter">obj_file</replaceable>', '<replaceable class="parameter">link_symbol</replaceable>'
32+
| <replaceable class="parameter">sql_body</replaceable>
3233
} ...
3334
</synopsis>
3435
</refsynopsisdiv>
@@ -167,7 +168,9 @@ CREATE [ OR REPLACE ] PROCEDURE
167168
The name of the language that the procedure is implemented in.
168169
It can be <literal>sql</literal>, <literal>c</literal>,
169170
<literal>internal</literal>, or the name of a user-defined
170-
procedural language, e.g., <literal>plpgsql</literal>. Enclosing the
171+
procedural language, e.g., <literal>plpgsql</literal>. The default is
172+
<literal>sql</literal> if <replaceable
173+
class="parameter">sql_body</replaceable> is specified. Enclosing the
171174
name in single quotes is deprecated and requires matching case.
172175
</para>
173176
</listitem>
@@ -304,6 +307,41 @@ CREATE [ OR REPLACE ] PROCEDURE
304307

305308
</listitem>
306309
</varlistentry>
310+
311+
<varlistentry>
312+
<term><replaceable class="parameter">sql_body</replaceable></term>
313+
314+
<listitem>
315+
<para>
316+
The body of a <literal>LANGUAGE SQL</literal> procedure. This should
317+
be a block
318+
<programlisting>
319+
BEGIN ATOMIC
320+
<replaceable>statement</replaceable>;
321+
<replaceable>statement</replaceable>;
322+
...
323+
<replaceable>statement</replaceable>;
324+
END
325+
</programlisting>
326+
</para>
327+
328+
<para>
329+
This is similar to writing the text of the procedure body as a string
330+
constant (see <replaceable>definition</replaceable> above), but there
331+
are some differences: This form only works for <literal>LANGUAGE
332+
SQL</literal>, the string constant form works for all languages. This
333+
form is parsed at procedure definition time, the string constant form is
334+
parsed at execution time; therefore this form cannot support
335+
polymorphic argument types and other constructs that are not resolvable
336+
at procedure definition time. This form tracks dependencies between the
337+
procedure and objects used in the procedure body, so <literal>DROP
338+
... CASCADE</literal> will work correctly, whereas the form using
339+
string literals may leave dangling procedures. Finally, this form is
340+
more compatible with the SQL standard and other SQL implementations.
341+
</para>
342+
</listitem>
343+
</varlistentry>
344+
307345
</variablelist>
308346
</refsect1>
309347

@@ -323,26 +361,39 @@ CREATE [ OR REPLACE ] PROCEDURE
323361
<refsect1 id="sql-createprocedure-examples">
324362
<title>Examples</title>
325363

364+
<para>
326365
<programlisting>
327366
CREATE PROCEDURE insert_data(a integer, b integer)
328367
LANGUAGE SQL
329368
AS $$
330369
INSERT INTO tbl VALUES (a);
331370
INSERT INTO tbl VALUES (b);
332371
$$;
333-
372+
</programlisting>
373+
or
374+
<programlisting>
375+
CREATE PROCEDURE insert_data(a integer, b integer)
376+
LANGUAGE SQL
377+
BEGIN ATOMIC
378+
INSERT INTO tbl VALUES (a);
379+
INSERT INTO tbl VALUES (b);
380+
END;
381+
</programlisting>
382+
and call like this:
383+
<programlisting>
334384
CALL insert_data(1, 2);
335385
</programlisting>
386+
</para>
336387
</refsect1>
337388

338389
<refsect1 id="sql-createprocedure-compat">
339390
<title>Compatibility</title>
340391

341392
<para>
342393
A <command>CREATE PROCEDURE</command> command is defined in the SQL
343-
standard. The <productname>PostgreSQL</productname> version is similar but
344-
not fully compatible. For details see
345-
also <xref linkend="sql-createfunction"/>.
394+
standard. The <productname>PostgreSQL</productname> implementation can be
395+
used in a compatible way but has many extensions. For details see also
396+
<xref linkend="sql-createfunction"/>.
346397
</para>
347398
</refsect1>
348399

src/backend/catalog/pg_aggregate.c

+1
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,7 @@ AggregateCreate(const char *aggName,
622622
InvalidOid, /* no validator */
623623
"aggregate_dummy", /* placeholder (no such proc) */
624624
NULL, /* probin */
625+
NULL, /* prosqlbody */
625626
PROKIND_AGGREGATE,
626627
false, /* security invoker (currently not
627628
* definable for agg) */

0 commit comments

Comments
 (0)