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 "common/int.h"
#include "executor/spi.h"
#include "funcapi.h"
#include "lib/qunique.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 TSTernaryValue TS_execute_recurse (QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
 
static bool TS_execute_locations_recurse (QueryItem *curitem, void *arg, TSExecuteCallback chkcond, List **locations)
 
static int tsvector_bsearch (const TSVector tsv, char *lexeme, int lexeme_len)
 
static Datum tsvector_update_trigger (PG_FUNCTION_ARGS, bool config_column)
 
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 TSTernaryValue checkclass_str (CHKVAL *chkval, WordEntry *entry, QueryOperand *val, ExecPhraseData *data)
 
static TSTernaryValue checkcondition_str (void *checkval, QueryOperand *val, ExecPhraseData *data)
 
static TSTernaryValue TS_phrase_output (ExecPhraseData *data, ExecPhraseData *Ldata, ExecPhraseData *Rdata, int emit, int Loffset, int Roffset, int max_npos)
 
static TSTernaryValue TS_phrase_execute (QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond, ExecPhraseData *data)
 
bool TS_execute (QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
 
TSTernaryValue TS_execute_ternary (QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
 
ListTS_execute_locations (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,
  b 
)
Value:
tsCompareString((pa) + (a)->pos, (a)->len, \
(pb) + (b)->pos, (b)->len, \
false)
int b
Definition: isn.c:70
int a
Definition: isn.c:69
const void size_t len
int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix)
Definition: tsvector_op.c:1153

Definition at line 355 of file tsvector_op.c.

◆ compareStatWord

#define compareStatWord (   a,
  e,
 
)
Value:
tsCompareString((a)->lexeme, (a)->lenlexeme, \
STRPTR(t) + (e)->pos, (e)->len, \
false)
#define STRPTR(x)
Definition: hstore.h:76
e
Definition: preproc-init.c:82

Definition at line 2311 of file tsvector_op.c.

◆ STATENTRYHDRSZ

#define STATENTRYHDRSZ   (offsetof(StatEntry, lexeme))

Definition at line 57 of file tsvector_op.c.

◆ TSPO_BOTH

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

Definition at line 1466 of file tsvector_op.c.

◆ TSPO_L_ONLY

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

Definition at line 1464 of file tsvector_op.c.

◆ TSPO_R_ONLY

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

Definition at line 1465 of file tsvector_op.c.

◆ 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); \
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
#define PG_FUNCTION_ARGS
Definition: fmgr.h:193
#define PG_GETARG_TSVECTOR(n)
Definition: ts_type.h:135
static int silly_cmp_tsvector(const TSVector a, const TSVector b)
Definition: tsvector_op.c:87
const char * type

Definition at line 146 of file tsvector_op.c.

Typedef Documentation

◆ StatEntry

typedef struct StatEntry StatEntry

Function Documentation

◆ add_pos()

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

Definition at line 365 of file tsvector_op.c.

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

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

Referenced by tsvector_concat().

◆ array_to_tsvector()

Datum array_to_tsvector ( PG_FUNCTION_ARGS  )

Definition at line 748 of file tsvector_op.c.

749 {
751  TSVector tsout;
752  Datum *dlexemes;
753  WordEntry *arrout;
754  bool *nulls;
755  int nitems,
756  i,
757  tslen,
758  datalen = 0;
759  char *cur;
760 
761  deconstruct_array_builtin(v, TEXTOID, &dlexemes, &nulls, &nitems);
762 
763  /*
764  * Reject nulls and zero length strings (maybe we should just ignore them,
765  * instead?)
766  */
767  for (i = 0; i < nitems; i++)
768  {
769  if (nulls[i])
770  ereport(ERROR,
771  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
772  errmsg("lexeme array may not contain nulls")));
773 
774  if (VARSIZE(dlexemes[i]) - VARHDRSZ == 0)
775  ereport(ERROR,
776  (errcode(ERRCODE_ZERO_LENGTH_CHARACTER_STRING),
777  errmsg("lexeme array may not contain empty strings")));
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  nitems = qunique(dlexemes, nitems, sizeof(Datum),
786  }
787 
788  /* Calculate space needed for surviving lexemes. */
789  for (i = 0; i < nitems; i++)
790  datalen += VARSIZE(dlexemes[i]) - VARHDRSZ;
791  tslen = CALCDATASIZE(nitems, datalen);
792 
793  /* Allocate and fill tsvector. */
794  tsout = (TSVector) palloc0(tslen);
795  SET_VARSIZE(tsout, tslen);
796  tsout->size = nitems;
797 
798  arrout = ARRPTR(tsout);
799  cur = STRPTR(tsout);
800  for (i = 0; i < nitems; i++)
801  {
802  char *lex = VARDATA(dlexemes[i]);
803  int lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ;
804 
805  memcpy(cur, lex, lex_len);
806  arrout[i].haspos = 0;
807  arrout[i].len = lex_len;
808  arrout[i].pos = cur - STRPTR(tsout);
809  cur += lex_len;
810  }
811 
812  PG_FREE_IF_COPY(v, 0);
813  PG_RETURN_POINTER(tsout);
814 }
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:263
void deconstruct_array_builtin(ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
Definition: arrayfuncs.c:3679
#define VARHDRSZ
Definition: c.h:681
#define ARRPTR(x)
Definition: cube.c:25
struct cursor * cur
Definition: ecpg.c:28
int errcode(int sqlerrcode)
Definition: elog.c:860
int errmsg(const char *fmt,...)
Definition: elog.c:1075
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define CALCDATASIZE(x, lenstr)
Definition: hstore.h:72
#define nitems(x)
Definition: indent.h:31
void * palloc0(Size size)
Definition: mcxt.c:1232
#define qsort(a, b, c, d)
Definition: port.h:449
uintptr_t Datum
Definition: postgres.h:64
static size_t qunique(void *array, size_t elements, size_t width, int(*compare)(const void *, const void *))
Definition: qunique.h:21
int32 size
Definition: ts_type.h:93
uint32 pos
Definition: ts_type.h:46
uint32 len
Definition: ts_type.h:45
TSVectorData * TSVector
Definition: ts_type.h:98
static int compare_text_lexemes(const void *va, const void *vb)
Definition: tsvector_op.c:443
#define VARDATA(PTR)
Definition: varatt.h:278
#define SET_VARSIZE(PTR, len)
Definition: varatt.h:305
#define VARSIZE(PTR)
Definition: varatt.h:279

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

◆ check_weight()

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

Definition at line 2296 of file tsvector_op.c.

2297 {
2298  int len = POSDATALEN(txt, wptr);
2299  int num = 0;
2300  WordEntryPos *ptr = POSDATAPTR(txt, wptr);
2301 
2302  while (len--)
2303  {
2304  if (weight & (1 << WEP_GETWEIGHT(*ptr)))
2305  num++;
2306  ptr++;
2307  }
2308  return num;
2309 }

References len, POSDATALEN, POSDATAPTR, and WEP_GETWEIGHT.

Referenced by insertStatEntry().

◆ checkclass_str()

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

Definition at line 1190 of file tsvector_op.c.

1192 {
1193  TSTernaryValue result = TS_NO;
1194 
1195  Assert(data == NULL || data->npos == 0);
1196 
1197  if (entry->haspos)
1198  {
1199  WordEntryPosVector *posvec;
1200 
1201  /*
1202  * We can't use the _POSVECPTR macro here because the pointer to the
1203  * tsvector's lexeme storage is already contained in chkval->values.
1204  */
1205  posvec = (WordEntryPosVector *)
1206  (chkval->values + SHORTALIGN(entry->pos + entry->len));
1207 
1208  if (val->weight && data)
1209  {
1210  WordEntryPos *posvec_iter = posvec->pos;
1211  WordEntryPos *dptr;
1212 
1213  /*
1214  * Filter position information by weights
1215  */
1216  dptr = data->pos = palloc(sizeof(WordEntryPos) * posvec->npos);
1217  data->allocated = true;
1218 
1219  /* Is there a position with a matching weight? */
1220  while (posvec_iter < posvec->pos + posvec->npos)
1221  {
1222  /* If true, append this position to the data->pos */
1223  if (val->weight & (1 << WEP_GETWEIGHT(*posvec_iter)))
1224  {
1225  *dptr = WEP_GETPOS(*posvec_iter);
1226  dptr++;
1227  }
1228 
1229  posvec_iter++;
1230  }
1231 
1232  data->npos = dptr - data->pos;
1233 
1234  if (data->npos > 0)
1235  result = TS_YES;
1236  else
1237  {
1238  pfree(data->pos);
1239  data->pos = NULL;
1240  data->allocated = false;
1241  }
1242  }
1243  else if (val->weight)
1244  {
1245  WordEntryPos *posvec_iter = posvec->pos;
1246 
1247  /* Is there a position with a matching weight? */
1248  while (posvec_iter < posvec->pos + posvec->npos)
1249  {
1250  if (val->weight & (1 << WEP_GETWEIGHT(*posvec_iter)))
1251  {
1252  result = TS_YES;
1253  break; /* no need to go further */
1254  }
1255 
1256  posvec_iter++;
1257  }
1258  }
1259  else if (data)
1260  {
1261  data->npos = posvec->npos;
1262  data->pos = posvec->pos;
1263  data->allocated = false;
1264  result = TS_YES;
1265  }
1266  else
1267  {
1268  /* simplest case: no weight check, positions not needed */
1269  result = TS_YES;
1270  }
1271  }
1272  else
1273  {
1274  /*
1275  * Position info is lacking, so if the caller requires it, we can only
1276  * say that maybe there is a match.
1277  *
1278  * Notice, however, that we *don't* check val->weight here.
1279  * Historically, stripped tsvectors are considered to match queries
1280  * whether or not the query has a weight restriction; that's a little
1281  * dubious but we'll preserve the behavior.
1282  */
1283  if (data)
1284  result = TS_MAYBE;
1285  else
1286  result = TS_YES;
1287  }
1288 
1289  return result;
1290 }
#define SHORTALIGN(LEN)
Definition: c.h:796
long val
Definition: informix.c:664
Assert(fmt[strlen(fmt) - 1] !='\n')
void pfree(void *pointer)
Definition: mcxt.c:1431
void * palloc(Size size)
Definition: mcxt.c:1201
const void * data
char * values
Definition: tsvector_op.c:41
WordEntryPos pos[FLEXIBLE_ARRAY_MEMBER]
Definition: ts_type.h:68
TSTernaryValue
Definition: ts_utils.h:133
@ TS_MAYBE
Definition: ts_utils.h:136
@ TS_NO
Definition: ts_utils.h:134
@ TS_YES
Definition: ts_utils.h:135

References Assert(), data, WordEntry::haspos, WordEntry::len, WordEntryPosVector::npos, palloc(), pfree(), WordEntry::pos, WordEntryPosVector::pos, SHORTALIGN, TS_MAYBE, TS_NO, TS_YES, val, CHKVAL::values, WEP_GETPOS, and WEP_GETWEIGHT.

Referenced by checkcondition_str().

◆ checkcondition_str()

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

Definition at line 1296 of file tsvector_op.c.

1297 {
1298  CHKVAL *chkval = (CHKVAL *) checkval;
1299  WordEntry *StopLow = chkval->arrb;
1300  WordEntry *StopHigh = chkval->arre;
1301  WordEntry *StopMiddle = StopHigh;
1303 
1304  /* Loop invariant: StopLow <= val < StopHigh */
1305  while (StopLow < StopHigh)
1306  {
1307  int difference;
1308 
1309  StopMiddle = StopLow + (StopHigh - StopLow) / 2;
1310  difference = tsCompareString(chkval->operand + val->distance,
1311  val->length,
1312  chkval->values + StopMiddle->pos,
1313  StopMiddle->len,
1314  false);
1315 
1316  if (difference == 0)
1317  {
1318  /* Check weight info & fill 'data' with positions */
1319  res = checkclass_str(chkval, StopMiddle, val, data);
1320  break;
1321  }
1322  else if (difference > 0)
1323  StopLow = StopMiddle + 1;
1324  else
1325  StopHigh = StopMiddle;
1326  }
1327 
1328  /*
1329  * If it's a prefix search, we should also consider lexemes that the
1330  * search term is a prefix of (which will necessarily immediately follow
1331  * the place we found in the above loop). But we can skip them if there
1332  * was a definite match on the exact term AND the caller doesn't need
1333  * position info.
1334  */
1335  if (val->prefix && (res != TS_YES || data))
1336  {
1337  WordEntryPos *allpos = NULL;
1338  int npos = 0,
1339  totalpos = 0;
1340 
1341  /* adjust start position for corner case */
1342  if (StopLow >= StopHigh)
1343  StopMiddle = StopHigh;
1344 
1345  /* we don't try to re-use any data from the initial match */
1346  if (data)
1347  {
1348  if (data->allocated)
1349  pfree(data->pos);
1350  data->pos = NULL;
1351  data->allocated = false;
1352  data->npos = 0;
1353  }
1354  res = TS_NO;
1355 
1356  while ((res != TS_YES || data) &&
1357  StopMiddle < chkval->arre &&
1358  tsCompareString(chkval->operand + val->distance,
1359  val->length,
1360  chkval->values + StopMiddle->pos,
1361  StopMiddle->len,
1362  true) == 0)
1363  {
1364  TSTernaryValue subres;
1365 
1366  subres = checkclass_str(chkval, StopMiddle, val, data);
1367 
1368  if (subres != TS_NO)
1369  {
1370  if (data)
1371  {
1372  /*
1373  * We need to join position information
1374  */
1375  if (subres == TS_MAYBE)
1376  {
1377  /*
1378  * No position info for this match, so we must report
1379  * MAYBE overall.
1380  */
1381  res = TS_MAYBE;
1382  /* forget any previous positions */
1383  npos = 0;
1384  /* don't leak storage */
1385  if (allpos)
1386  pfree(allpos);
1387  break;
1388  }
1389 
1390  while (npos + data->npos > totalpos)
1391  {
1392  if (totalpos == 0)
1393  {
1394  totalpos = 256;
1395  allpos = palloc(sizeof(WordEntryPos) * totalpos);
1396  }
1397  else
1398  {
1399  totalpos *= 2;
1400  allpos = repalloc(allpos, sizeof(WordEntryPos) * totalpos);
1401  }
1402  }
1403 
1404  memcpy(allpos + npos, data->pos, sizeof(WordEntryPos) * data->npos);
1405  npos += data->npos;
1406 
1407  /* don't leak storage from individual matches */
1408  if (data->allocated)
1409  pfree(data->pos);
1410  data->pos = NULL;
1411  data->allocated = false;
1412  /* it's important to reset data->npos before next loop */
1413  data->npos = 0;
1414  }
1415  else
1416  {
1417  /* Don't need positions, just handle YES/MAYBE */
1418  if (subres == TS_YES || res == TS_NO)
1419  res = subres;
1420  }
1421  }
1422 
1423  StopMiddle++;
1424  }
1425 
1426  if (data && npos > 0)
1427  {
1428  /* Sort and make unique array of found positions */
1429  data->pos = allpos;
1430  qsort(data->pos, npos, sizeof(WordEntryPos), compareWordEntryPos);
1431  data->npos = qunique(data->pos, npos, sizeof(WordEntryPos),
1433  data->allocated = true;
1434  res = TS_YES;
1435  }
1436  }
1437 
1438  return res;
1439 }
Datum difference(PG_FUNCTION_ARGS)
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1451
int32 * arrb
Definition: _int_bool.c:226
char * operand
Definition: ltxtquery_op.c:52
int32 * arre
Definition: _int_bool.c:227
int compareWordEntryPos(const void *a, const void *b)
Definition: tsvector.c:36
static TSTernaryValue checkclass_str(CHKVAL *chkval, WordEntry *entry, QueryOperand *val, ExecPhraseData *data)
Definition: tsvector_op.c:1190

References CHKVAL::arrb, CHKVAL::arre, checkclass_str(), compareWordEntryPos(), data, difference(), WordEntry::len, CHKVAL::operand, palloc(), pfree(), WordEntry::pos, qsort, qunique(), repalloc(), res, TS_MAYBE, TS_NO, TS_YES, tsCompareString(), val, and CHKVAL::values.

Referenced by ts_match_vq().

◆ chooseNextStatEntry()

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

Definition at line 2382 of file tsvector_op.c.

2384 {
2385  uint32 pos;
2386  uint32 middle = (low + high) >> 1;
2387 
2388  pos = (low + middle) >> 1;
2389  if (low != middle && pos >= offset && pos - offset < txt->size)
2390  insertStatEntry(persistentContext, stat, txt, pos - offset);
2391  pos = (high + middle + 1) >> 1;
2392  if (middle + 1 != high && pos >= offset && pos - offset < txt->size)
2393  insertStatEntry(persistentContext, stat, txt, pos - offset);
2394 
2395  if (low != middle)
2396  chooseNextStatEntry(persistentContext, stat, txt, low, middle, offset);
2397  if (high != middle + 1)
2398  chooseNextStatEntry(persistentContext, stat, txt, middle + 1, high, offset);
2399 }
unsigned int uint32
Definition: c.h:495
static void chooseNextStatEntry(MemoryContext persistentContext, TSVectorStat *stat, TSVector txt, uint32 low, uint32 high, uint32 offset)
Definition: tsvector_op.c:2382
static void insertStatEntry(MemoryContext persistentContext, TSVectorStat *stat, TSVector txt, uint32 off)
Definition: tsvector_op.c:2317

References insertStatEntry().

Referenced by ts_accum().

◆ compare_int()

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

Definition at line 434 of file tsvector_op.c.

435 {
436  int a = *((const int *) va);
437  int b = *((const int *) vb);
438 
439  return pg_cmp_s32(a, b);
440 }
static int pg_cmp_s32(int32 a, int32 b)
Definition: int.h:483

References a, b, and pg_cmp_s32().

Referenced by tsvector_delete_by_indices().

◆ compare_text_lexemes()

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

Definition at line 443 of file tsvector_op.c.

444 {
445  Datum a = *((const Datum *) va);
446  Datum b = *((const Datum *) vb);
447  char *alex = VARDATA_ANY(a);
448  int alex_len = VARSIZE_ANY_EXHDR(a);
449  char *blex = VARDATA_ANY(b);
450  int blex_len = VARSIZE_ANY_EXHDR(b);
451 
452  return tsCompareString(alex, alex_len, blex, blex_len, false);
453 }
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317

References a, b, tsCompareString(), VARDATA_ANY, and VARSIZE_ANY_EXHDR.

Referenced by array_to_tsvector().

◆ insertStatEntry()

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

Definition at line 2317 of file tsvector_op.c.

2318 {
2319  WordEntry *we = ARRPTR(txt) + off;
2320  StatEntry *node = stat->root,
2321  *pnode = NULL;
2322  int n,
2323  res = 0;
2324  uint32 depth = 1;
2325 
2326  if (stat->weight == 0)
2327  n = (we->haspos) ? POSDATALEN(txt, we) : 1;
2328  else
2329  n = (we->haspos) ? check_weight(txt, we, stat->weight) : 0;
2330 
2331  if (n == 0)
2332  return; /* nothing to insert */
2333 
2334  while (node)
2335  {
2336  res = compareStatWord(node, we, txt);
2337 
2338  if (res == 0)
2339  {
2340  break;
2341  }
2342  else
2343  {
2344  pnode = node;
2345  node = (res < 0) ? node->left : node->right;
2346  }
2347  depth++;
2348  }
2349 
2350  if (depth > stat->maxdepth)
2351  stat->maxdepth = depth;
2352 
2353  if (node == NULL)
2354  {
2355  node = MemoryContextAlloc(persistentContext, STATENTRYHDRSZ + we->len);
2356  node->left = node->right = NULL;
2357  node->ndoc = 1;
2358  node->nentry = n;
2359  node->lenlexeme = we->len;
2360  memcpy(node->lexeme, STRPTR(txt) + we->pos, node->lenlexeme);
2361 
2362  if (pnode == NULL)
2363  {
2364  stat->root = node;
2365  }
2366  else
2367  {
2368  if (res < 0)
2369  pnode->left = node;
2370  else
2371  pnode->right = node;
2372  }
2373  }
2374  else
2375  {
2376  node->ndoc++;
2377  node->nentry += n;
2378  }
2379 }
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1034
uint32 nentry
Definition: tsvector_op.c:50
struct StatEntry * left
Definition: tsvector_op.c:51
char lexeme[FLEXIBLE_ARRAY_MEMBER]
Definition: tsvector_op.c:54
uint32 lenlexeme
Definition: tsvector_op.c:53
uint32 ndoc
Definition: tsvector_op.c:48
struct StatEntry * right
Definition: tsvector_op.c:52
#define STATENTRYHDRSZ
Definition: tsvector_op.c:57
static int check_weight(TSVector txt, WordEntry *wptr, int8 weight)
Definition: tsvector_op.c:2296
#define compareStatWord(a, e, t)
Definition: tsvector_op.c:2311

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

Referenced by chooseNextStatEntry(), and ts_accum().

◆ silly_cmp_tsvector()

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

Definition at line 87 of file tsvector_op.c.

88 {
89  if (VARSIZE(a) < VARSIZE(b))
90  return -1;
91  else if (VARSIZE(a) > VARSIZE(b))
92  return 1;
93  else if (a->size < b->size)
94  return -1;
95  else if (a->size > b->size)
96  return 1;
97  else
98  {
99  WordEntry *aptr = ARRPTR(a);
100  WordEntry *bptr = ARRPTR(b);
101  int i = 0;
102  int res;
103 
104 
105  for (i = 0; i < a->size; i++)
106  {
107  if (aptr->haspos != bptr->haspos)
108  {
109  return (aptr->haspos > bptr->haspos) ? -1 : 1;
110  }
111  else if ((res = tsCompareString(STRPTR(a) + aptr->pos, aptr->len, STRPTR(b) + bptr->pos, bptr->len, false)) != 0)
112  {
113  return res;
114  }
115  else if (aptr->haspos)
116  {
117  WordEntryPos *ap = POSDATAPTR(a, aptr);
118  WordEntryPos *bp = POSDATAPTR(b, bptr);
119  int j;
120 
121  if (POSDATALEN(a, aptr) != POSDATALEN(b, bptr))
122  return (POSDATALEN(a, aptr) > POSDATALEN(b, bptr)) ? -1 : 1;
123 
124  for (j = 0; j < POSDATALEN(a, aptr); j++)
125  {
126  if (WEP_GETPOS(*ap) != WEP_GETPOS(*bp))
127  {
128  return (WEP_GETPOS(*ap) > WEP_GETPOS(*bp)) ? -1 : 1;
129  }
130  else if (WEP_GETWEIGHT(*ap) != WEP_GETWEIGHT(*bp))
131  {
132  return (WEP_GETWEIGHT(*ap) > WEP_GETWEIGHT(*bp)) ? -1 : 1;
133  }
134  ap++, bp++;
135  }
136  }
137 
138  aptr++;
139  bptr++;
140  }
141  }
142 
143  return 0;
144 }
int j
Definition: isn.c:74

References a, ARRPTR, b, WordEntry::haspos, i, j, WordEntry::len, WordEntry::pos, POSDATALEN, POSDATAPTR, res, STRPTR, tsCompareString(), VARSIZE, WEP_GETPOS, and WEP_GETWEIGHT.

◆ ts_accum()

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

Definition at line 2414 of file tsvector_op.c.

2415 {
2417  uint32 i,
2418  nbit = 0,
2419  offset;
2420 
2421  if (stat == NULL)
2422  { /* Init in first */
2423  stat = MemoryContextAllocZero(persistentContext, sizeof(TSVectorStat));
2424  stat->maxdepth = 1;
2425  }
2426 
2427  /* simple check of correctness */
2428  if (txt == NULL || txt->size == 0)
2429  {
2430  if (txt && txt != (TSVector) DatumGetPointer(data))
2431  pfree(txt);
2432  return stat;
2433  }
2434 
2435  i = txt->size - 1;
2436  for (; i > 0; i >>= 1)
2437  nbit++;
2438 
2439  nbit = 1 << nbit;
2440  offset = (nbit - txt->size) / 2;
2441 
2442  insertStatEntry(persistentContext, stat, txt, (nbit >> 1) - offset);
2443  chooseNextStatEntry(persistentContext, stat, txt, 0, nbit, offset);
2444 
2445  return stat;
2446 }
void * MemoryContextAllocZero(MemoryContext context, Size size)
Definition: mcxt.c:1077
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:312
static TSVector DatumGetTSVector(Datum X)
Definition: ts_type.h:118
#define stat
Definition: win32_port.h:284

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

Referenced by ts_stat_sql().

◆ TS_execute()

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

Definition at line 1855 of file tsvector_op.c.

1857 {
1858  /*
1859  * If we get TS_MAYBE from the recursion, return true. We could only see
1860  * that result if the caller passed TS_EXEC_PHRASE_NO_POS, so there's no
1861  * need to check again.
1862  */
1863  return TS_execute_recurse(curitem, arg, flags, chkcond) != TS_NO;
1864 }
void * arg
static TSTernaryValue TS_execute_recurse(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
Definition: tsvector_op.c:1884

References arg, TS_execute_recurse(), and TS_NO.

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

◆ TS_execute_locations()

List* TS_execute_locations ( QueryItem curitem,
void *  arg,
uint32  flags,
TSExecuteCallback  chkcond 
)

Definition at line 2008 of file tsvector_op.c.

2011 {
2012  List *result;
2013 
2014  /* No flags supported, as yet */
2015  Assert(flags == TS_EXEC_EMPTY);
2016  if (TS_execute_locations_recurse(curitem, arg, chkcond, &result))
2017  return result;
2018  return NIL;
2019 }
#define NIL
Definition: pg_list.h:68
Definition: pg_list.h:54
#define TS_EXEC_EMPTY
Definition: ts_utils.h:188
static bool TS_execute_locations_recurse(QueryItem *curitem, void *arg, TSExecuteCallback chkcond, List **locations)
Definition: tsvector_op.c:2026

References arg, Assert(), NIL, TS_EXEC_EMPTY, and TS_execute_locations_recurse().

Referenced by prsd_headline().

◆ TS_execute_locations_recurse()

static bool TS_execute_locations_recurse ( QueryItem curitem,
void *  arg,
TSExecuteCallback  chkcond,
List **  locations 
)
static

Definition at line 2026 of file tsvector_op.c.

2029 {
2030  bool lmatch,
2031  rmatch;
2032  List *llocations,
2033  *rlocations;
2035 
2036  /* since this function recurses, it could be driven to stack overflow */
2038 
2039  /* ... and let's check for query cancel while we're at it */
2041 
2042  /* Default locations result is empty */
2043  *locations = NIL;
2044 
2045  if (curitem->type == QI_VAL)
2046  {
2048  if (chkcond(arg, (QueryOperand *) curitem, data) == TS_YES)
2049  {
2050  *locations = list_make1(data);
2051  return true;
2052  }
2053  pfree(data);
2054  return false;
2055  }
2056 
2057  switch (curitem->qoperator.oper)
2058  {
2059  case OP_NOT:
2060  if (!TS_execute_locations_recurse(curitem + 1, arg, chkcond,
2061  &llocations))
2062  return true; /* we don't pass back any locations */
2063  return false;
2064 
2065  case OP_AND:
2066  if (!TS_execute_locations_recurse(curitem + curitem->qoperator.left,
2067  arg, chkcond,
2068  &llocations))
2069  return false;
2070  if (!TS_execute_locations_recurse(curitem + 1,
2071  arg, chkcond,
2072  &rlocations))
2073  return false;
2074  *locations = list_concat(llocations, rlocations);
2075  return true;
2076 
2077  case OP_OR:
2078  lmatch = TS_execute_locations_recurse(curitem + curitem->qoperator.left,
2079  arg, chkcond,
2080  &llocations);
2081  rmatch = TS_execute_locations_recurse(curitem + 1,
2082  arg, chkcond,
2083  &rlocations);
2084  if (lmatch || rmatch)
2085  {
2086  /*
2087  * We generate an AND'able location struct from each
2088  * combination of sub-matches, following the disjunctive law
2089  * (A & B) | (C & D) = (A | C) & (A | D) & (B | C) & (B | D).
2090  *
2091  * However, if either input didn't produce locations (i.e., it
2092  * failed or was a NOT), we must just return the other list.
2093  */
2094  if (llocations == NIL)
2095  *locations = rlocations;
2096  else if (rlocations == NIL)
2097  *locations = llocations;
2098  else
2099  {
2100  ListCell *ll;
2101 
2102  foreach(ll, llocations)
2103  {
2104  ExecPhraseData *ldata = (ExecPhraseData *) lfirst(ll);
2105  ListCell *lr;
2106 
2107  foreach(lr, rlocations)
2108  {
2109  ExecPhraseData *rdata = (ExecPhraseData *) lfirst(lr);
2110 
2112  (void) TS_phrase_output(data, ldata, rdata,
2114  0, 0,
2115  ldata->npos + rdata->npos);
2116  /* Report the larger width, as explained above. */
2117  data->width = Max(ldata->width, rdata->width);
2118  *locations = lappend(*locations, data);
2119  }
2120  }
2121  }
2122 
2123  return true;
2124  }
2125  return false;
2126 
2127  case OP_PHRASE:
2128  /* We can hand this off to TS_phrase_execute */
2130  if (TS_phrase_execute(curitem, arg, TS_EXEC_EMPTY, chkcond,
2131  data) == TS_YES)
2132  {
2133  if (!data->negate)
2134  *locations = list_make1(data);
2135  return true;
2136  }
2137  pfree(data);
2138  return false;
2139 
2140  default:
2141  elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
2142  }
2143 
2144  /* not reachable, but keep compiler quiet */
2145  return false;
2146 }
#define Max(x, y)
Definition: c.h:987
#define palloc0_object(type)
Definition: fe_memutils.h:63
List * lappend(List *list, void *datum)
Definition: list.c:339
List * list_concat(List *list1, const List *list2)
Definition: list.c:561
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:122
#define lfirst(lc)
Definition: pg_list.h:172
#define list_make1(x1)
Definition: pg_list.h:212
void check_stack_depth(void)
Definition: postgres.c:3523
uint32 left
Definition: ts_type.h:197
#define QI_VAL
Definition: ts_type.h:149
#define OP_AND
Definition: ts_type.h:180
#define OP_PHRASE
Definition: ts_type.h:182
#define OP_OR
Definition: ts_type.h:181
#define OP_NOT
Definition: ts_type.h:179
#define TSPO_BOTH
Definition: tsvector_op.c:1466
#define TSPO_R_ONLY
Definition: tsvector_op.c:1465
static TSTernaryValue TS_phrase_output(ExecPhraseData *data, ExecPhraseData *Ldata, ExecPhraseData *Rdata, int emit, int Loffset, int Roffset, int max_npos)
Definition: tsvector_op.c:1469
#define TSPO_L_ONLY
Definition: tsvector_op.c:1464
static TSTernaryValue TS_phrase_execute(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond, ExecPhraseData *data)
Definition: tsvector_op.c:1610
QueryOperator qoperator
Definition: ts_type.h:209
QueryItemType type
Definition: ts_type.h:208

References arg, CHECK_FOR_INTERRUPTS, check_stack_depth(), data, elog(), ERROR, lappend(), QueryOperator::left, lfirst, list_concat(), list_make1, Max, NIL, ExecPhraseData::npos, OP_AND, OP_NOT, OP_OR, OP_PHRASE, QueryOperator::oper, palloc0_object, pfree(), QI_VAL, QueryItem::qoperator, TS_EXEC_EMPTY, TS_phrase_execute(), TS_phrase_output(), TS_YES, TSPO_BOTH, TSPO_L_ONLY, TSPO_R_ONLY, QueryItem::type, and ExecPhraseData::width.

Referenced by TS_execute_locations().

◆ TS_execute_recurse()

static TSTernaryValue TS_execute_recurse ( QueryItem curitem,
void *  arg,
uint32  flags,
TSExecuteCallback  chkcond 
)
static

Definition at line 1884 of file tsvector_op.c.

1886 {
1887  TSTernaryValue lmatch;
1888 
1889  /* since this function recurses, it could be driven to stack overflow */
1891 
1892  /* ... and let's check for query cancel while we're at it */
1894 
1895  if (curitem->type == QI_VAL)
1896  return chkcond(arg, (QueryOperand *) curitem,
1897  NULL /* don't need position info */ );
1898 
1899  switch (curitem->qoperator.oper)
1900  {
1901  case OP_NOT:
1902  if (flags & TS_EXEC_SKIP_NOT)
1903  return TS_YES;
1904  switch (TS_execute_recurse(curitem + 1, arg, flags, chkcond))
1905  {
1906  case TS_NO:
1907  return TS_YES;
1908  case TS_YES:
1909  return TS_NO;
1910  case TS_MAYBE:
1911  return TS_MAYBE;
1912  }
1913  break;
1914 
1915  case OP_AND:
1916  lmatch = TS_execute_recurse(curitem + curitem->qoperator.left, arg,
1917  flags, chkcond);
1918  if (lmatch == TS_NO)
1919  return TS_NO;
1920  switch (TS_execute_recurse(curitem + 1, arg, flags, chkcond))
1921  {
1922  case TS_NO:
1923  return TS_NO;
1924  case TS_YES:
1925  return lmatch;
1926  case TS_MAYBE:
1927  return TS_MAYBE;
1928  }
1929  break;
1930 
1931  case OP_OR:
1932  lmatch = TS_execute_recurse(curitem + curitem->qoperator.left, arg,
1933  flags, chkcond);
1934  if (lmatch == TS_YES)
1935  return TS_YES;
1936  switch (TS_execute_recurse(curitem + 1, arg, flags, chkcond))
1937  {
1938  case TS_NO:
1939  return lmatch;
1940  case TS_YES:
1941  return TS_YES;
1942  case TS_MAYBE:
1943  return TS_MAYBE;
1944  }
1945  break;
1946 
1947  case OP_PHRASE:
1948 
1949  /*
1950  * If we get a MAYBE result, and the caller doesn't want that,
1951  * convert it to NO. It would be more consistent, perhaps, to
1952  * return the result of TS_phrase_execute() verbatim and then
1953  * convert MAYBE results at the top of the recursion. But
1954  * converting at the topmost phrase operator gives results that
1955  * are bug-compatible with the old implementation, so do it like
1956  * this for now.
1957  */
1958  switch (TS_phrase_execute(curitem, arg, flags, chkcond, NULL))
1959  {
1960  case TS_NO:
1961  return TS_NO;
1962  case TS_YES:
1963  return TS_YES;
1964  case TS_MAYBE:
1965  return (flags & TS_EXEC_PHRASE_NO_POS) ? TS_MAYBE : TS_NO;
1966  }
1967  break;
1968 
1969  default:
1970  elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
1971  }
1972 
1973  /* not reachable, but keep compiler quiet */
1974  return TS_NO;
1975 }
#define TS_EXEC_PHRASE_NO_POS
Definition: ts_utils.h:202
#define TS_EXEC_SKIP_NOT
Definition: ts_utils.h:195

References arg, CHECK_FOR_INTERRUPTS, check_stack_depth(), elog(), ERROR, QueryOperator::left, OP_AND, OP_NOT, OP_OR, OP_PHRASE, QueryOperator::oper, QI_VAL, QueryItem::qoperator, TS_EXEC_PHRASE_NO_POS, TS_EXEC_SKIP_NOT, TS_MAYBE, TS_NO, TS_phrase_execute(), TS_YES, and QueryItem::type.

Referenced by TS_execute(), and TS_execute_ternary().

◆ TS_execute_ternary()

TSTernaryValue TS_execute_ternary ( QueryItem curitem,
void *  arg,
uint32  flags,
TSExecuteCallback  chkcond 
)

Definition at line 1872 of file tsvector_op.c.

1874 {
1875  return TS_execute_recurse(curitem, arg, flags, chkcond);
1876 }

References arg, and TS_execute_recurse().

Referenced by gin_tsquery_consistent(), and gin_tsquery_triconsistent().

◆ ts_match_qv()

Datum ts_match_qv ( PG_FUNCTION_ARGS  )

Definition at line 2207 of file tsvector_op.c.

2208 {
2210  PG_GETARG_DATUM(1),
2211  PG_GETARG_DATUM(0)));
2212 }
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
#define PG_GETARG_DATUM(n)
Definition: fmgr.h:268
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
Datum ts_match_vq(PG_FUNCTION_ARGS)
Definition: tsvector_op.c:2215

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

◆ ts_match_tq()

Datum ts_match_tq ( PG_FUNCTION_ARGS  )

Definition at line 2267 of file tsvector_op.c.

2268 {
2269  TSVector vector;
2270  TSQuery query = PG_GETARG_TSQUERY(1);
2271  bool res;
2272 
2274  PG_GETARG_DATUM(0)));
2275 
2277  TSVectorGetDatum(vector),
2278  TSQueryGetDatum(query)));
2279 
2280  pfree(vector);
2281  PG_FREE_IF_COPY(query, 1);
2282 
2284 }
#define DirectFunctionCall1(func, arg1)
Definition: fmgr.h:642
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359
static bool DatumGetBool(Datum X)
Definition: postgres.h:90
Datum to_tsvector(PG_FUNCTION_ARGS)
Definition: to_tsany.c:271
static Datum TSVectorGetDatum(const TSVectorData *X)
Definition: ts_type.h:130
#define PG_GETARG_TSQUERY(n)
Definition: ts_type.h:266
static Datum TSQueryGetDatum(const TSQueryData *X)
Definition: ts_type.h:261

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

