Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Postgres/src/backend/access/spgist/   (Postgres Database Version 18.4©)  Datei vom 11.4.2026 mit Größe 11 kB image not shown  

Quelle  spgquadtreeproc.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * spgquadtreeproc.c
 *   implementation of quad tree over points for SP-GiST
 *
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *   src/backend/access/spgist/spgquadtreeproc.c
 *
 *-------------------------------------------------------------------------
 */


#include "postgres.h"

#include "access/spgist.h"
#include "access/spgist_private.h"
#include "access/stratnum.h"
#include "catalog/pg_type.h"
#include "utils/float.h"
#include "utils/fmgrprotos.h"
#include "utils/geo_decls.h"

Datum
spg_quad_config(PG_FUNCTION_ARGS)
{
 /* 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();
}

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

/*
 * Determine which quadrant a point falls into, relative to the centroid.
 *
 * Quadrants are identified like this:
 *
 *  4 |  1
 * ----+-----
 *  3 |  2
 *
 * Points on one of the axes are taken to lie in the lowest-numbered
 * adjacent quadrant.
 */

static int16
getQuadrant(Point *centroid, Point *tst)
{
 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;
}

/* Returns bounding box of a given quadrant inside given bounding box */
static BOX *
getQuadrantArea(BOX *bbox, Point *centroid, int quadrant)
{
 BOX     *result = (BOX *) palloc(sizeof(BOX));

 switch (quadrant)
 {
  case 1:
   result->high = bbox->high;
   result->low = *centroid;
   break;
  case 2:
   result->high.x = bbox->high.x;
   result->high.y = centroid->y;
   result->low.x = centroid->x;
   result->low.y = bbox->low.y;
   break;
  case 3:
   result->high = *centroid;
   result->low = bbox->low;
   break;
  case 4:
   result->high.x = centroid->x;
   result->high.y = bbox->high.y;
   result->low.x = bbox->low.x;
   result->low.y = centroid->y;
   break;
 }

 return result;
}

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

#ifdef USE_MEDIAN
static int
x_cmp(const void *a, const void *b, void *arg)
{
 Point    *pa = *(Point **) a;
 Point    *pb = *(Point **) b;

 if (pa->x == pb->x)
  return 0;
 return (pa->x > pb->x) ? 1 : -1;
}

static int
y_cmp(const void *a, const void *b, void *arg)
{
 Point    *pa = *(Point **) a;
 Point    *pb = *(Point **) b;

 if (pa->y == pb->y)
  return 0;
 return (pa->y > pb->y) ? 1 : -1;
}
#endif

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_inner_consistent(PG_FUNCTION_ARGS)
{
 spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
 spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
 Point    *centroid;
 BOX   infbbox;
 BOX     *bbox = NULL;
 int   which;
 int   i;

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

 /*
  * When ordering scan keys are specified, we've to calculate distance for
  * them.  In order to do that, we need calculate bounding boxes for all
  * children nodes.  Calculation of those bounding boxes on non-zero level
  * require knowledge of bounding box of upper node.  So, we save bounding
  * boxes to traversalValues.
 */

 if (in->norderbys > 0)
 {
  out->distances = (double **) palloc(sizeof(double *) * in->nNodes);
  out->traversalValues = (void **) palloc(sizeof(void *) * in->nNodes);

  if (in->level == 0)
  {
   double  inf = get_float8_infinity();

   infbbox.high.x = inf;
   infbbox.high.y = inf;
   infbbox.low.x = -inf;
   infbbox.low.y = -inf;
   bbox = &infbbox;
  }
  else
  {
   bbox = in->traversalValue;
   Assert(bbox);
  }
 }

 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;

   if (in->norderbys > 0)
   {
    MemoryContext oldCtx = MemoryContextSwitchTo(in->traversalMemoryContext);

    /* Use parent quadrant box as traversalValue */
    BOX     *quadrant = box_copy(bbox);

    MemoryContextSwitchTo(oldCtx);

    out->traversalValues[i] = quadrant;
    out->distances[i] = spg_key_orderbys_distances(BoxPGetDatum(quadrant), false,
                  in->orderbys, in->norderbys);
   }
  }
  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:
   case RTOldBelowStrategyNumber:
    if (SPTEST(point_above, centroid, query))
     which &= (1 << 2) | (1 << 3);
    break;
   case RTAboveStrategyNumber:
   case RTOldAboveStrategyNumber:
    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 */
 }

 out->levelAdds = palloc(sizeof(int) * 4);
 for (i = 0; i < 4; ++i)
  out->levelAdds[i] = 1;

 /* 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;

   if (in->norderbys > 0)
   {
    MemoryContext oldCtx = MemoryContextSwitchTo(in->traversalMemoryContext);
    BOX     *quadrant = getQuadrantArea(bbox, centroid, i);

    MemoryContextSwitchTo(oldCtx);

    out->traversalValues[out->nNodes] = quadrant;

    out->distances[out->nNodes] = spg_key_orderbys_distances(BoxPGetDatum(quadrant), false,
                   in->orderbys, in->norderbys);
   }

   out->nNodes++;
  }
 }

 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    *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:
   case RTOldBelowStrategyNumber:
    res = SPTEST(point_below, datum, query);
    break;
   case RTAboveStrategyNumber:
   case RTOldAboveStrategyNumber:
    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;
 }

 if (res && in->norderbys > 0)
  /* ok, it passes -> let's compute the distances */
  out->distances = spg_key_orderbys_distances(in->leafDatum, true,
             in->orderbys, in->norderbys);

 PG_RETURN_BOOL(res);
}

Messung V0.5 in Prozent
C=92 H=91 G=91

¤ Dauer der Verarbeitung: 0.14 Sekunden  (vorverarbeitet am  2026-08-08) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.