Merge pull request #783 from robin900/new-extend-names

Provides safe, backwards-compatible shard-extended names to any object name
pull/821/head
Marco Slot 2016-10-03 23:17:44 +02:00 committed by GitHub
commit 6c0fc0c970
10 changed files with 685 additions and 27 deletions

View File

@ -8,7 +8,7 @@ EXTENSION = citus
EXTVERSIONS = 5.0 5.0-1 5.0-2 \
5.1-1 5.1-2 5.1-3 5.1-4 5.1-5 5.1-6 5.1-7 5.1-8 \
5.2-1 5.2-2 5.2-3 5.2-4 \
6.0-1
6.0-1 6.0-2
# All citus--*.sql files in the source directory
DATA = $(patsubst $(citus_abs_srcdir)/%.sql,%.sql,$(wildcard $(citus_abs_srcdir)/$(EXTENSION)--*--*.sql))
@ -60,6 +60,8 @@ $(EXTENSION)--5.2-4.sql: $(EXTENSION)--5.2-3.sql $(EXTENSION)--5.2-3--5.2-4.sql
cat $^ > $@
$(EXTENSION)--6.0-1.sql: $(EXTENSION)--5.2-4.sql $(EXTENSION)--5.2-4--6.0-1.sql
cat $^ > $@
$(EXTENSION)--6.0-2.sql: $(EXTENSION)--6.0-1.sql $(EXTENSION)--6.0-1--6.0-2.sql
cat $^ > $@
NO_PGXS = 1

View File

@ -0,0 +1,9 @@
/* citus--6.0-1--6.0-2.sql */
CREATE FUNCTION pg_catalog.shard_name(object_name regclass, shard_id bigint)
RETURNS text
LANGUAGE C STABLE
AS 'MODULE_PATHNAME', $$shard_name$$;
COMMENT ON FUNCTION pg_catalog.shard_name(object_name regclass, shard_id bigint)
IS 'returns shard-extended version of object name';

View File

@ -1,6 +1,6 @@
# Citus extension
comment = 'Citus distributed database'
default_version = '6.0-1'
default_version = '6.0-2'
module_pathname = '$libdir/citus'
relocatable = false
schema = pg_catalog

View File

@ -317,14 +317,13 @@ DropShards(Oid relationId, char *schemaName, char *relationName,
ShardInterval *shardInterval = (ShardInterval *) lfirst(shardIntervalCell);
uint64 shardId = shardInterval->shardId;
char *quotedShardName = NULL;
StringInfo shardName = makeStringInfo();
char *shardRelationName = pnstrdup(relationName, NAMEDATALEN);
Assert(shardInterval->relationId == relationId);
/* Build shard relation name. */
appendStringInfoString(shardName, relationName);
AppendShardIdToStringInfo(shardName, shardId);
quotedShardName = quote_qualified_identifier(schemaName, shardName->data);
AppendShardIdToName(&shardRelationName, shardId);
quotedShardName = quote_qualified_identifier(schemaName, shardRelationName);
shardPlacementList = ShardPlacementList(shardId);
foreach(shardPlacementCell, shardPlacementList)
@ -386,7 +385,7 @@ DropShards(Oid relationId, char *schemaName, char *relationName,
workerName, workerPort);
ereport(WARNING, (errmsg("could not delete shard \"%s\" on node \"%s:%u\"",
shardName->data, workerName, workerPort),
shardRelationName, workerName, workerPort),
errdetail("Marking this shard placement for deletion")));
}

View File

