@ -2,6 +2,43 @@
\getenv libdir PG_LIBDIR
\getenv dlsuffix PG_DLSUFFIX
\set regresslib :libdir '/regress' :dlsuffix
-- Function to assist with verifying EXPLAIN which includes costs. A series
-- of bool flags allows control over which portions are masked out
CREATE FUNCTION explain_mask_costs(query text, do_analyze bool,
hide_costs bool, hide_row_est bool, hide_width bool) RETURNS setof text
LANGUAGE plpgsql AS
$$
DECLARE
ln text;
analyze_str text;
BEGIN
IF do_analyze = true THEN
analyze_str := 'on';
ELSE
analyze_str := 'off';
END IF;
FOR ln IN
EXECUTE format('explain (analyze %s, costs on, summary off, timing off) %s',
analyze_str, query)
LOOP
IF hide_costs = true THEN
ln := regexp_replace(ln, 'cost=\d+\.\d\d\.\.\d+\.\d\d', 'cost=N..N');
END IF;
IF hide_row_est = true THEN
-- don't use 'g' so that we leave the actual rows intact
ln := regexp_replace(ln, 'rows=\d+', 'rows=N');
END IF;
IF hide_width = true THEN
ln := regexp_replace(ln, 'width=\d+', 'width=N');
END IF;
RETURN NEXT ln;
END LOOP;
END;
$$;
--
-- num_nulls()
--
@ -594,6 +631,78 @@ SELECT * FROM tenk1 a JOIN my_gen_series(1,10) g ON a.unique1 = g;
Index Cond: (unique1 = g.g)
(4 rows)
--
-- Test the SupportRequestRows support function for generate_series_timestamp()
--
-- Ensure the row estimate matches the actual rows
SELECT explain_mask_costs($$
SELECT * FROM generate_series(TIMESTAMPTZ '2024-02-01', TIMESTAMPTZ '2024-03-01', INTERVAL '1 day') g(s);$$,
true, true, false, true);
explain_mask_costs
------------------------------------------------------------------------------------------
Function Scan on generate_series g (cost=N..N rows=30 width=N) (actual rows=30 loops=1)
(1 row)
-- As above but with generate_series_timestamp
SELECT explain_mask_costs($$
SELECT * FROM generate_series(TIMESTAMP '2024-02-01', TIMESTAMP '2024-03-01', INTERVAL '1 day') g(s);$$,
true, true, false, true);
explain_mask_costs
------------------------------------------------------------------------------------------
Function Scan on generate_series g (cost=N..N rows=30 width=N) (actual rows=30 loops=1)
(1 row)
-- As above but with generate_series_timestamptz_at_zone()
SELECT explain_mask_costs($$
SELECT * FROM generate_series(TIMESTAMPTZ '2024-02-01', TIMESTAMPTZ '2024-03-01', INTERVAL '1 day', 'UTC') g(s);$$,
true, true, false, true);
explain_mask_costs
------------------------------------------------------------------------------------------
Function Scan on generate_series g (cost=N..N rows=30 width=N) (actual rows=30 loops=1)
(1 row)
-- Ensure the estimated and actual row counts match when the range isn't
-- evenly divisible by the step
SELECT explain_mask_costs($$
SELECT * FROM generate_series(TIMESTAMPTZ '2024-02-01', TIMESTAMPTZ '2024-03-01', INTERVAL '7 day') g(s);$$,
true, true, false, true);
explain_mask_costs
----------------------------------------------------------------------------------------
Function Scan on generate_series g (cost=N..N rows=5 width=N) (actual rows=5 loops=1)
(1 row)
-- Ensure the estimates match when step is decreasing
SELECT explain_mask_costs($$
SELECT * FROM generate_series(TIMESTAMPTZ '2024-03-01', TIMESTAMPTZ '2024-02-01', INTERVAL '-1 day') g(s);$$,
true, true, false, true);
explain_mask_costs
------------------------------------------------------------------------------------------
Function Scan on generate_series g (cost=N..N rows=30 width=N) (actual rows=30 loops=1)
(1 row)
-- Ensure an empty range estimates 1 row
SELECT explain_mask_costs($$
SELECT * FROM generate_series(TIMESTAMPTZ '2024-03-01', TIMESTAMPTZ '2024-02-01', INTERVAL '1 day') g(s);$$,
true, true, false, true);
explain_mask_costs
----------------------------------------------------------------------------------------
Function Scan on generate_series g (cost=N..N rows=1 width=N) (actual rows=0 loops=1)
(1 row)
-- Ensure we get the default row estimate for infinity values
SELECT explain_mask_costs($$
SELECT * FROM generate_series(TIMESTAMPTZ '-infinity', TIMESTAMPTZ 'infinity', INTERVAL '1 day') g(s);$$,
false, true, false, true);
explain_mask_costs
-------------------------------------------------------------------
Function Scan on generate_series g (cost=N..N rows=1000 width=N)
(1 row)
-- Ensure the row estimate behaves correctly when step size is zero.
-- We expect generate_series_timestamp() to throw the error rather than in
-- the support function.
SELECT * FROM generate_series(TIMESTAMPTZ '2024-02-01', TIMESTAMPTZ '2024-03-01', INTERVAL '0 day') g(s);
ERROR: step size cannot equal zero
-- Test functions for control data
SELECT count(*) > 0 AS ok FROM pg_control_checkpoint();
ok
@ -706,3 +815,4 @@ SELECT pg_column_toast_chunk_id(a) IS NULL,
(1 row)
DROP TABLE test_chunk_id;
DROP FUNCTION explain_mask_costs(text, bool, bool, bool, bool);