Switch to sequential execution if the index name is long (#4209)

Citus has the logic to truncate the long shard names to prevent
various issues, including self-deadlocks. However, for partitioned
tables, when index is created on the parent table, the index names
on the partitions are auto-generated by Postgres. We use the same
Postgres function to generate the index names on the shards of the
partitions. If the length exceeds the limit, we switch to sequential
execution mode.
pull/4207/head
Önder Kalacı 2020-10-02 12:39:34 +02:00 committed by GitHub
parent 45bb0fb587
commit df5aa0f0cc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 666 additions and 81 deletions

1
.gitattributes vendored
View File

@ -30,6 +30,7 @@ src/backend/distributed/utils/pg11_snprintf.c -citus-style
src/backend/distributed/deparser/ruleutils_11.c -citus-style
src/backend/distributed/deparser/ruleutils_12.c -citus-style
src/backend/distributed/deparser/ruleutils_13.c -citus-style
src/backend/distributed/commands/index_pg_source.c -citus-style
src/include/distributed/citus_nodes.h -citus-style
/vendor/** -citus-style

View File

@ -29,8 +29,11 @@
#include "distributed/listutils.h"
#include "distributed/coordinator_protocol.h"
#include "distributed/metadata_cache.h"
#include "distributed/multi_executor.h"
#include "distributed/multi_physical_planner.h"
#include "distributed/multi_partitioning_utils.h"
#include "distributed/resource_lock.h"
#include "distributed/relation_access_tracking.h"
#include "distributed/version_compat.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
@ -41,8 +44,15 @@
#include "utils/lsyscache.h"
#include "utils/syscache.h"
/* Local functions forward declarations for helper functions */
static List * CreateIndexTaskList(Oid relationId, IndexStmt *indexStmt);
static void SwitchToSequentialExecutionIfIndexNameTooLong(Oid relationId, Oid
namespaceId,
IndexStmt *createIndexStatement);
static char * GenerateLongestShardPartitionIndexName(Oid relationId, Oid namespaceId,
IndexStmt *createIndexStatement);
static List * CreateReindexTaskList(Oid relationId, ReindexStmt *reindexStmt);
static void RangeVarCallbackForDropIndex(const RangeVar *rel, Oid relOid, Oid oldRelOid,
void *arg);
@ -183,6 +193,25 @@ PreprocessIndexStmt(Node *node, const char *createIndexCommand)
ddlJob->taskList = CreateIndexTaskList(relationId, createIndexStatement);
ddlJobs = list_make1(ddlJob);
/*
* Citus has the logic to truncate the long shard names to prevent
* various issues, including self-deadlocks. However, for partitioned
* tables, when index is created on the parent table, the index names
* on the partitions are auto-generated by Postgres. We use the same
* Postgres function to generate the index names on the shards of the
* partitions. If the length exceeds the limit, we switch to sequential
* execution mode.
*
* The root cause of the problem is that postgres truncates the
* table/index names if they are longer than "NAMEDATALEN - 1".
* From Citus' perspective, running commands in parallel on the
* shards could mean these table/index names are truncated to be
* the same, and thus forming a self-deadlock as these tables/
* indexes are inserted into postgres' metadata tables, like pg_class.
*/
SwitchToSequentialExecutionIfIndexNameTooLong(relationId, namespaceId,
createIndexStatement);
}
}
}
@ -191,6 +220,111 @@ PreprocessIndexStmt(Node *node, const char *createIndexCommand)
}
/*
* SwitchToSequentialExecutionIfIndexNameTooLong generates the longest index name
* on the shards of the partitions, and if exceeds the limit switches to the
* sequential execution to prevent self-deadlocks.
*/
static void
SwitchToSequentialExecutionIfIndexNameTooLong(Oid relationId, Oid namespaceId,
IndexStmt *createIndexStatement)
{
if (!PartitionedTable(relationId))
{
/* Citus already handles long names for regular tables */
return;
}
if (ShardIntervalCount(relationId) == 0)
{
/*
* Relation has no shards, so we cannot run into "long shard index
* name" issue.
*/
return;
}
char *indexName =
GenerateLongestShardPartitionIndexName(relationId, namespaceId,
createIndexStatement);
if (indexName &&
strnlen(indexName, NAMEDATALEN) >= NAMEDATALEN - 1)
{
if (ParallelQueryExecutedInTransaction())
{
/*
* If there has already been a parallel query executed, the sequential mode
* would still use the already opened parallel connections to the workers,
* thus contradicting our purpose of using sequential mode.
*/
ereport(ERROR, (errmsg(
"The index name (%s) on a shard is too long and could lead "
"to deadlocks when executed in a transaction "
"block after a parallel query", indexName),
errhint("Try re-running the transaction with "
"\"SET LOCAL citus.multi_shard_modify_mode TO "
"\'sequential\';\"")));
}
elog(DEBUG1, "the index name on the shards of the partition "
"is too long, switching to sequential execution "
"mode to prevent self deadlocks: %s", indexName);
SetLocalMultiShardModifyModeToSequential();
}
}
/*
* GenerateLongestShardPartitionIndexName emulates Postgres index name
* generation for partitions on the shards. It returns the longest
* possible index name.
*/
static char *
GenerateLongestShardPartitionIndexName(Oid relationId, Oid namespaceId,
IndexStmt *createIndexStatement)
{
char *longestPartitionName = LongestPartitionName(relationId);
if (longestPartitionName == NULL)
{
/* no partitions have been created yet */
return NULL;
}
char *longestPartitionShardName = pstrdup(longestPartitionName);
ShardInterval *shardInterval = LoadShardIntervalWithLongestShardName(relationId);
AppendShardIdToName(&longestPartitionShardName, shardInterval->shardId);
/*
* The rest of the code is copy & paste from DefineIndex()
* postgres/src/backend/commands/indexcmds.c
*/
/*
* Calculate the new list of index columns including both key columns and
* INCLUDE columns. Later we can determine which of these are key
* columns, and which are just part of the INCLUDE list by checking the
* list position. A list item in a position less than ii_NumIndexKeyAttrs
* is part of the key columns, and anything equal to and over is part of
* the INCLUDE columns.
*/
List *allIndexParams =
list_concat(list_copy(createIndexStatement->indexParams),
list_copy(createIndexStatement->indexIncludingParams));
List *indexColNames = ChooseIndexColumnNames(allIndexParams);
char *choosenIndexName = ChooseIndexName(longestPartitionShardName, namespaceId,
indexColNames,
createIndexStatement->excludeOpNames,
createIndexStatement->primary,
createIndexStatement->isconstraint);
return choosenIndexName;
}
/*
* PreprocessReindexStmt determines whether a given REINDEX statement involves
* a distributed table. If so (and if the statement does not use unsupported

View File

@ -0,0 +1,200 @@
/*-------------------------------------------------------------------------
*
* index_pg_source.c
* Helper functions copy & pasted from PostgreSQL source code.
* All the functions in this file is copied from
* postgres/src/backend/commands/indexcmds.c
*
* Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/distributed/commands/index_pg_source.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "commands/defrem.h"
#include "distributed/commands.h"
#include "distributed/listutils.h"
#include "mb/pg_wchar.h"
/* *INDENT-OFF* */
/*
* This function is copy & paste from Postgres source code:
* postgres/src/backend/commands/indexcmds.c
*
* Select the name to be used for an index.
*
* The argument list is pretty ad-hoc :-(
*/
char *
ChooseIndexName(const char *tabname, Oid namespaceId,
List *colnames, List *exclusionOpNames,
bool primary, bool isconstraint)
{
char *indexname;
if (primary)
{
/* the primary key's name does not depend on the specific column(s) */
indexname = ChooseRelationName(tabname,
NULL,
"pkey",
namespaceId,
true);
}
else if (exclusionOpNames != NIL)
{
indexname = ChooseRelationName(tabname,
ChooseIndexNameAddition(colnames),
"excl",
namespaceId,
true);
}
else if (isconstraint)
{
indexname = ChooseRelationName(tabname,
ChooseIndexNameAddition(colnames),
"key",
namespaceId,
true);
}
else
{
indexname = ChooseRelationName(tabname,
ChooseIndexNameAddition(colnames),
"idx",
namespaceId,
false);
}
return indexname;
}
/*
* This function is copy & paste from Postgres source code:
* postgres/src/backend/commands/indexcmds.c
*
* Generate "name2" for a new index given the list of column names for it
* (as produced by ChooseIndexColumnNames). This will be passed to
* ChooseRelationName along with the parent table name and a suitable label.
*
* We know that less than NAMEDATALEN characters will actually be used,
* so we can truncate the result once we've generated that many.
*
* XXX See also ChooseForeignKeyConstraintNameAddition and
* ChooseExtendedStatisticNameAddition.
*/
char *
ChooseIndexNameAddition(List *colnames)
{
char buf[NAMEDATALEN * 2];
int buflen = 0;
ListCell *lc;
buf[0] = '\0';
foreach(lc, colnames)
{
const char *name = (const char *) lfirst(lc);
if (buflen > 0)
{
buf[buflen++] = '_'; /* insert _ between names */
}
/*
* At this point we have buflen <= NAMEDATALEN. name should be less
* than NAMEDATALEN already, but use strlcpy for paranoia.
*/
strlcpy(buf + buflen, name, NAMEDATALEN);
buflen += strlen(buf + buflen);
if (buflen >= NAMEDATALEN)
{
break;
}
}
return pstrdup(buf);
}
/*
* * This function is copy & paste from Postgres source code:
* postgres/src/backend/commands/indexcmds.c
*
* Select the actual names to be used for the columns of an index, given the
* list of IndexElems for the columns. This is mostly about ensuring the
* names are unique so we don't get a conflicting-attribute-names error.
*
* Returns a List of plain strings (char *, not String nodes).
*/
List *
ChooseIndexColumnNames(List *indexElems)
{
List *result = NIL;
ListCell *lc;
foreach(lc, indexElems)
{
IndexElem *ielem = (IndexElem *) lfirst(lc);
const char *origname;
const char *curname;
int i;
char buf[NAMEDATALEN];
/* Get the preliminary name from the IndexElem */
if (ielem->indexcolname)
{
origname = ielem->indexcolname; /* caller-specified name */
}
else if (ielem->name)
{
origname = ielem->name; /* simple column reference */
}
else
{
origname = "expr"; /* default name for expression */
}
/* If it conflicts with any previous column, tweak it */
curname = origname;
for (i = 1;; i++)
{
ListCell *lc2;
char nbuf[32];
int nlen;
foreach(lc2, result)
{
if (strcmp(curname, (char *) lfirst(lc2)) == 0)
{
break;
}
}
if (lc2 == NULL)
{
break; /* found nonconflicting name */
}
sprintf(nbuf, "%d", i);
/* Ensure generated names are shorter than NAMEDATALEN */
nlen = pg_mbcliplen(origname, strlen(origname),
NAMEDATALEN - 1 - strlen(nbuf));
memcpy(buf, origname, nlen);
strcpy(buf + nlen, nbuf);
curname = buf;
}
/* And attach to the result list */
result = lappend(result, pstrdup(curname));
}
return result;
}
/* *INDENT-ON* */

