2 * In/Out definitions for tsvector type
4 * string of values, array of position lexem in string and it's length
5 * Teodor Sigaev <teodor@sigaev.ru>
9 #include "access/gist.h"
10 #include "access/itup.h"
11 #include "utils/builtins.h"
12 #include "storage/bufpage.h"
13 #include "executor/spi.h"
14 #include "commands/trigger.h"
15 #include "nodes/pg_list.h"
16 #include "catalog/namespace.h"
18 #include "utils/pg_locale.h"
20 #include <ctype.h> /* tolower */
26 PG_FUNCTION_INFO_V1(tsvector_in);
27 Datum tsvector_in(PG_FUNCTION_ARGS);
29 PG_FUNCTION_INFO_V1(tsvector_out);
30 Datum tsvector_out(PG_FUNCTION_ARGS);
32 PG_FUNCTION_INFO_V1(to_tsvector);
33 Datum to_tsvector(PG_FUNCTION_ARGS);
35 PG_FUNCTION_INFO_V1(to_tsvector_current);
36 Datum to_tsvector_current(PG_FUNCTION_ARGS);
38 PG_FUNCTION_INFO_V1(to_tsvector_name);
39 Datum to_tsvector_name(PG_FUNCTION_ARGS);
41 PG_FUNCTION_INFO_V1(tsearch2);
42 Datum tsearch2(PG_FUNCTION_ARGS);
44 PG_FUNCTION_INFO_V1(tsvector_length);
45 Datum tsvector_length(PG_FUNCTION_ARGS);
48 * in/out text index type
51 comparePos(const void *a, const void *b)
53 if (WEP_GETPOS(*(WordEntryPos *) a) == WEP_GETPOS(*(WordEntryPos *) b))
55 return (WEP_GETPOS(*(WordEntryPos *) a) > WEP_GETPOS(*(WordEntryPos *) b)) ? 1 : -1;
59 uniquePos(WordEntryPos * a, int4 l)
68 qsort((void *) a, l, sizeof(WordEntryPos), comparePos);
73 if (WEP_GETPOS(*ptr) != WEP_GETPOS(*res))
77 if (res - a >= MAXNUMPOS - 1 || WEP_GETPOS(*res) == MAXENTRYPOS - 1)
80 else if (WEP_GETWEIGHT(*ptr) > WEP_GETWEIGHT(*res))
81 WEP_SETWEIGHT(*res, WEP_GETWEIGHT(*ptr));
87 static char *BufferStr;
89 compareentry(const void *a, const void *b)
91 if (((WordEntryIN *) a)->entry.len == ((WordEntryIN *) b)->entry.len)
94 &BufferStr[((WordEntryIN *) a)->entry.pos],
95 &BufferStr[((WordEntryIN *) b)->entry.pos],
96 ((WordEntryIN *) a)->entry.len);
98 return (((WordEntryIN *) a)->entry.len > ((WordEntryIN *) b)->entry.len) ? 1 : -1;
102 uniqueentry(WordEntryIN * a, int4 l, char *buf, int4 *outbuflen)
112 *(uint16 *) (a->pos) = uniquePos(&(a->pos[1]), *(uint16 *) (a->pos));
113 *outbuflen = SHORTALIGN(res->entry.len) + (*(uint16 *) (a->pos) + 1) * sizeof(WordEntryPos);
120 qsort((void *) a, l, sizeof(WordEntryIN), compareentry);
124 if (!(ptr->entry.len == res->entry.len &&
125 strncmp(&buf[ptr->entry.pos], &buf[res->entry.pos], res->entry.len) == 0))
127 if (res->entry.haspos)
129 *(uint16 *) (res->pos) = uniquePos(&(res->pos[1]), *(uint16 *) (res->pos));
130 *outbuflen += *(uint16 *) (res->pos) * sizeof(WordEntryPos);
132 *outbuflen += SHORTALIGN(res->entry.len);
134 memcpy(res, ptr, sizeof(WordEntryIN));
136 else if (ptr->entry.haspos)
138 if (res->entry.haspos)
140 int4 len = *(uint16 *) (ptr->pos) + 1 + *(uint16 *) (res->pos);
142 res->pos = (WordEntryPos *) repalloc(res->pos, len * sizeof(WordEntryPos));
143 memcpy(&(res->pos[*(uint16 *) (res->pos) + 1]),
144 &(ptr->pos[1]), *(uint16 *) (ptr->pos) * sizeof(WordEntryPos));
145 *(uint16 *) (res->pos) += *(uint16 *) (ptr->pos);
150 res->entry.haspos = 1;
156 if (res->entry.haspos)
158 *(uint16 *) (res->pos) = uniquePos(&(res->pos[1]), *(uint16 *) (res->pos));
159 *outbuflen += *(uint16 *) (res->pos) * sizeof(WordEntryPos);
161 *outbuflen += SHORTALIGN(res->entry.len);
167 #define WAITENDWORD 2
168 #define WAITNEXTCHAR 3
169 #define WAITENDCMPLX 4
170 #define WAITPOSINFO 5
172 #define WAITPOSDELIM 7
174 #define RESIZEPRSBUF \
176 if ( state->curpos - state->word + 1 >= state->len ) \
178 int4 clen = state->curpos - state->word; \
180 state->word = (char*)repalloc( (void*)state->word, state->len ); \
181 state->curpos = state->word + clen; \
186 gettoken_tsvector(TI_IN_STATE * state)
190 state->curpos = state->word;
191 state->state = WAITWORD;
196 if (state->state == WAITWORD)
198 if (*(state->prsbuf) == '\0')
200 else if (*(state->prsbuf) == '\'')
201 state->state = WAITENDCMPLX;
202 else if (*(state->prsbuf) == '\\')
204 state->state = WAITNEXTCHAR;
205 oldstate = WAITENDWORD;
207 else if (state->oprisdelim && ISOPERATOR(*(state->prsbuf)))
209 (errcode(ERRCODE_SYNTAX_ERROR),
210 errmsg("syntax error")));
211 else if (*(state->prsbuf) != ' ')
213 *(state->curpos) = *(state->prsbuf);
215 state->state = WAITENDWORD;
218 else if (state->state == WAITNEXTCHAR)
220 if (*(state->prsbuf) == '\0')
222 (errcode(ERRCODE_SYNTAX_ERROR),
223 errmsg("there is no escaped character")));
227 *(state->curpos) = *(state->prsbuf);
229 state->state = oldstate;
232 else if (state->state == WAITENDWORD)
234 if (*(state->prsbuf) == '\\')
236 state->state = WAITNEXTCHAR;
237 oldstate = WAITENDWORD;
239 else if (*(state->prsbuf) == ' ' || *(state->prsbuf) == '\0' ||
240 (state->oprisdelim && ISOPERATOR(*(state->prsbuf))))
243 if (state->curpos == state->word)
245 (errcode(ERRCODE_SYNTAX_ERROR),
246 errmsg("syntax error")));
247 *(state->curpos) = '\0';
250 else if (*(state->prsbuf) == ':')
252 if (state->curpos == state->word)
254 (errcode(ERRCODE_SYNTAX_ERROR),
255 errmsg("syntax error")));
256 *(state->curpos) = '\0';
257 if (state->oprisdelim)
260 state->state = INPOSINFO;
265 *(state->curpos) = *(state->prsbuf);
269 else if (state->state == WAITENDCMPLX)
271 if (*(state->prsbuf) == '\'')
274 *(state->curpos) = '\0';
275 if (state->curpos == state->word)
277 (errcode(ERRCODE_SYNTAX_ERROR),
278 errmsg("syntax error")));
279 if (state->oprisdelim)
285 state->state = WAITPOSINFO;
287 else if (*(state->prsbuf) == '\\')
289 state->state = WAITNEXTCHAR;
290 oldstate = WAITENDCMPLX;
292 else if (*(state->prsbuf) == '\0')
294 (errcode(ERRCODE_SYNTAX_ERROR),
295 errmsg("syntax error")));
299 *(state->curpos) = *(state->prsbuf);
303 else if (state->state == WAITPOSINFO)
305 if (*(state->prsbuf) == ':')
306 state->state = INPOSINFO;
310 else if (state->state == INPOSINFO)
312 if (isdigit((unsigned char) *(state->prsbuf)))
314 if (state->alen == 0)
317 state->pos = (WordEntryPos *) palloc(sizeof(WordEntryPos) * state->alen);
318 *(uint16 *) (state->pos) = 0;
320 else if (*(uint16 *) (state->pos) + 1 >= state->alen)
323 state->pos = (WordEntryPos *) repalloc(state->pos, sizeof(WordEntryPos) * state->alen);
325 (*(uint16 *) (state->pos))++;
326 WEP_SETPOS(state->pos[*(uint16 *) (state->pos)], LIMITPOS(atoi(state->prsbuf)));
327 if (WEP_GETPOS(state->pos[*(uint16 *) (state->pos)]) == 0)
329 (errcode(ERRCODE_SYNTAX_ERROR),
330 errmsg("wrong position info")));
331 WEP_SETWEIGHT(state->pos[*(uint16 *) (state->pos)], 0);
332 state->state = WAITPOSDELIM;
336 (errcode(ERRCODE_SYNTAX_ERROR),
337 errmsg("syntax error")));
339 else if (state->state == WAITPOSDELIM)
341 if (*(state->prsbuf) == ',')
342 state->state = INPOSINFO;
343 else if (tolower(*(state->prsbuf)) == 'a' || *(state->prsbuf) == '*')
345 if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)]))
347 (errcode(ERRCODE_SYNTAX_ERROR),
348 errmsg("syntax error")));
349 WEP_SETWEIGHT(state->pos[*(uint16 *) (state->pos)], 3);
351 else if (tolower(*(state->prsbuf)) == 'b')
353 if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)]))
355 (errcode(ERRCODE_SYNTAX_ERROR),
356 errmsg("syntax error")));
357 WEP_SETWEIGHT(state->pos[*(uint16 *) (state->pos)], 2);
359 else if (tolower(*(state->prsbuf)) == 'c')
361 if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)]))
363 (errcode(ERRCODE_SYNTAX_ERROR),
364 errmsg("syntax error")));
365 WEP_SETWEIGHT(state->pos[*(uint16 *) (state->pos)], 1);
367 else if (tolower(*(state->prsbuf)) == 'd')
369 if (WEP_GETWEIGHT(state->pos[*(uint16 *) (state->pos)]))
371 (errcode(ERRCODE_SYNTAX_ERROR),
372 errmsg("syntax error")));
373 WEP_SETWEIGHT(state->pos[*(uint16 *) (state->pos)], 0);
375 else if (isspace((unsigned char) *(state->prsbuf)) ||
376 *(state->prsbuf) == '\0')
378 else if (!isdigit((unsigned char) *(state->prsbuf)))
380 (errcode(ERRCODE_SYNTAX_ERROR),
381 errmsg("syntax error")));
385 elog(ERROR, "internal error");
393 tsvector_in(PG_FUNCTION_ARGS)
395 char *buf = PG_GETARG_CSTRING(0);
410 state.word = (char *) palloc(state.len);
411 state.oprisdelim = false;
413 arr = (WordEntryIN *) palloc(sizeof(WordEntryIN) * totallen);
414 cur = tmpbuf = (char *) palloc(buflen);
415 while (gettoken_tsvector(&state))
420 arr = (WordEntryIN *) repalloc((void *) arr, sizeof(WordEntryIN) * totallen);
422 while ((cur - tmpbuf) + (state.curpos - state.word) >= buflen)
424 int4 dist = cur - tmpbuf;
427 tmpbuf = (char *) repalloc((void *) tmpbuf, buflen);
430 if (state.curpos - state.word >= MAXSTRLEN)
432 (errcode(ERRCODE_SYNTAX_ERROR),
433 errmsg("word is too long")));
434 arr[len].entry.len = state.curpos - state.word;
435 if (cur - tmpbuf > MAXSTRPOS)
437 (errcode(ERRCODE_SYNTAX_ERROR),
438 errmsg("too long value")));
439 arr[len].entry.pos = cur - tmpbuf;
440 memcpy((void *) cur, (void *) state.word, arr[len].entry.len);
441 cur += arr[len].entry.len;
444 arr[len].entry.haspos = 1;
445 arr[len].pos = state.pos;
448 arr[len].entry.haspos = 0;
454 len = uniqueentry(arr, len, tmpbuf, &buflen);
457 totallen = CALCDATASIZE(len, buflen);
458 in = (tsvector *) palloc(totallen);
459 memset(in, 0, totallen);
464 for (i = 0; i < len; i++)
466 memcpy((void *) cur, (void *) &tmpbuf[arr[i].entry.pos], arr[i].entry.len);
467 arr[i].entry.pos = cur - STRPTR(in);
468 cur += SHORTALIGN(arr[i].entry.len);
469 if (arr[i].entry.haspos)
471 memcpy(cur, arr[i].pos, (*(uint16 *) arr[i].pos + 1) * sizeof(WordEntryPos));
472 cur += (*(uint16 *) arr[i].pos + 1) * sizeof(WordEntryPos);
475 memcpy(&(inarr[i]), &(arr[i].entry), sizeof(WordEntry));
479 PG_RETURN_POINTER(in);
483 tsvector_length(PG_FUNCTION_ARGS)
485 tsvector *in = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
488 PG_FREE_IF_COPY(in, 0);
489 PG_RETURN_INT32(ret);
493 tsvector_out(PG_FUNCTION_ARGS)
495 tsvector *out = (tsvector *) PG_DETOAST_DATUM(PG_GETARG_DATUM(0));
501 WordEntry *ptr = ARRPTR(out);
505 lenbuf = out->size * 2 /* '' */ + out->size - 1 /* space */ + 2 /* \0 */ ;
506 for (i = 0; i < out->size; i++)
508 lenbuf += ptr[i].len * 2 /* for escape */ ;
510 lenbuf += 7 * POSDATALEN(out, &(ptr[i]));
513 curout = outbuf = (char *) palloc(lenbuf);
514 for (i = 0; i < out->size; i++)
516 curin = STRPTR(out) + ptr->pos;
525 int4 pos = curout - outbuf;
527 outbuf = (char *) repalloc((void *) outbuf, ++lenbuf);
528 curout = outbuf + pos;
531 *curout++ = *curin++;
534 if ((pp = POSDATALEN(out, ptr)) != 0)
539 wptr = POSDATAPTR(out, ptr);
542 sprintf(curout, "%d", WEP_GETPOS(*wptr));
543 curout = strchr(curout, '\0');
544 switch (WEP_GETWEIGHT(*wptr))
568 outbuf[lenbuf - 1] = '\0';
569 PG_FREE_IF_COPY(out, 0);
570 PG_RETURN_POINTER(outbuf);
574 compareWORD(const void *a, const void *b)
576 if (((TSWORD *) a)->len == ((TSWORD *) b)->len)
579 ((TSWORD *) a)->word,
580 ((TSWORD *) b)->word,
581 ((TSWORD *) b)->len);
584 return (((TSWORD *) a)->pos.pos > ((TSWORD *) b)->pos.pos) ? 1 : -1;
587 return (((TSWORD *) a)->len > ((TSWORD *) b)->len) ? 1 : -1;
591 uniqueWORD(TSWORD * a, int4 l)
599 tmppos = LIMITPOS(a->pos.pos);
601 a->pos.apos = (uint16 *) palloc(sizeof(uint16) * a->alen);
603 a->pos.apos[1] = tmppos;
610 qsort((void *) a, l, sizeof(TSWORD), compareWORD);
611 tmppos = LIMITPOS(a->pos.pos);
613 a->pos.apos = (uint16 *) palloc(sizeof(uint16) * a->alen);
615 a->pos.apos[1] = tmppos;
619 if (!(ptr->len == res->len &&
620 strncmp(ptr->word, res->word, res->len) == 0))
624 res->word = ptr->word;
625 tmppos = LIMITPOS(ptr->pos.pos);
627 res->pos.apos = (uint16 *) palloc(sizeof(uint16) * res->alen);
628 res->pos.apos[0] = 1;
629 res->pos.apos[1] = tmppos;
634 if (res->pos.apos[0] < MAXNUMPOS - 1 && res->pos.apos[res->pos.apos[0]] != MAXENTRYPOS - 1)
636 if (res->pos.apos[0] + 1 >= res->alen)
639 res->pos.apos = (uint16 *) repalloc(res->pos.apos, sizeof(uint16) * res->alen);
641 if (res->pos.apos[0] == 0 || res->pos.apos[res->pos.apos[0]] != LIMITPOS(ptr->pos.pos))
643 res->pos.apos[res->pos.apos[0] + 1] = LIMITPOS(ptr->pos.pos);
655 * make value of tsvector
658 makevalue(PRSTEXT * prs)
669 prs->curwords = uniqueWORD(prs->words, prs->curwords);
670 for (i = 0; i < prs->curwords; i++)
672 lenstr += SHORTALIGN(prs->words[i].len);
674 if (prs->words[i].alen)
675 lenstr += sizeof(uint16) + prs->words[i].pos.apos[0] * sizeof(WordEntryPos);
678 totallen = CALCDATASIZE(prs->curwords, lenstr);
679 in = (tsvector *) palloc(totallen);
680 memset(in, 0, totallen);
682 in->size = prs->curwords;
685 cur = str = STRPTR(in);
686 for (i = 0; i < prs->curwords; i++)
688 ptr->len = prs->words[i].len;
689 if (cur - str > MAXSTRPOS)
691 (errcode(ERRCODE_SYNTAX_ERROR),
692 errmsg("value is too big")));
693 ptr->pos = cur - str;
694 memcpy((void *) cur, (void *) prs->words[i].word, prs->words[i].len);
695 pfree(prs->words[i].word);
696 cur += SHORTALIGN(prs->words[i].len);
697 if (prs->words[i].alen)
702 *(uint16 *) cur = prs->words[i].pos.apos[0];
703 wptr = POSDATAPTR(in, ptr);
704 for (j = 0; j < *(uint16 *) cur; j++)
706 WEP_SETWEIGHT(wptr[j], 0);
707 WEP_SETPOS(wptr[j], prs->words[i].pos.apos[j + 1]);
709 cur += sizeof(uint16) + prs->words[i].pos.apos[0] * sizeof(WordEntryPos);
710 pfree(prs->words[i].pos.apos);
722 to_tsvector(PG_FUNCTION_ARGS)
724 text *in = PG_GETARG_TEXT_P(1);
726 tsvector *out = NULL;
730 cfg = findcfg(PG_GETARG_INT32(0));
735 prs.words = (TSWORD *) palloc(sizeof(TSWORD) * prs.lenwords);
737 parsetext_v2(cfg, &prs, VARDATA(in), VARSIZE(in) - VARHDRSZ);
738 PG_FREE_IF_COPY(in, 1);
741 out = makevalue(&prs);
745 out = palloc(CALCDATASIZE(0, 0));
746 out->len = CALCDATASIZE(0, 0);
749 PG_RETURN_POINTER(out);
753 to_tsvector_name(PG_FUNCTION_ARGS)
755 text *cfg = PG_GETARG_TEXT_P(0);
759 res = DirectFunctionCall3(
761 Int32GetDatum(name2id_cfg(cfg)),
766 PG_FREE_IF_COPY(cfg, 0);
767 PG_RETURN_DATUM(res);
771 to_tsvector_current(PG_FUNCTION_ARGS)
776 res = DirectFunctionCall3(
778 Int32GetDatum(get_currcfg()),
783 PG_RETURN_DATUM(res);
787 findFunc(char *fname)
789 FuncCandidateList clist,
791 Oid funcid = InvalidOid;
792 List *names = list_make1(makeString(fname));
794 ptr = clist = FuncnameGetCandidates(names, 1);
802 if (ptr->args[0] == TEXTOID && funcid == InvalidOid)
816 tsearch2(PG_FUNCTION_ARGS)
818 TriggerData *trigdata;
821 HeapTuple rettuple = NULL;
825 Datum datum = (Datum) 0;
826 Oid funcoid = InvalidOid;
830 cfg = findcfg(get_currcfg());
832 if (!CALLED_AS_TRIGGER(fcinfo))
834 elog(ERROR, "TSearch: Not fired by trigger manager");
836 trigdata = (TriggerData *) fcinfo->context;
837 if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
839 elog(ERROR, "TSearch: Can't process STATEMENT events");
840 if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
842 elog(ERROR, "TSearch: Must be fired BEFORE event");
844 if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
845 rettuple = trigdata->tg_trigtuple;
846 else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
847 rettuple = trigdata->tg_newtuple;
850 elog(ERROR, "TSearch: Unknown event");
852 trigger = trigdata->tg_trigger;
853 rel = trigdata->tg_relation;
855 if (trigger->tgnargs < 2)
857 elog(ERROR, "TSearch: format tsearch2(tsvector_field, text_field1,...)");
859 numidxattr = SPI_fnumber(rel->rd_att, trigger->tgargs[0]);
860 if (numidxattr == SPI_ERROR_NOATTRIBUTE)
862 (errcode(ERRCODE_UNDEFINED_COLUMN),
863 errmsg("tsvector column \"%s\" does not exist",
864 trigger->tgargs[0])));
869 prs.words = (TSWORD *) palloc(sizeof(TSWORD) * prs.lenwords);
871 /* find all words in indexable column */
872 for (i = 1; i < trigger->tgnargs; i++)
880 numattr = SPI_fnumber(rel->rd_att, trigger->tgargs[i]);
881 if (numattr == SPI_ERROR_NOATTRIBUTE)
883 funcoid = findFunc(trigger->tgargs[i]);
884 if (funcoid == InvalidOid)
886 (errcode(ERRCODE_UNDEFINED_COLUMN),
887 errmsg("could not find function or field \"%s\"",
888 trigger->tgargs[i])));
892 oidtype = SPI_gettypeid(rel->rd_att, numattr);
893 /* We assume char() and varchar() are binary-equivalent to text */
894 if (!(oidtype == TEXTOID ||
895 oidtype == VARCHAROID ||
896 oidtype == BPCHAROID))
898 elog(WARNING, "TSearch: '%s' is not of character type",
902 txt_toasted = SPI_getbinval(rettuple, rel->rd_att, numattr, &isnull);
906 if (funcoid != InvalidOid)
908 text *txttmp = (text *) DatumGetPointer(OidFunctionCall1(
910 PointerGetDatum(txt_toasted)
913 txt = (text *) DatumGetPointer(PG_DETOAST_DATUM(PointerGetDatum(txttmp)));
915 txt_toasted = PointerGetDatum(txt);
918 txt = (text *) DatumGetPointer(PG_DETOAST_DATUM(PointerGetDatum(txt_toasted)));
920 parsetext_v2(cfg, &prs, VARDATA(txt), VARSIZE(txt) - VARHDRSZ);
921 if (txt != (text *) DatumGetPointer(txt_toasted))
925 /* make tsvector value */
928 datum = PointerGetDatum(makevalue(&prs));
929 rettuple = SPI_modifytuple(rel, rettuple, 1, &numidxattr,
931 pfree(DatumGetPointer(datum));
935 tsvector *out = palloc(CALCDATASIZE(0, 0));
937 out->len = CALCDATASIZE(0, 0);
939 datum = PointerGetDatum(out);
941 rettuple = SPI_modifytuple(rel, rettuple, 1, &numidxattr,
945 if (rettuple == NULL)
947 elog(ERROR, "TSearch: %d returned by SPI_modifytuple", SPI_result);
949 return PointerGetDatum(rettuple);
953 silly_cmp_tsvector(const tsvector * a, const tsvector * b)
957 else if (a->len > b->len)
959 else if (a->size < b->size)
961 else if (a->size > b->size)
965 unsigned char *aptr = (unsigned char *) (a->data) + DATAHDRSIZE;
966 unsigned char *bptr = (unsigned char *) (b->data) + DATAHDRSIZE;
968 while (aptr - ((unsigned char *) (a->data)) < a->len)
971 return (*aptr < *bptr) ? -1 : 1;
979 PG_FUNCTION_INFO_V1(tsvector_cmp);
980 PG_FUNCTION_INFO_V1(tsvector_lt);
981 PG_FUNCTION_INFO_V1(tsvector_le);
982 PG_FUNCTION_INFO_V1(tsvector_eq);
983 PG_FUNCTION_INFO_V1(tsvector_ne);
984 PG_FUNCTION_INFO_V1(tsvector_ge);
985 PG_FUNCTION_INFO_V1(tsvector_gt);
986 Datum tsvector_cmp(PG_FUNCTION_ARGS);
987 Datum tsvector_lt(PG_FUNCTION_ARGS);
988 Datum tsvector_le(PG_FUNCTION_ARGS);
989 Datum tsvector_eq(PG_FUNCTION_ARGS);
990 Datum tsvector_ne(PG_FUNCTION_ARGS);
991 Datum tsvector_ge(PG_FUNCTION_ARGS);
992 Datum tsvector_gt(PG_FUNCTION_ARGS);
995 tsvector *a = (tsvector *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(0)));\
996 tsvector *b = (tsvector *) DatumGetPointer(PG_DETOAST_DATUM(PG_GETARG_DATUM(1)));\
997 int res = silly_cmp_tsvector(a,b); \
998 PG_FREE_IF_COPY(a,0); \
999 PG_FREE_IF_COPY(b,1); \
1002 tsvector_cmp(PG_FUNCTION_ARGS)
1005 PG_RETURN_INT32(res);
1009 tsvector_lt(PG_FUNCTION_ARGS)
1012 PG_RETURN_BOOL((res < 0) ? true : false);
1016 tsvector_le(PG_FUNCTION_ARGS)
1019 PG_RETURN_BOOL((res <= 0) ? true : false);
1023 tsvector_eq(PG_FUNCTION_ARGS)
1026 PG_RETURN_BOOL((res == 0) ? true : false);
1030 tsvector_ge(PG_FUNCTION_ARGS)
1033 PG_RETURN_BOOL((res >= 0) ? true : false);
1037 tsvector_gt(PG_FUNCTION_ARGS)
1040 PG_RETURN_BOOL((res > 0) ? true : false);
1044 tsvector_ne(PG_FUNCTION_ARGS)
1047 PG_RETURN_BOOL((res != 0) ? true : false);