Error out at master_create_distributed_table if the table has any rows

Before this change, we do not check whether given table which already contains any data
in master_create_distributed_table command. If that table contains any data, making it
it distributed, makes that data hidden to user. With this change, we now gave error to
user if the table contains data.
pull/762/head
Burak Yucesoy 2016-08-22 15:48:00 +03:00
parent 7168fdf62e
commit 12d1aba1fc
5 changed files with 90 additions and 1 deletions

View File

@ -28,6 +28,7 @@
#include "distributed/master_metadata_utility.h" #include "distributed/master_metadata_utility.h"
#include "distributed/metadata_cache.h" #include "distributed/metadata_cache.h"
#include "distributed/pg_dist_partition.h" #include "distributed/pg_dist_partition.h"
#include "executor/spi.h"
#include "nodes/execnodes.h" #include "nodes/execnodes.h"
#include "nodes/nodeFuncs.h" #include "nodes/nodeFuncs.h"
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
@ -48,6 +49,7 @@ static void RecordDistributedRelationDependencies(Oid distributedRelationId,
Node *distributionKey); Node *distributionKey);
static Oid SupportFunctionForColumn(Var *partitionColumn, Oid accessMethodId, static Oid SupportFunctionForColumn(Var *partitionColumn, Oid accessMethodId,
int16 supportFunctionNumber); int16 supportFunctionNumber);
static bool LocalTableEmpty(Oid tableId);
/* exports for SQL callable functions */ /* exports for SQL callable functions */
@ -122,6 +124,17 @@ master_create_distributed_table(PG_FUNCTION_ARGS)
"foreign tables."))); "foreign tables.")));
} }
/* check that the relation does not contain any rows */
if (!LocalTableEmpty(distributedRelationId))
{
ereport(ERROR, (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("cannot distribute relation \"%s\"",
distributedRelationName),
errdetail("Relation \"%s\" contains data.",
distributedRelationName),
errhint("Empty your table before distributing it.")));
}
distributionKey = BuildDistributionKeyFromColumnName(distributedRelation, distributionKey = BuildDistributionKeyFromColumnName(distributedRelation,
distributionColumnName); distributionColumnName);
distributionKeyString = nodeToString(distributionKey); distributionKeyString = nodeToString(distributionKey);
@ -377,3 +390,59 @@ SupportFunctionForColumn(Var *partitionColumn, Oid accessMethodId,
return supportFunctionOid; return supportFunctionOid;
} }
/*
* LocalTableEmpty function checks whether given local table contains any row and
* returns false if there is any data. This function is only for local tables and
* should not be called for distributed tables.
*/
static bool
LocalTableEmpty(Oid tableId)
{
Oid schemaId = get_rel_namespace(tableId);
char *schemaName = get_namespace_name(schemaId);
char *tableName = get_rel_name(tableId);
char *tableQualifiedName = quote_qualified_identifier(schemaName, tableName);
int spiConnectionResult = 0;
int spiQueryResult = 0;
StringInfo selectExistQueryString = makeStringInfo();
HeapTuple tuple = NULL;
Datum hasDataDatum = 0;
bool localTableEmpty = false;
bool columnNull = false;
bool readOnly = true;
int rowId = 0;
int attributeId = 1;
AssertArg(!IsDistributedTable(tableId));
spiConnectionResult = SPI_connect();
if (spiConnectionResult != SPI_OK_CONNECT)
{
ereport(ERROR, (errmsg("could not connect to SPI manager")));
}
appendStringInfo(selectExistQueryString, SELECT_EXIST_QUERY, tableQualifiedName);
spiQueryResult = SPI_execute(selectExistQueryString->data, readOnly, 0);
if (spiQueryResult != SPI_OK_SELECT)
{
ereport(ERROR, (errmsg("execution was not successful \"%s\"",
selectExistQueryString->data)));
}
/* we expect that SELECT EXISTS query will return single value in a single row */
Assert(SPI_processed == 1);
tuple = SPI_tuptable->vals[rowId];
hasDataDatum = SPI_getbinval(tuple, SPI_tuptable->tupdesc, attributeId, &columnNull);
localTableEmpty = !DatumGetBool(hasDataDatum);
SPI_finish();
return localTableEmpty;
}

View File

@ -24,6 +24,7 @@
/* total number of hash tokens (2^32) */ /* total number of hash tokens (2^32) */
#define HASH_TOKEN_COUNT INT64CONST(4294967296) #define HASH_TOKEN_COUNT INT64CONST(4294967296)
#define SELECT_EXIST_QUERY "SELECT EXISTS (SELECT 1 FROM %s)"
/* In-memory representation of a typed tuple in pg_dist_shard. */ /* In-memory representation of a typed tuple in pg_dist_shard. */
typedef struct ShardInterval typedef struct ShardInterval

View File

@ -390,7 +390,7 @@ ORDER BY
customer_keys.o_custkey DESC customer_keys.o_custkey DESC
LIMIT 10 OFFSET 20; LIMIT 10 OFFSET 20;
DEBUG: push down of limit count: 30 DEBUG: push down of limit count: 30
DEBUG: building index "pg_toast_17021_index" on table "pg_toast_17021" DEBUG: building index "pg_toast_17022_index" on table "pg_toast_17022"
o_custkey | total_order_count o_custkey | total_order_count
-----------+------------------- -----------+-------------------
1466 | 1 1466 | 1

View File

@ -75,6 +75,12 @@ CREATE TABLE nation (
n_name char(25) not null, n_name char(25) not null,
n_regionkey integer not null, n_regionkey integer not null,
n_comment varchar(152)); n_comment varchar(152));
\COPY nation FROM STDIN WITH CSV
SELECT master_create_distributed_table('nation', 'n_nationkey', 'append');
ERROR: cannot distribute relation "nation"
DETAIL: Relation "nation" contains data.
HINT: Empty your table before distributing it.
TRUNCATE nation;
SELECT master_create_distributed_table('nation', 'n_nationkey', 'append'); SELECT master_create_distributed_table('nation', 'n_nationkey', 'append');
master_create_distributed_table master_create_distributed_table
--------------------------------- ---------------------------------

View File

@ -61,6 +61,19 @@ CREATE TABLE nation (
n_name char(25) not null, n_name char(25) not null,
n_regionkey integer not null, n_regionkey integer not null,
n_comment varchar(152)); n_comment varchar(152));
\COPY nation FROM STDIN WITH CSV
1,'name',1,'comment_1'
2,'name',2,'comment_2'
3,'name',3,'comment_3'
4,'name',4,'comment_4'
5,'name',5,'comment_5'
\.
SELECT master_create_distributed_table('nation', 'n_nationkey', 'append');
TRUNCATE nation;
SELECT master_create_distributed_table('nation', 'n_nationkey', 'append'); SELECT master_create_distributed_table('nation', 'n_nationkey', 'append');
CREATE TABLE part ( CREATE TABLE part (