Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 8db5be4

Browse files
committed
Add alter_table function
1 parent 1782042 commit 8db5be4

File tree

2 files changed

+87
-34
lines changed

2 files changed

+87
-34
lines changed

pg_shardman--1.0.sql

Lines changed: 82 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -810,12 +810,13 @@ $$ LANGUAGE sql;
810810

811811
-- Execute command at all shardman nodes.
812812
-- It can be used to perform DDL at all nodes.
813-
CREATE FUNCTION forall(sql text, use_2pc bool = false) returns void AS $$
813+
CREATE FUNCTION forall(sql text, use_2pc bool = false, including_shardlord bool = false)
814+
returns void AS $$
814815
DECLARE
815816
node_id integer;
816817
cmds text = '';
817818
BEGIN
818-
IF shardman.redirect_to_shardlord(format('forall(%L, %L)', sql, use_2pc))
819+
IF shardman.redirect_to_shardlord(format('forall(%L, %L, %L)', sql, use_2pc, including_shardlord))
819820
THEN
820821
RETURN;
821822
END IF;
@@ -825,6 +826,13 @@ BEGIN
825826
LOOP
826827
cmds := format('%s%s:%s;', cmds, node_id, sql);
827828
END LOOP;
829+
830+
-- Execute command also at shardlord
831+
IF including_shardlord
832+
THEN
833+
cmds := format('%s0:%s;', cmds, sql);
834+
END IF;
835+
828836
PERFORM shardman.broadcast(cmds, two_phase => use_2pc);
829837
END
830838
$$ LANGUAGE plpgsql;
@@ -915,9 +923,6 @@ DECLARE
915923
rel_name text = rel::text;
916924
fdw_name text = format('%s_fdw', rel_name);
917925
srv_name text = format('node_%s', master_node_id);
918-
pk text;
919-
dst text;
920-
src text;
921926
new_master bool;
922927
BEGIN
923928
-- Check if valid node ID is passed and get connection string for this node
@@ -926,37 +931,17 @@ BEGIN
926931
RAISE EXCEPTION 'There is no node with ID % in the cluster', master_node_id;
927932
END IF;
928933

929-
-- Construct list of attributes of the table for update/insert
930-
SELECT INTO dst, src
931-
string_agg(quote_ident(attname), ', '),
932-
string_agg('NEW.' || quote_ident(attname), ', ')
933-
FROM pg_attribute
934-
WHERE attrelid = rel
935-
AND NOT attisdropped -- no dropped (dead) columns
936-
AND attnum > 0;
937-
938-
-- Construct primary key condition for update
939-
SELECT INTO pk
940-
string_agg(quote_ident(a.attname) || '=OLD.'|| quote_ident(a.attname), ' AND ')
941-
FROM pg_index i
942-
JOIN pg_attribute a ON a.attrelid = i.indrelid
943-
AND a.attnum = ANY(i.indkey)
944-
WHERE i.indrelid = rel
945-
AND i.indisprimary;
934+
-- Get information about relation attributes and primary keys needed to construct CREATE TABLE statement and
935+
PERFORM shardman.get_relation_metadata(rel, dst, src, pk);
946936

947-
-- Generate SQL statement creating this table
937+
-- Generate SQL statement creating this table
948938
SELECT shardman.gen_create_table_sql(rel_name) INTO create_table;
949939

950940
-- Construct table attributes for create foreign table
951941
SELECT shardman.reconstruct_table_attrs(rel) INTO table_attrs;
952942

953-
-- Create rules for redirecting updates
954-
create_rules := format('CREATE RULE on_update AS ON UPDATE TO %I DO INSTEAD UPDATE %I SET (%s) = (%s) WHERE %s;
955-
CREATE RULE on_insert AS ON INSERT TO %I DO INSTEAD INSERT INTO %I (%s) VALUES (%s);
956-
CREATE RULE on_delete AS ON DELETE TO %I DO INSTEAD DELETE FROM %I WHERE %s;',
957-
rel_name, fdw_name, dst, src, pk,
958-
rel_name, fdw_name, dst, src,
959-
rel_name, fdw_name, pk);
943+
-- Generatate SQL statements creating instead rules for updates
944+
SELECT shardman.gen_create_rules_sql(rel_name) INTO create_rules;
960945

961946
-- Create table at all nodes
962947
FOR node IN SELECT * FROM shardman.nodes
@@ -1445,11 +1430,78 @@ END
14451430
$$ LANGUAGE plpgsql;
14461431

14471432