◆ ts_match_tt()

Datum ts_match_tt ( PG_FUNCTION_ARGS  )

Definition at line 2245 of file tsvector_op.c.

2246 {
2247  TSVector vector;
2248  TSQuery query;
2249  bool res;
2250 
2252  PG_GETARG_DATUM(0)));
2254  PG_GETARG_DATUM(1)));
2255 
2257  TSVectorGetDatum(vector),
2258  TSQueryGetDatum(query)));
2259 
2260  pfree(vector);
2261  pfree(query);
2262 
2264 }
Datum plainto_tsquery(PG_FUNCTION_ARGS)
Definition: to_tsany.c:643
static TSQuery DatumGetTSQuery(Datum X)
Definition: ts_type.h:249

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

◆ ts_match_vq()

Datum ts_match_vq ( PG_FUNCTION_ARGS  )

Definition at line 2215 of file tsvector_op.c.

2216 {
2218  TSQuery query = PG_GETARG_TSQUERY(1);
2219  CHKVAL chkval;
2220  bool result;
2221 
2222  /* empty query matches nothing */
2223  if (!query->size)
2224  {
2225  PG_FREE_IF_COPY(val, 0);
2226  PG_FREE_IF_COPY(query, 1);
2227  PG_RETURN_BOOL(false);
2228  }
2229 
2230  chkval.arrb = ARRPTR(val);
2231  chkval.arre = chkval.arrb + val->size;
2232  chkval.values = STRPTR(val);
2233  chkval.operand = GETOPERAND(query);
2234  result = TS_execute(GETQUERY(query),
2235  &chkval,
2236  TS_EXEC_EMPTY,
2238 
2239  PG_FREE_IF_COPY(val, 0);
2240  PG_FREE_IF_COPY(query, 1);
2241  PG_RETURN_BOOL(result);
2242 }
#define GETQUERY(x)
Definition: _int.h:157
#define GETOPERAND(x)
Definition: ltree.h:165
int32 size
Definition: ts_type.h:221
static TSTernaryValue checkcondition_str(void *checkval, QueryOperand *val, ExecPhraseData *data)
Definition: tsvector_op.c:1296
bool TS_execute(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
Definition: tsvector_op.c:1855

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, TSQueryData::size, STRPTR, TS_EXEC_EMPTY, TS_execute(), val, and CHKVAL::values.

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

◆ TS_phrase_execute()

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

Definition at line 1610 of file tsvector_op.c.

1613 {
1614  ExecPhraseData Ldata,
1615  Rdata;
1616  TSTernaryValue lmatch,
1617  rmatch;
1618  int Loffset,
1619  Roffset,
1620  maxwidth;
1621 
1622  /* since this function recurses, it could be driven to stack overflow */
1624 
1625  /* ... and let's check for query cancel while we're at it */
1627 
1628  if (curitem->type == QI_VAL)
1629  return chkcond(arg, (QueryOperand *) curitem, data);
1630 
1631  switch (curitem->qoperator.oper)
1632  {
1633  case OP_NOT:
1634 
1635  /*
1636  * We need not touch data->width, since a NOT operation does not
1637  * change the match width.
1638  */
1639  if (flags & TS_EXEC_SKIP_NOT)
1640  {
1641  /* with SKIP_NOT, report NOT as "match everywhere" */
1642  Assert(data->npos == 0 && !data->negate);
1643  data->negate = true;
1644  return TS_YES;
1645  }
1646  switch (TS_phrase_execute(curitem + 1, arg, flags, chkcond, data))
1647  {
1648  case TS_NO:
1649  /* change "match nowhere" to "match everywhere" */
1650  Assert(data->npos == 0 && !data->negate);
1651  data->negate = true;
1652  return TS_YES;
1653  case TS_YES:
1654  if (data->npos > 0)
1655  {
1656  /* we have some positions, invert negate flag */
1657  data->negate = !data->negate;
1658  return TS_YES;
1659  }
1660  else if (data->negate)
1661  {
1662  /* change "match everywhere" to "match nowhere" */
1663  data->negate = false;
1664  return TS_NO;
1665  }
1666  /* Should not get here if result was TS_YES */
1667  Assert(false);
1668  break;
1669  case TS_MAYBE:
1670  /* match positions are, and remain, uncertain */
1671  return TS_MAYBE;
1672  }
1673  break;
1674 
1675  case OP_PHRASE:
1676  case OP_AND:
1677  memset(&Ldata, 0, sizeof(Ldata));
1678  memset(&Rdata, 0, sizeof(Rdata));
1679 
1680  lmatch = TS_phrase_execute(curitem + curitem->qoperator.left,
1681  arg, flags, chkcond, &Ldata);
1682  if (lmatch == TS_NO)
1683  return TS_NO;
1684 
1685  rmatch = TS_phrase_execute(curitem + 1,
1686  arg, flags, chkcond, &Rdata);
1687  if (rmatch == TS_NO)
1688  return TS_NO;
1689 
1690  /*
1691  * If either operand has no position information, then we can't
1692  * return reliable position data, only a MAYBE result.
1693  */
1694  if (lmatch == TS_MAYBE || rmatch == TS_MAYBE)
1695  return TS_MAYBE;
1696 
1697  if (curitem->qoperator.oper == OP_PHRASE)
1698  {
1699  /*
1700  * Compute Loffset and Roffset suitable for phrase match, and
1701  * compute overall width of whole phrase match.
1702  */
1703  Loffset = curitem->qoperator.distance + Rdata.width;
1704  Roffset = 0;
1705  if (data)
1706  data->width = curitem->qoperator.distance +
1707  Ldata.width + Rdata.width;
1708  }
1709  else
1710  {
1711  /*
1712  * For OP_AND, set output width and alignment like OP_OR (see
1713  * comment below)
1714  */
1715  maxwidth = Max(Ldata.width, Rdata.width);
1716  Loffset = maxwidth - Ldata.width;
1717  Roffset = maxwidth - Rdata.width;
1718  if (data)
1719  data->width = maxwidth;
1720  }
1721 
1722  if (Ldata.negate && Rdata.negate)
1723  {
1724  /* !L & !R: treat as !(L | R) */
1725  (void) TS_phrase_output(data, &Ldata, &Rdata,
1727  Loffset, Roffset,
1728  Ldata.npos + Rdata.npos);
1729  if (data)
1730  data->negate = true;
1731  return TS_YES;
1732  }
1733  else if (Ldata.negate)
1734  {
1735  /* !L & R */
1736  return TS_phrase_output(data, &Ldata, &Rdata,
1737  TSPO_R_ONLY,
1738  Loffset, Roffset,
1739  Rdata.npos);
1740  }
1741  else if (Rdata.negate)
1742  {
1743  /* L & !R */
1744  return TS_phrase_output(data, &Ldata, &Rdata,
1745  TSPO_L_ONLY,
1746  Loffset, Roffset,
1747  Ldata.npos);
1748  }
1749  else
1750  {
1751  /* straight AND */
1752  return TS_phrase_output(data, &Ldata, &Rdata,
1753  TSPO_BOTH,
1754  Loffset, Roffset,
1755  Min(Ldata.npos, Rdata.npos));
1756  }
1757 
1758  case OP_OR:
1759  memset(&Ldata, 0, sizeof(Ldata));
1760  memset(&Rdata, 0, sizeof(Rdata));
1761 
1762  lmatch = TS_phrase_execute(curitem + curitem->qoperator.left,
1763  arg, flags, chkcond, &Ldata);
1764  rmatch = TS_phrase_execute(curitem + 1,
1765  arg, flags, chkcond, &Rdata);
1766 
1767  if (lmatch == TS_NO && rmatch == TS_NO)
1768  return TS_NO;
1769 
1770  /*
1771  * If either operand has no position information, then we can't
1772  * return reliable position data, only a MAYBE result.
1773  */
1774  if (lmatch == TS_MAYBE || rmatch == TS_MAYBE)
1775  return TS_MAYBE;
1776 
1777  /*
1778  * Cope with undefined output width from failed submatch. (This
1779  * takes less code than trying to ensure that all failure returns
1780  * set data->width to zero.)
1781  */
1782  if (lmatch == TS_NO)
1783  Ldata.width = 0;
1784  if (rmatch == TS_NO)
1785  Rdata.width = 0;
1786 
1787  /*
1788  * For OP_AND and OP_OR, report the width of the wider of the two
1789  * inputs, and align the narrower input's positions to the right
1790  * end of that width. This rule deals at least somewhat
1791  * reasonably with cases like "x <-> (y | z <-> q)".
1792  */
1793  maxwidth = Max(Ldata.width, Rdata.width);
1794  Loffset = maxwidth - Ldata.width;
1795  Roffset = maxwidth - Rdata.width;
1796  data->width = maxwidth;
1797 
1798  if (Ldata.negate && Rdata.negate)
1799  {
1800  /* !L | !R: treat as !(L & R) */
1801  (void) TS_phrase_output(data, &Ldata, &Rdata,
1802  TSPO_BOTH,
1803  Loffset, Roffset,
1804  Min(Ldata.npos, Rdata.npos));
1805  data->negate = true;
1806  return TS_YES;
1807  }
1808  else if (Ldata.negate)
1809  {
1810  /* !L | R: treat as !(L & !R) */
1811  (void) TS_phrase_output(data, &Ldata, &Rdata,
1812  TSPO_L_ONLY,
1813  Loffset, Roffset,
1814  Ldata.npos);
1815  data->negate = true;
1816  return TS_YES;
1817  }
1818  else if (Rdata.negate)
1819  {
1820  /* L | !R: treat as !(!L & R) */
1821  (void) TS_phrase_output(data, &Ldata, &Rdata,
1822  TSPO_R_ONLY,
1823  Loffset, Roffset,
1824  Rdata.npos);
1825  data->negate = true;
1826  return TS_YES;
1827  }
1828  else
1829  {
1830  /* straight OR */
1831  return TS_phrase_output(data, &Ldata, &Rdata,
1833  Loffset, Roffset,
1834  Ldata.npos + Rdata.npos);
1835  }
1836 
1837  default:
1838  elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
1839  }
1840 
1841  /* not reachable, but keep compiler quiet */
1842  return TS_NO;
1843 }
#define Min(x, y)
Definition: c.h:993
int16 distance
Definition: ts_type.h:196

References arg, Assert(), CHECK_FOR_INTERRUPTS, check_stack_depth(), data, QueryOperator::distance, elog(), ERROR, QueryOperator::left, Max, Min, ExecPhraseData::negate, ExecPhraseData::npos, OP_AND, OP_NOT, OP_OR, OP_PHRASE, QueryOperator::oper, QI_VAL, QueryItem::qoperator, TS_EXEC_SKIP_NOT, TS_MAYBE, TS_NO, TS_phrase_output(), TS_YES, TSPO_BOTH, TSPO_L_ONLY, TSPO_R_ONLY, QueryItem::type, and ExecPhraseData::width.

Referenced by TS_execute_locations_recurse(), and TS_execute_recurse().

◆ TS_phrase_output()

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

Definition at line 1469 of file tsvector_op.c.

1476 {
1477  int Lindex,
1478  Rindex;
1479 
1480  /* Loop until both inputs are exhausted */
1481  Lindex = Rindex = 0;
1482  while (Lindex < Ldata->npos || Rindex < Rdata->npos)
1483  {
1484  int Lpos,
1485  Rpos;
1486  int output_pos = 0;
1487 
1488  /*
1489  * Fetch current values to compare. WEP_GETPOS() is needed because
1490  * ExecPhraseData->data can point to a tsvector's WordEntryPosVector.
1491  */
1492  if (Lindex < Ldata->npos)
1493  Lpos = WEP_GETPOS(Ldata->pos[Lindex]) + Loffset;
1494  else
1495  {
1496  /* L array exhausted, so we're done if R_ONLY isn't set */
1497  if (!(emit & TSPO_R_ONLY))
1498  break;
1499  Lpos = INT_MAX;
1500  }
1501  if (Rindex < Rdata->npos)
1502  Rpos = WEP_GETPOS(Rdata->pos[Rindex]) + Roffset;
1503  else
1504  {
1505  /* R array exhausted, so we're done if L_ONLY isn't set */
1506  if (!(emit & TSPO_L_ONLY))
1507  break;
1508  Rpos = INT_MAX;
1509  }
1510 
1511  /* Merge-join the two input lists */
1512  if (Lpos < Rpos)
1513  {
1514  /* Lpos is not matched in Rdata, should we output it? */
1515  if (emit & TSPO_L_ONLY)
1516  output_pos = Lpos;
1517  Lindex++;
1518  }
1519  else if (Lpos == Rpos)
1520  {
1521  /* Lpos and Rpos match ... should we output it? */
1522  if (emit & TSPO_BOTH)
1523  output_pos = Rpos;
1524  Lindex++;
1525  Rindex++;
1526  }
1527  else /* Lpos > Rpos */
1528  {
1529  /* Rpos is not matched in Ldata, should we output it? */
1530  if (emit & TSPO_R_ONLY)
1531  output_pos = Rpos;
1532  Rindex++;
1533  }
1534 
1535  if (output_pos > 0)
1536  {
1537  if (data)
1538  {
1539  /* Store position, first allocating output array if needed */
1540  if (data->pos == NULL)
1541  {
1542  data->pos = (WordEntryPos *)
1543  palloc(max_npos * sizeof(WordEntryPos));
1544  data->allocated = true;
1545  }
1546  data->pos[data->npos++] = output_pos;
1547  }
1548  else
1549  {
1550  /*
1551  * Exact positions not needed, so return TS_YES as soon as we
1552  * know there is at least one.
1553  */
1554  return TS_YES;
1555  }
1556  }
1557  }
1558 
1559  if (data && data->npos > 0)
1560  {
1561  /* Let's assert we didn't overrun the array */
1562  Assert(data->npos <= max_npos);
1563  return TS_YES;
1564  }
1565  return TS_NO;
1566 }
WordEntryPos * pos
Definition: ts_utils.h:166

References Assert(), data, palloc(), ExecPhraseData::pos, TS_NO, TS_YES, TSPO_BOTH, TSPO_L_ONLY, TSPO_R_ONLY, and WEP_GETPOS.

Referenced by TS_execute_locations_recurse(), and TS_phrase_execute().

◆ ts_process_call()

static Datum ts_process_call ( FuncCallContext funcctx)
static

Definition at line 2536 of file tsvector_op.c.

2537 {
2538  TSVectorStat *st;
2539  StatEntry *entry;
2540 
2541  st = (TSVectorStat *) funcctx->user_fctx;
2542 
2543  entry = walkStatEntryTree(st);
2544 
2545  if (entry != NULL)
2546  {
2547  Datum result;
2548  char *values[3];
2549  char ndoc[16];
2550  char nentry[16];
2551  HeapTuple tuple;
2552 
2553  values[0] = palloc(entry->lenlexeme + 1);
2554  memcpy(values[0], entry->lexeme, entry->lenlexeme);
2555  (values[0])[entry->lenlexeme] = '\0';
2556  sprintf(ndoc, "%d", entry->ndoc);
2557  values[1] = ndoc;
2558  sprintf(nentry, "%d", entry->nentry);
2559  values[2] = nentry;
2560 
2561  tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
2562  result = HeapTupleGetDatum(tuple);
2563 
2564  pfree(values[0]);
2565 
2566  /* mark entry as already visited */
2567  entry->ndoc = 0;
2568 
2569  return result;
2570  }
2571 
2572  return (Datum) 0;
2573 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2134
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define sprintf
Definition: port.h:240
void * user_fctx
Definition: funcapi.h:82
AttInMetadata * attinmeta
Definition: funcapi.h:91
static StatEntry * walkStatEntryTree(TSVectorStat *stat)
Definition: tsvector_op.c:2490

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().

◆ ts_setup_firstcall()

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

Definition at line 2449 of file tsvector_op.c.

2451 {
2452  TupleDesc tupdesc;
2453  MemoryContext oldcontext;
2454  StatEntry *node;
2455 
2456  funcctx->user_fctx = (void *) stat;
2457 
2458  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
2459 
2460  stat->stack = palloc0(sizeof(StatEntry *) * (stat->maxdepth + 1));
2461  stat->stackpos = 0;
2462 
2463  node = stat->root;
2464  /* find leftmost value */
2465  if (node == NULL)
2466  stat->stack[stat->stackpos] = NULL;
2467  else
2468  for (;;)
2469  {
2470  stat->stack[stat->stackpos] = node;
2471  if (node->left)
2472  {
2473  stat->stackpos++;
2474  node = node->left;
2475  }
2476  else
2477  break;
2478  }
2479  Assert(stat->stackpos <= stat->maxdepth);
2480 
2481  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
2482  elog(ERROR, "return type must be a row type");
2483  funcctx->tuple_desc = tupdesc;
2484  funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
2485 
2486  MemoryContextSwitchTo(oldcontext);
2487 }
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2085
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:124
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112

References Assert(), FuncCallContext::attinmeta, elog(), ERROR, get_call_result_type(), StatEntry::left, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, palloc0(), FuncCallContext::tuple_desc, TupleDescGetAttInMetadata(), TYPEFUNC_COMPOSITE, and FuncCallContext::user_fctx.

Referenced by ts_stat1(), and ts_stat2().

◆ ts_stat1()

Datum ts_stat1 ( PG_FUNCTION_ARGS  )

Definition at line 2665 of file tsvector_op.c.

2666 {
2667  FuncCallContext *funcctx;
2668  Datum result;
2669 
2670  if (SRF_IS_FIRSTCALL())
2671  {
2672  TSVectorStat *stat;
2673  text *txt = PG_GETARG_TEXT_PP(0);
2674 
2675  funcctx = SRF_FIRSTCALL_INIT();
2676  SPI_connect();
2677  stat = ts_stat_sql(funcctx->multi_call_memory_ctx, txt, NULL);
2678  PG_FREE_IF_COPY(txt, 0);
2679  ts_setup_firstcall(fcinfo, funcctx, stat);
2680  SPI_finish();
2681  }
2682 
2683  funcctx = SRF_PERCALL_SETUP();
2684  if ((result = ts_process_call(funcctx)) != (Datum) 0)
2685  SRF_RETURN_NEXT(funcctx, result);
2686  SRF_RETURN_DONE(funcctx);
2687 }
#define PG_GETARG_TEXT_PP(n)
Definition: fmgr.h:309
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
int SPI_connect(void)
Definition: spi.c:95
int SPI_finish(void)
Definition: spi.c:183
Definition: c.h:676
static Datum ts_process_call(FuncCallContext *funcctx)
Definition: tsvector_op.c:2536
static void ts_setup_firstcall(FunctionCallInfo fcinfo, FuncCallContext *funcctx, TSVectorStat *stat)
Definition: tsvector_op.c:2449
static TSVectorStat * ts_stat_sql(MemoryContext persistentContext, text *txt, text *ws)
Definition: tsvector_op.c:2576

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().

◆ ts_stat2()

Datum ts_stat2 ( PG_FUNCTION_ARGS  )

Definition at line 2690 of file tsvector_op.c.

2691 {
2692  FuncCallContext *funcctx;
2693  Datum result;
2694 
2695  if (SRF_IS_FIRSTCALL())
2696  {
2697  TSVectorStat *stat;
2698  text *txt = PG_GETARG_TEXT_PP(0);
2699  text *ws = PG_GETARG_TEXT_PP(1);
2700 
2701  funcctx = SRF_FIRSTCALL_INIT();
2702  SPI_connect();
2703  stat = ts_stat_sql(funcctx->multi_call_memory_ctx, txt, ws);
2704  PG_FREE_IF_COPY(txt, 0);
2705  PG_FREE_IF_COPY(ws, 1);
2706  ts_setup_firstcall(fcinfo, funcctx, stat);
2707  SPI_finish();
2708  }
2709 
2710  funcctx = SRF_PERCALL_SETUP();
2711  if ((result = ts_process_call(funcctx)) != (Datum) 0)
2712  SRF_RETURN_NEXT(funcctx, result);
2713  SRF_RETURN_DONE(funcctx);
2714 }

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().

◆ ts_stat_sql()

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

Definition at line 2576 of file tsvector_op.c.

2577 {
2578  char *query = text_to_cstring(txt);
2579  TSVectorStat *stat;
2580  bool isnull;
2581  Portal portal;
2582  SPIPlanPtr plan;
2583 
2584  if ((plan = SPI_prepare(query, 0, NULL)) == NULL)
2585  /* internal error */
2586  elog(ERROR, "SPI_prepare(\"%s\") failed", query);
2587 
2588  if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL)
2589  /* internal error */
2590  elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
2591 
2592  SPI_cursor_fetch(portal, true, 100);
2593 
2594  if (SPI_tuptable == NULL ||
2595  SPI_tuptable->tupdesc->natts != 1 ||
2597  TSVECTOROID))
2598  ereport(ERROR,
2599  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2600  errmsg("ts_stat query must return one tsvector column")));
2601 
2602  stat = MemoryContextAllocZero(persistentContext, sizeof(TSVectorStat));
2603  stat->maxdepth = 1;
2604 
2605  if (ws)
2606  {
2607  char *buf;
2608 
2609  buf = VARDATA_ANY(ws);
2610  while (buf - VARDATA_ANY(ws) < VARSIZE_ANY_EXHDR(ws))
2611  {
2612  if (pg_mblen(buf) == 1)
2613  {
2614  switch (*buf)
2615  {
2616  case 'A':
2617  case 'a':
2618  stat->weight |= 1 << 3;
2619  break;
2620  case 'B':
2621  case 'b':
2622  stat->weight |= 1 << 2;
2623  break;
2624  case 'C':
2625  case 'c':
2626  stat->weight |= 1 << 1;
2627  break;
2628  case 'D':
2629  case 'd':
2630  stat->weight |= 1;
2631  break;
2632  default:
2633  stat->weight |= 0;
2634  }
2635  }
2636  buf += pg_mblen(buf);
2637  }
2638  }
2639 
2640  while (SPI_processed > 0)
2641  {
2642  uint64 i;
2643 
2644  for (i = 0; i < SPI_processed; i++)
2645  {
2647 
2648  if (!isnull)
2649  stat = ts_accum(persistentContext, stat, data);
2650  }
2651 
2653  SPI_cursor_fetch(portal, true, 100);
2654  }
2655 
2657  SPI_cursor_close(portal);
2658  SPI_freeplan(plan);
2659  pfree(query);
2660 
2661  return stat;
2662 }
int pg_mblen(const char *mbstr)
Definition: mbutils.c:1024
bool IsBinaryCoercible(Oid srctype, Oid targettype)
#define plan(x)
Definition: pg_regress.c:162
static char * buf
Definition: pg_test_fsync.c:73
uint64 SPI_processed
Definition: spi.c:45
Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber)
Definition: spi.c:1306
int SPI_freeplan(SPIPlanPtr plan)
Definition: spi.c:1023
SPITupleTable * SPI_tuptable
Definition: spi.c:46
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1804
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:1384
Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only)
Definition: spi.c:1443
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:858
void SPI_cursor_close(Portal portal)
Definition: spi.c:1860
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:1250
TupleDesc tupdesc
Definition: spi.h:25
HeapTuple * vals
Definition: spi.h:26
static TSVectorStat * ts_accum(MemoryContext persistentContext, TSVectorStat *stat, Datum data)
Definition: tsvector_op.c:2414
char * text_to_cstring(const text *t)
Definition: varlena.c:217

