Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  spgkdtreeproc.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * spgkdtreeproc.c
 *   implementation of k-d 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/spgkdtreeproc.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_kd_config(PG_FUNCTION_ARGS)
{
 /* spgConfigIn *cfgin = (spgConfigIn *) PG_GETARG_POINTER(0); */
 spgConfigOut *cfg = (spgConfigOut *) PG_GETARG_POINTER(1);

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

static int
getSide(double coord, bool isX, Point *tst)
{
 double  tstcoord = (isX) ? tst->x : tst->y;

 if (coord == tstcoord)
  return 0;
 else if (coord > tstcoord)
  return 1;
 else
  return -1;
}

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

typedef struct SortedPoint
{
 Point    *p;
 int   i;
} SortedPoint;

static int
x_cmp(const void *a, const void *b)
{
 SortedPoint *pa = (SortedPoint *) a;
 SortedPoint *pb = (SortedPoint *) b;

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

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

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


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
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;
 BOX   bboxes[2];

 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:
   case RTOldBelowStrategyNumber:
    if ((in->level % 2) == 0 && FPlt(query->y, coord))
     which &= (1 << 1);
    break;
   case RTAboveStrategyNumber:
   case RTOldAboveStrategyNumber:
    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->nNodes = 0;

 /* Fast-path for no matching children */
 if (!which)
  PG_RETURN_VOID();

 out->nodeNumbers = (int *) palloc(sizeof(int) * 2);

 /*
  * When ordering scan keys are specified, we've to calculate distance for
  * them.  In order to do that, we need calculate bounding boxes for both
  * 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)
 {
  BOX   infArea;
  BOX     *area;

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

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

   infArea.high.x = inf;
   infArea.high.y = inf;
   infArea.low.x = -inf;
   infArea.low.y = -inf;
   area = &infArea;
  }
  else
  {
   area = (BOX *) in->traversalValue;
   Assert(area);
  }

  bboxes[0].low = area->low;
  bboxes[1].high = area->high;

  if (in->level % 2)
  {
   /* split box by x */
   bboxes[0].high.x = bboxes[1].low.x = coord;
   bboxes[0].high.y = area->high.y;
   bboxes[1].low.y = area->low.y;
  }
  else
  {
   /* split box by y */
   bboxes[0].high.y = bboxes[1].low.y = coord;
   bboxes[0].high.x = area->high.x;
   bboxes[1].low.x = area->low.x;
  }
 }

 for (i = 1; i <= 2; i++)
 {
  if (which & (1 << i))
  {
   out->nodeNumbers[out->nNodes] = i - 1;

   if (in->norderbys > 0)
   {
    MemoryContext oldCtx = MemoryContextSwitchTo(in->traversalMemoryContext);
    BOX     *box = box_copy(&bboxes[i - 1]);

    MemoryContextSwitchTo(oldCtx);

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

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

   out->nNodes++;
  }
 }

 /* Set up level increments, too */
 out->levelAdds = (int *) palloc(sizeof(int) * 2);
 out->levelAdds[0] = 1;
 out->levelAdds[1] = 1;

 PG_RETURN_VOID();
}

/*
 * spg_kd_leaf_consistent() is the same as spg_quad_leaf_consistent(),
 * since we support the same operators and the same leaf data type.
 * So we just borrow that function.
 */


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

¤ Dauer der Verarbeitung: 0.15 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.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=277311
#Domains=752002