Feature A: GiST index for equatorial type with KNN ordering (<-> strategy 15). 24-byte float-precision spherical bounding box, RA-wrapping aware merge/split, Vincenty lower-bound distance for correct KNN pruning. Apollo-hardened with epsilon-widened bounds, circular-aware picksplit, compile-time size assertions. Feature B: 4 new DE moon equatorial functions (galilean_equatorial_de, saturn_moon_equatorial_de, uranus_moon_equatorial_de, mars_moon_equatorial_de). Same-provider rule enforced, transparent VSOP87 fallback. 120 -> 132 SQL objects. 22 regression suites passing.
162 lines
6.3 KiB
SQL
162 lines
6.3 KiB
SQL
-- Test equatorial GiST index: KNN ordering, RA wrapping, cone search
|
|
CREATE EXTENSION IF NOT EXISTS pg_orrery;
|
|
|
|
-- ============================================================
|
|
-- Test table: known sky positions
|
|
-- ============================================================
|
|
CREATE TABLE sky_test (
|
|
id serial,
|
|
name text,
|
|
eq equatorial
|
|
);
|
|
|
|
-- Planets and Sun at a fixed epoch
|
|
INSERT INTO sky_test (name, eq) VALUES
|
|
('Jupiter', planet_equatorial_apparent(5, '2024-06-15 12:00:00+00')),
|
|
('Saturn', planet_equatorial_apparent(6, '2024-06-15 12:00:00+00')),
|
|
('Mars', planet_equatorial_apparent(4, '2024-06-15 12:00:00+00')),
|
|
('Venus', planet_equatorial_apparent(2, '2024-06-15 12:00:00+00')),
|
|
('Mercury', planet_equatorial_apparent(1, '2024-06-15 12:00:00+00')),
|
|
('Sun', sun_equatorial('2024-06-15 12:00:00+00')),
|
|
('Moon', moon_equatorial('2024-06-15 12:00:00+00'));
|
|
|
|
-- Bright stars at well-known positions
|
|
INSERT INTO sky_test (name, eq) VALUES
|
|
('Polaris', star_equatorial(2.530, 89.264, '2024-06-15 12:00:00+00')),
|
|
('Sirius', star_equatorial(6.752, -16.716, '2024-06-15 12:00:00+00')),
|
|
('Vega', star_equatorial(18.616, 38.784, '2024-06-15 12:00:00+00')),
|
|
('Canopus', star_equatorial(6.399, -52.696, '2024-06-15 12:00:00+00')),
|
|
('Arcturus', star_equatorial(14.261, 19.182, '2024-06-15 12:00:00+00'));
|
|
|
|
-- RA-wrapping test: objects near 0h and 23.9h
|
|
INSERT INTO sky_test (name, eq) VALUES
|
|
('NearZeroH', '(0.10000000,15.00000000,0.000)'::equatorial),
|
|
('Near24H', '(23.90000000,15.00000000,0.000)'::equatorial);
|
|
|
|
-- ============================================================
|
|
-- Test 1: Create GiST index
|
|
-- ============================================================
|
|
CREATE INDEX idx_sky_gist ON sky_test USING gist (eq);
|
|
|
|
-- ============================================================
|
|
-- Test 2: KNN correctness -- seqscan vs index scan
|
|
-- Query: 5 nearest to Jupiter
|
|
-- ============================================================
|
|
-- First get seqscan ordering
|
|
SET enable_indexscan = off;
|
|
SET enable_bitmapscan = off;
|
|
SELECT 'knn_seq' AS test, name,
|
|
round((eq <-> planet_equatorial_apparent(5, '2024-06-15 12:00:00+00'))::numeric, 4) AS dist
|
|
FROM sky_test
|
|
WHERE name != 'Jupiter'
|
|
ORDER BY eq <-> planet_equatorial_apparent(5, '2024-06-15 12:00:00+00')
|
|
LIMIT 5;
|
|
RESET enable_indexscan;
|
|
RESET enable_bitmapscan;
|
|
|
|
-- Now force index scan
|
|
SET enable_seqscan = off;
|
|
SELECT 'knn_idx' AS test, name,
|
|
round((eq <-> planet_equatorial_apparent(5, '2024-06-15 12:00:00+00'))::numeric, 4) AS dist
|
|
FROM sky_test
|
|
WHERE name != 'Jupiter'
|
|
ORDER BY eq <-> planet_equatorial_apparent(5, '2024-06-15 12:00:00+00')
|
|
LIMIT 5;
|
|
RESET enable_seqscan;
|
|
|
|
-- ============================================================
|
|
-- Test 3: KNN near Polaris (high declination)
|
|
-- ============================================================
|
|
SET enable_seqscan = off;
|
|
SELECT 'knn_polaris' AS test, name,
|
|
round((eq <-> star_equatorial(2.530, 89.264, '2024-06-15 12:00:00+00'))::numeric, 2) AS dist
|
|
FROM sky_test
|
|
ORDER BY eq <-> star_equatorial(2.530, 89.264, '2024-06-15 12:00:00+00')
|
|
LIMIT 3;
|
|
RESET enable_seqscan;
|
|
|
|
-- ============================================================
|
|
-- Test 4: RA wrapping -- NearZeroH and Near24H should be neighbors
|
|
-- (They are only 0.2h * 15 deg/h * cos(15) ~ 2.9 deg apart)
|
|
-- ============================================================
|
|
SET enable_seqscan = off;
|
|
SELECT 'ra_wrap' AS test, name,
|
|
round((eq <-> '(0.10000000,15.00000000,0.000)'::equatorial)::numeric, 2) AS dist
|
|
FROM sky_test
|
|
ORDER BY eq <-> '(0.10000000,15.00000000,0.000)'::equatorial
|
|
LIMIT 3;
|
|
RESET enable_seqscan;
|
|
|
|
-- ============================================================
|
|
-- Test 5: Cone search -- everything within 15 degrees of Vega
|
|
-- ============================================================
|
|
SET enable_seqscan = off;
|
|
SELECT 'cone_vega' AS test, name,
|
|
round((eq <-> star_equatorial(18.616, 38.784, '2024-06-15 12:00:00+00'))::numeric, 2) AS dist
|
|
FROM sky_test
|
|
WHERE eq_within_cone(eq, star_equatorial(18.616, 38.784, '2024-06-15 12:00:00+00'), 15.0)
|
|
ORDER BY eq <-> star_equatorial(18.616, 38.784, '2024-06-15 12:00:00+00');
|
|
RESET enable_seqscan;
|
|
|
|
-- ============================================================
|
|
-- Test 6: EXPLAIN shows Index Scan
|
|
-- ============================================================
|
|
SET enable_seqscan = off;
|
|
EXPLAIN (COSTS OFF)
|
|
SELECT name FROM sky_test
|
|
ORDER BY eq <-> '(12.00000000,0.00000000,0.000)'::equatorial
|
|
LIMIT 3;
|
|
RESET enable_seqscan;
|
|
|
|
-- ============================================================
|
|
-- Test 7: Empty table doesn't crash
|
|
-- ============================================================
|
|
CREATE TABLE sky_empty (eq equatorial);
|
|
CREATE INDEX idx_sky_empty ON sky_empty USING gist (eq);
|
|
SELECT 'empty_knn' AS test, count(*) AS n
|
|
FROM (
|
|
SELECT eq FROM sky_empty
|
|
ORDER BY eq <-> '(12.00000000,0.00000000,0.000)'::equatorial
|
|
) sub;
|
|
DROP TABLE sky_empty;
|
|
|
|
-- ============================================================
|
|
-- Test 8: Single row
|
|
-- ============================================================
|
|
CREATE TABLE sky_single (eq equatorial);
|
|
INSERT INTO sky_single VALUES ('(6.00000000,30.00000000,1000.000)'::equatorial);
|
|
CREATE INDEX idx_sky_single ON sky_single USING gist (eq);
|
|
SET enable_seqscan = off;
|
|
SELECT 'single_knn' AS test,
|
|
round((eq <-> '(12.00000000,0.00000000,0.000)'::equatorial)::numeric, 2) AS dist
|
|
FROM sky_single
|
|
ORDER BY eq <-> '(12.00000000,0.00000000,0.000)'::equatorial
|
|
LIMIT 1;
|
|
RESET enable_seqscan;
|
|
DROP TABLE sky_single;
|
|
|
|
-- ============================================================
|
|
-- Test 9: Larger batch -- verify no crashes on tree rebalancing
|
|
-- ============================================================
|
|
CREATE TABLE sky_batch (eq equatorial);
|
|
INSERT INTO sky_batch
|
|
SELECT planet_equatorial_apparent(
|
|
(i % 7) + 1 + (CASE WHEN (i % 7) + 1 >= 3 THEN 1 ELSE 0 END),
|
|
'2024-01-01 00:00:00+00'::timestamptz + (i || ' hours')::interval
|
|
)
|
|
FROM generate_series(1, 100) AS i;
|
|
CREATE INDEX idx_sky_batch ON sky_batch USING gist (eq);
|
|
SET enable_seqscan = off;
|
|
SELECT 'batch_knn' AS test, count(*) AS n
|
|
FROM (
|
|
SELECT eq
|
|
FROM sky_batch
|
|
ORDER BY eq <-> '(12.00000000,0.00000000,0.000)'::equatorial
|
|
LIMIT 10
|
|
) sub;
|
|
RESET enable_seqscan;
|
|
DROP TABLE sky_batch;
|
|
|
|
-- Cleanup
|
|
DROP TABLE sky_test;
|