mirror of https://github.com/citusdata/citus.git
Replace duplicate code and call check_functions_in_node (#1478)
MasterIrreducibleExpressionWalker has a copied code from function check_functions_in_node() which was available with PG 9.6+. Now PG 9.5 support is dropped we can remove duplicate code and directly call check_functions_in_node().pull/1488/head
parent
ea1fd9dd67
commit
2a4eada150
|
@ -90,7 +90,7 @@ static MultiPlan * CreateSingleTaskRouterPlan(Query *originalQuery,
|
||||||
static bool MasterIrreducibleExpression(Node *expression, bool *varArgument,
|
static bool MasterIrreducibleExpression(Node *expression, bool *varArgument,
|
||||||
bool *badCoalesce);
|
bool *badCoalesce);
|
||||||
static bool MasterIrreducibleExpressionWalker(Node *expression, WalkerState *state);
|
static bool MasterIrreducibleExpressionWalker(Node *expression, WalkerState *state);
|
||||||
static char MostPermissiveVolatileFlag(char left, char right);
|
static bool MasterIrreducibleExpressionFunctionChecker(Oid func_id, void *context);
|
||||||
static bool TargetEntryChangesValue(TargetEntry *targetEntry, Var *column,
|
static bool TargetEntryChangesValue(TargetEntry *targetEntry, Var *column,
|
||||||
FromExpr *joinTree);
|
FromExpr *joinTree);
|
||||||
static Task * RouterModifyTask(Oid distributedTableId, Query *originalQuery,
|
static Task * RouterModifyTask(Oid distributedTableId, Query *originalQuery,
|
||||||
|
@ -833,6 +833,7 @@ MasterIrreducibleExpressionWalker(Node *expression, WalkerState *state)
|
||||||
char volatileFlag = 0;
|
char volatileFlag = 0;
|
||||||
WalkerState childState = { false, false, false };
|
WalkerState childState = { false, false, false };
|
||||||
bool containsDisallowedFunction = false;
|
bool containsDisallowedFunction = false;
|
||||||
|
bool hasVolatileFunction PG_USED_FOR_ASSERTS_ONLY = false;
|
||||||
|
|
||||||
if (expression == NULL)
|
if (expression == NULL)
|
||||||
{
|
{
|
||||||
|
@ -883,123 +884,26 @@ MasterIrreducibleExpressionWalker(Node *expression, WalkerState *state)
|
||||||
*
|
*
|
||||||
* Look through contain_mutable_functions_walker or future PG's equivalent for new
|
* Look through contain_mutable_functions_walker or future PG's equivalent for new
|
||||||
* node types before bumping this version number to fix compilation; e.g. for any
|
* node types before bumping this version number to fix compilation; e.g. for any
|
||||||
* PostgreSQL after 9.5, see check_functions_in_node.
|
* PostgreSQL after 9.5, see check_functions_in_node. Review
|
||||||
|
* MasterIrreducibleExpressionFunctionChecker for any changes in volatility
|
||||||
|
* permissibility ordering.
|
||||||
*
|
*
|
||||||
* Once you've added them to this check, make sure you also evaluate them in the
|
* Once you've added them to this check, make sure you also evaluate them in the
|
||||||
* executor!
|
* executor!
|
||||||
*/
|
*/
|
||||||
StaticAssertStmt(PG_VERSION_NUM < 100100, "When porting to a newer PG this section"
|
|
||||||
" needs to be reviewed.");
|
|
||||||
if (IsA(expression, Aggref))
|
|
||||||
{
|
|
||||||
Aggref *expr = (Aggref *) expression;
|
|
||||||
|
|
||||||
volatileFlag = func_volatile(expr->aggfnoid);
|
/* subqueries aren't allowed and should fail before control reaches this point */
|
||||||
}
|
Assert(!IsA(expression, Query));
|
||||||
else if (IsA(expression, WindowFunc))
|
|
||||||
{
|
|
||||||
WindowFunc *expr = (WindowFunc *) expression;
|
|
||||||
|
|
||||||
volatileFlag = func_volatile(expr->winfnoid);
|
hasVolatileFunction =
|
||||||
}
|
check_functions_in_node(expression, MasterIrreducibleExpressionFunctionChecker,
|
||||||
else if (IsA(expression, OpExpr))
|
&volatileFlag);
|
||||||
{
|
|
||||||
OpExpr *expr = (OpExpr *) expression;
|
|
||||||
|
|
||||||
set_opfuncid(expr);
|
/* the caller should have already checked for this */
|
||||||
volatileFlag = func_volatile(expr->opfuncid);
|
Assert(!hasVolatileFunction);
|
||||||
}
|
Assert(volatileFlag != PROVOLATILE_VOLATILE);
|
||||||
else if (IsA(expression, FuncExpr))
|
|
||||||
{
|
|
||||||
FuncExpr *expr = (FuncExpr *) expression;
|
|
||||||
|
|
||||||
volatileFlag = func_volatile(expr->funcid);
|
if (volatileFlag == PROVOLATILE_STABLE)
|
||||||
}
|
|
||||||
else if (IsA(expression, DistinctExpr))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* to exercise this, you need to create a custom type for which the '=' operator
|
|
||||||
* is STABLE/VOLATILE
|
|
||||||
*/
|
|
||||||
DistinctExpr *expr = (DistinctExpr *) expression;
|
|
||||||
|
|
||||||
set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
|
|
||||||
volatileFlag = func_volatile(expr->opfuncid);
|
|
||||||
}
|
|
||||||
else if (IsA(expression, NullIfExpr))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* same as above, exercising this requires a STABLE/VOLATILE '=' operator
|
|
||||||
*/
|
|
||||||
NullIfExpr *expr = (NullIfExpr *) expression;
|
|
||||||
|
|
||||||
set_opfuncid((OpExpr *) expr); /* rely on struct equivalence */
|
|
||||||
volatileFlag = func_volatile(expr->opfuncid);
|
|
||||||
}
|
|
||||||
else if (IsA(expression, ScalarArrayOpExpr))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* to exercise this you need to CREATE OPERATOR with a binary predicate
|
|
||||||
* and use it within an ANY/ALL clause.
|
|
||||||
*/
|
|
||||||
ScalarArrayOpExpr *expr = (ScalarArrayOpExpr *) expression;
|
|
||||||
|
|
||||||
set_sa_opfuncid(expr);
|
|
||||||
volatileFlag = func_volatile(expr->opfuncid);
|
|
||||||
}
|
|
||||||
else if (IsA(expression, CoerceViaIO))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* to exercise this you need to use a type with a STABLE/VOLATILE intype or
|
|
||||||
* outtype.
|
|
||||||
*/
|
|
||||||
CoerceViaIO *expr = (CoerceViaIO *) expression;
|
|
||||||
Oid iofunc;
|
|
||||||
Oid typioparam;
|
|
||||||
bool typisvarlena;
|
|
||||||
|
|
||||||
/* check the result type's input function */
|
|
||||||
getTypeInputInfo(expr->resulttype,
|
|
||||||
&iofunc, &typioparam);
|
|
||||||
volatileFlag = MostPermissiveVolatileFlag(volatileFlag, func_volatile(iofunc));
|
|
||||||
|
|
||||||
/* check the input type's output function */
|
|
||||||
getTypeOutputInfo(exprType((Node *) expr->arg),
|
|
||||||
&iofunc, &typisvarlena);
|
|
||||||
volatileFlag = MostPermissiveVolatileFlag(volatileFlag, func_volatile(iofunc));
|
|
||||||
}
|
|
||||||
else if (IsA(expression, ArrayCoerceExpr))
|
|
||||||
{
|
|
||||||
ArrayCoerceExpr *expr = (ArrayCoerceExpr *) expression;
|
|
||||||
|
|
||||||
if (OidIsValid(expr->elemfuncid))
|
|
||||||
{
|
|
||||||
volatileFlag = func_volatile(expr->elemfuncid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (IsA(expression, RowCompareExpr))
|
|
||||||
{
|
|
||||||
RowCompareExpr *rcexpr = (RowCompareExpr *) expression;
|
|
||||||
ListCell *opid;
|
|
||||||
|
|
||||||
foreach(opid, rcexpr->opnos)
|
|
||||||
{
|
|
||||||
volatileFlag = MostPermissiveVolatileFlag(volatileFlag,
|
|
||||||
op_volatile(lfirst_oid(opid)));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (IsA(expression, Query))
|
|
||||||
{
|
|
||||||
/* subqueries aren't allowed and fail before control reaches this point */
|
|
||||||
Assert(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (volatileFlag == PROVOLATILE_VOLATILE)
|
|
||||||
{
|
|
||||||
/* the caller should have already checked for this */
|
|
||||||
Assert(false);
|
|
||||||
}
|
|
||||||
else if (volatileFlag == PROVOLATILE_STABLE)
|
|
||||||
{
|
{
|
||||||
containsDisallowedFunction =
|
containsDisallowedFunction =
|
||||||
expression_tree_walker(expression,
|
expression_tree_walker(expression,
|
||||||
|
@ -1025,26 +929,31 @@ MasterIrreducibleExpressionWalker(Node *expression, WalkerState *state)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Return the most-pessimistic volatility flag of the two params.
|
* MasterIrreducibleExpressionFunctionChecker returns true if a provided function
|
||||||
*
|
* oid corresponds to a volatile function. It also updates provided context if
|
||||||
* for example: given two flags, if one is stable and one is volatile, an expression
|
* the current volatility flag is more permissive than the provided one. It is
|
||||||
* involving both is volatile.
|
* only called from check_functions_in_node as checker function.
|
||||||
*/
|
*/
|
||||||
char
|
static bool
|
||||||
MostPermissiveVolatileFlag(char left, char right)
|
MasterIrreducibleExpressionFunctionChecker(Oid func_id, void *context)
|
||||||
{
|
{
|
||||||
if (left == PROVOLATILE_VOLATILE || right == PROVOLATILE_VOLATILE)
|
char volatileFlag = func_volatile(func_id);
|
||||||
|
char *volatileContext = (char *) context;
|
||||||
|
|
||||||
|
if (volatileFlag == PROVOLATILE_VOLATILE || *volatileContext == PROVOLATILE_VOLATILE)
|
||||||
{
|
{
|
||||||
return PROVOLATILE_VOLATILE;
|
*volatileContext = PROVOLATILE_VOLATILE;
|
||||||
}
|
}
|
||||||
else if (left == PROVOLATILE_STABLE || right == PROVOLATILE_STABLE)
|
else if (volatileFlag == PROVOLATILE_STABLE || *volatileContext == PROVOLATILE_STABLE)
|
||||||
{
|
{
|
||||||
return PROVOLATILE_STABLE;
|
*volatileContext = PROVOLATILE_STABLE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return PROVOLATILE_IMMUTABLE;
|
*volatileContext = PROVOLATILE_IMMUTABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return (volatileFlag == PROVOLATILE_VOLATILE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue