PostgreSQL Source Code  git master
tsvector_op.c File Reference
#include "postgres.h"
#include <limits.h>
#include "access/htup_details.h"
#include "catalog/namespace.h"
#include "catalog/pg_type.h"
#include "commands/trigger.h"
#include "executor/spi.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "parser/parse_coerce.h"
#include "tsearch/ts_utils.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/lsyscache.h"
#include "utils/regproc.h"
#include "utils/rel.h"
Include dependency graph for tsvector_op.c:

Go to the source code of this file.

Data Structures

struct  CHKVAL
 
struct  StatEntry
 
struct  TSVectorStat
 

Macros

#define STATENTRYHDRSZ   (offsetof(StatEntry, lexeme))
 
#define TSVECTORCMPFUNC(type, action, ret)
 
#define compareEntry(pa, a, pb, b)
 
#define TSPO_L_ONLY   0x01 /* emit positions appearing only in L */
 
#define TSPO_R_ONLY   0x02 /* emit positions appearing only in R */
 
#define TSPO_BOTH   0x04 /* emit positions appearing in both L&R */
 
#define compareStatWord(a, e, t)
 

Typedefs

typedef struct StatEntry StatEntry
 

Functions

static Datum tsvector_update_trigger (PG_FUNCTION_ARGS, bool config_column)
 
static int tsvector_bsearch (const TSVector tsv, char *lexeme, int lexeme_len)
 
static int silly_cmp_tsvector (const TSVector a, const TSVector b)
 
 TSVECTORCMPFUNC (lt,<, BOOL)
 
 TSVECTORCMPFUNC (le,<=, BOOL)
 
 TSVECTORCMPFUNC (eq,==, BOOL)
 
 TSVECTORCMPFUNC (ge, >=, BOOL)
 
 TSVECTORCMPFUNC (gt, >, BOOL)
 
 TSVECTORCMPFUNC (ne, !=, BOOL)
 
 TSVECTORCMPFUNC (cmp,+, INT32)
 
Datum tsvector_strip (PG_FUNCTION_ARGS)
 
Datum tsvector_length (PG_FUNCTION_ARGS)
 
Datum tsvector_setweight (PG_FUNCTION_ARGS)
 
Datum tsvector_setweight_by_filter (PG_FUNCTION_ARGS)
 
static int32 add_pos (TSVector src, WordEntry *srcptr, TSVector dest, WordEntry *destptr, int32 maxpos)
 
static int compare_int (const void *va, const void *vb)
 
static int compare_text_lexemes (const void *va, const void *vb)
 
static TSVector tsvector_delete_by_indices (TSVector tsv, int *indices_to_delete, int indices_count)
 
Datum tsvector_delete_str (PG_FUNCTION_ARGS)
 
Datum tsvector_delete_arr (PG_FUNCTION_ARGS)
 
Datum tsvector_unnest (PG_FUNCTION_ARGS)
 
Datum tsvector_to_array (PG_FUNCTION_ARGS)
 
Datum array_to_tsvector (PG_FUNCTION_ARGS)
 
Datum tsvector_filter (PG_FUNCTION_ARGS)
 
Datum tsvector_concat (PG_FUNCTION_ARGS)
 
int32 tsCompareString (char *a, int lena, char *b, int lenb, bool prefix)
 
static bool checkclass_str (CHKVAL *chkval, WordEntry *entry, QueryOperand *val, ExecPhraseData *data)
 
static int uniqueLongPos (WordEntryPos *pos, int npos)
 
static bool checkcondition_str (void *checkval, QueryOperand *val, ExecPhraseData *data)
 
static bool TS_phrase_output (ExecPhraseData *data, ExecPhraseData *Ldata, ExecPhraseData *Rdata, int emit, int Loffset, int Roffset, int max_npos)
 
static bool TS_phrase_execute (QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond, ExecPhraseData *data)
 
bool TS_execute (QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
 
bool tsquery_requires_match (QueryItem *curitem)
 
Datum ts_match_qv (PG_FUNCTION_ARGS)
 
Datum ts_match_vq (PG_FUNCTION_ARGS)
 
Datum ts_match_tt (PG_FUNCTION_ARGS)
 
Datum ts_match_tq (PG_FUNCTION_ARGS)
 
static int check_weight (TSVector txt, WordEntry *wptr, int8 weight)
 
static void insertStatEntry (MemoryContext persistentContext, TSVectorStat *stat, TSVector txt, uint32 off)
 
static void chooseNextStatEntry (MemoryContext persistentContext, TSVectorStat *stat, TSVector txt, uint32 low, uint32 high, uint32 offset)
 
static TSVectorStatts_accum (MemoryContext persistentContext, TSVectorStat *stat, Datum data)
 
static void ts_setup_firstcall (FunctionCallInfo fcinfo, FuncCallContext *funcctx, TSVectorStat *stat)
 
static StatEntrywalkStatEntryTree (TSVectorStat *stat)
 
static Datum ts_process_call (FuncCallContext *funcctx)
 
static TSVectorStatts_stat_sql (MemoryContext persistentContext, text *txt, text *ws)
 
Datum ts_stat1 (PG_FUNCTION_ARGS)
 
Datum ts_stat2 (PG_FUNCTION_ARGS)
 
Datum tsvector_update_trigger_byid (PG_FUNCTION_ARGS)
 
Datum tsvector_update_trigger_bycolumn (PG_FUNCTION_ARGS)
 

Macro Definition Documentation

◆ compareEntry

#define compareEntry (   pa,
  a,
  pb,
 
)
Value:
tsCompareString((pa) + (a)->pos, (a)->len, \
(pb) + (b)->pos, (b)->len, \
false)
int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix)
Definition: tsvector_op.c:1159

Definition at line 346 of file tsvector_op.c.

Referenced by tsvector_concat().

◆ compareStatWord

#define compareStatWord (   a,
  e,
 
)
Value:
tsCompareString((a)->lexeme, (a)->lenlexeme, \
STRPTR(t) + (e)->pos, (e)->len, \
false)
int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix)
Definition: tsvector_op.c:1159
e
Definition: preproc-init.c:82
#define STRPTR(x)
Definition: hstore.h:76

Definition at line 2018 of file tsvector_op.c.

Referenced by insertStatEntry().

◆ STATENTRYHDRSZ

#define STATENTRYHDRSZ   (offsetof(StatEntry, lexeme))

Definition at line 55 of file tsvector_op.c.

Referenced by insertStatEntry().

◆ TSPO_BOTH

#define TSPO_BOTH   0x04 /* emit positions appearing in both L&R */

Definition at line 1430 of file tsvector_op.c.

Referenced by TS_phrase_execute(), and TS_phrase_output().

◆ TSPO_L_ONLY

#define TSPO_L_ONLY   0x01 /* emit positions appearing only in L */

Definition at line 1428 of file tsvector_op.c.

Referenced by TS_phrase_execute(), and TS_phrase_output().

◆ TSPO_R_ONLY

#define TSPO_R_ONLY   0x02 /* emit positions appearing only in R */

Definition at line 1429 of file tsvector_op.c.

Referenced by TS_phrase_execute(), and TS_phrase_output().

◆ TSVECTORCMPFUNC

#define TSVECTORCMPFUNC (   type,
  action,
  ret 
)
Value:
Datum \
tsvector_##type(PG_FUNCTION_ARGS) \
{ \
TSVector a = PG_GETARG_TSVECTOR(0); \
TSVector b = PG_GETARG_TSVECTOR(1); \
int res = silly_cmp_tsvector(a, b); \
PG_FREE_IF_COPY(a,0); \
PG_FREE_IF_COPY(b,1); \
PG_RETURN_##ret( res action 0 ); \
} \
/* keep compiler quiet - no extra ; */ \
extern int no_such_variable
static int silly_cmp_tsvector(const TSVector a, const TSVector b)
Definition: tsvector_op.c:76
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:120
#define PG_FUNCTION_ARGS
Definition: fmgr.h:188

Definition at line 135 of file tsvector_op.c.

Typedef Documentation

◆ StatEntry

Function Documentation

◆ add_pos()

static int32 add_pos ( TSVector  src,
WordEntry srcptr,
TSVector  dest,
WordEntry destptr,
int32  maxpos 
)
static

Definition at line 356 of file tsvector_op.c.

References _POSVECPTR, WordEntry::haspos, i, LIMITPOS, MAXENTRYPOS, MAXNUMPOS, POSDATALEN, POSDATAPTR, WEP_GETPOS, WEP_GETWEIGHT, WEP_SETPOS, and WEP_SETWEIGHT.

Referenced by tsvector_concat().

359 {
360  uint16 *clen = &_POSVECPTR(dest, destptr)->npos;
361  int i;
362  uint16 slen = POSDATALEN(src, srcptr),
363  startlen;
364  WordEntryPos *spos = POSDATAPTR(src, srcptr),
365  *dpos = POSDATAPTR(dest, destptr);
366 
367  if (!destptr->haspos)
368  *clen = 0;
369 
370  startlen = *clen;
371  for (i = 0;
372  i < slen && *clen < MAXNUMPOS &&
373  (*clen == 0 || WEP_GETPOS(dpos[*clen - 1]) != MAXENTRYPOS - 1);
374  i++)
375  {
376  WEP_SETWEIGHT(dpos[*clen], WEP_GETWEIGHT(spos[i]));
377  WEP_SETPOS(dpos[*clen], LIMITPOS(WEP_GETPOS(spos[i]) + maxpos));
378  (*clen)++;
379  }
380 
381  if (*clen != startlen)
382  destptr->haspos = 1;
383  return *clen - startlen;
384 }
uint16 WordEntryPos
Definition: ts_type.h:63
#define POSDATALEN(x, e)
Definition: ts_type.h:110
#define _POSVECPTR(x, e)
Definition: ts_type.h:109
#define WEP_SETPOS(x, v)
Definition: ts_type.h:83
#define POSDATAPTR(x, e)
Definition: ts_type.h:111
unsigned short uint16
Definition: c.h:357
#define MAXNUMPOS
Definition: ts_type.h:86
#define WEP_GETPOS(x)
Definition: ts_type.h:80
#define WEP_SETWEIGHT(x, v)
Definition: ts_type.h:82
uint32 haspos
Definition: ts_type.h:44
int i
#define LIMITPOS(x)
Definition: ts_type.h:87
#define WEP_GETWEIGHT(x)
Definition: ts_type.h:79
#define MAXENTRYPOS
Definition: ts_type.h:85

◆ array_to_tsvector()

Datum array_to_tsvector ( PG_FUNCTION_ARGS  )

Definition at line 755 of file tsvector_op.c.

References ARRPTR, CALCDATASIZE, compare_text_lexemes(), cur, deconstruct_array(), ereport, errcode(), errmsg(), ERROR, WordEntry::haspos, i, WordEntry::len, palloc0(), PG_FREE_IF_COPY, PG_GETARG_ARRAYTYPE_P, PG_RETURN_POINTER, WordEntry::pos, qsort, SET_VARSIZE, TSVectorData::size, STRPTR, VARDATA, VARHDRSZ, and VARSIZE.

756 {
758  TSVector tsout;
759  Datum *dlexemes;
760  WordEntry *arrout;
761  bool *nulls;
762  int nitems,
763  i,
764  j,
765  tslen,
766  datalen = 0;
767  char *cur;
768 
769  deconstruct_array(v, TEXTOID, -1, false, 'i', &dlexemes, &nulls, &nitems);
770 
771  /* Reject nulls (maybe we should just ignore them, instead?) */
772  for (i = 0; i < nitems; i++)
773  {
774  if (nulls[i])
775  ereport(ERROR,
776  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
777  errmsg("lexeme array may not contain nulls")));
778  }
779 
780  /* Sort and de-dup, because this is required for a valid tsvector. */
781  if (nitems > 1)
782  {
783  qsort(dlexemes, nitems, sizeof(Datum), compare_text_lexemes);
784  j = 0;
785  for (i = 1; i < nitems; i++)
786  {
787  if (compare_text_lexemes(&dlexemes[j], &dlexemes[i]) < 0)
788  dlexemes[++j] = dlexemes[i];
789  }
790  nitems = ++j;
791  }
792 
793  /* Calculate space needed for surviving lexemes. */
794  for (i = 0; i < nitems; i++)
795  datalen += VARSIZE(dlexemes[i]) - VARHDRSZ;
796  tslen = CALCDATASIZE(nitems, datalen);
797 
798  /* Allocate and fill tsvector. */
799  tsout = (TSVector) palloc0(tslen);
800  SET_VARSIZE(tsout, tslen);
801  tsout->size = nitems;
802 
803  arrout = ARRPTR(tsout);
804  cur = STRPTR(tsout);
805  for (i = 0; i < nitems; i++)
806  {
807  char *lex = VARDATA(dlexemes[i]);
808  int lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ;
809 
810  memcpy(cur, lex, lex_len);
811  arrout[i].haspos = 0;
812  arrout[i].len = lex_len;
813  arrout[i].pos = cur - STRPTR(tsout);
814  cur += lex_len;
815  }
816 
817  PG_FREE_IF_COPY(v, 0);
818  PG_RETURN_POINTER(tsout);
819 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
#define VARDATA(PTR)
Definition: postgres.h:302
#define VARSIZE(PTR)
Definition: postgres.h:303
#define VARHDRSZ
Definition: c.h:555
uint32 len
Definition: ts_type.h:44
struct cursor * cur
Definition: ecpg.c:28
int errcode(int sqlerrcode)
Definition: elog.c:570
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:251
#define ERROR
Definition: elog.h:43
int32 size
Definition: ts_type.h:93
uint32 haspos
Definition: ts_type.h:44
#define ereport(elevel, rest)
Definition: elog.h:141
#define CALCDATASIZE(x, lenstr)
Definition: hstore.h:72
void * palloc0(Size size)
Definition: mcxt.c:955
uintptr_t Datum
Definition: postgres.h:367
TSVectorData * TSVector
Definition: ts_type.h:98
static int compare_text_lexemes(const void *va, const void *vb)
Definition: tsvector_op.c:436
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
uint32 pos
Definition: ts_type.h:44
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3461
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define STRPTR(x)
Definition: hstore.h:76
int i
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
#define ARRPTR(x)
Definition: cube.c:25
#define qsort(a, b, c, d)
Definition: port.h:488

◆ check_weight()

static int check_weight ( TSVector  txt,
WordEntry wptr,
int8  weight 
)
static

Definition at line 2003 of file tsvector_op.c.

References POSDATALEN, POSDATAPTR, and WEP_GETWEIGHT.

Referenced by insertStatEntry().

2004 {
2005  int len = POSDATALEN(txt, wptr);
2006  int num = 0;
2007  WordEntryPos *ptr = POSDATAPTR(txt, wptr);
2008 
2009  while (len--)
2010  {
2011  if (weight & (1 << WEP_GETWEIGHT(*ptr)))
2012  num++;
2013  ptr++;
2014  }
2015  return num;
2016 }
uint16 WordEntryPos
Definition: ts_type.h:63
#define POSDATALEN(x, e)
Definition: ts_type.h:110
#define POSDATAPTR(x, e)
Definition: ts_type.h:111
#define WEP_GETWEIGHT(x)
Definition: ts_type.h:79

◆ checkclass_str()

static bool checkclass_str ( CHKVAL chkval,
WordEntry entry,
QueryOperand val,
ExecPhraseData data 
)
static

Definition at line 1196 of file tsvector_op.c.

References ExecPhraseData::allocated, WordEntry::haspos, WordEntry::len, WordEntryPosVector::npos, ExecPhraseData::npos, palloc(), WordEntry::pos, WordEntryPosVector::pos, ExecPhraseData::pos, SHORTALIGN, CHKVAL::values, QueryOperand::weight, WEP_GETPOS, and WEP_GETWEIGHT.

Referenced by checkcondition_str().

1198 {
1199  bool result = false;
1200 
1201  if (entry->haspos && (val->weight || data))
1202  {
1203  WordEntryPosVector *posvec;
1204 
1205  /*
1206  * We can't use the _POSVECPTR macro here because the pointer to the
1207  * tsvector's lexeme storage is already contained in chkval->values.
1208  */
1209  posvec = (WordEntryPosVector *)
1210  (chkval->values + SHORTALIGN(entry->pos + entry->len));
1211 
1212  if (val->weight && data)
1213  {
1214  WordEntryPos *posvec_iter = posvec->pos;
1215  WordEntryPos *dptr;
1216 
1217  /*
1218  * Filter position information by weights
1219  */
1220  dptr = data->pos = palloc(sizeof(WordEntryPos) * posvec->npos);
1221  data->allocated = true;
1222 
1223  /* Is there a position with a matching weight? */
1224  while (posvec_iter < posvec->pos + posvec->npos)
1225  {
1226  /* If true, append this position to the data->pos */
1227  if (val->weight & (1 << WEP_GETWEIGHT(*posvec_iter)))
1228  {
1229  *dptr = WEP_GETPOS(*posvec_iter);
1230  dptr++;
1231  }
1232 
1233  posvec_iter++;
1234  }
1235 
1236  data->npos = dptr - data->pos;
1237 
1238  if (data->npos > 0)
1239  result = true;
1240  }
1241  else if (val->weight)
1242  {
1243  WordEntryPos *posvec_iter = posvec->pos;
1244 
1245  /* Is there a position with a matching weight? */
1246  while (posvec_iter < posvec->pos + posvec->npos)
1247  {
1248  if (val->weight & (1 << WEP_GETWEIGHT(*posvec_iter)))
1249  {
1250  result = true;
1251  break; /* no need to go further */
1252  }
1253 
1254  posvec_iter++;
1255  }
1256  }
1257  else /* data != NULL */
1258  {
1259  data->npos = posvec->npos;
1260  data->pos = posvec->pos;
1261  data->allocated = false;
1262  result = true;
1263  }
1264  }
1265  else
1266  {
1267  result = true;
1268  }
1269 
1270  return result;
1271 }
uint16 WordEntryPos
Definition: ts_type.h:63
bool allocated
Definition: ts_utils.h:152
uint32 len
Definition: ts_type.h:44
uint8 weight
Definition: ts_type.h:146
#define WEP_GETPOS(x)
Definition: ts_type.h:80
WordEntryPos pos[FLEXIBLE_ARRAY_MEMBER]
Definition: ts_type.h:68
WordEntryPos * pos
Definition: ts_utils.h:154
uint32 haspos
Definition: ts_type.h:44
uint32 pos
Definition: ts_type.h:44
char * values
Definition: tsvector_op.c:39
void * palloc(Size size)
Definition: mcxt.c:924
#define WEP_GETWEIGHT(x)
Definition: ts_type.h:79
#define SHORTALIGN(LEN)
Definition: c.h:681

◆ checkcondition_str()

static bool checkcondition_str ( void *  checkval,
QueryOperand val,
ExecPhraseData data 
)
static

Definition at line 1310 of file tsvector_op.c.

References ExecPhraseData::allocated, CHKVAL::arrb, CHKVAL::arre, checkclass_str(), difference(), QueryOperand::distance, WordEntry::len, QueryOperand::length, ExecPhraseData::npos, CHKVAL::operand, palloc(), WordEntry::pos, ExecPhraseData::pos, QueryOperand::prefix, repalloc(), tsCompareString(), uniqueLongPos(), and CHKVAL::values.

Referenced by ts_match_vq().

1311 {
1312  CHKVAL *chkval = (CHKVAL *) checkval;
1313  WordEntry *StopLow = chkval->arrb;
1314  WordEntry *StopHigh = chkval->arre;
1315  WordEntry *StopMiddle = StopHigh;
1316  int difference = -1;
1317  bool res = false;
1318 
1319  /* Loop invariant: StopLow <= val < StopHigh */
1320  while (StopLow < StopHigh)
1321  {
1322  StopMiddle = StopLow + (StopHigh - StopLow) / 2;
1323  difference = tsCompareString(chkval->operand + val->distance,
1324  val->length,
1325  chkval->values + StopMiddle->pos,
1326  StopMiddle->len,
1327  false);
1328 
1329  if (difference == 0)
1330  {
1331  /* Check weight info & fill 'data' with positions */
1332  res = checkclass_str(chkval, StopMiddle, val, data);
1333  break;
1334  }
1335  else if (difference > 0)
1336  StopLow = StopMiddle + 1;
1337  else
1338  StopHigh = StopMiddle;
1339  }
1340 
1341  if ((!res || data) && val->prefix)
1342  {
1343  WordEntryPos *allpos = NULL;
1344  int npos = 0,
1345  totalpos = 0;
1346 
1347  /*
1348  * there was a failed exact search, so we should scan further to find
1349  * a prefix match. We also need to do so if caller needs position info
1350  */
1351  if (StopLow >= StopHigh)
1352  StopMiddle = StopHigh;
1353 
1354  while ((!res || data) && StopMiddle < chkval->arre &&
1355  tsCompareString(chkval->operand + val->distance,
1356  val->length,
1357  chkval->values + StopMiddle->pos,
1358  StopMiddle->len,
1359  true) == 0)
1360  {
1361  if (data)
1362  {
1363  /*
1364  * We need to join position information
1365  */
1366  res = checkclass_str(chkval, StopMiddle, val, data);
1367 
1368  if (res)
1369  {
1370  while (npos + data->npos >= totalpos)
1371  {
1372  if (totalpos == 0)
1373  {
1374  totalpos = 256;
1375  allpos = palloc(sizeof(WordEntryPos) * totalpos);
1376  }
1377  else
1378  {
1379  totalpos *= 2;
1380  allpos = repalloc(allpos, sizeof(WordEntryPos) * totalpos);
1381  }
1382  }
1383 
1384  memcpy(allpos + npos, data->pos, sizeof(WordEntryPos) * data->npos);
1385  npos += data->npos;
1386  }
1387  }
1388  else
1389  {
1390  res = checkclass_str(chkval, StopMiddle, val, NULL);
1391  }
1392 
1393  StopMiddle++;
1394  }
1395 
1396  if (res && data)
1397  {
1398  /* Sort and make unique array of found positions */
1399  data->pos = allpos;
1400  data->npos = uniqueLongPos(allpos, npos);
1401  data->allocated = true;
1402  }
1403  }
1404 
1405  return res;
1406 }
uint16 WordEntryPos
Definition: ts_type.h:63
static int uniqueLongPos(WordEntryPos *pos, int npos)
Definition: tsvector_op.c:1280
bool allocated
Definition: ts_utils.h:152
uint32 len
Definition: ts_type.h:44
uint32 distance
Definition: ts_type.h:158
int32 * arrb
Definition: _int_bool.c:228
char * operand
Definition: ltxtquery_op.c:52
WordEntryPos * pos
Definition: ts_utils.h:154
Datum difference(PG_FUNCTION_ARGS)
int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix)
Definition: tsvector_op.c:1159
uint32 pos
Definition: ts_type.h:44
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1044
uint32 length
Definition: ts_type.h:158
char * values
Definition: tsvector_op.c:39
void * palloc(Size size)
Definition: mcxt.c:924
int32 * arre
Definition: _int_bool.c:229
bool prefix
Definition: ts_type.h:150
static bool checkclass_str(CHKVAL *chkval, WordEntry *entry, QueryOperand *val, ExecPhraseData *data)
Definition: tsvector_op.c:1196

◆ chooseNextStatEntry()

static void chooseNextStatEntry ( MemoryContext  persistentContext,
TSVectorStat stat,
TSVector  txt,
uint32  low,
uint32  high,
uint32  offset 
)
static

Definition at line 2090 of file tsvector_op.c.

References insertStatEntry().

Referenced by ts_accum().

2092 {
2093  uint32 pos;
2094  uint32 middle = (low + high) >> 1;
2095 
2096  pos = (low + middle) >> 1;
2097  if (low != middle && pos >= offset && pos - offset < txt->size)
2098  insertStatEntry(persistentContext, stat, txt, pos - offset);
2099  pos = (high + middle + 1) >> 1;
2100  if (middle + 1 != high && pos >= offset && pos - offset < txt->size)
2101  insertStatEntry(persistentContext, stat, txt, pos - offset);
2102 
2103  if (low != middle)
2104  chooseNextStatEntry(persistentContext, stat, txt, low, middle, offset);
2105  if (high != middle + 1)
2106  chooseNextStatEntry(persistentContext, stat, txt, middle + 1, high, offset);
2107 }
static void chooseNextStatEntry(MemoryContext persistentContext, TSVectorStat *stat, TSVector txt, uint32 low, uint32 high, uint32 offset)
Definition: tsvector_op.c:2090
unsigned int uint32
Definition: c.h:358
static void insertStatEntry(MemoryContext persistentContext, TSVectorStat *stat, TSVector txt, uint32 off)
Definition: tsvector_op.c:2024

◆ compare_int()

static int compare_int ( const void *  va,
const void *  vb 
)
static

Definition at line 425 of file tsvector_op.c.

Referenced by tsvector_delete_by_indices().

426 {
427  int a = *((const int *) va);
428  int b = *((const int *) vb);
429 
430  if (a == b)
431  return 0;
432  return (a > b) ? 1 : -1;
433 }

◆ compare_text_lexemes()

static int compare_text_lexemes ( const void *  va,
const void *  vb 
)
static

Definition at line 436 of file tsvector_op.c.

References tsCompareString(), VARDATA_ANY, and VARSIZE_ANY_EXHDR.

Referenced by array_to_tsvector().

437 {
438  Datum a = *((const Datum *) va);
439  Datum b = *((const Datum *) vb);
440  char *alex = VARDATA_ANY(a);
441  int alex_len = VARSIZE_ANY_EXHDR(a);
442  char *blex = VARDATA_ANY(b);
443  int blex_len = VARSIZE_ANY_EXHDR(b);
444 
445  return tsCompareString(alex, alex_len, blex, blex_len, false);
446 }
#define VARDATA_ANY(PTR)
Definition: postgres.h:348
uintptr_t Datum
Definition: postgres.h:367
int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix)
Definition: tsvector_op.c:1159
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:341

◆ insertStatEntry()

static void insertStatEntry ( MemoryContext  persistentContext,
TSVectorStat stat,
TSVector  txt,
uint32  off 
)
static

Definition at line 2024 of file tsvector_op.c.

References ARRPTR, check_weight(), compareStatWord, WordEntry::haspos, StatEntry::left, WordEntry::len, StatEntry::lenlexeme, StatEntry::lexeme, TSVectorStat::maxdepth, MemoryContextAlloc(), StatEntry::ndoc, StatEntry::nentry, WordEntry::pos, POSDATALEN, StatEntry::right, TSVectorStat::root, STATENTRYHDRSZ, STRPTR, and TSVectorStat::weight.

Referenced by chooseNextStatEntry(), and ts_accum().

2025 {
2026  WordEntry *we = ARRPTR(txt) + off;
2027  StatEntry *node = stat->root,
2028  *pnode = NULL;
2029  int n,
2030  res = 0;
2031  uint32 depth = 1;
2032 
2033  if (stat->weight == 0)
2034  n = (we->haspos) ? POSDATALEN(txt, we) : 1;
2035  else
2036  n = (we->haspos) ? check_weight(txt, we, stat->weight) : 0;
2037 
2038  if (n == 0)
2039  return; /* nothing to insert */
2040 
2041  while (node)
2042  {
2043  res = compareStatWord(node, we, txt);
2044 
2045  if (res == 0)
2046  {
2047  break;
2048  }
2049  else
2050  {
2051  pnode = node;
2052  node = (res < 0) ? node->left : node->right;
2053  }
2054  depth++;
2055  }
2056 
2057  if (depth > stat->maxdepth)
2058  stat->maxdepth = depth;
2059 
2060  if (node == NULL)
2061  {
2062  node = MemoryContextAlloc(persistentContext, STATENTRYHDRSZ + we->len);
2063  node->left = node->right = NULL;
2064  node->ndoc = 1;
2065  node->nentry = n;
2066  node->lenlexeme = we->len;
2067  memcpy(node->lexeme, STRPTR(txt) + we->pos, node->lenlexeme);
2068 
2069  if (pnode == NULL)
2070  {
2071  stat->root = node;
2072  }
2073  else
2074  {
2075  if (res < 0)
2076  pnode->left = node;
2077  else
2078  pnode->right = node;
2079  }
2080 
2081  }
2082  else
2083  {
2084  node->ndoc++;
2085  node->nentry += n;
2086  }
2087 }
uint32 nentry
Definition: tsvector_op.c:48
#define POSDATALEN(x, e)
Definition: ts_type.h:110
StatEntry * root
Definition: tsvector_op.c:66
uint32 len
Definition: ts_type.h:44
uint32 ndoc
Definition: tsvector_op.c:46
unsigned int uint32
Definition: c.h:358
uint32 lenlexeme
Definition: tsvector_op.c:51
uint32 haspos
Definition: ts_type.h:44
uint32 maxdepth
Definition: tsvector_op.c:61
struct StatEntry * left
Definition: tsvector_op.c:49
static int check_weight(TSVector txt, WordEntry *wptr, int8 weight)
Definition: tsvector_op.c:2003
uint32 pos
Definition: ts_type.h:44
#define STATENTRYHDRSZ
Definition: tsvector_op.c:55
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:771
#define STRPTR(x)
Definition: hstore.h:76
#define ARRPTR(x)
Definition: cube.c:25
#define compareStatWord(a, e, t)
Definition: tsvector_op.c:2018
struct StatEntry * right
Definition: tsvector_op.c:50
char lexeme[FLEXIBLE_ARRAY_MEMBER]
Definition: tsvector_op.c:52
int32 weight
Definition: tsvector_op.c:59

◆ silly_cmp_tsvector()

static int silly_cmp_tsvector ( const TSVector  a,
const TSVector  b 
)
static

Definition at line 76 of file tsvector_op.c.

References ARRPTR, WordEntry::haspos, i, WordEntry::len, WordEntry::pos, POSDATALEN, POSDATAPTR, TSVectorData::size, STRPTR, tsCompareString(), VARSIZE, WEP_GETPOS, and WEP_GETWEIGHT.

77 {
78  if (VARSIZE(a) < VARSIZE(b))
79  return -1;
80  else if (VARSIZE(a) > VARSIZE(b))
81  return 1;
82  else if (a->size < b->size)
83  return -1;
84  else if (a->size > b->size)
85  return 1;
86  else
87  {
88  WordEntry *aptr = ARRPTR(a);
89  WordEntry *bptr = ARRPTR(b);
90  int i = 0;
91  int res;
92 
93 
94  for (i = 0; i < a->size; i++)
95  {
96  if (aptr->haspos != bptr->haspos)
97  {
98  return (aptr->haspos > bptr->haspos) ? -1 : 1;
99  }
100  else if ((res = tsCompareString(STRPTR(a) + aptr->pos, aptr->len, STRPTR(b) + bptr->pos, bptr->len, false)) != 0)
101  {
102  return res;
103  }
104  else if (aptr->haspos)
105  {
106  WordEntryPos *ap = POSDATAPTR(a, aptr);
107  WordEntryPos *bp = POSDATAPTR(b, bptr);
108  int j;
109 
110  if (POSDATALEN(a, aptr) != POSDATALEN(b, bptr))
111  return (POSDATALEN(a, aptr) > POSDATALEN(b, bptr)) ? -1 : 1;
112 
113  for (j = 0; j < POSDATALEN(a, aptr); j++)
114  {
115  if (WEP_GETPOS(*ap) != WEP_GETPOS(*bp))
116  {
117  return (WEP_GETPOS(*ap) > WEP_GETPOS(*bp)) ? -1 : 1;
118  }
119  else if (WEP_GETWEIGHT(*ap) != WEP_GETWEIGHT(*bp))
120  {
121  return (WEP_GETWEIGHT(*ap) > WEP_GETWEIGHT(*bp)) ? -1 : 1;
122  }
123  ap++, bp++;
124  }
125  }
126 
127  aptr++;
128  bptr++;
129  }
130  }
131 
132  return 0;
133 }
uint16 WordEntryPos
Definition: ts_type.h:63
#define POSDATALEN(x, e)
Definition: ts_type.h:110
#define VARSIZE(PTR)
Definition: postgres.h:303
uint32 len
Definition: ts_type.h:44
#define POSDATAPTR(x, e)
Definition: ts_type.h:111
#define WEP_GETPOS(x)
Definition: ts_type.h:80
int32 size
Definition: ts_type.h:93
uint32 haspos
Definition: ts_type.h:44
int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix)
Definition: tsvector_op.c:1159
uint32 pos
Definition: ts_type.h:44
#define STRPTR(x)
Definition: hstore.h:76
int i
#define ARRPTR(x)
Definition: cube.c:25
#define WEP_GETWEIGHT(x)
Definition: ts_type.h:79

◆ ts_accum()

static TSVectorStat* ts_accum ( MemoryContext  persistentContext,
TSVectorStat stat,
Datum  data 
)
static

Definition at line 2122 of file tsvector_op.c.

References chooseNextStatEntry(), DatumGetPointer, DatumGetTSVector, i, insertStatEntry(), TSVectorStat::maxdepth, MemoryContextAllocZero(), pfree(), TSVectorData::size, and stat.

Referenced by ts_stat_sql().

2123 {
2124  TSVector txt = DatumGetTSVector(data);
2125  uint32 i,
2126  nbit = 0,
2127  offset;
2128 
2129  if (stat == NULL)
2130  { /* Init in first */
2131  stat = MemoryContextAllocZero(persistentContext, sizeof(TSVectorStat));
2132  stat->maxdepth = 1;
2133  }
2134 
2135  /* simple check of correctness */
2136  if (txt == NULL || txt->size == 0)
2137  {
2138  if (txt && txt != (TSVector) DatumGetPointer(data))
2139  pfree(txt);
2140  return stat;
2141  }
2142 
2143  i = txt->size - 1;
2144  for (; i > 0; i >>= 1)
2145  nbit++;
2146 
2147  nbit = 1 << nbit;
2148  offset = (nbit - txt->size) / 2;
2149 
2150  insertStatEntry(persistentContext, stat, txt, (nbit >> 1) - offset);
2151  chooseNextStatEntry(persistentContext, stat, txt, 0, nbit, offset);
2152 
2153  return stat;
2154 }
static void chooseNextStatEntry(MemoryContext persistentContext, TSVectorStat *stat, TSVector txt, uint32 low, uint32 high, uint32 offset)
Definition: tsvector_op.c:2090
void pfree(void *pointer)
Definition: mcxt.c:1031
int32 size
Definition: ts_type.h:93
unsigned int uint32
Definition: c.h:358
#define DatumGetTSVector(X)
Definition: ts_type.h:117
#define stat(a, b)
Definition: win32_port.h:264
static void insertStatEntry(MemoryContext persistentContext, TSVectorStat *stat, TSVector txt, uint32 off)
Definition: tsvector_op.c:2024
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:814
uint32 maxdepth
Definition: tsvector_op.c:61
#define DatumGetPointer(X)
Definition: postgres.h:549
int i

◆ TS_execute()

bool TS_execute ( QueryItem curitem,
void *  arg,
uint32  flags,
TSExecuteCallback  chkcond 
)

Definition at line 1814 of file tsvector_op.c.

References check_stack_depth(), elog, ERROR, OP_AND, OP_NOT, OP_OR, OP_PHRASE, QI_VAL, TS_EXEC_CALC_NOT, TS_execute(), TS_phrase_execute(), and QueryItem::type.

Referenced by Cover(), gin_tsquery_consistent(), gtsvector_consistent(), hlCover(), TS_execute(), and ts_match_vq().

1816 {
1817  /* since this function recurses, it could be driven to stack overflow */
1819 
1820  if (curitem->type == QI_VAL)
1821  return chkcond(arg, (QueryOperand *) curitem,
1822  NULL /* we don't need position info */ );
1823 
1824  switch (curitem->qoperator.oper)
1825  {
1826  case OP_NOT:
1827  if (flags & TS_EXEC_CALC_NOT)
1828  return !TS_execute(curitem + 1, arg, flags, chkcond);
1829  else
1830  return true;
1831 
1832  case OP_AND:
1833  if (TS_execute(curitem + curitem->qoperator.left, arg, flags, chkcond))
1834  return TS_execute(curitem + 1, arg, flags, chkcond);
1835  else
1836  return false;
1837 
1838  case OP_OR:
1839  if (TS_execute(curitem + curitem->qoperator.left, arg, flags, chkcond))
1840  return true;
1841  else
1842  return TS_execute(curitem + 1, arg, flags, chkcond);
1843 
1844  case OP_PHRASE:
1845  return TS_phrase_execute(curitem, arg, flags, chkcond, NULL);
1846 
1847  default:
1848  elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
1849  }
1850 
1851  /* not reachable, but keep compiler quiet */
1852  return false;
1853 }
bool TS_execute(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
Definition: tsvector_op.c:1814
QueryOperator qoperator
Definition: ts_type.h:196
#define TS_EXEC_CALC_NOT
Definition: ts_utils.h:183
#define QI_VAL
Definition: ts_type.h:134
#define OP_OR
Definition: ts_type.h:168
#define OP_AND
Definition: ts_type.h:167
#define ERROR
Definition: elog.h:43
void check_stack_depth(void)
Definition: postgres.c:3262
QueryItemType type
Definition: ts_type.h:195
#define OP_PHRASE
Definition: ts_type.h:169
uint32 left
Definition: ts_type.h:184
#define elog(elevel,...)
Definition: elog.h:226
void * arg
static bool TS_phrase_execute(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond, ExecPhraseData *data)
Definition: tsvector_op.c:1571
#define OP_NOT
Definition: ts_type.h:166

◆ ts_match_qv()

Datum ts_match_qv ( PG_FUNCTION_ARGS  )

Definition at line 1914 of file tsvector_op.c.

References DirectFunctionCall2, PG_GETARG_DATUM, PG_RETURN_DATUM, and ts_match_vq().

1915 {
1917  PG_GETARG_DATUM(1),
1918  PG_GETARG_DATUM(0)));
1919 }
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:263
Datum ts_match_vq(PG_FUNCTION_ARGS)
Definition: tsvector_op.c:1922
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:343
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:618

◆ ts_match_tq()

Datum ts_match_tq ( PG_FUNCTION_ARGS  )

Definition at line 1974 of file tsvector_op.c.

References DatumGetBool, DatumGetTSVector, DirectFunctionCall1, DirectFunctionCall2, pfree(), PG_FREE_IF_COPY, PG_GETARG_DATUM, PG_GETARG_TSQUERY, PG_RETURN_BOOL, to_tsvector(), ts_match_vq(), TSQueryGetDatum, and TSVectorGetDatum.

1975 {
1976  TSVector vector;
1977  TSQuery query = PG_GETARG_TSQUERY(1);
1978  bool res;
1979 
1981  PG_GETARG_DATUM(0)));
1982 
1984  TSVectorGetDatum(vector),
1985  TSQueryGetDatum(query)));
1986 
1987  pfree(vector);
1988  PG_FREE_IF_COPY(query, 1);
1989 
1990  PG_RETURN_BOOL(res);
1991 }
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:263
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:238
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:616
void pfree(void *pointer)
Definition: mcxt.c:1031
Datum ts_match_vq(PG_FUNCTION_ARGS)
Definition: tsvector_op.c:1922
#define DatumGetBool(X)
Definition: postgres.h:393
#define TSVectorGetDatum(X)
Definition: ts_type.h:119
#define DatumGetTSVector(X)
Definition: ts_type.h:117
#define TSQueryGetDatum(X)
Definition: ts_type.h:237
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:349
Datum to_tsvector(PG_FUNCTION_ARGS)
Definition: to_tsany.c:259
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:618

◆ ts_match_tt()

Datum ts_match_tt ( PG_FUNCTION_ARGS  )

Definition at line 1952 of file tsvector_op.c.

References DatumGetBool, DatumGetTSQuery, DatumGetTSVector, DirectFunctionCall1, DirectFunctionCall2, pfree(), PG_GETARG_DATUM, PG_RETURN_BOOL, plainto_tsquery(), to_tsvector(), ts_match_vq(), TSQueryGetDatum, and TSVectorGetDatum.

1953 {
1954  TSVector vector;
1955  TSQuery query;
1956  bool res;
1957 
1959  PG_GETARG_DATUM(0)));
1961  PG_GETARG_DATUM(1)));
1962 
1964  TSVectorGetDatum(vector),
1965  TSQueryGetDatum(query)));
1966 
1967  pfree(vector);
1968  pfree(query);
1969 
1970  PG_RETURN_BOOL(res);
1971 }
#define DatumGetTSQuery(X)
Definition: ts_type.h:235
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:263
Datum plainto_tsquery(PG_FUNCTION_ARGS)
Definition: to_tsany.c:617
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:616
void pfree(void *pointer)
Definition: mcxt.c:1031
Datum ts_match_vq(PG_FUNCTION_ARGS)
Definition: tsvector_op.c:1922
#define DatumGetBool(X)
Definition: postgres.h:393
#define TSVectorGetDatum(X)
Definition: ts_type.h:119
#define DatumGetTSVector(X)
Definition: ts_type.h:117
#define TSQueryGetDatum(X)
Definition: ts_type.h:237
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:349
Datum to_tsvector(PG_FUNCTION_ARGS)
Definition: to_tsany.c:259
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:618

◆ ts_match_vq()

Datum ts_match_vq ( PG_FUNCTION_ARGS  )

Definition at line 1922 of file tsvector_op.c.

References CHKVAL::arrb, CHKVAL::arre, ARRPTR, checkcondition_str(), GETOPERAND, GETQUERY, CHKVAL::operand, PG_FREE_IF_COPY, PG_GETARG_TSQUERY, PG_GETARG_TSVECTOR, PG_RETURN_BOOL, TSVectorData::size, TSQueryData::size, STRPTR, TS_EXEC_CALC_NOT, TS_execute(), val, and CHKVAL::values.

Referenced by ts_match_qv(), ts_match_tq(), and ts_match_tt().

