Change error message of queries with distributed and local table

Citus can handle INSERT INTO ... SELECT queries if the query inserts
into local table by reading data from distributed table. The opposite
way is not correct. With this commit we warn the user if the latter
option is used.
pull/1580/head
velioglu 2017-08-16 11:58:04 +03:00
parent fb70400b61
commit 0a56ed910b
6 changed files with 77 additions and 10 deletions

View File

@ -64,6 +64,7 @@ static DeferredErrorMessage * CoordinatorInsertSelectSupported(Query *insertSele
static Query * WrapSubquery(Query *subquery); static Query * WrapSubquery(Query *subquery);
static void CastSelectTargetList(List *selectTargetList, Oid targetRelationId, static void CastSelectTargetList(List *selectTargetList, Oid targetRelationId,
List *insertTargetList); List *insertTargetList);
static bool CheckInsertSelectQuery(Query *query);
/* /*
@ -73,18 +74,62 @@ static void CastSelectTargetList(List *selectTargetList, Oid targetRelationId,
* *
* Note that the input query should be the original parsetree of * Note that the input query should be the original parsetree of
* the query (i.e., not passed trough the standard planner). * the query (i.e., not passed trough the standard planner).
*/
bool
InsertSelectIntoDistributedTable(Query *query)
{
bool insertSelectQuery = CheckInsertSelectQuery(query);
if (insertSelectQuery)
{
RangeTblEntry *insertRte = ExtractInsertRangeTableEntry(query);
if (IsDistributedTable(insertRte->relid))
{
return true;
}
}
return false;
}
/*
* InsertSelectIntoLocalTable checks whether INSERT INTO ... SELECT inserts
* into local table. Note that query must be a sample of INSERT INTO ... SELECT
* type of query.
*/
bool
InsertSelectIntoLocalTable(Query *query)
{
bool insertSelectQuery = CheckInsertSelectQuery(query);
if (insertSelectQuery)
{
RangeTblEntry *insertRte = ExtractInsertRangeTableEntry(query);
if (!IsDistributedTable(insertRte->relid))
{
return true;
}
}
return false;
}
/*
* CheckInsertSelectQuery returns true when the input query is an INSERT INTO
* ... SELECT kind of query.
* *
* This function is inspired from getInsertSelectQuery() on * This function is inspired from getInsertSelectQuery() on
* rewrite/rewriteManip.c. * rewrite/rewriteManip.c.
*/ */
bool static bool
InsertSelectIntoDistributedTable(Query *query) CheckInsertSelectQuery(Query *query)
{ {
CmdType commandType = query->commandType; CmdType commandType = query->commandType;
List *fromList = NULL; List *fromList = NULL;
RangeTblRef *rangeTableReference = NULL; RangeTblRef *rangeTableReference = NULL;
RangeTblEntry *subqueryRte = NULL; RangeTblEntry *subqueryRte = NULL;
RangeTblEntry *insertRte = NULL;
if (commandType != CMD_INSERT) if (commandType != CMD_INSERT)
{ {
@ -117,12 +162,6 @@ InsertSelectIntoDistributedTable(Query *query)
/* ensure that there is a query */ /* ensure that there is a query */
Assert(IsA(subqueryRte->subquery, Query)); Assert(IsA(subqueryRte->subquery, Query));
insertRte = ExtractInsertRangeTableEntry(query);
if (!IsDistributedTable(insertRte->relid))
{
return false;
}
return true; return true;
} }

View File

@ -2976,6 +2976,11 @@ NeedsDistributedPlanning(Query *queryTree)
if (hasLocalRelation && hasDistributedRelation) if (hasLocalRelation && hasDistributedRelation)
{ {
if (InsertSelectIntoLocalTable(queryTree))
{
ereport(ERROR, (errmsg("cannot INSERT rows from a distributed query into a "
"local table")));
}
ereport(ERROR, (errmsg("cannot plan queries which include both local and " ereport(ERROR, (errmsg("cannot plan queries which include both local and "
"distributed relations"))); "distributed relations")));
} }

View File

@ -24,6 +24,7 @@
extern bool InsertSelectIntoDistributedTable(Query *query); extern bool InsertSelectIntoDistributedTable(Query *query);
extern bool InsertSelectIntoLocalTable(Query *query);
extern Query * ReorderInsertSelectTargetLists(Query *originalQuery, extern Query * ReorderInsertSelectTargetLists(Query *originalQuery,
RangeTblEntry *insertRte, RangeTblEntry *insertRte,
RangeTblEntry *subqueryRte); RangeTblEntry *subqueryRte);

View File

@ -336,7 +336,7 @@ step s1-initialize:
step s1-begin: BEGIN; step s1-begin: BEGIN;
step s1-insert-select: INSERT INTO insert_of_insert_select_hash SELECT * FROM select_of_insert_select_hash ORDER BY 1, 2 LIMIT 5;; step s1-insert-select: INSERT INTO insert_of_insert_select_hash SELECT * FROM select_of_insert_select_hash ORDER BY 1, 2 LIMIT 5;;
ERROR: cannot plan queries which include both local and distributed relations ERROR: cannot INSERT rows from a distributed query into a local table
step s2-distribute-table-on-inserted: SELECT create_distributed_table('insert_of_insert_select_hash', 'id'); step s2-distribute-table-on-inserted: SELECT create_distributed_table('insert_of_insert_select_hash', 'id');
create_distributed_table create_distributed_table

View File

@ -1,5 +1,15 @@
------------------------------------ ------------------------------------
------------------------------------ ------------------------------------
-- Insert into local table
------------------------------------
------------------------------------
CREATE TABLE test_table_1(id int);
INSERT INTO test_table_1
SELECT user_id FROM users_table;
ERROR: cannot INSERT rows from a distributed query into a local table
DROP TABLE test_table_1;
------------------------------------
------------------------------------
-- Vanilla funnel query -- Vanilla funnel query
------------------------------------ ------------------------------------
------------------------------------ ------------------------------------

View File

@ -1,3 +1,15 @@
------------------------------------
------------------------------------
-- Insert into local table
------------------------------------
------------------------------------
CREATE TABLE test_table_1(id int);
INSERT INTO test_table_1
SELECT user_id FROM users_table;
DROP TABLE test_table_1;
------------------------------------ ------------------------------------
------------------------------------ ------------------------------------
-- Vanilla funnel query -- Vanilla funnel query