mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
Undo decision to allow pg_proc.prosrc to be NULL.
Commit e717a9a18
changed the longstanding rule that prosrc is NOT NULL
because when a SQL-language function is written in SQL-standard style,
we don't currently have anything useful to put there. This seems a poor
decision though, as it could easily have negative impacts on external
PLs (opening them to crashes they didn't use to have, for instance).
SQL-function-related code can just as easily test "is prosqlbody not
null" as "is prosrc null", so there's no real gain there either.
Hence, revert the NOT NULL marking removal and adjust related logic.
For now, we just put an empty string into prosrc for SQL-standard
functions. Maybe we'll have a better idea later, although the
history of things like pg_attrdef.adsrc suggests that it's not
easy to maintain a string equivalent of a node tree.
This also adds an assertion that queryDesc->sourceText != NULL
to standard_ExecutorStart. We'd been silently relying on that
for awhile, so let's make it less silent.
Also fix some overlooked documentation and test cases.
Discussion: https://postgr.es/m/2197698.1617984583@sss.pgh.pa.us
This commit is contained in:
@ -6007,8 +6007,9 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
|
|||||||
<structfield>prosqlbody</structfield> <type>pg_node_tree</type>
|
<structfield>prosqlbody</structfield> <type>pg_node_tree</type>
|
||||||
</para>
|
</para>
|
||||||
<para>
|
<para>
|
||||||
Pre-parsed SQL function body. This will be used for language SQL
|
Pre-parsed SQL function body. This is used for SQL-language
|
||||||
functions if the body is not specified as a string constant.
|
functions when the body is given in SQL-standard notation
|
||||||
|
rather than as a string literal. It's null in other cases.
|
||||||
</para></entry>
|
</para></entry>
|
||||||
</row>
|
</row>
|
||||||
|
|
||||||
@ -6036,9 +6037,16 @@ SCRAM-SHA-256$<replaceable><iteration count></replaceable>:<replaceable>&l
|
|||||||
<para>
|
<para>
|
||||||
For compiled functions, both built-in and dynamically loaded,
|
For compiled functions, both built-in and dynamically loaded,
|
||||||
<structfield>prosrc</structfield> contains the function's C-language
|
<structfield>prosrc</structfield> contains the function's C-language
|
||||||
name (link symbol). For all other currently-known language types,
|
name (link symbol).
|
||||||
|
For SQL-language functions, <structfield>prosrc</structfield> contains
|
||||||
|
the function's source text if that is specified as a string literal;
|
||||||
|
but if the function body is specified in SQL-standard style,
|
||||||
|
<structfield>prosrc</structfield> is unused (typically it's an empty
|
||||||
|
string) and <structfield>prosqlbody</structfield> contains the
|
||||||
|
pre-parsed definition.
|
||||||
|
For all other currently-known language types,
|
||||||
<structfield>prosrc</structfield> contains the function's source
|
<structfield>prosrc</structfield> contains the function's source
|
||||||
text. <structfield>probin</structfield> is unused except for
|
text. <structfield>probin</structfield> is null except for
|
||||||
dynamically-loaded C functions, for which it gives the name of the
|
dynamically-loaded C functions, for which it gives the name of the
|
||||||
shared library file containing the function.
|
shared library file containing the function.
|
||||||
</para>
|
</para>
|
||||||
|
@ -121,7 +121,7 @@ ProcedureCreate(const char *procedureName,
|
|||||||
/*
|
/*
|
||||||
* sanity checks
|
* sanity checks
|
||||||
*/
|
*/
|
||||||
Assert(PointerIsValid(prosrc) || PointerIsValid(prosqlbody));
|
Assert(PointerIsValid(prosrc));
|
||||||
|
|
||||||
parameterCount = parameterTypes->dim1;
|
parameterCount = parameterTypes->dim1;
|
||||||
if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
|
if (parameterCount < 0 || parameterCount > FUNC_MAX_ARGS)
|
||||||
@ -336,10 +336,7 @@ ProcedureCreate(const char *procedureName,
|
|||||||
values[Anum_pg_proc_protrftypes - 1] = trftypes;
|
values[Anum_pg_proc_protrftypes - 1] = trftypes;
|
||||||
else
|
else
|
||||||
nulls[Anum_pg_proc_protrftypes - 1] = true;
|
nulls[Anum_pg_proc_protrftypes - 1] = true;
|
||||||
if (prosrc)
|
values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc);
|
||||||
values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc);
|
|
||||||
else
|
|
||||||
nulls[Anum_pg_proc_prosrc - 1] = true;
|
|
||||||
if (probin)
|
if (probin)
|
||||||
values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin);
|
values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin);
|
||||||
else
|
else
|
||||||
@ -874,26 +871,29 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
|
|||||||
/* Postpone body checks if !check_function_bodies */
|
/* Postpone body checks if !check_function_bodies */
|
||||||
if (check_function_bodies)
|
if (check_function_bodies)
|
||||||
{
|
{
|
||||||
|
tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
|
||||||
|
if (isnull)
|
||||||
|
elog(ERROR, "null prosrc");
|
||||||
|
|
||||||
|
prosrc = TextDatumGetCString(tmp);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Setup error traceback support for ereport().
|
* Setup error traceback support for ereport().
|
||||||
*/
|
*/
|
||||||
callback_arg.proname = NameStr(proc->proname);
|
callback_arg.proname = NameStr(proc->proname);
|
||||||
callback_arg.prosrc = NULL;
|
callback_arg.prosrc = prosrc;
|
||||||
|
|
||||||
sqlerrcontext.callback = sql_function_parse_error_callback;
|
sqlerrcontext.callback = sql_function_parse_error_callback;
|
||||||
sqlerrcontext.arg = (void *) &callback_arg;
|
sqlerrcontext.arg = (void *) &callback_arg;
|
||||||
sqlerrcontext.previous = error_context_stack;
|
sqlerrcontext.previous = error_context_stack;
|
||||||
error_context_stack = &sqlerrcontext;
|
error_context_stack = &sqlerrcontext;
|
||||||
|
|
||||||
tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
|
/* If we have prosqlbody, pay attention to that not prosrc */
|
||||||
if (isnull)
|
tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosqlbody, &isnull);
|
||||||
|
if (!isnull)
|
||||||
{
|
{
|
||||||
Node *n;
|
Node *n;
|
||||||
|
|
||||||
tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosqlbody, &isnull);
|
|
||||||
if (isnull)
|
|
||||||
elog(ERROR, "null prosrc and prosqlbody");
|
|
||||||
|
|
||||||
n = stringToNode(TextDatumGetCString(tmp));
|
n = stringToNode(TextDatumGetCString(tmp));
|
||||||
if (IsA(n, List))
|
if (IsA(n, List))
|
||||||
querytree_list = castNode(List, n);
|
querytree_list = castNode(List, n);
|
||||||
@ -902,10 +902,6 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
prosrc = TextDatumGetCString(tmp);
|
|
||||||
|
|
||||||
callback_arg.prosrc = prosrc;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We can't do full prechecking of the function definition if there
|
* We can't do full prechecking of the function definition if there
|
||||||
* are any polymorphic input types, because actual datatypes of
|
* are any polymorphic input types, because actual datatypes of
|
||||||
@ -1001,9 +997,6 @@ function_parse_error_transpose(const char *prosrc)
|
|||||||
int newerrposition;
|
int newerrposition;
|
||||||
const char *queryText;
|
const char *queryText;
|
||||||
|
|
||||||
if (!prosrc)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Nothing to do unless we are dealing with a syntax error that has a
|
* Nothing to do unless we are dealing with a syntax error that has a
|
||||||
* cursor position.
|
* cursor position.
|
||||||
|
@ -958,8 +958,17 @@ interpret_AS_clause(Oid languageOid, const char *languageName,
|
|||||||
*sql_body_out = (Node *) q;
|
*sql_body_out = (Node *) q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We must put something in prosrc. For the moment, just record an
|
||||||
|
* empty string. It might be useful to store the original text of the
|
||||||
|
* CREATE FUNCTION statement --- but to make actual use of that in
|
||||||
|
* error reports, we'd also have to adjust readfuncs.c to not throw
|
||||||
|
* away node location fields when reading prosqlbody.
|
||||||
|
*/
|
||||||
|
*prosrc_str_p = pstrdup("");
|
||||||
|
|
||||||
|
/* But we definitely don't need probin. */
|
||||||
*probin_str_p = NULL;
|
*probin_str_p = NULL;
|
||||||
*prosrc_str_p = NULL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -195,6 +195,8 @@ standard_ExecutorStart(QueryDesc *queryDesc, int eflags)
|
|||||||
palloc0(nParamExec * sizeof(ParamExecData));
|
palloc0(nParamExec * sizeof(ParamExecData));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We now require all callers to provide sourceText */
|
||||||
|
Assert(queryDesc->sourceText != NULL);
|
||||||
estate->es_sourceText = queryDesc->sourceText;
|
estate->es_sourceText = queryDesc->sourceText;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -667,6 +667,15 @@ init_sql_fcache(FunctionCallInfo fcinfo, Oid collation, bool lazyEvalOK)
|
|||||||
procedureTuple,
|
procedureTuple,
|
||||||
Anum_pg_proc_prosrc,
|
Anum_pg_proc_prosrc,
|
||||||
&isNull);
|
&isNull);
|
||||||
|
if (isNull)
|
||||||
|
elog(ERROR, "null prosrc for function %u", foid);
|
||||||
|
fcache->src = TextDatumGetCString(tmp);
|
||||||
|
|
||||||
|
/* If we have prosqlbody, pay attention to that not prosrc. */
|
||||||
|
tmp = SysCacheGetAttr(PROCOID,
|
||||||
|
procedureTuple,
|
||||||
|
Anum_pg_proc_prosqlbody,
|
||||||
|
&isNull);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Parse and rewrite the queries in the function text. Use sublists to
|
* Parse and rewrite the queries in the function text. Use sublists to
|
||||||
@ -678,18 +687,11 @@ init_sql_fcache(FunctionCallInfo fcinfo, Oid collation, bool lazyEvalOK)
|
|||||||
* plancache.c.
|
* plancache.c.
|
||||||
*/
|
*/
|
||||||
queryTree_list = NIL;
|
queryTree_list = NIL;
|
||||||
if (isNull)
|
if (!isNull)
|
||||||
{
|
{
|
||||||
Node *n;
|
Node *n;
|
||||||
List *stored_query_list;
|
List *stored_query_list;
|
||||||
|
|
||||||
tmp = SysCacheGetAttr(PROCOID,
|
|
||||||
procedureTuple,
|
|
||||||
Anum_pg_proc_prosqlbody,
|
|
||||||
&isNull);
|
|
||||||
if (isNull)
|
|
||||||
elog(ERROR, "null prosrc and prosqlbody for function %u", foid);
|
|
||||||
|
|
||||||
n = stringToNode(TextDatumGetCString(tmp));
|
n = stringToNode(TextDatumGetCString(tmp));
|
||||||
if (IsA(n, List))
|
if (IsA(n, List))
|
||||||
stored_query_list = linitial_node(List, castNode(List, n));
|
stored_query_list = linitial_node(List, castNode(List, n));
|
||||||
@ -710,8 +712,6 @@ init_sql_fcache(FunctionCallInfo fcinfo, Oid collation, bool lazyEvalOK)
|
|||||||
{
|
{
|
||||||
List *raw_parsetree_list;
|
List *raw_parsetree_list;
|
||||||
|
|
||||||
fcache->src = TextDatumGetCString(tmp);
|
|
||||||
|
|
||||||
raw_parsetree_list = pg_parse_query(fcache->src);
|
raw_parsetree_list = pg_parse_query(fcache->src);
|
||||||
|
|
||||||
foreach(lc, raw_parsetree_list)
|
foreach(lc, raw_parsetree_list)
|
||||||
|
@ -4317,32 +4317,37 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid,
|
|||||||
ALLOCSET_DEFAULT_SIZES);
|
ALLOCSET_DEFAULT_SIZES);
|
||||||
oldcxt = MemoryContextSwitchTo(mycxt);
|
oldcxt = MemoryContextSwitchTo(mycxt);
|
||||||
|
|
||||||
/*
|
|
||||||
* Setup error traceback support for ereport(). This is so that we can
|
|
||||||
* finger the function that bad information came from.
|
|
||||||
*/
|
|
||||||
callback_arg.proname = NameStr(funcform->proname);
|
|
||||||
callback_arg.prosrc = NULL;
|
|
||||||
|
|
||||||
sqlerrcontext.callback = sql_inline_error_callback;
|
|
||||||
sqlerrcontext.arg = (void *) &callback_arg;
|
|
||||||
sqlerrcontext.previous = error_context_stack;
|
|
||||||
error_context_stack = &sqlerrcontext;
|
|
||||||
|
|
||||||
/* Fetch the function body */
|
/* Fetch the function body */
|
||||||
tmp = SysCacheGetAttr(PROCOID,
|
tmp = SysCacheGetAttr(PROCOID,
|
||||||
func_tuple,
|
func_tuple,
|
||||||
Anum_pg_proc_prosrc,
|
Anum_pg_proc_prosrc,
|
||||||
&isNull);
|
&isNull);
|
||||||
if (isNull)
|
if (isNull)
|
||||||
|
elog(ERROR, "null prosrc for function %u", funcid);
|
||||||
|
src = TextDatumGetCString(tmp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup error traceback support for ereport(). This is so that we can
|
||||||
|
* finger the function that bad information came from.
|
||||||
|
*/
|
||||||
|
callback_arg.proname = NameStr(funcform->proname);
|
||||||
|
callback_arg.prosrc = src;
|
||||||
|
|
||||||
|
sqlerrcontext.callback = sql_inline_error_callback;
|
||||||
|
sqlerrcontext.arg = (void *) &callback_arg;
|
||||||
|
sqlerrcontext.previous = error_context_stack;
|
||||||
|
error_context_stack = &sqlerrcontext;
|
||||||
|
|
||||||
|
/* If we have prosqlbody, pay attention to that not prosrc */
|
||||||
|
tmp = SysCacheGetAttr(PROCOID,
|
||||||
|
func_tuple,
|
||||||
|
Anum_pg_proc_prosqlbody,
|
||||||
|
&isNull);
|
||||||
|
if (!isNull)
|
||||||
{
|
{
|
||||||
Node *n;
|
Node *n;
|
||||||
List *querytree_list;
|
List *querytree_list;
|
||||||
|
|
||||||
tmp = SysCacheGetAttr(PROCOID, func_tuple, Anum_pg_proc_prosqlbody, &isNull);
|
|
||||||
if (isNull)
|
|
||||||
elog(ERROR, "null prosrc and prosqlbody for function %u", funcid);
|
|
||||||
|
|
||||||
n = stringToNode(TextDatumGetCString(tmp));
|
n = stringToNode(TextDatumGetCString(tmp));
|
||||||
if (IsA(n, List))
|
if (IsA(n, List))
|
||||||
querytree_list = linitial_node(List, castNode(List, n));
|
querytree_list = linitial_node(List, castNode(List, n));
|
||||||
@ -4354,10 +4359,6 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
src = TextDatumGetCString(tmp);
|
|
||||||
|
|
||||||
callback_arg.prosrc = src;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up to handle parameters while parsing the function body. We need a
|
* Set up to handle parameters while parsing the function body. We need a
|
||||||
* dummy FuncExpr node containing the already-simplified arguments to pass
|
* dummy FuncExpr node containing the already-simplified arguments to pass
|
||||||
@ -4658,15 +4659,12 @@ sql_inline_error_callback(void *arg)
|
|||||||
int syntaxerrposition;
|
int syntaxerrposition;
|
||||||
|
|
||||||
/* If it's a syntax error, convert to internal syntax error report */
|
/* If it's a syntax error, convert to internal syntax error report */
|
||||||
if (callback_arg->prosrc)
|
syntaxerrposition = geterrposition();
|
||||||
|
if (syntaxerrposition > 0)
|
||||||
{
|
{
|
||||||
syntaxerrposition = geterrposition();
|
errposition(0);
|
||||||
if (syntaxerrposition > 0)
|
internalerrposition(syntaxerrposition);
|
||||||
{
|
internalerrquery(callback_arg->prosrc);
|
||||||
errposition(0);
|
|
||||||
internalerrposition(syntaxerrposition);
|
|
||||||
internalerrquery(callback_arg->prosrc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
errcontext("SQL function \"%s\" during inlining", callback_arg->proname);
|
errcontext("SQL function \"%s\" during inlining", callback_arg->proname);
|
||||||
@ -4778,6 +4776,7 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
|
|||||||
Oid func_oid;
|
Oid func_oid;
|
||||||
HeapTuple func_tuple;
|
HeapTuple func_tuple;
|
||||||
Form_pg_proc funcform;
|
Form_pg_proc funcform;
|
||||||
|
char *src;
|
||||||
Datum tmp;
|
Datum tmp;
|
||||||
bool isNull;
|
bool isNull;
|
||||||
MemoryContext oldcxt;
|
MemoryContext oldcxt;
|
||||||
@ -4886,31 +4885,36 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
|
|||||||
ALLOCSET_DEFAULT_SIZES);
|
ALLOCSET_DEFAULT_SIZES);
|
||||||
oldcxt = MemoryContextSwitchTo(mycxt);
|
oldcxt = MemoryContextSwitchTo(mycxt);
|
||||||
|
|
||||||
/*
|
|
||||||
* Setup error traceback support for ereport(). This is so that we can
|
|
||||||
* finger the function that bad information came from.
|
|
||||||
*/
|
|
||||||
callback_arg.proname = NameStr(funcform->proname);
|
|
||||||
callback_arg.prosrc = NULL;
|
|
||||||
|
|
||||||
sqlerrcontext.callback = sql_inline_error_callback;
|
|
||||||
sqlerrcontext.arg = (void *) &callback_arg;
|
|
||||||
sqlerrcontext.previous = error_context_stack;
|
|
||||||
error_context_stack = &sqlerrcontext;
|
|
||||||
|
|
||||||
/* Fetch the function body */
|
/* Fetch the function body */
|
||||||
tmp = SysCacheGetAttr(PROCOID,
|
tmp = SysCacheGetAttr(PROCOID,
|
||||||
func_tuple,
|
func_tuple,
|
||||||
Anum_pg_proc_prosrc,
|
Anum_pg_proc_prosrc,
|
||||||
&isNull);
|
&isNull);
|
||||||
if (isNull)
|
if (isNull)
|
||||||
|
elog(ERROR, "null prosrc for function %u", func_oid);
|
||||||
|
src = TextDatumGetCString(tmp);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Setup error traceback support for ereport(). This is so that we can
|
||||||
|
* finger the function that bad information came from.
|
||||||
|
*/
|
||||||
|
callback_arg.proname = NameStr(funcform->proname);
|
||||||
|
callback_arg.prosrc = src;
|
||||||
|
|
||||||
|
sqlerrcontext.callback = sql_inline_error_callback;
|
||||||
|
sqlerrcontext.arg = (void *) &callback_arg;
|
||||||
|
sqlerrcontext.previous = error_context_stack;
|
||||||
|
error_context_stack = &sqlerrcontext;
|
||||||
|
|
||||||
|
/* If we have prosqlbody, pay attention to that not prosrc */
|
||||||
|
tmp = SysCacheGetAttr(PROCOID,
|
||||||
|
func_tuple,
|
||||||
|
Anum_pg_proc_prosqlbody,
|
||||||
|
&isNull);
|
||||||
|
if (!isNull)
|
||||||
{
|
{
|
||||||
Node *n;
|
Node *n;
|
||||||
|
|
||||||
tmp = SysCacheGetAttr(PROCOID, func_tuple, Anum_pg_proc_prosqlbody, &isNull);
|
|
||||||
if (isNull)
|
|
||||||
elog(ERROR, "null prosrc and prosqlbody for function %u", func_oid);
|
|
||||||
|
|
||||||
n = stringToNode(TextDatumGetCString(tmp));
|
n = stringToNode(TextDatumGetCString(tmp));
|
||||||
if (IsA(n, List))
|
if (IsA(n, List))
|
||||||
querytree_list = linitial_node(List, castNode(List, n));
|
querytree_list = linitial_node(List, castNode(List, n));
|
||||||
@ -4927,12 +4931,6 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *src;
|
|
||||||
|
|
||||||
src = TextDatumGetCString(tmp);
|
|
||||||
|
|
||||||
callback_arg.prosrc = src;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up to handle parameters while parsing the function body. We can
|
* Set up to handle parameters while parsing the function body. We can
|
||||||
* use the FuncExpr just created as the input for
|
* use the FuncExpr just created as the input for
|
||||||
|
@ -12247,7 +12247,7 @@ dumpFunc(Archive *fout, const FuncInfo *finfo)
|
|||||||
|
|
||||||
if (fout->remoteVersion >= 140000)
|
if (fout->remoteVersion >= 140000)
|
||||||
appendPQExpBufferStr(query,
|
appendPQExpBufferStr(query,
|
||||||
"CASE WHEN prosrc IS NULL AND lanname = 'sql' THEN pg_get_function_sqlbody(p.oid) END AS prosqlbody\n");
|
"pg_get_function_sqlbody(p.oid) AS prosqlbody\n");
|
||||||
else
|
else
|
||||||
appendPQExpBufferStr(query,
|
appendPQExpBufferStr(query,
|
||||||
"NULL AS prosqlbody\n");
|
"NULL AS prosqlbody\n");
|
||||||
|
@ -512,7 +512,7 @@ describeFunctions(const char *functypes, const char *func_pattern,
|
|||||||
gettext_noop("Language"));
|
gettext_noop("Language"));
|
||||||
if (pset.sversion >= 140000)
|
if (pset.sversion >= 140000)
|
||||||
appendPQExpBuffer(&buf,
|
appendPQExpBuffer(&buf,
|
||||||
",\n COALESCE(p.prosrc, pg_catalog.pg_get_function_sqlbody(p.oid)) as \"%s\"",
|
",\n COALESCE(pg_catalog.pg_get_function_sqlbody(p.oid), p.prosrc) as \"%s\"",
|
||||||
gettext_noop("Source code"));
|
gettext_noop("Source code"));
|
||||||
else
|
else
|
||||||
appendPQExpBuffer(&buf,
|
appendPQExpBuffer(&buf,
|
||||||
|
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 202104081
|
#define CATALOG_VERSION_NO 202104151
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -112,7 +112,7 @@ CATALOG(pg_proc,1255,ProcedureRelationId) BKI_BOOTSTRAP BKI_ROWTYPE_OID(81,Proce
|
|||||||
Oid protrftypes[1] BKI_DEFAULT(_null_) BKI_LOOKUP(pg_type);
|
Oid protrftypes[1] BKI_DEFAULT(_null_) BKI_LOOKUP(pg_type);
|
||||||
|
|
||||||
/* procedure source text */
|
/* procedure source text */
|
||||||
text prosrc;
|
text prosrc BKI_FORCE_NOT_NULL;
|
||||||
|
|
||||||
/* secondary procedure info (can be NULL) */
|
/* secondary procedure info (can be NULL) */
|
||||||
text probin BKI_DEFAULT(_null_);
|
text probin BKI_DEFAULT(_null_);
|
||||||
|
@ -17,9 +17,6 @@
|
|||||||
#include "nodes/execnodes.h"
|
#include "nodes/execnodes.h"
|
||||||
#include "tcop/dest.h"
|
#include "tcop/dest.h"
|
||||||
|
|
||||||
/* This struct is known only within executor/functions.c */
|
|
||||||
typedef struct SQLFunctionParseInfo *SQLFunctionParseInfoPtr;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Data structure needed by the parser callback hooks to resolve parameter
|
* Data structure needed by the parser callback hooks to resolve parameter
|
||||||
* references during parsing of a SQL function's body. This is separate from
|
* references during parsing of a SQL function's body. This is separate from
|
||||||
@ -35,6 +32,8 @@ typedef struct SQLFunctionParseInfo
|
|||||||
Oid collation; /* function's input collation, if known */
|
Oid collation; /* function's input collation, if known */
|
||||||
} SQLFunctionParseInfo;
|
} SQLFunctionParseInfo;
|
||||||
|
|
||||||
|
typedef SQLFunctionParseInfo *SQLFunctionParseInfoPtr;
|
||||||
|
|
||||||
extern Datum fmgr_sql(PG_FUNCTION_ARGS);
|
extern Datum fmgr_sql(PG_FUNCTION_ARGS);
|
||||||
|
|
||||||
extern SQLFunctionParseInfoPtr prepare_sql_fn_parse_info(HeapTuple procedureTuple,
|
extern SQLFunctionParseInfoPtr prepare_sql_fn_parse_info(HeapTuple procedureTuple,
|
||||||
|
@ -290,6 +290,12 @@ CREATE FUNCTION functest_S_xx(x anyarray) RETURNS anyelement
|
|||||||
LANGUAGE SQL
|
LANGUAGE SQL
|
||||||
RETURN x[1];
|
RETURN x[1];
|
||||||
ERROR: SQL function with unquoted function body cannot have polymorphic arguments
|
ERROR: SQL function with unquoted function body cannot have polymorphic arguments
|
||||||
|
-- check reporting of parse-analysis errors
|
||||||
|
CREATE FUNCTION functest_S_xx(x date) RETURNS boolean
|
||||||
|
LANGUAGE SQL
|
||||||
|
RETURN x > 1;
|
||||||
|
ERROR: operator does not exist: date > integer
|
||||||
|
HINT: No operator matches the given name and argument types. You might need to add explicit type casts.
|
||||||
-- tricky parsing
|
-- tricky parsing
|
||||||
CREATE FUNCTION functest_S_15(x int) RETURNS boolean
|
CREATE FUNCTION functest_S_15(x int) RETURNS boolean
|
||||||
LANGUAGE SQL
|
LANGUAGE SQL
|
||||||
|
@ -91,10 +91,17 @@ WHERE p1.prolang = 0 OR p1.prorettype = 0 OR
|
|||||||
-----+---------
|
-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
|
||||||
-- prosrc should never be null or empty
|
-- prosrc should never be null; it can be empty only if prosqlbody isn't null
|
||||||
SELECT p1.oid, p1.proname
|
SELECT p1.oid, p1.proname
|
||||||
FROM pg_proc as p1
|
FROM pg_proc as p1
|
||||||
WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-';
|
WHERE prosrc IS NULL;
|
||||||
|
oid | proname
|
||||||
|
-----+---------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
SELECT p1.oid, p1.proname
|
||||||
|
FROM pg_proc as p1
|
||||||
|
WHERE (prosrc = '' OR prosrc = '-') AND prosqlbody IS NULL;
|
||||||
oid | proname
|
oid | proname
|
||||||
-----+---------
|
-----+---------
|
||||||
(0 rows)
|
(0 rows)
|
||||||
|
@ -191,6 +191,11 @@ CREATE FUNCTION functest_S_xx(x anyarray) RETURNS anyelement
|
|||||||
LANGUAGE SQL
|
LANGUAGE SQL
|
||||||
RETURN x[1];
|
RETURN x[1];
|
||||||
|
|
||||||
|
-- check reporting of parse-analysis errors
|
||||||
|
CREATE FUNCTION functest_S_xx(x date) RETURNS boolean
|
||||||
|
LANGUAGE SQL
|
||||||
|
RETURN x > 1;
|
||||||
|
|
||||||
-- tricky parsing
|
-- tricky parsing
|
||||||
CREATE FUNCTION functest_S_15(x int) RETURNS boolean
|
CREATE FUNCTION functest_S_15(x int) RETURNS boolean
|
||||||
LANGUAGE SQL
|
LANGUAGE SQL
|
||||||
|
@ -96,10 +96,13 @@ WHERE p1.prolang = 0 OR p1.prorettype = 0 OR
|
|||||||
provolatile NOT IN ('i', 's', 'v') OR
|
provolatile NOT IN ('i', 's', 'v') OR
|
||||||
proparallel NOT IN ('s', 'r', 'u');
|
proparallel NOT IN ('s', 'r', 'u');
|
||||||
|
|
||||||
-- prosrc should never be null or empty
|
-- prosrc should never be null; it can be empty only if prosqlbody isn't null
|
||||||
SELECT p1.oid, p1.proname
|
SELECT p1.oid, p1.proname
|
||||||
FROM pg_proc as p1
|
FROM pg_proc as p1
|
||||||
WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-';
|
WHERE prosrc IS NULL;
|
||||||
|
SELECT p1.oid, p1.proname
|
||||||
|
FROM pg_proc as p1
|
||||||
|
WHERE (prosrc = '' OR prosrc = '-') AND prosqlbody IS NULL;
|
||||||
|
|
||||||
-- proretset should only be set for normal functions
|
-- proretset should only be set for normal functions
|
||||||
SELECT p1.oid, p1.proname
|
SELECT p1.oid, p1.proname
|
||||||
|
Reference in New Issue
Block a user