References buf, data, elog(), ereport, errcode(), errmsg(), ERROR, i, IsBinaryCoercible(), MemoryContextAllocZero(), TupleDescData::natts, pfree(), pg_mblen(), plan, 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, and VARSIZE_ANY_EXHDR.

Referenced by ts_stat1(), and ts_stat2().

◆ tsCompareString()

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

Definition at line 1153 of file tsvector_op.c.

1154 {
1155  int cmp;
1156 
1157  if (lena == 0)
1158  {
1159  if (prefix)
1160  cmp = 0; /* empty string is prefix of anything */
1161  else
1162  cmp = (lenb > 0) ? -1 : 0;
1163  }
1164  else if (lenb == 0)
1165  {
1166  cmp = (lena > 0) ? 1 : 0;
1167  }
1168  else
1169  {
1170  cmp = memcmp(a, b, Min((unsigned int) lena, (unsigned int) lenb));
1171 
1172  if (prefix)
1173  {
1174  if (cmp == 0 && lena > lenb)
1175  cmp = 1; /* a is longer, so not a prefix of b */
1176  }
1177  else if (cmp == 0 && lena != lenb)
1178  {
1179  cmp = (lena < lenb) ? -1 : 1;
1180  }
1181  }
1182 
1183  return cmp;
1184 }
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743

