diff --git a/src/backend/distributed/planner/multi_router_planner.c b/src/backend/distributed/planner/multi_router_planner.c index 39bf01782..d74970832 100644 --- a/src/backend/distributed/planner/multi_router_planner.c +++ b/src/backend/distributed/planner/multi_router_planner.c @@ -1923,10 +1923,25 @@ TargetShardIntervalForModify(Query *query) char partitionMethod = cacheEntry->partitionMethod; bool fastShardPruningPossible = false; CmdType commandType = query->commandType; - bool updateOrDelete = (commandType == CMD_UPDATE || commandType == CMD_DELETE); + const char *commandName = NULL; Assert(commandType != CMD_SELECT); + + if (commandType == CMD_INSERT) + { + commandName = "INSERT"; + } + else if (commandType == CMD_UPDATE) + { + commandName = "UPDATE"; + } + else + { + Assert(commandType == CMD_DELETE); + commandName = "DELETE"; + } + /* error out if no shards exist for the table */ shardCount = cacheEntry->shardIntervalArrayLength; if (shardCount == 0) @@ -1974,56 +1989,52 @@ TargetShardIntervalForModify(Query *query) char *partitionKeyString = cacheEntry->partitionKeyString; char *partitionColumnName = ColumnNameToColumn(relationId, partitionKeyString); StringInfo errorHint = makeStringInfo(); - char *errorDetail = NULL; + const char *targetCountType = NULL; + bool showHint = false; if (prunedShardCount == 0) { - errorDetail = "This command modifies no shards."; + targetCountType = "no"; } - else if (prunedShardCount == shardCount) + else { - errorDetail = "This command modifies all shards."; + targetCountType = "multiple"; } - if (updateOrDelete) + if (commandType == CMD_INSERT && prunedShardCount == 0) { - appendStringInfo(errorHint, - "Consider using an equality filter on partition column " - "\"%s\". You can use master_modify_multiple_shards() to " - "perform multi-shard delete or update operations.", + appendStringInfo(errorHint, "Make sure you have created a shard which " + "can receive this partition column value."); + } + else if (commandType == CMD_INSERT) + { + appendStringInfo(errorHint, "Make sure the value for partition column " + "\"%s\" falls into a single shard.", partitionColumnName); } else { - appendStringInfo(errorHint, - "Make sure the value for partition column \"%s\" falls into " - "a single shard.", partitionColumnName); + appendStringInfo(errorHint, "Consider using an equality filter on " + "partition column \"%s\" to target a " + "single shard. If you'd like to run a " + "multi-shard operation, use " + "master_modify_multiple_shards().", + partitionColumnName); } - if (commandType == CMD_DELETE && partitionMethod == DISTRIBUTE_BY_APPEND) { - appendStringInfo(errorHint, - " You can also use master_apply_delete_command() to drop " - "all shards satisfying delete criteria."); + appendStringInfo(errorHint, " You can also use " + "master_apply_delete_command() to drop " + "all shards satisfying delete criteria."); } + showHint = errorHint->len > 0; - if (errorDetail == NULL) - { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("distributed modifications must target exactly one " - "shard"), - errhint("%s", errorHint->data))); - } - else - { - ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("distributed modifications must target exactly one " - "shard"), - errdetail("%s", errorDetail), - errhint("%s", errorHint->data))); - } + ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot run %s command which targets %s shards", + commandName, targetCountType), + showHint ? errhint("%s", errorHint->data) : 0)); } return (ShardInterval *) linitial(prunedShardList); diff --git a/src/test/regress/expected/multi_modifications.out b/src/test/regress/expected/multi_modifications.out index 2e4c6cf34..58682830b 100644 --- a/src/test/regress/expected/multi_modifications.out +++ b/src/test/regress/expected/multi_modifications.out @@ -140,14 +140,12 @@ SET citus.task_executor_type TO DEFAULT; -- try inserting without a range-partitioned shard to receive the value INSERT INTO range_partitioned VALUES (999999, 'AAPL', 9580, '2004-10-19 10:23:54', 'buy', 20.69); -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies no shards. -HINT: Make sure the value for partition column "id" falls into a single shard. +ERROR: cannot run INSERT command which targets no shards +HINT: Make sure you have created a shard which can receive this partition column value. -- and insert into an append-partitioned table with a value that spans shards: INSERT INTO append_partitioned VALUES (500000, 'AAPL', 9580, '2004-10-19 10:23:54', 'buy', 20.69); -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. +ERROR: cannot run INSERT command which targets multiple shards HINT: Make sure the value for partition column "id" falls into a single shard. -- INSERT with DEFAULT in the target list INSERT INTO limit_orders VALUES (12756, 'MSFT', 10959, '2013-05-08 07:29:23', 'sell', @@ -263,9 +261,8 @@ SELECT COUNT(*) FROM limit_orders WHERE id = 246; -- commands with no constraints on the partition key are not supported DELETE FROM limit_orders WHERE bidder_id = 162; -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "id". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run DELETE command which targets multiple shards +HINT: Consider using an equality filter on partition column "id" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). -- commands with a USING clause are unsupported CREATE TABLE bidders ( name text, id bigint ); DELETE FROM limit_orders USING bidders WHERE limit_orders.id = 246 AND @@ -278,9 +275,8 @@ DELETE FROM limit_orders; ERROR: common table expressions are not supported in distributed modifications -- cursors are not supported DELETE FROM limit_orders WHERE CURRENT OF cursor_name; -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "id". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run DELETE command which targets multiple shards +HINT: Consider using an equality filter on partition column "id" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). INSERT INTO limit_orders VALUES (246, 'TSLA', 162, '2007-07-02 16:32:15', 'sell', 20.69); -- simple UPDATE UPDATE limit_orders SET symbol = 'GM' WHERE id = 246; @@ -399,9 +395,8 @@ ALTER TABLE renamed_orders RENAME TO limit_orders_750000; \c - - - :master_port -- commands with no constraints on the partition key are not supported UPDATE limit_orders SET limit_price = 0.00; -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "id". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run UPDATE command which targets multiple shards +HINT: Consider using an equality filter on partition column "id" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). -- attempting to change the partition key is unsupported UPDATE limit_orders SET id = 0 WHERE id = 246; ERROR: modifying the partition value of rows is not allowed @@ -499,9 +494,8 @@ UPDATE limit_orders SET placed_at = placed_at WHERE id = 246 RETURNING NOW(); ERROR: non-IMMUTABLE functions are not allowed in the RETURNING clause -- cursors are not supported UPDATE limit_orders SET symbol = 'GM' WHERE CURRENT OF cursor_name; -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "id". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run UPDATE command which targets multiple shards +HINT: Consider using an equality filter on partition column "id" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). -- check that multi-row UPDATE/DELETEs with RETURNING work INSERT INTO multiple_hash VALUES ('0', '1'); INSERT INTO multiple_hash VALUES ('0', '2'); diff --git a/src/test/regress/expected/multi_modifying_xacts.out b/src/test/regress/expected/multi_modifying_xacts.out index 8d934ce52..9c2a1bcc5 100644 --- a/src/test/regress/expected/multi_modifying_xacts.out +++ b/src/test/regress/expected/multi_modifying_xacts.out @@ -749,8 +749,7 @@ SELECT * FROM append_researchers WHERE id = 0; BEGIN; INSERT INTO append_researchers VALUES (1, 1, 'John McCarthy'); INSERT INTO append_researchers VALUES (500000, 500000, 'Tony Hoare'); -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. +ERROR: cannot run INSERT command which targets multiple shards HINT: Make sure the value for partition column "id" falls into a single shard. ROLLBACK; SELECT * FROM append_researchers; diff --git a/src/test/regress/expected/multi_mx_modifications.out b/src/test/regress/expected/multi_mx_modifications.out index f72f222f0..34a97a70e 100644 --- a/src/test/regress/expected/multi_mx_modifications.out +++ b/src/test/regress/expected/multi_mx_modifications.out @@ -165,9 +165,8 @@ SELECT COUNT(*) FROM limit_orders_mx WHERE id = 246; -- commands with no constraints on the partition key are not supported DELETE FROM limit_orders_mx WHERE bidder_id = 162; -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "id". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run DELETE command which targets multiple shards +HINT: Consider using an equality filter on partition column "id" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). -- commands with a USING clause are unsupported CREATE TABLE bidders ( name text, id bigint ); DELETE FROM limit_orders_mx USING bidders WHERE limit_orders_mx.id = 246 AND @@ -180,9 +179,8 @@ DELETE FROM limit_orders_mx; ERROR: common table expressions are not supported in distributed modifications -- cursors are not supported DELETE FROM limit_orders_mx WHERE CURRENT OF cursor_name; -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "id". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run DELETE command which targets multiple shards +HINT: Consider using an equality filter on partition column "id" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). INSERT INTO limit_orders_mx VALUES (246, 'TSLA', 162, '2007-07-02 16:32:15', 'sell', 20.69); -- simple UPDATE UPDATE limit_orders_mx SET symbol = 'GM' WHERE id = 246; @@ -237,9 +235,8 @@ DETAIL: Key (id)=(275) already exists. CONTEXT: while executing command on localhost:57638 -- commands with no constraints on the partition key are not supported UPDATE limit_orders_mx SET limit_price = 0.00; -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "id". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run UPDATE command which targets multiple shards +HINT: Consider using an equality filter on partition column "id" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). -- attempting to change the partition key is unsupported UPDATE limit_orders_mx SET id = 0 WHERE id = 246; ERROR: modifying the partition value of rows is not allowed @@ -332,9 +329,8 @@ UPDATE limit_orders_mx SET placed_at = placed_at WHERE id = 246 RETURNING NOW(); ERROR: non-IMMUTABLE functions are not allowed in the RETURNING clause -- cursors are not supported UPDATE limit_orders_mx SET symbol = 'GM' WHERE CURRENT OF cursor_name; -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "id". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run UPDATE command which targets multiple shards +HINT: Consider using an equality filter on partition column "id" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). -- check that multi-row UPDATE/DELETEs with RETURNING work INSERT INTO multiple_hash_mx VALUES ('0', '1'); INSERT INTO multiple_hash_mx VALUES ('0', '2'); diff --git a/src/test/regress/expected/multi_prepare_plsql.out b/src/test/regress/expected/multi_prepare_plsql.out index 837ab4c2d..8caf592cf 100644 --- a/src/test/regress/expected/multi_prepare_plsql.out +++ b/src/test/regress/expected/multi_prepare_plsql.out @@ -917,9 +917,8 @@ SELECT partition_parameter_update(5, 51); (1 row) SELECT partition_parameter_update(6, 61); -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "key". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run UPDATE command which targets multiple shards +HINT: Consider using an equality filter on partition column "key" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). CONTEXT: SQL statement "UPDATE plpgsql_table SET value = $2 WHERE key = $1" PL/pgSQL function partition_parameter_update(integer,integer) line 3 at SQL statement CREATE FUNCTION non_partition_parameter_update(int, int) RETURNS void as $$ @@ -1032,9 +1031,8 @@ SELECT partition_parameter_delete(5, 51); (1 row) SELECT partition_parameter_delete(6, 61); -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "key". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run DELETE command which targets multiple shards +HINT: Consider using an equality filter on partition column "key" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). CONTEXT: SQL statement "DELETE FROM plpgsql_table WHERE key = $1 AND value = $2" PL/pgSQL function partition_parameter_delete(integer,integer) line 3 at SQL statement CREATE FUNCTION non_partition_parameter_delete(int) RETURNS void as $$ diff --git a/src/test/regress/expected/multi_prepare_sql.out b/src/test/regress/expected/multi_prepare_sql.out index 8f7e7424d..5c5339d2e 100644 --- a/src/test/regress/expected/multi_prepare_sql.out +++ b/src/test/regress/expected/multi_prepare_sql.out @@ -776,9 +776,8 @@ EXECUTE prepared_partition_parameter_update(3, 31); EXECUTE prepared_partition_parameter_update(4, 41); EXECUTE prepared_partition_parameter_update(5, 51); EXECUTE prepared_partition_parameter_update(6, 61); -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "key". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run UPDATE command which targets multiple shards +HINT: Consider using an equality filter on partition column "key" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). PREPARE prepared_non_partition_parameter_update(int, int) AS UPDATE prepare_table SET value = $2 WHERE key = 0 AND value = $1; -- execute 6 times to trigger prepared statement usage @@ -827,9 +826,8 @@ EXECUTE prepared_partition_parameter_delete(3, 31); EXECUTE prepared_partition_parameter_delete(4, 41); EXECUTE prepared_partition_parameter_delete(5, 51); EXECUTE prepared_partition_parameter_delete(6, 61); -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "key". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run DELETE command which targets multiple shards +HINT: Consider using an equality filter on partition column "key" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). PREPARE prepared_non_partition_parameter_delete(int) AS DELETE FROM prepare_table WHERE key = 0 AND value = $1; -- execute 6 times to trigger prepared statement usage diff --git a/src/test/regress/expected/multi_simple_queries.out b/src/test/regress/expected/multi_simple_queries.out index 0c650f34c..0820a83bf 100644 --- a/src/test/regress/expected/multi_simple_queries.out +++ b/src/test/regress/expected/multi_simple_queries.out @@ -92,13 +92,11 @@ INSERT INTO articles VALUES (50, 10, 'anjanette', 19519); INSERT INTO articles_single_shard VALUES (50, 10, 'anjanette', 19519); -- zero-shard modifications should fail UPDATE articles SET title = '' WHERE author_id = 1 AND author_id = 2; -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies no shards. -HINT: Consider using an equality filter on partition column "author_id". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run UPDATE command which targets no shards +HINT: Consider using an equality filter on partition column "author_id" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). DELETE FROM articles WHERE author_id = 1 AND author_id = 2; -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies no shards. -HINT: Consider using an equality filter on partition column "author_id". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. +ERROR: cannot run DELETE command which targets no shards +HINT: Consider using an equality filter on partition column "author_id" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). -- single-shard tests -- test simple select for a single row SELECT * FROM articles WHERE author_id = 10 AND id = 50; diff --git a/src/test/regress/output/multi_master_delete_protocol.source b/src/test/regress/output/multi_master_delete_protocol.source index 7ccee403b..d46a6b429 100644 --- a/src/test/regress/output/multi_master_delete_protocol.source +++ b/src/test/regress/output/multi_master_delete_protocol.source @@ -30,9 +30,8 @@ ERROR: cannot delete from distributed table DETAIL: Where clause includes a column other than partition column -- Check that free-form deletes are not supported. DELETE FROM customer_delete_protocol WHERE c_custkey > 100; -ERROR: distributed modifications must target exactly one shard -DETAIL: This command modifies all shards. -HINT: Consider using an equality filter on partition column "c_custkey". You can use master_modify_multiple_shards() to perform multi-shard delete or update operations. You can also use master_apply_delete_command() to drop all shards satisfying delete criteria. +ERROR: cannot run DELETE command which targets multiple shards +HINT: Consider using an equality filter on partition column "c_custkey" to target a single shard. If you'd like to run a multi-shard operation, use master_modify_multiple_shards(). You can also use master_apply_delete_command() to drop all shards satisfying delete criteria. -- Check that we delete a shard if and only if all rows in the shard satisfy the condition. SELECT master_apply_delete_command('DELETE FROM customer_delete_protocol WHERE c_custkey > 6500');