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

Quelle  network_spgist.c

  Sprache: C
 

/*-------------------------------------------------------------------------
 *
 * network_spgist.c
 *   SP-GiST support for network types.
 *
 * We split inet index entries first by address family (IPv4 or IPv6).
 * If the entries below a given inner tuple are all of the same family,
 * we identify their common prefix and split by the next bit of the address,
 * and by whether their masklens exceed the length of the common prefix.
 *
 * An inner tuple that has both IPv4 and IPv6 children has a null prefix
 * and exactly two nodes, the first being for IPv4 and the second for IPv6.
 *
 * Otherwise, the prefix is a CIDR value representing the common prefix,
 * and there are exactly four nodes.  Node numbers 0 and 1 are for addresses
 * with the same masklen as the prefix, while node numbers 2 and 3 are for
 * addresses with larger masklen.  (We do not allow a tuple to contain
 * entries with masklen smaller than its prefix's.)  Node numbers 0 and 1
 * are distinguished by the next bit of the address after the common prefix,
 * and likewise for node numbers 2 and 3.  If there are no more bits in
 * the address family, everything goes into node 0 (which will probably
 * lead to creating an allTheSame tuple).
 *
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
 *   src/backend/utils/adt/network_spgist.c
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

#include <sys/socket.h>

#include "access/spgist.h"
#include "catalog/pg_type.h"
#include "utils/fmgrprotos.h"
#include "utils/inet.h"
#include "varatt.h"


static int inet_spg_node_number(const inet *val, int commonbits);
static int inet_spg_consistent_bitmap(const inet *prefix, int nkeys,
            ScanKey scankeys, bool leaf);

/*
 * The SP-GiST configuration function
 */

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

 cfg->prefixType = CIDROID;
 cfg->labelType = VOIDOID;
 cfg->canReturnData = true;
 cfg->longValuesOK = false;

 PG_RETURN_VOID();
}

/*
 * The SP-GiST choose function
 */

Datum
inet_spg_choose(PG_FUNCTION_ARGS)
{
 spgChooseIn *in = (spgChooseIn *) PG_GETARG_POINTER(0);
 spgChooseOut *out = (spgChooseOut *) PG_GETARG_POINTER(1);
 inet    *val = DatumGetInetPP(in->datum),
      *prefix;
 int   commonbits;

 /*
  * If we're looking at a tuple that splits by address family, choose the
  * appropriate subnode.
 */

 if (!in->hasPrefix)
 {
  /* allTheSame isn't possible for such a tuple */
  Assert(!in->allTheSame);
  Assert(in->nNodes == 2);

  out->resultType = spgMatchNode;
  out->result.matchNode.nodeN = (ip_family(val) == PGSQL_AF_INET) ? 0 : 1;
  out->result.matchNode.restDatum = InetPGetDatum(val);

  PG_RETURN_VOID();
 }

 /* Else it must split by prefix */
 Assert(in->nNodes == 4 || in->allTheSame);

 prefix = DatumGetInetPP(in->prefixDatum);
 commonbits = ip_bits(prefix);

 /*
  * We cannot put addresses from different families under the same inner
  * node, so we have to split if the new value's family is different.
 */

 if (ip_family(val) != ip_family(prefix))
 {
  /* Set up 2-node tuple */
  out->resultType = spgSplitTuple;
  out->result.splitTuple.prefixHasPrefix = false;
  out->result.splitTuple.prefixNNodes = 2;
  out->result.splitTuple.prefixNodeLabels = NULL;

  /* Identify which node the existing data goes into */
  out->result.splitTuple.childNodeN =
   (ip_family(prefix) == PGSQL_AF_INET) ? 0 : 1;

  out->result.splitTuple.postfixHasPrefix = true;
  out->result.splitTuple.postfixPrefixDatum = InetPGetDatum(prefix);

  PG_RETURN_VOID();
 }

 /*
  * If the new value does not match the existing prefix, we have to split.
 */

 if (ip_bits(val) < commonbits ||
  bitncmp(ip_addr(prefix), ip_addr(val), commonbits) != 0)
 {
  /* Determine new prefix length for the split tuple */
  commonbits = bitncommon(ip_addr(prefix), ip_addr(val),
        Min(ip_bits(val), commonbits));

  /* Set up 4-node tuple */
  out->resultType = spgSplitTuple;
  out->result.splitTuple.prefixHasPrefix = true;
  out->result.splitTuple.prefixPrefixDatum =
   InetPGetDatum(cidr_set_masklen_internal(val, commonbits));
  out->result.splitTuple.prefixNNodes = 4;
  out->result.splitTuple.prefixNodeLabels = NULL;

  /* Identify which node the existing data goes into */
  out->result.splitTuple.childNodeN =
   inet_spg_node_number(prefix, commonbits);

  out->result.splitTuple.postfixHasPrefix = true;
  out->result.splitTuple.postfixPrefixDatum = InetPGetDatum(prefix);

  PG_RETURN_VOID();
 }

 /*
  * All OK, choose the node to descend into.  (If this tuple is marked
  * allTheSame, the core code will ignore our choice of nodeN; but we need
  * not account for that case explicitly here.)
 */

 out->resultType = spgMatchNode;
 out->result.matchNode.nodeN = inet_spg_node_number(val, commonbits);
 out->result.matchNode.restDatum = InetPGetDatum(val);

 PG_RETURN_VOID();
}