References a, b, 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().

◆ tsquery_requires_match()

bool tsquery_requires_match ( QueryItem curitem)

Definition at line 2157 of file tsvector_op.c.

2158 {
2159  /* since this function recurses, it could be driven to stack overflow */
2161 
2162  if (curitem->type == QI_VAL)
2163  return true;
2164 
2165  switch (curitem->qoperator.oper)
2166  {
2167  case OP_NOT:
2168 
2169  /*
2170  * Assume there are no required matches underneath a NOT. For
2171  * some cases with nested NOTs, we could prove there's a required
2172  * match, but it seems unlikely to be worth the trouble.
2173  */
2174  return false;
2175 
2176  case OP_PHRASE:
2177 
2178  /*
2179  * Treat OP_PHRASE as OP_AND here
2180  */
2181  case OP_AND:
2182  /* If either side requires a match, we're good */
2183  if (tsquery_requires_match(curitem + curitem->qoperator.left))
2184  return true;
2185  else
2186  return tsquery_requires_match(curitem + 1);
2187 
2188  case OP_OR:
2189  /* Both sides must require a match */
2190  if (tsquery_requires_match(curitem + curitem->qoperator.left))
2191  return tsquery_requires_match(curitem + 1);
2192  else
2193  return false;
2194 
2195  default:
2196  elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
2197  }
2198 
2199  /* not reachable, but keep compiler quiet */
2200  return false;
2201 }
bool tsquery_requires_match(QueryItem *curitem)
Definition: tsvector_op.c:2157

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