1923 {
1925  TSQuery query = PG_GETARG_TSQUERY(1);
1926  CHKVAL chkval;
1927  bool result;
1928 
1929  /* empty query matches nothing */
1930  if (!query->size)
1931  {
1932  PG_FREE_IF_COPY(val, 0);
1933  PG_FREE_IF_COPY(query, 1);
1934  PG_RETURN_BOOL(false);
1935  }
1936 
1937  chkval.arrb = ARRPTR(val);
1938  chkval.arre = chkval.arrb + val->size;
1939  chkval.values = STRPTR(val);
1940  chkval.operand = GETOPERAND(query);
1941  result = TS_execute(GETQUERY(query),
1942  &chkval,
1945 
1946  PG_FREE_IF_COPY(val, 0);
1947  PG_FREE_IF_COPY(query, 1);
1948  PG_RETURN_BOOL(result);
1949 }
bool TS_execute(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
Definition: tsvector_op.c:1814
#define TS_EXEC_CALC_NOT
Definition: ts_utils.h:183
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:238
#define GETQUERY(x)
Definition: _int.h:136
#define GETOPERAND(x)
Definition: ltree.h:118
int32 * arrb
Definition: _int_bool.c:228
static bool checkcondition_str(void *checkval, QueryOperand *val, ExecPhraseData *data)
Definition: tsvector_op.c:1310
char * operand
Definition: ltxtquery_op.c:52
int32 size
Definition: ts_type.h:93
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:349
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
char * values
Definition: tsvector_op.c:39
int32 * arre
Definition: _int_bool.c:229
#define STRPTR(x)
Definition: hstore.h:76
int32 size
Definition: ts_type.h:208
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:120
#define ARRPTR(x)
Definition: cube.c:25
long val
Definition: informix.c:684

◆ TS_phrase_execute()

static bool TS_phrase_execute ( QueryItem curitem,
void *  arg,
uint32  flags,
TSExecuteCallback  chkcond,
ExecPhraseData data 
)
static

Definition at line 1571 of file tsvector_op.c.

References Assert, check_stack_depth(), QueryOperand::distance, elog, ERROR, Max, Min, ExecPhraseData::negate, ExecPhraseData::npos, OP_AND, OP_NOT, OP_OR, OP_PHRASE, QI_VAL, true, TS_EXEC_PHRASE_NO_POS, TS_phrase_output(), TSPO_BOTH, TSPO_L_ONLY, TSPO_R_ONLY, QueryItem::type, and ExecPhraseData::width.

Referenced by TS_execute().

1574 {
1575  ExecPhraseData Ldata,
1576  Rdata;
1577  bool lmatch,
1578  rmatch;
1579  int Loffset,
1580  Roffset,
1581  maxwidth;
1582 
1583  /* since this function recurses, it could be driven to stack overflow */
1585 
1586  if (curitem->type == QI_VAL)
1587  return chkcond(arg, (QueryOperand *) curitem, data);
1588 
1589  switch (curitem->qoperator.oper)
1590  {
1591  case OP_NOT:
1592 
1593  /*
1594  * Because a "true" result with no specific positions is taken as
1595  * uncertain, we need no special care here for !TS_EXEC_CALC_NOT.
1596  * If it's a false positive, the right things happen anyway.
1597  *
1598  * Also, we need not touch data->width, since a NOT operation does
1599  * not change the match width.
1600  */
1601  if (TS_phrase_execute(curitem + 1, arg, flags, chkcond, data))
1602  {
1603  if (data->npos > 0)
1604  {
1605  /* we have some positions, invert negate flag */
1606  data->negate = !data->negate;
1607  return true;
1608  }
1609  else if (data->negate)
1610  {
1611  /* change "match everywhere" to "match nowhere" */
1612  data->negate = false;
1613  return false;
1614  }
1615  /* match positions are, and remain, uncertain */
1616  return true;
1617  }
1618  else
1619  {
1620  /* change "match nowhere" to "match everywhere" */
1621  Assert(data->npos == 0 && !data->negate);
1622  data->negate = true;
1623  return true;
1624  }
1625 
1626  case OP_PHRASE:
1627  case OP_AND:
1628  memset(&Ldata, 0, sizeof(Ldata));
1629  memset(&Rdata, 0, sizeof(Rdata));
1630 
1631  if (!TS_phrase_execute(curitem + curitem->qoperator.left,
1632  arg, flags, chkcond, &Ldata))
1633  return false;
1634 
1635  if (!TS_phrase_execute(curitem + 1,
1636  arg, flags, chkcond, &Rdata))
1637  return false;
1638 
1639  /*
1640  * If either operand has no position information, then we can't
1641  * return position data, only a "possible match" result. "Possible
1642  * match" answers are only wanted when TS_EXEC_PHRASE_NO_POS flag
1643  * is set, otherwise return false.
1644  */
1645  if ((Ldata.npos == 0 && !Ldata.negate) ||
1646  (Rdata.npos == 0 && !Rdata.negate))
1647  return (flags & TS_EXEC_PHRASE_NO_POS) ? true : false;
1648 
1649  if (curitem->qoperator.oper == OP_PHRASE)
1650  {
1651  /*
1652  * Compute Loffset and Roffset suitable for phrase match, and
1653  * compute overall width of whole phrase match.
1654  */
1655  Loffset = curitem->qoperator.distance + Rdata.width;
1656  Roffset = 0;
1657  if (data)
1658  data->width = curitem->qoperator.distance +
1659  Ldata.width + Rdata.width;
1660  }
1661  else
1662  {
1663  /*
1664  * For OP_AND, set output width and alignment like OP_OR (see
1665  * comment below)
1666  */
1667  maxwidth = Max(Ldata.width, Rdata.width);
1668  Loffset = maxwidth - Ldata.width;
1669  Roffset = maxwidth - Rdata.width;
1670  if (data)
1671  data->width = maxwidth;
1672  }
1673 
1674  if (Ldata.negate && Rdata.negate)
1675  {
1676  /* !L & !R: treat as !(L | R) */
1677  (void) TS_phrase_output(data, &Ldata, &Rdata,
1679  Loffset, Roffset,
1680  Ldata.npos + Rdata.npos);
1681  if (data)
1682  data->negate = true;
1683  return true;
1684  }
1685  else if (Ldata.negate)
1686  {
1687  /* !L & R */
1688  return TS_phrase_output(data, &Ldata, &Rdata,
1689  TSPO_R_ONLY,
1690  Loffset, Roffset,
1691  Rdata.npos);
1692  }
1693  else if (Rdata.negate)
1694  {
1695  /* L & !R */
1696  return TS_phrase_output(data, &Ldata, &Rdata,
1697  TSPO_L_ONLY,
1698  Loffset, Roffset,
1699  Ldata.npos);
1700  }
1701  else
1702  {
1703  /* straight AND */
1704  return TS_phrase_output(data, &Ldata, &Rdata,
1705  TSPO_BOTH,
1706  Loffset, Roffset,
1707  Min(Ldata.npos, Rdata.npos));
1708  }
1709 
1710  case OP_OR:
1711  memset(&Ldata, 0, sizeof(Ldata));
1712  memset(&Rdata, 0, sizeof(Rdata));
1713 
1714  lmatch = TS_phrase_execute(curitem + curitem->qoperator.left,
1715  arg, flags, chkcond, &Ldata);
1716  rmatch = TS_phrase_execute(curitem + 1,
1717  arg, flags, chkcond, &Rdata);
1718 
1719  if (!lmatch && !rmatch)
1720  return false;
1721 
1722  /*
1723  * If a valid operand has no position information, then we can't
1724  * return position data, only a "possible match" result. "Possible
1725  * match" answers are only wanted when TS_EXEC_PHRASE_NO_POS flag
1726  * is set, otherwise return false.
1727  */
1728  if ((lmatch && Ldata.npos == 0 && !Ldata.negate) ||
1729  (rmatch && Rdata.npos == 0 && !Rdata.negate))
1730  return (flags & TS_EXEC_PHRASE_NO_POS) ? true : false;
1731 
1732  /*
1733  * Cope with undefined output width from failed submatch. (This
1734  * takes less code than trying to ensure that all failure returns
1735  * set data->width to zero.)
1736  */
1737  if (!lmatch)
1738  Ldata.width = 0;
1739  if (!rmatch)
1740  Rdata.width = 0;
1741 
1742  /*
1743  * For OP_AND and OP_OR, report the width of the wider of the two
1744  * inputs, and align the narrower input's positions to the right
1745  * end of that width. This rule deals at least somewhat
1746  * reasonably with cases like "x <-> (y | z <-> q)".
1747  */
1748  maxwidth = Max(Ldata.width, Rdata.width);
1749  Loffset = maxwidth - Ldata.width;
1750  Roffset = maxwidth - Rdata.width;
1751  data->width = maxwidth;
1752 
1753  if (Ldata.negate && Rdata.negate)
1754  {
1755  /* !L | !R: treat as !(L & R) */
1756  (void) TS_phrase_output(data, &Ldata, &Rdata,
1757  TSPO_BOTH,
1758  Loffset, Roffset,
1759  Min(Ldata.npos, Rdata.npos));
1760  data->negate = true;
1761  return true;
1762  }
1763  else if (Ldata.negate)
1764  {
1765  /* !L | R: treat as !(L & !R) */
1766  (void) TS_phrase_output(data, &Ldata, &Rdata,
1767  TSPO_L_ONLY,
1768  Loffset, Roffset,
1769  Ldata.npos);
1770  data->negate = true;
1771  return true;
1772  }
1773  else if (Rdata.negate)
1774  {
1775  /* L | !R: treat as !(!L & R) */
1776  (void) TS_phrase_output(data, &Ldata, &Rdata,
1777  TSPO_R_ONLY,
1778  Loffset, Roffset,
1779  Rdata.npos);
1780  data->negate = true;
1781  return true;
1782  }
1783  else
1784  {
1785  /* straight OR */
1786  return TS_phrase_output(data, &Ldata, &Rdata,
1788  Loffset, Roffset,
1789  Ldata.npos + Rdata.npos);
1790  }
1791 
1792  default:
1793  elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
1794  }
1795 
1796  /* not reachable, but keep compiler quiet */
1797  return false;
1798 }
QueryOperator qoperator
Definition: ts_type.h:196
#define TSPO_R_ONLY
Definition: tsvector_op.c:1429
#define Min(x, y)
Definition: c.h:904
#define QI_VAL
Definition: ts_type.h:134
int16 distance
Definition: ts_type.h:183
#define TSPO_BOTH
Definition: tsvector_op.c:1430
#define OP_OR
Definition: ts_type.h:168
static bool TS_phrase_output(ExecPhraseData *data, ExecPhraseData *Ldata, ExecPhraseData *Rdata, int emit, int Loffset, int Roffset, int max_npos)
Definition: tsvector_op.c:1433
#define true
Definition: c.h:312
#define OP_AND
Definition: ts_type.h:167
#define ERROR
Definition: elog.h:43
void check_stack_depth(void)
Definition: postgres.c:3262
#define TSPO_L_ONLY
Definition: tsvector_op.c:1428
QueryItemType type
Definition: ts_type.h:195
#define Max(x, y)
Definition: c.h:898
#define Assert(condition)
Definition: c.h:732
#define OP_PHRASE
Definition: ts_type.h:169
#define TS_EXEC_PHRASE_NO_POS
Definition: ts_utils.h:190
uint32 left
Definition: ts_type.h:184
#define elog(elevel,...)
Definition: elog.h:226
void * arg
static bool TS_phrase_execute(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond, ExecPhraseData *data)
Definition: tsvector_op.c:1571
#define OP_NOT
Definition: ts_type.h:166

◆ TS_phrase_output()

static bool TS_phrase_output ( ExecPhraseData data,
ExecPhraseData Ldata,
ExecPhraseData Rdata,
int  emit,
int  Loffset,
int  Roffset,
int  max_npos 
)
static

Definition at line 1433 of file tsvector_op.c.

References ExecPhraseData::allocated, Assert, ExecPhraseData::npos, palloc(), ExecPhraseData::pos, TSPO_BOTH, TSPO_L_ONLY, TSPO_R_ONLY, and WEP_GETPOS.

Referenced by TS_phrase_execute().

1440 {
1441  int Lindex,
1442  Rindex;
1443 
1444  /* Loop until both inputs are exhausted */
1445  Lindex = Rindex = 0;
1446  while (Lindex < Ldata->npos || Rindex < Rdata->npos)
1447  {
1448  int Lpos,
1449  Rpos;
1450  int output_pos = 0;
1451 
1452  /*
1453  * Fetch current values to compare. WEP_GETPOS() is needed because
1454  * ExecPhraseData->data can point to a tsvector's WordEntryPosVector.
1455  */
1456  if (Lindex < Ldata->npos)
1457  Lpos = WEP_GETPOS(Ldata->pos[Lindex]) + Loffset;
1458  else
1459  {
1460  /* L array exhausted, so we're done if R_ONLY isn't set */
1461  if (!(emit & TSPO_R_ONLY))
1462  break;
1463  Lpos = INT_MAX;
1464  }
1465  if (Rindex < Rdata->npos)
1466  Rpos = WEP_GETPOS(Rdata->pos[Rindex]) + Roffset;
1467  else
1468  {
1469  /* R array exhausted, so we're done if L_ONLY isn't set */
1470  if (!(emit & TSPO_L_ONLY))
1471  break;
1472  Rpos = INT_MAX;
1473  }
1474 
1475  /* Merge-join the two input lists */
1476  if (Lpos < Rpos)
1477  {
1478  /* Lpos is not matched in Rdata, should we output it? */
1479  if (emit & TSPO_L_ONLY)
1480  output_pos = Lpos;
1481  Lindex++;
1482  }
1483  else if (Lpos == Rpos)
1484  {
1485  /* Lpos and Rpos match ... should we output it? */
1486  if (emit & TSPO_BOTH)
1487  output_pos = Rpos;
1488  Lindex++;
1489  Rindex++;
1490  }
1491  else /* Lpos > Rpos */
1492  {
1493  /* Rpos is not matched in Ldata, should we output it? */
1494  if (emit & TSPO_R_ONLY)
1495  output_pos = Rpos;
1496  Rindex++;
1497  }
1498 
1499  if (output_pos > 0)
1500  {
1501  if (data)
1502  {
1503  /* Store position, first allocating output array if needed */
1504  if (data->pos == NULL)
1505  {
1506  data->pos = (WordEntryPos *)
1507  palloc(max_npos * sizeof(WordEntryPos));
1508  data->allocated = true;
1509  }
1510  data->pos[data->npos++] = output_pos;
1511  }
1512  else
1513  {
1514  /*
1515  * Exact positions not needed, so return true as soon as we
1516  * know there is at least one.
1517  */
1518  return true;
1519  }
1520  }
1521  }
1522 
1523  if (data && data->npos > 0)
1524  {
1525  /* Let's assert we didn't overrun the array */
1526  Assert(data->npos <= max_npos);
1527  return true;
1528  }
1529  return false;
1530 }
uint16 WordEntryPos
Definition: ts_type.h:63
#define TSPO_R_ONLY
Definition: tsvector_op.c:1429
bool allocated
Definition: ts_utils.h:152
#define TSPO_BOTH
Definition: tsvector_op.c:1430
#define WEP_GETPOS(x)
Definition: ts_type.h:80
WordEntryPos * pos
Definition: ts_utils.h:154
#define TSPO_L_ONLY
Definition: tsvector_op.c:1428
#define Assert(condition)
Definition: c.h:732
void * palloc(Size size)
Definition: mcxt.c:924

◆ ts_process_call()

static Datum ts_process_call ( FuncCallContext funcctx)
static

Definition at line 2249 of file tsvector_op.c.

References FuncCallContext::attinmeta, BuildTupleFromCStrings(), HeapTupleGetDatum, StatEntry::lenlexeme, StatEntry::lexeme, StatEntry::ndoc, StatEntry::nentry, palloc(), pfree(), sprintf, FuncCallContext::user_fctx, values, and walkStatEntryTree().

Referenced by ts_stat1(), and ts_stat2().

2250 {
2251  TSVectorStat *st;
2252  StatEntry *entry;
2253 
2254  st = (TSVectorStat *) funcctx->user_fctx;
2255 
2256  entry = walkStatEntryTree(st);
2257 
2258  if (entry != NULL)
2259  {
2260  Datum result;
2261  char *values[3];
2262  char ndoc[16];
2263  char nentry[16];
2264  HeapTuple tuple;
2265 
2266  values[0] = palloc(entry->lenlexeme + 1);
2267  memcpy(values[0], entry->lexeme, entry->lenlexeme);
2268  (values[0])[entry->lenlexeme] = '\0';
2269  sprintf(ndoc, "%d", entry->ndoc);
2270  values[1] = ndoc;
2271  sprintf(nentry, "%d", entry->nentry);
2272  values[2] = nentry;
2273 
2274  tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
2275  result = HeapTupleGetDatum(tuple);
2276 
2277  pfree(values[0]);
2278 
2279  /* mark entry as already visited */
2280  entry->ndoc = 0;
2281 
2282  return result;
2283  }
2284 
2285  return (Datum) 0;
2286 }
uint32 nentry
Definition: tsvector_op.c:48
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2112
#define sprintf
Definition: port.h:194
uint32 ndoc
Definition: tsvector_op.c:46
void pfree(void *pointer)
Definition: mcxt.c:1031
static StatEntry * walkStatEntryTree(TSVectorStat *stat)
Definition: tsvector_op.c:2203
AttInMetadata * attinmeta
Definition: funcapi.h:92
uint32 lenlexeme
Definition: tsvector_op.c:51
uintptr_t Datum
Definition: postgres.h:367
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:221
static Datum values[MAXATTR]
Definition: bootstrap.c:167
void * user_fctx
Definition: funcapi.h:83
void * palloc(Size size)
Definition: mcxt.c:924
char lexeme[FLEXIBLE_ARRAY_MEMBER]
Definition: tsvector_op.c:52

◆ ts_setup_firstcall()

static void ts_setup_firstcall ( FunctionCallInfo  fcinfo,
FuncCallContext funcctx,
TSVectorStat stat 
)
static

Definition at line 2157 of file tsvector_op.c.

References Assert, FuncCallContext::attinmeta, BlessTupleDesc(), CreateTemplateTupleDesc(), StatEntry::left, TSVectorStat::maxdepth, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, palloc0(), TSVectorStat::root, TSVectorStat::stack, TSVectorStat::stackpos, FuncCallContext::tuple_desc, TupleDescGetAttInMetadata(), TupleDescInitEntry(), and FuncCallContext::user_fctx.

Referenced by ts_stat1(), and ts_stat2().

2159 {
2160  TupleDesc tupdesc;
2161  MemoryContext oldcontext;
2162  StatEntry *node;
2163 
2164  funcctx->user_fctx = (void *) stat;
2165 
2166  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2167 
2168  stat->stack = palloc0(sizeof(StatEntry *) * (stat->maxdepth + 1));
2169  stat->stackpos = 0;
2170 
2171  node = stat->root;
2172  /* find leftmost value */
2173  if (node == NULL)
2174  stat->stack[stat->stackpos] = NULL;
2175  else
2176  for (;;)
2177  {
2178  stat->stack[stat->stackpos] = node;
2179  if (node->left)
2180  {
2181  stat->stackpos++;
2182  node = node->left;
2183  }
2184  else
2185  break;
2186  }
2187  Assert(stat->stackpos <= stat->maxdepth);
2188 
2189  tupdesc = CreateTemplateTupleDesc(3);
2190  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
2191  TEXTOID, -1, 0);
2192  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "ndoc",
2193  INT4OID, -1, 0);
2194  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "nentry",
2195  INT4OID, -1, 0);
2196  funcctx->tuple_desc = BlessTupleDesc(tupdesc);
2197  funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
2198 
2199  MemoryContextSwitchTo(oldcontext);
2200 }
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
uint32 stackpos
Definition: tsvector_op.c:64
StatEntry * root
Definition: tsvector_op.c:66
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
TupleDesc tuple_desc
Definition: funcapi.h:113
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2048
AttInMetadata * attinmeta
Definition: funcapi.h:92
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
StatEntry ** stack
Definition: tsvector_op.c:63
void * palloc0(Size size)
Definition: mcxt.c:955
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2063
#define Assert(condition)
Definition: c.h:732
uint32 maxdepth
Definition: tsvector_op.c:61
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:102
struct StatEntry * left
Definition: tsvector_op.c:49
void * user_fctx
Definition: funcapi.h:83
int16 AttrNumber
Definition: attnum.h:21

◆ ts_stat1()

Datum ts_stat1 ( PG_FUNCTION_ARGS  )

Definition at line 2378 of file tsvector_op.c.

