Merge pull request #3942 from citusdata/fix-default-func-param-evaluation

citus_evaluate_expression: call expand_function_arguments beforehand to avoid segfaulting on implicit parameters
pull/3944/head
Philip Dubé 2020-06-23 18:37:40 +00:00 committed by GitHub
commit ac3c646ed5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 83 additions and 6 deletions

View File

@ -21,9 +21,13 @@
#include "nodes/nodes.h"
#include "nodes/primnodes.h"
#include "optimizer/clauses.h"
#if PG_VERSION_NUM >= PG_VERSION_12
#include "optimizer/optimizer.h"
#endif
#include "optimizer/planmain.h"
#include "utils/datum.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
/* private function declarations */
@ -36,6 +40,8 @@ static bool CitusIsMutableFunctionIdChecker(Oid func_id, void *context);
static bool ShouldEvaluateExpression(Expr *expression);
static bool ShouldEvaluateFunctionWithMasterContext(MasterEvaluationContext *
evaluationContext);
static void FixFunctionArguments(Node *expr);
static bool FixFunctionArgumentsWalker(Node *expr, void *context);
/*
* RequiresMasterEvaluation returns the executor needs to reparse and
@ -304,6 +310,9 @@ citus_evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
/* We can use the estate's working context to avoid memory leaks. */
MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
/* handles default values */
FixFunctionArguments((Node *) expr);
/* Make sure any opfuncids are filled in. */
fix_opfuncids((Node *) expr);
@ -452,3 +461,40 @@ CitusIsMutableFunction(Node *node)
return false;
}
/* FixFunctionArguments applies expand_function_arguments to all function calls. */
static void
FixFunctionArguments(Node *expr)
{
FixFunctionArgumentsWalker(expr, NULL);
}
/* FixFunctionArgumentsWalker is the helper function for fix_funcargs. */
static bool
FixFunctionArgumentsWalker(Node *expr, void *context)
{
if (expr == NULL)
{
return false;
}
if (IsA(expr, FuncExpr))
{
FuncExpr *funcExpr = castNode(FuncExpr, expr);
HeapTuple func_tuple =
SearchSysCache1(PROCOID, ObjectIdGetDatum(funcExpr->funcid));
if (!HeapTupleIsValid(func_tuple))
{
elog(ERROR, "cache lookup failed for function %u", funcExpr->funcid);
}
funcExpr->args = expand_function_arguments(funcExpr->args,
funcExpr->funcresulttype, func_tuple);
ReleaseSysCache(func_tuple);
}
return expression_tree_walker(expr, FixFunctionArgumentsWalker, NULL);
}

View File

@ -220,10 +220,27 @@ NOTICE: stable_fn called
DETAIL: from localhost:xxxxx
NOTICE: stable_fn called
DETAIL: from localhost:xxxxx
-- https://github.com/citusdata/citus/issues/3939
CREATE TABLE test_table(id int);
SELECT create_distributed_table('test_table', 'id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
CREATE OR REPLACE FUNCTION f(val text DEFAULT 'default')
RETURNS int AS $$ BEGIN RETURN length(val); END; $$ LANGUAGE 'plpgsql' IMMUTABLE;
INSERT INTO test_table VALUES (f('test'));
INSERT INTO test_table VALUES (f());
INSERT INTO test_table VALUES (f(f()::text));
SELECT * FROM test_table ORDER BY 1;
id
---------------------------------------------------------------------
1
4
7
(3 rows)
\set VERBOSITY terse
DROP SCHEMA multi_function_evaluation CASCADE;
NOTICE: drop cascades to 5 other objects
DETAIL: drop cascades to table example
drop cascades to sequence example_value_seq
drop cascades to function stable_fn()
drop cascades to table table_1
drop cascades to function stable_squared(integer)
NOTICE: drop cascades to 7 other objects

View File

@ -165,4 +165,18 @@ FROM (SELECT key, stable_squared((count(*) OVER ())::int) y FROM example GROUP B
UPDATE example SET value = timestamp '10-10-2000 00:00'
FROM (SELECT key, stable_squared(grouping(key)) y FROM example GROUP BY key) a WHERE example.key = a.key;
-- https://github.com/citusdata/citus/issues/3939
CREATE TABLE test_table(id int);
SELECT create_distributed_table('test_table', 'id');
CREATE OR REPLACE FUNCTION f(val text DEFAULT 'default')
RETURNS int AS $$ BEGIN RETURN length(val); END; $$ LANGUAGE 'plpgsql' IMMUTABLE;
INSERT INTO test_table VALUES (f('test'));
INSERT INTO test_table VALUES (f());
INSERT INTO test_table VALUES (f(f()::text));
SELECT * FROM test_table ORDER BY 1;
\set VERBOSITY terse
DROP SCHEMA multi_function_evaluation CASCADE;