PostgreSQL Source Code: src/backend/utils/adt/tsvector_op.c Source File (original) (raw)
1
2
3
4
5
6
7
8
9
10
11
12
13
15
16#include <limits.h>
17
34
35
36typedef struct
37{
41 char *operand;
43
44
46{
48
55
56#define STATENTRYHDRSZ (offsetof(StatEntry, lexeme))
57
58typedef struct
59{
61
63
66
69
70
75 void *arg,
77 List **locations);
80
81
82
83
84
85static int
87{
89 return -1;
91 return 1;
92 else if (a->size < b->size)
93 return -1;
94 else if (a->size > b->size)
95 return 1;
96 else
97 {
100 int i = 0;
101 int res;
102
103
104 for (i = 0; i < a->size; i++)
105 {
107 {
108 return (aptr->haspos > bptr->haspos) ? -1 : 1;
109 }
111 {
112 return res;
113 }
114 else if (aptr->haspos)
115 {
118 int j;
119
122
124 {
126 {
128 }
130 {
132 }
133 ap++, bp++;
134 }
135 }
136
137 aptr++;
138 bptr++;
139 }
140 }
141
142 return 0;
143}
144
145#define TSVECTORCMPFUNC( type, action, ret ) \
146Datum \
147tsvector_##type(PG_FUNCTION_ARGS) \
148{ \
149 TSVector a = PG_GETARG_TSVECTOR(0); \
150 TSVector b = PG_GETARG_TSVECTOR(1); \
151 int res = silly_cmp_tsvector(a, b); \
152 PG_FREE_IF_COPY(a,0); \
153 PG_FREE_IF_COPY(b,1); \
154 PG_RETURN_##ret( res action 0 ); \
155} \
156 \
157extern int no_such_variable
158
166
169{
172 int i,
175 *arrout;
176 char *cur;
177
178 for (i = 0; i < in->size; i++)
180
185 arrout = ARRPTR(out);
187 for (i = 0; i < in->size; i++)
188 {
189 memcpy(cur, STRPTR(in) + arrin[i].pos, arrin[i].len);
190 arrout[i].haspos = 0;
191 arrout[i].len = arrin[i].len;
194 }
195
198}
199
202{
205
208}
209
212{
216 int i,
217 j;
220 int w = 0;
221
222 switch (cw)
223 {
224 case 'A':
225 case 'a':
226 w = 3;
227 break;
228 case 'B':
229 case 'b':
230 w = 2;
231 break;
232 case 'C':
233 case 'c':
234 w = 1;
235 break;
236 case 'D':
237 case 'd':
238 w = 0;
239 break;
240 default:
241
242 elog(ERROR, "unrecognized weight: %d", cw);
243 }
244
246 memcpy(out, in, VARSIZE(in));
249 while (i--)
250 {
252 {
254 while (j--)
255 {
257 p++;
258 }
259 }
260 entry++;
261 }
262
265}
266
267
268
269
270
271
274{
278
280 int i,
281 j,
282 nlexemes,
283 weight;
286 bool *nulls;
287
288 switch (char_weight)
289 {
290 case 'A':
291 case 'a':
292 weight = 3;
293 break;
294 case 'B':
295 case 'b':
296 weight = 2;
297 break;
298 case 'C':
299 case 'c':
300 weight = 1;
301 break;
302 case 'D':
303 case 'd':
304 weight = 0;
305 break;
306 default:
307
308 elog(ERROR, "unrecognized weight: %c", char_weight);
309 }
310
312 memcpy(tsout, tsin, VARSIZE(tsin));
313 entry = ARRPTR(tsout);
314
316
317
318
319
320
321
322 for (i = 0; i < nlexemes; i++)
323 {
324 char *lex;
325 int lex_len,
326 lex_pos;
327
328
329 if (nulls[i])
330 continue;
331
335
336 if (lex_pos >= 0 && (j = POSDATALEN(tsout, entry + lex_pos)) != 0)
337 {
339
340 while (j--)
341 {
343 p++;
344 }
345 }
346 }
347
350
352}
353
354#define compareEntry(pa, a, pb, b) \
355 tsCompareString((pa) + (a)->pos, (a)->len, \
356 (pb) + (b)->pos, (b)->len, \
357 false)
358
359
360
361
362
367{
369 int i;
371 startlen;
374
375 if (!destptr->haspos)
376 *clen = 0;
377
378 startlen = *clen;
379 for (i = 0;
382 i++)
383 {
386 (*clen)++;
387 }
388
389 if (*clen != startlen)
391 return *clen - startlen;
392}
393
394
395
396
397
398
399static int
401{
403 int StopLow = 0,
404 StopHigh = tsv->size,
405 StopMiddle,
407
408 while (StopLow < StopHigh)
409 {
410 StopMiddle = (StopLow + StopHigh) / 2;
411
413 STRPTR(tsv) + arrin[StopMiddle].pos,
414 arrin[StopMiddle].len,
415 false);
416
417 if (cmp < 0)
418 StopHigh = StopMiddle;
419 else if (cmp > 0)
420 StopLow = StopMiddle + 1;
421 else
422 return StopMiddle;
423 }
424
425 return -1;
426}
427
428
429
430
431
432static int
434{
435 int a = *((const int *) va);
436 int b = *((const int *) vb);
437
439}
440
441static int
443{
450
451 return tsCompareString(alex, alex_len, blex, blex_len, false);
452}
453
454
455
456
457
458
459
460
461
462
465 int indices_count)
466{
469 *arrout;
471 *dataout;
472 int i,
473 j,
474 k,
475 curoff;
476
477
478
479
480
481
482 if (indices_count > 1)
483 {
484 qsort(indices_to_delete, indices_count, sizeof(int), compare_int);
485 indices_count = qunique(indices_to_delete, indices_count, sizeof(int),
487 }
488
489
490
491
492
494
495
496 tsout->size = tsv->size - indices_count;
497
498
499
500
501 arrout = ARRPTR(tsout);
502 dataout = STRPTR(tsout);
503 curoff = 0;
504 for (i = j = k = 0; i < tsv->size; i++)
505 {
506
507
508
509
510
511 if (k < indices_count && i == indices_to_delete[k])
512 {
513 k++;
514 continue;
515 }
516
517
518 memcpy(dataout + curoff, data + arrin[i].pos, arrin[i].len);
519 arrout[j].haspos = arrin[i].haspos;
520 arrout[j].len = arrin[i].len;
521 arrout[j].pos = curoff;
523 if (arrin[i].haspos)
524 {
527
529 memcpy(dataout + curoff,
532 curoff += len;
533 }
534
535 j++;
536 }
537
538
539
540
541
542
543 Assert(k == indices_count);
544
546 return tsout;
547}
548
549
550
551
552
555{
557 tsout;
561 skip_index;
562
565
567
571}
572
573
574
575
576
579{
581 tsout;
583 int i,
584 nlex,
585 skip_count,
586 *skip_indices;
588 bool *nulls;
589
591
592
593
594
595
596
597 skip_indices = palloc0(nlex * sizeof(int));
598 for (i = skip_count = 0; i < nlex; i++)
599 {
600 char *lex;
601 int lex_len,
602 lex_pos;
603
604
605 if (nulls[i])
606 continue;
607
611
612 if (lex_pos >= 0)
613 skip_indices[skip_count++] = lex_pos;
614 }
615
617
618 pfree(skip_indices);
621
623}
624
625
626
627
628
629
630
633{
636
638 {
641
644
647 TEXTOID, -1, 0);
649 INT2ARRAYOID, -1, 0);
651 TEXTARRAYOID, -1, 0);
653 elog(ERROR, "return type must be a row type");
655
657
659 }
660
663
665 {
669 int j,
671 bool nulls[] = {false, false, false};
673
675
676 if (arrin[i].haspos)
677 {
679 Datum *positions;
681 char weight;
682
683
684
685
686
687
691 for (j = 0; j < posv->npos; j++)
692 {
696 1));
697 }
698
701 }
702 else
703 {
704 nulls[1] = nulls[2] = true;
705 }
706
709 }
710 else
711 {
713 }
714}
715
716
717
718
721{
725 int i;
727
729
730 for (i = 0; i < tsin->size; i++)
731 {
734 }
735
737
741}
742
743
744
745
748{
753 bool *nulls;
755 i,
756 tslen,
757 datalen = 0;
758 char *cur;
759
761
762
763
764
765
767 {
768 if (nulls[i])
770 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
771 errmsg("lexeme array may not contain nulls")));
772
775 (errcode(ERRCODE_ZERO_LENGTH_CHARACTER_STRING),
776 errmsg("lexeme array may not contain empty strings")));
777 }
778
779
781 {
785 }
786
787
791
792
796
797 arrout = ARRPTR(tsout);
800 {
803
804 memcpy(cur, lex, lex_len);
808 cur += lex_len;
809 }
810
813}
814
815
816
817
820{
822 tsout;
825 *arrout;
826 char *datain = STRPTR(tsin),
827 *dataout;
829 bool *nulls;
830 int nweights;
831 int i,
832 j;
833 int cur_pos = 0;
834 char mask = 0;
835
837
838 for (i = 0; i < nweights; i++)
839 {
840 char char_weight;
841
842 if (nulls[i])
844 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
845 errmsg("weight array may not contain nulls")));
846
848 switch (char_weight)
849 {
850 case 'A':
851 case 'a':
852 mask = mask | 8;
853 break;
854 case 'B':
855 case 'b':
856 mask = mask | 4;
857 break;
858 case 'C':
859 case 'c':
860 mask = mask | 2;
861 break;
862 case 'D':
863 case 'd':
864 mask = mask | 1;
865 break;
866 default:
868 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
869 errmsg("unrecognized weight: \"%c\"", char_weight)));
870 }
871 }
872
874 tsout->size = tsin->size;
875 arrout = ARRPTR(tsout);
876 dataout = STRPTR(tsout);
877
878 for (i = j = 0; i < tsin->size; i++)
879 {
881 *posvout;
882 int npos = 0;
883 int k;
884
885 if (!arrin[i].haspos)
886 continue;
887
891
892 for (k = 0; k < posvin->npos; k++)
893 {
895 posvout->pos[npos++] = posvin->pos[k];
896 }
897
898
899 if (!npos)
900 continue;
901
902 arrout[j].haspos = true;
903 arrout[j].len = arrin[i].len;
904 arrout[j].pos = cur_pos;
905
906 memcpy(dataout + cur_pos, datain + arrin[i].pos, arrin[i].len);
907 posvout->npos = npos;
911 j++;
912 }
913
914 tsout->size = j;
915 if (dataout != STRPTR(tsout))
916 memmove(STRPTR(tsout), dataout, cur_pos);
917
919
922}
923
926{
932 *ptr2;
934 int maxpos = 0,
935 i,
936 j,
937 i1,
938 i2,
939 dataoff,
940 output_bytes,
941 output_size;
943 *data1,
944 *data2;
945
946
949 while (i--)
950 {
952 {
954 while (j--)
955 {
958 p++;
959 }
960 }
961 ptr++;
962 }
963
968 i1 = in1->size;
969 i2 = in2->size;
970
971
972
973
974
975
976 output_bytes = VARSIZE(in1) + VARSIZE(in2) + i1 + i2;
977
980
981
982
983
984
986
989 dataoff = 0;
990 while (i1 && i2)
991 {
993
994 if (cmp < 0)
995 {
998 memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
999 ptr->pos = dataoff;
1000 dataoff += ptr1->len;
1002 {
1006 }
1007
1008 ptr++;
1009 ptr1++;
1010 i1--;
1011 }
1012 else if (cmp > 0)
1013 {
1016 memcpy(data + dataoff, data2 + ptr2->pos, ptr2->len);
1017 ptr->pos = dataoff;
1018 dataoff += ptr2->len;
1020 {
1021 int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
1022
1023 if (addlen == 0)
1025 else
1026 {
1029 }
1030 }
1031
1032 ptr++;
1033 ptr2++;
1034 i2--;
1035 }
1036 else
1037 {
1040 memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
1041 ptr->pos = dataoff;
1042 dataoff += ptr1->len;
1044 {
1046 {
1052 }
1053 else
1054 {
1055 int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
1056
1057 if (addlen == 0)
1059 else
1060 {
1063 }
1064 }
1065 }
1066
1067 ptr++;
1068 ptr1++;
1069 ptr2++;
1070 i1--;
1071 i2--;
1072 }
1073 }
1074
1075 while (i1)
1076 {
1079 memcpy(data + dataoff, data1 + ptr1->pos, ptr1->len);
1080 ptr->pos = dataoff;
1081 dataoff += ptr1->len;
1083 {
1087 }
1088
1089 ptr++;
1090 ptr1++;
1091 i1--;
1092 }
1093
1094 while (i2)
1095 {
1098 memcpy(data + dataoff, data2 + ptr2->pos, ptr2->len);
1099 ptr->pos = dataoff;
1100 dataoff += ptr2->len;
1102 {
1103 int addlen = add_pos(in2, ptr2, out, ptr, maxpos);
1104
1105 if (addlen == 0)
1107 else
1108 {
1111 }
1112 }
1113
1114 ptr++;
1115 ptr2++;
1116 i2--;
1117 }
1118
1119
1120
1121
1122
1125 (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1126 errmsg("string is too long for tsvector (%d bytes, max %d bytes)", dataoff, MAXSTRPOS)));
1127
1128
1129
1130
1131
1132 output_size = ptr - ARRPTR(out);
1133 Assert(output_size <= out->size);
1134 out->size = output_size;
1136 memmove(STRPTR(out), data, dataoff);
1140
1144}
1145
1146
1147
1148
1149
1150
1153{
1154 int cmp;
1155
1156 if (lena == 0)
1157 {
1158 if (prefix)
1159 cmp = 0;
1160 else
1161 cmp = (lenb > 0) ? -1 : 0;
1162 }
1163 else if (lenb == 0)
1164 {
1165 cmp = (lena > 0) ? 1 : 0;
1166 }
1167 else
1168 {
1169 cmp = memcmp(a, b, Min((unsigned int) lena, (unsigned int) lenb));
1170
1171 if (prefix)
1172 {
1173 if (cmp == 0 && lena > lenb)
1174 cmp = 1;
1175 }
1176 else if (cmp == 0 && lena != lenb)
1177 {
1178 cmp = (lena < lenb) ? -1 : 1;
1179 }
1180 }
1181
1182 return cmp;
1183}
1184
1185
1186
1187
1191{
1193
1195
1197 {
1199
1200
1201
1202
1203
1206
1208 {
1211
1212
1213
1214
1216 data->allocated = true;
1217
1218
1219 while (posvec_iter < posvec->pos + posvec->npos)
1220 {
1221
1223 {
1225 dptr++;
1226 }
1227
1228 posvec_iter++;
1229 }
1230
1231 data->npos = dptr - data->pos;
1232
1233 if (data->npos > 0)
1235 else
1236 {
1238 data->pos = NULL;
1239 data->allocated = false;
1240 }
1241 }
1242 else if (val->weight)
1243 {
1245
1246
1247 while (posvec_iter < posvec->pos + posvec->npos)
1248 {
1250 {
1252 break;
1253 }
1254
1255 posvec_iter++;
1256 }
1257 }
1258 else if (data)
1259 {
1262 data->allocated = false;
1264 }
1265 else
1266 {
1267
1269 }
1270 }
1271 else
1272 {
1273
1274
1275
1276
1277
1278
1279
1280
1281
1284 else
1286 }
1287
1288 return result;
1289}
1290
1291
1292
1293
1296{
1300 WordEntry *StopMiddle = StopHigh;
1302
1303
1304 while (StopLow < StopHigh)
1305 {
1307
1308 StopMiddle = StopLow + (StopHigh - StopLow) / 2;
1310 val->length,
1311 chkval->values + StopMiddle->pos,
1312 StopMiddle->len,
1313 false);
1314
1316 {
1317
1319 break;
1320 }
1322 StopLow = StopMiddle + 1;
1323 else
1324 StopHigh = StopMiddle;
1325 }
1326
1327
1328
1329
1330
1331
1332
1333
1335 {
1337 int npos = 0,
1338 totalpos = 0;
1339
1340
1341 if (StopLow >= StopHigh)
1342 StopMiddle = StopHigh;
1343
1344
1346 {
1347 if (data->allocated)
1349 data->pos = NULL;
1350 data->allocated = false;
1351 data->npos = 0;
1352 }
1354
1356 StopMiddle < chkval->arre &&
1358 val->length,
1359 chkval->values + StopMiddle->pos,
1360 StopMiddle->len,
1361 true) == 0)
1362 {
1364
1366
1367 if (subres != TS_NO)
1368 {
1370 {
1371
1372
1373
1375 {
1376
1377
1378
1379
1381
1382 npos = 0;
1383
1384 if (allpos)
1386 break;
1387 }
1388
1389 while (npos + data->npos > totalpos)
1390 {
1391 if (totalpos == 0)
1392 {
1393 totalpos = 256;
1395 }
1396 else
1397 {
1398 totalpos *= 2;
1400 }
1401 }
1402
1404 npos += data->npos;
1405
1406
1407 if (data->allocated)
1409 data->pos = NULL;
1410 data->allocated = false;
1411
1412 data->npos = 0;
1413 }
1414 else
1415 {
1416
1418 res = subres;
1419 }
1420 }
1421
1422 StopMiddle++;
1423 }
1424
1425 if (data && npos > 0)
1426 {
1427
1428 data->pos = allpos;
1432 data->allocated = true;
1434 }
1435 }
1436
1437 return res;
1438}
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463#define TSPO_L_ONLY 0x01
1464#define TSPO_R_ONLY 0x02
1465#define TSPO_BOTH 0x04
1466
1471 int emit,
1472 int Loffset,
1473 int Roffset,
1474 int max_npos)
1475{
1476 int Lindex,
1477 Rindex;
1478
1479
1480 Lindex = Rindex = 0;
1481 while (Lindex < Ldata->npos || Rindex < Rdata->npos)
1482 {
1483 int Lpos,
1484 Rpos;
1485 int output_pos = 0;
1486
1487
1488
1489
1490
1491 if (Lindex < Ldata->npos)
1492 Lpos = WEP_GETPOS(Ldata->pos[Lindex]) + Loffset;
1493 else
1494 {
1495
1497 break;
1498 Lpos = INT_MAX;
1499 }
1500 if (Rindex < Rdata->npos)
1501 Rpos = WEP_GETPOS(Rdata->pos[Rindex]) + Roffset;
1502 else
1503 {
1504
1506 break;
1507 Rpos = INT_MAX;
1508 }
1509
1510
1511 if (Lpos < Rpos)
1512 {
1513
1515 output_pos = Lpos;
1516 Lindex++;
1517 }
1518 else if (Lpos == Rpos)
1519 {
1520
1522 output_pos = Rpos;
1523 Lindex++;
1524 Rindex++;
1525 }
1526 else
1527 {
1528
1530 output_pos = Rpos;
1531 Rindex++;
1532 }
1533
1534 if (output_pos > 0)
1535 {
1537 {
1538
1539 if (data->pos == NULL)
1540 {
1543 data->allocated = true;
1544 }
1545 data->pos[data->npos++] = output_pos;
1546 }
1547 else
1548 {
1549
1550
1551
1552
1554 }
1555 }
1556 }
1557
1559 {
1560
1563 }
1565}
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1612{
1614 Rdata;
1616 rmatch;
1617 int Loffset,
1618 Roffset,
1619 maxwidth;
1620
1621
1623
1624
1626
1629
1631 {
1633
1634
1635
1636
1637
1639 {
1640
1642 data->negate = true;
1644 }
1646 {
1648
1650 data->negate = true;
1653 if (data->npos > 0)
1654 {
1655
1656 data->negate = ->negate;
1658 }
1659 else if (data->negate)
1660 {
1661
1662 data->negate = false;
1664 }
1665
1667 break;
1669
1671 }
1672 break;
1673
1676 memset(&Ldata, 0, sizeof(Ldata));
1677 memset(&Rdata, 0, sizeof(Rdata));
1678
1680 arg, flags, chkcond, &Ldata);
1681 if (lmatch == TS_NO)
1683
1685 arg, flags, chkcond, &Rdata);
1686 if (rmatch == TS_NO)
1688
1689
1690
1691
1692
1695
1697 {
1698
1699
1700
1701
1703 Roffset = 0;
1707 }
1708 else
1709 {
1710
1711
1712
1713
1715 Loffset = maxwidth - Ldata.width;
1716 Roffset = maxwidth - Rdata.width;
1718 data->width = maxwidth;
1719 }
1720
1722 {
1723
1726 Loffset, Roffset,
1729 data->negate = true;
1731 }
1732 else if (Ldata.negate)
1733 {
1734
1737 Loffset, Roffset,
1738 Rdata.npos);
1739 }
1740 else if (Rdata.negate)
1741 {
1742
1745 Loffset, Roffset,
1746 Ldata.npos);
1747 }
1748 else
1749 {
1750
1753 Loffset, Roffset,
1755 }
1756
1758 memset(&Ldata, 0, sizeof(Ldata));
1759 memset(&Rdata, 0, sizeof(Rdata));
1760
1762 arg, flags, chkcond, &Ldata);
1764 arg, flags, chkcond, &Rdata);
1765
1766 if (lmatch == TS_NO && rmatch == TS_NO)
1768
1769
1770
1771
1772
1775
1776
1777
1778
1779
1780
1781 if (lmatch == TS_NO)
1782 Ldata.width = 0;
1783 if (rmatch == TS_NO)
1784 Rdata.width = 0;
1785
1786
1787
1788
1789
1790
1791
1793 Loffset = maxwidth - Ldata.width;
1794 Roffset = maxwidth - Rdata.width;
1795 data->width = maxwidth;
1796
1798 {
1799
1802 Loffset, Roffset,
1804 data->negate = true;
1806 }
1807 else if (Ldata.negate)
1808 {
1809
1812 Loffset, Roffset,
1813 Ldata.npos);
1814 data->negate = true;
1816 }
1817 else if (Rdata.negate)
1818 {
1819
1822 Loffset, Roffset,
1823 Rdata.npos);
1824 data->negate = true;
1826 }
1827 else
1828 {
1829
1832 Loffset, Roffset,
1834 }
1835
1836 default:
1838 }
1839
1840
1842}
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853bool
1856{
1857
1858
1859
1860
1861
1863}
1864
1865
1866
1867
1868
1869
1873{
1875}
1876
1877
1878
1879
1880
1881
1885{
1887
1888
1890
1891
1893
1896 NULL );
1897
1899 {
1904 {
1911 }
1912 break;
1913
1916 flags, chkcond);
1917 if (lmatch == TS_NO)
1920 {
1924 return lmatch;
1927 }
1928 break;
1929
1932 flags, chkcond);
1933 if (lmatch == TS_YES)
1936 {
1938 return lmatch;
1943 }
1944 break;
1945
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1958 {
1965 }
1966 break;
1967
1968 default:
1970 }
1971
1972
1974}
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2010{
2011 List *result;
2012
2013
2016 return result;
2017 return NIL;
2018}
2019
2020
2021
2022
2023
2024static bool
2027 List **locations)
2028{
2029 bool lmatch,
2030 rmatch;
2031 List *llocations,
2032 *rlocations;
2034
2035
2037
2038
2040
2041
2042 *locations = NIL;
2043
2045 {
2048 {
2050 return true;
2051 }
2053 return false;
2054 }
2055
2057 {
2060 &llocations))
2061 return true;
2062 return false;
2063
2066 arg, chkcond,
2067 &llocations))
2068 return false;
2070 arg, chkcond,
2071 &rlocations))
2072 return false;
2073 *locations = list_concat(llocations, rlocations);
2074 return true;
2075
2078 arg, chkcond,
2079 &llocations);
2081 arg, chkcond,
2082 &rlocations);
2083 if (lmatch || rmatch)
2084 {
2085
2086
2087
2088
2089
2090
2091
2092
2093 if (llocations == NIL)
2094 *locations = rlocations;
2095 else if (rlocations == NIL)
2096 *locations = llocations;
2097 else
2098 {
2100
2101 foreach(ll, llocations)
2102 {
2105
2106 foreach(lr, rlocations)
2107 {
2109
2113 0, 0,
2115
2118 }
2119 }
2120 }
2121
2122 return true;
2123 }
2124 return false;
2125
2127
2131 {
2132 if (->negate)
2134 return true;
2135 }
2137 return false;
2138
2139 default:
2141 }
2142
2143
2144 return false;
2145}
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155bool
2157{
2158
2160
2162 return true;
2163
2165 {
2167
2168
2169
2170
2171
2172
2173 return false;
2174
2176
2177
2178
2179
2181
2183 return true;
2184 else
2186
2188
2191 else
2192 return false;
2193
2194 default:
2196 }
2197
2198
2199 return false;
2200}
2201
2202
2203
2204
2207{
2211}
2212
2215{
2219 bool result;
2220
2221
2222 if (!query->size)
2223 {
2227 }
2228
2234 &chkval,
2237
2241}
2242
2245{
2248 bool res;
2249
2254
2258
2261
2263}
2264
2267{
2270 bool res;
2271
2274
2278
2281
2283}
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294static int
2296{
2298 int num = 0;
2300
2301 while (len--)
2302 {
2304 num++;
2305 ptr++;
2306 }
2307 return num;
2308}
2309
2310#define compareStatWord(a,e,t) \
2311 tsCompareString((a)->lexeme, (a)->lenlexeme, \
2312 STRPTR(t) + (e)->pos, (e)->len, \
2313 false)
2314
2315static void
2317{
2320 *pnode = NULL;
2321 int n,
2322 res = 0;
2324
2325 if (stat->weight == 0)
2327 else
2329
2330 if (n == 0)
2331 return;
2332
2333 while (node)
2334 {
2336
2337 if (res == 0)
2338 {
2339 break;
2340 }
2341 else
2342 {
2343 pnode = node;
2344 node = (res < 0) ? node->left : node->right;
2345 }
2346 depth++;
2347 }
2348
2349 if (depth > stat->maxdepth)
2350 stat->maxdepth = depth;
2351
2352 if (node == NULL)
2353 {
2355 node->left = node->right = NULL;
2356 node->ndoc = 1;
2360
2361 if (pnode == NULL)
2362 {
2363 stat->root = node;
2364 }
2365 else
2366 {
2367 if (res < 0)
2368 pnode->left = node;
2369 else
2370 pnode->right = node;
2371 }
2372 }
2373 else
2374 {
2375 node->ndoc++;
2377 }
2378}
2379
2380static void
2383{
2385 uint32 middle = (low + high) >> 1;
2386
2387 pos = (low + middle) >> 1;
2388 if (low != middle && pos >= offset && pos - offset < txt->size)
2390 pos = (high + middle + 1) >> 1;
2391 if (middle + 1 != high && pos >= offset && pos - offset < txt->size)
2393
2394 if (low != middle)
2396 if (high != middle + 1)
2398}
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2414{
2417 nbit = 0,
2418 offset;
2419
2420 if (stat == NULL)
2421 {
2423 stat->maxdepth = 1;
2424 }
2425
2426
2427 if (txt == NULL || txt->size == 0)
2428 {
2431 return stat;
2432 }
2433
2436 nbit++;
2437
2438 nbit = 1 << nbit;
2439 offset = (nbit - txt->size) / 2;
2440
2443
2444 return stat;
2445}
2446
2447static void
2450{
2454
2456
2458
2460 stat->stackpos = 0;
2461
2462 node = stat->root;
2463
2464 if (node == NULL)
2465 stat->stack[stat->stackpos] = NULL;
2466 else
2467 for (;;)
2468 {
2469 stat->stack[stat->stackpos] = node;
2470 if (node->left)
2471 {
2472 stat->stackpos++;
2473 node = node->left;
2474 }
2475 else
2476 break;
2477 }
2479
2481 elog(ERROR, "return type must be a row type");
2484
2486}
2487
2490{
2492
2493 if (node == NULL)
2494 return NULL;
2495
2496 if (node->ndoc != 0)
2497 {
2498
2499 return node;
2500 }
2501 else if (node->right && node->right != stat->stack[stat->stackpos + 1])
2502 {
2503
2504 stat->stackpos++;
2505 node = node->right;
2506
2507
2508 for (;;)
2509 {
2510 stat->stack[stat->stackpos] = node;
2511 if (node->left)
2512 {
2513 stat->stackpos++;
2514 node = node->left;
2515 }
2516 else
2517 break;
2518 }
2520 }
2521 else
2522 {
2523
2524 if (stat->stackpos == 0)
2525 return NULL;
2526
2527 stat->stackpos--;
2529 }
2530
2531 return node;
2532}
2533
2536{
2539
2541
2543
2544 if (entry != NULL)
2545 {
2548 char ndoc[16];
2551
2559
2562
2564
2565
2566 entry->ndoc = 0;
2567
2568 return result;
2569 }
2570
2571 return (Datum) 0;
2572}
2573
2576{
2579 bool isnull;
2582
2584
2585 elog(ERROR, "SPI_prepare(\"%s\") failed", query);
2586
2588
2589 elog(ERROR, "SPI_cursor_open(\"%s\") failed", query);
2590
2592
2596 TSVECTOROID))
2598 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2599 errmsg("ts_stat query must return one tsvector column")));
2600
2602 stat->maxdepth = 1;
2603
2604 if (ws)
2605 {
2606 char *buf;
2607
2610 {
2612 {
2613 switch (*buf)
2614 {
2615 case 'A':
2616 case 'a':
2617 stat->weight |= 1 << 3;
2618 break;
2619 case 'B':
2620 case 'b':
2621 stat->weight |= 1 << 2;
2622 break;
2623 case 'C':
2624 case 'c':
2625 stat->weight |= 1 << 1;
2626 break;
2627 case 'D':
2628 case 'd':
2629 stat->weight |= 1;
2630 break;
2631 default:
2632 stat->weight |= 0;
2633 }
2634 }
2636 }
2637 }
2638
2640 {
2642
2644 {
2646
2647 if (!isnull)
2649 }
2650
2653 }
2654
2659
2660 return stat;
2661}
2662
2665{
2668
2670 {
2673
2680 }
2681
2686}
2687
2690{
2693
2695 {
2699
2707 }
2708
2713}
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2728{
2730}
2731
2734{
2736}
2737
2740{
2745 int tsvector_attr_num,
2746 i;
2749 bool isnull;
2751 Oid cfgId;
2752 bool update_needed;
2753
2754
2756 elog(ERROR, "tsvector_update_trigger: not fired by trigger manager");
2757
2758 trigdata = (TriggerData *) fcinfo->context;
2760 elog(ERROR, "tsvector_update_trigger: must be fired for row");
2762 elog(ERROR, "tsvector_update_trigger: must be fired BEFORE event");
2763
2765 {
2767 update_needed = true;
2768 }
2770 {
2772 update_needed = false;
2773 }
2774 else
2775 elog(ERROR, "tsvector_update_trigger: must be fired for INSERT or UPDATE");
2776
2779
2780 if (trigger->tgnargs < 3)
2781 elog(ERROR, "tsvector_update_trigger: arguments must be tsvector_field, ts_config, text_field1, ...)");
2782
2783
2787 (errcode(ERRCODE_UNDEFINED_COLUMN),
2788 errmsg("tsvector column \"%s\" does not exist",
2789 trigger->tgargs[0])));
2790
2792 TSVECTOROID))
2794 (errcode(ERRCODE_DATATYPE_MISMATCH),
2795 errmsg("column \"%s\" is not of tsvector type",
2796 trigger->tgargs[0])));
2797
2798
2799 if (config_column)
2800 {
2801 int config_attr_num;
2802
2806 (errcode(ERRCODE_UNDEFINED_COLUMN),
2807 errmsg("configuration column \"%s\" does not exist",
2808 trigger->tgargs[1])));
2810 REGCONFIGOID))
2812 (errcode(ERRCODE_DATATYPE_MISMATCH),
2813 errmsg("column \"%s\" is not of regconfig type",
2814 trigger->tgargs[1])));
2815
2817 if (isnull)
2819 (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
2820 errmsg("configuration column \"%s\" must not be null",
2821 trigger->tgargs[1])));
2823 }
2824 else
2825 {
2826 List *names;
2827
2829
2832 (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
2833 errmsg("text search configuration name \"%s\" must be schema-qualified",
2834 trigger->tgargs[1])));
2836 }
2837
2838
2841 prs.pos = 0;
2843
2844
2845 for (i = 2; i < trigger->tgnargs; i++)
2846 {
2848
2852 (errcode(ERRCODE_UNDEFINED_COLUMN),
2853 errmsg("column \"%s\" does not exist",
2857 (errcode(ERRCODE_DATATYPE_MISMATCH),
2858 errmsg("column \"%s\" is not of a character type",
2860
2862 update_needed = true;
2863
2865 if (isnull)
2866 continue;
2867
2869
2871
2874 }
2875
2876 if (update_needed)
2877 {
2878
2880 isnull = false;
2881
2882
2884 1, &tsvector_attr_num,
2885 &datum, &isnull);
2886
2888 }
2889
2891}
#define PG_GETARG_ARRAYTYPE_P(n)
ArrayType * construct_array_builtin(Datum *elems, int nelems, Oid elmtype)
void deconstruct_array_builtin(const ArrayType *array, Oid elmtype, Datum **elemsp, bool **nullsp, int *nelemsp)
bool bms_is_member(int x, const Bitmapset *a)
static Datum values[MAXATTR]
#define FLEXIBLE_ARRAY_MEMBER
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
#define repalloc_array(pointer, type, count)
#define palloc_array(type, count)
#define palloc0_array(type, count)
#define palloc0_object(type)
#define PG_FREE_IF_COPY(ptr, n)
#define PG_GETARG_TEXT_PP(n)
#define DirectFunctionCall2(func, arg1, arg2)
#define PG_GETARG_CHAR(n)
#define DatumGetTextPP(X)
#define DirectFunctionCall1(func, arg1)
#define PG_GETARG_DATUM(n)
#define PG_RETURN_INT32(x)
#define PG_RETURN_DATUM(x)
#define PG_RETURN_POINTER(x)
#define PG_RETURN_BOOL(x)
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
#define SRF_IS_FIRSTCALL()
#define SRF_PERCALL_SETUP()
#define SRF_RETURN_NEXT(_funcctx, _result)
#define SRF_FIRSTCALL_INIT()
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
#define SRF_RETURN_DONE(_funcctx)
Datum difference(PG_FUNCTION_ARGS)
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_modify_tuple_by_cols(HeapTuple tuple, TupleDesc tupleDesc, int nCols, const int *replCols, const Datum *replValues, const bool *replIsnull)
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
#define CALCDATASIZE(x, lenstr)
static int pg_cmp_s32(int32 a, int32 b)
if(TABLE==NULL||TABLE_index==NULL)
List * lappend(List *list, void *datum)
List * list_concat(List *list1, const List *list2)
int pg_mblen(const char *mbstr)
void * MemoryContextAlloc(MemoryContext context, Size size)
void * MemoryContextAllocZero(MemoryContext context, Size size)
void pfree(void *pointer)
void * palloc0(Size size)
#define CHECK_FOR_INTERRUPTS()
Oid get_ts_config_oid(List *names, bool missing_ok)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
bool IsBinaryCoercible(Oid srctype, Oid targettype)
static int list_length(const List *l)
static char buf[DEFAULT_XLOG_SEG_SIZE]
#define qsort(a, b, c, d)
static bool DatumGetBool(Datum X)
static Datum PointerGetDatum(const void *X)
static Oid DatumGetObjectId(Datum X)
static Datum Int16GetDatum(int16 X)
static Pointer DatumGetPointer(Datum X)
static char DatumGetChar(Datum X)
static size_t qunique(void *array, size_t elements, size_t width, int(*compare)(const void *, const void *))
static int cmp(const chr *x, const chr *y, size_t len)
List * stringToQualifiedNameList(const char *string, Node *escontext)
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber)
int SPI_freeplan(SPIPlanPtr plan)
SPITupleTable * SPI_tuptable
Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, const Datum *Values, const char *Nulls, bool read_only)
void SPI_cursor_fetch(Portal portal, bool forward, long count)
void SPI_freetuptable(SPITupleTable *tuptable)
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
void SPI_cursor_close(Portal portal)
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
#define SPI_ERROR_NOATTRIBUTE
void check_stack_depth(void)
AttInMetadata * attinmeta
MemoryContext multi_call_memory_ctx
char lexeme[FLEXIBLE_ARRAY_MEMBER]
const Bitmapset * tg_updatedcols
WordEntryPos pos[FLEXIBLE_ARRAY_MEMBER]
#define FirstLowInvalidHeapAttributeNumber
Datum to_tsvector(PG_FUNCTION_ARGS)
TSVector make_tsvector(ParsedText *prs)
Datum plainto_tsquery(PG_FUNCTION_ARGS)
#define TRIGGER_FIRED_BEFORE(event)
#define CALLED_AS_TRIGGER(fcinfo)
#define TRIGGER_FIRED_FOR_ROW(event)
#define TRIGGER_FIRED_BY_INSERT(event)
#define TRIGGER_FIRED_BY_UPDATE(event)
void parsetext(Oid cfgId, ParsedText *prs, char *buf, int buflen)
#define PG_GETARG_TSVECTOR(n)
static TSQuery DatumGetTSQuery(Datum X)
static TSVector DatumGetTSVector(Datum X)
static Datum TSVectorGetDatum(const TSVectorData *X)
#define PG_GETARG_TSQUERY(n)
#define PG_GETARG_TSVECTOR_COPY(n)
#define WEP_SETWEIGHT(x, v)
static Datum TSQueryGetDatum(const TSQueryData *X)
#define TS_EXEC_PHRASE_NO_POS
TSTernaryValue(* TSExecuteCallback)(void *arg, QueryOperand *val, ExecPhraseData *data)
int compareWordEntryPos(const void *a, const void *b)
Datum tsvector_setweight_by_filter(PG_FUNCTION_ARGS)
static Datum ts_process_call(FuncCallContext *funcctx)
static TSTernaryValue checkcondition_str(void *checkval, QueryOperand *val, ExecPhraseData *data)
bool TS_execute(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
Datum ts_match_vq(PG_FUNCTION_ARGS)
Datum tsvector_update_trigger_byid(PG_FUNCTION_ARGS)
static int32 add_pos(TSVector src, WordEntry *srcptr, TSVector dest, WordEntry *destptr, int32 maxpos)
static TSVectorStat * ts_stat_sql(MemoryContext persistentContext, text *txt, text *ws)
List * TS_execute_locations(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
Datum tsvector_delete_arr(PG_FUNCTION_ARGS)
Datum array_to_tsvector(PG_FUNCTION_ARGS)
Datum tsvector_filter(PG_FUNCTION_ARGS)
static TSTernaryValue TS_phrase_output(ExecPhraseData *data, ExecPhraseData *Ldata, ExecPhraseData *Rdata, int emit, int Loffset, int Roffset, int max_npos)
#define compareEntry(pa, a, pb, b)
Datum tsvector_setweight(PG_FUNCTION_ARGS)
#define TSVECTORCMPFUNC(type, action, ret)
static int check_weight(TSVector txt, WordEntry *wptr, int8 weight)
Datum tsvector_strip(PG_FUNCTION_ARGS)
struct StatEntry StatEntry
Datum tsvector_length(PG_FUNCTION_ARGS)
Datum tsvector_to_array(PG_FUNCTION_ARGS)
Datum ts_match_tq(PG_FUNCTION_ARGS)
static int silly_cmp_tsvector(const TSVectorData *a, const TSVectorData *b)
Datum ts_stat1(PG_FUNCTION_ARGS)
int32 tsCompareString(char *a, int lena, char *b, int lenb, bool prefix)
Datum tsvector_delete_str(PG_FUNCTION_ARGS)
static Datum tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column)
Datum ts_match_qv(PG_FUNCTION_ARGS)
bool tsquery_requires_match(QueryItem *curitem)
Datum tsvector_concat(PG_FUNCTION_ARGS)
Datum tsvector_update_trigger_bycolumn(PG_FUNCTION_ARGS)
static bool TS_execute_locations_recurse(QueryItem *curitem, void *arg, TSExecuteCallback chkcond, List **locations)
static TSTernaryValue TS_execute_recurse(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
static TSVectorStat * ts_accum(MemoryContext persistentContext, TSVectorStat *stat, Datum data)
TSTernaryValue TS_execute_ternary(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond)
static int compare_int(const void *va, const void *vb)
static void ts_setup_firstcall(FunctionCallInfo fcinfo, FuncCallContext *funcctx, TSVectorStat *stat)
static void chooseNextStatEntry(MemoryContext persistentContext, TSVectorStat *stat, TSVector txt, uint32 low, uint32 high, uint32 offset)
Datum ts_match_tt(PG_FUNCTION_ARGS)
static TSTernaryValue TS_phrase_execute(QueryItem *curitem, void *arg, uint32 flags, TSExecuteCallback chkcond, ExecPhraseData *data)
static int tsvector_bsearch(const TSVectorData *tsv, char *lexeme, int lexeme_len)
static int compare_text_lexemes(const void *va, const void *vb)
static TSTernaryValue checkclass_str(CHKVAL *chkval, WordEntry *entry, QueryOperand *val, ExecPhraseData *data)
#define compareStatWord(a, e, t)
Datum tsvector_unnest(PG_FUNCTION_ARGS)
static StatEntry * walkStatEntryTree(TSVectorStat *stat)
Datum ts_stat2(PG_FUNCTION_ARGS)
static void insertStatEntry(MemoryContext persistentContext, TSVectorStat *stat, TSVector txt, uint32 off)
static TSVector tsvector_delete_by_indices(TSVector tsv, int *indices_to_delete, int indices_count)
TupleDesc CreateTemplateTupleDesc(int natts)
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
static Size VARSIZE_ANY_EXHDR(const void *PTR)
static Size VARSIZE(const void *PTR)
static char * VARDATA(const void *PTR)
static char * VARDATA_ANY(const void *PTR)
static void SET_VARSIZE(void *PTR, Size len)
text * cstring_to_text_with_len(const char *s, int len)
char * text_to_cstring(const text *t)