@@ -810,12 +810,13 @@ $$ LANGUAGE sql;
810
810
811
811
-- Execute command at all shardman nodes.
812
812
-- 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 $$
814
815
DECLARE
815
816
node_id integer ;
816
817
cmds text = ' ' ;
817
818
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 ))
819
820
THEN
820
821
RETURN;
821
822
END IF;
@@ -825,6 +826,13 @@ BEGIN
825
826
LOOP
826
827
cmds := format(' %s%s:%s;' , cmds, node_id, sql);
827
828
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
+
828
836
PERFORM shardman .broadcast (cmds, two_phase => use_2pc);
829
837
END
830
838
$$ LANGUAGE plpgsql;
@@ -915,9 +923,6 @@ DECLARE
915
923
rel_name text = rel::text ;
916
924
fdw_name text = format(' %s_fdw' , rel_name);
917
925
srv_name text = format(' node_%s' , master_node_id);
918
- pk text ;
919
- dst text ;
920
- src text ;
921
926
new_master bool;
922
927
BEGIN
923
928
-- Check if valid node ID is passed and get connection string for this node
@@ -926,37 +931,17 @@ BEGIN
926
931
RAISE EXCEPTION ' There is no node with ID % in the cluster' , master_node_id;
927
932
END IF;
928
933
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);
946
936
947
- -- Generate SQL statement creating this table
937
+ -- Generate SQL statement creating this table
948
938
SELECT shardman .gen_create_table_sql (rel_name) INTO create_table;
949
939
950
940
-- Construct table attributes for create foreign table
951
941
SELECT shardman .reconstruct_table_attrs (rel) INTO table_attrs;
952
942
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;
960
945
961
946
-- Create table at all nodes
962
947
FOR node IN SELECT * FROM shardman .nodes
@@ -1445,11 +1430,78 @@ END
1445
1430
$$ LANGUAGE plpgsql;
1446
1431
1447
1432
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;
1448
1466
1449
1467
-- -------------------------------------------------------------------
1450
1468
-- Utility functions
1451
1469
-- -------------------------------------------------------------------
1452
1470
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
+
1453
1505
-- Check if resource exists at remote node
1454
1506
CREATE FUNCTION not_exists (node_id int , what text ) RETURNS bool AS $$
1455
1507
DECLARE
0 commit comments