Extend syntax of CREATE FUNCTION to resemble SQL99.

This commit is contained in:
Peter Eisentraut 2002-05-17 18:32:52 +00:00
parent 97f7ceaaa6
commit 94bdc4855c
13 changed files with 504 additions and 271 deletions

View File

@ -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.
@ -95,6 +100,105 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
</listitem>
</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>
@ -125,116 +229,56 @@ CREATE [ OR REPLACE ] FUNCTION <replaceable class="parameter">name</replaceable>
</listitem>
</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>

View File

@ -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

View File

@ -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);
/*

View File

@ -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);

View File

@ -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,12 +933,10 @@ _equalProcedureStmt(ProcedureStmt *a, ProcedureStmt *b)
return false;
if (!equal(a->returnType, b->returnType))
return false;
if (!equal(a->options, b->options))
return false;
if (!equal(a->withClause, b->withClause))
return false;
if (!equal(a->as, b->as))
return false;
if (!equalstr(a->language, b->language))
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);

View File

@ -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

View File

@ -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},

View File

@ -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;

View File

@ -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 */

View File

@ -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");

View File

@ -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);

View File

@ -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,

View File

@ -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