@@ -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_tmpSELECT * 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_modificationON @extschema@.pathman_config
39+ FOR ALL USING (check_security_policy(partrel));
40+ CREATE POLICY allow_selectON @extschema@.pathman_config FORSELECT 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 ADDCONSTRAINT pathman_config_interval_check
1550CHECK (@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+ CREATEOR REPLACE FUNCTION @extschema@.replace_hash_partition(
550+ old_partitionREGCLASS,
551+ new_partitionREGCLASS,
552+ lock_parentBOOL DEFAULT TRUE)
553+ RETURNS REGCLASSAS $$
554+ DECLARE
555+ parent_relidREGCLASS;
556+ old_constr_nameTEXT ;/* name of old_partition's constraint*/
557+ old_constr_defTEXT ;/* definition of old_partition's constraint*/
558+ rel_persistenceCHAR ;
559+ p_init_callbackREGPROCEDURE;
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 relpersistenceFROM 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) ISNULL 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_partitionAND 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_paramsAS 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*/