Referenced by gin_extract_tsquery().

◆ tsvector_bsearch()

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

Definition at line 401 of file tsvector_op.c.

402 {
403  WordEntry *arrin = ARRPTR(tsv);
404  int StopLow = 0,
405  StopHigh = tsv->size,
406  StopMiddle,
407  cmp;
408 
409  while (StopLow < StopHigh)
410  {
411  StopMiddle = (StopLow + StopHigh) / 2;
412 
413  cmp = tsCompareString(lexeme, lexeme_len,
414  STRPTR(tsv) + arrin[StopMiddle].pos,
415  arrin[StopMiddle].len,
416  false);
417 
418  if (cmp < 0)
419  StopHigh = StopMiddle;
420  else if (cmp > 0)
421  StopLow = StopMiddle + 1;
422  else /* found it */
423  return StopMiddle;
424  }
425 
426  return -1;
427 }

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

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

◆ tsvector_concat()

Datum tsvector_concat ( PG_FUNCTION_ARGS  )

Definition at line 926 of file tsvector_op.c.

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

References _POSVECPTR, add_pos(), ARRPTR, Assert(), CALCDATASIZE, cmp(), compareEntry, data, ereport, errcode(), errmsg(), ERROR, WordEntry::haspos, i, j, WordEntry::len, MAXSTRPOS, 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.

◆ tsvector_delete_arr()

Datum tsvector_delete_arr ( PG_FUNCTION_ARGS  )

Definition at line 579 of file tsvector_op.c.

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_builtin(lexemes, TEXTOID, &dlexemes, &nulls, &nlex);
592 
593  /*
594  * In typical use case array of lexemes to delete is relatively small. So
595  * here we optimize things for that scenario: iterate through lexarr
596  * performing binary search of each lexeme from lexarr in tsvector.
597  */
598  skip_indices = palloc0(nlex * sizeof(int));
599  for (i = skip_count = 0; i < nlex; i++)
600  {
601  char *lex;
602  int lex_len,
603  lex_pos;
604 
605  /* Ignore null array elements, they surely don't match */
606  if (nulls[i])
607  continue;
608 
609  lex = VARDATA(dlexemes[i]);
610  lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ;
611  lex_pos = tsvector_bsearch(tsin, lex, lex_len);
612 
613  if (lex_pos >= 0)
614  skip_indices[skip_count++] = lex_pos;
615  }
616 
617  tsout = tsvector_delete_by_indices(tsin, skip_indices, skip_count);
618 
619  pfree(skip_indices);
620  PG_FREE_IF_COPY(tsin, 0);
621  PG_FREE_IF_COPY(lexemes, 1);
622 
623  PG_RETURN_POINTER(tsout);
624 }
static int tsvector_bsearch(const TSVector tsv, char *lexeme, int lexeme_len)
Definition: tsvector_op.c:401
static TSVector tsvector_delete_by_indices(TSVector tsv, int *indices_to_delete, int indices_count)
Definition: tsvector_op.c:465

References deconstruct_array_builtin(), 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.

◆ tsvector_delete_by_indices()

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

Definition at line 465 of file tsvector_op.c.

467 {
468  TSVector tsout;
469  WordEntry *arrin = ARRPTR(tsv),
470  *arrout;
471  char *data = STRPTR(tsv),
472  *dataout;
473  int i, /* index in arrin */
474  j, /* index in arrout */
475  k, /* index in indices_to_delete */
476  curoff; /* index in dataout area */
477 
478  /*
479  * Sort the filter array to simplify membership checks below. Also, get
480  * rid of any duplicate entries, so that we can assume that indices_count
481  * is exactly equal to the number of lexemes that will be removed.
482  */
483  if (indices_count > 1)
484  {
485  qsort(indices_to_delete, indices_count, sizeof(int), compare_int);
486  indices_count = qunique(indices_to_delete, indices_count, sizeof(int),
487  compare_int);
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 }
static int compare_int(const void *va, const void *vb)
Definition: tsvector_op.c:434

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

Referenced by tsvector_delete_arr(), and tsvector_delete_str().

◆ tsvector_delete_str()

Datum tsvector_delete_str ( PG_FUNCTION_ARGS  )

Definition at line 555 of file tsvector_op.c.

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 }

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.

◆ tsvector_filter()

Datum tsvector_filter ( PG_FUNCTION_ARGS  )

Definition at line 820 of file tsvector_op.c.