@ -144,7 +144,6 @@ DropShardsFromWorker(WorkerNode *workerNode, Oid relationId, List *shardInterval
char *schemaName = get_namespace_name(schemaId);
char *relationName = get_rel_name(relationId);
char relationKind = get_rel_relkind(relationId);
StringInfo shardName = makeStringInfo();
StringInfo workerCommand = makeStringInfo();
ListCell *shardIntervalCell = NULL;
@ -170,12 +169,11 @@ DropShardsFromWorker(WorkerNode *workerNode, Oid relationId, List *shardInterval
foreach(shardIntervalCell, shardIntervalList)
{
ShardInterval *shardInterval = (ShardInterval *) lfirst(shardIntervalCell);
char *shardName = pnstrdup(relationName, NAMEDATALEN);
char *quotedShardName = NULL;
resetStringInfo(shardName);
appendStringInfo(shardName, "%s", relationName);
AppendShardIdToStringInfo(shardName, shardInterval->shardId);
quotedShardName = quote_qualified_identifier(schemaName, shardName->data);
AppendShardIdToName(&shardName, shardInterval->shardId);
quotedShardName = quote_qualified_identifier(schemaName, shardName);
appendStringInfo(workerCommand, "%s", quotedShardName);
/* append a comma after the shard name if there are more shards */

View File

@ -21,6 +21,7 @@
#include "access/genam.h"
#include "access/heapam.h"
#include "access/htup_details.h"
#include "access/hash.h"
#include "access/htup.h"
#include "access/skey.h"
#include "access/stratnum.h"
@ -29,6 +30,7 @@
#include "catalog/pg_constraint.h"
#include "distributed/relay_utility.h"
#include "lib/stringinfo.h"
#include "mb/pg_wchar.h"
#include "nodes/nodes.h"
#include "nodes/nodeFuncs.h"
#include "nodes/parsenodes.h"
@ -36,9 +38,11 @@
#include "nodes/primnodes.h"
#include "nodes/value.h"
#include "storage/lock.h"
#include "utils/builtins.h"
#include "utils/elog.h"
#include "utils/errcodes.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/palloc.h"
#include "utils/relcache.h"
@ -50,6 +54,9 @@ static void AppendShardIdToConstraintName(AlterTableCmd *command, uint64 shardId
static void SetSchemaNameIfNotExist(char **schemaName, char *newSchemaName);
static bool UpdateWholeRowColumnReferencesWalker(Node *node, uint64 *shardId);
/* exports for SQL callable functions */
PG_FUNCTION_INFO_V1(shard_name);
/*
* RelayEventExtendNames extends relation names in the given parse tree for
* certain utility commands. The function more specifically extends table and
@ -624,32 +631,120 @@ AppendShardIdToName(char **name, uint64 shardId)
{
char extendedName[NAMEDATALEN];
uint32 extendedNameLength = 0;
int nameLength = strlen(*name);
char shardIdAndSeparator[NAMEDATALEN];
int shardIdAndSeparatorLength;
uint32 longNameHash = 0;
int multiByteClipLength = 0;
snprintf(extendedName, NAMEDATALEN, "%s%c" UINT64_FORMAT,
(*name), SHARD_NAME_SEPARATOR, shardId);
snprintf(shardIdAndSeparator, NAMEDATALEN, "%c" UINT64_FORMAT,
SHARD_NAME_SEPARATOR, shardId);
shardIdAndSeparatorLength = strlen(shardIdAndSeparator);
/*
* Parser should have already checked that the table name has enough space
* reserved for appending shardIds. Nonetheless, we perform an additional
* check here to verify that the appended name does not overflow.
* If *name strlen is < (NAMEDATALEN - shardIdAndSeparatorLength),
* it is safe merely to append the separator and shardId.
*/
extendedNameLength = strlen(extendedName) + 1;
if (extendedNameLength >= NAMEDATALEN)
if (nameLength < (NAMEDATALEN - shardIdAndSeparatorLength))
{
ereport(ERROR, (errmsg("shard name too long to extend: \"%s\"", (*name))));
snprintf(extendedName, NAMEDATALEN, "%s%s", (*name), shardIdAndSeparator);
}
/*
* Otherwise, we need to truncate the name further to accommodate
* a sufficient hash value. The resulting name will avoid collision
* with other hashed names such that for any given schema with
* 90 distinct object names that are long enough to require hashing
* (typically 57-63 characters), the chance of a collision existing is:
*
* If randomly generated UTF8 names:
* (1e-6) * (9.39323783788e-114) ~= (9.39e-120)
* If random case-insensitive ASCII names (letter first, 37 useful characters):
* (1e-6) * (2.80380202421e-74) ~= (2.8e-80)
* If names sharing only N distinct 45- to 47-character prefixes:
* (1e-6) * (1/N) = (1e-6/N)
* 1e-7 for 10 distinct prefixes
* 5e-8 for 20 distinct prefixes
*
* In practice, since shard IDs are globally unique, the risk of name collision
* exists only amongst objects that pertain to a single distributed table
* and are created for each shard: the table name and the names of any indexes
* or index-backed constraints. Since there are typically less than five such
* names, and almost never more than ten, the expected collision rate even in
* the worst case (ten names share same 45- to 47-character prefix) is roughly
* 1e-8: one in 100 million schemas will experience a name collision only if ALL
* 100 million schemas present the worst-case scenario.
*/
else
{
longNameHash = hash_any((unsigned char *) (*name), nameLength);
multiByteClipLength = pg_mbcliplen(*name, nameLength, (NAMEDATALEN -
shardIdAndSeparatorLength -
10));
snprintf(extendedName, NAMEDATALEN, "%.*s%c%.8x%s",
multiByteClipLength, (*name),
SHARD_NAME_SEPARATOR, longNameHash,
shardIdAndSeparator);
}
extendedNameLength = strlen(extendedName) + 1;
Assert(extendedNameLength <= NAMEDATALEN);
(*name) = (char *) repalloc((*name), extendedNameLength);
snprintf((*name), extendedNameLength, "%s", extendedName);
}
/*
* AppendShardIdToStringInfo appends shardId to the given name, represented
* by a StringInfo.
* shard_name() provides a PG function interface to AppendShardNameToId above.
*/
void
AppendShardIdToStringInfo(StringInfo name, uint64 shardId)
Datum
shard_name(PG_FUNCTION_ARGS)
{
appendStringInfo(name, "%c" UINT64_FORMAT, SHARD_NAME_SEPARATOR, shardId);
Oid relationId = InvalidOid;
int64 shardId = 0;
char *relationName = NULL;
/*
* Have to check arguments for NULLness as it can't be declared STRICT
* because of min/max arguments, which have to be NULLable for new shards.
*/
if (PG_ARGISNULL(0))
{
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("object_name cannot be null")));
}
if (PG_ARGISNULL(1))
{
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("shard_id cannot be null")));
}
relationId = PG_GETARG_OID(0);
shardId = PG_GETARG_INT64(1);
if (shardId <= 0)
{
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("shard_id cannot be zero or negative value")));
}
if (!OidIsValid(relationId))
{
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("object_name does not reference a valid relation")));
}
relationName = get_rel_name(relationId);
if (relationName == NULL)
{
ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("object_name does not reference a valid relation")));
}
AppendShardIdToName(&relationName, shardId);
PG_RETURN_TEXT_P(cstring_to_text(relationName));
}

