mirror of https://github.com/citusdata/citus.git
PG11 compatibility update
- changes in ruleutils_11.c is reflected - vacuum statement api change is handled. We now allow multi-table vacuum commands. - some other function header changes are reflected - api conflicts between PG11 and earlier versions are handled by adding shims in version_compat.h - various regression tests are fixed due output and functionality in PG1 - no change is made to support new features in PG11 they need to be handled by new commitpull/2118/head
parent
49255213d4
commit
a6fe5ca183
|
@ -21,7 +21,9 @@
|
||||||
#include "catalog/dependency.h"
|
#include "catalog/dependency.h"
|
||||||
#include "catalog/index.h"
|
#include "catalog/index.h"
|
||||||
#include "catalog/pg_am.h"
|
#include "catalog/pg_am.h"
|
||||||
|
#if (PG_VERSION_NUM < 110000)
|
||||||
#include "catalog/pg_constraint_fn.h"
|
#include "catalog/pg_constraint_fn.h"
|
||||||
|
#endif
|
||||||
#include "catalog/pg_enum.h"
|
#include "catalog/pg_enum.h"
|
||||||
#include "catalog/pg_extension.h"
|
#include "catalog/pg_extension.h"
|
||||||
#include "catalog/pg_opclass.h"
|
#include "catalog/pg_opclass.h"
|
||||||
|
@ -1103,8 +1105,9 @@ CreateTruncateTrigger(Oid relationId)
|
||||||
trigger->whenClause = NULL;
|
trigger->whenClause = NULL;
|
||||||
trigger->isconstraint = false;
|
trigger->isconstraint = false;
|
||||||
|
|
||||||
CreateTrigger(trigger, NULL, relationId, InvalidOid, InvalidOid, InvalidOid,
|
CreateTriggerInternal(trigger, NULL, relationId, InvalidOid, InvalidOid, InvalidOid,
|
||||||
internal);
|
InvalidOid, InvalidOid, NULL,
|
||||||
|
internal, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -799,12 +799,13 @@ OpenCopyConnections(CopyStmt *copyStatement, ShardConnections *shardConnections,
|
||||||
List *connectionList = NULL;
|
List *connectionList = NULL;
|
||||||
int64 shardId = shardConnections->shardId;
|
int64 shardId = shardConnections->shardId;
|
||||||
bool raiseInterrupts = true;
|
bool raiseInterrupts = true;
|
||||||
|
MemoryContext localContext =
|
||||||
|
AllocSetContextCreateExtended(CurrentMemoryContext,
|
||||||
|
"OpenCopyConnections",
|
||||||
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
MemoryContext localContext = AllocSetContextCreate(CurrentMemoryContext,
|
|
||||||
"OpenCopyConnections",
|
|
||||||
ALLOCSET_DEFAULT_MINSIZE,
|
|
||||||
ALLOCSET_DEFAULT_INITSIZE,
|
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
|
||||||
|
|
||||||
/* release finalized placement list at the end of this function */
|
/* release finalized placement list at the end of this function */
|
||||||
MemoryContext oldContext = MemoryContextSwitchTo(localContext);
|
MemoryContext oldContext = MemoryContextSwitchTo(localContext);
|
||||||
|
@ -1280,8 +1281,24 @@ ConversionPathForTypes(Oid inputType, Oid destType, CopyCoercionData *result)
|
||||||
|
|
||||||
case COERCION_PATH_ARRAYCOERCE:
|
case COERCION_PATH_ARRAYCOERCE:
|
||||||
{
|
{
|
||||||
ereport(ERROR, (errmsg("can not run query which uses an implicit coercion"
|
Oid inputBaseType = get_base_element_type(inputType);
|
||||||
" between array types")));
|
Oid destBaseType = get_base_element_type(destType);
|
||||||
|
CoercionPathType baseCoercionType = COERCION_PATH_NONE;
|
||||||
|
|
||||||
|
if (inputBaseType != InvalidOid && destBaseType != InvalidOid)
|
||||||
|
{
|
||||||
|
baseCoercionType = find_coercion_pathway(inputBaseType, destBaseType,
|
||||||
|
COERCION_EXPLICIT,
|
||||||
|
&coercionFuncId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baseCoercionType != COERCION_PATH_COERCEVIAIO)
|
||||||
|
{
|
||||||
|
ereport(ERROR, (errmsg("can not run query which uses an implicit coercion"
|
||||||
|
" between array types")));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fallthrough */
|
||||||
}
|
}
|
||||||
|
|
||||||
case COERCION_PATH_COERCEVIAIO:
|
case COERCION_PATH_COERCEVIAIO:
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "distributed/metadata_cache.h"
|
#include "distributed/metadata_cache.h"
|
||||||
#include "distributed/hash_helpers.h"
|
#include "distributed/hash_helpers.h"
|
||||||
#include "distributed/placement_connection.h"
|
#include "distributed/placement_connection.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "utils/hsearch.h"
|
#include "utils/hsearch.h"
|
||||||
#include "utils/memutils.h"
|
#include "utils/memutils.h"
|
||||||
|
@ -58,10 +59,11 @@ InitializeConnectionManagement(void)
|
||||||
* management. Doing so, instead of allocating in TopMemoryContext, makes
|
* management. Doing so, instead of allocating in TopMemoryContext, makes
|
||||||
* it easier to associate used memory.
|
* it easier to associate used memory.
|
||||||
*/
|
*/
|
||||||
ConnectionContext = AllocSetContextCreate(TopMemoryContext, "Connection Context",
|
ConnectionContext = AllocSetContextCreateExtended(TopMemoryContext,
|
||||||
ALLOCSET_DEFAULT_MINSIZE,
|
"Connection Context",
|
||||||
ALLOCSET_DEFAULT_INITSIZE,
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
/* create (host,port,user,database) -> [connection] hash */
|
/* create (host,port,user,database) -> [connection] hash */
|
||||||
memset(&info, 0, sizeof(info));
|
memset(&info, 0, sizeof(info));
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
#include "distributed/remote_commands.h"
|
#include "distributed/remote_commands.h"
|
||||||
#include "distributed/remote_transaction.h"
|
#include "distributed/remote_transaction.h"
|
||||||
#include "distributed/resource_lock.h"
|
#include "distributed/resource_lock.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "executor/execdesc.h"
|
#include "executor/execdesc.h"
|
||||||
#include "executor/executor.h"
|
#include "executor/executor.h"
|
||||||
#include "executor/instrument.h"
|
#include "executor/instrument.h"
|
||||||
|
@ -1260,6 +1261,9 @@ SendQueryInSingleRowMode(MultiConnection *connection, char *query,
|
||||||
Oid *parameterTypes = NULL;
|
Oid *parameterTypes = NULL;
|
||||||
const char **parameterValues = NULL;
|
const char **parameterValues = NULL;
|
||||||
|
|
||||||
|
/* force evaluation of bound params */
|
||||||
|
paramListInfo = copyParamList(paramListInfo);
|
||||||
|
|
||||||
ExtractParametersFromParamListInfo(paramListInfo, ¶meterTypes,
|
ExtractParametersFromParamListInfo(paramListInfo, ¶meterTypes,
|
||||||
¶meterValues);
|
¶meterValues);
|
||||||
|
|
||||||
|
@ -1381,11 +1385,12 @@ StoreQueryResult(CitusScanState *scanState, MultiConnection *connection,
|
||||||
bool randomAccess = true;
|
bool randomAccess = true;
|
||||||
bool interTransactions = false;
|
bool interTransactions = false;
|
||||||
bool commandFailed = false;
|
bool commandFailed = false;
|
||||||
MemoryContext ioContext = AllocSetContextCreate(CurrentMemoryContext,
|
MemoryContext ioContext = AllocSetContextCreateExtended(CurrentMemoryContext,
|
||||||
"StoreQueryResult",
|
"StoreQueryResult",
|
||||||
ALLOCSET_DEFAULT_MINSIZE,
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
ALLOCSET_DEFAULT_INITSIZE,
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
*rows = 0;
|
*rows = 0;
|
||||||
|
|
||||||
if (scanState->tuplestorestate == NULL)
|
if (scanState->tuplestorestate == NULL)
|
||||||
|
|
|
@ -128,9 +128,10 @@ static Node * WorkerProcessAlterTableStmt(AlterTableStmt *alterTableStatement,
|
||||||
static List * PlanAlterObjectSchemaStmt(AlterObjectSchemaStmt *alterObjectSchemaStmt,
|
static List * PlanAlterObjectSchemaStmt(AlterObjectSchemaStmt *alterObjectSchemaStmt,
|
||||||
const char *alterObjectSchemaCommand);
|
const char *alterObjectSchemaCommand);
|
||||||
static void ProcessVacuumStmt(VacuumStmt *vacuumStmt, const char *vacuumCommand);
|
static void ProcessVacuumStmt(VacuumStmt *vacuumStmt, const char *vacuumCommand);
|
||||||
static bool IsSupportedDistributedVacuumStmt(Oid relationId, VacuumStmt *vacuumStmt);
|
static bool IsSupportedDistributedVacuumStmt(VacuumStmt *vacuumStmt,
|
||||||
static List * VacuumTaskList(Oid relationId, VacuumStmt *vacuumStmt);
|
List *vacuumRelationIdList);
|
||||||
static StringInfo DeparseVacuumStmtPrefix(VacuumStmt *vacuumStmt);
|
static List * VacuumTaskList(Oid relationId, int vacuumOptions, List *vacuumColumnList);
|
||||||
|
static StringInfo DeparseVacuumStmtPrefix(int vacuumFlags);
|
||||||
static char * DeparseVacuumColumnNames(List *columnNameList);
|
static char * DeparseVacuumColumnNames(List *columnNameList);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1162,8 +1163,7 @@ PlanDropIndexStmt(DropStmt *dropIndexStatement, const char *dropIndexCommand)
|
||||||
Oid relationId = InvalidOid;
|
Oid relationId = InvalidOid;
|
||||||
bool isDistributedRelation = false;
|
bool isDistributedRelation = false;
|
||||||
struct DropRelationCallbackState state;
|
struct DropRelationCallbackState state;
|
||||||
bool missingOK = true;
|
uint32 rvrFlags = RVR_MISSING_OK;
|
||||||
bool noWait = false;
|
|
||||||
LOCKMODE lockmode = AccessExclusiveLock;
|
LOCKMODE lockmode = AccessExclusiveLock;
|
||||||
|
|
||||||
List *objectNameList = (List *) lfirst(dropObjectCell);
|
List *objectNameList = (List *) lfirst(dropObjectCell);
|
||||||
|
@ -1188,8 +1188,9 @@ PlanDropIndexStmt(DropStmt *dropIndexStatement, const char *dropIndexCommand)
|
||||||
state.relkind = RELKIND_INDEX;
|
state.relkind = RELKIND_INDEX;
|
||||||
state.heapOid = InvalidOid;
|
state.heapOid = InvalidOid;
|
||||||
state.concurrent = dropIndexStatement->concurrent;
|
state.concurrent = dropIndexStatement->concurrent;
|
||||||
indexId = RangeVarGetRelidExtended(rangeVar, lockmode, missingOK,
|
|
||||||
noWait, RangeVarCallbackForDropIndex,
|
indexId = RangeVarGetRelidInternal(rangeVar, lockmode, rvrFlags,
|
||||||
|
RangeVarCallbackForDropIndex,
|
||||||
(void *) &state);
|
(void *) &state);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1568,17 +1569,15 @@ PlanAlterObjectSchemaStmt(AlterObjectSchemaStmt *alterObjectSchemaStmt,
|
||||||
const char *alterObjectSchemaCommand)
|
const char *alterObjectSchemaCommand)
|
||||||
{
|
{
|
||||||
Oid relationId = InvalidOid;
|
Oid relationId = InvalidOid;
|
||||||
bool noWait = false;
|
|
||||||
|
|
||||||
if (alterObjectSchemaStmt->relation == NULL)
|
if (alterObjectSchemaStmt->relation == NULL)
|
||||||
{
|
{
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
relationId = RangeVarGetRelidExtended(alterObjectSchemaStmt->relation,
|
relationId = RangeVarGetRelid(alterObjectSchemaStmt->relation,
|
||||||
AccessExclusiveLock,
|
AccessExclusiveLock,
|
||||||
alterObjectSchemaStmt->missing_ok,
|
alterObjectSchemaStmt->missing_ok);
|
||||||
noWait, NULL, NULL);
|
|
||||||
|
|
||||||
/* first check whether a distributed relation is affected */
|
/* first check whether a distributed relation is affected */
|
||||||
if (!OidIsValid(relationId) || !IsDistributedTable(relationId))
|
if (!OidIsValid(relationId) || !IsDistributedTable(relationId))
|
||||||
|
@ -1609,73 +1608,107 @@ PlanAlterObjectSchemaStmt(AlterObjectSchemaStmt *alterObjectSchemaStmt,
|
||||||
static void
|
static void
|
||||||
ProcessVacuumStmt(VacuumStmt *vacuumStmt, const char *vacuumCommand)
|
ProcessVacuumStmt(VacuumStmt *vacuumStmt, const char *vacuumCommand)
|
||||||
{
|
{
|
||||||
Oid relationId = InvalidOid;
|
int relationIndex = 0;
|
||||||
List *taskList = NIL;
|
|
||||||
bool supportedVacuumStmt = false;
|
bool supportedVacuumStmt = false;
|
||||||
|
List *vacuumRelationList = ExtractVacuumTargetRels(vacuumStmt);
|
||||||
|
ListCell *vacuumRelationCell = NULL;
|
||||||
|
List *relationIdList = NIL;
|
||||||
|
ListCell *relationIdCell = NULL;
|
||||||
|
LOCKMODE lockMode = (vacuumStmt->options & VACOPT_FULL) ? AccessExclusiveLock :
|
||||||
|
ShareUpdateExclusiveLock;
|
||||||
|
int executedVacuumCount = 0;
|
||||||
|
|
||||||
if (vacuumStmt->relation != NULL)
|
foreach(vacuumRelationCell, vacuumRelationList)
|
||||||
{
|
{
|
||||||
LOCKMODE lockMode = (vacuumStmt->options & VACOPT_FULL) ?
|
RangeVar *vacuumRelation = (RangeVar *) lfirst(vacuumRelationCell);
|
||||||
AccessExclusiveLock : ShareUpdateExclusiveLock;
|
Oid relationId = RangeVarGetRelid(vacuumRelation, lockMode, false);
|
||||||
|
relationIdList = lappend_oid(relationIdList, relationId);
|
||||||
relationId = RangeVarGetRelid(vacuumStmt->relation, lockMode, false);
|
|
||||||
|
|
||||||
if (relationId == InvalidOid)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
supportedVacuumStmt = IsSupportedDistributedVacuumStmt(relationId, vacuumStmt);
|
supportedVacuumStmt = IsSupportedDistributedVacuumStmt(vacuumStmt, relationIdList);
|
||||||
if (!supportedVacuumStmt)
|
if (!supportedVacuumStmt)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
taskList = VacuumTaskList(relationId, vacuumStmt);
|
/* execute vacuum on distributed tables */
|
||||||
|
foreach(relationIdCell, relationIdList)
|
||||||
/*
|
|
||||||
* VACUUM commands cannot run inside a transaction block, so we use
|
|
||||||
* the "bare" commit protocol without BEGIN/COMMIT. However, ANALYZE
|
|
||||||
* commands can run inside a transaction block.
|
|
||||||
*/
|
|
||||||
if ((vacuumStmt->options & VACOPT_VACUUM) != 0)
|
|
||||||
{
|
{
|
||||||
/* save old commit protocol to restore at xact end */
|
Oid relationId = lfirst_oid(relationIdCell);
|
||||||
Assert(SavedMultiShardCommitProtocol == COMMIT_PROTOCOL_BARE);
|
if (IsDistributedTable(relationId))
|
||||||
SavedMultiShardCommitProtocol = MultiShardCommitProtocol;
|
{
|
||||||
MultiShardCommitProtocol = COMMIT_PROTOCOL_BARE;
|
List *vacuumColumnList = NIL;
|
||||||
}
|
List *taskList = NIL;
|
||||||
|
|
||||||
ExecuteModifyTasksWithoutResults(taskList);
|
/*
|
||||||
|
* VACUUM commands cannot run inside a transaction block, so we use
|
||||||
|
* the "bare" commit protocol without BEGIN/COMMIT. However, ANALYZE
|
||||||
|
* commands can run inside a transaction block. Notice that we do this
|
||||||
|
* once even if there are multiple distributed tables to be vacuumed.
|
||||||
|
*/
|
||||||
|
if (executedVacuumCount == 0 && (vacuumStmt->options & VACOPT_VACUUM) != 0)
|
||||||
|
{
|
||||||
|
/* save old commit protocol to restore at xact end */
|
||||||
|
Assert(SavedMultiShardCommitProtocol == COMMIT_PROTOCOL_BARE);
|
||||||
|
SavedMultiShardCommitProtocol = MultiShardCommitProtocol;
|
||||||
|
MultiShardCommitProtocol = COMMIT_PROTOCOL_BARE;
|
||||||
|
}
|
||||||
|
|
||||||
|
vacuumColumnList = VacuumColumnList(vacuumStmt, relationIndex);
|
||||||
|
taskList = VacuumTaskList(relationId, vacuumStmt->options, vacuumColumnList);
|
||||||
|
|
||||||
|
ExecuteModifyTasksWithoutResults(taskList);
|
||||||
|
|
||||||
|
executedVacuumCount++;
|
||||||
|
}
|
||||||
|
relationIndex++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* IsSupportedDistributedVacuumStmt returns whether distributed execution of a
|
* IsSupportedDistributedVacuumStmt returns whether distributed execution of a
|
||||||
* given VacuumStmt is supported. The provided relationId (if valid) represents
|
* given VacuumStmt is supported. The provided relationId list represents
|
||||||
* the table targeted by the provided statement.
|
* the list of tables targeted by the provided statement.
|
||||||
*
|
*
|
||||||
* Returns true if the statement requires distributed execution and returns
|
* Returns true if the statement requires distributed execution and returns
|
||||||
* false otherwise; however, this function will raise errors if the provided
|
* false otherwise; however, this function will raise errors if the provided
|
||||||
* statement needs distributed execution but contains unsupported options.
|
* statement needs distributed execution but contains unsupported options.
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
IsSupportedDistributedVacuumStmt(Oid relationId, VacuumStmt *vacuumStmt)
|
IsSupportedDistributedVacuumStmt(VacuumStmt *vacuumStmt, List *vacuumRelationIdList)
|
||||||
{
|
{
|
||||||
const char *stmtName = (vacuumStmt->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
|
const char *stmtName = (vacuumStmt->options & VACOPT_VACUUM) ? "VACUUM" : "ANALYZE";
|
||||||
bool distributeStmt = false;
|
bool distributeStmt = false;
|
||||||
|
ListCell *relationIdCell = NULL;
|
||||||
|
int distributedRelationCount = 0;
|
||||||
|
int vacuumedRelationCount = 0;
|
||||||
|
|
||||||
if (vacuumStmt->relation == NULL)
|
/*
|
||||||
|
* No table in the vacuum statement means vacuuming all relations
|
||||||
|
* which is not supported by citus.
|
||||||
|
*/
|
||||||
|
vacuumedRelationCount = list_length(vacuumRelationIdList);
|
||||||
|
if (vacuumedRelationCount == 0)
|
||||||
{
|
{
|
||||||
/* WARN for unqualified VACUUM commands */
|
/* WARN for unqualified VACUUM commands */
|
||||||
ereport(WARNING, (errmsg("not propagating %s command to worker nodes", stmtName),
|
ereport(WARNING, (errmsg("not propagating %s command to worker nodes", stmtName),
|
||||||
errhint("Provide a specific table in order to %s "
|
errhint("Provide a specific table in order to %s "
|
||||||
"distributed tables.", stmtName)));
|
"distributed tables.", stmtName)));
|
||||||
}
|
}
|
||||||
else if (!OidIsValid(relationId) || !IsDistributedTable(relationId))
|
|
||||||
|
foreach(relationIdCell, vacuumRelationIdList)
|
||||||
{
|
{
|
||||||
/* Nothing to do here; relation no longer exists or is not distributed */
|
Oid relationId = lfirst_oid(relationIdCell);
|
||||||
|
if (OidIsValid(relationId) && IsDistributedTable(relationId))
|
||||||
|
{
|
||||||
|
distributedRelationCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (distributedRelationCount == 0)
|
||||||
|
{
|
||||||
|
/* nothing to do here */
|
||||||
}
|
}
|
||||||
else if (!EnableDDLPropagation)
|
else if (!EnableDDLPropagation)
|
||||||
{
|
{
|
||||||
|
@ -1705,20 +1738,22 @@ IsSupportedDistributedVacuumStmt(Oid relationId, VacuumStmt *vacuumStmt)
|
||||||
* a VacuumStmt which targets a distributed relation.
|
* a VacuumStmt which targets a distributed relation.
|
||||||
*/
|
*/
|
||||||
static List *
|
static List *
|
||||||
VacuumTaskList(Oid relationId, VacuumStmt *vacuumStmt)
|
VacuumTaskList(Oid relationId, int vacuumOptions, List *vacuumColumnList)
|
||||||
{
|
{
|
||||||
List *taskList = NIL;
|
List *taskList = NIL;
|
||||||
List *shardIntervalList = NIL;
|
List *shardIntervalList = NIL;
|
||||||
ListCell *shardIntervalCell = NULL;
|
ListCell *shardIntervalCell = NULL;
|
||||||
uint64 jobId = INVALID_JOB_ID;
|
uint64 jobId = INVALID_JOB_ID;
|
||||||
int taskId = 1;
|
int taskId = 1;
|
||||||
StringInfo vacuumString = DeparseVacuumStmtPrefix(vacuumStmt);
|
StringInfo vacuumString = DeparseVacuumStmtPrefix(vacuumOptions);
|
||||||
const char *columnNames = DeparseVacuumColumnNames(vacuumStmt->va_cols);
|
const char *columnNames = NULL;
|
||||||
const int vacuumPrefixLen = vacuumString->len;
|
const int vacuumPrefixLen = vacuumString->len;
|
||||||
Oid schemaId = get_rel_namespace(relationId);
|
Oid schemaId = get_rel_namespace(relationId);
|
||||||
char *schemaName = get_namespace_name(schemaId);
|
char *schemaName = get_namespace_name(schemaId);
|
||||||
char *tableName = get_rel_name(relationId);
|
char *tableName = get_rel_name(relationId);
|
||||||
|
|
||||||
|
columnNames = DeparseVacuumColumnNames(vacuumColumnList);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We obtain ShareUpdateExclusiveLock here to not conflict with INSERT's
|
* We obtain ShareUpdateExclusiveLock here to not conflict with INSERT's
|
||||||
* RowExclusiveLock. However if VACUUM FULL is used, we already obtain
|
* RowExclusiveLock. However if VACUUM FULL is used, we already obtain
|
||||||
|
@ -1770,10 +1805,9 @@ VacuumTaskList(Oid relationId, VacuumStmt *vacuumStmt)
|
||||||
* statements.
|
* statements.
|
||||||
*/
|
*/
|
||||||
static StringInfo
|
static StringInfo
|
||||||
DeparseVacuumStmtPrefix(VacuumStmt *vacuumStmt)
|
DeparseVacuumStmtPrefix(int vacuumFlags)
|
||||||
{
|
{
|
||||||
StringInfo vacuumPrefix = makeStringInfo();
|
StringInfo vacuumPrefix = makeStringInfo();
|
||||||
int vacuumFlags = vacuumStmt->options;
|
|
||||||
const int unsupportedFlags PG_USED_FOR_ASSERTS_ONLY = ~(
|
const int unsupportedFlags PG_USED_FOR_ASSERTS_ONLY = ~(
|
||||||
VACOPT_ANALYZE |
|
VACOPT_ANALYZE |
|
||||||
VACOPT_DISABLE_PAGE_SKIPPING |
|
VACOPT_DISABLE_PAGE_SKIPPING |
|
||||||
|
@ -2433,7 +2467,7 @@ ErrorIfUnsupportedConstraint(Relation relation, char distributionMethod,
|
||||||
}
|
}
|
||||||
|
|
||||||
attributeCount = indexInfo->ii_NumIndexAttrs;
|
attributeCount = indexInfo->ii_NumIndexAttrs;
|
||||||
attributeNumberArray = indexInfo->ii_KeyAttrNumbers;
|
attributeNumberArray = IndexInfoAttributeNumberArray(indexInfo);
|
||||||
|
|
||||||
for (attributeIndex = 0; attributeIndex < attributeCount; attributeIndex++)
|
for (attributeIndex = 0; attributeIndex < attributeCount; attributeIndex++)
|
||||||
{
|
{
|
||||||
|
@ -3390,8 +3424,9 @@ RangeVarCallbackForDropIndex(const RangeVar *rel, Oid relOid, Oid oldRelOid, voi
|
||||||
/* Allow DROP to either table owner or schema owner */
|
/* Allow DROP to either table owner or schema owner */
|
||||||
if (!pg_class_ownercheck(relOid, GetUserId()) &&
|
if (!pg_class_ownercheck(relOid, GetUserId()) &&
|
||||||
!pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
|
!pg_namespace_ownercheck(classform->relnamespace, GetUserId()))
|
||||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
|
{
|
||||||
rel->relname);
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACLCHECK_OBJECT_INDEX, rel->relname);
|
||||||
|
}
|
||||||
|
|
||||||
if (!allowSystemTableMods && IsSystemClass(relOid, classform))
|
if (!allowSystemTableMods && IsSystemClass(relOid, classform))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
|
@ -3657,7 +3692,7 @@ PlanGrantStmt(GrantStmt *grantStmt)
|
||||||
* grants aren't interesting anyway.
|
* grants aren't interesting anyway.
|
||||||
*/
|
*/
|
||||||
if (grantStmt->targtype != ACL_TARGET_OBJECT ||
|
if (grantStmt->targtype != ACL_TARGET_OBJECT ||
|
||||||
grantStmt->objtype != ACL_OBJECT_RELATION)
|
grantStmt->objtype != RELATION_OBJECT_TYPE)
|
||||||
{
|
{
|
||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "distributed/remote_commands.h"
|
#include "distributed/remote_commands.h"
|
||||||
#include "distributed/worker_manager.h"
|
#include "distributed/worker_manager.h"
|
||||||
#include "distributed/worker_protocol.h"
|
#include "distributed/worker_protocol.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "parser/scansup.h"
|
#include "parser/scansup.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
|
@ -1278,8 +1279,7 @@ EnsureTablePermissions(Oid relationId, AclMode mode)
|
||||||
|
|
||||||
if (aclresult != ACLCHECK_OK)
|
if (aclresult != ACLCHECK_OK)
|
||||||
{
|
{
|
||||||
aclcheck_error(aclresult, ACL_KIND_CLASS,
|
aclcheck_error(aclresult, ACLCHECK_OBJECT_TABLE, get_rel_name(relationId));
|
||||||
get_rel_name(relationId));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1293,7 +1293,7 @@ EnsureTableOwner(Oid relationId)
|
||||||
{
|
{
|
||||||
if (!pg_class_ownercheck(relationId, GetUserId()))
|
if (!pg_class_ownercheck(relationId, GetUserId()))
|
||||||
{
|
{
|
||||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACLCHECK_OBJECT_TABLE,
|
||||||
get_rel_name(relationId));
|
get_rel_name(relationId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,9 @@
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
#include "catalog/pg_class.h"
|
#include "catalog/pg_class.h"
|
||||||
#include "catalog/pg_constraint.h"
|
#include "catalog/pg_constraint.h"
|
||||||
|
#if (PG_VERSION_NUM < 110000)
|
||||||
#include "catalog/pg_constraint_fn.h"
|
#include "catalog/pg_constraint_fn.h"
|
||||||
|
#endif
|
||||||
#include "catalog/pg_index.h"
|
#include "catalog/pg_index.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "catalog/pg_namespace.h"
|
#include "catalog/pg_namespace.h"
|
||||||
|
|
|
@ -44,6 +44,7 @@
|
||||||
#include "distributed/transaction_management.h"
|
#include "distributed/transaction_management.h"
|
||||||
#include "distributed/worker_manager.h"
|
#include "distributed/worker_manager.h"
|
||||||
#include "distributed/worker_protocol.h"
|
#include "distributed/worker_protocol.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
|
@ -860,8 +861,8 @@ WorkerShardStats(ShardPlacement *placement, Oid relationId, char *shardName,
|
||||||
|
|
||||||
/* fill in the partition column name and shard name in the query. */
|
/* fill in the partition column name and shard name in the query. */
|
||||||
partitionColumn = PartitionColumn(relationId, unusedTableId);
|
partitionColumn = PartitionColumn(relationId, unusedTableId);
|
||||||
partitionColumnName = get_attname(relationId, partitionColumn->varattno);
|
partitionColumnName = get_attname_internal(relationId, partitionColumn->varattno,
|
||||||
|
false);
|
||||||
appendStringInfo(partitionValueQuery, SHARD_RANGE_QUERY,
|
appendStringInfo(partitionValueQuery, SHARD_RANGE_QUERY,
|
||||||
partitionColumnName, partitionColumnName, shardName);
|
partitionColumnName, partitionColumnName, shardName);
|
||||||
|
|
||||||
|
|
|
@ -92,10 +92,9 @@ start_metadata_sync_to_node(PG_FUNCTION_ARGS)
|
||||||
EnsureModificationsCanRun();
|
EnsureModificationsCanRun();
|
||||||
CheckCitusVersion(ERROR);
|
CheckCitusVersion(ERROR);
|
||||||
|
|
||||||
PreventTransactionChain(true, "start_metadata_sync_to_node");
|
PreventInTransactionBlock(true, "start_metadata_sync_to_node");
|
||||||
|
|
||||||
workerNode = FindWorkerNode(nodeNameString, nodePort);
|
workerNode = FindWorkerNode(nodeNameString, nodePort);
|
||||||
|
|
||||||
if (workerNode == NULL)
|
if (workerNode == NULL)
|
||||||
{
|
{
|
||||||
ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
||||||
|
|
|
@ -639,6 +639,9 @@ CreateDistributedSelectPlan(uint64 planId, Query *originalQuery, Query *query,
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* force evaluation of bound params */
|
||||||
|
boundParams = copyParamList(boundParams);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If there are parameters that do have a value in boundParams, replace
|
* If there are parameters that do have a value in boundParams, replace
|
||||||
* them in the original query. This allows us to more easily cut the
|
* them in the original query. This allows us to more easily cut the
|
||||||
|
@ -1464,14 +1467,22 @@ HasUnresolvedExternParamsWalker(Node *expression, ParamListInfo boundParams)
|
||||||
if (boundParams && paramId > 0 && paramId <= boundParams->numParams)
|
if (boundParams && paramId > 0 && paramId <= boundParams->numParams)
|
||||||
{
|
{
|
||||||
ParamExternData *externParam = &boundParams->params[paramId - 1];
|
ParamExternData *externParam = &boundParams->params[paramId - 1];
|
||||||
|
Oid paramType = externParam->ptype;
|
||||||
|
|
||||||
/* give hook a chance in case parameter is dynamic */
|
/* give hook a chance in case parameter is dynamic */
|
||||||
if (!OidIsValid(externParam->ptype) && boundParams->paramFetch != NULL)
|
if (!OidIsValid(paramType) && boundParams->paramFetch != NULL)
|
||||||
{
|
{
|
||||||
|
#if (PG_VERSION_NUM >= 110000)
|
||||||
|
ParamExternData externParamPlaceholder;
|
||||||
|
externParam = (*boundParams->paramFetch)(boundParams, paramId, false,
|
||||||
|
&externParamPlaceholder);
|
||||||
|
#else
|
||||||
(*boundParams->paramFetch)(boundParams, paramId);
|
(*boundParams->paramFetch)(boundParams, paramId);
|
||||||
|
#endif
|
||||||
|
paramType = externParam->ptype;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (OidIsValid(externParam->ptype))
|
if (OidIsValid(paramType))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1142,6 +1142,7 @@ CreateCoordinatorInsertSelectPlan(Query *parse)
|
||||||
|
|
||||||
/* copy CTEs from the INSERT ... SELECT statement into outer SELECT */
|
/* copy CTEs from the INSERT ... SELECT statement into outer SELECT */
|
||||||
selectQuery->cteList = copyObject(insertSelectQuery->cteList);
|
selectQuery->cteList = copyObject(insertSelectQuery->cteList);
|
||||||
|
selectQuery->hasModifyingCTE = insertSelectQuery->hasModifyingCTE;
|
||||||
}
|
}
|
||||||
else if (selectQuery->setOperations != NULL)
|
else if (selectQuery->setOperations != NULL)
|
||||||
{
|
{
|
||||||
|
|
|
@ -36,6 +36,7 @@
|
||||||
#include "distributed/recursive_planning.h"
|
#include "distributed/recursive_planning.h"
|
||||||
#include "distributed/placement_connection.h"
|
#include "distributed/placement_connection.h"
|
||||||
#include "distributed/worker_protocol.h"
|
#include "distributed/worker_protocol.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#include "nodes/plannodes.h"
|
#include "nodes/plannodes.h"
|
||||||
#include "nodes/primnodes.h"
|
#include "nodes/primnodes.h"
|
||||||
|
@ -241,7 +242,7 @@ ExplainJob(Job *job, ExplainState *es)
|
||||||
|
|
||||||
ExplainOpenGroup("Job", "Job", true, es);
|
ExplainOpenGroup("Job", "Job", true, es);
|
||||||
|
|
||||||
ExplainPropertyInteger("Task Count", taskCount, es);
|
ExplainPropertyIntegerInternal("Task Count", NULL, taskCount, es);
|
||||||
|
|
||||||
if (dependedJobCount > 0)
|
if (dependedJobCount > 0)
|
||||||
{
|
{
|
||||||
|
@ -317,9 +318,8 @@ ExplainMapMergeJob(MapMergeJob *mapMergeJob, ExplainState *es)
|
||||||
}
|
}
|
||||||
|
|
||||||
ExplainOpenGroup("MapMergeJob", NULL, true, es);
|
ExplainOpenGroup("MapMergeJob", NULL, true, es);
|
||||||
|
ExplainPropertyIntegerInternal("Map Task Count", NULL, mapTaskCount, es);
|
||||||
ExplainPropertyInteger("Map Task Count", mapTaskCount, es);
|
ExplainPropertyIntegerInternal("Merge Task Count", NULL, mergeTaskCount, es);
|
||||||
ExplainPropertyInteger("Merge Task Count", mergeTaskCount, es);
|
|
||||||
|
|
||||||
if (dependedJobCount > 0)
|
if (dependedJobCount > 0)
|
||||||
{
|
{
|
||||||
|
@ -662,7 +662,10 @@ ExplainOneQuery(Query *query, IntoClause *into, ExplainState *es,
|
||||||
{
|
{
|
||||||
/* if an advisor plugin is present, let it manage things */
|
/* if an advisor plugin is present, let it manage things */
|
||||||
if (ExplainOneQuery_hook)
|
if (ExplainOneQuery_hook)
|
||||||
#if (PG_VERSION_NUM >= 100000)
|
#if (PG_VERSION_NUM >= 110000)
|
||||||
|
(*ExplainOneQuery_hook) (query, cursorOptions, into, es,
|
||||||
|
queryString, params, queryEnv);
|
||||||
|
#elif (PG_VERSION_NUM >= 100000)
|
||||||
(*ExplainOneQuery_hook) (query, cursorOptions, into, es,
|
(*ExplainOneQuery_hook) (query, cursorOptions, into, es,
|
||||||
queryString, params);
|
queryString, params);
|
||||||
#else
|
#else
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "distributed/relation_restriction_equivalence.h"
|
#include "distributed/relation_restriction_equivalence.h"
|
||||||
#include "distributed/multi_router_planner.h"
|
#include "distributed/multi_router_planner.h"
|
||||||
#include "distributed/worker_protocol.h"
|
#include "distributed/worker_protocol.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "nodes/nodeFuncs.h"
|
#include "nodes/nodeFuncs.h"
|
||||||
#include "nodes/relation.h"
|
#include "nodes/relation.h"
|
||||||
|
@ -2706,7 +2707,8 @@ ExtractFromExpressionWalker(Node *node, QualifierWalkerContext *walkerContext)
|
||||||
{
|
{
|
||||||
/* this part of code only run for subqueries */
|
/* this part of code only run for subqueries */
|
||||||
Node *joinClause = eval_const_expressions(NULL, joinQualifiersNode);
|
Node *joinClause = eval_const_expressions(NULL, joinQualifiersNode);
|
||||||
joinClause = (Node *) canonicalize_qual((Expr *) joinClause);
|
joinClause = (Node *) canonicalize_qual_compat((Expr *) joinClause,
|
||||||
|
false);
|
||||||
joinQualifierList = make_ands_implicit((Expr *) joinClause);
|
joinQualifierList = make_ands_implicit((Expr *) joinClause);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2739,7 +2741,8 @@ ExtractFromExpressionWalker(Node *node, QualifierWalkerContext *walkerContext)
|
||||||
{
|
{
|
||||||
/* this part of code only run for subqueries */
|
/* this part of code only run for subqueries */
|
||||||
Node *fromClause = eval_const_expressions(NULL, fromQualifiersNode);
|
Node *fromClause = eval_const_expressions(NULL, fromQualifiersNode);
|
||||||
fromClause = (Node *) canonicalize_qual((Expr *) fromClause);
|
fromClause = (Node *) canonicalize_qual_compat((Expr *) fromClause,
|
||||||
|
false);
|
||||||
fromQualifierList = make_ands_implicit((Expr *) fromClause);
|
fromQualifierList = make_ands_implicit((Expr *) fromClause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -47,6 +47,7 @@
|
||||||
#include "distributed/task_tracker.h"
|
#include "distributed/task_tracker.h"
|
||||||
#include "distributed/worker_manager.h"
|
#include "distributed/worker_manager.h"
|
||||||
#include "distributed/worker_protocol.h"
|
#include "distributed/worker_protocol.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "nodes/nodeFuncs.h"
|
#include "nodes/nodeFuncs.h"
|
||||||
#include "optimizer/clauses.h"
|
#include "optimizer/clauses.h"
|
||||||
|
@ -4234,7 +4235,7 @@ ColumnName(Var *column, List *rangeTableList)
|
||||||
else if (rangeTableKind == CITUS_RTE_RELATION)
|
else if (rangeTableKind == CITUS_RTE_RELATION)
|
||||||
{
|
{
|
||||||
Oid relationId = rangeTableEntry->relid;
|
Oid relationId = rangeTableEntry->relid;
|
||||||
columnName = get_attname(relationId, columnNumber);
|
columnName = get_attname_internal(relationId, columnNumber, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Assert(columnName != NULL);
|
Assert(columnName != NULL);
|
||||||
|
|
|
@ -31,6 +31,7 @@
|
||||||
#include "catalog/pg_constraint.h"
|
#include "catalog/pg_constraint.h"
|
||||||
#include "distributed/metadata_cache.h"
|
#include "distributed/metadata_cache.h"
|
||||||
#include "distributed/relay_utility.h"
|
#include "distributed/relay_utility.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "nodes/nodes.h"
|
#include "nodes/nodes.h"
|
||||||
|
@ -289,9 +290,8 @@ RelayEventExtendNames(Node *parseTree, char *schemaName, uint64 shardId)
|
||||||
case T_GrantStmt:
|
case T_GrantStmt:
|
||||||
{
|
{
|
||||||
GrantStmt *grantStmt = (GrantStmt *) parseTree;
|
GrantStmt *grantStmt = (GrantStmt *) parseTree;
|
||||||
|
|
||||||
if (grantStmt->targtype == ACL_TARGET_OBJECT &&
|
if (grantStmt->targtype == ACL_TARGET_OBJECT &&
|
||||||
grantStmt->objtype == ACL_OBJECT_RELATION)
|
grantStmt->objtype == RELATION_OBJECT_TYPE)
|
||||||
{
|
{
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@
|
||||||
#include "distributed/remote_commands.h"
|
#include "distributed/remote_commands.h"
|
||||||
#include "distributed/transaction_recovery.h"
|
#include "distributed/transaction_recovery.h"
|
||||||
#include "distributed/worker_manager.h"
|
#include "distributed/worker_manager.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#include "storage/lmgr.h"
|
#include "storage/lmgr.h"
|
||||||
#include "storage/lock.h"
|
#include "storage/lock.h"
|
||||||
|
@ -176,11 +177,12 @@ RecoverWorkerTransactions(WorkerNode *workerNode)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
localContext = AllocSetContextCreate(CurrentMemoryContext,
|
localContext = AllocSetContextCreateExtended(CurrentMemoryContext,
|
||||||
"RecoverWorkerTransactions",
|
"RecoverWorkerTransactions",
|
||||||
ALLOCSET_DEFAULT_MINSIZE,
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
ALLOCSET_DEFAULT_INITSIZE,
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
oldContext = MemoryContextSwitchTo(localContext);
|
oldContext = MemoryContextSwitchTo(localContext);
|
||||||
|
|
||||||
/* take table lock first to avoid running concurrently */
|
/* take table lock first to avoid running concurrently */
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
#include "access/htup_details.h"
|
#include "access/htup_details.h"
|
||||||
#include "distributed/distribution_column.h"
|
#include "distributed/distribution_column.h"
|
||||||
#include "distributed/metadata_cache.h"
|
#include "distributed/metadata_cache.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "nodes/nodes.h"
|
#include "nodes/nodes.h"
|
||||||
#include "nodes/primnodes.h"
|
#include "nodes/primnodes.h"
|
||||||
|
@ -205,7 +206,7 @@ ColumnNameToColumn(Oid relationId, char *columnNodeString)
|
||||||
columnNumber, relationName)));
|
columnNumber, relationName)));
|
||||||
}
|
}
|
||||||
|
|
||||||
columnName = get_attname(relationId, column->varattno);
|
columnName = get_attname_internal(relationId, column->varattno, false);
|
||||||
if (columnName == NULL)
|
if (columnName == NULL)
|
||||||
{
|
{
|
||||||
char *relationName = get_rel_name(relationId);
|
char *relationName = get_rel_name(relationId);
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "distributed/metadata_cache.h"
|
#include "distributed/metadata_cache.h"
|
||||||
#include "distributed/statistics_collection.h"
|
#include "distributed/statistics_collection.h"
|
||||||
#include "distributed/transaction_recovery.h"
|
#include "distributed/transaction_recovery.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "postmaster/bgworker.h"
|
#include "postmaster/bgworker.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
|
@ -276,7 +277,7 @@ CitusMaintenanceDaemonMain(Datum main_arg)
|
||||||
databaseOid, myDbData->userOid);
|
databaseOid, myDbData->userOid);
|
||||||
|
|
||||||
/* connect to database, after that we can actually access catalogs */
|
/* connect to database, after that we can actually access catalogs */
|
||||||
BackgroundWorkerInitializeConnectionByOid(databaseOid, myDbData->userOid);
|
BackgroundWorkerInitializeConnectionByOid(databaseOid, myDbData->userOid, 0);
|
||||||
|
|
||||||
/* make worker recognizable in pg_stat_activity */
|
/* make worker recognizable in pg_stat_activity */
|
||||||
pgstat_report_appname("Citus Maintenance Daemon");
|
pgstat_report_appname("Citus Maintenance Daemon");
|
||||||
|
|
|
@ -15,7 +15,9 @@
|
||||||
#endif
|
#endif
|
||||||
#include "catalog/pg_class.h"
|
#include "catalog/pg_class.h"
|
||||||
#include "catalog/pg_inherits.h"
|
#include "catalog/pg_inherits.h"
|
||||||
#include "catalog/pg_inherits_fn.h"
|
#if (PG_VERSION_NUM < 110000)
|
||||||
|
#include "catalog/pg_constraint_fn.h"
|
||||||
|
#endif
|
||||||
#include "distributed/citus_ruleutils.h"
|
#include "distributed/citus_ruleutils.h"
|
||||||
#include "distributed/multi_partitioning_utils.h"
|
#include "distributed/multi_partitioning_utils.h"
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
|
@ -23,6 +25,7 @@
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
|
#include "utils/rel.h"
|
||||||
#include "utils/syscache.h"
|
#include "utils/syscache.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -96,13 +96,13 @@
|
||||||
#define PRETTYINDENT_LIMIT 40 /* wrap limit */
|
#define PRETTYINDENT_LIMIT 40 /* wrap limit */
|
||||||
|
|
||||||
/* Pretty flags */
|
/* Pretty flags */
|
||||||
#define PRETTYFLAG_PAREN 1
|
#define PRETTYFLAG_PAREN 0x0001
|
||||||
#define PRETTYFLAG_INDENT 2
|
#define PRETTYFLAG_INDENT 0x0002
|
||||||
|
|
||||||
/* Default line length for pretty-print wrapping: 0 means wrap always */
|
/* Default line length for pretty-print wrapping: 0 means wrap always */
|
||||||
#define WRAP_COLUMN_DEFAULT 0
|
#define WRAP_COLUMN_DEFAULT 0
|
||||||
|
|
||||||
/* macro to test if pretty action needed */
|
/* macros to test if pretty action needed */
|
||||||
#define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
|
#define PRETTY_PAREN(context) ((context)->prettyFlags & PRETTYFLAG_PAREN)
|
||||||
#define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
|
#define PRETTY_INDENT(context) ((context)->prettyFlags & PRETTYFLAG_INDENT)
|
||||||
|
|
||||||
|
@ -122,7 +122,7 @@ typedef struct
|
||||||
int prettyFlags; /* enabling of pretty-print functions */
|
int prettyFlags; /* enabling of pretty-print functions */
|
||||||
int wrapColumn; /* max line length, or -1 for no limit */
|
int wrapColumn; /* max line length, or -1 for no limit */
|
||||||
int indentLevel; /* current indent level for prettyprint */
|
int indentLevel; /* current indent level for prettyprint */
|
||||||
bool varprefix; /* TRUE to print prefixes on Vars */
|
bool varprefix; /* true to print prefixes on Vars */
|
||||||
Oid distrelid; /* the distributed table being modified, if valid */
|
Oid distrelid; /* the distributed table being modified, if valid */
|
||||||
int64 shardid; /* a distributed table's shardid, if positive */
|
int64 shardid; /* a distributed table's shardid, if positive */
|
||||||
ParseExprKind special_exprkind; /* set only for exprkinds needing special
|
ParseExprKind special_exprkind; /* set only for exprkinds needing special
|
||||||
|
@ -142,7 +142,7 @@ typedef struct
|
||||||
* rtable_columns holds the column alias names to be used for each RTE.
|
* rtable_columns holds the column alias names to be used for each RTE.
|
||||||
*
|
*
|
||||||
* In some cases we need to make names of merged JOIN USING columns unique
|
* In some cases we need to make names of merged JOIN USING columns unique
|
||||||
* across the whole query, not only per-RTE. If so, unique_using is TRUE
|
* across the whole query, not only per-RTE. If so, unique_using is true
|
||||||
* and using_names is a list of C strings representing names already assigned
|
* and using_names is a list of C strings representing names already assigned
|
||||||
* to USING columns.
|
* to USING columns.
|
||||||
*
|
*
|
||||||
|
@ -317,7 +317,7 @@ static void set_relation_column_names(deparse_namespace *dpns,
|
||||||
deparse_columns *colinfo);
|
deparse_columns *colinfo);
|
||||||
static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
|
static void set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
|
||||||
deparse_columns *colinfo);
|
deparse_columns *colinfo);
|
||||||
static bool colname_is_unique(char *colname, deparse_namespace *dpns,
|
static bool colname_is_unique(const char *colname, deparse_namespace *dpns,
|
||||||
deparse_columns *colinfo);
|
deparse_columns *colinfo);
|
||||||
static char *make_colname_unique(char *colname, deparse_namespace *dpns,
|
static char *make_colname_unique(char *colname, deparse_namespace *dpns,
|
||||||
deparse_columns *colinfo);
|
deparse_columns *colinfo);
|
||||||
|
@ -824,7 +824,7 @@ set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
|
||||||
* If there's a USING clause, select the USING column names and push
|
* If there's a USING clause, select the USING column names and push
|
||||||
* those names down to the children. We have two strategies:
|
* those names down to the children. We have two strategies:
|
||||||
*
|
*
|
||||||
* If dpns->unique_using is TRUE, we force all USING names to be
|
* If dpns->unique_using is true, we force all USING names to be
|
||||||
* unique across the whole query level. In principle we'd only need
|
* unique across the whole query level. In principle we'd only need
|
||||||
* the names of dangerous USING columns to be globally unique, but to
|
* the names of dangerous USING columns to be globally unique, but to
|
||||||
* safely assign all USING names in a single pass, we have to enforce
|
* safely assign all USING names in a single pass, we have to enforce
|
||||||
|
@ -837,7 +837,7 @@ set_using_names(deparse_namespace *dpns, Node *jtnode, List *parentUsing)
|
||||||
* this simplifies the logic and seems likely to lead to less aliasing
|
* this simplifies the logic and seems likely to lead to less aliasing
|
||||||
* overall.
|
* overall.
|
||||||
*
|
*
|
||||||
* If dpns->unique_using is FALSE, we only need USING names to be
|
* If dpns->unique_using is false, we only need USING names to be
|
||||||
* unique within their own join RTE. We still need to honor
|
* unique within their own join RTE. We still need to honor
|
||||||
* pushed-down names, though.
|
* pushed-down names, though.
|
||||||
*
|
*
|
||||||
|
@ -1350,7 +1350,7 @@ set_join_column_names(deparse_namespace *dpns, RangeTblEntry *rte,
|
||||||
* dpns is query-wide info, colinfo is for the column's RTE
|
* dpns is query-wide info, colinfo is for the column's RTE
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
colname_is_unique(char *colname, deparse_namespace *dpns,
|
colname_is_unique(const char *colname, deparse_namespace *dpns,
|
||||||
deparse_columns *colinfo)
|
deparse_columns *colinfo)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -2194,7 +2194,7 @@ get_simple_values_rte(Query *query)
|
||||||
ListCell *lc;
|
ListCell *lc;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We want to return TRUE even if the Query also contains OLD or NEW rule
|
* We want to return true even if the Query also contains OLD or NEW rule
|
||||||
* RTEs. So the idea is to scan the rtable and see if there is only one
|
* RTEs. So the idea is to scan the rtable and see if there is only one
|
||||||
* inFromCl RTE that is a VALUES RTE.
|
* inFromCl RTE that is a VALUES RTE.
|
||||||
*/
|
*/
|
||||||
|
@ -2891,6 +2891,8 @@ get_rule_windowspec(WindowClause *wc, List *targetList,
|
||||||
appendStringInfoString(buf, "RANGE ");
|
appendStringInfoString(buf, "RANGE ");
|
||||||
else if (wc->frameOptions & FRAMEOPTION_ROWS)
|
else if (wc->frameOptions & FRAMEOPTION_ROWS)
|
||||||
appendStringInfoString(buf, "ROWS ");
|
appendStringInfoString(buf, "ROWS ");
|
||||||
|
else if (wc->frameOptions & FRAMEOPTION_GROUPS)
|
||||||
|
appendStringInfoString(buf, "GROUPS ");
|
||||||
else
|
else
|
||||||
Assert(false);
|
Assert(false);
|
||||||
if (wc->frameOptions & FRAMEOPTION_BETWEEN)
|
if (wc->frameOptions & FRAMEOPTION_BETWEEN)
|
||||||
|
@ -2899,12 +2901,12 @@ get_rule_windowspec(WindowClause *wc, List *targetList,
|
||||||
appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
|
appendStringInfoString(buf, "UNBOUNDED PRECEDING ");
|
||||||
else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
|
else if (wc->frameOptions & FRAMEOPTION_START_CURRENT_ROW)
|
||||||
appendStringInfoString(buf, "CURRENT ROW ");
|
appendStringInfoString(buf, "CURRENT ROW ");
|
||||||
else if (wc->frameOptions & FRAMEOPTION_START_VALUE)
|
else if (wc->frameOptions & FRAMEOPTION_START_OFFSET)
|
||||||
{
|
{
|
||||||
get_rule_expr(wc->startOffset, context, false);
|
get_rule_expr(wc->startOffset, context, false);
|
||||||
if (wc->frameOptions & FRAMEOPTION_START_VALUE_PRECEDING)
|
if (wc->frameOptions & FRAMEOPTION_START_OFFSET_PRECEDING)
|
||||||
appendStringInfoString(buf, " PRECEDING ");
|
appendStringInfoString(buf, " PRECEDING ");
|
||||||
else if (wc->frameOptions & FRAMEOPTION_START_VALUE_FOLLOWING)
|
else if (wc->frameOptions & FRAMEOPTION_START_OFFSET_FOLLOWING)
|
||||||
appendStringInfoString(buf, " FOLLOWING ");
|
appendStringInfoString(buf, " FOLLOWING ");
|
||||||
else
|
else
|
||||||
Assert(false);
|
Assert(false);
|
||||||
|
@ -2918,12 +2920,12 @@ get_rule_windowspec(WindowClause *wc, List *targetList,
|
||||||
appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
|
appendStringInfoString(buf, "UNBOUNDED FOLLOWING ");
|
||||||
else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
|
else if (wc->frameOptions & FRAMEOPTION_END_CURRENT_ROW)
|
||||||
appendStringInfoString(buf, "CURRENT ROW ");
|
appendStringInfoString(buf, "CURRENT ROW ");
|
||||||
else if (wc->frameOptions & FRAMEOPTION_END_VALUE)
|
else if (wc->frameOptions & FRAMEOPTION_END_OFFSET)
|
||||||
{
|
{
|
||||||
get_rule_expr(wc->endOffset, context, false);
|
get_rule_expr(wc->endOffset, context, false);
|
||||||
if (wc->frameOptions & FRAMEOPTION_END_VALUE_PRECEDING)
|
if (wc->frameOptions & FRAMEOPTION_END_OFFSET_PRECEDING)
|
||||||
appendStringInfoString(buf, " PRECEDING ");
|
appendStringInfoString(buf, " PRECEDING ");
|
||||||
else if (wc->frameOptions & FRAMEOPTION_END_VALUE_FOLLOWING)
|
else if (wc->frameOptions & FRAMEOPTION_END_OFFSET_FOLLOWING)
|
||||||
appendStringInfoString(buf, " FOLLOWING ");
|
appendStringInfoString(buf, " FOLLOWING ");
|
||||||
else
|
else
|
||||||
Assert(false);
|
Assert(false);
|
||||||
|
@ -2931,6 +2933,12 @@ get_rule_windowspec(WindowClause *wc, List *targetList,
|
||||||
else
|
else
|
||||||
Assert(false);
|
Assert(false);
|
||||||
}
|
}
|
||||||
|
if (wc->frameOptions & FRAMEOPTION_EXCLUDE_CURRENT_ROW)
|
||||||
|
appendStringInfoString(buf, "EXCLUDE CURRENT ROW ");
|
||||||
|
else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_GROUP)
|
||||||
|
appendStringInfoString(buf, "EXCLUDE GROUP ");
|
||||||
|
else if (wc->frameOptions & FRAMEOPTION_EXCLUDE_TIES)
|
||||||
|
appendStringInfoString(buf, "EXCLUDE TIES ");
|
||||||
/* we will now have a trailing space; remove it */
|
/* we will now have a trailing space; remove it */
|
||||||
buf->len--;
|
buf->len--;
|
||||||
}
|
}
|
||||||
|
@ -3023,8 +3031,9 @@ get_insert_query_def(Query *query, deparse_context *context)
|
||||||
* tle->resname, since resname will fail to track RENAME.
|
* tle->resname, since resname will fail to track RENAME.
|
||||||
*/
|
*/
|
||||||
appendStringInfoString(buf,
|
appendStringInfoString(buf,
|
||||||
quote_identifier(get_relid_attribute_name(rte->relid,
|
quote_identifier(get_attname(rte->relid,
|
||||||
tle->resno)));
|
tle->resno,
|
||||||
|
false)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print any indirection needed (subfields or subscripts), and strip
|
* Print any indirection needed (subfields or subscripts), and strip
|
||||||
|
@ -3358,8 +3367,9 @@ get_update_query_targetlist_def(Query *query, List *targetList,
|
||||||
* tle->resname, since resname will fail to track RENAME.
|
* tle->resname, since resname will fail to track RENAME.
|
||||||
*/
|
*/
|
||||||
appendStringInfoString(buf,
|
appendStringInfoString(buf,
|
||||||
quote_identifier(get_relid_attribute_name(rte->relid,
|
quote_identifier(get_attname(rte->relid,
|
||||||
tle->resno)));
|
tle->resno,
|
||||||
|
false)));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Print any indirection needed (subfields or subscripts), and strip
|
* Print any indirection needed (subfields or subscripts), and strip
|
||||||
|
@ -3536,7 +3546,7 @@ get_utility_query_def(Query *query, deparse_context *context)
|
||||||
* the Var's varlevelsup has to be interpreted with respect to a context
|
* the Var's varlevelsup has to be interpreted with respect to a context
|
||||||
* above the current one; levelsup indicates the offset.
|
* above the current one; levelsup indicates the offset.
|
||||||
*
|
*
|
||||||
* If istoplevel is TRUE, the Var is at the top level of a SELECT's
|
* If istoplevel is true, the Var is at the top level of a SELECT's
|
||||||
* targetlist, which means we need special treatment of whole-row Vars.
|
* targetlist, which means we need special treatment of whole-row Vars.
|
||||||
* Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
|
* Instead of the normal "tab.*", we'll print "tab.*::typename", which is a
|
||||||
* dirty hack to prevent "tab.*" from being expanded into multiple columns.
|
* dirty hack to prevent "tab.*" from being expanded into multiple columns.
|
||||||
|
@ -3681,7 +3691,7 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
|
||||||
else if (GetRangeTblKind(rte) == CITUS_RTE_SHARD)
|
else if (GetRangeTblKind(rte) == CITUS_RTE_SHARD)
|
||||||
{
|
{
|
||||||
/* System column on a Citus shard */
|
/* System column on a Citus shard */
|
||||||
attname = get_relid_attribute_name(rte->relid, attnum);
|
attname = get_attname(rte->relid, attnum, false);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -3869,17 +3879,12 @@ get_name_for_var_field(Var *var, int fieldno,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If it's a Var of type RECORD, we have to find what the Var refers to;
|
* If it's a Var of type RECORD, we have to find what the Var refers to;
|
||||||
* if not, we can use get_expr_result_type. If that fails, we try
|
* if not, we can use get_expr_result_tupdesc().
|
||||||
* lookup_rowtype_tupdesc, which will probably fail too, but will ereport
|
|
||||||
* an acceptable message.
|
|
||||||
*/
|
*/
|
||||||
if (!IsA(var, Var) ||
|
if (!IsA(var, Var) ||
|
||||||
var->vartype != RECORDOID)
|
var->vartype != RECORDOID)
|
||||||
{
|
{
|
||||||
if (get_expr_result_type((Node *) var, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
|
tupleDesc = get_expr_result_tupdesc((Node *) var, false);
|
||||||
tupleDesc = lookup_rowtype_tupdesc_copy(exprType((Node *) var),
|
|
||||||
exprTypmod((Node *) var));
|
|
||||||
Assert(tupleDesc);
|
|
||||||
/* Got the tupdesc, so we can extract the field name */
|
/* Got the tupdesc, so we can extract the field name */
|
||||||
Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
|
Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
|
||||||
return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
|
return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
|
||||||
|
@ -4182,14 +4187,9 @@ get_name_for_var_field(Var *var, int fieldno,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We now have an expression we can't expand any more, so see if
|
* We now have an expression we can't expand any more, so see if
|
||||||
* get_expr_result_type() can do anything with it. If not, pass to
|
* get_expr_result_tupdesc() can do anything with it.
|
||||||
* lookup_rowtype_tupdesc() which will probably fail, but will give an
|
|
||||||
* appropriate error message while failing.
|
|
||||||
*/
|
*/
|
||||||
if (get_expr_result_type(expr, NULL, &tupleDesc) != TYPEFUNC_COMPOSITE)
|
tupleDesc = get_expr_result_tupdesc(expr, false);
|
||||||
tupleDesc = lookup_rowtype_tupdesc_copy(exprType(expr),
|
|
||||||
exprTypmod(expr));
|
|
||||||
Assert(tupleDesc);
|
|
||||||
/* Got the tupdesc, so we can extract the field name */
|
/* Got the tupdesc, so we can extract the field name */
|
||||||
Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
|
Assert(fieldno >= 1 && fieldno <= tupleDesc->natts);
|
||||||
return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
|
return NameStr(TupleDescAttr(tupleDesc, fieldno - 1)->attname);
|
||||||
|
@ -5838,8 +5838,23 @@ get_rule_expr(Node *node, deparse_context *context,
|
||||||
ListCell *cell;
|
ListCell *cell;
|
||||||
char *sep;
|
char *sep;
|
||||||
|
|
||||||
|
if (spec->is_default)
|
||||||
|
{
|
||||||
|
appendStringInfoString(buf, "DEFAULT");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
switch (spec->strategy)
|
switch (spec->strategy)
|
||||||
{
|
{
|
||||||
|
case PARTITION_STRATEGY_HASH:
|
||||||
|
Assert(spec->modulus > 0 && spec->remainder >= 0);
|
||||||
|
Assert(spec->modulus > spec->remainder);
|
||||||
|
|
||||||
|
appendStringInfoString(buf, "FOR VALUES");
|
||||||
|
appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
|
||||||
|
spec->modulus, spec->remainder);
|
||||||
|
break;
|
||||||
|
|
||||||
case PARTITION_STRATEGY_LIST:
|
case PARTITION_STRATEGY_LIST:
|
||||||
Assert(spec->listdatums != NIL);
|
Assert(spec->listdatums != NIL);
|
||||||
|
|
||||||
|
@ -7461,8 +7476,8 @@ processIndirection(Node *node, deparse_context *context)
|
||||||
* target lists, but this function cannot be used for that case.
|
* target lists, but this function cannot be used for that case.
|
||||||
*/
|
*/
|
||||||
Assert(list_length(fstore->fieldnums) == 1);
|
Assert(list_length(fstore->fieldnums) == 1);
|
||||||
fieldname = get_relid_attribute_name(typrelid,
|
fieldname = get_attname(typrelid,
|
||||||
linitial_int(fstore->fieldnums));
|
linitial_int(fstore->fieldnums), false);
|
||||||
appendStringInfo(buf, ".%s", quote_identifier(fieldname));
|
appendStringInfo(buf, ".%s", quote_identifier(fieldname));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -7688,7 +7703,7 @@ generate_fragment_name(char *schemaName, char *tableName)
|
||||||
* means a FuncExpr or Aggref, not some other way of calling a function), then
|
* means a FuncExpr or Aggref, not some other way of calling a function), then
|
||||||
* has_variadic must specify whether variadic arguments have been merged,
|
* has_variadic must specify whether variadic arguments have been merged,
|
||||||
* and *use_variadic_p will be set to indicate whether to print VARIADIC in
|
* and *use_variadic_p will be set to indicate whether to print VARIADIC in
|
||||||
* the output. For non-FuncExpr cases, has_variadic should be FALSE and
|
* the output. For non-FuncExpr cases, has_variadic should be false and
|
||||||
* use_variadic_p can be NULL.
|
* use_variadic_p can be NULL.
|
||||||
*
|
*
|
||||||
* The result includes all necessary quoting and schema-prefixing.
|
* The result includes all necessary quoting and schema-prefixing.
|
||||||
|
|
|
@ -43,6 +43,7 @@ typedef struct utsname
|
||||||
#include "distributed/shardinterval_utils.h"
|
#include "distributed/shardinterval_utils.h"
|
||||||
#include "distributed/statistics_collection.h"
|
#include "distributed/statistics_collection.h"
|
||||||
#include "distributed/worker_manager.h"
|
#include "distributed/worker_manager.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/json.h"
|
#include "utils/json.h"
|
||||||
|
@ -249,7 +250,7 @@ CheckForUpdatesCallback(char *contents, size_t size, size_t count, void *userDat
|
||||||
{
|
{
|
||||||
Datum responseCStringDatum = CStringGetDatum(responseNullTerminated->data);
|
Datum responseCStringDatum = CStringGetDatum(responseNullTerminated->data);
|
||||||
Datum responseJasonbDatum = DirectFunctionCall1(jsonb_in, responseCStringDatum);
|
Datum responseJasonbDatum = DirectFunctionCall1(jsonb_in, responseCStringDatum);
|
||||||
responseJsonb = DatumGetJsonb(responseJasonbDatum);
|
responseJsonb = DatumGetJsonbP(responseJasonbDatum);
|
||||||
ReleaseCurrentSubTransaction();
|
ReleaseCurrentSubTransaction();
|
||||||
}
|
}
|
||||||
PG_CATCH();
|
PG_CATCH();
|
||||||
|
|
|
@ -35,6 +35,7 @@
|
||||||
#include "distributed/task_tracker.h"
|
#include "distributed/task_tracker.h"
|
||||||
#include "distributed/transmit.h"
|
#include "distributed/transmit.h"
|
||||||
#include "distributed/worker_protocol.h"
|
#include "distributed/worker_protocol.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "libpq/hba.h"
|
#include "libpq/hba.h"
|
||||||
#include "libpq/pqsignal.h"
|
#include "libpq/pqsignal.h"
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
|
@ -145,10 +146,10 @@ TaskTrackerMain(Datum main_arg)
|
||||||
* that we can reset the context during error recovery and thereby avoid
|
* that we can reset the context during error recovery and thereby avoid
|
||||||
* possible memory leaks.
|
* possible memory leaks.
|
||||||
*/
|
*/
|
||||||
TaskTrackerContext = AllocSetContextCreate(TopMemoryContext, "Task Tracker",
|
TaskTrackerContext = AllocSetContextCreateExtended(TopMemoryContext, "Task Tracker",
|
||||||
ALLOCSET_DEFAULT_MINSIZE,
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
ALLOCSET_DEFAULT_INITSIZE,
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
MemoryContextSwitchTo(TaskTrackerContext);
|
MemoryContextSwitchTo(TaskTrackerContext);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "commands/tablecmds.h"
|
#include "commands/tablecmds.h"
|
||||||
#include "distributed/metadata_cache.h"
|
#include "distributed/metadata_cache.h"
|
||||||
#include "distributed/worker_protocol.h"
|
#include "distributed/worker_protocol.h"
|
||||||
|
#include "distributed/version_compat.h"
|
||||||
#include "executor/spi.h"
|
#include "executor/spi.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
#include "parser/parse_type.h"
|
#include "parser/parse_type.h"
|
||||||
|
@ -333,7 +334,7 @@ RemoveJobSchema(StringInfo schemaName)
|
||||||
bool permissionsOK = pg_namespace_ownercheck(schemaId, GetUserId());
|
bool permissionsOK = pg_namespace_ownercheck(schemaId, GetUserId());
|
||||||
if (!permissionsOK)
|
if (!permissionsOK)
|
||||||
{
|
{
|
||||||
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE, schemaName->data);
|
aclcheck_error(ACLCHECK_NOT_OWNER, ACLCHECK_OBJECT_SCHEMA, schemaName->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
schemaObject.classId = NamespaceRelationId;
|
schemaObject.classId = NamespaceRelationId;
|
||||||
|
|
|
@ -1000,11 +1000,11 @@ InitRowOutputState(void)
|
||||||
* recover palloc'd memory. This avoids any problems with leaks inside data
|
* recover palloc'd memory. This avoids any problems with leaks inside data
|
||||||
* type output routines, and should be faster than retail pfree's anyway.
|
* type output routines, and should be faster than retail pfree's anyway.
|
||||||
*/
|
*/
|
||||||
rowOutputState->rowcontext = AllocSetContextCreate(CurrentMemoryContext,
|
rowOutputState->rowcontext = AllocSetContextCreateExtended(CurrentMemoryContext,
|
||||||
"WorkerRowOutputContext",
|
"WorkerRowOutputContext",
|
||||||
ALLOCSET_DEFAULT_MINSIZE,
|
ALLOCSET_DEFAULT_MINSIZE,
|
||||||
ALLOCSET_DEFAULT_INITSIZE,
|
ALLOCSET_DEFAULT_INITSIZE,
|
||||||
ALLOCSET_DEFAULT_MAXSIZE);
|
ALLOCSET_DEFAULT_MAXSIZE);
|
||||||
|
|
||||||
/* allocate the message buffer to use for serializing a row */
|
/* allocate the message buffer to use for serializing a row */
|
||||||
rowOutputState->fe_msgbuf = makeStringInfo();
|
rowOutputState->fe_msgbuf = makeStringInfo();
|
||||||
|
|
|
@ -12,6 +12,9 @@
|
||||||
#define VERSION_COMPAT_H
|
#define VERSION_COMPAT_H
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
|
#include "commands/explain.h"
|
||||||
|
#include "catalog/namespace.h"
|
||||||
|
#include "nodes/parsenodes.h"
|
||||||
|
|
||||||
#if (PG_VERSION_NUM >= 90600 && PG_VERSION_NUM < 90700)
|
#if (PG_VERSION_NUM >= 90600 && PG_VERSION_NUM < 90700)
|
||||||
|
|
||||||
|
@ -25,10 +28,37 @@
|
||||||
|
|
||||||
#include "access/hash.h"
|
#include "access/hash.h"
|
||||||
#include "storage/fd.h"
|
#include "storage/fd.h"
|
||||||
|
#include "optimizer/prep.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
|
|
||||||
/* PostgreSQL 11 splits hash procs into "standard" and "extended" */
|
/* PostgreSQL 11 splits hash procs into "standard" and "extended" */
|
||||||
#define HASHSTANDARD_PROC HASHPROC
|
#define HASHSTANDARD_PROC HASHPROC
|
||||||
|
|
||||||
|
/* following functions are renamed in PG11 */
|
||||||
|
#define PreventInTransactionBlock PreventTransactionChain
|
||||||
|
#define DatumGetJsonbP(d) DatumGetJsonb(d)
|
||||||
|
|
||||||
|
/* following defines also exist for PG11 */
|
||||||
|
#define RELATION_OBJECT_TYPE ACL_OBJECT_RELATION
|
||||||
|
#define IndexInfoAttributeNumberArray(indexinfo) (indexinfo->ii_KeyAttrNumbers)
|
||||||
|
|
||||||
|
/* CreateTrigger api is changed in PG11 */
|
||||||
|
#define CreateTriggerInternal(stmt, queryString, relOid, refRelOid, constraintOid, \
|
||||||
|
indexOid, funcoid, parentTriggerOid, whenClause, isInternal, \
|
||||||
|
in_partition) \
|
||||||
|
CreateTrigger(stmt, queryString, relOid, refRelOid, constraintOid, indexOid, \
|
||||||
|
isInternal)
|
||||||
|
|
||||||
|
#define get_attname_internal(relationId, columnNumber, false) \
|
||||||
|
get_attname(relationId, columnNumber)
|
||||||
|
|
||||||
|
#define BackgroundWorkerInitializeConnectionByOid(dboid, useroid, flags) \
|
||||||
|
BackgroundWorkerInitializeConnectionByOid(dboid, useroid)
|
||||||
|
|
||||||
|
|
||||||
|
#define ACLCHECK_OBJECT_TABLE ACL_KIND_CLASS
|
||||||
|
#define ACLCHECK_OBJECT_SCHEMA ACL_KIND_NAMESPACE
|
||||||
|
#define ACLCHECK_OBJECT_INDEX ACL_KIND_CLASS
|
||||||
|
|
||||||
static inline int
|
static inline int
|
||||||
BasicOpenFilePerm(FileName fileName, int fileFlags, int fileMode)
|
BasicOpenFilePerm(FileName fileName, int fileFlags, int fileMode)
|
||||||
|
@ -44,6 +74,142 @@ PathNameOpenFilePerm(FileName fileName, int fileFlags, int fileMode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline MemoryContext
|
||||||
|
AllocSetContextCreateExtended(MemoryContext parent, const char *name, Size minContextSize,
|
||||||
|
Size initBlockSize, Size maxBlockSize)
|
||||||
|
{
|
||||||
|
return AllocSetContextCreate(parent, name, minContextSize, initBlockSize,
|
||||||
|
maxBlockSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
ExplainPropertyIntegerInternal(const char *qlabel, const char *unit, int64 value,
|
||||||
|
ExplainState *es)
|
||||||
|
{
|
||||||
|
return ExplainPropertyInteger(qlabel, value, es);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline List *
|
||||||
|
ExtractVacuumTargetRels(VacuumStmt *vacuumStmt)
|
||||||
|
{
|
||||||
|
List *vacuumList = NIL;
|
||||||
|
|
||||||
|
if (vacuumStmt->relation != NULL)
|
||||||
|
{
|
||||||
|
vacuumList = list_make1(vacuumStmt->relation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vacuumList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline List *
|
||||||
|
VacuumColumnList(VacuumStmt *vacuumStmt, int relationIndex)
|
||||||
|
{
|
||||||
|
Assert(relationIndex == 0);
|
||||||
|
|
||||||
|
return vacuumStmt->va_cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#define RVR_MISSING_OK 1
|
||||||
|
#define RVR_NOWAIT 2
|
||||||
|
|
||||||
|
static inline Oid
|
||||||
|
RangeVarGetRelidInternal(const RangeVar *relation, LOCKMODE lockmode, uint32 flags,
|
||||||
|
RangeVarGetRelidCallback callback, void *callback_arg)
|
||||||
|
{
|
||||||
|
bool missingOK = ((flags & RVR_MISSING_OK) != 0);
|
||||||
|
bool noWait = ((flags & RVR_NOWAIT) != 0);
|
||||||
|
|
||||||
|
return RangeVarGetRelidExtended(relation, lockmode, missingOK, noWait,
|
||||||
|
callback, callback_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline Expr *
|
||||||
|
canonicalize_qual_compat(Expr *qual, bool is_check)
|
||||||
|
{
|
||||||
|
return canonicalize_qual(qual);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if (PG_VERSION_NUM >= 110000)
|
||||||
|
#include "optimizer/prep.h"
|
||||||
|
|
||||||
|
/* following macros should be removed when we drop support for PG10 and below */
|
||||||
|
#define RELATION_OBJECT_TYPE OBJECT_TABLE
|
||||||
|
#define IndexInfoAttributeNumberArray(indexinfo) (indexinfo->ii_IndexAttrNumbers)
|
||||||
|
#define CreateTriggerInternal CreateTrigger
|
||||||
|
#define get_attname_internal get_attname
|
||||||
|
|
||||||
|
#define ACLCHECK_OBJECT_TABLE OBJECT_TABLE
|
||||||
|
#define ACLCHECK_OBJECT_SCHEMA OBJECT_SCHEMA
|
||||||
|
#define ACLCHECK_OBJECT_INDEX OBJECT_INDEX
|
||||||
|
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
ExplainPropertyIntegerInternal(const char *qlabel, const char *unit, int64 value,
|
||||||
|
ExplainState *es)
|
||||||
|
{
|
||||||
|
return ExplainPropertyInteger(qlabel, unit, value, es);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline Expr *
|
||||||
|
canonicalize_qual_compat(Expr *qual, bool is_check)
|
||||||
|
{
|
||||||
|
return canonicalize_qual(qual, is_check);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ExtractVacuumTargetRels returns list of target
|
||||||
|
* relations from vacuum statement.
|
||||||
|
*/
|
||||||
|
static inline List *
|
||||||
|
ExtractVacuumTargetRels(VacuumStmt *vacuumStmt)
|
||||||
|
{
|
||||||
|
List *vacuumList = NIL;
|
||||||
|
|
||||||
|
ListCell *vacuumRelationCell = NULL;
|
||||||
|
foreach(vacuumRelationCell, vacuumStmt->rels)
|
||||||
|
{
|
||||||
|
VacuumRelation *vacuumRelation = (VacuumRelation *) lfirst(vacuumRelationCell);
|
||||||
|
vacuumList = lappend(vacuumList, vacuumRelation->relation);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vacuumList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* VacuumColumnList returns list of columns from relation
|
||||||
|
* in the vacuum statement at specified relationIndex.
|
||||||
|
*/
|
||||||
|
static inline List *
|
||||||
|
VacuumColumnList(VacuumStmt *vacuumStmt, int relationIndex)
|
||||||
|
{
|
||||||
|
VacuumRelation *vacuumRelation = (VacuumRelation *) list_nth(vacuumStmt->rels,
|
||||||
|
relationIndex);
|
||||||
|
|
||||||
|
return vacuumRelation->va_cols;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static inline Oid
|
||||||
|
RangeVarGetRelidInternal(const RangeVar *relation, LOCKMODE lockmode, uint32 flags,
|
||||||
|
RangeVarGetRelidCallback callback, void *callback_arg)
|
||||||
|
{
|
||||||
|
return RangeVarGetRelidExtended(relation, lockmode, flags, callback, callback_arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif /* VERSION_COMPAT_H */
|
#endif /* VERSION_COMPAT_H */
|
||||||
|
|
|
@ -231,7 +231,7 @@ step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 &
|
||||||
step s2-table-size: SELECT citus_total_relation_size('partitioned_copy');
|
step s2-table-size: SELECT citus_total_relation_size('partitioned_copy');
|
||||||
citus_total_relation_size
|
citus_total_relation_size
|
||||||
|
|
||||||
32768
|
0
|
||||||
step s1-commit: COMMIT;
|
step s1-commit: COMMIT;
|
||||||
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
count
|
count
|
||||||
|
@ -511,7 +511,7 @@ step s1-begin: BEGIN;
|
||||||
step s1-table-size: SELECT citus_total_relation_size('partitioned_copy');
|
step s1-table-size: SELECT citus_total_relation_size('partitioned_copy');
|
||||||
citus_total_relation_size
|
citus_total_relation_size
|
||||||
|
|
||||||
32768
|
0
|
||||||
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
step s1-commit: COMMIT;
|
step s1-commit: COMMIT;
|
||||||
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
|
|
@ -1,6 +1,576 @@
|
||||||
Parsed test spec with 2 sessions
|
Parsed test spec with 2 sessions
|
||||||
|
|
||||||
starting permutation: s1-initialize s1-begin s1-copy s2-copy s1-commit s1-select-count
|
starting permutation: s1-initialize s1-begin s1-copy s2-copy s1-commit s1-select-count
|
||||||
setup failed: ERROR: syntax error at or near "PARTITION"
|
create_distributed_table
|
||||||
LINE 3: ...itioned_copy(id integer, data text, int_data int) PARTITION ...
|
|
||||||
^
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
15
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-router-select s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-router-select: SELECT * FROM partitioned_copy WHERE id = 1;
|
||||||
|
id data int_data
|
||||||
|
|
||||||
|
1 b 1
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-real-time-select s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-real-time-select: SELECT * FROM partitioned_copy ORDER BY 1, 2;
|
||||||
|
id data int_data
|
||||||
|
|
||||||
|
0 a 0
|
||||||
|
1 b 1
|
||||||
|
2 c 2
|
||||||
|
3 d 3
|
||||||
|
4 e 4
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-task-tracker-select s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-task-tracker-select:
|
||||||
|
SET citus.task_executor_type TO "task-tracker";
|
||||||
|
SELECT * FROM partitioned_copy AS t1 JOIN partitioned_copy AS t2 ON t1.id = t2.int_data ORDER BY 1, 2, 3, 4;
|
||||||
|
|
||||||
|
id data int_data id data int_data
|
||||||
|
|
||||||
|
0 a 0 0 a 0
|
||||||
|
1 b 1 1 b 1
|
||||||
|
2 c 2 2 c 2
|
||||||
|
3 d 3 3 d 3
|
||||||
|
4 e 4 4 e 4
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-insert s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-insert: INSERT INTO partitioned_copy VALUES(0, 'k', 0);
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
11
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-insert-select s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-insert-select: INSERT INTO partitioned_copy SELECT * FROM partitioned_copy;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
15
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-update s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-update: UPDATE partitioned_copy SET data = 'l' WHERE id = 0;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-delete s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-delete: DELETE FROM partitioned_copy WHERE id = 1;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
9
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-truncate s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-truncate: TRUNCATE partitioned_copy; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-truncate: <... completed>
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
0
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-drop s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-drop: DROP TABLE partitioned_copy; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-drop: <... completed>
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
ERROR: relation "partitioned_copy" does not exist
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-ddl-add-column s1-commit s1-select-count s1-show-columns
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-ddl-add-column: ALTER TABLE partitioned_copy ADD new_column int DEFAULT 0; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-ddl-add-column: <... completed>
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''partitioned_copy%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
|
||||||
|
run_command_on_workers
|
||||||
|
|
||||||
|
(localhost,57637,t,new_column)
|
||||||
|
(localhost,57638,t,new_column)
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-ddl-add-column s1-begin s1-copy-additional-column s2-ddl-drop-column s1-commit s1-select-count s1-show-columns
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-ddl-add-column: ALTER TABLE partitioned_copy ADD new_column int DEFAULT 0;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy-additional-column: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5, 5 && echo 6, g, 6, 6 && echo 7, h, 7, 7 && echo 8, i, 8, 8 && echo 9, j, 9, 9' WITH CSV;
|
||||||
|
step s2-ddl-drop-column: ALTER TABLE partitioned_copy DROP new_column; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-ddl-drop-column: <... completed>
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''partitioned_copy%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
|
||||||
|
run_command_on_workers
|
||||||
|
|
||||||
|
(localhost,57637,t,"")
|
||||||
|
(localhost,57638,t,"")
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-ddl-rename-column s1-commit s1-select-count s1-show-columns
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-ddl-rename-column: ALTER TABLE partitioned_copy RENAME data TO new_column; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-ddl-rename-column: <... completed>
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''partitioned_copy%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
|
||||||
|
run_command_on_workers
|
||||||
|
|
||||||
|
(localhost,57637,t,new_column)
|
||||||
|
(localhost,57638,t,new_column)
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-table-size s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-table-size: SELECT citus_total_relation_size('partitioned_copy');
|
||||||
|
citus_total_relation_size
|
||||||
|
|
||||||
|
32768
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-master-modify-multiple-shards s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-master-modify-multiple-shards: SELECT master_modify_multiple_shards('DELETE FROM partitioned_copy;');
|
||||||
|
master_modify_multiple_shards
|
||||||
|
|
||||||
|
5
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
5
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-master-drop-all-shards s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-master-drop-all-shards: SELECT master_drop_all_shards('partitioned_copy'::regclass, 'public', 'partitioned_copy'); <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-master-drop-all-shards: <... completed>
|
||||||
|
master_drop_all_shards
|
||||||
|
|
||||||
|
4
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
0
|
||||||
|
|
||||||
|
starting permutation: s1-drop s1-create-non-distributed-table s1-initialize s1-begin s1-copy s2-distribute-table s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-drop: DROP TABLE partitioned_copy;
|
||||||
|
step s1-create-non-distributed-table: CREATE TABLE partitioned_copy(id integer, data text, int_data int); COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s2-distribute-table: SELECT create_distributed_table('partitioned_copy', 'id'); <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-distribute-table: <... completed>
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
15
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-router-select s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-router-select: SELECT * FROM partitioned_copy WHERE id = 1;
|
||||||
|
id data int_data
|
||||||
|
|
||||||
|
1 b 1
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-real-time-select s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-real-time-select: SELECT * FROM partitioned_copy ORDER BY 1, 2;
|
||||||
|
id data int_data
|
||||||
|
|
||||||
|
0 a 0
|
||||||
|
1 b 1
|
||||||
|
2 c 2
|
||||||
|
3 d 3
|
||||||
|
4 e 4
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-task-tracker-select s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-task-tracker-select:
|
||||||
|
SET citus.task_executor_type TO "task-tracker";
|
||||||
|
SELECT * FROM partitioned_copy AS t1 JOIN partitioned_copy AS t2 ON t1.id = t2.int_data ORDER BY 1, 2, 3, 4;
|
||||||
|
|
||||||
|
id data int_data id data int_data
|
||||||
|
|
||||||
|
0 a 0 0 a 0
|
||||||
|
1 b 1 1 b 1
|
||||||
|
2 c 2 2 c 2
|
||||||
|
3 d 3 3 d 3
|
||||||
|
4 e 4 4 e 4
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-insert s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-insert: INSERT INTO partitioned_copy VALUES(0, 'k', 0);
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
11
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-insert-select s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-insert-select: INSERT INTO partitioned_copy SELECT * FROM partitioned_copy;
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
15
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-update s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-update: UPDATE partitioned_copy SET data = 'l' WHERE id = 0;
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-delete s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-delete: DELETE FROM partitioned_copy WHERE id = 1;
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
9
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-truncate s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-truncate: TRUNCATE partitioned_copy;
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-copy: <... completed>
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
5
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-drop s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-drop: DROP TABLE partitioned_copy;
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-copy: <... completed>
|
||||||
|
error in steps s1-commit s2-copy: ERROR: relation "partitioned_copy" does not exist
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
ERROR: relation "partitioned_copy" does not exist
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-ddl-add-column s2-copy s1-commit s1-select-count s1-show-columns
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-ddl-add-column: ALTER TABLE partitioned_copy ADD new_column int DEFAULT 0;
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-copy: <... completed>
|
||||||
|
error in steps s1-commit s2-copy: ERROR: missing data for column "new_column"
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
5
|
||||||
|
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''partitioned_copy%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
|
||||||
|
run_command_on_workers
|
||||||
|
|
||||||
|
(localhost,57637,t,new_column)
|
||||||
|
(localhost,57638,t,new_column)
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-ddl-add-column s1-begin s1-ddl-drop-column s2-copy s1-commit s1-select-count s1-show-columns
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-ddl-add-column: ALTER TABLE partitioned_copy ADD new_column int DEFAULT 0;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-ddl-drop-column: ALTER TABLE partitioned_copy DROP new_column;
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-copy: <... completed>
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''partitioned_copy%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
|
||||||
|
run_command_on_workers
|
||||||
|
|
||||||
|
(localhost,57637,t,"")
|
||||||
|
(localhost,57638,t,"")
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-ddl-rename-column s2-copy s1-commit s1-select-count s1-show-columns
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-ddl-rename-column: ALTER TABLE partitioned_copy RENAME data TO new_column;
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-copy: <... completed>
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
step s1-show-columns: SELECT run_command_on_workers('SELECT column_name FROM information_schema.columns WHERE table_name LIKE ''partitioned_copy%'' AND column_name = ''new_column'' ORDER BY 1 LIMIT 1');
|
||||||
|
run_command_on_workers
|
||||||
|
|
||||||
|
(localhost,57637,t,new_column)
|
||||||
|
(localhost,57638,t,new_column)
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-table-size s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-table-size: SELECT citus_total_relation_size('partitioned_copy');
|
||||||
|
citus_total_relation_size
|
||||||
|
|
||||||
|
32768
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
10
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-master-modify-multiple-shards s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-master-modify-multiple-shards: SELECT master_modify_multiple_shards('DELETE FROM partitioned_copy;');
|
||||||
|
master_modify_multiple_shards
|
||||||
|
|
||||||
|
5
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV;
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
5
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-master-drop-all-shards s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-master-drop-all-shards: SELECT master_drop_all_shards('partitioned_copy'::regclass, 'public', 'partitioned_copy');
|
||||||
|
master_drop_all_shards
|
||||||
|
|
||||||
|
4
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-copy: <... completed>
|
||||||
|
error in steps s1-commit s2-copy: ERROR: could not find any shards into which to copy
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
0
|
||||||
|
|
||||||
|
starting permutation: s1-drop s1-create-non-distributed-table s1-initialize s1-begin s1-distribute-table s2-copy s1-commit s1-select-count
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s1-drop: DROP TABLE partitioned_copy;
|
||||||
|
step s1-create-non-distributed-table: CREATE TABLE partitioned_copy(id integer, data text, int_data int); COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-initialize: COPY partitioned_copy FROM PROGRAM 'echo 0, a, 0 && echo 1, b, 1 && echo 2, c, 2 && echo 3, d, 3 && echo 4, e, 4' WITH CSV;
|
||||||
|
step s1-begin: BEGIN;
|
||||||
|
step s1-distribute-table: SELECT create_distributed_table('partitioned_copy', 'id');
|
||||||
|
create_distributed_table
|
||||||
|
|
||||||
|
|
||||||
|
step s2-copy: COPY partitioned_copy FROM PROGRAM 'echo 5, f, 5 && echo 6, g, 6 && echo 7, h, 7 && echo 8, i, 8 && echo 9, j, 9' WITH CSV; <waiting ...>
|
||||||
|
step s1-commit: COMMIT;
|
||||||
|
step s2-copy: <... completed>
|
||||||
|
step s1-select-count: SELECT COUNT(*) FROM partitioned_copy;
|
||||||
|
count
|
||||||
|
|
||||||
|
15
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
Parsed test spec with 2 sessions
|
||||||
|
|
||||||
|
starting permutation: s1-initialize s1-begin s1-copy s2-copy s1-commit s1-select-count
|
||||||
|
setup failed: ERROR: syntax error at or near "PARTITION"
|
||||||
|
LINE 3: ...itioned_copy(id integer, data text, int_data int) PARTITION ...
|
||||||
|
^
|
File diff suppressed because it is too large
Load Diff
|
@ -6,9 +6,9 @@ SET citus.next_shard_id TO 650000;
|
||||||
SET citus.explain_distributed_queries TO off;
|
SET citus.explain_distributed_queries TO off;
|
||||||
SET citus.log_multi_join_order TO TRUE;
|
SET citus.log_multi_join_order TO TRUE;
|
||||||
SET citus.task_executor_type = 'task-tracker'; -- can't explain all queries otherwise
|
SET citus.task_executor_type = 'task-tracker'; -- can't explain all queries otherwise
|
||||||
SET client_min_messages TO DEBUG2;
|
|
||||||
SET citus.shard_count to 2;
|
SET citus.shard_count to 2;
|
||||||
SET citus.shard_replication_factor to 1;
|
SET citus.shard_replication_factor to 1;
|
||||||
|
RESET client_min_messages;
|
||||||
-- Create new table definitions for use in testing in distributed planning and
|
-- Create new table definitions for use in testing in distributed planning and
|
||||||
-- execution functionality. Also create indexes to boost performance.
|
-- execution functionality. Also create indexes to boost performance.
|
||||||
CREATE TABLE lineitem_hash (
|
CREATE TABLE lineitem_hash (
|
||||||
|
@ -29,8 +29,6 @@ CREATE TABLE lineitem_hash (
|
||||||
l_shipmode char(10) not null,
|
l_shipmode char(10) not null,
|
||||||
l_comment varchar(44) not null,
|
l_comment varchar(44) not null,
|
||||||
PRIMARY KEY(l_orderkey, l_linenumber) );
|
PRIMARY KEY(l_orderkey, l_linenumber) );
|
||||||
DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "lineitem_hash_pkey" for table "lineitem_hash"
|
|
||||||
DEBUG: building index "lineitem_hash_pkey" on table "lineitem_hash"
|
|
||||||
SELECT create_distributed_table('lineitem_hash', 'l_orderkey');
|
SELECT create_distributed_table('lineitem_hash', 'l_orderkey');
|
||||||
create_distributed_table
|
create_distributed_table
|
||||||
--------------------------
|
--------------------------
|
||||||
|
@ -38,7 +36,6 @@ SELECT create_distributed_table('lineitem_hash', 'l_orderkey');
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
CREATE INDEX lineitem_hash_time_index ON lineitem_hash (l_shipdate);
|
CREATE INDEX lineitem_hash_time_index ON lineitem_hash (l_shipdate);
|
||||||
DEBUG: building index "lineitem_hash_time_index" on table "lineitem_hash"
|
|
||||||
CREATE TABLE orders_hash (
|
CREATE TABLE orders_hash (
|
||||||
o_orderkey bigint not null,
|
o_orderkey bigint not null,
|
||||||
o_custkey integer not null,
|
o_custkey integer not null,
|
||||||
|
@ -50,8 +47,6 @@ CREATE TABLE orders_hash (
|
||||||
o_shippriority integer not null,
|
o_shippriority integer not null,
|
||||||
o_comment varchar(79) not null,
|
o_comment varchar(79) not null,
|
||||||
PRIMARY KEY(o_orderkey) );
|
PRIMARY KEY(o_orderkey) );
|
||||||
DEBUG: CREATE TABLE / PRIMARY KEY will create implicit index "orders_hash_pkey" for table "orders_hash"
|
|
||||||
DEBUG: building index "orders_hash_pkey" on table "orders_hash"
|
|
||||||
SELECT create_distributed_table('orders_hash', 'o_orderkey');
|
SELECT create_distributed_table('orders_hash', 'o_orderkey');
|
||||||
create_distributed_table
|
create_distributed_table
|
||||||
--------------------------
|
--------------------------
|
||||||
|
@ -73,6 +68,7 @@ SELECT create_distributed_table('customer_hash', 'c_custkey');
|
||||||
|
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
SET client_min_messages TO DEBUG2;
|
||||||
-- The following query checks that we can correctly handle self-joins
|
-- The following query checks that we can correctly handle self-joins
|
||||||
EXPLAIN SELECT l1.l_quantity FROM lineitem l1, lineitem l2
|
EXPLAIN SELECT l1.l_quantity FROM lineitem l1, lineitem l2
|
||||||
WHERE l1.l_orderkey = l2.l_orderkey AND l1.l_quantity > 5;
|
WHERE l1.l_orderkey = l2.l_orderkey AND l1.l_quantity > 5;
|
||||||
|
|
|
@ -3,6 +3,14 @@
|
||||||
--
|
--
|
||||||
-- Test user permissions.
|
-- Test user permissions.
|
||||||
--
|
--
|
||||||
|
-- print whether we're using version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_ten;
|
||||||
|
version_above_ten
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SET citus.next_shard_id TO 1420000;
|
SET citus.next_shard_id TO 1420000;
|
||||||
ALTER SEQUENCE pg_catalog.pg_dist_jobid_seq RESTART 1420000;
|
ALTER SEQUENCE pg_catalog.pg_dist_jobid_seq RESTART 1420000;
|
||||||
SET citus.shard_replication_factor TO 1;
|
SET citus.shard_replication_factor TO 1;
|
||||||
|
@ -110,7 +118,7 @@ HINT: Run the command with a superuser.
|
||||||
-- check read permission
|
-- check read permission
|
||||||
SET ROLE read_access;
|
SET ROLE read_access;
|
||||||
EXECUTE prepare_insert(1);
|
EXECUTE prepare_insert(1);
|
||||||
ERROR: permission denied for relation test
|
ERROR: permission denied for table test
|
||||||
EXECUTE prepare_select;
|
EXECUTE prepare_select;
|
||||||
count
|
count
|
||||||
-------
|
-------
|
||||||
|
@ -118,7 +126,7 @@ EXECUTE prepare_select;
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
INSERT INTO test VALUES (2);
|
INSERT INTO test VALUES (2);
|
||||||
ERROR: permission denied for relation test
|
ERROR: permission denied for table test
|
||||||
SELECT count(*) FROM test;
|
SELECT count(*) FROM test;
|
||||||
count
|
count
|
||||||
-------
|
-------
|
||||||
|
@ -153,21 +161,21 @@ SET citus.task_executor_type TO 'real-time';
|
||||||
-- check no permission
|
-- check no permission
|
||||||
SET ROLE no_access;
|
SET ROLE no_access;
|
||||||
EXECUTE prepare_insert(1);
|
EXECUTE prepare_insert(1);
|
||||||
ERROR: permission denied for relation test
|
ERROR: permission denied for table test
|
||||||
EXECUTE prepare_select;
|
EXECUTE prepare_select;
|
||||||
ERROR: permission denied for relation test
|
ERROR: permission denied for table test
|
||||||
INSERT INTO test VALUES (2);
|
INSERT INTO test VALUES (2);
|
||||||
ERROR: permission denied for relation test
|
ERROR: permission denied for table test
|
||||||
SELECT count(*) FROM test;
|
SELECT count(*) FROM test;
|
||||||
ERROR: permission denied for relation test
|
ERROR: permission denied for table test
|
||||||
SELECT count(*) FROM test WHERE id = 1;
|
SELECT count(*) FROM test WHERE id = 1;
|
||||||
ERROR: permission denied for relation test
|
ERROR: permission denied for table test
|
||||||
SET citus.task_executor_type TO 'task-tracker';
|
SET citus.task_executor_type TO 'task-tracker';
|
||||||
SELECT count(*) FROM test;
|
SELECT count(*) FROM test;
|
||||||
ERROR: permission denied for relation test
|
ERROR: permission denied for table test
|
||||||
-- test re-partition query
|
-- test re-partition query
|
||||||
SELECT count(*) FROM test a JOIN test b ON (a.val = b.val) WHERE a.id = 1 AND b.id = 2;
|
SELECT count(*) FROM test a JOIN test b ON (a.val = b.val) WHERE a.id = 1 AND b.id = 2;
|
||||||
ERROR: permission denied for relation test
|
ERROR: permission denied for table test
|
||||||
-- should not be able to transmit directly
|
-- should not be able to transmit directly
|
||||||
COPY "postgresql.conf" TO STDOUT WITH (format transmit);
|
COPY "postgresql.conf" TO STDOUT WITH (format transmit);
|
||||||
ERROR: operation is not allowed
|
ERROR: operation is not allowed
|
||||||
|
@ -200,7 +208,7 @@ END;
|
||||||
-- as long as we don't read from a table
|
-- as long as we don't read from a table
|
||||||
BEGIN;
|
BEGIN;
|
||||||
SELECT create_intermediate_result('topten', 'SELECT count(*) FROM test');
|
SELECT create_intermediate_result('topten', 'SELECT count(*) FROM test');
|
||||||
ERROR: permission denied for relation test
|
ERROR: permission denied for table test
|
||||||
ABORT;
|
ABORT;
|
||||||
RESET ROLE;
|
RESET ROLE;
|
||||||
DROP TABLE test;
|
DROP TABLE test;
|
||||||
|
|
|
@ -0,0 +1,217 @@
|
||||||
|
--
|
||||||
|
-- MULTI_MULTIUSERS
|
||||||
|
--
|
||||||
|
-- Test user permissions.
|
||||||
|
--
|
||||||
|
-- print whether we're using version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_ten;
|
||||||
|
version_above_ten
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SET citus.next_shard_id TO 1420000;
|
||||||
|
ALTER SEQUENCE pg_catalog.pg_dist_jobid_seq RESTART 1420000;
|
||||||
|
SET citus.shard_replication_factor TO 1;
|
||||||
|
CREATE TABLE test (id integer, val integer);
|
||||||
|
SELECT create_distributed_table('test', 'id');
|
||||||
|
create_distributed_table
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- turn off propagation to avoid Enterprise processing the following section
|
||||||
|
SET citus.enable_ddl_propagation TO off;
|
||||||
|
CREATE USER full_access;
|
||||||
|
NOTICE: not propagating CREATE ROLE/USER commands to worker nodes
|
||||||
|
HINT: Connect to worker nodes directly to manually create all necessary users and roles.
|
||||||
|
CREATE USER read_access;
|
||||||
|
NOTICE: not propagating CREATE ROLE/USER commands to worker nodes
|
||||||
|
HINT: Connect to worker nodes directly to manually create all necessary users and roles.
|
||||||
|
CREATE USER no_access;
|
||||||
|
NOTICE: not propagating CREATE ROLE/USER commands to worker nodes
|
||||||
|
HINT: Connect to worker nodes directly to manually create all necessary users and roles.
|
||||||
|
GRANT ALL ON TABLE test TO full_access;
|
||||||
|
GRANT SELECT ON TABLE test TO read_access;
|
||||||
|
SET citus.enable_ddl_propagation TO DEFAULT;
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
CREATE USER full_access;
|
||||||
|
NOTICE: not propagating CREATE ROLE/USER commands to worker nodes
|
||||||
|
HINT: Connect to worker nodes directly to manually create all necessary users and roles.
|
||||||
|
CREATE USER read_access;
|
||||||
|
NOTICE: not propagating CREATE ROLE/USER commands to worker nodes
|
||||||
|
HINT: Connect to worker nodes directly to manually create all necessary users and roles.
|
||||||
|
CREATE USER no_access;
|
||||||
|
NOTICE: not propagating CREATE ROLE/USER commands to worker nodes
|
||||||
|
HINT: Connect to worker nodes directly to manually create all necessary users and roles.
|
||||||
|
GRANT ALL ON TABLE test_1420000 TO full_access;
|
||||||
|
GRANT SELECT ON TABLE test_1420000 TO read_access;
|
||||||
|
GRANT ALL ON TABLE test_1420002 TO full_access;
|
||||||
|
GRANT SELECT ON TABLE test_1420002 TO read_access;
|
||||||
|
\c - - - :worker_2_port
|
||||||
|
CREATE USER full_access;
|
||||||
|
NOTICE: not propagating CREATE ROLE/USER commands to worker nodes
|
||||||
|
HINT: Connect to worker nodes directly to manually create all necessary users and roles.
|
||||||
|
CREATE USER read_access;
|
||||||
|
NOTICE: not propagating CREATE ROLE/USER commands to worker nodes
|
||||||
|
HINT: Connect to worker nodes directly to manually create all necessary users and roles.
|
||||||
|
CREATE USER no_access;
|
||||||
|
NOTICE: not propagating CREATE ROLE/USER commands to worker nodes
|
||||||
|
HINT: Connect to worker nodes directly to manually create all necessary users and roles.
|
||||||
|
GRANT ALL ON TABLE test_1420001 TO full_access;
|
||||||
|
GRANT SELECT ON TABLE test_1420001 TO read_access;
|
||||||
|
GRANT ALL ON TABLE test_1420003 TO full_access;
|
||||||
|
GRANT SELECT ON TABLE test_1420003 TO read_access;
|
||||||
|
\c - - - :master_port
|
||||||
|
-- create prepare tests
|
||||||
|
PREPARE prepare_insert AS INSERT INTO test VALUES ($1);
|
||||||
|
PREPARE prepare_select AS SELECT count(*) FROM test;
|
||||||
|
-- not allowed to read absolute paths, even as superuser
|
||||||
|
COPY "/etc/passwd" TO STDOUT WITH (format transmit);
|
||||||
|
ERROR: absolute path not allowed
|
||||||
|
-- check full permission
|
||||||
|
SET ROLE full_access;
|
||||||
|
EXECUTE prepare_insert(1);
|
||||||
|
EXECUTE prepare_select;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
INSERT INTO test VALUES (2);
|
||||||
|
SELECT count(*) FROM test;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT count(*) FROM test WHERE id = 1;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SET citus.task_executor_type TO 'task-tracker';
|
||||||
|
SELECT count(*) FROM test;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- test re-partition query (needs to transmit intermediate results)
|
||||||
|
SELECT count(*) FROM test a JOIN test b ON (a.val = b.val) WHERE a.id = 1 AND b.id = 2;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- should not be able to transmit directly
|
||||||
|
COPY "postgresql.conf" TO STDOUT WITH (format transmit);
|
||||||
|
ERROR: operation is not allowed
|
||||||
|
HINT: Run the command with a superuser.
|
||||||
|
SET citus.task_executor_type TO 'real-time';
|
||||||
|
-- should not be able to transmit directly
|
||||||
|
COPY "postgresql.conf" TO STDOUT WITH (format transmit);
|
||||||
|
ERROR: operation is not allowed
|
||||||
|
HINT: Run the command with a superuser.
|
||||||
|
-- check read permission
|
||||||
|
SET ROLE read_access;
|
||||||
|
EXECUTE prepare_insert(1);
|
||||||
|
ERROR: permission denied for relation test
|
||||||
|
EXECUTE prepare_select;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
INSERT INTO test VALUES (2);
|
||||||
|
ERROR: permission denied for relation test
|
||||||
|
SELECT count(*) FROM test;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT count(*) FROM test WHERE id = 1;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SET citus.task_executor_type TO 'task-tracker';
|
||||||
|
SELECT count(*) FROM test;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- test re-partition query (needs to transmit intermediate results)
|
||||||
|
SELECT count(*) FROM test a JOIN test b ON (a.val = b.val) WHERE a.id = 1 AND b.id = 2;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- should not be able to transmit directly
|
||||||
|
COPY "postgresql.conf" TO STDOUT WITH (format transmit);
|
||||||
|
ERROR: operation is not allowed
|
||||||
|
HINT: Run the command with a superuser.
|
||||||
|
SET citus.task_executor_type TO 'real-time';
|
||||||
|
-- check no permission
|
||||||
|
SET ROLE no_access;
|
||||||
|
EXECUTE prepare_insert(1);
|
||||||
|
ERROR: permission denied for relation test
|
||||||
|
EXECUTE prepare_select;
|
||||||
|
ERROR: permission denied for relation test
|
||||||
|
INSERT INTO test VALUES (2);
|
||||||
|
ERROR: permission denied for relation test
|
||||||
|
SELECT count(*) FROM test;
|
||||||
|
ERROR: permission denied for relation test
|
||||||
|
SELECT count(*) FROM test WHERE id = 1;
|
||||||
|
ERROR: permission denied for relation test
|
||||||
|
SET citus.task_executor_type TO 'task-tracker';
|
||||||
|
SELECT count(*) FROM test;
|
||||||
|
ERROR: permission denied for relation test
|
||||||
|
-- test re-partition query
|
||||||
|
SELECT count(*) FROM test a JOIN test b ON (a.val = b.val) WHERE a.id = 1 AND b.id = 2;
|
||||||
|
ERROR: permission denied for relation test
|
||||||
|
-- should not be able to transmit directly
|
||||||
|
COPY "postgresql.conf" TO STDOUT WITH (format transmit);
|
||||||
|
ERROR: operation is not allowed
|
||||||
|
HINT: Run the command with a superuser.
|
||||||
|
SET citus.task_executor_type TO 'real-time';
|
||||||
|
-- should be able to use intermediate results as any user
|
||||||
|
BEGIN;
|
||||||
|
SELECT create_intermediate_result('topten', 'SELECT s FROM generate_series(1,10) s');
|
||||||
|
create_intermediate_result
|
||||||
|
----------------------------
|
||||||
|
10
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM read_intermediate_result('topten', 'binary'::citus_copy_format) AS res (s int) ORDER BY s;
|
||||||
|
s
|
||||||
|
----
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
7
|
||||||
|
8
|
||||||
|
9
|
||||||
|
10
|
||||||
|
(10 rows)
|
||||||
|
|
||||||
|
END;
|
||||||
|
-- as long as we don't read from a table
|
||||||
|
BEGIN;
|
||||||
|
SELECT create_intermediate_result('topten', 'SELECT count(*) FROM test');
|
||||||
|
ERROR: permission denied for relation test
|
||||||
|
ABORT;
|
||||||
|
RESET ROLE;
|
||||||
|
DROP TABLE test;
|
||||||
|
DROP USER full_access;
|
||||||
|
DROP USER read_access;
|
||||||
|
DROP USER no_access;
|
|
@ -240,10 +240,7 @@ SELECT "Column", "Type", "Modifiers" FROM table_desc WHERE relid='mx_ddl_table_1
|
||||||
|
|
||||||
-- Show that DDL commands are done within a two-phase commit transaction
|
-- Show that DDL commands are done within a two-phase commit transaction
|
||||||
\c - - - :master_port
|
\c - - - :master_port
|
||||||
SET client_min_messages TO debug2;
|
|
||||||
CREATE INDEX ddl_test_index ON mx_ddl_table(value);
|
CREATE INDEX ddl_test_index ON mx_ddl_table(value);
|
||||||
DEBUG: building index "ddl_test_index" on table "mx_ddl_table"
|
|
||||||
RESET client_min_messages;
|
|
||||||
DROP INDEX ddl_test_index;
|
DROP INDEX ddl_test_index;
|
||||||
-- show that sequences owned by mx tables result in unique values
|
-- show that sequences owned by mx tables result in unique values
|
||||||
SET citus.shard_replication_factor TO 1;
|
SET citus.shard_replication_factor TO 1;
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
-- This test checks that we can handle null min/max values in shard statistics
|
-- This test checks that we can handle null min/max values in shard statistics
|
||||||
-- and that we don't partition or join prune shards that have null values.
|
-- and that we don't partition or join prune shards that have null values.
|
||||||
SET citus.next_shard_id TO 760000;
|
SET citus.next_shard_id TO 760000;
|
||||||
-- print whether we're using version > 9 to make version-specific tests clear
|
-- print major version number for version-specific tests
|
||||||
SHOW server_version \gset
|
SHOW server_version \gset
|
||||||
SELECT substring(:'server_version', '\d+')::int > 9 AS version_above_nine;
|
SELECT substring(:'server_version', '\d+')::int AS server_version;
|
||||||
version_above_nine
|
server_version
|
||||||
--------------------
|
----------------
|
||||||
t
|
11
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SET client_min_messages TO DEBUG2;
|
SET client_min_messages TO DEBUG2;
|
||||||
|
|
|
@ -4,12 +4,12 @@
|
||||||
-- This test checks that we can handle null min/max values in shard statistics
|
-- This test checks that we can handle null min/max values in shard statistics
|
||||||
-- and that we don't partition or join prune shards that have null values.
|
-- and that we don't partition or join prune shards that have null values.
|
||||||
SET citus.next_shard_id TO 760000;
|
SET citus.next_shard_id TO 760000;
|
||||||
-- print whether we're using version > 9 to make version-specific tests clear
|
-- print major version number for version-specific tests
|
||||||
SHOW server_version \gset
|
SHOW server_version \gset
|
||||||
SELECT substring(:'server_version', '\d+')::int > 9 AS version_above_nine;
|
SELECT substring(:'server_version', '\d+')::int AS server_version;
|
||||||
version_above_nine
|
server_version
|
||||||
--------------------
|
----------------
|
||||||
f
|
10
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SET client_min_messages TO DEBUG2;
|
SET client_min_messages TO DEBUG2;
|
||||||
|
@ -69,8 +69,8 @@ SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders
|
||||||
LOG: join order: [ "lineitem" ][ local partition join "orders" ]
|
LOG: join order: [ "lineitem" ][ local partition join "orders" ]
|
||||||
DEBUG: join prunable for intervals [1,5986] and [8997,14947]
|
DEBUG: join prunable for intervals [1,5986] and [8997,14947]
|
||||||
DEBUG: join prunable for intervals [8997,14947] and [1,5986]
|
DEBUG: join prunable for intervals [8997,14947] and [1,5986]
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
------------------------------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
Aggregate
|
Aggregate
|
||||||
-> Custom Scan (Citus Real-Time)
|
-> Custom Scan (Citus Real-Time)
|
||||||
Task Count: 2
|
Task Count: 2
|
||||||
|
@ -78,18 +78,20 @@ DEBUG: join prunable for intervals [8997,14947] and [1,5986]
|
||||||
-> Task
|
-> Task
|
||||||
Node: host=localhost port=57637 dbname=regression
|
Node: host=localhost port=57637 dbname=regression
|
||||||
-> Aggregate
|
-> Aggregate
|
||||||
-> Merge Join
|
-> Hash Join
|
||||||
Merge Cond: (orders.o_orderkey = lineitem.l_orderkey)
|
Hash Cond: (lineitem.l_orderkey = orders.o_orderkey)
|
||||||
-> Index Only Scan using orders_pkey_290003 on orders_290003 orders
|
-> Seq Scan on lineitem_290001 lineitem
|
||||||
-> Index Only Scan using lineitem_pkey_290001 on lineitem_290001 lineitem
|
-> Hash
|
||||||
|
-> Seq Scan on orders_290003 orders
|
||||||
-> Task
|
-> Task
|
||||||
Node: host=localhost port=57638 dbname=regression
|
Node: host=localhost port=57638 dbname=regression
|
||||||
-> Aggregate
|
-> Aggregate
|
||||||
-> Merge Join
|
-> Hash Join
|
||||||
Merge Cond: (orders.o_orderkey = lineitem.l_orderkey)
|
Hash Cond: (lineitem.l_orderkey = orders.o_orderkey)
|
||||||
-> Index Only Scan using orders_pkey_290002 on orders_290002 orders
|
-> Seq Scan on lineitem_290000 lineitem
|
||||||
-> Index Only Scan using lineitem_pkey_290000 on lineitem_290000 lineitem
|
-> Hash
|
||||||
(18 rows)
|
-> Seq Scan on orders_290002 orders
|
||||||
|
(20 rows)
|
||||||
|
|
||||||
-- Now set the minimum value for a shard to null. Then check that we don't apply
|
-- Now set the minimum value for a shard to null. Then check that we don't apply
|
||||||
-- partition or join pruning for the shard with null min value. Since it is not
|
-- partition or join pruning for the shard with null min value. Since it is not
|
||||||
|
|
|
@ -0,0 +1,304 @@
|
||||||
|
--
|
||||||
|
-- MULTI_NULL_MINMAX_VALUE_PRUNING
|
||||||
|
--
|
||||||
|
-- This test checks that we can handle null min/max values in shard statistics
|
||||||
|
-- and that we don't partition or join prune shards that have null values.
|
||||||
|
SET citus.next_shard_id TO 760000;
|
||||||
|
-- print major version number for version-specific tests
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int AS server_version;
|
||||||
|
server_version
|
||||||
|
----------------
|
||||||
|
9
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SET client_min_messages TO DEBUG2;
|
||||||
|
SET citus.explain_all_tasks TO on;
|
||||||
|
-- to avoid differing explain output - executor doesn't matter,
|
||||||
|
-- because were testing pruning here.
|
||||||
|
SET citus.task_executor_type TO 'real-time';
|
||||||
|
-- Change configuration to treat lineitem and orders tables as large
|
||||||
|
SET citus.large_table_shard_count TO 2;
|
||||||
|
SET citus.log_multi_join_order to true;
|
||||||
|
SET citus.enable_repartition_joins to ON;
|
||||||
|
SELECT shardminvalue, shardmaxvalue from pg_dist_shard WHERE shardid = 290000;
|
||||||
|
shardminvalue | shardmaxvalue
|
||||||
|
---------------+---------------
|
||||||
|
1 | 5986
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT shardminvalue, shardmaxvalue from pg_dist_shard WHERE shardid = 290001;
|
||||||
|
shardminvalue | shardmaxvalue
|
||||||
|
---------------+---------------
|
||||||
|
8997 | 14947
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Check that partition and join pruning works when min/max values exist
|
||||||
|
-- Adding l_orderkey = 1 to make the query not router executable
|
||||||
|
EXPLAIN (COSTS FALSE)
|
||||||
|
SELECT l_orderkey, l_linenumber, l_shipdate FROM lineitem WHERE l_orderkey = 9030 or l_orderkey = 1;
|
||||||
|
LOG: join order: [ "lineitem" ]
|
||||||
|
QUERY PLAN
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
Custom Scan (Citus Real-Time)
|
||||||
|
Task Count: 2
|
||||||
|
Tasks Shown: All
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> Bitmap Heap Scan on lineitem_290001 lineitem
|
||||||
|
Recheck Cond: ((l_orderkey = 9030) OR (l_orderkey = 1))
|
||||||
|
-> BitmapOr
|
||||||
|
-> Bitmap Index Scan on lineitem_pkey_290001
|
||||||
|
Index Cond: (l_orderkey = 9030)
|
||||||
|
-> Bitmap Index Scan on lineitem_pkey_290001
|
||||||
|
Index Cond: (l_orderkey = 1)
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57638 dbname=regression
|
||||||
|
-> Bitmap Heap Scan on lineitem_290000 lineitem
|
||||||
|
Recheck Cond: ((l_orderkey = 9030) OR (l_orderkey = 1))
|
||||||
|
-> BitmapOr
|
||||||
|
-> Bitmap Index Scan on lineitem_pkey_290000
|
||||||
|
Index Cond: (l_orderkey = 9030)
|
||||||
|
-> Bitmap Index Scan on lineitem_pkey_290000
|
||||||
|
Index Cond: (l_orderkey = 1)
|
||||||
|
(21 rows)
|
||||||
|
|
||||||
|
EXPLAIN (COSTS FALSE)
|
||||||
|
SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders
|
||||||
|
WHERE l_orderkey = o_orderkey;
|
||||||
|
LOG: join order: [ "lineitem" ][ local partition join "orders" ]
|
||||||
|
DEBUG: join prunable for intervals [1,5986] and [8997,14947]
|
||||||
|
DEBUG: join prunable for intervals [8997,14947] and [1,5986]
|
||||||
|
QUERY PLAN
|
||||||
|
------------------------------------------------------------------------------------------------------
|
||||||
|
Aggregate
|
||||||
|
-> Custom Scan (Citus Real-Time)
|
||||||
|
Task Count: 2
|
||||||
|
Tasks Shown: All
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> Aggregate
|
||||||
|
-> Merge Join
|
||||||
|
Merge Cond: (orders.o_orderkey = lineitem.l_orderkey)
|
||||||
|
-> Index Only Scan using orders_pkey_290003 on orders_290003 orders
|
||||||
|
-> Index Only Scan using lineitem_pkey_290001 on lineitem_290001 lineitem
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57638 dbname=regression
|
||||||
|
-> Aggregate
|
||||||
|
-> Merge Join
|
||||||
|
Merge Cond: (orders.o_orderkey = lineitem.l_orderkey)
|
||||||
|
-> Index Only Scan using orders_pkey_290002 on orders_290002 orders
|
||||||
|
-> Index Only Scan using lineitem_pkey_290000 on lineitem_290000 lineitem
|
||||||
|
(18 rows)
|
||||||
|
|
||||||
|
-- Now set the minimum value for a shard to null. Then check that we don't apply
|
||||||
|
-- partition or join pruning for the shard with null min value. Since it is not
|
||||||
|
-- supported with single-repartition join, dual-repartition has been used.
|
||||||
|
UPDATE pg_dist_shard SET shardminvalue = NULL WHERE shardid = 290000;
|
||||||
|
EXPLAIN (COSTS FALSE)
|
||||||
|
SELECT l_orderkey, l_linenumber, l_shipdate FROM lineitem WHERE l_orderkey = 9030;
|
||||||
|
LOG: join order: [ "lineitem" ]
|
||||||
|
QUERY PLAN
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Custom Scan (Citus Real-Time)
|
||||||
|
Task Count: 2
|
||||||
|
Tasks Shown: All
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> Index Scan using lineitem_pkey_290001 on lineitem_290001 lineitem
|
||||||
|
Index Cond: (l_orderkey = 9030)
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57638 dbname=regression
|
||||||
|
-> Index Scan using lineitem_pkey_290000 on lineitem_290000 lineitem
|
||||||
|
Index Cond: (l_orderkey = 9030)
|
||||||
|
(11 rows)
|
||||||
|
|
||||||
|
EXPLAIN (COSTS FALSE)
|
||||||
|
SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders
|
||||||
|
WHERE l_partkey = o_custkey;
|
||||||
|
LOG: join order: [ "lineitem" ][ dual partition join "orders" ]
|
||||||
|
DEBUG: join prunable for task partitionId 0 and 1
|
||||||
|
DEBUG: join prunable for task partitionId 0 and 2
|
||||||
|
DEBUG: join prunable for task partitionId 0 and 3
|
||||||
|
DEBUG: join prunable for task partitionId 1 and 0
|
||||||
|
DEBUG: join prunable for task partitionId 1 and 2
|
||||||
|
DEBUG: join prunable for task partitionId 1 and 3
|
||||||
|
DEBUG: join prunable for task partitionId 2 and 0
|
||||||
|
DEBUG: join prunable for task partitionId 2 and 1
|
||||||
|
DEBUG: join prunable for task partitionId 2 and 3
|
||||||
|
DEBUG: join prunable for task partitionId 3 and 0
|
||||||
|
DEBUG: join prunable for task partitionId 3 and 1
|
||||||
|
DEBUG: join prunable for task partitionId 3 and 2
|
||||||
|
DEBUG: pruning merge fetch taskId 1
|
||||||
|
DETAIL: Creating dependency on merge taskId 3
|
||||||
|
DEBUG: pruning merge fetch taskId 2
|
||||||
|
DETAIL: Creating dependency on merge taskId 3
|
||||||
|
DEBUG: pruning merge fetch taskId 4
|
||||||
|
DETAIL: Creating dependency on merge taskId 6
|
||||||
|
DEBUG: pruning merge fetch taskId 5
|
||||||
|
DETAIL: Creating dependency on merge taskId 6
|
||||||
|
DEBUG: pruning merge fetch taskId 7
|
||||||
|
DETAIL: Creating dependency on merge taskId 9
|
||||||
|
DEBUG: pruning merge fetch taskId 8
|
||||||
|
DETAIL: Creating dependency on merge taskId 9
|
||||||
|
DEBUG: pruning merge fetch taskId 10
|
||||||
|
DETAIL: Creating dependency on merge taskId 12
|
||||||
|
DEBUG: pruning merge fetch taskId 11
|
||||||
|
DETAIL: Creating dependency on merge taskId 12
|
||||||
|
DEBUG: cannot use real time executor with repartition jobs
|
||||||
|
HINT: Since you enabled citus.enable_repartition_joins Citus chose to use task-tracker.
|
||||||
|
QUERY PLAN
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Aggregate
|
||||||
|
-> Custom Scan (Citus Task-Tracker)
|
||||||
|
Task Count: 4
|
||||||
|
Tasks Shown: None, not supported for re-partition queries
|
||||||
|
-> MapMergeJob
|
||||||
|
Map Task Count: 2
|
||||||
|
Merge Task Count: 4
|
||||||
|
-> MapMergeJob
|
||||||
|
Map Task Count: 2
|
||||||
|
Merge Task Count: 4
|
||||||
|
(10 rows)
|
||||||
|
|
||||||
|
-- Next, set the maximum value for another shard to null. Then check that we
|
||||||
|
-- don't apply partition or join pruning for this other shard either. Since it
|
||||||
|
-- is not supported with single-repartition join, dual-repartition has been used.
|
||||||
|
UPDATE pg_dist_shard SET shardmaxvalue = NULL WHERE shardid = 290001;
|
||||||
|
EXPLAIN (COSTS FALSE)
|
||||||
|
SELECT l_orderkey, l_linenumber, l_shipdate FROM lineitem WHERE l_orderkey = 9030;
|
||||||
|
LOG: join order: [ "lineitem" ]
|
||||||
|
QUERY PLAN
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Custom Scan (Citus Real-Time)
|
||||||
|
Task Count: 2
|
||||||
|
Tasks Shown: All
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> Index Scan using lineitem_pkey_290001 on lineitem_290001 lineitem
|
||||||
|
Index Cond: (l_orderkey = 9030)
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57638 dbname=regression
|
||||||
|
-> Index Scan using lineitem_pkey_290000 on lineitem_290000 lineitem
|
||||||
|
Index Cond: (l_orderkey = 9030)
|
||||||
|
(11 rows)
|
||||||
|
|
||||||
|
EXPLAIN (COSTS FALSE)
|
||||||
|
SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders
|
||||||
|
WHERE l_partkey = o_custkey;
|
||||||
|
LOG: join order: [ "lineitem" ][ dual partition join "orders" ]
|
||||||
|
DEBUG: join prunable for task partitionId 0 and 1
|
||||||
|
DEBUG: join prunable for task partitionId 0 and 2
|
||||||
|
DEBUG: join prunable for task partitionId 0 and 3
|
||||||
|
DEBUG: join prunable for task partitionId 1 and 0
|
||||||
|
DEBUG: join prunable for task partitionId 1 and 2
|
||||||
|
DEBUG: join prunable for task partitionId 1 and 3
|
||||||
|
DEBUG: join prunable for task partitionId 2 and 0
|
||||||
|
DEBUG: join prunable for task partitionId 2 and 1
|
||||||
|
DEBUG: join prunable for task partitionId 2 and 3
|
||||||
|
DEBUG: join prunable for task partitionId 3 and 0
|
||||||
|
DEBUG: join prunable for task partitionId 3 and 1
|
||||||
|
DEBUG: join prunable for task partitionId 3 and 2
|
||||||
|
DEBUG: pruning merge fetch taskId 1
|
||||||
|
DETAIL: Creating dependency on merge taskId 3
|
||||||
|
DEBUG: pruning merge fetch taskId 2
|
||||||
|
DETAIL: Creating dependency on merge taskId 3
|
||||||
|
DEBUG: pruning merge fetch taskId 4
|
||||||
|
DETAIL: Creating dependency on merge taskId 6
|
||||||
|
DEBUG: pruning merge fetch taskId 5
|
||||||
|
DETAIL: Creating dependency on merge taskId 6
|
||||||
|
DEBUG: pruning merge fetch taskId 7
|
||||||
|
DETAIL: Creating dependency on merge taskId 9
|
||||||
|
DEBUG: pruning merge fetch taskId 8
|
||||||
|
DETAIL: Creating dependency on merge taskId 9
|
||||||
|
DEBUG: pruning merge fetch taskId 10
|
||||||
|
DETAIL: Creating dependency on merge taskId 12
|
||||||
|
DEBUG: pruning merge fetch taskId 11
|
||||||
|
DETAIL: Creating dependency on merge taskId 12
|
||||||
|
DEBUG: cannot use real time executor with repartition jobs
|
||||||
|
HINT: Since you enabled citus.enable_repartition_joins Citus chose to use task-tracker.
|
||||||
|
QUERY PLAN
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Aggregate
|
||||||
|
-> Custom Scan (Citus Task-Tracker)
|
||||||
|
Task Count: 4
|
||||||
|
Tasks Shown: None, not supported for re-partition queries
|
||||||
|
-> MapMergeJob
|
||||||
|
Map Task Count: 2
|
||||||
|
Merge Task Count: 4
|
||||||
|
-> MapMergeJob
|
||||||
|
Map Task Count: 2
|
||||||
|
Merge Task Count: 4
|
||||||
|
(10 rows)
|
||||||
|
|
||||||
|
-- Last, set the minimum value to 0 and check that we don't treat it as null. We
|
||||||
|
-- should apply partition and join pruning for this shard now. Since it is not
|
||||||
|
-- supported with single-repartition join, dual-repartition has been used.
|
||||||
|
UPDATE pg_dist_shard SET shardminvalue = '0' WHERE shardid = 290000;
|
||||||
|
EXPLAIN (COSTS FALSE)
|
||||||
|
SELECT l_orderkey, l_linenumber, l_shipdate FROM lineitem WHERE l_orderkey = 9030;
|
||||||
|
LOG: join order: [ "lineitem" ]
|
||||||
|
DEBUG: Plan is router executable
|
||||||
|
QUERY PLAN
|
||||||
|
-------------------------------------------------------------------------------
|
||||||
|
Custom Scan (Citus Router)
|
||||||
|
Task Count: 1
|
||||||
|
Tasks Shown: All
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> Index Scan using lineitem_pkey_290001 on lineitem_290001 lineitem
|
||||||
|
Index Cond: (l_orderkey = 9030)
|
||||||
|
(7 rows)
|
||||||
|
|
||||||
|
EXPLAIN (COSTS FALSE)
|
||||||
|
SELECT sum(l_linenumber), avg(l_linenumber) FROM lineitem, orders
|
||||||
|
WHERE l_partkey = o_custkey;
|
||||||
|
LOG: join order: [ "lineitem" ][ dual partition join "orders" ]
|
||||||
|
DEBUG: join prunable for task partitionId 0 and 1
|
||||||
|
DEBUG: join prunable for task partitionId 0 and 2
|
||||||
|
DEBUG: join prunable for task partitionId 0 and 3
|
||||||
|
DEBUG: join prunable for task partitionId 1 and 0
|
||||||
|
DEBUG: join prunable for task partitionId 1 and 2
|
||||||
|
DEBUG: join prunable for task partitionId 1 and 3
|
||||||
|
DEBUG: join prunable for task partitionId 2 and 0
|
||||||
|
DEBUG: join prunable for task partitionId 2 and 1
|
||||||
|
DEBUG: join prunable for task partitionId 2 and 3
|
||||||
|
DEBUG: join prunable for task partitionId 3 and 0
|
||||||
|
DEBUG: join prunable for task partitionId 3 and 1
|
||||||
|
DEBUG: join prunable for task partitionId 3 and 2
|
||||||
|
DEBUG: pruning merge fetch taskId 1
|
||||||
|
DETAIL: Creating dependency on merge taskId 3
|
||||||
|
DEBUG: pruning merge fetch taskId 2
|
||||||
|
DETAIL: Creating dependency on merge taskId 3
|
||||||
|
DEBUG: pruning merge fetch taskId 4
|
||||||
|
DETAIL: Creating dependency on merge taskId 6
|
||||||
|
DEBUG: pruning merge fetch taskId 5
|
||||||
|
DETAIL: Creating dependency on merge taskId 6
|
||||||
|
DEBUG: pruning merge fetch taskId 7
|
||||||
|
DETAIL: Creating dependency on merge taskId 9
|
||||||
|
DEBUG: pruning merge fetch taskId 8
|
||||||
|
DETAIL: Creating dependency on merge taskId 9
|
||||||
|
DEBUG: pruning merge fetch taskId 10
|
||||||
|
DETAIL: Creating dependency on merge taskId 12
|
||||||
|
DEBUG: pruning merge fetch taskId 11
|
||||||
|
DETAIL: Creating dependency on merge taskId 12
|
||||||
|
DEBUG: cannot use real time executor with repartition jobs
|
||||||
|
HINT: Since you enabled citus.enable_repartition_joins Citus chose to use task-tracker.
|
||||||
|
QUERY PLAN
|
||||||
|
-------------------------------------------------------------------
|
||||||
|
Aggregate
|
||||||
|
-> Custom Scan (Citus Task-Tracker)
|
||||||
|
Task Count: 4
|
||||||
|
Tasks Shown: None, not supported for re-partition queries
|
||||||
|
-> MapMergeJob
|
||||||
|
Map Task Count: 2
|
||||||
|
Merge Task Count: 4
|
||||||
|
-> MapMergeJob
|
||||||
|
Map Task Count: 2
|
||||||
|
Merge Task Count: 4
|
||||||
|
(10 rows)
|
||||||
|
|
||||||
|
-- Set minimum and maximum values for two shards back to their original values
|
||||||
|
UPDATE pg_dist_shard SET shardminvalue = '1' WHERE shardid = 290000;
|
||||||
|
UPDATE pg_dist_shard SET shardmaxvalue = '14947' WHERE shardid = 290001;
|
||||||
|
SET client_min_messages TO NOTICE;
|
|
@ -181,30 +181,30 @@ LIMIT 2;
|
||||||
1
|
1
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
EXPLAIN
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT user_id
|
SELECT user_id
|
||||||
FROM users_table
|
FROM users_table
|
||||||
GROUP BY user_id
|
GROUP BY user_id
|
||||||
ORDER BY (10000 / (sum(value_1 + value_2))) DESC
|
ORDER BY (10000 / (sum(value_1 + value_2))) DESC
|
||||||
LIMIT 2;
|
LIMIT 2;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
---------------------------------------------------------------------------------------------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------
|
||||||
Limit (cost=0.00..0.00 rows=0 width=0)
|
Limit
|
||||||
-> Sort (cost=0.00..0.00 rows=0 width=0)
|
-> Sort
|
||||||
Sort Key: (10000 / (pg_catalog.sum(((10000 / (pg_catalog.sum(remote_scan.worker_column_2))::bigint))))::bigint) DESC
|
Sort Key: (10000 / (pg_catalog.sum(((10000 / (pg_catalog.sum(remote_scan.worker_column_2))::bigint))))::bigint) DESC
|
||||||
-> HashAggregate (cost=0.00..0.00 rows=0 width=0)
|
-> HashAggregate
|
||||||
Group Key: remote_scan.user_id
|
Group Key: remote_scan.user_id
|
||||||
-> Custom Scan (Citus Real-Time) (cost=0.00..0.00 rows=0 width=0)
|
-> Custom Scan (Citus Real-Time)
|
||||||
Task Count: 4
|
Task Count: 4
|
||||||
Tasks Shown: One of 4
|
Tasks Shown: One of 4
|
||||||
-> Task
|
-> Task
|
||||||
Node: host=localhost port=57637 dbname=regression
|
Node: host=localhost port=57637 dbname=regression
|
||||||
-> Limit (cost=1.78..1.78 rows=2 width=20)
|
-> Limit
|
||||||
-> Sort (cost=1.78..1.78 rows=2 width=20)
|
-> Sort
|
||||||
Sort Key: ((10000 / sum((value_1 + value_2)))) DESC
|
Sort Key: ((10000 / sum((value_1 + value_2)))) DESC
|
||||||
-> HashAggregate (cost=1.74..1.77 rows=2 width=20)
|
-> HashAggregate
|
||||||
Group Key: user_id
|
Group Key: user_id
|
||||||
-> Seq Scan on users_table_1400000 users_table (cost=0.00..1.33 rows=33 width=12)
|
-> Seq Scan on users_table_1400000 users_table
|
||||||
(16 rows)
|
(16 rows)
|
||||||
|
|
||||||
SELECT 10000 / (sum(value_1 + value_2))
|
SELECT 10000 / (sum(value_1 + value_2))
|
||||||
|
@ -249,30 +249,30 @@ LIMIT 2;
|
||||||
4
|
4
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
EXPLAIN
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT user_id
|
SELECT user_id
|
||||||
FROM users_table
|
FROM users_table
|
||||||
GROUP BY user_id
|
GROUP BY user_id
|
||||||
ORDER BY sum(value_1) DESC
|
ORDER BY sum(value_1) DESC
|
||||||
LIMIT 2;
|
LIMIT 2;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
--------------------------------------------------------------------------------------------------------------------------------
|
----------------------------------------------------------------------------------------------------------
|
||||||
Limit (cost=0.00..0.00 rows=0 width=0)
|
Limit
|
||||||
-> Sort (cost=0.00..0.00 rows=0 width=0)
|
-> Sort
|
||||||
Sort Key: (pg_catalog.sum(((pg_catalog.sum(remote_scan.worker_column_2))::bigint)))::bigint DESC
|
Sort Key: (pg_catalog.sum(((pg_catalog.sum(remote_scan.worker_column_2))::bigint)))::bigint DESC
|
||||||
-> HashAggregate (cost=0.00..0.00 rows=0 width=0)
|
-> HashAggregate
|
||||||
Group Key: remote_scan.user_id
|
Group Key: remote_scan.user_id
|
||||||
-> Custom Scan (Citus Real-Time) (cost=0.00..0.00 rows=0 width=0)
|
-> Custom Scan (Citus Real-Time)
|
||||||
Task Count: 4
|
Task Count: 4
|
||||||
Tasks Shown: One of 4
|
Tasks Shown: One of 4
|
||||||
-> Task
|
-> Task
|
||||||
Node: host=localhost port=57637 dbname=regression
|
Node: host=localhost port=57637 dbname=regression
|
||||||
-> Limit (cost=1.53..1.53 rows=2 width=12)
|
-> Limit
|
||||||
-> Sort (cost=1.53..1.53 rows=2 width=12)
|
-> Sort
|
||||||
Sort Key: (sum(value_1)) DESC
|
Sort Key: (sum(value_1)) DESC
|
||||||
-> HashAggregate (cost=1.50..1.52 rows=2 width=12)
|
-> HashAggregate
|
||||||
Group Key: user_id
|
Group Key: user_id
|
||||||
-> Seq Scan on users_table_1400000 users_table (cost=0.00..1.33 rows=33 width=8)
|
-> Seq Scan on users_table_1400000 users_table
|
||||||
(16 rows)
|
(16 rows)
|
||||||
|
|
||||||
SELECT ut.user_id, avg(ut.value_2)
|
SELECT ut.user_id, avg(ut.value_2)
|
||||||
|
@ -290,7 +290,7 @@ LIMIT 5;
|
||||||
4 | 2.1739130434782609
|
4 | 2.1739130434782609
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
|
||||||
EXPLAIN
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT ut.user_id, avg(ut.value_2)
|
SELECT ut.user_id, avg(ut.value_2)
|
||||||
FROM users_table ut, events_table et
|
FROM users_table ut, events_table et
|
||||||
WHERE ut.user_id = et.user_id and et.value_2 < 5
|
WHERE ut.user_id = et.user_id and et.value_2 < 5
|
||||||
|
@ -325,7 +325,7 @@ LIMIT 2;
|
||||||
6 | 5
|
6 | 5
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
EXPLAIN
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT ut.user_id, count(DISTINCT ut.value_2)
|
SELECT ut.user_id, count(DISTINCT ut.value_2)
|
||||||
FROM users_table ut, events_table et
|
FROM users_table ut, events_table et
|
||||||
WHERE ut.user_id = et.user_id and et.value_2 < 5
|
WHERE ut.user_id = et.user_id and et.value_2 < 5
|
||||||
|
|
|
@ -4,6 +4,14 @@
|
||||||
SET citus.next_shard_id TO 1660000;
|
SET citus.next_shard_id TO 1660000;
|
||||||
SET citus.shard_count TO 4;
|
SET citus.shard_count TO 4;
|
||||||
SET citus.shard_replication_factor TO 1;
|
SET citus.shard_replication_factor TO 1;
|
||||||
|
-- print major version number for version-specific tests
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int AS server_version;
|
||||||
|
server_version
|
||||||
|
----------------
|
||||||
|
11
|
||||||
|
(1 row)
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Distributed Partitioned Table Creation Tests
|
-- Distributed Partitioned Table Creation Tests
|
||||||
--
|
--
|
||||||
|
@ -299,8 +307,8 @@ SELECT * FROM partitioning_test WHERE id = 7 OR id = 8 ORDER BY 1;
|
||||||
|
|
||||||
-- UPDATE that tries to move a row to a non-existing partition (this should fail)
|
-- UPDATE that tries to move a row to a non-existing partition (this should fail)
|
||||||
UPDATE partitioning_test SET time = '2020-07-07' WHERE id = 7;
|
UPDATE partitioning_test SET time = '2020-07-07' WHERE id = 7;
|
||||||
ERROR: new row for relation "partitioning_test_2013_1660021" violates partition constraint
|
ERROR: no partition of relation "partitioning_test_1660001" found for row
|
||||||
DETAIL: Failing row contains (7, 2020-07-07).
|
DETAIL: Partition key of the failing row contains ("time") = (2020-07-07).
|
||||||
CONTEXT: while executing command on localhost:57638
|
CONTEXT: while executing command on localhost:57638
|
||||||
-- UPDATE with subqueries on partitioned table
|
-- UPDATE with subqueries on partitioned table
|
||||||
UPDATE
|
UPDATE
|
||||||
|
@ -402,19 +410,24 @@ CONTEXT: while executing command on localhost:57638
|
||||||
--
|
--
|
||||||
-- test CREATE INDEX
|
-- test CREATE INDEX
|
||||||
-- CREATE INDEX on partitioned table - this will error out
|
-- CREATE INDEX on partitioned table - this will error out
|
||||||
|
-- on earlier versions of postgres earlier than 11.
|
||||||
CREATE INDEX partitioning_index ON partitioning_test(id);
|
CREATE INDEX partitioning_index ON partitioning_test(id);
|
||||||
ERROR: cannot create index on partitioned table "partitioning_test"
|
|
||||||
-- CREATE INDEX on partition
|
-- CREATE INDEX on partition
|
||||||
CREATE INDEX partitioning_2009_index ON partitioning_test_2009(id);
|
CREATE INDEX partitioning_2009_index ON partitioning_test_2009(id);
|
||||||
-- CREATE INDEX CONCURRENTLY on partition
|
-- CREATE INDEX CONCURRENTLY on partition
|
||||||
CREATE INDEX CONCURRENTLY partitioned_2010_index ON partitioning_test_2010(id);
|
CREATE INDEX CONCURRENTLY partitioned_2010_index ON partitioning_test_2010(id);
|
||||||
-- see index is created
|
-- see index is created
|
||||||
SELECT tablename, indexname FROM pg_indexes WHERE tablename LIKE 'partitioning_test%' ORDER BY indexname;
|
SELECT tablename, indexname FROM pg_indexes WHERE tablename LIKE 'partitioning_test%' ORDER BY indexname;
|
||||||
tablename | indexname
|
tablename | indexname
|
||||||
------------------------+-------------------------
|
------------------------+-------------------------------
|
||||||
partitioning_test_2010 | partitioned_2010_index
|
partitioning_test_2010 | partitioned_2010_index
|
||||||
partitioning_test_2009 | partitioning_2009_index
|
partitioning_test_2009 | partitioning_2009_index
|
||||||
(2 rows)
|
partitioning_test_2009 | partitioning_test_2009_id_idx
|
||||||
|
partitioning_test_2010 | partitioning_test_2010_id_idx
|
||||||
|
partitioning_test_2011 | partitioning_test_2011_id_idx
|
||||||
|
partitioning_test_2012 | partitioning_test_2012_id_idx
|
||||||
|
partitioning_test_2013 | partitioning_test_2013_id_idx
|
||||||
|
(7 rows)
|
||||||
|
|
||||||
-- test add COLUMN
|
-- test add COLUMN
|
||||||
-- add COLUMN to partitioned table
|
-- add COLUMN to partitioned table
|
||||||
|
@ -442,9 +455,8 @@ SELECT name, type FROM table_attrs WHERE relid = 'partitioning_test_2010'::regcl
|
||||||
-- test add PRIMARY KEY
|
-- test add PRIMARY KEY
|
||||||
-- add PRIMARY KEY to partitioned table - this will error out
|
-- add PRIMARY KEY to partitioned table - this will error out
|
||||||
ALTER TABLE partitioning_test ADD CONSTRAINT partitioning_primary PRIMARY KEY (id);
|
ALTER TABLE partitioning_test ADD CONSTRAINT partitioning_primary PRIMARY KEY (id);
|
||||||
ERROR: primary key constraints are not supported on partitioned tables
|
ERROR: insufficient columns in PRIMARY KEY constraint definition
|
||||||
LINE 1: ALTER TABLE partitioning_test ADD CONSTRAINT partitioning_pr...
|
DETAIL: PRIMARY KEY constraint on table "partitioning_test" lacks column "time" which is part of the partition key.
|
||||||
^
|
|
||||||
-- ADD PRIMARY KEY to partition
|
-- ADD PRIMARY KEY to partition
|
||||||
ALTER TABLE partitioning_test_2009 ADD CONSTRAINT partitioning_2009_primary PRIMARY KEY (id);
|
ALTER TABLE partitioning_test_2009 ADD CONSTRAINT partitioning_2009_primary PRIMARY KEY (id);
|
||||||
-- see PRIMARY KEY is created
|
-- see PRIMARY KEY is created
|
||||||
|
@ -465,9 +477,7 @@ WHERE
|
||||||
-- test ADD FOREIGN CONSTRAINT
|
-- test ADD FOREIGN CONSTRAINT
|
||||||
-- add FOREIGN CONSTRAINT to partitioned table -- this will error out
|
-- add FOREIGN CONSTRAINT to partitioned table -- this will error out
|
||||||
ALTER TABLE partitioning_test ADD CONSTRAINT partitioning_foreign FOREIGN KEY (id) REFERENCES partitioning_test_2009 (id);
|
ALTER TABLE partitioning_test ADD CONSTRAINT partitioning_foreign FOREIGN KEY (id) REFERENCES partitioning_test_2009 (id);
|
||||||
ERROR: foreign key constraints are not supported on partitioned tables
|
ERROR: cannot ALTER TABLE "partitioning_test_2009" because it is being used by active queries in this session
|
||||||
LINE 1: ALTER TABLE partitioning_test ADD CONSTRAINT partitioning_fo...
|
|
||||||
^
|
|
||||||
-- add FOREIGN CONSTRAINT to partition
|
-- add FOREIGN CONSTRAINT to partition
|
||||||
INSERT INTO partitioning_test_2009 VALUES (5, '2009-06-06');
|
INSERT INTO partitioning_test_2009 VALUES (5, '2009-06-06');
|
||||||
INSERT INTO partitioning_test_2009 VALUES (6, '2009-07-07');
|
INSERT INTO partitioning_test_2009 VALUES (6, '2009-07-07');
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,3 +1,11 @@
|
||||||
|
-- This test has different output per major version
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int as server_major_version;
|
||||||
|
server_major_version
|
||||||
|
----------------------
|
||||||
|
11
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- ===================================================================
|
-- ===================================================================
|
||||||
-- create test functions
|
-- create test functions
|
||||||
-- ===================================================================
|
-- ===================================================================
|
||||||
|
@ -191,6 +199,7 @@ SELECT worker_apply_inter_shard_ddl_command(referencing_shard:=100, referencing_
|
||||||
id | integer | | | | plain | |
|
id | integer | | | | plain | |
|
||||||
time | date | | | | plain | |
|
time | date | | | | plain | |
|
||||||
Partition key: RANGE ("time")
|
Partition key: RANGE ("time")
|
||||||
|
Number of partitions: 0
|
||||||
|
|
||||||
-- now lets have some more complex partitioning hierarcies with
|
-- now lets have some more complex partitioning hierarcies with
|
||||||
-- tables on different schemas and constraints on the tables
|
-- tables on different schemas and constraints on the tables
|
||||||
|
|
|
@ -1,3 +1,11 @@
|
||||||
|
-- This test has different output per major version
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int as server_major_version;
|
||||||
|
server_major_version
|
||||||
|
----------------------
|
||||||
|
10
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- ===================================================================
|
-- ===================================================================
|
||||||
-- create test functions
|
-- create test functions
|
||||||
-- ===================================================================
|
-- ===================================================================
|
||||||
|
@ -72,69 +80,101 @@ END;
|
||||||
$function$;
|
$function$;
|
||||||
-- create a partitioned table
|
-- create a partitioned table
|
||||||
CREATE TABLE date_partitioned_table(id int, time date) PARTITION BY RANGE (time);
|
CREATE TABLE date_partitioned_table(id int, time date) PARTITION BY RANGE (time);
|
||||||
ERROR: syntax error at or near "PARTITION"
|
|
||||||
LINE 1: ...E TABLE date_partitioned_table(id int, time date) PARTITION ...
|
|
||||||
^
|
|
||||||
-- we should be able to get the partitioning information even if there are no partitions
|
-- we should be able to get the partitioning information even if there are no partitions
|
||||||
SELECT generate_partition_information('date_partitioned_table');
|
SELECT generate_partition_information('date_partitioned_table');
|
||||||
ERROR: relation "date_partitioned_table" does not exist
|
generate_partition_information
|
||||||
LINE 1: SELECT generate_partition_information('date_partitioned_tabl...
|
--------------------------------
|
||||||
^
|
RANGE ("time")
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- we should be able to drop and re-create the partitioned table using the command that Citus generate
|
-- we should be able to drop and re-create the partitioned table using the command that Citus generate
|
||||||
SELECT drop_and_recreate_partitioned_table('date_partitioned_table');
|
SELECT drop_and_recreate_partitioned_table('date_partitioned_table');
|
||||||
ERROR: relation "date_partitioned_table" does not exist
|
drop_and_recreate_partitioned_table
|
||||||
LINE 1: SELECT drop_and_recreate_partitioned_table('date_partitioned...
|
-------------------------------------
|
||||||
^
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- we should also be able to see the PARTITION BY ... for the parent table
|
-- we should also be able to see the PARTITION BY ... for the parent table
|
||||||
SELECT master_get_table_ddl_events('date_partitioned_table');
|
SELECT master_get_table_ddl_events('date_partitioned_table');
|
||||||
ERROR: relation "date_partitioned_table" does not exist
|
master_get_table_ddl_events
|
||||||
|
---------------------------------------------------------------------------------------------------
|
||||||
|
CREATE TABLE public.date_partitioned_table (id integer, "time" date) PARTITION BY RANGE ("time")
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- now create the partitions
|
-- now create the partitions
|
||||||
CREATE TABLE date_partition_2006 PARTITION OF date_partitioned_table FOR VALUES FROM ('2006-01-01') TO ('2007-01-01');
|
CREATE TABLE date_partition_2006 PARTITION OF date_partitioned_table FOR VALUES FROM ('2006-01-01') TO ('2007-01-01');
|
||||||
ERROR: syntax error at or near "PARTITION"
|
|
||||||
LINE 1: CREATE TABLE date_partition_2006 PARTITION OF date_partition...
|
|
||||||
^
|
|
||||||
CREATE TABLE date_partition_2007 PARTITION OF date_partitioned_table FOR VALUES FROM ('2007-01-01') TO ('2008-01-01');
|
CREATE TABLE date_partition_2007 PARTITION OF date_partitioned_table FOR VALUES FROM ('2007-01-01') TO ('2008-01-01');
|
||||||
ERROR: syntax error at or near "PARTITION"
|
|
||||||
LINE 1: CREATE TABLE date_partition_2007 PARTITION OF date_partition...
|
|
||||||
^
|
|
||||||
-- we should be able to get the partitioning information after the partitions are created
|
-- we should be able to get the partitioning information after the partitions are created
|
||||||
SELECT generate_partition_information('date_partitioned_table');
|
SELECT generate_partition_information('date_partitioned_table');
|
||||||
ERROR: relation "date_partitioned_table" does not exist
|
generate_partition_information
|
||||||
LINE 1: SELECT generate_partition_information('date_partitioned_tabl...
|
--------------------------------
|
||||||
^
|
RANGE ("time")
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- lets get the attach partition commands
|
-- lets get the attach partition commands
|
||||||
SELECT generate_alter_table_attach_partition_command('date_partition_2006');
|
SELECT generate_alter_table_attach_partition_command('date_partition_2006');
|
||||||
ERROR: relation "date_partition_2006" does not exist
|
generate_alter_table_attach_partition_command
|
||||||
LINE 1: ...ECT generate_alter_table_attach_partition_command('date_part...
|
-----------------------------------------------------------------------------------------------------------------------------------------
|
||||||
^
|
ALTER TABLE public.date_partitioned_table ATTACH PARTITION public.date_partition_2006 FOR VALUES FROM ('01-01-2006') TO ('01-01-2007');
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT generate_alter_table_attach_partition_command('date_partition_2007');
|
SELECT generate_alter_table_attach_partition_command('date_partition_2007');
|
||||||
ERROR: relation "date_partition_2007" does not exist
|
generate_alter_table_attach_partition_command
|
||||||
LINE 1: ...ECT generate_alter_table_attach_partition_command('date_part...
|
-----------------------------------------------------------------------------------------------------------------------------------------
|
||||||
^
|
ALTER TABLE public.date_partitioned_table ATTACH PARTITION public.date_partition_2007 FOR VALUES FROM ('01-01-2007') TO ('01-01-2008');
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- detach and attach the partition by the command generated by us
|
-- detach and attach the partition by the command generated by us
|
||||||
\d+ date_partitioned_table
|
\d+ date_partitioned_table
|
||||||
|
Table "public.date_partitioned_table"
|
||||||
|
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
|
||||||
|
--------+---------+-----------+----------+---------+---------+--------------+-------------
|
||||||
|
id | integer | | | | plain | |
|
||||||
|
time | date | | | | plain | |
|
||||||
|
Partition key: RANGE ("time")
|
||||||
|
Partitions: date_partition_2006 FOR VALUES FROM ('01-01-2006') TO ('01-01-2007'),
|
||||||
|
date_partition_2007 FOR VALUES FROM ('01-01-2007') TO ('01-01-2008')
|
||||||
|
|
||||||
SELECT detach_and_attach_partition('date_partition_2007', 'date_partitioned_table');
|
SELECT detach_and_attach_partition('date_partition_2007', 'date_partitioned_table');
|
||||||
ERROR: relation "date_partition_2007" does not exist
|
detach_and_attach_partition
|
||||||
LINE 1: SELECT detach_and_attach_partition('date_partition_2007', 'd...
|
-----------------------------
|
||||||
^
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- check that both partitions are visiable
|
-- check that both partitions are visiable
|
||||||
\d+ date_partitioned_table
|
\d+ date_partitioned_table
|
||||||
|
Table "public.date_partitioned_table"
|
||||||
|
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
|
||||||
|
--------+---------+-----------+----------+---------+---------+--------------+-------------
|
||||||
|
id | integer | | | | plain | |
|
||||||
|
time | date | | | | plain | |
|
||||||
|
Partition key: RANGE ("time")
|
||||||
|
Partitions: date_partition_2006 FOR VALUES FROM ('01-01-2006') TO ('01-01-2007'),
|
||||||
|
date_partition_2007 FOR VALUES FROM ('01-01-2007') TO ('01-01-2008')
|
||||||
|
|
||||||
-- make sure that inter shard commands work as expected
|
-- make sure that inter shard commands work as expected
|
||||||
-- assume that the shardId is 100
|
-- assume that the shardId is 100
|
||||||
CREATE TABLE date_partitioned_table_100 (id int, time date) PARTITION BY RANGE (time);
|
CREATE TABLE date_partitioned_table_100 (id int, time date) PARTITION BY RANGE (time);
|
||||||
ERROR: syntax error at or near "PARTITION"
|
|
||||||
LINE 1: ...LE date_partitioned_table_100 (id int, time date) PARTITION ...
|
|
||||||
^
|
|
||||||
CREATE TABLE date_partition_2007_100 (id int, time date );
|
CREATE TABLE date_partition_2007_100 (id int, time date );
|
||||||
-- now create the partitioning hierarcy
|
-- now create the partitioning hierarcy
|
||||||
SELECT worker_apply_inter_shard_ddl_command(referencing_shard:=100, referencing_schema_name:='public',
|
SELECT worker_apply_inter_shard_ddl_command(referencing_shard:=100, referencing_schema_name:='public',
|
||||||
referenced_shard:=100, referenced_schema_name:='public',
|
referenced_shard:=100, referenced_schema_name:='public',
|
||||||
command:='ALTER TABLE date_partitioned_table ATTACH PARTITION date_partition_2007 FOR VALUES FROM (''2007-01-01'') TO (''2008-01-02'')' );
|
command:='ALTER TABLE date_partitioned_table ATTACH PARTITION date_partition_2007 FOR VALUES FROM (''2007-01-01'') TO (''2008-01-02'')' );
|
||||||
ERROR: syntax error at or near "ATTACH"
|
worker_apply_inter_shard_ddl_command
|
||||||
LINE 1: SELECT worker_apply_inter_shard_ddl_command(referencing_shar...
|
--------------------------------------
|
||||||
^
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- the hierarcy is successfully created
|
-- the hierarcy is successfully created
|
||||||
\d+ date_partitioned_table_100
|
\d+ date_partitioned_table_100
|
||||||
|
Table "public.date_partitioned_table_100"
|
||||||
|
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
|
||||||
|
--------+---------+-----------+----------+---------+---------+--------------+-------------
|
||||||
|
id | integer | | | | plain | |
|
||||||
|
time | date | | | | plain | |
|
||||||
|
Partition key: RANGE ("time")
|
||||||
|
Partitions: date_partition_2007_100 FOR VALUES FROM ('01-01-2007') TO ('01-02-2008')
|
||||||
|
|
||||||
-- Citus can also get the DDL events for the partitions as regular tables
|
-- Citus can also get the DDL events for the partitions as regular tables
|
||||||
SELECT master_get_table_ddl_events('date_partition_2007_100');
|
SELECT master_get_table_ddl_events('date_partition_2007_100');
|
||||||
master_get_table_ddl_events
|
master_get_table_ddl_events
|
||||||
|
@ -146,90 +186,111 @@ SELECT master_get_table_ddl_events('date_partition_2007_100');
|
||||||
SELECT worker_apply_inter_shard_ddl_command(referencing_shard:=100, referencing_schema_name:='public',
|
SELECT worker_apply_inter_shard_ddl_command(referencing_shard:=100, referencing_schema_name:='public',
|
||||||
referenced_shard:=100, referenced_schema_name:='public',
|
referenced_shard:=100, referenced_schema_name:='public',
|
||||||
command:='ALTER TABLE date_partitioned_table DETACH PARTITION date_partition_2007' );
|
command:='ALTER TABLE date_partitioned_table DETACH PARTITION date_partition_2007' );
|
||||||
ERROR: syntax error at or near "DETACH"
|
worker_apply_inter_shard_ddl_command
|
||||||
LINE 1: SELECT worker_apply_inter_shard_ddl_command(referencing_shar...
|
--------------------------------------
|
||||||
^
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- the hierarcy is successfully broken
|
-- the hierarcy is successfully broken
|
||||||
\d+ date_partitioned_table_100
|
\d+ date_partitioned_table_100
|
||||||
|
Table "public.date_partitioned_table_100"
|
||||||
|
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
|
||||||
|
--------+---------+-----------+----------+---------+---------+--------------+-------------
|
||||||
|
id | integer | | | | plain | |
|
||||||
|
time | date | | | | plain | |
|
||||||
|
Partition key: RANGE ("time")
|
||||||
|
|
||||||
-- now lets have some more complex partitioning hierarcies with
|
-- now lets have some more complex partitioning hierarcies with
|
||||||
-- tables on different schemas and constraints on the tables
|
-- tables on different schemas and constraints on the tables
|
||||||
CREATE SCHEMA partition_parent_schema;
|
CREATE SCHEMA partition_parent_schema;
|
||||||
CREATE TABLE partition_parent_schema.parent_table (id int NOT NULL, time date DEFAULT now()) PARTITION BY RANGE (time);
|
CREATE TABLE partition_parent_schema.parent_table (id int NOT NULL, time date DEFAULT now()) PARTITION BY RANGE (time);
|
||||||
ERROR: syntax error at or near "PARTITION"
|
|
||||||
LINE 1: ..._table (id int NOT NULL, time date DEFAULT now()) PARTITION ...
|
|
||||||
^
|
|
||||||
CREATE SCHEMA partition_child_1_schema;
|
CREATE SCHEMA partition_child_1_schema;
|
||||||
CREATE TABLE partition_child_1_schema.child_1 (id int NOT NULL, time date );
|
CREATE TABLE partition_child_1_schema.child_1 (id int NOT NULL, time date );
|
||||||
CREATE SCHEMA partition_child_2_schema;
|
CREATE SCHEMA partition_child_2_schema;
|
||||||
CREATE TABLE partition_child_2_schema.child_2 (id int NOT NULL, time date );
|
CREATE TABLE partition_child_2_schema.child_2 (id int NOT NULL, time date );
|
||||||
-- we should be able to get the partitioning information even if there are no partitions
|
-- we should be able to get the partitioning information even if there are no partitions
|
||||||
SELECT generate_partition_information('partition_parent_schema.parent_table');
|
SELECT generate_partition_information('partition_parent_schema.parent_table');
|
||||||
ERROR: relation "partition_parent_schema.parent_table" does not exist
|
generate_partition_information
|
||||||
LINE 1: SELECT generate_partition_information('partition_parent_sche...
|
--------------------------------
|
||||||
^
|
RANGE ("time")
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- we should be able to drop and re-create the partitioned table using the command that Citus generate
|
-- we should be able to drop and re-create the partitioned table using the command that Citus generate
|
||||||
SELECT drop_and_recreate_partitioned_table('partition_parent_schema.parent_table');
|
SELECT drop_and_recreate_partitioned_table('partition_parent_schema.parent_table');
|
||||||
ERROR: relation "partition_parent_schema.parent_table" does not exist
|
NOTICE: schema "partition_parent_schema" already exists, skipping
|
||||||
LINE 1: SELECT drop_and_recreate_partitioned_table('partition_parent...
|
CONTEXT: SQL statement "CREATE SCHEMA IF NOT EXISTS partition_parent_schema AUTHORIZATION postgres"
|
||||||
^
|
PL/pgSQL function drop_and_recreate_partitioned_table(regclass) line 15 at EXECUTE
|
||||||
|
drop_and_recreate_partitioned_table
|
||||||
|
-------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
ALTER TABLE partition_parent_schema.parent_table ATTACH PARTITION partition_child_1_schema.child_1 FOR VALUES FROM ('2009-01-01') TO ('2010-01-02');
|
ALTER TABLE partition_parent_schema.parent_table ATTACH PARTITION partition_child_1_schema.child_1 FOR VALUES FROM ('2009-01-01') TO ('2010-01-02');
|
||||||
ERROR: syntax error at or near "ATTACH"
|
|
||||||
LINE 1: ALTER TABLE partition_parent_schema.parent_table ATTACH PART...
|
|
||||||
^
|
|
||||||
SET search_path = 'partition_parent_schema';
|
SET search_path = 'partition_parent_schema';
|
||||||
ALTER TABLE parent_table ATTACH PARTITION partition_child_2_schema.child_2 FOR VALUES FROM ('2006-01-01') TO ('2007-01-01');
|
ALTER TABLE parent_table ATTACH PARTITION partition_child_2_schema.child_2 FOR VALUES FROM ('2006-01-01') TO ('2007-01-01');
|
||||||
ERROR: syntax error at or near "ATTACH"
|
|
||||||
LINE 1: ALTER TABLE parent_table ATTACH PARTITION partition_child_2...
|
|
||||||
^
|
|
||||||
SELECT public.generate_partition_information('parent_table');
|
SELECT public.generate_partition_information('parent_table');
|
||||||
ERROR: relation "parent_table" does not exist
|
generate_partition_information
|
||||||
LINE 1: SELECT public.generate_partition_information('parent_table')...
|
--------------------------------
|
||||||
^
|
RANGE ("time")
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- lets get the attach partition commands
|
-- lets get the attach partition commands
|
||||||
SELECT public.generate_alter_table_attach_partition_command('partition_child_1_schema.child_1');
|
SELECT public.generate_alter_table_attach_partition_command('partition_child_1_schema.child_1');
|
||||||
generate_alter_table_attach_partition_command
|
generate_alter_table_attach_partition_command
|
||||||
-----------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
ALTER TABLE partition_parent_schema.parent_table ATTACH PARTITION partition_child_1_schema.child_1 FOR VALUES FROM ('01-01-2009') TO ('01-02-2010');
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SET search_path = 'partition_child_2_schema';
|
SET search_path = 'partition_child_2_schema';
|
||||||
SELECT public.generate_alter_table_attach_partition_command('child_2');
|
SELECT public.generate_alter_table_attach_partition_command('child_2');
|
||||||
generate_alter_table_attach_partition_command
|
generate_alter_table_attach_partition_command
|
||||||
-----------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
ALTER TABLE partition_parent_schema.parent_table ATTACH PARTITION partition_child_2_schema.child_2 FOR VALUES FROM ('01-01-2006') TO ('01-01-2007');
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SET search_path = 'partition_parent_schema';
|
SET search_path = 'partition_parent_schema';
|
||||||
-- detach and attach the partition by the command generated by us
|
-- detach and attach the partition by the command generated by us
|
||||||
\d+ parent_table
|
\d+ parent_table
|
||||||
|
Table "partition_parent_schema.parent_table"
|
||||||
|
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
|
||||||
|
--------+---------+-----------+----------+---------+---------+--------------+-------------
|
||||||
|
id | integer | | not null | | plain | |
|
||||||
|
time | date | | | now() | plain | |
|
||||||
|
Partition key: RANGE ("time")
|
||||||
|
Partitions: partition_child_1_schema.child_1 FOR VALUES FROM ('01-01-2009') TO ('01-02-2010'),
|
||||||
|
partition_child_2_schema.child_2 FOR VALUES FROM ('01-01-2006') TO ('01-01-2007')
|
||||||
|
|
||||||
SELECT public.detach_and_attach_partition('partition_child_1_schema.child_1', 'parent_table');
|
SELECT public.detach_and_attach_partition('partition_child_1_schema.child_1', 'parent_table');
|
||||||
ERROR: relation "parent_table" does not exist
|
detach_and_attach_partition
|
||||||
LINE 1: ...ach_partition('partition_child_1_schema.child_1', 'parent_ta...
|
-----------------------------
|
||||||
^
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- check that both partitions are visiable
|
-- check that both partitions are visiable
|
||||||
\d+ parent_table
|
\d+ parent_table
|
||||||
|
Table "partition_parent_schema.parent_table"
|
||||||
|
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
|
||||||
|
--------+---------+-----------+----------+---------+---------+--------------+-------------
|
||||||
|
id | integer | | not null | | plain | |
|
||||||
|
time | date | | | now() | plain | |
|
||||||
|
Partition key: RANGE ("time")
|
||||||
|
Partitions: partition_child_1_schema.child_1 FOR VALUES FROM ('01-01-2009') TO ('01-02-2010'),
|
||||||
|
partition_child_2_schema.child_2 FOR VALUES FROM ('01-01-2006') TO ('01-01-2007')
|
||||||
|
|
||||||
-- some very simple checks that should error out
|
-- some very simple checks that should error out
|
||||||
SELECT public.generate_alter_table_attach_partition_command('parent_table');
|
SELECT public.generate_alter_table_attach_partition_command('parent_table');
|
||||||
ERROR: relation "parent_table" does not exist
|
ERROR: "parent_table" is not a partition
|
||||||
LINE 1: ...lic.generate_alter_table_attach_partition_command('parent_ta...
|
|
||||||
^
|
|
||||||
SELECT public.generate_partition_information('partition_child_1_schema.child_1');
|
SELECT public.generate_partition_information('partition_child_1_schema.child_1');
|
||||||
generate_partition_information
|
ERROR: "child_1" is not a parent table
|
||||||
--------------------------------
|
|
||||||
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
SELECT public.print_partitions('partition_child_1_schema.child_1');
|
SELECT public.print_partitions('partition_child_1_schema.child_1');
|
||||||
print_partitions
|
ERROR: "child_1" is not a parent table
|
||||||
------------------
|
|
||||||
|
|
||||||
(1 row)
|
|
||||||
|
|
||||||
-- now pring the partitions
|
-- now pring the partitions
|
||||||
SELECT public.print_partitions('parent_table');
|
SELECT public.print_partitions('parent_table');
|
||||||
ERROR: relation "parent_table" does not exist
|
print_partitions
|
||||||
LINE 1: SELECT public.print_partitions('parent_table');
|
------------------
|
||||||
^
|
child_1,child_2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SET search_path = 'public';
|
SET search_path = 'public';
|
||||||
-- test multi column / expression partitioning with UNBOUNDED ranges
|
-- test multi column / expression partitioning with UNBOUNDED ranges
|
||||||
CREATE OR REPLACE FUNCTION some_function(input_val text)
|
CREATE OR REPLACE FUNCTION some_function(input_val text)
|
||||||
|
@ -244,9 +305,6 @@ CREATE TABLE multi_column_partitioned (
|
||||||
b int,
|
b int,
|
||||||
c text
|
c text
|
||||||
) PARTITION BY RANGE (a, (a+b+1), some_function(upper(c)));
|
) PARTITION BY RANGE (a, (a+b+1), some_function(upper(c)));
|
||||||
ERROR: syntax error at or near "PARTITION"
|
|
||||||
LINE 5: ) PARTITION BY RANGE (a, (a+b+1), some_function(upper(c)));
|
|
||||||
^
|
|
||||||
CREATE TABLE multi_column_partition_1(
|
CREATE TABLE multi_column_partition_1(
|
||||||
a int,
|
a int,
|
||||||
b int,
|
b int,
|
||||||
|
@ -259,65 +317,71 @@ CREATE TABLE multi_column_partition_2(
|
||||||
);
|
);
|
||||||
-- partitioning information
|
-- partitioning information
|
||||||
SELECT generate_partition_information('multi_column_partitioned');
|
SELECT generate_partition_information('multi_column_partitioned');
|
||||||
ERROR: relation "multi_column_partitioned" does not exist
|
generate_partition_information
|
||||||
LINE 1: SELECT generate_partition_information('multi_column_partitio...
|
-----------------------------------------------------
|
||||||
^
|
RANGE (a, (((a + b) + 1)), some_function(upper(c)))
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT master_get_table_ddl_events('multi_column_partitioned');
|
SELECT master_get_table_ddl_events('multi_column_partitioned');
|
||||||
ERROR: relation "multi_column_partitioned" does not exist
|
master_get_table_ddl_events
|
||||||
|
------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
CREATE TABLE public.multi_column_partitioned (a integer, b integer, c text) PARTITION BY RANGE (a, (((a + b) + 1)), public.some_function(upper(c)))
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT drop_and_recreate_partitioned_table('multi_column_partitioned');
|
SELECT drop_and_recreate_partitioned_table('multi_column_partitioned');
|
||||||
ERROR: relation "multi_column_partitioned" does not exist
|
drop_and_recreate_partitioned_table
|
||||||
LINE 1: SELECT drop_and_recreate_partitioned_table('multi_column_par...
|
-------------------------------------
|
||||||
^
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- partitions and their ranges
|
-- partitions and their ranges
|
||||||
ALTER TABLE multi_column_partitioned ATTACH PARTITION multi_column_partition_1 FOR VALUES FROM (1, 10, '250') TO (1, 20, '250');
|
ALTER TABLE multi_column_partitioned ATTACH PARTITION multi_column_partition_1 FOR VALUES FROM (1, 10, '250') TO (1, 20, '250');
|
||||||
ERROR: syntax error at or near "ATTACH"
|
|
||||||
LINE 1: ALTER TABLE multi_column_partitioned ATTACH PARTITION multi_...
|
|
||||||
^
|
|
||||||
SELECT generate_alter_table_attach_partition_command('multi_column_partition_1');
|
SELECT generate_alter_table_attach_partition_command('multi_column_partition_1');
|
||||||
generate_alter_table_attach_partition_command
|
generate_alter_table_attach_partition_command
|
||||||
-----------------------------------------------
|
------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
ALTER TABLE public.multi_column_partitioned ATTACH PARTITION public.multi_column_partition_1 FOR VALUES FROM (1, 10, '250') TO (1, 20, '250');
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
ALTER TABLE multi_column_partitioned ATTACH PARTITION multi_column_partition_2 FOR VALUES FROM (10, 1000, '2500') TO (MAXVALUE, MAXVALUE, MAXVALUE);
|
ALTER TABLE multi_column_partitioned ATTACH PARTITION multi_column_partition_2 FOR VALUES FROM (10, 1000, '2500') TO (MAXVALUE, MAXVALUE, MAXVALUE);
|
||||||
ERROR: syntax error at or near "ATTACH"
|
|
||||||
LINE 1: ALTER TABLE multi_column_partitioned ATTACH PARTITION multi_...
|
|
||||||
^
|
|
||||||
SELECT generate_alter_table_attach_partition_command('multi_column_partition_2');
|
SELECT generate_alter_table_attach_partition_command('multi_column_partition_2');
|
||||||
generate_alter_table_attach_partition_command
|
generate_alter_table_attach_partition_command
|
||||||
-----------------------------------------------
|
--------------------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
ALTER TABLE public.multi_column_partitioned ATTACH PARTITION public.multi_column_partition_2 FOR VALUES FROM (10, 1000, '2500') TO (MAXVALUE, MAXVALUE, MAXVALUE);
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
SELECT generate_alter_table_detach_partition_command('multi_column_partition_2');
|
SELECT generate_alter_table_detach_partition_command('multi_column_partition_2');
|
||||||
generate_alter_table_detach_partition_command
|
generate_alter_table_detach_partition_command
|
||||||
-----------------------------------------------
|
---------------------------------------------------------------------------------------------------------
|
||||||
|
ALTER TABLE IF EXISTS public.multi_column_partitioned DETACH PARTITION public.multi_column_partition_2;
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
-- finally a test with LIST partitioning
|
-- finally a test with LIST partitioning
|
||||||
CREATE TABLE list_partitioned (col1 NUMERIC, col2 NUMERIC, col3 VARCHAR(10)) PARTITION BY LIST (col1) ;
|
CREATE TABLE list_partitioned (col1 NUMERIC, col2 NUMERIC, col3 VARCHAR(10)) PARTITION BY LIST (col1) ;
|
||||||
ERROR: syntax error at or near "PARTITION"
|
|
||||||
LINE 1: ...ed (col1 NUMERIC, col2 NUMERIC, col3 VARCHAR(10)) PARTITION ...
|
|
||||||
^
|
|
||||||
SELECT generate_partition_information('list_partitioned');
|
SELECT generate_partition_information('list_partitioned');
|
||||||
ERROR: relation "list_partitioned" does not exist
|
generate_partition_information
|
||||||
LINE 1: SELECT generate_partition_information('list_partitioned');
|
--------------------------------
|
||||||
^
|
LIST (col1)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT master_get_table_ddl_events('list_partitioned');
|
SELECT master_get_table_ddl_events('list_partitioned');
|
||||||
ERROR: relation "list_partitioned" does not exist
|
master_get_table_ddl_events
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------
|
||||||
|
CREATE TABLE public.list_partitioned (col1 numeric, col2 numeric, col3 character varying(10)) PARTITION BY LIST (col1)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT drop_and_recreate_partitioned_table('list_partitioned');
|
SELECT drop_and_recreate_partitioned_table('list_partitioned');
|
||||||
ERROR: relation "list_partitioned" does not exist
|
drop_and_recreate_partitioned_table
|
||||||
LINE 1: SELECT drop_and_recreate_partitioned_table('list_partitioned...
|
-------------------------------------
|
||||||
^
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
CREATE TABLE list_partitioned_1 PARTITION OF list_partitioned FOR VALUES IN (100, 101, 102, 103, 104);
|
CREATE TABLE list_partitioned_1 PARTITION OF list_partitioned FOR VALUES IN (100, 101, 102, 103, 104);
|
||||||
ERROR: syntax error at or near "PARTITION"
|
|
||||||
LINE 1: CREATE TABLE list_partitioned_1 PARTITION OF list_partitione...
|
|
||||||
^
|
|
||||||
SELECT generate_alter_table_attach_partition_command('list_partitioned_1');
|
SELECT generate_alter_table_attach_partition_command('list_partitioned_1');
|
||||||
ERROR: relation "list_partitioned_1" does not exist
|
generate_alter_table_attach_partition_command
|
||||||
LINE 1: ...ECT generate_alter_table_attach_partition_command('list_part...
|
-----------------------------------------------------------------------------------------------------------------------------------
|
||||||
^
|
ALTER TABLE public.list_partitioned ATTACH PARTITION public.list_partitioned_1 FOR VALUES IN ('100', '101', '102', '103', '104');
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- also differentiate partitions and inhereted tables
|
-- also differentiate partitions and inhereted tables
|
||||||
CREATE TABLE cities (
|
CREATE TABLE cities (
|
||||||
name text,
|
name text,
|
||||||
|
@ -337,9 +401,11 @@ SELECT table_inherits('capitals');
|
||||||
-- although date_partition_2006 inherits from its parent
|
-- although date_partition_2006 inherits from its parent
|
||||||
-- returns false since the hierarcy is formed via partitioning
|
-- returns false since the hierarcy is formed via partitioning
|
||||||
SELECT table_inherits('date_partition_2006');
|
SELECT table_inherits('date_partition_2006');
|
||||||
ERROR: relation "date_partition_2006" does not exist
|
table_inherits
|
||||||
LINE 1: SELECT table_inherits('date_partition_2006');
|
----------------
|
||||||
^
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- returns true since cities inherited by capitals
|
-- returns true since cities inherited by capitals
|
||||||
SELECT table_inherited('cities');
|
SELECT table_inherited('cities');
|
||||||
table_inherited
|
table_inherited
|
||||||
|
@ -350,9 +416,11 @@ SELECT table_inherited('cities');
|
||||||
-- although date_partitioned_table inherited by its partitions
|
-- although date_partitioned_table inherited by its partitions
|
||||||
-- returns false since the hierarcy is formed via partitioning
|
-- returns false since the hierarcy is formed via partitioning
|
||||||
SELECT table_inherited('date_partitioned_table');
|
SELECT table_inherited('date_partitioned_table');
|
||||||
ERROR: relation "date_partitioned_table" does not exist
|
table_inherited
|
||||||
LINE 1: SELECT table_inherited('date_partitioned_table');
|
-----------------
|
||||||
^
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- also these are not supported
|
-- also these are not supported
|
||||||
SELECT master_get_table_ddl_events('capitals');
|
SELECT master_get_table_ddl_events('capitals');
|
||||||
ERROR: capitals is not a regular, foreign or partitioned table
|
ERROR: capitals is not a regular, foreign or partitioned table
|
||||||
|
@ -360,4 +428,3 @@ SELECT master_get_table_ddl_events('cities');
|
||||||
ERROR: cities is not a regular, foreign or partitioned table
|
ERROR: cities is not a regular, foreign or partitioned table
|
||||||
-- dropping parents frop the partitions
|
-- dropping parents frop the partitions
|
||||||
DROP TABLE date_partitioned_table, multi_column_partitioned, list_partitioned, partition_parent_schema.parent_table, cities, capitals;
|
DROP TABLE date_partitioned_table, multi_column_partitioned, list_partitioned, partition_parent_schema.parent_table, cities, capitals;
|
||||||
ERROR: table "date_partitioned_table" does not exist
|
|
||||||
|
|
|
@ -0,0 +1,371 @@
|
||||||
|
-- This test has different output per major version
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int as server_major_version;
|
||||||
|
server_major_version
|
||||||
|
----------------------
|
||||||
|
9
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- ===================================================================
|
||||||
|
-- create test functions
|
||||||
|
-- ===================================================================
|
||||||
|
CREATE FUNCTION generate_alter_table_detach_partition_command(regclass)
|
||||||
|
RETURNS text
|
||||||
|
AS 'citus'
|
||||||
|
LANGUAGE C STRICT;
|
||||||
|
CREATE FUNCTION generate_alter_table_attach_partition_command(regclass)
|
||||||
|
RETURNS text
|
||||||
|
AS 'citus'
|
||||||
|
LANGUAGE C STRICT;
|
||||||
|
CREATE FUNCTION generate_partition_information(regclass)
|
||||||
|
RETURNS text
|
||||||
|
AS 'citus'
|
||||||
|
LANGUAGE C STRICT;
|
||||||
|
CREATE FUNCTION print_partitions(regclass)
|
||||||
|
RETURNS text
|
||||||
|
AS 'citus'
|
||||||
|
LANGUAGE C STRICT;
|
||||||
|
CREATE FUNCTION table_inherits(regclass)
|
||||||
|
RETURNS bool
|
||||||
|
AS 'citus'
|
||||||
|
LANGUAGE C STRICT;
|
||||||
|
CREATE FUNCTION table_inherited(regclass)
|
||||||
|
RETURNS bool
|
||||||
|
AS 'citus'
|
||||||
|
LANGUAGE C STRICT;
|
||||||
|
CREATE OR REPLACE FUNCTION detach_and_attach_partition(partition_name regclass, parent_table_name regclass)
|
||||||
|
RETURNS void LANGUAGE plpgsql VOLATILE
|
||||||
|
AS $function$
|
||||||
|
DECLARE
|
||||||
|
detach_partition_command text := '';
|
||||||
|
attach_partition_command text := '';
|
||||||
|
command_result text := '';
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
-- first generate the command
|
||||||
|
SELECT public.generate_alter_table_attach_partition_command(partition_name) INTO attach_partition_command;
|
||||||
|
|
||||||
|
-- now genereate the detach command
|
||||||
|
SELECT public.generate_alter_table_detach_partition_command(partition_name) INTO detach_partition_command;
|
||||||
|
|
||||||
|
-- later detach the same partition
|
||||||
|
EXECUTE detach_partition_command;
|
||||||
|
|
||||||
|
-- not attach it again
|
||||||
|
EXECUTE attach_partition_command;
|
||||||
|
END;
|
||||||
|
$function$;
|
||||||
|
CREATE OR REPLACE FUNCTION drop_and_recreate_partitioned_table(parent_table_name regclass)
|
||||||
|
RETURNS void LANGUAGE plpgsql VOLATILE
|
||||||
|
AS $function$
|
||||||
|
DECLARE
|
||||||
|
command text := '';
|
||||||
|
|
||||||
|
BEGIN
|
||||||
|
-- first generate the command
|
||||||
|
CREATE TABLE partitioned_table_create_commands AS SELECT master_get_table_ddl_events(parent_table_name::text);
|
||||||
|
|
||||||
|
-- later detach the same partition
|
||||||
|
EXECUTE 'DROP TABLE ' || parent_table_name::text || ';';
|
||||||
|
|
||||||
|
FOR command IN SELECT * FROM partitioned_table_create_commands
|
||||||
|
LOOP
|
||||||
|
-- can do some processing here
|
||||||
|
EXECUTE command;
|
||||||
|
END LOOP;
|
||||||
|
|
||||||
|
DROP TABLE partitioned_table_create_commands;
|
||||||
|
|
||||||
|
END;
|
||||||
|
$function$;
|
||||||
|
-- create a partitioned table
|
||||||
|
CREATE TABLE date_partitioned_table(id int, time date) PARTITION BY RANGE (time);
|
||||||
|
ERROR: syntax error at or near "PARTITION"
|
||||||
|
LINE 1: ...E TABLE date_partitioned_table(id int, time date) PARTITION ...
|
||||||
|
^
|
||||||
|
-- we should be able to get the partitioning information even if there are no partitions
|
||||||
|
SELECT generate_partition_information('date_partitioned_table');
|
||||||
|
ERROR: relation "date_partitioned_table" does not exist
|
||||||
|
LINE 1: SELECT generate_partition_information('date_partitioned_tabl...
|
||||||
|
^
|
||||||
|
-- we should be able to drop and re-create the partitioned table using the command that Citus generate
|
||||||
|
SELECT drop_and_recreate_partitioned_table('date_partitioned_table');
|
||||||
|
ERROR: relation "date_partitioned_table" does not exist
|
||||||
|
LINE 1: SELECT drop_and_recreate_partitioned_table('date_partitioned...
|
||||||
|
^
|
||||||
|
-- we should also be able to see the PARTITION BY ... for the parent table
|
||||||
|
SELECT master_get_table_ddl_events('date_partitioned_table');
|
||||||
|
ERROR: relation "date_partitioned_table" does not exist
|
||||||
|
-- now create the partitions
|
||||||
|
CREATE TABLE date_partition_2006 PARTITION OF date_partitioned_table FOR VALUES FROM ('2006-01-01') TO ('2007-01-01');
|
||||||
|
ERROR: syntax error at or near "PARTITION"
|
||||||
|
LINE 1: CREATE TABLE date_partition_2006 PARTITION OF date_partition...
|
||||||
|
^
|
||||||
|
CREATE TABLE date_partition_2007 PARTITION OF date_partitioned_table FOR VALUES FROM ('2007-01-01') TO ('2008-01-01');
|
||||||
|
ERROR: syntax error at or near "PARTITION"
|
||||||
|
LINE 1: CREATE TABLE date_partition_2007 PARTITION OF date_partition...
|
||||||
|
^
|
||||||
|
-- we should be able to get the partitioning information after the partitions are created
|
||||||
|
SELECT generate_partition_information('date_partitioned_table');
|
||||||
|
ERROR: relation "date_partitioned_table" does not exist
|
||||||
|
LINE 1: SELECT generate_partition_information('date_partitioned_tabl...
|
||||||
|
^
|
||||||
|
-- lets get the attach partition commands
|
||||||
|
SELECT generate_alter_table_attach_partition_command('date_partition_2006');
|
||||||
|
ERROR: relation "date_partition_2006" does not exist
|
||||||
|
LINE 1: ...ECT generate_alter_table_attach_partition_command('date_part...
|
||||||
|
^
|
||||||
|
SELECT generate_alter_table_attach_partition_command('date_partition_2007');
|
||||||
|
ERROR: relation "date_partition_2007" does not exist
|
||||||
|
LINE 1: ...ECT generate_alter_table_attach_partition_command('date_part...
|
||||||
|
^
|
||||||
|
-- detach and attach the partition by the command generated by us
|
||||||
|
\d+ date_partitioned_table
|
||||||
|
SELECT detach_and_attach_partition('date_partition_2007', 'date_partitioned_table');
|
||||||
|
ERROR: relation "date_partition_2007" does not exist
|
||||||
|
LINE 1: SELECT detach_and_attach_partition('date_partition_2007', 'd...
|
||||||
|
^
|
||||||
|
-- check that both partitions are visiable
|
||||||
|
\d+ date_partitioned_table
|
||||||
|
-- make sure that inter shard commands work as expected
|
||||||
|
-- assume that the shardId is 100
|
||||||
|
CREATE TABLE date_partitioned_table_100 (id int, time date) PARTITION BY RANGE (time);
|
||||||
|
ERROR: syntax error at or near "PARTITION"
|
||||||
|
LINE 1: ...LE date_partitioned_table_100 (id int, time date) PARTITION ...
|
||||||
|
^
|
||||||
|
CREATE TABLE date_partition_2007_100 (id int, time date );
|
||||||
|
-- now create the partitioning hierarcy
|
||||||
|
SELECT worker_apply_inter_shard_ddl_command(referencing_shard:=100, referencing_schema_name:='public',
|
||||||
|
referenced_shard:=100, referenced_schema_name:='public',
|
||||||
|
command:='ALTER TABLE date_partitioned_table ATTACH PARTITION date_partition_2007 FOR VALUES FROM (''2007-01-01'') TO (''2008-01-02'')' );
|
||||||
|
ERROR: syntax error at or near "ATTACH"
|
||||||
|
LINE 1: SELECT worker_apply_inter_shard_ddl_command(referencing_shar...
|
||||||
|
^
|
||||||
|
-- the hierarcy is successfully created
|
||||||
|
\d+ date_partitioned_table_100
|
||||||
|
-- Citus can also get the DDL events for the partitions as regular tables
|
||||||
|
SELECT master_get_table_ddl_events('date_partition_2007_100');
|
||||||
|
master_get_table_ddl_events
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
CREATE TABLE public.date_partition_2007_100 (id integer, "time" date)
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- now break the partitioning hierarcy
|
||||||
|
SELECT worker_apply_inter_shard_ddl_command(referencing_shard:=100, referencing_schema_name:='public',
|
||||||
|
referenced_shard:=100, referenced_schema_name:='public',
|
||||||
|
command:='ALTER TABLE date_partitioned_table DETACH PARTITION date_partition_2007' );
|
||||||
|
ERROR: syntax error at or near "DETACH"
|
||||||
|
LINE 1: SELECT worker_apply_inter_shard_ddl_command(referencing_shar...
|
||||||
|
^
|
||||||
|
-- the hierarcy is successfully broken
|
||||||
|
\d+ date_partitioned_table_100
|
||||||
|
-- now lets have some more complex partitioning hierarcies with
|
||||||
|
-- tables on different schemas and constraints on the tables
|
||||||
|
CREATE SCHEMA partition_parent_schema;
|
||||||
|
CREATE TABLE partition_parent_schema.parent_table (id int NOT NULL, time date DEFAULT now()) PARTITION BY RANGE (time);
|
||||||
|
ERROR: syntax error at or near "PARTITION"
|
||||||
|
LINE 1: ..._table (id int NOT NULL, time date DEFAULT now()) PARTITION ...
|
||||||
|
^
|
||||||
|
CREATE SCHEMA partition_child_1_schema;
|
||||||
|
CREATE TABLE partition_child_1_schema.child_1 (id int NOT NULL, time date );
|
||||||
|
CREATE SCHEMA partition_child_2_schema;
|
||||||
|
CREATE TABLE partition_child_2_schema.child_2 (id int NOT NULL, time date );
|
||||||
|
-- we should be able to get the partitioning information even if there are no partitions
|
||||||
|
SELECT generate_partition_information('partition_parent_schema.parent_table');
|
||||||
|
ERROR: relation "partition_parent_schema.parent_table" does not exist
|
||||||
|
LINE 1: SELECT generate_partition_information('partition_parent_sche...
|
||||||
|
^
|
||||||
|
-- we should be able to drop and re-create the partitioned table using the command that Citus generate
|
||||||
|
SELECT drop_and_recreate_partitioned_table('partition_parent_schema.parent_table');
|
||||||
|
ERROR: relation "partition_parent_schema.parent_table" does not exist
|
||||||
|
LINE 1: SELECT drop_and_recreate_partitioned_table('partition_parent...
|
||||||
|
^
|
||||||
|
ALTER TABLE partition_parent_schema.parent_table ATTACH PARTITION partition_child_1_schema.child_1 FOR VALUES FROM ('2009-01-01') TO ('2010-01-02');
|
||||||
|
ERROR: syntax error at or near "ATTACH"
|
||||||
|
LINE 1: ALTER TABLE partition_parent_schema.parent_table ATTACH PART...
|
||||||
|
^
|
||||||
|
SET search_path = 'partition_parent_schema';
|
||||||
|
ALTER TABLE parent_table ATTACH PARTITION partition_child_2_schema.child_2 FOR VALUES FROM ('2006-01-01') TO ('2007-01-01');
|
||||||
|
ERROR: syntax error at or near "ATTACH"
|
||||||
|
LINE 1: ALTER TABLE parent_table ATTACH PARTITION partition_child_2...
|
||||||
|
^
|
||||||
|
SELECT public.generate_partition_information('parent_table');
|
||||||
|
ERROR: relation "parent_table" does not exist
|
||||||
|
LINE 1: SELECT public.generate_partition_information('parent_table')...
|
||||||
|
^
|
||||||
|
-- lets get the attach partition commands
|
||||||
|
SELECT public.generate_alter_table_attach_partition_command('partition_child_1_schema.child_1');
|
||||||
|
generate_alter_table_attach_partition_command
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SET search_path = 'partition_child_2_schema';
|
||||||
|
SELECT public.generate_alter_table_attach_partition_command('child_2');
|
||||||
|
generate_alter_table_attach_partition_command
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SET search_path = 'partition_parent_schema';
|
||||||
|
-- detach and attach the partition by the command generated by us
|
||||||
|
\d+ parent_table
|
||||||
|
SELECT public.detach_and_attach_partition('partition_child_1_schema.child_1', 'parent_table');
|
||||||
|
ERROR: relation "parent_table" does not exist
|
||||||
|
LINE 1: ...ach_partition('partition_child_1_schema.child_1', 'parent_ta...
|
||||||
|
^
|
||||||
|
-- check that both partitions are visiable
|
||||||
|
\d+ parent_table
|
||||||
|
-- some very simple checks that should error out
|
||||||
|
SELECT public.generate_alter_table_attach_partition_command('parent_table');
|
||||||
|
ERROR: relation "parent_table" does not exist
|
||||||
|
LINE 1: ...lic.generate_alter_table_attach_partition_command('parent_ta...
|
||||||
|
^
|
||||||
|
SELECT public.generate_partition_information('partition_child_1_schema.child_1');
|
||||||
|
generate_partition_information
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT public.print_partitions('partition_child_1_schema.child_1');
|
||||||
|
print_partitions
|
||||||
|
------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- now pring the partitions
|
||||||
|
SELECT public.print_partitions('parent_table');
|
||||||
|
ERROR: relation "parent_table" does not exist
|
||||||
|
LINE 1: SELECT public.print_partitions('parent_table');
|
||||||
|
^
|
||||||
|
SET search_path = 'public';
|
||||||
|
-- test multi column / expression partitioning with UNBOUNDED ranges
|
||||||
|
CREATE OR REPLACE FUNCTION some_function(input_val text)
|
||||||
|
RETURNS text LANGUAGE plpgsql IMMUTABLE
|
||||||
|
AS $function$
|
||||||
|
BEGIN
|
||||||
|
return reverse(input_val);
|
||||||
|
END;
|
||||||
|
$function$;
|
||||||
|
CREATE TABLE multi_column_partitioned (
|
||||||
|
a int,
|
||||||
|
b int,
|
||||||
|
c text
|
||||||
|
) PARTITION BY RANGE (a, (a+b+1), some_function(upper(c)));
|
||||||
|
ERROR: syntax error at or near "PARTITION"
|
||||||
|
LINE 5: ) PARTITION BY RANGE (a, (a+b+1), some_function(upper(c)));
|
||||||
|
^
|
||||||
|
CREATE TABLE multi_column_partition_1(
|
||||||
|
a int,
|
||||||
|
b int,
|
||||||
|
c text
|
||||||
|
);
|
||||||
|
CREATE TABLE multi_column_partition_2(
|
||||||
|
a int,
|
||||||
|
b int,
|
||||||
|
c text
|
||||||
|
);
|
||||||
|
-- partitioning information
|
||||||
|
SELECT generate_partition_information('multi_column_partitioned');
|
||||||
|
ERROR: relation "multi_column_partitioned" does not exist
|
||||||
|
LINE 1: SELECT generate_partition_information('multi_column_partitio...
|
||||||
|
^
|
||||||
|
SELECT master_get_table_ddl_events('multi_column_partitioned');
|
||||||
|
ERROR: relation "multi_column_partitioned" does not exist
|
||||||
|
SELECT drop_and_recreate_partitioned_table('multi_column_partitioned');
|
||||||
|
ERROR: relation "multi_column_partitioned" does not exist
|
||||||
|
LINE 1: SELECT drop_and_recreate_partitioned_table('multi_column_par...
|
||||||
|
^
|
||||||
|
-- partitions and their ranges
|
||||||
|
ALTER TABLE multi_column_partitioned ATTACH PARTITION multi_column_partition_1 FOR VALUES FROM (1, 10, '250') TO (1, 20, '250');
|
||||||
|
ERROR: syntax error at or near "ATTACH"
|
||||||
|
LINE 1: ALTER TABLE multi_column_partitioned ATTACH PARTITION multi_...
|
||||||
|
^
|
||||||
|
SELECT generate_alter_table_attach_partition_command('multi_column_partition_1');
|
||||||
|
generate_alter_table_attach_partition_command
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
ALTER TABLE multi_column_partitioned ATTACH PARTITION multi_column_partition_2 FOR VALUES FROM (10, 1000, '2500') TO (MAXVALUE, MAXVALUE, MAXVALUE);
|
||||||
|
ERROR: syntax error at or near "ATTACH"
|
||||||
|
LINE 1: ALTER TABLE multi_column_partitioned ATTACH PARTITION multi_...
|
||||||
|
^
|
||||||
|
SELECT generate_alter_table_attach_partition_command('multi_column_partition_2');
|
||||||
|
generate_alter_table_attach_partition_command
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT generate_alter_table_detach_partition_command('multi_column_partition_2');
|
||||||
|
generate_alter_table_detach_partition_command
|
||||||
|
-----------------------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- finally a test with LIST partitioning
|
||||||
|
CREATE TABLE list_partitioned (col1 NUMERIC, col2 NUMERIC, col3 VARCHAR(10)) PARTITION BY LIST (col1) ;
|
||||||
|
ERROR: syntax error at or near "PARTITION"
|
||||||
|
LINE 1: ...ed (col1 NUMERIC, col2 NUMERIC, col3 VARCHAR(10)) PARTITION ...
|
||||||
|
^
|
||||||
|
SELECT generate_partition_information('list_partitioned');
|
||||||
|
ERROR: relation "list_partitioned" does not exist
|
||||||
|
LINE 1: SELECT generate_partition_information('list_partitioned');
|
||||||
|
^
|
||||||
|
SELECT master_get_table_ddl_events('list_partitioned');
|
||||||
|
ERROR: relation "list_partitioned" does not exist
|
||||||
|
SELECT drop_and_recreate_partitioned_table('list_partitioned');
|
||||||
|
ERROR: relation "list_partitioned" does not exist
|
||||||
|
LINE 1: SELECT drop_and_recreate_partitioned_table('list_partitioned...
|
||||||
|
^
|
||||||
|
CREATE TABLE list_partitioned_1 PARTITION OF list_partitioned FOR VALUES IN (100, 101, 102, 103, 104);
|
||||||
|
ERROR: syntax error at or near "PARTITION"
|
||||||
|
LINE 1: CREATE TABLE list_partitioned_1 PARTITION OF list_partitione...
|
||||||
|
^
|
||||||
|
SELECT generate_alter_table_attach_partition_command('list_partitioned_1');
|
||||||
|
ERROR: relation "list_partitioned_1" does not exist
|
||||||
|
LINE 1: ...ECT generate_alter_table_attach_partition_command('list_part...
|
||||||
|
^
|
||||||
|
-- also differentiate partitions and inhereted tables
|
||||||
|
CREATE TABLE cities (
|
||||||
|
name text,
|
||||||
|
population float,
|
||||||
|
altitude int -- in feet
|
||||||
|
);
|
||||||
|
CREATE TABLE capitals (
|
||||||
|
state char(2)
|
||||||
|
) INHERITS (cities);
|
||||||
|
-- returns true since capitals inherits from cities
|
||||||
|
SELECT table_inherits('capitals');
|
||||||
|
table_inherits
|
||||||
|
----------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- although date_partition_2006 inherits from its parent
|
||||||
|
-- returns false since the hierarcy is formed via partitioning
|
||||||
|
SELECT table_inherits('date_partition_2006');
|
||||||
|
ERROR: relation "date_partition_2006" does not exist
|
||||||
|
LINE 1: SELECT table_inherits('date_partition_2006');
|
||||||
|
^
|
||||||
|
-- returns true since cities inherited by capitals
|
||||||
|
SELECT table_inherited('cities');
|
||||||
|
table_inherited
|
||||||
|
-----------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- although date_partitioned_table inherited by its partitions
|
||||||
|
-- returns false since the hierarcy is formed via partitioning
|
||||||
|
SELECT table_inherited('date_partitioned_table');
|
||||||
|
ERROR: relation "date_partitioned_table" does not exist
|
||||||
|
LINE 1: SELECT table_inherited('date_partitioned_table');
|
||||||
|
^
|
||||||
|
-- also these are not supported
|
||||||
|
SELECT master_get_table_ddl_events('capitals');
|
||||||
|
ERROR: capitals is not a regular, foreign or partitioned table
|
||||||
|
SELECT master_get_table_ddl_events('cities');
|
||||||
|
ERROR: cities is not a regular, foreign or partitioned table
|
||||||
|
-- dropping parents frop the partitions
|
||||||
|
DROP TABLE date_partitioned_table, multi_column_partitioned, list_partitioned, partition_parent_schema.parent_table, cities, capitals;
|
||||||
|
ERROR: table "date_partitioned_table" does not exist
|
|
@ -1,3 +1,11 @@
|
||||||
|
-- print whether we're using version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_nine;
|
||||||
|
version_above_nine
|
||||||
|
--------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
CREATE TABLE artists (
|
CREATE TABLE artists (
|
||||||
id bigint NOT NULL,
|
id bigint NOT NULL,
|
||||||
name text NOT NULL
|
name text NOT NULL
|
||||||
|
@ -119,7 +127,7 @@ ERROR: null value in column "name" violates not-null constraint
|
||||||
SAVEPOINT s3;
|
SAVEPOINT s3;
|
||||||
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
||||||
ROLLBACK TO SAVEPOINT s3;
|
ROLLBACK TO SAVEPOINT s3;
|
||||||
ERROR: no such savepoint
|
ERROR: savepoint "s3" does not exist
|
||||||
COMMIT;
|
COMMIT;
|
||||||
-- ===================================================================
|
-- ===================================================================
|
||||||
-- Tests for replication factor > 1
|
-- Tests for replication factor > 1
|
||||||
|
|
|
@ -0,0 +1,285 @@
|
||||||
|
-- print whether we're using version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_nine;
|
||||||
|
version_above_nine
|
||||||
|
--------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
CREATE TABLE artists (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
name text NOT NULL
|
||||||
|
);
|
||||||
|
SELECT create_distributed_table('artists', 'id');
|
||||||
|
create_distributed_table
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- add some data
|
||||||
|
INSERT INTO artists VALUES (1, 'Pablo Picasso');
|
||||||
|
INSERT INTO artists VALUES (2, 'Vincent van Gogh');
|
||||||
|
INSERT INTO artists VALUES (3, 'Claude Monet');
|
||||||
|
INSERT INTO artists VALUES (4, 'William Kurelek');
|
||||||
|
-- RELEASE SAVEPOINT
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO artists VALUES (5, 'Asher Lev');
|
||||||
|
SAVEPOINT s1;
|
||||||
|
DELETE FROM artists WHERE id=5;
|
||||||
|
RELEASE SAVEPOINT s1;
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM artists WHERE id=5;
|
||||||
|
id | name
|
||||||
|
----+------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
-- ROLLBACK TO SAVEPOINT
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO artists VALUES (5, 'Asher Lev');
|
||||||
|
SAVEPOINT s1;
|
||||||
|
DELETE FROM artists WHERE id=5;
|
||||||
|
ROLLBACK TO SAVEPOINT s1;
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM artists WHERE id=5;
|
||||||
|
id | name
|
||||||
|
----+-----------
|
||||||
|
5 | Asher Lev
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Serial sub-transaction releases
|
||||||
|
BEGIN;
|
||||||
|
SAVEPOINT s1;
|
||||||
|
DELETE FROM artists WHERE id=5;
|
||||||
|
RELEASE SAVEPOINT s1;
|
||||||
|
SAVEPOINT s2;
|
||||||
|
INSERT INTO artists VALUES (5, 'Jacob Kahn');
|
||||||
|
RELEASE SAVEPOINT s2;
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM artists WHERE id=5;
|
||||||
|
id | name
|
||||||
|
----+------------
|
||||||
|
5 | Jacob Kahn
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Serial sub-transaction rollbacks
|
||||||
|
BEGIN;
|
||||||
|
SAVEPOINT s1;
|
||||||
|
UPDATE artists SET name='A' WHERE id=5;
|
||||||
|
ROLLBACK TO SAVEPOINT s1;
|
||||||
|
SAVEPOINT s2;
|
||||||
|
DELETE FROM artists WHERE id=5;
|
||||||
|
ROLLBACK TO SAVEPOINT s2;
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM artists WHERE id=5;
|
||||||
|
id | name
|
||||||
|
----+------------
|
||||||
|
5 | Jacob Kahn
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Multiple sub-transaction activity before first query
|
||||||
|
BEGIN;
|
||||||
|
SAVEPOINT s0;
|
||||||
|
SAVEPOINT s1;
|
||||||
|
SAVEPOINT s2;
|
||||||
|
SAVEPOINT s3;
|
||||||
|
ROLLBACK TO SAVEPOINT s2;
|
||||||
|
RELEASE SAVEPOINT s1;
|
||||||
|
INSERT INTO artists VALUES (6, 'John J. Audubon');
|
||||||
|
ROLLBACK TO SAVEPOINT s0;
|
||||||
|
INSERT INTO artists VALUES (6, 'Emily Carr');
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM artists WHERE id=6;
|
||||||
|
id | name
|
||||||
|
----+------------
|
||||||
|
6 | Emily Carr
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Release after rollback
|
||||||
|
BEGIN;
|
||||||
|
SAVEPOINT s1;
|
||||||
|
ROLLBACK TO s1;
|
||||||
|
RELEASE SAVEPOINT s1;
|
||||||
|
SAVEPOINT s2;
|
||||||
|
INSERT INTO artists VALUES (7, 'John J. Audubon');
|
||||||
|
ROLLBACK TO s2;
|
||||||
|
RELEASE SAVEPOINT s2;
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM artists WHERE id=7;
|
||||||
|
id | name
|
||||||
|
----+------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
-- Recover from errors
|
||||||
|
\set VERBOSITY terse
|
||||||
|
BEGIN;
|
||||||
|
SAVEPOINT s1;
|
||||||
|
SAVEPOINT s2;
|
||||||
|
INSERT INTO artists VALUES (7, NULL);
|
||||||
|
ERROR: null value in column "name" violates not-null constraint
|
||||||
|
ROLLBACK TO SAVEPOINT s1;
|
||||||
|
COMMIT;
|
||||||
|
-- Don't recover from errors
|
||||||
|
BEGIN;
|
||||||
|
SAVEPOINT s1;
|
||||||
|
SAVEPOINT s2;
|
||||||
|
INSERT INTO artists VALUES (7, NULL);
|
||||||
|
ERROR: null value in column "name" violates not-null constraint
|
||||||
|
SAVEPOINT s3;
|
||||||
|
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
||||||
|
ROLLBACK TO SAVEPOINT s3;
|
||||||
|
ERROR: no such savepoint
|
||||||
|
COMMIT;
|
||||||
|
-- ===================================================================
|
||||||
|
-- Tests for replication factor > 1
|
||||||
|
-- ===================================================================
|
||||||
|
CREATE TABLE researchers (
|
||||||
|
id bigint NOT NULL,
|
||||||
|
lab_id int NOT NULL,
|
||||||
|
name text NOT NULL
|
||||||
|
);
|
||||||
|
SELECT master_create_distributed_table('researchers', 'lab_id', 'hash');
|
||||||
|
master_create_distributed_table
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT master_create_worker_shards('researchers', 2, 2);
|
||||||
|
master_create_worker_shards
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Basic rollback and release
|
||||||
|
BEGIN;
|
||||||
|
INSERT INTO researchers VALUES (7, 4, 'Jan Plaza');
|
||||||
|
SAVEPOINT s1;
|
||||||
|
INSERT INTO researchers VALUES (8, 4, 'Alonzo Church');
|
||||||
|
ROLLBACK TO s1;
|
||||||
|
RELEASE SAVEPOINT s1;
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM researchers WHERE id in (7, 8);
|
||||||
|
id | lab_id | name
|
||||||
|
----+--------+-----------
|
||||||
|
7 | 4 | Jan Plaza
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Recover from failure on one of nodes
|
||||||
|
BEGIN;
|
||||||
|
SAVEPOINT s1;
|
||||||
|
INSERT INTO researchers VALUES (11, 11, 'Dana Scott');
|
||||||
|
INSERT INTO researchers VALUES (NULL, 10, 'Stephen Kleene');
|
||||||
|
ERROR: null value in column "id" violates not-null constraint
|
||||||
|
ROLLBACK TO SAVEPOINT s1;
|
||||||
|
INSERT INTO researchers VALUES (12, 10, 'Stephen Kleene');
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM researchers WHERE lab_id=10;
|
||||||
|
id | lab_id | name
|
||||||
|
----+--------+----------------
|
||||||
|
12 | 10 | Stephen Kleene
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Don't recover, but rollback
|
||||||
|
BEGIN;
|
||||||
|
SAVEPOINT s1;
|
||||||
|
INSERT INTO researchers VALUES (NULL, 10, 'Raymond Smullyan');
|
||||||
|
ERROR: null value in column "id" violates not-null constraint
|
||||||
|
RELEASE SAVEPOINT s1;
|
||||||
|
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
||||||
|
SAVEPOINT s2;
|
||||||
|
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
||||||
|
ROLLBACK;
|
||||||
|
SELECT * FROM researchers WHERE lab_id=10;
|
||||||
|
id | lab_id | name
|
||||||
|
----+--------+----------------
|
||||||
|
12 | 10 | Stephen Kleene
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Don't recover, and commit
|
||||||
|
BEGIN;
|
||||||
|
SAVEPOINT s1;
|
||||||
|
INSERT INTO researchers VALUES (NULL, 10, 'Raymond Smullyan');
|
||||||
|
ERROR: null value in column "id" violates not-null constraint
|
||||||
|
RELEASE SAVEPOINT s1;
|
||||||
|
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
||||||
|
SAVEPOINT s2;
|
||||||
|
ERROR: current transaction is aborted, commands ignored until end of transaction block
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM researchers WHERE lab_id=10;
|
||||||
|
id | lab_id | name
|
||||||
|
----+--------+----------------
|
||||||
|
12 | 10 | Stephen Kleene
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Implicit savepoints via pl/pgsql exceptions
|
||||||
|
BEGIN;
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO researchers VALUES (15, 10, 'Melvin Fitting');
|
||||||
|
INSERT INTO researchers VALUES (NULL, 10, 'Raymond Smullyan');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN not_null_violation THEN
|
||||||
|
RAISE NOTICE 'caught not_null_violation';
|
||||||
|
END $$;
|
||||||
|
NOTICE: caught not_null_violation
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM researchers WHERE lab_id=10;
|
||||||
|
id | lab_id | name
|
||||||
|
----+--------+----------------
|
||||||
|
12 | 10 | Stephen Kleene
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO researchers VALUES (15, 10, 'Melvin Fitting');
|
||||||
|
RAISE EXCEPTION plpgsql_error;
|
||||||
|
EXCEPTION
|
||||||
|
WHEN plpgsql_error THEN
|
||||||
|
RAISE NOTICE 'caught manual plpgsql_error';
|
||||||
|
END $$;
|
||||||
|
NOTICE: caught manual plpgsql_error
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM researchers WHERE lab_id=10;
|
||||||
|
id | lab_id | name
|
||||||
|
----+--------+----------------
|
||||||
|
12 | 10 | Stephen Kleene
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO researchers VALUES (15, 10, 'Melvin Fitting');
|
||||||
|
INSERT INTO researchers VALUES (NULL, 10, 'Raymond Smullyan');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN not_null_violation THEN
|
||||||
|
RAISE EXCEPTION not_null_violation; -- rethrow it
|
||||||
|
END $$;
|
||||||
|
ERROR: not_null_violation
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM researchers WHERE lab_id=10;
|
||||||
|
id | lab_id | name
|
||||||
|
----+--------+----------------
|
||||||
|
12 | 10 | Stephen Kleene
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- Insert something after catching error.
|
||||||
|
BEGIN;
|
||||||
|
DO $$
|
||||||
|
BEGIN
|
||||||
|
INSERT INTO researchers VALUES (15, 10, 'Melvin Fitting');
|
||||||
|
INSERT INTO researchers VALUES (NULL, 10, 'Raymond Smullyan');
|
||||||
|
EXCEPTION
|
||||||
|
WHEN not_null_violation THEN
|
||||||
|
INSERT INTO researchers VALUES (32, 10, 'Raymond Smullyan');
|
||||||
|
END $$;
|
||||||
|
COMMIT;
|
||||||
|
SELECT * FROM researchers WHERE lab_id=10;
|
||||||
|
id | lab_id | name
|
||||||
|
----+--------+------------------
|
||||||
|
12 | 10 | Stephen Kleene
|
||||||
|
32 | 10 | Raymond Smullyan
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- Clean-up
|
||||||
|
DROP TABLE artists;
|
||||||
|
DROP TABLE researchers;
|
|
@ -1,4 +1,12 @@
|
||||||
SET citus.next_shard_id TO 990000;
|
SET citus.next_shard_id TO 990000;
|
||||||
|
-- print server version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 as version_above_ten;
|
||||||
|
version_above_ten
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- ===================================================================
|
-- ===================================================================
|
||||||
-- test utility statement functionality
|
-- test utility statement functionality
|
||||||
-- ===================================================================
|
-- ===================================================================
|
||||||
|
@ -174,6 +182,19 @@ SELECT master_create_worker_shards('dustbunnies', 1, 2);
|
||||||
|
|
||||||
-- add some data to the distributed table
|
-- add some data to the distributed table
|
||||||
\copy dustbunnies (id, name) from stdin with csv
|
\copy dustbunnies (id, name) from stdin with csv
|
||||||
|
CREATE TABLE second_dustbunnies(id integer, name text, age integer);
|
||||||
|
SELECT master_create_distributed_table('second_dustbunnies', 'id', 'hash');
|
||||||
|
master_create_distributed_table
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT master_create_worker_shards('second_dustbunnies', 1, 2);
|
||||||
|
master_create_worker_shards
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
-- following approach adapted from PostgreSQL's stats.sql file
|
-- following approach adapted from PostgreSQL's stats.sql file
|
||||||
-- save relevant stat counter values in refreshable view
|
-- save relevant stat counter values in refreshable view
|
||||||
\c - - - :worker_1_port
|
\c - - - :worker_1_port
|
||||||
|
@ -361,6 +382,8 @@ WHERE tablename = 'dustbunnies_990002' ORDER BY attname;
|
||||||
VACUUM;
|
VACUUM;
|
||||||
WARNING: not propagating VACUUM command to worker nodes
|
WARNING: not propagating VACUUM command to worker nodes
|
||||||
HINT: Provide a specific table in order to VACUUM distributed tables.
|
HINT: Provide a specific table in order to VACUUM distributed tables.
|
||||||
|
-- check for multiple table vacuum
|
||||||
|
VACUUM dustbunnies, second_dustbunnies;
|
||||||
-- check the current number of vacuum and analyze run on dustbunnies
|
-- check the current number of vacuum and analyze run on dustbunnies
|
||||||
SELECT run_command_on_workers($$SELECT wait_for_stats()$$);
|
SELECT run_command_on_workers($$SELECT wait_for_stats()$$);
|
||||||
run_command_on_workers
|
run_command_on_workers
|
||||||
|
@ -372,8 +395,8 @@ SELECT run_command_on_workers($$SELECT wait_for_stats()$$);
|
||||||
SELECT run_command_on_workers($$SELECT pg_stat_get_vacuum_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
SELECT run_command_on_workers($$SELECT pg_stat_get_vacuum_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
||||||
run_command_on_workers
|
run_command_on_workers
|
||||||
------------------------
|
------------------------
|
||||||
(localhost,57637,t,3)
|
(localhost,57637,t,4)
|
||||||
(localhost,57638,t,3)
|
(localhost,57638,t,4)
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
SELECT run_command_on_workers($$SELECT pg_stat_get_analyze_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
SELECT run_command_on_workers($$SELECT pg_stat_get_analyze_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
||||||
|
@ -403,8 +426,8 @@ SELECT run_command_on_workers($$SELECT wait_for_stats()$$);
|
||||||
SELECT run_command_on_workers($$SELECT pg_stat_get_vacuum_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
SELECT run_command_on_workers($$SELECT pg_stat_get_vacuum_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
||||||
run_command_on_workers
|
run_command_on_workers
|
||||||
------------------------
|
------------------------
|
||||||
(localhost,57637,t,3)
|
(localhost,57637,t,4)
|
||||||
(localhost,57638,t,3)
|
(localhost,57638,t,4)
|
||||||
(2 rows)
|
(2 rows)
|
||||||
|
|
||||||
SELECT run_command_on_workers($$SELECT pg_stat_get_analyze_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
SELECT run_command_on_workers($$SELECT pg_stat_get_analyze_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
||||||
|
|
|
@ -0,0 +1,478 @@
|
||||||
|
SET citus.next_shard_id TO 990000;
|
||||||
|
-- print server version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 as version_above_ten;
|
||||||
|
version_above_ten
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- ===================================================================
|
||||||
|
-- test utility statement functionality
|
||||||
|
-- ===================================================================
|
||||||
|
CREATE TABLE sharded_table ( name text, id bigint );
|
||||||
|
SELECT master_create_distributed_table('sharded_table', 'id', 'hash');
|
||||||
|
master_create_distributed_table
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT master_create_worker_shards('sharded_table', 2, 1);
|
||||||
|
master_create_worker_shards
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- COPY out is supported with distributed tables
|
||||||
|
COPY sharded_table TO STDOUT;
|
||||||
|
COPY (SELECT COUNT(*) FROM sharded_table) TO STDOUT;
|
||||||
|
0
|
||||||
|
BEGIN;
|
||||||
|
SET TRANSACTION READ ONLY;
|
||||||
|
COPY sharded_table TO STDOUT;
|
||||||
|
COPY (SELECT COUNT(*) FROM sharded_table) TO STDOUT;
|
||||||
|
0
|
||||||
|
COMMIT;
|
||||||
|
-- ANALYZE is supported in a transaction block
|
||||||
|
BEGIN;
|
||||||
|
ANALYZE sharded_table;
|
||||||
|
ANALYZE sharded_table;
|
||||||
|
END;
|
||||||
|
-- cursors may not involve distributed tables
|
||||||
|
DECLARE all_sharded_rows CURSOR FOR SELECT * FROM sharded_table;
|
||||||
|
ERROR: DECLARE CURSOR can only be used in transaction blocks
|
||||||
|
-- verify PREPARE functionality
|
||||||
|
PREPARE sharded_insert AS INSERT INTO sharded_table VALUES ('adam', 1);
|
||||||
|
PREPARE sharded_update AS UPDATE sharded_table SET name = 'bob' WHERE id = 1;
|
||||||
|
PREPARE sharded_delete AS DELETE FROM sharded_table WHERE id = 1;
|
||||||
|
PREPARE sharded_query AS SELECT name FROM sharded_table WHERE id = 1;
|
||||||
|
EXECUTE sharded_query;
|
||||||
|
name
|
||||||
|
------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
EXECUTE sharded_insert;
|
||||||
|
EXECUTE sharded_query;
|
||||||
|
name
|
||||||
|
------
|
||||||
|
adam
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
EXECUTE sharded_update;
|
||||||
|
EXECUTE sharded_query;
|
||||||
|
name
|
||||||
|
------
|
||||||
|
bob
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
EXECUTE sharded_delete;
|
||||||
|
EXECUTE sharded_query;
|
||||||
|
name
|
||||||
|
------
|
||||||
|
(0 rows)
|
||||||
|
|
||||||
|
-- try to drop shards with where clause
|
||||||
|
SELECT master_apply_delete_command('DELETE FROM sharded_table WHERE id > 0');
|
||||||
|
ERROR: cannot delete from hash distributed table with this command
|
||||||
|
DETAIL: Delete statements on hash-partitioned tables are not supported with master_apply_delete_command.
|
||||||
|
HINT: Use master_modify_multiple_shards command instead.
|
||||||
|
-- drop all shards
|
||||||
|
SELECT master_apply_delete_command('DELETE FROM sharded_table');
|
||||||
|
ERROR: cannot delete from hash distributed table with this command
|
||||||
|
DETAIL: Delete statements on hash-partitioned tables are not supported with master_apply_delete_command.
|
||||||
|
HINT: Use master_modify_multiple_shards command instead.
|
||||||
|
-- lock shard metadata: take some share locks and exclusive locks
|
||||||
|
BEGIN;
|
||||||
|
SELECT lock_shard_metadata(5, ARRAY[999001, 999002, 999002]);
|
||||||
|
lock_shard_metadata
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT lock_shard_metadata(7, ARRAY[999001, 999003, 999004]);
|
||||||
|
lock_shard_metadata
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT locktype, objid, mode, granted
|
||||||
|
FROM pg_locks
|
||||||
|
WHERE objid IN (999001, 999002, 999003, 999004)
|
||||||
|
ORDER BY objid, mode;
|
||||||
|
locktype | objid | mode | granted
|
||||||
|
----------+--------+---------------+---------
|
||||||
|
advisory | 999001 | ExclusiveLock | t
|
||||||
|
advisory | 999001 | ShareLock | t
|
||||||
|
advisory | 999002 | ShareLock | t
|
||||||
|
advisory | 999003 | ExclusiveLock | t
|
||||||
|
advisory | 999004 | ExclusiveLock | t
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
END;
|
||||||
|
-- lock shard metadata: unsupported lock type
|
||||||
|
SELECT lock_shard_metadata(0, ARRAY[990001, 999002]);
|
||||||
|
ERROR: unsupported lockmode 0
|
||||||
|
-- lock shard metadata: invalid shard ID
|
||||||
|
SELECT lock_shard_metadata(5, ARRAY[0]);
|
||||||
|
lock_shard_metadata
|
||||||
|
---------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- lock shard metadata: lock nothing
|
||||||
|
SELECT lock_shard_metadata(5, ARRAY[]::bigint[]);
|
||||||
|
ERROR: no locks specified
|
||||||
|
-- lock shard resources: take some share locks and exclusive locks
|
||||||
|
BEGIN;
|
||||||
|
SELECT lock_shard_resources(5, ARRAY[999001, 999002, 999002]);
|
||||||
|
lock_shard_resources
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT lock_shard_resources(7, ARRAY[999001, 999003, 999004]);
|
||||||
|
lock_shard_resources
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT locktype, objid, mode, granted
|
||||||
|
FROM pg_locks
|
||||||
|
WHERE objid IN (999001, 999002, 999003, 999004)
|
||||||
|
ORDER BY objid, mode;
|
||||||
|
locktype | objid | mode | granted
|
||||||
|
----------+--------+---------------+---------
|
||||||
|
advisory | 999001 | ExclusiveLock | t
|
||||||
|
advisory | 999001 | ShareLock | t
|
||||||
|
advisory | 999002 | ShareLock | t
|
||||||
|
advisory | 999003 | ExclusiveLock | t
|
||||||
|
advisory | 999004 | ExclusiveLock | t
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
END;
|
||||||
|
-- lock shard metadata: unsupported lock type
|
||||||
|
SELECT lock_shard_resources(0, ARRAY[990001, 999002]);
|
||||||
|
ERROR: unsupported lockmode 0
|
||||||
|
-- lock shard metadata: invalid shard ID
|
||||||
|
SELECT lock_shard_resources(5, ARRAY[-1]);
|
||||||
|
lock_shard_resources
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- lock shard metadata: lock nothing
|
||||||
|
SELECT lock_shard_resources(5, ARRAY[]::bigint[]);
|
||||||
|
ERROR: no locks specified
|
||||||
|
-- drop table
|
||||||
|
DROP TABLE sharded_table;
|
||||||
|
-- VACUUM tests
|
||||||
|
-- create a table with a single shard (for convenience)
|
||||||
|
CREATE TABLE dustbunnies (id integer, name text, age integer);
|
||||||
|
SELECT master_create_distributed_table('dustbunnies', 'id', 'hash');
|
||||||
|
master_create_distributed_table
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT master_create_worker_shards('dustbunnies', 1, 2);
|
||||||
|
master_create_worker_shards
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- add some data to the distributed table
|
||||||
|
\copy dustbunnies (id, name) from stdin with csv
|
||||||
|
CREATE TABLE second_dustbunnies(id integer, name text, age integer);
|
||||||
|
SELECT master_create_distributed_table('second_dustbunnies', 'id', 'hash');
|
||||||
|
master_create_distributed_table
|
||||||
|
---------------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT master_create_worker_shards('second_dustbunnies', 1, 2);
|
||||||
|
master_create_worker_shards
|
||||||
|
-----------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- following approach adapted from PostgreSQL's stats.sql file
|
||||||
|
-- save relevant stat counter values in refreshable view
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
CREATE MATERIALIZED VIEW prevcounts AS
|
||||||
|
SELECT analyze_count, vacuum_count FROM pg_stat_user_tables
|
||||||
|
WHERE relname='dustbunnies_990002';
|
||||||
|
-- create function that sleeps until those counters increment
|
||||||
|
create function wait_for_stats() returns void as $$
|
||||||
|
declare
|
||||||
|
start_time timestamptz := clock_timestamp();
|
||||||
|
analyze_updated bool;
|
||||||
|
vacuum_updated bool;
|
||||||
|
begin
|
||||||
|
-- we don't want to wait forever; loop will exit after 10 seconds
|
||||||
|
for i in 1 .. 100 loop
|
||||||
|
|
||||||
|
-- check to see if analyze has been updated
|
||||||
|
SELECT (st.analyze_count >= pc.analyze_count + 1) INTO analyze_updated
|
||||||
|
FROM pg_stat_user_tables AS st, pg_class AS cl, prevcounts AS pc
|
||||||
|
WHERE st.relname='dustbunnies_990002' AND cl.relname='dustbunnies_990002';
|
||||||
|
|
||||||
|
-- check to see if vacuum has been updated
|
||||||
|
SELECT (st.vacuum_count >= pc.vacuum_count + 1) INTO vacuum_updated
|
||||||
|
FROM pg_stat_user_tables AS st, pg_class AS cl, prevcounts AS pc
|
||||||
|
WHERE st.relname='dustbunnies_990002' AND cl.relname='dustbunnies_990002';
|
||||||
|
|
||||||
|
exit when analyze_updated or vacuum_updated;
|
||||||
|
|
||||||
|
-- wait a little
|
||||||
|
perform pg_sleep(0.1);
|
||||||
|
|
||||||
|
-- reset stats snapshot so we can test again
|
||||||
|
perform pg_stat_clear_snapshot();
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
-- report time waited in postmaster log (where it won't change test output)
|
||||||
|
raise log 'wait_for_stats delayed % seconds',
|
||||||
|
extract(epoch from clock_timestamp() - start_time);
|
||||||
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
\c - - - :worker_2_port
|
||||||
|
CREATE MATERIALIZED VIEW prevcounts AS
|
||||||
|
SELECT analyze_count, vacuum_count FROM pg_stat_user_tables
|
||||||
|
WHERE relname='dustbunnies_990001';
|
||||||
|
-- create function that sleeps until those counters increment
|
||||||
|
create function wait_for_stats() returns void as $$
|
||||||
|
declare
|
||||||
|
start_time timestamptz := clock_timestamp();
|
||||||
|
analyze_updated bool;
|
||||||
|
vacuum_updated bool;
|
||||||
|
begin
|
||||||
|
-- we don't want to wait forever; loop will exit after 10 seconds
|
||||||
|
for i in 1 .. 100 loop
|
||||||
|
|
||||||
|
-- check to see if analyze has been updated
|
||||||
|
SELECT (st.analyze_count >= pc.analyze_count + 1) INTO analyze_updated
|
||||||
|
FROM pg_stat_user_tables AS st, pg_class AS cl, prevcounts AS pc
|
||||||
|
WHERE st.relname='dustbunnies_990001' AND cl.relname='dustbunnies_990001';
|
||||||
|
|
||||||
|
-- check to see if vacuum has been updated
|
||||||
|
SELECT (st.vacuum_count >= pc.vacuum_count + 1) INTO vacuum_updated
|
||||||
|
FROM pg_stat_user_tables AS st, pg_class AS cl, prevcounts AS pc
|
||||||
|
WHERE st.relname='dustbunnies_990001' AND cl.relname='dustbunnies_990001';
|
||||||
|
|
||||||
|
exit when analyze_updated or vacuum_updated;
|
||||||
|
|
||||||
|
-- wait a little
|
||||||
|
perform pg_sleep(0.1);
|
||||||
|
|
||||||
|
-- reset stats snapshot so we can test again
|
||||||
|
perform pg_stat_clear_snapshot();
|
||||||
|
|
||||||
|
end loop;
|
||||||
|
|
||||||
|
-- report time waited in postmaster log (where it won't change test output)
|
||||||
|
raise log 'wait_for_stats delayed % seconds',
|
||||||
|
extract(epoch from clock_timestamp() - start_time);
|
||||||
|
end
|
||||||
|
$$ language plpgsql;
|
||||||
|
-- run VACUUM and ANALYZE against the table on the master
|
||||||
|
\c - - - :master_port
|
||||||
|
VACUUM dustbunnies;
|
||||||
|
ANALYZE dustbunnies;
|
||||||
|
-- verify that the VACUUM and ANALYZE ran
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
SELECT wait_for_stats();
|
||||||
|
wait_for_stats
|
||||||
|
----------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
REFRESH MATERIALIZED VIEW prevcounts;
|
||||||
|
SELECT pg_stat_get_vacuum_count('dustbunnies_990002'::regclass);
|
||||||
|
pg_stat_get_vacuum_count
|
||||||
|
--------------------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_stat_get_analyze_count('dustbunnies_990002'::regclass);
|
||||||
|
pg_stat_get_analyze_count
|
||||||
|
---------------------------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- get file node to verify VACUUM FULL
|
||||||
|
SELECT relfilenode AS oldnode FROM pg_class WHERE oid='dustbunnies_990002'::regclass
|
||||||
|
\gset
|
||||||
|
-- send a VACUUM FULL and a VACUUM ANALYZE
|
||||||
|
\c - - - :master_port
|
||||||
|
VACUUM (FULL) dustbunnies;
|
||||||
|
VACUUM ANALYZE dustbunnies;
|
||||||
|
-- verify that relfilenode changed
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
SELECT relfilenode != :oldnode AS table_rewritten FROM pg_class
|
||||||
|
WHERE oid='dustbunnies_990002'::regclass;
|
||||||
|
table_rewritten
|
||||||
|
-----------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- verify the VACUUM ANALYZE incremented both vacuum and analyze counts
|
||||||
|
SELECT wait_for_stats();
|
||||||
|
wait_for_stats
|
||||||
|
----------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_stat_get_vacuum_count('dustbunnies_990002'::regclass);
|
||||||
|
pg_stat_get_vacuum_count
|
||||||
|
--------------------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT pg_stat_get_analyze_count('dustbunnies_990002'::regclass);
|
||||||
|
pg_stat_get_analyze_count
|
||||||
|
---------------------------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- disable auto-VACUUM for next test
|
||||||
|
ALTER TABLE dustbunnies_990002 SET (autovacuum_enabled = false);
|
||||||
|
SELECT relfrozenxid AS frozenxid FROM pg_class WHERE oid='dustbunnies_990002'::regclass
|
||||||
|
\gset
|
||||||
|
-- send a VACUUM FREEZE after adding a new row
|
||||||
|
\c - - - :master_port
|
||||||
|
INSERT INTO dustbunnies VALUES (5, 'peter');
|
||||||
|
VACUUM (FREEZE) dustbunnies;
|
||||||
|
-- verify that relfrozenxid increased
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
SELECT relfrozenxid::text::integer > :frozenxid AS frozen_performed FROM pg_class
|
||||||
|
WHERE oid='dustbunnies_990002'::regclass;
|
||||||
|
frozen_performed
|
||||||
|
------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- check there are no nulls in either column
|
||||||
|
SELECT attname, null_frac FROM pg_stats
|
||||||
|
WHERE tablename = 'dustbunnies_990002' ORDER BY attname;
|
||||||
|
attname | null_frac
|
||||||
|
---------+-----------
|
||||||
|
age | 1
|
||||||
|
id | 0
|
||||||
|
name | 0
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- add NULL values, then perform column-specific ANALYZE
|
||||||
|
\c - - - :master_port
|
||||||
|
INSERT INTO dustbunnies VALUES (6, NULL, NULL);
|
||||||
|
ANALYZE dustbunnies (name);
|
||||||
|
-- verify that name's NULL ratio is updated but age's is not
|
||||||
|
\c - - - :worker_1_port
|
||||||
|
SELECT attname, null_frac FROM pg_stats
|
||||||
|
WHERE tablename = 'dustbunnies_990002' ORDER BY attname;
|
||||||
|
attname | null_frac
|
||||||
|
---------+-----------
|
||||||
|
age | 1
|
||||||
|
id | 0
|
||||||
|
name | 0.166667
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
\c - - - :master_port
|
||||||
|
-- verify warning for unqualified VACUUM
|
||||||
|
VACUUM;
|
||||||
|
WARNING: not propagating VACUUM command to worker nodes
|
||||||
|
HINT: Provide a specific table in order to VACUUM distributed tables.
|
||||||
|
-- check for multiple table vacuum
|
||||||
|
VACUUM dustbunnies, second_dustbunnies;
|
||||||
|
ERROR: syntax error at or near ","
|
||||||
|
LINE 1: VACUUM dustbunnies, second_dustbunnies;
|
||||||
|
^
|
||||||
|
-- check the current number of vacuum and analyze run on dustbunnies
|
||||||
|
SELECT run_command_on_workers($$SELECT wait_for_stats()$$);
|
||||||
|
run_command_on_workers
|
||||||
|
------------------------
|
||||||
|
(localhost,57637,t,"")
|
||||||
|
(localhost,57638,t,"")
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT run_command_on_workers($$SELECT pg_stat_get_vacuum_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
||||||
|
run_command_on_workers
|
||||||
|
------------------------
|
||||||
|
(localhost,57637,t,3)
|
||||||
|
(localhost,57638,t,3)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT run_command_on_workers($$SELECT pg_stat_get_analyze_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
||||||
|
run_command_on_workers
|
||||||
|
------------------------
|
||||||
|
(localhost,57637,t,3)
|
||||||
|
(localhost,57638,t,3)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- and warning when using targeted VACUUM without DDL propagation
|
||||||
|
SET citus.enable_ddl_propagation to false;
|
||||||
|
VACUUM dustbunnies;
|
||||||
|
WARNING: not propagating VACUUM command to worker nodes
|
||||||
|
HINT: Set citus.enable_ddl_propagation to true in order to send targeted VACUUM commands to worker nodes.
|
||||||
|
ANALYZE dustbunnies;
|
||||||
|
WARNING: not propagating ANALYZE command to worker nodes
|
||||||
|
HINT: Set citus.enable_ddl_propagation to true in order to send targeted ANALYZE commands to worker nodes.
|
||||||
|
SET citus.enable_ddl_propagation to DEFAULT;
|
||||||
|
-- should not propagate the vacuum and analyze
|
||||||
|
SELECT run_command_on_workers($$SELECT wait_for_stats()$$);
|
||||||
|
run_command_on_workers
|
||||||
|
------------------------
|
||||||
|
(localhost,57637,t,"")
|
||||||
|
(localhost,57638,t,"")
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT run_command_on_workers($$SELECT pg_stat_get_vacuum_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
||||||
|
run_command_on_workers
|
||||||
|
------------------------
|
||||||
|
(localhost,57637,t,3)
|
||||||
|
(localhost,57638,t,3)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT run_command_on_workers($$SELECT pg_stat_get_analyze_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
||||||
|
run_command_on_workers
|
||||||
|
------------------------
|
||||||
|
(localhost,57637,t,3)
|
||||||
|
(localhost,57638,t,3)
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- test worker_hash
|
||||||
|
SELECT worker_hash(123);
|
||||||
|
worker_hash
|
||||||
|
-------------
|
||||||
|
-205084363
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT worker_hash('1997-08-08'::date);
|
||||||
|
worker_hash
|
||||||
|
-------------
|
||||||
|
-499701663
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- test a custom type (this test should run after multi_data_types)
|
||||||
|
SELECT worker_hash('(1, 2)');
|
||||||
|
ERROR: cannot find a hash function for the input type
|
||||||
|
HINT: Cast input to a data type with a hash function.
|
||||||
|
SELECT worker_hash('(1, 2)'::test_composite_type);
|
||||||
|
worker_hash
|
||||||
|
-------------
|
||||||
|
-1895345704
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT citus_truncate_trigger();
|
||||||
|
ERROR: must be called as trigger
|
||||||
|
-- confirm that citus_create_restore_point works
|
||||||
|
SELECT 1 FROM citus_create_restore_point('regression-test');
|
||||||
|
?column?
|
||||||
|
----------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- TODO: support VERBOSE
|
||||||
|
-- VACUUM VERBOSE dustbunnies;
|
||||||
|
-- VACUUM (FULL, VERBOSE) dustbunnies;
|
||||||
|
-- ANALYZE VERBOSE dustbunnies;
|
|
@ -5,6 +5,14 @@
|
||||||
-- Citus features: simple selects, aggregates, joins, outer joins
|
-- Citus features: simple selects, aggregates, joins, outer joins
|
||||||
-- router queries, single row inserts, multi row inserts via insert
|
-- router queries, single row inserts, multi row inserts via insert
|
||||||
-- into select, multi row insert via copy commands.
|
-- into select, multi row insert via copy commands.
|
||||||
|
-- print whether we're using version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_ten;
|
||||||
|
version_above_ten
|
||||||
|
-------------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT count(*) FROM lineitem_hash_part;
|
SELECT count(*) FROM lineitem_hash_part;
|
||||||
count
|
count
|
||||||
-------
|
-------
|
||||||
|
@ -789,8 +797,8 @@ RESET citus.subquery_pushdown;
|
||||||
VACUUM ANALYZE users_table;
|
VACUUM ANALYZE users_table;
|
||||||
-- explain tests
|
-- explain tests
|
||||||
EXPLAIN (COSTS FALSE) SELECT user_id FROM recent_selected_users GROUP BY 1 ORDER BY 1;
|
EXPLAIN (COSTS FALSE) SELECT user_id FROM recent_selected_users GROUP BY 1 ORDER BY 1;
|
||||||
QUERY PLAN
|
QUERY PLAN
|
||||||
---------------------------------------------------------------------------------------------------------------------------------------------------------
|
---------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
Sort
|
Sort
|
||||||
Sort Key: remote_scan.user_id
|
Sort Key: remote_scan.user_id
|
||||||
-> HashAggregate
|
-> HashAggregate
|
||||||
|
@ -802,19 +810,17 @@ EXPLAIN (COSTS FALSE) SELECT user_id FROM recent_selected_users GROUP BY 1 ORDER
|
||||||
Node: host=localhost port=57637 dbname=regression
|
Node: host=localhost port=57637 dbname=regression
|
||||||
-> HashAggregate
|
-> HashAggregate
|
||||||
Group Key: users_table.user_id
|
Group Key: users_table.user_id
|
||||||
-> Hash Join
|
-> Nested Loop
|
||||||
Hash Cond: (users_table.user_id = ru.user_id)
|
Join Filter: (users_table.user_id = users_table_1.user_id)
|
||||||
|
-> Sort
|
||||||
|
Sort Key: (max(users_table_1."time")) DESC
|
||||||
|
-> HashAggregate
|
||||||
|
Group Key: users_table_1.user_id
|
||||||
|
Filter: (max(users_table_1."time") > '2017-11-23 16:20:33.264457'::timestamp without time zone)
|
||||||
|
-> Seq Scan on users_table_1400000 users_table_1
|
||||||
-> Seq Scan on users_table_1400000 users_table
|
-> Seq Scan on users_table_1400000 users_table
|
||||||
Filter: ((value_1 >= 1) AND (value_1 < 3))
|
Filter: ((value_1 >= 1) AND (value_1 < 3))
|
||||||
-> Hash
|
(21 rows)
|
||||||
-> Subquery Scan on ru
|
|
||||||
-> Sort
|
|
||||||
Sort Key: (max(users_table_1."time")) DESC
|
|
||||||
-> HashAggregate
|
|
||||||
Group Key: users_table_1.user_id
|
|
||||||
Filter: (max(users_table_1."time") > '2017-11-23 16:20:33.264457'::timestamp without time zone)
|
|
||||||
-> Seq Scan on users_table_1400000 users_table_1
|
|
||||||
(23 rows)
|
|
||||||
|
|
||||||
EXPLAIN (COSTS FALSE) SELECT *
|
EXPLAIN (COSTS FALSE) SELECT *
|
||||||
FROM (
|
FROM (
|
||||||
|
|
|
@ -0,0 +1,937 @@
|
||||||
|
--
|
||||||
|
-- MULTI_VIEW
|
||||||
|
--
|
||||||
|
-- This file contains test cases for view support. It verifies various
|
||||||
|
-- Citus features: simple selects, aggregates, joins, outer joins
|
||||||
|
-- router queries, single row inserts, multi row inserts via insert
|
||||||
|
-- into select, multi row insert via copy commands.
|
||||||
|
-- print whether we're using version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_ten;
|
||||||
|
version_above_ten
|
||||||
|
-------------------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT count(*) FROM lineitem_hash_part;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
12000
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT count(*) FROM orders_hash_part;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2985
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- create a view for priority orders
|
||||||
|
CREATE VIEW priority_orders AS SELECT * FROM orders_hash_part WHERE o_orderpriority < '3-MEDIUM';
|
||||||
|
-- aggregate pushdown
|
||||||
|
SELECT o_orderpriority, count(*) FROM priority_orders GROUP BY 1 ORDER BY 2, 1;
|
||||||
|
o_orderpriority | count
|
||||||
|
-----------------+-------
|
||||||
|
2-HIGH | 593
|
||||||
|
1-URGENT | 604
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT o_orderpriority, count(*) FROM orders_hash_part WHERE o_orderpriority < '3-MEDIUM' GROUP BY 1 ORDER BY 2,1;
|
||||||
|
o_orderpriority | count
|
||||||
|
-----------------+-------
|
||||||
|
2-HIGH | 593
|
||||||
|
1-URGENT | 604
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- filters
|
||||||
|
SELECT o_orderpriority, count(*) as all, count(*) FILTER (WHERE o_orderstatus ='F') as fullfilled FROM priority_orders GROUP BY 1 ORDER BY 2, 1;
|
||||||
|
o_orderpriority | all | fullfilled
|
||||||
|
-----------------+-----+------------
|
||||||
|
2-HIGH | 593 | 271
|
||||||
|
1-URGENT | 604 | 280
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- having
|
||||||
|
SELECT o_orderdate, count(*) from priority_orders group by 1 having (count(*) > 3) order by 2 desc, 1 desc;
|
||||||
|
o_orderdate | count
|
||||||
|
-------------+-------
|
||||||
|
08-20-1996 | 5
|
||||||
|
10-10-1994 | 4
|
||||||
|
05-05-1994 | 4
|
||||||
|
04-07-1994 | 4
|
||||||
|
03-17-1993 | 4
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
-- having with filters
|
||||||
|
SELECT o_orderdate, count(*) as all, count(*) FILTER(WHERE o_orderstatus = 'F') from priority_orders group by 1 having (count(*) > 3) order by 2 desc, 1 desc;
|
||||||
|
o_orderdate | all | count
|
||||||
|
-------------+-----+-------
|
||||||
|
08-20-1996 | 5 | 0
|
||||||
|
10-10-1994 | 4 | 4
|
||||||
|
05-05-1994 | 4 | 4
|
||||||
|
04-07-1994 | 4 | 4
|
||||||
|
03-17-1993 | 4 | 4
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
-- limit
|
||||||
|
SELECT o_orderkey, o_totalprice from orders_hash_part order by 2 desc, 1 asc limit 5 ;
|
||||||
|
o_orderkey | o_totalprice
|
||||||
|
------------+--------------
|
||||||
|
4421 | 401055.62
|
||||||
|
10209 | 400191.77
|
||||||
|
11142 | 395039.05
|
||||||
|
14179 | 384265.43
|
||||||
|
11296 | 378166.33
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
SELECT o_orderkey, o_totalprice from priority_orders order by 2 desc, 1 asc limit 1 ;
|
||||||
|
o_orderkey | o_totalprice
|
||||||
|
------------+--------------
|
||||||
|
14179 | 384265.43
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
CREATE VIEW priority_lineitem AS SELECT li.* FROM lineitem_hash_part li JOIN priority_orders ON (l_orderkey = o_orderkey);
|
||||||
|
SELECT l_orderkey, count(*) FROM priority_lineitem GROUP BY 1 ORDER BY 2 DESC, 1 LIMIT 5;
|
||||||
|
l_orderkey | count
|
||||||
|
------------+-------
|
||||||
|
7 | 7
|
||||||
|
225 | 7
|
||||||
|
226 | 7
|
||||||
|
322 | 7
|
||||||
|
326 | 7
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
CREATE VIEW air_shipped_lineitems AS SELECT * FROM lineitem_hash_part WHERE l_shipmode = 'AIR';
|
||||||
|
-- join between view and table
|
||||||
|
SELECT count(*) FROM orders_hash_part join air_shipped_lineitems ON (o_orderkey = l_orderkey);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
1706
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- join between views
|
||||||
|
SELECT count(*) FROM priority_orders join air_shipped_lineitems ON (o_orderkey = l_orderkey);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
700
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- count distinct on partition column is supported
|
||||||
|
SELECT count(distinct o_orderkey) FROM priority_orders join air_shipped_lineitems ON (o_orderkey = l_orderkey);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
551
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- count distinct on non-partition column is supported
|
||||||
|
SELECT count(distinct o_orderpriority) FROM priority_orders join air_shipped_lineitems ON (o_orderkey = l_orderkey);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- count distinct on partition column is supported on router queries
|
||||||
|
SELECT count(distinct o_orderkey) FROM priority_orders join air_shipped_lineitems
|
||||||
|
ON (o_orderkey = l_orderkey)
|
||||||
|
WHERE (o_orderkey = 231);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- select distinct on router joins of views also works
|
||||||
|
SELECT distinct(o_orderkey) FROM priority_orders join air_shipped_lineitems
|
||||||
|
ON (o_orderkey = l_orderkey)
|
||||||
|
WHERE (o_orderkey = 231);
|
||||||
|
o_orderkey
|
||||||
|
------------
|
||||||
|
231
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- left join support depends on flattening of the query
|
||||||
|
-- following query fails since the inner part is kept as subquery
|
||||||
|
SELECT * FROM priority_orders left join air_shipped_lineitems ON (o_orderkey = l_orderkey);
|
||||||
|
ERROR: cannot perform distributed planning on this query
|
||||||
|
DETAIL: Subqueries in outer joins are not supported
|
||||||
|
-- however, this works
|
||||||
|
SELECT count(*) FROM priority_orders left join lineitem_hash_part ON (o_orderkey = l_orderkey) WHERE l_shipmode ='AIR';
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
700
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- view at the inner side of is not supported
|
||||||
|
SELECT count(*) FROM priority_orders right join lineitem_hash_part ON (o_orderkey = l_orderkey) WHERE l_shipmode ='AIR';
|
||||||
|
ERROR: cannot perform distributed planning on this query
|
||||||
|
DETAIL: Subqueries in outer joins are not supported
|
||||||
|
-- but view at the outer side is. This is essentially the same as a left join with arguments reversed.
|
||||||
|
SELECT count(*) FROM lineitem_hash_part right join priority_orders ON (o_orderkey = l_orderkey) WHERE l_shipmode ='AIR';
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
700
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- left join on router query is supported
|
||||||
|
SELECT o_orderkey, l_linenumber FROM priority_orders left join air_shipped_lineitems ON (o_orderkey = l_orderkey)
|
||||||
|
WHERE o_orderkey = 2;
|
||||||
|
o_orderkey | l_linenumber
|
||||||
|
------------+--------------
|
||||||
|
2 |
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- repartition query on view join
|
||||||
|
-- it passes planning, fails at execution stage
|
||||||
|
SET client_min_messages TO DEBUG1;
|
||||||
|
SELECT * FROM priority_orders JOIN air_shipped_lineitems ON (o_custkey = l_suppkey) ORDER BY o_orderkey DESC, o_custkey DESC, o_orderpriority DESC LIMIT 5;
|
||||||
|
DEBUG: generating subplan 22_1 for subquery SELECT lineitem_hash_part.l_orderkey, lineitem_hash_part.l_partkey, lineitem_hash_part.l_suppkey, lineitem_hash_part.l_linenumber, lineitem_hash_part.l_quantity, lineitem_hash_part.l_extendedprice, lineitem_hash_part.l_discount, lineitem_hash_part.l_tax, lineitem_hash_part.l_returnflag, lineitem_hash_part.l_linestatus, lineitem_hash_part.l_shipdate, lineitem_hash_part.l_commitdate, lineitem_hash_part.l_receiptdate, lineitem_hash_part.l_shipinstruct, lineitem_hash_part.l_shipmode, lineitem_hash_part.l_comment FROM public.lineitem_hash_part WHERE (lineitem_hash_part.l_shipmode = 'AIR'::bpchar)
|
||||||
|
DEBUG: Plan 22 query after replacing subqueries and CTEs: SELECT priority_orders.o_orderkey, priority_orders.o_custkey, priority_orders.o_orderstatus, priority_orders.o_totalprice, priority_orders.o_orderdate, priority_orders.o_orderpriority, priority_orders.o_clerk, priority_orders.o_shippriority, priority_orders.o_comment, air_shipped_lineitems.l_orderkey, air_shipped_lineitems.l_partkey, air_shipped_lineitems.l_suppkey, air_shipped_lineitems.l_linenumber, air_shipped_lineitems.l_quantity, air_shipped_lineitems.l_extendedprice, air_shipped_lineitems.l_discount, air_shipped_lineitems.l_tax, air_shipped_lineitems.l_returnflag, air_shipped_lineitems.l_linestatus, air_shipped_lineitems.l_shipdate, air_shipped_lineitems.l_commitdate, air_shipped_lineitems.l_receiptdate, air_shipped_lineitems.l_shipinstruct, air_shipped_lineitems.l_shipmode, air_shipped_lineitems.l_comment FROM ((SELECT orders_hash_part.o_orderkey, orders_hash_part.o_custkey, orders_hash_part.o_orderstatus, orders_hash_part.o_totalprice, orders_hash_part.o_orderdate, orders_hash_part.o_orderpriority, orders_hash_part.o_clerk, orders_hash_part.o_shippriority, orders_hash_part.o_comment FROM public.orders_hash_part WHERE (orders_hash_part.o_orderpriority < '3-MEDIUM'::bpchar)) priority_orders JOIN (SELECT intermediate_result.l_orderkey, intermediate_result.l_partkey, intermediate_result.l_suppkey, intermediate_result.l_linenumber, intermediate_result.l_quantity, intermediate_result.l_extendedprice, intermediate_result.l_discount, intermediate_result.l_tax, intermediate_result.l_returnflag, intermediate_result.l_linestatus, intermediate_result.l_shipdate, intermediate_result.l_commitdate, intermediate_result.l_receiptdate, intermediate_result.l_shipinstruct, intermediate_result.l_shipmode, intermediate_result.l_comment FROM read_intermediate_result('22_1'::text, 'binary'::citus_copy_format) intermediate_result(l_orderkey bigint, l_partkey integer, l_suppkey integer, l_linenumber integer, l_quantity numeric(15,2), l_extendedprice numeric(15,2), l_discount numeric(15,2), l_tax numeric(15,2), l_returnflag character(1), l_linestatus character(1), l_shipdate date, l_commitdate date, l_receiptdate date, l_shipinstruct character(25), l_shipmode character(10), l_comment character varying(44))) air_shipped_lineitems ON ((priority_orders.o_custkey = air_shipped_lineitems.l_suppkey))) ORDER BY priority_orders.o_orderkey DESC, priority_orders.o_custkey DESC, priority_orders.o_orderpriority DESC LIMIT 5
|
||||||
|
DEBUG: push down of limit count: 5
|
||||||
|
o_orderkey | o_custkey | o_orderstatus | o_totalprice | o_orderdate | o_orderpriority | o_clerk | o_shippriority | o_comment | l_orderkey | l_partkey | l_suppkey | l_linenumber | l_quantity | l_extendedprice | l_discount | l_tax | l_returnflag | l_linestatus | l_shipdate | l_commitdate | l_receiptdate | l_shipinstruct | l_shipmode | l_comment
|
||||||
|
------------+-----------+---------------+--------------+-------------+-----------------+-----------------+----------------+-------------------------------------------------------+------------+-----------+-----------+--------------+------------+-----------------+------------+-------+--------------+--------------+------------+--------------+---------------+---------------------------+------------+-------------------------------------------
|
||||||
|
14821 | 1435 | O | 322002.95 | 06-12-1998 | 2-HIGH | Clerk#000000630 | 0 | n packages are furiously ironic ideas. d | 1607 | 118923 | 1435 | 2 | 37.00 | 71851.04 | 0.05 | 0.02 | N | O | 02-27-1996 | 02-18-1996 | 03-16-1996 | NONE | AIR | alongside
|
||||||
|
14790 | 613 | O | 270163.54 | 08-21-1996 | 2-HIGH | Clerk#000000347 | 0 | p. regular deposits wake. final n | 2629 | 123076 | 613 | 2 | 31.00 | 34071.17 | 0.08 | 0.03 | N | O | 05-24-1998 | 05-26-1998 | 06-10-1998 | COLLECT COD | AIR | ate blithely bold, regular deposits. bold
|
||||||
|
14758 | 1225 | F | 37812.49 | 10-27-1993 | 2-HIGH | Clerk#000000687 | 0 | ages nag about the furio | 9156 | 176190 | 1225 | 2 | 22.00 | 27856.18 | 0.03 | 0.00 | R | F | 02-08-1994 | 04-01-1994 | 02-24-1994 | DELIVER IN PERSON | AIR | equests dete
|
||||||
|
14725 | 569 | O | 261801.45 | 06-17-1995 | 2-HIGH | Clerk#000000177 | 0 | ng asymptotes. final, ironic accounts cajole after | 14688 | 173017 | 569 | 3 | 10.00 | 10900.10 | 0.02 | 0.08 | N | O | 03-14-1997 | 04-22-1997 | 04-05-1997 | COLLECT COD | AIR | riously even packages sleep a
|
||||||
|
14657 | 370 | F | 116160.53 | 02-28-1994 | 1-URGENT | Clerk#000000756 | 0 | ly across the ironic, ironic instructions. bold ideas | 5153 | 67863 | 370 | 3 | 30.00 | 54925.80 | 0.09 | 0.01 | N | O | 11-10-1995 | 11-14-1995 | 11-16-1995 | DELIVER IN PERSON | AIR | beans sleep bl
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
RESET client_min_messages;
|
||||||
|
SELECT count(*) FROM priority_orders JOIN air_shipped_lineitems ON (o_custkey = l_suppkey);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
192
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- materialized views work
|
||||||
|
-- insert into... select works with views
|
||||||
|
CREATE TABLE temp_lineitem(LIKE lineitem_hash_part);
|
||||||
|
SELECT create_distributed_table('temp_lineitem', 'l_orderkey', 'hash', 'lineitem_hash_part');
|
||||||
|
create_distributed_table
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
INSERT INTO temp_lineitem SELECT * FROM air_shipped_lineitems;
|
||||||
|
SELECT count(*) FROM temp_lineitem;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
1706
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- following is a where false query, should not be inserting anything
|
||||||
|
INSERT INTO temp_lineitem SELECT * FROM air_shipped_lineitems WHERE l_shipmode = 'MAIL';
|
||||||
|
SELECT count(*) FROM temp_lineitem;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
1706
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- can create and query materialized views
|
||||||
|
CREATE MATERIALIZED VIEW mode_counts
|
||||||
|
AS SELECT l_shipmode, count(*) FROM temp_lineitem GROUP BY l_shipmode;
|
||||||
|
SELECT * FROM mode_counts WHERE l_shipmode = 'AIR' ORDER BY 2 DESC, 1 LIMIT 10;
|
||||||
|
l_shipmode | count
|
||||||
|
------------+-------
|
||||||
|
AIR | 1706
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- materialized views are local, cannot join with distributed tables
|
||||||
|
SELECT count(*) FROM mode_counts JOIN temp_lineitem USING (l_shipmode);
|
||||||
|
ERROR: relation mode_counts is not distributed
|
||||||
|
-- new data is not immediately reflected in the view
|
||||||
|
INSERT INTO temp_lineitem SELECT * FROM air_shipped_lineitems;
|
||||||
|
SELECT * FROM mode_counts WHERE l_shipmode = 'AIR' ORDER BY 2 DESC, 1 LIMIT 10;
|
||||||
|
l_shipmode | count
|
||||||
|
------------+-------
|
||||||
|
AIR | 1706
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- refresh updates the materialised view with new data
|
||||||
|
REFRESH MATERIALIZED VIEW mode_counts;
|
||||||
|
SELECT * FROM mode_counts WHERE l_shipmode = 'AIR' ORDER BY 2 DESC, 1 LIMIT 10;
|
||||||
|
l_shipmode | count
|
||||||
|
------------+-------
|
||||||
|
AIR | 3412
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP MATERIALIZED VIEW mode_counts;
|
||||||
|
SET citus.task_executor_type to "task-tracker";
|
||||||
|
-- single view repartition subqueries are not supported
|
||||||
|
SELECT l_suppkey, count(*) FROM
|
||||||
|
(SELECT l_suppkey, l_shipdate, count(*)
|
||||||
|
FROM air_shipped_lineitems GROUP BY l_suppkey, l_shipdate) supps
|
||||||
|
GROUP BY l_suppkey ORDER BY 2 DESC, 1 LIMIT 5;
|
||||||
|
ERROR: cannot perform distributed planning on this query
|
||||||
|
DETAIL: Subqueries without group by clause are not supported yet
|
||||||
|
-- logically same query without a view works fine
|
||||||
|
SELECT l_suppkey, count(*) FROM
|
||||||
|
(SELECT l_suppkey, l_shipdate, count(*)
|
||||||
|
FROM lineitem_hash_part WHERE l_shipmode = 'AIR' GROUP BY l_suppkey, l_shipdate) supps
|
||||||
|
GROUP BY l_suppkey ORDER BY 2 DESC, 1 LIMIT 5;
|
||||||
|
l_suppkey | count
|
||||||
|
-----------+-------
|
||||||
|
7680 | 4
|
||||||
|
160 | 3
|
||||||
|
1042 | 3
|
||||||
|
1318 | 3
|
||||||
|
5873 | 3
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
-- when a view is replaced by actual query it still fails
|
||||||
|
SELECT l_suppkey, count(*) FROM
|
||||||
|
(SELECT l_suppkey, l_shipdate, count(*)
|
||||||
|
FROM (SELECT * FROM lineitem_hash_part WHERE l_shipmode = 'AIR') asi
|
||||||
|
GROUP BY l_suppkey, l_shipdate) supps
|
||||||
|
GROUP BY l_suppkey ORDER BY 2 DESC, 1 LIMIT 5;
|
||||||
|
ERROR: cannot perform distributed planning on this query
|
||||||
|
DETAIL: Subqueries without group by clause are not supported yet
|
||||||
|
-- repartition query on view with single table subquery
|
||||||
|
CREATE VIEW supp_count_view AS SELECT * FROM (SELECT l_suppkey, count(*) FROM lineitem_hash_part GROUP BY 1) s1;
|
||||||
|
SELECT * FROM supp_count_view ORDER BY 2 DESC, 1 LIMIT 10;
|
||||||
|
l_suppkey | count
|
||||||
|
-----------+-------
|
||||||
|
6104 | 8
|
||||||
|
1868 | 6
|
||||||
|
5532 | 6
|
||||||
|
5849 | 6
|
||||||
|
6169 | 6
|
||||||
|
6669 | 6
|
||||||
|
6692 | 6
|
||||||
|
7703 | 6
|
||||||
|
7869 | 6
|
||||||
|
8426 | 6
|
||||||
|
(10 rows)
|
||||||
|
|
||||||
|
SET citus.task_executor_type to DEFAULT;
|
||||||
|
-- create a view with aggregate
|
||||||
|
CREATE VIEW lineitems_by_shipping_method AS
|
||||||
|
SELECT l_shipmode, count(*) as cnt FROM lineitem_hash_part GROUP BY 1;
|
||||||
|
-- following will be supported via recursive planning
|
||||||
|
SELECT * FROM lineitems_by_shipping_method ORDER BY 1,2 LIMIT 5;
|
||||||
|
l_shipmode | cnt
|
||||||
|
------------+------
|
||||||
|
AIR | 1706
|
||||||
|
FOB | 1709
|
||||||
|
MAIL | 1739
|
||||||
|
RAIL | 1706
|
||||||
|
REG AIR | 1679
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
-- create a view with group by on partition column
|
||||||
|
CREATE VIEW lineitems_by_orderkey AS
|
||||||
|
SELECT
|
||||||
|
l_orderkey, count(*)
|
||||||
|
FROM
|
||||||
|
lineitem_hash_part
|
||||||
|
GROUP BY 1;
|
||||||
|
-- this should work since we're able to push down this query
|
||||||
|
SELECT * FROM lineitems_by_orderkey ORDER BY 2 DESC, 1 ASC LIMIT 10;
|
||||||
|
l_orderkey | count
|
||||||
|
------------+-------
|
||||||
|
7 | 7
|
||||||
|
68 | 7
|
||||||
|
129 | 7
|
||||||
|
164 | 7
|
||||||
|
194 | 7
|
||||||
|
225 | 7
|
||||||
|
226 | 7
|
||||||
|
322 | 7
|
||||||
|
326 | 7
|
||||||
|
354 | 7
|
||||||
|
(10 rows)
|
||||||
|
|
||||||
|
-- it would also work since it is made router plannable
|
||||||
|
SELECT * FROM lineitems_by_orderkey WHERE l_orderkey = 100;
|
||||||
|
l_orderkey | count
|
||||||
|
------------+-------
|
||||||
|
100 | 5
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
DROP TABLE temp_lineitem CASCADE;
|
||||||
|
DROP VIEW supp_count_view;
|
||||||
|
DROP VIEW lineitems_by_orderkey;
|
||||||
|
DROP VIEW lineitems_by_shipping_method;
|
||||||
|
DROP VIEW air_shipped_lineitems;
|
||||||
|
DROP VIEW priority_lineitem;
|
||||||
|
DROP VIEW priority_orders;
|
||||||
|
-- new tests for real time use case including views and subqueries
|
||||||
|
-- create view to display recent user who has an activity after a timestamp
|
||||||
|
CREATE VIEW recent_users AS
|
||||||
|
SELECT user_id, max(time) as lastseen FROM users_table
|
||||||
|
GROUP BY user_id
|
||||||
|
HAVING max(time) > '2017-11-23 16:20:33.264457'::timestamp order by 2 DESC;
|
||||||
|
SELECT * FROM recent_users;
|
||||||
|
user_id | lastseen
|
||||||
|
---------+---------------------------------
|
||||||
|
1 | Thu Nov 23 17:30:34.635085 2017
|
||||||
|
5 | Thu Nov 23 16:48:32.08896 2017
|
||||||
|
3 | Thu Nov 23 17:18:51.048758 2017
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- create a view for recent_events
|
||||||
|
CREATE VIEW recent_events AS
|
||||||
|
SELECT user_id, time FROM events_table
|
||||||
|
WHERE time > '2017-11-23 16:20:33.264457'::timestamp;
|
||||||
|
SELECT count(*) FROM recent_events;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
6
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- count number of events of recent_users
|
||||||
|
SELECT count(*) FROM recent_users ru JOIN events_table et ON (ru.user_id = et.user_id);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
50
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- count number of events of per recent users order by count
|
||||||
|
SELECT ru.user_id, count(*)
|
||||||
|
FROM recent_users ru
|
||||||
|
JOIN events_table et
|
||||||
|
ON (ru.user_id = et.user_id)
|
||||||
|
GROUP BY ru.user_id
|
||||||
|
ORDER BY 2 DESC, 1;
|
||||||
|
user_id | count
|
||||||
|
---------+-------
|
||||||
|
3 | 21
|
||||||
|
1 | 15
|
||||||
|
5 | 14
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- the same query with a left join however, it would still generate the same result
|
||||||
|
SELECT ru.user_id, count(*)
|
||||||
|
FROM recent_users ru
|
||||||
|
LEFT JOIN events_table et
|
||||||
|
ON (ru.user_id = et.user_id)
|
||||||
|
GROUP BY ru.user_id
|
||||||
|
ORDER BY 2 DESC, 1;
|
||||||
|
user_id | count
|
||||||
|
---------+-------
|
||||||
|
3 | 21
|
||||||
|
1 | 15
|
||||||
|
5 | 14
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- query wrapped inside a subquery, it needs another top level order by
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT ru.user_id, count(*)
|
||||||
|
FROM recent_users ru
|
||||||
|
JOIN events_table et
|
||||||
|
ON (ru.user_id = et.user_id)
|
||||||
|
GROUP BY ru.user_id
|
||||||
|
ORDER BY 2 DESC, 1) s1
|
||||||
|
ORDER BY 2 DESC, 1;
|
||||||
|
user_id | count
|
||||||
|
---------+-------
|
||||||
|
3 | 21
|
||||||
|
1 | 15
|
||||||
|
5 | 14
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- non-partition key joins are not supported inside subquery
|
||||||
|
-- since the join with a table
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT ru.user_id, count(*)
|
||||||
|
FROM recent_users ru
|
||||||
|
JOIN events_table et
|
||||||
|
ON (ru.user_id = et.event_type)
|
||||||
|
GROUP BY ru.user_id
|
||||||
|
ORDER BY 2 DESC, 1) s1
|
||||||
|
ORDER BY 2 DESC, 1;
|
||||||
|
ERROR: bogus varno: 3
|
||||||
|
-- join between views
|
||||||
|
-- recent users who has an event in recent events
|
||||||
|
SELECT ru.user_id FROM recent_users ru JOIN recent_events re USING(user_id) GROUP BY ru.user_id ORDER BY ru.user_id;
|
||||||
|
user_id
|
||||||
|
---------
|
||||||
|
1
|
||||||
|
3
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
-- outer join inside a subquery
|
||||||
|
-- recent_events who are not done by recent users
|
||||||
|
SELECT count(*) FROM (
|
||||||
|
SELECT re.*, ru.user_id AS recent_user
|
||||||
|
FROM recent_events re LEFT JOIN recent_users ru USING(user_id)) reu
|
||||||
|
WHERE recent_user IS NULL;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- same query with anti-join
|
||||||
|
SELECT count(*)
|
||||||
|
FROM recent_events re LEFT JOIN recent_users ru ON(ru.user_id = re.user_id)
|
||||||
|
WHERE ru.user_id IS NULL;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- join between view and table
|
||||||
|
-- users who has recent activity and they have an entry with value_1 is less than 3
|
||||||
|
SELECT ut.* FROM recent_users ru JOIN users_table ut USING (user_id) WHERE ut.value_1 < 3 ORDER BY 1,2;
|
||||||
|
user_id | time | value_1 | value_2 | value_3 | value_4
|
||||||
|
---------+---------------------------------+---------+---------+---------+---------
|
||||||
|
1 | Thu Nov 23 09:26:42.145043 2017 | 1 | 3 | 3 |
|
||||||
|
3 | Wed Nov 22 18:43:51.450263 2017 | 1 | 1 | 4 |
|
||||||
|
3 | Wed Nov 22 20:43:31.008625 2017 | 1 | 3 | 2 |
|
||||||
|
3 | Thu Nov 23 00:15:45.610845 2017 | 1 | 1 | 4 |
|
||||||
|
3 | Thu Nov 23 03:23:24.702501 2017 | 1 | 2 | 5 |
|
||||||
|
3 | Thu Nov 23 06:20:05.854857 2017 | 1 | 4 | 2 |
|
||||||
|
3 | Thu Nov 23 09:57:41.540228 2017 | 2 | 2 | 3 |
|
||||||
|
3 | Thu Nov 23 11:18:53.114408 2017 | 2 | 2 | 0 |
|
||||||
|
3 | Thu Nov 23 12:56:49.29191 2017 | 0 | 5 | 1 |
|
||||||
|
3 | Thu Nov 23 17:18:51.048758 2017 | 1 | 5 | 5 |
|
||||||
|
5 | Wed Nov 22 20:43:18.667473 2017 | 0 | 3 | 2 |
|
||||||
|
5 | Wed Nov 22 21:02:07.575129 2017 | 2 | 0 | 2 |
|
||||||
|
5 | Wed Nov 22 22:10:24.315371 2017 | 1 | 2 | 1 |
|
||||||
|
5 | Thu Nov 23 00:54:44.192608 2017 | 1 | 3 | 2 |
|
||||||
|
5 | Thu Nov 23 07:47:09.542999 2017 | 1 | 4 | 3 |
|
||||||
|
5 | Thu Nov 23 09:05:08.53142 2017 | 2 | 2 | 2 |
|
||||||
|
5 | Thu Nov 23 09:17:47.706703 2017 | 2 | 5 | 3 |
|
||||||
|
5 | Thu Nov 23 10:15:31.764558 2017 | 2 | 2 | 2 |
|
||||||
|
5 | Thu Nov 23 14:29:02.557934 2017 | 2 | 1 | 2 |
|
||||||
|
5 | Thu Nov 23 15:55:08.493462 2017 | 0 | 3 | 3 |
|
||||||
|
5 | Thu Nov 23 16:28:38.455322 2017 | 2 | 5 | 4 |
|
||||||
|
(21 rows)
|
||||||
|
|
||||||
|
-- determine if a recent user has done a given event type or not
|
||||||
|
SELECT ru.user_id, CASE WHEN et.user_id IS NULL THEN 'NO' ELSE 'YES' END as done_event
|
||||||
|
FROM recent_users ru
|
||||||
|
LEFT JOIN events_table et
|
||||||
|
ON(ru.user_id = et.user_id AND et.event_type = 6)
|
||||||
|
ORDER BY 2 DESC, 1;
|
||||||
|
user_id | done_event
|
||||||
|
---------+------------
|
||||||
|
1 | YES
|
||||||
|
3 | NO
|
||||||
|
5 | NO
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- view vs table join wrapped inside a subquery
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT ru.user_id, CASE WHEN et.user_id IS NULL THEN 'NO' ELSE 'YES' END as done_event
|
||||||
|
FROM recent_users ru
|
||||||
|
LEFT JOIN events_table et
|
||||||
|
ON(ru.user_id = et.user_id AND et.event_type = 6)
|
||||||
|
) s1
|
||||||
|
ORDER BY 2 DESC, 1;
|
||||||
|
user_id | done_event
|
||||||
|
---------+------------
|
||||||
|
1 | YES
|
||||||
|
3 | NO
|
||||||
|
5 | NO
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- event vs table non-partition-key join is not supported
|
||||||
|
-- given that we cannot recursively plan tables yet
|
||||||
|
SELECT * FROM
|
||||||
|
(SELECT ru.user_id, CASE WHEN et.user_id IS NULL THEN 'NO' ELSE 'YES' END as done_event
|
||||||
|
FROM recent_users ru
|
||||||
|
LEFT JOIN events_table et
|
||||||
|
ON(ru.user_id = et.event_type)
|
||||||
|
) s1
|
||||||
|
ORDER BY 2 DESC, 1;
|
||||||
|
ERROR: bogus varno: 3
|
||||||
|
-- create a select only view
|
||||||
|
CREATE VIEW selected_users AS SELECT * FROM users_table WHERE value_1 >= 1 and value_1 <3;
|
||||||
|
CREATE VIEW recent_selected_users AS SELECT su.* FROM selected_users su JOIN recent_users ru USING(user_id);
|
||||||
|
SELECT user_id FROM recent_selected_users GROUP BY 1 ORDER BY 1;
|
||||||
|
user_id
|
||||||
|
---------
|
||||||
|
1
|
||||||
|
3
|
||||||
|
5
|
||||||
|
(3 rows)
|
||||||
|
|
||||||
|
-- this would be supported when we implement where partition_key in (subquery) support
|
||||||
|
SELECT et.user_id, et.time FROM events_table et WHERE et.user_id IN (SELECT user_id FROM recent_selected_users) GROUP BY 1,2 ORDER BY 1 DESC,2 DESC LIMIT 5;
|
||||||
|
user_id | time
|
||||||
|
---------+---------------------------------
|
||||||
|
5 | Thu Nov 23 16:11:02.929469 2017
|
||||||
|
5 | Thu Nov 23 14:40:40.467511 2017
|
||||||
|
5 | Thu Nov 23 14:28:51.833214 2017
|
||||||
|
5 | Thu Nov 23 14:23:09.889786 2017
|
||||||
|
5 | Thu Nov 23 13:26:45.571108 2017
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
-- it is supported when it is a router query
|
||||||
|
SELECT count(*) FROM events_table et WHERE et.user_id IN (SELECT user_id FROM recent_selected_users WHERE user_id = 1);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
15
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- union between views is supported through recursive planning
|
||||||
|
(SELECT user_id FROM recent_users)
|
||||||
|
UNION
|
||||||
|
(SELECT user_id FROM selected_users)
|
||||||
|
ORDER BY 1;
|
||||||
|
user_id
|
||||||
|
---------
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
|
-- wrapping it inside a SELECT * works
|
||||||
|
SELECT *
|
||||||
|
FROM (
|
||||||
|
(SELECT user_id FROM recent_users)
|
||||||
|
UNION
|
||||||
|
(SELECT user_id FROM selected_users) ) u
|
||||||
|
WHERE user_id < 2 AND user_id > 0
|
||||||
|
ORDER BY user_id;
|
||||||
|
user_id
|
||||||
|
---------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- union all also works for views
|
||||||
|
SELECT *
|
||||||
|
FROM (
|
||||||
|
(SELECT user_id FROM recent_users)
|
||||||
|
UNION ALL
|
||||||
|
(SELECT user_id FROM selected_users) ) u
|
||||||
|
WHERE user_id < 2 AND user_id > 0
|
||||||
|
ORDER BY user_id;
|
||||||
|
user_id
|
||||||
|
---------
|
||||||
|
1
|
||||||
|
1
|
||||||
|
(2 rows)
|
||||||
|
|
||||||
|
SELECT count(*)
|
||||||
|
FROM (
|
||||||
|
(SELECT user_id FROM recent_users)
|
||||||
|
UNION
|
||||||
|
(SELECT user_id FROM selected_users) ) u
|
||||||
|
WHERE user_id < 2 AND user_id > 0;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- UNION ALL between views is supported through recursive planning
|
||||||
|
SELECT count(*)
|
||||||
|
FROM (
|
||||||
|
(SELECT user_id FROM recent_users)
|
||||||
|
UNION ALL
|
||||||
|
(SELECT user_id FROM selected_users) ) u
|
||||||
|
WHERE user_id < 2 AND user_id > 0;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- expand view definitions and re-run last 2 queries
|
||||||
|
SELECT count(*)
|
||||||
|
FROM (
|
||||||
|
(SELECT user_id FROM (SELECT user_id, max(time) as lastseen FROM users_table
|
||||||
|
GROUP BY user_id
|
||||||
|
HAVING max(time) > '2017-11-22 05:45:49.978738'::timestamp order by 2 DESC) aa
|
||||||
|
)
|
||||||
|
UNION
|
||||||
|
(SELECT user_id FROM (SELECT * FROM users_table WHERE value_1 >= 1 and value_1 < 3) bb) ) u
|
||||||
|
WHERE user_id < 2 AND user_id > 0;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT count(*)
|
||||||
|
FROM (
|
||||||
|
(SELECT user_id FROM (SELECT user_id, max(time) as lastseen FROM users_table
|
||||||
|
GROUP BY user_id
|
||||||
|
HAVING max(time) > '2017-11-22 05:45:49.978738'::timestamp order by 2 DESC) aa
|
||||||
|
)
|
||||||
|
UNION ALL
|
||||||
|
(SELECT user_id FROM (SELECT * FROM users_table WHERE value_1 >= 1 and value_1 < 3) bb) ) u
|
||||||
|
WHERE user_id < 2 AND user_id > 0;
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- test distinct
|
||||||
|
-- distinct is supported if it is on a partition key
|
||||||
|
CREATE VIEW distinct_user_with_value_1_3 AS SELECT DISTINCT user_id FROM users_table WHERE value_1 = 3;
|
||||||
|
SELECT * FROM distinct_user_with_value_1_3 ORDER BY user_id;
|
||||||
|
user_id
|
||||||
|
---------
|
||||||
|
1
|
||||||
|
2
|
||||||
|
3
|
||||||
|
4
|
||||||
|
5
|
||||||
|
6
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
|
-- distinct is not supported if it is on a non-partition key
|
||||||
|
-- but will be supported via recursive planning
|
||||||
|
CREATE VIEW distinct_value_1 AS SELECT DISTINCT value_1 FROM users_table WHERE value_2 = 3;
|
||||||
|
SELECT * FROM distinct_value_1 ORDER BY 1 DESC LIMIT 5;
|
||||||
|
value_1
|
||||||
|
---------
|
||||||
|
5
|
||||||
|
4
|
||||||
|
3
|
||||||
|
2
|
||||||
|
1
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
-- CTEs are supported even if they are on views
|
||||||
|
CREATE VIEW cte_view_1 AS
|
||||||
|
WITH c1 AS (SELECT * FROM users_table WHERE value_1 = 3) SELECT * FROM c1 WHERE value_2 < 4;
|
||||||
|
SELECT * FROM cte_view_1 ORDER BY 1,2,3,4,5 LIMIT 5;
|
||||||
|
user_id | time | value_1 | value_2 | value_3 | value_4
|
||||||
|
---------+---------------------------------+---------+---------+---------+---------
|
||||||
|
1 | Thu Nov 23 03:32:50.803031 2017 | 3 | 2 | 1 |
|
||||||
|
2 | Thu Nov 23 13:52:54.83829 2017 | 3 | 1 | 4 |
|
||||||
|
3 | Wed Nov 22 23:24:32.080584 2017 | 3 | 2 | 5 |
|
||||||
|
4 | Wed Nov 22 23:59:46.493416 2017 | 3 | 1 | 3 |
|
||||||
|
4 | Thu Nov 23 01:55:21.824618 2017 | 3 | 1 | 4 |
|
||||||
|
(5 rows)
|
||||||
|
|
||||||
|
-- this is single shard query and still not supported since it has view + cte
|
||||||
|
-- router planner can't detect it
|
||||||
|
SELECT * FROM cte_view_1 WHERE user_id = 2 ORDER BY 1,2,3,4,5;
|
||||||
|
user_id | time | value_1 | value_2 | value_3 | value_4
|
||||||
|
---------+--------------------------------+---------+---------+---------+---------
|
||||||
|
2 | Thu Nov 23 13:52:54.83829 2017 | 3 | 1 | 4 |
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- if CTE itself prunes down to a single shard than the view is supported (router plannable)
|
||||||
|
CREATE VIEW cte_view_2 AS
|
||||||
|
WITH c1 AS (SELECT * FROM users_table WHERE user_id = 2) SELECT * FROM c1 WHERE value_1 = 3;
|
||||||
|
SELECT * FROM cte_view_2;
|
||||||
|
user_id | time | value_1 | value_2 | value_3 | value_4
|
||||||
|
---------+---------------------------------+---------+---------+---------+---------
|
||||||
|
2 | Thu Nov 23 00:19:14.138058 2017 | 3 | 4 | 0 |
|
||||||
|
2 | Thu Nov 23 13:52:54.83829 2017 | 3 | 1 | 4 |
|
||||||
|
2 | Wed Nov 22 18:19:49.944985 2017 | 3 | 5 | 1 |
|
||||||
|
2 | Thu Nov 23 11:41:04.042936 2017 | 3 | 4 | 1 |
|
||||||
|
(4 rows)
|
||||||
|
|
||||||
|
CREATE VIEW router_view AS SELECT * FROM users_table WHERE user_id = 2;
|
||||||
|
-- router plannable
|
||||||
|
SELECT user_id FROM router_view GROUP BY 1;
|
||||||
|
user_id
|
||||||
|
---------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- join a router view
|
||||||
|
SELECT * FROM (SELECT user_id FROM router_view GROUP BY 1) rv JOIN recent_events USING (user_id) ORDER BY 2 LIMIT 3;
|
||||||
|
user_id | time
|
||||||
|
---------+---------------------------------
|
||||||
|
2 | Thu Nov 23 17:26:14.563216 2017
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT * FROM (SELECT user_id FROM router_view GROUP BY 1) rv JOIN (SELECT * FROM recent_events) re USING (user_id) ORDER BY 2 LIMIT 3;
|
||||||
|
user_id | time
|
||||||
|
---------+---------------------------------
|
||||||
|
2 | Thu Nov 23 17:26:14.563216 2017
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
-- views with limits
|
||||||
|
CREATE VIEW recent_10_users AS
|
||||||
|
SELECT user_id, max(time) as lastseen FROM users_table
|
||||||
|
GROUP BY user_id
|
||||||
|
ORDER BY lastseen DESC
|
||||||
|
LIMIT 10;
|
||||||
|
-- this is not supported since it has limit in it and subquery_pushdown is not set
|
||||||
|
SELECT * FROM recent_10_users;
|
||||||
|
user_id | lastseen
|
||||||
|
---------+---------------------------------
|
||||||
|
1 | Thu Nov 23 17:30:34.635085 2017
|
||||||
|
3 | Thu Nov 23 17:18:51.048758 2017
|
||||||
|
5 | Thu Nov 23 16:48:32.08896 2017
|
||||||
|
4 | Thu Nov 23 15:32:02.360969 2017
|
||||||
|
6 | Thu Nov 23 14:43:18.024104 2017
|
||||||
|
2 | Thu Nov 23 13:52:54.83829 2017
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
|
SET citus.subquery_pushdown to ON;
|
||||||
|
-- still not supported since outer query does not have limit
|
||||||
|
-- it shows a different (subquery with single relation) error message
|
||||||
|
SELECT * FROM recent_10_users;
|
||||||
|
ERROR: cannot perform distributed planning on this query
|
||||||
|
DETAIL: Subqueries with limit are not supported yet
|
||||||
|
-- now it displays more correct error message
|
||||||
|
SELECT et.* FROM recent_10_users JOIN events_table et USING(user_id);
|
||||||
|
ERROR: cannot push down this subquery
|
||||||
|
DETAIL: Limit in subquery without limit in the outermost query is unsupported
|
||||||
|
-- now both are supported when there is a limit on the outer most query
|
||||||
|
SELECT * FROM recent_10_users ORDER BY lastseen DESC LIMIT 10;
|
||||||
|
user_id | lastseen
|
||||||
|
---------+---------------------------------
|
||||||
|
1 | Thu Nov 23 17:30:34.635085 2017
|
||||||
|
3 | Thu Nov 23 17:18:51.048758 2017
|
||||||
|
5 | Thu Nov 23 16:48:32.08896 2017
|
||||||
|
4 | Thu Nov 23 15:32:02.360969 2017
|
||||||
|
6 | Thu Nov 23 14:43:18.024104 2017
|
||||||
|
2 | Thu Nov 23 13:52:54.83829 2017
|
||||||
|
(6 rows)
|
||||||
|
|
||||||
|
SELECT et.* FROM recent_10_users JOIN events_table et USING(user_id) ORDER BY et.time DESC LIMIT 10;
|
||||||
|
user_id | time | event_type | value_2 | value_3 | value_4
|
||||||
|
---------+---------------------------------+------------+---------+---------+---------
|
||||||
|
1 | Thu Nov 23 21:54:46.924477 2017 | 6 | 4 | 5 |
|
||||||
|
4 | Thu Nov 23 18:10:21.338399 2017 | 1 | 2 | 4 |
|
||||||
|
3 | Thu Nov 23 18:08:26.550729 2017 | 2 | 4 | 3 |
|
||||||
|
2 | Thu Nov 23 17:26:14.563216 2017 | 1 | 5 | 3 |
|
||||||
|
3 | Thu Nov 23 16:44:41.903713 2017 | 4 | 2 | 2 |
|
||||||
|
3 | Thu Nov 23 16:31:56.219594 2017 | 5 | 1 | 2 |
|
||||||
|
4 | Thu Nov 23 16:20:33.264457 2017 | 0 | 0 | 3 |
|
||||||
|
5 | Thu Nov 23 16:11:02.929469 2017 | 4 | 2 | 0 |
|
||||||
|
2 | Thu Nov 23 15:58:49.273421 2017 | 5 | 1 | 2 |
|
||||||
|
5 | Thu Nov 23 14:40:40.467511 2017 | 1 | 4 | 1 |
|
||||||
|
(10 rows)
|
||||||
|
|
||||||
|
RESET citus.subquery_pushdown;
|
||||||
|
VACUUM ANALYZE users_table;
|
||||||
|
-- explain tests
|
||||||
|
EXPLAIN (COSTS FALSE) SELECT user_id FROM recent_selected_users GROUP BY 1 ORDER BY 1;
|
||||||
|
QUERY PLAN
|
||||||
|
---------------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
Sort
|
||||||
|
Sort Key: remote_scan.user_id
|
||||||
|
-> HashAggregate
|
||||||
|
Group Key: remote_scan.user_id
|
||||||
|
-> Custom Scan (Citus Real-Time)
|
||||||
|
Task Count: 4
|
||||||
|
Tasks Shown: One of 4
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> HashAggregate
|
||||||
|
Group Key: users_table.user_id
|
||||||
|
-> Hash Join
|
||||||
|
Hash Cond: (users_table.user_id = ru.user_id)
|
||||||
|
-> Seq Scan on users_table_1400000 users_table
|
||||||
|
Filter: ((value_1 >= 1) AND (value_1 < 3))
|
||||||
|
-> Hash
|
||||||
|
-> Subquery Scan on ru
|
||||||
|
-> Sort
|
||||||
|
Sort Key: (max(users_table_1."time")) DESC
|
||||||
|
-> HashAggregate
|
||||||
|
Group Key: users_table_1.user_id
|
||||||
|
Filter: (max(users_table_1."time") > '2017-11-23 16:20:33.264457'::timestamp without time zone)
|
||||||
|
-> Seq Scan on users_table_1400000 users_table_1
|
||||||
|
(23 rows)
|
||||||
|
|
||||||
|
EXPLAIN (COSTS FALSE) SELECT *
|
||||||
|
FROM (
|
||||||
|
(SELECT user_id FROM recent_users)
|
||||||
|
UNION
|
||||||
|
(SELECT user_id FROM selected_users) ) u
|
||||||
|
WHERE user_id < 4 AND user_id > 1
|
||||||
|
ORDER BY user_id;
|
||||||
|
QUERY PLAN
|
||||||
|
-------------------------------------------------------------------------------------------------------------------------------------------------
|
||||||
|
Sort
|
||||||
|
Sort Key: remote_scan.user_id
|
||||||
|
-> Custom Scan (Citus Real-Time)
|
||||||
|
Task Count: 4
|
||||||
|
Tasks Shown: One of 4
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> Unique
|
||||||
|
-> Sort
|
||||||
|
Sort Key: recent_users.user_id
|
||||||
|
-> Append
|
||||||
|
-> Subquery Scan on recent_users
|
||||||
|
-> Sort
|
||||||
|
Sort Key: (max(users_table."time")) DESC
|
||||||
|
-> GroupAggregate
|
||||||
|
Group Key: users_table.user_id
|
||||||
|
Filter: (max(users_table."time") > '2017-11-23 16:20:33.264457'::timestamp without time zone)
|
||||||
|
-> Sort
|
||||||
|
Sort Key: users_table.user_id
|
||||||
|
-> Seq Scan on users_table_1400000 users_table
|
||||||
|
Filter: ((user_id < 4) AND (user_id > 1))
|
||||||
|
-> Seq Scan on users_table_1400000 users_table_1
|
||||||
|
Filter: ((value_1 >= 1) AND (value_1 < 3) AND (user_id < 4) AND (user_id > 1))
|
||||||
|
(23 rows)
|
||||||
|
|
||||||
|
EXPLAIN (COSTS FALSE) SELECT et.* FROM recent_10_users JOIN events_table et USING(user_id) ORDER BY et.time DESC LIMIT 10;
|
||||||
|
QUERY PLAN
|
||||||
|
---------------------------------------------------------------------------------------------------------------------
|
||||||
|
Limit
|
||||||
|
-> Sort
|
||||||
|
Sort Key: remote_scan."time" DESC
|
||||||
|
-> Custom Scan (Citus Real-Time)
|
||||||
|
-> Distributed Subplan 95_1
|
||||||
|
-> Limit
|
||||||
|
-> Sort
|
||||||
|
Sort Key: max((max(remote_scan.lastseen))) DESC
|
||||||
|
-> HashAggregate
|
||||||
|
Group Key: remote_scan.user_id
|
||||||
|
-> Custom Scan (Citus Real-Time)
|
||||||
|
Task Count: 4
|
||||||
|
Tasks Shown: One of 4
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> Limit
|
||||||
|
-> Sort
|
||||||
|
Sort Key: (max("time")) DESC
|
||||||
|
-> HashAggregate
|
||||||
|
Group Key: user_id
|
||||||
|
-> Seq Scan on users_table_1400000 users_table
|
||||||
|
Task Count: 4
|
||||||
|
Tasks Shown: One of 4
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> Limit
|
||||||
|
-> Sort
|
||||||
|
Sort Key: et."time" DESC
|
||||||
|
-> Hash Join
|
||||||
|
Hash Cond: (intermediate_result.user_id = et.user_id)
|
||||||
|
-> Function Scan on read_intermediate_result intermediate_result
|
||||||
|
-> Hash
|
||||||
|
-> Seq Scan on events_table_1400004 et
|
||||||
|
(33 rows)
|
||||||
|
|
||||||
|
SET citus.subquery_pushdown to ON;
|
||||||
|
EXPLAIN (COSTS FALSE) SELECT et.* FROM recent_10_users JOIN events_table et USING(user_id) ORDER BY et.time DESC LIMIT 10;
|
||||||
|
QUERY PLAN
|
||||||
|
---------------------------------------------------------------------------------------------------------------------
|
||||||
|
Limit
|
||||||
|
-> Sort
|
||||||
|
Sort Key: remote_scan."time" DESC
|
||||||
|
-> Custom Scan (Citus Real-Time)
|
||||||
|
Task Count: 4
|
||||||
|
Tasks Shown: One of 4
|
||||||
|
-> Task
|
||||||
|
Node: host=localhost port=57637 dbname=regression
|
||||||
|
-> Limit
|
||||||
|
-> Sort
|
||||||
|
Sort Key: et."time" DESC
|
||||||
|
-> Hash Join
|
||||||
|
Hash Cond: (et.user_id = recent_10_users.user_id)
|
||||||
|
-> Seq Scan on events_table_1400004 et
|
||||||
|
-> Hash
|
||||||
|
-> Subquery Scan on recent_10_users
|
||||||
|
-> Limit
|
||||||
|
-> Sort
|
||||||
|
Sort Key: (max(users_table."time")) DESC
|
||||||
|
-> HashAggregate
|
||||||
|
Group Key: users_table.user_id
|
||||||
|
-> Seq Scan on users_table_1400000 users_table
|
||||||
|
(22 rows)
|
||||||
|
|
||||||
|
RESET citus.subquery_pushdown;
|
||||||
|
DROP VIEW recent_10_users;
|
||||||
|
DROP VIEW router_view;
|
||||||
|
DROP VIEW cte_view_2;
|
||||||
|
DROP VIEW cte_view_1;
|
||||||
|
DROP VIEW distinct_value_1;
|
||||||
|
DROP VIEW distinct_user_with_value_1_3;
|
||||||
|
DROP VIEW recent_selected_users;
|
||||||
|
DROP VIEW selected_users;
|
||||||
|
DROP VIEW recent_events;
|
||||||
|
DROP VIEW recent_users;
|
|
@ -17,6 +17,7 @@ FROM
|
||||||
WHERE users_table_local.user_id = evs.user_id
|
WHERE users_table_local.user_id = evs.user_id
|
||||||
) as foo;
|
) as foo;
|
||||||
ERROR: relation users_table_local is not distributed
|
ERROR: relation users_table_local is not distributed
|
||||||
|
RESET client_min_messages;
|
||||||
-- we don't support subqueries with local tables when they are not leaf queries
|
-- we don't support subqueries with local tables when they are not leaf queries
|
||||||
SELECT user_id FROM users_table WHERE user_id IN
|
SELECT user_id FROM users_table WHERE user_id IN
|
||||||
(SELECT
|
(SELECT
|
||||||
|
@ -28,6 +29,7 @@ SELECT user_id FROM users_table WHERE user_id IN
|
||||||
ERROR: relation "events_table_local" does not exist
|
ERROR: relation "events_table_local" does not exist
|
||||||
LINE 5: users_table_local JOIN (SELECT user_id FROM events_table_...
|
LINE 5: users_table_local JOIN (SELECT user_id FROM events_table_...
|
||||||
^
|
^
|
||||||
|
SET client_min_messages TO DEBUG1;
|
||||||
-- we don't support aggregate distinct if the group by is not on partition key, expect for count distinct
|
-- we don't support aggregate distinct if the group by is not on partition key, expect for count distinct
|
||||||
-- thus baz and bar are recursively planned but not foo
|
-- thus baz and bar are recursively planned but not foo
|
||||||
SELECT
|
SELECT
|
||||||
|
|
|
@ -684,8 +684,7 @@ DEBUG: Plan 69 query after replacing subqueries and CTEs: SELECT count(*) AS co
|
||||||
10
|
10
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
DROP TABLE local_table;
|
|
||||||
DEBUG: EventTriggerInvoke 19977
|
|
||||||
SET client_min_messages TO DEFAULT;
|
SET client_min_messages TO DEFAULT;
|
||||||
|
DROP TABLE local_table;
|
||||||
DROP SCHEMA subquery_in_where CASCADE;
|
DROP SCHEMA subquery_in_where CASCADE;
|
||||||
SET search_path TO public;
|
SET search_path TO public;
|
||||||
|
|
|
@ -99,7 +99,8 @@ test: multi_large_table_join_planning multi_large_table_pruning multi_large_tabl
|
||||||
# ---------
|
# ---------
|
||||||
|
|
||||||
test: with_nested with_where with_basics with_prepare with_set_operations
|
test: with_nested with_where with_basics with_prepare with_set_operations
|
||||||
test: with_modifying with_executors with_join with_partitioning
|
test: with_modifying
|
||||||
|
test: with_executors with_join with_partitioning
|
||||||
|
|
||||||
# ----------
|
# ----------
|
||||||
# Tests to check our large record loading and shard deletion behavior
|
# Tests to check our large record loading and shard deletion behavior
|
||||||
|
|
|
@ -10,9 +10,9 @@ SET citus.next_shard_id TO 650000;
|
||||||
SET citus.explain_distributed_queries TO off;
|
SET citus.explain_distributed_queries TO off;
|
||||||
SET citus.log_multi_join_order TO TRUE;
|
SET citus.log_multi_join_order TO TRUE;
|
||||||
SET citus.task_executor_type = 'task-tracker'; -- can't explain all queries otherwise
|
SET citus.task_executor_type = 'task-tracker'; -- can't explain all queries otherwise
|
||||||
SET client_min_messages TO DEBUG2;
|
|
||||||
SET citus.shard_count to 2;
|
SET citus.shard_count to 2;
|
||||||
SET citus.shard_replication_factor to 1;
|
SET citus.shard_replication_factor to 1;
|
||||||
|
RESET client_min_messages;
|
||||||
|
|
||||||
-- Create new table definitions for use in testing in distributed planning and
|
-- Create new table definitions for use in testing in distributed planning and
|
||||||
-- execution functionality. Also create indexes to boost performance.
|
-- execution functionality. Also create indexes to boost performance.
|
||||||
|
@ -63,6 +63,7 @@ CREATE TABLE customer_hash (
|
||||||
c_comment varchar(117) not null);
|
c_comment varchar(117) not null);
|
||||||
SELECT create_distributed_table('customer_hash', 'c_custkey');
|
SELECT create_distributed_table('customer_hash', 'c_custkey');
|
||||||
|
|
||||||
|
SET client_min_messages TO DEBUG2;
|
||||||
-- The following query checks that we can correctly handle self-joins
|
-- The following query checks that we can correctly handle self-joins
|
||||||
|
|
||||||
EXPLAIN SELECT l1.l_quantity FROM lineitem l1, lineitem l2
|
EXPLAIN SELECT l1.l_quantity FROM lineitem l1, lineitem l2
|
||||||
|
|
|
@ -4,6 +4,10 @@
|
||||||
-- Test user permissions.
|
-- Test user permissions.
|
||||||
--
|
--
|
||||||
|
|
||||||
|
-- print whether we're using version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_ten;
|
||||||
|
|
||||||
SET citus.next_shard_id TO 1420000;
|
SET citus.next_shard_id TO 1420000;
|
||||||
ALTER SEQUENCE pg_catalog.pg_dist_jobid_seq RESTART 1420000;
|
ALTER SEQUENCE pg_catalog.pg_dist_jobid_seq RESTART 1420000;
|
||||||
|
|
||||||
|
|
|
@ -91,12 +91,8 @@ SELECT "Column", "Type", "Modifiers" FROM table_desc WHERE relid='mx_ddl_table_1
|
||||||
-- Show that DDL commands are done within a two-phase commit transaction
|
-- Show that DDL commands are done within a two-phase commit transaction
|
||||||
\c - - - :master_port
|
\c - - - :master_port
|
||||||
|
|
||||||
SET client_min_messages TO debug2;
|
|
||||||
|
|
||||||
CREATE INDEX ddl_test_index ON mx_ddl_table(value);
|
CREATE INDEX ddl_test_index ON mx_ddl_table(value);
|
||||||
|
|
||||||
RESET client_min_messages;
|
|
||||||
|
|
||||||
DROP INDEX ddl_test_index;
|
DROP INDEX ddl_test_index;
|
||||||
|
|
||||||
-- show that sequences owned by mx tables result in unique values
|
-- show that sequences owned by mx tables result in unique values
|
||||||
|
|
|
@ -8,9 +8,9 @@
|
||||||
|
|
||||||
SET citus.next_shard_id TO 760000;
|
SET citus.next_shard_id TO 760000;
|
||||||
|
|
||||||
-- print whether we're using version > 9 to make version-specific tests clear
|
-- print major version number for version-specific tests
|
||||||
SHOW server_version \gset
|
SHOW server_version \gset
|
||||||
SELECT substring(:'server_version', '\d+')::int > 9 AS version_above_nine;
|
SELECT substring(:'server_version', '\d+')::int AS server_version;
|
||||||
|
|
||||||
SET client_min_messages TO DEBUG2;
|
SET client_min_messages TO DEBUG2;
|
||||||
SET citus.explain_all_tasks TO on;
|
SET citus.explain_all_tasks TO on;
|
||||||
|
|
|
@ -109,7 +109,7 @@ GROUP BY user_id
|
||||||
ORDER BY (10000 / (sum(value_1 + value_2))) DESC
|
ORDER BY (10000 / (sum(value_1 + value_2))) DESC
|
||||||
LIMIT 2;
|
LIMIT 2;
|
||||||
|
|
||||||
EXPLAIN
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT user_id
|
SELECT user_id
|
||||||
FROM users_table
|
FROM users_table
|
||||||
GROUP BY user_id
|
GROUP BY user_id
|
||||||
|
@ -139,7 +139,7 @@ GROUP BY user_id
|
||||||
ORDER BY sum(value_1) DESC
|
ORDER BY sum(value_1) DESC
|
||||||
LIMIT 2;
|
LIMIT 2;
|
||||||
|
|
||||||
EXPLAIN
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT user_id
|
SELECT user_id
|
||||||
FROM users_table
|
FROM users_table
|
||||||
GROUP BY user_id
|
GROUP BY user_id
|
||||||
|
@ -153,7 +153,7 @@ GROUP BY ut.user_id
|
||||||
ORDER BY MAX(et.time), AVG(ut.value_1)
|
ORDER BY MAX(et.time), AVG(ut.value_1)
|
||||||
LIMIT 5;
|
LIMIT 5;
|
||||||
|
|
||||||
EXPLAIN
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT ut.user_id, avg(ut.value_2)
|
SELECT ut.user_id, avg(ut.value_2)
|
||||||
FROM users_table ut, events_table et
|
FROM users_table ut, events_table et
|
||||||
WHERE ut.user_id = et.user_id and et.value_2 < 5
|
WHERE ut.user_id = et.user_id and et.value_2 < 5
|
||||||
|
@ -176,7 +176,7 @@ GROUP BY ut.user_id
|
||||||
ORDER BY 2, AVG(ut.value_1), 1 DESC
|
ORDER BY 2, AVG(ut.value_1), 1 DESC
|
||||||
LIMIT 2;
|
LIMIT 2;
|
||||||
|
|
||||||
EXPLAIN
|
EXPLAIN (COSTS OFF)
|
||||||
SELECT ut.user_id, count(DISTINCT ut.value_2)
|
SELECT ut.user_id, count(DISTINCT ut.value_2)
|
||||||
FROM users_table ut, events_table et
|
FROM users_table ut, events_table et
|
||||||
WHERE ut.user_id = et.user_id and et.value_2 < 5
|
WHERE ut.user_id = et.user_id and et.value_2 < 5
|
||||||
|
|
|
@ -6,6 +6,10 @@ SET citus.next_shard_id TO 1660000;
|
||||||
SET citus.shard_count TO 4;
|
SET citus.shard_count TO 4;
|
||||||
SET citus.shard_replication_factor TO 1;
|
SET citus.shard_replication_factor TO 1;
|
||||||
|
|
||||||
|
-- print major version number for version-specific tests
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int AS server_version;
|
||||||
|
|
||||||
--
|
--
|
||||||
-- Distributed Partitioned Table Creation Tests
|
-- Distributed Partitioned Table Creation Tests
|
||||||
--
|
--
|
||||||
|
@ -257,6 +261,7 @@ SELECT master_modify_multiple_shards('UPDATE partitioning_test_2009 SET time = t
|
||||||
|
|
||||||
-- test CREATE INDEX
|
-- test CREATE INDEX
|
||||||
-- CREATE INDEX on partitioned table - this will error out
|
-- CREATE INDEX on partitioned table - this will error out
|
||||||
|
-- on earlier versions of postgres earlier than 11.
|
||||||
CREATE INDEX partitioning_index ON partitioning_test(id);
|
CREATE INDEX partitioning_index ON partitioning_test(id);
|
||||||
|
|
||||||
-- CREATE INDEX on partition
|
-- CREATE INDEX on partition
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
-- This test has different output per major version
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int as server_major_version;
|
||||||
|
|
||||||
-- ===================================================================
|
-- ===================================================================
|
||||||
-- create test functions
|
-- create test functions
|
||||||
-- ===================================================================
|
-- ===================================================================
|
||||||
|
|
|
@ -1,3 +1,7 @@
|
||||||
|
-- print whether we're using version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_nine;
|
||||||
|
|
||||||
|
|
||||||
CREATE TABLE artists (
|
CREATE TABLE artists (
|
||||||
id bigint NOT NULL,
|
id bigint NOT NULL,
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
|
|
||||||
SET citus.next_shard_id TO 990000;
|
SET citus.next_shard_id TO 990000;
|
||||||
|
-- print server version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 as version_above_ten;
|
||||||
|
|
||||||
-- ===================================================================
|
-- ===================================================================
|
||||||
-- test utility statement functionality
|
-- test utility statement functionality
|
||||||
|
@ -107,6 +109,10 @@ SELECT master_create_worker_shards('dustbunnies', 1, 2);
|
||||||
4,roger
|
4,roger
|
||||||
\.
|
\.
|
||||||
|
|
||||||
|
CREATE TABLE second_dustbunnies(id integer, name text, age integer);
|
||||||
|
SELECT master_create_distributed_table('second_dustbunnies', 'id', 'hash');
|
||||||
|
SELECT master_create_worker_shards('second_dustbunnies', 1, 2);
|
||||||
|
|
||||||
-- following approach adapted from PostgreSQL's stats.sql file
|
-- following approach adapted from PostgreSQL's stats.sql file
|
||||||
|
|
||||||
-- save relevant stat counter values in refreshable view
|
-- save relevant stat counter values in refreshable view
|
||||||
|
@ -255,6 +261,9 @@ WHERE tablename = 'dustbunnies_990002' ORDER BY attname;
|
||||||
-- verify warning for unqualified VACUUM
|
-- verify warning for unqualified VACUUM
|
||||||
VACUUM;
|
VACUUM;
|
||||||
|
|
||||||
|
-- check for multiple table vacuum
|
||||||
|
VACUUM dustbunnies, second_dustbunnies;
|
||||||
|
|
||||||
-- check the current number of vacuum and analyze run on dustbunnies
|
-- check the current number of vacuum and analyze run on dustbunnies
|
||||||
SELECT run_command_on_workers($$SELECT wait_for_stats()$$);
|
SELECT run_command_on_workers($$SELECT wait_for_stats()$$);
|
||||||
SELECT run_command_on_workers($$SELECT pg_stat_get_vacuum_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
SELECT run_command_on_workers($$SELECT pg_stat_get_vacuum_count(tablename::regclass) from pg_tables where tablename LIKE 'dustbunnies_%' limit 1$$);
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
-- router queries, single row inserts, multi row inserts via insert
|
-- router queries, single row inserts, multi row inserts via insert
|
||||||
-- into select, multi row insert via copy commands.
|
-- into select, multi row insert via copy commands.
|
||||||
|
|
||||||
|
-- print whether we're using version > 10 to make version-specific tests clear
|
||||||
|
SHOW server_version \gset
|
||||||
|
SELECT substring(:'server_version', '\d+')::int > 10 AS version_above_ten;
|
||||||
|
|
||||||
SELECT count(*) FROM lineitem_hash_part;
|
SELECT count(*) FROM lineitem_hash_part;
|
||||||
|
|
||||||
SELECT count(*) FROM orders_hash_part;
|
SELECT count(*) FROM orders_hash_part;
|
||||||
|
|
|
@ -20,6 +20,7 @@ FROM
|
||||||
WHERE users_table_local.user_id = evs.user_id
|
WHERE users_table_local.user_id = evs.user_id
|
||||||
) as foo;
|
) as foo;
|
||||||
|
|
||||||
|
RESET client_min_messages;
|
||||||
-- we don't support subqueries with local tables when they are not leaf queries
|
-- we don't support subqueries with local tables when they are not leaf queries
|
||||||
SELECT user_id FROM users_table WHERE user_id IN
|
SELECT user_id FROM users_table WHERE user_id IN
|
||||||
(SELECT
|
(SELECT
|
||||||
|
@ -29,6 +30,8 @@ SELECT user_id FROM users_table WHERE user_id IN
|
||||||
USING (user_id)
|
USING (user_id)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
SET client_min_messages TO DEBUG1;
|
||||||
|
|
||||||
-- we don't support aggregate distinct if the group by is not on partition key, expect for count distinct
|
-- we don't support aggregate distinct if the group by is not on partition key, expect for count distinct
|
||||||
-- thus baz and bar are recursively planned but not foo
|
-- thus baz and bar are recursively planned but not foo
|
||||||
SELECT
|
SELECT
|
||||||
|
|
|
@ -509,9 +509,8 @@ IN
|
||||||
FROM
|
FROM
|
||||||
local_table);
|
local_table);
|
||||||
|
|
||||||
DROP TABLE local_table;
|
|
||||||
|
|
||||||
SET client_min_messages TO DEFAULT;
|
SET client_min_messages TO DEFAULT;
|
||||||
|
|
||||||
|
DROP TABLE local_table;
|
||||||
DROP SCHEMA subquery_in_where CASCADE;
|
DROP SCHEMA subquery_in_where CASCADE;
|
||||||
SET search_path TO public;
|
SET search_path TO public;
|
||||||
|
|
Loading…
Reference in New Issue