References FuncCallContext::multi_call_memory_ctx, PG_FREE_IF_COPY, PG_GETARG_TEXT_PP, SPI_connect(), SPI_finish(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, stat, ts_process_call(), ts_setup_firstcall(), and ts_stat_sql().

2379 {
2380  FuncCallContext *funcctx;
2381  Datum result;
2382 
2383  if (SRF_IS_FIRSTCALL())
2384  {
2385  TSVectorStat *stat;
2386  text *txt = PG_GETARG_TEXT_PP(0);
2387 
2388  funcctx = SRF_FIRSTCALL_INIT();
2389  SPI_connect();
2390  stat = ts_stat_sql(funcctx->multi_call_memory_ctx, txt, NULL);
2391  PG_FREE_IF_COPY(txt, 0);
2392  ts_setup_firstcall(fcinfo, funcctx, stat);
2393  SPI_finish();
2394  }
2395 
2396  funcctx = SRF_PERCALL_SETUP();
2397  if ((result = ts_process_call(funcctx)) != (Datum) 0)
2398  SRF_RETURN_NEXT(funcctx, result);
2399  SRF_RETURN_DONE(funcctx);
2400 }
int SPI_connect(void)
Definition: spi.c:89
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:283
int SPI_finish(void)
Definition: spi.c:176
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:287
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:303
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:289
static TSVectorStat * ts_stat_sql(MemoryContext persistentContext, text *txt, text *ws)
Definition: tsvector_op.c:2289
static void ts_setup_firstcall(FunctionCallInfo fcinfo, FuncCallContext *funcctx, TSVectorStat *stat)
Definition: tsvector_op.c:2157
#define stat(a, b)
Definition: win32_port.h:264
uintptr_t Datum
Definition: postgres.h:367
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:102
static Datum ts_process_call(FuncCallContext *funcctx)
Definition: tsvector_op.c:2249
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
Definition: c.h:549
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:307
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:285

◆ ts_stat2()

Datum ts_stat2 ( PG_FUNCTION_ARGS  )

Definition at line 2403 of file tsvector_op.c.

References FuncCallContext::multi_call_memory_ctx, PG_FREE_IF_COPY, PG_GETARG_TEXT_PP, SPI_connect(), SPI_finish(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, stat, ts_process_call(), ts_setup_firstcall(), and ts_stat_sql().

2404 {
2405  FuncCallContext *funcctx;
2406  Datum result;
2407 
2408  if (SRF_IS_FIRSTCALL())
2409  {
2410  TSVectorStat *stat;
2411  text *txt = PG_GETARG_TEXT_PP(0);
2412  text *ws = PG_GETARG_TEXT_PP(1);
2413 
2414  funcctx = SRF_FIRSTCALL_INIT();
2415  SPI_connect();
2416  stat = ts_stat_sql(funcctx->multi_call_memory_ctx, txt, ws);
2417  PG_FREE_IF_COPY(txt, 0);
2418  PG_FREE_IF_COPY(ws, 1);
2419  ts_setup_firstcall(fcinfo, funcctx, stat);
2420  SPI_finish();
2421  }
2422 
2423  funcctx = SRF_PERCALL_SETUP();
2424  if ((result = ts_process_call(funcctx)) != (Datum) 0)
2425  SRF_RETURN_NEXT(funcctx, result);
2426  SRF_RETURN_DONE(funcctx);
2427 }
int SPI_connect(void)
Definition: spi.c:89
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:283
int SPI_finish(void)
Definition: spi.c:176
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:287
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:303
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:289
static TSVectorStat * ts_stat_sql(MemoryContext persistentContext, text *txt, text *ws)
Definition: tsvector_op.c:2289
static void ts_setup_firstcall(FunctionCallInfo fcinfo, FuncCallContext *funcctx, TSVectorStat *stat)
Definition: tsvector_op.c:2157
#define stat(a, b)
Definition: win32_port.h:264
uintptr_t Datum
Definition: postgres.h:367
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:102
static Datum ts_process_call(FuncCallContext *funcctx)
Definition: tsvector_op.c:2249
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
Definition: c.h:549
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:307
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:285

◆ ts_stat_sql()

static TSVectorStat* ts_stat_sql ( MemoryContext  persistentContext,
text txt,
text ws 
)
static

Definition at line 2289 of file tsvector_op.c.

References buf, elog, ereport, errcode(), errmsg(), ERROR, i, IsBinaryCoercible(), TSVectorStat::maxdepth, MemoryContextAllocZero(), TupleDescData::natts, pfree(), pg_mblen(), SPI_cursor_close(), SPI_cursor_fetch(), SPI_cursor_open(), SPI_freeplan(), SPI_freetuptable(), SPI_getbinval(), SPI_gettypeid(), SPI_prepare(), SPI_processed, SPI_tuptable, stat, text_to_cstring(), ts_accum(), SPITupleTable::tupdesc, SPITupleTable::vals, VARDATA_ANY, VARSIZE_ANY_EXHDR, and TSVectorStat::weight.

Referenced by ts_stat1(), and ts_stat2().

2290 {
2291  char *query = text_to_cstring(txt);
2292  TSVectorStat *stat;
2293  bool isnull;
2294  Portal portal;
2295  SPIPlanPtr plan;
2296 
2297  if ((plan = SPI_prepare(query, 0, NULL)) == NULL)
2298  /* internal error */
2299  elog(ERROR, "SPI_prepare(\"%s\") failed", query);
2300 
2301  if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL)
2302  /* internal error */
2303  elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
2304 
2305  SPI_cursor_fetch(portal, true, 100);
2306 
2307  if (SPI_tuptable == NULL ||
2308  SPI_tuptable->tupdesc->natts != 1 ||
2310  TSVECTOROID))
2311  ereport(ERROR,
2312  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2313  errmsg("ts_stat query must return one tsvector column")));
2314 
2315  stat = MemoryContextAllocZero(persistentContext, sizeof(TSVectorStat));
2316  stat->maxdepth = 1;
2317 
2318  if (ws)
2319  {
2320  char *buf;
2321 
2322  buf = VARDATA_ANY(ws);
2323  while (buf - VARDATA_ANY(ws) < VARSIZE_ANY_EXHDR(ws))
2324  {
2325  if (pg_mblen(buf) == 1)
2326  {
2327  switch (*buf)
2328  {
2329  case 'A':
2330  case 'a':
2331  stat->weight |= 1 << 3;
2332  break;
2333  case 'B':
2334  case 'b':
2335  stat->weight |= 1 << 2;
2336  break;
2337  case 'C':
2338  case 'c':
2339  stat->weight |= 1 << 1;
2340  break;
2341  case 'D':
2342  case 'd':
2343  stat->weight |= 1;
2344  break;
2345  default:
2346  stat->weight |= 0;
2347  }
2348  }
2349  buf += pg_mblen(buf);
2350  }
2351  }
2352 
2353  while (SPI_processed > 0)
2354  {
2355  uint64 i;
2356 
2357  for (i = 0; i < SPI_processed; i++)
2358  {
2359  Datum data = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull);
2360 
2361  if (!isnull)
2362  stat = ts_accum(persistentContext, stat, data);
2363  }
2364 
2366  SPI_cursor_fetch(portal, true, 100);
2367  }
2368 
2370  SPI_cursor_close(portal);
2371  SPI_freeplan(plan);
2372  pfree(query);
2373 
2374  return stat;
2375 }
Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber)
Definition: spi.c:1084
#define VARDATA_ANY(PTR)
Definition: postgres.h:348
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:674
SPITupleTable * SPI_tuptable
Definition: spi.c:46
int errcode(int sqlerrcode)
Definition: elog.c:570
Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only)
Definition: spi.c:1221
HeapTuple * vals
Definition: spi.h:26
uint64 SPI_processed
Definition: spi.c:45
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1028
static char * buf
Definition: pg_test_fsync.c:68
#define ereport(elevel, rest)
Definition: elog.h:141
bool IsBinaryCoercible(Oid srctype, Oid targettype)
#define stat(a, b)
Definition: win32_port.h:264
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1162
uintptr_t Datum
Definition: postgres.h:367
TupleDesc tupdesc
Definition: spi.h:25
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:814
uint32 maxdepth
Definition: tsvector_op.c:61
int pg_mblen(const char *mbstr)
Definition: mbutils.c:752
int SPI_freeplan(SPIPlanPtr plan)
Definition: spi.c:801
void SPI_cursor_close(Portal portal)
Definition: spi.c:1595
char * text_to_cstring(const text *t)
Definition: varlena.c:204
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:341
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
int i
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1539
static TSVectorStat * ts_accum(MemoryContext persistentContext, TSVectorStat *stat, Datum data)
Definition: tsvector_op.c:2122
int32 weight
Definition: tsvector_op.c:59

◆ tsCompareString()

int32 tsCompareString ( char *  a,
int  lena,
char *  b,
int  lenb,
bool  prefix 
)

Definition at line 1159 of file tsvector_op.c.

References cmp(), and Min.

Referenced by checkcondition_str(), compare_text_lexemes(), compareentry(), compareQueryOperand(), compareWORD(), gin_cmp_prefix(), gin_cmp_tslexeme(), hlfinditem(), QTNodeCompare(), silly_cmp_tsvector(), and tsvector_bsearch().

1160 {
1161  int cmp;
1162 
1163  if (lena == 0)
1164  {
1165  if (prefix)
1166  cmp = 0; /* empty string is prefix of anything */
1167  else
1168  cmp = (lenb > 0) ? -1 : 0;
1169  }
1170  else if (lenb == 0)
1171  {
1172  cmp = (lena > 0) ? 1 : 0;
1173  }
1174  else
1175  {
1176  cmp = memcmp(a, b, Min(lena, lenb));
1177 
1178  if (prefix)
1179  {
1180  if (cmp == 0 && lena > lenb)
1181  cmp = 1; /* a is longer, so not a prefix of b */
1182  }
1183  else if (cmp == 0 && lena != lenb)
1184  {
1185  cmp = (lena < lenb) ? -1 : 1;
1186  }
1187  }
1188 
1189  return cmp;
1190 }
#define Min(x, y)
Definition: c.h:904
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:742

◆ tsquery_requires_match()

bool tsquery_requires_match ( QueryItem curitem)

Definition at line 1864 of file tsvector_op.c.

References check_stack_depth(), elog, ERROR, QueryOperator::left, OP_AND, OP_NOT, OP_OR, OP_PHRASE, QueryOperator::oper, QI_VAL, QueryItem::qoperator, tsquery_requires_match(), and QueryItem::type.

Referenced by gin_extract_tsquery(), and tsquery_requires_match().

1865 {
1866  /* since this function recurses, it could be driven to stack overflow */
1868 
1869  if (curitem->type == QI_VAL)
1870  return true;
1871 
1872  switch (curitem->qoperator.oper)
1873  {
1874  case OP_NOT:
1875 
1876  /*
1877  * Assume there are no required matches underneath a NOT. For
1878  * some cases with nested NOTs, we could prove there's a required
1879  * match, but it seems unlikely to be worth the trouble.
1880  */
1881  return false;
1882 
1883  case OP_PHRASE:
1884 
1885  /*
1886  * Treat OP_PHRASE as OP_AND here
1887  */
1888  case OP_AND:
1889  /* If either side requires a match, we're good */
1890  if (tsquery_requires_match(curitem + curitem->qoperator.left))
1891  return true;
1892  else
1893  return tsquery_requires_match(curitem + 1);
1894 
1895  case OP_OR:
1896  /* Both sides must require a match */
1897  if (tsquery_requires_match(curitem + curitem->qoperator.left))
1898  return tsquery_requires_match(curitem + 1);
1899  else
1900  return false;
1901 
1902  default:
1903  elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
1904  }
1905 
1906  /* not reachable, but keep compiler quiet */
1907  return false;
1908 }
QueryOperator qoperator
Definition: ts_type.h:196
bool tsquery_requires_match(QueryItem *curitem)
Definition: tsvector_op.c:1864
#define QI_VAL
Definition: ts_type.h:134
#define OP_OR
Definition: ts_type.h:168
#define OP_AND
Definition: ts_type.h:167
#define ERROR
Definition: elog.h:43
void check_stack_depth(void)
Definition: postgres.c:3262
QueryItemType type
Definition: ts_type.h:195
#define OP_PHRASE
Definition: ts_type.h:169
uint32 left
Definition: ts_type.h:184
#define elog(elevel,...)
Definition: elog.h:226
#define OP_NOT
Definition: ts_type.h:166

◆ tsvector_bsearch()

static int tsvector_bsearch ( const TSVector  tsv,
char *  lexeme,
int  lexeme_len 
)
static

Definition at line 392 of file tsvector_op.c.

References ARRPTR, cmp(), TSVectorData::size, STRPTR, and tsCompareString().

Referenced by tsvector_delete_arr(), tsvector_delete_str(), and tsvector_setweight_by_filter().

393 {
394  WordEntry *arrin = ARRPTR(tsv);
395  int StopLow = 0,
396  StopHigh = tsv->size,
397  StopMiddle,
398  cmp;
399 
400  while (StopLow < StopHigh)
401  {
402  StopMiddle = (StopLow + StopHigh) / 2;
403 
404  cmp = tsCompareString(lexeme, lexeme_len,
405  STRPTR(tsv) + arrin[StopMiddle].pos,
406  arrin[StopMiddle].len,
407  false);
408 
409  if (cmp < 0)
410  StopHigh = StopMiddle;
411  else if (cmp > 0)
412  StopLow = StopMiddle + 1;
413  else /* found it */
414  return StopMiddle;
415  }
416 
417  return -1;
418 }
int32 size
Definition: ts_type.h:93
int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix)
Definition: tsvector_op.c:1159
#define STRPTR(x)
Definition: hstore.h:76
#define ARRPTR(x)
Definition: cube.c:25
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:742

◆ tsvector_concat()

Datum tsvector_concat ( PG_FUNCTION_ARGS  )

Definition at line 932 of file tsvector_op.c.

References _POSVECPTR, add_pos(), ARRPTR, Assert, CALCDATASIZE, cmp(), compareEntry, ereport, errcode(), errmsg(), ERROR, WordEntry::haspos, i, WordEntry::len, MAXSTRPOS, memmove, palloc0(), PG_FREE_IF_COPY, PG_GETARG_TSVECTOR, PG_RETURN_POINTER, WordEntry::pos, POSDATALEN, POSDATAPTR, SET_VARSIZE, SHORTALIGN, TSVectorData::size, STRPTR, VARSIZE, and WEP_GETPOS.

933 {
934  TSVector in1 = PG_GETARG_TSVECTOR(0);
935  TSVector in2 = PG_GETARG_TSVECTOR(1);
936  TSVector out;
937  WordEntry *ptr;
938  WordEntry *ptr1,
939  *ptr2;
940  WordEntryPos *p;
941  int maxpos = 0,
942  i,
943  j,
944  i1,
945  i2,
946  dataoff,
947  output_bytes,
948  output_size;
949  char *data,
950  *data1,
951  *data2;
952 
953  /* Get max position in in1; we'll need this to offset in2's positions */
954  ptr = ARRPTR(in1);
955  i = in1->size;
956  while (i--)
957  {
958  if ((j = POSDATALEN(in1, ptr)) != 0)
959  {
960  p = POSDATAPTR(in1, ptr);
961  while (j--)
962  {
963  if (WEP_GETPOS(*p) > maxpos)
964  maxpos = WEP_GETPOS(*p);
965  p++;
966  }
967  }
968  ptr++;
969  }
970 
971  ptr1 = ARRPTR(in1);
972  ptr2 = ARRPTR(in2);
973  data1 = STRPTR(in1);
974  data2 = STRPTR(in2);
975  i1 = in1->size;
976  i2 = in2->size;
977 
978  /*
979  * Conservative estimate of space needed. We might need all the data in
980  * both inputs, and conceivably add a pad byte before position data for
981  * each item where there was none before.
982  */
983  output_bytes = VARSIZE(in1) + VARSIZE(in2) + i1 + i2;
984 
985  out = (TSVector) palloc0(output_bytes);
986  SET_VARSIZE(out, output_bytes);
987 
988  /*
989  * We must make out->size valid so that STRPTR(out) is sensible. We'll
990  * collapse out any unused space at the end.
991  */
992  out->size = in1->size + in2->size;
993 
994  ptr = ARRPTR(out);
995  data = STRPTR(out);
996  dataoff = 0;
997  while (i1 && i2)
998  {
999  int cmp = compareEntry(data1, ptr1, data2, ptr2);
1000 
1001  if (cmp < 0)
1002  { /* in1 first */
1003  ptr->haspos = ptr1->haspos;
1004  ptr->len = ptr1->len;
1005  memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
1006  ptr->pos = dataoff;
1007  dataoff += ptr1->len;
1008  if (ptr->haspos)
1009  {
1010  dataoff = SHORTALIGN(dataoff);
1011  memcpy(data + dataoff, _POSVECPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
1012  dataoff += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
1013  }
1014 
1015  ptr++;
1016  ptr1++;
1017  i1--;
1018  }
1019  else if (cmp > 0)
1020  { /* in2 first */
1021  ptr->haspos = ptr2->haspos;
1022  ptr->len = ptr2->len;
1023  memcpy(data + dataoff, data2 + ptr2->pos, ptr2->len);
1024  ptr->pos = dataoff;
1025  dataoff += ptr2->len;
1026  if (ptr->haspos)
1027  {
1028  int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
1029 
1030  if (addlen == 0)
1031  ptr->haspos = 0;
1032  else
1033  {
1034  dataoff = SHORTALIGN(dataoff);
1035  dataoff += addlen * sizeof(WordEntryPos) + sizeof(uint16);
1036  }
1037  }
1038 
1039  ptr++;
1040  ptr2++;
1041  i2--;
1042  }
1043  else
1044  {
1045  ptr->haspos = ptr1->haspos | ptr2->haspos;
1046  ptr->len = ptr1->len;
1047  memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
1048  ptr->pos = dataoff;
1049  dataoff += ptr1->len;
1050  if (ptr->haspos)
1051  {
1052  if (ptr1->haspos)
1053  {
1054  dataoff = SHORTALIGN(dataoff);
1055  memcpy(data + dataoff, _POSVECPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
1056  dataoff += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
1057  if (ptr2->haspos)
1058  dataoff += add_pos(in2, ptr2, out, ptr, maxpos) * sizeof(WordEntryPos);
1059  }
1060  else /* must have ptr2->haspos */
1061  {
1062  int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
1063 
1064  if (addlen == 0)
1065  ptr->haspos = 0;
1066  else
1067  {
1068  dataoff = SHORTALIGN(dataoff);
1069  dataoff += addlen * sizeof(WordEntryPos) + sizeof(uint16);
1070  }
1071  }
1072  }
1073 
1074  ptr++;
1075  ptr1++;
1076  ptr2++;
1077  i1--;
1078  i2--;
1079  }
1080  }
1081 
1082  while (i1)
1083  {
1084  ptr->haspos = ptr1->haspos;
1085  ptr->len = ptr1->len;
1086  memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
1087  ptr->pos = dataoff;
1088  dataoff += ptr1->len;
1089  if (ptr->haspos)
1090  {
1091  dataoff = SHORTALIGN(dataoff);
1092  memcpy(data + dataoff, _POSVECPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
1093  dataoff += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
1094  }
1095 
1096  ptr++;
1097  ptr1++;
1098  i1--;
1099  }
1100 
1101  while (i2)
1102  {
1103  ptr->haspos = ptr2->haspos;
1104  ptr->len = ptr2->len;
1105  memcpy(data + dataoff, data2 + ptr2->pos, ptr2->len);
1106  ptr->pos = dataoff;
1107  dataoff += ptr2->len;
1108  if (ptr->haspos)
1109  {
1110  int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
1111 
1112  if (addlen == 0)
1113  ptr->haspos = 0;
1114  else
1115  {
1116  dataoff = SHORTALIGN(dataoff);
1117  dataoff += addlen * sizeof(WordEntryPos) + sizeof(uint16);
1118  }
1119  }
1120 
1121  ptr++;
1122  ptr2++;
1123  i2--;
1124  }
1125 
1126  /*
1127  * Instead of checking each offset individually, we check for overflow of
1128  * pos fields once at the end.
1129  */
1130  if (dataoff > MAXSTRPOS)
1131  ereport(ERROR,
1132  (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1133  errmsg("string is too long for tsvector (%d bytes, max %d bytes)", dataoff, MAXSTRPOS)));
1134 
1135  /*
1136  * Adjust sizes (asserting that we didn't overrun the original estimates)
1137  * and collapse out any unused array entries.
1138  */
1139  output_size = ptr - ARRPTR(out);
1140  Assert(output_size <= out->size);
1141  out->size = output_size;
1142  if (data != STRPTR(out))
1143  memmove(STRPTR(out), data, dataoff);
1144  output_bytes = CALCDATASIZE(out->size, dataoff);
1145  Assert(output_bytes <= VARSIZE(out));
1146  SET_VARSIZE(out, output_bytes);
1147 
1148  PG_FREE_IF_COPY(in1, 0);
1149  PG_FREE_IF_COPY(in2, 1);
1150  PG_RETURN_POINTER(out);
1151 }
uint16 WordEntryPos
Definition: ts_type.h:63
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
#define POSDATALEN(x, e)
Definition: ts_type.h:110
#define VARSIZE(PTR)
Definition: postgres.h:303
#define _POSVECPTR(x, e)
Definition: ts_type.h:109
uint32 len
Definition: ts_type.h:44
int errcode(int sqlerrcode)
Definition: elog.c:570
#define MAXSTRPOS
Definition: ts_type.h:50
#define POSDATAPTR(x, e)
Definition: ts_type.h:111
unsigned short uint16
Definition: c.h:357
#define ERROR
Definition: elog.h:43
#define WEP_GETPOS(x)
Definition: ts_type.h:80
#define memmove(d, s, c)
Definition: c.h:1238
int32 size
Definition: ts_type.h:93
uint32 haspos
Definition: ts_type.h:44
#define ereport(elevel, rest)
Definition: elog.h:141
#define CALCDATASIZE(x, lenstr)
Definition: hstore.h:72
void * palloc0(Size size)
Definition: mcxt.c:955
TSVectorData * TSVector
Definition: ts_type.h:98
#define Assert(condition)
Definition: c.h:732
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
uint32 pos
Definition: ts_type.h:44
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define STRPTR(x)
Definition: hstore.h:76
int i
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:120
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
#define ARRPTR(x)
Definition: cube.c:25
#define SHORTALIGN(LEN)
Definition: c.h:681
static int32 add_pos(TSVector src, WordEntry *srcptr, TSVector dest, WordEntry *destptr, int32 maxpos)
Definition: tsvector_op.c:356
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:742
#define compareEntry(pa, a, pb, b)
Definition: tsvector_op.c:346

◆ tsvector_delete_arr()

Datum tsvector_delete_arr ( PG_FUNCTION_ARGS  )

Definition at line 579 of file tsvector_op.c.

References deconstruct_array(), ereport, errcode(), errmsg(), ERROR, i, palloc0(), pfree(), PG_FREE_IF_COPY, PG_GETARG_ARRAYTYPE_P, PG_GETARG_TSVECTOR, PG_RETURN_POINTER, tsvector_bsearch(), tsvector_delete_by_indices(), VARDATA, VARHDRSZ, and VARSIZE.

580 {
581  TSVector tsin = PG_GETARG_TSVECTOR(0),
582  tsout;
583  ArrayType *lexemes = PG_GETARG_ARRAYTYPE_P(1);
584  int i,
585  nlex,
586  skip_count,
587  *skip_indices;
588  Datum *dlexemes;
589  bool *nulls;
590 
591  deconstruct_array(lexemes, TEXTOID, -1, false, 'i',
592  &dlexemes, &nulls, &nlex);
593 
594  /*
595  * In typical use case array of lexemes to delete is relatively small. So
596  * here we optimize things for that scenario: iterate through lexarr
597  * performing binary search of each lexeme from lexarr in tsvector.
598  */
599  skip_indices = palloc0(nlex * sizeof(int));
600  for (i = skip_count = 0; i < nlex; i++)
601  {
602  char *lex;
603  int lex_len,
604  lex_pos;
605 
606  if (nulls[i])
607  ereport(ERROR,
608  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
609  errmsg("lexeme array may not contain nulls")));
610 
611  lex = VARDATA(dlexemes[i]);
612  lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ;
613  lex_pos = tsvector_bsearch(tsin, lex, lex_len);
614 
615  if (lex_pos >= 0)
616  skip_indices[skip_count++] = lex_pos;
617  }
618 
619  tsout = tsvector_delete_by_indices(tsin, skip_indices, skip_count);
620 
621  pfree(skip_indices);
622  PG_FREE_IF_COPY(tsin, 0);
623  PG_FREE_IF_COPY(lexemes, 1);
624 
625  PG_RETURN_POINTER(tsout);
626 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
#define VARDATA(PTR)
Definition: postgres.h:302
#define VARSIZE(PTR)
Definition: postgres.h:303
#define VARHDRSZ
Definition: c.h:555
int errcode(int sqlerrcode)
Definition: elog.c:570
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:251
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
#define ereport(elevel, rest)
Definition: elog.h:141
static TSVector tsvector_delete_by_indices(TSVector tsv, int *indices_to_delete, int indices_count)
Definition: tsvector_op.c:458
void * palloc0(Size size)
Definition: mcxt.c:955
uintptr_t Datum
Definition: postgres.h:367
static int tsvector_bsearch(const TSVector tsv, char *lexeme, int lexeme_len)
Definition: tsvector_op.c:392
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3461
int errmsg(const char *fmt,...)
Definition: elog.c:784
int i
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:120

◆ tsvector_delete_by_indices()

static TSVector tsvector_delete_by_indices ( TSVector  tsv,
int *  indices_to_delete,
int  indices_count 
)
static

Definition at line 458 of file tsvector_op.c.

References ARRPTR, Assert, CALCDATASIZE, compare_int(), WordEntry::haspos, i, WordEntry::len, palloc0(), POSDATALEN, qsort, SET_VARSIZE, SHORTALIGN, TSVectorData::size, STRPTR, and VARSIZE.

Referenced by tsvector_delete_arr(), and tsvector_delete_str().

460 {
461  TSVector tsout;
462  WordEntry *arrin = ARRPTR(tsv),
463  *arrout;
464  char *data = STRPTR(tsv),
465  *dataout;
466  int i, /* index in arrin */
467  j, /* index in arrout */
468  k, /* index in indices_to_delete */
469  curoff; /* index in dataout area */
470 
471  /*
472  * Sort the filter array to simplify membership checks below. Also, get
473  * rid of any duplicate entries, so that we can assume that indices_count
474  * is exactly equal to the number of lexemes that will be removed.
475  */
476  if (indices_count > 1)
477  {
478  int kp;
479 
480  qsort(indices_to_delete, indices_count, sizeof(int), compare_int);
481  kp = 0;
482  for (k = 1; k < indices_count; k++)
483  {
484  if (indices_to_delete[k] != indices_to_delete[kp])
485  indices_to_delete[++kp] = indices_to_delete[k];
486  }
487  indices_count = ++kp;
488  }
489 
490  /*
491  * Here we overestimate tsout size, since we don't know how much space is
492  * used by the deleted lexeme(s). We will set exact size below.
493  */
494  tsout = (TSVector) palloc0(VARSIZE(tsv));
495 
496  /* This count must be correct because STRPTR(tsout) relies on it. */
497  tsout->size = tsv->size - indices_count;
498 
499  /*
500  * Copy tsv to tsout, skipping lexemes listed in indices_to_delete.
501  */
502  arrout = ARRPTR(tsout);
503  dataout = STRPTR(tsout);
504  curoff = 0;
505  for (i = j = k = 0; i < tsv->size; i++)
506  {
507  /*
508  * If current i is present in indices_to_delete, skip this lexeme.
509  * Since indices_to_delete is already sorted, we only need to check
510  * the current (k'th) entry.
511  */
512  if (k < indices_count && i == indices_to_delete[k])
513  {
514  k++;
515  continue;
516  }
517 
518  /* Copy lexeme and its positions and weights */
519  memcpy(dataout + curoff, data + arrin[i].pos, arrin[i].len);
520  arrout[j].haspos = arrin[i].haspos;
521  arrout[j].len = arrin[i].len;
522  arrout[j].pos = curoff;
523  curoff += arrin[i].len;
524  if (arrin[i].haspos)
525  {
526  int len = POSDATALEN(tsv, arrin + i) * sizeof(WordEntryPos)
527  + sizeof(uint16);
528 
529  curoff = SHORTALIGN(curoff);
530  memcpy(dataout + curoff,
531  STRPTR(tsv) + SHORTALIGN(arrin[i].pos + arrin[i].len),
532  len);
533  curoff += len;
534  }
535 
536  j++;
537  }
538 
539  /*
540  * k should now be exactly equal to indices_count. If it isn't then the
541  * caller provided us with indices outside of [0, tsv->size) range and
542  * estimation of tsout's size is wrong.
543  */
544  Assert(k == indices_count);
545 
546  SET_VARSIZE(tsout, CALCDATASIZE(tsout->size, curoff));
547  return tsout;
548 }
uint16 WordEntryPos
Definition: ts_type.h:63
#define POSDATALEN(x, e)
Definition: ts_type.h:110
#define VARSIZE(PTR)
Definition: postgres.h:303
uint32 len
Definition: ts_type.h:44
unsigned short uint16
Definition: c.h:357
int32 size
Definition: ts_type.h:93
uint32 haspos
Definition: ts_type.h:44
#define CALCDATASIZE(x, lenstr)
Definition: hstore.h:72
void * palloc0(Size size)
Definition: mcxt.c:955
TSVectorData * TSVector
Definition: ts_type.h:98
#define Assert(condition)
Definition: c.h:732
#define STRPTR(x)
Definition: hstore.h:76
int i
static int compare_int(const void *va, const void *vb)
Definition: tsvector_op.c:425
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
#define ARRPTR(x)
Definition: cube.c:25
#define qsort(a, b, c, d)
Definition: port.h:488
#define SHORTALIGN(LEN)
Definition: c.h:681

◆ tsvector_delete_str()

Datum tsvector_delete_str ( PG_FUNCTION_ARGS  )

Definition at line 555 of file tsvector_op.c.

References StatEntry::lexeme, PG_FREE_IF_COPY, PG_GETARG_TEXT_PP, PG_GETARG_TSVECTOR, PG_RETURN_POINTER, tsvector_bsearch(), tsvector_delete_by_indices(), VARDATA_ANY, and VARSIZE_ANY_EXHDR.

556 {
557  TSVector tsin = PG_GETARG_TSVECTOR(0),
558  tsout;
559  text *tlexeme = PG_GETARG_TEXT_PP(1);
560  char *lexeme = VARDATA_ANY(tlexeme);
561  int lexeme_len = VARSIZE_ANY_EXHDR(tlexeme),
562  skip_index;
563 
564  if ((skip_index = tsvector_bsearch(tsin, lexeme, lexeme_len)) == -1)
565  PG_RETURN_POINTER(tsin);
566 
567  tsout = tsvector_delete_by_indices(tsin, &skip_index, 1);
568 
569  PG_FREE_IF_COPY(tsin, 0);
570  PG_FREE_IF_COPY(tlexeme, 1);
571  PG_RETURN_POINTER(tsout);
572 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
#define VARDATA_ANY(PTR)
Definition: postgres.h:348
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:303
static TSVector tsvector_delete_by_indices(TSVector tsv, int *indices_to_delete, int indices_count)
Definition: tsvector_op.c:458
static int tsvector_bsearch(const TSVector tsv, char *lexeme, int lexeme_len)
Definition: tsvector_op.c:392
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:341
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:120
Definition: c.h:549

◆ tsvector_filter()

Datum tsvector_filter ( PG_FUNCTION_ARGS  )

Definition at line 825 of file tsvector_op.c.

References _POSVECPTR, ARRPTR, CALCDATASIZE, DatumGetChar, deconstruct_array(), ereport, errcode(), errmsg(), ERROR, i, WordEntry::len, memmove, WordEntryPosVector::npos, palloc0(), PG_FREE_IF_COPY, PG_GETARG_ARRAYTYPE_P, PG_GETARG_TSVECTOR, PG_RETURN_POINTER, WordEntryPosVector::pos, POSDATALEN, SET_VARSIZE, SHORTALIGN, TSVectorData::size, STRPTR, VARSIZE, weights, and WEP_GETWEIGHT.

826 {
827  TSVector tsin = PG_GETARG_TSVECTOR(0),
828  tsout;
830  WordEntry *arrin = ARRPTR(tsin),
831  *arrout;
832  char *datain = STRPTR(tsin),
833  *dataout;
834  Datum *dweights;
835  bool *nulls;
836  int nweights;
837  int i,
838  j;
839  int cur_pos = 0;
840  char mask = 0;
841 
842  deconstruct_array(weights, CHAROID, 1, true, 'c',
843  &dweights, &nulls, &nweights);
844 
845  for (i = 0; i < nweights; i++)
846  {
847  char char_weight;
848 
849  if (nulls[i])
850  ereport(ERROR,
851  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
852  errmsg("weight array may not contain nulls")));
853 
854  char_weight = DatumGetChar(dweights[i]);
855  switch (char_weight)
856  {
857  case 'A':
858  case 'a':
859  mask = mask | 8;
860  break;
861  case 'B':
862  case 'b':
863  mask = mask | 4;
864  break;
865  case 'C':
866  case 'c':
867  mask = mask | 2;
868  break;
869  case 'D':
870  case 'd':
871  mask = mask | 1;
872  break;
873  default:
874  ereport(ERROR,
875  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
876  errmsg("unrecognized weight: \"%c\"", char_weight)));
877  }
878  }
879 
880  tsout = (TSVector) palloc0(VARSIZE(tsin));
881  tsout->size = tsin->size;
882  arrout = ARRPTR(tsout);
883  dataout = STRPTR(tsout);
884 
885  for (i = j = 0; i < tsin->size; i++)
886  {
887  WordEntryPosVector *posvin,
888  *posvout;
889  int npos = 0;
890  int k;
891 
892  if (!arrin[i].haspos)
893  continue;
894 
895  posvin = _POSVECPTR(tsin, arrin + i);
896  posvout = (WordEntryPosVector *)
897  (dataout + SHORTALIGN(cur_pos + arrin[i].len));
898 
899  for (k = 0; k < posvin->npos; k++)
900  {
901  if (mask & (1 << WEP_GETWEIGHT(posvin->pos[k])))
902  posvout->pos[npos++] = posvin->pos[k];
903  }
904 
905  /* if no satisfactory positions found, skip lexeme */
906  if (!npos)
907  continue;
908 
909  arrout[j].haspos = true;
910  arrout[j].len = arrin[i].len;
911  arrout[j].pos = cur_pos;
912 
913  memcpy(dataout + cur_pos, datain + arrin[i].pos, arrin[i].len);
914  posvout->npos = npos;
915  cur_pos += SHORTALIGN(arrin[i].len);
916  cur_pos += POSDATALEN(tsout, arrout + j) * sizeof(WordEntryPos) +
917  sizeof(uint16);
918  j++;
919  }
920 
921  tsout->size = j;
922  if (dataout != STRPTR(tsout))
923  memmove(STRPTR(tsout), dataout, cur_pos);
924 
925  SET_VARSIZE(tsout, CALCDATASIZE(tsout->size, cur_pos));
926 
927  PG_FREE_IF_COPY(tsin, 0);
928  PG_RETURN_POINTER(tsout);
929 }
uint16 WordEntryPos
Definition: ts_type.h:63
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
#define POSDATALEN(x, e)
Definition: ts_type.h:110
#define VARSIZE(PTR)
Definition: postgres.h:303
#define _POSVECPTR(x, e)
Definition: ts_type.h:109
uint32 len
Definition: ts_type.h:44
int errcode(int sqlerrcode)
Definition: elog.c:570
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:251
unsigned short uint16
Definition: c.h:357
#define ERROR
Definition: elog.h:43
WordEntryPos pos[FLEXIBLE_ARRAY_MEMBER]
Definition: ts_type.h:68
#define memmove(d, s, c)
Definition: c.h:1238
int32 size
Definition: ts_type.h:93
#define ereport(elevel, rest)
Definition: elog.h:141
#define CALCDATASIZE(x, lenstr)
Definition: hstore.h:72
void * palloc0(Size size)
Definition: mcxt.c:955
uintptr_t Datum
Definition: postgres.h:367
TSVectorData * TSVector
Definition: ts_type.h:98
#define DatumGetChar(X)
Definition: postgres.h:409
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3461
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define STRPTR(x)
Definition: hstore.h:76
int i
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:120
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
#define ARRPTR(x)
Definition: cube.c:25
#define WEP_GETWEIGHT(x)
Definition: ts_type.h:79
#define SHORTALIGN(LEN)
Definition: c.h:681
static const float weights[]
Definition: tsrank.c:25

◆ tsvector_length()

Datum tsvector_length ( PG_FUNCTION_ARGS  )

Definition at line 191 of file tsvector_op.c.

References PG_FREE_IF_COPY, PG_GETARG_TSVECTOR, PG_RETURN_INT32, and TSVectorData::size.

192 {
194  int32 ret = in->size;
195 
196  PG_FREE_IF_COPY(in, 0);
197  PG_RETURN_INT32(ret);
198 }
#define PG_RETURN_INT32(x)
Definition: fmgr.h:344
signed int int32
Definition: c.h:346
int32 size
Definition: ts_type.h:93
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:120

◆ tsvector_setweight()

Datum tsvector_setweight ( PG_FUNCTION_ARGS  )

Definition at line 201 of file tsvector_op.c.

References ARRPTR, elog, ERROR, i, palloc(), PG_FREE_IF_COPY, PG_GETARG_CHAR, PG_GETARG_TSVECTOR, PG_RETURN_POINTER, POSDATALEN, POSDATAPTR, TSVectorData::size, VARSIZE, and WEP_SETWEIGHT.

202 {
204  char cw = PG_GETARG_CHAR(1);
205  TSVector out;
206  int i,
207  j;
208  WordEntry *entry;
209  WordEntryPos *p;
210  int w = 0;
211 
212  switch (cw)
213  {
214  case 'A':
215  case 'a':
216  w = 3;
217  break;
218  case 'B':
219  case 'b':
220  w = 2;
221  break;
222  case 'C':
223  case 'c':
224  w = 1;
225  break;
226  case 'D':
227  case 'd':
228  w = 0;
229  break;
230  default:
231  /* internal error */
232  elog(ERROR, "unrecognized weight: %d", cw);
233  }
234 
235  out = (TSVector) palloc(VARSIZE(in));
236  memcpy(out, in, VARSIZE(in));
237  entry = ARRPTR(out);
238  i = out->size;
239  while (i--)
240  {
241  if ((j = POSDATALEN(out, entry)) != 0)
242  {
243  p = POSDATAPTR(out, entry);
244  while (j--)
245  {
246  WEP_SETWEIGHT(*p, w);
247  p++;
248  }
249  }
250  entry++;
251  }
252 
253  PG_FREE_IF_COPY(in, 0);
254  PG_RETURN_POINTER(out);
255 }
uint16 WordEntryPos
Definition: ts_type.h:63
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
#define POSDATALEN(x, e)
Definition: ts_type.h:110
#define VARSIZE(PTR)
Definition: postgres.h:303
#define POSDATAPTR(x, e)
Definition: ts_type.h:111
#define ERROR
Definition: elog.h:43
#define WEP_SETWEIGHT(x, v)
Definition: ts_type.h:82
int32 size
Definition: ts_type.h:93
TSVectorData * TSVector
Definition: ts_type.h:98
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
void * palloc(Size size)
Definition: mcxt.c:924
#define elog(elevel,...)
Definition: elog.h:226
int i
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:120
#define ARRPTR(x)
Definition: cube.c:25
#define PG_GETARG_CHAR(n)
Definition: fmgr.h:268

◆ tsvector_setweight_by_filter()

Datum tsvector_setweight_by_filter ( PG_FUNCTION_ARGS  )

Definition at line 263 of file tsvector_op.c.

References ARRPTR, deconstruct_array(), elog, ereport, errcode(), errmsg(), ERROR, i, palloc(), PG_FREE_IF_COPY, PG_GETARG_ARRAYTYPE_P, PG_GETARG_CHAR, PG_GETARG_TSVECTOR, PG_RETURN_POINTER, POSDATALEN, POSDATAPTR, tsvector_bsearch(), VARDATA, VARHDRSZ, VARSIZE, and WEP_SETWEIGHT.

264 {
265  TSVector tsin = PG_GETARG_TSVECTOR(0);
266  char char_weight = PG_GETARG_CHAR(1);
267  ArrayType *lexemes = PG_GETARG_ARRAYTYPE_P(2);
268 
269  TSVector tsout;
270  int i,
271  j,
272  nlexemes,
273  weight;
274  WordEntry *entry;
275  Datum *dlexemes;
276  bool *nulls;
277 
278  switch (char_weight)
279  {
280  case 'A':
281  case 'a':
282  weight = 3;
283  break;
284  case 'B':
285  case 'b':
286  weight = 2;
287  break;
288  case 'C':
289  case 'c':
290  weight = 1;
291  break;
292  case 'D':
293  case 'd':
294  weight = 0;
295  break;
296  default:
297  /* internal error */
298  elog(ERROR, "unrecognized weight: %c", char_weight);
299  }
300 
301  tsout = (TSVector) palloc(VARSIZE(tsin));
302  memcpy(tsout, tsin, VARSIZE(tsin));
303  entry = ARRPTR(tsout);
304 
305  deconstruct_array(lexemes, TEXTOID, -1, false, 'i',
306  &dlexemes, &nulls, &nlexemes);
307 
308  /*
309  * Assuming that lexemes array is significantly shorter than tsvector we
310  * can iterate through lexemes performing binary search of each lexeme
311  * from lexemes in tsvector.
312  */
313  for (i = 0; i < nlexemes; i++)
314  {
315  char *lex;
316  int lex_len,
317  lex_pos;
318 
319  if (nulls[i])
320  ereport(ERROR,
321  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
322  errmsg("lexeme array may not contain nulls")));
323 
324  lex = VARDATA(dlexemes[i]);
325  lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ;
326  lex_pos = tsvector_bsearch(tsout, lex, lex_len);
327 
328  if (lex_pos >= 0 && (j = POSDATALEN(tsout, entry + lex_pos)) != 0)
329  {
330  WordEntryPos *p = POSDATAPTR(tsout, entry + lex_pos);
331 
332  while (j--)
333  {
334  WEP_SETWEIGHT(*p, weight);
335  p++;
336  }
337  }
338  }
339 
340  PG_FREE_IF_COPY(tsin, 0);
341  PG_FREE_IF_COPY(lexemes, 2);
342 
343  PG_RETURN_POINTER(tsout);
344 }
uint16 WordEntryPos
Definition: ts_type.h:63
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
#define VARDATA(PTR)
Definition: postgres.h:302
#define POSDATALEN(x, e)
Definition: ts_type.h:110
#define VARSIZE(PTR)
Definition: postgres.h:303
#define VARHDRSZ
Definition: c.h:555
int errcode(int sqlerrcode)
Definition: elog.c:570
#define POSDATAPTR(x, e)
Definition: ts_type.h:111
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:251
#define ERROR
Definition: elog.h:43
#define WEP_SETWEIGHT(x, v)
Definition: ts_type.h:82
#define ereport(elevel, rest)
Definition: elog.h:141
uintptr_t Datum
Definition: postgres.h:367
TSVectorData * TSVector
Definition: ts_type.h:98
static int tsvector_bsearch(const TSVector tsv, char *lexeme, int lexeme_len)
Definition: tsvector_op.c:392
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
void deconstruct_array(ArrayType *array, Oid elmtype, int elmlen, bool elmbyval, char elmalign, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3461
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
int i
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:120
#define ARRPTR(x)
Definition: cube.c:25
#define PG_GETARG_CHAR(n)
Definition: fmgr.h:268

◆ tsvector_strip()

Datum tsvector_strip ( PG_FUNCTION_ARGS  )

Definition at line 158 of file tsvector_op.c.

References ARRPTR, CALCDATASIZE, cur, i, WordEntry::len, palloc0(), PG_FREE_IF_COPY, PG_GETARG_TSVECTOR, PG_RETURN_POINTER, SET_VARSIZE, TSVectorData::size, and STRPTR.

159 {
161  TSVector out;
162  int i,
163  len = 0;
164  WordEntry *arrin = ARRPTR(in),
165  *arrout;
166  char *cur;
167 
168  for (i = 0; i < in->size; i++)
169  len += arrin[i].len;
170 
171  len = CALCDATASIZE(in->size, len);
172  out = (TSVector) palloc0(len);
173  SET_VARSIZE(out, len);
174  out->size = in->size;
175  arrout = ARRPTR(out);
176  cur = STRPTR(out);
177  for (i = 0; i < in->size; i++)
178  {
179  memcpy(cur, STRPTR(in) + arrin[i].pos, arrin[i].len);
180  arrout[i].haspos = 0;
181  arrout[i].len = arrin[i].len;
182  arrout[i].pos = cur - STRPTR(out);
183  cur += arrout[i].len;
184  }
185 
186  PG_FREE_IF_COPY(in, 0);
187  PG_RETURN_POINTER(out);
188 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
uint32 len
Definition: ts_type.h:44
struct cursor * cur
Definition: ecpg.c:28
int32 size
Definition: ts_type.h:93
#define CALCDATASIZE(x, lenstr)
Definition: hstore.h:72
void * palloc0(Size size)
Definition: mcxt.c:955
TSVectorData * TSVector
Definition: ts_type.h:98
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
#define STRPTR(x)
Definition: hstore.h:76
int i
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:120
#define SET_VARSIZE(PTR, len)
Definition: postgres.h:329
#define ARRPTR(x)
Definition: cube.c:25

◆ tsvector_to_array()

Datum tsvector_to_array ( PG_FUNCTION_ARGS  )

Definition at line 727 of file tsvector_op.c.

References ARRPTR, construct_array(), cstring_to_text_with_len(), i, palloc(), pfree(), PG_FREE_IF_COPY, PG_GETARG_TSVECTOR, PG_RETURN_POINTER, PointerGetDatum, TSVectorData::size, and STRPTR.

728 {
729  TSVector tsin = PG_GETARG_TSVECTOR(0);
730  WordEntry *arrin = ARRPTR(tsin);
731  Datum *elements;
732  int i;
733  ArrayType *array;
734 
735  elements = palloc(tsin->size * sizeof(Datum));
736 
737  for (i = 0; i < tsin->size; i++)
738  {
739  elements[i] = PointerGetDatum(
740  cstring_to_text_with_len(STRPTR(tsin) + arrin[i].pos, arrin[i].len)
741  );
742  }
743 
744  array = construct_array(elements, tsin->size, TEXTOID, -1, false, 'i');
745 
746  pfree(elements);
747  PG_FREE_IF_COPY(tsin, 0);
748  PG_RETURN_POINTER(array);
749 }
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:351
#define PointerGetDatum(X)
Definition: postgres.h:556
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3291
void pfree(void *pointer)
Definition: mcxt.c:1031
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:183
int32 size
Definition: ts_type.h:93
uintptr_t Datum
Definition: postgres.h:367
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:255
void * palloc(Size size)
Definition: mcxt.c:924
#define STRPTR(x)
Definition: hstore.h:76
int i
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:120
#define ARRPTR(x)
Definition: cube.c:25

◆ tsvector_unnest()

Datum tsvector_unnest ( PG_FUNCTION_ARGS  )

Definition at line 635 of file tsvector_op.c.

References _POSVECPTR, ARRPTR, BlessTupleDesc(), FuncCallContext::call_cntr, construct_array(), CreateTemplateTupleDesc(), cstring_to_text_with_len(), heap_form_tuple(), HeapTupleGetDatum, i, Int16GetDatum, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, WordEntryPosVector::npos, palloc(), pfree(), PG_GETARG_TSVECTOR_COPY, PointerGetDatum, WordEntryPosVector::pos, TSVectorData::size, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, STRPTR, FuncCallContext::tuple_desc, TupleDescInitEntry(), FuncCallContext::user_fctx, values, weights, WEP_GETPOS, and WEP_GETWEIGHT.

636 {
637  FuncCallContext *funcctx;
638  TSVector tsin;
639 
640  if (SRF_IS_FIRSTCALL())
641  {
642  MemoryContext oldcontext;
643  TupleDesc tupdesc;
644 
645  funcctx = SRF_FIRSTCALL_INIT();
646  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
647 
648  tupdesc = CreateTemplateTupleDesc(3);
649  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "lexeme",
650  TEXTOID, -1, 0);
651  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "positions",
652  INT2ARRAYOID, -1, 0);
653  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "weights",
654  TEXTARRAYOID, -1, 0);
655  funcctx->tuple_desc = BlessTupleDesc(tupdesc);
656 
657  funcctx->user_fctx = PG_GETARG_TSVECTOR_COPY(0);
658 
659  MemoryContextSwitchTo(oldcontext);
660  }
661 
662  funcctx = SRF_PERCALL_SETUP();
663  tsin = (TSVector) funcctx->user_fctx;
664 
665  if (funcctx->call_cntr < tsin->size)
666  {
667  WordEntry *arrin = ARRPTR(tsin);
668  char *data = STRPTR(tsin);
669  HeapTuple tuple;
670  int j,
671  i = funcctx->call_cntr;
672  bool nulls[] = {false, false, false};
673  Datum values[3];
674 
675  values[0] = PointerGetDatum(
676  cstring_to_text_with_len(data + arrin[i].pos, arrin[i].len)
677  );
678 
679  if (arrin[i].haspos)
680  {
681  WordEntryPosVector *posv;
682  Datum *positions;
683  Datum *weights;
684  char weight;
685 
686  /*
687  * Internally tsvector stores position and weight in the same
688  * uint16 (2 bits for weight, 14 for position). Here we extract
689  * that in two separate arrays.
690  */
691  posv = _POSVECPTR(tsin, arrin + i);
692  positions = palloc(posv->npos * sizeof(Datum));
693  weights = palloc(posv->npos * sizeof(Datum));
694  for (j = 0; j < posv->npos; j++)
695  {
696  positions[j] = Int16GetDatum(WEP_GETPOS(posv->pos[j]));
697  weight = 'D' - WEP_GETWEIGHT(posv->pos[j]);
698  weights[j] = PointerGetDatum(
699  cstring_to_text_with_len(&weight, 1)
700  );
701  }
702 
703  values[1] = PointerGetDatum(
704  construct_array(positions, posv->npos, INT2OID, 2, true, 's'));
705  values[2] = PointerGetDatum(
706  construct_array(weights, posv->npos, TEXTOID, -1, false, 'i'));
707  }
708  else
709  {
710  nulls[1] = nulls[2] = true;
711  }
712 
713  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
714  SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
715  }
716  else
717  {
718  pfree(tsin);
719  SRF_RETURN_DONE(funcctx);
720  }
721 }
uint64 call_cntr
Definition: funcapi.h:66
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:44
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:283
#define PointerGetDatum(X)
Definition: postgres.h:556
#define _POSVECPTR(x, e)
Definition: ts_type.h:109
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
#define Int16GetDatum(X)
Definition: postgres.h:451
ArrayType * construct_array(Datum *elems, int nelems, Oid elmtype, int elmlen, bool elmbyval, char elmalign)
Definition: arrayfuncs.c:3291
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:287
TupleDesc tuple_desc
Definition: funcapi.h:113
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:289
void pfree(void *pointer)
Definition: mcxt.c:1031
#define WEP_GETPOS(x)
Definition: ts_type.h:80
TupleDesc BlessTupleDesc(TupleDesc tupdesc)
Definition: execTuples.c:2048
WordEntryPos pos[FLEXIBLE_ARRAY_MEMBER]
Definition: ts_type.h:68
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:183
int32 size
Definition: ts_type.h:93
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603
uintptr_t Datum
Definition: postgres.h:367
TSVectorData * TSVector
Definition: ts_type.h:98
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:102
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:221
static Datum values[MAXATTR]
Definition: bootstrap.c:167
void * user_fctx
Definition: funcapi.h:83
void * palloc(Size size)
Definition: mcxt.c:924
#define STRPTR(x)
Definition: hstore.h:76
int i
#define PG_GETARG_TSVECTOR_COPY(n)
Definition: ts_type.h:121
#define ARRPTR(x)
Definition: cube.c:25
#define WEP_GETWEIGHT(x)
Definition: ts_type.h:79
int16 AttrNumber
Definition: attnum.h:21
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:307
static const float weights[]
Definition: tsrank.c:25
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:285