/*
 * The GiST PickSplit method
 */

Datum
inet_spg_picksplit(PG_FUNCTION_ARGS)
{
 spgPickSplitIn *in = (spgPickSplitIn *) PG_GETARG_POINTER(0);
 spgPickSplitOut *out = (spgPickSplitOut *) PG_GETARG_POINTER(1);
 inet    *prefix,
      *tmp;
 int   i,
    commonbits;
 bool  differentFamilies = false;

 /* Initialize the prefix with the first item */
 prefix = DatumGetInetPP(in->datums[0]);
 commonbits = ip_bits(prefix);

 /* Examine remaining items to discover minimum common prefix length */
 for (i = 1; i < in->nTuples; i++)
 {
  tmp = DatumGetInetPP(in->datums[i]);

  if (ip_family(tmp) != ip_family(prefix))
  {
   differentFamilies = true;
   break;
  }

  if (ip_bits(tmp) < commonbits)
   commonbits = ip_bits(tmp);
  commonbits = bitncommon(ip_addr(prefix), ip_addr(tmp), commonbits);
  if (commonbits == 0)
   break;
 }

 /* Don't need labels; allocate output arrays */
 out->nodeLabels = NULL;
 out->mapTuplesToNodes = (int *) palloc(sizeof(int) * in->nTuples);
 out->leafTupleDatums = (Datum *) palloc(sizeof(Datum) * in->nTuples);

 if (differentFamilies)
 {
  /* Set up 2-node tuple */
  out->hasPrefix = false;
  out->nNodes = 2;

  for (i = 0; i < in->nTuples; i++)
  {
   tmp = DatumGetInetPP(in->datums[i]);
   out->mapTuplesToNodes[i] =
    (ip_family(tmp) == PGSQL_AF_INET) ? 0 : 1;
   out->leafTupleDatums[i] = InetPGetDatum(tmp);
  }
 }
 else
 {
  /* Set up 4-node tuple */
  out->hasPrefix = true;
  out->prefixDatum =
   InetPGetDatum(cidr_set_masklen_internal(prefix, commonbits));
  out->nNodes = 4;

  for (i = 0; i < in->nTuples; i++)
  {
   tmp = DatumGetInetPP(in->datums[i]);
   out->mapTuplesToNodes[i] = inet_spg_node_number(tmp, commonbits);
   out->leafTupleDatums[i] = InetPGetDatum(tmp);
  }
 }

 PG_RETURN_VOID();
}

/*
 * The SP-GiST query consistency check for inner tuples
 */

