@@ -1459,7 +1459,6 @@ END
14591459$$;
14601460
14611461
1462-
14631462CREATE
OR REPLACE FUNCTION @
[email protected] _maintenance(
14641463 p_parent_table text DEFAULT NULL
14651464 -- If these defaults change reflect them in `run_maintenance_proc`!
@@ -1478,6 +1477,7 @@ ex_message text;
14781477v_adv_lock boolean ;
14791478v_analyze boolean := FALSE;
14801479v_check_subpart int ;
1480+ v_child_timestamp timestamptz ;
14811481v_control_type text ;
14821482v_create_count int := 0 ;
14831483v_current_partition_id bigint ;
@@ -1495,7 +1495,6 @@ v_last_partition_timestamp timestamptz;
14951495v_max_id bigint ;
14961496v_max_id_default bigint ;
14971497v_max_time_default timestamptz ;
1498- v_max_timestamp timestamptz ;
14991498v_new_search_path text ;
15001499v_next_partition_id bigint ;
15011500v_next_partition_timestamp timestamptz ;
@@ -1681,31 +1680,31 @@ LOOP
16811680 -- Must be reset to null otherwise if the next partition set in the loop is empty, the previous partition set's value could be used
16821681 v_current_partition_timestamp := NULL ;
16831682
1684- -- Loop through child tables starting from highest to get current max value in partition set
1683+ -- Loop through child tables starting from highest to get a timestamp from the highest non-empty partition in the set
16851684 -- Avoids doing a scan on entire partition set and/or getting any values accidentally in default.
16861685 FOR v_row_max_time IN
16871686 SELECT partition_schemaname, partition_tablename
FROM @
[email protected] _partitions(
v_row .
parent_table ,
' DESC' , false)
16881687 LOOP
1689- EXECUTE format(' SELECT max(%s) ::text FROM %I.%I'
1688+ EXECUTE format(' SELECT %s ::text FROM %I.%I LIMIT 1 '
16901689 , v_partition_expression
16911690 , v_row_max_time .partition_schemaname
16921691 , v_row_max_time .partition_tablename
1693- ) INTO v_max_timestamp ;
1692+ ) INTO v_child_timestamp ;
16941693
1695- IF v_row .infinite_time_partitions AND v_max_timestamp < CURRENT_TIMESTAMP THEN
1694+ IF v_row .infinite_time_partitions AND v_child_timestamp < CURRENT_TIMESTAMP THEN
16961695 -- No new data has been inserted relative to "now", but keep making child tables anyway
16971696 v_current_partition_timestamp = CURRENT_TIMESTAMP ;
16981697 -- Nothing else to do in this case so just end early
16991698 EXIT;
17001699 END IF;
1701- IF v_max_timestamp IS NOT NULL THEN
1702- SELECT suffix_timestamp INTO v_current_partition_timestamp
FROM @
[email protected] _partition_name(
v_row .
parent_table ,
v_max_timestamp ::
text );
1700+ IF v_child_timestamp IS NOT NULL THEN
1701+ SELECT suffix_timestamp INTO v_current_partition_timestamp
FROM @
[email protected] _partition_name(
v_row .
parent_table ,
v_child_timestamp ::
text );
17031702 EXIT;
17041703 END IF;
17051704 END LOOP;
1706- IF v_row .infinite_time_partitions AND v_max_timestamp IS NULL THEN
1705+ IF v_row .infinite_time_partitions AND v_child_timestamp IS NULL THEN
17071706 -- If partition set is completely empty, still keep making child tables anyway
1708- -- Has to be separate check outside above loop since "future" tables are likely going to be empty and make max value in that loop NULL
1707+ -- Has to be separate check outside above loop since "future" tables are likely going to be empty, hence ignored in that loop
17091708 v_current_partition_timestamp = CURRENT_TIMESTAMP ;
17101709 END IF;
17111710
@@ -1725,7 +1724,7 @@ LOOP
17251724 UPDATE @
[email protected] _config
SET maintenance_last_run
= clock_timestamp()
WHERE parent_table
= v_row .
parent_table ;
17261725 CONTINUE;
17271726 END IF;
1728- RAISE DEBUG ' run_maint: v_max_timestamp : %, v_current_partition_timestamp: %, v_max_time_default: %' , v_max_timestamp , v_current_partition_timestamp, v_max_time_default;
1727+ RAISE DEBUG ' run_maint: v_child_timestamp : %, v_current_partition_timestamp: %, v_max_time_default: %' , v_child_timestamp , v_current_partition_timestamp, v_max_time_default;
17291728 IF v_current_partition_timestamp IS NULL OR (v_max_time_default > v_current_partition_timestamp) THEN
17301729 SELECT suffix_timestamp INTO v_current_partition_timestamp
FROM @
[email protected] _partition_name(
v_row .
parent_table , v_max_time_default::
text );
17311730 END IF;
@@ -1915,3 +1914,49 @@ DETAIL: %
19151914HINT: %' , ex_message, ex_context, ex_detail, ex_hint;
19161915END
19171916$$;
1917+
1918+
1919+ CREATE
OR REPLACE FUNCTION @
[email protected] _name_length (
1920+ p_object_name text
1921+ , p_suffix text DEFAULT NULL
1922+ , p_table_partition boolean DEFAULT FALSE
1923+ )
1924+ RETURNS text
1925+ LANGUAGE plpgsql IMMUTABLE
1926+ SET search_path TO pg_catalog, pg_temp
1927+ AS $$
1928+ DECLARE
1929+ v_new_name text ;
1930+ v_suffix text ;
1931+ BEGIN
1932+ /*
1933+ * Truncate the name of the given object if it is greater than the postgres default max (63 bytes).
1934+ * Also appends given suffix and schema if given and truncates the name so that the entire suffix will fit.
1935+ * Returns original name (with suffix if given) if it doesn't require truncation
1936+ */
1937+
1938+ IF p_table_partition IS TRUE AND (NULLIF(p_suffix, ' ' ) IS NULL ) THEN
1939+ RAISE EXCEPTION ' Table partition name requires a suffix value' ;
1940+ END IF;
1941+
1942+
1943+ v_suffix := format(' %s%s' , CASE WHEN p_table_partition THEN ' _p' END, p_suffix);
1944+ -- Use optimistic behavior: in almost all cases `v_new_name` will be less than allowed maximum.
1945+ -- Do "heavy" work only in rare cases.
1946+ v_new_name := p_object_name || v_suffix;
1947+
1948+ -- Postgres' relation name limit is in bytes, not characters; also it can be compiled with bigger allowed length.
1949+ -- Use its internals to detect where to cut new object name.
1950+ IF v_new_name::name != v_new_name THEN
1951+ -- Here we need to detect how many chars (not bytes) we need to get from the `p_object_name`.
1952+ -- Use suffix as prefix and get the rest of `p_object_name`.
1953+ v_new_name := (v_suffix || p_object_name)::name;
1954+ -- `substr` starts from 1, that is why we need to add 1 below.
1955+ -- Edge case: `v_suffix` is empty, length is 0, but need to start from 1.
1956+ v_new_name := substr(v_new_name, length(v_suffix) + 1 ) || v_suffix;
1957+ END IF;
1958+
1959+ RETURN v_new_name;
1960+
1961+ END
1962+ $$;
0 commit comments