Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1446612

Browse files
committed
Fix handling of R/W expanded datums that are passed to SQL functions.
fmgr_sql must make expanded-datum arguments read-only, because it's possible that the function body will pass the argument to more than one callee function. If one of those functions takes the datum's R/W property as license to scribble on it, then later callees will see an unexpected value, leading to wrong answers. From a performance standpoint, it'd be nice to skip this in the common case that the argument value is passed to only one callee. However, detecting that seems fairly hard, and certainly not something that I care to attempt in a back-patched bug fix. Per report from Adam Mackler. This has been broken since we invented expanded datums, so back-patch to all supported branches. Discussion: https://postgr.es/m/WScDU5qfoZ7PB2gXwNqwGGgDPmWzz08VdydcPFLhOwUKZcdWbblbo-0Lku-qhuEiZoXJ82jpiQU4hOjOcrevYEDeoAvz6nR0IU4IHhXnaCA=@mackler.email Discussion: https://postgr.es/m/[email protected]
1 parent c8b9321 commit 1446612

File tree

3 files changed

+49
-5
lines changed

3 files changed

+49
-5
lines changed

src/backend/executor/functions.c

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -902,6 +902,7 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
902902
if (nargs > 0)
903903
{
904904
ParamListInfo paramLI;
905+
Oid *argtypes = fcache->pinfo->argtypes;
905906
int i;
906907

907908
if (fcache->paramLI == NULL)
@@ -928,10 +929,24 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
928929
{
929930
ParamExternData *prm = &paramLI->params[i];
930931

931-
prm->value = fcinfo->arg[i];
932+
/*
933+
* If an incoming parameter value is a R/W expanded datum, we
934+
* force it to R/O. We'd be perfectly entitled to scribble on it,
935+
* but the problem is that if the parameter is referenced more
936+
* than once in the function, earlier references might mutate the
937+
* value seen by later references, which won't do at all. We
938+
* could do better if we could be sure of the number of Param
939+
* nodes in the function's plans; but we might not have planned
940+
* all the statements yet, nor do we have plan tree walker
941+
* infrastructure. (Examining the parse trees is not good enough,
942+
* because of possible function inlining during planning.)
943+
*/
932944
prm->isnull = fcinfo->argnull[i];
945+
prm->value = MakeExpandedObjectReadOnly(fcinfo->arg[i],
946+
prm->isnull,
947+
get_typlen(argtypes[i]));
933948
prm->pflags = 0;
934-
prm->ptype = fcache->pinfo->argtypes[i];
949+
prm->ptype = argtypes[i];
935950
}
936951
}
937952
else

src/test/regress/expected/create_function_3.out

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -227,9 +227,25 @@ ERROR: could not find a function named "functest_b_1"
227227
DROP FUNCTION functest_b_2; -- error, ambiguous
228228
ERROR: function name "functest_b_2" is not unique
229229
HINT: Specify the argument list to select the function unambiguously.
230-
-- Cleanups
230+
-- Regression tests for bugs:
231+
-- Check that arguments that are R/W expanded datums aren't corrupted by
232+
-- multiple uses. This test knows that array_append() returns a R/W datum
233+
-- and will modify a R/W array input in-place. We use SETOF to prevent
234+
-- inlining of the SQL function.
235+
CREATE FUNCTION double_append(anyarray, anyelement) RETURNS SETOF anyarray
236+
LANGUAGE SQL IMMUTABLE AS
237+
$$ SELECT array_append($1, $2) || array_append($1, $2) $$;
238+
SELECT double_append(array_append(ARRAY[q1], q2), q3)
239+
FROM (VALUES(1,2,3), (4,5,6)) v(q1,q2,q3);
240+
double_append
241+
---------------
242+
{1,2,3,1,2,3}
243+
{4,5,6,4,5,6}
244+
(2 rows)
245+
246+
-- Cleanup
231247
DROP SCHEMA temp_func_test CASCADE;
232-
NOTICE: drop cascades to 16 other objects
248+
NOTICE: drop cascades to 17 other objects
233249
DETAIL: drop cascades to function functest_a_1(text,date)
234250
drop cascades to function functest_a_2(text[])
235251
drop cascades to function functest_a_3()
@@ -246,5 +262,6 @@ drop cascades to function functext_f_2(integer)
246262
drop cascades to function functext_f_3(integer)
247263
drop cascades to function functext_f_4(integer)
248264
drop cascades to function functest_b_2(bigint)
265+
drop cascades to function double_append(anyarray,anyelement)
249266
DROP USER regress_unpriv_user;
250267
RESET search_path;

src/test/regress/sql/create_function_3.sql

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,20 @@ DROP FUNCTION functest_b_1;
166166
DROP FUNCTION functest_b_1; -- error, not found
167167
DROP FUNCTION functest_b_2; -- error, ambiguous
168168

169+
-- Regression tests for bugs:
169170

170-
-- Cleanups
171+
-- Check that arguments that are R/W expanded datums aren't corrupted by
172+
-- multiple uses. This test knows that array_append() returns a R/W datum
173+
-- and will modify a R/W array input in-place. We use SETOF to prevent
174+
-- inlining of the SQL function.
175+
CREATE FUNCTION double_append(anyarray, anyelement) RETURNS SETOF anyarray
176+
LANGUAGE SQL IMMUTABLE AS
177+
$$ SELECT array_append($1, $2) || array_append($1, $2) $$;
178+
179+
SELECT double_append(array_append(ARRAY[q1], q2), q3)
180+
FROM (VALUES(1,2,3), (4,5,6)) v(q1,q2,q3);
181+
182+
-- Cleanup
171183
DROP SCHEMA temp_func_test CASCADE;
172184
DROP USER regress_unpriv_user;
173185
RESET search_path;

0 commit comments

Comments
 (0)