slope_corner_cases.sql
application/octet-stream
Filename: slope_corner_cases.sql
Type: application/octet-stream
Part: 0
--
-- Test numeric corner cases
--
CREATE TEMPORARY TABLE slope_numeric_corners (i serial, x float8);
INSERT INTO slope_numeric_corners (x)
SELECT x::float8 as x FROM
unnest(ARRAY['-inf', '-1', '0', '1', 'inf', 'nan']) x(x)
ORDER BY 1;
CREATE INDEX slope_numeric_corners_x_idx_nulllast ON slope_numeric_corners (x NULLS LAST);
CREATE INDEX slope_numeric_corners_x_idx_nullfirst ON slope_numeric_corners (x NULLS FIRST);
-- Find displaced values as the minimal set of values that need to be removed
-- from both arrays to make them equal.
-- Exponential time algorithm, acceptable for length 6 arrays.
CREATE OR REPLACE FUNCTION displaced_values(v1 int4[], v2 int4[]) RETURNS int4[]
AS $$
DECLARE
displaced int4[];
BEGIN
RETURN (WITH RECURSIVE
removal(a, b, removed) AS (
VALUES (v1, v2, '{}'::int4[])
UNION ALL
-- Try removing each candidate element from both arrays
SELECT
array_remove(r.a, c.e),
array_remove(r.b, c.e),
r.removed || c.e
FROM removal r
CROSS JOIN LATERAL (SELECT DISTINCT unnest(r.a || r.b) AS e) AS c
WHERE r.a <> r.b -- keep going until equal
AND c.e <> ALL(r.removed) -- don't re-remove same element
)
SELECT removed AS displaced
FROM removal
WHERE a = b
ORDER BY array_length(removed, 1) NULLS FIRST
LIMIT 1);
END;
$$ LANGUAGE plpgsql IMMUTABLE STRICT;
create temporary table slope_numeric_corners_results (
seq serial,
expr text COLLATE "C",
sort_order text COLLATE "C",
result text COLLATE "C",
expected text COLLATE "C",
nan_values text COLLATE "C",
plan1_json json,
plan2_json json
);
DO $$
DECLARE
r record;
result text;
expected text;
query text;
agg_query text;
plan_query text;
nan_query text;
nan_values text;
plan1_json json;
plan2_json json;
BEGIN
SET enable_bitmapscan = off;
SET enable_indexscan = off;
SET enable_indexonlyscan = off;
SET enable_seqscan = off;
SET enable_sort = off;
FOR r IN
SELECT replace(s, 'a', a) as expr, sort_order
FROM
unnest(ARRAY['ASC', 'DESC']) WITH ORDINALITY AS so(sort_order, so_i),
unnest(ARRAY[
'x+a', 'x-a', 'x*a', 'x/a',
'a+x', 'a-x', 'a*x', '-x'
]) WITH ORDINALITY AS s(s, s_i),
unnest(ARRAY['''inf''::float8', '''-inf''::float8', '1::float8']) WITH ORDINALITY AS a(a, a_i)
ORDER BY s_i, so_i
LOOP
query := 'SELECT *, ' || r.expr || ' as f FROM slope_numeric_corners ORDER BY f ' || r.sort_order;
nan_query := 'SELECT array_agg(i)::text FROM slope_numeric_corners
WHERE ' || r.expr || ' = ''nan''::float8 AND x != ''nan''::float8';
agg_query := 'SELECT array_agg(i)::text FROM (' || query || ') tmp';
plan_query := 'EXPLAIN (FORMAT JSON) ' || query;
-- slope optimization disabled
SET enable_seqscan = on;
SET enable_indexscan = off;
SET enable_sort = on;
EXECUTE agg_query into expected;
EXECUTE nan_query into nan_values;
EXECUTE plan_query into plan1_json;
-- slope optimization enabled
SET enable_seqscan = off;
SET enable_indexscan = on;
SET enable_sort = off;
EXECUTE agg_query into result;
EXECUTE plan_query into plan2_json;
INSERT INTO slope_numeric_corners_results
(expr, sort_order, result, expected, nan_values, plan1_json, plan2_json)
VALUES (r.expr, r.sort_order, result, expected, nan_values, plan1_json, plan2_json);
END LOOP;
END;
$$;
SELECT expr, sort_order as order, expected, result,
nan_values, displaced_values(result::int4[], expected::int4[]) as displaced
-- plan1_json->0->'Plan'->>'Node Type' as plan1,
-- plan2_json->0->'Plan'->>'Node Type' as plan2
FROM slope_numeric_corners_results
ORDER BY result != expected, seq;