00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include "postgres.h"
00017
00018 #include "access/gist.h"
00019 #include "access/spgist.h"
00020 #include "catalog/pg_type.h"
00021 #include "utils/builtins.h"
00022 #include "utils/geo_decls.h"
00023
00024
00025 Datum
00026 spg_quad_config(PG_FUNCTION_ARGS)
00027 {
00028
00029 spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1);
00030
00031 cfg->prefixType = POINTOID;
00032 cfg->labelType = VOIDOID;
00033 cfg->canReturnData = true;
00034 cfg->longValuesOK = false;
00035 PG_RETURN_VOID();
00036 }
00037
00038 #define SPTEST(f, x, y) \
00039 DatumGetBool(DirectFunctionCall2(f, PointPGetDatum(x), PointPGetDatum(y)))
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053 static int16
00054 getQuadrant(Point *centroid, Point *tst)
00055 {
00056 if ((SPTEST(point_above, tst, centroid) ||
00057 SPTEST(point_horiz, tst, centroid)) &&
00058 (SPTEST(point_right, tst, centroid) ||
00059 SPTEST(point_vert, tst, centroid)))
00060 return 1;
00061
00062 if (SPTEST(point_below, tst, centroid) &&
00063 (SPTEST(point_right, tst, centroid) ||
00064 SPTEST(point_vert, tst, centroid)))
00065 return 2;
00066
00067 if ((SPTEST(point_below, tst, centroid) ||
00068 SPTEST(point_horiz, tst, centroid)) &&
00069 SPTEST(point_left, tst, centroid))
00070 return 3;
00071
00072 if (SPTEST(point_above, tst, centroid) &&
00073 SPTEST(point_left, tst, centroid))
00074 return 4;
00075
00076 elog(ERROR, "getQuadrant: impossible case");
00077 return 0;
00078 }
00079
00080
00081 Datum
00082 spg_quad_choose(PG_FUNCTION_ARGS)
00083 {
00084 spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
00085 spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
00086 Point *inPoint = DatumGetPointP(in->datum),
00087 *centroid;
00088
00089 if (in->allTheSame)
00090 {
00091 out->resultType = spgMatchNode;
00092
00093 out->result.matchNode.levelAdd = 0;
00094 out->result.matchNode.restDatum = PointPGetDatum(inPoint);
00095 PG_RETURN_VOID();
00096 }
00097
00098 Assert(in->hasPrefix);
00099 centroid = DatumGetPointP(in->prefixDatum);
00100
00101 Assert(in->nNodes == 4);
00102
00103 out->resultType = spgMatchNode;
00104 out->result.matchNode.nodeN = getQuadrant(centroid, inPoint) - 1;
00105 out->result.matchNode.levelAdd = 0;
00106 out->result.matchNode.restDatum = PointPGetDatum(inPoint);
00107
00108 PG_RETURN_VOID();
00109 }
00110
00111 #ifdef USE_MEDIAN
00112 static int
00113 x_cmp(const void *a, const void *b, void *arg)
00114 {
00115 Point *pa = *(Point **) a;
00116 Point *pb = *(Point **) b;
00117
00118 if (pa->x == pb->x)
00119 return 0;
00120 return (pa->x > pb->x) ? 1 : -1;
00121 }
00122
00123 static int
00124 y_cmp(const void *a, const void *b, void *arg)
00125 {
00126 Point *pa = *(Point **) a;
00127 Point *pb = *(Point **) b;
00128
00129 if (pa->y == pb->y)
00130 return 0;
00131 return (pa->y > pb->y) ? 1 : -1;
00132 }
00133 #endif
00134
00135 Datum
00136 spg_quad_picksplit(PG_FUNCTION_ARGS)
00137 {
00138 spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
00139 spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
00140 int i;
00141 Point *centroid;
00142
00143 #ifdef USE_MEDIAN
00144
00145 Point **sorted;
00146
00147 sorted = palloc(sizeof(*sorted) * in->nTuples);
00148 for (i = 0; i < in->nTuples; i++)
00149 sorted[i] = DatumGetPointP(in->datums[i]);
00150
00151 centroid = palloc(sizeof(*centroid));
00152
00153 qsort(sorted, in->nTuples, sizeof(*sorted), x_cmp);
00154 centroid->x = sorted[in->nTuples >> 1]->x;
00155 qsort(sorted, in->nTuples, sizeof(*sorted), y_cmp);
00156 centroid->y = sorted[in->nTuples >> 1]->y;
00157 #else
00158
00159 centroid = palloc0(sizeof(*centroid));
00160
00161 for (i = 0; i < in->nTuples; i++)
00162 {
00163 centroid->x += DatumGetPointP(in->datums[i])->x;
00164 centroid->y += DatumGetPointP(in->datums[i])->y;
00165 }
00166
00167 centroid->x /= in->nTuples;
00168 centroid->y /= in->nTuples;
00169 #endif
00170
00171 out->hasPrefix = true;
00172 out->prefixDatum = PointPGetDatum(centroid);
00173
00174 out->nNodes = 4;
00175 out->nodeLabels = NULL;
00176
00177 out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples);
00178 out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples);
00179
00180 for (i = 0; i < in->nTuples; i++)
00181 {
00182 Point *p = DatumGetPointP(in->datums[i]);
00183 int quadrant = getQuadrant(centroid, p) - 1;
00184
00185 out->leafTupleDatums[i] = PointPGetDatum(p);
00186 out->mapTuplesToNodes[i] = quadrant;
00187 }
00188
00189 PG_RETURN_VOID();
00190 }
00191
00192
00193 Datum
00194 spg_quad_inner_consistent(PG_FUNCTION_ARGS)
00195 {
00196 spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
00197 spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
00198 Point *centroid;
00199 int which;
00200 int i;
00201
00202 Assert(in->hasPrefix);
00203 centroid = DatumGetPointP(in->prefixDatum);
00204
00205 if (in->allTheSame)
00206 {
00207
00208 out->nNodes = in->nNodes;
00209 out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
00210 for (i = 0; i < in->nNodes; i++)
00211 out->nodeNumbers[i] = i;
00212 PG_RETURN_VOID();
00213 }
00214
00215 Assert(in->nNodes == 4);
00216
00217
00218 which = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);
00219
00220 for (i = 0; i < in->nkeys; i++)
00221 {
00222 Point *query = DatumGetPointP(in->scankeys[i].sk_argument);
00223 BOX *boxQuery;
00224
00225 switch (in->scankeys[i].sk_strategy)
00226 {
00227 case RTLeftStrategyNumber:
00228 if (SPTEST(point_right, centroid, query))
00229 which &= (1 << 3) | (1 << 4);
00230 break;
00231 case RTRightStrategyNumber:
00232 if (SPTEST(point_left, centroid, query))
00233 which &= (1 << 1) | (1 << 2);
00234 break;
00235 case RTSameStrategyNumber:
00236 which &= (1 << getQuadrant(centroid, query));
00237 break;
00238 case RTBelowStrategyNumber:
00239 if (SPTEST(point_above, centroid, query))
00240 which &= (1 << 2) | (1 << 3);
00241 break;
00242 case RTAboveStrategyNumber:
00243 if (SPTEST(point_below, centroid, query))
00244 which &= (1 << 1) | (1 << 4);
00245 break;
00246 case RTContainedByStrategyNumber:
00247
00248
00249
00250
00251
00252
00253 boxQuery = DatumGetBoxP(in->scankeys[i].sk_argument);
00254
00255 if (DatumGetBool(DirectFunctionCall2(box_contain_pt,
00256 PointerGetDatum(boxQuery),
00257 PointerGetDatum(centroid))))
00258 {
00259
00260 }
00261 else
00262 {
00263
00264 Point p;
00265 int r = 0;
00266
00267 p = boxQuery->low;
00268 r |= 1 << getQuadrant(centroid, &p);
00269 p.y = boxQuery->high.y;
00270 r |= 1 << getQuadrant(centroid, &p);
00271 p = boxQuery->high;
00272 r |= 1 << getQuadrant(centroid, &p);
00273 p.x = boxQuery->low.x;
00274 r |= 1 << getQuadrant(centroid, &p);
00275
00276 which &= r;
00277 }
00278 break;
00279 default:
00280 elog(ERROR, "unrecognized strategy number: %d",
00281 in->scankeys[i].sk_strategy);
00282 break;
00283 }
00284
00285 if (which == 0)
00286 break;
00287 }
00288
00289
00290 out->nodeNumbers = (int *) palloc(sizeof(int) * 4);
00291 out->nNodes = 0;
00292 for (i = 1; i <= 4; i++)
00293 {
00294 if (which & (1 << i))
00295 out->nodeNumbers[out->nNodes++] = i - 1;
00296 }
00297
00298 PG_RETURN_VOID();
00299 }
00300
00301
00302 Datum
00303 spg_quad_leaf_consistent(PG_FUNCTION_ARGS)
00304 {
00305 spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0);
00306 spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1);
00307 Point *datum = DatumGetPointP(in->leafDatum);
00308 bool res;
00309 int i;
00310
00311
00312 out->recheck = false;
00313
00314
00315 out->leafValue = in->leafDatum;
00316
00317
00318 res = true;
00319 for (i = 0; i < in->nkeys; i++)
00320 {
00321 Point *query = DatumGetPointP(in->scankeys[i].sk_argument);
00322
00323 switch (in->scankeys[i].sk_strategy)
00324 {
00325 case RTLeftStrategyNumber:
00326 res = SPTEST(point_left, datum, query);
00327 break;
00328 case RTRightStrategyNumber:
00329 res = SPTEST(point_right, datum, query);
00330 break;
00331 case RTSameStrategyNumber:
00332 res = SPTEST(point_eq, datum, query);
00333 break;
00334 case RTBelowStrategyNumber:
00335 res = SPTEST(point_below, datum, query);
00336 break;
00337 case RTAboveStrategyNumber:
00338 res = SPTEST(point_above, datum, query);
00339 break;
00340 case RTContainedByStrategyNumber:
00341
00342
00343
00344
00345
00346
00347 res = SPTEST(box_contain_pt, query, datum);
00348 break;
00349 default:
00350 elog(ERROR, "unrecognized strategy number: %d",
00351 in->scankeys[i].sk_strategy);
00352 break;
00353 }
00354
00355 if (!res)
00356 break;
00357 }
00358
00359 PG_RETURN_BOOL(res);
00360 }