View File

@ -512,6 +512,35 @@ LoadShardIntervalList(Oid relationId)
}
/*
* LoadShardIntervalWithLongestShardName is a utility function that returns
* the shard interaval with the largest shardId for the given relationId. Note
* that largest shardId implies longest shard name.
*/
ShardInterval *
LoadShardIntervalWithLongestShardName(Oid relationId)
{
CitusTableCacheEntry *cacheEntry = GetCitusTableCacheEntry(relationId);
int shardIntervalCount = cacheEntry->shardIntervalArrayLength;
int maxShardIndex = shardIntervalCount - 1;
uint64 largestShardId = INVALID_SHARD_ID;
for (int shardIndex = 0; shardIndex <= maxShardIndex; ++shardIndex)
{
ShardInterval *currentShardInterval =
cacheEntry->sortedShardIntervalArray[shardIndex];
if (largestShardId < currentShardInterval->shardId)
{
largestShardId = currentShardInterval->shardId;
}
}
return LoadShardInterval(largestShardId);
}
/*
* ShardIntervalCount returns number of shard intervals for a given distributed table.
* The function returns 0 if no shards can be found for the given relation id.

View File

@ -17,6 +17,7 @@
#include "catalog/pg_inherits.h"
#include "distributed/citus_ruleutils.h"
#include "distributed/colocation_utils.h"
#include "distributed/listutils.h"
#include "distributed/metadata_utility.h"
#include "distributed/coordinator_protocol.h"
#include "distributed/multi_partitioning_utils.h"
@ -271,6 +272,33 @@ PartitionParentOid(Oid partitionOid)
}
/*
* LongestPartitionName is a uitility function that returns the partition
* name which is the longest in terms of number of characters.
*/
char *
LongestPartitionName(Oid parentRelationId)
{
char *longestName = NULL;
int longestNameLength = 0;
List *partitionList = PartitionList(parentRelationId);
Oid partitionRelationId = InvalidOid;
foreach_oid(partitionRelationId, partitionList)
{
char *partitionName = get_rel_name(partitionRelationId);
int partitionNameLength = strnlen(partitionName, NAMEDATALEN);
if (partitionNameLength > longestNameLength)
{
longestName = partitionName;
longestNameLength = partitionNameLength;
}
}
return longestName;
}
/*
* Takes a parent relation and returns Oid list of its partitions. The
* function errors out if the given relation is not a parent.

View File

@ -170,6 +170,11 @@ extern List * PreprocessGrantStmt(Node *node, const char *queryString);
extern bool IsIndexRenameStmt(RenameStmt *renameStmt);
extern List * PreprocessIndexStmt(Node *createIndexStatement,
const char *createIndexCommand);
extern char * ChooseIndexName(const char *tabname, Oid namespaceId,
List *colnames, List *exclusionOpNames,
bool primary, bool isconstraint);
extern char * ChooseIndexNameAddition(List *colnames);
extern List * ChooseIndexColumnNames(List *indexElems);
extern List * PreprocessReindexStmt(Node *ReindexStatement,
const char *ReindexCommand);
extern List * PreprocessDropIndexStmt(Node *dropIndexStatement,

View File

@ -99,6 +99,7 @@ extern Datum citus_relation_size(PG_FUNCTION_ARGS);
/* Function declarations to read shard and shard placement data */
extern uint32 TableShardReplicationFactor(Oid relationId);
extern List * LoadShardIntervalList(Oid relationId);
extern ShardInterval * LoadShardIntervalWithLongestShardName(Oid relationId);
extern int ShardIntervalCount(Oid relationId);
extern List * LoadShardList(Oid relationId);
extern ShardInterval * CopyShardInterval(ShardInterval *srcInterval);

