Datum spg_quad_choose(PG_FUNCTION_ARGS) { spgChooseIn *in = (spgChooseIn*)PG_GETARG_POINTER(0); spgChooseOut *out = (spgChooseOut*)PG_GETARG_POINTER(1); Point *inPoint = DatumGetPointP(in->datum), *centroid; Point *d; Assert(in->hasPrefix); centroid = DatumGetPointP(in->prefixDatum); Assert(in->nNodes == 4); d = palloc(sizeof(*d)); *d = *inPoint; out->resultType = spgMatchNode; out->result.matchNode.nodeN = getQuadrant(centroid, inPoint) - 1; out->result.matchNode.levelAdd = 0; out->result.matchNode.restDatum = PointPGetDatum(d); PG_RETURN_VOID(); }
Datum spg_quad_choose(PG_FUNCTION_ARGS) { spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0); spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1); Point *inPoint = DatumGetPointP(in->datum), *centroid; if (in->allTheSame) { out->resultType = spgMatchNode; /* nodeN will be set by core */ out->result.matchNode.levelAdd = 0; out->result.matchNode.restDatum = PointPGetDatum(inPoint); PG_RETURN_VOID(); } Assert(in->hasPrefix); centroid = DatumGetPointP(in->prefixDatum); Assert(in->nNodes == 4); out->resultType = spgMatchNode; out->result.matchNode.nodeN = getQuadrant(centroid, inPoint) - 1; out->result.matchNode.levelAdd = 0; out->result.matchNode.restDatum = PointPGetDatum(inPoint); PG_RETURN_VOID(); }
Datum spg_quad_picksplit(PG_FUNCTION_ARGS) { spgPickSplitIn *in = (spgPickSplitIn*)PG_GETARG_POINTER(0); spgPickSplitOut *out = (spgPickSplitOut*)PG_GETARG_POINTER(1); int i; Point *centroid; int nQuadrants[] = {0, 0, 0, 0}; centroid = palloc(sizeof(*centroid)); for(i=0; i<in->nTuples; i++) { Point *p = DatumGetPointP(in->datums[i]); if (i==0) { *centroid = *p; } else { centroid->x += p->x; centroid->y += p->y; } } centroid->x /= (double)in->nTuples; centroid->y /= (double)in->nTuples; out->hasPrefix = true; out->prefixDatum = PointPGetDatum(centroid); out->nNodes = 4; out->nodeDatums = palloc(sizeof(Datum) * 4); for(i=0; i<4; i++) out->nodeDatums[i] = Int16GetDatum((int2)i); out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples); out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples); for(i=0; i<in->nTuples; i++) { Point *p = DatumGetPointP(in->datums[i]), *op; int2 quadrant = getQuadrant(centroid, p) - 1; op = palloc(sizeof(*op)); *op = *p; out->leafTupleDatums[ i ] = PointPGetDatum(op); out->mapTuplesToNodes[ i ] = quadrant; nQuadrants[quadrant]++; } for(i=0; i<4; i++) { if (nQuadrants[i] == in->nTuples) elog(ERROR, "Could not support some strange corner cases, will fix in future"); } PG_RETURN_VOID(); }
Datum spg_quad_picksplit(PG_FUNCTION_ARGS) { spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0); spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1); int i; Point *centroid; #ifdef USE_MEDIAN /* Use the median values of x and y as the centroid point */ Point **sorted; sorted = palloc(sizeof(*sorted) * in->nTuples); for (i = 0; i < in->nTuples; i++) sorted[i] = DatumGetPointP(in->datums[i]); centroid = palloc(sizeof(*centroid)); qsort(sorted, in->nTuples, sizeof(*sorted), x_cmp); centroid->x = sorted[in->nTuples >> 1]->x; qsort(sorted, in->nTuples, sizeof(*sorted), y_cmp); centroid->y = sorted[in->nTuples >> 1]->y; #else /* Use the average values of x and y as the centroid point */ centroid = palloc0(sizeof(*centroid)); for (i = 0; i < in->nTuples; i++) { centroid->x += DatumGetPointP(in->datums[i])->x; centroid->y += DatumGetPointP(in->datums[i])->y; } centroid->x /= in->nTuples; centroid->y /= in->nTuples; #endif out->hasPrefix = true; out->prefixDatum = PointPGetDatum(centroid); out->nNodes = 4; out->nodeLabels = NULL; /* we don't need node labels */ out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples); out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples); for (i = 0; i < in->nTuples; i++) { Point *p = DatumGetPointP(in->datums[i]); int quadrant = getQuadrant(centroid, p) - 1; out->leafTupleDatums[i] = PointPGetDatum(p); out->mapTuplesToNodes[i] = quadrant; } PG_RETURN_VOID(); }
Datum spg_quad_leaf_consistent(PG_FUNCTION_ARGS) { spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0); spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1); Point *query = DatumGetPointP(in->query); Point *datum = DatumGetPointP(in->leafDatum); bool res; /* all tests are exact */ out->recheck = false; /* leafDatum is what it is... */ out->leafValue = in->leafDatum; switch (in->strategy) { case RTLeftStrategyNumber: res = SPTEST(point_left, datum, query); break; case RTRightStrategyNumber: res = SPTEST(point_right, datum, query); break; case RTSameStrategyNumber: res = SPTEST(point_eq, datum, query); break; case RTBelowStrategyNumber: res = SPTEST(point_below, datum, query); break; case RTAboveStrategyNumber: res = SPTEST(point_above, datum, query); break; case RTContainedByStrategyNumber: /* * For this operator, the query is a box not a point. We cheat to * the extent of assuming that DatumGetPointP won't do anything * that would be bad for a pointer-to-box. */ res = SPTEST(box_contain_pt, query, datum); break; default: elog(ERROR, "unrecognized strategy number: %d", in->strategy); res = false; break; } PG_RETURN_BOOL(res); }
Datum spg_quad_inner_consistent(PG_FUNCTION_ARGS) { spgInnerConsistentIn *in = (spgInnerConsistentIn*)PG_GETARG_POINTER(0); spgInnerConsistentOut *out = (spgInnerConsistentOut*)PG_GETARG_POINTER(1); Point *query, *centroid; query = DatumGetPointP(in->query); Assert(in->hasPrefix); centroid = DatumGetPointP(in->prefixDatum); out->levelAdd = 0; out->nodeNumbers = palloc(sizeof(int)); out->nNodes = 1; out->nodeNumbers[0] = getQuadrant(centroid, query) - 1; PG_RETURN_VOID(); }
Datum spg_kd_picksplit(PG_FUNCTION_ARGS) { spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0); spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1); int i; int middle; SortedPoint *sorted; double coord; sorted = palloc(sizeof(*sorted) * in->nTuples); for (i = 0; i < in->nTuples; i++) { sorted[i].p = DatumGetPointP(in->datums[i]); sorted[i].i = i; } qsort(sorted, in->nTuples, sizeof(*sorted), (in->level % 2) ? x_cmp : y_cmp); middle = in->nTuples >> 1; coord = (in->level % 2) ? sorted[middle].p->x : sorted[middle].p->y; out->hasPrefix = true; out->prefixDatum = Float8GetDatum(coord); out->nNodes = 2; out->nodeLabels = NULL; /* we don't need node labels */ out->mapTuplesToNodes = palloc(sizeof(int) * in->nTuples); out->leafTupleDatums = palloc(sizeof(Datum) * in->nTuples); /* * Note: points that have coordinates exactly equal to coord may get * classified into either node, depending on where they happen to fall in * the sorted list. This is okay as long as the inner_consistent function * descends into both sides for such cases. This is better than the * alternative of trying to have an exact boundary, because it keeps the * tree balanced even when we have many instances of the same point value. * So we should never trigger the allTheSame logic. */ for (i = 0; i < in->nTuples; i++) { Point *p = sorted[i].p; int n = sorted[i].i; out->mapTuplesToNodes[n] = (i < middle) ? 0 : 1; out->leafTupleDatums[n] = PointPGetDatum(p); } PG_RETURN_VOID(); }
Datum gist_point_compress(PG_FUNCTION_ARGS) { GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0); if (entry->leafkey) /* Point, actually */ { BOX *box = palloc(sizeof(BOX)); Point *point = DatumGetPointP(entry->key); GISTENTRY *retval = palloc(sizeof(GISTENTRY)); box->high = box->low = *point; gistentryinit(*retval, BoxPGetDatum(box), entry->rel, entry->page, entry->offset, FALSE); PG_RETURN_POINTER(retval); } PG_RETURN_POINTER(entry); }
Datum spg_kd_choose(PG_FUNCTION_ARGS) { spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0); spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1); Point *inPoint = DatumGetPointP(in->datum); double coord; if (in->allTheSame) elog(ERROR, "allTheSame should not occur for k-d trees"); Assert(in->hasPrefix); coord = DatumGetFloat8(in->prefixDatum); Assert(in->nNodes == 2); out->resultType = spgMatchNode; out->result.matchNode.nodeN = (getSide(coord, in->level % 2, inPoint) > 0) ? 0 : 1; out->result.matchNode.levelAdd = 1; out->result.matchNode.restDatum = PointPGetDatum(inPoint); PG_RETURN_VOID(); }
Datum spg_quad_inner_consistent(PG_FUNCTION_ARGS) { spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0); spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1); Point *query, *centroid; BOX *boxQuery; query = DatumGetPointP(in->query); Assert(in->hasPrefix); centroid = DatumGetPointP(in->prefixDatum); if (in->allTheSame) { /* Report that all nodes should be visited */ int i; out->nNodes = in->nNodes; out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes); for (i = 0; i < in->nNodes; i++) out->nodeNumbers[i] = i; PG_RETURN_VOID(); } Assert(in->nNodes == 4); out->nodeNumbers = (int *) palloc(sizeof(int) * 4); switch (in->strategy) { case RTLeftStrategyNumber: setNodes(out, SPTEST(point_left, centroid, query), 3, 4); break; case RTRightStrategyNumber: setNodes(out, SPTEST(point_right, centroid, query), 1, 2); break; case RTSameStrategyNumber: out->nNodes = 1; out->nodeNumbers[0] = getQuadrant(centroid, query) - 1; break; case RTBelowStrategyNumber: setNodes(out, SPTEST(point_below, centroid, query), 2, 3); break; case RTAboveStrategyNumber: setNodes(out, SPTEST(point_above, centroid, query), 1, 4); break; case RTContainedByStrategyNumber: /* * For this operator, the query is a box not a point. We cheat to * the extent of assuming that DatumGetPointP won't do anything * that would be bad for a pointer-to-box. */ boxQuery = DatumGetBoxP(in->query); if (DatumGetBool(DirectFunctionCall2(box_contain_pt, PointerGetDatum(boxQuery), PointerGetDatum(centroid)))) { /* centroid is in box, so descend to all quadrants */ setNodes(out, true, 0, 0); } else { /* identify quadrant(s) containing all corners of box */ Point p; int i, r = 0; p = boxQuery->low; r |= 1 << (getQuadrant(centroid, &p) - 1); p.y = boxQuery->high.y; r |= 1 << (getQuadrant(centroid, &p) - 1); p = boxQuery->high; r |= 1 << (getQuadrant(centroid, &p) - 1); p.x = boxQuery->low.x; r |= 1 << (getQuadrant(centroid, &p) - 1); /* we must descend into those quadrant(s) */ out->nNodes = 0; for (i = 0; i < 4; i++) { if (r & (1 << i)) { out->nodeNumbers[out->nNodes] = i; out->nNodes++; } } } break; default: elog(ERROR, "unrecognized strategy number: %d", in->strategy); break; } PG_RETURN_VOID(); }
Datum spg_kd_inner_consistent(PG_FUNCTION_ARGS) { spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0); spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1); double coord; int which; int i; Assert(in->hasPrefix); coord = DatumGetFloat8(in->prefixDatum); if (in->allTheSame) elog(ERROR, "allTheSame should not occur for k-d trees"); Assert(in->nNodes == 2); /* "which" is a bitmask of children that satisfy all constraints */ which = (1 << 1) | (1 << 2); for (i = 0; i < in->nkeys; i++) { Point *query = DatumGetPointP(in->scankeys[i].sk_argument); BOX *boxQuery; switch (in->scankeys[i].sk_strategy) { case RTLeftStrategyNumber: if ((in->level % 2) != 0 && FPlt(query->x, coord)) which &= (1 << 1); break; case RTRightStrategyNumber: if ((in->level % 2) != 0 && FPgt(query->x, coord)) which &= (1 << 2); break; case RTSameStrategyNumber: if ((in->level % 2) != 0) { if (FPlt(query->x, coord)) which &= (1 << 1); else if (FPgt(query->x, coord)) which &= (1 << 2); } else { if (FPlt(query->y, coord)) which &= (1 << 1); else if (FPgt(query->y, coord)) which &= (1 << 2); } break; case RTBelowStrategyNumber: if ((in->level % 2) == 0 && FPlt(query->y, coord)) which &= (1 << 1); break; case RTAboveStrategyNumber: if ((in->level % 2) == 0 && FPgt(query->y, coord)) which &= (1 << 2); break; case RTContainedByStrategyNumber: /* * For this operator, the query is a box not a point. We * cheat to the extent of assuming that DatumGetPointP won't * do anything that would be bad for a pointer-to-box. */ boxQuery = DatumGetBoxP(in->scankeys[i].sk_argument); if ((in->level % 2) != 0) { if (FPlt(boxQuery->high.x, coord)) which &= (1 << 1); else if (FPgt(boxQuery->low.x, coord)) which &= (1 << 2); } else { if (FPlt(boxQuery->high.y, coord)) which &= (1 << 1); else if (FPgt(boxQuery->low.y, coord)) which &= (1 << 2); } break; default: elog(ERROR, "unrecognized strategy number: %d", in->scankeys[i].sk_strategy); break; } if (which == 0) break; /* no need to consider remaining conditions */ } /* We must descend into the children identified by which */ out->nodeNumbers = (int *) palloc(sizeof(int) * 2); out->nNodes = 0; for (i = 1; i <= 2; i++) { if (which & (1 << i)) out->nodeNumbers[out->nNodes++] = i - 1; } /* Set up level increments, too */ out->levelAdds = (int *) palloc(sizeof(int) * 2); out->levelAdds[0] = 1; out->levelAdds[1] = 1; PG_RETURN_VOID(); }