Datum
inet_spg_inner_consistent(PG_FUNCTION_ARGS)
{
 spgInnerConsistentIn *in = (spgInnerConsistentIn *) PG_GETARG_POINTER(0);
 spgInnerConsistentOut *out = (spgInnerConsistentOut *) PG_GETARG_POINTER(1);
 int   i;
 int   which;

 if (!in->hasPrefix)
 {
  Assert(!in->allTheSame);
  Assert(in->nNodes == 2);

  /* Identify which child nodes need to be visited */
  which = 1 | (1 << 1);

  for (i = 0; i < in->nkeys; i++)
  {
   StrategyNumber strategy = in->scankeys[i].sk_strategy;
   inet    *argument = DatumGetInetPP(in->scankeys[i].sk_argument);

   switch (strategy)
   {
    case RTLessStrategyNumber:
    case RTLessEqualStrategyNumber:
     if (ip_family(argument) == PGSQL_AF_INET)
      which &= 1;
     break;

    case RTGreaterEqualStrategyNumber:
    case RTGreaterStrategyNumber:
     if (ip_family(argument) == PGSQL_AF_INET6)
      which &= (1 << 1);
     break;

    case RTNotEqualStrategyNumber:
     break;

    default:
     /* all other ops can only match addrs of same family */
     if (ip_family(argument) == PGSQL_AF_INET)
      which &= 1;
     else
      which &= (1 << 1);
     break;
   }
  }
 }
 else if (!in->allTheSame)
 {
  Assert(in->nNodes == 4);

  /* Identify which child nodes need to be visited */
  which = inet_spg_consistent_bitmap(DatumGetInetPP(in->prefixDatum),
             in->nkeys, in->scankeys, false);
 }
 else
 {
  /* Must visit all nodes; we assume there are less than 32 of 'em */
  which = ~0;
 }

 out->nNodes = 0;

 if (which)
 {
  out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);

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

 PG_RETURN_VOID();
}

/*
 * The SP-GiST query consistency check for leaf tuples
 */

Datum
inet_spg_leaf_consistent(PG_FUNCTION_ARGS)
{
 spgLeafConsistentIn *in = (spgLeafConsistentIn *) PG_GETARG_POINTER(0);
 spgLeafConsistentOut *out = (spgLeafConsistentOut *) PG_GETARG_POINTER(1);
 inet    *leaf = DatumGetInetPP(in->leafDatum);

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

 /* Leaf is what it is... */
 out->leafValue = InetPGetDatum(leaf);

 /* Use common code to apply the tests. */
 PG_RETURN_BOOL(inet_spg_consistent_bitmap(leaf, in->nkeys, in->scankeys,
             true));
}

/*
 * Calculate node number (within a 4-node, single-family inner index tuple)
 *
 * The value must have the same family as the node's prefix, and
 * commonbits is the mask length of the prefix.  We use even or odd
 * nodes according to the next address bit after the commonbits,
 * and low or high nodes according to whether the value's mask length
 * is larger than commonbits.
 */

static int
inet_spg_node_number(const inet *val, int commonbits)
{
 int   nodeN = 0;

 if (commonbits < ip_maxbits(val) &&
  ip_addr(val)[commonbits / 8] & (1 << (7 - commonbits % 8)))
  nodeN |= 1;
 if (commonbits < ip_bits(val))
  nodeN |= 2;

 return nodeN;
}

/*
 * Calculate bitmap of node numbers that are consistent with the query
 *
 * This can be used either at a 4-way inner tuple, or at a leaf tuple.
 * In the latter case, we should return a boolean result (0 or 1)
 * not a bitmap.
 *
 * This definition is pretty odd, but the inner and leaf consistency checks
 * are mostly common and it seems best to keep them in one function.
 */

