@@ -11,6 +11,41 @@ RETURNS BOOL AS 'pg_pathman', 'validate_interval_value'
1111LANGUAGE C;
1212
1313ALTER TABLE @extschema@.pathman_config DROP COLUMN cooked_expr;
14+ /*
15+ * Dropped columns are never actually purged, entry in pg_attribute remains.
16+ * Since dealing with different number of attrs in C code is cumbersome,
17+ * let's recreate table instead.
18+ */
19+ CREATE TABLE @extschema@.pathman_config_tmp (LIKE @extschema@.pathman_config INCLUDING ALL);
20+ INSERT INTO @extschema@.pathman_config_tmp SELECT * FROM @extschema@.pathman_config;
21+ ALTER EVENT TRIGGER pathman_ddl_trigger DISABLE;
22+ DROP TABLE @extschema@.pathman_config;
23+ ALTER TABLE @extschema@.pathman_config_tmp RENAME TO pathman_config;
24+ ALTER EVENT TRIGGER pathman_ddl_trigger ENABLE;
25+
26+ /*
27+ * Get back stuff not preserved by CREATE TABLE LIKE: ACL, RLS and
28+ * pg_extension_config_dump mark.
29+ */
30+
31+ GRANT SELECT , INSERT, UPDATE , DELETE
32+ ON @extschema@.pathman_config
33+ TO public;
34+
35+ /*
36+ * Row security policy to restrict partitioning operations to owner and superusers only
37+ */
38+ CREATE POLICY deny_modification ON @extschema@.pathman_config
39+ FOR ALL USING (check_security_policy(partrel));
40+ CREATE POLICY allow_select ON @extschema@.pathman_config FOR SELECT USING (true);
41+ ALTER TABLE @extschema@.pathman_config ENABLE ROW LEVEL SECURITY;
42+
43+ /*
44+ * Enable dump of config tables with pg_dump.
45+ */
46+ SELECT pg_catalog .pg_extension_config_dump (' @extschema@.pathman_config' , ' ' );
47+
48+
1449ALTER TABLE @extschema@.pathman_config ADD CONSTRAINT pathman_config_interval_check
1550 CHECK (@extschema@.validate_interval_value(partrel,
1651 expr,
@@ -505,6 +540,100 @@ BEGIN
505540END
506541$$ LANGUAGE plpgsql;
507542
543+ /*
544+ * Replace hash partition with another one. It could be useful in case when
545+ * someone wants to attach foreign table as a partition.
546+ *
547+ * lock_parent - should we take an exclusive lock?
548+ */
549+ CREATE OR REPLACE FUNCTION @extschema@.replace_hash_partition(
550+ old_partition REGCLASS,
551+ new_partition REGCLASS,
552+ lock_parent BOOL DEFAULT TRUE)
553+ RETURNS REGCLASS AS $$
554+ DECLARE
555+ parent_relid REGCLASS;
556+ old_constr_name TEXT ; /* name of old_partition's constraint */
557+ old_constr_def TEXT ; /* definition of old_partition's constraint */
558+ rel_persistence CHAR ;
559+ p_init_callback REGPROCEDURE;
560+
561+ BEGIN
562+ PERFORM @extschema@.validate_relname(old_partition);
563+ PERFORM @extschema@.validate_relname(new_partition);
564+
565+ /* Parent relation */
566+ parent_relid := @extschema@.get_parent_of_partition(old_partition);
567+
568+ IF lock_parent THEN
569+ /* Acquire data modification lock (prevent further modifications) */
570+ PERFORM @extschema@.prevent_data_modification(parent_relid);
571+ ELSE
572+ /* Acquire lock on parent */
573+ PERFORM @extschema@.prevent_part_modification(parent_relid);
574+ END IF;
575+
576+ /* Acquire data modification lock (prevent further modifications) */
577+ PERFORM @extschema@.prevent_data_modification(old_partition);
578+ PERFORM @extschema@.prevent_data_modification(new_partition);
579+
580+ /* Ignore temporary tables */
581+ SELECT relpersistence FROM pg_catalog .pg_class
582+ WHERE oid = new_partition INTO rel_persistence;
583+
584+ IF rel_persistence = ' t' ::CHAR THEN
585+ RAISE EXCEPTION ' temporary table "%" cannot be used as a partition' ,
586+ new_partition::TEXT ;
587+ END IF;
588+
589+ /* Check that new partition has an equal structure as parent does */
590+ IF NOT @extschema@.is_tuple_convertible(parent_relid, new_partition) THEN
591+ RAISE EXCEPTION ' partition must have a compatible tuple format' ;
592+ END IF;
593+
594+ /* Check that table is partitioned */
595+ IF @extschema@.get_partition_key(parent_relid) IS NULL THEN
596+ RAISE EXCEPTION ' table "%" is not partitioned' , parent_relid::TEXT ;
597+ END IF;
598+
599+ /* Fetch name of old_partition's HASH constraint */
600+ old_constr_name = @extschema@.build_check_constraint_name(old_partition::REGCLASS);
601+
602+ /* Fetch definition of old_partition's HASH constraint */
603+ SELECT pg_catalog .pg_get_constraintdef (oid ) FROM pg_catalog .pg_constraint
604+ WHERE conrelid = old_partition AND quote_ident(conname) = old_constr_name
605+ INTO old_constr_def;
606+
607+ /* Detach old partition */
608+ EXECUTE format(' ALTER TABLE %s NO INHERIT %s' , old_partition, parent_relid);
609+ EXECUTE format(' ALTER TABLE %s DROP CONSTRAINT %s' ,
610+ old_partition,
611+ old_constr_name);
612+
613+ /* Attach the new one */
614+ EXECUTE format(' ALTER TABLE %s INHERIT %s' , new_partition, parent_relid);
615+ EXECUTE format(' ALTER TABLE %s ADD CONSTRAINT %s %s' ,
616+ new_partition,
617+ @extschema@.build_check_constraint_name(new_partition::REGCLASS),
618+ old_constr_def);
619+
620+ /* Fetch init_callback from 'params' table */
621+ WITH stub_callback(stub) as (values (0 ))
622+ SELECT init_callback
623+ FROM stub_callback
624+ LEFT JOIN @extschema@.pathman_config_params AS params
625+ ON params .partrel = parent_relid
626+ INTO p_init_callback;
627+
628+ /* Finally invoke init_callback */
629+ PERFORM @extschema@.invoke_on_partition_created_callback(parent_relid,
630+ new_partition,
631+ p_init_callback);
632+
633+ RETURN new_partition;
634+ END
635+ $$ LANGUAGE plpgsql;
636+
508637/*
509638 * Disable pathman partitioning for specified relation.
510639 */
0 commit comments