Skip to content

Commit fb072af

Browse files
matweyhackorum
authored andcommitted
Add initial support for spgist quadtree @<(point,circle) operator
Signed-off-by: Matwey V. Kornilov <matwey.kornilov@gmail.com>
1 parent e5a29d9 commit fb072af

4 files changed

Lines changed: 197 additions & 7 deletions

File tree

src/backend/access/spgist/spgquadtreeproc.c

Lines changed: 66 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,44 @@ spg_quad_inner_consistent_box_helper(ScanKey sk, Point *centroid)
144144
return r;
145145
}
146146

147+
static int
148+
spg_quad_inner_consistent_circle_helper(ScanKey sk, Point *centroid)
149+
{
150+
/*
151+
* Evaluate distances between the query center point and the quadrants.
152+
* The distance between a set and a point is the minimal possible distance
153+
* between any set point and the point. There are three possible cases: the
154+
* point belongs to the quandrand, the point projection is on the quadrant
155+
* edge, the point projections is on the quadrant vertex.
156+
*/
157+
CIRCLE *circleQuery = DatumGetCircleP(sk->sk_argument);
158+
int r = 0;
159+
160+
const Point cp = {
161+
.x = float8_mi(centroid->x, circleQuery->center.x),
162+
.y = float8_mi(centroid->y, circleQuery->center.y)
163+
};
164+
165+
const float8 x_p0 = (0. > cp.x ? 0. : cp.x);
166+
const float8 y_p0 = (0. > cp.y ? 0. : cp.y);
167+
const float8 x_n0 = (0. < cp.x ? 0. : cp.x);
168+
const float8 y_n0 = (0. < cp.y ? 0. : cp.y);
169+
170+
const float8 d[4] = {
171+
HYPOT(x_p0, y_p0),
172+
HYPOT(x_p0, y_n0),
173+
HYPOT(x_n0, y_n0),
174+
HYPOT(x_n0, y_p0)
175+
};
176+
177+
for (int i = 0; i < 4; i++) {
178+
if (d[i] <= circleQuery->radius)
179+
r |= (1 << (i + 1));
180+
}
181+
182+
return r;
183+
}
184+
147185
Datum
148186
spg_quad_choose(PG_FUNCTION_ARGS)
149187
{
@@ -359,7 +397,18 @@ spg_quad_inner_consistent(PG_FUNCTION_ARGS)
359397
which &= (1 << 1) | (1 << 4);
360398
break;
361399
case RTContainedByStrategyNumber:
362-
which &= spg_quad_inner_consistent_box_helper(sk, centroid);
400+
401+
switch (sk->sk_subtype) {
402+
case BOXOID:
403+
which &= spg_quad_inner_consistent_box_helper(sk, centroid);
404+
break;
405+
case CIRCLEOID:
406+
which &= spg_quad_inner_consistent_circle_helper(sk, centroid);
407+
break;
408+
default:
409+
elog(ERROR, "unrecognized right type OID: %d", sk->sk_subtype);
410+
break;
411+
}
363412
break;
364413
default:
365414
elog(ERROR, "unrecognized strategy number: %d", sk->sk_strategy);
@@ -448,12 +497,22 @@ spg_quad_leaf_consistent(PG_FUNCTION_ARGS)
448497
break;
449498
case RTContainedByStrategyNumber:
450499

451-
/*
452-
* For this operator, the query is a box not a point. We
453-
* cheat to the extent of assuming that DatumGetPointP won't
454-
* do anything that would be bad for a pointer-to-box.
455-
*/
456-
res = SPTEST(box_contain_pt, query, datum);
500+
switch (sk->sk_subtype) {
501+
case BOXOID:
502+
/*
503+
* For this operator, the query is a box not a point. We
504+
* cheat to the extent of assuming that DatumGetPointP won't
505+
* do anything that would be bad for a pointer-to-box.
506+
*/
507+
res = SPTEST(box_contain_pt, query, datum);
508+
break;
509+
case CIRCLEOID:
510+
res = SPTEST(circle_contain_pt, query, datum);
511+
break;
512+
default:
513+
elog(ERROR, "unrecognized right type OID: %d", sk->sk_subtype);
514+
break;
515+
}
457516
break;
458517
default:
459518
elog(ERROR, "unrecognized strategy number: %d", sk->sk_strategy);

src/include/catalog/pg_amop.dat

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1524,6 +1524,9 @@
15241524
{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point',
15251525
amoprighttype => 'box', amopstrategy => '8', amopopr => '<@(point,box)',
15261526
amopmethod => 'spgist' },
1527+
{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point',
1528+
amoprighttype => 'circle', amopstrategy => '8', amopopr => '<@(point,circle)',
1529+
amopmethod => 'spgist' },
15271530
{ amopfamily => 'spgist/quad_point_ops', amoplefttype => 'point',
15281531
amoprighttype => 'point', amopstrategy => '15', amoppurpose => 'o',
15291532
amopopr => '<->(point,point)', amopmethod => 'spgist',

src/test/regress/expected/create_index_spgist.out

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,102 @@ SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
5050
1057
5151
(1 row)
5252

53+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,399),1.41>';
54+
count
55+
-------
56+
0
57+
(1 row)
58+
59+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,399),1.42>';
60+
count
61+
-------
62+
1000
63+
(1 row)
64+
65+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,401),1.41>';
66+
count
67+
-------
68+
0
69+
(1 row)
70+
71+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,401),1.42>';
72+
count
73+
-------
74+
1000
75+
(1 row)
76+
77+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,399),1.41>';
78+
count
79+
-------
80+
0
81+
(1 row)
82+
83+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,399),1.42>';
84+
count
85+
-------
86+
1000
87+
(1 row)
88+
89+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,401),1.41>';
90+
count
91+
-------
92+
0
93+
(1 row)
94+
95+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,401),1.42>';
96+
count
97+
-------
98+
1000
99+
(1 row)
100+
101+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(333,399),0.99>';
102+
count
103+
-------
104+
0
105+
(1 row)
106+
107+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(333,399),1.01>';
108+
count
109+
-------
110+
1000
111+
(1 row)
112+
113+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(333,401),0.99>';
114+
count
115+
-------
116+
0
117+
(1 row)
118+
119+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(333,401),1.01>';
120+
count
121+
-------
122+
1000
123+
(1 row)
124+
125+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,400),0.99>';
126+
count
127+
-------
128+
0
129+
(1 row)
130+
131+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,400),1.01>';
132+
count
133+
-------
134+
1000
135+
(1 row)
136+
137+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,400),0.99>';
138+
count
139+
-------
140+
0
141+
(1 row)
142+
143+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,400),1.01>';
144+
count
145+
-------
146+
1000
147+
(1 row)
148+
53149
SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
54150
count
55151
-------

src/test/regress/sql/create_index_spgist.sql

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,38 @@ SELECT count(*) FROM quad_point_tbl WHERE p <@ box '(200,200,1000,1000)';
4242

4343
SELECT count(*) FROM quad_point_tbl WHERE box '(200,200,1000,1000)' @> p;
4444

45+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,399),1.41>';
46+
47+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,399),1.42>';
48+
49+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,401),1.41>';
50+
51+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,401),1.42>';
52+
53+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,399),1.41>';
54+
55+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,399),1.42>';
56+
57+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,401),1.41>';
58+
59+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,401),1.42>';
60+
61+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(333,399),0.99>';
62+
63+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(333,399),1.01>';
64+
65+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(333,401),0.99>';
66+
67+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(333,401),1.01>';
68+
69+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,400),0.99>';
70+
71+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(332,400),1.01>';
72+
73+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,400),0.99>';
74+
75+
SELECT count(*) FROM quad_point_tbl WHERE p <@ circle '<(334,400),1.01>';
76+
4577
SELECT count(*) FROM quad_point_tbl WHERE p << '(5000, 4000)';
4678

4779
SELECT count(*) FROM quad_point_tbl WHERE p >> '(5000, 4000)';

0 commit comments

Comments
 (0)