1
0
mirror of https://github.com/postgres/postgres.git synced 2025-08-27 07:42:10 +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:
Tom Lane
2021-04-15 17:17:20 -04:00
parent 3157cbe974
commit 1111b2668d
15 changed files with 125 additions and 95 deletions

View File

@@ -4317,32 +4317,37 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid,
ALLOCSET_DEFAULT_SIZES);
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 */
tmp = SysCacheGetAttr(PROCOID,
func_tuple,
Anum_pg_proc_prosrc,
&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;
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));
if (IsA(n, List))
querytree_list = linitial_node(List, castNode(List, n));
@@ -4354,10 +4359,6 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid,
}
else
{
src = TextDatumGetCString(tmp);
callback_arg.prosrc = src;
/*
* Set up to handle parameters while parsing the function body. We need a
* dummy FuncExpr node containing the already-simplified arguments to pass
@@ -4658,15 +4659,12 @@ sql_inline_error_callback(void *arg)
int syntaxerrposition;
/* If it's a syntax error, convert to internal syntax error report */
if (callback_arg->prosrc)
syntaxerrposition = geterrposition();
if (syntaxerrposition > 0)
{
syntaxerrposition = geterrposition();
if (syntaxerrposition > 0)
{
errposition(0);
internalerrposition(syntaxerrposition);
internalerrquery(callback_arg->prosrc);
}
errposition(0);
internalerrposition(syntaxerrposition);
internalerrquery(callback_arg->prosrc);
}
errcontext("SQL function \"%s\" during inlining", callback_arg->proname);
@@ -4778,6 +4776,7 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
Oid func_oid;
HeapTuple func_tuple;
Form_pg_proc funcform;
char *src;
Datum tmp;
bool isNull;
MemoryContext oldcxt;
@@ -4886,31 +4885,36 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
ALLOCSET_DEFAULT_SIZES);
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 */
tmp = SysCacheGetAttr(PROCOID,
func_tuple,
Anum_pg_proc_prosrc,
&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;
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));
if (IsA(n, List))
querytree_list = linitial_node(List, castNode(List, n));
@@ -4927,12 +4931,6 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte)
}
else
{
char *src;
src = TextDatumGetCString(tmp);
callback_arg.prosrc = src;
/*
* Set up to handle parameters while parsing the function body. We can
* use the FuncExpr just created as the input for