|
2 | 2 | \getenv libdir PG_LIBDIR
|
3 | 3 | \getenv dlsuffix PG_DLSUFFIX
|
4 | 4 | \set regresslib :libdir '/regress' :dlsuffix
|
| 5 | +-- Function to assist with verifying EXPLAIN which includes costs. A series |
| 6 | +-- of bool flags allows control over which portions are masked out |
| 7 | +CREATE FUNCTION explain_mask_costs(query text, do_analyze bool, |
| 8 | + hide_costs bool, hide_row_est bool, hide_width bool) RETURNS setof text |
| 9 | +LANGUAGE plpgsql AS |
| 10 | +$$ |
| 11 | +DECLARE |
| 12 | + ln text; |
| 13 | + analyze_str text; |
| 14 | +BEGIN |
| 15 | + IF do_analyze = true THEN |
| 16 | + analyze_str := 'on'; |
| 17 | + ELSE |
| 18 | + analyze_str := 'off'; |
| 19 | + END IF; |
| 20 | + |
| 21 | + FOR ln IN |
| 22 | + EXECUTE format('explain (analyze %s, costs on, summary off, timing off) %s', |
| 23 | + analyze_str, query) |
| 24 | + LOOP |
| 25 | + IF hide_costs = true THEN |
| 26 | + ln := regexp_replace(ln, 'cost=\d+\.\d\d\.\.\d+\.\d\d', 'cost=N..N'); |
| 27 | + END IF; |
| 28 | + |
| 29 | + IF hide_row_est = true THEN |
| 30 | + -- don't use 'g' so that we leave the actual rows intact |
| 31 | + ln := regexp_replace(ln, 'rows=\d+', 'rows=N'); |
| 32 | + END IF; |
| 33 | + |
| 34 | + IF hide_width = true THEN |
| 35 | + ln := regexp_replace(ln, 'width=\d+', 'width=N'); |
| 36 | + END IF; |
| 37 | + |
| 38 | + RETURN NEXT ln; |
| 39 | + END LOOP; |
| 40 | +END; |
| 41 | +$$; |
5 | 42 | --
|
6 | 43 | -- num_nulls()
|
7 | 44 | --
|
@@ -594,6 +631,78 @@ SELECT * FROM tenk1 a JOIN my_gen_series(1,10) g ON a.unique1 = g;
|
594 | 631 | Index Cond: (unique1 = g.g)
|
595 | 632 | (4 rows)
|
596 | 633 |
|
| 634 | +-- |
| 635 | +-- Test the SupportRequestRows support function for generate_series_timestamp() |
| 636 | +-- |
| 637 | +-- Ensure the row estimate matches the actual rows |
| 638 | +SELECT explain_mask_costs($$ |
| 639 | +SELECT * FROM generate_series(TIMESTAMPTZ '2024-02-01', TIMESTAMPTZ '2024-03-01', INTERVAL '1 day') g(s);$$, |
| 640 | +true, true, false, true); |
| 641 | + explain_mask_costs |
| 642 | +------------------------------------------------------------------------------------------ |
| 643 | + Function Scan on generate_series g (cost=N..N rows=30 width=N) (actual rows=30 loops=1) |
| 644 | +(1 row) |
| 645 | + |
| 646 | +-- As above but with generate_series_timestamp |
| 647 | +SELECT explain_mask_costs($$ |
| 648 | +SELECT * FROM generate_series(TIMESTAMP '2024-02-01', TIMESTAMP '2024-03-01', INTERVAL '1 day') g(s);$$, |
| 649 | +true, true, false, true); |
| 650 | + explain_mask_costs |
| 651 | +------------------------------------------------------------------------------------------ |
| 652 | + Function Scan on generate_series g (cost=N..N rows=30 width=N) (actual rows=30 loops=1) |
| 653 | +(1 row) |
| 654 | + |
| 655 | +-- As above but with generate_series_timestamptz_at_zone() |
| 656 | +SELECT explain_mask_costs($$ |
| 657 | +SELECT * FROM generate_series(TIMESTAMPTZ '2024-02-01', TIMESTAMPTZ '2024-03-01', INTERVAL '1 day', 'UTC') g(s);$$, |
| 658 | +true, true, false, true); |
| 659 | + explain_mask_costs |
| 660 | +------------------------------------------------------------------------------------------ |
| 661 | + Function Scan on generate_series g (cost=N..N rows=30 width=N) (actual rows=30 loops=1) |
| 662 | +(1 row) |
| 663 | + |
| 664 | +-- Ensure the estimated and actual row counts match when the range isn't |
| 665 | +-- evenly divisible by the step |
| 666 | +SELECT explain_mask_costs($$ |
| 667 | +SELECT * FROM generate_series(TIMESTAMPTZ '2024-02-01', TIMESTAMPTZ '2024-03-01', INTERVAL '7 day') g(s);$$, |
| 668 | +true, true, false, true); |
| 669 | + explain_mask_costs |
| 670 | +---------------------------------------------------------------------------------------- |
| 671 | + Function Scan on generate_series g (cost=N..N rows=5 width=N) (actual rows=5 loops=1) |
| 672 | +(1 row) |
| 673 | + |
| 674 | +-- Ensure the estimates match when step is decreasing |
| 675 | +SELECT explain_mask_costs($$ |
| 676 | +SELECT * FROM generate_series(TIMESTAMPTZ '2024-03-01', TIMESTAMPTZ '2024-02-01', INTERVAL '-1 day') g(s);$$, |
| 677 | +true, true, false, true); |
| 678 | + explain_mask_costs |
| 679 | +------------------------------------------------------------------------------------------ |
| 680 | + Function Scan on generate_series g (cost=N..N rows=30 width=N) (actual rows=30 loops=1) |
| 681 | +(1 row) |
| 682 | + |
| 683 | +-- Ensure an empty range estimates 1 row |
| 684 | +SELECT explain_mask_costs($$ |
| 685 | +SELECT * FROM generate_series(TIMESTAMPTZ '2024-03-01', TIMESTAMPTZ '2024-02-01', INTERVAL '1 day') g(s);$$, |
| 686 | +true, true, false, true); |
| 687 | + explain_mask_costs |
| 688 | +---------------------------------------------------------------------------------------- |
| 689 | + Function Scan on generate_series g (cost=N..N rows=1 width=N) (actual rows=0 loops=1) |
| 690 | +(1 row) |
| 691 | + |
| 692 | +-- Ensure we get the default row estimate for infinity values |
| 693 | +SELECT explain_mask_costs($$ |
| 694 | +SELECT * FROM generate_series(TIMESTAMPTZ '-infinity', TIMESTAMPTZ 'infinity', INTERVAL '1 day') g(s);$$, |
| 695 | +false, true, false, true); |
| 696 | + explain_mask_costs |
| 697 | +------------------------------------------------------------------- |
| 698 | + Function Scan on generate_series g (cost=N..N rows=1000 width=N) |
| 699 | +(1 row) |
| 700 | + |
| 701 | +-- Ensure the row estimate behaves correctly when step size is zero. |
| 702 | +-- We expect generate_series_timestamp() to throw the error rather than in |
| 703 | +-- the support function. |
| 704 | +SELECT * FROM generate_series(TIMESTAMPTZ '2024-02-01', TIMESTAMPTZ '2024-03-01', INTERVAL '0 day') g(s); |
| 705 | +ERROR: step size cannot equal zero |
597 | 706 | -- Test functions for control data
|
598 | 707 | SELECT count(*) > 0 AS ok FROM pg_control_checkpoint();
|
599 | 708 | ok
|
@@ -706,3 +815,4 @@ SELECT pg_column_toast_chunk_id(a) IS NULL,
|
706 | 815 | (1 row)
|
707 | 816 |
|
708 | 817 | DROP TABLE test_chunk_id;
|
| 818 | +DROP FUNCTION explain_mask_costs(text, bool, bool, bool, bool); |
0 commit comments