mirror of https://github.com/citusdata/citus.git
citus_evaluate_expression: call expand_function_arguments beforehand to avoid segfaulting on implicit parameters
parent
a98226842d
commit
cd0b2ad5b5
|
@ -21,9 +21,13 @@
|
||||||
#include "nodes/nodes.h"
|
#include "nodes/nodes.h"
|
||||||
#include "nodes/primnodes.h"
|
#include "nodes/primnodes.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
|
#if PG_VERSION_NUM >= PG_VERSION_12
|
||||||
|
#include "optimizer/optimizer.h"
|
||||||
|
#endif
|
||||||
#include "optimizer/planmain.h"
|
#include "optimizer/planmain.h"
|
||||||
#include "utils/datum.h"
|
#include "utils/datum.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
/* private function declarations */
|
/* private function declarations */
|
||||||
|
@ -36,6 +40,8 @@ static bool CitusIsMutableFunctionIdChecker(Oid func_id, void *context);
|
||||||
static bool ShouldEvaluateExpression(Expr *expression);
|
static bool ShouldEvaluateExpression(Expr *expression);
|
||||||
static bool ShouldEvaluateFunctionWithMasterContext(MasterEvaluationContext *
|
static bool ShouldEvaluateFunctionWithMasterContext(MasterEvaluationContext *
|
||||||
evaluationContext);
|
evaluationContext);
|
||||||
|
static void FixFunctionArguments(Node *expr);
|
||||||
|
static bool FixFunctionArgumentsWalker(Node *expr, void *context);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RequiresMasterEvaluation returns the executor needs to reparse and
|
* 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. */
|
/* We can use the estate's working context to avoid memory leaks. */
|
||||||
MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
MemoryContext oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
|
||||||
|
|
||||||
|
/* handles default values */
|
||||||
|
FixFunctionArguments((Node *) expr);
|
||||||
|
|
||||||
/* Make sure any opfuncids are filled in. */
|
/* Make sure any opfuncids are filled in. */
|
||||||
fix_opfuncids((Node *) expr);
|
fix_opfuncids((Node *) expr);
|
||||||
|
|
||||||
|
@ -452,3 +461,40 @@ CitusIsMutableFunction(Node *node)
|
||||||
|
|
||||||
return false;
|
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);
|
||||||
|
}
|
||||||
|
|
|
@ -220,10 +220,27 @@ NOTICE: stable_fn called
|
||||||
DETAIL: from localhost:xxxxx
|
DETAIL: from localhost:xxxxx
|
||||||
NOTICE: stable_fn called
|
NOTICE: stable_fn called
|
||||||
DETAIL: from localhost:xxxxx
|
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;
|
DROP SCHEMA multi_function_evaluation CASCADE;
|
||||||
NOTICE: drop cascades to 5 other objects
|
NOTICE: drop cascades to 7 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)
|
|
||||||
|
|
|
@ -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'
|
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;
|
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;
|
DROP SCHEMA multi_function_evaluation CASCADE;
|
||||||
|
|
Loading…
Reference in New Issue