Commit 9048b731 authored by Tom Lane's avatar Tom Lane

Implement the DO statement to support execution of PL code without having

to create a function for it.

Procedural languages now have an additional entry point, namely a function
to execute an inline code block.  This seemed a better design than trying
to hide the transient-ness of the code from the PL.  As of this patch, only
plpgsql has an inline handler, but probably people will soon write handlers
for the other standard PLs.

In passing, remove the long-dead LANCOMPILER option of CREATE LANGUAGE.

Petr Jelinek
parent d5a43ffd
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.206 2009/08/10 22:13:50 alvherre Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.207 2009/09/22 23:43:37 tgl Exp $ -->
<!-- <!--
Documentation of the system catalogs, directed toward PostgreSQL developers Documentation of the system catalogs, directed toward PostgreSQL developers
--> -->
...@@ -2941,6 +2941,18 @@ ...@@ -2941,6 +2941,18 @@
</entry> </entry>
</row> </row>
<row>
<entry><structfield>laninline</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link>.oid</literal></entry>
<entry>
This references a function that is responsible for executing
<quote>inline</> anonymous code blocks
(<xref linkend="sql-do" endterm="sql-do-title"> blocks).
Zero if inline blocks are not supported
</entry>
</row>
<row> <row>
<entry><structfield>lanvalidator</structfield></entry> <entry><structfield>lanvalidator</structfield></entry>
<entry><type>oid</type></entry> <entry><type>oid</type></entry>
...@@ -3547,6 +3559,12 @@ ...@@ -3547,6 +3559,12 @@
<entry>Name of call handler function</entry> <entry>Name of call handler function</entry>
</row> </row>
<row>
<entry><structfield>tmplinline</structfield></entry>
<entry><type>text</type></entry>
<entry>Name of anonymous-block handler function, or NULL if none</entry>
</row>
<row> <row>
<entry><structfield>tmplvalidator</structfield></entry> <entry><structfield>tmplvalidator</structfield></entry>
<entry><type>text</type></entry> <entry><type>text</type></entry>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.228 2009/09/13 19:52:29 petere Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.229 2009/09/22 23:43:37 tgl Exp $ -->
<chapter Id="runtime-config"> <chapter Id="runtime-config">
<title>Server Configuration</title> <title>Server Configuration</title>
...@@ -3964,6 +3964,21 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv; ...@@ -3964,6 +3964,21 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry id="guc-default-do-language" xreflabel="default_do_language">
<term><varname>default_do_language</varname> (<type>string</type>)</term>
<indexterm>
<primary><varname>default_do_language</> configuration parameter</primary>
</indexterm>
<listitem>
<para>
This parameter specifies the language to use when the
<literal>LANGUAGE</> option is omitted in a
<xref linkend="sql-do" endterm="sql-do-title"> statement.
The default is <literal>plpgsql</literal>.
</para>
</listitem>
</varlistentry>
<varlistentry id="guc-default-transaction-isolation" xreflabel="default_transaction_isolation"> <varlistentry id="guc-default-transaction-isolation" xreflabel="default_transaction_isolation">
<indexterm> <indexterm>
<primary>transaction isolation level</primary> <primary>transaction isolation level</primary>
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/keywords.sgml,v 2.25 2009/04/06 15:01:36 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/keywords.sgml,v 2.26 2009/09/22 23:43:37 tgl Exp $ -->
<appendix id="sql-keywords-appendix"> <appendix id="sql-keywords-appendix">
<title><acronym>SQL</acronym> Key Words</title> <title><acronym>SQL</acronym> Key Words</title>
...@@ -2375,6 +2375,14 @@ ...@@ -2375,6 +2375,14 @@
<entry>reserved</entry> <entry>reserved</entry>
<entry>reserved</entry> <entry>reserved</entry>
</row> </row>
<row>
<entry><token>INLINE</token></entry>
<entry>non-reserved</entry>
<entry></entry>
<entry></entry>
<entry></entry>
<entry></entry>
</row>
<row> <row>
<entry><token>INNER</token></entry> <entry><token>INNER</token></entry>
<entry>reserved (can be function or type)</entry> <entry>reserved (can be function or type)</entry>
...@@ -2575,14 +2583,6 @@ ...@@ -2575,14 +2583,6 @@
<entry></entry> <entry></entry>
<entry></entry> <entry></entry>
</row> </row>
<row>
<entry><token>LANCOMPILER</token></entry>
<entry>non-reserved</entry>
<entry></entry>
<entry></entry>
<entry></entry>
<entry></entry>
</row>
<row> <row>
<entry><token>LANGUAGE</token></entry> <entry><token>LANGUAGE</token></entry>
<entry>non-reserved</entry> <entry>non-reserved</entry>
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.74 2008/12/19 16:25:16 petere Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.75 2009/09/22 23:43:37 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
Complete list of usable sgml source files in this directory. Complete list of usable sgml source files in this directory.
--> -->
...@@ -77,6 +77,7 @@ Complete list of usable sgml source files in this directory. ...@@ -77,6 +77,7 @@ Complete list of usable sgml source files in this directory.
<!entity declare system "declare.sgml"> <!entity declare system "declare.sgml">
<!entity delete system "delete.sgml"> <!entity delete system "delete.sgml">
<!entity discard system "discard.sgml"> <!entity discard system "discard.sgml">
<!entity do system "do.sgml">
<!entity dropAggregate system "drop_aggregate.sgml"> <!entity dropAggregate system "drop_aggregate.sgml">
<!entity dropCast system "drop_cast.sgml"> <!entity dropCast system "drop_cast.sgml">
<!entity dropConversion system "drop_conversion.sgml"> <!entity dropConversion system "drop_conversion.sgml">
......
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_language.sgml,v 1.45 2008/11/14 10:22:46 petere Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_language.sgml,v 1.46 2009/09/22 23:43:37 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
...@@ -23,7 +23,7 @@ PostgreSQL documentation ...@@ -23,7 +23,7 @@ PostgreSQL documentation
<synopsis> <synopsis>
CREATE [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable> CREATE [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable>
CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable> CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</replaceable>
HANDLER <replaceable class="parameter">call_handler</replaceable> [ VALIDATOR <replaceable>valfunction</replaceable> ] HANDLER <replaceable class="parameter">call_handler</replaceable> [ INLINE <replaceable class="parameter">inline_handler</replaceable> ] [ VALIDATOR <replaceable>valfunction</replaceable> ]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
...@@ -133,7 +133,7 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</ ...@@ -133,7 +133,7 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</
<para> <para>
<replaceable class="parameter">call_handler</replaceable> is <replaceable class="parameter">call_handler</replaceable> is
the name of a previously registered function that will be the name of a previously registered function that will be
called to execute the procedural language functions. The call called to execute the procedural language's functions. The call
handler for a procedural language must be written in a compiled handler for a procedural language must be written in a compiled
language such as C with version 1 call convention and language such as C with version 1 call convention and
registered with <productname>PostgreSQL</productname> as a registered with <productname>PostgreSQL</productname> as a
...@@ -144,6 +144,27 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</ ...@@ -144,6 +144,27 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>INLINE</literal> <replaceable class="parameter">inline_handler</replaceable></term>
<listitem>
<para>
<replaceable class="parameter">inline_handler</replaceable> is the
name of a previously registered function that will be called
to execute an anonymous code block
(<xref linkend="sql-do" endterm="sql-do-title"> command)
in this language.
If no <replaceable class="parameter">inline_handler</replaceable>
function is specified, the language does not support anonymous code
blocks.
The handler function must take one argument of
type <type>internal</type>, which will be the <command>DO</> command's
internal representation, and it will typically return
<type>void</>. The return value of the handler is ignored.
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><literal>VALIDATOR</literal> <replaceable class="parameter">valfunction</replaceable></term> <term><literal>VALIDATOR</literal> <replaceable class="parameter">valfunction</replaceable></term>
...@@ -216,7 +237,8 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</ ...@@ -216,7 +237,8 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</
</para> </para>
<para> <para>
The call handler function and the validator function (if any) The call handler function, the inline handler function (if any),
and the validator function (if any)
must already exist if the server does not have an entry for the language must already exist if the server does not have an entry for the language
in <structname>pg_pltemplate</>. But when there is an entry, in <structname>pg_pltemplate</>. But when there is an entry,
the functions need not already exist; the functions need not already exist;
...@@ -230,7 +252,7 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</ ...@@ -230,7 +252,7 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</
In <productname>PostgreSQL</productname> versions before 7.3, it was In <productname>PostgreSQL</productname> versions before 7.3, it was
necessary to declare handler functions as returning the placeholder necessary to declare handler functions as returning the placeholder
type <type>opaque</>, rather than <type>language_handler</>. type <type>opaque</>, rather than <type>language_handler</>.
To support loading To support loading
of old dump files, <command>CREATE LANGUAGE</> will accept a function of old dump files, <command>CREATE LANGUAGE</> will accept a function
declared as returning <type>opaque</>, but it will issue a notice and declared as returning <type>opaque</>, but it will issue a notice and
change the function's declared return type to <type>language_handler</>. change the function's declared return type to <type>language_handler</>.
......
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/do.sgml,v 1.1 2009/09/22 23:43:37 tgl Exp $
PostgreSQL documentation
-->
<refentry id="SQL-DO">
<refmeta>
<refentrytitle id="sql-do-title">DO</refentrytitle>
<manvolnum>7</manvolnum>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>DO</refname>
<refpurpose>execute an anonymous code block</refpurpose>
</refnamediv>
<indexterm zone="sql-do">
<primary>DO</primary>
</indexterm>
<indexterm zone="sql-do">
<primary>anonymous code blocks</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
DO <replaceable class="PARAMETER">code</replaceable> [ LANGUAGE <replaceable class="PARAMETER">lang_name</replaceable> ]
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>DO</command> executes an anonymous code block, or in other
words a transient anonymous function in a procedural language.
</para>
<para>
The code block is treated as though it were the body of a function
with no parameters, returning <type>void</>. It is parsed and
executed a single time.
</para>
</refsect1>
<refsect1>
<title>Parameters</title>
<variablelist>
<varlistentry>
<term><replaceable class="PARAMETER">code</replaceable></term>
<listitem>
<para>
The procedural language code to be executed. This must be specified
as a string literal, just as in <command>CREATE FUNCTION</>.
Use of a dollar-quoted literal is recommended.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="PARAMETER">lang_name</replaceable></term>
<listitem>
<para>
The name of the procedural language the code is written in.
If omitted, the default is determined by the runtime parameter
<xref linkend="guc-default-do-language">.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>
<para>
The procedural language to be used must already have been installed
into the current database by means of <command>CREATE LANGUAGE</>.
</para>
<para>
The user must have <literal>USAGE</> privilege for the procedural
language, or must be a superuser if the language is untrusted.
This is the same privilege requirement as for creating a function
in the language.
</para>
</refsect1>
<refsect1 id="sql-do-examples">
<title id="sql-do-examples-title">Examples</title>
<para>
Execute a simple PL/pgsql loop without needing to create a function:
<programlisting>
DO $$
DECLARE r record;
BEGIN
FOR r IN SELECT rtrim(roomno) AS roomno, comment FROM Room ORDER BY roomno
LOOP
RAISE NOTICE '%, %', r.roomno, r.comment;
END LOOP;
END$$;
</programlisting>
</para>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
There is no <command>DO</command> statement in the SQL standard.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-createlanguage" endterm="sql-createlanguage-title"></member>
</simplelist>
</refsect1>
</refentry>
<!-- $PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.67 2008/12/19 16:25:16 petere Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.68 2009/09/22 23:43:37 tgl Exp $ -->
<part id="reference"> <part id="reference">
<title>Reference</title> <title>Reference</title>
...@@ -105,6 +105,7 @@ ...@@ -105,6 +105,7 @@
&declare; &declare;
&delete; &delete;
&discard; &discard;
&do;
&dropAggregate; &dropAggregate;
&dropCast; &dropCast;
&dropConversion; &dropConversion;
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/xplang.sgml,v 1.34 2007/02/01 00:28:18 momjian Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/xplang.sgml,v 1.35 2009/09/22 23:43:37 tgl Exp $ -->
<chapter id="xplang"> <chapter id="xplang">
<title id="xplang-title">Procedural Languages</title> <title id="xplang-title">Procedural Languages</title>
...@@ -75,9 +75,9 @@ createlang plpgsql template1 ...@@ -75,9 +75,9 @@ createlang plpgsql template1
</title> </title>
<para> <para>
A procedural language is installed in a database in four steps, A procedural language is installed in a database in five steps,
which must be carried out by a database superuser. (For languages which must be carried out by a database superuser. (For languages
known to <command>CREATE LANGUAGE</>, the second and third steps known to <command>CREATE LANGUAGE</>, the second through fourth steps
can be omitted, because they will be carried out automatically can be omitted, because they will be carried out automatically
if needed.) if needed.)
</para> </para>
...@@ -110,12 +110,28 @@ CREATE FUNCTION <replaceable>handler_function_name</replaceable>() ...@@ -110,12 +110,28 @@ CREATE FUNCTION <replaceable>handler_function_name</replaceable>()
</step> </step>
<step performance="optional" id="xplang-install-cr3"> <step performance="optional" id="xplang-install-cr3">
<para>
Optionally, the language handler can provide an <quote>inline</>
handler function that executes anonymous code blocks
(<xref linkend="sql-do" endterm="sql-do-title"> commands)
written in this language. If an inline handler function
is provided by the language, declare it with a command like
<synopsis>
CREATE FUNCTION <replaceable>inline_function_name</replaceable>(internal)
RETURNS void
AS '<replaceable>path-to-shared-object</replaceable>'
LANGUAGE C;
</synopsis>
</para>
</step>
<step performance="optional" id="xplang-install-cr4">
<para> <para>
Optionally, the language handler can provide a <quote>validator</> Optionally, the language handler can provide a <quote>validator</>
function that checks a function definition for correctness without function that checks a function definition for correctness without
actually executing it. The validator function is called by actually executing it. The validator function is called by
<command>CREATE FUNCTION</> if it exists. If a validator function <command>CREATE FUNCTION</> if it exists. If a validator function
is provided by the handler, declare it with a command like is provided by the language, declare it with a command like
<synopsis> <synopsis>
CREATE FUNCTION <replaceable>validator_function_name</replaceable>(oid) CREATE FUNCTION <replaceable>validator_function_name</replaceable>(oid)
RETURNS void RETURNS void
...@@ -125,12 +141,13 @@ CREATE FUNCTION <replaceable>validator_function_name</replaceable>(oid) ...@@ -125,12 +141,13 @@ CREATE FUNCTION <replaceable>validator_function_name</replaceable>(oid)
</para> </para>
</step> </step>
<step performance="required" id="xplang-install-cr4"> <step performance="required" id="xplang-install-cr5">
<para> <para>
The PL must be declared with the command The PL must be declared with the command
<synopsis> <synopsis>
CREATE <optional>TRUSTED</optional> <optional>PROCEDURAL</optional> LANGUAGE <replaceable>language-name</replaceable> CREATE <optional>TRUSTED</optional> <optional>PROCEDURAL</optional> LANGUAGE <replaceable>language-name</replaceable>
HANDLER <replaceable>handler_function_name</replaceable> HANDLER <replaceable>handler_function_name</replaceable>
<optional>INLINE <replaceable>inline_function_name</replaceable></optional>
<optional>VALIDATOR <replaceable>validator_function_name</replaceable></optional> ; <optional>VALIDATOR <replaceable>validator_function_name</replaceable></optional> ;
</synopsis> </synopsis>
The optional key word <literal>TRUSTED</literal> specifies that The optional key word <literal>TRUSTED</literal> specifies that
...@@ -173,10 +190,13 @@ CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler AS ...@@ -173,10 +190,13 @@ CREATE FUNCTION plpgsql_call_handler() RETURNS language_handler AS
</para> </para>
<para> <para>
<application>PL/pgSQL</application> has a validator function, <application>PL/pgSQL</application> has an inline handler function
so we declare that too: and a validator function, so we declare those too:
<programlisting> <programlisting>
CREATE FUNCTION plpgsql_inline_handler(internal) RETURNS void AS
'$libdir/plpgsql' LANGUAGE C;
CREATE FUNCTION plpgsql_validator(oid) RETURNS void AS CREATE FUNCTION plpgsql_validator(oid) RETURNS void AS
'$libdir/plpgsql' LANGUAGE C; '$libdir/plpgsql' LANGUAGE C;
</programlisting> </programlisting>
...@@ -187,6 +207,7 @@ CREATE FUNCTION plpgsql_validator(oid) RETURNS void AS ...@@ -187,6 +207,7 @@ CREATE FUNCTION plpgsql_validator(oid) RETURNS void AS
<programlisting> <programlisting>
CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql CREATE TRUSTED PROCEDURAL LANGUAGE plpgsql
HANDLER plpgsql_call_handler HANDLER plpgsql_call_handler
INLINE plpgsql_inline_handler
VALIDATOR plpgsql_validator; VALIDATOR plpgsql_validator;
</programlisting> </programlisting>
then defines that the previously declared functions then defines that the previously declared functions
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.164 2009/06/11 14:48:55 momjian Exp $ * $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.165 2009/09/22 23:43:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -782,11 +782,12 @@ sql_function_parse_error_callback(void *arg) ...@@ -782,11 +782,12 @@ sql_function_parse_error_callback(void *arg)
/* /*
* Adjust a syntax error occurring inside the function body of a CREATE * Adjust a syntax error occurring inside the function body of a CREATE
* FUNCTION command. This can be used by any function validator, not only * FUNCTION or DO command. This can be used by any function validator or
* for SQL-language functions. It is assumed that the syntax error position * anonymous-block handler, not only for SQL-language functions.
* is initially relative to the function body string (as passed in). If * It is assumed that the syntax error position is initially relative to the
* possible, we adjust the position to reference the original CREATE command; * function body string (as passed in). If possible, we adjust the position
* if we can't manage that, we set up an "internal query" syntax error instead. * to reference the original command text; if we can't manage that, we set
* up an "internal query" syntax error instead.
* *
* Returns true if a syntax error was processed, false if not. * Returns true if a syntax error was processed, false if not.
*/ */
...@@ -843,8 +844,8 @@ function_parse_error_transpose(const char *prosrc) ...@@ -843,8 +844,8 @@ function_parse_error_transpose(const char *prosrc)
/* /*
* Try to locate the string literal containing the function body in the * Try to locate the string literal containing the function body in the
* given text of the CREATE FUNCTION command. If successful, return the * given text of the CREATE FUNCTION or DO command. If successful, return
* character (not byte) index within the command corresponding to the * the character (not byte) index within the command corresponding to the
* given character index within the literal. If not successful, return 0. * given character index within the literal. If not successful, return 0.
*/ */
static int static int
...@@ -852,7 +853,7 @@ match_prosrc_to_query(const char *prosrc, const char *queryText, ...@@ -852,7 +853,7 @@ match_prosrc_to_query(const char *prosrc, const char *queryText,
int cursorpos) int cursorpos)
{ {
/* /*
* Rather than fully parsing the CREATE FUNCTION command, we just scan the * Rather than fully parsing the original command, we just scan the
* command looking for $prosrc$ or 'prosrc'. This could be fooled (though * command looking for $prosrc$ or 'prosrc'. This could be fooled (though
* not in any very probable scenarios), so fail if we find more than one * not in any very probable scenarios), so fail if we find more than one
* match. * match.
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.110 2009/06/11 14:48:55 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.111 2009/09/22 23:43:37 tgl Exp $
* *
* DESCRIPTION * DESCRIPTION
* These routines take the parse tree and pick out the * These routines take the parse tree and pick out the
...@@ -1915,3 +1915,110 @@ AlterFunctionNamespace(List *name, List *argtypes, bool isagg, ...@@ -1915,3 +1915,110 @@ AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
heap_close(procRel, RowExclusiveLock); heap_close(procRel, RowExclusiveLock);
} }
/*
* ExecuteDoStmt
* Execute inline procedural-language code
*/
void
ExecuteDoStmt(DoStmt *stmt)
{
InlineCodeBlock *codeblock = makeNode(InlineCodeBlock);
ListCell *arg;
DefElem *as_item = NULL;
DefElem *language_item = NULL;
char *language;
char *languageName;
Oid laninline;
HeapTuple languageTuple;
Form_pg_language languageStruct;
/* Process options we got from gram.y */
foreach(arg, stmt->args)
{
DefElem *defel = (DefElem *) lfirst(arg);
if (strcmp(defel->defname, "as") == 0)
{
if (as_item)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
as_item = defel;
}
else if (strcmp(defel->defname, "language") == 0)
{
if (language_item)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
language_item = defel;
}
else
elog(ERROR, "option \"%s\" not recognized",
defel->defname);
}
if (as_item)
codeblock->source_text = strVal(as_item->arg);
else
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("no inline code specified")));
/* if LANGUAGE option wasn't specified, use the default language */
if (language_item)
language = strVal(language_item->arg);
else
language = default_do_language;
/* Convert language name to canonical case */
languageName = case_translate_language_name(language);
/* Look up the language and validate permissions */
languageTuple = SearchSysCache(LANGNAME,
PointerGetDatum(languageName),
0, 0, 0);
if (!HeapTupleIsValid(languageTuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("language \"%s\" does not exist", languageName),
(PLTemplateExists(languageName) ?
errhint("Use CREATE LANGUAGE to load the language into the database.") : 0)));
codeblock->langOid = HeapTupleGetOid(languageTuple);
languageStruct = (Form_pg_language) GETSTRUCT(languageTuple);
if (languageStruct->lanpltrusted)
{
/* if trusted language, need USAGE privilege */
AclResult aclresult;
aclresult = pg_language_aclcheck(codeblock->langOid, GetUserId(),
ACL_USAGE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_LANGUAGE,
NameStr(languageStruct->lanname));
}
else
{
/* if untrusted language, must be superuser */
if (!superuser())
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
NameStr(languageStruct->lanname));
}
/* get the handler function's OID */
laninline = languageStruct->laninline;
if (!OidIsValid(laninline))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("language \"%s\" does not support inline code execution",
NameStr(languageStruct->lanname))));
ReleaseSysCache(languageTuple);
/* execute the inline handler */
OidFunctionCall1(laninline, PointerGetDatum(codeblock));
}
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.86 2009/07/12 17:12:33 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.87 2009/09/22 23:43:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -44,12 +44,14 @@ typedef struct ...@@ -44,12 +44,14 @@ typedef struct
bool tmpltrusted; /* trusted? */ bool tmpltrusted; /* trusted? */
bool tmpldbacreate; /* db owner allowed to create? */ bool tmpldbacreate; /* db owner allowed to create? */
char *tmplhandler; /* name of handler function */ char *tmplhandler; /* name of handler function */
char *tmplinline; /* name of anonymous-block handler, or NULL */
char *tmplvalidator; /* name of validator function, or NULL */ char *tmplvalidator; /* name of validator function, or NULL */
char *tmpllibrary; /* path of shared library */ char *tmpllibrary; /* path of shared library */
} PLTemplate; } PLTemplate;
static void create_proc_lang(const char *languageName, static void create_proc_lang(const char *languageName,
Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted); Oid languageOwner, Oid handlerOid, Oid inlineOid,
Oid valOid, bool trusted);
static PLTemplate *find_language_template(const char *languageName); static PLTemplate *find_language_template(const char *languageName);
static void AlterLanguageOwner_internal(HeapTuple tup, Relation rel, static void AlterLanguageOwner_internal(HeapTuple tup, Relation rel,
Oid newOwnerId); Oid newOwnerId);
...@@ -65,6 +67,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) ...@@ -65,6 +67,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
char *languageName; char *languageName;
PLTemplate *pltemplate; PLTemplate *pltemplate;
Oid handlerOid, Oid handlerOid,
inlineOid,
valOid; valOid;
Oid funcrettype; Oid funcrettype;
Oid funcargtypes[1]; Oid funcargtypes[1];
...@@ -154,6 +157,44 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) ...@@ -154,6 +157,44 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
0); 0);
} }
/*
* Likewise for the anonymous block handler, if required;
* but we don't care about its return type.
*/
if (pltemplate->tmplinline)
{
funcname = SystemFuncName(pltemplate->tmplinline);
funcargtypes[0] = INTERNALOID;
inlineOid = LookupFuncName(funcname, 1, funcargtypes, true);
if (!OidIsValid(inlineOid))
{
inlineOid = ProcedureCreate(pltemplate->tmplinline,
PG_CATALOG_NAMESPACE,
false, /* replace */
false, /* returnsSet */
VOIDOID,
ClanguageId,
F_FMGR_C_VALIDATOR,
pltemplate->tmplinline,
pltemplate->tmpllibrary,
false, /* isAgg */
false, /* isWindowFunc */
false, /* security_definer */
true, /* isStrict */
PROVOLATILE_VOLATILE,
buildoidvector(funcargtypes, 1),
PointerGetDatum(NULL),
PointerGetDatum(NULL),
PointerGetDatum(NULL),
NIL,
PointerGetDatum(NULL),
1,
0);
}
}
else
inlineOid = InvalidOid;
/* /*
* Likewise for the validator, if required; but we don't care about * Likewise for the validator, if required; but we don't care about
* its return type. * its return type.
...@@ -177,7 +218,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) ...@@ -177,7 +218,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
false, /* isAgg */ false, /* isAgg */
false, /* isWindowFunc */ false, /* isWindowFunc */
false, /* security_definer */ false, /* security_definer */
false, /* isStrict */ true, /* isStrict */
PROVOLATILE_VOLATILE, PROVOLATILE_VOLATILE,
buildoidvector(funcargtypes, 1), buildoidvector(funcargtypes, 1),
PointerGetDatum(NULL), PointerGetDatum(NULL),
...@@ -193,8 +234,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) ...@@ -193,8 +234,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
valOid = InvalidOid; valOid = InvalidOid;
/* ok, create it */ /* ok, create it */
create_proc_lang(languageName, GetUserId(), handlerOid, valOid, create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
pltemplate->tmpltrusted); valOid, pltemplate->tmpltrusted);
} }
else else
{ {
...@@ -246,6 +287,16 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) ...@@ -246,6 +287,16 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
NameListToString(stmt->plhandler)))); NameListToString(stmt->plhandler))));
} }
/* validate the inline function */
if (stmt->plinline)
{
funcargtypes[0] = INTERNALOID;
inlineOid = LookupFuncName(stmt->plinline, 1, funcargtypes, false);
/* return value is ignored, so we don't check the type */
}
else
inlineOid = InvalidOid;
/* validate the validator function */ /* validate the validator function */
if (stmt->plvalidator) if (stmt->plvalidator)
{ {
...@@ -257,8 +308,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) ...@@ -257,8 +308,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
valOid = InvalidOid; valOid = InvalidOid;
/* ok, create it */ /* ok, create it */
create_proc_lang(languageName, GetUserId(), handlerOid, valOid, create_proc_lang(languageName, GetUserId(), handlerOid, inlineOid,
stmt->pltrusted); valOid, stmt->pltrusted);
} }
} }
...@@ -267,7 +318,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt) ...@@ -267,7 +318,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
*/ */
static void static void
create_proc_lang(const char *languageName, create_proc_lang(const char *languageName,
Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted) Oid languageOwner, Oid handlerOid, Oid inlineOid,
Oid valOid, bool trusted)
{ {
Relation rel; Relation rel;
TupleDesc tupDesc; TupleDesc tupDesc;
...@@ -293,6 +345,7 @@ create_proc_lang(const char *languageName, ...@@ -293,6 +345,7 @@ create_proc_lang(const char *languageName,
values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true); values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted); values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid); values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
values[Anum_pg_language_laninline - 1] = ObjectIdGetDatum(inlineOid);
values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid); values[Anum_pg_language_lanvalidator - 1] = ObjectIdGetDatum(valOid);
nulls[Anum_pg_language_lanacl - 1] = true; nulls[Anum_pg_language_lanacl - 1] = true;
...@@ -321,6 +374,15 @@ create_proc_lang(const char *languageName, ...@@ -321,6 +374,15 @@ create_proc_lang(const char *languageName,
referenced.objectSubId = 0; referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL); recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
/* dependency on the inline handler function, if any */
if (OidIsValid(inlineOid))
{
referenced.classId = ProcedureRelationId;
referenced.objectId = inlineOid;
referenced.objectSubId = 0;
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
}
/* dependency on the validator function, if any */ /* dependency on the validator function, if any */
if (OidIsValid(valOid)) if (OidIsValid(valOid))
{ {
...@@ -371,6 +433,11 @@ find_language_template(const char *languageName) ...@@ -371,6 +433,11 @@ find_language_template(const char *languageName)
if (!isnull) if (!isnull)
result->tmplhandler = TextDatumGetCString(datum); result->tmplhandler = TextDatumGetCString(datum);
datum = heap_getattr(tup, Anum_pg_pltemplate_tmplinline,
RelationGetDescr(rel), &isnull);
if (!isnull)
result->tmplinline = TextDatumGetCString(datum);
datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator, datum = heap_getattr(tup, Anum_pg_pltemplate_tmplvalidator,
RelationGetDescr(rel), &isnull); RelationGetDescr(rel), &isnull);
if (!isnull) if (!isnull)
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.437 2009/07/30 02:45:37 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.438 2009/09/22 23:43:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2561,6 +2561,16 @@ _copyRemoveFuncStmt(RemoveFuncStmt *from) ...@@ -2561,6 +2561,16 @@ _copyRemoveFuncStmt(RemoveFuncStmt *from)
return newnode; return newnode;
} }
static DoStmt *
_copyDoStmt(DoStmt *from)
{
DoStmt *newnode = makeNode(DoStmt);
COPY_NODE_FIELD(args);
return newnode;
}
static RemoveOpClassStmt * static RemoveOpClassStmt *
_copyRemoveOpClassStmt(RemoveOpClassStmt *from) _copyRemoveOpClassStmt(RemoveOpClassStmt *from)
{ {
...@@ -3104,6 +3114,7 @@ _copyCreatePLangStmt(CreatePLangStmt *from) ...@@ -3104,6 +3114,7 @@ _copyCreatePLangStmt(CreatePLangStmt *from)
COPY_STRING_FIELD(plname); COPY_STRING_FIELD(plname);
COPY_NODE_FIELD(plhandler); COPY_NODE_FIELD(plhandler);
COPY_NODE_FIELD(plinline);
COPY_NODE_FIELD(plvalidator); COPY_NODE_FIELD(plvalidator);
COPY_SCALAR_FIELD(pltrusted); COPY_SCALAR_FIELD(pltrusted);
...@@ -3797,6 +3808,9 @@ copyObject(void *from) ...@@ -3797,6 +3808,9 @@ copyObject(void *from)
case T_RemoveFuncStmt: case T_RemoveFuncStmt:
retval = _copyRemoveFuncStmt(from); retval = _copyRemoveFuncStmt(from);
break; break;
case T_DoStmt:
retval = _copyDoStmt(from);
break;
case T_RemoveOpClassStmt: case T_RemoveOpClassStmt:
retval = _copyRemoveOpClassStmt(from); retval = _copyRemoveOpClassStmt(from);
break; break;
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.360 2009/07/30 02:45:37 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.361 2009/09/22 23:43:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1212,6 +1212,14 @@ _equalRemoveFuncStmt(RemoveFuncStmt *a, RemoveFuncStmt *b) ...@@ -1212,6 +1212,14 @@ _equalRemoveFuncStmt(RemoveFuncStmt *a, RemoveFuncStmt *b)
return true; return true;
} }
static bool
_equalDoStmt(DoStmt *a, DoStmt *b)
{
COMPARE_NODE_FIELD(args);
return true;
}
static bool static bool
_equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b) _equalRemoveOpClassStmt(RemoveOpClassStmt *a, RemoveOpClassStmt *b)
{ {
...@@ -1667,6 +1675,7 @@ _equalCreatePLangStmt(CreatePLangStmt *a, CreatePLangStmt *b) ...@@ -1667,6 +1675,7 @@ _equalCreatePLangStmt(CreatePLangStmt *a, CreatePLangStmt *b)
{ {
COMPARE_STRING_FIELD(plname); COMPARE_STRING_FIELD(plname);
COMPARE_NODE_FIELD(plhandler); COMPARE_NODE_FIELD(plhandler);
COMPARE_NODE_FIELD(plinline);
COMPARE_NODE_FIELD(plvalidator); COMPARE_NODE_FIELD(plvalidator);
COMPARE_SCALAR_FIELD(pltrusted); COMPARE_SCALAR_FIELD(pltrusted);
...@@ -2576,6 +2585,9 @@ equal(void *a, void *b) ...@@ -2576,6 +2585,9 @@ equal(void *a, void *b)
case T_RemoveFuncStmt: case T_RemoveFuncStmt:
retval = _equalRemoveFuncStmt(a, b); retval = _equalRemoveFuncStmt(a, b);
break; break;
case T_DoStmt:
retval = _equalDoStmt(a, b);
break;
case T_RemoveOpClassStmt: case T_RemoveOpClassStmt:
retval = _equalRemoveOpClassStmt(a, b); retval = _equalRemoveOpClassStmt(a, b);
break; break;
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.678 2009/09/21 20:10:21 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.679 2009/09/22 23:43:38 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -196,7 +196,7 @@ static TypeName *TableFuncTypeName(List *columns); ...@@ -196,7 +196,7 @@ static TypeName *TableFuncTypeName(List *columns);
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateFdwStmt CreateForeignServerStmt CreateAssertStmt CreateTrigStmt CreateFdwStmt CreateForeignServerStmt CreateAssertStmt CreateTrigStmt
CreateUserStmt CreateUserMappingStmt CreateRoleStmt CreateUserStmt CreateUserMappingStmt CreateRoleStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt DoStmt
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
...@@ -246,7 +246,6 @@ static TypeName *TableFuncTypeName(List *columns); ...@@ -246,7 +246,6 @@ static TypeName *TableFuncTypeName(List *columns);
%type <list> OptSchemaEltList %type <list> OptSchemaEltList
%type <boolean> TriggerActionTime TriggerForSpec opt_trusted opt_restart_seqs %type <boolean> TriggerActionTime TriggerForSpec opt_trusted opt_restart_seqs
%type <str> opt_lancompiler
%type <ival> TriggerEvents TriggerOneEvent %type <ival> TriggerEvents TriggerOneEvent
%type <value> TriggerFuncArg %type <value> TriggerFuncArg
...@@ -256,7 +255,7 @@ static TypeName *TableFuncTypeName(List *columns); ...@@ -256,7 +255,7 @@ static TypeName *TableFuncTypeName(List *columns);
index_name name file_name cluster_index_specification index_name name file_name cluster_index_specification
%type <list> func_name handler_name qual_Op qual_all_Op subquery_Op %type <list> func_name handler_name qual_Op qual_all_Op subquery_Op
opt_class opt_validator validator_clause opt_class opt_inline_handler opt_validator validator_clause
%type <range> qualified_name OptConstrFromTable %type <range> qualified_name OptConstrFromTable
...@@ -295,12 +294,12 @@ static TypeName *TableFuncTypeName(List *columns); ...@@ -295,12 +294,12 @@ static TypeName *TableFuncTypeName(List *columns);
execute_param_clause using_clause returning_clause execute_param_clause using_clause returning_clause
enum_val_list table_func_column_list enum_val_list table_func_column_list
create_generic_options alter_generic_options create_generic_options alter_generic_options
relation_expr_list relation_expr_list dostmt_opt_list
%type <range> OptTempTableName %type <range> OptTempTableName
%type <into> into_clause create_as_target %type <into> into_clause create_as_target
%type <defelt> createfunc_opt_item common_func_opt_item %type <defelt> createfunc_opt_item common_func_opt_item dostmt_opt_item
%type <fun_param> func_arg func_arg_with_default table_func_column %type <fun_param> func_arg func_arg_with_default table_func_column
%type <fun_param_mode> arg_class %type <fun_param_mode> arg_class
%type <typnam> func_return func_type %type <typnam> func_return func_type
...@@ -481,7 +480,7 @@ static TypeName *TableFuncTypeName(List *columns); ...@@ -481,7 +480,7 @@ static TypeName *TableFuncTypeName(List *columns);
HANDLER HAVING HEADER_P HOLD HOUR_P HANDLER HAVING HEADER_P HOLD HOUR_P
IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P IDENTITY_P IF_P ILIKE IMMEDIATE IMMUTABLE IMPLICIT_P IN_P
INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INCLUDING INCREMENT INDEX INDEXES INHERIT INHERITS INITIALLY INLINE_P
INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
...@@ -489,7 +488,7 @@ static TypeName *TableFuncTypeName(List *columns); ...@@ -489,7 +488,7 @@ static TypeName *TableFuncTypeName(List *columns);
KEY KEY
LANCOMPILER LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING LANGUAGE LARGE_P LAST_P LC_COLLATE_P LC_CTYPE_P LEADING
LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP
LOCATION LOCK_P LOGIN_P LOCATION LOCK_P LOGIN_P
...@@ -676,6 +675,7 @@ stmt : ...@@ -676,6 +675,7 @@ stmt :
| DefineStmt | DefineStmt
| DeleteStmt | DeleteStmt
| DiscardStmt | DiscardStmt
| DoStmt
| DropAssertStmt | DropAssertStmt
| DropCastStmt | DropCastStmt
| DropFdwStmt | DropFdwStmt
...@@ -2771,19 +2771,20 @@ CreatePLangStmt: ...@@ -2771,19 +2771,20 @@ CreatePLangStmt:
n->plname = $5; n->plname = $5;
/* parameters are all to be supplied by system */ /* parameters are all to be supplied by system */
n->plhandler = NIL; n->plhandler = NIL;
n->plinline = NIL;
n->plvalidator = NIL; n->plvalidator = NIL;
n->pltrusted = false; n->pltrusted = false;
$$ = (Node *)n; $$ = (Node *)n;
} }
| CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst | CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
HANDLER handler_name opt_validator opt_lancompiler HANDLER handler_name opt_inline_handler opt_validator
{ {
CreatePLangStmt *n = makeNode(CreatePLangStmt); CreatePLangStmt *n = makeNode(CreatePLangStmt);
n->plname = $5; n->plname = $5;
n->plhandler = $7; n->plhandler = $7;
n->plvalidator = $8; n->plinline = $8;
n->plvalidator = $9;
n->pltrusted = $2; n->pltrusted = $2;
/* LANCOMPILER is now ignored entirely */
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
...@@ -2802,6 +2803,11 @@ handler_name: ...@@ -2802,6 +2803,11 @@ handler_name:
| name attrs { $$ = lcons(makeString($1), $2); } | name attrs { $$ = lcons(makeString($1), $2); }
; ;
opt_inline_handler:
INLINE_P handler_name { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
validator_clause: validator_clause:
VALIDATOR handler_name { $$ = $2; } VALIDATOR handler_name { $$ = $2; }
| NO VALIDATOR { $$ = NIL; } | NO VALIDATOR { $$ = NIL; }
...@@ -2812,11 +2818,6 @@ opt_validator: ...@@ -2812,11 +2818,6 @@ opt_validator:
| /*EMPTY*/ { $$ = NIL; } | /*EMPTY*/ { $$ = NIL; }
; ;
opt_lancompiler:
LANCOMPILER Sconst { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
DropPLangStmt: DropPLangStmt:
DROP opt_procedural LANGUAGE ColId_or_Sconst opt_drop_behavior DROP opt_procedural LANGUAGE ColId_or_Sconst opt_drop_behavior
{ {
...@@ -5139,6 +5140,38 @@ any_operator: ...@@ -5139,6 +5140,38 @@ any_operator:
{ $$ = lcons(makeString($1), $3); } { $$ = lcons(makeString($1), $3); }
; ;
/*****************************************************************************
*
* DO <anonymous code block> [ LANGUAGE language ]
*
* We use a DefElem list for future extensibility, and to allow flexibility
* in the clause order.
*
*****************************************************************************/
DoStmt: DO dostmt_opt_list
{
DoStmt *n = makeNode(DoStmt);
n->args = $2;
$$ = (Node *)n;
}
;
dostmt_opt_list:
dostmt_opt_item { $$ = list_make1($1); }
| dostmt_opt_list dostmt_opt_item { $$ = lappend($1, $2); }
;
dostmt_opt_item:
Sconst
{
$$ = makeDefElem("as", (Node *)makeString($1));
}
| LANGUAGE ColId_or_Sconst
{
$$ = makeDefElem("language", (Node *)makeString($2));
}
;
/***************************************************************************** /*****************************************************************************
* *
...@@ -10362,6 +10395,7 @@ unreserved_keyword: ...@@ -10362,6 +10395,7 @@ unreserved_keyword:
| INDEXES | INDEXES
| INHERIT | INHERIT
| INHERITS | INHERITS
| INLINE_P
| INPUT_P | INPUT_P
| INSENSITIVE | INSENSITIVE
| INSERT | INSERT
...@@ -10369,7 +10403,6 @@ unreserved_keyword: ...@@ -10369,7 +10403,6 @@ unreserved_keyword:
| INVOKER | INVOKER
| ISOLATION | ISOLATION
| KEY | KEY
| LANCOMPILER
| LANGUAGE | LANGUAGE
| LARGE_P | LARGE_P
| LAST_P | LAST_P
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.313 2009/07/29 20:56:19 tgl Exp $ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.314 2009/09/22 23:43:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -840,6 +840,10 @@ ProcessUtility(Node *parsetree, ...@@ -840,6 +840,10 @@ ProcessUtility(Node *parsetree,
} }
break; break;
case T_DoStmt:
ExecuteDoStmt((DoStmt *) parsetree);
break;
case T_CreatedbStmt: case T_CreatedbStmt:
PreventTransactionChain(isTopLevel, "CREATE DATABASE"); PreventTransactionChain(isTopLevel, "CREATE DATABASE");
createdb((CreatedbStmt *) parsetree); createdb((CreatedbStmt *) parsetree);
...@@ -1761,6 +1765,10 @@ CreateCommandTag(Node *parsetree) ...@@ -1761,6 +1765,10 @@ CreateCommandTag(Node *parsetree)
} }
break; break;
case T_DoStmt:
tag = "DO";
break;
case T_CreatedbStmt: case T_CreatedbStmt:
tag = "CREATE DATABASE"; tag = "CREATE DATABASE";
break; break;
...@@ -2276,6 +2284,10 @@ GetCommandLogLevel(Node *parsetree) ...@@ -2276,6 +2284,10 @@ GetCommandLogLevel(Node *parsetree)
lev = LOGSTMT_DDL; lev = LOGSTMT_DDL;
break; break;
case T_DoStmt:
lev = LOGSTMT_ALL;
break;
case T_CreatedbStmt: case T_CreatedbStmt:
lev = LOGSTMT_DDL; lev = LOGSTMT_DDL;
break; break;
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>. * Written by Peter Eisentraut <peter_e@gmx.net>.
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.518 2009/09/17 21:15:18 petere Exp $ * $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.519 2009/09/22 23:43:38 tgl Exp $
* *
*-------------------------------------------------------------------- *--------------------------------------------------------------------
*/ */
...@@ -385,6 +385,8 @@ char *external_pid_file; ...@@ -385,6 +385,8 @@ char *external_pid_file;
char *pgstat_temp_directory; char *pgstat_temp_directory;
char *default_do_language;
int tcp_keepalives_idle; int tcp_keepalives_idle;
int tcp_keepalives_interval; int tcp_keepalives_interval;
int tcp_keepalives_count; int tcp_keepalives_count;
...@@ -2539,6 +2541,15 @@ static struct config_string ConfigureNamesString[] = ...@@ -2539,6 +2541,15 @@ static struct config_string ConfigureNamesString[] =
}, },
#endif /* USE_SSL */ #endif /* USE_SSL */
{
{"default_do_language", PGC_USERSET, CLIENT_CONN_STATEMENT,
gettext_noop("Sets the language used in DO statement if LANGUAGE is not specified."),
NULL
},
&default_do_language,
"plpgsql", NULL, NULL
},
/* End-of-list marker */ /* End-of-list marker */
{ {
{NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL {NULL, 0, 0, NULL, NULL}, NULL, NULL, NULL, NULL
......
...@@ -422,6 +422,7 @@ ...@@ -422,6 +422,7 @@
#temp_tablespaces = '' # a list of tablespace names, '' uses #temp_tablespaces = '' # a list of tablespace names, '' uses
# only default tablespace # only default tablespace
#check_function_bodies = on #check_function_bodies = on
#default_do_language = 'plpgsql'
#default_transaction_isolation = 'read committed' #default_transaction_isolation = 'read committed'
#default_transaction_read_only = off #default_transaction_read_only = off
#session_replication_role = 'origin' #session_replication_role = 'origin'
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* by PostgreSQL * by PostgreSQL
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.547 2009/09/11 19:17:04 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.548 2009/09/22 23:43:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -4445,6 +4445,7 @@ getProcLangs(int *numProcLangs) ...@@ -4445,6 +4445,7 @@ getProcLangs(int *numProcLangs)
int i_lanname; int i_lanname;
int i_lanpltrusted; int i_lanpltrusted;
int i_lanplcallfoid; int i_lanplcallfoid;
int i_laninline;
int i_lanvalidator; int i_lanvalidator;
int i_lanacl; int i_lanacl;
int i_lanowner; int i_lanowner;
...@@ -4452,7 +4453,19 @@ getProcLangs(int *numProcLangs) ...@@ -4452,7 +4453,19 @@ getProcLangs(int *numProcLangs)
/* Make sure we are in proper schema */ /* Make sure we are in proper schema */
selectSourceSchema("pg_catalog"); selectSourceSchema("pg_catalog");
if (g_fout->remoteVersion >= 80300) if (g_fout->remoteVersion >= 80500)
{
/* pg_language has a laninline column */
appendPQExpBuffer(query, "SELECT tableoid, oid, "
"lanname, lanpltrusted, lanplcallfoid, "
"laninline, lanvalidator, lanacl, "
"(%s lanowner) AS lanowner "
"FROM pg_language "
"WHERE lanispl "
"ORDER BY oid",
username_subquery);
}
else if (g_fout->remoteVersion >= 80300)
{ {
/* pg_language has a lanowner column */ /* pg_language has a lanowner column */
appendPQExpBuffer(query, "SELECT tableoid, oid, " appendPQExpBuffer(query, "SELECT tableoid, oid, "
...@@ -4515,6 +4528,7 @@ getProcLangs(int *numProcLangs) ...@@ -4515,6 +4528,7 @@ getProcLangs(int *numProcLangs)
i_lanpltrusted = PQfnumber(res, "lanpltrusted"); i_lanpltrusted = PQfnumber(res, "lanpltrusted");
i_lanplcallfoid = PQfnumber(res, "lanplcallfoid"); i_lanplcallfoid = PQfnumber(res, "lanplcallfoid");
/* these may fail and return -1: */ /* these may fail and return -1: */
i_laninline = PQfnumber(res, "laninline");
i_lanvalidator = PQfnumber(res, "lanvalidator"); i_lanvalidator = PQfnumber(res, "lanvalidator");
i_lanacl = PQfnumber(res, "lanacl"); i_lanacl = PQfnumber(res, "lanacl");
i_lanowner = PQfnumber(res, "lanowner"); i_lanowner = PQfnumber(res, "lanowner");
...@@ -4529,6 +4543,10 @@ getProcLangs(int *numProcLangs) ...@@ -4529,6 +4543,10 @@ getProcLangs(int *numProcLangs)
planginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_lanname)); planginfo[i].dobj.name = strdup(PQgetvalue(res, i, i_lanname));
planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't'; planginfo[i].lanpltrusted = *(PQgetvalue(res, i, i_lanpltrusted)) == 't';
planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid)); planginfo[i].lanplcallfoid = atooid(PQgetvalue(res, i, i_lanplcallfoid));
if (i_laninline >= 0)
planginfo[i].laninline = atooid(PQgetvalue(res, i, i_laninline));
else
planginfo[i].laninline = InvalidOid;
if (i_lanvalidator >= 0) if (i_lanvalidator >= 0)
planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator)); planginfo[i].lanvalidator = atooid(PQgetvalue(res, i, i_lanvalidator));
else else
...@@ -6994,6 +7012,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang) ...@@ -6994,6 +7012,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
char *qlanname; char *qlanname;
char *lanschema; char *lanschema;
FuncInfo *funcInfo; FuncInfo *funcInfo;
FuncInfo *inlineInfo = NULL;
FuncInfo *validatorInfo = NULL; FuncInfo *validatorInfo = NULL;
if (dataOnly) if (dataOnly)
...@@ -7011,6 +7030,13 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang) ...@@ -7011,6 +7030,13 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
if (funcInfo != NULL && !funcInfo->dobj.dump) if (funcInfo != NULL && !funcInfo->dobj.dump)
funcInfo = NULL; /* treat not-dumped same as not-found */ funcInfo = NULL; /* treat not-dumped same as not-found */
if (OidIsValid(plang->laninline))
{
inlineInfo = findFuncByOid(plang->laninline);
if (inlineInfo != NULL && !inlineInfo->dobj.dump)
inlineInfo = NULL;
}
if (OidIsValid(plang->lanvalidator)) if (OidIsValid(plang->lanvalidator))
{ {
validatorInfo = findFuncByOid(plang->lanvalidator); validatorInfo = findFuncByOid(plang->lanvalidator);
...@@ -7024,6 +7050,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang) ...@@ -7024,6 +7050,7 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
* dump it. * dump it.
*/ */
useParams = (funcInfo != NULL && useParams = (funcInfo != NULL &&
(inlineInfo != NULL || !OidIsValid(plang->laninline)) &&
(validatorInfo != NULL || !OidIsValid(plang->lanvalidator))); (validatorInfo != NULL || !OidIsValid(plang->lanvalidator)));
if (!useParams && !shouldDumpProcLangs()) if (!useParams && !shouldDumpProcLangs())
...@@ -7054,6 +7081,16 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang) ...@@ -7054,6 +7081,16 @@ dumpProcLang(Archive *fout, ProcLangInfo *plang)
{ {
appendPQExpBuffer(defqry, " HANDLER %s", appendPQExpBuffer(defqry, " HANDLER %s",
fmtId(funcInfo->dobj.name)); fmtId(funcInfo->dobj.name));
if (OidIsValid(plang->laninline))
{
appendPQExpBuffer(defqry, " INLINE ");
/* Cope with possibility that inline is in different schema */
if (inlineInfo->dobj.namespace != funcInfo->dobj.namespace)
appendPQExpBuffer(defqry, "%s.",
fmtId(inlineInfo->dobj.namespace->dobj.name));
appendPQExpBuffer(defqry, "%s",
fmtId(inlineInfo->dobj.name));
}
if (OidIsValid(plang->lanvalidator)) if (OidIsValid(plang->lanvalidator))
{ {
appendPQExpBuffer(defqry, " VALIDATOR "); appendPQExpBuffer(defqry, " VALIDATOR ");
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.156 2009/08/02 22:14:52 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.157 2009/09/22 23:43:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -357,6 +357,7 @@ typedef struct _procLangInfo ...@@ -357,6 +357,7 @@ typedef struct _procLangInfo
DumpableObject dobj; DumpableObject dobj;
bool lanpltrusted; bool lanpltrusted;
Oid lanplcallfoid; Oid lanplcallfoid;
Oid laninline;
Oid lanvalidator; Oid lanvalidator;
char *lanacl; char *lanacl;
char *lanowner; /* name of owner, or empty string */ char *lanowner; /* name of owner, or empty string */
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/bin/scripts/droplang.c,v 1.31 2009/02/26 16:02:39 petere Exp $ * $PostgreSQL: pgsql/src/bin/scripts/droplang.c,v 1.32 2009/09/22 23:43:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -38,7 +38,6 @@ main(int argc, char *argv[]) ...@@ -38,7 +38,6 @@ main(int argc, char *argv[])
const char *progname; const char *progname;
int optindex; int optindex;
int c; int c;
bool listlangs = false; bool listlangs = false;
const char *dbname = NULL; const char *dbname = NULL;
char *host = NULL; char *host = NULL;
...@@ -47,19 +46,20 @@ main(int argc, char *argv[]) ...@@ -47,19 +46,20 @@ main(int argc, char *argv[])
enum trivalue prompt_password = TRI_DEFAULT; enum trivalue prompt_password = TRI_DEFAULT;
bool echo = false; bool echo = false;
char *langname = NULL; char *langname = NULL;
char *p; char *p;
Oid lanplcallfoid; Oid lanplcallfoid;
Oid laninline;
Oid lanvalidator; Oid lanvalidator;
char *handler; char *handler;
char *inline_handler;
char *validator; char *validator;
char *handler_ns; char *handler_ns;
char *inline_ns;
char *validator_ns; char *validator_ns;
bool keephandler; bool keephandler;
bool keepinline;
bool keepvalidator; bool keepvalidator;
PQExpBufferData sql; PQExpBufferData sql;
PGconn *conn; PGconn *conn;
PGresult *result; PGresult *result;
...@@ -190,10 +190,10 @@ main(int argc, char *argv[]) ...@@ -190,10 +190,10 @@ main(int argc, char *argv[])
executeCommand(conn, "SET search_path = pg_catalog;", progname, echo); executeCommand(conn, "SET search_path = pg_catalog;", progname, echo);
/* /*
* Make sure the language is installed and find the OIDs of the handler * Make sure the language is installed and find the OIDs of the
* and validator functions * language support functions
*/ */
printfPQExpBuffer(&sql, "SELECT lanplcallfoid, lanvalidator " printfPQExpBuffer(&sql, "SELECT lanplcallfoid, laninline, lanvalidator "
"FROM pg_language WHERE lanname = '%s' AND lanispl;", "FROM pg_language WHERE lanname = '%s' AND lanispl;",
langname); langname);
result = executeQuery(conn, sql.data, progname, echo); result = executeQuery(conn, sql.data, progname, echo);
...@@ -206,7 +206,8 @@ main(int argc, char *argv[]) ...@@ -206,7 +206,8 @@ main(int argc, char *argv[])
exit(1); exit(1);
} }
lanplcallfoid = atooid(PQgetvalue(result, 0, 0)); lanplcallfoid = atooid(PQgetvalue(result, 0, 0));
lanvalidator = atooid(PQgetvalue(result, 0, 1)); laninline = atooid(PQgetvalue(result, 0, 1));
lanvalidator = atooid(PQgetvalue(result, 0, 2));
PQclear(result); PQclear(result);
/* /*
...@@ -260,6 +261,44 @@ main(int argc, char *argv[]) ...@@ -260,6 +261,44 @@ main(int argc, char *argv[])
handler_ns = NULL; handler_ns = NULL;
} }
/*
* Check that the inline function isn't used by some other language
*/
if (OidIsValid(laninline))
{
printfPQExpBuffer(&sql, "SELECT count(*) FROM pg_language "
"WHERE laninline = %u AND lanname <> '%s';",
laninline, langname);
result = executeQuery(conn, sql.data, progname, echo);
if (strcmp(PQgetvalue(result, 0, 0), "0") == 0)
keepinline = false;
else
keepinline = true;
PQclear(result);
}
else
keepinline = true; /* don't try to delete it */
/*
* Find the inline handler name
*/
if (!keepinline)
{
printfPQExpBuffer(&sql, "SELECT proname, (SELECT nspname "
"FROM pg_namespace ns WHERE ns.oid = pronamespace) "
"AS prons FROM pg_proc WHERE oid = %u;",
laninline);
result = executeQuery(conn, sql.data, progname, echo);
inline_handler = strdup(PQgetvalue(result, 0, 0));
inline_ns = strdup(PQgetvalue(result, 0, 1));
PQclear(result);
}
else
{
inline_handler = NULL;
inline_ns = NULL;
}
/* /*
* Check that the validator function isn't used by some other language * Check that the validator function isn't used by some other language
*/ */
...@@ -305,6 +344,9 @@ main(int argc, char *argv[]) ...@@ -305,6 +344,9 @@ main(int argc, char *argv[])
if (!keephandler) if (!keephandler)
appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" ();\n", appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" ();\n",
handler_ns, handler); handler_ns, handler);
if (!keepinline)
appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" (internal);\n",
inline_ns, inline_handler);
if (!keepvalidator) if (!keepvalidator)
appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" (oid);\n", appendPQExpBuffer(&sql, "DROP FUNCTION \"%s\".\"%s\" (oid);\n",
validator_ns, validator); validator_ns, validator);
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.538 2009/09/01 03:53:08 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.539 2009/09/22 23:43:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200908311 #define CATALOG_VERSION_NO 200909221
#endif #endif
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_language.h,v 1.34 2009/01/01 17:23:57 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_language.h,v 1.35 2009/09/22 23:43:41 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -35,6 +35,7 @@ CATALOG(pg_language,2612) ...@@ -35,6 +35,7 @@ CATALOG(pg_language,2612)
bool lanispl; /* Is a procedural language */ bool lanispl; /* Is a procedural language */
bool lanpltrusted; /* PL is trusted */ bool lanpltrusted; /* PL is trusted */
Oid lanplcallfoid; /* Call handler for PL */ Oid lanplcallfoid; /* Call handler for PL */
Oid laninline; /* Optional anonymous-block handler function */
Oid lanvalidator; /* Optional validation function */ Oid lanvalidator; /* Optional validation function */
aclitem lanacl[1]; /* Access privileges */ aclitem lanacl[1]; /* Access privileges */
} FormData_pg_language; } FormData_pg_language;
...@@ -50,27 +51,28 @@ typedef FormData_pg_language *Form_pg_language; ...@@ -50,27 +51,28 @@ typedef FormData_pg_language *Form_pg_language;
* compiler constants for pg_language * compiler constants for pg_language
* ---------------- * ----------------
*/ */
#define Natts_pg_language 7 #define Natts_pg_language 8
#define Anum_pg_language_lanname 1 #define Anum_pg_language_lanname 1
#define Anum_pg_language_lanowner 2 #define Anum_pg_language_lanowner 2
#define Anum_pg_language_lanispl 3 #define Anum_pg_language_lanispl 3
#define Anum_pg_language_lanpltrusted 4 #define Anum_pg_language_lanpltrusted 4
#define Anum_pg_language_lanplcallfoid 5 #define Anum_pg_language_lanplcallfoid 5
#define Anum_pg_language_lanvalidator 6 #define Anum_pg_language_laninline 6
#define Anum_pg_language_lanacl 7 #define Anum_pg_language_lanvalidator 7
#define Anum_pg_language_lanacl 8
/* ---------------- /* ----------------
* initial contents of pg_language * initial contents of pg_language
* ---------------- * ----------------
*/ */
DATA(insert OID = 12 ( "internal" PGUID f f 0 2246 _null_ )); DATA(insert OID = 12 ( "internal" PGUID f f 0 0 2246 _null_ ));
DESCR("built-in functions"); DESCR("built-in functions");
#define INTERNALlanguageId 12 #define INTERNALlanguageId 12
DATA(insert OID = 13 ( "c" PGUID f f 0 2247 _null_ )); DATA(insert OID = 13 ( "c" PGUID f f 0 0 2247 _null_ ));
DESCR("dynamically-loaded C functions"); DESCR("dynamically-loaded C functions");
#define ClanguageId 13 #define ClanguageId 13
DATA(insert OID = 14 ( "sql" PGUID f t 0 2248 _null_ )); DATA(insert OID = 14 ( "sql" PGUID f t 0 0 2248 _null_ ));
DESCR("SQL-language functions"); DESCR("SQL-language functions");
#define SQLlanguageId 14 #define SQLlanguageId 14
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.7 2009/01/01 17:23:57 momjian Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.8 2009/09/22 23:43:41 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
...@@ -34,6 +34,7 @@ CATALOG(pg_pltemplate,1136) BKI_SHARED_RELATION BKI_WITHOUT_OIDS ...@@ -34,6 +34,7 @@ CATALOG(pg_pltemplate,1136) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
bool tmpltrusted; /* PL is trusted? */ bool tmpltrusted; /* PL is trusted? */
bool tmpldbacreate; /* PL is installable by db owner? */ bool tmpldbacreate; /* PL is installable by db owner? */
text tmplhandler; /* name of call handler function */ text tmplhandler; /* name of call handler function */
text tmplinline; /* name of anonymous-block handler, or NULL */
text tmplvalidator; /* name of validator function, or NULL */ text tmplvalidator; /* name of validator function, or NULL */
text tmpllibrary; /* path of shared library */ text tmpllibrary; /* path of shared library */
aclitem tmplacl[1]; /* access privileges for template */ aclitem tmplacl[1]; /* access privileges for template */
...@@ -50,14 +51,15 @@ typedef FormData_pg_pltemplate *Form_pg_pltemplate; ...@@ -50,14 +51,15 @@ typedef FormData_pg_pltemplate *Form_pg_pltemplate;
* compiler constants for pg_pltemplate * compiler constants for pg_pltemplate
* ---------------- * ----------------
*/ */
#define Natts_pg_pltemplate 7 #define Natts_pg_pltemplate 8
#define Anum_pg_pltemplate_tmplname 1 #define Anum_pg_pltemplate_tmplname 1
#define Anum_pg_pltemplate_tmpltrusted 2 #define Anum_pg_pltemplate_tmpltrusted 2
#define Anum_pg_pltemplate_tmpldbacreate 3 #define Anum_pg_pltemplate_tmpldbacreate 3
#define Anum_pg_pltemplate_tmplhandler 4 #define Anum_pg_pltemplate_tmplhandler 4
#define Anum_pg_pltemplate_tmplvalidator 5 #define Anum_pg_pltemplate_tmplinline 5
#define Anum_pg_pltemplate_tmpllibrary 6 #define Anum_pg_pltemplate_tmplvalidator 6
#define Anum_pg_pltemplate_tmplacl 7 #define Anum_pg_pltemplate_tmpllibrary 7
#define Anum_pg_pltemplate_tmplacl 8
/* ---------------- /* ----------------
...@@ -65,11 +67,11 @@ typedef FormData_pg_pltemplate *Form_pg_pltemplate; ...@@ -65,11 +67,11 @@ typedef FormData_pg_pltemplate *Form_pg_pltemplate;
* ---------------- * ----------------
*/ */
DATA(insert ( "plpgsql" t t "plpgsql_call_handler" "plpgsql_validator" "$libdir/plpgsql" _null_ )); DATA(insert ( "plpgsql" t t "plpgsql_call_handler" "plpgsql_inline_handler" "plpgsql_validator" "$libdir/plpgsql" _null_ ));
DATA(insert ( "pltcl" t t "pltcl_call_handler" _null_ "$libdir/pltcl" _null_ )); DATA(insert ( "pltcl" t t "pltcl_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
DATA(insert ( "pltclu" f f "pltclu_call_handler" _null_ "$libdir/pltcl" _null_ )); DATA(insert ( "pltclu" f f "pltclu_call_handler" _null_ _null_ "$libdir/pltcl" _null_ ));
DATA(insert ( "plperl" t t "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ )); DATA(insert ( "plperl" t t "plperl_call_handler" _null_ "plperl_validator" "$libdir/plperl" _null_ ));
DATA(insert ( "plperlu" f f "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ )); DATA(insert ( "plperlu" f f "plperl_call_handler" _null_ "plperl_validator" "$libdir/plperl" _null_ ));
DATA(insert ( "plpythonu" f f "plpython_call_handler" _null_ "$libdir/plpython" _null_ )); DATA(insert ( "plpythonu" f f "plpython_call_handler" _null_ _null_ "$libdir/plpython" _null_ ));
#endif /* PG_PLTEMPLATE_H */ #endif /* PG_PLTEMPLATE_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.96 2009/07/29 20:56:20 tgl Exp $ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.97 2009/09/22 23:43:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -61,6 +61,7 @@ extern void DropCast(DropCastStmt *stmt); ...@@ -61,6 +61,7 @@ extern void DropCast(DropCastStmt *stmt);
extern void DropCastById(Oid castOid); extern void DropCastById(Oid castOid);
extern void AlterFunctionNamespace(List *name, List *argtypes, bool isagg, extern void AlterFunctionNamespace(List *name, List *argtypes, bool isagg,
const char *newschema); const char *newschema);
extern void ExecuteDoStmt(DoStmt *stmt);
/* commands/operatorcmds.c */ /* commands/operatorcmds.c */
extern void DefineOperator(List *names, List *parameters); extern void DefineOperator(List *names, List *parameters);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.225 2009/09/17 20:49:29 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.226 2009/09/22 23:43:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -274,6 +274,7 @@ typedef enum NodeTag ...@@ -274,6 +274,7 @@ typedef enum NodeTag
T_CreateFunctionStmt, T_CreateFunctionStmt,
T_AlterFunctionStmt, T_AlterFunctionStmt,
T_RemoveFuncStmt, T_RemoveFuncStmt,
T_DoStmt,
T_RenameStmt, T_RenameStmt,
T_RuleStmt, T_RuleStmt,
T_NotifyStmt, T_NotifyStmt,
...@@ -388,7 +389,8 @@ typedef enum NodeTag ...@@ -388,7 +389,8 @@ typedef enum NodeTag
T_TriggerData = 950, /* in commands/trigger.h */ T_TriggerData = 950, /* in commands/trigger.h */
T_ReturnSetInfo, /* in nodes/execnodes.h */ T_ReturnSetInfo, /* in nodes/execnodes.h */
T_WindowObjectData, /* private in nodeWindowAgg.c */ T_WindowObjectData, /* private in nodeWindowAgg.c */
T_TIDBitmap /* in nodes/tidbitmap.h */ T_TIDBitmap, /* in nodes/tidbitmap.h */
T_InlineCodeBlock /* in nodes/parsenodes.h */
} NodeTag; } NodeTag;
/* /*
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.401 2009/08/02 22:14:53 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.402 2009/09/22 23:43:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1570,6 +1570,7 @@ typedef struct CreatePLangStmt ...@@ -1570,6 +1570,7 @@ typedef struct CreatePLangStmt
NodeTag type; NodeTag type;
char *plname; /* PL name */ char *plname; /* PL name */
List *plhandler; /* PL call handler function (qual. name) */ List *plhandler; /* PL call handler function (qual. name) */
List *plinline; /* optional inline function (qual. name) */
List *plvalidator; /* optional validator function (qual. name) */ List *plvalidator; /* optional validator function (qual. name) */
bool pltrusted; /* PL is trusted */ bool pltrusted; /* PL is trusted */
} CreatePLangStmt; } CreatePLangStmt;
...@@ -1922,6 +1923,25 @@ typedef struct RemoveFuncStmt ...@@ -1922,6 +1923,25 @@ typedef struct RemoveFuncStmt
bool missing_ok; /* skip error if missing? */ bool missing_ok; /* skip error if missing? */
} RemoveFuncStmt; } RemoveFuncStmt;
/* ----------------------
* DO Statement
*
* DoStmt is the raw parser output, InlineCodeBlock is the execution-time API
* ----------------------
*/
typedef struct DoStmt
{
NodeTag type;
List *args; /* List of DefElem nodes */
} DoStmt;
typedef struct InlineCodeBlock
{
NodeTag type;
char *source_text; /* source text of anonymous code block */
Oid langOid; /* OID of selected language */
} InlineCodeBlock;
/* ---------------------- /* ----------------------
* Drop Operator Class Statement * Drop Operator Class Statement
* ---------------------- * ----------------------
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.2 2009/04/06 08:42:53 heikki Exp $ * $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.3 2009/09/22 23:43:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -187,6 +187,7 @@ PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD) ...@@ -187,6 +187,7 @@ PG_KEYWORD("indexes", INDEXES, UNRESERVED_KEYWORD)
PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD) PG_KEYWORD("inherit", INHERIT, UNRESERVED_KEYWORD)
PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD) PG_KEYWORD("inherits", INHERITS, UNRESERVED_KEYWORD)
PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD) PG_KEYWORD("initially", INITIALLY, RESERVED_KEYWORD)
PG_KEYWORD("inline", INLINE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("inner", INNER_P, TYPE_FUNC_NAME_KEYWORD)
PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD) PG_KEYWORD("inout", INOUT, COL_NAME_KEYWORD)
PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD) PG_KEYWORD("input", INPUT_P, UNRESERVED_KEYWORD)
...@@ -204,7 +205,6 @@ PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD) ...@@ -204,7 +205,6 @@ PG_KEYWORD("isnull", ISNULL, TYPE_FUNC_NAME_KEYWORD)
PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD) PG_KEYWORD("isolation", ISOLATION, UNRESERVED_KEYWORD)
PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("join", JOIN, TYPE_FUNC_NAME_KEYWORD)
PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD) PG_KEYWORD("key", KEY, UNRESERVED_KEYWORD)
PG_KEYWORD("lancompiler", LANCOMPILER, UNRESERVED_KEYWORD)
PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD) PG_KEYWORD("language", LANGUAGE, UNRESERVED_KEYWORD)
PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD) PG_KEYWORD("large", LARGE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD) PG_KEYWORD("last", LAST_P, UNRESERVED_KEYWORD)
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Copyright (c) 2000-2009, PostgreSQL Global Development Group * Copyright (c) 2000-2009, PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>. * Written by Peter Eisentraut <peter_e@gmx.net>.
* *
* $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.104 2009/09/03 22:08:05 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/guc.h,v 1.105 2009/09/22 23:43:41 tgl Exp $
*-------------------------------------------------------------------- *--------------------------------------------------------------------
*/ */
#ifndef GUC_H #ifndef GUC_H
...@@ -178,6 +178,8 @@ extern char *HbaFileName; ...@@ -178,6 +178,8 @@ extern char *HbaFileName;
extern char *IdentFileName; extern char *IdentFileName;
extern char *external_pid_file; extern char *external_pid_file;
extern char *default_do_language;
extern int tcp_keepalives_idle; extern int tcp_keepalives_idle;
extern int tcp_keepalives_interval; extern int tcp_keepalives_interval;
extern int tcp_keepalives_count; extern int tcp_keepalives_count;
......
/* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.trailer,v 1.11 2009/08/14 13:28:22 meskes Exp $ */ /* $PostgreSQL: pgsql/src/interfaces/ecpg/preproc/ecpg.trailer,v 1.12 2009/09/22 23:43:42 tgl Exp $ */
statements: /*EMPTY*/ statements: /*EMPTY*/
| statements statement | statements statement
...@@ -1614,12 +1614,12 @@ ECPGunreserved_con: ABORT_P { $$ = make_str("abort"); } ...@@ -1614,12 +1614,12 @@ ECPGunreserved_con: ABORT_P { $$ = make_str("abort"); }
| INDEXES { $$ = make_str("indexes"); } | INDEXES { $$ = make_str("indexes"); }
| INHERIT { $$ = make_str("inherit"); } | INHERIT { $$ = make_str("inherit"); }
| INHERITS { $$ = make_str("inherits"); } | INHERITS { $$ = make_str("inherits"); }
| INLINE_P { $$ = make_str("inline"); }
| INSENSITIVE { $$ = make_str("insensitive"); } | INSENSITIVE { $$ = make_str("insensitive"); }
| INSERT { $$ = make_str("insert"); } | INSERT { $$ = make_str("insert"); }
| INSTEAD { $$ = make_str("instead"); } | INSTEAD { $$ = make_str("instead"); }
| ISOLATION { $$ = make_str("isolation"); } | ISOLATION { $$ = make_str("isolation"); }
| KEY { $$ = make_str("key"); } | KEY { $$ = make_str("key"); }
| LANCOMPILER { $$ = make_str("lancompiler"); }
| LANGUAGE { $$ = make_str("language"); } | LANGUAGE { $$ = make_str("language"); }
| LARGE_P { $$ = make_str("large"); } | LARGE_P { $$ = make_str("large"); }
| LAST_P { $$ = make_str("last"); } | LAST_P { $$ = make_str("last"); }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.138 2009/09/20 01:53:32 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.139 2009/09/22 23:43:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -95,6 +95,7 @@ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo, ...@@ -95,6 +95,7 @@ static PLpgSQL_function *do_compile(FunctionCallInfo fcinfo,
PLpgSQL_function *function, PLpgSQL_function *function,
PLpgSQL_func_hashkey *hashkey, PLpgSQL_func_hashkey *hashkey,
bool forValidator); bool forValidator);
static void add_dummy_return(PLpgSQL_function *function);
static PLpgSQL_row *build_row_from_class(Oid classOid); static PLpgSQL_row *build_row_from_class(Oid classOid);
static PLpgSQL_row *build_row_from_vars(PLpgSQL_variable **vars, int numvars); static PLpgSQL_row *build_row_from_vars(PLpgSQL_variable **vars, int numvars);
static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod); static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod);
...@@ -670,36 +671,11 @@ do_compile(FunctionCallInfo fcinfo, ...@@ -670,36 +671,11 @@ do_compile(FunctionCallInfo fcinfo,
* If it has OUT parameters or returns VOID or returns a set, we allow * If it has OUT parameters or returns VOID or returns a set, we allow
* control to fall off the end without an explicit RETURN statement. The * control to fall off the end without an explicit RETURN statement. The
* easiest way to implement this is to add a RETURN statement to the end * easiest way to implement this is to add a RETURN statement to the end
* of the statement list during parsing. However, if the outer block has * of the statement list during parsing.
* an EXCEPTION clause, we need to make a new outer block, since the added
* RETURN shouldn't act like it is inside the EXCEPTION clause.
*/ */
if (num_out_args > 0 || function->fn_rettype == VOIDOID || if (num_out_args > 0 || function->fn_rettype == VOIDOID ||
function->fn_retset) function->fn_retset)
{ add_dummy_return(function);
if (function->action->exceptions != NULL)
{
PLpgSQL_stmt_block *new;
new = palloc0(sizeof(PLpgSQL_stmt_block));
new->cmd_type = PLPGSQL_STMT_BLOCK;
new->body = list_make1(function->action);
function->action = new;
}
if (function->action->body == NIL ||
((PLpgSQL_stmt *) llast(function->action->body))->cmd_type != PLPGSQL_STMT_RETURN)
{
PLpgSQL_stmt_return *new;
new = palloc0(sizeof(PLpgSQL_stmt_return));
new->cmd_type = PLPGSQL_STMT_RETURN;
new->expr = NULL;
new->retvarno = function->out_param_varno;
function->action->body = lappend(function->action->body, new);
}
}
/* /*
* Complete the function's info * Complete the function's info
...@@ -735,12 +711,150 @@ do_compile(FunctionCallInfo fcinfo, ...@@ -735,12 +711,150 @@ do_compile(FunctionCallInfo fcinfo,
return function; return function;
} }
/* ----------
* plpgsql_compile_inline Make an execution tree for an anonymous code block.
*
* Note: this is generally parallel to do_compile(); is it worth trying to
* merge the two?
*
* Note: we assume the block will be thrown away so there is no need to build
* persistent data structures.
* ----------
*/
PLpgSQL_function *
plpgsql_compile_inline(char *proc_source)
{
char *func_name = "inline_code_block";
PLpgSQL_function *function;
ErrorContextCallback plerrcontext;
Oid typinput;
PLpgSQL_variable *var;
int parse_rc;
MemoryContext func_cxt;
int i;
/*
* Setup the scanner input and error info. We assume that this function
* cannot be invoked recursively, so there's no need to save and restore
* the static variables used here.
*/
plpgsql_scanner_init(proc_source);
plpgsql_error_funcname = func_name;
plpgsql_error_lineno = 0;
/*
* Setup error traceback support for ereport()
*/
plerrcontext.callback = plpgsql_compile_error_callback;
plerrcontext.arg = proc_source;
plerrcontext.previous = error_context_stack;
error_context_stack = &plerrcontext;
plpgsql_ns_init();
plpgsql_ns_push(func_name);
plpgsql_DumpExecTree = false;
datums_alloc = 128;
plpgsql_nDatums = 0;
plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc);
datums_last = 0;
/* Do extra syntax checking if check_function_bodies is on */
plpgsql_check_syntax = check_function_bodies;
/* Function struct does not live past current statement */
function = (PLpgSQL_function *) palloc0(sizeof(PLpgSQL_function));
plpgsql_curr_compile = function;
/*
* All the rest of the compile-time storage (e.g. parse tree) is kept in
* its own memory context, so it can be reclaimed easily.
*/
func_cxt = AllocSetContextCreate(CurrentMemoryContext,
"PL/PgSQL function context",
ALLOCSET_DEFAULT_MINSIZE,
ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
compile_tmp_cxt = MemoryContextSwitchTo(func_cxt);
function->fn_name = pstrdup(func_name);
function->fn_is_trigger = false;
function->fn_cxt = func_cxt;
function->out_param_varno = -1; /* set up for no OUT param */
/* Set up as though in a function returning VOID */
function->fn_rettype = VOIDOID;
function->fn_retset = false;
function->fn_retistuple = false;
/* a bit of hardwired knowledge about type VOID here */
function->fn_retbyval = true;
function->fn_rettyplen = sizeof(int32);
getTypeInputInfo(VOIDOID, &typinput, &function->fn_rettypioparam);
fmgr_info(typinput, &(function->fn_retinput));
/*
* Remember if function is STABLE/IMMUTABLE. XXX would it be better
* to set this TRUE inside a read-only transaction? Not clear.
*/
function->fn_readonly = false;
/*
* Create the magic FOUND variable.
*/
var = plpgsql_build_variable("found", 0,
plpgsql_build_datatype(BOOLOID, -1),
true);
function->found_varno = var->dno;
/*
* Now parse the function's text
*/
parse_rc = plpgsql_yyparse();
if (parse_rc != 0)
elog(ERROR, "plpgsql parser returned %d", parse_rc);
function->action = plpgsql_yylval.program;
plpgsql_scanner_finish();
/*
* If it returns VOID (always true at the moment), we allow control to
* fall off the end without an explicit RETURN statement.
*/
if (function->fn_rettype == VOIDOID)
add_dummy_return(function);
/*
* Complete the function's info
*/
function->fn_nargs = 0;
function->ndatums = plpgsql_nDatums;
function->datums = palloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
for (i = 0; i < plpgsql_nDatums; i++)
function->datums[i] = plpgsql_Datums[i];
/*
* Pop the error context stack
*/
error_context_stack = plerrcontext.previous;
plpgsql_error_funcname = NULL;
plpgsql_error_lineno = 0;
plpgsql_check_syntax = false;
MemoryContextSwitchTo(compile_tmp_cxt);
compile_tmp_cxt = NULL;
return function;
}
/* /*
* error context callback to let us supply a call-stack traceback. If * error context callback to let us supply a call-stack traceback.
* we are validating, the function source is passed as an * If we are validating or executing an anonymous code block, the function
* argument. This function is public only for the sake of an assertion * source text is passed as an argument.
* in gram.y *
* This function is public only for the sake of an assertion in gram.y
*/ */
void void
plpgsql_compile_error_callback(void *arg) plpgsql_compile_error_callback(void *arg)
...@@ -749,7 +863,7 @@ plpgsql_compile_error_callback(void *arg) ...@@ -749,7 +863,7 @@ plpgsql_compile_error_callback(void *arg)
{ {
/* /*
* Try to convert syntax error position to reference text of original * Try to convert syntax error position to reference text of original
* CREATE FUNCTION command. * CREATE FUNCTION or DO command.
*/ */
if (function_parse_error_transpose((const char *) arg)) if (function_parse_error_transpose((const char *) arg))
return; return;
...@@ -766,6 +880,42 @@ plpgsql_compile_error_callback(void *arg) ...@@ -766,6 +880,42 @@ plpgsql_compile_error_callback(void *arg)
} }
/*
* Add a dummy RETURN statement to the given function's body
*/
static void
add_dummy_return(PLpgSQL_function *function)
{
/*
* If the outer block has an EXCEPTION clause, we need to make a new outer
* block, since the added RETURN shouldn't act like it is inside the
* EXCEPTION clause.
*/
if (function->action->exceptions != NULL)
{
PLpgSQL_stmt_block *new;
new = palloc0(sizeof(PLpgSQL_stmt_block));
new->cmd_type = PLPGSQL_STMT_BLOCK;
new->body = list_make1(function->action);
function->action = new;
}
if (function->action->body == NIL ||
((PLpgSQL_stmt *) llast(function->action->body))->cmd_type != PLPGSQL_STMT_RETURN)
{
PLpgSQL_stmt_return *new;
new = palloc0(sizeof(PLpgSQL_stmt_return));
new->cmd_type = PLPGSQL_STMT_RETURN;
new->expr = NULL;
new->retvarno = function->out_param_varno;
function->action->body = lappend(function->action->body, new);
}
}
/* ---------- /* ----------
* plpgsql_parse_word The scanner calls this to postparse * plpgsql_parse_word The scanner calls this to postparse
* any single word not found by a * any single word not found by a
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.45 2009/08/04 21:22:46 alvherre Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_handler.c,v 1.46 2009/09/22 23:43:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -114,6 +114,57 @@ plpgsql_call_handler(PG_FUNCTION_ARGS) ...@@ -114,6 +114,57 @@ plpgsql_call_handler(PG_FUNCTION_ARGS)
return retval; return retval;
} }
/* ----------
* plpgsql_inline_handler
*
* Called by PostgreSQL to execute an anonymous code block
* ----------
*/
PG_FUNCTION_INFO_V1(plpgsql_inline_handler);
Datum
plpgsql_inline_handler(PG_FUNCTION_ARGS)
{
InlineCodeBlock *codeblock = (InlineCodeBlock *) DatumGetPointer(PG_GETARG_DATUM(0));
PLpgSQL_function *func;
FunctionCallInfoData fake_fcinfo;
FmgrInfo flinfo;
Datum retval;
int rc;
Assert(IsA(codeblock, InlineCodeBlock));
/*
* Connect to SPI manager
*/
if ((rc = SPI_connect()) != SPI_OK_CONNECT)
elog(ERROR, "SPI_connect failed: %s", SPI_result_code_string(rc));
/* Compile the anonymous code block */
func = plpgsql_compile_inline(codeblock->source_text);
/*
* Set up a fake fcinfo with just enough info to satisfy
* plpgsql_exec_function(). In particular note that this sets things up
* with no arguments passed.
*/
MemSet(&fake_fcinfo, 0, sizeof(fake_fcinfo));
MemSet(&flinfo, 0, sizeof(flinfo));
fake_fcinfo.flinfo = &flinfo;
flinfo.fn_oid = InvalidOid;
flinfo.fn_mcxt = CurrentMemoryContext;
retval = plpgsql_exec_function(func, &fake_fcinfo);
/*
* Disconnect from SPI manager
*/
if ((rc = SPI_finish()) != SPI_OK_FINISH)
elog(ERROR, "SPI_finish failed: %s", SPI_result_code_string(rc));
return retval;
}
/* ---------- /* ----------
* plpgsql_validator * plpgsql_validator
* *
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.115 2009/08/04 21:22:46 alvherre Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.116 2009/09/22 23:43:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -799,6 +799,7 @@ extern PLpgSQL_plugin **plugin_ptr; ...@@ -799,6 +799,7 @@ extern PLpgSQL_plugin **plugin_ptr;
*/ */
extern PLpgSQL_function *plpgsql_compile(FunctionCallInfo fcinfo, extern PLpgSQL_function *plpgsql_compile(FunctionCallInfo fcinfo,
bool forValidator); bool forValidator);
extern PLpgSQL_function *plpgsql_compile_inline(char *proc_source);
extern int plpgsql_parse_word(const char *word); extern int plpgsql_parse_word(const char *word);
extern int plpgsql_parse_dblword(const char *word); extern int plpgsql_parse_dblword(const char *word);
extern int plpgsql_parse_tripword(const char *word); extern int plpgsql_parse_tripword(const char *word);
...@@ -828,6 +829,7 @@ extern void plpgsql_compile_error_callback(void *arg); ...@@ -828,6 +829,7 @@ extern void plpgsql_compile_error_callback(void *arg);
*/ */
extern void _PG_init(void); extern void _PG_init(void);
extern Datum plpgsql_call_handler(PG_FUNCTION_ARGS); extern Datum plpgsql_call_handler(PG_FUNCTION_ARGS);
extern Datum plpgsql_inline_handler(PG_FUNCTION_ARGS);
extern Datum plpgsql_validator(PG_FUNCTION_ARGS); extern Datum plpgsql_validator(PG_FUNCTION_ARGS);
/* ---------- /* ----------
......
...@@ -3861,3 +3861,40 @@ NOTICE: foo\bar!baz ...@@ -3861,3 +3861,40 @@ NOTICE: foo\bar!baz
(1 row) (1 row)
drop function strtest(); drop function strtest();
-- Test anonymous code blocks.
DO $$
DECLARE r record;
BEGIN
FOR r IN SELECT rtrim(roomno) AS roomno, comment FROM Room ORDER BY roomno
LOOP
RAISE NOTICE '%, %', r.roomno, r.comment;
END LOOP;
END$$ LANGUAGE plpgsql;
NOTICE: 001, Entrance
NOTICE: 002, Office
NOTICE: 003, Office
NOTICE: 004, Technical
NOTICE: 101, Office
NOTICE: 102, Conference
NOTICE: 103, Restroom
NOTICE: 104, Technical
NOTICE: 105, Office
NOTICE: 106, Office
-- these are to check syntax error reporting
DO LANGUAGE plpgsql $$begin return 1; end$$;
ERROR: RETURN cannot have a parameter in function returning void at or near "1"
LINE 1: DO LANGUAGE plpgsql $$begin return 1; end$$;
^
DO LANGUAGE plpgsql $$
DECLARE r record;
BEGIN
FOR r IN SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
LOOP
RAISE NOTICE '%, %', r.roomno, r.comment;
END LOOP;
END$$;
ERROR: column "foo" does not exist
LINE 1: SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY room...
^
QUERY: SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
CONTEXT: PL/pgSQL function "inline_code_block" line 3 at FOR over SELECT rows
...@@ -3079,3 +3079,26 @@ $$ language plpgsql; ...@@ -3079,3 +3079,26 @@ $$ language plpgsql;
select strtest(); select strtest();
drop function strtest(); drop function strtest();
-- Test anonymous code blocks.
DO $$
DECLARE r record;
BEGIN
FOR r IN SELECT rtrim(roomno) AS roomno, comment FROM Room ORDER BY roomno
LOOP
RAISE NOTICE '%, %', r.roomno, r.comment;
END LOOP;
END$$ LANGUAGE plpgsql;
-- these are to check syntax error reporting
DO LANGUAGE plpgsql $$begin return 1; end$$;
DO LANGUAGE plpgsql $$
DECLARE r record;
BEGIN
FOR r IN SELECT rtrim(roomno) AS roomno, foo FROM Room ORDER BY roomno
LOOP
RAISE NOTICE '%, %', r.roomno, r.comment;
END LOOP;
END$$;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment