Merge branch 'main' into alter_database_propagation

pull/7172/head
Gürkan İndibay 2023-09-07 11:27:59 +03:00 committed by GitHub
commit 260b8b089f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
44 changed files with 1640 additions and 255 deletions

View File

@ -6,7 +6,7 @@ orbs:
parameters: parameters:
image_suffix: image_suffix:
type: string type: string
default: '-v0c8d80c' default: '-v641cdcd'
pg14_version: pg14_version:
type: string type: string
default: '14.9' default: '14.9'
@ -15,10 +15,10 @@ parameters:
default: '15.4' default: '15.4'
pg16_version: pg16_version:
type: string type: string
default: '16beta3' default: '16rc1'
upgrade_pg_versions: upgrade_pg_versions:
type: string type: string
default: '14.9-15.4-16beta3' default: '14.9-15.4-16rc1'
style_checker_tools_version: style_checker_tools_version:
type: string type: string
default: '0.8.18' default: '0.8.18'

View File

@ -53,6 +53,7 @@
#include "distributed/multi_executor.h" #include "distributed/multi_executor.h"
#include "distributed/multi_logical_planner.h" #include "distributed/multi_logical_planner.h"
#include "distributed/multi_partitioning_utils.h" #include "distributed/multi_partitioning_utils.h"
#include "distributed/namespace_utils.h"
#include "distributed/reference_table_utils.h" #include "distributed/reference_table_utils.h"
#include "distributed/relation_access_tracking.h" #include "distributed/relation_access_tracking.h"
#include "distributed/replication_origin_session_utils.h" #include "distributed/replication_origin_session_utils.h"
@ -1764,10 +1765,7 @@ CreateMaterializedViewDDLCommand(Oid matViewOid)
* Set search_path to NIL so that all objects outside of pg_catalog will be * Set search_path to NIL so that all objects outside of pg_catalog will be
* schema-prefixed. * schema-prefixed.
*/ */
OverrideSearchPath *overridePath = GetOverrideSearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
overridePath->schemas = NIL;
overridePath->addCatalog = true;
PushOverrideSearchPath(overridePath);
/* /*
* Push the transaction snapshot to be able to get vief definition with pg_get_viewdef * Push the transaction snapshot to be able to get vief definition with pg_get_viewdef
@ -1779,7 +1777,7 @@ CreateMaterializedViewDDLCommand(Oid matViewOid)
char *viewDefinition = TextDatumGetCString(viewDefinitionDatum); char *viewDefinition = TextDatumGetCString(viewDefinitionDatum);
PopActiveSnapshot(); PopActiveSnapshot();
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
appendStringInfo(query, "AS %s", viewDefinition); appendStringInfo(query, "AS %s", viewDefinition);

View File

@ -1478,11 +1478,20 @@ InsertMetadataForCitusLocalTable(Oid citusLocalTableId, uint64 shardId,
static void static void
FinalizeCitusLocalTableCreation(Oid relationId) FinalizeCitusLocalTableCreation(Oid relationId)
{ {
#if PG_VERSION_NUM >= PG_VERSION_16
/*
* PG16+ supports truncate triggers on foreign tables
*/
if (RegularTable(relationId) || IsForeignTable(relationId))
#else
/* /*
* If it is a foreign table, then skip creating citus truncate trigger * If it is a foreign table, then skip creating citus truncate trigger
* as foreign tables do not support truncate triggers. * as foreign tables do not support truncate triggers.
*/ */
if (RegularTable(relationId)) if (RegularTable(relationId))
#endif
{ {
CreateTruncateTrigger(relationId); CreateTruncateTrigger(relationId);
} }

View File

@ -1256,8 +1256,17 @@ CreateCitusTable(Oid relationId, CitusTableType tableType,
colocationId, citusTableParams.replicationModel, colocationId, citusTableParams.replicationModel,
autoConverted); autoConverted);
#if PG_VERSION_NUM >= PG_VERSION_16
/*
* PG16+ supports truncate triggers on foreign tables
*/
if (RegularTable(relationId) || IsForeignTable(relationId))
#else
/* foreign tables do not support TRUNCATE trigger */ /* foreign tables do not support TRUNCATE trigger */
if (RegularTable(relationId)) if (RegularTable(relationId))
#endif
{ {
CreateTruncateTrigger(relationId); CreateTruncateTrigger(relationId);
} }
@ -1659,6 +1668,7 @@ PropagatePrerequisiteObjectsForDistributedTable(Oid relationId)
ObjectAddress *tableAddress = palloc0(sizeof(ObjectAddress)); ObjectAddress *tableAddress = palloc0(sizeof(ObjectAddress));
ObjectAddressSet(*tableAddress, RelationRelationId, relationId); ObjectAddressSet(*tableAddress, RelationRelationId, relationId);
EnsureAllObjectDependenciesExistOnAllNodes(list_make1(tableAddress)); EnsureAllObjectDependenciesExistOnAllNodes(list_make1(tableAddress));
TrackPropagatedTableAndSequences(relationId);
} }

View File

@ -112,15 +112,35 @@ EnsureDependenciesExistOnAllNodes(const ObjectAddress *target)
dependency->objectSubId, ExclusiveLock); dependency->objectSubId, ExclusiveLock);
} }
WorkerNode *workerNode = NULL;
foreach_ptr(workerNode, workerNodeList)
{
const char *nodeName = workerNode->workerName;
uint32 nodePort = workerNode->workerPort;
SendCommandListToWorkerOutsideTransaction(nodeName, nodePort, /*
CitusExtensionOwnerName(), * We need to propagate dependencies via the current user's metadata connection if
ddlCommands); * any dependency for the target is created in the current transaction. Our assumption
* is that if we rely on a dependency created in the current transaction, then the
* current user, most probably, has permissions to create the target object as well.
* Note that, user still may not be able to create the target due to no permissions
* for any of its dependencies. But this is ok since it should be rare.
*
* If we opted to use a separate superuser connection for the target, then we would
* have visibility issues since propagated dependencies would be invisible to
* the separate connection until we locally commit.
*/
if (HasAnyDependencyInPropagatedObjects(target))
{
SendCommandListToWorkersWithMetadata(ddlCommands);
}
else
{
WorkerNode *workerNode = NULL;
foreach_ptr(workerNode, workerNodeList)
{
const char *nodeName = workerNode->workerName;
uint32 nodePort = workerNode->workerPort;
SendCommandListToWorkerOutsideTransaction(nodeName, nodePort,
CitusExtensionOwnerName(),
ddlCommands);
}
} }
/* /*

View File

@ -50,7 +50,7 @@ static List * GetAllViews(void);
static bool ShouldPropagateExtensionCommand(Node *parseTree); static bool ShouldPropagateExtensionCommand(Node *parseTree);
static bool IsAlterExtensionSetSchemaCitus(Node *parseTree); static bool IsAlterExtensionSetSchemaCitus(Node *parseTree);
static Node * RecreateExtensionStmt(Oid extensionOid); static Node * RecreateExtensionStmt(Oid extensionOid);
static List * GenerateGrantCommandsOnExtesionDependentFDWs(Oid extensionId); static List * GenerateGrantCommandsOnExtensionDependentFDWs(Oid extensionId);
/* /*
@ -985,7 +985,7 @@ CreateExtensionDDLCommand(const ObjectAddress *extensionAddress)
/* any privilege granted on FDWs that belong to the extension should be included */ /* any privilege granted on FDWs that belong to the extension should be included */
List *FDWGrants = List *FDWGrants =
GenerateGrantCommandsOnExtesionDependentFDWs(extensionAddress->objectId); GenerateGrantCommandsOnExtensionDependentFDWs(extensionAddress->objectId);
ddlCommands = list_concat(ddlCommands, FDWGrants); ddlCommands = list_concat(ddlCommands, FDWGrants);
@ -1048,11 +1048,11 @@ RecreateExtensionStmt(Oid extensionOid)
/* /*
* GenerateGrantCommandsOnExtesionDependentFDWs returns a list of commands that GRANTs * GenerateGrantCommandsOnExtensionDependentFDWs returns a list of commands that GRANTs
* the privileges on FDWs that are depending on the given extension. * the privileges on FDWs that are depending on the given extension.
*/ */
static List * static List *
GenerateGrantCommandsOnExtesionDependentFDWs(Oid extensionId) GenerateGrantCommandsOnExtensionDependentFDWs(Oid extensionId)
{ {
List *commands = NIL; List *commands = NIL;
List *FDWOids = GetDependentFDWsToExtension(extensionId); List *FDWOids = GetDependentFDWsToExtension(extensionId);

View File

@ -895,7 +895,7 @@ GetForeignConstraintCommandsInternal(Oid relationId, int flags)
List *foreignKeyCommands = NIL; List *foreignKeyCommands = NIL;
PushOverrideEmptySearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
Oid foreignKeyOid = InvalidOid; Oid foreignKeyOid = InvalidOid;
foreach_oid(foreignKeyOid, foreignKeyOids) foreach_oid(foreignKeyOid, foreignKeyOids)
@ -906,7 +906,7 @@ GetForeignConstraintCommandsInternal(Oid relationId, int flags)
} }
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
return foreignKeyCommands; return foreignKeyCommands;
} }

View File

@ -909,15 +909,14 @@ GetFunctionDDLCommand(const RegProcedure funcOid, bool useCreateOrReplace)
else else
{ {
Datum sqlTextDatum = (Datum) 0; Datum sqlTextDatum = (Datum) 0;
int saveNestLevel = PushEmptySearchPath();
PushOverrideEmptySearchPath(CurrentMemoryContext);
sqlTextDatum = DirectFunctionCall1(pg_get_functiondef, sqlTextDatum = DirectFunctionCall1(pg_get_functiondef,
ObjectIdGetDatum(funcOid)); ObjectIdGetDatum(funcOid));
createFunctionSQL = TextDatumGetCString(sqlTextDatum); createFunctionSQL = TextDatumGetCString(sqlTextDatum);
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
} }
return createFunctionSQL; return createFunctionSQL;

View File

@ -530,7 +530,7 @@ GetExplicitStatisticsCommandList(Oid relationId)
RelationClose(relation); RelationClose(relation);
/* generate fully-qualified names */ /* generate fully-qualified names */
PushOverrideEmptySearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
Oid statisticsId = InvalidOid; Oid statisticsId = InvalidOid;
foreach_oid(statisticsId, statisticsIdList) foreach_oid(statisticsId, statisticsIdList)
@ -579,7 +579,7 @@ GetExplicitStatisticsCommandList(Oid relationId)
} }
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
return explicitStatisticsCommandList; return explicitStatisticsCommandList;
} }

View File

@ -74,7 +74,7 @@ GetExplicitTriggerCommandList(Oid relationId)
{ {
List *createTriggerCommandList = NIL; List *createTriggerCommandList = NIL;
PushOverrideEmptySearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
List *triggerIdList = GetExplicitTriggerIdList(relationId); List *triggerIdList = GetExplicitTriggerIdList(relationId);
@ -116,7 +116,7 @@ GetExplicitTriggerCommandList(Oid relationId)
} }
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
return createTriggerCommandList; return createTriggerCommandList;
} }

View File

@ -77,6 +77,7 @@
#include "tcop/utility.h" #include "tcop/utility.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
@ -193,6 +194,7 @@ multi_ProcessUtility(PlannedStmt *pstmt,
bool isCreateAlterExtensionUpdateCitusStmt = IsCreateAlterExtensionUpdateCitusStmt( bool isCreateAlterExtensionUpdateCitusStmt = IsCreateAlterExtensionUpdateCitusStmt(
parsetree); parsetree);
if (EnableVersionChecks && isCreateAlterExtensionUpdateCitusStmt) if (EnableVersionChecks && isCreateAlterExtensionUpdateCitusStmt)
{ {
ErrorIfUnstableCreateOrAlterExtensionStmt(parsetree); ErrorIfUnstableCreateOrAlterExtensionStmt(parsetree);
@ -207,6 +209,18 @@ multi_ProcessUtility(PlannedStmt *pstmt,
PreprocessCreateExtensionStmtForCitusColumnar(parsetree); PreprocessCreateExtensionStmtForCitusColumnar(parsetree);
} }
if (isCreateAlterExtensionUpdateCitusStmt || IsDropCitusExtensionStmt(parsetree))
{
/*
* Citus maintains a higher level cache. We use the cache invalidation mechanism
* of Postgres to achieve cache coherency between backends. Any change to citus
* extension should be made known to other backends. We do this by invalidating the
* relcache and therefore invoking the citus registered callback that invalidates
* the citus cache in other backends.
*/
CacheInvalidateRelcacheAll();
}
/* /*
* Make sure that on DROP DATABASE we terminate the background daemon * Make sure that on DROP DATABASE we terminate the background daemon
* associated with it. * associated with it.
@ -923,18 +937,10 @@ ProcessUtilityInternal(PlannedStmt *pstmt,
foreach_ptr(address, addresses) foreach_ptr(address, addresses)
{ {
MarkObjectDistributed(address); MarkObjectDistributed(address);
TrackPropagatedObject(address);
} }
} }
} }
if (!IsDropCitusExtensionStmt(parsetree) && !IsA(parsetree, DropdbStmt))
{
/*
* Ensure value is valid, we can't do some checks during CREATE
* EXTENSION. This is important to register some invalidation callbacks.
*/
CitusHasBeenLoaded(); /* lgtm[cpp/return-value-ignored] */
}
} }

View File

@ -479,10 +479,7 @@ AppendViewDefinitionToCreateViewCommand(StringInfo buf, Oid viewOid)
* Set search_path to NIL so that all objects outside of pg_catalog will be * Set search_path to NIL so that all objects outside of pg_catalog will be
* schema-prefixed. * schema-prefixed.
*/ */
OverrideSearchPath *overridePath = GetOverrideSearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
overridePath->schemas = NIL;
overridePath->addCatalog = true;
PushOverrideSearchPath(overridePath);
/* /*
* Push the transaction snapshot to be able to get vief definition with pg_get_viewdef * Push the transaction snapshot to be able to get vief definition with pg_get_viewdef
@ -494,7 +491,7 @@ AppendViewDefinitionToCreateViewCommand(StringInfo buf, Oid viewOid)
char *viewDefinition = TextDatumGetCString(viewDefinitionDatum); char *viewDefinition = TextDatumGetCString(viewDefinitionDatum);
PopActiveSnapshot(); PopActiveSnapshot();
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
appendStringInfo(buf, "AS %s ", viewDefinition); appendStringInfo(buf, "AS %s ", viewDefinition);
} }

View File

@ -818,7 +818,7 @@ deparse_shard_index_statement(IndexStmt *origStmt, Oid distrelid, int64 shardid,
* Switch to empty search_path to deparse_index_columns to produce fully- * Switch to empty search_path to deparse_index_columns to produce fully-
* qualified names in expressions. * qualified names in expressions.
*/ */
PushOverrideEmptySearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
/* index column or expression list begins here */ /* index column or expression list begins here */
appendStringInfoChar(buffer, '('); appendStringInfoChar(buffer, '(');
@ -855,7 +855,7 @@ deparse_shard_index_statement(IndexStmt *origStmt, Oid distrelid, int64 shardid,
} }
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
} }