View File

@ -15,6 +15,7 @@
#ifndef RELAY_UTILITY_H
#define RELAY_UTILITY_H
#include "fmgr.h"
#include "lib/stringinfo.h"
#include "nodes/nodes.h"
@ -41,7 +42,5 @@ typedef enum
/* Function declarations to extend names in DDL commands */
extern void RelayEventExtendNames(Node *parseTree, char *schemaName, uint64 shardId);
extern void AppendShardIdToName(char **name, uint64 shardId);
extern void AppendShardIdToStringInfo(StringInfo name, uint64 shardId);
#endif /* RELAY_UTILITY_H */

View File

@ -0,0 +1,398 @@
--
-- MULTI_NAME_LENGTHS
--
ALTER SEQUENCE pg_catalog.pg_dist_shardid_seq RESTART 225000;
ALTER SEQUENCE pg_catalog.pg_dist_jobid_seq RESTART 225000;
SET citus.multi_shard_commit_protocol = '2pc';
-- Verify that a table name > 56 characters gets hashed properly.
CREATE TABLE too_long_12345678901234567890123456789012345678901234567890 (
col1 integer not null,
col2 integer not null);
SELECT master_create_distributed_table('too_long_12345678901234567890123456789012345678901234567890', 'col1', 'hash');
master_create_distributed_table
---------------------------------
(1 row)
SELECT master_create_worker_shards('too_long_12345678901234567890123456789012345678901234567890', '2', '2');
master_create_worker_shards
-----------------------------
(1 row)
\c - - - :worker_1_port
\d too_long_*
Table "public.too_long_12345678901234567890123456789012345678_e0119164_225000"
Column | Type | Modifiers
--------+---------+-----------
col1 | integer | not null
col2 | integer | not null
Table "public.too_long_12345678901234567890123456789012345678_e0119164_225001"
Column | Type | Modifiers
--------+---------+-----------
col1 | integer | not null
col2 | integer | not null
\c - - - :master_port
-- Verify that the UDF works and rejects bad arguments.
SELECT shard_name(NULL, 666666);
ERROR: object_name cannot be null
SELECT shard_name(0, 666666);
ERROR: object_name does not reference a valid relation
SELECT shard_name('too_long_12345678901234567890123456789012345678901234567890'::regclass, 666666);
shard_name
-----------------------------------------------------------------
too_long_12345678901234567890123456789012345678_e0119164_666666
(1 row)
SELECT shard_name('too_long_12345678901234567890123456789012345678901234567890'::regclass, NULL);
ERROR: shard_id cannot be null
SELECT shard_name('too_long_12345678901234567890123456789012345678901234567890'::regclass, -21);
ERROR: shard_id cannot be zero or negative value
DROP TABLE too_long_12345678901234567890123456789012345678901234567890 CASCADE;
-- Table to use for rename checks.
CREATE TABLE name_lengths (
col1 integer not null,
col2 integer not null,
constraint constraint_a UNIQUE (col1)
);
SELECT master_create_distributed_table('name_lengths', 'col1', 'hash');
master_create_distributed_table
---------------------------------
(1 row)
SELECT master_create_worker_shards('name_lengths', '2', '2');
master_create_worker_shards
-----------------------------
(1 row)
-- Verify that we CAN add columns with "too-long names", because
-- the columns' names are not extended in the corresponding shard tables.
ALTER TABLE name_lengths ADD COLUMN float_col_12345678901234567890123456789012345678901234567890 FLOAT;
NOTICE: using one-phase commit for distributed DDL commands
HINT: You can enable two-phase commit for extra safety with: SET citus.multi_shard_commit_protocol TO '2pc'
ALTER TABLE name_lengths ADD COLUMN date_col_12345678901234567890123456789012345678901234567890 DATE;
ALTER TABLE name_lengths ADD COLUMN int_col_12345678901234567890123456789012345678901234567890 INTEGER DEFAULT 1;
-- Placeholders for unsupported ALTER TABLE to add constraints with implicit names that are likely too long
ALTER TABLE name_lengths ADD UNIQUE (float_col_12345678901234567890123456789012345678901234567890);
ERROR: alter table command is currently supported
DETAIL: Only ADD|DROP COLUMN, SET|DROP NOT NULL, SET|DROP DEFAULT and TYPE subcommands are supported.
ALTER TABLE name_lengths ADD EXCLUDE (int_col_12345678901234567890123456789012345678901234567890 WITH =);
ERROR: alter table command is currently supported
DETAIL: Only ADD|DROP COLUMN, SET|DROP NOT NULL, SET|DROP DEFAULT and TYPE subcommands are supported.
ALTER TABLE name_lengths ADD CHECK (date_col_12345678901234567890123456789012345678901234567890 > '2014-01-01'::date);
ERROR: alter table command is currently supported
DETAIL: Only ADD|DROP COLUMN, SET|DROP NOT NULL, SET|DROP DEFAULT and TYPE subcommands are supported.
\c - - - :worker_1_port
\d name_lengths_*
Table "public.name_lengths_225002"
Column | Type | Modifiers
--------------------------------------------------------------+------------------+-----------
col1 | integer | not null
col2 | integer | not null
float_col_12345678901234567890123456789012345678901234567890 | double precision |
date_col_12345678901234567890123456789012345678901234567890 | date |
int_col_12345678901234567890123456789012345678901234567890 | integer | default 1
Indexes:
"constraint_a_225002" UNIQUE CONSTRAINT, btree (col1)
Table "public.name_lengths_225003"
Column | Type | Modifiers
--------------------------------------------------------------+------------------+-----------
col1 | integer | not null
col2 | integer | not null
float_col_12345678901234567890123456789012345678901234567890 | double precision |
date_col_12345678901234567890123456789012345678901234567890 | date |
int_col_12345678901234567890123456789012345678901234567890 | integer | default 1
Indexes:
"constraint_a_225003" UNIQUE CONSTRAINT, btree (col1)
\c - - - :master_port
-- Placeholders for unsupported add constraints with EXPLICIT names that are too long
ALTER TABLE name_lengths ADD CONSTRAINT nl_unique_12345678901234567890123456789012345678901234567890 UNIQUE (float_col_12345678901234567890123456789012345678901234567890);
ERROR: alter table command is currently supported
DETAIL: Only ADD|DROP COLUMN, SET|DROP NOT NULL, SET|DROP DEFAULT and TYPE subcommands are supported.
ALTER TABLE name_lengths ADD CONSTRAINT nl_exclude_12345678901234567890123456789012345678901234567890 EXCLUDE (int_col_12345678901234567890123456789012345678901234567890 WITH =);
ERROR: alter table command is currently supported
DETAIL: Only ADD|DROP COLUMN, SET|DROP NOT NULL, SET|DROP DEFAULT and TYPE subcommands are supported.
ALTER TABLE name_lengths ADD CONSTRAINT nl_checky_12345678901234567890123456789012345678901234567890 CHECK (date_col_12345678901234567890123456789012345678901234567890 >= '2014-01-01'::date);
ERROR: alter table command is currently supported
DETAIL: Only ADD|DROP COLUMN, SET|DROP NOT NULL, SET|DROP DEFAULT and TYPE subcommands are supported.
\c - - - :worker_1_port
\d nl_*
\c - - - :master_port
-- Placeholders for RENAME operations
ALTER TABLE name_lengths RENAME TO name_len_12345678901234567890123456789012345678901234567890;
ERROR: renaming distributed tables or their objects is currently unsupported
ALTER TABLE name_lengths RENAME CONSTRAINT unique_12345678901234567890123456789012345678901234567890 TO unique2_12345678901234567890123456789012345678901234567890;
ERROR: renaming distributed tables or their objects is currently unsupported
-- Verify that CREATE INDEX on already distributed table has proper shard names.
CREATE INDEX tmp_idx_12345678901234567890123456789012345678901234567890 ON name_lengths(col2);
NOTICE: using one-phase commit for distributed DDL commands
HINT: You can enable two-phase commit for extra safety with: SET citus.multi_shard_commit_protocol TO '2pc'
\c - - - :worker_1_port
\d tmp_idx_*
Index "public.tmp_idx_123456789012345678901234567890123456789_5e470afa_225002"
Column | Type | Definition
--------+---------+------------
col2 | integer | col2
btree, for table "public.name_lengths_225002"
Index "public.tmp_idx_123456789012345678901234567890123456789_5e470afa_225003"
Column | Type | Definition
--------+---------+------------
col2 | integer | col2
btree, for table "public.name_lengths_225003"
\c - - - :master_port
-- Verify that a new index name > 63 characters is auto-truncated
-- by the parser/rewriter before further processing, just as in Postgres.
CREATE INDEX tmp_idx_123456789012345678901234567890123456789012345678901234567890 ON name_lengths(col2);
NOTICE: identifier "tmp_idx_123456789012345678901234567890123456789012345678901234567890" will be truncated to "tmp_idx_1234567890123456789012345678901234567890123456789012345"
NOTICE: using one-phase commit for distributed DDL commands
HINT: You can enable two-phase commit for extra safety with: SET citus.multi_shard_commit_protocol TO '2pc'
\c - - - :worker_1_port
\d tmp_idx_*
Index "public.tmp_idx_123456789012345678901234567890123456789_599636aa_225002"
Column | Type | Definition
--------+---------+------------
col2 | integer | col2
btree, for table "public.name_lengths_225002"
Index "public.tmp_idx_123456789012345678901234567890123456789_599636aa_225003"
Column | Type | Definition
--------+---------+------------
col2 | integer | col2
btree, for table "public.name_lengths_225003"
Index "public.tmp_idx_123456789012345678901234567890123456789_5e470afa_225002"
Column | Type | Definition
--------+---------+------------
col2 | integer | col2
btree, for table "public.name_lengths_225002"
Index "public.tmp_idx_123456789012345678901234567890123456789_5e470afa_225003"
Column | Type | Definition
--------+---------+------------
col2 | integer | col2
btree, for table "public.name_lengths_225003"
\c - - - :master_port
-- Verify that distributed tables with too-long names
-- for CHECK constraints are no trouble.
CREATE TABLE sneaky_name_lengths (
col1 integer not null,
col2 integer not null,
int_col_12345678901234567890123456789012345678901234567890 integer not null,
CHECK (int_col_12345678901234567890123456789012345678901234567890 > 100)
);
SELECT master_create_distributed_table('sneaky_name_lengths', 'col1', 'hash');
master_create_distributed_table
---------------------------------
(1 row)
SELECT master_create_worker_shards('sneaky_name_lengths', '2', '2');
master_create_worker_shards
-----------------------------
(1 row)
DROP TABLE sneaky_name_lengths CASCADE;
CREATE TABLE sneaky_name_lengths (
int_col_123456789012345678901234567890123456789012345678901234 integer UNIQUE not null,
col2 integer not null,
CONSTRAINT checky_12345678901234567890123456789012345678901234567890 CHECK (int_col_123456789012345678901234567890123456789012345678901234 > 100)
);
\d sneaky_name_lengths*
Table "public.sneaky_name_lengths"
Column | Type | Modifiers
----------------------------------------------------------------+---------+-----------
int_col_123456789012345678901234567890123456789012345678901234 | integer | not null
col2 | integer | not null
Indexes:
"sneaky_name_lengths_int_col_1234567890123456789012345678901_key" UNIQUE CONSTRAINT, btree (int_col_123456789012345678901234567890123456789012345678901234)
Check constraints:
"checky_12345678901234567890123456789012345678901234567890" CHECK (int_col_123456789012345678901234567890123456789012345678901234 > 100)
Index "public.sneaky_name_lengths_int_col_1234567890123456789012345678901_key"
Column | Type | Definition
----------------------------------------------------------------+---------+----------------------------------------------------------------
int_col_123456789012345678901234567890123456789012345678901234 | integer | int_col_123456789012345678901234567890123456789012345678901234
unique, btree, for table "public.sneaky_name_lengths"
SELECT master_create_distributed_table('sneaky_name_lengths', 'int_col_123456789012345678901234567890123456789012345678901234', 'hash');
master_create_distributed_table
---------------------------------
(1 row)
SELECT master_create_worker_shards('sneaky_name_lengths', '2', '2');
master_create_worker_shards
-----------------------------
(1 row)
\c - - - :worker_1_port
\d sneaky_name_lengths*
Table "public.sneaky_name_lengths_225006"
Column | Type | Modifiers
----------------------------------------------------------------+---------+-----------
int_col_123456789012345678901234567890123456789012345678901234 | integer | not null
col2 | integer | not null
Indexes:
"sneaky_name_lengths_int_col_1234567890123456789_6402d2cd_225006" UNIQUE CONSTRAINT, btree (int_col_123456789012345678901234567890123456789012345678901234)
Check constraints:
"checky_12345678901234567890123456789012345678901234567890" CHECK (int_col_123456789012345678901234567890123456789012345678901234 > 100)
Table "public.sneaky_name_lengths_225007"
Column | Type | Modifiers
----------------------------------------------------------------+---------+-----------
int_col_123456789012345678901234567890123456789012345678901234 | integer | not null
col2 | integer | not null
Indexes:
"sneaky_name_lengths_int_col_1234567890123456789_6402d2cd_225007" UNIQUE CONSTRAINT, btree (int_col_123456789012345678901234567890123456789012345678901234)
Check constraints:
"checky_12345678901234567890123456789012345678901234567890" CHECK (int_col_123456789012345678901234567890123456789012345678901234 > 100)
Index "public.sneaky_name_lengths_int_col_1234567890123456789_6402d2cd_225006"
Column | Type | Definition
----------------------------------------------------------------+---------+----------------------------------------------------------------
int_col_123456789012345678901234567890123456789012345678901234 | integer | int_col_123456789012345678901234567890123456789012345678901234
unique, btree, for table "public.sneaky_name_lengths_225006"
Index "public.sneaky_name_lengths_int_col_1234567890123456789_6402d2cd_225007"
Column | Type | Definition
----------------------------------------------------------------+---------+----------------------------------------------------------------
int_col_123456789012345678901234567890123456789012345678901234 | integer | int_col_123456789012345678901234567890123456789012345678901234
unique, btree, for table "public.sneaky_name_lengths_225007"
\c - - - :master_port
DROP TABLE sneaky_name_lengths CASCADE;
-- verify that named constraint with too-long name gets hashed properly
CREATE TABLE sneaky_name_lengths (
col1 integer not null,
col2 integer not null,
int_col_12345678901234567890123456789012345678901234567890 integer not null,
constraint unique_12345678901234567890123456789012345678901234567890 UNIQUE (col1)
);
SELECT master_create_distributed_table('sneaky_name_lengths', 'col1', 'hash');
master_create_distributed_table
---------------------------------
(1 row)
SELECT master_create_worker_shards('sneaky_name_lengths', '2', '2');
master_create_worker_shards
-----------------------------
(1 row)
\c - - - :worker_1_port
\d sneaky_name_lengths*
Table "public.sneaky_name_lengths_225008"
Column | Type | Modifiers
------------------------------------------------------------+---------+-----------
col1 | integer | not null
col2 | integer | not null
int_col_12345678901234567890123456789012345678901234567890 | integer | not null
Indexes:
"unique_1234567890123456789012345678901234567890_a5986f27_225008" UNIQUE CONSTRAINT, btree (col1)
Table "public.sneaky_name_lengths_225009"
Column | Type | Modifiers
------------------------------------------------------------+---------+-----------
col1 | integer | not null
col2 | integer | not null
int_col_12345678901234567890123456789012345678901234567890 | integer | not null
Indexes:
"unique_1234567890123456789012345678901234567890_a5986f27_225009" UNIQUE CONSTRAINT, btree (col1)
\c - - - :master_port
DROP TABLE sneaky_name_lengths CASCADE;
-- Verify that much larger shardIds are handled properly
ALTER SEQUENCE pg_catalog.pg_dist_shardid_seq RESTART 2250000000000;
CREATE TABLE too_long_12345678901234567890123456789012345678901234567890 (
col1 integer not null,
col2 integer not null);
SELECT master_create_distributed_table('too_long_12345678901234567890123456789012345678901234567890', 'col1', 'hash');
master_create_distributed_table
---------------------------------
(1 row)
SELECT master_create_worker_shards('too_long_12345678901234567890123456789012345678901234567890', '2', '2');
master_create_worker_shards
-----------------------------
(1 row)
\c - - - :worker_1_port
\d too_long_*
Table "public.too_long_1234567890123456789012345678901_e0119164_2250000000000"
Column | Type | Modifiers
--------+---------+-----------
col1 | integer | not null
col2 | integer | not null
Table "public.too_long_1234567890123456789012345678901_e0119164_2250000000001"
Column | Type | Modifiers
--------+---------+-----------
col1 | integer | not null
col2 | integer | not null
\c - - - :master_port
DROP TABLE too_long_12345678901234567890123456789012345678901234567890 CASCADE;
-- Verify that multi-byte boundaries are respected for databases with UTF8 encoding.
CREATE TABLE U&"elephant_!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D" UESCAPE '!' (
col1 integer not null PRIMARY KEY,
col2 integer not null);
SELECT master_create_distributed_table(U&'elephant_!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D' UESCAPE '!', 'col1', 'hash');
master_create_distributed_table
---------------------------------
(1 row)
SELECT master_create_worker_shards(U&'elephant_!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D' UESCAPE '!', '2', '2');
master_create_worker_shards
-----------------------------
(1 row)
\c - - - :worker_1_port
\d elephant_*
Index "public.elephant_слонслонслонсло_14d34928_2250000000002"
Column | Type | Definition
--------+---------+------------
col1 | integer | col1
primary key, btree, for table "public.elephant_слонслонслонсло_c8b737c2_2250000000002"
Index "public.elephant_слонслонслонсло_14d34928_2250000000003"
Column | Type | Definition
--------+---------+------------
col1 | integer | col1
primary key, btree, for table "public.elephant_слонслонслонсло_c8b737c2_2250000000003"
Table "public.elephant_слонслонслонсло_c8b737c2_2250000000002"
Column | Type | Modifiers
--------+---------+-----------
col1 | integer | not null
col2 | integer | not null
Indexes:
"elephant_слонслонслонсло_14d34928_2250000000002" PRIMARY KEY, btree (col1)
Table "public.elephant_слонслонслонсло_c8b737c2_2250000000003"
Column | Type | Modifiers
--------+---------+-----------
col1 | integer | not null
col2 | integer | not null
Indexes:
"elephant_слонслонслонсло_14d34928_2250000000003" PRIMARY KEY, btree (col1)
\c - - - :master_port
-- Clean up.
DROP TABLE name_lengths CASCADE;
DROP TABLE U&"elephant_!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D" UESCAPE '!' CASCADE;