static int
inet_spg_consistent_bitmap(const inet *prefix, int nkeys, ScanKey scankeys,
         bool leaf)
{
 int   bitmap;
 int   commonbits,
    i;

 /* Initialize result to allow visiting all children */
 if (leaf)
  bitmap = 1;
 else
  bitmap = 1 | (1 << 1) | (1 << 2) | (1 << 3);

 commonbits = ip_bits(prefix);

 for (i = 0; i < nkeys; i++)
 {
  inet    *argument = DatumGetInetPP(scankeys[i].sk_argument);
  StrategyNumber strategy = scankeys[i].sk_strategy;
  int   order;

  /*
   * Check 0: different families
   *
   * Matching families do not help any of the strategies.
 */

  if (ip_family(argument) != ip_family(prefix))
  {
   switch (strategy)
   {
    case RTLessStrategyNumber:
    case RTLessEqualStrategyNumber:
     if (ip_family(argument) < ip_family(prefix))
      bitmap = 0;
     break;

    case RTGreaterEqualStrategyNumber:
    case RTGreaterStrategyNumber:
     if (ip_family(argument) > ip_family(prefix))
      bitmap = 0;
     break;

    case RTNotEqualStrategyNumber:
     break;

    default:
     /* For all other cases, we can be sure there is no match */
     bitmap = 0;
     break;
   }

   if (!bitmap)
    break;

   /* Other checks make no sense with different families. */
   continue;
  }

  /*
   * Check 1: network bit count
   *
   * Network bit count (ip_bits) helps to check leaves for sub network
   * and sup network operators.  At non-leaf nodes, we know every child
   * value has greater ip_bits, so we can avoid descending in some cases
   * too.
   *
   * This check is less expensive than checking the address bits, so we
   * are doing this before, but it has to be done after for the basic
   * comparison strategies, because ip_bits only affect their results
   * when the common network bits are the same.
 */

  switch (strategy)
  {
   case RTSubStrategyNumber:
    if (commonbits <= ip_bits(argument))
     bitmap &= (1 << 2) | (1 << 3);
    break;

   case RTSubEqualStrategyNumber:
    if (commonbits < ip_bits(argument))
     bitmap &= (1 << 2) | (1 << 3);
    break;

   case RTSuperStrategyNumber:
    if (commonbits == ip_bits(argument) - 1)
     bitmap &= 1 | (1 << 1);
    else if (commonbits >= ip_bits(argument))
     bitmap = 0;
    break;

   case RTSuperEqualStrategyNumber:
    if (commonbits == ip_bits(argument))
     bitmap &= 1 | (1 << 1);
    else if (commonbits > ip_bits(argument))
     bitmap = 0;
    break;

   case RTEqualStrategyNumber:
    if (commonbits < ip_bits(argument))
     bitmap &= (1 << 2) | (1 << 3);
    else if (commonbits == ip_bits(argument))
     bitmap &= 1 | (1 << 1);
    else
     bitmap = 0;
    break;
  }

  if (!bitmap)
   break;

  /*
   * Check 2: common network bits
   *
   * Compare available common prefix bits to the query, but not beyond
   * either the query's netmask or the minimum netmask among the
   * represented values.  If these bits don't match the query, we can
   * eliminate some cases.
 */

  order = bitncmp(ip_addr(prefix), ip_addr(argument),
      Min(commonbits, ip_bits(argument)));

  if (order != 0)
  {
   switch (strategy)
   {
    case RTLessStrategyNumber:
    case RTLessEqualStrategyNumber:
     if (order > 0)
      bitmap = 0;
     break;

    case RTGreaterEqualStrategyNumber:
    case RTGreaterStrategyNumber:
     if (order < 0)
      bitmap = 0;
     break;

    case RTNotEqualStrategyNumber:
     break;

    default:
     /* For all other cases, we can be sure there is no match */
     bitmap = 0;
     break;
   }

   if (!bitmap)
    break;

   /*
    * Remaining checks make no sense when common bits don't match.
 */

   continue;
  }

  /*
   * Check 3: next network bit
   *
   * We can filter out branch 2 or 3 using the next network bit of the
   * argument, if it is available.
   *
   * This check matters for the performance of the search. The results
   * would be correct without it.
 */

  if (bitmap & ((1 << 2) | (1 << 3)) &&
   commonbits < ip_bits(argument))
  {
   int   nextbit;

   nextbit = ip_addr(argument)[commonbits / 8] &
    (1 << (7 - commonbits % 8));

   switch (strategy)
   {
    case RTLessStrategyNumber:
    case RTLessEqualStrategyNumber:
     if (!nextbit)
      bitmap &= 1 | (1 << 1) | (1 << 2);
     break;

    case RTGreaterEqualStrategyNumber:
    case RTGreaterStrategyNumber:
     if (nextbit)
      bitmap &= 1 | (1 << 1) | (1 << 3);
     break;

    case RTNotEqualStrategyNumber:
     break;

    default:
     if (!nextbit)
      bitmap &= 1 | (1 << 1) | (1 << 2);
     else
      bitmap &= 1 | (1 << 1) | (1 << 3);
     break;
   }

   if (!bitmap)
    break;
  }

  /*
   * Remaining checks are only for the basic comparison strategies. This
   * test relies on the strategy number ordering defined in stratnum.h.
 */

  if (strategy < RTEqualStrategyNumber ||
   strategy > RTGreaterEqualStrategyNumber)
   continue;

  /*
   * Check 4: network bit count
   *
   * At this point, we know that the common network bits of the prefix
   * and the argument are the same, so we can go forward and check the
   * ip_bits.
 */

  switch (strategy)
  {
   case RTLessStrategyNumber:
   case RTLessEqualStrategyNumber:
    if (commonbits == ip_bits(argument))
     bitmap &= 1 | (1 << 1);
    else if (commonbits > ip_bits(argument))
     bitmap = 0;
    break;

   case RTGreaterEqualStrategyNumber:
   case RTGreaterStrategyNumber:
    if (commonbits < ip_bits(argument))
     bitmap &= (1 << 2) | (1 << 3);
    break;
  }

  if (!bitmap)
   break;

  /* Remaining checks don't make sense with different ip_bits. */
  if (commonbits != ip_bits(argument))
   continue;

  /*
   * Check 5: next host bit
   *
   * We can filter out branch 0 or 1 using the next host bit of the
   * argument, if it is available.
   *
   * This check matters for the performance of the search. The results
   * would be correct without it.  There is no point in running it for
   * leafs as we have to check the whole address on the next step.
 */

  if (!leaf && bitmap & (1 | (1 << 1)) &&
   commonbits < ip_maxbits(argument))
  {
   int   nextbit;

   nextbit = ip_addr(argument)[commonbits / 8] &
    (1 << (7 - commonbits % 8));

   switch (strategy)
   {
    case RTLessStrategyNumber:
    case RTLessEqualStrategyNumber:
     if (!nextbit)
      bitmap &= 1 | (1 << 2) | (1 << 3);
     break;

    case RTGreaterEqualStrategyNumber:
    case RTGreaterStrategyNumber:
     if (nextbit)
      bitmap &= (1 << 1) | (1 << 2) | (1 << 3);
     break;

    case RTNotEqualStrategyNumber:
     break;

    default:
     if (!nextbit)
      bitmap &= 1 | (1 << 2) | (1 << 3);
     else
      bitmap &= (1 << 1) | (1 << 2) | (1 << 3);
     break;
   }

   if (!bitmap)
    break;
  }

  /*
   * Check 6: whole address
   *
   * This is the last check for correctness of the basic comparison
   * strategies.  It's only appropriate at leaf entries.
 */

  if (leaf)
  {
   /* Redo ordering comparison using all address bits */
   order = bitncmp(ip_addr(prefix), ip_addr(argument),
       ip_maxbits(prefix));

   switch (strategy)
   {
    case RTLessStrategyNumber:
     if (order >= 0)
      bitmap = 0;
     break;

    case RTLessEqualStrategyNumber:
     if (order > 0)
      bitmap = 0;
     break;

    case RTEqualStrategyNumber:
     if (order != 0)
      bitmap = 0;
     break;

    case RTGreaterEqualStrategyNumber:
     if (order < 0)
      bitmap = 0;
     break;

    case RTGreaterStrategyNumber:
     if (order <= 0)
      bitmap = 0;
     break;

    case RTNotEqualStrategyNumber:
     if (order == 0)
      bitmap = 0;
     break;
   }

   if (!bitmap)
    break;
  }
 }

 return bitmap;
}

Messung V0.5 in Prozent
C=93 H=94 G=93

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