Merge pull request #4198 from citusdata/disallow-volatile-subquery-in-updates

Disallow volatile functions on single shard update subqueries
pull/4205/head
Hanefi Onaldi 2020-09-29 16:27:13 +03:00 committed by GitHub
commit 85d32bcf35
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 63 additions and 18 deletions

View File

@ -136,9 +136,12 @@ static DeferredErrorMessage * DeferErrorIfUnsupportedModifyQueryWithCitusLocalTa
RTEListProperties *rteListProperties, Oid targetRelationId); RTEListProperties *rteListProperties, Oid targetRelationId);
static DeferredErrorMessage * DeferErrorIfUnsupportedModifyQueryWithPostgresLocalTable( static DeferredErrorMessage * DeferErrorIfUnsupportedModifyQueryWithPostgresLocalTable(
RTEListProperties *rteListProperties, Oid targetRelationId); RTEListProperties *rteListProperties, Oid targetRelationId);
static DeferredErrorMessage * MultiShardModifyQuerySupported(Query *originalQuery, static DeferredErrorMessage * MultiShardUpdateDeleteSupported(Query *originalQuery,
PlannerRestrictionContext * PlannerRestrictionContext *
plannerRestrictionContext); plannerRestrictionContext);
static DeferredErrorMessage * SingleShardUpdateDeleteSupported(Query *originalQuery,
PlannerRestrictionContext *
plannerRestrictionContext);
static bool HasDangerousJoinUsing(List *rtableList, Node *jtnode); static bool HasDangerousJoinUsing(List *rtableList, Node *jtnode);
static bool MasterIrreducibleExpression(Node *expression, bool *varArgument, static bool MasterIrreducibleExpression(Node *expression, bool *varArgument,
bool *badCoalesce); bool *badCoalesce);
@ -1061,10 +1064,20 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer
} }
} }
if (commandType != CMD_INSERT && multiShardQuery) if (commandType != CMD_INSERT)
{ {
DeferredErrorMessage *errorMessage = MultiShardModifyQuerySupported( DeferredErrorMessage *errorMessage = NULL;
originalQuery, plannerRestrictionContext);
if (multiShardQuery)
{
errorMessage = MultiShardUpdateDeleteSupported(originalQuery,
plannerRestrictionContext);
}
else
{
errorMessage = SingleShardUpdateDeleteSupported(originalQuery,
plannerRestrictionContext);
}
if (errorMessage != NULL) if (errorMessage != NULL)
{ {
@ -1217,12 +1230,12 @@ ErrorIfOnConflictNotSupported(Query *queryTree)
/* /*
* MultiShardModifyQuerySupported returns the error message if the modify query is * MultiShardUpdateDeleteSupported returns the error message if the update/delete is
* not pushdownable, otherwise it returns NULL. * not pushdownable, otherwise it returns NULL.
*/ */
static DeferredErrorMessage * static DeferredErrorMessage *
MultiShardModifyQuerySupported(Query *originalQuery, MultiShardUpdateDeleteSupported(Query *originalQuery,
PlannerRestrictionContext *plannerRestrictionContext) PlannerRestrictionContext *plannerRestrictionContext)
{ {
DeferredErrorMessage *errorMessage = NULL; DeferredErrorMessage *errorMessage = NULL;
RangeTblEntry *resultRangeTable = ExtractResultRelationRTE(originalQuery); RangeTblEntry *resultRangeTable = ExtractResultRelationRTE(originalQuery);
@ -1261,6 +1274,35 @@ MultiShardModifyQuerySupported(Query *originalQuery,
} }
/*
* SingleShardUpdateDeleteSupported returns the error message if the update/delete query is
* not routable, otherwise it returns NULL.
*/
static DeferredErrorMessage *
SingleShardUpdateDeleteSupported(Query *originalQuery,
PlannerRestrictionContext *plannerRestrictionContext)
{
DeferredErrorMessage *errorMessage = NULL;
/*
* We currently do not support volatile functions in update/delete statements because
* the function evaluation logic does not know how to distinguish volatile functions
* (that need to be evaluated per row) from stable functions (that need to be evaluated per query),
* and it is also not safe to push the volatile functions down on replicated tables.
*/
if (FindNodeMatchingCheckFunction((Node *) originalQuery,
CitusIsVolatileFunction))
{
errorMessage = DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"functions used in UPDATE queries on distributed "
"tables must not be VOLATILE",
NULL, NULL);
}
return errorMessage;
}
/* /*
* HasDangerousJoinUsing search jointree for unnamed JOIN USING. Check the * HasDangerousJoinUsing search jointree for unnamed JOIN USING. Check the
* implementation of has_dangerous_join_using in ruleutils. * implementation of has_dangerous_join_using in ruleutils.

View File

@ -2314,11 +2314,6 @@ DEBUG: query has a single distribution column value: 1
52 52
(7 rows) (7 rows)
-- https://github.com/citusdata/citus/issues/3624
UPDATE articles_hash SET id = id
WHERE author_id = 1 AND title IN (SELECT name FROM authors_reference WHERE random() > 0.5);
DEBUG: Creating router plan
DEBUG: query has a single distribution column value: 1
SET client_min_messages to 'NOTICE'; SET client_min_messages to 'NOTICE';
-- test that a connection failure marks placements invalid -- test that a connection failure marks placements invalid
SET citus.shard_replication_factor TO 2; SET citus.shard_replication_factor TO 2;

View File

@ -704,6 +704,12 @@ SET value_2 = 5 * random()
FROM events_test_table FROM events_test_table
WHERE users_test_table.user_id = events_test_table.user_id; WHERE users_test_table.user_id = events_test_table.user_id;
ERROR: functions used in UPDATE queries on distributed tables must not be VOLATILE ERROR: functions used in UPDATE queries on distributed tables must not be VOLATILE
UPDATE users_test_table
SET value_1 = 3
WHERE user_id = 1 AND value_1 IN (SELECT value_1
FROM users_test_table
WHERE user_id = 1 AND value_2 > random());
ERROR: functions used in UPDATE queries on distributed tables must not be VOLATILE
-- Recursive modify planner does not take care of following test because the query -- Recursive modify planner does not take care of following test because the query
-- is fully pushdownable, yet not allowed because it would lead to inconsistent replicas. -- is fully pushdownable, yet not allowed because it would lead to inconsistent replicas.
UPDATE users_test_table UPDATE users_test_table

View File

@ -1126,10 +1126,6 @@ SELECT id
WHERE author_id = 1 WHERE author_id = 1
ORDER BY 1; ORDER BY 1;
-- https://github.com/citusdata/citus/issues/3624
UPDATE articles_hash SET id = id
WHERE author_id = 1 AND title IN (SELECT name FROM authors_reference WHERE random() > 0.5);
SET client_min_messages to 'NOTICE'; SET client_min_messages to 'NOTICE';
-- test that a connection failure marks placements invalid -- test that a connection failure marks placements invalid

View File

@ -579,6 +579,12 @@ SET value_2 = 5 * random()
FROM events_test_table FROM events_test_table
WHERE users_test_table.user_id = events_test_table.user_id; WHERE users_test_table.user_id = events_test_table.user_id;
UPDATE users_test_table
SET value_1 = 3
WHERE user_id = 1 AND value_1 IN (SELECT value_1
FROM users_test_table
WHERE user_id = 1 AND value_2 > random());
-- Recursive modify planner does not take care of following test because the query -- Recursive modify planner does not take care of following test because the query
-- is fully pushdownable, yet not allowed because it would lead to inconsistent replicas. -- is fully pushdownable, yet not allowed because it would lead to inconsistent replicas.
UPDATE users_test_table UPDATE users_test_table