Skip to content

Commit

Permalink
Block multi-statement DDL command in one query
Browse files Browse the repository at this point in the history
Ensure that queries involving several distributed DDL commands
in one query string are blocked.

Fix #4818
  • Loading branch information
pmwkaa authored and SachinSetiya committed Nov 16, 2022
1 parent c151778 commit 7fdac95
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 12 deletions.
18 changes: 18 additions & 0 deletions tsl/src/remote/dist_ddl.c
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,21 @@ dist_ddl_error_if_not_allowed_data_node_session(void)
dist_ddl_error_raise_blocked();
}

static void
dist_ddl_error_if_multi_command(const ProcessUtilityArgs *args)
{
List *parsetree_list;

/* Parse the SQL string into a list of raw parse trees */
parsetree_list = pg_parse_query(args->query_string);

/* Prevent 'command;command' execution */
if (list_length(parsetree_list) != 1)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("nested commands are not supported on distributed hypertable")));
}

static void
dist_ddl_state_add_remote_command(const char *cmd)
{
Expand Down Expand Up @@ -314,6 +329,9 @@ dist_ddl_state_set_hypertable(const ProcessUtilityArgs *args)
if (num_hypertables > 1)
dist_ddl_error_raise_unsupported();

/* Prevent execution of several commands in one query string */
dist_ddl_error_if_multi_command(args);

/* Get the distributed hypertable */
ht =
ts_hypertable_cache_get_entry(hcache, linitial_oid(args->hypertable_list), CACHE_FLAG_NONE);
Expand Down
49 changes: 37 additions & 12 deletions tsl/test/expected/dist_ddl.out
Original file line number Diff line number Diff line change
Expand Up @@ -2539,6 +2539,31 @@ INSERT INTO hyper SELECT t, ceil((random() * 5))::int, random() * 80
FROM generate_series('2019-01-01'::timestamptz, '2019-01-05'::timestamptz, '1 minute') as t;
ANALYZE hyper;
--
-- Ensure single query multi-statement command is blocked
--
-- Issue #4818
--
CREATE TABLE disttable(time timestamptz NOT NULL, device int);
SELECT * FROM create_distributed_hypertable('disttable', 'time', 'device');
hypertable_id | schema_name | table_name | created
---------------+-------------+------------+---------
21 | public | disttable | t
(1 row)

CREATE OR REPLACE PROCEDURE test_dist_multi_stmt_command()
LANGUAGE plpgsql AS $$
BEGIN
EXECUTE 'ANALYZE disttable; ANALYZE disttable';
END
$$;
SET timescaledb.hide_data_node_name_in_errors = 'on';
-- unsupported
\set ON_ERROR_STOP 0
CALL test_dist_multi_stmt_command();
ERROR: nested commands are not supported on distributed hypertable
\set ON_ERROR_STOP 1
DROP TABLE disttable;
--
-- Test hypertable distributed defaults
--
SHOW timescaledb.hypertable_distributed_default;
Expand All @@ -2563,7 +2588,7 @@ ERROR: local hypertables cannot set replication_factor
SELECT create_hypertable('drf_test', 'time', distributed=>true, replication_factor=>1);
create_hypertable
------------------------
(21,public,drf_test,t)
(22,public,drf_test,t)
(1 row)

SELECT is_distributed, replication_factor FROM timescaledb_information.hypertables WHERE hypertable_name = 'drf_test';
Expand All @@ -2581,7 +2606,7 @@ CREATE TABLE drf_test(time TIMESTAMPTZ NOT NULL);
SELECT create_hypertable('drf_test', 'time', distributed=>false);
create_hypertable
------------------------
(22,public,drf_test,t)
(23,public,drf_test,t)
(1 row)

SELECT is_distributed, replication_factor FROM timescaledb_information.hypertables WHERE hypertable_name = 'drf_test';
Expand All @@ -2596,7 +2621,7 @@ CREATE TABLE drf_test(time TIMESTAMPTZ NOT NULL);
SELECT create_hypertable('drf_test', 'time', distributed=>true);
create_hypertable
------------------------
(23,public,drf_test,t)
(24,public,drf_test,t)
(1 row)

SELECT is_distributed, replication_factor FROM timescaledb_information.hypertables WHERE hypertable_name = 'drf_test';
Expand All @@ -2613,7 +2638,7 @@ CREATE TABLE drf_test(time TIMESTAMPTZ NOT NULL);
SELECT create_hypertable('drf_test', 'time', distributed=>false);
create_hypertable
------------------------
(24,public,drf_test,t)
(25,public,drf_test,t)
(1 row)

SELECT is_distributed, replication_factor FROM timescaledb_information.hypertables WHERE hypertable_name = 'drf_test';
Expand All @@ -2628,7 +2653,7 @@ CREATE TABLE drf_test(time TIMESTAMPTZ NOT NULL);
SELECT create_hypertable('drf_test', 'time', distributed=>true);
create_hypertable
------------------------
(25,public,drf_test,t)
(26,public,drf_test,t)
(1 row)

SELECT is_distributed, replication_factor FROM timescaledb_information.hypertables WHERE hypertable_name = 'drf_test';
Expand All @@ -2652,7 +2677,7 @@ CREATE TABLE drf_test(time TIMESTAMPTZ NOT NULL);
SELECT create_hypertable('drf_test', 'time', distributed=>true);
create_hypertable
------------------------
(26,public,drf_test,t)
(27,public,drf_test,t)
(1 row)

SELECT is_distributed, replication_factor FROM timescaledb_information.hypertables WHERE hypertable_name = 'drf_test';
Expand All @@ -2670,7 +2695,7 @@ CREATE TABLE drf_test(time TIMESTAMPTZ NOT NULL);
SELECT create_hypertable('drf_test', 'time', replication_factor=>2);
create_hypertable
------------------------
(27,public,drf_test,t)
(28,public,drf_test,t)
(1 row)

SELECT is_distributed, replication_factor FROM timescaledb_information.hypertables WHERE hypertable_name = 'drf_test';
Expand All @@ -2687,7 +2712,7 @@ CREATE TABLE drf_test(time TIMESTAMPTZ NOT NULL);
SELECT create_hypertable('drf_test', 'time', replication_factor=>2);
create_hypertable
------------------------
(28,public,drf_test,t)
(29,public,drf_test,t)
(1 row)

SELECT is_distributed, replication_factor FROM timescaledb_information.hypertables WHERE hypertable_name = 'drf_test';
Expand Down Expand Up @@ -2721,7 +2746,7 @@ CREATE TABLE drf_test(time TIMESTAMPTZ NOT NULL);
SELECT create_hypertable('drf_test', 'time');
create_hypertable
------------------------
(29,public,drf_test,t)
(30,public,drf_test,t)
(1 row)

SELECT is_distributed, replication_factor FROM timescaledb_information.hypertables WHERE hypertable_name = 'drf_test';
Expand All @@ -2738,7 +2763,7 @@ CREATE TABLE drf_test(time TIMESTAMPTZ NOT NULL);
SELECT create_hypertable('drf_test', 'time');
create_hypertable
------------------------
(30,public,drf_test,t)
(31,public,drf_test,t)
(1 row)

SELECT is_distributed, replication_factor FROM timescaledb_information.hypertables WHERE hypertable_name = 'drf_test';
Expand All @@ -2756,7 +2781,7 @@ CREATE TABLE drf_test(time TIMESTAMPTZ NOT NULL);
SELECT create_hypertable('drf_test', 'time');
create_hypertable
------------------------
(31,public,drf_test,t)
(32,public,drf_test,t)
(1 row)

DROP TABLE drf_test;
Expand All @@ -2768,7 +2793,7 @@ CREATE TABLE drf_test(time TIMESTAMPTZ NOT NULL);
SELECT create_distributed_hypertable('drf_test', 'time');
create_distributed_hypertable
-------------------------------
(32,public,drf_test,t)
(33,public,drf_test,t)
(1 row)

SELECT is_distributed, replication_factor FROM timescaledb_information.hypertables WHERE hypertable_name = 'drf_test';
Expand Down
23 changes: 23 additions & 0 deletions tsl/test/sql/dist_ddl.sql
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,29 @@ INSERT INTO hyper SELECT t, ceil((random() * 5))::int, random() * 80
FROM generate_series('2019-01-01'::timestamptz, '2019-01-05'::timestamptz, '1 minute') as t;
ANALYZE hyper;

--
-- Ensure single query multi-statement command is blocked
--
-- Issue #4818
--
CREATE TABLE disttable(time timestamptz NOT NULL, device int);
SELECT * FROM create_distributed_hypertable('disttable', 'time', 'device');

CREATE OR REPLACE PROCEDURE test_dist_multi_stmt_command()
LANGUAGE plpgsql AS $$
BEGIN
EXECUTE 'ANALYZE disttable; ANALYZE disttable';
END
$$;

SET timescaledb.hide_data_node_name_in_errors = 'on';

-- unsupported
\set ON_ERROR_STOP 0
CALL test_dist_multi_stmt_command();
\set ON_ERROR_STOP 1

DROP TABLE disttable;
--
-- Test hypertable distributed defaults
--
Expand Down

0 comments on commit 7fdac95

Please sign in to comment.