View File

@ -17,6 +17,7 @@
# ---
test: multi_extension
test: multi_table_ddl
test: multi_name_lengths
# ----------
# The following distributed tests depend on creating a partitioned table and

View File

@ -0,0 +1,157 @@
--
-- MULTI_NAME_LENGTHS
--
ALTER SEQUENCE pg_catalog.pg_dist_shardid_seq RESTART 225000;
ALTER SEQUENCE pg_catalog.pg_dist_jobid_seq RESTART 225000;
SET citus.multi_shard_commit_protocol = '2pc';
-- Verify that a table name > 56 characters gets hashed properly.
CREATE TABLE too_long_12345678901234567890123456789012345678901234567890 (
col1 integer not null,
col2 integer not null);
SELECT master_create_distributed_table('too_long_12345678901234567890123456789012345678901234567890', 'col1', 'hash');
SELECT master_create_worker_shards('too_long_12345678901234567890123456789012345678901234567890', '2', '2');
\c - - - :worker_1_port
\d too_long_*
\c - - - :master_port
-- Verify that the UDF works and rejects bad arguments.
SELECT shard_name(NULL, 666666);
SELECT shard_name(0, 666666);
SELECT shard_name('too_long_12345678901234567890123456789012345678901234567890'::regclass, 666666);
SELECT shard_name('too_long_12345678901234567890123456789012345678901234567890'::regclass, NULL);
SELECT shard_name('too_long_12345678901234567890123456789012345678901234567890'::regclass, -21);
DROP TABLE too_long_12345678901234567890123456789012345678901234567890 CASCADE;
-- Table to use for rename checks.
CREATE TABLE name_lengths (
col1 integer not null,
col2 integer not null,
constraint constraint_a UNIQUE (col1)
);
SELECT master_create_distributed_table('name_lengths', 'col1', 'hash');
SELECT master_create_worker_shards('name_lengths', '2', '2');
-- Verify that we CAN add columns with "too-long names", because
-- the columns' names are not extended in the corresponding shard tables.
ALTER TABLE name_lengths ADD COLUMN float_col_12345678901234567890123456789012345678901234567890 FLOAT;
ALTER TABLE name_lengths ADD COLUMN date_col_12345678901234567890123456789012345678901234567890 DATE;
ALTER TABLE name_lengths ADD COLUMN int_col_12345678901234567890123456789012345678901234567890 INTEGER DEFAULT 1;
-- Placeholders for unsupported ALTER TABLE to add constraints with implicit names that are likely too long
ALTER TABLE name_lengths ADD UNIQUE (float_col_12345678901234567890123456789012345678901234567890);
ALTER TABLE name_lengths ADD EXCLUDE (int_col_12345678901234567890123456789012345678901234567890 WITH =);
ALTER TABLE name_lengths ADD CHECK (date_col_12345678901234567890123456789012345678901234567890 > '2014-01-01'::date);
\c - - - :worker_1_port
\d name_lengths_*
\c - - - :master_port
-- Placeholders for unsupported add constraints with EXPLICIT names that are too long
ALTER TABLE name_lengths ADD CONSTRAINT nl_unique_12345678901234567890123456789012345678901234567890 UNIQUE (float_col_12345678901234567890123456789012345678901234567890);
ALTER TABLE name_lengths ADD CONSTRAINT nl_exclude_12345678901234567890123456789012345678901234567890 EXCLUDE (int_col_12345678901234567890123456789012345678901234567890 WITH =);
ALTER TABLE name_lengths ADD CONSTRAINT nl_checky_12345678901234567890123456789012345678901234567890 CHECK (date_col_12345678901234567890123456789012345678901234567890 >= '2014-01-01'::date);
\c - - - :worker_1_port
\d nl_*
\c - - - :master_port
-- Placeholders for RENAME operations
ALTER TABLE name_lengths RENAME TO name_len_12345678901234567890123456789012345678901234567890;
ALTER TABLE name_lengths RENAME CONSTRAINT unique_12345678901234567890123456789012345678901234567890 TO unique2_12345678901234567890123456789012345678901234567890;
-- Verify that CREATE INDEX on already distributed table has proper shard names.
CREATE INDEX tmp_idx_12345678901234567890123456789012345678901234567890 ON name_lengths(col2);
\c - - - :worker_1_port
\d tmp_idx_*
\c - - - :master_port
-- Verify that a new index name > 63 characters is auto-truncated
-- by the parser/rewriter before further processing, just as in Postgres.
CREATE INDEX tmp_idx_123456789012345678901234567890123456789012345678901234567890 ON name_lengths(col2);
\c - - - :worker_1_port
\d tmp_idx_*
\c - - - :master_port
-- Verify that distributed tables with too-long names
-- for CHECK constraints are no trouble.
CREATE TABLE sneaky_name_lengths (
col1 integer not null,
col2 integer not null,
int_col_12345678901234567890123456789012345678901234567890 integer not null,
CHECK (int_col_12345678901234567890123456789012345678901234567890 > 100)
);
SELECT master_create_distributed_table('sneaky_name_lengths', 'col1', 'hash');
SELECT master_create_worker_shards('sneaky_name_lengths', '2', '2');
DROP TABLE sneaky_name_lengths CASCADE;
CREATE TABLE sneaky_name_lengths (
int_col_123456789012345678901234567890123456789012345678901234 integer UNIQUE not null,
col2 integer not null,
CONSTRAINT checky_12345678901234567890123456789012345678901234567890 CHECK (int_col_123456789012345678901234567890123456789012345678901234 > 100)
);
\d sneaky_name_lengths*
SELECT master_create_distributed_table('sneaky_name_lengths', 'int_col_123456789012345678901234567890123456789012345678901234', 'hash');
SELECT master_create_worker_shards('sneaky_name_lengths', '2', '2');
\c - - - :worker_1_port
\d sneaky_name_lengths*
\c - - - :master_port
DROP TABLE sneaky_name_lengths CASCADE;
-- verify that named constraint with too-long name gets hashed properly
CREATE TABLE sneaky_name_lengths (
col1 integer not null,
col2 integer not null,
int_col_12345678901234567890123456789012345678901234567890 integer not null,
constraint unique_12345678901234567890123456789012345678901234567890 UNIQUE (col1)
);
SELECT master_create_distributed_table('sneaky_name_lengths', 'col1', 'hash');
SELECT master_create_worker_shards('sneaky_name_lengths', '2', '2');
\c - - - :worker_1_port
\d sneaky_name_lengths*
\c - - - :master_port
DROP TABLE sneaky_name_lengths CASCADE;
-- Verify that much larger shardIds are handled properly
ALTER SEQUENCE pg_catalog.pg_dist_shardid_seq RESTART 2250000000000;
CREATE TABLE too_long_12345678901234567890123456789012345678901234567890 (
col1 integer not null,
col2 integer not null);
SELECT master_create_distributed_table('too_long_12345678901234567890123456789012345678901234567890', 'col1', 'hash');
SELECT master_create_worker_shards('too_long_12345678901234567890123456789012345678901234567890', '2', '2');
\c - - - :worker_1_port
\d too_long_*
\c - - - :master_port
DROP TABLE too_long_12345678901234567890123456789012345678901234567890 CASCADE;
-- Verify that multi-byte boundaries are respected for databases with UTF8 encoding.
CREATE TABLE U&"elephant_!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D" UESCAPE '!' (
col1 integer not null PRIMARY KEY,
col2 integer not null);
SELECT master_create_distributed_table(U&'elephant_!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D' UESCAPE '!', 'col1', 'hash');
SELECT master_create_worker_shards(U&'elephant_!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D' UESCAPE '!', '2', '2');
\c - - - :worker_1_port
\d elephant_*
\c - - - :master_port
-- Clean up.
DROP TABLE name_lengths CASCADE;
DROP TABLE U&"elephant_!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D!0441!043B!043E!043D" UESCAPE '!' CASCADE;