View File

@ -345,9 +345,9 @@ AppendAlterDomainStmtSetDefault(StringInfo buf, AlterDomainStmt *stmt)
expr = TransformDefaultExpr(expr, stmt->typeName, baseTypeName); expr = TransformDefaultExpr(expr, stmt->typeName, baseTypeName);
/* deparse while the searchpath is cleared to force qualification of identifiers */ /* deparse while the searchpath is cleared to force qualification of identifiers */
PushOverrideEmptySearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
char *exprSql = deparse_expression(expr, NIL, true, true); char *exprSql = deparse_expression(expr, NIL, true, true);
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
appendStringInfo(buf, "SET DEFAULT %s", exprSql); appendStringInfo(buf, "SET DEFAULT %s", exprSql);
} }
@ -443,9 +443,9 @@ AppendConstraint(StringInfo buf, Constraint *constraint, List *domainName,
elog(ERROR, "missing expression for domain constraint"); elog(ERROR, "missing expression for domain constraint");
} }
PushOverrideEmptySearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
char *exprSql = deparse_expression(expr, NIL, true, true); char *exprSql = deparse_expression(expr, NIL, true, true);
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
appendStringInfo(buf, " CHECK (%s)", exprSql); appendStringInfo(buf, " CHECK (%s)", exprSql);
return; return;
@ -469,9 +469,9 @@ AppendConstraint(StringInfo buf, Constraint *constraint, List *domainName,
elog(ERROR, "missing expression for domain default"); elog(ERROR, "missing expression for domain default");
} }
PushOverrideEmptySearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
char *exprSql = deparse_expression(expr, NIL, true, true); char *exprSql = deparse_expression(expr, NIL, true, true);
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
appendStringInfo(buf, " DEFAULT %s", exprSql); appendStringInfo(buf, " DEFAULT %s", exprSql);
return; return;

View File

@ -307,11 +307,11 @@ AppendWhereClauseExpression(StringInfo buf, RangeVar *tableName,
List *relationContext = deparse_context_for(tableName->relname, relation->rd_id); List *relationContext = deparse_context_for(tableName->relname, relation->rd_id);
PushOverrideEmptySearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
char *whereClauseString = deparse_expression(whereClause, char *whereClauseString = deparse_expression(whereClause,
relationContext, relationContext,
true, true); true, true);
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
appendStringInfoString(buf, whereClauseString); appendStringInfoString(buf, whereClauseString);

View File

@ -562,9 +562,9 @@ DeparseRawExprForColumnDefault(Oid relationId, Oid columnTypeId, int32 columnTyp
List *deparseContext = deparse_context_for(get_rel_name(relationId), relationId); List *deparseContext = deparse_context_for(get_rel_name(relationId), relationId);
PushOverrideEmptySearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
char *defaultExprStr = deparse_expression(defaultExpr, deparseContext, false, false); char *defaultExprStr = deparse_expression(defaultExpr, deparseContext, false, false);
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
RelationClose(relation); RelationClose(relation);

View File

@ -53,6 +53,7 @@
#include "common/keywords.h" #include "common/keywords.h"
#include "distributed/citus_nodefuncs.h" #include "distributed/citus_nodefuncs.h"
#include "distributed/citus_ruleutils.h" #include "distributed/citus_ruleutils.h"
#include "distributed/namespace_utils.h"
#include "executor/spi.h" #include "executor/spi.h"
#include "foreign/foreign.h" #include "foreign/foreign.h"
#include "funcapi.h" #include "funcapi.h"
@ -610,18 +611,14 @@ pg_get_rule_expr(Node *expression)
{ {
bool showImplicitCasts = true; bool showImplicitCasts = true;
deparse_context context; deparse_context context;
OverrideSearchPath *overridePath = NULL;
StringInfo buffer = makeStringInfo(); StringInfo buffer = makeStringInfo();
/* /*
* Set search_path to NIL so that all objects outside of pg_catalog will be * Set search_path to NIL so that all objects outside of pg_catalog will be
* schema-prefixed. pg_catalog will be added automatically when we call * schema-prefixed. pg_catalog will be added automatically when we call
* PushOverrideSearchPath(), since we set addCatalog to true; * PushEmptySearchPath().
*/ */
overridePath = GetOverrideSearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
overridePath->schemas = NIL;
overridePath->addCatalog = true;
PushOverrideSearchPath(overridePath);
context.buf = buffer; context.buf = buffer;
context.namespaces = NIL; context.namespaces = NIL;
@ -638,7 +635,7 @@ pg_get_rule_expr(Node *expression)
get_rule_expr(expression, &context, showImplicitCasts); get_rule_expr(expression, &context, showImplicitCasts);
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
return buffer->data; return buffer->data;
} }
@ -1955,8 +1952,6 @@ get_query_def_extended(Query *query, StringInfo buf, List *parentnamespace,
deparse_context context; deparse_context context;
deparse_namespace dpns; deparse_namespace dpns;
OverrideSearchPath *overridePath = NULL;
/* Guard against excessively long or deeply-nested queries */ /* Guard against excessively long or deeply-nested queries */
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
check_stack_depth(); check_stack_depth();
@ -1975,12 +1970,9 @@ get_query_def_extended(Query *query, StringInfo buf, List *parentnamespace,
/* /*
* Set search_path to NIL so that all objects outside of pg_catalog will be * Set search_path to NIL so that all objects outside of pg_catalog will be
* schema-prefixed. pg_catalog will be added automatically when we call * schema-prefixed. pg_catalog will be added automatically when we call
* PushOverrideSearchPath(), since we set addCatalog to true; * PushEmptySearchPath().
*/ */
overridePath = GetOverrideSearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
overridePath->schemas = NIL;
overridePath->addCatalog = true;
PushOverrideSearchPath(overridePath);
context.buf = buf; context.buf = buf;
context.namespaces = lcons(&dpns, list_copy(parentnamespace)); context.namespaces = lcons(&dpns, list_copy(parentnamespace));
@ -2031,7 +2023,7 @@ get_query_def_extended(Query *query, StringInfo buf, List *parentnamespace,
} }
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
} }
/* ---------- /* ----------

View File

@ -54,6 +54,7 @@
#include "distributed/citus_nodefuncs.h" #include "distributed/citus_nodefuncs.h"
#include "distributed/citus_ruleutils.h" #include "distributed/citus_ruleutils.h"
#include "distributed/multi_router_planner.h" #include "distributed/multi_router_planner.h"
#include "distributed/namespace_utils.h"
#include "executor/spi.h" #include "executor/spi.h"
#include "foreign/foreign.h" #include "foreign/foreign.h"
#include "funcapi.h" #include "funcapi.h"
@ -624,18 +625,14 @@ pg_get_rule_expr(Node *expression)
{ {
bool showImplicitCasts = true; bool showImplicitCasts = true;
deparse_context context; deparse_context context;
OverrideSearchPath *overridePath = NULL;
StringInfo buffer = makeStringInfo(); StringInfo buffer = makeStringInfo();
/* /*
* Set search_path to NIL so that all objects outside of pg_catalog will be * Set search_path to NIL so that all objects outside of pg_catalog will be
* schema-prefixed. pg_catalog will be added automatically when we call * schema-prefixed. pg_catalog will be added automatically when we call
* PushOverrideSearchPath(), since we set addCatalog to true; * PushEmptySearchPath(), since we set addCatalog to true;
*/ */
overridePath = GetOverrideSearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
overridePath->schemas = NIL;
overridePath->addCatalog = true;
PushOverrideSearchPath(overridePath);
context.buf = buffer; context.buf = buffer;
context.namespaces = NIL; context.namespaces = NIL;
@ -652,7 +649,7 @@ pg_get_rule_expr(Node *expression)
get_rule_expr(expression, &context, showImplicitCasts); get_rule_expr(expression, &context, showImplicitCasts);
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
return buffer->data; return buffer->data;
} }
@ -2038,8 +2035,6 @@ get_query_def_extended(Query *query, StringInfo buf, List *parentnamespace,
deparse_context context; deparse_context context;
deparse_namespace dpns; deparse_namespace dpns;
OverrideSearchPath *overridePath = NULL;
/* Guard against excessively long or deeply-nested queries */ /* Guard against excessively long or deeply-nested queries */
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
check_stack_depth(); check_stack_depth();
@ -2058,12 +2053,9 @@ get_query_def_extended(Query *query, StringInfo buf, List *parentnamespace,
/* /*
* Set search_path to NIL so that all objects outside of pg_catalog will be * Set search_path to NIL so that all objects outside of pg_catalog will be
* schema-prefixed. pg_catalog will be added automatically when we call * schema-prefixed. pg_catalog will be added automatically when we call
* PushOverrideSearchPath(), since we set addCatalog to true; * PushEmptySearchPath().
*/ */
overridePath = GetOverrideSearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
overridePath->schemas = NIL;
overridePath->addCatalog = true;
PushOverrideSearchPath(overridePath);
context.buf = buf; context.buf = buf;
context.namespaces = lcons(&dpns, list_copy(parentnamespace)); context.namespaces = lcons(&dpns, list_copy(parentnamespace));
@ -2118,7 +2110,7 @@ get_query_def_extended(Query *query, StringInfo buf, List *parentnamespace,
} }
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
} }
/* ---------- /* ----------

View File

@ -54,6 +54,7 @@
#include "distributed/citus_nodefuncs.h" #include "distributed/citus_nodefuncs.h"
#include "distributed/citus_ruleutils.h" #include "distributed/citus_ruleutils.h"
#include "distributed/multi_router_planner.h" #include "distributed/multi_router_planner.h"
#include "distributed/namespace_utils.h"
#include "executor/spi.h" #include "executor/spi.h"
#include "foreign/foreign.h" #include "foreign/foreign.h"
#include "funcapi.h" #include "funcapi.h"
@ -641,18 +642,14 @@ pg_get_rule_expr(Node *expression)
{ {
bool showImplicitCasts = true; bool showImplicitCasts = true;
deparse_context context; deparse_context context;
OverrideSearchPath *overridePath = NULL;
StringInfo buffer = makeStringInfo(); StringInfo buffer = makeStringInfo();
/* /*
* Set search_path to NIL so that all objects outside of pg_catalog will be * Set search_path to NIL so that all objects outside of pg_catalog will be
* schema-prefixed. pg_catalog will be added automatically when we call * schema-prefixed. pg_catalog will be added automatically when we call
* PushOverrideSearchPath(), since we set addCatalog to true; * PushEmptySearchPath().
*/ */
overridePath = GetOverrideSearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
overridePath->schemas = NIL;
overridePath->addCatalog = true;
PushOverrideSearchPath(overridePath);
context.buf = buffer; context.buf = buffer;
context.namespaces = NIL; context.namespaces = NIL;
@ -669,7 +666,7 @@ pg_get_rule_expr(Node *expression)
get_rule_expr(expression, &context, showImplicitCasts); get_rule_expr(expression, &context, showImplicitCasts);
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
return buffer->data; return buffer->data;
} }
@ -2052,8 +2049,6 @@ get_query_def_extended(Query *query, StringInfo buf, List *parentnamespace,
deparse_context context; deparse_context context;
deparse_namespace dpns; deparse_namespace dpns;
OverrideSearchPath *overridePath = NULL;
/* Guard against excessively long or deeply-nested queries */ /* Guard against excessively long or deeply-nested queries */
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
check_stack_depth(); check_stack_depth();
@ -2072,12 +2067,9 @@ get_query_def_extended(Query *query, StringInfo buf, List *parentnamespace,
/* /*
* Set search_path to NIL so that all objects outside of pg_catalog will be * Set search_path to NIL so that all objects outside of pg_catalog will be
* schema-prefixed. pg_catalog will be added automatically when we call * schema-prefixed. pg_catalog will be added automatically when we call
* PushOverrideSearchPath(), since we set addCatalog to true; * PushEmptySearchPath().
*/ */
overridePath = GetOverrideSearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
overridePath->schemas = NIL;
overridePath->addCatalog = true;
PushOverrideSearchPath(overridePath);
context.buf = buf; context.buf = buf;
context.namespaces = lcons(&dpns, list_copy(parentnamespace)); context.namespaces = lcons(&dpns, list_copy(parentnamespace));
@ -2132,7 +2124,7 @@ get_query_def_extended(Query *query, StringInfo buf, List *parentnamespace,
} }
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
} }
/* ---------- /* ----------

View File

@ -133,6 +133,19 @@ typedef struct ShardIdCacheEntry
int shardIndex; int shardIndex;
} ShardIdCacheEntry; } ShardIdCacheEntry;
/*
* ExtensionCreatedState is used to track if citus extension has been created
* using CREATE EXTENSION command.
* UNKNOWN : MetadataCache is invalid. State is UNKNOWN.
* CREATED : Citus is created.
* NOTCREATED : Citus is not created.
*/
typedef enum ExtensionCreatedState
{
UNKNOWN = 0,
CREATED = 1,
NOTCREATED = 2,
} ExtensionCreatedState;
/* /*
* State which should be cleared upon DROP EXTENSION. When the configuration * State which should be cleared upon DROP EXTENSION. When the configuration
@ -140,7 +153,7 @@ typedef struct ShardIdCacheEntry
*/ */
typedef struct MetadataCacheData typedef struct MetadataCacheData
{ {
bool extensionLoaded; ExtensionCreatedState extensionCreatedState;
Oid distShardRelationId; Oid distShardRelationId;
Oid distPlacementRelationId; Oid distPlacementRelationId;
Oid distBackgroundJobRelationId; Oid distBackgroundJobRelationId;
@ -288,7 +301,6 @@ static void CreateDistTableCache(void);
static void CreateShardIdCache(void); static void CreateShardIdCache(void);
static void CreateDistObjectCache(void); static void CreateDistObjectCache(void);
static void InvalidateForeignRelationGraphCacheCallback(Datum argument, Oid relationId); static void InvalidateForeignRelationGraphCacheCallback(Datum argument, Oid relationId);
static void InvalidateDistRelationCacheCallback(Datum argument, Oid relationId);
static void InvalidateNodeRelationCacheCallback(Datum argument, Oid relationId); static void InvalidateNodeRelationCacheCallback(Datum argument, Oid relationId);
static void InvalidateLocalGroupIdRelationCacheCallback(Datum argument, Oid relationId); static void InvalidateLocalGroupIdRelationCacheCallback(Datum argument, Oid relationId);
static void InvalidateConnParamsCacheCallback(Datum argument, Oid relationId); static void InvalidateConnParamsCacheCallback(Datum argument, Oid relationId);
@ -2187,16 +2199,30 @@ HasOverlappingShardInterval(ShardInterval **shardIntervalArray,
bool bool
CitusHasBeenLoaded(void) CitusHasBeenLoaded(void)
{ {
if (!MetadataCache.extensionLoaded || creating_extension) /*
* We do not use Citus hooks during CREATE/ALTER EXTENSION citus
* since the objects used by the C code might be not be there yet.
*/
if (creating_extension)
{ {
/* Oid citusExtensionOid = get_extension_oid("citus", true);
* Refresh if we have not determined whether the extension has been
* loaded yet, or in case of ALTER EXTENSION since we want to treat
* Citus as "not loaded" during ALTER EXTENSION citus.
*/
bool extensionLoaded = CitusHasBeenLoadedInternal();
if (extensionLoaded && !MetadataCache.extensionLoaded) if (CurrentExtensionObject == citusExtensionOid)
{
return false;
}
}
/*
* If extensionCreatedState is UNKNOWN, query pg_extension for Citus
* and cache the result. Otherwise return the value extensionCreatedState
* indicates.
*/
if (MetadataCache.extensionCreatedState == UNKNOWN)
{
bool extensionCreated = CitusHasBeenLoadedInternal();
if (extensionCreated)
{ {
/* /*
* Loaded Citus for the first time in this session, or first time after * Loaded Citus for the first time in this session, or first time after
@ -2208,31 +2234,22 @@ CitusHasBeenLoaded(void)
*/ */
StartupCitusBackend(); StartupCitusBackend();
/*
* InvalidateDistRelationCacheCallback resets state such as extensionLoaded
* when it notices changes to pg_dist_partition (which usually indicate
* `DROP EXTENSION citus;` has been run)
*
* Ensure InvalidateDistRelationCacheCallback will notice those changes
* by caching pg_dist_partition's oid.
*
* We skip these checks during upgrade since pg_dist_partition is not
* present during early stages of upgrade operation.
*/
DistPartitionRelationId();
/* /*
* This needs to be initialized so we can receive foreign relation graph * This needs to be initialized so we can receive foreign relation graph
* invalidation messages in InvalidateForeignRelationGraphCacheCallback(). * invalidation messages in InvalidateForeignRelationGraphCacheCallback().
* See the comments of InvalidateForeignKeyGraph for more context. * See the comments of InvalidateForeignKeyGraph for more context.
*/ */
DistColocationRelationId(); DistColocationRelationId();
}
MetadataCache.extensionLoaded = extensionLoaded; MetadataCache.extensionCreatedState = CREATED;
}
else
{
MetadataCache.extensionCreatedState = NOTCREATED;
}
} }
return MetadataCache.extensionLoaded; return (MetadataCache.extensionCreatedState == CREATED) ? true : false;
} }
@ -2257,15 +2274,6 @@ CitusHasBeenLoadedInternal(void)
return false; return false;
} }
if (creating_extension && CurrentExtensionObject == citusExtensionOid)
{
/*
* We do not use Citus hooks during CREATE/ALTER EXTENSION citus
* since the objects used by the C code might be not be there yet.
*/
return false;
}
/* citus extension exists and has been created */ /* citus extension exists and has been created */
return true; return true;
} }
@ -4201,10 +4209,6 @@ InitializeDistCache(void)
CreateShardIdCache(); CreateShardIdCache();
InitializeDistObjectCache(); InitializeDistObjectCache();
/* Watch for invalidation events. */
CacheRegisterRelcacheCallback(InvalidateDistRelationCacheCallback,
(Datum) 0);
} }
@ -4754,7 +4758,7 @@ InvalidateForeignKeyGraph(void)
* InvalidateDistRelationCacheCallback flushes cache entries when a relation * InvalidateDistRelationCacheCallback flushes cache entries when a relation
* is updated (or flushes the entire cache). * is updated (or flushes the entire cache).
*/ */
static void void
InvalidateDistRelationCacheCallback(Datum argument, Oid relationId) InvalidateDistRelationCacheCallback(Datum argument, Oid relationId)
{ {
/* invalidate either entire cache or a specific entry */ /* invalidate either entire cache or a specific entry */
@ -4762,12 +4766,18 @@ InvalidateDistRelationCacheCallback(Datum argument, Oid relationId)
{ {
InvalidateDistTableCache(); InvalidateDistTableCache();
InvalidateDistObjectCache(); InvalidateDistObjectCache();
InvalidateMetadataSystemCache();
} }
else else
{ {
void *hashKey = (void *) &relationId; void *hashKey = (void *) &relationId;
bool foundInCache = false; bool foundInCache = false;
if (DistTableCacheHash == NULL)
{
return;
}
CitusTableCacheEntrySlot *cacheSlot = CitusTableCacheEntrySlot *cacheSlot =
hash_search(DistTableCacheHash, hashKey, HASH_FIND, &foundInCache); hash_search(DistTableCacheHash, hashKey, HASH_FIND, &foundInCache);
if (foundInCache) if (foundInCache)
@ -4776,21 +4786,19 @@ InvalidateDistRelationCacheCallback(Datum argument, Oid relationId)
} }
/* /*
* If pg_dist_partition is being invalidated drop all state * if pg_dist_partition relcache is invalidated for some reason,
* This happens pretty rarely, but most importantly happens during * invalidate the MetadataCache. It is likely an overkill to invalidate
* DROP EXTENSION citus; This isn't the only time when this happens * the entire cache here. But until a better fix, we keep it this way
* though, it can happen for multiple other reasons, such as an * for postgres regression tests that includes
* autovacuum running ANALYZE on pg_dist_partition. Such an ANALYZE * REINDEX SCHEMA CONCURRENTLY pg_catalog
* wouldn't really need a full Metadata cache invalidation, but we * command.
* don't know how to differentiate between DROP EXTENSION and ANALYZE.
* So for now we simply drop it in both cases and take the slight
* temporary performance hit.
*/ */
if (relationId == MetadataCache.distPartitionRelationId) if (relationId == MetadataCache.distPartitionRelationId)
{ {
InvalidateMetadataSystemCache(); InvalidateMetadataSystemCache();
} }
if (relationId == MetadataCache.distObjectRelationId) if (relationId == MetadataCache.distObjectRelationId)
{ {
InvalidateDistObjectCache(); InvalidateDistObjectCache();
@ -4830,6 +4838,11 @@ InvalidateDistTableCache(void)
CitusTableCacheEntrySlot *cacheSlot = NULL; CitusTableCacheEntrySlot *cacheSlot = NULL;
HASH_SEQ_STATUS status; HASH_SEQ_STATUS status;
if (DistTableCacheHash == NULL)
{
return;
}
hash_seq_init(&status, DistTableCacheHash); hash_seq_init(&status, DistTableCacheHash);
while ((cacheSlot = (CitusTableCacheEntrySlot *) hash_seq_search(&status)) != NULL) while ((cacheSlot = (CitusTableCacheEntrySlot *) hash_seq_search(&status)) != NULL)
@ -4848,6 +4861,11 @@ InvalidateDistObjectCache(void)
DistObjectCacheEntry *cacheEntry = NULL; DistObjectCacheEntry *cacheEntry = NULL;
HASH_SEQ_STATUS status; HASH_SEQ_STATUS status;
if (DistObjectCacheHash == NULL)
{
return;
}
hash_seq_init(&status, DistObjectCacheHash); hash_seq_init(&status, DistObjectCacheHash);
while ((cacheEntry = (DistObjectCacheEntry *) hash_seq_search(&status)) != NULL) while ((cacheEntry = (DistObjectCacheEntry *) hash_seq_search(&status)) != NULL)
@ -4930,8 +4948,8 @@ CreateDistObjectCache(void)
/* /*
* InvalidateMetadataSystemCache resets all the cached OIDs and the extensionLoaded flag, * InvalidateMetadataSystemCache resets all the cached OIDs and the extensionCreatedState
* and invalidates the worker node, ConnParams, and local group ID caches. * flag and invalidates the worker node, ConnParams, and local group ID caches.
*/ */
void void
InvalidateMetadataSystemCache(void) InvalidateMetadataSystemCache(void)

View File

@ -612,7 +612,7 @@ GetPreLoadTableCreationCommands(Oid relationId,
{ {
List *tableDDLEventList = NIL; List *tableDDLEventList = NIL;
PushOverrideEmptySearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
/* fetch table schema and column option definitions */ /* fetch table schema and column option definitions */
char *tableSchemaDef = pg_get_tableschemadef_string(relationId, char *tableSchemaDef = pg_get_tableschemadef_string(relationId,
@ -665,7 +665,7 @@ GetPreLoadTableCreationCommands(Oid relationId,
tableDDLEventList = list_concat(tableDDLEventList, policyCommands); tableDDLEventList = list_concat(tableDDLEventList, policyCommands);
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
return tableDDLEventList; return tableDDLEventList;
} }
@ -754,7 +754,7 @@ GatherIndexAndConstraintDefinitionList(Form_pg_index indexForm, List **indexDDLE
int indexFlags) int indexFlags)
{ {
/* generate fully-qualified names */ /* generate fully-qualified names */
PushOverrideEmptySearchPath(CurrentMemoryContext); int saveNestLevel = PushEmptySearchPath();
Oid indexId = indexForm->indexrelid; Oid indexId = indexForm->indexrelid;
bool indexImpliedByConstraint = IndexImpliedByAConstraint(indexForm); bool indexImpliedByConstraint = IndexImpliedByAConstraint(indexForm);
@ -805,7 +805,7 @@ GatherIndexAndConstraintDefinitionList(Form_pg_index indexForm, List **indexDDLE
} }
/* revert back to original search_path */ /* revert back to original search_path */
PopOverrideSearchPath(); PopEmptySearchPath(saveNestLevel);
} }

View File

@ -158,7 +158,7 @@ NoneDistTableDropCoordinatorPlacementTable(Oid noneDistTableId)
* local session because changes made to shards are allowed for Citus internal * local session because changes made to shards are allowed for Citus internal
* backends anyway. * backends anyway.
*/ */
int save_nestlevel = NewGUCNestLevel(); int saveNestLevel = NewGUCNestLevel();
SetLocalEnableLocalReferenceForeignKeys(false); SetLocalEnableLocalReferenceForeignKeys(false);
SetLocalEnableManualChangesToShard(true); SetLocalEnableManualChangesToShard(true);
@ -184,7 +184,7 @@ NoneDistTableDropCoordinatorPlacementTable(Oid noneDistTableId)
bool localExecutionSupported = true; bool localExecutionSupported = true;
ExecuteUtilityTaskList(list_make1(task), localExecutionSupported); ExecuteUtilityTaskList(list_make1(task), localExecutionSupported);
AtEOXact_GUC(true, save_nestlevel); AtEOXact_GUC(true, saveNestLevel);
} }

View File

@ -109,6 +109,8 @@
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
#include "utils/guc.h" #include "utils/guc.h"
#include "utils/guc_tables.h" #include "utils/guc_tables.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "utils/varlena.h" #include "utils/varlena.h"
@ -554,6 +556,9 @@ _PG_init(void)
"ColumnarSupportsIndexAM", "ColumnarSupportsIndexAM",
true, &handle); true, &handle);
CacheRegisterRelcacheCallback(InvalidateDistRelationCacheCallback,
(Datum) 0);
INIT_COLUMNAR_SYMBOL(CompressionTypeStr_type, CompressionTypeStr); INIT_COLUMNAR_SYMBOL(CompressionTypeStr_type, CompressionTypeStr);
INIT_COLUMNAR_SYMBOL(IsColumnarTableAmTable_type, IsColumnarTableAmTable); INIT_COLUMNAR_SYMBOL(IsColumnarTableAmTable_type, IsColumnarTableAmTable);
INIT_COLUMNAR_SYMBOL(ReadColumnarOptions_type, ReadColumnarOptions); INIT_COLUMNAR_SYMBOL(ReadColumnarOptions_type, ReadColumnarOptions);

View File

@ -19,6 +19,8 @@
#include "access/twophase.h" #include "access/twophase.h"
#include "access/xact.h" #include "access/xact.h"
#include "catalog/dependency.h"
#include "common/hashfn.h"
#include "distributed/backend_data.h" #include "distributed/backend_data.h"
#include "distributed/citus_safe_lib.h" #include "distributed/citus_safe_lib.h"
#include "distributed/connection_management.h" #include "distributed/connection_management.h"
@ -30,6 +32,7 @@
#include "distributed/local_executor.h" #include "distributed/local_executor.h"
#include "distributed/locally_reserved_shared_connections.h" #include "distributed/locally_reserved_shared_connections.h"
#include "distributed/maintenanced.h" #include "distributed/maintenanced.h"
#include "distributed/metadata/dependency.h"
#include "distributed/multi_executor.h" #include "distributed/multi_executor.h"
#include "distributed/multi_logical_replication.h" #include "distributed/multi_logical_replication.h"
#include "distributed/multi_explain.h" #include "distributed/multi_explain.h"
@ -89,14 +92,25 @@ StringInfo activeSetStmts;
* Though a list, we treat this as a stack, pushing on subxact contexts whenever * Though a list, we treat this as a stack, pushing on subxact contexts whenever
* e.g. a SAVEPOINT is executed (though this is actually performed by providing * e.g. a SAVEPOINT is executed (though this is actually performed by providing
* PostgreSQL with a sub-xact callback). At present, the context of a subxact * PostgreSQL with a sub-xact callback). At present, the context of a subxact
* includes a subxact identifier as well as any SET LOCAL statements propagated * includes
* to workers during the sub-transaction. * - a subxact identifier,
* - any SET LOCAL statements propagated to workers during the sub-transaction,
* - all objects propagated to workers during the sub-transaction.
* *
* To be clear, last item of activeSubXactContexts list corresponds to top of * To be clear, last item of activeSubXactContexts list corresponds to top of
* stack. * stack.
*/ */
static List *activeSubXactContexts = NIL; static List *activeSubXactContexts = NIL;
/*
* PropagatedObjectsInTx is a set of objects propagated in the root transaction.
* We also keep track of objects propagated in sub-transactions in activeSubXactContexts.
* Any committed sub-transaction would cause the objects, which are propagated during
* the sub-transaction, to be moved to upper transaction's set. Objects are discarded
* when the sub-transaction is aborted.
*/
static HTAB *PropagatedObjectsInTx = NULL;
/* some pre-allocated memory so we don't need to call malloc() during callbacks */ /* some pre-allocated memory so we don't need to call malloc() during callbacks */
MemoryContext CitusXactCallbackContext = NULL; MemoryContext CitusXactCallbackContext = NULL;
@ -142,11 +156,17 @@ static void CoordinatedSubTransactionCallback(SubXactEvent event, SubTransaction
/* remaining functions */ /* remaining functions */
static void AdjustMaxPreparedTransactions(void); static void AdjustMaxPreparedTransactions(void);
static void PushSubXact(SubTransactionId subId); static void PushSubXact(SubTransactionId subId);
static void PopSubXact(SubTransactionId subId); static void PopSubXact(SubTransactionId subId, bool commit);
static void ResetGlobalVariables(void); static void ResetGlobalVariables(void);
static bool SwallowErrors(void (*func)(void)); static bool SwallowErrors(void (*func)(void));
static void ForceAllInProgressConnectionsToClose(void); static void ForceAllInProgressConnectionsToClose(void);
static void EnsurePrepareTransactionIsAllowed(void); static void EnsurePrepareTransactionIsAllowed(void);
static HTAB * CurrentTransactionPropagatedObjects(bool readonly);
static HTAB * ParentTransactionPropagatedObjects(bool readonly);
static void MovePropagatedObjectsToParentTransaction(void);
static bool DependencyInPropagatedObjectsHash(HTAB *propagatedObjects,
const ObjectAddress *dependency);
static HTAB * CreateTxPropagatedObjectsHash(void);
/* /*
@ -321,6 +341,7 @@ CoordinatedTransactionCallback(XactEvent event, void *arg)
ResetGlobalVariables(); ResetGlobalVariables();
ResetRelationAccessHash(); ResetRelationAccessHash();
ResetPropagatedObjects();
/* /*
* Make sure that we give the shared connections back to the shared * Make sure that we give the shared connections back to the shared
@ -391,6 +412,7 @@ CoordinatedTransactionCallback(XactEvent event, void *arg)
ResetGlobalVariables(); ResetGlobalVariables();
ResetRelationAccessHash(); ResetRelationAccessHash();
ResetPropagatedObjects();
/* Reset any local replication origin session since transaction has been aborted.*/ /* Reset any local replication origin session since transaction has been aborted.*/
ResetReplicationOriginLocalSession(); ResetReplicationOriginLocalSession();
@ -638,7 +660,7 @@ CoordinatedSubTransactionCallback(SubXactEvent event, SubTransactionId subId,
switch (event) switch (event)
{ {
/* /*
* Our subtransaction stack should be consistent with postgres' internal * Our sub-transaction stack should be consistent with postgres' internal
* transaction stack. In case of subxact begin, postgres calls our * transaction stack. In case of subxact begin, postgres calls our
* callback after it has pushed the transaction into stack, so we have to * callback after it has pushed the transaction into stack, so we have to
* do the same even if worker commands fail, so we PushSubXact() first. * do the same even if worker commands fail, so we PushSubXact() first.
@ -672,7 +694,7 @@ CoordinatedSubTransactionCallback(SubXactEvent event, SubTransactionId subId,
{ {
CoordinatedRemoteTransactionsSavepointRelease(subId); CoordinatedRemoteTransactionsSavepointRelease(subId);
} }
PopSubXact(subId); PopSubXact(subId, true);
/* Set CachedDuringCitusCreation to one level lower to represent citus creation is done */ /* Set CachedDuringCitusCreation to one level lower to represent citus creation is done */
@ -706,7 +728,7 @@ CoordinatedSubTransactionCallback(SubXactEvent event, SubTransactionId subId,
{ {
CoordinatedRemoteTransactionsSavepointRollback(subId); CoordinatedRemoteTransactionsSavepointRollback(subId);
} }
PopSubXact(subId); PopSubXact(subId, false);
/* /*
* Clear MetadataCache table if we're aborting from a CREATE EXTENSION Citus * Clear MetadataCache table if we're aborting from a CREATE EXTENSION Citus
@ -775,6 +797,9 @@ PushSubXact(SubTransactionId subId)
state->subId = subId; state->subId = subId;
state->setLocalCmds = activeSetStmts; state->setLocalCmds = activeSetStmts;
/* we lazily create hashset when any object is propagated during sub-transaction */
state->propagatedObjects = NULL;
/* append to list and reset active set stmts for upcoming sub-xact */ /* append to list and reset active set stmts for upcoming sub-xact */
activeSubXactContexts = lappend(activeSubXactContexts, state); activeSubXactContexts = lappend(activeSubXactContexts, state);
activeSetStmts = makeStringInfo(); activeSetStmts = makeStringInfo();
@ -783,7 +808,7 @@ PushSubXact(SubTransactionId subId)
/* PopSubXact pops subId from the stack of active sub-transactions. */ /* PopSubXact pops subId from the stack of active sub-transactions. */
static void static void
PopSubXact(SubTransactionId subId) PopSubXact(SubTransactionId subId, bool commit)
{ {
SubXactContext *state = llast(activeSubXactContexts); SubXactContext *state = llast(activeSubXactContexts);
@ -806,6 +831,16 @@ PopSubXact(SubTransactionId subId)
*/ */
activeSetStmts = state->setLocalCmds; activeSetStmts = state->setLocalCmds;
/*
* Keep subtransaction's propagated objects at parent transaction
* if subtransaction committed. Otherwise, discard them.
*/
if (commit)
{
MovePropagatedObjectsToParentTransaction();
}
hash_destroy(state->propagatedObjects);
/* /*
* Free state to avoid memory leaks when we create subxacts for each row, * Free state to avoid memory leaks when we create subxacts for each row,
* e.g. in exception handling of UDFs. * e.g. in exception handling of UDFs.
@ -913,3 +948,227 @@ EnsurePrepareTransactionIsAllowed(void)
errmsg("cannot use 2PC in transactions involving " errmsg("cannot use 2PC in transactions involving "
"multiple servers"))); "multiple servers")));
} }
/*
* CurrentTransactionPropagatedObjects returns the objects propagated in current
* sub-transaction or the root transaction if no sub-transaction exists.
*
* If the propagated objects are readonly it will not create the hashmap if it does not
* already exist in the current sub-transaction.
*/
static HTAB *
CurrentTransactionPropagatedObjects(bool readonly)
{
if (activeSubXactContexts == NIL)
{
/* hashset in the root transaction if there is no sub-transaction */
if (PropagatedObjectsInTx == NULL && !readonly)
{
/* lazily create hashset for root transaction, for mutating uses */
PropagatedObjectsInTx = CreateTxPropagatedObjectsHash();
}
return PropagatedObjectsInTx;
}
/* hashset in top level sub-transaction */
SubXactContext *state = llast(activeSubXactContexts);
if (state->propagatedObjects == NULL && !readonly)
{
/* lazily create hashset for sub-transaction, for mutating uses */
state->propagatedObjects = CreateTxPropagatedObjectsHash();
}
return state->propagatedObjects;
}
/*
* ParentTransactionPropagatedObjects returns the objects propagated in parent
* transaction of active sub-transaction. It returns the root transaction if
* no sub-transaction exists.
*
* If the propagated objects are readonly it will not create the hashmap if it does not
* already exist in the target sub-transaction.
*/
static HTAB *
ParentTransactionPropagatedObjects(bool readonly)
{
int nestingLevel = list_length(activeSubXactContexts);
if (nestingLevel <= 1)
{
/*
* The parent is the root transaction, when there is single level sub-transaction
* or no sub-transaction.
*/
if (PropagatedObjectsInTx == NULL && !readonly)
{
/* lazily create hashset for root transaction, for mutating uses */
PropagatedObjectsInTx = CreateTxPropagatedObjectsHash();
}
return PropagatedObjectsInTx;
}
/* parent is upper sub-transaction */
Assert(nestingLevel >= 2);
SubXactContext *state = list_nth(activeSubXactContexts, nestingLevel - 2);
if (state->propagatedObjects == NULL && !readonly)
{
/* lazily create hashset for parent sub-transaction */
state->propagatedObjects = CreateTxPropagatedObjectsHash();
}
return state->propagatedObjects;
}
/*
* MovePropagatedObjectsToParentTransaction moves all objects propagated in the current
* sub-transaction to the parent transaction. This should only be called when there is
* active sub-transaction.
*/
static void
MovePropagatedObjectsToParentTransaction(void)
{
Assert(llast(activeSubXactContexts) != NULL);
HTAB *currentPropagatedObjects = CurrentTransactionPropagatedObjects(true);
if (currentPropagatedObjects == NULL)
{
/* nothing to move */
return;
}
/*
* Only after we know we have objects to move into the parent do we get a handle on
* a guaranteed existing parent hash table. This makes sure that the parents only
* get populated once there are objects to be tracked.
*/
HTAB *parentPropagatedObjects = ParentTransactionPropagatedObjects(false);
HASH_SEQ_STATUS propagatedObjectsSeq;
hash_seq_init(&propagatedObjectsSeq, currentPropagatedObjects);
ObjectAddress *objectAddress = NULL;
while ((objectAddress = hash_seq_search(&propagatedObjectsSeq)) != NULL)
{
hash_search(parentPropagatedObjects, objectAddress, HASH_ENTER, NULL);
}
}
/*
* DependencyInPropagatedObjectsHash checks if dependency is in given hashset
* of propagated objects.
*/
static bool
DependencyInPropagatedObjectsHash(HTAB *propagatedObjects, const
ObjectAddress *dependency)
{
if (propagatedObjects == NULL)
{
return false;
}
bool found = false;
hash_search(propagatedObjects, dependency, HASH_FIND, &found);
return found;
}
/*
* CreateTxPropagatedObjectsHash creates a hashset to keep track of the objects
* propagated in the current root transaction or sub-transaction.
*/
static HTAB *
CreateTxPropagatedObjectsHash(void)
{
HASHCTL info;
memset(&info, 0, sizeof(info));
info.keysize = sizeof(ObjectAddress);
info.entrysize = sizeof(ObjectAddress);
info.hash = tag_hash;
info.hcxt = CitusXactCallbackContext;
int hashFlags = (HASH_ELEM | HASH_CONTEXT | HASH_FUNCTION);
return hash_create("Tx Propagated Objects", 16, &info, hashFlags);
}
/*
* TrackPropagatedObject adds given object into the objects propagated in the current
* sub-transaction.
*/
void
TrackPropagatedObject(const ObjectAddress *objectAddress)
{
HTAB *currentPropagatedObjects = CurrentTransactionPropagatedObjects(false);
hash_search(currentPropagatedObjects, objectAddress, HASH_ENTER, NULL);
}
/*
* TrackPropagatedTableAndSequences adds given table and its sequences to the objects
* propagated in the current sub-transaction.
*/
void
TrackPropagatedTableAndSequences(Oid relationId)
{
/* track table */
ObjectAddress *tableAddress = palloc0(sizeof(ObjectAddress));
ObjectAddressSet(*tableAddress, RelationRelationId, relationId);
TrackPropagatedObject(tableAddress);
/* track its sequences */
List *ownedSeqIdList = getOwnedSequences(relationId);
Oid ownedSeqId = InvalidOid;
foreach_oid(ownedSeqId, ownedSeqIdList)
{
ObjectAddress *seqAddress = palloc0(sizeof(ObjectAddress));
ObjectAddressSet(*seqAddress, RelationRelationId, ownedSeqId);
TrackPropagatedObject(seqAddress);
}
}
/*
* ResetPropagatedObjects destroys hashset of propagated objects in the root transaction.
*/
void
ResetPropagatedObjects(void)
{
hash_destroy(PropagatedObjectsInTx);
PropagatedObjectsInTx = NULL;
}
/*
* HasAnyDependencyInPropagatedObjects decides if any dependency of given object is
* propagated in the current transaction.
*/
bool
HasAnyDependencyInPropagatedObjects(const ObjectAddress *objectAddress)
{
List *dependencyList = GetAllSupportedDependenciesForObject(objectAddress);
ObjectAddress *dependency = NULL;
foreach_ptr(dependency, dependencyList)
{
/* first search in root transaction */
if (DependencyInPropagatedObjectsHash(PropagatedObjectsInTx, dependency))
{
return true;
}
/* search in all nested sub-transactions */
if (activeSubXactContexts == NIL)
{
continue;
}
SubXactContext *state = NULL;
foreach_ptr(state, activeSubXactContexts)
{
if (DependencyInPropagatedObjectsHash(state->propagatedObjects, dependency))
{
return true;
}
}
}
return false;
}

View File

@ -135,6 +135,21 @@ SendCommandToWorkersWithMetadataViaSuperUser(const char *command)
} }
/*
* SendCommandListToWorkersWithMetadata sends all commands to all metadata workers
* with the current user. See `SendCommandToWorkersWithMetadata`for details.
*/
void
SendCommandListToWorkersWithMetadata(List *commands)
{
char *command = NULL;
foreach_ptr(command, commands)
{
SendCommandToWorkersWithMetadata(command);
}
}
/* /*
* TargetWorkerSetNodeList returns a list of WorkerNode's that satisfies the * TargetWorkerSetNodeList returns a list of WorkerNode's that satisfies the
* TargetWorkerSet. * TargetWorkerSet.

View File

@ -175,12 +175,11 @@ BreakColocation(Oid sourceRelationId)
*/ */
Relation pgDistColocation = table_open(DistColocationRelationId(), ExclusiveLock); Relation pgDistColocation = table_open(DistColocationRelationId(), ExclusiveLock);
uint32 newColocationId = GetNextColocationId(); uint32 oldColocationId = TableColocationId(sourceRelationId);
bool localOnly = false; CreateColocationGroupForRelation(sourceRelationId);
UpdateRelationColocationGroup(sourceRelationId, newColocationId, localOnly);
/* if there is not any remaining table in the colocation group, delete it */ /* if there is not any remaining table in the old colocation group, delete it */
DeleteColocationGroupIfNoTablesBelong(sourceRelationId); DeleteColocationGroupIfNoTablesBelong(oldColocationId);
table_close(pgDistColocation, NoLock); table_close(pgDistColocation, NoLock);
} }

View File

@ -11,22 +11,33 @@
#include "postgres.h" #include "postgres.h"
#include "catalog/namespace.h"
#include "distributed/citus_ruleutils.h"
#include "distributed/namespace_utils.h" #include "distributed/namespace_utils.h"
#include "utils/guc.h"
#include "utils/regproc.h" #include "utils/regproc.h"
/* /*
* PushOverrideEmptySearchPath pushes search_path to be NIL and sets addCatalog to * We use the equivalent of a function SET option to allow the setting to
* true so that all objects outside of pg_catalog will be schema-prefixed. * persist for the exact duration of the transaction, guc.c takes care of
* Afterwards, PopOverrideSearchPath can be used to revert the search_path back. * undoing the setting on error.
*
* We set search_path to "pg_catalog" instead of "" to expose useful utilities.
*/
int
PushEmptySearchPath()
{
int saveNestLevel = NewGUCNestLevel();
(void) set_config_option("search_path", "pg_catalog",
PGC_USERSET, PGC_S_SESSION,
GUC_ACTION_SAVE, true, 0, false);
return saveNestLevel;
}
/*
* Restore the GUC variable search_path we set in PushEmptySearchPath
*/ */
void void
PushOverrideEmptySearchPath(MemoryContext memoryContext) PopEmptySearchPath(int saveNestLevel)
{ {
OverrideSearchPath *overridePath = GetOverrideSearchPath(memoryContext); AtEOXact_GUC(true, saveNestLevel);
overridePath->schemas = NIL;
overridePath->addCatalog = true;
PushOverrideSearchPath(overridePath);
} }

View File

@ -137,6 +137,8 @@ typedef enum
ANY_CITUS_TABLE_TYPE ANY_CITUS_TABLE_TYPE
} CitusTableType; } CitusTableType;
void InvalidateDistRelationCacheCallback(Datum argument, Oid relationId);
extern List * AllCitusTableIds(void); extern List * AllCitusTableIds(void);
extern bool IsCitusTableType(Oid relationId, CitusTableType tableType); extern bool IsCitusTableType(Oid relationId, CitusTableType tableType);
extern CitusTableType GetCitusTableType(CitusTableCacheEntry *tableEntry); extern CitusTableType GetCitusTableType(CitusTableCacheEntry *tableEntry);

View File

@ -10,6 +10,7 @@
#ifndef NAMESPACE_UTILS_H #ifndef NAMESPACE_UTILS_H
#define NAMESPACE_UTILS_H #define NAMESPACE_UTILS_H
extern void PushOverrideEmptySearchPath(MemoryContext memoryContext); extern int PushEmptySearchPath(void);
extern void PopEmptySearchPath(int saveNestLevel);
#endif /* NAMESPACE_UTILS_H */ #endif /* NAMESPACE_UTILS_H */

View File

@ -10,11 +10,13 @@
#define TRANSACTION_MANAGMENT_H #define TRANSACTION_MANAGMENT_H
#include "access/xact.h" #include "access/xact.h"
#include "catalog/objectaddress.h"
#include "lib/ilist.h" #include "lib/ilist.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
#include "nodes/primnodes.h" #include "nodes/primnodes.h"
#include "utils/hsearch.h"
/* forward declare, to avoid recursive includes */ /* forward declare, to avoid recursive includes */
struct DistObjectCacheEntry; struct DistObjectCacheEntry;
@ -58,6 +60,7 @@ typedef struct SubXactContext
{ {
SubTransactionId subId; SubTransactionId subId;
StringInfo setLocalCmds; StringInfo setLocalCmds;
HTAB *propagatedObjects;
} SubXactContext; } SubXactContext;
/* /*
@ -157,6 +160,11 @@ extern bool IsMultiStatementTransaction(void);
extern void EnsureDistributedTransactionId(void); extern void EnsureDistributedTransactionId(void);
extern bool MaybeExecutingUDF(void); extern bool MaybeExecutingUDF(void);
/* functions for tracking the objects propagated in current transaction */
extern void TrackPropagatedObject(const ObjectAddress *objectAddress);
extern void TrackPropagatedTableAndSequences(Oid relationId);
extern void ResetPropagatedObjects(void);
extern bool HasAnyDependencyInPropagatedObjects(const ObjectAddress *objectAddress);
/* initialization function(s) */ /* initialization function(s) */
extern void InitializeTransactionManagement(void); extern void InitializeTransactionManagement(void);

View File

@ -73,6 +73,7 @@ extern bool SendOptionalMetadataCommandListToWorkerInCoordinatedTransaction(cons
commandList); commandList);
extern void SendCommandToWorkersWithMetadata(const char *command); extern void SendCommandToWorkersWithMetadata(const char *command);
extern void SendCommandToWorkersWithMetadataViaSuperUser(const char *command); extern void SendCommandToWorkersWithMetadataViaSuperUser(const char *command);
extern void SendCommandListToWorkersWithMetadata(List *commands);
extern void SendBareCommandListToMetadataWorkers(List *commandList); extern void SendBareCommandListToMetadataWorkers(List *commandList);
extern void EnsureNoModificationsHaveBeenDone(void); extern void EnsureNoModificationsHaveBeenDone(void);
extern void SendCommandListToWorkerOutsideTransaction(const char *nodeName, extern void SendCommandListToWorkerOutsideTransaction(const char *nodeName,

View File

@ -429,6 +429,10 @@ PORT_UPPER_BOUND = 32768
next_port = PORT_LOWER_BOUND next_port = PORT_LOWER_BOUND
def notice_handler(diag: psycopg.errors.Diagnostic):
print(f"{diag.severity}: {diag.message_primary}")
def cleanup_test_leftovers(nodes): def cleanup_test_leftovers(nodes):
""" """
Cleaning up test leftovers needs to be done in a specific order, because Cleaning up test leftovers needs to be done in a specific order, because
@ -444,7 +448,7 @@ def cleanup_test_leftovers(nodes):
node.cleanup_publications() node.cleanup_publications()
for node in nodes: for node in nodes:
node.cleanup_logical_replication_slots() node.cleanup_replication_slots()
for node in nodes: for node in nodes:
node.cleanup_schemas() node.cleanup_schemas()
@ -526,10 +530,12 @@ class QueryRunner(ABC):
def conn(self, *, autocommit=True, **kwargs): def conn(self, *, autocommit=True, **kwargs):
"""Open a psycopg connection to this server""" """Open a psycopg connection to this server"""
self.set_default_connection_options(kwargs) self.set_default_connection_options(kwargs)
return psycopg.connect( conn = psycopg.connect(
autocommit=autocommit, autocommit=autocommit,
**kwargs, **kwargs,
) )
conn.add_notice_handler(notice_handler)
return conn
def aconn(self, *, autocommit=True, **kwargs): def aconn(self, *, autocommit=True, **kwargs):
"""Open an asynchronous psycopg connection to this server""" """Open an asynchronous psycopg connection to this server"""
@ -572,6 +578,21 @@ class QueryRunner(ABC):
with self.cur(**kwargs) as cur: with self.cur(**kwargs) as cur:
cur.execute(query, params=params) cur.execute(query, params=params)
def sql_row(self, query, params=None, allow_empty_result=False, **kwargs):
"""Run an SQL query that returns a single row and returns this row
This opens a new connection and closes it once the query is done
"""
with self.cur(**kwargs) as cur:
cur.execute(query, params=params)
result = cur.fetchall()
if allow_empty_result and len(result) == 0:
return None
assert len(result) == 1, "sql_row returns more than one row"
return result[0]
def sql_value(self, query, params=None, allow_empty_result=False, **kwargs): def sql_value(self, query, params=None, allow_empty_result=False, **kwargs):
"""Run an SQL query that returns a single cell and return this value """Run an SQL query that returns a single cell and return this value
@ -731,7 +752,7 @@ class Postgres(QueryRunner):
# Used to track objects that we want to clean up at the end of a test # Used to track objects that we want to clean up at the end of a test
self.subscriptions = set() self.subscriptions = set()
self.publications = set() self.publications = set()
self.logical_replication_slots = set() self.replication_slots = set()
self.schemas = set() self.schemas = set()
self.users = set() self.users = set()
@ -983,7 +1004,7 @@ class Postgres(QueryRunner):
def create_logical_replication_slot( def create_logical_replication_slot(
self, name, plugin, temporary=False, twophase=False self, name, plugin, temporary=False, twophase=False
): ):
self.logical_replication_slots.add(name) self.replication_slots.add(name)
self.sql( self.sql(
"SELECT pg_catalog.pg_create_logical_replication_slot(%s,%s,%s,%s)", "SELECT pg_catalog.pg_create_logical_replication_slot(%s,%s,%s,%s)",
(name, plugin, temporary, twophase), (name, plugin, temporary, twophase),
@ -1015,12 +1036,21 @@ class Postgres(QueryRunner):
) )
) )
def cleanup_logical_replication_slots(self): def cleanup_replication_slots(self):
for slot in self.logical_replication_slots: for slot in self.replication_slots:
self.sql( start = time.time()
"SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots WHERE slot_name = %s", while True:
(slot,), try:
) self.sql(
"SELECT pg_drop_replication_slot(slot_name) FROM pg_replication_slots WHERE slot_name = %s",
(slot,),
)
except psycopg.errors.ObjectInUse:
if time.time() < start + 10:
time.sleep(0.5)
continue
raise
break
def cleanup_subscriptions(self): def cleanup_subscriptions(self):
for subscription in self.subscriptions: for subscription in self.subscriptions:

View File

@ -168,6 +168,7 @@ DEPS = {
], ],
), ),
"grant_on_schema_propagation": TestDeps("minimal_schedule"), "grant_on_schema_propagation": TestDeps("minimal_schedule"),
"propagate_extension_commands": TestDeps("minimal_schedule"),
} }

View File

@ -0,0 +1,44 @@
import psycopg
import pytest
def test_create_drop_citus(coord):
with coord.cur() as cur1:
with coord.cur() as cur2:
# Conn1 drops the extension
# and Conn2 cannot use it.
cur1.execute("DROP EXTENSION citus")
with pytest.raises(psycopg.errors.UndefinedFunction):
# Conn1 dropped the extension. citus_version udf
# cannot be found.sycopg.errors.UndefinedFunction
# is expected here.
cur2.execute("SELECT citus_version();")
# Conn2 creates the extension,
# Conn1 is able to use it immediadtely.
cur2.execute("CREATE EXTENSION citus")
cur1.execute("SELECT citus_version();")
cur1.execute("DROP EXTENSION citus;")
with coord.cur() as cur1:
with coord.cur() as cur2:
# A connection is able to create and use the extension
# within a transaction block.
cur1.execute("BEGIN;")
cur1.execute("CREATE TABLE t1(id int);")
cur1.execute("CREATE EXTENSION citus;")
cur1.execute("SELECT create_reference_table('t1')")
cur1.execute("ABORT;")
# Conn1 aborted so Conn2 is be able to create and
# use the extension within a transaction block.
cur2.execute("BEGIN;")
cur2.execute("CREATE TABLE t1(id int);")
cur2.execute("CREATE EXTENSION citus;")
cur2.execute("SELECT create_reference_table('t1')")
cur2.execute("COMMIT;")
# Conn2 commited so Conn1 is be able to use the
# extension immediately.
cur1.execute("SELECT citus_version();")

View File

@ -947,3 +947,4 @@ DROP DOMAIN IF EXISTS domain_does_not_exist;
NOTICE: type "domain_does_not_exist" does not exist, skipping NOTICE: type "domain_does_not_exist" does not exist, skipping
SET client_min_messages TO warning; SET client_min_messages TO warning;
DROP SCHEMA distributed_domain, distributed_domain_moved CASCADE; DROP SCHEMA distributed_domain, distributed_domain_moved CASCADE;
DROP ROLE domain_owner;

View File

@ -19,7 +19,7 @@ step s1-rebalance-c1-block-writes:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -40,8 +40,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 8000| 1|move |t |t |f |Copying Data colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 8000| 1|move |t |t |f |Copying Data
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 8000| 1|move |t |t |f |Copying Data colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 8000| 1|move |t |t |f |Copying Data
colocated1|1500002| 200000|localhost | 57637| 200000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet colocated1|1500002| 200000|localhost | 57637| 200000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet
colocated2|1500006| 8000|localhost | 57637| 8000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet colocated2|1500006| 8000|localhost | 57637| 8000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet
(4 rows) (4 rows)
@ -63,7 +63,7 @@ rebalance_table_shards
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -102,7 +102,7 @@ step s1-rebalance-c1-block-writes:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -123,8 +123,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 50000| 2|move |t |t |f |Completed colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 40000| 2|move |t |t |f |Completed
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 400000| 2|move |t |t |f |Completed colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 480000| 2|move |t |t |f |Completed
colocated1|1500002| 200000|localhost | 57637| 200000|localhost | 57638| 0| 1|move |t |t |f |Setting Up colocated1|1500002| 200000|localhost | 57637| 200000|localhost | 57638| 0| 1|move |t |t |f |Setting Up
colocated2|1500006| 8000|localhost | 57637| 8000|localhost | 57638| 0| 1|move |t |t |f |Setting Up colocated2|1500006| 8000|localhost | 57637| 8000|localhost | 57638| 0| 1|move |t |t |f |Setting Up
(4 rows) (4 rows)
@ -141,7 +141,7 @@ rebalance_table_shards
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -184,7 +184,7 @@ step s1-rebalance-c1-block-writes:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -205,8 +205,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 50000| 1|move |t |t |f |Copying Data colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 40000| 1|move |t |t |f |Copying Data
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 400000| 1|move |t |t |f |Copying Data colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 480000| 1|move |t |t |f |Copying Data
colocated1|1500002| 200000|localhost | 57637| 200000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet colocated1|1500002| 200000|localhost | 57637| 200000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet
colocated2|1500006| 8000|localhost | 57637| 8000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet colocated2|1500006| 8000|localhost | 57637| 8000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet
(4 rows) (4 rows)
@ -228,7 +228,7 @@ rebalance_table_shards
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -271,7 +271,7 @@ step s1-rebalance-c1-online:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -292,8 +292,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 8000| 1|move |t |t |f |Setting Up colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 8000| 1|move |t |t |f |Setting Up
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 8000| 1|move |t |t |f |Setting Up colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 8000| 1|move |t |t |f |Setting Up
colocated1|1500002| 200000|localhost | 57637| 200000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet colocated1|1500002| 200000|localhost | 57637| 200000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet
colocated2|1500006| 8000|localhost | 57637| 8000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet colocated2|1500006| 8000|localhost | 57637| 8000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet
(4 rows) (4 rows)
@ -315,7 +315,7 @@ rebalance_table_shards
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -358,7 +358,7 @@ step s1-rebalance-c1-online:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -379,8 +379,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 50000| 1|move |t |t |t |Final Catchup colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 40000| 1|move |t |t |t |Final Catchup
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 400000| 1|move |t |t |t |Final Catchup colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 480000| 1|move |t |t |t |Final Catchup
colocated1|1500002| 200000|localhost | 57637| 200000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet colocated1|1500002| 200000|localhost | 57637| 200000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet
colocated2|1500006| 8000|localhost | 57637| 8000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet colocated2|1500006| 8000|localhost | 57637| 8000|localhost | 57638| 0| 0|move |t |t |f |Not Started Yet
(4 rows) (4 rows)
@ -402,7 +402,7 @@ rebalance_table_shards
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -445,7 +445,7 @@ step s1-shard-move-c1-block-writes:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -466,8 +466,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 8000| 1|move |t |t |f |Copying Data colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 8000| 1|move |t |t |f |Copying Data
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 8000| 1|move |t |t |f |Copying Data colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 8000| 1|move |t |t |f |Copying Data
(2 rows) (2 rows)
step s5-release-advisory-lock: step s5-release-advisory-lock:
@ -487,7 +487,7 @@ citus_move_shard_placement
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -530,7 +530,7 @@ step s1-shard-move-c1-block-writes:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -551,8 +551,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 50000| 1|move |t |t |f |Copying Data colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 40000| 1|move |t |t |f |Copying Data
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 400000| 1|move |t |t |f |Copying Data colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 480000| 1|move |t |t |f |Copying Data
(2 rows) (2 rows)
step s6-release-advisory-lock: step s6-release-advisory-lock:
@ -572,7 +572,7 @@ citus_move_shard_placement
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -616,7 +616,7 @@ step s1-shard-copy-c1-block-writes:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -637,8 +637,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 8000| 1|copy |t |t |f |Copying Data colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 8000| 1|copy |t |t |f |Copying Data
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 8000| 1|copy |t |t |f |Copying Data colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 8000| 1|copy |t |t |f |Copying Data
(2 rows) (2 rows)
step s5-release-advisory-lock: step s5-release-advisory-lock:
@ -658,7 +658,7 @@ citus_copy_shard_placement
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -702,7 +702,7 @@ step s1-shard-copy-c1-block-writes:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -723,8 +723,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 50000| 1|copy |t |t |f |Copying Data colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 40000| 1|copy |t |t |f |Copying Data
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 400000| 1|copy |t |t |f |Copying Data colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 480000| 1|copy |t |t |f |Copying Data
(2 rows) (2 rows)
step s6-release-advisory-lock: step s6-release-advisory-lock:
@ -744,7 +744,7 @@ citus_copy_shard_placement
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -787,7 +787,7 @@ step s1-shard-move-c1-online:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -808,8 +808,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 8000| 1|move |t |t |f |Setting Up colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 8000| 1|move |t |t |f |Setting Up
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 8000| 1|move |t |t |f |Setting Up colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 8000| 1|move |t |t |f |Setting Up
(2 rows) (2 rows)
step s5-release-advisory-lock: step s5-release-advisory-lock:
@ -829,7 +829,7 @@ citus_move_shard_placement
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -872,7 +872,7 @@ step s1-shard-move-c1-online:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -893,8 +893,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 50000| 1|move |t |t |t |Final Catchup colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 40000| 1|move |t |t |t |Final Catchup
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 400000| 1|move |t |t |t |Final Catchup colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 480000| 1|move |t |t |t |Final Catchup
(2 rows) (2 rows)
step s6-release-advisory-lock: step s6-release-advisory-lock:
@ -914,7 +914,7 @@ citus_move_shard_placement
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -958,7 +958,7 @@ step s1-shard-copy-c1-online:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -979,8 +979,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 8000| 1|copy |t |t |f |Setting Up colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 8000| 1|copy |t |t |f |Setting Up
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 8000| 1|copy |t |t |f |Setting Up colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 8000| 1|copy |t |t |f |Setting Up
(2 rows) (2 rows)
step s5-release-advisory-lock: step s5-release-advisory-lock:
@ -1000,7 +1000,7 @@ citus_copy_shard_placement
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -1044,7 +1044,7 @@ step s1-shard-copy-c1-online:
<waiting ...> <waiting ...>
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -1065,8 +1065,8 @@ step s7-get-progress:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available|status
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 50000| 1|copy |t |t |t |Final Catchup colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 40000| 1|copy |t |t |t |Final Catchup
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 400000| 1|copy |t |t |t |Final Catchup colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 480000| 1|copy |t |t |t |Final Catchup
(2 rows) (2 rows)
step s6-release-advisory-lock: step s6-release-advisory-lock:
@ -1086,7 +1086,7 @@ citus_copy_shard_placement
step s1-wait: step s1-wait:
step s7-get-progress: step s7-get-progress:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -1132,7 +1132,7 @@ step s4-shard-move-sep-block-writes:
<waiting ...> <waiting ...>
step s7-get-progress-ordered: step s7-get-progress-ordered:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -1153,9 +1153,9 @@ step s7-get-progress-ordered:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 8000| 1|move |t |t |f colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 8000| 1|move |t |t |f
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 8000| 1|move |t |t |f colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 8000| 1|move |t |t |f
separate |1500009| 50000|localhost | 57637| 50000|localhost | 57638| 8000| 1|move |t |t |f separate |1500009| 200000|localhost | 57637| 200000|localhost | 57638| 8000| 1|move |t |t |f
(3 rows) (3 rows)
step s5-release-advisory-lock: step s5-release-advisory-lock:
@ -1182,7 +1182,7 @@ step s1-wait:
step s4-wait: step s4-wait:
step s7-get-progress-ordered: step s7-get-progress-ordered:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -1228,7 +1228,7 @@ step s4-shard-move-sep-block-writes:
<waiting ...> <waiting ...>
step s7-get-progress-ordered: step s7-get-progress-ordered:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -1249,9 +1249,9 @@ step s7-get-progress-ordered:
table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available table_name|shardid|shard_size|sourcename|sourceport|source_shard_size|targetname|targetport|target_shard_size|progress|operation_type|lsn_sanity_check|source_lsn_available|target_lsn_available
--------------------------------------------------------------------- ---------------------------------------------------------------------
colocated1|1500001| 50000|localhost | 57637| 50000|localhost | 57638| 50000| 1|move |t |t |f colocated1|1500001| 40000|localhost | 57637| 40000|localhost | 57638| 40000| 1|move |t |t |f
colocated2|1500005| 400000|localhost | 57637| 400000|localhost | 57638| 400000| 1|move |t |t |f colocated2|1500005| 480000|localhost | 57637| 480000|localhost | 57638| 480000| 1|move |t |t |f
separate |1500009| 50000|localhost | 57637| 50000|localhost | 57638| 200000| 1|move |t |t |f separate |1500009| 200000|localhost | 57637| 200000|localhost | 57638| 200000| 1|move |t |t |f
(3 rows) (3 rows)
step s6-release-advisory-lock: step s6-release-advisory-lock:
@ -1278,7 +1278,7 @@ step s1-wait:
step s4-wait: step s4-wait:
step s7-get-progress-ordered: step s7-get-progress-ordered:
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,

View File

@ -1393,6 +1393,284 @@ BEGIN;
ALTER SCHEMA bar RENAME TO foo; ALTER SCHEMA bar RENAME TO foo;
ROLLBACK; ROLLBACK;
-- below tests are to verify dependency propagation with nested sub-transactions
-- TEST1
BEGIN;
CREATE SCHEMA sc1;
CREATE SEQUENCE sc1.seq;
CREATE TABLE sc1.s1(id int default(nextval('sc1.seq')));
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to sequence sc1.seq
drop cascades to table sc1.s1
-- TEST2
CREATE SCHEMA sc1;
BEGIN;
CREATE SEQUENCE sc1.seq1;
CREATE TABLE sc1.s1(id int default(nextval('sc1.seq1')));
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to sequence sc1.seq1
drop cascades to table sc1.s1
-- TEST3
SET citus.enable_metadata_sync TO off;
CREATE SCHEMA sc1;
SET citus.enable_metadata_sync TO on;
BEGIN;
CREATE TABLE sc1.s1(id int);
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to table sc1.s1
-- TEST4
BEGIN;
SAVEPOINT sp1;
CREATE SCHEMA sc1;
ROLLBACK TO SAVEPOINT sp1;
SET LOCAL citus.enable_metadata_sync TO off;
CREATE SCHEMA sc1;
SET LOCAL citus.enable_metadata_sync TO on;
CREATE TABLE sc1.s1(id int);
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to table sc1.s1
-- TEST5
BEGIN;
SAVEPOINT sp1;
CREATE SCHEMA sc1;
RELEASE SAVEPOINT sp1;
CREATE SEQUENCE seq1;
CREATE TABLE sc1.s1(id int default(nextval('seq1')));
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to table sc1.s1
DROP SEQUENCE seq1;
-- TEST6
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc1;
ROLLBACK TO SAVEPOINT sp2;
RELEASE SAVEPOINT sp1;
SET LOCAL citus.enable_metadata_sync TO off;
CREATE SCHEMA sc1;
SET LOCAL citus.enable_metadata_sync TO on;
CREATE TABLE sc1.s1(id int);
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to table sc1.s1
-- TEST7
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc1;
RELEASE SAVEPOINT sp2;
RELEASE SAVEPOINT sp1;
CREATE SEQUENCE seq1;
CREATE TABLE sc1.s1(id int default(nextval('seq1')));
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to table sc1.s1
DROP SEQUENCE seq1;
-- TEST8
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc1;
RELEASE SAVEPOINT sp2;
ROLLBACK TO SAVEPOINT sp1;
SET LOCAL citus.enable_metadata_sync TO off;
CREATE SCHEMA sc1;
SET LOCAL citus.enable_metadata_sync TO on;
CREATE TABLE sc1.s1(id int);
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to table sc1.s1
-- TEST9
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc2;
ROLLBACK TO SAVEPOINT sp2;
SAVEPOINT sp3;
CREATE SCHEMA sc1;
RELEASE SAVEPOINT sp3;
RELEASE SAVEPOINT sp1;
CREATE SEQUENCE seq1;
CREATE TABLE sc1.s1(id int default(nextval('seq1')));
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to table sc1.s1
DROP SEQUENCE seq1;
-- TEST10
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc2;
RELEASE SAVEPOINT sp2;
SAVEPOINT sp3;
CREATE SCHEMA sc3;
SAVEPOINT sp4;
CREATE SCHEMA sc1;
ROLLBACK TO SAVEPOINT sp4;
RELEASE SAVEPOINT sp3;
RELEASE SAVEPOINT sp1;
SET LOCAL citus.enable_metadata_sync TO off;
CREATE SCHEMA sc1;
SET LOCAL citus.enable_metadata_sync TO on;
CREATE TABLE sc1.s1(id int);
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to table sc1.s1
DROP SCHEMA sc2 CASCADE;
DROP SCHEMA sc3 CASCADE;
-- TEST11
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc2;
RELEASE SAVEPOINT sp2;
SAVEPOINT sp3;
CREATE SCHEMA sc3;
SAVEPOINT sp4;
CREATE SCHEMA sc1;
RELEASE SAVEPOINT sp4;
RELEASE SAVEPOINT sp3;
RELEASE SAVEPOINT sp1;
CREATE SEQUENCE seq1;
CREATE TABLE sc1.s1(id int default(nextval('seq1')));
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to table sc1.s1
DROP SCHEMA sc2 CASCADE;
DROP SCHEMA sc3 CASCADE;
DROP SEQUENCE seq1;
-- TEST12
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc2;
RELEASE SAVEPOINT sp2;
SAVEPOINT sp3;
CREATE SCHEMA sc3;
SAVEPOINT sp4;
CREATE SEQUENCE seq1;
CREATE SCHEMA sc1;
CREATE TABLE sc1.s1(id int default(nextval('seq1')));
SELECT create_distributed_table('sc1.s1','id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
RELEASE SAVEPOINT sp4;
RELEASE SAVEPOINT sp3;
RELEASE SAVEPOINT sp1;
COMMIT;
DROP SCHEMA sc1 CASCADE;
NOTICE: drop cascades to table sc1.s1
DROP SCHEMA sc2 CASCADE;
DROP SCHEMA sc3 CASCADE;
DROP SEQUENCE seq1;
-- issue-6614
CREATE FUNCTION create_schema_test() RETURNS void AS $$
BEGIN
SET citus.create_object_propagation = 'deferred';
CREATE SCHEMA test_1;
CREATE TABLE test_1.test (
id bigserial constraint test_pk primary key,
creation_date timestamp constraint test_creation_date_df default timezone('UTC'::text, CURRENT_TIMESTAMP) not null
);
PERFORM create_reference_table('test_1.test');
RETURN;
END;
$$ LANGUAGE plpgsql;
SELECT create_schema_test();
create_schema_test
---------------------------------------------------------------------
(1 row)
SELECT result FROM run_command_on_all_nodes($$ SELECT COUNT(*) = 1 FROM pg_dist_partition WHERE logicalrelid = 'test_1.test'::regclass $$);
result
---------------------------------------------------------------------
t
t
t
(3 rows)
DROP FUNCTION create_schema_test;
DROP SCHEMA test_1 CASCADE;
NOTICE: drop cascades to 2 other objects
DETAIL: drop cascades to table test_1.test
drop cascades to table test_1.test_1197064
-- Clean up the created schema -- Clean up the created schema
SET client_min_messages TO WARNING; SET client_min_messages TO WARNING;
SELECT pg_identify_object_as_address(classid, objid, objsubid) FROM pg_catalog.pg_dist_object SELECT pg_identify_object_as_address(classid, objid, objsubid) FROM pg_catalog.pg_dist_object

View File

@ -314,6 +314,80 @@ SELECT result FROM run_command_on_workers
(2 rows) (2 rows)
SET search_path TO pg16; SET search_path TO pg16;
SET citus.next_shard_id TO 951000;
-- Foreign table TRUNCATE trigger
-- Relevant PG commit:
-- https://github.com/postgres/postgres/commit/3b00a94
SELECT 1 FROM citus_add_node('localhost', :master_port, groupid => 0);
?column?
---------------------------------------------------------------------
1
(1 row)
SET citus.use_citus_managed_tables TO ON;
CREATE TABLE foreign_table_test (id integer NOT NULL, data text, a bigserial);
INSERT INTO foreign_table_test VALUES (1, 'text_test');
CREATE EXTENSION postgres_fdw;
CREATE SERVER foreign_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'localhost', port :'master_port', dbname 'regression');
CREATE USER MAPPING FOR CURRENT_USER
SERVER foreign_server
OPTIONS (user 'postgres');
CREATE FOREIGN TABLE foreign_table (
id integer NOT NULL,
data text,
a bigserial
)
SERVER foreign_server
OPTIONS (schema_name 'pg16', table_name 'foreign_table_test');
-- verify it's a Citus foreign table
SELECT partmethod, repmodel FROM pg_dist_partition
WHERE logicalrelid = 'foreign_table'::regclass ORDER BY logicalrelid;
partmethod | repmodel
---------------------------------------------------------------------
n | s
(1 row)
INSERT INTO foreign_table VALUES (2, 'test_2');
INSERT INTO foreign_table_test VALUES (3, 'test_3');
CREATE FUNCTION trigger_func() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
RAISE NOTICE 'trigger_func(%) called: action = %, when = %, level = %',
TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL;
RETURN NULL;
END;$$;
CREATE FUNCTION trigger_func_on_shard() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
RAISE NOTICE 'trigger_func_on_shard(%) called: action = %, when = %, level = %',
TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL;
RETURN NULL;
END;$$;
CREATE TRIGGER trig_stmt_before BEFORE TRUNCATE ON foreign_table
FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
SET citus.override_table_visibility TO off;
CREATE TRIGGER trig_stmt_shard_before BEFORE TRUNCATE ON foreign_table_951001
FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func_on_shard();
RESET citus.override_table_visibility;
SELECT * FROM foreign_table ORDER BY 1;
id | data | a
---------------------------------------------------------------------
1 | text_test | 1
2 | test_2 | 1
3 | test_3 | 2
(3 rows)
TRUNCATE foreign_table;
NOTICE: trigger_func(<NULL>) called: action = TRUNCATE, when = BEFORE, level = STATEMENT
CONTEXT: PL/pgSQL function trigger_func() line XX at RAISE
NOTICE: trigger_func_on_shard(<NULL>) called: action = TRUNCATE, when = BEFORE, level = STATEMENT
CONTEXT: PL/pgSQL function trigger_func_on_shard() line XX at RAISE
SELECT * FROM foreign_table ORDER BY 1;
id | data | a
---------------------------------------------------------------------
(0 rows)
RESET citus.use_citus_managed_tables;
-- --
-- COPY FROM ... DEFAULT -- COPY FROM ... DEFAULT
-- Already supported in Citus, adding all PG tests with a distributed table -- Already supported in Citus, adding all PG tests with a distributed table
@ -676,6 +750,62 @@ SELECT result FROM run_command_on_workers
REINDEX REINDEX
(2 rows) (2 rows)
--
-- random_normal() to provide normally-distributed random numbers
-- adding here the same tests as the ones with random() in aggregate_support.sql
-- Relevant PG commit: https://github.com/postgres/postgres/commit/38d8176
--
CREATE TABLE dist_table (dist_col int, agg_col numeric);
SELECT create_distributed_table('dist_table', 'dist_col');
create_distributed_table
---------------------------------------------------------------------
(1 row)
CREATE TABLE ref_table (int_col int);
SELECT create_reference_table('ref_table');
create_reference_table
---------------------------------------------------------------------
(1 row)
-- Test the cases where the worker agg exec. returns no tuples.
SELECT PERCENTILE_DISC(.25) WITHIN GROUP (ORDER BY agg_col)
FROM (SELECT *, random_normal() FROM dist_table) a;
percentile_disc
---------------------------------------------------------------------
(1 row)
SELECT PERCENTILE_DISC((2 > random_normal(stddev => 1, mean => 0))::int::numeric / 10)
WITHIN GROUP (ORDER BY agg_col)
FROM dist_table
LEFT JOIN ref_table ON TRUE;
percentile_disc
---------------------------------------------------------------------
(1 row)
-- run the same queries after loading some data
INSERT INTO dist_table VALUES (2, 11.2), (3, NULL), (6, 3.22), (3, 4.23), (5, 5.25),
(4, 63.4), (75, NULL), (80, NULL), (96, NULL), (8, 1078), (0, 1.19);
SELECT PERCENTILE_DISC(.25) WITHIN GROUP (ORDER BY agg_col)
FROM (SELECT *, random_normal() FROM dist_table) a;
percentile_disc
---------------------------------------------------------------------
3.22
(1 row)
SELECT PERCENTILE_DISC((2 > random_normal(stddev => 1, mean => 0))::int::numeric / 10)
WITHIN GROUP (ORDER BY agg_col)
FROM dist_table
LEFT JOIN ref_table ON TRUE;
percentile_disc
---------------------------------------------------------------------
1.19
(1 row)
\set VERBOSITY terse \set VERBOSITY terse
SET client_min_messages TO ERROR; SET client_min_messages TO ERROR;
DROP EXTENSION postgres_fdw CASCADE;
DROP SCHEMA pg16 CASCADE; DROP SCHEMA pg16 CASCADE;

