aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Eisentraut <peter_e@gmx.net>2002-05-17 18:32:52 +0000
committerPeter Eisentraut <peter_e@gmx.net>2002-05-17 18:32:52 +0000
commit94bdc4855cf8db8a2df83a19d18ce72fd5eb2691 (patch)
tree41ce44b368365702d41eee6753c1aa0e34500252
parent97f7ceaaa6a80cecc2bd3c6b1e7757c4ab504a69 (diff)
downloadpostgresql-94bdc4855cf8db8a2df83a19d18ce72fd5eb2691.tar.gz
postgresql-94bdc4855cf8db8a2df83a19d18ce72fd5eb2691.zip
Extend syntax of CREATE FUNCTION to resemble SQL99.
-rw-r--r--doc/src/sgml/ref/create_function.sgml348
-rw-r--r--doc/src/sgml/release.sgml3
-rw-r--r--src/backend/commands/functioncmds.c151
-rw-r--r--src/backend/nodes/copyfuncs.c15
-rw-r--r--src/backend/nodes/equalfuncs.c14
-rw-r--r--src/backend/parser/gram.y142
-rw-r--r--src/backend/parser/keywords.c13
-rw-r--r--src/backend/tcop/postgres.c6
-rw-r--r--src/backend/tcop/utility.c6
-rw-r--r--src/bin/pg_dump/pg_dump.c60
-rw-r--r--src/include/commands/defrem.h4
-rw-r--r--src/include/nodes/nodes.h4
-rw-r--r--src/include/nodes/parsenodes.h9
13 files changed, 504 insertions, 271 deletions
diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml
index 18961336531..495a1331464 100644
--- a/doc/src/sgml/ref/create_function.sgml
+++ b/doc/src/sgml/ref/create_function.sgml
@@ -1,5 +1,5 @@
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.37 2002/04/23 02:07:15 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.38 2002/05/17 18:32:52 petere Exp $
-->
<refentry id="SQL-CREATEFUNCTION">
@@ -17,13 +17,13 @@ $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.37 2002/04/23
<synopsis>
CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">argtype</replaceable> [, ...] ] )
RETURNS <replaceable class="parameter">rettype</replaceable>
- AS '<replaceable class="parameter">definition</replaceable>'
- LANGUAGE <replaceable class="parameter">langname</replaceable>
- [ WITH ( <replaceable class="parameter">attribute</replaceable> [, ...] ) ]
-CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable> ( [ <replaceable class="parameter">argtype</replaceable> [, ...] ] )
- RETURNS <replaceable class="parameter">rettype</replaceable>
- AS '<replaceable class="parameter">obj_file</replaceable>', '<replaceable class="parameter">link_symbol</replaceable>'
- LANGUAGE <replaceable class="parameter">langname</replaceable>
+ { LANGUAGE <replaceable class="parameter">langname</replaceable>
+ | IMMUTABLE | STABLE | VOLATILE
+ | CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
+ | IMPLICIT CAST
+ | AS '<replaceable class="parameter">definition</replaceable>'
+ | AS '<replaceable class="parameter">obj_file</replaceable>', '<replaceable class="parameter">link_symbol</replaceable>'
+ } ...
[ WITH ( <replaceable class="parameter">attribute</replaceable> [, ...] ) ]
</synopsis>
</refsynopsisdiv>
@@ -33,8 +33,13 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
<para>
<command>CREATE FUNCTION</command> defines a new function.
- <command>CREATE OR REPLACE FUNCTION</command> will either create
- a new function, or replace an existing definition.
+ <command>CREATE OR REPLACE FUNCTION</command> will either create a
+ new function, or replace an existing definition.
+ </para>
+
+ <para>
+ The user that creates the function becomes the owner of the function.
+ </para>
<variablelist>
<title>Parameters</title>
@@ -81,7 +86,7 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
<listitem>
<para>
- The return data type. The output type may be specified as a
+ The return data type. The return type may be specified as a
base type, complex type, <literal>setof</literal> type,
<literal>opaque</literal>, or the same as the type of an
existing column.
@@ -96,6 +101,105 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
</varlistentry>
<varlistentry>
+ <term><replaceable class="parameter">langname</replaceable></term>
+
+ <listitem>
+ <para>
+ The name of the language that the function is implemented in.
+ May be <literal>SQL</literal>, <literal>C</literal>,
+ <literal>internal</literal>, or the name of a user-defined
+ procedural language. (See also <xref linkend="app-createlang"
+ endterm="app-createlang-title">.) For backward compatibility,
+ the name may be enclosed by single quotes.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>IMMUTABLE</term>
+ <term>STABLE</term>
+ <term>VOLATILE</term>
+
+ <listitem>
+ <para>
+ These attributes inform the system whether it is safe to
+ replace multiple evaluations of the function with a single
+ evaluation, for run-time optimization. At most one choice
+ should be specified. If none of these appear,
+ <literal>VOLATILE</literal> is the default assumption.
+ </para>
+
+ <para>
+ <literal>IMMUTABLE</literal> indicates that the function always
+ returns the same result when given the same argument values; that
+ is, it does not do database lookups or otherwise use information not
+ directly present in its parameter list. If this option is given,
+ any call of the function with all-constant arguments can be
+ immediately replaced with the function value.
+ </para>
+
+ <para>
+ <literal>STABLE</literal> indicates that within a single table scan
+ the function will consistently
+ return the same result for the same argument values, but that its
+ result could change across SQL statements. This is the appropriate
+ selection for functions whose results depend on database lookups,
+ parameter variables (such as the current time zone), etc. Also note
+ that the <literal>CURRENT_TIMESTAMP</> family of functions qualify
+ as stable, since their values do not change within a transaction.
+ </para>
+
+ <para>
+ <literal>VOLATILE</literal> indicates that the function value can
+ change even within a single table scan, so no optimizations can be
+ made. Relatively few database functions are volatile in this sense;
+ some examples are <literal>random()</>, <literal>currval()</>,
+ <literal>timeofday()</>. Note that any function that has side-effects
+ must be classified volatile, even if its result is quite predictable,
+ to prevent calls from being optimized away; an example is
+ <literal>setval()</>.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>CALLED ON NULL INPUT</term>
+ <term>RETURNS NULL ON NULL INPUT</term>
+ <term>STRICT</term>
+
+ <listitem>
+ <para>
+ <literal>CALLED ON NULL INPUT</literal> (the default) indicates
+ that the function will be called normally when some of its
+ arguments are null. It is then the function author's
+ responsibility to check for NULLs if necessary and respond
+ appropriately.
+ </para>
+
+ <para>
+ <literal>RETURNS NULL ON NULL INPUT</literal> or
+ <literal>STRICT</literal> indicates that the function always
+ returns NULL whenever any of its arguments are NULL. If this
+ parameter is specified, the function is not executed when there
+ are NULL arguments; instead a NULL result is assumed
+ automatically.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>IMPLICIT CAST</literal</term>
+
+ <listitem>
+ <para>
+ Indicates that the function may be used for implicit type
+ conversions. See <xref linkend="sql-createfunction-cast-functions"
+ endterm="sql-createfunction-cast-functions-title"> for more detail.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
<term><replaceable class="parameter">definition</replaceable></term>
<listitem>
@@ -126,115 +230,55 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
</varlistentry>
<varlistentry>
- <term><replaceable class="parameter">langname</replaceable></term>
-
- <listitem>
- <para>
- May be <literal>SQL</literal>, <literal>C</literal>,
- <literal>internal</literal>, or <replaceable
- class="parameter">plname</replaceable>, where <replaceable
- class="parameter">plname</replaceable> is the name of a
- created procedural language. See
- <xref linkend="sql-createlanguage" endterm="sql-createlanguage-title">
- for details. For backward compatibility, the name may be
- enclosed by single quotes.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
<term><replaceable class="parameter">attribute</replaceable></term>
<listitem>
<para>
- An optional piece of information about the function, used for
- optimization. See below for details.
- </para>
- </listitem>
- </varlistentry>
+ The historical way to specify optional pieces of information
+ about the function. The following attributes may appear here:
+
+ <variablelist>
+ <varlistentry>
+ <term>isStrict</term>
+ <listitem>
+ <para>
+ Equivalent to <literal>STRICT</literal> or <literal>RETURNS NULL ON NULL INPUT</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>isImmutable</term>
+ <term>isCachable</term>
+ <term>isStable</term>
+ <term>isVolatile</term>
+ <listitem>
+ <para>
+ Equivalent to <literal>IMMUTABLE</literal>,
+ <literal>STABLE</literal>, <literal>VOLATILE</literal>.
+ <literal>isCachable</literal> is an obsolete equivalent of
+ <literal>isImmutable</literal>; it's still accepted for
+ backwards-compatibility reasons.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term>implicitCoercion</term>
+ <listitem>
+ <para>
+ Same as <literal>IMPLICIT CAST</literal>
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+
+ Attribute names are not case-sensitive.
+ </para>
+ </listitem>
+ </varlistentry>
</variablelist>
- </para>
-
- <para>
- The user that creates the function becomes the owner of the function.
- </para>
-
- <para>
- The following attributes may appear in the WITH clause:
-
- <variablelist>
- <varlistentry>
- <term>isStrict</term>
- <listitem>
- <para>
- <option>isStrict</option> indicates that the function always
- returns NULL whenever any of its arguments are NULL. If this
- attribute is specified, the function is not executed when there
- are NULL arguments; instead a NULL result is assumed automatically.
- When <option>isStrict</option> is not specified, the function will
- be called for NULL inputs. It is then the function author's
- responsibility to check for NULLs if necessary and respond
- appropriately.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>isImmutable</term>
- <term>isCachable</term>
- <term>isStable</term>
- <term>isVolatile</term>
- <listitem>
- <para>
- These attributes inform the system whether it is safe to replace
- multiple evaluations of the function with a single evaluation.
- At most one choice should be specified. (If none of these appear,
- <option>isVolatile</option> is the default assumption.)
- <option>isImmutable</option> indicates that the function always
- returns the same result when given the same argument values; that
- is, it does not do database lookups or otherwise use information not
- directly present in its parameter list. If this option is given,
- any call of the function with all-constant arguments can be
- immediately replaced with the function value.
- <option>isCachable</option> is an
- obsolete equivalent of <option>isImmutable</option>; it's still
- accepted for backwards-compatibility reasons.
- <option>isStable</option> indicates that within a single table scan
- the function will consistently
- return the same result for the same argument values, but that its
- result could change across SQL statements. This is the appropriate
- selection for functions whose results depend on database lookups,
- parameter variables (such as the current timezone), etc. Also note
- that the <literal>CURRENT_TIMESTAMP</> family of functions qualify
- as stable, since their values do not change within a transaction.
- <option>isVolatile</option> indicates that the function value can
- change even within a single table scan, so no optimizations can be
- made. Relatively few database functions are volatile in this sense;
- some examples are <literal>random()</>, <literal>currval()</>,
- <literal>timeofday()</>. Note that any function that has side-effects
- must be classified volatile, even if its result is quite predictable,
- to prevent calls from being optimized away; an example is
- <literal>setval()</>.
- </para>
- </listitem>
- </varlistentry>
-
- <varlistentry>
- <term>implicitCoercion</term>
- <listitem>
- <para>
- <option>implicitCoercion</option> indicates that the function
- may be used for implicit type conversions.
- See <xref linkend="coercion-functions"
- endterm="coercion-functions-title"> for more detail.
- </para>
- </listitem>
- </varlistentry>
- </variablelist>
-
- Attribute names are not case-sensitive.
- </para>
</refsect1>
@@ -328,21 +372,18 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
</para>
</refsect1>
- <refsect1 id="COERCION-FUNCTIONS">
- <refsect1info>
- <date>2002-04-11</date>
- </refsect1info>
- <title id="coercion-functions-title">
- Type Coercion Functions
+ <refsect1 id="sql-createfunction-cast-function">
+ <title id="sql-createfunction-cast-functions-title">
+ Type Cast Functions
</title>
<para>
- A function that has one parameter and is named the same as its output
- datatype (including the schema name) is considered to be a <firstterm>type
- coercion function</>: it can be invoked to convert a value of its input
- datatype into a value
+ A function that has one argument and is named the same as its return
+ data type (including the schema name) is considered to be a <firstterm>type
+ casting function</>: it can be invoked to convert a value of its input
+ data type into a value
of its output datatype. For example,
<programlisting>
- SELECT CAST(42 AS text);
+SELECT CAST(42 AS text);
</programlisting>
converts the integer constant 42 to text by invoking a function
<literal>text(int4)</>, if such a function exists and returns type
@@ -350,31 +391,33 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
</para>
<para>
- If a potential coercion function is marked <literal>implicitCoercion</>,
- then it can be invoked in any context where the conversion it defines
- is required. Coercion functions not so marked can be invoked only by
- explicit <literal>CAST</>,
- <replaceable>x</><literal>::</><replaceable>typename</>,
- or <replaceable>typename</>(<replaceable>x</>) constructs.
- For example, supposing that foo.f1 is a column of type text, then
+ If a potential cast function is marked <literal>IMPLICIT CAST</>,
+ then it can be invoked implicitly in any context where the
+ conversion it defines is required. Cast functions not so marked
+ can be invoked only by explicit <literal>CAST</>,
+ <replaceable>x</><literal>::</><replaceable>typename</>, or
+ <replaceable>typename</>(<replaceable>x</>) constructs. For
+ example, supposing that <literal>foo.f1</literal> is a column of
+ type <type>text</type>, then
<programlisting>
- INSERT INTO foo(f1) VALUES(42);
+INSERT INTO foo(f1) VALUES(42);
</programlisting>
will be allowed if <literal>text(int4)</> is marked
- <literal>implicitCoercion</>, otherwise not.
+ <literal>IMPLICIT CAST</>, otherwise not.
</para>
<para>
- It is wise to be conservative about marking coercion functions as
- implicit coercions. An overabundance of implicit coercion paths
- can cause <productname>PostgreSQL</productname> to choose surprising
- interpretations of commands,
- or to be unable to resolve commands at all because there are multiple
- possible interpretations. A good rule of thumb is to make coercions
- implicitly invokable only for information-preserving transformations
- between types in the same general type category. For example, int2
- to int4 coercion can reasonably be implicit, but be wary of marking
- int4 to text or float8 to int4 as implicit coercions.
+ It is wise to be conservative about marking cast functions as
+ implicit casts. An overabundance of implicit casting paths can
+ cause <productname>PostgreSQL</productname> to choose surprising
+ interpretations of commands, or to be unable to resolve commands at
+ all because there are multiple possible interpretations. A good
+ rule of thumb is to make cast implicitly invokable only for
+ information-preserving transformations between types in the same
+ general type category. For example, <type>int2</type> to
+ <type>int4</type> casts can reasonably be implicit, but be wary of
+ marking <type>int4</type> to <type>text</type> or
+ <type>float8</type> to <type>int4</type> as implicit casts.
</para>
</refsect1>
@@ -403,7 +446,7 @@ SELECT one() AS answer;
user-created shared library named <filename>funcs.so</> (the extension
may vary across platforms). The shared library file is sought in the
server's dynamic library search path. This particular routine calculates
- a check digit and returns TRUE if the check digit in the function
+ a check digit and returns true if the check digit in the function
parameters is correct. It is intended for use in a CHECK
constraint.
@@ -422,7 +465,7 @@ CREATE TABLE product (
</para>
<para>
- This example creates a function that does type conversion from the
+ The next example creates a function that does type conversion from the
user-defined type complex to the built-in type point. The
function is implemented by a dynamically loaded object that was
compiled from C source (we illustrate the now-deprecated alternative
@@ -436,7 +479,7 @@ CREATE TABLE product (
<programlisting>
CREATE FUNCTION point(complex) RETURNS point
AS '/home/bernie/pgsql/lib/complex.so', 'complex_to_point'
- LANGUAGE C WITH (isStrict);
+ LANGUAGE C STRICT;
</programlisting>
The C declaration of the function could be:
@@ -466,7 +509,7 @@ Point * complex_to_point (Complex *z)
<para>
A <command>CREATE FUNCTION</command> command is defined in SQL99.
The <application>PostgreSQL</application> version is similar but
- not compatible. The attributes are not portable, neither are the
+ not fully compatible. The attributes are not portable, neither are the
different available languages.
</para>
</refsect1>
@@ -476,10 +519,11 @@ Point * complex_to_point (Complex *z)
<title>See Also</title>
<para>
- <xref linkend="sql-dropfunction">,
- <xref linkend="sql-grant">,
- <xref linkend="sql-load">,
- <xref linkend="sql-revoke">,
+ <xref linkend="sql-dropfunction" endterm="sql-dropfunction-title">,
+ <xref linkend="sql-grant" endterm="sql-grant-title">,
+ <xref linkend="sql-load" endterm="sql-load-title">,
+ <xref linkend="sql-revoke" endterm="sql-revoke-title">,
+ <xref linkend="app-createlang">,
<citetitle>PostgreSQL Programmer's Guide</citetitle>
</para>
</refsect1>
diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml
index 889f2203f69..9b75049938a 100644
--- a/doc/src/sgml/release.sgml
+++ b/doc/src/sgml/release.sgml
@@ -1,5 +1,5 @@
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.135 2002/05/17 01:19:16 tgl Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.136 2002/05/17 18:32:52 petere Exp $
-->
<appendix id="release">
@@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without
worries about funny characters.
-->
<literallayout><![CDATA[
+Syntax of CREATE FUNCTION has been extended to resemble SQL99
Effects of SET within a transaction block now roll back if transaction aborts
New SET LOCAL syntax sets a parameter for the life of the current transaction
Datestyle, timezone, client_encoding can be set in postgresql.conf
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index ce4b43b5936..e294b6f973e 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.3 2002/04/27 03:45:01 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.4 2002/05/17 18:32:52 petere Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
@@ -159,6 +159,104 @@ compute_parameter_types(List *argTypes, Oid languageOid,
return parameterCount;
}
+
+/*
+ * Dissect the list of options assembled in gram.y into function
+ * attributes.
+ */
+
+static void
+compute_attributes_sql_style(const List *options,
+ List **as,
+ char **language,
+ char *volatility_p,
+ bool *strict_p,
+ bool *security_definer,
+ bool *implicit_cast)
+{
+ const List *option;
+ DefElem *as_item = NULL;
+ DefElem *language_item = NULL;
+ DefElem *volatility_item = NULL;
+ DefElem *strict_item = NULL;
+ DefElem *security_item = NULL;
+ DefElem *implicit_item = NULL;
+
+ foreach(option, options)
+ {
+ DefElem *defel = (DefElem *) lfirst(option);
+
+ if (strcmp(defel->defname, "as")==0)
+ {
+ if (as_item)
+ elog(ERROR, "conflicting or redundant options");
+ as_item = defel;
+ }
+ else if (strcmp(defel->defname, "language")==0)
+ {
+ if (language_item)
+ elog(ERROR, "conflicting or redundant options");
+ language_item = defel;
+ }
+ else if (strcmp(defel->defname, "volatility")==0)
+ {
+ if (volatility_item)
+ elog(ERROR, "conflicting or redundant options");
+ volatility_item = defel;
+ }
+ else if (strcmp(defel->defname, "strict")==0)
+ {
+ if (strict_item)
+ elog(ERROR, "conflicting or redundant options");
+ strict_item = defel;
+ }
+ else if (strcmp(defel->defname, "security")==0)
+ {
+ if (security_item)
+ elog(ERROR, "conflicting or redundant options");
+ security_item = defel;
+ }
+ else if (strcmp(defel->defname, "implicit")==0)
+ {
+ if (implicit_item)
+ elog(ERROR, "conflicting or redundant options");
+ implicit_item = defel;
+ }
+ else
+ elog(ERROR, "invalid CREATE FUNCTION option");
+ }
+
+ if (as_item)
+ *as = (List *)as_item->arg;
+ else
+ elog(ERROR, "no function body specified");
+
+ if (language_item)
+ *language = strVal(language_item->arg);
+ else
+ elog(ERROR, "no language specified");
+
+ if (volatility_item)
+ {
+ if (strcmp(strVal(volatility_item->arg), "immutable")==0)
+ *volatility_p = PROVOLATILE_IMMUTABLE;
+ else if (strcmp(strVal(volatility_item->arg), "stable")==0)
+ *volatility_p = PROVOLATILE_STABLE;
+ else if (strcmp(strVal(volatility_item->arg), "volatile")==0)
+ *volatility_p = PROVOLATILE_VOLATILE;
+ else
+ elog(ERROR, "invalid volatility");
+ }
+
+ if (strict_item)
+ *strict_p = intVal(strict_item->arg);
+ if (security_item)
+ *security_definer = intVal(security_item->arg);
+ if (implicit_item)
+ *implicit_cast = intVal(implicit_item->arg);
+}
+
+
/*-------------
* Interpret the parameters *parameters and return their contents as
* *byte_pct_p, etc.
@@ -183,23 +281,14 @@ compute_parameter_types(List *argTypes, Oid languageOid,
*------------
*/
static void
-compute_full_attributes(List *parameters,
- int32 *byte_pct_p, int32 *perbyte_cpu_p,
- int32 *percall_cpu_p, int32 *outin_ratio_p,
- bool *isImplicit_p, bool *isStrict_p,
- char *volatility_p)
+compute_attributes_with_style(List *parameters,
+ int32 *byte_pct_p, int32 *perbyte_cpu_p,
+ int32 *percall_cpu_p, int32 *outin_ratio_p,
+ bool *isImplicit_p, bool *isStrict_p,
+ char *volatility_p)
{
List *pl;
- /* the defaults */
- *byte_pct_p = BYTE_PCT;
- *perbyte_cpu_p = PERBYTE_CPU;
- *percall_cpu_p = PERCALL_CPU;
- *outin_ratio_p = OUTIN_RATIO;
- *isImplicit_p = false;
- *isStrict_p = false;
- *volatility_p = PROVOLATILE_VOLATILE;
-
foreach(pl, parameters)
{
DefElem *param = (DefElem *) lfirst(pl);
@@ -290,12 +379,13 @@ interpret_AS_clause(Oid languageOid, const char *languageName, const List *as,
* Execute a CREATE FUNCTION utility statement.
*/
void
-CreateFunction(ProcedureStmt *stmt)
+CreateFunction(CreateFunctionStmt *stmt)
{
char *probin_str;
char *prosrc_str;
Oid prorettype;
bool returnsSet;
+ char *language;
char languageName[NAMEDATALEN];
Oid languageOid;
char *funcname;
@@ -308,10 +398,12 @@ CreateFunction(ProcedureStmt *stmt)
percall_cpu,
outin_ratio;
bool isImplicit,
- isStrict;
+ isStrict,
+ security;
char volatility;
HeapTuple languageTuple;
Form_pg_language languageStruct;
+ List *as_clause;
/* Convert list of names to a name and namespace */
namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
@@ -322,8 +414,21 @@ CreateFunction(ProcedureStmt *stmt)
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, get_namespace_name(namespaceId));
+ /* defaults attributes */
+ byte_pct = BYTE_PCT;
+ perbyte_cpu = PERBYTE_CPU;
+ percall_cpu = PERCALL_CPU;
+ outin_ratio = OUTIN_RATIO;
+ isImplicit = false;
+ isStrict = false;
+ volatility = PROVOLATILE_VOLATILE;
+
+ /* override attributes from explicit list */
+ compute_attributes_sql_style(stmt->options,
+ &as_clause, &language, &volatility, &isStrict, &security, &isImplicit);
+
/* Convert language name to canonical case */
- case_translate_language_name(stmt->language, languageName);
+ case_translate_language_name(language, languageName);
/* Look up the language and validate permissions */
languageTuple = SearchSysCache(LANGNAME,
@@ -363,12 +468,12 @@ CreateFunction(ProcedureStmt *stmt)
parameterCount = compute_parameter_types(stmt->argTypes, languageOid,
parameterTypes);
- compute_full_attributes(stmt->withClause,
- &byte_pct, &perbyte_cpu, &percall_cpu,
- &outin_ratio, &isImplicit, &isStrict,
- &volatility);
+ compute_attributes_with_style(stmt->withClause,
+ &byte_pct, &perbyte_cpu, &percall_cpu,
+ &outin_ratio, &isImplicit, &isStrict,
+ &volatility);
- interpret_AS_clause(languageOid, languageName, stmt->as,
+ interpret_AS_clause(languageOid, languageName, as_clause,
&prosrc_str, &probin_str);
/*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 909847dc856..1f0cc11934f 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.186 2002/05/17 01:19:17 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.187 2002/05/17 18:32:52 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2098,18 +2098,17 @@ _copyIndexStmt(IndexStmt *from)
return newnode;
}
-static ProcedureStmt *
-_copyProcedureStmt(ProcedureStmt *from)
+static CreateFunctionStmt *
+_copyCreateFunctionStmt(CreateFunctionStmt *from)
{
- ProcedureStmt *newnode = makeNode(ProcedureStmt);
+ CreateFunctionStmt *newnode = makeNode(CreateFunctionStmt);
newnode->replace = from->replace;
Node_Copy(from, newnode, funcname);
Node_Copy(from, newnode, argTypes);
Node_Copy(from, newnode, returnType);
+ Node_Copy(from, newnode, options);
Node_Copy(from, newnode, withClause);
- Node_Copy(from, newnode, as);
- newnode->language = pstrdup(from->language);
return newnode;
}
@@ -2865,8 +2864,8 @@ copyObject(void *from)
case T_IndexStmt:
retval = _copyIndexStmt(from);
break;
- case T_ProcedureStmt:
- retval = _copyProcedureStmt(from);
+ case T_CreateFunctionStmt:
+ retval = _copyCreateFunctionStmt(from);
break;
case T_RemoveAggrStmt:
retval = _copyRemoveAggrStmt(from);
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 1f0d175326b..f48d6d033f4 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.133 2002/05/17 01:19:17 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.134 2002/05/17 18:32:52 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -923,7 +923,7 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b)
}
static bool
-_equalProcedureStmt(ProcedureStmt *a, ProcedureStmt *b)
+_equalCreateFunctionStmt(CreateFunctionStmt *a, CreateFunctionStmt *b)
{
if (a->replace != b->replace)
return false;
@@ -933,11 +933,9 @@ _equalProcedureStmt(ProcedureStmt *a, ProcedureStmt *b)
return false;
if (!equal(a->returnType, b->returnType))
return false;
- if (!equal(a->withClause, b->withClause))
- return false;
- if (!equal(a->as, b->as))
+ if (!equal(a->options, b->options))
return false;
- if (!equalstr(a->language, b->language))
+ if (!equal(a->withClause, b->withClause))
return false;
return true;
@@ -2020,8 +2018,8 @@ equal(void *a, void *b)
case T_IndexStmt:
retval = _equalIndexStmt(a, b);
break;
- case T_ProcedureStmt:
- retval = _equalProcedureStmt(a, b);
+ case T_CreateFunctionStmt:
+ retval = _equalCreateFunctionStmt(a, b);
break;
case T_RemoveAggrStmt:
retval = _equalRemoveAggrStmt(a, b);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 0009b9df2f0..70a9e78cfa0 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.316 2002/05/17 01:19:17 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.317 2002/05/17 18:32:52 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -141,7 +141,7 @@ static void doNegateFloat(Value *v);
DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropAssertStmt, DropTrigStmt,
DropRuleStmt, DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt,
GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt,
- NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt,
+ NotifyStmt, OptimizableStmt, CreateFunctionStmt, ReindexStmt,
RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt,
RenameStmt, RevokeStmt, RuleActionStmt, RuleActionStmtOrEmpty,
RuleStmt, SelectStmt, TransactionStmt, TruncateStmt,
@@ -201,7 +201,7 @@ static void doNegateFloat(Value *v);
%type <list> stmtblock, stmtmulti,
OptTableElementList, OptInherit, definition, opt_distinct,
- opt_with, func_args, func_args_list, func_as,
+ opt_with, func_args, func_args_list, func_as, createfunc_opt_list
oper_argtypes, RuleActionList, RuleActionMulti,
opt_column_list, columnList, opt_name_list,
sort_clause, sortby_list, index_params, index_list, name_list,
@@ -214,6 +214,7 @@ static void doNegateFloat(Value *v);
%type <range> into_clause, OptTempTableName
+%type <defelt> createfunc_opt_item
%type <typnam> func_arg, func_return, func_type, aggr_argtype
%type <boolean> opt_arg, TriggerForOpt, TriggerForType, OptTemp, OptWithOids
@@ -388,6 +389,9 @@ static void doNegateFloat(Value *v);
TEMP, TEMPLATE, TOAST, TRUNCATE, TRUSTED,
UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION
+%token <keyword> CALLED, DEFINER, EXTERNAL, IMMUTABLE, IMPLICIT, INPUT,
+ INVOKER, SECURITY, STABLE, STRICT, VOLATILE
+
/* The grammar thinks these are keywords, but they are not in the keywords.c
* list and so can never be entered directly. The filter in parser.c
* creates these tokens when required.
@@ -467,6 +471,7 @@ stmt : AlterDatabaseSetStmt
| CreateStmt
| CreateAsStmt
| CreateDomainStmt
+ | CreateFunctionStmt
| CreateSchemaStmt
| CreateGroupStmt
| CreateSeqStmt
@@ -494,7 +499,6 @@ stmt : AlterDatabaseSetStmt
| UnlistenStmt
| LockStmt
| NotifyStmt
- | ProcedureStmt
| ReindexStmt
| RemoveAggrStmt
| RemoveOperStmt
@@ -2769,17 +2773,16 @@ RecipeStmt: EXECUTE RECIPE recipe_name
*
*****************************************************************************/
-ProcedureStmt: CREATE opt_or_replace FUNCTION func_name func_args
- RETURNS func_return AS func_as LANGUAGE ColId_or_Sconst opt_with
+CreateFunctionStmt: CREATE opt_or_replace FUNCTION func_name func_args
+ RETURNS func_return createfunc_opt_list opt_with
{
- ProcedureStmt *n = makeNode(ProcedureStmt);
+ CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
n->replace = $2;
n->funcname = $4;
n->argTypes = $5;
n->returnType = $7;
- n->withClause = $12;
- n->as = $9;
- n->language = $11;
+ n->options = $8;
+ n->withClause = $9;
$$ = (Node *)n;
};
@@ -2787,10 +2790,6 @@ opt_or_replace: OR REPLACE { $$ = TRUE; }
| /*EMPTY*/ { $$ = FALSE; }
;
-opt_with: WITH definition { $$ = $2; }
- | /*EMPTY*/ { $$ = NIL; }
- ;
-
func_args: '(' func_args_list ')' { $$ = $2; }
| '(' ')' { $$ = NIL; }
;
@@ -2831,12 +2830,6 @@ opt_arg: IN
}
;
-func_as: Sconst
- { $$ = makeList1(makeString($1)); }
- | Sconst ',' Sconst
- { $$ = makeList2(makeString($1), makeString($3)); }
- ;
-
func_return: func_type
{
/* We can catch over-specified arguments here if we want to,
@@ -2864,6 +2857,104 @@ func_type: Typename
}
;
+
+createfunc_opt_list: createfunc_opt_item
+ { $$ = makeList1($1); }
+ | createfunc_opt_list createfunc_opt_item
+ { $$ = lappend($1, $2); }
+ ;
+
+createfunc_opt_item: AS func_as
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "as";
+ $$->arg = (Node *)$2;
+ }
+ | LANGUAGE ColId_or_Sconst
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "language";
+ $$->arg = (Node *)makeString($2);
+ }
+ | IMMUTABLE
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "volatility";
+ $$->arg = (Node *)makeString("immutable");
+ }
+ | STABLE
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "volatility";
+ $$->arg = (Node *)makeString("stable");
+ }
+ | VOLATILE
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "volatility";
+ $$->arg = (Node *)makeString("volatile");
+ }
+ | CALLED ON NULL_P INPUT
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "strict";
+ $$->arg = (Node *)makeInteger(FALSE);
+ }
+ | RETURNS NULL_P ON NULL_P INPUT
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "strict";
+ $$->arg = (Node *)makeInteger(TRUE);
+ }
+ | STRICT
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "strict";
+ $$->arg = (Node *)makeInteger(TRUE);
+ }
+ | EXTERNAL SECURITY DEFINER
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "security";
+ $$->arg = (Node *)makeInteger(TRUE);
+ }
+ | EXTERNAL SECURITY INVOKER
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "security";
+ $$->arg = (Node *)makeInteger(FALSE);
+ }
+ | SECURITY DEFINER
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "security";
+ $$->arg = (Node *)makeInteger(TRUE);
+ }
+ | SECURITY INVOKER
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "security";
+ $$->arg = (Node *)makeInteger(FALSE);
+ }
+ | IMPLICIT CAST
+ {
+ $$ = makeNode(DefElem);
+ $$->defname = "implicit";
+ $$->arg = (Node *)makeInteger(TRUE);
+ }
+ ;
+
+func_as: Sconst
+ { $$ = makeList1(makeString($1)); }
+ | Sconst ',' Sconst
+ { $$ = makeList2(makeString($1), makeString($3)); }
+ ;
+
+opt_with: WITH definition { $$ = $2; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+
/*****************************************************************************
*
* QUERY:
@@ -6137,6 +6228,7 @@ unreserved_keyword:
| BEGIN_TRANS
| BY
| CACHE
+ | CALLED
| CASCADE
| CHAIN
| CHARACTERISTICS
@@ -6156,6 +6248,7 @@ unreserved_keyword:
| DAY_P
| DECLARE
| DEFERRED
+ | DEFINER
| DELETE
| DELIMITERS
| DOMAIN_P
@@ -6168,6 +6261,7 @@ unreserved_keyword:
| EXCLUSIVE
| EXECUTE
| EXPLAIN
+ | EXTERNAL
| FETCH
| FORCE
| FORWARD
@@ -6176,13 +6270,17 @@ unreserved_keyword:
| HANDLER
| HOUR_P
| IMMEDIATE
+ | IMMUTABLE
+ | IMPLICIT
| INCREMENT
| INDEX
| INHERITS
| INOUT
+ | INPUT
| INSENSITIVE
| INSERT
| INSTEAD
+ | INVOKER
| ISOLATION
| KEY
| LANGUAGE
@@ -6238,18 +6336,21 @@ unreserved_keyword:
| SCHEMA
| SCROLL
| SECOND_P
+ | SECURITY
| SESSION
| SEQUENCE
| SERIALIZABLE
| SET
| SHARE
| SHOW
+ | STABLE
| START
| STATEMENT
| STATISTICS
| STDIN
| STDOUT
| STORAGE
+ | STRICT
| SYSID
| TEMP
| TEMPLATE
@@ -6272,6 +6373,7 @@ unreserved_keyword:
| VARYING
| VERSION
| VIEW
+ | VOLATILE
| WITH
| WITHOUT
| WORK
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index 0c7612350a5..36900127ea8 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.109 2002/05/03 00:32:16 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.110 2002/05/17 18:32:52 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -57,6 +57,7 @@ static const ScanKeyword ScanKeywords[] = {
{"both", BOTH},
{"by", BY},
{"cache", CACHE},
+ {"called", CALLED},
{"cascade", CASCADE},
{"case", CASE},
{"cast", CAST},
@@ -95,6 +96,7 @@ static const ScanKeyword ScanKeywords[] = {
{"default", DEFAULT},
{"deferrable", DEFERRABLE},
{"deferred", DEFERRED},
+ {"definer", DEFINER},
{"delete", DELETE},
{"delimiters", DELIMITERS},
{"desc", DESC},
@@ -114,6 +116,7 @@ static const ScanKeyword ScanKeywords[] = {
{"execute", EXECUTE},
{"exists", EXISTS},
{"explain", EXPLAIN},
+ {"external", EXTERNAL},
{"extract", EXTRACT},
{"false", FALSE_P},
{"fetch", FETCH},
@@ -134,6 +137,8 @@ static const ScanKeyword ScanKeywords[] = {
{"hour", HOUR_P},
{"ilike", ILIKE},
{"immediate", IMMEDIATE},
+ {"immutable", IMMUTABLE},
+ {"implicit", IMPLICIT},
{"in", IN},
{"increment", INCREMENT},
{"index", INDEX},
@@ -141,6 +146,7 @@ static const ScanKeyword ScanKeywords[] = {
{"initially", INITIALLY},
{"inner", INNER_P},
{"inout", INOUT},
+ {"input", INPUT},
{"insensitive", INSENSITIVE},
{"insert", INSERT},
{"instead", INSTEAD},
@@ -149,6 +155,7 @@ static const ScanKeyword ScanKeywords[] = {
{"intersect", INTERSECT},
{"interval", INTERVAL},
{"into", INTO},
+ {"invoker", INVOKER},
{"is", IS},
{"isnull", ISNULL},
{"isolation", ISOLATION},
@@ -234,6 +241,7 @@ static const ScanKeyword ScanKeywords[] = {
{"schema", SCHEMA},
{"scroll", SCROLL},
{"second", SECOND_P},
+ {"security", SECURITY},
{"select", SELECT},
{"sequence", SEQUENCE},
{"serializable", SERIALIZABLE},
@@ -245,12 +253,14 @@ static const ScanKeyword ScanKeywords[] = {
{"show", SHOW},
{"smallint", SMALLINT},
{"some", SOME},
+ {"stable", STABLE},
{"start", START},
{"statement", STATEMENT},
{"statistics", STATISTICS},
{"stdin", STDIN},
{"stdout", STDOUT},
{"storage", STORAGE},
+ {"strict", STRICT},
{"substring", SUBSTRING},
{"sysid", SYSID},
{"table", TABLE},
@@ -288,6 +298,7 @@ static const ScanKeyword ScanKeywords[] = {
{"verbose", VERBOSE},
{"version", VERSION},
{"view", VIEW},
+ {"volatile", VOLATILE},
{"when", WHEN},
{"where", WHERE},
{"with", WITH},
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 53bf45dce9c..1ea4fa9a6b5 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.265 2002/05/17 01:19:18 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.266 2002/05/17 18:32:52 petere Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -1688,7 +1688,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.265 $ $Date: 2002/05/17 01:19:18 $\n");
+ puts("$Revision: 1.266 $ $Date: 2002/05/17 18:32:52 $\n");
}
/*
@@ -2229,7 +2229,7 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE";
break;
- case T_ProcedureStmt: /* CREATE FUNCTION */
+ case T_CreateFunctionStmt: /* CREATE FUNCTION */
tag = "CREATE";
break;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index e72d8dfccf7..e7091d9aa34 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.154 2002/05/17 01:19:18 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.155 2002/05/17 18:32:52 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -574,8 +574,8 @@ ProcessUtility(Node *parsetree,
}
break;
- case T_ProcedureStmt: /* CREATE FUNCTION */
- CreateFunction((ProcedureStmt *) parsetree);
+ case T_CreateFunctionStmt: /* CREATE FUNCTION */
+ CreateFunction((CreateFunctionStmt *) parsetree);
break;
case T_IndexStmt: /* CREATE INDEX */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index f3b8f8a19b1..cb268c50bf1 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -22,7 +22,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.260 2002/05/13 17:45:30 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.261 2002/05/17 18:32:52 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3152,18 +3152,14 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs)
(*deps)[depIdx++] = strdup(lanplcallfoid);
- appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE ");
- formatStringLiteral(delqry, lanname, CONV_ALL);
- appendPQExpBuffer(delqry, ";\n");
+ appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n", fmtId(lanname, force_quotes));
- appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE ",
+ appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s",
(PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ?
- "TRUSTED " : "");
- formatStringLiteral(defqry, lanname, CONV_ALL);
- appendPQExpBuffer(defqry, " HANDLER %s LANCOMPILER ",
+ "TRUSTED " : "",
+ fmtId(lanname, force_quotes));
+ appendPQExpBuffer(defqry, " HANDLER %s;\n",
fmtId(finfo[fidx].proname, force_quotes));
- formatStringLiteral(defqry, lancompiler, CONV_ALL);
- appendPQExpBuffer(defqry, ";\n");
(*deps)[depIdx++] = NULL; /* End of List */
@@ -3221,9 +3217,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
char *proimplicit;
char *proisstrict;
char *lanname;
- char *listSep;
- char *listSepComma = ",";
- char *listSepNone = "";
char *rettypename;
if (finfo->dumped)
@@ -3337,52 +3330,33 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo)
rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque);
appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data);
- appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE ",
+ appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE %s",
(proretset[0] == 't') ? "SETOF " : "",
rettypename,
- asPart->data);
- formatStringLiteral(q, lanname, CONV_ALL);
+ asPart->data,
+ fmtId(lanname, force_quotes));
free(rettypename);
- if (provolatile[0] != PROVOLATILE_VOLATILE ||
- proimplicit[0] == 't' ||
- proisstrict[0] == 't') /* OR in new attrs here */
+ if (provolatile[0] != PROVOLATILE_VOLATILE)
{
- appendPQExpBuffer(q, " WITH (");
- listSep = listSepNone;
-
if (provolatile[0] == PROVOLATILE_IMMUTABLE)
- {
- appendPQExpBuffer(q, "%s isImmutable", listSep);
- listSep = listSepComma;
- }
+ appendPQExpBuffer(q, " IMMUTABLE");
else if (provolatile[0] == PROVOLATILE_STABLE)
- {
- appendPQExpBuffer(q, "%s isStable", listSep);
- listSep = listSepComma;
- }
+ appendPQExpBuffer(q, " STABLE");
else if (provolatile[0] != PROVOLATILE_VOLATILE)
{
write_msg(NULL, "Unexpected provolatile value for function %s\n",
finfo->proname);
exit_nicely();
}
+ }
- if (proimplicit[0] == 't')
- {
- appendPQExpBuffer(q, "%s implicitCoercion", listSep);
- listSep = listSepComma;
- }
+ if (proimplicit[0] == 't')
+ appendPQExpBuffer(q, " IMPLICIT CAST");
- if (proisstrict[0] == 't')
- {
- appendPQExpBuffer(q, "%s isStrict", listSep);
- listSep = listSepComma;
- }
-
- appendPQExpBuffer(q, " )");
- }
+ if (proisstrict[0] == 't')
+ appendPQExpBuffer(q, " STRICT");
appendPQExpBuffer(q, ";\n");
diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h
index 4e257fbd91a..cf9048c714b 100644
--- a/src/include/commands/defrem.h
+++ b/src/include/commands/defrem.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: defrem.h,v 1.36 2002/04/16 23:08:12 tgl Exp $
+ * $Id: defrem.h,v 1.37 2002/05/17 18:32:52 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -38,7 +38,7 @@ extern void ReindexDatabase(const char *databaseName, bool force, bool all);
* DefineFoo and RemoveFoo are now both in foocmds.c
*/
-extern void CreateFunction(ProcedureStmt *stmt);
+extern void CreateFunction(CreateFunctionStmt *stmt);
extern void RemoveFunction(List *functionName, List *argTypes);
extern void DefineOperator(List *names, List *parameters);
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 7de647d1362..6aa253e9d41 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: nodes.h,v 1.107 2002/05/12 23:43:04 tgl Exp $
+ * $Id: nodes.h,v 1.108 2002/05/17 18:32:52 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -160,7 +160,7 @@ typedef enum NodeTag
T_CommentStmt,
T_FetchStmt,
T_IndexStmt,
- T_ProcedureStmt,
+ T_CreateFunctionStmt,
T_RemoveAggrStmt,
T_RemoveFuncStmt,
T_RemoveOperStmt,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index a0bf47d7ed0..3466e125982 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.177 2002/05/17 01:19:19 tgl Exp $
+ * $Id: parsenodes.h,v 1.178 2002/05/17 18:32:52 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1200,17 +1200,16 @@ typedef struct IndexStmt
* Create Function Statement
* ----------------------
*/
-typedef struct ProcedureStmt
+typedef struct CreateFunctionStmt
{
NodeTag type;
bool replace; /* T => replace if already exists */
List *funcname; /* qualified name of function to create */
List *argTypes; /* list of argument types (TypeName nodes) */
TypeName *returnType; /* the return type */
+ List *options; /* a list of DefElem */
List *withClause; /* a list of DefElem */
- List *as; /* definition of function body */
- char *language; /* C, SQL, etc */
-} ProcedureStmt;
+} CreateFunctionStmt;
/* ----------------------
* Drop Aggregate Statement