821 {
822  TSVector tsin = PG_GETARG_TSVECTOR(0),
823  tsout;
825  WordEntry *arrin = ARRPTR(tsin),
826  *arrout;
827  char *datain = STRPTR(tsin),
828  *dataout;
829  Datum *dweights;
830  bool *nulls;
831  int nweights;
832  int i,
833  j;
834  int cur_pos = 0;
835  char mask = 0;
836 
837  deconstruct_array_builtin(weights, CHAROID, &dweights, &nulls, &nweights);
838 
839  for (i = 0; i < nweights; i++)
840  {
841  char char_weight;
842 
843  if (nulls[i])
844  ereport(ERROR,
845  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
846  errmsg("weight array may not contain nulls")));
847 
848  char_weight = DatumGetChar(dweights[i]);
849  switch (char_weight)
850  {
851  case 'A':
852  case 'a':
853  mask = mask | 8;
854  break;
855  case 'B':
856  case 'b':
857  mask = mask | 4;
858  break;
859  case 'C':
860  case 'c':
861  mask = mask | 2;
862  break;
863  case 'D':
864  case 'd':
865  mask = mask | 1;
866  break;
867  default:
868  ereport(ERROR,
869  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
870  errmsg("unrecognized weight: \"%c\"", char_weight)));
871  }
872  }
873 
874  tsout = (TSVector) palloc0(VARSIZE(tsin));
875  tsout->size = tsin->size;
876  arrout = ARRPTR(tsout);
877  dataout = STRPTR(tsout);
878 
879  for (i = j = 0; i < tsin->size; i++)
880  {
881  WordEntryPosVector *posvin,
882  *posvout;
883  int npos = 0;
884  int k;
885 
886  if (!arrin[i].haspos)
887  continue;
888 
889  posvin = _POSVECPTR(tsin, arrin + i);
890  posvout = (WordEntryPosVector *)
891  (dataout + SHORTALIGN(cur_pos + arrin[i].len));
892 
893  for (k = 0; k < posvin->npos; k++)
894  {
895  if (mask & (1 << WEP_GETWEIGHT(posvin->pos[k])))
896  posvout->pos[npos++] = posvin->pos[k];
897  }
898 
899  /* if no satisfactory positions found, skip lexeme */
900  if (!npos)
901  continue;
902 
903  arrout[j].haspos = true;
904  arrout[j].len = arrin[i].len;
905  arrout[j].pos = cur_pos;
906 
907  memcpy(dataout + cur_pos, datain + arrin[i].pos, arrin[i].len);
908  posvout->npos = npos;
909  cur_pos += SHORTALIGN(arrin[i].len);
910  cur_pos += POSDATALEN(tsout, arrout + j) * sizeof(WordEntryPos) +
911  sizeof(uint16);
912  j++;
913  }
914 
915  tsout->size = j;
916  if (dataout != STRPTR(tsout))
917  memmove(STRPTR(tsout), dataout, cur_pos);
918 
919  SET_VARSIZE(tsout, CALCDATASIZE(tsout->size, cur_pos));
920 
921  PG_FREE_IF_COPY(tsin, 0);
922  PG_RETURN_POINTER(tsout);
923 }
static char DatumGetChar(Datum X)
Definition: postgres.h:112
static const float weights[]
Definition: tsrank.c:24

References _POSVECPTR, ARRPTR, CALCDATASIZE, DatumGetChar(), deconstruct_array_builtin(), ereport, errcode(), errmsg(), ERROR, i, j, WordEntry::len, len, 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.

◆ tsvector_length()

Datum tsvector_length ( PG_FUNCTION_ARGS  )

Definition at line 202 of file tsvector_op.c.

203 {
205  int32 ret = in->size;
206 
207  PG_FREE_IF_COPY(in, 0);
208  PG_RETURN_INT32(ret);
209 }
signed int int32
Definition: c.h:483
#define PG_RETURN_INT32(x)
Definition: fmgr.h:354

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

◆ tsvector_setweight()

Datum tsvector_setweight ( PG_FUNCTION_ARGS  )

Definition at line 212 of file tsvector_op.c.

213 {
215  char cw = PG_GETARG_CHAR(1);
216  TSVector out;
217  int i,
218  j;
219  WordEntry *entry;
220  WordEntryPos *p;
221  int w = 0;
222 
223  switch (cw)
224  {
225  case 'A':
226  case 'a':
227  w = 3;
228  break;
229  case 'B':
230  case 'b':
231  w = 2;
232  break;
233  case 'C':
234  case 'c':
235  w = 1;
236  break;
237  case 'D':
238  case 'd':
239  w = 0;
240  break;
241  default:
242  /* internal error */
243  elog(ERROR, "unrecognized weight: %d", cw);
244  }
245 
246  out = (TSVector) palloc(VARSIZE(in));
247  memcpy(out, in, VARSIZE(in));
248  entry = ARRPTR(out);
249  i = out->size;
250  while (i--)
251  {
252  if ((j = POSDATALEN(out, entry)) != 0)
253  {
254  p = POSDATAPTR(out, entry);
255  while (j--)
256  {
257  WEP_SETWEIGHT(*p, w);
258  p++;
259  }
260  }
261  entry++;
262  }
263 
264  PG_FREE_IF_COPY(in, 0);
265  PG_RETURN_POINTER(out);
266 }
#define PG_GETARG_CHAR(n)
Definition: fmgr.h:273

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

◆ tsvector_setweight_by_filter()

Datum tsvector_setweight_by_filter ( PG_FUNCTION_ARGS  )

Definition at line 274 of file tsvector_op.c.

275 {
276  TSVector tsin = PG_GETARG_TSVECTOR(0);
277  char char_weight = PG_GETARG_CHAR(1);
278  ArrayType *lexemes = PG_GETARG_ARRAYTYPE_P(2);
279 
280  TSVector tsout;
281  int i,
282  j,
283  nlexemes,
284  weight;
285  WordEntry *entry;
286  Datum *dlexemes;
287  bool *nulls;
288 
289  switch (char_weight)
290  {
291  case 'A':
292  case 'a':
293  weight = 3;
294  break;
295  case 'B':
296  case 'b':
297  weight = 2;
298  break;
299  case 'C':
300  case 'c':
301  weight = 1;
302  break;
303  case 'D':
304  case 'd':
305  weight = 0;
306  break;
307  default:
308  /* internal error */
309  elog(ERROR, "unrecognized weight: %c", char_weight);
310  }
311 
312  tsout = (TSVector) palloc(VARSIZE(tsin));
313  memcpy(tsout, tsin, VARSIZE(tsin));
314  entry = ARRPTR(tsout);
315 
316  deconstruct_array_builtin(lexemes, TEXTOID, &dlexemes, &nulls, &nlexemes);
317 
318  /*
319  * Assuming that lexemes array is significantly shorter than tsvector we
320  * can iterate through lexemes performing binary search of each lexeme
321  * from lexemes in tsvector.
322  */
323  for (i = 0; i < nlexemes; i++)
324  {
325  char *lex;
326  int lex_len,
327  lex_pos;
328 
329  /* Ignore null array elements, they surely don't match */
330  if (nulls[i])
331  continue;
332 
333  lex = VARDATA(dlexemes[i]);
334  lex_len = VARSIZE(dlexemes[i]) - VARHDRSZ;
335  lex_pos = tsvector_bsearch(tsout, lex, lex_len);
336 
337  if (lex_pos >= 0 && (j = POSDATALEN(tsout, entry + lex_pos)) != 0)
338  {
339  WordEntryPos *p = POSDATAPTR(tsout, entry + lex_pos);
340 
341  while (j--)
342  {
343  WEP_SETWEIGHT(*p, weight);
344  p++;
345  }
346  }
347  }
348 
349  PG_FREE_IF_COPY(tsin, 0);
350  PG_FREE_IF_COPY(lexemes, 2);
351 
352  PG_RETURN_POINTER(tsout);
353 }

References ARRPTR, deconstruct_array_builtin(), elog(), ERROR, i, j, 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.

◆ tsvector_strip()

Datum tsvector_strip ( PG_FUNCTION_ARGS  )

Definition at line 169 of file tsvector_op.c.

170 {
172  TSVector out;
173  int i,
174  len = 0;
175  WordEntry *arrin = ARRPTR(in),
176  *arrout;
177  char *cur;
178 
179  for (i = 0; i < in->size; i++)
180  len += arrin[i].len;
181 
182  len = CALCDATASIZE(in->size, len);
183  out = (TSVector) palloc0(len);
184  SET_VARSIZE(out, len);
185  out->size = in->size;
186  arrout = ARRPTR(out);
187  cur = STRPTR(out);
188  for (i = 0; i < in->size; i++)
189  {
190  memcpy(cur, STRPTR(in) + arrin[i].pos, arrin[i].len);
191  arrout[i].haspos = 0;
192  arrout[i].len = arrin[i].len;
193  arrout[i].pos = cur - STRPTR(out);
194  cur += arrout[i].len;
195  }
196 
197  PG_FREE_IF_COPY(in, 0);
198  PG_RETURN_POINTER(out);
199 }

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

◆ tsvector_to_array()

Datum tsvector_to_array ( PG_FUNCTION_ARGS  )

Definition at line 721 of file tsvector_op.c.

722 {
723  TSVector tsin = PG_GETARG_TSVECTOR(0);
724  WordEntry *arrin = ARRPTR(tsin);
725  Datum *elements;
726  int i;
727  ArrayType *array;
728 
729  elements = palloc(tsin->size * sizeof(Datum));
730 
731  for (i = 0; i < tsin->size; i++)
732  {
733  elements[i] = PointerGetDatum(cstring_to_text_with_len(STRPTR(tsin) + arrin[i].pos,
734  arrin[i].len));
735  }
736 
737  array = construct_array_builtin(elements, tsin->size, TEXTOID);
738 
739  pfree(elements);
740  PG_FREE_IF_COPY(tsin, 0);
741  PG_RETURN_POINTER(array);
742 }
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
Definition: arrayfuncs.c:3375
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:322
text * cstring_to_text_with_len(const char *s, int len)
Definition: varlena.c:196

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

◆ tsvector_unnest()

Datum tsvector_unnest ( PG_FUNCTION_ARGS  )

Definition at line 633 of file tsvector_op.c.

634 {
635  FuncCallContext *funcctx;
636  TSVector tsin;
637 
638  if (SRF_IS_FIRSTCALL())
639  {
640  MemoryContext oldcontext;
641  TupleDesc tupdesc;
642 
643  funcctx = SRF_FIRSTCALL_INIT();
644  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
645 
646  tupdesc = CreateTemplateTupleDesc(3);
647  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "lexeme",
648  TEXTOID, -1, 0);
649  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "positions",
650  INT2ARRAYOID, -1, 0);
651  TupleDescInitEntry(tupdesc, (AttrNumber) 3, "weights",
652  TEXTARRAYOID, -1, 0);
653  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
654  elog(ERROR, "return type must be a row type");
655  funcctx->tuple_desc = 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(cstring_to_text_with_len(data + arrin[i].pos, arrin[i].len));
676 
677  if (arrin[i].haspos)
678  {
679  WordEntryPosVector *posv;
680  Datum *positions;
681  Datum *weights;
682  char weight;
683 
684  /*
685  * Internally tsvector stores position and weight in the same
686  * uint16 (2 bits for weight, 14 for position). Here we extract
687  * that in two separate arrays.
688  */
689  posv = _POSVECPTR(tsin, arrin + i);
690  positions = palloc(posv->npos * sizeof(Datum));
691  weights = palloc(posv->npos * sizeof(Datum));
692  for (j = 0; j < posv->npos; j++)
693  {
694  positions[j] = Int16GetDatum(WEP_GETPOS(posv->pos[j]));
695  weight = 'D' - WEP_GETWEIGHT(posv->pos[j]);
697  1));
698  }
699 
700  values[1] = PointerGetDatum(construct_array_builtin(positions, posv->npos, INT2OID));
702  }
703  else
704  {
705  nulls[1] = nulls[2] = true;
706  }
707 
708  tuple = heap_form_tuple(funcctx->tuple_desc, values, nulls);
709  SRF_RETURN_NEXT(funcctx, HeapTupleGetDatum(tuple));
710  }
711  else
712  {
713  SRF_RETURN_DONE(funcctx);
714  }
715 }
int16 AttrNumber
Definition: attnum.h:21
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:77
static Datum Int16GetDatum(int16 X)
Definition: postgres.h:172
uint64 call_cntr
Definition: funcapi.h:65
#define PG_GETARG_TSVECTOR_COPY(n)
Definition: ts_type.h:136
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:67
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:603

References _POSVECPTR, ARRPTR, FuncCallContext::call_cntr, construct_array_builtin(), CreateTemplateTupleDesc(), cstring_to_text_with_len(), data, elog(), ERROR, get_call_result_type(), heap_form_tuple(), HeapTupleGetDatum(), i, if(), Int16GetDatum(), j, len, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, WordEntryPosVector::npos, palloc(), 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(), TYPEFUNC_COMPOSITE, FuncCallContext::user_fctx, values, weights, WEP_GETPOS, and WEP_GETWEIGHT.

◆ tsvector_update_trigger()

