Allow routing modifying CTEs

We still recursively plan some cases, eg:
- INSERTs
- SELECT FOR UPDATE when reference tables in query
- Everything must be same single shard & replication model
pull/3654/head
Philip Dubé 2020-03-19 21:58:23 +00:00
parent e37c385d6c
commit 1722d8ac8b
30 changed files with 2192 additions and 587 deletions

View File

@ -1467,11 +1467,6 @@ ReadOnlyTask(TaskType taskType)
case MAP_TASK:
case MERGE_TASK:
{
/*
* TODO: We currently do not execute modifying CTEs via ROUTER_TASK/SQL_TASK.
* When we implement it, we should either not use the mentioned task types for
* modifying CTEs detect them here.
*/
return true;
}

View File

@ -54,7 +54,7 @@ static Node * DelayedErrorCreateScan(CustomScan *scan);
/* functions that are common to different scans */
static void CitusBeginScan(CustomScanState *node, EState *estate, int eflags);
static void CitusBeginSelectScan(CustomScanState *node, EState *estate, int eflags);
static void CitusBeginReadOnlyScan(CustomScanState *node, EState *estate, int eflags);
static void CitusBeginModifyScan(CustomScanState *node, EState *estate, int eflags);
static void CitusPreExecScan(CitusScanState *scanState);
static bool ModifyJobNeedsEvaluation(Job *workerJob);
@ -206,7 +206,7 @@ CitusBeginScan(CustomScanState *node, EState *estate, int eflags)
}
else if (distributedPlan->modLevel == ROW_MODIFY_READONLY)
{
CitusBeginSelectScan(node, estate, eflags);
CitusBeginReadOnlyScan(node, estate, eflags);
}
else
{
@ -248,14 +248,16 @@ CitusExecScan(CustomScanState *node)
/*
* CitusBeginSelectScan handles deferred pruning and plan caching for SELECTs.
* CitusBeginReadOnlyScan handles deferred pruning and plan caching for SELECTs.
*/
static void
CitusBeginSelectScan(CustomScanState *node, EState *estate, int eflags)
CitusBeginReadOnlyScan(CustomScanState *node, EState *estate, int eflags)
{
CitusScanState *scanState = (CitusScanState *) node;
DistributedPlan *originalDistributedPlan = scanState->distributedPlan;
Assert(originalDistributedPlan->workerJob->jobQuery->commandType == CMD_SELECT);
if (!originalDistributedPlan->workerJob->deferredPruning)
{
/*
@ -295,7 +297,7 @@ CitusBeginSelectScan(CustomScanState *node, EState *estate, int eflags)
*
* TODO: evaluate stable functions
*/
ExecuteMasterEvaluableParameters(jobQuery, planState);
ExecuteMasterEvaluableExpressions(jobQuery, planState);
/* job query no longer has parameters, so we should not send any */
workerJob->parametersInJobQueryResolved = true;
@ -345,8 +347,7 @@ CitusBeginModifyScan(CustomScanState *node, EState *estate, int eflags)
if (ModifyJobNeedsEvaluation(workerJob))
{
/* evaluate both functions and parameters */
ExecuteMasterEvaluableFunctionsAndParameters(jobQuery, planState);
ExecuteMasterEvaluableExpressions(jobQuery, planState);
/* job query no longer has parameters, so we should not send any */
workerJob->parametersInJobQueryResolved = true;

View File

@ -190,7 +190,7 @@ IsLocalPlanCachingSupported(Job *currentJob, DistributedPlan *originalDistribute
* We do not cache plans with volatile functions in the query.
*
* The reason we care about volatile functions is primarily that we
* already executed them in ExecuteMasterEvaluableFunctionsAndParameters
* already executed them in ExecuteMasterEvaluableExpressions
* and since we're falling back to the original query tree here we would
* execute them again if we execute the plan.
*/

View File

@ -457,6 +457,19 @@ IsDistributedTableRTE(Node *node)
}
/*
* IsReferenceTableRTE gets a node and returns true if the node
* is a range table relation entry that points to a reference table.
*/
bool
IsReferenceTableRTE(Node *node)
{
Oid relationId = NodeTryGetRteRelid(node);
return relationId != InvalidOid && IsCitusTable(relationId) &&
PartitionMethod(relationId) == DISTRIBUTE_BY_NONE;
}
/*
* FullCompositeFieldList gets a composite field list, and checks if all fields
* of composite type are used in the list.

View File

@ -4636,6 +4636,22 @@ RowModifyLevelForQuery(Query *query)
if (commandType == CMD_SELECT)
{
if (query->hasModifyingCTE)
{
/* skip checking for INSERT as those CTEs are recursively planned */
CommonTableExpr *cte = NULL;
foreach_ptr(cte, query->cteList)
{
Query *cteQuery = (Query *) cte->ctequery;
if (cteQuery->commandType == CMD_UPDATE ||
cteQuery->commandType == CMD_DELETE)
{
return ROW_MODIFY_NONCOMMUTATIVE;
}
}
}
return ROW_MODIFY_READONLY;
}

View File

@ -125,6 +125,9 @@ static void CreateSingleTaskRouterSelectPlan(DistributedPlan *distributedPlan,
plannerRestrictionContext);
static Oid ResultRelationOidForQuery(Query *query);
static bool IsTidColumn(Node *node);
static DeferredErrorMessage * ModifyPartialQuerySupported(Query *queryTree, bool
multiShardQuery,
Oid *distributedTableId);
static DeferredErrorMessage * MultiShardModifyQuerySupported(Query *originalQuery,
PlannerRestrictionContext *
plannerRestrictionContext);
@ -149,19 +152,16 @@ static List * BuildRoutesForInsert(Query *query, DeferredErrorMessage **planning
static List * GroupInsertValuesByShardId(List *insertValuesList);
static List * ExtractInsertValuesList(Query *query, Var *partitionColumn);
static DeferredErrorMessage * MultiRouterPlannableQuery(Query *query);
static DeferredErrorMessage * ErrorIfQueryHasModifyingCTE(Query *queryTree);
static DeferredErrorMessage * ErrorIfQueryHasUnroutableModifyingCTE(Query *queryTree);
static bool SelectsFromDistributedTable(List *rangeTableList, Query *query);
static ShardPlacement * CreateDummyPlacement(void);
static List * get_all_actual_clauses(List *restrictinfo_list);
static int CompareInsertValuesByShardId(const void *leftElement,
const void *rightElement);
static List * SingleShardSelectTaskList(Query *query, uint64 jobId,
List *relationShardList, List *placementList,
uint64 shardId, bool parametersInQueryResolved);
static List * SingleShardTaskList(Query *query, uint64 jobId,
List *relationShardList, List *placementList,
uint64 shardId, bool parametersInQueryResolved);
static bool RowLocksOnRelations(Node *node, List **rtiLockList);
static List * SingleShardModifyTaskList(Query *query, uint64 jobId,
List *relationShardList, List *placementList,
uint64 shardId, bool parametersInQueryResolved);
static List * RemoveCoordinatorPlacement(List *placementList);
static void ReorderTaskPlacementsByTaskAssignmentPolicy(Job *job,
TaskAssignmentPolicyType
@ -511,7 +511,12 @@ ResultRelationOidForQuery(Query *query)
RangeTblEntry *
ExtractResultRelationRTE(Query *query)
{
return rt_fetch(query->resultRelation, query->rtable);
if (query->resultRelation > 0)
{
return rt_fetch(query->resultRelation, query->rtable);
}
return NULL;
}
@ -535,28 +540,18 @@ IsTidColumn(Node *node)
/*
* ModifyQuerySupported returns NULL if the query only contains supported
* features, otherwise it returns an error description.
* Note that we need both the original query and the modified one because
* different checks need different versions. In particular, we cannot
* perform the ContainsReadIntermediateResultFunction check on the
* rewritten query because it may have been replaced by a subplan,
* while some of the checks for setting the partition column value rely
* on the rewritten query.
* ModifyPartialQuerySupported implements a subset of what ModifyQuerySupported checks,
* that subset being what's necessary to check modifying CTEs for.
*/
DeferredErrorMessage *
ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuery,
PlannerRestrictionContext *plannerRestrictionContext)
static DeferredErrorMessage *
ModifyPartialQuerySupported(Query *queryTree, bool multiShardQuery,
Oid *distributedTableIdOutput)
{
uint32 rangeTableId = 1;
List *rangeTableList = NIL;
ListCell *rangeTableCell = NULL;
uint32 queryTableCount = 0;
CmdType commandType = queryTree->commandType;
bool fastPathRouterQuery =
plannerRestrictionContext->fastPathRestrictionContext->fastPathRouterQuery;
Oid distributedTableId = ModifyQueryResultRelationId(queryTree);
*distributedTableIdOutput = distributedTableId;
if (!IsCitusTable(distributedTableId))
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
@ -573,30 +568,6 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer
return deferredError;
}
/*
* Here, we check if a recursively planned query tries to modify
* rows based on the ctid column. This is a bad idea because ctid of
* the rows could be changed before the modification part of
* the query is executed.
*
* We can exclude fast path queries since they cannot have intermediate
* results by definition.
*/
if (!fastPathRouterQuery &&
ContainsReadIntermediateResultFunction((Node *) originalQuery))
{
bool hasTidColumn = FindNodeCheck((Node *) originalQuery->jointree, IsTidColumn);
if (hasTidColumn)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"cannot perform distributed planning for the given "
"modification",
"Recursively planned distributed modifications "
"with ctid on where clause are not supported.",
NULL);
}
}
/*
* Reject subqueries which are in SELECT or WHERE clause.
* Queries which include subqueries in FROM clauses are rejected below.
@ -626,17 +597,38 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer
Query *cteQuery = (Query *) cte->ctequery;
if (cteQuery->commandType != CMD_SELECT)
{
/* Modifying CTEs still not supported for INSERTs & multi shard queries. */
if (queryTree->commandType == CMD_INSERT)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"Router planner doesn't support non-select common table expressions with non-select queries.",
NULL, NULL);
}
if (multiShardQuery)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"Router planner doesn't support non-select common table expressions with multi shard queries.",
NULL, NULL);
}
}
/* Modifying CTEs exclude both INSERT CTEs & INSERT queries. */
if (cteQuery->commandType == CMD_INSERT)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"Router planner doesn't support non-select common table expressions.",
"Router planner doesn't support INSERT common table expressions.",
NULL, NULL);
}
if (cteQuery->hasForUpdate)
if (cteQuery->hasForUpdate &&
FindNodeCheckInRangeTableList(cteQuery->rtable, IsReferenceTableRTE))
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"Router planner doesn't support SELECT FOR UPDATE"
" in common table expressions.",
" in common table expressions involving reference tables.",
NULL, NULL);
}
@ -648,14 +640,184 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer
NULL, NULL);
}
DeferredErrorMessage *cteError = MultiRouterPlannableQuery(cteQuery);
if (cteError)
if (cteQuery->commandType == CMD_SELECT)
{
return cteError;
DeferredErrorMessage *cteError = MultiRouterPlannableQuery(cteQuery);
if (cteError)
{
return cteError;
}
}
}
}
if (commandType == CMD_INSERT || commandType == CMD_UPDATE ||
commandType == CMD_DELETE)
{
bool hasVarArgument = false; /* A STABLE function is passed a Var argument */
bool hasBadCoalesce = false; /* CASE/COALESCE passed a mutable function */
FromExpr *joinTree = queryTree->jointree;
ListCell *targetEntryCell = NULL;
foreach(targetEntryCell, queryTree->targetList)
{
TargetEntry *targetEntry = (TargetEntry *) lfirst(targetEntryCell);
bool targetEntryPartitionColumn = false;
/* reference tables do not have partition column */
if (partitionColumn == NULL)
{
targetEntryPartitionColumn = false;
}
else if (targetEntry->resno == partitionColumn->varattno)
{
targetEntryPartitionColumn = true;
}
/* skip resjunk entries: UPDATE adds some for ctid, etc. */
if (targetEntry->resjunk)
{
continue;
}
if (commandType == CMD_UPDATE &&
FindNodeCheck((Node *) targetEntry->expr, CitusIsVolatileFunction))
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"functions used in UPDATE queries on distributed "
"tables must not be VOLATILE",
NULL, NULL);
}
if (commandType == CMD_UPDATE && targetEntryPartitionColumn &&
TargetEntryChangesValue(targetEntry, partitionColumn,
queryTree->jointree))
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"modifying the partition value of rows is not "
"allowed",
NULL, NULL);
}
if (commandType == CMD_UPDATE &&
MasterIrreducibleExpression((Node *) targetEntry->expr,
&hasVarArgument, &hasBadCoalesce))
{
Assert(hasVarArgument || hasBadCoalesce);
}
}
if (joinTree != NULL)
{
if (FindNodeCheck((Node *) joinTree->quals, CitusIsVolatileFunction))
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"functions used in the WHERE clause of modification "
"queries on distributed tables must not be VOLATILE",
NULL, NULL);
}
else if (MasterIrreducibleExpression(joinTree->quals, &hasVarArgument,
&hasBadCoalesce))
{
Assert(hasVarArgument || hasBadCoalesce);
}
}
if (hasVarArgument)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"STABLE functions used in UPDATE queries "
"cannot be called with column references",
NULL, NULL);
}
if (hasBadCoalesce)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"non-IMMUTABLE functions are not allowed in CASE or "
"COALESCE statements",
NULL, NULL);
}
if (contain_mutable_functions((Node *) queryTree->returningList))
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"non-IMMUTABLE functions are not allowed in the "
"RETURNING clause",
NULL, NULL);
}
if (queryTree->jointree->quals != NULL &&
nodeTag(queryTree->jointree->quals) == T_CurrentOfExpr)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"cannot run DML queries with cursors", NULL,
NULL);
}
}
deferredError = ErrorIfOnConflictNotSupported(queryTree);
if (deferredError != NULL)
{
return deferredError;
}
return NULL;
}
/*
* ModifyQuerySupported returns NULL if the query only contains supported
* features, otherwise it returns an error description.
* Note that we need both the original query and the modified one because
* different checks need different versions. In particular, we cannot
* perform the ContainsReadIntermediateResultFunction check on the
* rewritten query because it may have been replaced by a subplan,
* while some of the checks for setting the partition column value rely
* on the rewritten query.
*/
DeferredErrorMessage *
ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuery,
PlannerRestrictionContext *plannerRestrictionContext)
{
Oid distributedTableId = InvalidOid;
DeferredErrorMessage *error = ModifyPartialQuerySupported(queryTree, multiShardQuery,
&distributedTableId);
if (error)
{
return error;
}
List *rangeTableList = NIL;
uint32 queryTableCount = 0;
CmdType commandType = queryTree->commandType;
bool fastPathRouterQuery =
plannerRestrictionContext->fastPathRestrictionContext->fastPathRouterQuery;
/*
* Here, we check if a recursively planned query tries to modify
* rows based on the ctid column. This is a bad idea because ctid of
* the rows could be changed before the modification part of
* the query is executed.
*
* We can exclude fast path queries since they cannot have intermediate
* results by definition.
*/
if (!fastPathRouterQuery &&
ContainsReadIntermediateResultFunction((Node *) originalQuery))
{
bool hasTidColumn = FindNodeCheck((Node *) originalQuery->jointree, IsTidColumn);
if (hasTidColumn)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"cannot perform distributed planning for the given "
"modification",
"Recursively planned distributed modifications "
"with ctid on where clause are not supported.",
NULL);
}
}
/*
* Extract range table entries for queries that are not fast path. We can skip fast
* path queries because their definition is a single RTE entry, which is a relation,
@ -666,10 +828,9 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer
ExtractRangeTableEntryWalker((Node *) originalQuery, &rangeTableList);
}
foreach(rangeTableCell, rangeTableList)
RangeTblEntry *rangeTableEntry = NULL;
foreach_ptr(rangeTableEntry, rangeTableList)
{
RangeTblEntry *rangeTableEntry = (RangeTblEntry *) lfirst(rangeTableCell);
if (rangeTableEntry->rtekind == RTE_RELATION)
{
/* we do not expect to see a view in modify query */
@ -789,117 +950,6 @@ ModifyQuerySupported(Query *queryTree, Query *originalQuery, bool multiShardQuer
}
}
if (commandType == CMD_INSERT || commandType == CMD_UPDATE ||
commandType == CMD_DELETE)
{
bool hasVarArgument = false; /* A STABLE function is passed a Var argument */
bool hasBadCoalesce = false; /* CASE/COALESCE passed a mutable function */
FromExpr *joinTree = queryTree->jointree;
ListCell *targetEntryCell = NULL;
foreach(targetEntryCell, queryTree->targetList)
{
TargetEntry *targetEntry = (TargetEntry *) lfirst(targetEntryCell);
bool targetEntryPartitionColumn = false;
/* reference tables do not have partition column */
if (partitionColumn == NULL)
{
targetEntryPartitionColumn = false;
}
else if (targetEntry->resno == partitionColumn->varattno)
{
targetEntryPartitionColumn = true;
}
/* skip resjunk entries: UPDATE adds some for ctid, etc. */
if (targetEntry->resjunk)
{
continue;
}
if (commandType == CMD_UPDATE &&
FindNodeCheck((Node *) targetEntry->expr, CitusIsVolatileFunction))
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"functions used in UPDATE queries on distributed "
"tables must not be VOLATILE",
NULL, NULL);
}
if (commandType == CMD_UPDATE && targetEntryPartitionColumn &&
TargetEntryChangesValue(targetEntry, partitionColumn,
queryTree->jointree))
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"modifying the partition value of rows is not "
"allowed",
NULL, NULL);
}
if (commandType == CMD_UPDATE &&
MasterIrreducibleExpression((Node *) targetEntry->expr,
&hasVarArgument, &hasBadCoalesce))
{
Assert(hasVarArgument || hasBadCoalesce);
}
}
if (joinTree != NULL)
{
if (FindNodeCheck((Node *) joinTree->quals, CitusIsVolatileFunction))
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"functions used in the WHERE clause of modification "
"queries on distributed tables must not be VOLATILE",
NULL, NULL);
}
else if (MasterIrreducibleExpression(joinTree->quals, &hasVarArgument,
&hasBadCoalesce))
{
Assert(hasVarArgument || hasBadCoalesce);
}
}
if (hasVarArgument)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"STABLE functions used in UPDATE queries "
"cannot be called with column references",
NULL, NULL);
}
if (hasBadCoalesce)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"non-IMMUTABLE functions are not allowed in CASE or "
"COALESCE statements",
NULL, NULL);
}
if (contain_mutable_functions((Node *) queryTree->returningList))
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"non-IMMUTABLE functions are not allowed in the "
"RETURNING clause",
NULL, NULL);
}
if (queryTree->jointree->quals != NULL &&
nodeTag(queryTree->jointree->quals) == T_CurrentOfExpr)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"cannot run DML queries with cursors", NULL,
NULL);
}
}
deferredError = ErrorIfOnConflictNotSupported(queryTree);
if (deferredError != NULL)
{
return deferredError;
}
return NULL;
}
@ -1053,8 +1103,7 @@ MultiShardModifyQuerySupported(Query *originalQuery,
PlannerRestrictionContext *plannerRestrictionContext)
{
DeferredErrorMessage *errorMessage = NULL;
RangeTblEntry *resultRangeTable = rt_fetch(originalQuery->resultRelation,
originalQuery->rtable);
RangeTblEntry *resultRangeTable = ExtractResultRelationRTE(originalQuery);
Oid resultRelationOid = resultRangeTable->relid;
char resultPartitionMethod = PartitionMethod(resultRelationOid);
@ -1666,10 +1715,10 @@ GenerateSingleShardRouterTaskList(Job *job, List *relationShardList,
if (originalQuery->commandType == CMD_SELECT)
{
job->taskList = SingleShardSelectTaskList(originalQuery, job->jobId,
relationShardList, placementList,
shardId,
job->parametersInJobQueryResolved);
job->taskList = SingleShardTaskList(originalQuery, job->jobId,
relationShardList, placementList,
shardId,
job->parametersInJobQueryResolved);
/*
* Queries to reference tables, or distributed tables with multiple replica's have
@ -1693,10 +1742,10 @@ GenerateSingleShardRouterTaskList(Job *job, List *relationShardList,
}
else
{
job->taskList = SingleShardModifyTaskList(originalQuery, job->jobId,
relationShardList, placementList,
shardId,
job->parametersInJobQueryResolved);
job->taskList = SingleShardTaskList(originalQuery, job->jobId,
relationShardList, placementList,
shardId,
job->parametersInJobQueryResolved);
}
}
@ -1783,15 +1832,65 @@ RemoveCoordinatorPlacement(List *placementList)
/*
* SingleShardSelectTaskList generates a task for single shard select query
* SingleShardTaskList generates a task for single shard query
* and returns it as a list.
*/
static List *
SingleShardSelectTaskList(Query *query, uint64 jobId, List *relationShardList,
List *placementList, uint64 shardId,
bool parametersInQueryResolved)
SingleShardTaskList(Query *query, uint64 jobId, List *relationShardList,
List *placementList, uint64 shardId,
bool parametersInQueryResolved)
{
Task *task = CreateTask(READ_TASK);
TaskType taskType = READ_TASK;
char replicationModel = 0;
if (query->commandType != CMD_SELECT)
{
List *rangeTableList = NIL;
ExtractRangeTableEntryWalker((Node *) query, &rangeTableList);
RangeTblEntry *updateOrDeleteRTE = ExtractResultRelationRTE(query);
Assert(updateOrDeleteRTE != NULL);
CitusTableCacheEntry *modificationTableCacheEntry = GetCitusTableCacheEntry(
updateOrDeleteRTE->relid);
char modificationPartitionMethod = modificationTableCacheEntry->partitionMethod;
if (modificationPartitionMethod == DISTRIBUTE_BY_NONE &&
SelectsFromDistributedTable(rangeTableList, query))
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot perform select on a distributed table "
"and modify a reference table")));
}
taskType = MODIFY_TASK;
replicationModel = modificationTableCacheEntry->replicationModel;
}
if (taskType == READ_TASK && query->hasModifyingCTE)
{
/* assume ErrorIfQueryHasUnroutableModifyingCTE checked query already */
CommonTableExpr *cte = NULL;
foreach_ptr(cte, query->cteList)
{
Query *cteQuery = (Query *) cte->ctequery;
if (cteQuery->commandType != CMD_SELECT)
{
RangeTblEntry *updateOrDeleteRTE = ExtractResultRelationRTE(cteQuery);
CitusTableCacheEntry *modificationTableCacheEntry =
GetCitusTableCacheEntry(
updateOrDeleteRTE->relid);
taskType = MODIFY_TASK;
replicationModel = modificationTableCacheEntry->replicationModel;
break;
}
}
}
Task *task = CreateTask(taskType);
List *relationRowLockList = NIL;
RowLocksOnRelations((Node *) query, &relationRowLockList);
@ -1807,6 +1906,7 @@ SingleShardSelectTaskList(Query *query, uint64 jobId, List *relationShardList,
task->jobId = jobId;
task->relationShardList = relationShardList;
task->relationRowLockList = relationRowLockList;
task->replicationModel = replicationModel;
task->parametersInQueryStringResolved = parametersInQueryResolved;
return list_make1(task);
@ -1854,45 +1954,6 @@ RowLocksOnRelations(Node *node, List **relationRowLockList)
}
/*
* SingleShardModifyTaskList generates a task for single shard update/delete query
* and returns it as a list.
*/
static List *
SingleShardModifyTaskList(Query *query, uint64 jobId, List *relationShardList,
List *placementList, uint64 shardId,
bool parametersInQueryResolved)
{
Task *task = CreateTask(MODIFY_TASK);
List *rangeTableList = NIL;
ExtractRangeTableEntryWalker((Node *) query, &rangeTableList);
RangeTblEntry *updateOrDeleteRTE = ExtractResultRelationRTE(query);
CitusTableCacheEntry *modificationTableCacheEntry = GetCitusTableCacheEntry(
updateOrDeleteRTE->relid);
char modificationPartitionMethod = modificationTableCacheEntry->partitionMethod;
if (modificationPartitionMethod == DISTRIBUTE_BY_NONE &&
SelectsFromDistributedTable(rangeTableList, query))
{
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot perform select on a distributed table "
"and modify a reference table")));
}
task->taskPlacementList = placementList;
SetTaskQueryIfShouldLazyDeparse(task, query);
task->anchorShardId = shardId;
task->jobId = jobId;
task->relationShardList = relationShardList;
task->replicationModel = modificationTableCacheEntry->replicationModel;
task->parametersInQueryStringResolved = parametersInQueryResolved;
return list_make1(task);
}
/*
* SelectsFromDistributedTable checks if there is a select on a distributed
* table by looking into range table entries.
@ -1901,12 +1962,11 @@ static bool
SelectsFromDistributedTable(List *rangeTableList, Query *query)
{
ListCell *rangeTableCell = NULL;
int resultRelation = query->resultRelation;
RangeTblEntry *resultRangeTableEntry = NULL;
if (resultRelation > 0)
if (query->resultRelation > 0)
{
resultRangeTableEntry = rt_fetch(resultRelation, query->rtable);
resultRangeTableEntry = ExtractResultRelationRTE(query);
}
foreach(rangeTableCell, rangeTableList)
@ -3186,7 +3246,7 @@ MultiRouterPlannableQuery(Query *query)
}
}
return ErrorIfQueryHasModifyingCTE(query);
return ErrorIfQueryHasUnroutableModifyingCTE(query);
}
@ -3247,19 +3307,25 @@ CopyRelationRestrictionContext(RelationRestrictionContext *oldContext)
/*
* ErrorIfQueryHasModifyingCTE checks if the query contains modifying common table
* ErrorIfQueryHasUnroutableModifyingCTE checks if the query contains modifying common table
* expressions and errors out if it does.
*/
static DeferredErrorMessage *
ErrorIfQueryHasModifyingCTE(Query *queryTree)
ErrorIfQueryHasUnroutableModifyingCTE(Query *queryTree)
{
ListCell *cteCell = NULL;
Assert(queryTree->commandType == CMD_SELECT);
foreach(cteCell, queryTree->cteList)
if (!queryTree->hasModifyingCTE)
{
return NULL;
}
/* we can't route conflicting replication models */
char replicationModel = 0;
CommonTableExpr *cte = NULL;
foreach_ptr(cte, queryTree->cteList)
{
CommonTableExpr *cte = (CommonTableExpr *) lfirst(cteCell);
Query *cteQuery = (Query *) cte->ctequery;
/*
@ -3268,13 +3334,48 @@ ErrorIfQueryHasModifyingCTE(Query *queryTree)
* be at top level of CTE. Therefore it is OK to just check for top level.
* Similarly, we do not need to check for subqueries.
*/
if (cteQuery->commandType != CMD_SELECT)
if (cteQuery->commandType != CMD_SELECT &&
cteQuery->commandType != CMD_UPDATE &&
cteQuery->commandType != CMD_DELETE)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"data-modifying statements are not supported in "
"the WITH clauses of distributed queries",
"only SELECT, UPDATE, or DELETE common table expressions "
"may be router planned",
NULL, NULL);
}
if (cteQuery->commandType != CMD_SELECT)
{
Oid distributedTableId = InvalidOid;
DeferredErrorMessage *cteError =
ModifyPartialQuerySupported(cteQuery, false, &distributedTableId);
if (cteError)
{
return cteError;
}
CitusTableCacheEntry *modificationTableCacheEntry =
GetCitusTableCacheEntry(distributedTableId);
char modificationPartitionMethod =
modificationTableCacheEntry->partitionMethod;
if (modificationPartitionMethod == DISTRIBUTE_BY_NONE)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"cannot router plan modification of a reference table",
NULL, NULL);
}
if (replicationModel &&
modificationTableCacheEntry->replicationModel != replicationModel)
{
return DeferredError(ERRCODE_FEATURE_NOT_SUPPORTED,
"cannot route mixed replication models",
NULL, NULL);
}
replicationModel = modificationTableCacheEntry->replicationModel;
}
}
/* everything OK */

View File

@ -38,14 +38,14 @@ static bool ShouldEvaluateFunctionWithMasterContext(MasterEvaluationContext *
evaluationContext);
/*
* RequiresMastereEvaluation returns the executor needs to reparse and
* RequiresMasterEvaluation returns the executor needs to reparse and
* try to execute this query, which is the case if the query contains
* any stable or volatile function.
*/
bool
RequiresMasterEvaluation(Query *query)
{
if (query->commandType == CMD_SELECT)
if (query->commandType == CMD_SELECT && !query->hasModifyingCTE)
{
return false;
}
@ -55,32 +55,23 @@ RequiresMasterEvaluation(Query *query)
/*
* ExecuteMasterEvaluableFunctionsAndParameters evaluates expressions and parameters
* ExecuteMasterEvaluableExpressions evaluates expressions and parameters
* that can be resolved to a constant.
*/
void
ExecuteMasterEvaluableFunctionsAndParameters(Query *query, PlanState *planState)
ExecuteMasterEvaluableExpressions(Query *query, PlanState *planState)
{
MasterEvaluationContext masterEvaluationContext;
masterEvaluationContext.planState = planState;
masterEvaluationContext.evaluationMode = EVALUATE_FUNCTIONS_PARAMS;
PartiallyEvaluateExpression((Node *) query, &masterEvaluationContext);
}
/*
* ExecuteMasterEvaluableParameters evaluates external parameters that can be
* resolved to a constant.
*/
void
ExecuteMasterEvaluableParameters(Query *query, PlanState *planState)
{
MasterEvaluationContext masterEvaluationContext;
masterEvaluationContext.planState = planState;
masterEvaluationContext.evaluationMode = EVALUATE_PARAMS;
if (query->commandType == CMD_SELECT)
{
masterEvaluationContext.evaluationMode = EVALUATE_PARAMS;
}
else
{
masterEvaluationContext.evaluationMode = EVALUATE_FUNCTIONS_PARAMS;
}
PartiallyEvaluateExpression((Node *) query, &masterEvaluationContext);
}
@ -146,9 +137,22 @@ PartiallyEvaluateExpression(Node *expression,
}
else if (nodeTag == T_Query)
{
return (Node *) query_tree_mutator((Query *) expression,
Query *query = (Query *) expression;
MasterEvaluationContext subContext = *masterEvaluationContext;
if (query->commandType != CMD_SELECT)
{
/*
* Currently INSERT SELECT evaluates stable functions on master,
* while a plain SELECT does not. For evaluating SELECT evaluationMode is
* EVALUATE_PARAMS, but if recursing into a modifying CTE switch into
* EVALUATE_FUNCTIONS_PARAMS.
*/
subContext.evaluationMode = EVALUATE_FUNCTIONS_PARAMS;
}
return (Node *) query_tree_mutator(query,
PartiallyEvaluateExpression,
masterEvaluationContext,
&subContext,
QTW_DONT_COPY_QUERY);
}
else
@ -359,6 +363,8 @@ citus_evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod,
resultTypByVal);
}
/* *INDENT-ON* */
/*
* CitusIsVolatileFunctionIdChecker checks if the given function id is
@ -446,6 +452,3 @@ CitusIsMutableFunction(Node *node)
return false;
}
/* *INDENT-ON* */

View File

@ -44,9 +44,7 @@ typedef struct MasterEvaluationContext
extern bool RequiresMasterEvaluation(Query *query);
extern void ExecuteMasterEvaluableFunctionsAndParameters(Query *query,
PlanState *planState);
extern void ExecuteMasterEvaluableParameters(Query *query, PlanState *planState);
extern void ExecuteMasterEvaluableExpressions(Query *query, PlanState *planState);
extern Node * PartiallyEvaluateExpression(Node *expression,
MasterEvaluationContext *masterEvaluationContext);
extern bool CitusIsVolatileFunction(Node *node);

View File

@ -123,7 +123,7 @@ extern uint64 ExecuteTaskListExtended(ExecutionParams *executionParams);
extern uint64 ExecuteTaskListIntoTupleStore(RowModifyLevel modLevel, List *taskList,
TupleDesc tupleDescriptor,
Tuplestorestate *tupleStore,
bool hasReturning);
bool expectResults);
extern bool IsCitusCustomState(PlanState *planState);
extern TupleTableSlot * CitusExecScan(CustomScanState *node);
extern TupleTableSlot * ReturnTupleFromTuplestore(CitusScanState *scanState);