1433+
-- Alter table at sharload and all nodes
1434+
CREATE FUNCTION alter_table(rel regclass, alter_clause text) RETURNS void AS $$
1435+
DECLARE
1436+
rel_name text = rel::text;
1437+
t shardman.tables;
1438+
repl shardman.replicas;
1439+
create_table text;
1440+
create_rules text;
1441+
alters text = '';
1442+
BEGIN
1443+
IF shardman.redirect_to_shardlord(format('alter_table(%L,%L)', rel_name, alter_clause))
1444+
THEN
1445+
RETURN;
1446+
END IF;
1447+
1448+
PERFORM shardman.forall(format('ALTER TABLE %I %s', rel_name, alter_clause), including_shardlord=>true);
1449+
1450+
SELECT * INTO t FROM shardman.tables WHERE relation=rel_name;
1451+
SELECT shardman.gen_create_table_sql(t.relation) INTO create_table;
1452+
IF t.master_node IS NOT NULL
1453+
THEN
1454+
SELECT shardman.gen_create_rules_sql(t.relation, format('%s_fdw', t.relation)) INTO create_rules;
1455+
END IF;
1456+
UPDATE shardman.tables SET create_sql=create_table, create_rules_sql=create_rules WHERE relation=t.relation;
1457+
1458+
FOR repl IN SELECT * FROM shardman.replicas
1459+
LOOP
1460+
alters := format('%s%s:ALTER TABLE %I %s;',
1461+
alters, repl.node_id, repl.part_name, alter_clause);
1462+
END LOOP;
1463+
PERFORM shardman.broadcast(alters);
1464+
END
1465+
$$ LANGUAGE plpgsql;
14481466

14491467
---------------------------------------------------------------------
14501468
-- Utility functions
14511469
---------------------------------------------------------------------
14521470

1471+
-- Generate rules for redirecting updates for shared table
1472+
CREATE FUNCTION gen_create_rules_sql(rel_name text, fdw_name text) RETURNS text AS $$
1473+
DECLARE
1474+
pk text;
1475+
dst text;
1476+
src text;
1477+
BEGIN
1478+
-- Construct list of attributes of the table for update/insert
1479+
SELECT INTO dst, src
1480+
string_agg(quote_ident(attname), ', '),
1481+
string_agg('NEW.' || quote_ident(attname), ', ')
1482+
FROM pg_attribute
1483+
WHERE attrelid = rel_name::regclass
1484+
AND NOT attisdropped -- no dropped (dead) columns
1485+
AND attnum > 0;
1486+
1487+
-- Construct primary key condition for update
1488+
SELECT INTO pk
1489+
string_agg(quote_ident(a.attname) || '=OLD.'|| quote_ident(a.attname), ' AND ')
1490+
FROM pg_index i
1491+
JOIN pg_attribute a ON a.attrelid = i.indrelid
1492+
AND a.attnum = ANY(i.indkey)
1493+
WHERE i.indrelid = rel_name::regclass
1494+
AND i.indisprimary;
1495+
1496+
RETURN format('CREATE RULE on_update AS ON UPDATE TO %I DO INSTEAD UPDATE %I SET (%s) = (%s) WHERE %s;
1497+
CREATE RULE on_insert AS ON INSERT TO %I DO INSTEAD INSERT INTO %I (%s) VALUES (%s);
1498+
CREATE RULE on_delete AS ON DELETE TO %I DO INSTEAD DELETE FROM %I WHERE %s;',
1499+
rel_name, fdw_name, dst, src, pk,
1500+
rel_name, fdw_name, dst, src,
1501+
rel_name, fdw_name, pk);
1502+
END
1503+
$$ LANGUAGE plpgsql;
1504+
14531505
-- Check if resource exists at remote node
14541506
CREATE FUNCTION not_exists(node_id int, what text) RETURNS bool AS $$
14551507
DECLARE

readme.md

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -235,10 +235,11 @@ have some limitations which doesn't allow to build efficient execution plans for
235235
some queries.
236236

237237
Shardlord commands called on workers are implicitly redirected to shardlord, but
238-
it is highly recommended to perform them directly at shardlord. DDL commands can
239-
be broadcasted to all cluster nodes using `shardman.forall(cmd text)` function,
240-
but right now shardman doesn't support altering of existing tables schema. You
241-
can, however, try to create indexes. It must be done per each partition
238+
it is highly recommended to perform them directly at shardlord. It is possible to
239+
broadcast command to all cluster nodes using `shardman.forall(cmd text, use_2pc bool = false, including_shardlord bool = false)` function.
240+
But if you are going to alter sharded or shared table, you should use
241+
`shardman.forall(rel regclass, alter_clause text)` function.
242+
You can also create new indexes. It must be done per each partition
242243
separately, see
243244
[pathman docs](https://github.com/postgrespro/pg_pathman/wiki/How-do-I-create-indexes)
244245

0 commit comments

Comments
 (0)