View File

@ -19,6 +19,7 @@ extern bool PartitionTableNoLock(Oid relationId);
extern bool IsChildTable(Oid relationId);
extern bool IsParentTable(Oid relationId);
extern Oid PartitionParentOid(Oid partitionOid);
extern char * LongestPartitionName(Oid parentRelationId);
extern List * PartitionList(Oid parentRelationId);
extern char * GenerateDetachPartitionCommand(Oid partitionTableId);
extern char * GenerateAttachShardPartitionCommand(ShardInterval *shardInterval);

View File

@ -6,6 +6,8 @@
--
-- CREATE TEST TABLES
--
CREATE SCHEMA multi_index_statements;
SET search_path TO multi_index_statements;
SET citus.next_shard_id TO 102080;
CREATE TABLE index_test_range(a int, b int, c int);
SELECT create_distributed_table('index_test_range', 'a', 'range');
@ -58,13 +60,13 @@ SELECT master_create_empty_shard('index_test_append');
-- CREATE INDEX
--
-- Verify that we can create different types of indexes
CREATE INDEX lineitem_orderkey_index ON lineitem (l_orderkey);
CREATE INDEX lineitem_partkey_desc_index ON lineitem (l_partkey DESC);
CREATE INDEX lineitem_partial_index ON lineitem (l_shipdate)
CREATE INDEX lineitem_orderkey_index ON public.lineitem (l_orderkey);
CREATE INDEX lineitem_partkey_desc_index ON public.lineitem (l_partkey DESC);
CREATE INDEX lineitem_partial_index ON public.lineitem (l_shipdate)
WHERE l_shipdate < '1995-01-01';
CREATE INDEX lineitem_colref_index ON lineitem (record_ne(lineitem.*, NULL));
CREATE INDEX lineitem_colref_index ON public.lineitem (record_ne(lineitem.*, NULL));
SET client_min_messages = ERROR; -- avoid version dependant warning about WAL
CREATE INDEX lineitem_orderkey_hash_index ON lineitem USING hash (l_partkey);
CREATE INDEX lineitem_orderkey_hash_index ON public.lineitem USING hash (l_partkey);
CREATE UNIQUE INDEX index_test_range_index_a ON index_test_range(a);
CREATE UNIQUE INDEX index_test_range_index_a_b ON index_test_range(a,b);
CREATE UNIQUE INDEX index_test_hash_index_a ON index_test_hash(a);
@ -74,18 +76,18 @@ CREATE UNIQUE INDEX index_test_range_index_a_b_partial ON index_test_range(a,b)
CREATE UNIQUE INDEX index_test_hash_index_a_b_c ON index_test_hash(a) INCLUDE (b,c);
RESET client_min_messages;
-- Verify that we handle if not exists statements correctly
CREATE INDEX lineitem_orderkey_index on lineitem(l_orderkey);
CREATE INDEX lineitem_orderkey_index on public.lineitem(l_orderkey);
ERROR: relation "lineitem_orderkey_index" already exists
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on lineitem(l_orderkey);
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on public.lineitem(l_orderkey);
NOTICE: relation "lineitem_orderkey_index" already exists, skipping
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index_new on lineitem(l_orderkey);
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index_new on public.lineitem(l_orderkey);
-- Verify if not exists behavior with an index with same name on a different table
CREATE INDEX lineitem_orderkey_index on index_test_hash(a);
CREATE INDEX lineitem_orderkey_index on public.nation(n_nationkey);
ERROR: relation "lineitem_orderkey_index" already exists
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on index_test_hash(a);
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on public.nation(n_nationkey);
NOTICE: relation "lineitem_orderkey_index" already exists, skipping
-- Verify that we can create indexes concurrently
CREATE INDEX CONCURRENTLY lineitem_concurrently_index ON lineitem (l_orderkey);
CREATE INDEX CONCURRENTLY lineitem_concurrently_index ON public.lineitem (l_orderkey);
-- Verify that no-name local CREATE INDEX CONCURRENTLY works
CREATE TABLE local_table (id integer, name text);
CREATE INDEX CONCURRENTLY ON local_table(id);
@ -100,24 +102,24 @@ CLUSTER local_table USING local_table_index;
DROP TABLE local_table;
-- Verify that all indexes got created on the master node and one of the workers
SELECT * FROM pg_indexes WHERE tablename = 'lineitem' or tablename like 'index_test_%' ORDER BY indexname;
schemaname | tablename | indexname | tablespace | indexdef
schemaname | tablename | indexname | tablespace | indexdef
---------------------------------------------------------------------
public | index_test_hash | index_test_hash_index_a | | CREATE UNIQUE INDEX index_test_hash_index_a ON public.index_test_hash USING btree (a)
public | index_test_hash | index_test_hash_index_a_b | | CREATE UNIQUE INDEX index_test_hash_index_a_b ON public.index_test_hash USING btree (a, b)
public | index_test_hash | index_test_hash_index_a_b_c | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c ON public.index_test_hash USING btree (a) INCLUDE (b, c)
public | index_test_hash | index_test_hash_index_a_b_partial | | CREATE UNIQUE INDEX index_test_hash_index_a_b_partial ON public.index_test_hash USING btree (a, b) WHERE (c IS NOT NULL)
public | index_test_range | index_test_range_index_a | | CREATE UNIQUE INDEX index_test_range_index_a ON public.index_test_range USING btree (a)
public | index_test_range | index_test_range_index_a_b | | CREATE UNIQUE INDEX index_test_range_index_a_b ON public.index_test_range USING btree (a, b)
public | index_test_range | index_test_range_index_a_b_partial | | CREATE UNIQUE INDEX index_test_range_index_a_b_partial ON public.index_test_range USING btree (a, b) WHERE (c IS NOT NULL)
public | lineitem | lineitem_colref_index | | CREATE INDEX lineitem_colref_index ON public.lineitem USING btree (record_ne(lineitem.*, NULL::record))
public | lineitem | lineitem_concurrently_index | | CREATE INDEX lineitem_concurrently_index ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_orderkey_hash_index | | CREATE INDEX lineitem_orderkey_hash_index ON public.lineitem USING hash (l_partkey)
public | lineitem | lineitem_orderkey_index | | CREATE INDEX lineitem_orderkey_index ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_orderkey_index_new | | CREATE INDEX lineitem_orderkey_index_new ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_partial_index | | CREATE INDEX lineitem_partial_index ON public.lineitem USING btree (l_shipdate) WHERE (l_shipdate < '01-01-1995'::date)
public | lineitem | lineitem_partkey_desc_index | | CREATE INDEX lineitem_partkey_desc_index ON public.lineitem USING btree (l_partkey DESC)
public | lineitem | lineitem_pkey | | CREATE UNIQUE INDEX lineitem_pkey ON public.lineitem USING btree (l_orderkey, l_linenumber)
public | lineitem | lineitem_time_index | | CREATE INDEX lineitem_time_index ON public.lineitem USING btree (l_shipdate)
multi_index_statements | index_test_hash | index_test_hash_index_a | | CREATE UNIQUE INDEX index_test_hash_index_a ON multi_index_statements.index_test_hash USING btree (a)
multi_index_statements | index_test_hash | index_test_hash_index_a_b | | CREATE UNIQUE INDEX index_test_hash_index_a_b ON multi_index_statements.index_test_hash USING btree (a, b)
multi_index_statements | index_test_hash | index_test_hash_index_a_b_c | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c ON multi_index_statements.index_test_hash USING btree (a) INCLUDE (b, c)
multi_index_statements | index_test_hash | index_test_hash_index_a_b_partial | | CREATE UNIQUE INDEX index_test_hash_index_a_b_partial ON multi_index_statements.index_test_hash USING btree (a, b) WHERE (c IS NOT NULL)
multi_index_statements | index_test_range | index_test_range_index_a | | CREATE UNIQUE INDEX index_test_range_index_a ON multi_index_statements.index_test_range USING btree (a)
multi_index_statements | index_test_range | index_test_range_index_a_b | | CREATE UNIQUE INDEX index_test_range_index_a_b ON multi_index_statements.index_test_range USING btree (a, b)
multi_index_statements | index_test_range | index_test_range_index_a_b_partial | | CREATE UNIQUE INDEX index_test_range_index_a_b_partial ON multi_index_statements.index_test_range USING btree (a, b) WHERE (c IS NOT NULL)
public | lineitem | lineitem_colref_index | | CREATE INDEX lineitem_colref_index ON public.lineitem USING btree (record_ne(lineitem.*, NULL::record))
public | lineitem | lineitem_concurrently_index | | CREATE INDEX lineitem_concurrently_index ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_orderkey_hash_index | | CREATE INDEX lineitem_orderkey_hash_index ON public.lineitem USING hash (l_partkey)
public | lineitem | lineitem_orderkey_index | | CREATE INDEX lineitem_orderkey_index ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_orderkey_index_new | | CREATE INDEX lineitem_orderkey_index_new ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_partial_index | | CREATE INDEX lineitem_partial_index ON public.lineitem USING btree (l_shipdate) WHERE (l_shipdate < '01-01-1995'::date)
public | lineitem | lineitem_partkey_desc_index | | CREATE INDEX lineitem_partkey_desc_index ON public.lineitem USING btree (l_partkey DESC)
public | lineitem | lineitem_pkey | | CREATE UNIQUE INDEX lineitem_pkey ON public.lineitem USING btree (l_orderkey, l_linenumber)
public | lineitem | lineitem_time_index | | CREATE INDEX lineitem_time_index ON public.lineitem USING btree (l_shipdate)
(16 rows)
\c - - - :worker_1_port
@ -146,8 +148,9 @@ SELECT count(*) FROM pg_indexes WHERE tablename LIKE 'index_test_append%';
(1 row)
\c - - - :master_port
SET search_path TO multi_index_statements, public;
-- Verify that we error out on unsupported statement types
CREATE UNIQUE INDEX try_index ON lineitem (l_orderkey);
CREATE UNIQUE INDEX try_index ON public.lineitem (l_orderkey);
ERROR: creating unique indexes on append-partitioned tables is currently unsupported
CREATE INDEX try_index ON lineitem (l_orderkey) TABLESPACE newtablespace;
ERROR: specifying tablespaces with CREATE INDEX statements is currently unsupported
@ -178,24 +181,24 @@ CREATE INDEX ON lineitem (l_orderkey);
ERROR: creating index without a name on a distributed table is currently unsupported
-- Verify that none of failed indexes got created on the master node
SELECT * FROM pg_indexes WHERE tablename = 'lineitem' or tablename like 'index_test_%' ORDER BY indexname;
schemaname | tablename | indexname | tablespace | indexdef
schemaname | tablename | indexname | tablespace | indexdef
---------------------------------------------------------------------
public | index_test_hash | index_test_hash_index_a | | CREATE UNIQUE INDEX index_test_hash_index_a ON public.index_test_hash USING btree (a)
public | index_test_hash | index_test_hash_index_a_b | | CREATE UNIQUE INDEX index_test_hash_index_a_b ON public.index_test_hash USING btree (a, b)
public | index_test_hash | index_test_hash_index_a_b_c | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c ON public.index_test_hash USING btree (a) INCLUDE (b, c)
public | index_test_hash | index_test_hash_index_a_b_partial | | CREATE UNIQUE INDEX index_test_hash_index_a_b_partial ON public.index_test_hash USING btree (a, b) WHERE (c IS NOT NULL)
public | index_test_range | index_test_range_index_a | | CREATE UNIQUE INDEX index_test_range_index_a ON public.index_test_range USING btree (a)
public | index_test_range | index_test_range_index_a_b | | CREATE UNIQUE INDEX index_test_range_index_a_b ON public.index_test_range USING btree (a, b)
public | index_test_range | index_test_range_index_a_b_partial | | CREATE UNIQUE INDEX index_test_range_index_a_b_partial ON public.index_test_range USING btree (a, b) WHERE (c IS NOT NULL)
public | lineitem | lineitem_colref_index | | CREATE INDEX lineitem_colref_index ON public.lineitem USING btree (record_ne(lineitem.*, NULL::record))
public | lineitem | lineitem_concurrently_index | | CREATE INDEX lineitem_concurrently_index ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_orderkey_hash_index | | CREATE INDEX lineitem_orderkey_hash_index ON public.lineitem USING hash (l_partkey)
public | lineitem | lineitem_orderkey_index | | CREATE INDEX lineitem_orderkey_index ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_orderkey_index_new | | CREATE INDEX lineitem_orderkey_index_new ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_partial_index | | CREATE INDEX lineitem_partial_index ON public.lineitem USING btree (l_shipdate) WHERE (l_shipdate < '01-01-1995'::date)
public | lineitem | lineitem_partkey_desc_index | | CREATE INDEX lineitem_partkey_desc_index ON public.lineitem USING btree (l_partkey DESC)
public | lineitem | lineitem_pkey | | CREATE UNIQUE INDEX lineitem_pkey ON public.lineitem USING btree (l_orderkey, l_linenumber)
public | lineitem | lineitem_time_index | | CREATE INDEX lineitem_time_index ON public.lineitem USING btree (l_shipdate)
multi_index_statements | index_test_hash | index_test_hash_index_a | | CREATE UNIQUE INDEX index_test_hash_index_a ON multi_index_statements.index_test_hash USING btree (a)
multi_index_statements | index_test_hash | index_test_hash_index_a_b | | CREATE UNIQUE INDEX index_test_hash_index_a_b ON multi_index_statements.index_test_hash USING btree (a, b)
multi_index_statements | index_test_hash | index_test_hash_index_a_b_c | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c ON multi_index_statements.index_test_hash USING btree (a) INCLUDE (b, c)
multi_index_statements | index_test_hash | index_test_hash_index_a_b_partial | | CREATE UNIQUE INDEX index_test_hash_index_a_b_partial ON multi_index_statements.index_test_hash USING btree (a, b) WHERE (c IS NOT NULL)
multi_index_statements | index_test_range | index_test_range_index_a | | CREATE UNIQUE INDEX index_test_range_index_a ON multi_index_statements.index_test_range USING btree (a)
multi_index_statements | index_test_range | index_test_range_index_a_b | | CREATE UNIQUE INDEX index_test_range_index_a_b ON multi_index_statements.index_test_range USING btree (a, b)
multi_index_statements | index_test_range | index_test_range_index_a_b_partial | | CREATE UNIQUE INDEX index_test_range_index_a_b_partial ON multi_index_statements.index_test_range USING btree (a, b) WHERE (c IS NOT NULL)
public | lineitem | lineitem_colref_index | | CREATE INDEX lineitem_colref_index ON public.lineitem USING btree (record_ne(lineitem.*, NULL::record))
public | lineitem | lineitem_concurrently_index | | CREATE INDEX lineitem_concurrently_index ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_orderkey_hash_index | | CREATE INDEX lineitem_orderkey_hash_index ON public.lineitem USING hash (l_partkey)
public | lineitem | lineitem_orderkey_index | | CREATE INDEX lineitem_orderkey_index ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_orderkey_index_new | | CREATE INDEX lineitem_orderkey_index_new ON public.lineitem USING btree (l_orderkey)
public | lineitem | lineitem_partial_index | | CREATE INDEX lineitem_partial_index ON public.lineitem USING btree (l_shipdate) WHERE (l_shipdate < '01-01-1995'::date)
public | lineitem | lineitem_partkey_desc_index | | CREATE INDEX lineitem_partkey_desc_index ON public.lineitem USING btree (l_partkey DESC)
public | lineitem | lineitem_pkey | | CREATE UNIQUE INDEX lineitem_pkey ON public.lineitem USING btree (l_orderkey, l_linenumber)
public | lineitem | lineitem_time_index | | CREATE INDEX lineitem_time_index ON public.lineitem USING btree (l_shipdate)
(16 rows)
--
@ -243,9 +246,9 @@ SELECT indrelid::regclass, indexrelid::regclass FROM pg_index WHERE indrelid = (
(0 rows)
SELECT * FROM pg_indexes WHERE tablename LIKE 'index_test_%' ORDER BY indexname;
schemaname | tablename | indexname | tablespace | indexdef
schemaname | tablename | indexname | tablespace | indexdef
---------------------------------------------------------------------
public | index_test_hash | index_test_hash_index_a_b_c | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c ON public.index_test_hash USING btree (a) INCLUDE (b, c)
multi_index_statements | index_test_hash | index_test_hash_index_a_b_c | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c ON multi_index_statements.index_test_hash USING btree (a) INCLUDE (b, c)
(1 row)
\c - - - :worker_1_port
@ -255,21 +258,22 @@ SELECT indrelid::regclass, indexrelid::regclass FROM pg_index WHERE indrelid = (
(0 rows)
SELECT * FROM pg_indexes WHERE tablename LIKE 'index_test_%' ORDER BY indexname;
schemaname | tablename | indexname | tablespace | indexdef
schemaname | tablename | indexname | tablespace | indexdef
---------------------------------------------------------------------
public | index_test_hash_102082 | index_test_hash_index_a_b_c_102082 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102082 ON public.index_test_hash_102082 USING btree (a) INCLUDE (b, c)
public | index_test_hash_102083 | index_test_hash_index_a_b_c_102083 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102083 ON public.index_test_hash_102083 USING btree (a) INCLUDE (b, c)
public | index_test_hash_102084 | index_test_hash_index_a_b_c_102084 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102084 ON public.index_test_hash_102084 USING btree (a) INCLUDE (b, c)
public | index_test_hash_102085 | index_test_hash_index_a_b_c_102085 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102085 ON public.index_test_hash_102085 USING btree (a) INCLUDE (b, c)
public | index_test_hash_102086 | index_test_hash_index_a_b_c_102086 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102086 ON public.index_test_hash_102086 USING btree (a) INCLUDE (b, c)
public | index_test_hash_102087 | index_test_hash_index_a_b_c_102087 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102087 ON public.index_test_hash_102087 USING btree (a) INCLUDE (b, c)
public | index_test_hash_102088 | index_test_hash_index_a_b_c_102088 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102088 ON public.index_test_hash_102088 USING btree (a) INCLUDE (b, c)
public | index_test_hash_102089 | index_test_hash_index_a_b_c_102089 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102089 ON public.index_test_hash_102089 USING btree (a) INCLUDE (b, c)
multi_index_statements | index_test_hash_102082 | index_test_hash_index_a_b_c_102082 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102082 ON multi_index_statements.index_test_hash_102082 USING btree (a) INCLUDE (b, c)
multi_index_statements | index_test_hash_102083 | index_test_hash_index_a_b_c_102083 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102083 ON multi_index_statements.index_test_hash_102083 USING btree (a) INCLUDE (b, c)
multi_index_statements | index_test_hash_102084 | index_test_hash_index_a_b_c_102084 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102084 ON multi_index_statements.index_test_hash_102084 USING btree (a) INCLUDE (b, c)
multi_index_statements | index_test_hash_102085 | index_test_hash_index_a_b_c_102085 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102085 ON multi_index_statements.index_test_hash_102085 USING btree (a) INCLUDE (b, c)
multi_index_statements | index_test_hash_102086 | index_test_hash_index_a_b_c_102086 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102086 ON multi_index_statements.index_test_hash_102086 USING btree (a) INCLUDE (b, c)
multi_index_statements | index_test_hash_102087 | index_test_hash_index_a_b_c_102087 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102087 ON multi_index_statements.index_test_hash_102087 USING btree (a) INCLUDE (b, c)
multi_index_statements | index_test_hash_102088 | index_test_hash_index_a_b_c_102088 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102088 ON multi_index_statements.index_test_hash_102088 USING btree (a) INCLUDE (b, c)
multi_index_statements | index_test_hash_102089 | index_test_hash_index_a_b_c_102089 | | CREATE UNIQUE INDEX index_test_hash_index_a_b_c_102089 ON multi_index_statements.index_test_hash_102089 USING btree (a) INCLUDE (b, c)
(8 rows)
-- create index that will conflict with master operations
CREATE INDEX CONCURRENTLY ith_b_idx_102089 ON index_test_hash_102089(b);
CREATE INDEX CONCURRENTLY ith_b_idx_102089 ON multi_index_statements.index_test_hash_102089(b);
\c - - - :master_port
SET search_path TO multi_index_statements;
-- should fail because worker index already exists
CREATE INDEX CONCURRENTLY ith_b_idx ON index_test_hash(b);
ERROR: CONCURRENTLY-enabled index command failed
@ -292,13 +296,107 @@ SELECT indisvalid AS "Index Valid?" FROM pg_index WHERE indexrelid='ith_b_idx'::
(1 row)
\c - - - :worker_1_port
SET search_path TO multi_index_statements;
-- now drop shard index to test partial master DROP failure
DROP INDEX CONCURRENTLY ith_b_idx_102089;
\c - - - :master_port
SET search_path TO multi_index_statements;
SET citus.next_shard_id TO 103080;
SET citus.shard_count TO 32;
SET citus.shard_replication_factor TO 1;
-- the following tests are intended to show that
-- Citus does not get into self-deadlocks because
-- of long index names. So, make sure that we have
-- enough remote connections to trigger the case
SET citus.force_max_query_parallelization TO ON;
CREATE TABLE test_index_creation1
(
tenant_id integer NOT NULL,
timeperiod timestamp without time zone NOT NULL,
field1 integer NOT NULL,
inserted_utc timestamp without time zone NOT NULL DEFAULT now(),
PRIMARY KEY(tenant_id, timeperiod)
) PARTITION BY RANGE (timeperiod);
select create_distributed_table('test_index_creation1', 'tenant_id');
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- should be able to create short named indexes in parallel
-- as there are no partitions even if the index name is too long
SET client_min_messages TO DEBUG1;
CREATE INDEX ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1
ON test_index_creation1 USING btree
(tenant_id, timeperiod);
NOTICE: identifier "ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1" will be truncated to "ix_test_index_creation1_ix_test_index_creation1_ix_test_index_c"
RESET client_min_messages;
CREATE TABLE test_index_creation1_p2020_09_26 PARTITION OF test_index_creation1 FOR VALUES FROM ('2020-09-26 00:00:00') TO ('2020-09-27 00:00:00');
CREATE TABLE test_index_creation1_p2020_09_27 PARTITION OF test_index_creation1 FOR VALUES FROM ('2020-09-27 00:00:00') TO ('2020-09-28 00:00:00');
-- should switch to sequential execution as the index name on the partition is
-- longer than 63
SET client_min_messages TO DEBUG1;
CREATE INDEX ix_test_index_creation2
ON test_index_creation1 USING btree
(tenant_id, timeperiod);
DEBUG: the index name on the shards of the partition is too long, switching to sequential execution mode to prevent self deadlocks: test_index_creation1_p2020_09_26_10311_tenant_id_timeperiod_idx
-- same test with schema qualified
SET search_path TO public;
CREATE INDEX ix_test_index_creation3
ON multi_index_statements.test_index_creation1 USING btree
(tenant_id, timeperiod);
DEBUG: the index name on the shards of the partition is too long, switching to sequential execution mode to prevent self deadlocks: test_index_creation1_p2020_09_26_10311_tenant_id_timeperiod_idx
SET search_path TO multi_index_statements;
-- we cannot switch to sequential execution
-- after a parallel query
BEGIN;
SELECT count(*) FROM test_index_creation1;
count
---------------------------------------------------------------------
0
(1 row)
CREATE INDEX ix_test_index_creation4
ON test_index_creation1 USING btree
(tenant_id, timeperiod);
ERROR: The index name (test_index_creation1_p2020_09_26_10311_tenant_id_timeperiod_idx) on a shard is too long and could lead to deadlocks when executed in a transaction block after a parallel query
HINT: Try re-running the transaction with "SET LOCAL citus.multi_shard_modify_mode TO 'sequential';"
ROLLBACK;
-- try inside a sequential block
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
SELECT count(*) FROM test_index_creation1;
count
---------------------------------------------------------------------
0
(1 row)
CREATE INDEX ix_test_index_creation4
ON test_index_creation1 USING btree
(tenant_id, timeperiod);
DEBUG: the index name on the shards of the partition is too long, switching to sequential execution mode to prevent self deadlocks: test_index_creation1_p2020_09_26_10311_tenant_id_timeperiod_idx
ROLLBACK;
-- should be able to create indexes with INCLUDE/WHERE
CREATE INDEX ix_test_index_creation5 ON test_index_creation1
USING btree(tenant_id, timeperiod)
INCLUDE (field1) WHERE (tenant_id = 100);
DEBUG: the index name on the shards of the partition is too long, switching to sequential execution mode to prevent self deadlocks: test_index_creation1_p2020_09_2_tenant_id_timeperiod_field1_idx
CREATE UNIQUE INDEX ix_test_index_creation6 ON test_index_creation1
USING btree(tenant_id, timeperiod);
DEBUG: the index name on the shards of the partition is too long, switching to sequential execution mode to prevent self deadlocks: test_index_creation1_p2020_09_26_10311_tenant_id_timeperiod_idx
-- should be able to create short named indexes in parallel
-- as the table/index name is short
CREATE INDEX f1
ON test_index_creation1 USING btree
(field1);
SET citus.force_max_query_parallelization TO OFF;
SET client_min_messages TO ERROR;
\set VERBOSITY terse
DROP INDEX f1;
DROP INDEX ix_test_index_creation2;
DROP INDEX ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1;
DROP INDEX CONCURRENTLY ith_b_idx;
ERROR: CONCURRENTLY-enabled index command failed
DETAIL: CONCURRENTLY-enabled index commands can fail partially, leaving behind an INVALID index.
HINT: Use DROP INDEX CONCURRENTLY IF EXISTS to remove the invalid index, then retry the original command.
-- the failure results in an INVALID index
SELECT indisvalid AS "Index Valid?" FROM pg_index WHERE indexrelid='ith_b_idx'::regclass;
Index Valid?
@ -308,7 +406,4 @@ SELECT indisvalid AS "Index Valid?" FROM pg_index WHERE indexrelid='ith_b_idx'::
-- final clean up
DROP INDEX CONCURRENTLY IF EXISTS ith_b_idx;
-- Drop created tables
DROP TABLE index_test_range;
DROP TABLE index_test_hash;
DROP TABLE index_test_append;
DROP SCHEMA multi_index_statements CASCADE;

View File

@ -9,6 +9,9 @@
-- CREATE TEST TABLES
--
CREATE SCHEMA multi_index_statements;
SET search_path TO multi_index_statements;
SET citus.next_shard_id TO 102080;
CREATE TABLE index_test_range(a int, b int, c int);
@ -32,17 +35,17 @@ SELECT master_create_empty_shard('index_test_append');
-- Verify that we can create different types of indexes
CREATE INDEX lineitem_orderkey_index ON lineitem (l_orderkey);
CREATE INDEX lineitem_orderkey_index ON public.lineitem (l_orderkey);
CREATE INDEX lineitem_partkey_desc_index ON lineitem (l_partkey DESC);
CREATE INDEX lineitem_partkey_desc_index ON public.lineitem (l_partkey DESC);
CREATE INDEX lineitem_partial_index ON lineitem (l_shipdate)
CREATE INDEX lineitem_partial_index ON public.lineitem (l_shipdate)
WHERE l_shipdate < '1995-01-01';
CREATE INDEX lineitem_colref_index ON lineitem (record_ne(lineitem.*, NULL));
CREATE INDEX lineitem_colref_index ON public.lineitem (record_ne(lineitem.*, NULL));
SET client_min_messages = ERROR; -- avoid version dependant warning about WAL
CREATE INDEX lineitem_orderkey_hash_index ON lineitem USING hash (l_partkey);
CREATE INDEX lineitem_orderkey_hash_index ON public.lineitem USING hash (l_partkey);
CREATE UNIQUE INDEX index_test_range_index_a ON index_test_range(a);
CREATE UNIQUE INDEX index_test_range_index_a_b ON index_test_range(a,b);
CREATE UNIQUE INDEX index_test_hash_index_a ON index_test_hash(a);
@ -53,16 +56,16 @@ CREATE UNIQUE INDEX index_test_hash_index_a_b_c ON index_test_hash(a) INCLUDE (b
RESET client_min_messages;
-- Verify that we handle if not exists statements correctly
CREATE INDEX lineitem_orderkey_index on lineitem(l_orderkey);
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on lineitem(l_orderkey);
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index_new on lineitem(l_orderkey);
CREATE INDEX lineitem_orderkey_index on public.lineitem(l_orderkey);
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on public.lineitem(l_orderkey);
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index_new on public.lineitem(l_orderkey);
-- Verify if not exists behavior with an index with same name on a different table
CREATE INDEX lineitem_orderkey_index on index_test_hash(a);
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on index_test_hash(a);
CREATE INDEX lineitem_orderkey_index on public.nation(n_nationkey);
CREATE INDEX IF NOT EXISTS lineitem_orderkey_index on public.nation(n_nationkey);
-- Verify that we can create indexes concurrently
CREATE INDEX CONCURRENTLY lineitem_concurrently_index ON lineitem (l_orderkey);
CREATE INDEX CONCURRENTLY lineitem_concurrently_index ON public.lineitem (l_orderkey);
-- Verify that no-name local CREATE INDEX CONCURRENTLY works
CREATE TABLE local_table (id integer, name text);
@ -86,10 +89,11 @@ SELECT count(*) FROM pg_indexes WHERE tablename LIKE 'index_test_hash%';
SELECT count(*) FROM pg_indexes WHERE tablename LIKE 'index_test_range%';
SELECT count(*) FROM pg_indexes WHERE tablename LIKE 'index_test_append%';
\c - - - :master_port
SET search_path TO multi_index_statements, public;
-- Verify that we error out on unsupported statement types
CREATE UNIQUE INDEX try_index ON lineitem (l_orderkey);
CREATE UNIQUE INDEX try_index ON public.lineitem (l_orderkey);
CREATE INDEX try_index ON lineitem (l_orderkey) TABLESPACE newtablespace;
CREATE UNIQUE INDEX try_unique_range_index ON index_test_range(b);
@ -162,9 +166,10 @@ SELECT indrelid::regclass, indexrelid::regclass FROM pg_index WHERE indrelid = (
SELECT * FROM pg_indexes WHERE tablename LIKE 'index_test_%' ORDER BY indexname;
-- create index that will conflict with master operations
CREATE INDEX CONCURRENTLY ith_b_idx_102089 ON index_test_hash_102089(b);
CREATE INDEX CONCURRENTLY ith_b_idx_102089 ON multi_index_statements.index_test_hash_102089(b);
\c - - - :master_port
SET search_path TO multi_index_statements;
-- should fail because worker index already exists
CREATE INDEX CONCURRENTLY ith_b_idx ON index_test_hash(b);
@ -178,11 +183,100 @@ CREATE INDEX CONCURRENTLY ith_b_idx ON index_test_hash(b);
SELECT indisvalid AS "Index Valid?" FROM pg_index WHERE indexrelid='ith_b_idx'::regclass;
\c - - - :worker_1_port
SET search_path TO multi_index_statements;
-- now drop shard index to test partial master DROP failure
DROP INDEX CONCURRENTLY ith_b_idx_102089;
\c - - - :master_port
SET search_path TO multi_index_statements;
SET citus.next_shard_id TO 103080;
SET citus.shard_count TO 32;
SET citus.shard_replication_factor TO 1;
-- the following tests are intended to show that
-- Citus does not get into self-deadlocks because
-- of long index names. So, make sure that we have
-- enough remote connections to trigger the case
SET citus.force_max_query_parallelization TO ON;
CREATE TABLE test_index_creation1
(
tenant_id integer NOT NULL,
timeperiod timestamp without time zone NOT NULL,
field1 integer NOT NULL,
inserted_utc timestamp without time zone NOT NULL DEFAULT now(),
PRIMARY KEY(tenant_id, timeperiod)
) PARTITION BY RANGE (timeperiod);
select create_distributed_table('test_index_creation1', 'tenant_id');
-- should be able to create short named indexes in parallel
-- as there are no partitions even if the index name is too long
SET client_min_messages TO DEBUG1;
CREATE INDEX ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1
ON test_index_creation1 USING btree
(tenant_id, timeperiod);
RESET client_min_messages;
CREATE TABLE test_index_creation1_p2020_09_26 PARTITION OF test_index_creation1 FOR VALUES FROM ('2020-09-26 00:00:00') TO ('2020-09-27 00:00:00');
CREATE TABLE test_index_creation1_p2020_09_27 PARTITION OF test_index_creation1 FOR VALUES FROM ('2020-09-27 00:00:00') TO ('2020-09-28 00:00:00');
-- should switch to sequential execution as the index name on the partition is
-- longer than 63
SET client_min_messages TO DEBUG1;
CREATE INDEX ix_test_index_creation2
ON test_index_creation1 USING btree
(tenant_id, timeperiod);
-- same test with schema qualified
SET search_path TO public;
CREATE INDEX ix_test_index_creation3
ON multi_index_statements.test_index_creation1 USING btree
(tenant_id, timeperiod);
SET search_path TO multi_index_statements;
-- we cannot switch to sequential execution
-- after a parallel query
BEGIN;
SELECT count(*) FROM test_index_creation1;
CREATE INDEX ix_test_index_creation4
ON test_index_creation1 USING btree
(tenant_id, timeperiod);
ROLLBACK;
-- try inside a sequential block
BEGIN;
SET LOCAL citus.multi_shard_modify_mode TO 'sequential';
SELECT count(*) FROM test_index_creation1;
CREATE INDEX ix_test_index_creation4
ON test_index_creation1 USING btree
(tenant_id, timeperiod);
ROLLBACK;
-- should be able to create indexes with INCLUDE/WHERE
CREATE INDEX ix_test_index_creation5 ON test_index_creation1
USING btree(tenant_id, timeperiod)
INCLUDE (field1) WHERE (tenant_id = 100);
CREATE UNIQUE INDEX ix_test_index_creation6 ON test_index_creation1
USING btree(tenant_id, timeperiod);
-- should be able to create short named indexes in parallel
-- as the table/index name is short
CREATE INDEX f1
ON test_index_creation1 USING btree
(field1);
SET citus.force_max_query_parallelization TO OFF;
SET client_min_messages TO ERROR;
\set VERBOSITY terse
DROP INDEX f1;
DROP INDEX ix_test_index_creation2;
DROP INDEX ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1_ix_test_index_creation1;
DROP INDEX CONCURRENTLY ith_b_idx;
-- the failure results in an INVALID index
@ -191,7 +285,4 @@ SELECT indisvalid AS "Index Valid?" FROM pg_index WHERE indexrelid='ith_b_idx'::
-- final clean up
DROP INDEX CONCURRENTLY IF EXISTS ith_b_idx;
-- Drop created tables
DROP TABLE index_test_range;
DROP TABLE index_test_hash;
DROP TABLE index_test_append;
DROP SCHEMA multi_index_statements CASCADE;