◆ tsvector_update_trigger()

static Datum tsvector_update_trigger ( PG_FUNCTION_ARGS  ,
bool  config_column 
)
static

Definition at line 2453 of file tsvector_op.c.

References CALLED_AS_TRIGGER, ParsedText::curwords, DatumGetObjectId, DatumGetPointer, DatumGetTextPP, elog, ereport, errcode(), errmsg(), ERROR, get_ts_config_oid(), heap_modify_tuple_by_cols(), i, IsBinaryCoercible(), ParsedText::lenwords, list_length(), make_tsvector(), numattr, palloc(), parsetext(), pfree(), PointerGetDatum, ParsedText::pos, RelationData::rd_att, SPI_ERROR_NOATTRIBUTE, SPI_fnumber(), SPI_getbinval(), SPI_gettypeid(), stringToQualifiedNameList(), TriggerData::tg_event, TriggerData::tg_newtuple, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, Trigger::tgargs, Trigger::tgnargs, TRIGGER_FIRED_BEFORE, TRIGGER_FIRED_BY_INSERT, TRIGGER_FIRED_BY_UPDATE, TRIGGER_FIRED_FOR_ROW, TSVectorGetDatum, VARDATA_ANY, VARSIZE_ANY_EXHDR, and ParsedText::words.