static Datum tsvector_update_trigger ( PG_FUNCTION_ARGS  ,
bool  config_column 
)
static

Definition at line 2740 of file tsvector_op.c.

2741 {
2742  TriggerData *trigdata;
2743  Trigger *trigger;
2744  Relation rel;
2745  HeapTuple rettuple = NULL;
2746  int tsvector_attr_num,
2747  i;
2748  ParsedText prs;
2749  Datum datum;
2750  bool isnull;
2751  text *txt;
2752  Oid cfgId;
2753  bool update_needed;
2754 
2755  /* Check call context */
2756  if (!CALLED_AS_TRIGGER(fcinfo)) /* internal error */
2757  elog(ERROR, "tsvector_update_trigger: not fired by trigger manager");
2758 
2759  trigdata = (TriggerData *) fcinfo->context;
2760  if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
2761  elog(ERROR, "tsvector_update_trigger: must be fired for row");
2762  if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
2763  elog(ERROR, "tsvector_update_trigger: must be fired BEFORE event");
2764 
2765  if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
2766  {
2767  rettuple = trigdata->tg_trigtuple;
2768  update_needed = true;
2769  }
2770  else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
2771  {
2772  rettuple = trigdata->tg_newtuple;
2773  update_needed = false; /* computed below */
2774  }
2775  else
2776  elog(ERROR, "tsvector_update_trigger: must be fired for INSERT or UPDATE");
2777 
2778  trigger = trigdata->tg_trigger;
2779  rel = trigdata->tg_relation;
2780 
2781  if (trigger->tgnargs < 3)
2782  elog(ERROR, "tsvector_update_trigger: arguments must be tsvector_field, ts_config, text_field1, ...)");
2783 
2784  /* Find the target tsvector column */
2785  tsvector_attr_num = SPI_fnumber(rel->rd_att, trigger->tgargs[0]);
2786  if (tsvector_attr_num == SPI_ERROR_NOATTRIBUTE)
2787  ereport(ERROR,
2788  (errcode(ERRCODE_UNDEFINED_COLUMN),
2789  errmsg("tsvector column \"%s\" does not exist",
2790  trigger->tgargs[0])));
2791  /* This will effectively reject system columns, so no separate test: */
2792  if (!IsBinaryCoercible(SPI_gettypeid(rel->rd_att, tsvector_attr_num),
2793  TSVECTOROID))
2794  ereport(ERROR,
2795  (errcode(ERRCODE_DATATYPE_MISMATCH),
2796  errmsg("column \"%s\" is not of tsvector type",
2797  trigger->tgargs[0])));
2798 
2799  /* Find the configuration to use */
2800  if (config_column)
2801  {
2802  int config_attr_num;
2803 
2804  config_attr_num = SPI_fnumber(rel->rd_att, trigger->tgargs[1]);
2805  if (config_attr_num == SPI_ERROR_NOATTRIBUTE)
2806  ereport(ERROR,
2807  (errcode(ERRCODE_UNDEFINED_COLUMN),
2808  errmsg("configuration column \"%s\" does not exist",
2809  trigger->tgargs[1])));
2810  if (!IsBinaryCoercible(SPI_gettypeid(rel->rd_att, config_attr_num),
2811  REGCONFIGOID))
2812  ereport(ERROR,
2813  (errcode(ERRCODE_DATATYPE_MISMATCH),
2814  errmsg("column \"%s\" is not of regconfig type",
2815  trigger->tgargs[1])));
2816 
2817  datum = SPI_getbinval(rettuple, rel->rd_att, config_attr_num, &isnull);
2818  if (isnull)
2819  ereport(ERROR,
2820  (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2821  errmsg("configuration column \"%s\" must not be null",
2822  trigger->tgargs[1])));
2823  cfgId = DatumGetObjectId(datum);
2824  }
2825  else
2826  {
2827  List *names;
2828 
2829  names = stringToQualifiedNameList(trigger->tgargs[1], NULL);
2830  /* require a schema so that results are not search path dependent */
2831  if (list_length(names) < 2)
2832  ereport(ERROR,
2833  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2834  errmsg("text search configuration name \"%s\" must be schema-qualified",
2835  trigger->tgargs[1])));
2836  cfgId = get_ts_config_oid(names, false);
2837  }
2838 
2839  /* initialize parse state */
2840  prs.lenwords = 32;
2841  prs.curwords = 0;
2842  prs.pos = 0;
2843  prs.words = (ParsedWord *) palloc(sizeof(ParsedWord) * prs.lenwords);
2844 
2845  /* find all words in indexable column(s) */
2846  for (i = 2; i < trigger->tgnargs; i++)
2847  {
2848  int numattr;
2849 
2850  numattr = SPI_fnumber(rel->rd_att, trigger->tgargs[i]);
2852  ereport(ERROR,
2853  (errcode(ERRCODE_UNDEFINED_COLUMN),
2854  errmsg("column \"%s\" does not exist",
2855  trigger->tgargs[i])));
2856  if (!IsBinaryCoercible(SPI_gettypeid(rel->rd_att, numattr), TEXTOID))
2857  ereport(ERROR,
2858  (errcode(ERRCODE_DATATYPE_MISMATCH),
2859  errmsg("column \"%s\" is not of a character type",
2860  trigger->tgargs[i])));
2861 
2863  update_needed = true;
2864 
2865  datum = SPI_getbinval(rettuple, rel->rd_att, numattr, &isnull);
2866  if (isnull)
2867  continue;
2868 
2869  txt = DatumGetTextPP(datum);
2870 
2871  parsetext(cfgId, &prs, VARDATA_ANY(txt), VARSIZE_ANY_EXHDR(txt));
2872 
2873  if (txt != (text *) DatumGetPointer(datum))
2874  pfree(txt);
2875  }
2876 
2877  if (update_needed)
2878  {
2879  /* make tsvector value */
2880  datum = TSVectorGetDatum(make_tsvector(&prs));
2881  isnull = false;
2882 
2883  /* and insert it into tuple */
2884  rettuple = heap_modify_tuple_by_cols(rettuple, rel->rd_att,
2885  1, &tsvector_attr_num,
2886  &datum, &isnull);
2887 
2888  pfree(DatumGetPointer(datum));
2889  }
2890 
2891  return PointerGetDatum(rettuple);
2892 }
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:523
int numattr
Definition: bootstrap.c:66
#define DatumGetTextPP(X)
Definition: fmgr.h:292
HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple, TupleDesc tupleDesc, int nCols, const int *replCols, const Datum *replValues, const bool *replIsnull)
Definition: heaptuple.c:1278
Oid get_ts_config_oid(List *names, bool missing_ok)
Definition: namespace.c:3137
static int list_length(const List *l)
Definition: pg_list.h:152
static Oid DatumGetObjectId(Datum X)
Definition: postgres.h:242
unsigned int Oid
Definition: postgres_ext.h:31
List * stringToQualifiedNameList(const char *string, Node *escontext)
Definition: regproc.c:1777
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
Definition: spi.c:1173
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:76
int32 pos
Definition: ts_utils.h:107
int32 lenwords
Definition: ts_utils.h:105
int32 curwords
Definition: ts_utils.h:106
ParsedWord * words
Definition: ts_utils.h:104
TupleDesc rd_att
Definition: rel.h:112
Relation tg_relation
Definition: trigger.h:35
const Bitmapset * tg_updatedcols
Definition: trigger.h:43
TriggerEvent tg_event
Definition: trigger.h:34
HeapTuple tg_newtuple
Definition: trigger.h:37
Trigger * tg_trigger
Definition: trigger.h:38
HeapTuple tg_trigtuple
Definition: trigger.h:36
int16 tgnargs
Definition: reltrigger.h:38
char ** tgargs
Definition: reltrigger.h:41
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
TSVector make_tsvector(ParsedText *prs)
Definition: to_tsany.c:166
#define TRIGGER_FIRED_BEFORE(event)
Definition: trigger.h:128
#define CALLED_AS_TRIGGER(fcinfo)
Definition: trigger.h:26
#define TRIGGER_FIRED_FOR_ROW(event)
Definition: trigger.h:122
#define TRIGGER_FIRED_BY_INSERT(event)
Definition: trigger.h:110
#define TRIGGER_FIRED_BY_UPDATE(event)
Definition: trigger.h:116
void parsetext(Oid cfgId, ParsedText *prs, char *buf, int buflen)
Definition: ts_parse.c:355

References bms_is_member(), CALLED_AS_TRIGGER, ParsedText::curwords, DatumGetObjectId(), DatumGetPointer(), DatumGetTextPP, elog(), ereport, errcode(), errmsg(), ERROR, FirstLowInvalidHeapAttributeNumber, get_ts_config_oid(), heap_modify_tuple_by_cols(), i, if(), 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, TriggerData::tg_updatedcols, 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().

◆ tsvector_update_trigger_bycolumn()

Datum tsvector_update_trigger_bycolumn ( PG_FUNCTION_ARGS  )

Definition at line 2734 of file tsvector_op.c.

2735 {
2736  return tsvector_update_trigger(fcinfo, true);
2737 }
static Datum tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column)
Definition: tsvector_op.c:2740

References tsvector_update_trigger().

◆ tsvector_update_trigger_byid()

Datum tsvector_update_trigger_byid ( PG_FUNCTION_ARGS  )

Definition at line 2728 of file tsvector_op.c.

2729 {
2730  return tsvector_update_trigger(fcinfo, false);
2731 }

References tsvector_update_trigger().

◆ TSVECTORCMPFUNC() [1/7]

TSVECTORCMPFUNC ( cmp  ,
,
INT32   
)

◆ TSVECTORCMPFUNC() [2/7]

TSVECTORCMPFUNC ( eq  ,
BOOL   
)

◆ TSVECTORCMPFUNC() [3/7]

TSVECTORCMPFUNC ( ge  ,
>=  ,
BOOL   
)

◆ TSVECTORCMPFUNC() [4/7]

TSVECTORCMPFUNC ( gt  ,
BOOL   
)

◆ TSVECTORCMPFUNC() [5/7]

TSVECTORCMPFUNC ( le  ,
<=  ,
BOOL   
)

◆ TSVECTORCMPFUNC() [6/7]

TSVECTORCMPFUNC ( lt  )

◆ TSVECTORCMPFUNC() [7/7]

TSVECTORCMPFUNC ( ne  ,
,
BOOL   
)

◆ walkStatEntryTree()

static StatEntry* walkStatEntryTree ( TSVectorStat stat)
static

Definition at line 2490 of file tsvector_op.c.

2491 {
2492  StatEntry *node = stat->stack[stat->stackpos];
2493 
2494  if (node == NULL)
2495  return NULL;
2496 
2497  if (node->ndoc != 0)
2498  {
2499  /* return entry itself: we already was at left sublink */
2500  return node;
2501  }
2502  else if (node->right && node->right != stat->stack[stat->stackpos + 1])
2503  {
2504  /* go on right sublink */
2505  stat->stackpos++;
2506  node = node->right;
2507 
2508  /* find most-left value */
2509  for (;;)
2510  {
2511  stat->stack[stat->stackpos] = node;
2512  if (node->left)
2513  {
2514  stat->stackpos++;
2515  node = node->left;
2516  }
2517  else
2518  break;
2519  }
2520  Assert(stat->stackpos <= stat->maxdepth);
2521  }
2522  else
2523  {
2524  /* we already return all left subtree, itself and right subtree */
2525  if (stat->stackpos == 0)
2526  return NULL;
2527 
2528  stat->stackpos--;
2529  return walkStatEntryTree(stat);
2530  }
2531 
2532  return node;
2533 }

References Assert(), StatEntry::left, StatEntry::ndoc, and StatEntry::right.

Referenced by ts_process_call().