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:
Tom Lane 2018-01-26 12:25:44 -05:00
parent b0313f9cc8
commit 4971d2a322
6 changed files with 38 additions and 132 deletions

View File

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

View File

@ -637,21 +637,21 @@ update_proconfig_value(ArrayType *a, List *set_items)
* attributes.
*/
static void
compute_attributes_sql_style(ParseState *pstate,
bool is_procedure,
List *options,
List **as,
char **language,
Node **transform,
bool *windowfunc_p,
char *volatility_p,
bool *strict_p,
bool *security_definer,
bool *leakproof_p,
ArrayType **proconfig,
float4 *procost,
float4 *prorows,
char *parallel_p)
compute_function_attributes(ParseState *pstate,
bool is_procedure,
List *options,
List **as,
char **language,
Node **transform,
bool *windowfunc_p,
char *volatility_p,
bool *strict_p,
bool *security_definer,
bool *leakproof_p,
ArrayType **proconfig,
float4 *procost,
float4 *prorows,
char *parallel_p)
{
ListCell *option;
DefElem *as_item = NULL;
@ -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,14 +915,14 @@ CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt)
prorows = -1; /* indicates not set */
parallel = PROPARALLEL_UNSAFE;
/* override attributes from explicit list */
compute_attributes_sql_style(pstate,
stmt->is_procedure,
stmt->options,
&as_clause, &language, &transformDefElem,
&isWindowFunc, &volatility,
&isStrict, &security, &isLeakProof,
&proconfig, &procost, &prorows, &parallel);
/* Extract non-default attributes from stmt->options list */
compute_function_attributes(pstate,
stmt->is_procedure,
stmt->options,
&as_clause, &language, &transformDefElem,
&isWindowFunc, &volatility,
&isStrict, &security, &isLeakProof,
&proconfig, &procost, &prorows, &parallel);
/* Look up the language and validate permissions */
languageTuple = SearchSysCache1(LANGNAME, PointerGetDatum(language));
@ -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);
@ -2269,7 +2214,7 @@ ExecuteCallStmt(ParseState *pstate, CallStmt *stmt, bool atomic)
FuncExpr *fexpr;
int nargs;
int i;
AclResult aclresult;
AclResult aclresult;
FmgrInfo flinfo;
FunctionCallInfoData fcinfo;
CallContext *callcontext;
@ -2329,7 +2274,7 @@ ExecuteCallStmt(ParseState *pstate, CallStmt *stmt, bool atomic)
InitFunctionCallInfoData(fcinfo, &flinfo, nargs, fexpr->inputcollid, (Node *) callcontext, NULL);
i = 0;
foreach (lc, fexpr->args)
foreach(lc, fexpr->args)
{
EState *estate;
ExprState *exprstate;

View File

@ -3217,7 +3217,7 @@ _copyClosePortalStmt(const ClosePortalStmt *from)
static CallStmt *
_copyCallStmt(const CallStmt *from)
{
CallStmt *newnode = makeNode(CallStmt);
CallStmt *newnode = makeNode(CallStmt);
COPY_NODE_FIELD(funccall);
@ -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;
}

View File

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

View File

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

View File

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