Header And Logo

PostgreSQL
| The world's most advanced open source database.

Defines | Functions

spgquadtreeproc.c File Reference

#include "postgres.h"
#include "access/gist.h"
#include "access/spgist.h"
#include "catalog/pg_type.h"
#include "utils/builtins.h"
#include "utils/geo_decls.h"
Include dependency graph for spgquadtreeproc.c:

Go to the source code of this file.

Defines

#define SPTEST(f, x, y)   DatumGetBool(DirectFunctionCall2(f, PointPGetDatum(x), PointPGetDatum(y)))

Functions

Datum spg_quad_config (PG_FUNCTION_ARGS)
static int16 getQuadrant (Point *centroid, Point *tst)
Datum spg_quad_choose (PG_FUNCTION_ARGS)
Datum spg_quad_picksplit (PG_FUNCTION_ARGS)
Datum spg_quad_inner_consistent (PG_FUNCTION_ARGS)
Datum spg_quad_leaf_consistent (PG_FUNCTION_ARGS)

Define Documentation

#define SPTEST (   f,
  x,
  y 
)    DatumGetBool(DirectFunctionCall2(f, PointPGetDatum(x), PointPGetDatum(y)))

Function Documentation

static int16 getQuadrant ( Point centroid,
Point tst 
) [static]

Definition at line 54 of file spgquadtreeproc.c.

References elog, ERROR, point_above(), point_below(), point_horiz(), point_left(), point_right(), point_vert(), and SPTEST.

Referenced by spg_quad_choose(), spg_quad_inner_consistent(), and spg_quad_picksplit().

{
    if ((SPTEST(point_above, tst, centroid) ||
         SPTEST(point_horiz, tst, centroid)) &&
        (SPTEST(point_right, tst, centroid) ||
         SPTEST(point_vert, tst, centroid)))
        return 1;

    if (SPTEST(point_below, tst, centroid) &&
        (SPTEST(point_right, tst, centroid) ||
         SPTEST(point_vert, tst, centroid)))
        return 2;

    if ((SPTEST(point_below, tst, centroid) ||
         SPTEST(point_horiz, tst, centroid)) &&
        SPTEST(point_left, tst, centroid))
        return 3;

    if (SPTEST(point_above, tst, centroid) &&
        SPTEST(point_left, tst, centroid))
        return 4;

    elog(ERROR, "getQuadrant: impossible case");
    return 0;
}

Datum spg_quad_choose ( PG_FUNCTION_ARGS   ) 

Definition at line 82 of file spgquadtreeproc.c.

References spgChooseIn::allTheSame, Assert, spgChooseIn::datum, DatumGetPointP, getQuadrant(), spgChooseIn::hasPrefix, spgChooseOut::matchNode, spgChooseIn::nNodes, PG_GETARG_POINTER, PG_RETURN_VOID, PointPGetDatum, spgChooseIn::prefixDatum, spgChooseOut::result, and spgChooseOut::resultType.

{
    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_config ( PG_FUNCTION_ARGS   ) 

Definition at line 26 of file spgquadtreeproc.c.

References spgConfigOut::canReturnData, spgConfigOut::labelType, spgConfigOut::longValuesOK, PG_GETARG_POINTER, PG_RETURN_VOID, and spgConfigOut::prefixType.

{
    /* spgConfigIn *cfgin = (spgConfigIn *) PG_GETARG_POINTER(0); */
    spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1);

    cfg->prefixType = POINTOID;
    cfg->labelType = VOIDOID;   /* we don't need node labels */
    cfg->canReturnData = true;
    cfg->longValuesOK = false;
    PG_RETURN_VOID();
}

Datum spg_quad_inner_consistent ( PG_FUNCTION_ARGS   ) 

Definition at line 194 of file spgquadtreeproc.c.

References spgInnerConsistentIn::allTheSame, Assert, box_contain_pt(), DatumGetBool, DatumGetBoxP, DatumGetPointP, DirectFunctionCall2, elog, ERROR, getQuadrant(), spgInnerConsistentIn::hasPrefix, BOX::high, i, BOX::low, spgInnerConsistentIn::nkeys, spgInnerConsistentIn::nNodes, spgInnerConsistentOut::nNodes, spgInnerConsistentOut::nodeNumbers, palloc(), PG_GETARG_POINTER, PG_RETURN_VOID, point_above(), point_below(), point_left(), point_right(), PointerGetDatum, spgInnerConsistentIn::prefixDatum, RTAboveStrategyNumber, RTBelowStrategyNumber, RTContainedByStrategyNumber, RTLeftStrategyNumber, RTRightStrategyNumber, RTSameStrategyNumber, spgInnerConsistentIn::scankeys, ScanKeyData::sk_argument, ScanKeyData::sk_strategy, SPTEST, Point::x, and Point::y.