View File

@ -193,6 +193,8 @@ extern bool TargetListOnPartitionColumn(Query *query, List *targetEntryList);
extern bool FindNodeCheckInRangeTableList(List *rtable, bool (*check)(Node *));
extern bool IsCitusTableRTE(Node *node);
extern bool IsDistributedTableRTE(Node *node);
extern bool IsReferenceTableRTE(Node *node);
extern bool QueryContainsDistributedTableRTE(Query *query);
extern bool IsCitusExtraDataContainerRelation(RangeTblEntry *rte);
extern bool ContainsReadIntermediateResultFunction(Node *node);
extern bool ContainsReadIntermediateResultArrayFunction(Node *node);

View File

@ -60,6 +60,9 @@ s/(job_[0-9]+\/task_[0-9]+\/p_[0-9]+\.)[0-9]+/\1xxxx/g
# isolation_ref2ref_foreign_keys
s/"(ref_table_[0-9]_|ref_table_[0-9]_value_fkey_)[0-9]+"/"\1xxxxxxx"/g
# pg11/pg12 varies in isolation debug output
s/s1: DEBUG:/DEBUG:/g
# commands cascading to shard relations
s/(NOTICE: .*_)[0-9]{5,}( CASCADE)/\1xxxxx\2/g
s/(NOTICE: [a-z]+ cascades to table ".*)_[0-9]{5,}"/\1_xxxxx"/g

View File

@ -924,7 +924,7 @@ DEBUG: Plan is router executable
-- we don't inline CTEs if they are modifying CTEs
WITH cte_1 AS (DELETE FROM test_table WHERE key % 3 = 1 RETURNING key)
SELECT * FROM cte_1 ORDER BY 1 DESC LIMIT 3;
DEBUG: data-modifying statements are not supported in the WITH clauses of distributed queries
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: generating subplan XXX_1 for CTE cte_1: DELETE FROM cte_inline.test_table WHERE ((key OPERATOR(pg_catalog.%) 3) OPERATOR(pg_catalog.=) 1) RETURNING key
DEBUG: Creating router plan
DEBUG: Plan is router executable
@ -941,7 +941,7 @@ DEBUG: Plan is router executable
-- NOT MATERIALIZED should not affect modifying CTEs
WITH cte_1 AS NOT MATERIALIZED (DELETE FROM test_table WHERE key % 3 = 0 RETURNING key)
SELECT count(*) FROM cte_1;
DEBUG: data-modifying statements are not supported in the WITH clauses of distributed queries
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: generating subplan XXX_1 for CTE cte_1: DELETE FROM cte_inline.test_table WHERE ((key OPERATOR(pg_catalog.%) 3) OPERATOR(pg_catalog.=) 0) RETURNING key
DEBUG: Creating router plan
DEBUG: Plan is router executable

View File

@ -801,7 +801,7 @@ ERROR: syntax error at or near "NOT"
-- we don't inline CTEs if they are modifying CTEs
WITH cte_1 AS (DELETE FROM test_table WHERE key % 3 = 1 RETURNING key)
SELECT * FROM cte_1 ORDER BY 1 DESC LIMIT 3;
DEBUG: data-modifying statements are not supported in the WITH clauses of distributed queries
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: generating subplan XXX_1 for CTE cte_1: DELETE FROM cte_inline.test_table WHERE ((key OPERATOR(pg_catalog.%) 3) OPERATOR(pg_catalog.=) 1) RETURNING key
DEBUG: Creating router plan
DEBUG: Plan is router executable

View File

@ -146,7 +146,7 @@ ERROR: non-IMMUTABLE functions are not allowed in the RETURNING clause
-- modifying ctes are not supported via fast-path
WITH t1 AS (DELETE FROM modify_fast_path WHERE key = 1), t2 AS (SELECT * FROM modify_fast_path) SELECT * FROM t2;
DEBUG: CTE t2 is going to be inlined via distributed planning
DEBUG: data-modifying statements are not supported in the WITH clauses of distributed queries
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: generating subplan XXX_1 for CTE t1: DELETE FROM fast_path_router_modify.modify_fast_path WHERE (key OPERATOR(pg_catalog.=) 1)
DEBUG: Distributed planning for a fast-path router query
DEBUG: Creating router plan

View File

@ -920,6 +920,48 @@ BEGIN;
ERROR: cannot execute DML on reference table "transitive_reference_table" because there was a parallel DML access to distributed table "on_update_fkey_table" in the same transaction
HINT: Try re-running the transaction with "SET LOCAL citus.multi_shard_modify_mode TO 'sequential';"
ROLLBACK;
BEGIN;
WITH cte AS (UPDATE on_update_fkey_table SET value_1 = 16 WHERE value_1 = 15 RETURNING *)
SELECT * FROM cte;
id | value_1
---------------------------------------------------------------------
15 | 16
115 | 16
215 | 16
315 | 16
415 | 16
515 | 16
615 | 16
715 | 16
815 | 16
915 | 16
(10 rows)
UPDATE reference_table SET id = 160 WHERE id = 15;
ERROR: cannot execute DML on reference table "reference_table" because there was a parallel DML access to distributed table "on_update_fkey_table" in the same transaction
HINT: Try re-running the transaction with "SET LOCAL citus.multi_shard_modify_mode TO 'sequential';"
ROLLBACK;
BEGIN;
WITH cte AS (UPDATE on_update_fkey_table SET value_1 = 16 WHERE value_1 = 15 RETURNING *)
SELECT * FROM cte;
id | value_1
---------------------------------------------------------------------
15 | 16
115 | 16
215 | 16
315 | 16
415 | 16
515 | 16
615 | 16
715 | 16
815 | 16
915 | 16
(10 rows)
UPDATE transitive_reference_table SET id = 160 WHERE id = 15;
ERROR: cannot execute DML on reference table "transitive_reference_table" because there was a parallel DML access to distributed table "on_update_fkey_table" in the same transaction
HINT: Try re-running the transaction with "SET LOCAL citus.multi_shard_modify_mode TO 'sequential';"
ROLLBACK;
-- case 5.3: Parallel UPDATE on distributed table follow by an unrelated DDL on reference table
BEGIN;
UPDATE on_update_fkey_table SET value_1 = 16 WHERE value_1 = 15;

View File

@ -670,7 +670,7 @@ WITH r AS (
)
INSERT INTO target_table SELECT source_table.a, max(source_table.b) FROM source_table NATURAL JOIN r GROUP BY source_table.a;
DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT
DEBUG: data-modifying statements are not supported in the WITH clauses of distributed queries
DEBUG: only SELECT, UPDATE, or DELETE common table expressions may be router planned
DEBUG: generating subplan XXX_1 for CTE r: INSERT INTO insert_select_repartition.target_table (a, b) SELECT a, b FROM insert_select_repartition.source_table RETURNING target_table.a, target_table.b
DEBUG: INSERT target table and the source relation of the SELECT partition column value must be colocated in distributed INSERT ... SELECT
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT a, max AS b FROM (SELECT source_table.a, max(source_table.b) AS max FROM (insert_select_repartition.source_table JOIN (SELECT intermediate_result.a, intermediate_result.b FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a integer, b integer)) r USING (a, b)) GROUP BY source_table.a) citus_insert_select_subquery

View File

@ -2,30 +2,30 @@ Parsed test spec with 2 sessions
starting permutation: s1-begin s1-select-from-t1-t2-for-update s2-begin s2-update-t1 s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-select-from-t1-t2-for-update:
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_2_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE;
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_2_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE;
id val_1 id val_1
1 2 1 2
step s2-begin:
BEGIN;
BEGIN;
step s2-update-t1:
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
<waiting ...>
step s1-commit:
COMMIT;
COMMIT;
step s2-update-t1: <... completed>
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -33,30 +33,30 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-select-from-t1-t2-for-share s2-begin s2-delete-t1 s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-select-from-t1-t2-for-share:
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_2_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR SHARE;
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_2_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR SHARE;
id val_1 id val_1
1 2 1 2
step s2-begin:
BEGIN;
BEGIN;
step s2-delete-t1:
DELETE FROM test_table_1_rf1 WHERE id = 1;
DELETE FROM test_table_1_rf1 WHERE id = 1;
<waiting ...>
step s1-commit:
COMMIT;
COMMIT;
step s2-delete-t1: <... completed>
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -64,30 +64,30 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-select-from-t1-rt-for-update s2-begin s2-update-t1 s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-select-from-t1-rt-for-update:
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN ref_table as rt1 on tt1.id = rt1.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE;
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN ref_table as rt1 on tt1.id = rt1.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE;
id val_1 id val_1
1 2 1 2
step s2-begin:
BEGIN;
BEGIN;
step s2-update-t1:
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
<waiting ...>
step s1-commit:
COMMIT;
COMMIT;
step s2-update-t1: <... completed>
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -95,31 +95,31 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-select-from-t1-rt-with-lc-for-update s2-begin s2-update-rt s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-select-from-t1-rt-with-lc-for-update:
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN ref_table as rt1 on tt1.id = rt1.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE
OF rt1;
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN ref_table as rt1 on tt1.id = rt1.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE
OF rt1;
id val_1 id val_1
1 2 1 2
step s2-begin:
BEGIN;
BEGIN;
step s2-update-rt:
UPDATE ref_table SET val_1 = 5 WHERE id = 1;
UPDATE ref_table SET val_1 = 5 WHERE id = 1;
<waiting ...>
step s1-commit:
COMMIT;
COMMIT;
step s2-update-rt: <... completed>
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -127,30 +127,30 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-select-from-t1-rt-with-lc-for-update s2-begin s2-update-t1 s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-select-from-t1-rt-with-lc-for-update:
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN ref_table as rt1 on tt1.id = rt1.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE
OF rt1;
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN ref_table as rt1 on tt1.id = rt1.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE
OF rt1;
id val_1 id val_1
1 2 1 2
step s2-begin:
BEGIN;
BEGIN;
step s2-update-t1:
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
step s1-commit:
COMMIT;
COMMIT;
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -158,36 +158,36 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-select-from-t1-t2-for-share s2-begin s2-select-from-t1-t2-for-share s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-select-from-t1-t2-for-share:
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_2_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR SHARE;
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_2_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR SHARE;
id val_1 id val_1
1 2 1 2
step s2-begin:
BEGIN;
BEGIN;
step s2-select-from-t1-t2-for-share:
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_1_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR SHARE;
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_1_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR SHARE;
id val_1 id val_1
1 2 1 2
step s1-commit:
COMMIT;
COMMIT;
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -195,37 +195,37 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-select-from-t1-rt-for-update s2-begin s2-select-from-t1-t2-for-update s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-select-from-t1-rt-for-update:
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN ref_table as rt1 on tt1.id = rt1.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE;
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN ref_table as rt1 on tt1.id = rt1.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE;
id val_1 id val_1
1 2 1 2
step s2-begin:
BEGIN;
BEGIN;
step s2-select-from-t1-t2-for-update:
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_1_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE;
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_1_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE;
<waiting ...>
step s1-commit:
COMMIT;
COMMIT;
step s2-select-from-t1-t2-for-update: <... completed>
id val_1 id val_1
1 2 1 2
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -233,34 +233,34 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-select-from-t1-within-cte s2-begin s2-select-from-t1-t2-for-update s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-select-from-t1-within-cte:
WITH first_value AS ( SELECT val_1 FROM test_table_1_rf1 WHERE id = 1 FOR UPDATE)
SELECT * FROM first_value;
WITH first_value AS (SELECT val_1 FROM test_table_1_rf1 WHERE id = 1 FOR UPDATE)
SELECT * FROM first_value WHERE EXISTS (SELECT * FROM first_value);
val_1
2
step s2-begin:
BEGIN;
BEGIN;
step s2-select-from-t1-t2-for-update:
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_1_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE;
SELECT * FROM
test_table_1_rf1 as tt1 INNER JOIN test_table_1_rf1 as tt2 on tt1.id = tt2.id
WHERE tt1.id = 1
ORDER BY 1
FOR UPDATE;
<waiting ...>
step s1-commit:
COMMIT;
COMMIT;
step s2-select-from-t1-t2-for-update: <... completed>
id val_1 id val_1
1 2 1 2
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -268,27 +268,27 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-select-from-t1-within-cte s2-begin s2-update-t1 s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-select-from-t1-within-cte:
WITH first_value AS ( SELECT val_1 FROM test_table_1_rf1 WHERE id = 1 FOR UPDATE)
SELECT * FROM first_value;
WITH first_value AS (SELECT val_1 FROM test_table_1_rf1 WHERE id = 1 FOR UPDATE)
SELECT * FROM first_value WHERE EXISTS (SELECT * FROM first_value);
val_1
2
step s2-begin:
BEGIN;
BEGIN;
step s2-update-t1:
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
<waiting ...>
step s1-commit:
COMMIT;
COMMIT;
step s2-update-t1: <... completed>
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -296,26 +296,31 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-select-from-t1-with-subquery s2-begin s2-update-t1 s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
DEBUG: Creating router plan
step s1-select-from-t1-with-subquery:
SELECT * FROM (SELECT * FROM test_table_1_rf1 FOR UPDATE) foo WHERE id = 1;
SET client_min_messages TO DEBUG2;
SELECT * FROM (SELECT * FROM test_table_1_rf1 FOR UPDATE) foo WHERE id = 1;
RESET client_min_messages;
DEBUG: Plan is router executable
DETAIL: distribution column value: 1
id val_1
1 2
step s2-begin:
BEGIN;
BEGIN;
step s2-update-t1:
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
<waiting ...>
step s1-commit:
COMMIT;
COMMIT;
step s2-update-t1: <... completed>
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -323,26 +328,26 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-select-from-rt-with-subquery s2-begin s2-update-rt s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-select-from-rt-with-subquery:
SELECT * FROM (SELECT * FROM ref_table FOR UPDATE) foo WHERE id = 1;
SELECT * FROM (SELECT * FROM ref_table FOR UPDATE) foo WHERE id = 1;
id val_1
1 2
step s2-begin:
BEGIN;
BEGIN;
step s2-update-rt:
UPDATE ref_table SET val_1 = 5 WHERE id = 1;
UPDATE ref_table SET val_1 = 5 WHERE id = 1;
<waiting ...>
step s1-commit:
COMMIT;
COMMIT;
step s2-update-rt: <... completed>
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -350,26 +355,26 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-select-from-t1-with-view s2-begin s2-update-t1 s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-select-from-t1-with-view:
SELECT * FROM test_1 WHERE id = 1 FOR UPDATE;
SELECT * FROM test_1 WHERE id = 1 FOR UPDATE;
id val_1
1 2
step s2-begin:
BEGIN;
BEGIN;
step s2-update-t1:
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
UPDATE test_table_1_rf1 SET val_1 = 5 WHERE id = 1;
<waiting ...>
step s1-commit:
COMMIT;
COMMIT;
step s2-update-t1: <... completed>
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func
@ -377,24 +382,24 @@ restore_isolation_tester_func
starting permutation: s1-begin s1-update-rt-with-cte-select-from-rt s2-begin s2-update-rt s1-commit s2-commit
step s1-begin:
BEGIN;
BEGIN;
step s1-update-rt-with-cte-select-from-rt:
WITH foo AS (SELECT * FROM ref_table FOR UPDATE)
UPDATE ref_table SET val_1 = 4 FROM foo WHERE ref_table.id = foo.id;
WITH foo AS (SELECT * FROM ref_table FOR UPDATE)
UPDATE ref_table SET val_1 = 4 FROM foo WHERE ref_table.id = foo.id AND EXISTS (SELECT * FROM foo);
step s2-begin:
BEGIN;
BEGIN;
step s2-update-rt:
UPDATE ref_table SET val_1 = 5 WHERE id = 1;
UPDATE ref_table SET val_1 = 5 WHERE id = 1;
<waiting ...>
step s1-commit:
COMMIT;
COMMIT;
step s2-update-rt: <... completed>
step s2-commit:
COMMIT;
COMMIT;
restore_isolation_tester_func

View File

@ -20,6 +20,32 @@ restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-update-cte s2-update-cte s1-commit s2-commit s1-select-count
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-update-cte: <... completed>
id data
4 l
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-update s2-delete s1-commit s2-commit s1-select-count
create_distributed_table
@ -295,6 +321,289 @@ restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-update-cte s2-delete s1-commit s2-commit s1-select-count
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s2-delete: DELETE FROM update_hash WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-delete: <... completed>
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
4
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-update-cte s2-truncate s1-commit s2-commit s1-select-count
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s2-truncate: TRUNCATE update_hash; <waiting ...>
step s1-commit: COMMIT;
step s2-truncate: <... completed>
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
0
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-update-cte s2-drop s1-commit s2-commit s1-select-count
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s2-drop: DROP TABLE update_hash; <waiting ...>
step s1-commit: COMMIT;
step s2-drop: <... completed>
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
ERROR: relation "update_hash" does not exist
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-update-cte s2-ddl-create-index s1-commit s2-commit s1-select-count s1-show-indexes
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s2-ddl-create-index: CREATE INDEX update_hash_index ON update_hash(id); <waiting ...>
step s1-commit: COMMIT;
step s2-ddl-create-index: <... completed>
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
step s1-show-indexes: SELECT run_command_on_workers('SELECT COUNT(*) FROM pg_indexes WHERE tablename LIKE ''update_hash%''');
run_command_on_workers
(localhost,57637,t,2)
(localhost,57638,t,2)
restore_isolation_tester_func
starting permutation: s1-initialize s1-ddl-create-index s1-begin s2-begin s1-update-cte s2-ddl-drop-index s1-commit s2-commit s1-select-count s1-show-indexes
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-ddl-create-index: CREATE INDEX update_hash_index ON update_hash(id);
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s2-ddl-drop-index: DROP INDEX update_hash_index; <waiting ...>
step s1-commit: COMMIT;
step s2-ddl-drop-index: <... completed>
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
step s1-show-indexes: SELECT run_command_on_workers('SELECT COUNT(*) FROM pg_indexes WHERE tablename LIKE ''update_hash%''');
run_command_on_workers
(localhost,57637,t,0)
(localhost,57638,t,0)
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s1-update-cte s2-ddl-create-index-concurrently s1-commit s1-select-count s1-show-indexes
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s2-ddl-create-index-concurrently: CREATE INDEX CONCURRENTLY update_hash_index ON update_hash(id); <waiting ...>
step s1-commit: COMMIT;
step s2-ddl-create-index-concurrently: <... completed>
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
step s1-show-indexes: SELECT run_command_on_workers('SELECT COUNT(*) FROM pg_indexes WHERE tablename LIKE ''update_hash%''');
run_command_on_workers
(localhost,57637,t,2)
(localhost,57638,t,2)
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-update-cte s2-ddl-add-column s1-commit s2-commit s1-select-count s1-show-columns
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s2-ddl-add-column: ALTER TABLE update_hash ADD new_column int DEFAULT 0; <waiting ...>
step s1-commit: COMMIT;
step s2-ddl-add-column: <... completed>
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''update_hash%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
run_command_on_workers
(localhost,57637,t,new_column)
(localhost,57638,t,new_column)
restore_isolation_tester_func
starting permutation: s1-initialize s1-ddl-add-column s1-begin s2-begin s1-update-cte s2-ddl-drop-column s1-commit s2-commit s1-select-count s1-show-columns
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-ddl-add-column: ALTER TABLE update_hash ADD new_column int DEFAULT 0;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data new_column
4 l 0
step s2-ddl-drop-column: ALTER TABLE update_hash DROP new_column; <waiting ...>
step s1-commit: COMMIT;
step s2-ddl-drop-column: <... completed>
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''update_hash%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
run_command_on_workers
(localhost,57637,t,"")
(localhost,57638,t,"")
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-update-cte s2-ddl-rename-column s1-commit s2-commit s1-select-count s1-show-columns
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s2-ddl-rename-column: ALTER TABLE update_hash RENAME data TO new_column; <waiting ...>
step s1-commit: COMMIT;
step s2-ddl-rename-column: <... completed>
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''update_hash%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
run_command_on_workers
(localhost,57637,t,new_column)
(localhost,57638,t,new_column)
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-update-cte s2-table-size s1-commit s2-commit s1-select-count
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s2-table-size: SELECT citus_total_relation_size('update_hash');
citus_total_relation_size
57344
step s1-commit: COMMIT;
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-update-cte s2-master-modify-multiple-shards s1-commit s2-commit s1-select-count
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s2-master-modify-multiple-shards: DELETE FROM update_hash; <waiting ...>
step s1-commit: COMMIT;
step s2-master-modify-multiple-shards: <... completed>
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
0
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-delete s2-update s1-commit s2-commit s1-select-count
create_distributed_table
@ -548,3 +857,282 @@ count
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-delete s2-update-cte s1-commit s2-commit s1-select-count
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-delete: DELETE FROM update_hash WHERE id = 4;
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-update-cte: <... completed>
id data
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
4
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-truncate s2-update-cte s1-commit s2-commit s1-select-count
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-truncate: TRUNCATE update_hash;
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-update-cte: <... completed>
id data
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
0
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-drop s2-update-cte s1-commit s2-commit s1-select-count
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-drop: DROP TABLE update_hash;
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-update-cte: <... completed>
error in steps s1-commit s2-update-cte: ERROR: relation "update_hash" does not exist
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
ERROR: relation "update_hash" does not exist
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-ddl-create-index s2-update-cte s1-commit s2-commit s1-select-count s1-show-indexes
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-ddl-create-index: CREATE INDEX update_hash_index ON update_hash(id);
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-update-cte: <... completed>
id data
4 l
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
step s1-show-indexes: SELECT run_command_on_workers('SELECT COUNT(*) FROM pg_indexes WHERE tablename LIKE ''update_hash%''');
run_command_on_workers
(localhost,57637,t,2)
(localhost,57638,t,2)
restore_isolation_tester_func
starting permutation: s1-initialize s1-ddl-create-index s1-begin s2-begin s1-ddl-drop-index s2-update-cte s1-commit s2-commit s1-select-count s1-show-indexes
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-ddl-create-index: CREATE INDEX update_hash_index ON update_hash(id);
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-ddl-drop-index: DROP INDEX update_hash_index;
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-update-cte: <... completed>
id data
4 l
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
step s1-show-indexes: SELECT run_command_on_workers('SELECT COUNT(*) FROM pg_indexes WHERE tablename LIKE ''update_hash%''');
run_command_on_workers
(localhost,57637,t,0)
(localhost,57638,t,0)
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-ddl-add-column s2-update-cte s1-commit s2-commit s1-select-count s1-show-columns
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-ddl-add-column: ALTER TABLE update_hash ADD new_column int DEFAULT 0;
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-update-cte: <... completed>
id data new_column
4 l 0
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''update_hash%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
run_command_on_workers
(localhost,57637,t,new_column)
(localhost,57638,t,new_column)
restore_isolation_tester_func
starting permutation: s1-initialize s1-ddl-add-column s1-begin s2-begin s1-ddl-drop-column s2-update-cte s1-commit s2-commit s1-select-count s1-show-columns
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-ddl-add-column: ALTER TABLE update_hash ADD new_column int DEFAULT 0;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-ddl-drop-column: ALTER TABLE update_hash DROP new_column;
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-update-cte: <... completed>
id data
4 l
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''update_hash%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
run_command_on_workers
(localhost,57637,t,"")
(localhost,57638,t,"")
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-ddl-rename-column s2-update-cte s1-commit s2-commit s1-select-count s1-show-columns
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-ddl-rename-column: ALTER TABLE update_hash RENAME data TO new_column;
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-update-cte: <... completed>
error in steps s1-commit s2-update-cte: ERROR: column "data" of relation "update_hash" does not exist
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''update_hash%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
run_command_on_workers
(localhost,57637,t,new_column)
(localhost,57638,t,new_column)
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-table-size s2-update-cte s1-commit s2-commit s1-select-count
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-table-size: SELECT citus_total_relation_size('update_hash');
citus_total_relation_size
57344
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4;
id data
4 l
step s1-commit: COMMIT;
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
5
restore_isolation_tester_func
starting permutation: s1-initialize s1-begin s2-begin s1-master-modify-multiple-shards s2-update-cte s1-commit s2-commit s1-select-count
create_distributed_table
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-master-modify-multiple-shards: DELETE FROM update_hash;
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-update-cte: <... completed>
id data
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
0
restore_isolation_tester_func
starting permutation: s1-drop s1-create-non-distributed-table s1-initialize s1-begin s2-begin s1-distribute-table s2-update-cte s1-commit s2-commit s1-select-count
create_distributed_table
step s1-drop: DROP TABLE update_hash;
step s1-create-non-distributed-table: CREATE TABLE update_hash(id integer, data text); COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-initialize: COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV;
step s1-begin: BEGIN;
step s2-begin: BEGIN;
step s1-distribute-table: SELECT create_distributed_table('update_hash', 'id');
create_distributed_table
step s2-update-cte: WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; <waiting ...>
step s1-commit: COMMIT;
step s2-update-cte: <... completed>
id data
4 l
4 l
step s2-commit: COMMIT;
step s1-select-count: SELECT COUNT(*) FROM update_hash;
count
10
restore_isolation_tester_func

View File

@ -314,6 +314,44 @@ DETAIL: distribution column value: 1
41
(5 rows)
-- SELECT FOR UPDATE is supported if not involving reference table
BEGIN;
WITH first_author AS (
SELECT articles_hash.id, auref.name FROM articles_hash, authors_reference auref
WHERE author_id = 2 AND auref.id = author_id
FOR UPDATE
)
UPDATE articles_hash SET title = first_author.name
FROM first_author WHERE articles_hash.author_id = 2 AND articles_hash.id = first_author.id;
DEBUG: Router planner doesn't support SELECT FOR UPDATE in common table expressions involving reference tables.
DEBUG: generating subplan XXX_1 for CTE first_author: SELECT articles_hash.id, auref.name FROM public.articles_hash, public.authors_reference auref WHERE ((articles_hash.author_id OPERATOR(pg_catalog.=) 2) AND (auref.id OPERATOR(pg_catalog.=) articles_hash.author_id)) FOR UPDATE OF articles_hash FOR UPDATE OF auref
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 2
DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE public.articles_hash SET title = first_author.name FROM (SELECT intermediate_result.id, intermediate_result.name FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(id bigint, name character varying(20))) first_author WHERE ((articles_hash.author_id OPERATOR(pg_catalog.=) 2) AND (articles_hash.id OPERATOR(pg_catalog.=) first_author.id))
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 2
WITH first_author AS (
SELECT id, word_count FROM articles_hash WHERE author_id = 2
FOR UPDATE
)
UPDATE articles_hash SET title = first_author.word_count::text
FROM first_author WHERE articles_hash.author_id = 2 AND articles_hash.id = first_author.id;
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 2
-- Without FOR UPDATE this is router plannable
WITH first_author AS (
SELECT articles_hash.id, auref.name FROM articles_hash, authors_reference auref
WHERE author_id = 2 AND auref.id = author_id
)
UPDATE articles_hash SET title = first_author.name
FROM first_author WHERE articles_hash.author_id = 2 AND articles_hash.id = first_author.id;
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 2
ROLLBACK;
-- queries with CTEs are supported even if CTE is not referenced inside query
WITH first_author AS ( SELECT id FROM articles_hash WHERE author_id = 1)
SELECT title FROM articles_hash WHERE author_id = 1;
@ -476,7 +514,7 @@ WITH new_article AS (
INSERT INTO articles_hash VALUES (1, 1, 'arsenous', 9) RETURNING *
)
SELECT * FROM new_article;
DEBUG: data-modifying statements are not supported in the WITH clauses of distributed queries
DEBUG: only SELECT, UPDATE, or DELETE common table expressions may be router planned
DEBUG: generating subplan XXX_1 for CTE new_article: INSERT INTO public.articles_hash (id, author_id, title, word_count) VALUES (1, 1, 'arsenous'::character varying, 9) RETURNING id, author_id, title, word_count
DEBUG: Creating router plan
DEBUG: Plan is router executable
@ -493,7 +531,7 @@ WITH update_article AS (
UPDATE articles_hash SET word_count = 10 WHERE id = 1 AND word_count = 9 RETURNING *
)
SELECT * FROM update_article;
DEBUG: data-modifying statements are not supported in the WITH clauses of distributed queries
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: generating subplan XXX_1 for CTE update_article: UPDATE public.articles_hash SET word_count = 10 WHERE ((id OPERATOR(pg_catalog.=) 1) AND (word_count OPERATOR(pg_catalog.=) 9)) RETURNING id, author_id, title, word_count
DEBUG: Creating router plan
DEBUG: Plan is router executable
@ -509,7 +547,7 @@ WITH delete_article AS (
DELETE FROM articles_hash WHERE id = 1 AND word_count = 10 RETURNING *
)
SELECT * FROM delete_article;
DEBUG: data-modifying statements are not supported in the WITH clauses of distributed queries
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: generating subplan XXX_1 for CTE delete_article: DELETE FROM public.articles_hash WHERE ((id OPERATOR(pg_catalog.=) 1) AND (word_count OPERATOR(pg_catalog.=) 10)) RETURNING id, author_id, title, word_count
DEBUG: Creating router plan
DEBUG: Plan is router executable
@ -2241,7 +2279,8 @@ DEBUG: Router planner cannot handle multi-shard select queries
PREPARE author_1_articles as
SELECT *
FROM articles_hash
WHERE author_id = 1;
WHERE author_id = 1
ORDER BY 1;
EXECUTE author_1_articles;
DEBUG: Creating router plan
DEBUG: Plan is router executable
@ -2259,7 +2298,8 @@ DETAIL: distribution column value: 1
PREPARE author_articles(int) as
SELECT *
FROM articles_hash
WHERE author_id = $1;
WHERE author_id = $1
ORDER BY 1;
EXECUTE author_articles(1);
DEBUG: Creating router plan
DEBUG: Plan is router executable
@ -2310,7 +2350,7 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
SELECT * FROM author_articles_id_word_count();
SELECT * FROM author_articles_id_word_count() ORDER BY 1;
DEBUG: Creating router plan
CONTEXT: SQL statement "SELECT ah.id, ah.word_count
FROM articles_hash ah
@ -2369,7 +2409,8 @@ SELECT * FROM mv_articles_hash_data ORDER BY 1, 2, 3, 4;
SET citus.task_executor_type to 'task-tracker';
SELECT id
FROM articles_hash
WHERE author_id = 1;
WHERE author_id = 1
ORDER BY 1;
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 1
@ -2390,7 +2431,8 @@ DETAIL: distribution column value: 1
-- verify insert is successful (not router plannable and executable)
SELECT id
FROM articles_hash
WHERE author_id = 1;
WHERE author_id = 1
ORDER BY 1;
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 1

View File

@ -319,7 +319,7 @@ WITH update_article AS (
UPDATE articles_hash SET word_count = 10 WHERE id = 1 AND word_count = 9 RETURNING *
)
SELECT * FROM update_article;
DEBUG: data-modifying statements are not supported in the WITH clauses of distributed queries
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: generating subplan XXX_1 for CTE update_article: UPDATE fast_path_router_select.articles_hash SET word_count = 10 WHERE ((id OPERATOR(pg_catalog.=) 1) AND (word_count OPERATOR(pg_catalog.=) 9)) RETURNING id, author_id, title, word_count
DEBUG: Creating router plan
DEBUG: Plan is router executable
@ -334,7 +334,7 @@ WITH delete_article AS (
DELETE FROM articles_hash WHERE id = 1 AND word_count = 10 RETURNING *
)
SELECT * FROM delete_article;
DEBUG: data-modifying statements are not supported in the WITH clauses of distributed queries
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: generating subplan XXX_1 for CTE delete_article: DELETE FROM fast_path_router_select.articles_hash WHERE ((id OPERATOR(pg_catalog.=) 1) AND (word_count OPERATOR(pg_catalog.=) 10)) RETURNING id, author_id, title, word_count
DEBUG: Creating router plan
DEBUG: Plan is router executable

View File

@ -44,7 +44,7 @@ BEGIN
END IF;
END;
$$ LANGUAGE 'plpgsql' IMMUTABLE;
CREATE VIEW relation_acesses AS
CREATE VIEW relation_accesses AS
SELECT table_name,
relation_access_mode_to_text(table_name, relation_select_access_mode(table_name::regclass)) as select_access,
relation_access_mode_to_text(table_name, relation_dml_access_mode(table_name::regclass)) as dml_access,
@ -109,21 +109,21 @@ BEGIN;
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('table_7') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_7') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_7 | not_parallel_accessed | not_parallel_accessed | parallel_access
(1 row)
COMMIT;
-- outisde the transaction blocks, the function always returns zero
-- outside the transaction blocks, the function always returns zero
SELECT count(*) FROM table_1;
count
---------------------------------------------------------------------
101
(1 row)
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -132,7 +132,7 @@ SELECT * FROM relation_acesses WHERE table_name = 'table_1';
-- a very simple test that first checks sequential
-- and parallel SELECTs,DMLs, and DDLs
BEGIN;
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -144,7 +144,7 @@ BEGIN;
1
(1 row)
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -156,21 +156,21 @@ BEGIN;
2
(1 row)
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
(1 row)
INSERT INTO table_1 VALUES (1,1);
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
(1 row)
INSERT INTO table_1 VALUES (1,1), (2,2);
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -178,7 +178,7 @@ BEGIN;
ALTER TABLE table_1 ADD COLUMN test_col INT;
-- now see that the other tables are not accessed at all
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | parallel_access
@ -194,7 +194,7 @@ BEGIN;
1
(1 row)
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -206,21 +206,21 @@ BEGIN;
1
(1 row)
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
(1 row)
INSERT INTO table_1 VALUES (1,1);
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
(1 row)
INSERT INTO table_1 VALUES (2,2);
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -230,7 +230,7 @@ ROLLBACK;
-- a sample DDL example
BEGIN;
ALTER TABLE table_1 ADD CONSTRAINT table_1_u UNIQUE (key);
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | parallel_access
@ -252,7 +252,7 @@ BEGIN;
1
(1 row)
SELECT * FROM relation_acesses WHERE table_name LIKE 'table_%' ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name LIKE 'table_%' ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -278,7 +278,7 @@ BEGIN;
101
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -301,7 +301,7 @@ BEGIN;
101
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -328,7 +328,7 @@ BEGIN;
101
(1 row)
SELECT * FROM relation_acesses WHERE table_name LIKE 'table_%' ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name LIKE 'table_%' ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -346,7 +346,7 @@ ROLLBACK;
-- access for all the shards accessed. But, sequential mode is OK
BEGIN;
UPDATE table_1 SET value = 15;
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | parallel_access | not_parallel_accessed
@ -354,7 +354,7 @@ BEGIN;
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
UPDATE table_2 SET value = 15;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | parallel_access | not_parallel_accessed
@ -367,7 +367,7 @@ BEGIN;
UPDATE
table_1 SET value = 15
WHERE key IN (SELECT key FROM table_2 JOIN table_3 USING (key) WHERE table_2.value = 15);
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | parallel_access | not_parallel_accessed
@ -379,7 +379,7 @@ ROLLBACK;
-- INSERT .. SELECT pushdown
BEGIN;
INSERT INTO table_2 SELECT * FROM table_1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -391,7 +391,7 @@ ROLLBACK;
BEGIN;
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
INSERT INTO table_2 SELECT * FROM table_1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -403,7 +403,7 @@ ROLLBACK;
BEGIN;
-- We use offset 1 to make sure the result needs to be pulled to the coordinator, offset 0 would be optimized away
INSERT INTO table_2 SELECT * FROM table_1 OFFSET 1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -430,7 +430,7 @@ BEGIN;
101
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -453,7 +453,7 @@ BEGIN;
table_1.key = table_2.key
OFFSET 0
) as foo;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -479,7 +479,7 @@ BEGIN;
AND table_1.key = 1
OFFSET 0
) as foo;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -505,7 +505,7 @@ BEGIN;
OFFSET 0
) as foo
) AND value IN (SELECT key FROM table_4);
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2', 'table_3', 'table_4') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2', 'table_3', 'table_4') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -521,7 +521,7 @@ BEGIN;
1 1
2 2
3 3
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -531,7 +531,7 @@ ROLLBACK;
-- copy in
BEGIN;
COPY table_1 FROM STDIN WITH CSV;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | parallel_access | not_parallel_accessed
@ -541,7 +541,7 @@ ROLLBACK;
-- copy in single shard
BEGIN;
COPY table_1 FROM STDIN WITH CSV;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -556,21 +556,21 @@ BEGIN;
101
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('table_6');
SELECT * FROM relation_accesses WHERE table_name IN ('table_6');
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_6 | reference_table_access | not_accessed | not_accessed
(1 row)
UPDATE table_6 SET value = 15;
SELECT * FROM relation_acesses WHERE table_name IN ('table_6');
SELECT * FROM relation_accesses WHERE table_name IN ('table_6');
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_6 | reference_table_access | reference_table_access | not_accessed
(1 row)
ALTER TABLE table_6 ADD COLUMN x INT;
SELECT * FROM relation_acesses WHERE table_name IN ('table_6');
SELECT * FROM relation_accesses WHERE table_name IN ('table_6');
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_6 | reference_table_access | reference_table_access | reference_table_access
@ -585,7 +585,7 @@ BEGIN;
101
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('table_6', 'table_1') ORDER BY 1,2;
SELECT * FROM relation_accesses WHERE table_name IN ('table_6', 'table_1') ORDER BY 1,2;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -596,7 +596,7 @@ ROLLBACK;
-- TRUNCATE should be DDL
BEGIN;
TRUNCATE table_1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | parallel_access
@ -607,7 +607,7 @@ ROLLBACK;
BEGIN;
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
TRUNCATE table_1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -617,7 +617,7 @@ ROLLBACK;
-- TRUNCATE on a reference table should be sequential
BEGIN;
TRUNCATE table_6;
SELECT * FROM relation_acesses WHERE table_name IN ('table_6') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_6') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_6 | not_accessed | not_accessed | reference_table_access
@ -628,7 +628,7 @@ ROLLBACK;
ALTER TABLE table_1 ADD CONSTRAINT table_1_u UNIQUE (key);
BEGIN;
ALTER TABLE table_2 ADD CONSTRAINT table_2_u FOREIGN KEY (key) REFERENCES table_1(key);
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | parallel_access
@ -641,7 +641,7 @@ ROLLBACK;
BEGIN;
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
ALTER TABLE table_2 ADD CONSTRAINT table_2_u FOREIGN KEY (key) REFERENCES table_1(key);
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -659,7 +659,7 @@ SELECT create_distributed_table('partitioning_test', 'id');
-- Adding partition tables via CREATE TABLE should have DDL access the partitioned table as well
BEGIN;
CREATE TABLE partitioning_test_2009 PARTITION OF partitioning_test FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | not_parallel_accessed | not_parallel_accessed | parallel_access
@ -671,7 +671,7 @@ ROLLBACK;
CREATE TABLE partitioning_test_2009 AS SELECT * FROM partitioning_test;
BEGIN;
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2009 FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | not_parallel_accessed | not_parallel_accessed | parallel_access
@ -689,7 +689,7 @@ SELECT create_distributed_table('partitioning_test_2010', 'id');
BEGIN;
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2010 FOR VALUES FROM ('2010-01-01') TO ('2011-01-01');
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | not_parallel_accessed | not_parallel_accessed | parallel_access
@ -705,7 +705,7 @@ BEGIN;
0
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -723,7 +723,7 @@ BEGIN;
0
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -735,7 +735,7 @@ COMMIT;
-- updating partitioned table marks all of its partitions
BEGIN;
UPDATE partitioning_test SET time = now();
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | parallel_access | parallel_access | not_parallel_accessed
@ -748,7 +748,7 @@ COMMIT;
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
UPDATE partitioning_test SET time = now();
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -760,7 +760,7 @@ COMMIT;
-- DDLs on partitioned table marks all of its partitions
BEGIN;
ALTER TABLE partitioning_test ADD COLUMN X INT;
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | not_parallel_accessed | not_parallel_accessed | parallel_access
@ -773,7 +773,7 @@ ROLLBACK;
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
ALTER TABLE partitioning_test ADD COLUMN X INT;
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -790,7 +790,7 @@ BEGIN;
0
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -808,7 +808,7 @@ BEGIN;
0
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -820,7 +820,7 @@ COMMIT;
-- updating from partition table marks its parent
BEGIN;
UPDATE partitioning_test_2009 SET time = now();
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | parallel_access | parallel_access | not_parallel_accessed
@ -833,7 +833,7 @@ COMMIT;
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
UPDATE partitioning_test_2009 SET time = now();
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -845,7 +845,7 @@ COMMIT;
-- DDLs on partition table marks its parent
BEGIN;
CREATE INDEX i1000000 ON partitioning_test_2009 (id);
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | not_parallel_accessed | not_parallel_accessed | parallel_access
@ -858,7 +858,7 @@ ROLLBACK;
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
CREATE INDEX i1000000 ON partitioning_test_2009 (id);
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
partitioning_test | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -872,7 +872,7 @@ ALTER TABLE table_2 ADD CONSTRAINT table_2_u FOREIGN KEY (key) REFERENCES table_
BEGIN;
TRUNCATE table_1 CASCADE;
NOTICE: truncate cascades to table "table_2"
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | parallel_access
@ -889,7 +889,7 @@ BEGIN;
101
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | not_parallel_accessed | not_parallel_accessed
@ -906,7 +906,7 @@ BEGIN;
101
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -924,7 +924,7 @@ BEGIN;
1002 | 1002
(3 rows)
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
@ -940,7 +940,7 @@ BEGIN;
101
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | parallel_access | not_parallel_accessed
@ -949,6 +949,7 @@ BEGIN;
ROLLBACK;
-- modifying CTEs should work fine with sequential mode
BEGIN;
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
WITH cte_1 AS (UPDATE table_1 SET value = 15 RETURNING *)
SELECT count(*) FROM cte_1 ORDER BY 1;
count
@ -956,10 +957,43 @@ BEGIN;
101
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | parallel_access | parallel_access | not_parallel_accessed
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
(1 row)
ROLLBACK;
-- router planned modifying CTEs should work fine with parallel mode
BEGIN;
WITH cte_1 AS (UPDATE table_1 SET value = 15 WHERE key = 6 RETURNING *)
SELECT count(*) FROM cte_1 ORDER BY 1;
count
---------------------------------------------------------------------
1
(1 row)
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
(1 row)
ROLLBACK;
-- router planned modifying CTEs should work fine with sequential mode
BEGIN;
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
WITH cte_1 AS (UPDATE table_1 SET value = 15 WHERE key = 6 RETURNING *)
SELECT count(*) FROM cte_1 ORDER BY 1;
count
---------------------------------------------------------------------
1
(1 row)
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_1 | not_parallel_accessed | not_parallel_accessed | not_parallel_accessed
(1 row)
ROLLBACK;
@ -979,7 +1013,7 @@ HINT: To remove the local data, run: SELECT truncate_local_data_after_distribut
(1 row)
SELECT * FROM relation_acesses WHERE table_name IN ('table_3') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_3') ORDER BY 1;
table_name | select_access | dml_access | ddl_access
---------------------------------------------------------------------
table_3 | not_parallel_accessed | parallel_access | parallel_access
@ -994,7 +1028,7 @@ drop cascades to function access_tracking.relation_dml_access_mode(oid)
drop cascades to function access_tracking.relation_ddl_access_mode(oid)
drop cascades to function access_tracking.distributed_relation(text)
drop cascades to function access_tracking.relation_access_mode_to_text(text,integer)
drop cascades to view access_tracking.relation_acesses
drop cascades to view access_tracking.relation_accesses
drop cascades to table access_tracking.table_1
drop cascades to table access_tracking.table_2
drop cascades to table access_tracking.table_4

View File

@ -2,6 +2,7 @@
SET citus.next_shard_id TO 1502000;
CREATE SCHEMA with_modifying;
SET search_path TO with_modifying, public;
CREATE TABLE with_modifying.local_table (id int, val int);
CREATE TABLE with_modifying.modify_table (id int, val int);
SELECT create_distributed_table('modify_table', 'id');
create_distributed_table
@ -192,13 +193,13 @@ INSERT INTO modify_table (SELECT cte_1.user_id FROM cte_1 join cte_2 on cte_1.va
-- between different executors
CREATE FUNCTION raise_failed_execution_cte(query text) RETURNS void AS $$
BEGIN
EXECUTE query;
EXCEPTION WHEN OTHERS THEN
IF SQLERRM LIKE '%more than one row returned by a subquery used as an expression%' THEN
RAISE 'Task failed to execute';
ELSIF SQLERRM LIKE '%could not receive query results%' THEN
RAISE 'Task failed to execute';
END IF;
EXECUTE query;
EXCEPTION WHEN OTHERS THEN
IF SQLERRM LIKE '%more than one row returned by a subquery used as an expression%' THEN
RAISE 'Task failed to execute';
ELSIF SQLERRM LIKE '%could not receive query results%' THEN
RAISE 'Task failed to execute';
END IF;
END;
$$LANGUAGE plpgsql;
SET client_min_messages TO ERROR;
@ -378,11 +379,11 @@ INSERT INTO summary_table SELECT id, COUNT(*) AS counter FROM raw_data GROUP BY
INSERT INTO modify_table VALUES (21, 1), (22, 2), (23, 3);
-- read ids from the same table
WITH distinct_ids AS (
SELECT DISTINCT id FROM modify_table
SELECT DISTINCT id FROM modify_table
),
update_data AS (
UPDATE modify_table SET val = 100 WHERE id > 10 AND
id IN (SELECT * FROM distinct_ids) RETURNING *
UPDATE modify_table SET val = 100 WHERE id > 10 AND
id IN (SELECT * FROM distinct_ids) RETURNING *
)
SELECT count(*) FROM update_data;
count
@ -392,11 +393,11 @@ SELECT count(*) FROM update_data;
-- read ids from a different table
WITH distinct_ids AS (
SELECT DISTINCT id FROM summary_table
SELECT DISTINCT id FROM summary_table
),
update_data AS (
UPDATE modify_table SET val = 100 WHERE id > 10 AND
id IN (SELECT * FROM distinct_ids) RETURNING *
UPDATE modify_table SET val = 100 WHERE id > 10 AND
id IN (SELECT * FROM distinct_ids) RETURNING *
)
SELECT count(*) FROM update_data;
count
@ -667,6 +668,157 @@ SELECT * FROM raw_data ORDER BY val;
---------------------------------------------------------------------
(0 rows)
-- Test that local tables are barred
UPDATE local_table lt SET val = mt.val
FROM modify_table mt WHERE mt.id = lt.id;
ERROR: cannot plan modifications of local tables involving distributed tables
-- Including inside CTEs
WITH cte AS (
UPDATE local_table lt SET val = mt.val
FROM modify_table mt WHERE mt.id = lt.id
RETURNING lt.id, lt.val
) SELECT * FROM cte JOIN modify_table mt ON mt.id = cte.id ORDER BY 1,2;
ERROR: cannot plan modifications of local tables involving distributed tables
-- Make sure checks for volatile functions apply to CTEs too
WITH cte AS (UPDATE modify_table SET val = random() WHERE id = 3 RETURNING *)
SELECT * FROM cte JOIN modify_table mt ON mt.id = 3 AND mt.id = cte.id ORDER BY 1,2;
ERROR: functions used in UPDATE queries on distributed tables must not be VOLATILE
-- Two queries from HammerDB:
-- 1
CREATE TABLE with_modifying.stock (s_i_id numeric(6,0) NOT NULL, s_w_id numeric(4,0) NOT NULL, s_quantity numeric(6,0), s_dist_01 character(24)) WITH (fillfactor='50');
ALTER TABLE with_modifying.stock ADD CONSTRAINT stock_i1 PRIMARY KEY (s_i_id, s_w_id);
SELECT create_distributed_table('stock', 's_w_id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
INSERT INTO with_modifying.stock VALUES
(64833, 10, 3, 'test1'),
(64834, 10, 3, 'test2'),
(63867, 10, 3, 'test3');
PREPARE su_after(INT[], SMALLINT[], SMALLINT[], NUMERIC(5,2)[], NUMERIC, NUMERIC, NUMERIC) AS
WITH stock_update AS (
UPDATE stock
SET s_quantity = ( CASE WHEN s_quantity < (item_stock.quantity + 10) THEN s_quantity + 91 ELSE s_quantity END) - item_stock.quantity
FROM UNNEST($1, $2, $3, $4) AS item_stock (item_id, supply_wid, quantity, price)
WHERE stock.s_i_id = item_stock.item_id
AND stock.s_w_id = item_stock.supply_wid
AND stock.s_w_id = ANY ($2)
RETURNING stock.s_dist_01 as s_dist, stock.s_quantity, ( item_stock.quantity + item_stock.price * ( 1 + $5 + $6 ) * ( 1 - $7) ) amount
)
SELECT array_agg ( s_dist ), array_agg ( s_quantity ), array_agg ( amount )
FROM stock_update;
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{"test1 "} | {86} | {24.7958000000}
(1 row)
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{"test1 "} | {78} | {24.7958000000}
(1 row)
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{"test1 "} | {70} | {24.7958000000}
(1 row)
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{"test1 "} | {62} | {24.7958000000}
(1 row)
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{"test1 "} | {54} | {24.7958000000}
(1 row)
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{"test1 "} | {46} | {24.7958000000}
(1 row)
-- 2
CREATE TABLE with_modifying.orders (o_id numeric NOT NULL, o_w_id numeric NOT NULL, o_d_id numeric NOT NULL, o_c_id numeric) WITH (fillfactor='50');
CREATE UNIQUE INDEX orders_i2 ON with_modifying.orders USING btree (o_w_id, o_d_id, o_c_id, o_id) TABLESPACE pg_default;
ALTER TABLE with_modifying.orders ADD CONSTRAINT orders_i1 PRIMARY KEY (o_w_id, o_d_id, o_id);
CREATE TABLE with_modifying.order_line (ol_w_id numeric NOT NULL, ol_d_id numeric NOT NULL, ol_o_id numeric NOT NULL, ol_number numeric NOT NULL, ol_delivery_d timestamp without time zone, ol_amount numeric) WITH (fillfactor='50');
ALTER TABLE with_modifying.order_line ADD CONSTRAINT order_line_i1 PRIMARY KEY (ol_w_id, ol_d_id, ol_o_id, ol_number);
SELECT create_distributed_table('orders', 'o_w_id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
SELECT create_distributed_table('order_line', 'ol_w_id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
INSERT INTO orders VALUES (1, 1, 1, 1), (2, 2, 2, 2), (3, 3, 3, 3);
INSERT INTO order_line VALUES (1, 1, 1, 10), (2, 2, 2, 20), (3, 3, 3, 30);
PREPARE olu(int,int[],int[]) AS
WITH order_line_update AS (
UPDATE order_line
SET ol_delivery_d = current_timestamp
FROM UNNEST($2, $3) AS ids(o_id, d_id)
WHERE ol_o_id = ids.o_id
AND ol_d_id = ids.d_id
AND ol_w_id = $1
RETURNING ol_d_id, ol_o_id, ol_amount
)
SELECT array_agg(ol_d_id), array_agg(c_id), array_agg(sum_amount)
FROM (
SELECT ol_d_id,
(SELECT DISTINCT o_c_id FROM orders WHERE o_id = ol_o_id AND o_d_id = ol_d_id AND o_w_id = $1) AS c_id,
sum(ol_amount) AS sum_amount
FROM order_line_update
GROUP BY ol_d_id, ol_o_id
) AS inner_sum;
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{1} | {1} | {NULL}
(1 row)
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{1} | {1} | {NULL}
(1 row)
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{1} | {1} | {NULL}
(1 row)
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{1} | {1} | {NULL}
(1 row)
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{1} | {1} | {NULL}
(1 row)
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
array_agg | array_agg | array_agg
---------------------------------------------------------------------
{1} | {1} | {NULL}
(1 row)
-- Test with replication factor 2
SET citus.shard_replication_factor to 2;
DROP TABLE modify_table;
@ -730,17 +882,88 @@ BEGIN;
ROLLBACK;
-- similarly, make sure that the intermediate result uses a seperate connection
WITH first_query AS (INSERT INTO modify_table (id) VALUES (10001)),
WITH first_query AS (INSERT INTO modify_table (id) VALUES (10001)),
second_query AS (SELECT * FROM modify_table) SELECT count(*) FROM second_query;
count
---------------------------------------------------------------------
1
(1 row)
SET client_min_messages TO debug2;
-- pushed down without the insert
WITH mb AS (UPDATE modify_table SET val = 3 WHERE id = 3 RETURNING NULL) INSERT INTO modify_table WITH ma AS (SELECT * FROM modify_table LIMIT 10) SELECT count(*) FROM mb;
DEBUG: LIMIT clauses are not allowed in distributed INSERT ... SELECT queries
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 3
DEBUG: Collecting INSERT ... SELECT results on coordinator
-- not pushed down due to volatile
WITH ma AS (SELECT count(*) FROM modify_table where id = 1), mu AS (WITH allref AS (SELECT random() a FROM modify_table limit 4) UPDATE modify_table SET val = 3 WHERE id = 1 AND val IN (SELECT a FROM allref) RETURNING id+1) SELECT count(*) FROM mu, ma;
DEBUG: CTE ma is going to be inlined via distributed planning
DEBUG: Router planner doesn't support VOLATILE functions in common table expressions.
DEBUG: generating subplan XXX_1 for CTE mu: WITH allref AS (SELECT random() AS a FROM with_modifying.modify_table modify_table_1 LIMIT 4) UPDATE with_modifying.modify_table SET val = 3 WHERE ((id OPERATOR(pg_catalog.=) 1) AND ((val)::double precision OPERATOR(pg_catalog.=) ANY (SELECT allref.a FROM allref))) RETURNING (id OPERATOR(pg_catalog.+) 1)
DEBUG: Router planner doesn't support VOLATILE functions in common table expressions.
DEBUG: generating subplan XXX_1 for CTE allref: SELECT random() AS a FROM with_modifying.modify_table LIMIT 4
DEBUG: Router planner cannot handle multi-shard select queries
DEBUG: push down of limit count: 4
DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE with_modifying.modify_table SET val = 3 WHERE ((id OPERATOR(pg_catalog.=) 1) AND ((val)::double precision OPERATOR(pg_catalog.=) ANY (SELECT allref.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a double precision)) allref))) RETURNING (id OPERATOR(pg_catalog.+) 1)
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 1
DEBUG: Distributed planning for a fast-path router query
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 1
DEBUG: generating subplan XXX_2 for subquery SELECT count(*) AS count FROM with_modifying.modify_table WHERE (id OPERATOR(pg_catalog.=) 1)
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result."?column?" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("?column?" integer)) mu, (SELECT intermediate_result.count FROM read_intermediate_result('XXX_2'::text, 'binary'::citus_copy_format) intermediate_result(count bigint)) ma
DEBUG: Creating router plan
DEBUG: Plan is router executable
count
---------------------------------------------------------------------
0
(1 row)
WITH mu AS (WITH allref AS (SELECT random() a FROM anchor_table) UPDATE modify_table SET val = 3 WHERE id = 1 AND val IN (SELECT a FROM allref) RETURNING id+1) SELECT count(*) FROM mu;
DEBUG: Router planner doesn't support VOLATILE functions in common table expressions.
DEBUG: generating subplan XXX_1 for CTE mu: WITH allref AS (SELECT random() AS a FROM with_modifying.anchor_table) UPDATE with_modifying.modify_table SET val = 3 WHERE ((id OPERATOR(pg_catalog.=) 1) AND ((val)::double precision OPERATOR(pg_catalog.=) ANY (SELECT allref.a FROM allref))) RETURNING (id OPERATOR(pg_catalog.+) 1)
DEBUG: Router planner doesn't support VOLATILE functions in common table expressions.
DEBUG: generating subplan XXX_1 for CTE allref: SELECT random() AS a FROM with_modifying.anchor_table
DEBUG: Distributed planning for a fast-path router query
DEBUG: Creating router plan
DEBUG: Plan is router executable
DEBUG: Plan XXX query after replacing subqueries and CTEs: UPDATE with_modifying.modify_table SET val = 3 WHERE ((id OPERATOR(pg_catalog.=) 1) AND ((val)::double precision OPERATOR(pg_catalog.=) ANY (SELECT allref.a FROM (SELECT intermediate_result.a FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result(a double precision)) allref))) RETURNING (id OPERATOR(pg_catalog.+) 1)
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 1
DEBUG: Plan XXX query after replacing subqueries and CTEs: SELECT count(*) AS count FROM (SELECT intermediate_result."?column?" FROM read_intermediate_result('XXX_1'::text, 'binary'::citus_copy_format) intermediate_result("?column?" integer)) mu
DEBUG: Creating router plan
DEBUG: Plan is router executable
count
---------------------------------------------------------------------
0
(1 row)
-- pushed down
WITH mu AS (WITH allref AS (SELECT id a FROM anchor_table) UPDATE modify_table SET val = 3 WHERE id = 1 AND val IN (SELECT a FROM allref) RETURNING id+1) SELECT count(*) FROM mu;
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 1
count
---------------------------------------------------------------------
0
(1 row)
-- pushed down and stable function evaluated
WITH mu AS (WITH allref AS (SELECT now() a FROM anchor_table) UPDATE modify_table SET val = 3 WHERE id = 1 AND now() IN (SELECT a FROM allref) RETURNING id+1) SELECT count(*) FROM mu;
DEBUG: Creating router plan
DEBUG: Plan is router executable
DETAIL: distribution column value: 1
count
---------------------------------------------------------------------
0
(1 row)
RESET client_min_messages;
\set VERBOSITY terse
DROP SCHEMA with_modifying CASCADE;
NOTICE: drop cascades to 5 other objects
DETAIL: drop cascades to table users_table
drop cascades to table anchor_table
drop cascades to function raise_failed_execution_cte(text)
drop cascades to table modify_table
drop cascades to table summary_table
NOTICE: drop cascades to 9 other objects

View File

@ -186,6 +186,31 @@ FROM
event_id
WHERE
events_user_id IN (SELECT user_id FROM users_table);
-- Prepare routable modifying CTEs
PREPARE prepared_test_7 AS
WITH basic_delete AS (
DELETE FROM users_table WHERE user_id=6 RETURNING *
)
SELECT
*
FROM
basic_delete
ORDER BY
user_id,
time
LIMIT 10;
PREPARE prepared_test_8 AS
WITH basic_delete AS (
UPDATE users_table SET value_1 = value_1 + 1 WHERE user_id=6 RETURNING *
)
SELECT
*
FROM
basic_delete
ORDER BY
user_id,
time
LIMIT 10;
EXECUTE prepared_test_1;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
@ -590,6 +615,274 @@ EXECUTE prepared_test_6;
101
(1 row)
BEGIN;
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 1 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 2 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 1 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 5 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 2 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 0 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 5 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 2 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 0 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 3 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
(0 rows)
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
(0 rows)
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
(0 rows)
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
(0 rows)
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
(0 rows)
ROLLBACK;
BEGIN;
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 1 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 2 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 1 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 5 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 2 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 0 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 5 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 2 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 0 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 3 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
(0 rows)
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
(0 rows)
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
(0 rows)
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
(0 rows)
EXECUTE prepared_test_7;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
(0 rows)
ROLLBACK;
BEGIN;
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 2 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 3 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 2 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 6 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 3 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 1 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 6 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 3 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 1 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 4 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 3 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 4 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 3 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 7 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 4 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 2 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 7 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 4 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 2 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 5 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 4 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 5 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 4 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 8 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 5 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 3 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 8 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 5 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 3 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 6 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 5 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 6 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 5 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 9 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 6 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 4 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 9 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 6 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 4 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 7 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 6 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 7 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 6 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 10 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 7 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 5 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 10 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 7 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 5 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 8 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 7 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 8 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 7 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 11 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 8 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 6 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 11 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 8 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 6 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 9 | 2 | 5 |
(10 rows)
ROLLBACK;
BEGIN;
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 2 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 3 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 2 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 6 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 3 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 1 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 6 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 3 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 1 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 4 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 3 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 4 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 3 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 7 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 4 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 2 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 7 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 4 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 2 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 5 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 4 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 5 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 4 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 8 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 5 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 3 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 8 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 5 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 3 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 6 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 5 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 6 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 5 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 9 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 6 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 4 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 9 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 6 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 4 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 7 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 6 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 7 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 6 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 10 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 7 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 5 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 10 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 7 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 5 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 8 | 2 | 5 |
(10 rows)
EXECUTE prepared_test_8;
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------
6 | Wed Nov 22 20:15:53.317797 2017 | 7 | 1 | 1 |
6 | Wed Nov 22 23:01:24.82289 2017 | 8 | 4 | 1 |
6 | Thu Nov 23 00:07:11.068353 2017 | 7 | 1 | 4 |
6 | Thu Nov 23 00:09:44.19812 2017 | 11 | 2 | 0 |
6 | Thu Nov 23 01:13:50.526322 2017 | 8 | 4 | 1 |
6 | Thu Nov 23 01:14:55.769581 2017 | 6 | 0 | 5 |
6 | Thu Nov 23 10:22:11.02918 2017 | 11 | 0 | 5 |
6 | Thu Nov 23 11:08:04.244582 2017 | 8 | 3 | 2 |
6 | Thu Nov 23 13:51:16.92838 2017 | 6 | 4 | 2 |
6 | Thu Nov 23 14:43:18.024104 2017 | 9 | 2 | 5 |
(10 rows)
ROLLBACK;
EXECUTE prepared_partition_column_insert(1);
user_id | time | value_1 | value_2 | value_3 | value_4
---------------------------------------------------------------------

View File

@ -76,19 +76,21 @@ step "s1-select-from-t1-rt-with-lc-for-update"
step "s1-select-from-t1-within-cte"
{
WITH first_value AS ( SELECT val_1 FROM test_table_1_rf1 WHERE id = 1 FOR UPDATE)
SELECT * FROM first_value;
WITH first_value AS (SELECT val_1 FROM test_table_1_rf1 WHERE id = 1 FOR UPDATE)
SELECT * FROM first_value WHERE EXISTS (SELECT * FROM first_value);
}
step "s1-update-rt-with-cte-select-from-rt"
{
WITH foo AS (SELECT * FROM ref_table FOR UPDATE)
UPDATE ref_table SET val_1 = 4 FROM foo WHERE ref_table.id = foo.id;
UPDATE ref_table SET val_1 = 4 FROM foo WHERE ref_table.id = foo.id AND EXISTS (SELECT * FROM foo);
}
step "s1-select-from-t1-with-subquery"
{
SET client_min_messages TO DEBUG2;
SELECT * FROM (SELECT * FROM test_table_1_rf1 FOR UPDATE) foo WHERE id = 1;
RESET client_min_messages;
}
step "s1-select-from-rt-with-subquery"

View File

@ -26,6 +26,7 @@ session "s1"
step "s1-initialize" { COPY update_hash FROM PROGRAM 'echo 0, a && echo 1, b && echo 2, c && echo 3, d && echo 4, e' WITH CSV; }
step "s1-begin" { BEGIN; }
step "s1-update" { UPDATE update_hash SET data = 'l' WHERE id = 4; }
step "s1-update-cte" { WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; }
step "s1-delete" { DELETE FROM update_hash WHERE id = 4; }
step "s1-truncate" { TRUNCATE update_hash; }
step "s1-drop" { DROP TABLE update_hash; }
@ -47,6 +48,7 @@ step "s1-commit" { COMMIT; }
session "s2"
step "s2-begin" { BEGIN; }
step "s2-update" { UPDATE update_hash SET data = 'l' WHERE id = 4; }
step "s2-update-cte" { WITH cte AS (UPDATE update_hash SET data = 'l' WHERE id = 4 RETURNING *) SELECT * FROM cte WHERE id = 4; }
step "s2-delete" { DELETE FROM update_hash WHERE id = 4; }
step "s2-truncate" { TRUNCATE update_hash; }
step "s2-drop" { DROP TABLE update_hash; }
@ -63,6 +65,7 @@ step "s2-commit" { COMMIT; }
// permutations - UPDATE vs UPDATE
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update" "s2-update" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update-cte" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count"
// permutations - UPDATE first
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update" "s2-delete" "s1-commit" "s2-commit" "s1-select-count"
@ -78,6 +81,18 @@ permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update" "s2-table-size" "s
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update" "s2-master-modify-multiple-shards" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-drop" "s1-create-non-distributed-table" "s1-initialize" "s1-begin" "s2-begin" "s1-update" "s2-distribute-table" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update-cte" "s2-delete" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update-cte" "s2-truncate" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update-cte" "s2-drop" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update-cte" "s2-ddl-create-index" "s1-commit" "s2-commit" "s1-select-count" "s1-show-indexes"
permutation "s1-initialize" "s1-ddl-create-index" "s1-begin" "s2-begin" "s1-update-cte" "s2-ddl-drop-index" "s1-commit" "s2-commit" "s1-select-count" "s1-show-indexes"
permutation "s1-initialize" "s1-begin" "s1-update-cte" "s2-ddl-create-index-concurrently" "s1-commit" "s1-select-count" "s1-show-indexes"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update-cte" "s2-ddl-add-column" "s1-commit" "s2-commit" "s1-select-count" "s1-show-columns"
permutation "s1-initialize" "s1-ddl-add-column" "s1-begin" "s2-begin" "s1-update-cte" "s2-ddl-drop-column" "s1-commit" "s2-commit" "s1-select-count" "s1-show-columns"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update-cte" "s2-ddl-rename-column" "s1-commit" "s2-commit" "s1-select-count" "s1-show-columns"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update-cte" "s2-table-size" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-update-cte" "s2-master-modify-multiple-shards" "s1-commit" "s2-commit" "s1-select-count"
// permutations - UPDATE second
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-delete" "s2-update" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-truncate" "s2-update" "s1-commit" "s2-commit" "s1-select-count"
@ -90,3 +105,15 @@ permutation "s1-initialize" "s1-begin" "s2-begin" "s1-ddl-rename-column" "s2-upd
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-table-size" "s2-update" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-master-modify-multiple-shards" "s2-update" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-drop" "s1-create-non-distributed-table" "s1-initialize" "s1-begin" "s2-begin" "s1-distribute-table" "s2-update" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-delete" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-truncate" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-drop" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-ddl-create-index" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count" "s1-show-indexes"
permutation "s1-initialize" "s1-ddl-create-index" "s1-begin" "s2-begin" "s1-ddl-drop-index" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count" "s1-show-indexes"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-ddl-add-column" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count" "s1-show-columns"
permutation "s1-initialize" "s1-ddl-add-column" "s1-begin" "s2-begin" "s1-ddl-drop-column" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count" "s1-show-columns"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-ddl-rename-column" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count" "s1-show-columns"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-table-size" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-initialize" "s1-begin" "s2-begin" "s1-master-modify-multiple-shards" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count"
permutation "s1-drop" "s1-create-non-distributed-table" "s1-initialize" "s1-begin" "s2-begin" "s1-distribute-table" "s2-update-cte" "s1-commit" "s2-commit" "s1-select-count"

View File

@ -532,6 +532,18 @@ BEGIN;
UPDATE transitive_reference_table SET id = 160 WHERE id = 15;
ROLLBACK;
BEGIN;
WITH cte AS (UPDATE on_update_fkey_table SET value_1 = 16 WHERE value_1 = 15 RETURNING *)
SELECT * FROM cte;
UPDATE reference_table SET id = 160 WHERE id = 15;
ROLLBACK;
BEGIN;
WITH cte AS (UPDATE on_update_fkey_table SET value_1 = 16 WHERE value_1 = 15 RETURNING *)
SELECT * FROM cte;
UPDATE transitive_reference_table SET id = 160 WHERE id = 15;
ROLLBACK;
-- case 5.3: Parallel UPDATE on distributed table follow by an unrelated DDL on reference table
BEGIN;
UPDATE on_update_fkey_table SET value_1 = 16 WHERE value_1 = 15;

View File

@ -171,6 +171,32 @@ SELECT * FROM articles_hash WHERE author_id IN (1, NULL) ORDER BY id;
WITH first_author AS ( SELECT id FROM articles_hash WHERE author_id = 1)
SELECT * FROM first_author;
-- SELECT FOR UPDATE is supported if not involving reference table
BEGIN;
WITH first_author AS (
SELECT articles_hash.id, auref.name FROM articles_hash, authors_reference auref
WHERE author_id = 2 AND auref.id = author_id
FOR UPDATE
)
UPDATE articles_hash SET title = first_author.name
FROM first_author WHERE articles_hash.author_id = 2 AND articles_hash.id = first_author.id;
WITH first_author AS (
SELECT id, word_count FROM articles_hash WHERE author_id = 2
FOR UPDATE
)
UPDATE articles_hash SET title = first_author.word_count::text
FROM first_author WHERE articles_hash.author_id = 2 AND articles_hash.id = first_author.id;
-- Without FOR UPDATE this is router plannable
WITH first_author AS (
SELECT articles_hash.id, auref.name FROM articles_hash, authors_reference auref
WHERE author_id = 2 AND auref.id = author_id
)
UPDATE articles_hash SET title = first_author.name
FROM first_author WHERE articles_hash.author_id = 2 AND articles_hash.id = first_author.id;
ROLLBACK;
-- queries with CTEs are supported even if CTE is not referenced inside query
WITH first_author AS ( SELECT id FROM articles_hash WHERE author_id = 1)
SELECT title FROM articles_hash WHERE author_id = 1;
@ -1038,7 +1064,8 @@ SELECT count(*), count(*) FILTER (WHERE id < 3)
PREPARE author_1_articles as
SELECT *
FROM articles_hash
WHERE author_id = 1;
WHERE author_id = 1
ORDER BY 1;
EXECUTE author_1_articles;
@ -1046,7 +1073,8 @@ EXECUTE author_1_articles;
PREPARE author_articles(int) as
SELECT *
FROM articles_hash
WHERE author_id = $1;
WHERE author_id = $1
ORDER BY 1;
EXECUTE author_articles(1);
@ -1076,7 +1104,7 @@ BEGIN
END;
$$ LANGUAGE plpgsql;
SELECT * FROM author_articles_id_word_count();
SELECT * FROM author_articles_id_word_count() ORDER BY 1;
-- materialized views can be created for router plannable queries
CREATE MATERIALIZED VIEW mv_articles_hash_empty AS
@ -1091,7 +1119,8 @@ SELECT * FROM mv_articles_hash_data ORDER BY 1, 2, 3, 4;
SET citus.task_executor_type to 'task-tracker';
SELECT id
FROM articles_hash
WHERE author_id = 1;
WHERE author_id = 1
ORDER BY 1;
-- insert query is router plannable even under task-tracker
INSERT INTO articles_hash VALUES (51, 1, 'amateus', 1814), (52, 1, 'second amateus', 2824);
@ -1099,7 +1128,8 @@ INSERT INTO articles_hash VALUES (51, 1, 'amateus', 1814), (52, 1, 'second amate
-- verify insert is successful (not router plannable and executable)
SELECT id
FROM articles_hash
WHERE author_id = 1;
WHERE author_id = 1
ORDER BY 1;
-- https://github.com/citusdata/citus/issues/3624
UPDATE articles_hash SET id = id

View File

@ -55,7 +55,7 @@ $$ LANGUAGE 'plpgsql' IMMUTABLE;
CREATE VIEW relation_acesses AS
CREATE VIEW relation_accesses AS
SELECT table_name,
relation_access_mode_to_text(table_name, relation_select_access_mode(table_name::regclass)) as select_access,
relation_access_mode_to_text(table_name, relation_dml_access_mode(table_name::regclass)) as dml_access,
@ -93,29 +93,29 @@ INSERT INTO table_6 SELECT i, i FROM generate_series(0,100) i;
BEGIN;
CREATE TABLE table_7 (key int, value int);
SELECT create_distributed_table('table_7', 'key');
SELECT * FROM relation_acesses WHERE table_name IN ('table_7') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_7') ORDER BY 1;
COMMIT;
-- outisde the transaction blocks, the function always returns zero
-- outside the transaction blocks, the function always returns zero
SELECT count(*) FROM table_1;
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
-- a very simple test that first checks sequential
-- and parallel SELECTs,DMLs, and DDLs
BEGIN;
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
SELECT count(*) FROM table_1 WHERE key = 1;
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
SELECT count(*) FROM table_1 WHERE key = 1 OR key = 2;
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
INSERT INTO table_1 VALUES (1,1);
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
INSERT INTO table_1 VALUES (1,1), (2,2);
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
ALTER TABLE table_1 ADD COLUMN test_col INT;
-- now see that the other tables are not accessed at all
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
ROLLBACK;
@ -124,19 +124,19 @@ ROLLBACK;
-- commands executed, we can treat the transaction as sequential
BEGIN;
SELECT count(*) FROM table_1 WHERE key = 1;
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
SELECT count(*) FROM table_1 WHERE key = 2;
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
INSERT INTO table_1 VALUES (1,1);
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
INSERT INTO table_1 VALUES (2,2);
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
ROLLBACK;
-- a sample DDL example
BEGIN;
ALTER TABLE table_1 ADD CONSTRAINT table_1_u UNIQUE (key);
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
ROLLBACK;
-- a simple join touches single shard per table
@ -150,7 +150,7 @@ BEGIN;
table_3.key = table_4.key AND table_4.key = table_5.key AND
table_1.key = 1;
SELECT * FROM relation_acesses WHERE table_name LIKE 'table_%' ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name LIKE 'table_%' ORDER BY 1;
ROLLBACK;
-- a simple real-time join touches all shard per table
@ -162,7 +162,7 @@ BEGIN;
WHERE
table_1.key = table_2.key;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
ROLLBACK;
-- a simple real-time join touches all shard per table
@ -177,7 +177,7 @@ BEGIN;
WHERE
table_1.key = table_2.key;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
ROLLBACK;
-- a simple subquery pushdown that touches all shards
@ -196,7 +196,7 @@ BEGIN;
table_3.key = table_4.key AND table_4.key = table_5.key
) as foo;
SELECT * FROM relation_acesses WHERE table_name LIKE 'table_%' ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name LIKE 'table_%' ORDER BY 1;
ROLLBACK;
-- simple multi shard update both sequential and parallel modes
@ -204,10 +204,10 @@ ROLLBACK;
-- access for all the shards accessed. But, sequential mode is OK
BEGIN;
UPDATE table_1 SET value = 15;
SELECT * FROM relation_acesses WHERE table_name = 'table_1';
SELECT * FROM relation_accesses WHERE table_name = 'table_1';
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
UPDATE table_2 SET value = 15;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
ROLLBACK;
-- now UPDATE/DELETE with subselect pushdown
@ -215,13 +215,13 @@ BEGIN;
UPDATE
table_1 SET value = 15
WHERE key IN (SELECT key FROM table_2 JOIN table_3 USING (key) WHERE table_2.value = 15);
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
ROLLBACK;
-- INSERT .. SELECT pushdown
BEGIN;
INSERT INTO table_2 SELECT * FROM table_1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
ROLLBACK;
-- INSERT .. SELECT pushdown in sequential mode should be OK
@ -229,14 +229,14 @@ BEGIN;
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
INSERT INTO table_2 SELECT * FROM table_1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
ROLLBACK;
-- coordinator INSERT .. SELECT
BEGIN;
-- We use offset 1 to make sure the result needs to be pulled to the coordinator, offset 0 would be optimized away
INSERT INTO table_2 SELECT * FROM table_1 OFFSET 1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
ROLLBACK;
@ -257,7 +257,7 @@ BEGIN;
OFFSET 0
) as foo;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
ROLLBACK;
-- recursively planned SELECT and coordinator INSERT .. SELECT
@ -277,7 +277,7 @@ BEGIN;
OFFSET 0
) as foo;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
ROLLBACK;
-- recursively planned SELECT and coordinator INSERT .. SELECT
@ -299,7 +299,7 @@ BEGIN;
OFFSET 0
) as foo;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2', 'table_3') ORDER BY 1;
ROLLBACK;
-- recursively planned SELECT and recursively planned multi-shard DELETE
@ -320,13 +320,13 @@ BEGIN;
) as foo
) AND value IN (SELECT key FROM table_4);
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2', 'table_3', 'table_4') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2', 'table_3', 'table_4') ORDER BY 1;
ROLLBACK;
-- copy out
BEGIN;
COPY (SELECT * FROM table_1 WHERE key IN (1,2,3) ORDER BY 1) TO stdout;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
ROLLBACK;
-- copy in
@ -336,7 +336,7 @@ BEGIN;
2,2
3,3
\.
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
ROLLBACK;
-- copy in single shard
@ -346,51 +346,51 @@ BEGIN;
1,2
1,3
\.
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
ROLLBACK;
-- reference table accesses should always be a sequential
BEGIN;
SELECT count(*) FROM table_6;
SELECT * FROM relation_acesses WHERE table_name IN ('table_6');
SELECT * FROM relation_accesses WHERE table_name IN ('table_6');
UPDATE table_6 SET value = 15;
SELECT * FROM relation_acesses WHERE table_name IN ('table_6');
SELECT * FROM relation_accesses WHERE table_name IN ('table_6');
ALTER TABLE table_6 ADD COLUMN x INT;
SELECT * FROM relation_acesses WHERE table_name IN ('table_6');
SELECT * FROM relation_accesses WHERE table_name IN ('table_6');
ROLLBACK;
-- reference table join with a distributed table
BEGIN;
SELECT count(*) FROM table_1 JOIN table_6 USING(key);
SELECT * FROM relation_acesses WHERE table_name IN ('table_6', 'table_1') ORDER BY 1,2;
SELECT * FROM relation_accesses WHERE table_name IN ('table_6', 'table_1') ORDER BY 1,2;
ROLLBACK;
-- TRUNCATE should be DDL
BEGIN;
TRUNCATE table_1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
ROLLBACK;
-- TRUNCATE can be a sequential DDL
BEGIN;
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
TRUNCATE table_1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
ROLLBACK;
-- TRUNCATE on a reference table should be sequential
BEGIN;
TRUNCATE table_6;
SELECT * FROM relation_acesses WHERE table_name IN ('table_6') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_6') ORDER BY 1;
ROLLBACK;
-- creating foreign keys should consider adding the placement accesses for the referenced table
ALTER TABLE table_1 ADD CONSTRAINT table_1_u UNIQUE (key);
BEGIN;
ALTER TABLE table_2 ADD CONSTRAINT table_2_u FOREIGN KEY (key) REFERENCES table_1(key);
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
ROLLBACK;
-- creating foreign keys should consider adding the placement accesses for the referenced table
@ -399,7 +399,7 @@ BEGIN;
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
ALTER TABLE table_2 ADD CONSTRAINT table_2_u FOREIGN KEY (key) REFERENCES table_1(key);
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
ROLLBACK;
CREATE TABLE partitioning_test(id int, time date) PARTITION BY RANGE (time);
@ -408,14 +408,14 @@ SELECT create_distributed_table('partitioning_test', 'id');
-- Adding partition tables via CREATE TABLE should have DDL access the partitioned table as well
BEGIN;
CREATE TABLE partitioning_test_2009 PARTITION OF partitioning_test FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009') ORDER BY 1;
ROLLBACK;
-- Adding partition tables via ATTACH PARTITION on local tables should have DDL access the partitioned table as well
CREATE TABLE partitioning_test_2009 AS SELECT * FROM partitioning_test;
BEGIN;
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2009 FOR VALUES FROM ('2009-01-01') TO ('2010-01-01');
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009') ORDER BY 1;
COMMIT;
-- Adding partition tables via ATTACH PARTITION on distributed tables should have DDL access the partitioned table as well
@ -423,95 +423,95 @@ CREATE TABLE partitioning_test_2010 AS SELECT * FROM partitioning_test;
SELECT create_distributed_table('partitioning_test_2010', 'id');
BEGIN;
ALTER TABLE partitioning_test ATTACH PARTITION partitioning_test_2010 FOR VALUES FROM ('2010-01-01') TO ('2011-01-01');
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2010') ORDER BY 1;
COMMIT;
-- reading from partitioned table marks all of its partitions
BEGIN;
SELECT count(*) FROM partitioning_test;
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
COMMIT;
-- reading from partitioned table sequentially marks all of its partitions with sequential accesses
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
SELECT count(*) FROM partitioning_test;
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
COMMIT;
-- updating partitioned table marks all of its partitions
BEGIN;
UPDATE partitioning_test SET time = now();
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
COMMIT;
-- updating partitioned table sequentially marks all of its partitions with sequential accesses
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
UPDATE partitioning_test SET time = now();
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
COMMIT;
-- DDLs on partitioned table marks all of its partitions
BEGIN;
ALTER TABLE partitioning_test ADD COLUMN X INT;
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
ROLLBACK;
-- DDLs on partitioned table sequentially marks all of its partitions with sequential accesses
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
ALTER TABLE partitioning_test ADD COLUMN X INT;
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
ROLLBACK;
-- reading from partition table marks its parent
BEGIN;
SELECT count(*) FROM partitioning_test_2009;
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
COMMIT;
-- rreading from partition table marks its parent with sequential accesses
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
SELECT count(*) FROM partitioning_test_2009;
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
COMMIT;
-- updating from partition table marks its parent
BEGIN;
UPDATE partitioning_test_2009 SET time = now();
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
COMMIT;
-- updating from partition table marks its parent sequential accesses
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
UPDATE partitioning_test_2009 SET time = now();
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
COMMIT;
-- DDLs on partition table marks its parent
BEGIN;
CREATE INDEX i1000000 ON partitioning_test_2009 (id);
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
ROLLBACK;
-- DDLs on partition table marks its parent in sequential mode
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
CREATE INDEX i1000000 ON partitioning_test_2009 (id);
SELECT * FROM relation_acesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('partitioning_test', 'partitioning_test_2009', 'partitioning_test_2010') ORDER BY 1;
ROLLBACK;
-- TRUNCATE CASCADE works fine
ALTER TABLE table_2 ADD CONSTRAINT table_2_u FOREIGN KEY (key) REFERENCES table_1(key);
BEGIN;
TRUNCATE table_1 CASCADE;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1', 'table_2') ORDER BY 1;
ROLLBACK;
-- CTEs with SELECT only should work fine
@ -519,7 +519,7 @@ BEGIN;
WITH cte AS (SELECT count(*) FROM table_1)
SELECT * FROM cte;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
COMMIT;
-- CTEs with SELECT only in sequential mode should work fine
@ -528,7 +528,7 @@ BEGIN;
WITH cte AS (SELECT count(*) FROM table_1)
SELECT * FROM cte;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
COMMIT;
-- modifying CTEs should work fine with multi-row inserts, which are by default in sequential
@ -536,7 +536,7 @@ BEGIN;
WITH cte_1 AS (INSERT INTO table_1 VALUES (1000,1000), (1001, 1001), (1002, 1002) RETURNING *)
SELECT * FROM cte_1 ORDER BY 1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
ROLLBACK;
-- modifying CTEs should work fine with parallel mode
@ -544,15 +544,33 @@ BEGIN;
WITH cte_1 AS (UPDATE table_1 SET value = 15 RETURNING *)
SELECT count(*) FROM cte_1 ORDER BY 1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
ROLLBACK;
-- modifying CTEs should work fine with sequential mode
BEGIN;
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
WITH cte_1 AS (UPDATE table_1 SET value = 15 RETURNING *)
SELECT count(*) FROM cte_1 ORDER BY 1;
SELECT * FROM relation_acesses WHERE table_name IN ('table_1') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
ROLLBACK;
-- router planned modifying CTEs should work fine with parallel mode
BEGIN;
WITH cte_1 AS (UPDATE table_1 SET value = 15 WHERE key = 6 RETURNING *)
SELECT count(*) FROM cte_1 ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
ROLLBACK;
-- router planned modifying CTEs should work fine with sequential mode
BEGIN;
SET LOCAL citus.multi_shard_modify_mode = 'sequential';
WITH cte_1 AS (UPDATE table_1 SET value = 15 WHERE key = 6 RETURNING *)
SELECT count(*) FROM cte_1 ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_1') ORDER BY 1;
ROLLBACK;
-- create distributed table with data loading
@ -562,7 +580,7 @@ CREATE TABLE table_3 (key int, value int);
INSERT INTO table_3 SELECT i, i FROM generate_series(0,100) i;
BEGIN;
SELECT create_distributed_table('table_3', 'key');
SELECT * FROM relation_acesses WHERE table_name IN ('table_3') ORDER BY 1;
SELECT * FROM relation_accesses WHERE table_name IN ('table_3') ORDER BY 1;
COMMIT;
SET search_path TO 'public';

View File

@ -4,6 +4,8 @@ SET citus.next_shard_id TO 1502000;
CREATE SCHEMA with_modifying;
SET search_path TO with_modifying, public;
CREATE TABLE with_modifying.local_table (id int, val int);
CREATE TABLE with_modifying.modify_table (id int, val int);
SELECT create_distributed_table('modify_table', 'id');
@ -113,13 +115,13 @@ INSERT INTO modify_table (SELECT cte_1.user_id FROM cte_1 join cte_2 on cte_1.va
-- between different executors
CREATE FUNCTION raise_failed_execution_cte(query text) RETURNS void AS $$
BEGIN
EXECUTE query;
EXCEPTION WHEN OTHERS THEN
IF SQLERRM LIKE '%more than one row returned by a subquery used as an expression%' THEN
RAISE 'Task failed to execute';
ELSIF SQLERRM LIKE '%could not receive query results%' THEN
RAISE 'Task failed to execute';
END IF;
EXECUTE query;
EXCEPTION WHEN OTHERS THEN
IF SQLERRM LIKE '%more than one row returned by a subquery used as an expression%' THEN
RAISE 'Task failed to execute';
ELSIF SQLERRM LIKE '%could not receive query results%' THEN
RAISE 'Task failed to execute';
END IF;
END;
$$LANGUAGE plpgsql;
@ -236,21 +238,21 @@ INSERT INTO modify_table VALUES (21, 1), (22, 2), (23, 3);
-- read ids from the same table
WITH distinct_ids AS (
SELECT DISTINCT id FROM modify_table
SELECT DISTINCT id FROM modify_table
),
update_data AS (
UPDATE modify_table SET val = 100 WHERE id > 10 AND
id IN (SELECT * FROM distinct_ids) RETURNING *
UPDATE modify_table SET val = 100 WHERE id > 10 AND
id IN (SELECT * FROM distinct_ids) RETURNING *
)
SELECT count(*) FROM update_data;
-- read ids from a different table
WITH distinct_ids AS (
SELECT DISTINCT id FROM summary_table
SELECT DISTINCT id FROM summary_table
),
update_data AS (
UPDATE modify_table SET val = 100 WHERE id > 10 AND
id IN (SELECT * FROM distinct_ids) RETURNING *
UPDATE modify_table SET val = 100 WHERE id > 10 AND
id IN (SELECT * FROM distinct_ids) RETURNING *
)
SELECT count(*) FROM update_data;
@ -410,6 +412,84 @@ raw_data AS (
)
SELECT * FROM raw_data ORDER BY val;
-- Test that local tables are barred
UPDATE local_table lt SET val = mt.val
FROM modify_table mt WHERE mt.id = lt.id;
-- Including inside CTEs
WITH cte AS (
UPDATE local_table lt SET val = mt.val
FROM modify_table mt WHERE mt.id = lt.id
RETURNING lt.id, lt.val
) SELECT * FROM cte JOIN modify_table mt ON mt.id = cte.id ORDER BY 1,2;
-- Make sure checks for volatile functions apply to CTEs too
WITH cte AS (UPDATE modify_table SET val = random() WHERE id = 3 RETURNING *)
SELECT * FROM cte JOIN modify_table mt ON mt.id = 3 AND mt.id = cte.id ORDER BY 1,2;
-- Two queries from HammerDB:
-- 1
CREATE TABLE with_modifying.stock (s_i_id numeric(6,0) NOT NULL, s_w_id numeric(4,0) NOT NULL, s_quantity numeric(6,0), s_dist_01 character(24)) WITH (fillfactor='50');
ALTER TABLE with_modifying.stock ADD CONSTRAINT stock_i1 PRIMARY KEY (s_i_id, s_w_id);
SELECT create_distributed_table('stock', 's_w_id');
INSERT INTO with_modifying.stock VALUES
(64833, 10, 3, 'test1'),
(64834, 10, 3, 'test2'),
(63867, 10, 3, 'test3');
PREPARE su_after(INT[], SMALLINT[], SMALLINT[], NUMERIC(5,2)[], NUMERIC, NUMERIC, NUMERIC) AS
WITH stock_update AS (
UPDATE stock
SET s_quantity = ( CASE WHEN s_quantity < (item_stock.quantity + 10) THEN s_quantity + 91 ELSE s_quantity END) - item_stock.quantity
FROM UNNEST($1, $2, $3, $4) AS item_stock (item_id, supply_wid, quantity, price)
WHERE stock.s_i_id = item_stock.item_id
AND stock.s_w_id = item_stock.supply_wid
AND stock.s_w_id = ANY ($2)
RETURNING stock.s_dist_01 as s_dist, stock.s_quantity, ( item_stock.quantity + item_stock.price * ( 1 + $5 + $6 ) * ( 1 - $7) ) amount
)
SELECT array_agg ( s_dist ), array_agg ( s_quantity ), array_agg ( amount )
FROM stock_update;
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
EXECUTE su_after('{64833,63857,13941,76514,35858,10004,88553,34483,91251,28144,51687,36407,54436,72873}', '{10,10,10,10,10,10,10,10,10,10,10,10,10,10}', '{8,2,2,6,7,4,6,1,1,5,6,7,6,2}', '{26.04,4.79,67.84,77.66,47.06,23.12,32.74,56.99,84.75,37.52,73.52,98.86,49.96,29.47}', 0.1800, 0.1100, 0.5000);
-- 2
CREATE TABLE with_modifying.orders (o_id numeric NOT NULL, o_w_id numeric NOT NULL, o_d_id numeric NOT NULL, o_c_id numeric) WITH (fillfactor='50');
CREATE UNIQUE INDEX orders_i2 ON with_modifying.orders USING btree (o_w_id, o_d_id, o_c_id, o_id) TABLESPACE pg_default;
ALTER TABLE with_modifying.orders ADD CONSTRAINT orders_i1 PRIMARY KEY (o_w_id, o_d_id, o_id);
CREATE TABLE with_modifying.order_line (ol_w_id numeric NOT NULL, ol_d_id numeric NOT NULL, ol_o_id numeric NOT NULL, ol_number numeric NOT NULL, ol_delivery_d timestamp without time zone, ol_amount numeric) WITH (fillfactor='50');
ALTER TABLE with_modifying.order_line ADD CONSTRAINT order_line_i1 PRIMARY KEY (ol_w_id, ol_d_id, ol_o_id, ol_number);
SELECT create_distributed_table('orders', 'o_w_id');
SELECT create_distributed_table('order_line', 'ol_w_id');
INSERT INTO orders VALUES (1, 1, 1, 1), (2, 2, 2, 2), (3, 3, 3, 3);
INSERT INTO order_line VALUES (1, 1, 1, 10), (2, 2, 2, 20), (3, 3, 3, 30);
PREPARE olu(int,int[],int[]) AS
WITH order_line_update AS (
UPDATE order_line
SET ol_delivery_d = current_timestamp
FROM UNNEST($2, $3) AS ids(o_id, d_id)
WHERE ol_o_id = ids.o_id
AND ol_d_id = ids.d_id
AND ol_w_id = $1
RETURNING ol_d_id, ol_o_id, ol_amount
)
SELECT array_agg(ol_d_id), array_agg(c_id), array_agg(sum_amount)
FROM (
SELECT ol_d_id,
(SELECT DISTINCT o_c_id FROM orders WHERE o_id = ol_o_id AND o_d_id = ol_d_id AND o_w_id = $1) AS c_id,
sum(ol_amount) AS sum_amount
FROM order_line_update
GROUP BY ol_d_id, ol_o_id
) AS inner_sum;
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
EXECUTE olu(1,ARRAY[1,2],ARRAY[1,2]);
-- Test with replication factor 2
SET citus.shard_replication_factor to 2;
@ -441,7 +521,23 @@ BEGIN;
ROLLBACK;
-- similarly, make sure that the intermediate result uses a seperate connection
WITH first_query AS (INSERT INTO modify_table (id) VALUES (10001)),
WITH first_query AS (INSERT INTO modify_table (id) VALUES (10001)),
second_query AS (SELECT * FROM modify_table) SELECT count(*) FROM second_query;
SET client_min_messages TO debug2;
-- pushed down without the insert
WITH mb AS (UPDATE modify_table SET val = 3 WHERE id = 3 RETURNING NULL) INSERT INTO modify_table WITH ma AS (SELECT * FROM modify_table LIMIT 10) SELECT count(*) FROM mb;
-- not pushed down due to volatile
WITH ma AS (SELECT count(*) FROM modify_table where id = 1), mu AS (WITH allref AS (SELECT random() a FROM modify_table limit 4) UPDATE modify_table SET val = 3 WHERE id = 1 AND val IN (SELECT a FROM allref) RETURNING id+1) SELECT count(*) FROM mu, ma;
WITH mu AS (WITH allref AS (SELECT random() a FROM anchor_table) UPDATE modify_table SET val = 3 WHERE id = 1 AND val IN (SELECT a FROM allref) RETURNING id+1) SELECT count(*) FROM mu;
-- pushed down
WITH mu AS (WITH allref AS (SELECT id a FROM anchor_table) UPDATE modify_table SET val = 3 WHERE id = 1 AND val IN (SELECT a FROM allref) RETURNING id+1) SELECT count(*) FROM mu;
-- pushed down and stable function evaluated
WITH mu AS (WITH allref AS (SELECT now() a FROM anchor_table) UPDATE modify_table SET val = 3 WHERE id = 1 AND now() IN (SELECT a FROM allref) RETURNING id+1) SELECT count(*) FROM mu;
RESET client_min_messages;
\set VERBOSITY terse
DROP SCHEMA with_modifying CASCADE;

View File

@ -198,6 +198,33 @@ FROM
WHERE
events_user_id IN (SELECT user_id FROM users_table);
-- Prepare routable modifying CTEs
PREPARE prepared_test_7 AS
WITH basic_delete AS (
DELETE FROM users_table WHERE user_id=6 RETURNING *
)
SELECT
*
FROM
basic_delete
ORDER BY
user_id,
time
LIMIT 10;
PREPARE prepared_test_8 AS
WITH basic_delete AS (
UPDATE users_table SET value_1 = value_1 + 1 WHERE user_id=6 RETURNING *
)
SELECT
*
FROM
basic_delete
ORDER BY
user_id,
time
LIMIT 10;
EXECUTE prepared_test_1;
EXECUTE prepared_test_1;
EXECUTE prepared_test_1;
@ -240,6 +267,40 @@ EXECUTE prepared_test_6;
EXECUTE prepared_test_6;
EXECUTE prepared_test_6;
BEGIN;
EXECUTE prepared_test_7;
EXECUTE prepared_test_7;
EXECUTE prepared_test_7;
EXECUTE prepared_test_7;
EXECUTE prepared_test_7;
EXECUTE prepared_test_7;
ROLLBACK;
BEGIN;
EXECUTE prepared_test_7;
EXECUTE prepared_test_7;
EXECUTE prepared_test_7;
EXECUTE prepared_test_7;
EXECUTE prepared_test_7;
EXECUTE prepared_test_7;
ROLLBACK;
BEGIN;
EXECUTE prepared_test_8;
EXECUTE prepared_test_8;
EXECUTE prepared_test_8;
EXECUTE prepared_test_8;
EXECUTE prepared_test_8;
EXECUTE prepared_test_8;
ROLLBACK;
BEGIN;
EXECUTE prepared_test_8;
EXECUTE prepared_test_8;
EXECUTE prepared_test_8;
EXECUTE prepared_test_8;
EXECUTE prepared_test_8;
EXECUTE prepared_test_8;
ROLLBACK;
EXECUTE prepared_partition_column_insert(1);
EXECUTE prepared_partition_column_insert(2);
EXECUTE prepared_partition_column_insert(3);