PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
spgtextproc.c File Reference
#include "postgres.h"
#include "access/spgist.h"
#include "catalog/pg_type.h"
#include "mb/pg_wchar.h"
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/pg_locale.h"
#include "utils/varlena.h"
Include dependency graph for spgtextproc.c:

Go to the source code of this file.

Data Structures

struct  spgNodePtr
 

Macros

#define SPGIST_MAX_PREFIX_LENGTH   Max((int) (BLCKSZ - 258 * 16 - 100), 32)
 

Typedefs

typedef struct spgNodePtr spgNodePtr
 

Functions

Datum spg_text_config (PG_FUNCTION_ARGS)
 
static Datum formTextDatum (const char *data, int datalen)
 
static int commonPrefix (const char *a, const char *b, int lena, int lenb)
 
static bool searchChar (Datum *nodeLabels, int nNodes, int16 c, int *i)
 
Datum spg_text_choose (PG_FUNCTION_ARGS)
 
static int cmpNodePtr (const void *a, const void *b)
 
Datum spg_text_picksplit (PG_FUNCTION_ARGS)
 
Datum spg_text_inner_consistent (PG_FUNCTION_ARGS)
 
Datum spg_text_leaf_consistent (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

#define SPGIST_MAX_PREFIX_LENGTH   Max((int) (BLCKSZ - 258 * 16 - 100), 32)

Definition at line 68 of file spgtextproc.c.

Referenced by spg_text_picksplit().

Typedef Documentation

Function Documentation

static int cmpNodePtr ( const void *  a,
const void *  b 
)
static

Definition at line 308 of file spgtextproc.c.

References spgNodePtr::c.

Referenced by spg_text_picksplit().

309 {
310  const spgNodePtr *aa = (const spgNodePtr *) a;
311  const spgNodePtr *bb = (const spgNodePtr *) b;
312 
313  return aa->c - bb->c;
314 }
static int commonPrefix ( const char *  a,
const char *  b,
int  lena,
int  lenb 
)
static

Definition at line 122 of file spgtextproc.c.

References i.

Referenced by spg_text_choose(), and spg_text_picksplit().

123 {
124  int i = 0;
125 
126  while (i < lena && i < lenb && *a == *b)
127  {
128  a++;
129  b++;
130  i++;
131  }
132 
133  return i;
134 }
int i
static Datum formTextDatum ( const char *  data,
int  datalen 
)
static

Definition at line 97 of file spgtextproc.c.

References palloc(), PointerGetDatum, SET_VARSIZE, SET_VARSIZE_SHORT, VARATT_SHORT_MAX, VARHDRSZ, and VARHDRSZ_SHORT.

Referenced by spg_text_choose(), and spg_text_picksplit().

98 {
99  char *p;
100 
101  p = (char *) palloc(datalen + VARHDRSZ);
102 
103  if (datalen + VARHDRSZ_SHORT <= VARATT_SHORT_MAX)
104  {
105  SET_VARSIZE_SHORT(p, datalen + VARHDRSZ_SHORT);
106  if (datalen)
107  memcpy(p + VARHDRSZ_SHORT, data, datalen);
108  }
109  else
110  {
111  SET_VARSIZE(p, datalen + VARHDRSZ);
112  memcpy(p + VARHDRSZ, data, datalen);
113  }
114 
115  return PointerGetDatum(p);
116 }
#define SET_VARSIZE_SHORT(PTR, len)
Definition: postgres.h:329
#define VARHDRSZ_SHORT
Definition: postgres.h:269
#define VARATT_SHORT_MAX
Definition: postgres.h:270
#define PointerGetDatum(X)
Definition: postgres.h:562
#define VARHDRSZ
Definition: c.h:445
void * palloc(Size size)
Definition: mcxt.c:849
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:328
static bool searchChar ( Datum nodeLabels,
int  nNodes,
int16  c,
int *  i 
)
static

Definition at line 142 of file spgtextproc.c.

References DatumGetInt16.

Referenced by spg_text_choose().

143 {
144  int StopLow = 0,
145  StopHigh = nNodes;
146 
147  while (StopLow < StopHigh)
148  {
149  int StopMiddle = (StopLow + StopHigh) >> 1;
150  int16 middle = DatumGetInt16(nodeLabels[StopMiddle]);
151 
152  if (c < middle)
153  StopHigh = StopMiddle;
154  else if (c > middle)
155  StopLow = StopMiddle + 1;
156  else
157  {
158  *i = StopMiddle;
159  return true;
160  }
161  }
162 
163  *i = StopHigh;
164  return false;
165 }
signed short int16
Definition: c.h:255
char * c
#define DatumGetInt16(X)
Definition: postgres.h:450
int i
Datum spg_text_choose ( PG_FUNCTION_ARGS  )

Definition at line 168 of file spgtextproc.c.

References spgChooseOut::addNode, spgChooseIn::allTheSame, commonPrefix(), spgChooseIn::datum, DatumGetTextPP, formTextDatum(), spgChooseIn::hasPrefix, i, Int16GetDatum, spgChooseIn::level, spgChooseOut::matchNode, spgChooseIn::nNodes, spgChooseIn::nodeLabels, NULL, palloc(), PG_GETARG_POINTER, PG_RETURN_VOID, spgChooseIn::prefixDatum, spgChooseOut::result, spgChooseOut::resultType, searchChar(), spgAddNode, spgMatchNode, spgSplitTuple, spgChooseOut::splitTuple, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

169 {
172  text *inText = DatumGetTextPP(in->datum);
173  char *inStr = VARDATA_ANY(inText);
174  int inSize = VARSIZE_ANY_EXHDR(inText);
175  char *prefixStr = NULL;
176  int prefixSize = 0;
177  int commonLen = 0;
178  int16 nodeChar = 0;
179  int i = 0;
180 
181  /* Check for prefix match, set nodeChar to first byte after prefix */
182  if (in->hasPrefix)
183  {
184  text *prefixText = DatumGetTextPP(in->prefixDatum);
185 
186  prefixStr = VARDATA_ANY(prefixText);
187  prefixSize = VARSIZE_ANY_EXHDR(prefixText);
188 
189  commonLen = commonPrefix(inStr + in->level,
190  prefixStr,
191  inSize - in->level,
192  prefixSize);
193 
194  if (commonLen == prefixSize)
195  {
196  if (inSize - in->level > commonLen)
197  nodeChar = *(unsigned char *) (inStr + in->level + commonLen);
198  else
199  nodeChar = -1;
200  }
201  else
202  {
203  /* Must split tuple because incoming value doesn't match prefix */
204  out->resultType = spgSplitTuple;
205 
206  if (commonLen == 0)
207  {
208  out->result.splitTuple.prefixHasPrefix = false;
209  }
210  else
211  {
212  out->result.splitTuple.prefixHasPrefix = true;
213  out->result.splitTuple.prefixPrefixDatum =
214  formTextDatum(prefixStr, commonLen);
215  }
216  out->result.splitTuple.prefixNNodes = 1;
217  out->result.splitTuple.prefixNodeLabels =
218  (Datum *) palloc(sizeof(Datum));
219  out->result.splitTuple.prefixNodeLabels[0] =
220  Int16GetDatum(*(unsigned char *) (prefixStr + commonLen));
221 
222  out->result.splitTuple.childNodeN = 0;
223 
224  if (prefixSize - commonLen == 1)
225  {
226  out->result.splitTuple.postfixHasPrefix = false;
227  }
228  else
229  {
230  out->result.splitTuple.postfixHasPrefix = true;
231  out->result.splitTuple.postfixPrefixDatum =
232  formTextDatum(prefixStr + commonLen + 1,
233  prefixSize - commonLen - 1);
234  }
235 
236  PG_RETURN_VOID();
237  }
238  }
239  else if (inSize > in->level)
240  {
241  nodeChar = *(unsigned char *) (inStr + in->level);
242  }
243  else
244  {
245  nodeChar = -1;
246  }
247 
248  /* Look up nodeChar in the node label array */
249  if (searchChar(in->nodeLabels, in->nNodes, nodeChar, &i))
250  {
251  /*
252  * Descend to existing node. (If in->allTheSame, the core code will
253  * ignore our nodeN specification here, but that's OK. We still have
254  * to provide the correct levelAdd and restDatum values, and those are
255  * the same regardless of which node gets chosen by core.)
256  */
257  int levelAdd;
258 
259  out->resultType = spgMatchNode;
260  out->result.matchNode.nodeN = i;
261  levelAdd = commonLen;
262  if (nodeChar >= 0)
263  levelAdd++;
264  out->result.matchNode.levelAdd = levelAdd;
265  if (inSize - in->level - levelAdd > 0)
266  out->result.matchNode.restDatum =
267  formTextDatum(inStr + in->level + levelAdd,
268  inSize - in->level - levelAdd);
269  else
270  out->result.matchNode.restDatum =
271  formTextDatum(NULL, 0);
272  }
273  else if (in->allTheSame)
274  {
275  /*
276  * Can't use AddNode action, so split the tuple. The upper tuple has
277  * the same prefix as before and uses a dummy node label -2 for the
278  * lower tuple. The lower tuple has no prefix and the same node
279  * labels as the original tuple.
280  *
281  * Note: it might seem tempting to shorten the upper tuple's prefix,
282  * if it has one, then use its last byte as label for the lower tuple.
283  * But that doesn't win since we know the incoming value matches the
284  * whole prefix: we'd just end up splitting the lower tuple again.
285  */
286  out->resultType = spgSplitTuple;
287  out->result.splitTuple.prefixHasPrefix = in->hasPrefix;
288  out->result.splitTuple.prefixPrefixDatum = in->prefixDatum;
289  out->result.splitTuple.prefixNNodes = 1;
290  out->result.splitTuple.prefixNodeLabels = (Datum *) palloc(sizeof(Datum));
291  out->result.splitTuple.prefixNodeLabels[0] = Int16GetDatum(-2);
292  out->result.splitTuple.childNodeN = 0;
293  out->result.splitTuple.postfixHasPrefix = false;
294  }
295  else
296  {
297  /* Add a node for the not-previously-seen nodeChar value */
298  out->resultType = spgAddNode;
299  out->result.addNode.nodeLabel = Int16GetDatum(nodeChar);
300  out->result.addNode.nodeN = i;
301  }
302 
303  PG_RETURN_VOID();
304 }
signed short int16
Definition: c.h:255
Datum datum
Definition: spgist.h:56
bool hasPrefix
Definition: spgist.h:62
#define VARDATA_ANY(PTR)
Definition: postgres.h:347
int level
Definition: spgist.h:58
#define DatumGetTextPP(X)
Definition: fmgr.h:248
#define Int16GetDatum(X)
Definition: postgres.h:457
Datum prefixDatum
Definition: spgist.h:63
union spgChooseOut::@42 result
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:233
struct spgChooseOut::@42::@44 addNode
int nNodes
Definition: spgist.h:64
static Datum formTextDatum(const char *data, int datalen)
Definition: spgtextproc.c:97
uintptr_t Datum
Definition: postgres.h:372
spgChooseResultType resultType
Definition: spgist.h:77
static int commonPrefix(const char *a, const char *b, int lena, int lenb)
Definition: spgtextproc.c:122
struct spgChooseOut::@42::@43 matchNode
#define PG_RETURN_VOID()
Definition: fmgr.h:301
#define NULL
Definition: c.h:229
Datum * nodeLabels
Definition: spgist.h:65
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:340
void * palloc(Size size)
Definition: mcxt.c:849
int i
bool allTheSame
Definition: spgist.h:61
Definition: c.h:439
struct spgChooseOut::@42::@45 splitTuple
static bool searchChar(Datum *nodeLabels, int nNodes, int16 c, int *i)
Definition: spgtextproc.c:142
Datum spg_text_config ( PG_FUNCTION_ARGS  )

Definition at line 80 of file spgtextproc.c.

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

81 {
82  /* spgConfigIn *cfgin = (spgConfigIn *) PG_GETARG_POINTER(0); */
84 
85  cfg->prefixType = TEXTOID;
86  cfg->labelType = INT2OID;
87  cfg->canReturnData = true;
88  cfg->longValuesOK = true; /* suffixing will shorten long values */
90 }
bool canReturnData
Definition: spgist.h:47
#define TEXTOID
Definition: pg_type.h:324
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:233
#define INT2OID
Definition: pg_type.h:308
bool longValuesOK
Definition: spgist.h:48
Oid prefixType
Definition: spgist.h:45
#define PG_RETURN_VOID()
Definition: fmgr.h:301
Oid labelType
Definition: spgist.h:46
Datum spg_text_inner_consistent ( PG_FUNCTION_ARGS  )

Definition at line 410 of file spgtextproc.c.

References Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, datumCopy(), DatumGetInt16, DatumGetPointer, DatumGetTextPP, elog, ERROR, spgInnerConsistentIn::hasPrefix, i, lc_collate_is_c(), spgInnerConsistentIn::level, spgInnerConsistentOut::levelAdds, Min, spgInnerConsistentIn::nkeys, spgInnerConsistentIn::nNodes, spgInnerConsistentOut::nNodes, spgInnerConsistentIn::nodeLabels, spgInnerConsistentOut::nodeNumbers, NULL, palloc(), PG_GET_COLLATION, PG_GETARG_POINTER, PG_RETURN_VOID, PointerGetDatum, spgInnerConsistentIn::prefixDatum, spgInnerConsistentIn::reconstructedValue, spgInnerConsistentOut::reconstructedValues, spgInnerConsistentIn::scankeys, SET_VARSIZE, ScanKeyData::sk_argument, ScanKeyData::sk_strategy, VARDATA, VARDATA_ANY, VARHDRSZ, and VARSIZE_ANY_EXHDR.

411 {
414  bool collate_is_c = lc_collate_is_c(PG_GET_COLLATION());
415  text *reconstructedValue;
416  text *reconstrText;
417  int maxReconstrLen;
418  text *prefixText = NULL;
419  int prefixSize = 0;
420  int i;
421 
422  /*
423  * Reconstruct values represented at this tuple, including parent data,
424  * prefix of this tuple if any, and the node label if it's non-dummy.
425  * in->level should be the length of the previously reconstructed value,
426  * and the number of bytes added here is prefixSize or prefixSize + 1.
427  *
428  * Note: we assume that in->reconstructedValue isn't toasted and doesn't
429  * have a short varlena header. This is okay because it must have been
430  * created by a previous invocation of this routine, and we always emit
431  * long-format reconstructed values.
432  */
433  reconstructedValue = (text *) DatumGetPointer(in->reconstructedValue);
434  Assert(reconstructedValue == NULL ? in->level == 0 :
435  VARSIZE_ANY_EXHDR(reconstructedValue) == in->level);
436 
437  maxReconstrLen = in->level + 1;
438  if (in->hasPrefix)
439  {
440  prefixText = DatumGetTextPP(in->prefixDatum);
441  prefixSize = VARSIZE_ANY_EXHDR(prefixText);
442  maxReconstrLen += prefixSize;
443  }
444 
445  reconstrText = palloc(VARHDRSZ + maxReconstrLen);
446  SET_VARSIZE(reconstrText, VARHDRSZ + maxReconstrLen);
447 
448  if (in->level)
449  memcpy(VARDATA(reconstrText),
450  VARDATA(reconstructedValue),
451  in->level);
452  if (prefixSize)
453  memcpy(((char *) VARDATA(reconstrText)) + in->level,
454  VARDATA_ANY(prefixText),
455  prefixSize);
456  /* last byte of reconstrText will be filled in below */
457 
458  /*
459  * Scan the child nodes. For each one, complete the reconstructed value
460  * and see if it's consistent with the query. If so, emit an entry into
461  * the output arrays.
462  */
463  out->nodeNumbers = (int *) palloc(sizeof(int) * in->nNodes);
464  out->levelAdds = (int *) palloc(sizeof(int) * in->nNodes);
465  out->reconstructedValues = (Datum *) palloc(sizeof(Datum) * in->nNodes);
466  out->nNodes = 0;
467 
468  for (i = 0; i < in->nNodes; i++)
469  {
470  int16 nodeChar = DatumGetInt16(in->nodeLabels[i]);
471  int thisLen;
472  bool res = true;
473  int j;
474 
475  /* If nodeChar is a dummy value, don't include it in data */
476  if (nodeChar <= 0)
477  thisLen = maxReconstrLen - 1;
478  else
479  {
480  ((unsigned char *) VARDATA(reconstrText))[maxReconstrLen - 1] = nodeChar;
481  thisLen = maxReconstrLen;
482  }
483 
484  for (j = 0; j < in->nkeys; j++)
485  {
486  StrategyNumber strategy = in->scankeys[j].sk_strategy;
487  text *inText;
488  int inSize;
489  int r;
490 
491  /*
492  * If it's a collation-aware operator, but the collation is C, we
493  * can treat it as non-collation-aware. With non-C collation we
494  * need to traverse whole tree :-( so there's no point in making
495  * any check here. (Note also that our reconstructed value may
496  * well end with a partial multibyte character, so that applying
497  * any encoding-sensitive test to it would be risky anyhow.)
498  */
499  if (strategy > 10)
500  {
501  if (collate_is_c)
502  strategy -= 10;
503  else
504  continue;
505  }
506 
507  inText = DatumGetTextPP(in->scankeys[j].sk_argument);
508  inSize = VARSIZE_ANY_EXHDR(inText);
509 
510  r = memcmp(VARDATA(reconstrText), VARDATA_ANY(inText),
511  Min(inSize, thisLen));
512 
513  switch (strategy)
514  {
517  if (r > 0)
518  res = false;
519  break;
521  if (r != 0 || inSize < thisLen)
522  res = false;
523  break;
526  if (r < 0)
527  res = false;
528  break;
529  default:
530  elog(ERROR, "unrecognized strategy number: %d",
531  in->scankeys[j].sk_strategy);
532  break;
533  }
534 
535  if (!res)
536  break; /* no need to consider remaining conditions */
537  }
538 
539  if (res)
540  {
541  out->nodeNumbers[out->nNodes] = i;
542  out->levelAdds[out->nNodes] = thisLen - in->level;
543  SET_VARSIZE(reconstrText, VARHDRSZ + thisLen);
544  out->reconstructedValues[out->nNodes] =
545  datumCopy(PointerGetDatum(reconstrText), false, -1);
546  out->nNodes++;
547  }
548  }
549 
550  PG_RETURN_VOID();
551 }
signed short int16
Definition: c.h:255
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define VARDATA_ANY(PTR)
Definition: postgres.h:347
#define VARDATA(PTR)
Definition: postgres.h:303
#define PointerGetDatum(X)
Definition: postgres.h:562
#define VARHDRSZ
Definition: c.h:445
#define DatumGetTextPP(X)
Definition: fmgr.h:248
#define Min(x, y)
Definition: c.h:806
uint16 StrategyNumber
Definition: stratnum.h:22
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:233
Datum reconstructedValue
Definition: spgist.h:138
#define PG_GET_COLLATION()
Definition: fmgr.h:155
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
#define ERROR
Definition: elog.h:43
bool lc_collate_is_c(Oid collation)
Definition: pg_locale.c:1128
StrategyNumber sk_strategy
Definition: skey.h:68
#define DatumGetInt16(X)
Definition: postgres.h:450
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:128
uintptr_t Datum
Definition: postgres.h:372
Datum * nodeLabels
Definition: spgist.h:150
#define PG_RETURN_VOID()
Definition: fmgr.h:301
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
Datum * reconstructedValues
Definition: spgist.h:158
ScanKey scankeys
Definition: spgist.h:135
#define DatumGetPointer(X)
Definition: postgres.h:555
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:340
void * palloc(Size size)
Definition: mcxt.c:849
int i
Definition: c.h:439
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:328
#define elog
Definition: elog.h:219
#define BTLessStrategyNumber
Definition: stratnum.h:29
Datum sk_argument
Definition: skey.h:72
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
Datum spg_text_leaf_consistent ( PG_FUNCTION_ARGS  )

Definition at line 554 of file spgtextproc.c.

References Assert, BTEqualStrategyNumber, BTGreaterEqualStrategyNumber, BTGreaterStrategyNumber, BTLessEqualStrategyNumber, BTLessStrategyNumber, DatumGetPointer, DatumGetTextPP, elog, ERROR, spgLeafConsistentIn::leafDatum, spgLeafConsistentOut::leafValue, spgLeafConsistentIn::level, Min, spgLeafConsistentIn::nkeys, NULL, palloc(), PG_GET_COLLATION, PG_GETARG_POINTER, PG_RETURN_BOOL, pg_verifymbstr(), PointerGetDatum, spgLeafConsistentOut::recheck, spgLeafConsistentIn::reconstructedValue, spgLeafConsistentIn::scankeys, SET_VARSIZE, ScanKeyData::sk_argument, ScanKeyData::sk_strategy, VARDATA, VARDATA_ANY, VARHDRSZ, VARSIZE_ANY_EXHDR, and varstr_cmp().

555 {
558  int level = in->level;
559  text *leafValue,
560  *reconstrValue = NULL;
561  char *fullValue;
562  int fullLen;
563  bool res;
564  int j;
565 
566  /* all tests are exact */
567  out->recheck = false;
568 
569  leafValue = DatumGetTextPP(in->leafDatum);
570 
571  /* As above, in->reconstructedValue isn't toasted or short. */
573  reconstrValue = (text *) DatumGetPointer(in->reconstructedValue);
574 
575  Assert(reconstrValue == NULL ? level == 0 :
576  VARSIZE_ANY_EXHDR(reconstrValue) == level);
577 
578  /* Reconstruct the full string represented by this leaf tuple */
579  fullLen = level + VARSIZE_ANY_EXHDR(leafValue);
580  if (VARSIZE_ANY_EXHDR(leafValue) == 0 && level > 0)
581  {
582  fullValue = VARDATA(reconstrValue);
583  out->leafValue = PointerGetDatum(reconstrValue);
584  }
585  else
586  {
587  text *fullText = palloc(VARHDRSZ + fullLen);
588 
589  SET_VARSIZE(fullText, VARHDRSZ + fullLen);
590  fullValue = VARDATA(fullText);
591  if (level)
592  memcpy(fullValue, VARDATA(reconstrValue), level);
593  if (VARSIZE_ANY_EXHDR(leafValue) > 0)
594  memcpy(fullValue + level, VARDATA_ANY(leafValue),
595  VARSIZE_ANY_EXHDR(leafValue));
596  out->leafValue = PointerGetDatum(fullText);
597  }
598 
599  /* Perform the required comparison(s) */
600  res = true;
601  for (j = 0; j < in->nkeys; j++)
602  {
603  StrategyNumber strategy = in->scankeys[j].sk_strategy;
604  text *query = DatumGetTextPP(in->scankeys[j].sk_argument);
605  int queryLen = VARSIZE_ANY_EXHDR(query);
606  int r;
607 
608  if (strategy > 10)
609  {
610  /* Collation-aware comparison */
611  strategy -= 10;
612 
613  /* If asserts enabled, verify encoding of reconstructed string */
614  Assert(pg_verifymbstr(fullValue, fullLen, false));
615 
616  r = varstr_cmp(fullValue, Min(queryLen, fullLen),
617  VARDATA_ANY(query), Min(queryLen, fullLen),
618  PG_GET_COLLATION());
619  }
620  else
621  {
622  /* Non-collation-aware comparison */
623  r = memcmp(fullValue, VARDATA_ANY(query), Min(queryLen, fullLen));
624  }
625 
626  if (r == 0)
627  {
628  if (queryLen > fullLen)
629  r = -1;
630  else if (queryLen < fullLen)
631  r = 1;
632  }
633 
634  switch (strategy)
635  {
637  res = (r < 0);
638  break;
640  res = (r <= 0);
641  break;
643  res = (r == 0);
644  break;
646  res = (r >= 0);
647  break;
649  res = (r > 0);
650  break;
651  default:
652  elog(ERROR, "unrecognized strategy number: %d",
653  in->scankeys[j].sk_strategy);
654  res = false;
655  break;
656  }
657 
658  if (!res)
659  break; /* no need to consider remaining conditions */
660  }
661 
662  PG_RETURN_BOOL(res);
663 }
Datum reconstructedValue
Definition: spgist.h:170
#define BTGreaterStrategyNumber
Definition: stratnum.h:33
#define VARDATA_ANY(PTR)
Definition: postgres.h:347
#define VARDATA(PTR)
Definition: postgres.h:303
#define PointerGetDatum(X)
Definition: postgres.h:562
#define VARHDRSZ
Definition: c.h:445
#define DatumGetTextPP(X)
Definition: fmgr.h:248
#define Min(x, y)
Definition: c.h:806
uint16 StrategyNumber
Definition: stratnum.h:22
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:233
#define PG_GET_COLLATION()
Definition: fmgr.h:155
#define BTLessEqualStrategyNumber
Definition: stratnum.h:30
#define ERROR
Definition: elog.h:43
StrategyNumber sk_strategy
Definition: skey.h:68
ScanKey scankeys
Definition: spgist.h:167
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:311
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
int varstr_cmp(char *arg1, int len1, char *arg2, int len2, Oid collid)
Definition: varlena.c:1382
#define DatumGetPointer(X)
Definition: postgres.h:555
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:340
void * palloc(Size size)
Definition: mcxt.c:849
Definition: c.h:439
bool pg_verifymbstr(const char *mbstr, int len, bool noError)
Definition: wchar.c:1866
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:328
#define elog
Definition: elog.h:219
#define BTLessStrategyNumber
Definition: stratnum.h:29
Datum sk_argument
Definition: skey.h:72
#define BTEqualStrategyNumber
Definition: stratnum.h:31
#define BTGreaterEqualStrategyNumber
Definition: stratnum.h:32
Datum spg_text_picksplit ( PG_FUNCTION_ARGS  )

Definition at line 317 of file spgtextproc.c.

References spgNodePtr::c, cmpNodePtr(), commonPrefix(), spgNodePtr::d, DatumGetTextPP, spgPickSplitIn::datums, formTextDatum(), spgPickSplitOut::hasPrefix, i, spgNodePtr::i, Int16GetDatum, spgPickSplitOut::leafTupleDatums, spgPickSplitOut::mapTuplesToNodes, Min, spgPickSplitOut::nNodes, spgPickSplitOut::nodeLabels, spgPickSplitIn::nTuples, NULL, palloc(), PG_GETARG_POINTER, PG_RETURN_VOID, spgPickSplitOut::prefixDatum, qsort, SPGIST_MAX_PREFIX_LENGTH, VARDATA_ANY, and VARSIZE_ANY_EXHDR.

318 {
321  text *text0 = DatumGetTextPP(in->datums[0]);
322  int i,
323  commonLen;
324  spgNodePtr *nodes;
325 
326  /* Identify longest common prefix, if any */
327  commonLen = VARSIZE_ANY_EXHDR(text0);
328  for (i = 1; i < in->nTuples && commonLen > 0; i++)
329  {
330  text *texti = DatumGetTextPP(in->datums[i]);
331  int tmp = commonPrefix(VARDATA_ANY(text0),
332  VARDATA_ANY(texti),
333  VARSIZE_ANY_EXHDR(text0),
334  VARSIZE_ANY_EXHDR(texti));
335 
336  if (tmp < commonLen)
337  commonLen = tmp;
338  }
339 
340  /*
341  * Limit the prefix length, if necessary, to ensure that the resulting
342  * inner tuple will fit on a page.
343  */
344  commonLen = Min(commonLen, SPGIST_MAX_PREFIX_LENGTH);
345 
346  /* Set node prefix to be that string, if it's not empty */
347  if (commonLen == 0)
348  {
349  out->hasPrefix = false;
350  }
351  else
352  {
353  out->hasPrefix = true;
354  out->prefixDatum = formTextDatum(VARDATA_ANY(text0), commonLen);
355  }
356 
357  /* Extract the node label (first non-common byte) from each value */
358  nodes = (spgNodePtr *) palloc(sizeof(spgNodePtr) * in->nTuples);
359 
360  for (i = 0; i < in->nTuples; i++)
361  {
362  text *texti = DatumGetTextPP(in->datums[i]);
363 
364  if (commonLen < VARSIZE_ANY_EXHDR(texti))
365  nodes[i].c = *(unsigned char *) (VARDATA_ANY(texti) + commonLen);
366  else
367  nodes[i].c = -1; /* use -1 if string is all common */
368  nodes[i].i = i;
369  nodes[i].d = in->datums[i];
370  }
371 
372  /*
373  * Sort by label values so that we can group the values into nodes. This
374  * also ensures that the nodes are ordered by label value, allowing the
375  * use of binary search in searchChar.
376  */
377  qsort(nodes, in->nTuples, sizeof(*nodes), cmpNodePtr);
378 
379  /* And emit results */
380  out->nNodes = 0;
381  out->nodeLabels = (Datum *) palloc(sizeof(Datum) * in->nTuples);
382  out->mapTuplesToNodes = (int *) palloc(sizeof(int) * in->nTuples);
383  out->leafTupleDatums = (Datum *) palloc(sizeof(Datum) * in->nTuples);
384 
385  for (i = 0; i < in->nTuples; i++)
386  {
387  text *texti = DatumGetTextPP(nodes[i].d);
388  Datum leafD;
389 
390  if (i == 0 || nodes[i].c != nodes[i - 1].c)
391  {
392  out->nodeLabels[out->nNodes] = Int16GetDatum(nodes[i].c);
393  out->nNodes++;
394  }
395 
396  if (commonLen < VARSIZE_ANY_EXHDR(texti))
397  leafD = formTextDatum(VARDATA_ANY(texti) + commonLen + 1,
398  VARSIZE_ANY_EXHDR(texti) - commonLen - 1);
399  else
400  leafD = formTextDatum(NULL, 0);
401 
402  out->leafTupleDatums[nodes[i].i] = leafD;
403  out->mapTuplesToNodes[nodes[i].i] = out->nNodes - 1;
404  }
405 
406  PG_RETURN_VOID();
407 }
#define VARDATA_ANY(PTR)
Definition: postgres.h:347
Datum * leafTupleDatums
Definition: spgist.h:127
Datum * datums
Definition: spgist.h:114
#define DatumGetTextPP(X)
Definition: fmgr.h:248
#define Min(x, y)
Definition: c.h:806
#define Int16GetDatum(X)
Definition: postgres.h:457
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:233
#define SPGIST_MAX_PREFIX_LENGTH
Definition: spgtextproc.c:68
Datum * nodeLabels
Definition: spgist.h:124
char * c
static Datum formTextDatum(const char *data, int datalen)
Definition: spgtextproc.c:97
static int cmpNodePtr(const void *a, const void *b)
Definition: spgtextproc.c:308
uintptr_t Datum
Definition: postgres.h:372
static int commonPrefix(const char *a, const char *b, int lena, int lenb)
Definition: spgtextproc.c:122
#define PG_RETURN_VOID()
Definition: fmgr.h:301
#define NULL
Definition: c.h:229
bool hasPrefix
Definition: spgist.h:120
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:340
void * palloc(Size size)
Definition: mcxt.c:849
int i
int * mapTuplesToNodes
Definition: spgist.h:126
Datum prefixDatum
Definition: spgist.h:121
Definition: c.h:439
#define qsort(a, b, c, d)
Definition: port.h:440