#include "postgres.h"#include "catalog/namespace.h"#include "catalog/pg_type.h"#include "commands/trigger.h"#include "executor/spi.h"#include "funcapi.h"#include "mb/pg_wchar.h"#include "miscadmin.h"#include "tsearch/ts_utils.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/rel.h"
Go to the source code of this file.
Data Structures | |
| struct | CHKVAL |
| struct | StatEntry |
| struct | TSVectorStat |
Defines | |
| #define | STATENTRYHDRSZ (offsetof(StatEntry, lexeme)) |
| #define | STATHDRSIZE (offsetof(TSVectorStat, data)) |
| #define | TSVECTORCMPFUNC(type, action, ret) |
| #define | compareEntry(pa, a, pb, b) |
| #define | compareStatWord(a, e, t) |
Typedefs | |
| typedef struct StatEntry | StatEntry |
Functions | |
| static Datum | tsvector_update_trigger (PG_FUNCTION_ARGS, bool config_column) |
| static bool | is_expected_type (Oid typid, Oid expected_type) |
| static bool | is_text_type (Oid typid) |
| 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) |
| static int32 | add_pos (TSVector src, WordEntry *srcptr, TSVector dest, WordEntry *destptr, int32 maxpos) |
| Datum | tsvector_concat (PG_FUNCTION_ARGS) |
| int32 | tsCompareString (char *a, int lena, char *b, int lenb, bool prefix) |
| static bool | checkclass_str (CHKVAL *chkval, WordEntry *val, QueryOperand *item) |
| static bool | checkcondition_str (void *checkval, QueryOperand *val) |
| bool | TS_execute (QueryItem *curitem, void *checkval, bool calcnot, bool(*chkcond)(void *checkval, QueryOperand *val)) |
| 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 TSVectorStat * | ts_accum (MemoryContext persistentContext, TSVectorStat *stat, Datum data) |
| static void | ts_setup_firstcall (FunctionCallInfo fcinfo, FuncCallContext *funcctx, TSVectorStat *stat) |
| static StatEntry * | walkStatEntryTree (TSVectorStat *stat) |
| static Datum | ts_process_call (FuncCallContext *funcctx) |
| static TSVectorStat * | ts_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) |
| #define compareEntry | ( | pa, | ||
| a, | ||||
| pb, | ||||
| b | ||||
| ) |
tsCompareString((pa) + (a)->pos, (a)->len, \ (pb) + (b)->pos, (b)->len, \ false)
Definition at line 287 of file tsvector_op.c.
Referenced by tsvector_concat().
| #define compareStatWord | ( | a, | ||
| e, | ||||
| t | ||||
| ) |
tsCompareString((a)->lexeme, (a)->lenlexeme, \ STRPTR(t) + (e)->pos, (e)->len, \ false)
Definition at line 877 of file tsvector_op.c.
Referenced by insertStatEntry().
| #define STATENTRYHDRSZ (offsetof(StatEntry, lexeme)) |
Definition at line 50 of file tsvector_op.c.
Referenced by insertStatEntry().
| #define STATHDRSIZE (offsetof(TSVectorStat, data)) |
Definition at line 64 of file tsvector_op.c.
| #define TSVECTORCMPFUNC | ( | type, | ||
| action, | ||||
| ret | ||||
| ) |
Datum \ tsvector_##type(PG_FUNCTION_ARGS) \ { \ TSVector a = PG_GETARG_TSVECTOR(0); \ TSVector b = PG_GETARG_TSVECTOR(1); \ int res = silly_cmp_tsvector(a, b); \ PG_FREE_IF_COPY(a,0); \ PG_FREE_IF_COPY(b,1); \ PG_RETURN_##ret( res action 0 ); \ } \ /* keep compiler quiet - no extra ; */ \ extern int no_such_variable
Definition at line 165 of file tsvector_op.c.
| static int32 add_pos | ( | TSVector | src, | |
| WordEntry * | srcptr, | |||
| TSVector | dest, | |||
| WordEntry * | destptr, | |||
| int32 | maxpos | |||
| ) | [static] |
Definition at line 297 of file tsvector_op.c.
References _POSVECPTR, WordEntry::haspos, i, LIMITPOS, MAXENTRYPOS, MAXNUMPOS, POSDATALEN, POSDATAPTR, WEP_GETPOS, WEP_GETWEIGHT, WEP_SETPOS, and WEP_SETWEIGHT.
Referenced by tsvector_concat().
{
uint16 *clen = &_POSVECPTR(dest, destptr)->npos;
int i;
uint16 slen = POSDATALEN(src, srcptr),
startlen;
WordEntryPos *spos = POSDATAPTR(src, srcptr),
*dpos = POSDATAPTR(dest, destptr);
if (!destptr->haspos)
*clen = 0;
startlen = *clen;
for (i = 0;
i < slen && *clen < MAXNUMPOS &&
(*clen == 0 || WEP_GETPOS(dpos[*clen - 1]) != MAXENTRYPOS - 1);
i++)
{
WEP_SETWEIGHT(dpos[*clen], WEP_GETWEIGHT(spos[i]));
WEP_SETPOS(dpos[*clen], LIMITPOS(WEP_GETPOS(spos[i]) + maxpos));
(*clen)++;
}
if (*clen != startlen)
destptr->haspos = 1;
return *clen - startlen;
}
Definition at line 862 of file tsvector_op.c.
References POSDATALEN, POSDATAPTR, and WEP_GETWEIGHT.
Referenced by insertStatEntry().
{
int len = POSDATALEN(txt, wptr);
int num = 0;
WordEntryPos *ptr = POSDATAPTR(txt, wptr);
while (len--)
{
if (weight & (1 << WEP_GETWEIGHT(*ptr)))
num++;
ptr++;
}
return num;
}
| static bool checkclass_str | ( | CHKVAL * | chkval, | |
| WordEntry * | val, | |||
| QueryOperand * | item | |||
| ) | [static] |
Definition at line 593 of file tsvector_op.c.
References WordEntry::len, WordEntryPosVector::npos, WordEntryPosVector::pos, WordEntry::pos, SHORTALIGN, CHKVAL::values, QueryOperand::weight, and WEP_GETWEIGHT.
Referenced by checkcondition_str().
{
WordEntryPosVector *posvec;
WordEntryPos *ptr;
uint16 len;
posvec = (WordEntryPosVector *)
(chkval->values + SHORTALIGN(val->pos + val->len));
len = posvec->npos;
ptr = posvec->pos;
while (len--)
{
if (item->weight & (1 << WEP_GETWEIGHT(*ptr)))
return true;
ptr++;
}
return false;
}
| static bool checkcondition_str | ( | void * | checkval, | |
| QueryOperand * | val | |||
| ) | [static] |
Definition at line 618 of file tsvector_op.c.
References CHKVAL::arrb, CHKVAL::arre, checkclass_str(), difference(), QueryOperand::distance, WordEntry::haspos, WordEntry::len, QueryOperand::length, CHKVAL::operand, WordEntry::pos, QueryOperand::prefix, tsCompareString(), CHKVAL::values, and QueryOperand::weight.
Referenced by ts_match_vq().
{
CHKVAL *chkval = (CHKVAL *) checkval;
WordEntry *StopLow = chkval->arrb;
WordEntry *StopHigh = chkval->arre;
WordEntry *StopMiddle = StopHigh;
int difference = -1;
bool res = false;
/* Loop invariant: StopLow <= val < StopHigh */
while (StopLow < StopHigh)
{
StopMiddle = StopLow + (StopHigh - StopLow) / 2;
difference = tsCompareString(chkval->operand + val->distance, val->length,
chkval->values + StopMiddle->pos, StopMiddle->len,
false);
if (difference == 0)
{
res = (val->weight && StopMiddle->haspos) ?
checkclass_str(chkval, StopMiddle, val) : true;
break;
}
else if (difference > 0)
StopLow = StopMiddle + 1;
else
StopHigh = StopMiddle;
}
if (!res && val->prefix)
{
/*
* there was a failed exact search, so we should scan further to find
* a prefix match.
*/
if (StopLow >= StopHigh)
StopMiddle = StopHigh;
while (res == false && StopMiddle < chkval->arre &&
tsCompareString(chkval->operand + val->distance, val->length,
chkval->values + StopMiddle->pos, StopMiddle->len,
true) == 0)
{
res = (val->weight && StopMiddle->haspos) ?
checkclass_str(chkval, StopMiddle, val) : true;
StopMiddle++;
}
}
return res;
}
| static void chooseNextStatEntry | ( | MemoryContext | persistentContext, | |
| TSVectorStat * | stat, | |||
| TSVector | txt, | |||
| uint32 | low, | |||
| uint32 | high, | |||
| uint32 | offset | |||
| ) | [static] |
Definition at line 949 of file tsvector_op.c.
References insertStatEntry().
Referenced by ts_accum().
{
uint32 pos;
uint32 middle = (low + high) >> 1;
pos = (low + middle) >> 1;
if (low != middle && pos >= offset && pos - offset < txt->size)
insertStatEntry(persistentContext, stat, txt, pos - offset);
pos = (high + middle + 1) >> 1;
if (middle + 1 != high && pos >= offset && pos - offset < txt->size)
insertStatEntry(persistentContext, stat, txt, pos - offset);
if (low != middle)
chooseNextStatEntry(persistentContext, stat, txt, low, middle, offset);
if (high != middle + 1)
chooseNextStatEntry(persistentContext, stat, txt, middle + 1, high, offset);
}
| static void insertStatEntry | ( | MemoryContext | persistentContext, | |
| TSVectorStat * | stat, | |||
| TSVector | txt, | |||
| uint32 | off | |||
| ) | [static] |
Definition at line 883 of file tsvector_op.c.
References ARRPTR, check_weight(), compareStatWord, WordEntry::haspos, StatEntry::left, WordEntry::len, StatEntry::lenlexeme, StatEntry::lexeme, TSVectorStat::maxdepth, MemoryContextAlloc(), StatEntry::ndoc, StatEntry::nentry, NULL, WordEntry::pos, POSDATALEN, StatEntry::right, TSVectorStat::root, STATENTRYHDRSZ, STRPTR, and TSVectorStat::weight.
Referenced by chooseNextStatEntry(), and ts_accum().
{
WordEntry *we = ARRPTR(txt) + off;
StatEntry *node = stat->root,
*pnode = NULL;
int n,
res = 0;
uint32 depth = 1;
if (stat->weight == 0)
n = (we->haspos) ? POSDATALEN(txt, we) : 1;
else
n = (we->haspos) ? check_weight(txt, we, stat->weight) : 0;
if (n == 0)
return; /* nothing to insert */
while (node)
{
res = compareStatWord(node, we, txt);
if (res == 0)
{
break;
}
else
{
pnode = node;
node = (res < 0) ? node->left : node->right;
}
depth++;
}
if (depth > stat->maxdepth)
stat->maxdepth = depth;
if (node == NULL)
{
node = MemoryContextAlloc(persistentContext, STATENTRYHDRSZ + we->len);
node->left = node->right = NULL;
node->ndoc = 1;
node->nentry = n;
node->lenlexeme = we->len;
memcpy(node->lexeme, STRPTR(txt) + we->pos, node->lenlexeme);
if (pnode == NULL)
{
stat->root = node;
}
else
{
if (res < 0)
pnode->left = node;
else
pnode->right = node;
}
}
else
{
node->ndoc++;
node->nentry += n;
}
}
Definition at line 77 of file tsvector_op.c.
References getBaseType().
Referenced by ts_stat_sql(), and tsvector_update_trigger().
{
if (typid == expected_type)
return true;
typid = getBaseType(typid);
if (typid == expected_type)
return true;
return false;
}
Definition at line 89 of file tsvector_op.c.
References BPCHAROID, getBaseType(), TEXTOID, and VARCHAROID.
Referenced by tsvector_update_trigger().
{
/* varchar(n) and char(n) are binary-compatible with text */
if (typid == TEXTOID || typid == VARCHAROID || typid == BPCHAROID)
return true;
/* Allow domains over these types, too */
typid = getBaseType(typid);
if (typid == TEXTOID || typid == VARCHAROID || typid == BPCHAROID)
return true;
return false;
}
Definition at line 106 of file tsvector_op.c.
References ARRPTR, WordEntry::haspos, i, WordEntry::len, WordEntry::pos, POSDATALEN, POSDATAPTR, TSVectorData::size, STRPTR, tsCompareString(), VARSIZE, WEP_GETPOS, and WEP_GETWEIGHT.
{
if (VARSIZE(a) < VARSIZE(b))
return -1;
else if (VARSIZE(a) > VARSIZE(b))
return 1;
else if (a->size < b->size)
return -1;
else if (a->size > b->size)
return 1;
else
{
WordEntry *aptr = ARRPTR(a);
WordEntry *bptr = ARRPTR(b);
int i = 0;
int res;
for (i = 0; i < a->size; i++)
{
if (aptr->haspos != bptr->haspos)
{
return (aptr->haspos > bptr->haspos) ? -1 : 1;
}
else if ((res = tsCompareString(STRPTR(a) + aptr->pos, aptr->len, STRPTR(b) + bptr->pos, bptr->len, false)) != 0)
{
return res;
}
else if (aptr->haspos)
{
WordEntryPos *ap = POSDATAPTR(a, aptr);
WordEntryPos *bp = POSDATAPTR(b, bptr);
int j;
if (POSDATALEN(a, aptr) != POSDATALEN(b, bptr))
return (POSDATALEN(a, aptr) > POSDATALEN(b, bptr)) ? -1 : 1;
for (j = 0; j < POSDATALEN(a, aptr); j++)
{
if (WEP_GETPOS(*ap) != WEP_GETPOS(*bp))
{
return (WEP_GETPOS(*ap) > WEP_GETPOS(*bp)) ? -1 : 1;
}
else if (WEP_GETWEIGHT(*ap) != WEP_GETWEIGHT(*bp))
{
return (WEP_GETWEIGHT(*ap) > WEP_GETWEIGHT(*bp)) ? -1 : 1;
}
ap++, bp++;
}
}
aptr++;
bptr++;
}
}
return 0;
}
| static TSVectorStat* ts_accum | ( | MemoryContext | persistentContext, | |
| TSVectorStat * | stat, | |||
| Datum | data | |||
| ) | [static] |
Definition at line 981 of file tsvector_op.c.
References chooseNextStatEntry(), DatumGetPointer, DatumGetTSVector, i, insertStatEntry(), TSVectorStat::maxdepth, MemoryContextAllocZero(), NULL, pfree(), and TSVectorData::size.
Referenced by ts_stat_sql().
{
TSVector txt = DatumGetTSVector(data);
uint32 i,
nbit = 0,
offset;
if (stat == NULL)
{ /* Init in first */
stat = MemoryContextAllocZero(persistentContext, sizeof(TSVectorStat));
stat->maxdepth = 1;
}
/* simple check of correctness */
if (txt == NULL || txt->size == 0)
{
if (txt && txt != (TSVector) DatumGetPointer(data))
pfree(txt);
return stat;
}
i = txt->size - 1;
for (; i > 0; i >>= 1)
nbit++;
nbit = 1 << nbit;
offset = (nbit - txt->size) / 2;
insertStatEntry(persistentContext, stat, txt, (nbit >> 1) - offset);
chooseNextStatEntry(persistentContext, stat, txt, 0, nbit, offset);
return stat;
}
| bool TS_execute | ( | QueryItem * | curitem, | |
| void * | checkval, | |||
| bool | calcnot, | |||
| bool(*)(void *checkval, QueryOperand *val) | chkcond | |||
| ) |
Definition at line 681 of file tsvector_op.c.
References check_stack_depth(), elog, ERROR, OP_AND, OP_NOT, OP_OR, QI_VAL, TS_execute(), and QueryItem::type.
Referenced by Cover(), gin_tsquery_consistent(), gtsvector_consistent(), hlCover(), TS_execute(), and ts_match_vq().
{
/* since this function recurses, it could be driven to stack overflow */
check_stack_depth();
if (curitem->type == QI_VAL)
return chkcond(checkval, (QueryOperand *) curitem);
switch (curitem->qoperator.oper)
{
case OP_NOT:
if (calcnot)
return !TS_execute(curitem + 1, checkval, calcnot, chkcond);
else
return true;
case OP_AND:
if (TS_execute(curitem + curitem->qoperator.left, checkval, calcnot, chkcond))
return TS_execute(curitem + 1, checkval, calcnot, chkcond);
else
return false;
case OP_OR:
if (TS_execute(curitem + curitem->qoperator.left, checkval, calcnot, chkcond))
return true;
else
return TS_execute(curitem + 1, checkval, calcnot, chkcond);
default:
elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
}
/* not reachable, but keep compiler quiet */
return false;
}
| Datum ts_match_qv | ( | PG_FUNCTION_ARGS | ) |
Definition at line 772 of file tsvector_op.c.
References DirectFunctionCall2, PG_GETARG_DATUM, PG_RETURN_DATUM, and ts_match_vq().
{
PG_RETURN_DATUM(DirectFunctionCall2(ts_match_vq,
PG_GETARG_DATUM(1),
PG_GETARG_DATUM(0)));
}
| Datum ts_match_tq | ( | PG_FUNCTION_ARGS | ) |
Definition at line 833 of file tsvector_op.c.
References DatumGetBool, DatumGetTSVector, DirectFunctionCall1, DirectFunctionCall2, pfree(), PG_FREE_IF_COPY, PG_GETARG_DATUM, PG_GETARG_TSQUERY, PG_RETURN_BOOL, to_tsvector(), ts_match_vq(), TSQueryGetDatum, and TSVectorGetDatum.
{
TSVector vector;
TSQuery query = PG_GETARG_TSQUERY(1);
bool res;
vector = DatumGetTSVector(DirectFunctionCall1(to_tsvector,
PG_GETARG_DATUM(0)));
res = DatumGetBool(DirectFunctionCall2(ts_match_vq,
TSVectorGetDatum(vector),
TSQueryGetDatum(query)));
pfree(vector);
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(res);
}
| Datum ts_match_tt | ( | PG_FUNCTION_ARGS | ) |
Definition at line 811 of file tsvector_op.c.
References DatumGetBool, DatumGetTSQuery, DatumGetTSVector, DirectFunctionCall1, DirectFunctionCall2, pfree(), PG_GETARG_DATUM, PG_RETURN_BOOL, plainto_tsquery(), to_tsvector(), ts_match_vq(), TSQueryGetDatum, and TSVectorGetDatum.
{
TSVector vector;
TSQuery query;
bool res;
vector = DatumGetTSVector(DirectFunctionCall1(to_tsvector,
PG_GETARG_DATUM(0)));
query = DatumGetTSQuery(DirectFunctionCall1(plainto_tsquery,
PG_GETARG_DATUM(1)));
res = DatumGetBool(DirectFunctionCall2(ts_match_vq,
TSVectorGetDatum(vector),
TSQueryGetDatum(query)));
pfree(vector);
pfree(query);
PG_RETURN_BOOL(res);
}
| Datum ts_match_vq | ( | PG_FUNCTION_ARGS | ) |
Definition at line 780 of file tsvector_op.c.
References CHKVAL::arrb, CHKVAL::arre, ARRPTR, checkcondition_str(), GETOPERAND, GETQUERY, CHKVAL::operand, PG_FREE_IF_COPY, PG_GETARG_TSQUERY, PG_GETARG_TSVECTOR, PG_RETURN_BOOL, TSQueryData::size, TSVectorData::size, STRPTR, TS_execute(), val, and CHKVAL::values.
Referenced by ts_match_qv(), ts_match_tq(), and ts_match_tt().
{
TSVector val = PG_GETARG_TSVECTOR(0);
TSQuery query = PG_GETARG_TSQUERY(1);
CHKVAL chkval;
bool result;
if (!val->size || !query->size)
{
PG_FREE_IF_COPY(val, 0);
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(false);
}
chkval.arrb = ARRPTR(val);
chkval.arre = chkval.arrb + val->size;
chkval.values = STRPTR(val);
chkval.operand = GETOPERAND(query);
result = TS_execute(
GETQUERY(query),
&chkval,
true,
checkcondition_str
);
PG_FREE_IF_COPY(val, 0);
PG_FREE_IF_COPY(query, 1);
PG_RETURN_BOOL(result);
}
| static Datum ts_process_call | ( | FuncCallContext * | funcctx | ) | [static] |
Definition at line 1108 of file tsvector_op.c.
References FuncCallContext::attinmeta, BuildTupleFromCStrings(), HeapTupleGetDatum, StatEntry::lenlexeme, StatEntry::lexeme, StatEntry::ndoc, StatEntry::nentry, NULL, palloc(), pfree(), FuncCallContext::user_fctx, values, and walkStatEntryTree().
Referenced by ts_stat1(), and ts_stat2().
{
TSVectorStat *st;
StatEntry *entry;
st = (TSVectorStat *) funcctx->user_fctx;
entry = walkStatEntryTree(st);
if (entry != NULL)
{
Datum result;
char *values[3];
char ndoc[16];
char nentry[16];
HeapTuple tuple;
values[0] = palloc(entry->lenlexeme + 1);
memcpy(values[0], entry->lexeme, entry->lenlexeme);
(values[0])[entry->lenlexeme] = '\0';
sprintf(ndoc, "%d", entry->ndoc);
values[1] = ndoc;
sprintf(nentry, "%d", entry->nentry);
values[2] = nentry;
tuple = BuildTupleFromCStrings(funcctx->attinmeta, values);
result = HeapTupleGetDatum(tuple);
pfree(values[0]);
/* mark entry as already visited */
entry->ndoc = 0;
return result;
}
return (Datum) 0;
}
| static void ts_setup_firstcall | ( | FunctionCallInfo | fcinfo, | |
| FuncCallContext * | funcctx, | |||
| TSVectorStat * | stat | |||
| ) | [static] |
Definition at line 1016 of file tsvector_op.c.
References Assert, FuncCallContext::attinmeta, BlessTupleDesc(), CreateTemplateTupleDesc(), INT4OID, StatEntry::left, TSVectorStat::maxdepth, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, NULL, palloc0(), TSVectorStat::root, TSVectorStat::stack, TSVectorStat::stackpos, TEXTOID, FuncCallContext::tuple_desc, TupleDescGetAttInMetadata(), TupleDescInitEntry(), and FuncCallContext::user_fctx.
Referenced by ts_stat1(), and ts_stat2().
{
TupleDesc tupdesc;
MemoryContext oldcontext;
StatEntry *node;
funcctx->user_fctx = (void *) stat;
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
stat->stack = palloc0(sizeof(StatEntry *) * (stat->maxdepth + 1));
stat->stackpos = 0;
node = stat->root;
/* find leftmost value */
if (node == NULL)
stat->stack[stat->stackpos] = NULL;
else
for (;;)
{
stat->stack[stat->stackpos] = node;
if (node->left)
{
stat->stackpos++;
node = node->left;
}
else
break;
}
Assert(stat->stackpos <= stat->maxdepth);
tupdesc = CreateTemplateTupleDesc(3, false);
TupleDescInitEntry(tupdesc, (AttrNumber) 1, "word",
TEXTOID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 2, "ndoc",
INT4OID, -1, 0);
TupleDescInitEntry(tupdesc, (AttrNumber) 3, "nentry",
INT4OID, -1, 0);
funcctx->tuple_desc = BlessTupleDesc(tupdesc);
funcctx->attinmeta = TupleDescGetAttInMetadata(tupdesc);
MemoryContextSwitchTo(oldcontext);
}
| Datum ts_stat1 | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1236 of file tsvector_op.c.
References FuncCallContext::multi_call_memory_ctx, NULL, PG_FREE_IF_COPY, PG_GETARG_TEXT_P, SPI_connect(), SPI_finish(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, ts_process_call(), ts_setup_firstcall(), and ts_stat_sql().
{
FuncCallContext *funcctx;
Datum result;
if (SRF_IS_FIRSTCALL())
{
TSVectorStat *stat;
text *txt = PG_GETARG_TEXT_P(0);
funcctx = SRF_FIRSTCALL_INIT();
SPI_connect();
stat = ts_stat_sql(funcctx->multi_call_memory_ctx, txt, NULL);
PG_FREE_IF_COPY(txt, 0);
ts_setup_firstcall(fcinfo, funcctx, stat);
SPI_finish();
}
funcctx = SRF_PERCALL_SETUP();
if ((result = ts_process_call(funcctx)) != (Datum) 0)
SRF_RETURN_NEXT(funcctx, result);
SRF_RETURN_DONE(funcctx);
}
| Datum ts_stat2 | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1261 of file tsvector_op.c.
References FuncCallContext::multi_call_memory_ctx, PG_FREE_IF_COPY, PG_GETARG_TEXT_P, SPI_connect(), SPI_finish(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, ts_process_call(), ts_setup_firstcall(), and ts_stat_sql().
{
FuncCallContext *funcctx;
Datum result;
if (SRF_IS_FIRSTCALL())
{
TSVectorStat *stat;
text *txt = PG_GETARG_TEXT_P(0);
text *ws = PG_GETARG_TEXT_P(1);
funcctx = SRF_FIRSTCALL_INIT();
SPI_connect();
stat = ts_stat_sql(funcctx->multi_call_memory_ctx, txt, ws);
PG_FREE_IF_COPY(txt, 0);
PG_FREE_IF_COPY(ws, 1);
ts_setup_firstcall(fcinfo, funcctx, stat);
SPI_finish();
}
funcctx = SRF_PERCALL_SETUP();
if ((result = ts_process_call(funcctx)) != (Datum) 0)
SRF_RETURN_NEXT(funcctx, result);
SRF_RETURN_DONE(funcctx);
}
| static TSVectorStat* ts_stat_sql | ( | MemoryContext | persistentContext, | |
| text * | txt, | |||
| text * | ws | |||
| ) | [static] |
Definition at line 1148 of file tsvector_op.c.
References buf, elog, ereport, errcode(), errmsg(), ERROR, i, is_expected_type(), TSVectorStat::maxdepth, MemoryContextAllocZero(), tupleDesc::natts, NULL, pfree(), pg_mblen(), SPI_cursor_close(), SPI_cursor_fetch(), SPI_cursor_open(), SPI_freeplan(), SPI_freetuptable(), SPI_getbinval(), SPI_gettypeid(), SPI_prepare(), SPI_processed, SPI_tuptable, text_to_cstring(), ts_accum(), TSVECTOROID, SPITupleTable::tupdesc, SPITupleTable::vals, VARDATA, VARHDRSZ, VARSIZE, and TSVectorStat::weight.
Referenced by ts_stat1(), and ts_stat2().
{
char *query = text_to_cstring(txt);
int i;
TSVectorStat *stat;
bool isnull;
Portal portal;
SPIPlanPtr plan;
if ((plan = SPI_prepare(query, 0, NULL)) == NULL)
/* internal error */
elog(ERROR, "SPI_prepare(\"%s\") failed", query);
if ((portal = SPI_cursor_open(NULL, plan, NULL, NULL, true)) == NULL)
/* internal error */
elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
SPI_cursor_fetch(portal, true, 100);
if (SPI_tuptable == NULL ||
SPI_tuptable->tupdesc->natts != 1 ||
!is_expected_type(SPI_gettypeid(SPI_tuptable->tupdesc, 1),
TSVECTOROID))
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("ts_stat query must return one tsvector column")));
stat = MemoryContextAllocZero(persistentContext, sizeof(TSVectorStat));
stat->maxdepth = 1;
if (ws)
{
char *buf;
buf = VARDATA(ws);
while (buf - VARDATA(ws) < VARSIZE(ws) - VARHDRSZ)
{
if (pg_mblen(buf) == 1)
{
switch (*buf)
{
case 'A':
case 'a':
stat->weight |= 1 << 3;
break;
case 'B':
case 'b':
stat->weight |= 1 << 2;
break;
case 'C':
case 'c':
stat->weight |= 1 << 1;
break;
case 'D':
case 'd':
stat->weight |= 1;
break;
default:
stat->weight |= 0;
}
}
buf += pg_mblen(buf);
}
}
while (SPI_processed > 0)
{
for (i = 0; i < SPI_processed; i++)
{
Datum data = SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull);
if (!isnull)
stat = ts_accum(persistentContext, stat, data);
}
SPI_freetuptable(SPI_tuptable);
SPI_cursor_fetch(portal, true, 100);
}
SPI_freetuptable(SPI_tuptable);
SPI_cursor_close(portal);
SPI_freeplan(plan);
pfree(query);
return stat;
}
Definition at line 556 of file tsvector_op.c.
Referenced by checkcondition_str(), compareentry(), compareQueryOperand(), compareWORD(), gin_cmp_prefix(), gin_cmp_tslexeme(), hlfinditem(), QTNodeCompare(), and silly_cmp_tsvector().
{
int cmp;
if (lena == 0)
{
if (prefix)
cmp = 0; /* empty string is prefix of anything */
else
cmp = (lenb > 0) ? -1 : 0;
}
else if (lenb == 0)
{
cmp = (lena > 0) ? 1 : 0;
}
else
{
cmp = memcmp(a, b, Min(lena, lenb));
if (prefix)
{
if (cmp == 0 && lena > lenb)
cmp = 1; /* a is longer, so not a prefix of b */
}
else if (cmp == 0 && lena != lenb)
{
cmp = (lena < lenb) ? -1 : 1;
}
}
return cmp;
}
Definition at line 727 of file tsvector_op.c.
References check_stack_depth(), elog, ERROR, QueryOperator::left, OP_AND, OP_NOT, OP_OR, QueryOperator::oper, QI_VAL, QueryItem::qoperator, tsquery_requires_match(), and QueryItem::type.
Referenced by gin_extract_tsquery(), and tsquery_requires_match().
{
/* since this function recurses, it could be driven to stack overflow */
check_stack_depth();
if (curitem->type == QI_VAL)
return true;
switch (curitem->qoperator.oper)
{
case OP_NOT:
/*
* Assume there are no required matches underneath a NOT. For
* some cases with nested NOTs, we could prove there's a required
* match, but it seems unlikely to be worth the trouble.
*/
return false;
case OP_AND:
/* If either side requires a match, we're good */
if (tsquery_requires_match(curitem + curitem->qoperator.left))
return true;
else
return tsquery_requires_match(curitem + 1);
case OP_OR:
/* Both sides must require a match */
if (tsquery_requires_match(curitem + curitem->qoperator.left))
return tsquery_requires_match(curitem + 1);
else
return false;
default:
elog(ERROR, "unrecognized operator: %d", curitem->qoperator.oper);
}
/* not reachable, but keep compiler quiet */
return false;
}
| Datum tsvector_concat | ( | PG_FUNCTION_ARGS | ) |
Definition at line 329 of file tsvector_op.c.
References _POSVECPTR, add_pos(), ARRPTR, Assert, CALCDATASIZE, cmp(), compareEntry, ereport, errcode(), errmsg(), ERROR, WordEntry::haspos, i, WordEntry::len, MAXSTRPOS, memmove, palloc0(), PG_FREE_IF_COPY, PG_GETARG_TSVECTOR, PG_RETURN_POINTER, WordEntry::pos, POSDATALEN, POSDATAPTR, SET_VARSIZE, SHORTALIGN, TSVectorData::size, STRPTR, VARSIZE, and WEP_GETPOS.
{
TSVector in1 = PG_GETARG_TSVECTOR(0);
TSVector in2 = PG_GETARG_TSVECTOR(1);
TSVector out;
WordEntry *ptr;
WordEntry *ptr1,
*ptr2;
WordEntryPos *p;
int maxpos = 0,
i,
j,
i1,
i2,
dataoff,
output_bytes,
output_size;
char *data,
*data1,
*data2;
/* Get max position in in1; we'll need this to offset in2's positions */
ptr = ARRPTR(in1);
i = in1->size;
while (i--)
{
if ((j = POSDATALEN(in1, ptr)) != 0)
{
p = POSDATAPTR(in1, ptr);
while (j--)
{
if (WEP_GETPOS(*p) > maxpos)
maxpos = WEP_GETPOS(*p);
p++;
}
}
ptr++;
}
ptr1 = ARRPTR(in1);
ptr2 = ARRPTR(in2);
data1 = STRPTR(in1);
data2 = STRPTR(in2);
i1 = in1->size;
i2 = in2->size;
/*
* Conservative estimate of space needed. We might need all the data in
* both inputs, and conceivably add a pad byte before position data for
* each item where there was none before.
*/
output_bytes = VARSIZE(in1) + VARSIZE(in2) + i1 + i2;
out = (TSVector) palloc0(output_bytes);
SET_VARSIZE(out, output_bytes);
/*
* We must make out->size valid so that STRPTR(out) is sensible. We'll
* collapse out any unused space at the end.
*/
out->size = in1->size + in2->size;
ptr = ARRPTR(out);
data = STRPTR(out);
dataoff = 0;
while (i1 && i2)
{
int cmp = compareEntry(data1, ptr1, data2, ptr2);
if (cmp < 0)
{ /* in1 first */
ptr->haspos = ptr1->haspos;
ptr->len = ptr1->len;
memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
ptr->pos = dataoff;
dataoff += ptr1->len;
if (ptr->haspos)
{
dataoff = SHORTALIGN(dataoff);
memcpy(data + dataoff, _POSVECPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
dataoff += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
}
ptr++;
ptr1++;
i1--;
}
else if (cmp > 0)
{ /* in2 first */
ptr->haspos = ptr2->haspos;
ptr->len = ptr2->len;
memcpy(data + dataoff, data2 + ptr2->pos, ptr2->len);
ptr->pos = dataoff;
dataoff += ptr2->len;
if (ptr->haspos)
{
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
if (addlen == 0)
ptr->haspos = 0;
else
{
dataoff = SHORTALIGN(dataoff);
dataoff += addlen * sizeof(WordEntryPos) + sizeof(uint16);
}
}
ptr++;
ptr2++;
i2--;
}
else
{
ptr->haspos = ptr1->haspos | ptr2->haspos;
ptr->len = ptr1->len;
memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
ptr->pos = dataoff;
dataoff += ptr1->len;
if (ptr->haspos)
{
if (ptr1->haspos)
{
dataoff = SHORTALIGN(dataoff);
memcpy(data + dataoff, _POSVECPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
dataoff += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
if (ptr2->haspos)
dataoff += add_pos(in2, ptr2, out, ptr, maxpos) * sizeof(WordEntryPos);
}
else /* must have ptr2->haspos */
{
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
if (addlen == 0)
ptr->haspos = 0;
else
{
dataoff = SHORTALIGN(dataoff);
dataoff += addlen * sizeof(WordEntryPos) + sizeof(uint16);
}
}
}
ptr++;
ptr1++;
ptr2++;
i1--;
i2--;
}
}
while (i1)
{
ptr->haspos = ptr1->haspos;
ptr->len = ptr1->len;
memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
ptr->pos = dataoff;
dataoff += ptr1->len;
if (ptr->haspos)
{
dataoff = SHORTALIGN(dataoff);
memcpy(data + dataoff, _POSVECPTR(in1, ptr1), POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16));
dataoff += POSDATALEN(in1, ptr1) * sizeof(WordEntryPos) + sizeof(uint16);
}
ptr++;
ptr1++;
i1--;
}
while (i2)
{
ptr->haspos = ptr2->haspos;
ptr->len = ptr2->len;
memcpy(data + dataoff, data2 + ptr2->pos, ptr2->len);
ptr->pos = dataoff;
dataoff += ptr2->len;
if (ptr->haspos)
{
int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
if (addlen == 0)
ptr->haspos = 0;
else
{
dataoff = SHORTALIGN(dataoff);
dataoff += addlen * sizeof(WordEntryPos) + sizeof(uint16);
}
}
ptr++;
ptr2++;
i2--;
}
/*
* Instead of checking each offset individually, we check for overflow of
* pos fields once at the end.
*/
if (dataoff > MAXSTRPOS)
ereport(ERROR,
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
errmsg("string is too long for tsvector (%d bytes, max %d bytes)", dataoff, MAXSTRPOS)));
/*
* Adjust sizes (asserting that we didn't overrun the original estimates)
* and collapse out any unused array entries.
*/
output_size = ptr - ARRPTR(out);
Assert(output_size <= out->size);
out->size = output_size;
if (data != STRPTR(out))
memmove(STRPTR(out), data, dataoff);
output_bytes = CALCDATASIZE(out->size, dataoff);
Assert(output_bytes <= VARSIZE(out));
SET_VARSIZE(out, output_bytes);
PG_FREE_IF_COPY(in1, 0);
PG_FREE_IF_COPY(in2, 1);
PG_RETURN_POINTER(out);
}
| Datum tsvector_length | ( | PG_FUNCTION_ARGS | ) |
Definition at line 221 of file tsvector_op.c.
References PG_FREE_IF_COPY, PG_GETARG_TSVECTOR, PG_RETURN_INT32, and TSVectorData::size.
{
TSVector in = PG_GETARG_TSVECTOR(0);
int32 ret = in->size;
PG_FREE_IF_COPY(in, 0);
PG_RETURN_INT32(ret);
}
| Datum tsvector_setweight | ( | PG_FUNCTION_ARGS | ) |
Definition at line 231 of file tsvector_op.c.
References ARRPTR, elog, ERROR, i, palloc(), PG_FREE_IF_COPY, PG_GETARG_CHAR, PG_GETARG_TSVECTOR, PG_RETURN_POINTER, POSDATALEN, POSDATAPTR, TSVectorData::size, VARSIZE, and WEP_SETWEIGHT.
{
TSVector in = PG_GETARG_TSVECTOR(0);
char cw = PG_GETARG_CHAR(1);
TSVector out;
int i,
j;
WordEntry *entry;
WordEntryPos *p;
int w = 0;
switch (cw)
{
case 'A':
case 'a':
w = 3;
break;
case 'B':
case 'b':
w = 2;
break;
case 'C':
case 'c':
w = 1;
break;
case 'D':
case 'd':
w = 0;
break;
default:
/* internal error */
elog(ERROR, "unrecognized weight: %d", cw);
}
out = (TSVector) palloc(VARSIZE(in));
memcpy(out, in, VARSIZE(in));
entry = ARRPTR(out);
i = out->size;
while (i--)
{
if ((j = POSDATALEN(out, entry)) != 0)
{
p = POSDATAPTR(out, entry);
while (j--)
{
WEP_SETWEIGHT(*p, w);
p++;
}
}
entry++;
}
PG_FREE_IF_COPY(in, 0);
PG_RETURN_POINTER(out);
}
| Datum tsvector_strip | ( | PG_FUNCTION_ARGS | ) |
Definition at line 188 of file tsvector_op.c.
References ARRPTR, CALCDATASIZE, cur, i, WordEntry::len, palloc0(), PG_FREE_IF_COPY, PG_GETARG_TSVECTOR, PG_RETURN_POINTER, SET_VARSIZE, TSVectorData::size, and STRPTR.
{
TSVector in = PG_GETARG_TSVECTOR(0);
TSVector out;
int i,
len = 0;
WordEntry *arrin = ARRPTR(in),
*arrout;
char *cur;
for (i = 0; i < in->size; i++)
len += arrin[i].len;
len = CALCDATASIZE(in->size, len);
out = (TSVector) palloc0(len);
SET_VARSIZE(out, len);
out->size = in->size;
arrout = ARRPTR(out);
cur = STRPTR(out);
for (i = 0; i < in->size; i++)
{
memcpy(cur, STRPTR(in) + arrin[i].pos, arrin[i].len);
arrout[i].haspos = 0;
arrout[i].len = arrin[i].len;
arrout[i].pos = cur - STRPTR(out);
cur += arrout[i].len;
}
PG_FREE_IF_COPY(in, 0);
PG_RETURN_POINTER(out);
}
Definition at line 1311 of file tsvector_op.c.
References CALCDATASIZE, CALLED_AS_TRIGGER, ParsedText::curwords, DatumGetObjectId, DatumGetPointer, DatumGetTextP, elog, ereport, errcode(), errmsg(), ERROR, get_ts_config_oid(), i, is_expected_type(), is_text_type(), ParsedText::lenwords, list_length(), make_tsvector(), NULL, numattr, palloc(), parsetext(), pfree(), PointerGetDatum, ParsedText::pos, RelationData::rd_att, REGCONFIGOID, SET_VARSIZE, TSVectorData::size, SPI_ERROR_NOATTRIBUTE, SPI_fnumber(), SPI_getbinval(), SPI_gettypeid(), SPI_modifytuple(), SPI_result, stringToQualifiedNameList(), TriggerData::tg_event, TriggerData::tg_newtuple, TriggerData::tg_relation, TriggerData::tg_trigger, TriggerData::tg_trigtuple, Trigger::tgargs, Trigger::tgnargs, TRIGGER_FIRED_BEFORE, TRIGGER_FIRED_BY_INSERT, TRIGGER_FIRED_BY_UPDATE, TRIGGER_FIRED_FOR_ROW, TSVECTOROID, VARDATA, VARHDRSZ, VARSIZE, and ParsedText::words.
Referenced by tsvector_update_trigger_bycolumn(), and tsvector_update_trigger_byid().
{
TriggerData *trigdata;
Trigger *trigger;
Relation rel;
HeapTuple rettuple = NULL;
int tsvector_attr_num,
i;
ParsedText prs;
Datum datum;
bool isnull;
text *txt;
Oid cfgId;
/* Check call context */
if (!CALLED_AS_TRIGGER(fcinfo)) /* internal error */
elog(ERROR, "tsvector_update_trigger: not fired by trigger manager");
trigdata = (TriggerData *) fcinfo->context;
if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
elog(ERROR, "tsvector_update_trigger: must be fired for row");
if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
elog(ERROR, "tsvector_update_trigger: must be fired BEFORE event");
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
rettuple = trigdata->tg_trigtuple;
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
rettuple = trigdata->tg_newtuple;
else
elog(ERROR, "tsvector_update_trigger: must be fired for INSERT or UPDATE");
trigger = trigdata->tg_trigger;
rel = trigdata->tg_relation;
if (trigger->tgnargs < 3)
elog(ERROR, "tsvector_update_trigger: arguments must be tsvector_field, ts_config, text_field1, ...)");
/* Find the target tsvector column */
tsvector_attr_num = SPI_fnumber(rel->rd_att, trigger->tgargs[0]);
if (tsvector_attr_num == SPI_ERROR_NOATTRIBUTE)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("tsvector column \"%s\" does not exist",
trigger->tgargs[0])));
if (!is_expected_type(SPI_gettypeid(rel->rd_att, tsvector_attr_num),
TSVECTOROID))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column \"%s\" is not of tsvector type",
trigger->tgargs[0])));
/* Find the configuration to use */
if (config_column)
{
int config_attr_num;
config_attr_num = SPI_fnumber(rel->rd_att, trigger->tgargs[1]);
if (config_attr_num == SPI_ERROR_NOATTRIBUTE)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("configuration column \"%s\" does not exist",
trigger->tgargs[1])));
if (!is_expected_type(SPI_gettypeid(rel->rd_att, config_attr_num),
REGCONFIGOID))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column \"%s\" is not of regconfig type",
trigger->tgargs[1])));
datum = SPI_getbinval(rettuple, rel->rd_att, config_attr_num, &isnull);
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("configuration column \"%s\" must not be null",
trigger->tgargs[1])));
cfgId = DatumGetObjectId(datum);
}
else
{
List *names;
names = stringToQualifiedNameList(trigger->tgargs[1]);
/* require a schema so that results are not search path dependent */
if (list_length(names) < 2)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("text search configuration name \"%s\" must be schema-qualified",
trigger->tgargs[1])));
cfgId = get_ts_config_oid(names, false);
}
/* initialize parse state */
prs.lenwords = 32;
prs.curwords = 0;
prs.pos = 0;
prs.words = (ParsedWord *) palloc(sizeof(ParsedWord) * prs.lenwords);
/* find all words in indexable column(s) */
for (i = 2; i < trigger->tgnargs; i++)
{
int numattr;
numattr = SPI_fnumber(rel->rd_att, trigger->tgargs[i]);
if (numattr == SPI_ERROR_NOATTRIBUTE)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_COLUMN),
errmsg("column \"%s\" does not exist",
trigger->tgargs[i])));
if (!is_text_type(SPI_gettypeid(rel->rd_att, numattr)))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("column \"%s\" is not of a character type",
trigger->tgargs[i])));
datum = SPI_getbinval(rettuple, rel->rd_att, numattr, &isnull);
if (isnull)
continue;
txt = DatumGetTextP(datum);
parsetext(cfgId, &prs, VARDATA(txt), VARSIZE(txt) - VARHDRSZ);
if (txt != (text *) DatumGetPointer(datum))
pfree(txt);
}
/* make tsvector value */
if (prs.curwords)
{
datum = PointerGetDatum(make_tsvector(&prs));
rettuple = SPI_modifytuple(rel, rettuple, 1, &tsvector_attr_num,
&datum, NULL);
pfree(DatumGetPointer(datum));
}
else
{
TSVector out = palloc(CALCDATASIZE(0, 0));
SET_VARSIZE(out, CALCDATASIZE(0, 0));
out->size = 0;
datum = PointerGetDatum(out);
rettuple = SPI_modifytuple(rel, rettuple, 1, &tsvector_attr_num,
&datum, NULL);
pfree(prs.words);
}
if (rettuple == NULL) /* internal error */
elog(ERROR, "tsvector_update_trigger: %d returned by SPI_modifytuple",
SPI_result);
return PointerGetDatum(rettuple);
}
| Datum tsvector_update_trigger_bycolumn | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1305 of file tsvector_op.c.
References tsvector_update_trigger().
{
return tsvector_update_trigger(fcinfo, true);
}
| Datum tsvector_update_trigger_byid | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1299 of file tsvector_op.c.
References tsvector_update_trigger().
Referenced by tsa_tsearch2().
{
return tsvector_update_trigger(fcinfo, false);
}
| TSVECTORCMPFUNC | ( | gt | , | |
| BOOL | ||||
| ) |
| TSVECTORCMPFUNC | ( | lt | ) |
| TSVECTORCMPFUNC | ( | eq | , | |
| BOOL | ||||
| ) |
| TSVECTORCMPFUNC | ( | ge | , | |
| >= | , | |||
| BOOL | ||||
| ) |
| TSVECTORCMPFUNC | ( | le | , | |
| <= | , | |||
| BOOL | ||||
| ) |
| TSVECTORCMPFUNC | ( | cmp | , | |
| + | , | |||
| INT32 | ||||
| ) |
| TSVECTORCMPFUNC | ( | ne | , | |
| ! | , | |||
| BOOL | ||||
| ) |
| static StatEntry* walkStatEntryTree | ( | TSVectorStat * | stat | ) | [static] |
Definition at line 1062 of file tsvector_op.c.
References Assert, StatEntry::left, TSVectorStat::maxdepth, StatEntry::ndoc, NULL, StatEntry::right, TSVectorStat::stack, and TSVectorStat::stackpos.
Referenced by ts_process_call().
{
StatEntry *node = stat->stack[stat->stackpos];
if (node == NULL)
return NULL;
if (node->ndoc != 0)
{
/* return entry itself: we already was at left sublink */
return node;
}
else if (node->right && node->right != stat->stack[stat->stackpos + 1])
{
/* go on right sublink */
stat->stackpos++;
node = node->right;
/* find most-left value */
for (;;)
{
stat->stack[stat->stackpos] = node;
if (node->left)
{
stat->stackpos++;
node = node->left;
}
else
break;
}
Assert(stat->stackpos <= stat->maxdepth);
}
else
{
/* we already return all left subtree, itself and right subtree */
if (stat->stackpos == 0)
return NULL;
stat->stackpos--;
return walkStatEntryTree(stat);
}
return node;
}
1.7.1