View File

@ -375,6 +375,158 @@ END;
CREATE PUBLICATION pubdep FOR TABLES IN SCHEMA deptest; CREATE PUBLICATION pubdep FOR TABLES IN SCHEMA deptest;
RESET citus.create_object_propagation; RESET citus.create_object_propagation;
DROP SCHEMA deptest CASCADE; DROP SCHEMA deptest CASCADE;
--
-- PG16 allows publications with schema and table of the same schema.
-- backpatched to PG15
-- Relevant PG commit: https://github.com/postgres/postgres/commit/13a185f
--
CREATE SCHEMA publication2;
CREATE TABLE publication2.test1 (id int);
SELECT create_distributed_table('publication2.test1', 'id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- should be able to create publication with schema and table of the same
-- schema
CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2, TABLE publication2.test1;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
c
---------------------------------------------------------------------
SELECT worker_create_or_replace_object('CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2, TABLE publication2.test1 WITH (publish_via_partition_root = ''false'', publish = ''insert, update, delete, truncate'')');
(1 row)
CREATE TABLE publication.test2 (id int);
SELECT create_distributed_table('publication.test2', 'id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER PUBLICATION testpub_for_tbl_schema ADD TABLE publication.test2;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
c
---------------------------------------------------------------------
SELECT worker_create_or_replace_object('CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2, TABLE publication2.test1, TABLE publication.test2 WITH (publish_via_partition_root = ''false'', publish = ''insert, update, delete, truncate'')');
(1 row)
-- should be able to have publication2 schema and its new table test2 in testpub_for_tbl_schema publication
ALTER TABLE test2 SET SCHEMA publication2;
-- should be able to add a table of the same schema to the schema publication
CREATE TABLE publication2.test3 (x int primary key, y int, "column-1" int);
SELECT create_distributed_table('publication2.test3', 'x');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER PUBLICATION testpub_for_tbl_schema ADD TABLE publication2.test3;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
c
---------------------------------------------------------------------
SELECT worker_create_or_replace_object('CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2, TABLE publication2.test1, TABLE publication2.test2, TABLE publication2.test3 WITH (publish_via_partition_root = ''false'', publish = ''insert, update, delete, truncate'')');
(1 row)
-- should be able to drop the table
ALTER PUBLICATION testpub_for_tbl_schema DROP TABLE publication2.test3;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
c
---------------------------------------------------------------------
SELECT worker_create_or_replace_object('CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2, TABLE publication2.test1, TABLE publication2.test2 WITH (publish_via_partition_root = ''false'', publish = ''insert, update, delete, truncate'')');
(1 row)
DROP PUBLICATION testpub_for_tbl_schema;
CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2;
-- should be able to set publication with schema and table of the same schema
ALTER PUBLICATION testpub_for_tbl_schema SET TABLES IN SCHEMA publication2, TABLE publication2.test1 WHERE (id < 99);
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
c
---------------------------------------------------------------------
SELECT worker_create_or_replace_object('CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2, TABLE publication2.test1 WHERE ((test1.id < 99)) WITH (publish_via_partition_root = ''false'', publish = ''insert, update, delete, truncate'')');
(1 row)
-- test that using column list for table is disallowed if any schemas are
-- part of the publication
DROP PUBLICATION testpub_for_tbl_schema;
-- failure - cannot use column list and schema together
CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2, TABLE publication2.test3(y);
ERROR: cannot use column list for relation "publication2.test3" in publication "testpub_for_tbl_schema"
DETAIL: Column lists cannot be specified in publications containing FOR TABLES IN SCHEMA elements.
-- ok - only publish schema
CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
c
---------------------------------------------------------------------
SELECT worker_create_or_replace_object('CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2 WITH (publish_via_partition_root = ''false'', publish = ''insert, update, delete, truncate'')');
(1 row)
-- failure - add a table with column list when there is already a schema in the
-- publication
ALTER PUBLICATION testpub_for_tbl_schema ADD TABLE publication2.test3(y);
ERROR: cannot use column list for relation "publication2.test3" in publication "testpub_for_tbl_schema"
DETAIL: Column lists cannot be specified in publications containing FOR TABLES IN SCHEMA elements.
-- ok - only publish table with column list
ALTER PUBLICATION testpub_for_tbl_schema SET TABLE publication2.test3(y);
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
c
---------------------------------------------------------------------
SELECT worker_create_or_replace_object('CREATE PUBLICATION testpub_for_tbl_schema FOR TABLE publication2.test3 (y) WITH (publish_via_partition_root = ''false'', publish = ''insert, update, delete, truncate'')');
(1 row)
-- failure - specify a schema when there is already a column list in the
-- publication
ALTER PUBLICATION testpub_for_tbl_schema ADD TABLES IN SCHEMA publication2;
ERROR: cannot add schema to publication "testpub_for_tbl_schema"
DETAIL: Schemas cannot be added if any tables that specify a column list are already part of the publication.
-- failure - cannot SET column list and schema together
ALTER PUBLICATION testpub_for_tbl_schema SET TABLES IN SCHEMA publication2, TABLE publication2.test3(y);
ERROR: cannot use column list for relation "publication2.test3" in publication "testpub_for_tbl_schema"
DETAIL: Column lists cannot be specified in publications containing FOR TABLES IN SCHEMA elements.
-- ok - drop table
ALTER PUBLICATION testpub_for_tbl_schema DROP TABLE publication2.test3;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
c
---------------------------------------------------------------------
SELECT worker_create_or_replace_object('CREATE PUBLICATION testpub_for_tbl_schema WITH (publish_via_partition_root = ''false'', publish = ''insert, update, delete, truncate'')');
(1 row)
-- failure - cannot ADD column list and schema together
ALTER PUBLICATION testpub_for_tbl_schema ADD TABLES IN SCHEMA publication2, TABLE publication2.test3(y);
ERROR: cannot use column list for relation "publication2.test3" in publication "testpub_for_tbl_schema"
DETAIL: Column lists cannot be specified in publications containing FOR TABLES IN SCHEMA elements.
-- make sure we can sync all the publication metadata -- make sure we can sync all the publication metadata
SELECT start_metadata_sync_to_all_nodes(); SELECT start_metadata_sync_to_all_nodes();
start_metadata_sync_to_all_nodes start_metadata_sync_to_all_nodes
@ -386,7 +538,9 @@ DROP PUBLICATION pubdep;
DROP PUBLICATION "pub-mix"; DROP PUBLICATION "pub-mix";
DROP PUBLICATION pubtables; DROP PUBLICATION pubtables;
DROP PUBLICATION pubpartitioned; DROP PUBLICATION pubpartitioned;
DROP PUBLICATION testpub_for_tbl_schema;
SET client_min_messages TO ERROR; SET client_min_messages TO ERROR;
DROP SCHEMA publication CASCADE; DROP SCHEMA publication CASCADE;
DROP SCHEMA "publication-1" CASCADE; DROP SCHEMA "publication-1" CASCADE;
DROP SCHEMA citus_schema_1 CASCADE; DROP SCHEMA citus_schema_1 CASCADE;
DROP SCHEMA publication2 CASCADE;

View File

@ -131,7 +131,7 @@ session "s7"
step "s7-get-progress" step "s7-get-progress"
{ {
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,
@ -157,7 +157,7 @@ step "s7-get-progress"
step "s7-get-progress-ordered" step "s7-get-progress-ordered"
{ {
set LOCAL client_min_messages=NOTICE; set LOCAL client_min_messages=NOTICE;
WITH possible_sizes(size) as (VALUES (0), (8000), (50000), (200000), (400000)) WITH possible_sizes(size) as (VALUES (0), (8000), (40000), (200000), (480000))
SELECT SELECT
table_name, table_name,
shardid, shardid,

View File

@ -487,3 +487,4 @@ DROP DOMAIN IF EXISTS domain_does_not_exist;
SET client_min_messages TO warning; SET client_min_messages TO warning;
DROP SCHEMA distributed_domain, distributed_domain_moved CASCADE; DROP SCHEMA distributed_domain, distributed_domain_moved CASCADE;
DROP ROLE domain_owner;

View File

@ -995,6 +995,219 @@ BEGIN;
ALTER SCHEMA bar RENAME TO foo; ALTER SCHEMA bar RENAME TO foo;
ROLLBACK; ROLLBACK;
-- below tests are to verify dependency propagation with nested sub-transactions
-- TEST1
BEGIN;
CREATE SCHEMA sc1;
CREATE SEQUENCE sc1.seq;
CREATE TABLE sc1.s1(id int default(nextval('sc1.seq')));
SELECT create_distributed_table('sc1.s1','id');
COMMIT;
DROP SCHEMA sc1 CASCADE;
-- TEST2
CREATE SCHEMA sc1;
BEGIN;
CREATE SEQUENCE sc1.seq1;
CREATE TABLE sc1.s1(id int default(nextval('sc1.seq1')));
SELECT create_distributed_table('sc1.s1','id');
COMMIT;
DROP SCHEMA sc1 CASCADE;
-- TEST3
SET citus.enable_metadata_sync TO off;
CREATE SCHEMA sc1;
SET citus.enable_metadata_sync TO on;
BEGIN;
CREATE TABLE sc1.s1(id int);
SELECT create_distributed_table('sc1.s1','id');
COMMIT;
DROP SCHEMA sc1 CASCADE;
-- TEST4
BEGIN;
SAVEPOINT sp1;
CREATE SCHEMA sc1;
ROLLBACK TO SAVEPOINT sp1;
SET LOCAL citus.enable_metadata_sync TO off;
CREATE SCHEMA sc1;
SET LOCAL citus.enable_metadata_sync TO on;
CREATE TABLE sc1.s1(id int);
SELECT create_distributed_table('sc1.s1','id');
COMMIT;
DROP SCHEMA sc1 CASCADE;
-- TEST5
BEGIN;
SAVEPOINT sp1;
CREATE SCHEMA sc1;
RELEASE SAVEPOINT sp1;
CREATE SEQUENCE seq1;
CREATE TABLE sc1.s1(id int default(nextval('seq1')));
SELECT create_distributed_table('sc1.s1','id');
COMMIT;
DROP SCHEMA sc1 CASCADE;
DROP SEQUENCE seq1;
-- TEST6
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc1;
ROLLBACK TO SAVEPOINT sp2;
RELEASE SAVEPOINT sp1;
SET LOCAL citus.enable_metadata_sync TO off;
CREATE SCHEMA sc1;
SET LOCAL citus.enable_metadata_sync TO on;
CREATE TABLE sc1.s1(id int);
SELECT create_distributed_table('sc1.s1','id');
COMMIT;
DROP SCHEMA sc1 CASCADE;
-- TEST7
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc1;
RELEASE SAVEPOINT sp2;
RELEASE SAVEPOINT sp1;
CREATE SEQUENCE seq1;
CREATE TABLE sc1.s1(id int default(nextval('seq1')));
SELECT create_distributed_table('sc1.s1','id');
COMMIT;
DROP SCHEMA sc1 CASCADE;
DROP SEQUENCE seq1;
-- TEST8
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc1;
RELEASE SAVEPOINT sp2;
ROLLBACK TO SAVEPOINT sp1;
SET LOCAL citus.enable_metadata_sync TO off;
CREATE SCHEMA sc1;
SET LOCAL citus.enable_metadata_sync TO on;
CREATE TABLE sc1.s1(id int);
SELECT create_distributed_table('sc1.s1','id');
COMMIT;
DROP SCHEMA sc1 CASCADE;
-- TEST9
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc2;
ROLLBACK TO SAVEPOINT sp2;
SAVEPOINT sp3;
CREATE SCHEMA sc1;
RELEASE SAVEPOINT sp3;
RELEASE SAVEPOINT sp1;
CREATE SEQUENCE seq1;
CREATE TABLE sc1.s1(id int default(nextval('seq1')));
SELECT create_distributed_table('sc1.s1','id');
COMMIT;
DROP SCHEMA sc1 CASCADE;
DROP SEQUENCE seq1;
-- TEST10
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc2;
RELEASE SAVEPOINT sp2;
SAVEPOINT sp3;
CREATE SCHEMA sc3;
SAVEPOINT sp4;
CREATE SCHEMA sc1;
ROLLBACK TO SAVEPOINT sp4;
RELEASE SAVEPOINT sp3;
RELEASE SAVEPOINT sp1;
SET LOCAL citus.enable_metadata_sync TO off;
CREATE SCHEMA sc1;
SET LOCAL citus.enable_metadata_sync TO on;
CREATE TABLE sc1.s1(id int);
SELECT create_distributed_table('sc1.s1','id');
COMMIT;
DROP SCHEMA sc1 CASCADE;
DROP SCHEMA sc2 CASCADE;
DROP SCHEMA sc3 CASCADE;
-- TEST11
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc2;
RELEASE SAVEPOINT sp2;
SAVEPOINT sp3;
CREATE SCHEMA sc3;
SAVEPOINT sp4;
CREATE SCHEMA sc1;
RELEASE SAVEPOINT sp4;
RELEASE SAVEPOINT sp3;
RELEASE SAVEPOINT sp1;
CREATE SEQUENCE seq1;
CREATE TABLE sc1.s1(id int default(nextval('seq1')));
SELECT create_distributed_table('sc1.s1','id');
COMMIT;
DROP SCHEMA sc1 CASCADE;
DROP SCHEMA sc2 CASCADE;
DROP SCHEMA sc3 CASCADE;
DROP SEQUENCE seq1;
-- TEST12
BEGIN;
SAVEPOINT sp1;
SAVEPOINT sp2;
CREATE SCHEMA sc2;
RELEASE SAVEPOINT sp2;
SAVEPOINT sp3;
CREATE SCHEMA sc3;
SAVEPOINT sp4;
CREATE SEQUENCE seq1;
CREATE SCHEMA sc1;
CREATE TABLE sc1.s1(id int default(nextval('seq1')));
SELECT create_distributed_table('sc1.s1','id');
RELEASE SAVEPOINT sp4;
RELEASE SAVEPOINT sp3;
RELEASE SAVEPOINT sp1;
COMMIT;
DROP SCHEMA sc1 CASCADE;
DROP SCHEMA sc2 CASCADE;
DROP SCHEMA sc3 CASCADE;
DROP SEQUENCE seq1;
-- issue-6614
CREATE FUNCTION create_schema_test() RETURNS void AS $$
BEGIN
SET citus.create_object_propagation = 'deferred';
CREATE SCHEMA test_1;
CREATE TABLE test_1.test (
id bigserial constraint test_pk primary key,
creation_date timestamp constraint test_creation_date_df default timezone('UTC'::text, CURRENT_TIMESTAMP) not null
);
PERFORM create_reference_table('test_1.test');
RETURN;
END;
$$ LANGUAGE plpgsql;
SELECT create_schema_test();
SELECT result FROM run_command_on_all_nodes($$ SELECT COUNT(*) = 1 FROM pg_dist_partition WHERE logicalrelid = 'test_1.test'::regclass $$);
DROP FUNCTION create_schema_test;
DROP SCHEMA test_1 CASCADE;
-- Clean up the created schema -- Clean up the created schema
SET client_min_messages TO WARNING; SET client_min_messages TO WARNING;

View File

@ -146,6 +146,63 @@ DROP DATABASE test_db;
SELECT result FROM run_command_on_workers SELECT result FROM run_command_on_workers
($$DROP DATABASE test_db$$); ($$DROP DATABASE test_db$$);
SET search_path TO pg16; SET search_path TO pg16;
SET citus.next_shard_id TO 951000;
-- Foreign table TRUNCATE trigger
-- Relevant PG commit:
-- https://github.com/postgres/postgres/commit/3b00a94
SELECT 1 FROM citus_add_node('localhost', :master_port, groupid => 0);
SET citus.use_citus_managed_tables TO ON;
CREATE TABLE foreign_table_test (id integer NOT NULL, data text, a bigserial);
INSERT INTO foreign_table_test VALUES (1, 'text_test');
CREATE EXTENSION postgres_fdw;
CREATE SERVER foreign_server
FOREIGN DATA WRAPPER postgres_fdw
OPTIONS (host 'localhost', port :'master_port', dbname 'regression');
CREATE USER MAPPING FOR CURRENT_USER
SERVER foreign_server
OPTIONS (user 'postgres');
CREATE FOREIGN TABLE foreign_table (
id integer NOT NULL,
data text,
a bigserial
)
SERVER foreign_server
OPTIONS (schema_name 'pg16', table_name 'foreign_table_test');
-- verify it's a Citus foreign table
SELECT partmethod, repmodel FROM pg_dist_partition
WHERE logicalrelid = 'foreign_table'::regclass ORDER BY logicalrelid;
INSERT INTO foreign_table VALUES (2, 'test_2');
INSERT INTO foreign_table_test VALUES (3, 'test_3');
CREATE FUNCTION trigger_func() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
RAISE NOTICE 'trigger_func(%) called: action = %, when = %, level = %',
TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL;
RETURN NULL;
END;$$;
CREATE FUNCTION trigger_func_on_shard() RETURNS trigger LANGUAGE plpgsql AS $$
BEGIN
RAISE NOTICE 'trigger_func_on_shard(%) called: action = %, when = %, level = %',
TG_ARGV[0], TG_OP, TG_WHEN, TG_LEVEL;
RETURN NULL;
END;$$;
CREATE TRIGGER trig_stmt_before BEFORE TRUNCATE ON foreign_table
FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func();
SET citus.override_table_visibility TO off;
CREATE TRIGGER trig_stmt_shard_before BEFORE TRUNCATE ON foreign_table_951001
FOR EACH STATEMENT EXECUTE PROCEDURE trigger_func_on_shard();
RESET citus.override_table_visibility;
SELECT * FROM foreign_table ORDER BY 1;
TRUNCATE foreign_table;
SELECT * FROM foreign_table ORDER BY 1;
RESET citus.use_citus_managed_tables;
-- --
-- COPY FROM ... DEFAULT -- COPY FROM ... DEFAULT
@ -388,6 +445,42 @@ REINDEX SYSTEM;
SELECT result FROM run_command_on_workers SELECT result FROM run_command_on_workers
($$REINDEX SYSTEM$$); ($$REINDEX SYSTEM$$);
--
-- random_normal() to provide normally-distributed random numbers
-- adding here the same tests as the ones with random() in aggregate_support.sql
-- Relevant PG commit: https://github.com/postgres/postgres/commit/38d8176
--
CREATE TABLE dist_table (dist_col int, agg_col numeric);
SELECT create_distributed_table('dist_table', 'dist_col');
CREATE TABLE ref_table (int_col int);
SELECT create_reference_table('ref_table');
-- Test the cases where the worker agg exec. returns no tuples.
SELECT PERCENTILE_DISC(.25) WITHIN GROUP (ORDER BY agg_col)
FROM (SELECT *, random_normal() FROM dist_table) a;
SELECT PERCENTILE_DISC((2 > random_normal(stddev => 1, mean => 0))::int::numeric / 10)
WITHIN GROUP (ORDER BY agg_col)
FROM dist_table
LEFT JOIN ref_table ON TRUE;
-- run the same queries after loading some data
INSERT INTO dist_table VALUES (2, 11.2), (3, NULL), (6, 3.22), (3, 4.23), (5, 5.25),
(4, 63.4), (75, NULL), (80, NULL), (96, NULL), (8, 1078), (0, 1.19);
SELECT PERCENTILE_DISC(.25) WITHIN GROUP (ORDER BY agg_col)
FROM (SELECT *, random_normal() FROM dist_table) a;
SELECT PERCENTILE_DISC((2 > random_normal(stddev => 1, mean => 0))::int::numeric / 10)
WITHIN GROUP (ORDER BY agg_col)
FROM dist_table
LEFT JOIN ref_table ON TRUE;
\set VERBOSITY terse \set VERBOSITY terse
SET client_min_messages TO ERROR; SET client_min_messages TO ERROR;
DROP EXTENSION postgres_fdw CASCADE;
DROP SCHEMA pg16 CASCADE; DROP SCHEMA pg16 CASCADE;

View File

@ -273,6 +273,110 @@ CREATE PUBLICATION pubdep FOR TABLES IN SCHEMA deptest;
RESET citus.create_object_propagation; RESET citus.create_object_propagation;
DROP SCHEMA deptest CASCADE; DROP SCHEMA deptest CASCADE;
--
-- PG16 allows publications with schema and table of the same schema.
-- backpatched to PG15
-- Relevant PG commit: https://github.com/postgres/postgres/commit/13a185f
--
CREATE SCHEMA publication2;
CREATE TABLE publication2.test1 (id int);
SELECT create_distributed_table('publication2.test1', 'id');
-- should be able to create publication with schema and table of the same
-- schema
CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2, TABLE publication2.test1;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
CREATE TABLE publication.test2 (id int);
SELECT create_distributed_table('publication.test2', 'id');
ALTER PUBLICATION testpub_for_tbl_schema ADD TABLE publication.test2;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
-- should be able to have publication2 schema and its new table test2 in testpub_for_tbl_schema publication
ALTER TABLE test2 SET SCHEMA publication2;
-- should be able to add a table of the same schema to the schema publication
CREATE TABLE publication2.test3 (x int primary key, y int, "column-1" int);
SELECT create_distributed_table('publication2.test3', 'x');
ALTER PUBLICATION testpub_for_tbl_schema ADD TABLE publication2.test3;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
-- should be able to drop the table
ALTER PUBLICATION testpub_for_tbl_schema DROP TABLE publication2.test3;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
DROP PUBLICATION testpub_for_tbl_schema;
CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2;
-- should be able to set publication with schema and table of the same schema
ALTER PUBLICATION testpub_for_tbl_schema SET TABLES IN SCHEMA publication2, TABLE publication2.test1 WHERE (id < 99);
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
-- test that using column list for table is disallowed if any schemas are
-- part of the publication
DROP PUBLICATION testpub_for_tbl_schema;
-- failure - cannot use column list and schema together
CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2, TABLE publication2.test3(y);
-- ok - only publish schema
CREATE PUBLICATION testpub_for_tbl_schema FOR TABLES IN SCHEMA publication2;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
-- failure - add a table with column list when there is already a schema in the
-- publication
ALTER PUBLICATION testpub_for_tbl_schema ADD TABLE publication2.test3(y);
-- ok - only publish table with column list
ALTER PUBLICATION testpub_for_tbl_schema SET TABLE publication2.test3(y);
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
-- failure - specify a schema when there is already a column list in the
-- publication
ALTER PUBLICATION testpub_for_tbl_schema ADD TABLES IN SCHEMA publication2;
-- failure - cannot SET column list and schema together
ALTER PUBLICATION testpub_for_tbl_schema SET TABLES IN SCHEMA publication2, TABLE publication2.test3(y);
-- ok - drop table
ALTER PUBLICATION testpub_for_tbl_schema DROP TABLE publication2.test3;
SELECT DISTINCT c FROM (
SELECT unnest(result::text[]) c
FROM run_command_on_workers($$
SELECT array_agg(c) FROM (SELECT c FROM unnest(activate_node_snapshot()) c WHERE c LIKE '%CREATE PUBLICATION%' AND c LIKE '%testpub_for_tbl_schema%' ORDER BY 1) s$$)
ORDER BY c) s;
-- failure - cannot ADD column list and schema together
ALTER PUBLICATION testpub_for_tbl_schema ADD TABLES IN SCHEMA publication2, TABLE publication2.test3(y);
-- make sure we can sync all the publication metadata -- make sure we can sync all the publication metadata
SELECT start_metadata_sync_to_all_nodes(); SELECT start_metadata_sync_to_all_nodes();
@ -280,8 +384,10 @@ DROP PUBLICATION pubdep;
DROP PUBLICATION "pub-mix"; DROP PUBLICATION "pub-mix";
DROP PUBLICATION pubtables; DROP PUBLICATION pubtables;
DROP PUBLICATION pubpartitioned; DROP PUBLICATION pubpartitioned;
DROP PUBLICATION testpub_for_tbl_schema;
SET client_min_messages TO ERROR; SET client_min_messages TO ERROR;
DROP SCHEMA publication CASCADE; DROP SCHEMA publication CASCADE;
DROP SCHEMA "publication-1" CASCADE; DROP SCHEMA "publication-1" CASCADE;
DROP SCHEMA citus_schema_1 CASCADE; DROP SCHEMA citus_schema_1 CASCADE;
DROP SCHEMA publication2 CASCADE;