mirror of https://github.com/citusdata/citus.git
commit
f90fb10b5f
|
@ -103,7 +103,8 @@ static bool LocalTableEmpty(Oid tableId);
|
||||||
static void CopyLocalDataIntoShards(Oid relationId);
|
static void CopyLocalDataIntoShards(Oid relationId);
|
||||||
static List * TupleDescColumnNameList(TupleDesc tupleDescriptor);
|
static List * TupleDescColumnNameList(TupleDesc tupleDescriptor);
|
||||||
static bool RelationUsesIdentityColumns(TupleDesc relationDesc);
|
static bool RelationUsesIdentityColumns(TupleDesc relationDesc);
|
||||||
static bool RelationUsesGeneratedStoredColumns(TupleDesc relationDesc);
|
static bool DistributionColumnUsesGeneratedStoredColumn(TupleDesc relationDesc,
|
||||||
|
Var *distributionColumn);
|
||||||
static bool RelationUsesHeapAccessMethodOrNone(Relation relation);
|
static bool RelationUsesHeapAccessMethodOrNone(Relation relation);
|
||||||
static bool CanUseExclusiveConnections(Oid relationId, bool localTableEmpty);
|
static bool CanUseExclusiveConnections(Oid relationId, bool localTableEmpty);
|
||||||
|
|
||||||
|
@ -684,12 +685,13 @@ EnsureRelationCanBeDistributed(Oid relationId, Var *distributionColumn,
|
||||||
"... AS IDENTITY.")));
|
"... AS IDENTITY.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* verify target relation does not use generated columns */
|
/* verify target relation is not distributed by a generated columns */
|
||||||
if (RelationUsesGeneratedStoredColumns(relationDesc))
|
if (distributionMethod != DISTRIBUTE_BY_NONE &&
|
||||||
|
DistributionColumnUsesGeneratedStoredColumn(relationDesc, distributionColumn))
|
||||||
{
|
{
|
||||||
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
errmsg("cannot distribute relation: %s", relationName),
|
errmsg("cannot distribute relation: %s", relationName),
|
||||||
errdetail("Distributed relations must not use GENERATED ALWAYS "
|
errdetail("Distribution column must not use GENERATED ALWAYS "
|
||||||
"AS (...) STORED.")));
|
"AS (...) STORED.")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1368,7 +1370,11 @@ TupleDescColumnNameList(TupleDesc tupleDescriptor)
|
||||||
Form_pg_attribute currentColumn = TupleDescAttr(tupleDescriptor, columnIndex);
|
Form_pg_attribute currentColumn = TupleDescAttr(tupleDescriptor, columnIndex);
|
||||||
char *columnName = NameStr(currentColumn->attname);
|
char *columnName = NameStr(currentColumn->attname);
|
||||||
|
|
||||||
if (currentColumn->attisdropped)
|
if (currentColumn->attisdropped
|
||||||
|
#if PG_VERSION_NUM >= 120000
|
||||||
|
|| currentColumn->attgenerated == ATTRIBUTE_GENERATED_STORED
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1381,8 +1387,8 @@ TupleDescColumnNameList(TupleDesc tupleDescriptor)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelationUsesIdentityColumns returns whether a given relation uses the SQL
|
* RelationUsesIdentityColumns returns whether a given relation uses
|
||||||
* GENERATED ... AS IDENTITY features introduced as of PostgreSQL 10.
|
* GENERATED ... AS IDENTITY
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
RelationUsesIdentityColumns(TupleDesc relationDesc)
|
RelationUsesIdentityColumns(TupleDesc relationDesc)
|
||||||
|
@ -1404,23 +1410,20 @@ RelationUsesIdentityColumns(TupleDesc relationDesc)
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* RelationUsesIdentityColumns returns whether a given relation uses the SQL
|
* DistributionColumnUsesGeneratedStoredColumn returns whether a given relation uses
|
||||||
* GENERATED ... AS IDENTITY features introduced as of PostgreSQL 10.
|
* GENERATED ALWAYS AS (...) STORED on distribution column
|
||||||
*/
|
*/
|
||||||
static bool
|
static bool
|
||||||
RelationUsesGeneratedStoredColumns(TupleDesc relationDesc)
|
DistributionColumnUsesGeneratedStoredColumn(TupleDesc relationDesc,
|
||||||
|
Var *distributionColumn)
|
||||||
{
|
{
|
||||||
#if PG_VERSION_NUM >= 120000
|
#if PG_VERSION_NUM >= 120000
|
||||||
int attributeIndex = 0;
|
Form_pg_attribute attributeForm = TupleDescAttr(relationDesc,
|
||||||
|
distributionColumn->varattno - 1);
|
||||||
|
|
||||||
for (attributeIndex = 0; attributeIndex < relationDesc->natts; attributeIndex++)
|
if (attributeForm->attgenerated == ATTRIBUTE_GENERATED_STORED)
|
||||||
{
|
{
|
||||||
Form_pg_attribute attributeForm = TupleDescAttr(relationDesc, attributeIndex);
|
return true;
|
||||||
|
|
||||||
if (attributeForm->attgenerated == ATTRIBUTE_GENERATED_STORED)
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@
|
||||||
#include "access/sysattr.h"
|
#include "access/sysattr.h"
|
||||||
#include "access/xact.h"
|
#include "access/xact.h"
|
||||||
#include "catalog/namespace.h"
|
#include "catalog/namespace.h"
|
||||||
|
#include "catalog/pg_attribute.h"
|
||||||
#include "catalog/pg_type.h"
|
#include "catalog/pg_type.h"
|
||||||
#include "commands/copy.h"
|
#include "commands/copy.h"
|
||||||
#include "commands/defrem.h"
|
#include "commands/defrem.h"
|
||||||
|
@ -481,7 +482,11 @@ CopyToExistingShards(CopyStmt *copyStatement, char *completionTag)
|
||||||
Form_pg_attribute currentColumn = TupleDescAttr(tupleDescriptor, columnIndex);
|
Form_pg_attribute currentColumn = TupleDescAttr(tupleDescriptor, columnIndex);
|
||||||
char *columnName = NameStr(currentColumn->attname);
|
char *columnName = NameStr(currentColumn->attname);
|
||||||
|
|
||||||
if (currentColumn->attisdropped)
|
if (currentColumn->attisdropped
|
||||||
|
#if PG_VERSION_NUM >= 120000
|
||||||
|
|| currentColumn->attgenerated == ATTRIBUTE_GENERATED_STORED
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -510,7 +515,7 @@ CopyToExistingShards(CopyStmt *copyStatement, char *completionTag)
|
||||||
* of BeginCopyFrom. However, we obviously should not do this in relcache
|
* of BeginCopyFrom. However, we obviously should not do this in relcache
|
||||||
* and therefore make a copy of the Relation.
|
* and therefore make a copy of the Relation.
|
||||||
*/
|
*/
|
||||||
copiedDistributedRelation = (Relation) palloc0(sizeof(RelationData));
|
copiedDistributedRelation = (Relation) palloc(sizeof(RelationData));
|
||||||
copiedDistributedRelationTuple = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
|
copiedDistributedRelationTuple = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1028,7 +1033,11 @@ CanUseBinaryCopyFormat(TupleDesc tupleDescription)
|
||||||
Form_pg_attribute currentColumn = TupleDescAttr(tupleDescription, columnIndex);
|
Form_pg_attribute currentColumn = TupleDescAttr(tupleDescription, columnIndex);
|
||||||
Oid typeId = InvalidOid;
|
Oid typeId = InvalidOid;
|
||||||
|
|
||||||
if (currentColumn->attisdropped)
|
if (currentColumn->attisdropped
|
||||||
|
#if PG_VERSION_NUM >= 120000
|
||||||
|
|| currentColumn->attgenerated == ATTRIBUTE_GENERATED_STORED
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1667,7 +1676,11 @@ AppendCopyRowData(Datum *valueArray, bool *isNullArray, TupleDesc rowDescriptor,
|
||||||
value = CoerceColumnValue(value, &columnCoercionPaths[columnIndex]);
|
value = CoerceColumnValue(value, &columnCoercionPaths[columnIndex]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (currentColumn->attisdropped)
|
if (currentColumn->attisdropped
|
||||||
|
#if PG_VERSION_NUM >= 120000
|
||||||
|
|| currentColumn->attgenerated == ATTRIBUTE_GENERATED_STORED
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -1787,7 +1800,11 @@ AvailableColumnCount(TupleDesc tupleDescriptor)
|
||||||
{
|
{
|
||||||
Form_pg_attribute currentColumn = TupleDescAttr(tupleDescriptor, columnIndex);
|
Form_pg_attribute currentColumn = TupleDescAttr(tupleDescriptor, columnIndex);
|
||||||
|
|
||||||
if (!currentColumn->attisdropped)
|
if (!currentColumn->attisdropped
|
||||||
|
#if PG_VERSION_NUM >= 120000
|
||||||
|
&& currentColumn->attgenerated != ATTRIBUTE_GENERATED_STORED
|
||||||
|
#endif
|
||||||
|
)
|
||||||
{
|
{
|
||||||
columnCount++;
|
columnCount++;
|
||||||
}
|
}
|
||||||
|
|
|
@ -312,7 +312,7 @@ pg_get_tableschemadef_string(Oid tableRelationId, bool includeSequenceDefaults)
|
||||||
* reasoning behind this is that Citus implements declarative partitioning
|
* reasoning behind this is that Citus implements declarative partitioning
|
||||||
* by creating the partitions first and then sending
|
* by creating the partitions first and then sending
|
||||||
* "ALTER TABLE parent_table ATTACH PARTITION .." command. This may not play
|
* "ALTER TABLE parent_table ATTACH PARTITION .." command. This may not play
|
||||||
* well with regular inhereted tables, which isn't a big concern from Citus'
|
* well with regular inherited tables, which isn't a big concern from Citus'
|
||||||
* perspective.
|
* perspective.
|
||||||
*/
|
*/
|
||||||
if (!attributeForm->attisdropped)
|
if (!attributeForm->attisdropped)
|
||||||
|
@ -371,7 +371,19 @@ pg_get_tableschemadef_string(Oid tableRelationId, bool includeSequenceDefaults)
|
||||||
defaultString = deparse_expression(defaultNode, defaultContext,
|
defaultString = deparse_expression(defaultNode, defaultContext,
|
||||||
false, false);
|
false, false);
|
||||||
|
|
||||||
|
#if PG_VERSION_NUM >= 120000
|
||||||
|
if (attributeForm->attgenerated == ATTRIBUTE_GENERATED_STORED)
|
||||||
|
{
|
||||||
|
appendStringInfo(&buffer, " GENERATED ALWAYS AS (%s) STORED",
|
||||||
|
defaultString);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
appendStringInfo(&buffer, " DEFAULT %s", defaultString);
|
||||||
|
}
|
||||||
|
#else
|
||||||
appendStringInfo(&buffer, " DEFAULT %s", defaultString);
|
appendStringInfo(&buffer, " DEFAULT %s", defaultString);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,37 +33,41 @@ create table gen2 (
|
||||||
);
|
);
|
||||||
insert into gen1 (id, val1) values (1,4),(3,6),(5,2),(7,2);
|
insert into gen1 (id, val1) values (1,4),(3,6),(5,2),(7,2);
|
||||||
insert into gen2 (id, val1) values (1,4),(3,6),(5,2),(7,2);
|
insert into gen2 (id, val1) values (1,4),(3,6),(5,2),(7,2);
|
||||||
select * from create_distributed_table('gen1', 'id');
|
select create_distributed_table('gen1', 'id');
|
||||||
ERROR: cannot distribute relation: gen1
|
NOTICE: Copying data from local table...
|
||||||
DETAIL: Distributed relations must not use GENERATED ALWAYS AS (...) STORED.
|
create_distributed_table
|
||||||
select * from create_distributed_table('gen2', 'val2');
|
--------------------------
|
||||||
|
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
select create_distributed_table('gen2', 'val2');
|
||||||
ERROR: cannot distribute relation: gen2
|
ERROR: cannot distribute relation: gen2
|
||||||
DETAIL: Distributed relations must not use GENERATED ALWAYS AS (...) STORED.
|
DETAIL: Distribution column must not use GENERATED ALWAYS AS (...) STORED.
|
||||||
insert into gen1 (id, val1) values (2,4),(4,6),(6,2),(8,2);
|
insert into gen1 (id, val1) values (2,4),(4,6),(6,2),(8,2);
|
||||||
insert into gen2 (id, val1) values (2,4),(4,6),(6,2),(8,2);
|
insert into gen2 (id, val1) values (2,4),(4,6),(6,2),(8,2);
|
||||||
select * from gen1;
|
select * from gen1 order by 1,2,3;
|
||||||
id | val1 | val2
|
id | val1 | val2
|
||||||
----+------+------
|
----+------+------
|
||||||
1 | 4 | 6
|
1 | 4 | 6
|
||||||
3 | 6 | 8
|
|
||||||
5 | 2 | 4
|
|
||||||
7 | 2 | 4
|
|
||||||
2 | 4 | 6
|
2 | 4 | 6
|
||||||
|
3 | 6 | 8
|
||||||
4 | 6 | 8
|
4 | 6 | 8
|
||||||
|
5 | 2 | 4
|
||||||
6 | 2 | 4
|
6 | 2 | 4
|
||||||
|
7 | 2 | 4
|
||||||
8 | 2 | 4
|
8 | 2 | 4
|
||||||
(8 rows)
|
(8 rows)
|
||||||
|
|
||||||
select * from gen2;
|
select * from gen2 order by 1,2,3;
|
||||||
id | val1 | val2
|
id | val1 | val2
|
||||||
----+------+------
|
----+------+------
|
||||||
1 | 4 | 6
|
1 | 4 | 6
|
||||||
3 | 6 | 8
|
|
||||||
5 | 2 | 4
|
|
||||||
7 | 2 | 4
|
|
||||||
2 | 4 | 6
|
2 | 4 | 6
|
||||||
|
3 | 6 | 8
|
||||||
4 | 6 | 8
|
4 | 6 | 8
|
||||||
|
5 | 2 | 4
|
||||||
6 | 2 | 4
|
6 | 2 | 4
|
||||||
|
7 | 2 | 4
|
||||||
8 | 2 | 4
|
8 | 2 | 4
|
||||||
(8 rows)
|
(8 rows)
|
||||||
|
|
||||||
|
@ -169,7 +173,7 @@ $Q$);
|
||||||
coordinator_plan
|
coordinator_plan
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
Custom Scan (Citus Adaptive)
|
Custom Scan (Citus Adaptive)
|
||||||
-> Distributed Subplan 5_1
|
-> Distributed Subplan 7_1
|
||||||
-> Custom Scan (Citus Adaptive)
|
-> Custom Scan (Citus Adaptive)
|
||||||
Task Count: 4
|
Task Count: 4
|
||||||
(4 rows)
|
(4 rows)
|
||||||
|
@ -214,7 +218,7 @@ $Q$);
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
Aggregate
|
Aggregate
|
||||||
-> Custom Scan (Citus Adaptive)
|
-> Custom Scan (Citus Adaptive)
|
||||||
-> Distributed Subplan 8_1
|
-> Distributed Subplan 10_1
|
||||||
-> Custom Scan (Citus Adaptive)
|
-> Custom Scan (Citus Adaptive)
|
||||||
Task Count: 4
|
Task Count: 4
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
@ -235,7 +239,7 @@ $Q$);
|
||||||
------------------------------------------------
|
------------------------------------------------
|
||||||
Aggregate
|
Aggregate
|
||||||
-> Custom Scan (Citus Adaptive)
|
-> Custom Scan (Citus Adaptive)
|
||||||
-> Distributed Subplan 10_1
|
-> Distributed Subplan 12_1
|
||||||
-> Custom Scan (Citus Adaptive)
|
-> Custom Scan (Citus Adaptive)
|
||||||
Task Count: 4
|
Task Count: 4
|
||||||
(5 rows)
|
(5 rows)
|
||||||
|
@ -280,8 +284,8 @@ NOTICE: Copying data from local table...
|
||||||
|
|
||||||
-- should still fail because of fkey
|
-- should still fail because of fkey
|
||||||
INSERT INTO collection_users VALUES (1, 1000, 1);
|
INSERT INTO collection_users VALUES (1, 1000, 1);
|
||||||
ERROR: insert or update on table "collection_users_60024" violates foreign key constraint "collection_users_fkey_60024"
|
ERROR: insert or update on table "collection_users_60028" violates foreign key constraint "collection_users_fkey_60028"
|
||||||
DETAIL: Key (key, collection_id)=(1, 1000) is not present in table "collections_list_60012".
|
DETAIL: Key (key, collection_id)=(1, 1000) is not present in table "collections_list_60016".
|
||||||
CONTEXT: while executing command on localhost:57637
|
CONTEXT: while executing command on localhost:57637
|
||||||
-- whereas new record with partition should go through
|
-- whereas new record with partition should go through
|
||||||
INSERT INTO collections_list VALUES (2, 1, '1.2');
|
INSERT INTO collections_list VALUES (2, 1, '1.2');
|
||||||
|
|
|
@ -39,14 +39,14 @@ create table gen2 (
|
||||||
insert into gen1 (id, val1) values (1,4),(3,6),(5,2),(7,2);
|
insert into gen1 (id, val1) values (1,4),(3,6),(5,2),(7,2);
|
||||||
insert into gen2 (id, val1) values (1,4),(3,6),(5,2),(7,2);
|
insert into gen2 (id, val1) values (1,4),(3,6),(5,2),(7,2);
|
||||||
|
|
||||||
select * from create_distributed_table('gen1', 'id');
|
select create_distributed_table('gen1', 'id');
|
||||||
select * from create_distributed_table('gen2', 'val2');
|
select create_distributed_table('gen2', 'val2');
|
||||||
|
|
||||||
insert into gen1 (id, val1) values (2,4),(4,6),(6,2),(8,2);
|
insert into gen1 (id, val1) values (2,4),(4,6),(6,2),(8,2);
|
||||||
insert into gen2 (id, val1) values (2,4),(4,6),(6,2),(8,2);
|
insert into gen2 (id, val1) values (2,4),(4,6),(6,2),(8,2);
|
||||||
|
|
||||||
select * from gen1;
|
select * from gen1 order by 1,2,3;
|
||||||
select * from gen2;
|
select * from gen2 order by 1,2,3;
|
||||||
|
|
||||||
-- Test new VACUUM/ANALYZE options
|
-- Test new VACUUM/ANALYZE options
|
||||||
analyze (skip_locked) gen1;
|
analyze (skip_locked) gen1;
|
||||||
|
|
Loading…
Reference in New Issue