Referenced by tsvector_update_trigger_bycolumn(), and tsvector_update_trigger_byid().

2454 {
2455  TriggerData *trigdata;
2456  Trigger *trigger;
2457  Relation rel;
2458  HeapTuple rettuple = NULL;
2459  int tsvector_attr_num,
2460  i;
2461  ParsedText prs;
2462  Datum datum;
2463  bool isnull;
2464  text *txt;
2465  Oid cfgId;
2466 
2467  /* Check call context */
2468  if (!CALLED_AS_TRIGGER(fcinfo)) /* internal error */
2469  elog(ERROR, "tsvector_update_trigger: not fired by trigger manager");
2470 
2471  trigdata = (TriggerData *) fcinfo->context;
2472  if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
2473  elog(ERROR, "tsvector_update_trigger: must be fired for row");
2474  if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
2475  elog(ERROR, "tsvector_update_trigger: must be fired BEFORE event");
2476 
2477  if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
2478  rettuple = trigdata->tg_trigtuple;
2479  else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
2480  rettuple = trigdata->tg_newtuple;
2481  else
2482  elog(ERROR, "tsvector_update_trigger: must be fired for INSERT or UPDATE");
2483 
2484  trigger = trigdata->tg_trigger;
2485  rel = trigdata->tg_relation;
2486 
2487  if (trigger->tgnargs < 3)
2488  elog(ERROR, "tsvector_update_trigger: arguments must be tsvector_field, ts_config, text_field1, ...)");
2489 
2490  /* Find the target tsvector column */
2491  tsvector_attr_num = SPI_fnumber(rel->rd_att, trigger->tgargs[0]);
2492  if (tsvector_attr_num == SPI_ERROR_NOATTRIBUTE)
2493  ereport(ERROR,
2494  (errcode(ERRCODE_UNDEFINED_COLUMN),
2495  errmsg("tsvector column \"%s\" does not exist",
2496  trigger->tgargs[0])));
2497  /* This will effectively reject system columns, so no separate test: */
2498  if (!IsBinaryCoercible(SPI_gettypeid(rel->rd_att, tsvector_attr_num),
2499  TSVECTOROID))
2500  ereport(ERROR,
2501  (errcode(ERRCODE_DATATYPE_MISMATCH),
2502  errmsg("column \"%s\" is not of tsvector type",
2503  trigger->tgargs[0])));
2504 
2505  /* Find the configuration to use */
2506  if (config_column)
2507  {
2508  int config_attr_num;
2509 
2510  config_attr_num = SPI_fnumber(rel->rd_att, trigger->tgargs[1]);
2511  if (config_attr_num == SPI_ERROR_NOATTRIBUTE)
2512  ereport(ERROR,
2513  (errcode(ERRCODE_UNDEFINED_COLUMN),
2514  errmsg("configuration column \"%s\" does not exist",
2515  trigger->tgargs[1])));
2516  if (!IsBinaryCoercible(SPI_gettypeid(rel->rd_att, config_attr_num),
2517  REGCONFIGOID))
2518  ereport(ERROR,
2519  (errcode(ERRCODE_DATATYPE_MISMATCH),
2520  errmsg("column \"%s\" is not of regconfig type",
2521  trigger->tgargs[1])));
2522 
2523  datum = SPI_getbinval(rettuple, rel->rd_att, config_attr_num, &isnull);
2524  if (isnull)
2525  ereport(ERROR,
2526  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2527  errmsg("configuration column \"%s\" must not be null",
2528  trigger->tgargs[1])));
2529  cfgId = DatumGetObjectId(datum);
2530  }
2531  else
2532  {
2533  List *names;
2534 
2535  names = stringToQualifiedNameList(trigger->tgargs[1]);
2536  /* require a schema so that results are not search path dependent */
2537  if (list_length(names) < 2)
2538  ereport(ERROR,
2539  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2540  errmsg("text search configuration name \"%s\" must be schema-qualified",
2541  trigger->tgargs[1])));
2542  cfgId = get_ts_config_oid(names, false);
2543  }
2544 
2545  /* initialize parse state */
2546  prs.lenwords = 32;
2547  prs.curwords = 0;
2548  prs.pos = 0;
2549  prs.words = (ParsedWord *) palloc(sizeof(ParsedWord) * prs.lenwords);
2550 
2551  /* find all words in indexable column(s) */
2552  for (i = 2; i < trigger->tgnargs; i++)
2553  {
2554  int numattr;
2555 
2556  numattr = SPI_fnumber(rel->rd_att, trigger->tgargs[i]);
2557  if (numattr == SPI_ERROR_NOATTRIBUTE)
2558  ereport(ERROR,
2559  (errcode(ERRCODE_UNDEFINED_COLUMN),
2560  errmsg("column \"%s\" does not exist",
2561  trigger->tgargs[i])));
2562  if (!IsBinaryCoercible(SPI_gettypeid(rel->rd_att, numattr), TEXTOID))
2563  ereport(ERROR,
2564  (errcode(ERRCODE_DATATYPE_MISMATCH),
2565  errmsg("column \"%s\" is not of a character type",
2566  trigger->tgargs[i])));
2567 
2568  datum = SPI_getbinval(rettuple, rel->rd_att, numattr, &isnull);
2569  if (isnull)
2570  continue;
2571 
2572  txt = DatumGetTextPP(datum);
2573 
2574  parsetext(cfgId, &prs, VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt));
2575 
2576  if (txt != (text *) DatumGetPointer(datum))
2577  pfree(txt);
2578  }
2579 
2580  /* make tsvector value */
2581  datum = TSVectorGetDatum(make_tsvector(&prs));
2582  isnull = false;
2583 
2584  /* and insert it into tuple */
2585  rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att,
2586  1, &tsvector_attr_num,
2587  &datum, &isnull);
2588 
2589  pfree(DatumGetPointer(datum));
2590 
2591  return PointerGetDatum(rettuple);
2592 }
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
Definition: spi.c:951
Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber)
Definition: spi.c:1084
TSVector make_tsvector(ParsedText *prs)
Definition: to_tsany.c:156
#define VARDATA_ANY(PTR)
Definition: postgres.h:348
int numattr
Definition: bootstrap.c:77
#define PointerGetDatum(X)
Definition: postgres.h:556
#define DatumGetObjectId(X)
Definition: postgres.h:500
#define DatumGetTextPP(X)
Definition: fmgr.h:286
int errcode(int sqlerrcode)
Definition: elog.c:570
Oid get_ts_config_oid(List *names, bool missing_ok)
Definition: namespace.c:2671
int32 lenwords
Definition: ts_utils.h:101
unsigned int Oid
Definition: postgres_ext.h:31
int32 curwords
Definition: ts_utils.h:102
HeapTuple tg_trigtuple
Definition: trigger.h:35
void pfree(void *pointer)
Definition: mcxt.c:1031
#define ERROR
Definition: elog.h:43
void parsetext(Oid cfgId, ParsedText *prs, char *buf, int buflen)
Definition: ts_parse.c:358
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1028
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:47
ParsedWord * words
Definition: ts_utils.h:100
#define TSVectorGetDatum(X)
Definition: ts_type.h:119
#define ereport(elevel, rest)
Definition: elog.h:141
bool IsBinaryCoercible(Oid srctype, Oid targettype)
char ** tgargs
Definition: reltrigger.h:40
uintptr_t Datum
Definition: postgres.h:367
Trigger * tg_trigger
Definition: trigger.h:37
TupleDesc rd_att
Definition: rel.h:84
HeapTuple tg_newtuple
Definition: trigger.h:36
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:25
TriggerEvent tg_event
Definition: trigger.h:33
int32 pos
Definition: ts_utils.h:103
static int list_length(const List *l)
Definition: pg_list.h:169
HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple, TupleDesc tupleDesc, int nCols, int *replCols, Datum *replValues, bool *replIsnull)
Definition: heaptuple.c:1181
#define DatumGetPointer(X)
Definition: postgres.h:549
#define TRIGGER_FIRED_BEFORE(event)
Definition: trigger.h:134
List * stringToQualifiedNameList(const char *string)
Definition: regproc.c:1687
#define TRIGGER_FIRED_BY_INSERT(event)
Definition: trigger.h:116
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:341
void * palloc(Size size)
Definition: mcxt.c:924
int errmsg(const char *fmt,...)
Definition: elog.c:784
#define elog(elevel,...)
Definition: elog.h:226
int i
int16 tgnargs
Definition: reltrigger.h:37
Definition: c.h:549
#define TRIGGER_FIRED_FOR_ROW(event)
Definition: trigger.h:128
Definition: pg_list.h:50
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition: trigger.h:122
Relation tg_relation
Definition: trigger.h:34

◆ tsvector_update_trigger_bycolumn()

Datum tsvector_update_trigger_bycolumn ( PG_FUNCTION_ARGS  )

Definition at line 2447 of file tsvector_op.c.

References tsvector_update_trigger().

2448 {
2449  return tsvector_update_trigger(fcinfo, true);
2450 }
static Datum tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column)
Definition: tsvector_op.c:2453

◆ tsvector_update_trigger_byid()

Datum tsvector_update_trigger_byid ( PG_FUNCTION_ARGS  )

Definition at line 2441 of file tsvector_op.c.

References tsvector_update_trigger().

2442 {
2443  return tsvector_update_trigger(fcinfo, false);
2444 }
static Datum tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column)
Definition: tsvector_op.c:2453

◆ TSVECTORCMPFUNC() [1/7]

TSVECTORCMPFUNC ( lt  )

◆ TSVECTORCMPFUNC() [2/7]

TSVECTORCMPFUNC ( le  ,
<=  ,
BOOL   
)

◆ TSVECTORCMPFUNC() [3/7]

TSVECTORCMPFUNC ( eq  ,
BOOL   
)

◆ TSVECTORCMPFUNC() [4/7]

TSVECTORCMPFUNC ( ge  ,
>=  ,
BOOL   
)

◆ TSVECTORCMPFUNC() [5/7]

TSVECTORCMPFUNC ( gt  ,
BOOL   
)

◆ TSVECTORCMPFUNC() [6/7]

TSVECTORCMPFUNC ( ne  ,
,
BOOL   
)

◆ TSVECTORCMPFUNC() [7/7]

TSVECTORCMPFUNC ( cmp  ,
,
INT32   
)

◆ uniqueLongPos()

static int uniqueLongPos ( WordEntryPos pos,
int  npos 
)
static

Definition at line 1280 of file tsvector_op.c.

References compareWordEntryPos(), qsort, and WEP_GETPOS.

Referenced by checkcondition_str().

1281 {
1282  WordEntryPos *pos_iter,
1283  *result;
1284 
1285  if (npos <= 1)
1286  return npos;
1287 
1288  qsort((void *) pos, npos, sizeof(WordEntryPos), compareWordEntryPos);
1289 
1290  result = pos;
1291  pos_iter = pos + 1;
1292  while (pos_iter < pos + npos)
1293  {
1294  if (WEP_GETPOS(*pos_iter) != WEP_GETPOS(*result))
1295  {
1296  result++;
1297  *result = WEP_GETPOS(*pos_iter);
1298  }
1299 
1300  pos_iter++;
1301  }
1302 
1303  return result + 1 - pos;
1304 }
uint16 WordEntryPos
Definition: ts_type.h:63
int compareWordEntryPos(const void *a, const void *b)
Definition: tsvector.c:33
#define WEP_GETPOS(x)
Definition: ts_type.h:80
#define qsort(a, b, c, d)
Definition: port.h:488

◆ walkStatEntryTree()

static StatEntry* walkStatEntryTree ( TSVectorStat stat)
static

Definition at line 2203 of file tsvector_op.c.

References Assert, StatEntry::left, TSVectorStat::maxdepth, StatEntry::ndoc, StatEntry::right, TSVectorStat::stack, and TSVectorStat::stackpos.

Referenced by ts_process_call().

2204 {
2205  StatEntry *node = stat->stack[stat->stackpos];
2206 
2207  if (node == NULL)
2208  return NULL;
2209 
2210  if (node->ndoc != 0)
2211  {
2212  /* return entry itself: we already was at left sublink */
2213  return node;
2214  }
2215  else if (node->right && node->right != stat->stack[stat->stackpos + 1])
2216  {
2217  /* go on right sublink */
2218  stat->stackpos++;
2219  node = node->right;
2220 
2221  /* find most-left value */
2222  for (;;)
2223  {
2224  stat->stack[stat->stackpos] = node;
2225  if (node->left)
2226  {
2227  stat->stackpos++;
2228  node = node->left;
2229  }
2230  else
2231  break;
2232  }
2233  Assert(stat->stackpos <= stat->maxdepth);
2234  }
2235  else
2236  {
2237  /* we already return all left subtree, itself and right subtree */
2238  if (stat->stackpos == 0)
2239  return NULL;
2240 
2241  stat->stackpos--;
2242  return walkStatEntryTree(stat);
2243  }
2244 
2245  return node;
2246 }
uint32 stackpos
Definition: tsvector_op.c:64
uint32 ndoc
Definition: tsvector_op.c:46
static StatEntry * walkStatEntryTree(TSVectorStat *stat)
Definition: tsvector_op.c:2203
StatEntry ** stack
Definition: tsvector_op.c:63
#define Assert(condition)
Definition: c.h:732
uint32 maxdepth
Definition: tsvector_op.c:61
struct StatEntry * left
Definition: tsvector_op.c:49
struct StatEntry * right
Definition: tsvector_op.c:50