{
    spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
    spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
    Point      *centroid;
    int         which;
    int         i;

    Assert(in->hasPrefix);
    centroid = DatumGetPointP(in->prefixDatum);

    if (in->allTheSame)
    {
        /* Report that all nodes should be visited */
        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);

    /* "which" is a bitmask of quadrants that satisfy all constraints */
    which = (1 << 1) | (1 << 2) | (1 << 3) | (1 << 4);

    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 (SPTEST(point_right, centroid, query))
                    which &= (1 << 3) | (1 << 4);
                break;
            case RTRightStrategyNumber:
                if (SPTEST(point_left, centroid, query))
                    which &= (1 << 1) | (1 << 2);
                break;
            case RTSameStrategyNumber:
                which &= (1 << getQuadrant(centroid, query));
                break;
            case RTBelowStrategyNumber:
                if (SPTEST(point_above, centroid, query))
                    which &= (1 << 2) | (1 << 3);
                break;
            case RTAboveStrategyNumber:
                if (SPTEST(point_below, centroid, query))
                    which &= (1 << 1) | (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->scankeys[i].sk_argument);

                if (DatumGetBool(DirectFunctionCall2(box_contain_pt,
                                                   PointerGetDatum(boxQuery),
                                                 PointerGetDatum(centroid))))
                {
                    /* centroid is in box, so all quadrants are OK */
                }
                else
                {
                    /* identify quadrant(s) containing all corners of box */
                    Point       p;
                    int         r = 0;

                    p = boxQuery->low;
                    r |= 1 << getQuadrant(centroid, &p);
                    p.y = boxQuery->high.y;
                    r |= 1 << getQuadrant(centroid, &p);
                    p = boxQuery->high;
                    r |= 1 << getQuadrant(centroid, &p);
                    p.x = boxQuery->low.x;
                    r |= 1 << getQuadrant(centroid, &p);

                    which &= r;
                }
                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 quadrant(s) identified by which */
    out->nodeNumbers = (int *) palloc(sizeof(int) * 4);
    out->nNodes = 0;
    for (i = 1; i <= 4; i++)
    {
        if (which & (1 << i))
            out->nodeNumbers[out->nNodes++] = i - 1;
    }

    PG_RETURN_VOID();
}

Datum spg_quad_leaf_consistent ( PG_FUNCTION_ARGS   ) 

Definition at line 303 of file spgquadtreeproc.c.

References box_contain_pt(), DatumGetPointP, elog, ERROR, i, spgLeafConsistentIn::leafDatum, spgLeafConsistentOut::leafValue, spgLeafConsistentIn::nkeys, PG_GETARG_POINTER, PG_RETURN_BOOL, point_above(), point_below(), point_eq(), point_left(), point_right(), spgLeafConsistentOut::recheck, RTAboveStrategyNumber, RTBelowStrategyNumber, RTContainedByStrategyNumber, RTLeftStrategyNumber, RTRightStrategyNumber, RTSameStrategyNumber, spgLeafConsistentIn::scankeys, ScanKeyData::sk_argument, ScanKeyData::sk_strategy, and SPTEST.

{
    spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0);
    spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1);
    Point      *datum = DatumGetPointP(in->leafDatum);
    bool        res;
    int         i;

    /* all tests are exact */
    out->recheck = false;

    /* leafDatum is what it is... */
    out->leafValue = in->leafDatum;

    /* Perform the required comparison(s) */
    res = true;
    for (i = 0; i < in->nkeys; i++)
    {
        Point      *query = DatumGetPointP(in->scankeys[i].sk_argument);

        switch (in->scankeys[i].sk_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->scankeys[i].sk_strategy);
                break;
        }

        if (!res)
            break;
    }

    PG_RETURN_BOOL(res);
}

Datum spg_quad_picksplit ( PG_FUNCTION_ARGS   ) 

Definition at line 136 of file spgquadtreeproc.c.

References DatumGetPointP, spgPickSplitIn::datums, getQuadrant(), spgPickSplitOut::hasPrefix, i, spgPickSplitOut::leafTupleDatums, spgPickSplitOut::mapTuplesToNodes, spgPickSplitOut::nNodes, spgPickSplitOut::nodeLabels, spgPickSplitIn::nTuples, palloc(), palloc0(), PG_GETARG_POINTER, PG_RETURN_VOID, PointPGetDatum, spgPickSplitOut::prefixDatum, qsort, Point::x, x_cmp(), Point::y, and y_cmp().

{
    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();
}