Remove the obsolete WITH clause of CREATE FUNCTION.
This clause was superseded by SQL-standard syntax back in 7.3. We've kept it around for backwards-compatibility purposes ever since; but 15 years seems like long enough for that, especially seeing that there are undocumented weirdnesses in how it interacts with the SQL-standard syntax for specifying the same options. Michael Paquier, per an observation by Daniel Gustafsson; some small cosmetic adjustments to nearby code by me. Discussion: https://postgr.es/m/20180115022748.GB1724@paquier.xyz
This commit is contained in:
parent
b0313f9cc8
commit
4971d2a322
|
@ -37,7 +37,6 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||
| 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>
|
||||
|
||||
|
@ -560,41 +559,6 @@ CREATE [ OR REPLACE ] FUNCTION
|
|||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable class="parameter">attribute</replaceable></term>
|
||||
|
||||
<listitem>
|
||||
<para>
|
||||
The historical way to specify optional pieces of information
|
||||
about the function. The following attributes can appear here:
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><literal>isStrict</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Equivalent to <literal>STRICT</literal> or <literal>RETURNS NULL ON NULL INPUT</literal>.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>isCachable</literal></term>
|
||||
<listitem>
|
||||
<para><literal>isCachable</literal> is an obsolete equivalent of
|
||||
<literal>IMMUTABLE</literal>; it's still accepted for
|
||||
backwards-compatibility reasons.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
Attribute names are not case-sensitive.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
|
||||
<para>
|
||||
|
|
|
@ -637,7 +637,7 @@ update_proconfig_value(ArrayType *a, List *set_items)
|
|||
* attributes.
|
||||
*/
|
||||
static void
|
||||
compute_attributes_sql_style(ParseState *pstate,
|
||||
compute_function_attributes(ParseState *pstate,
|
||||
bool is_procedure,
|
||||
List *options,
|
||||
List **as,
|
||||
|
@ -789,59 +789,6 @@ compute_attributes_sql_style(ParseState *pstate,
|
|||
}
|
||||
|
||||
|
||||
/*-------------
|
||||
* Interpret the parameters *parameters and return their contents via
|
||||
* *isStrict_p and *volatility_p.
|
||||
*
|
||||
* These parameters supply optional information about a function.
|
||||
* All have defaults if not specified. Parameters:
|
||||
*
|
||||
* * isStrict means the function should not be called when any NULL
|
||||
* inputs are present; instead a NULL result value should be assumed.
|
||||
*
|
||||
* * volatility tells the optimizer whether the function's result can
|
||||
* be assumed to be repeatable over multiple evaluations.
|
||||
*------------
|
||||
*/
|
||||
static void
|
||||
compute_attributes_with_style(ParseState *pstate, bool is_procedure, List *parameters, bool *isStrict_p, char *volatility_p)
|
||||
{
|
||||
ListCell *pl;
|
||||
|
||||
foreach(pl, parameters)
|
||||
{
|
||||
DefElem *param = (DefElem *) lfirst(pl);
|
||||
|
||||
if (pg_strcasecmp(param->defname, "isstrict") == 0)
|
||||
{
|
||||
if (is_procedure)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("invalid attribute in procedure definition"),
|
||||
parser_errposition(pstate, param->location)));
|
||||
*isStrict_p = defGetBoolean(param);
|
||||
}
|
||||
else if (pg_strcasecmp(param->defname, "iscachable") == 0)
|
||||
{
|
||||
/* obsolete spelling of isImmutable */
|
||||
if (is_procedure)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
||||
errmsg("invalid attribute in procedure definition"),
|
||||
parser_errposition(pstate, param->location)));
|
||||
if (defGetBoolean(param))
|
||||
*volatility_p = PROVOLATILE_IMMUTABLE;
|
||||
}
|
||||
else
|
||||
ereport(WARNING,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("unrecognized function attribute \"%s\" ignored",
|
||||
param->defname),
|
||||
parser_errposition(pstate, param->location)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* For a dynamically linked C language object, the form of the clause is
|
||||
*
|
||||
|
@ -909,7 +856,7 @@ interpret_AS_clause(Oid languageOid, const char *languageName,
|
|||
|
||||
/*
|
||||
* CreateFunction
|
||||
* Execute a CREATE FUNCTION utility statement.
|
||||
* Execute a CREATE FUNCTION (or CREATE PROCEDURE) utility statement.
|
||||
*/
|
||||
ObjectAddress
|
||||
CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
|
||||
|
@ -957,7 +904,7 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
|
|||
aclcheck_error(aclresult, OBJECT_SCHEMA,
|
||||
get_namespace_name(namespaceId));
|
||||
|
||||
/* default attributes */
|
||||
/* Set default attributes */
|
||||
isWindowFunc = false;
|
||||
isStrict = false;
|
||||
security = false;
|
||||
|
@ -968,8 +915,8 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
|
|||
prorows = -1; /* indicates not set */
|
||||
parallel = PROPARALLEL_UNSAFE;
|
||||
|
||||
/* override attributes from explicit list */
|
||||
compute_attributes_sql_style(pstate,
|
||||
/* Extract non-default attributes from stmt->options list */
|
||||
compute_function_attributes(pstate,
|
||||
stmt->is_procedure,
|
||||
stmt->options,
|
||||
&as_clause, &language, &transformDefElem,
|
||||
|
@ -1107,8 +1054,6 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
|
|||
trftypes = NULL;
|
||||
}
|
||||
|
||||
compute_attributes_with_style(pstate, stmt->is_procedure, stmt->withClause, &isStrict, &volatility);
|
||||
|
||||
interpret_AS_clause(languageOid, language, funcname, as_clause,
|
||||
&prosrc_str, &probin_str);
|
||||
|
||||
|
|
|
@ -3422,13 +3422,12 @@ _copyCreateFunctionStmt(const CreateFunctionStmt *from)
|
|||
{
|
||||
CreateFunctionStmt *newnode = makeNode(CreateFunctionStmt);
|
||||
|
||||
COPY_SCALAR_FIELD(is_procedure);
|
||||
COPY_SCALAR_FIELD(replace);
|
||||
COPY_NODE_FIELD(funcname);
|
||||
COPY_NODE_FIELD(parameters);
|
||||
COPY_NODE_FIELD(returnType);
|
||||
COPY_SCALAR_FIELD(is_procedure);
|
||||
COPY_NODE_FIELD(options);
|
||||
COPY_NODE_FIELD(withClause);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
|
|
@ -1370,13 +1370,12 @@ _equalCreateStatsStmt(const CreateStatsStmt *a, const CreateStatsStmt *b)
|
|||
static bool
|
||||
_equalCreateFunctionStmt(const CreateFunctionStmt *a, const CreateFunctionStmt *b)
|
||||
{
|
||||
COMPARE_SCALAR_FIELD(is_procedure);
|
||||
COMPARE_SCALAR_FIELD(replace);
|
||||
COMPARE_NODE_FIELD(funcname);
|
||||
COMPARE_NODE_FIELD(parameters);
|
||||
COMPARE_NODE_FIELD(returnType);
|
||||
COMPARE_SCALAR_FIELD(is_procedure);
|
||||
COMPARE_NODE_FIELD(options);
|
||||
COMPARE_NODE_FIELD(withClause);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -7506,51 +7506,51 @@ opt_nulls_order: NULLS_LA FIRST_P { $$ = SORTBY_NULLS_FIRST; }
|
|||
|
||||
CreateFunctionStmt:
|
||||
CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
|
||||
RETURNS func_return createfunc_opt_list opt_definition
|
||||
RETURNS func_return createfunc_opt_list
|
||||
{
|
||||
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
|
||||
n->is_procedure = false;
|
||||
n->replace = $2;
|
||||
n->funcname = $4;
|
||||
n->parameters = $5;
|
||||
n->returnType = $7;
|
||||
n->options = $8;
|
||||
n->withClause = $9;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
|
||||
RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list opt_definition
|
||||
RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list
|
||||
{
|
||||
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
|
||||
n->is_procedure = false;
|
||||
n->replace = $2;
|
||||
n->funcname = $4;
|
||||
n->parameters = mergeTableFuncParameters($5, $9);
|
||||
n->returnType = TableFuncTypeName($9);
|
||||
n->returnType->location = @7;
|
||||
n->options = $11;
|
||||
n->withClause = $12;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
|
||||
createfunc_opt_list opt_definition
|
||||
createfunc_opt_list
|
||||
{
|
||||
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
|
||||
n->is_procedure = false;
|
||||
n->replace = $2;
|
||||
n->funcname = $4;
|
||||
n->parameters = $5;
|
||||
n->returnType = NULL;
|
||||
n->options = $6;
|
||||
n->withClause = $7;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| CREATE opt_or_replace PROCEDURE func_name func_args_with_defaults
|
||||
createfunc_opt_list
|
||||
{
|
||||
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
|
||||
n->is_procedure = true;
|
||||
n->replace = $2;
|
||||
n->funcname = $4;
|
||||
n->parameters = $5;
|
||||
n->returnType = NULL;
|
||||
n->is_procedure = true;
|
||||
n->options = $6;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
|
|
|
@ -2735,13 +2735,12 @@ typedef struct CreateStatsStmt
|
|||
typedef struct CreateFunctionStmt
|
||||
{
|
||||
NodeTag type;
|
||||
bool is_procedure; /* it's really CREATE PROCEDURE */
|
||||
bool replace; /* T => replace if already exists */
|
||||
List *funcname; /* qualified name of function to create */
|
||||
List *parameters; /* a list of FunctionParameter */
|
||||
TypeName *returnType; /* the return type */
|
||||
bool is_procedure;
|
||||
List *options; /* a list of DefElem */
|
||||
List *withClause; /* a list of DefElem */
|
||||
} CreateFunctionStmt;
|
||||
|
||||
typedef enum FunctionParameterMode
|
||||
|
|
Loading…
Reference in New Issue