summaryrefslogtreecommitdiffstats
path: root/contrib/pg_trgm
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 13:44:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-13 13:44:03 +0000
commit293913568e6a7a86fd1479e1cff8e2ecb58d6568 (patch)
treefc3b469a3ec5ab71b36ea97cc7aaddb838423a0c /contrib/pg_trgm
parentInitial commit. (diff)
downloadpostgresql-16-293913568e6a7a86fd1479e1cff8e2ecb58d6568.tar.xz
postgresql-16-293913568e6a7a86fd1479e1cff8e2ecb58d6568.zip
Adding upstream version 16.2.upstream/16.2
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'contrib/pg_trgm')
-rw-r--r--contrib/pg_trgm/.gitignore4
-rw-r--r--contrib/pg_trgm/Makefile28
-rw-r--r--contrib/pg_trgm/data/trgm.data1000
-rw-r--r--contrib/pg_trgm/data/trgm2.data696
-rw-r--r--contrib/pg_trgm/expected/pg_strict_word_trgm.out1027
-rw-r--r--contrib/pg_trgm/expected/pg_trgm.out5404
-rw-r--r--contrib/pg_trgm/expected/pg_word_trgm.out1052
-rw-r--r--contrib/pg_trgm/meson.build46
-rw-r--r--contrib/pg_trgm/pg_trgm--1.0--1.1.sql12
-rw-r--r--contrib/pg_trgm/pg_trgm--1.1--1.2.sql74
-rw-r--r--contrib/pg_trgm/pg_trgm--1.2--1.3.sql65
-rw-r--r--contrib/pg_trgm/pg_trgm--1.3--1.4.sql68
-rw-r--r--contrib/pg_trgm/pg_trgm--1.3.sql254
-rw-r--r--contrib/pg_trgm/pg_trgm--1.4--1.5.sql23
-rw-r--r--contrib/pg_trgm/pg_trgm--1.5--1.6.sql10
-rw-r--r--contrib/pg_trgm/pg_trgm.control6
-rw-r--r--contrib/pg_trgm/sql/pg_strict_word_trgm.sql45
-rw-r--r--contrib/pg_trgm/sql/pg_trgm.sql238
-rw-r--r--contrib/pg_trgm/sql/pg_word_trgm.sql48
-rw-r--r--contrib/pg_trgm/trgm.h140
-rw-r--r--contrib/pg_trgm/trgm_gin.c360
-rw-r--r--contrib/pg_trgm/trgm_gist.c971
-rw-r--r--contrib/pg_trgm/trgm_op.c1323
-rw-r--r--contrib/pg_trgm/trgm_regexp.c2358
24 files changed, 15252 insertions, 0 deletions
diff --git a/contrib/pg_trgm/.gitignore b/contrib/pg_trgm/.gitignore
new file mode 100644
index 0000000..5dcb3ff
--- /dev/null
+++ b/contrib/pg_trgm/.gitignore
@@ -0,0 +1,4 @@
+# Generated subdirectories
+/log/
+/results/
+/tmp_check/
diff --git a/contrib/pg_trgm/Makefile b/contrib/pg_trgm/Makefile
new file mode 100644
index 0000000..1fbdc9e
--- /dev/null
+++ b/contrib/pg_trgm/Makefile
@@ -0,0 +1,28 @@
+# contrib/pg_trgm/Makefile
+
+MODULE_big = pg_trgm
+OBJS = \
+ $(WIN32RES) \
+ trgm_gin.o \
+ trgm_gist.o \
+ trgm_op.o \
+ trgm_regexp.o
+
+EXTENSION = pg_trgm
+DATA = pg_trgm--1.5--1.6.sql pg_trgm--1.4--1.5.sql pg_trgm--1.3--1.4.sql \
+ pg_trgm--1.3.sql pg_trgm--1.2--1.3.sql pg_trgm--1.1--1.2.sql \
+ pg_trgm--1.0--1.1.sql
+PGFILEDESC = "pg_trgm - trigram matching"
+
+REGRESS = pg_trgm pg_word_trgm pg_strict_word_trgm
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/pg_trgm
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/contrib/pg_trgm/data/trgm.data b/contrib/pg_trgm/data/trgm.data
new file mode 100644
index 0000000..37319d6
--- /dev/null
+++ b/contrib/pg_trgm/data/trgm.data
@@ -0,0 +1,1000 @@
+qwertyu0001
+qwertyu0002
+qwertyu0003
+qwertyu0004
+qwertyu0005
+qwertyu0006
+qwertyu0007
+qwertyu0008
+qwertyu0009
+qwertyu0010
+qwertyu0011
+qwertyu0012
+qwertyu0013
+qwertyu0014
+qwertyu0015
+qwertyu0016
+qwertyu0017
+qwertyu0018
+qwertyu0019
+qwertyu0020
+qwertyu0021
+qwertyu0022
+qwertyu0023
+qwertyu0024
+qwertyu0025
+qwertyu0026
+qwertyu0027
+qwertyu0028
+qwertyu0029
+qwertyu0030
+qwertyu0031
+qwertyu0032
+qwertyu0033
+qwertyu0034
+qwertyu0035
+qwertyu0036
+qwertyu0037
+qwertyu0038
+qwertyu0039
+qwertyu0040
+qwertyu0041
+qwertyu0042
+qwertyu0043
+qwertyu0044
+qwertyu0045
+qwertyu0046
+qwertyu0047
+qwertyu0048
+qwertyu0049
+qwertyu0050
+qwertyu0051
+qwertyu0052
+qwertyu0053
+qwertyu0054
+qwertyu0055
+qwertyu0056
+qwertyu0057
+qwertyu0058
+qwertyu0059
+qwertyu0060
+qwertyu0061
+qwertyu0062
+qwertyu0063
+qwertyu0064
+qwertyu0065
+qwertyu0066
+qwertyu0067
+qwertyu0068
+qwertyu0069
+qwertyu0070
+qwertyu0071
+qwertyu0072
+qwertyu0073
+qwertyu0074
+qwertyu0075
+qwertyu0076
+qwertyu0077
+qwertyu0078
+qwertyu0079
+qwertyu0080
+qwertyu0081
+qwertyu0082
+qwertyu0083
+qwertyu0084
+qwertyu0085
+qwertyu0086
+qwertyu0087
+qwertyu0088
+qwertyu0089
+qwertyu0090
+qwertyu0091
+qwertyu0092
+qwertyu0093
+qwertyu0094
+qwertyu0095
+qwertyu0096
+qwertyu0097
+qwertyu0098
+qwertyu0099
+qwertyu0100
+qwertyu0101
+qwertyu0102
+qwertyu0103
+qwertyu0104
+qwertyu0105
+qwertyu0106
+qwertyu0107
+qwertyu0108
+qwertyu0109
+qwertyu0110
+qwertyu0111
+qwertyu0112
+qwertyu0113
+qwertyu0114
+qwertyu0115
+qwertyu0116
+qwertyu0117
+qwertyu0118
+qwertyu0119
+qwertyu0120
+qwertyu0121
+qwertyu0122
+qwertyu0123
+qwertyu0124
+qwertyu0125
+qwertyu0126
+qwertyu0127
+qwertyu0128
+qwertyu0129
+qwertyu0130
+qwertyu0131
+qwertyu0132
+qwertyu0133
+qwertyu0134
+qwertyu0135
+qwertyu0136
+qwertyu0137
+qwertyu0138
+qwertyu0139
+qwertyu0140
+qwertyu0141
+qwertyu0142
+qwertyu0143
+qwertyu0144
+qwertyu0145
+qwertyu0146
+qwertyu0147
+qwertyu0148
+qwertyu0149
+qwertyu0150
+qwertyu0151
+qwertyu0152
+qwertyu0153
+qwertyu0154
+qwertyu0155
+qwertyu0156
+qwertyu0157
+qwertyu0158
+qwertyu0159
+qwertyu0160
+qwertyu0161
+qwertyu0162
+qwertyu0163
+qwertyu0164
+qwertyu0165
+qwertyu0166
+qwertyu0167
+qwertyu0168
+qwertyu0169
+qwertyu0170
+qwertyu0171
+qwertyu0172
+qwertyu0173
+qwertyu0174
+qwertyu0175
+qwertyu0176
+qwertyu0177
+qwertyu0178
+qwertyu0179
+qwertyu0180
+qwertyu0181
+qwertyu0182
+qwertyu0183
+qwertyu0184
+qwertyu0185
+qwertyu0186
+qwertyu0187
+qwertyu0188
+qwertyu0189
+qwertyu0190
+qwertyu0191
+qwertyu0192
+qwertyu0193
+qwertyu0194
+qwertyu0195
+qwertyu0196
+qwertyu0197
+qwertyu0198
+qwertyu0199
+qwertyu0200
+qwertyu0201
+qwertyu0202
+qwertyu0203
+qwertyu0204
+qwertyu0205
+qwertyu0206
+qwertyu0207
+qwertyu0208
+qwertyu0209
+qwertyu0210
+qwertyu0211
+qwertyu0212
+qwertyu0213
+qwertyu0214
+qwertyu0215
+qwertyu0216
+qwertyu0217
+qwertyu0218
+qwertyu0219
+qwertyu0220
+qwertyu0221
+qwertyu0222
+qwertyu0223
+qwertyu0224
+qwertyu0225
+qwertyu0226
+qwertyu0227
+qwertyu0228
+qwertyu0229
+qwertyu0230
+qwertyu0231
+qwertyu0232
+qwertyu0233
+qwertyu0234
+qwertyu0235
+qwertyu0236
+qwertyu0237
+qwertyu0238
+qwertyu0239
+qwertyu0240
+qwertyu0241
+qwertyu0242
+qwertyu0243
+qwertyu0244
+qwertyu0245
+qwertyu0246
+qwertyu0247
+qwertyu0248
+qwertyu0249
+qwertyu0250
+qwertyu0251
+qwertyu0252
+qwertyu0253
+qwertyu0254
+qwertyu0255
+qwertyu0256
+qwertyu0257
+qwertyu0258
+qwertyu0259
+qwertyu0260
+qwertyu0261
+qwertyu0262
+qwertyu0263
+qwertyu0264
+qwertyu0265
+qwertyu0266
+qwertyu0267
+qwertyu0268
+qwertyu0269
+qwertyu0270
+qwertyu0271
+qwertyu0272
+qwertyu0273
+qwertyu0274
+qwertyu0275
+qwertyu0276
+qwertyu0277
+qwertyu0278
+qwertyu0279
+qwertyu0280
+qwertyu0281
+qwertyu0282
+qwertyu0283
+qwertyu0284
+qwertyu0285
+qwertyu0286
+qwertyu0287
+qwertyu0288
+qwertyu0289
+qwertyu0290
+qwertyu0291
+qwertyu0292
+qwertyu0293
+qwertyu0294
+qwertyu0295
+qwertyu0296
+qwertyu0297
+qwertyu0298
+qwertyu0299
+qwertyu0300
+qwertyu0301
+qwertyu0302
+qwertyu0303
+qwertyu0304
+qwertyu0305
+qwertyu0306
+qwertyu0307
+qwertyu0308
+qwertyu0309
+qwertyu0310
+qwertyu0311
+qwertyu0312
+qwertyu0313
+qwertyu0314
+qwertyu0315
+qwertyu0316
+qwertyu0317
+qwertyu0318
+qwertyu0319
+qwertyu0320
+qwertyu0321
+qwertyu0322
+qwertyu0323
+qwertyu0324
+qwertyu0325
+qwertyu0326
+qwertyu0327
+qwertyu0328
+qwertyu0329
+qwertyu0330
+qwertyu0331
+qwertyu0332
+qwertyu0333
+qwertyu0334
+qwertyu0335
+qwertyu0336
+qwertyu0337
+qwertyu0338
+qwertyu0339
+qwertyu0340
+qwertyu0341
+qwertyu0342
+qwertyu0343
+qwertyu0344
+qwertyu0345
+qwertyu0346
+qwertyu0347
+qwertyu0348
+qwertyu0349
+qwertyu0350
+qwertyu0351
+qwertyu0352
+qwertyu0353
+qwertyu0354
+qwertyu0355
+qwertyu0356
+qwertyu0357
+qwertyu0358
+qwertyu0359
+qwertyu0360
+qwertyu0361
+qwertyu0362
+qwertyu0363
+qwertyu0364
+qwertyu0365
+qwertyu0366
+qwertyu0367
+qwertyu0368
+qwertyu0369
+qwertyu0370
+qwertyu0371
+qwertyu0372
+qwertyu0373
+qwertyu0374
+qwertyu0375
+qwertyu0376
+qwertyu0377
+qwertyu0378
+qwertyu0379
+qwertyu0380
+qwertyu0381
+qwertyu0382
+qwertyu0383
+qwertyu0384
+qwertyu0385
+qwertyu0386
+qwertyu0387
+qwertyu0388
+qwertyu0389
+qwertyu0390
+qwertyu0391
+qwertyu0392
+qwertyu0393
+qwertyu0394
+qwertyu0395
+qwertyu0396
+qwertyu0397
+qwertyu0398
+qwertyu0399
+qwertyu0400
+qwertyu0401
+qwertyu0402
+qwertyu0403
+qwertyu0404
+qwertyu0405
+qwertyu0406
+qwertyu0407
+qwertyu0408
+qwertyu0409
+qwertyu0410
+qwertyu0411
+qwertyu0412
+qwertyu0413
+qwertyu0414
+qwertyu0415
+qwertyu0416
+qwertyu0417
+qwertyu0418
+qwertyu0419
+qwertyu0420
+qwertyu0421
+qwertyu0422
+qwertyu0423
+qwertyu0424
+qwertyu0425
+qwertyu0426
+qwertyu0427
+qwertyu0428
+qwertyu0429
+qwertyu0430
+qwertyu0431
+qwertyu0432
+qwertyu0433
+qwertyu0434
+qwertyu0435
+qwertyu0436
+qwertyu0437
+qwertyu0438
+qwertyu0439
+qwertyu0440
+qwertyu0441
+qwertyu0442
+qwertyu0443
+qwertyu0444
+qwertyu0445
+qwertyu0446
+qwertyu0447
+qwertyu0448
+qwertyu0449
+qwertyu0450
+qwertyu0451
+qwertyu0452
+qwertyu0453
+qwertyu0454
+qwertyu0455
+qwertyu0456
+qwertyu0457
+qwertyu0458
+qwertyu0459
+qwertyu0460
+qwertyu0461
+qwertyu0462
+qwertyu0463
+qwertyu0464
+qwertyu0465
+qwertyu0466
+qwertyu0467
+qwertyu0468
+qwertyu0469
+qwertyu0470
+qwertyu0471
+qwertyu0472
+qwertyu0473
+qwertyu0474
+qwertyu0475
+qwertyu0476
+qwertyu0477
+qwertyu0478
+qwertyu0479
+qwertyu0480
+qwertyu0481
+qwertyu0482
+qwertyu0483
+qwertyu0484
+qwertyu0485
+qwertyu0486
+qwertyu0487
+qwertyu0488
+qwertyu0489
+qwertyu0490
+qwertyu0491
+qwertyu0492
+qwertyu0493
+qwertyu0494
+qwertyu0495
+qwertyu0496
+qwertyu0497
+qwertyu0498
+qwertyu0499
+qwertyu0500
+qwertyu0501
+qwertyu0502
+qwertyu0503
+qwertyu0504
+qwertyu0505
+qwertyu0506
+qwertyu0507
+qwertyu0508
+qwertyu0509
+qwertyu0510
+qwertyu0511
+qwertyu0512
+qwertyu0513
+qwertyu0514
+qwertyu0515
+qwertyu0516
+qwertyu0517
+qwertyu0518
+qwertyu0519
+qwertyu0520
+qwertyu0521
+qwertyu0522
+qwertyu0523
+qwertyu0524
+qwertyu0525
+qwertyu0526
+qwertyu0527
+qwertyu0528
+qwertyu0529
+qwertyu0530
+qwertyu0531
+qwertyu0532
+qwertyu0533
+qwertyu0534
+qwertyu0535
+qwertyu0536
+qwertyu0537
+qwertyu0538
+qwertyu0539
+qwertyu0540
+qwertyu0541
+qwertyu0542
+qwertyu0543
+qwertyu0544
+qwertyu0545
+qwertyu0546
+qwertyu0547
+qwertyu0548
+qwertyu0549
+qwertyu0550
+qwertyu0551
+qwertyu0552
+qwertyu0553
+qwertyu0554
+qwertyu0555
+qwertyu0556
+qwertyu0557
+qwertyu0558
+qwertyu0559
+qwertyu0560
+qwertyu0561
+qwertyu0562
+qwertyu0563
+qwertyu0564
+qwertyu0565
+qwertyu0566
+qwertyu0567
+qwertyu0568
+qwertyu0569
+qwertyu0570
+qwertyu0571
+qwertyu0572
+qwertyu0573
+qwertyu0574
+qwertyu0575
+qwertyu0576
+qwertyu0577
+qwertyu0578
+qwertyu0579
+qwertyu0580
+qwertyu0581
+qwertyu0582
+qwertyu0583
+qwertyu0584
+qwertyu0585
+qwertyu0586
+qwertyu0587
+qwertyu0588
+qwertyu0589
+qwertyu0590
+qwertyu0591
+qwertyu0592
+qwertyu0593
+qwertyu0594
+qwertyu0595
+qwertyu0596
+qwertyu0597
+qwertyu0598
+qwertyu0599
+qwertyu0600
+qwertyu0601
+qwertyu0602
+qwertyu0603
+qwertyu0604
+qwertyu0605
+qwertyu0606
+qwertyu0607
+qwertyu0608
+qwertyu0609
+qwertyu0610
+qwertyu0611
+qwertyu0612
+qwertyu0613
+qwertyu0614
+qwertyu0615
+qwertyu0616
+qwertyu0617
+qwertyu0618
+qwertyu0619
+qwertyu0620
+qwertyu0621
+qwertyu0622
+qwertyu0623
+qwertyu0624
+qwertyu0625
+qwertyu0626
+qwertyu0627
+qwertyu0628
+qwertyu0629
+qwertyu0630
+qwertyu0631
+qwertyu0632
+qwertyu0633
+qwertyu0634
+qwertyu0635
+qwertyu0636
+qwertyu0637
+qwertyu0638
+qwertyu0639
+qwertyu0640
+qwertyu0641
+qwertyu0642
+qwertyu0643
+qwertyu0644
+qwertyu0645
+qwertyu0646
+qwertyu0647
+qwertyu0648
+qwertyu0649
+qwertyu0650
+qwertyu0651
+qwertyu0652
+qwertyu0653
+qwertyu0654
+qwertyu0655
+qwertyu0656
+qwertyu0657
+qwertyu0658
+qwertyu0659
+qwertyu0660
+qwertyu0661
+qwertyu0662
+qwertyu0663
+qwertyu0664
+qwertyu0665
+qwertyu0666
+qwertyu0667
+qwertyu0668
+qwertyu0669
+qwertyu0670
+qwertyu0671
+qwertyu0672
+qwertyu0673
+qwertyu0674
+qwertyu0675
+qwertyu0676
+qwertyu0677
+qwertyu0678
+qwertyu0679
+qwertyu0680
+qwertyu0681
+qwertyu0682
+qwertyu0683
+qwertyu0684
+qwertyu0685
+qwertyu0686
+qwertyu0687
+qwertyu0688
+qwertyu0689
+qwertyu0690
+qwertyu0691
+qwertyu0692
+qwertyu0693
+qwertyu0694
+qwertyu0695
+qwertyu0696
+qwertyu0697
+qwertyu0698
+qwertyu0699
+qwertyu0700
+qwertyu0701
+qwertyu0702
+qwertyu0703
+qwertyu0704
+qwertyu0705
+qwertyu0706
+qwertyu0707
+qwertyu0708
+qwertyu0709
+qwertyu0710
+qwertyu0711
+qwertyu0712
+qwertyu0713
+qwertyu0714
+qwertyu0715
+qwertyu0716
+qwertyu0717
+qwertyu0718
+qwertyu0719
+qwertyu0720
+qwertyu0721
+qwertyu0722
+qwertyu0723
+qwertyu0724
+qwertyu0725
+qwertyu0726
+qwertyu0727
+qwertyu0728
+qwertyu0729
+qwertyu0730
+qwertyu0731
+qwertyu0732
+qwertyu0733
+qwertyu0734
+qwertyu0735
+qwertyu0736
+qwertyu0737
+qwertyu0738
+qwertyu0739
+qwertyu0740
+qwertyu0741
+qwertyu0742
+qwertyu0743
+qwertyu0744
+qwertyu0745
+qwertyu0746
+qwertyu0747
+qwertyu0748
+qwertyu0749
+qwertyu0750
+qwertyu0751
+qwertyu0752
+qwertyu0753
+qwertyu0754
+qwertyu0755
+qwertyu0756
+qwertyu0757
+qwertyu0758
+qwertyu0759
+qwertyu0760
+qwertyu0761
+qwertyu0762
+qwertyu0763
+qwertyu0764
+qwertyu0765
+qwertyu0766
+qwertyu0767
+qwertyu0768
+qwertyu0769
+qwertyu0770
+qwertyu0771
+qwertyu0772
+qwertyu0773
+qwertyu0774
+qwertyu0775
+qwertyu0776
+qwertyu0777
+qwertyu0778
+qwertyu0779
+qwertyu0780
+qwertyu0781
+qwertyu0782
+qwertyu0783
+qwertyu0784
+qwertyu0785
+qwertyu0786
+qwertyu0787
+qwertyu0788
+qwertyu0789
+qwertyu0790
+qwertyu0791
+qwertyu0792
+qwertyu0793
+qwertyu0794
+qwertyu0795
+qwertyu0796
+qwertyu0797
+qwertyu0798
+qwertyu0799
+qwertyu0800
+qwertyu0801
+qwertyu0802
+qwertyu0803
+qwertyu0804
+qwertyu0805
+qwertyu0806
+qwertyu0807
+qwertyu0808
+qwertyu0809
+qwertyu0810
+qwertyu0811
+qwertyu0812
+qwertyu0813
+qwertyu0814
+qwertyu0815
+qwertyu0816
+qwertyu0817
+qwertyu0818
+qwertyu0819
+qwertyu0820
+qwertyu0821
+qwertyu0822
+qwertyu0823
+qwertyu0824
+qwertyu0825
+qwertyu0826
+qwertyu0827
+qwertyu0828
+qwertyu0829
+qwertyu0830
+qwertyu0831
+qwertyu0832
+qwertyu0833
+qwertyu0834
+qwertyu0835
+qwertyu0836
+qwertyu0837
+qwertyu0838
+qwertyu0839
+qwertyu0840
+qwertyu0841
+qwertyu0842
+qwertyu0843
+qwertyu0844
+qwertyu0845
+qwertyu0846
+qwertyu0847
+qwertyu0848
+qwertyu0849
+qwertyu0850
+qwertyu0851
+qwertyu0852
+qwertyu0853
+qwertyu0854
+qwertyu0855
+qwertyu0856
+qwertyu0857
+qwertyu0858
+qwertyu0859
+qwertyu0860
+qwertyu0861
+qwertyu0862
+qwertyu0863
+qwertyu0864
+qwertyu0865
+qwertyu0866
+qwertyu0867
+qwertyu0868
+qwertyu0869
+qwertyu0870
+qwertyu0871
+qwertyu0872
+qwertyu0873
+qwertyu0874
+qwertyu0875
+qwertyu0876
+qwertyu0877
+qwertyu0878
+qwertyu0879
+qwertyu0880
+qwertyu0881
+qwertyu0882
+qwertyu0883
+qwertyu0884
+qwertyu0885
+qwertyu0886
+qwertyu0887
+qwertyu0888
+qwertyu0889
+qwertyu0890
+qwertyu0891
+qwertyu0892
+qwertyu0893
+qwertyu0894
+qwertyu0895
+qwertyu0896
+qwertyu0897
+qwertyu0898
+qwertyu0899
+qwertyu0900
+qwertyu0901
+qwertyu0902
+qwertyu0903
+qwertyu0904
+qwertyu0905
+qwertyu0906
+qwertyu0907
+qwertyu0908
+qwertyu0909
+qwertyu0910
+qwertyu0911
+qwertyu0912
+qwertyu0913
+qwertyu0914
+qwertyu0915
+qwertyu0916
+qwertyu0917
+qwertyu0918
+qwertyu0919
+qwertyu0920
+qwertyu0921
+qwertyu0922
+qwertyu0923
+qwertyu0924
+qwertyu0925
+qwertyu0926
+qwertyu0927
+qwertyu0928
+qwertyu0929
+qwertyu0930
+qwertyu0931
+qwertyu0932
+qwertyu0933
+qwertyu0934
+qwertyu0935
+qwertyu0936
+qwertyu0937
+qwertyu0938
+qwertyu0939
+qwertyu0940
+qwertyu0941
+qwertyu0942
+qwertyu0943
+qwertyu0944
+qwertyu0945
+qwertyu0946
+qwertyu0947
+qwertyu0948
+qwertyu0949
+qwertyu0950
+qwertyu0951
+qwertyu0952
+qwertyu0953
+qwertyu0954
+qwertyu0955
+qwertyu0956
+qwertyu0957
+qwertyu0958
+qwertyu0959
+qwertyu0960
+qwertyu0961
+qwertyu0962
+qwertyu0963
+qwertyu0964
+qwertyu0965
+qwertyu0966
+qwertyu0967
+qwertyu0968
+qwertyu0969
+qwertyu0970
+qwertyu0971
+qwertyu0972
+qwertyu0973
+qwertyu0974
+qwertyu0975
+qwertyu0976
+qwertyu0977
+qwertyu0978
+qwertyu0979
+qwertyu0980
+qwertyu0981
+qwertyu0982
+qwertyu0983
+qwertyu0984
+qwertyu0985
+qwertyu0986
+qwertyu0987
+qwertyu0988
+qwertyu0989
+qwertyu0990
+qwertyu0991
+qwertyu0992
+qwertyu0993
+qwertyu0994
+qwertyu0995
+qwertyu0996
+qwertyu0997
+qwertyu0998
+qwertyu0999
+qwertyu1000
diff --git a/contrib/pg_trgm/data/trgm2.data b/contrib/pg_trgm/data/trgm2.data
new file mode 100644
index 0000000..664e079
--- /dev/null
+++ b/contrib/pg_trgm/data/trgm2.data
@@ -0,0 +1,696 @@
+Baikal
+Baikaluobbal
+Lake Baikal
+Baikalakko
+Baikal Business Centre
+Baikal Listvyanka Hotel
+Baikal Airfield
+Baikalovo
+Transbaikalia
+Baikal Mountains
+Baikal Hotel Moscow
+Zabaikalie
+Pribaikalskaya
+Baikal Plaza
+Rubaikale
+Tandobai Algad
+Daikalay
+Bakall
+Stubaital
+Neustift im Stubaital
+Anonyme Appartments Stubaital
+Barkaladja Pool
+Awabakal Nature Reserve
+Awabakal Field Studies Centre
+Barkala
+Bailallie
+Barkala Park
+Purba Kalaujan
+Nabakalas
+Barkal
+Baikanthapur
+Baikarjhuti
+Baika
+Baikari
+Bakalia Char
+Dakshin Bakalia
+Purba Kalmegha
+Efreytor-Bakalovo
+Baykalsko
+Baykal
+Baskaltsi
+Bakalite
+Bajkal
+Efrejtor Bakalovo
+Kampong Bakaladong
+Riacho do Sambaibal
+Sambaibal
+Barkalabava
+Zabaykal
+Bakalar Lake
+Kaikalahun Indian Reserve 25
+Tumba-Kalamba
+Kamba-Kalele
+Boyagbakala
+Bombakalo
+Batikalengbe
+Bakalukudu
+Bakalawa
+Bakala
+Matamba-Kalenge
+Kusu-Bakali
+Kambakala
+Bakali
+Abakalu
+Bonagbakala
+Bakalua
+Bikala Madila
+Bikala
+Bumba-Kaloki
+Tumba-Kalunga
+Kabankala
+Mambakala
+Tumba-Kalumba
+Kabakala
+Bikalabwa
+Bomba-Kalende
+Mwalaba-Kalamba
+Matamba-Kalenga
+Bumba-Kalumba
+Bikalange
+Kabikala
+Mubikale
+Kanampumba-Kalawa
+Tshiabakale
+Bakaly
+Bakalongo
+Bakale
+Bakala Koupi
+Bambakala
+Bakalou
+Tsibakala
+Kimbakala
+Dabakalakoro
+Dabakala
+Bakalafoulou
+Ngao Bakala
+Mobaika
+Baimalou
+Xibaitaling
+Baikai
+Baikang
+Baitaling
+Baikan
+Baimaling Linchang
+Baimalong
+Baikanzui
+Baiyali
+Baimaling
+Baimalang Donggang
+Baikangshuoma
+Baitaliao
+Taikale
+Babainale
+Bailale
+Baibale
+Baiwale
+Baikangnei
+Baitali
+Xiabaikan
+Bailalong
+Baimaluo
+Baikacun
+Baisala
+Bailalin
+Baimala
+Baidalong
+Dabaika
+Caikalong
+Cuobaikacun
+Baikadangcun
+Baimalin
+Subaika
+Gabakkale
+Barkallou
+Embatkala
+Bodega Tabaibal
+Golba Kalo
+Haikala
+Kaikale
+Waikaloulevu
+Waikalou Creek
+Waikalou
+Ndelaikalou
+Ndelaikalokalo
+Bay of Backaland
+Bankali
+Ker Samba Kalla
+Demba Kali
+Bakalarr
+Baipal
+Kalibakalako
+Dalabakala
+Bikal
+Sembaikan
+Praikalogu
+Tanjung Ompaikalio
+Bonebabakal
+Tanjung Batikala
+Pulau Bakalanpauno
+Teluk Bakalan
+Bakaltua Bank
+Bakalrejo
+Bakalan
+Sungai Bakaladiyan
+Bakal
+Buku Baikole
+Pulau Baika
+Tanjung Bakalinga
+Pulau Bakalan
+Desa Bakalan
+Kebakkalang
+Ngambakalang
+Mota Sabakal
+Bakalan Lor
+Babakalo
+Buyu Rapanbakalai
+Kalimundubakalan
+Bakalpokok
+Bakaldukuh
+Tanabakal
+Tanjung Aikaluin
+Desa Bakalrejo
+Bakalan Kidul
+Desa Kebakalan
+Kebakalan
+Bakalan Kulon
+Gunung Bakalan
+Kalibakal
+Bakaljaya
+Trobakal
+Bakalan Wetan
+Desa Bakal
+Alue Bakkala
+Uruk Bakal
+Bakalbuah
+Kwala Bakala
+Bakal Lama
+Bakal Julu
+Bakal Batu
+Moncong Baika
+Sampangbakalan
+Bakalam
+Desa Bakalankrapyak
+Lebakkalapa Tonggoh
+Trembakal
+Bakalan Tengah
+Kali Bakalan
+Desa Cemengbakalan
+Desa Bakalanpule
+Gunung Bakal
+Desa Tambakkalisogo
+Tambakkalisogo
+Desa Bakalanrayung
+Salu Bakalaeng
+Bakalaeng
+Danau Bakalan
+Selat Bakalan
+Selat Bakalanpauno
+Laikalanda
+Bakalinga
+Tanjung Mbakalang
+Desa Bakalankrajan
+Bakalan Dua
+Kali Purbakala
+Desa Bakalanwringinpitu
+Tukad Kubakal
+Praikalangga
+Banjar Kubakal
+Eat Bakal
+Sungai Bakala
+Kombakalada
+Sori Rabakalo
+Kahambikalela
+Baikarara
+Baikapaka
+Tukad Bakalan
+Teluk Haludubakal
+Yabakalewa
+Praikalumbang
+Waikalowo
+Praikalubu
+Loko Praikalubu
+Ramuk Ombakalada
+Praikalebung
+Praikaleka
+Andabakal
+Praikalau
+Praikalokat
+Praikalimbung
+Bambakalo
+Leubakkalian
+Pematang Baitalimbangan
+Lebakalil
+Gereba Kaler
+Krajan Bakalan
+Bakalan Barat
+Muarabakal
+Umbulan Maharobakal
+Bakaldalam
+Talang Bakal
+Pematang Bakalpanang
+Baidaloen
+Jatibakal
+Tubu Bakalekuk
+Dola Peimambakal
+Bakalang
+Teluk Bakalang
+Salu Baidale
+Bakalerek
+Ile Bakalibu
+Parbakalan
+Praikalembu
+Palindi Laikali
+Praikalu
+Sori Labakalate
+Air Bakal-kecil
+Sungaikalung
+Sungaikalong
+Pematang Bakalpanjang
+Payabakal
+Waikala
+Sungaikali
+Sungai Pebakalan
+Parit Membakal
+Bakalpakebo
+Baikat Abu Jaraban
+Maikalganj
+Maikala Range
+Bakalha
+Baitalpur
+Baikanthpur
+Baihal
+Barkala Reserved Forest
+Babaipalli
+Kaikalapettai
+Kambainallur
+Bakkalale
+Kaikalui
+Baijalpur
+Nehalla Bankalah Reserved Forest
+Barkala Rao
+Barkali
+Baidal
+Barkaleh
+Darreh Pumba Kal
+Bahkalleh
+Wibakale
+Gaikali
+Gagaba Kalo
+Barkalare
+Bakkalmal
+Gora Bakalyadyr
+Rodnik Bakalybulak
+Urochishche Bakaly
+Sopka Bakaly
+Gory Bakaly
+Bugor Arba-Kalgan
+Ozero Baykal
+Kolodets Tabakkalgan
+Walangivattu Vaikal
+Vattevaikal Anicut
+Vaikali Tevar Kulam
+Vaikalitevan Kulam
+Vaikaladichchenai
+Uchchodaikallu
+Sellapattu Vaikal
+Savata Vaikal
+Puttadivali Vaikal
+Palukadu Vaikal
+Mulaikallu Kulam
+Koraikallimadu
+Koraikalapu Kulam
+Karaiyamullivaikal
+Karaivaikal Kulam
+Kanawali Vaikal
+Habakkala
+Chalam Vaikal Aru
+Ambakala Wewa
+Alaikallupoddakulam
+Alaikallupodda Alankulam
+Akamadi Vaikal
+Alaikalluppodda Kulam
+Vaikaliththevakulam
+Baikole
+Sidi Mohammed el Bakali
+Sidi Mohammed Bakkal
+Sidi Bakal
+Oulad el Bakkal
+Zaouia Oulad Bakal
+Azib el Bakkali
+Tombakala
+Malaikaly
+Ambadikala
+Bakalica
+Bakalnica
+Abankala
+Kombakala
+Bawkalut
+Bakaleko
+Bawkalut Chaung
+Baukala
+Cerro Bainaltzin
+Sungai Bakal
+Bukit Ubaibalih
+Kampong Sombakal
+Kampung Lebai Ali
+Batikal
+Bakalalan Airport
+Maikali
+Bakalum
+Bakalambani
+Abakaliki
+Tsaunin Maikalaji
+Baikaha
+Llano Limbaika
+Barkald
+Barkald stasjon
+Barkaleitet
+Barkaldfossen
+Barkaldvola
+Bakkalegskardet
+Baikajavri
+Barkalden
+Bakkalia
+Siljabaika
+Aikaluokta
+Blombakkali
+Bavkalasis
+Baikajohka
+Bakkalykkja
+Bakalauri
+Bakalauri1
+Bakalauri2
+Bakalauri3
+Bakalauri4
+Bakalauri5
+Bakalauri6
+Bakalauri7
+Bakalauri8
+Bakalauri9
+Bakalsen
+Baiyaldi
+Naikala
+Baikanda
+Barkalne
+Bakalipur
+Bakaldum
+Raikal
+Baikatte
+Maikal
+Bakalbhar
+Waikalabubu Bay
+Baikai Island
+Abikal
+Boikalakalawa Bay
+Maikal River
+Bakalao Asibi Point
+Bankal
+Bakalod Island
+Bakalao Point
+Bakalan River
+Bakal Dos
+Bakal Uno
+Daang Bakal
+Bankal School
+Bakal Tres
+Kabankalan City Public Plaza
+Ranra Tabai Algad
+Bairkal Jabal
+Bairkal Dhora
+Bairkal
+Zaibai Algad
+Gulba Kalle
+Ragha Bakalzai
+Dabbarkal Sar
+Tabai Algad
+Haikalzai
+Wuchobai Algad
+Jabba Kalai
+Goth Soba Kaloi
+Baikar Tsarai
+Dudgaikal
+Baixale Kamar
+Zebai Algad
+Bakal Khel
+Goth Haikal
+Haikal
+Jaba Kalle
+Bakalovina
+Salabaikasy
+Guba Kalita
+Guba Kalgalaksha
+Guba Kaldo
+Bakalovo
+Baykalovo
+Baskalino
+Sopka Barkaleptskaya
+Bakalovskaya Ferma
+Bakalinskiy Rayon
+Sovkhoz Bakalinskiy
+Bakalinskiy
+Bakaldy
+Bakaldinskoye
+Urochishche Bakaldikha
+Zabaykalovskiy
+Barkalova
+Barkalovka
+Gora Barkalova
+Gora Barkalyu
+Bikalamakhi
+Stantsiya Bakal
+Baykalovskiy Rayon
+Baykalovskiy
+Baykalovsk
+Bakalda
+Boloto Malyy Baykal
+Boloto Baykal
+Zabaykalka
+Stantsiya Baykal
+Baykalo-Amurskaya Zheleznaya Doroga
+Kolkhoz Krasnyy Baykal
+Zaliv Baykal
+Bakalino
+Ovrag Bakalda
+Bakaldovshchina
+Prud Novyy Baykal
+Bakaleyka
+Bakalka
+Bakaly TV Mast
+Urochishche Bakalovo
+Kambaika
+Maloye Baykalovo
+Bakalinskiy Leskhoz
+Bikalikha
+Kordon Barkalo
+Sanatoriy Baykal
+Port Baykal
+Baykalikha
+Polevoy Stan Baykal
+Bakalovka
+Ramada Makkah Shubaika
+Mount Tohebakala
+Tambakale Island
+Mbanitambaika Island
+Mbakalaka Island
+Kumbakale
+Kaikaloka
+Kelesaikal
+Nasb Gabakallah
+Jabal Barkal
+Jabal Abakallah
+Al Barkali
+Shabakal Abbass
+Mabaikuli
+Bambakalema
+Bambakalia
+Baiwala
+Babakalia
+Baikama
+Bankalol
+Kundebakali
+Yumbaikamadu
+Tabakali
+Daba Kalharereh
+Barkale
+Bakalshile
+Bakaloolay
+Buur Bakaley
+Bakaley
+Buur Bakale
+Bakalaale
+Jabal Mobakali
+Khor Bakallii
+Korombaital
+Ambakali
+Ba Kaliin
+Mbay Bakala
+Tagobikala
+Fayzabadkala
+Aghbai Allazy
+Aghbai Alikagar
+Gora Fayzabadkala
+Daraikalot
+Aghbai Alakisirak
+Beikala
+Foho Berbakalau
+Mota Caicabaisala
+Sungai Utabailale
+Urochishche Bakalarnyn-Ayasy
+Urochishche Batkali
+Khrebet Batkali
+Ras Barkallah
+Babakale
+Fabrikalar
+Bakalukalu Shan
+Bakalukalu
+Laikala
+Waikalakaka
+Columbus Bakalar Municipal Airport
+Bakalar Library
+Bakkala Cemetery
+Clifton T Barkalow Elementary School
+Barkalow Hollow
+Kailuapuhi Waikalua Homesteads
+Kawaikalia Gulch
+Waikalae
+Waikaloa Stream
+Waikalua-Loko Fish Pond
+Halekou Waikaluakai Homesteads
+East Waikalua
+Omar Haikal Islamic Academy
+Bakalar Air Force Base (historical)
+Koshbakaly
+Bagkalen
+Gora Baikara
+Mfumbaika
+Mbakalungu
+Chumbaika
+Ntombankala School
+Bakalabwa Pans
+Khobai al Janhra
+Holiday Inn Dubai Al Barsha
+Novotel Dubai Al Barsha
+Doubletree Res.Dubai-Al Barsha
+Doubletree By Hilton Hotel and Apartments Dubai Al Barsha
+Doubletree By Hilton Dubai Al Barsha Hotel and Res
+Park Inn By Radisson Dubai Al Barsha
+Ramee Rose Hotel Dubai Al Barsha
+Aparthotel Adagio Premium Dubai Al Barsha
+Ataikala
+Selman Marrakech
+Riad Ain Marrakech
+Taj Palace Marrakech
+Delano Marrakech
+Pullman Marrakech Palmeraie Resort And Spa
+Lalla Calipau Marrakech
+Hotel Fashion Marrakech
+Four Seasons Resort Marrakech
+Adama Resort Marrakech
+Pullman Marrakech Palmeraie Re
+Ramada Resort Marrakech Douar Al Hana
+Hotel Zahia Marrakech
+Hotel Marrakech Le Tichka
+Le Chems Marrakech
+Beachcomber Royal Palm Marrakech
+Residence Marrakech
+Riad Hermes Marrakech
+Riad La Lune De Marrakech
+Hotel Marrakech Le Sangho Privilege
+Tempoo Hotel Marrakech
+Ag Hotel & Spa Marrakech
+Palm Appart Club Marrakech
+Hotel Ibis Moussafir Marrakech Palmeraie
+Ibis Marrakech Gare Voyageurs
+Marrakech Ryads Parc And Spa
+Terra Mia Marrakech Riad
+Residence Dar Lamia Marrakech
+Pullman Marrakech Palmeraie Rs
+Moussaf Marrakech Centre Gare
+Tempoo Hotel Marrakech Adults Only
+Sahara Palace Marrakech
+Moroccan House Marrakech
+El Andalouss And Spa Marrakech
+Suite Novotel Marrakech Rs
+Dar Catalina Marrakech Hotel Non Refundable Room
+Marrakech Hotel
+Oued Tammarrakech
+Tammarrakech
+Cercle de Marrakech-Banlieue
+Marrakech-Tensift-Al Haouz
+Koudia Marrakech
+Hotel Tichka Salam Marrakech
+L'Atlas Marrakech
+Royal Mirage Deluxe Marrakech
+Golden Tulip Farah Marrakech
+Ryad Mogador Marrakech
+Coralia Club Marrakech Palmariva
+La Sultana Marrakech
+Marrakech-Medina
+Marrakech
+Museum of Marrakech
+Douar Marrakechiyinc
+Ibis Marrakech Centre Gare
+Golden Tulip Rawabi Marrakech
+Murano Resort Marrakech
+Marrakech Garden Hotel
+Pullman Marrakech Palmerai Resort & Spa
+The Pearl Marrakech
+Palais Calipau Marrakech
+Hostal Equity Point Marrakech
+Sofitel Marrakech Lounge And Spa
+Pullman Marrakech Hotel And Spa
+Sofitel Marrakech Palais Imperial
+Hotel Ibis Moussafir Marrakech Centre Gare
+Red Hotel Marrakech
+Riad Zenith Marrakech
+Ksar Catalina Marrakech Hotel
+Blue Sea Hotel Marrakech Ryads Parc & Spa
+Bluebay Marrakech
+Pullman Marrakech Palmeraie Resort & Spa Hotel
+Riad Litzy Marrakech
+Sultana Hotel & Spa Marrakech
+Albatros Club Marrakech
+Hotel Sangho Club Marrakech
+Suite Novotel Marrakech Hotel
+Riad Utopia Suites & Spa Marrakech
+Riad Fatinat Marrakech
+Riad Dar El Aila Marrakech
+Es Saadi And Casino De Marrakech
+Dar Catalina Marrakech Hotel
+Grace Marrakech
+Marrakesh Apartments
+Marrakesh Country Club
+Koudiat Lmerrakechiyine
+Sidi Mohammed el Marrakchi
+Marrakesh
+Marrakchien
+Marrakchia
+Marrakesh Menara Airport
+Marrakesh Hua Hin Resort & Spa
+Marrakesh Hua Hin Resort And Spa
+Marrakesh Resort And Spa (Pool Suite)
+Marrakesh Huahin Resort & Spa
+Ibis Moussafir Marrakesh Centre Gare Hotel
+Maerak-chi
+Dar Hammou Ben Merrakchi
+Lalla el Marakchia
+Khrebet Marrakh
+Sungai Maru Kechil
+Marrache
+Goth Marracha
+Maramech Hill
+Maramech Woods Nature Preserve
+Oued Karakech
+Samarra School
+Jangal-e Marakeh Sar
diff --git a/contrib/pg_trgm/expected/pg_strict_word_trgm.out b/contrib/pg_trgm/expected/pg_strict_word_trgm.out
new file mode 100644
index 0000000..1e1ee16
--- /dev/null
+++ b/contrib/pg_trgm/expected/pg_strict_word_trgm.out
@@ -0,0 +1,1027 @@
+DROP INDEX trgm_idx2;
+\copy test_trgm3 from 'data/trgm2.data'
+ERROR: relation "test_trgm3" does not exist
+-- reduce noise
+set extra_float_digits = 0;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.666667
+ Baykalovo | 0.545455
+ Baykalsko | 0.545455
+ Maloye Baykalovo | 0.545455
+ Baykalikha | 0.5
+ Baykalovsk | 0.5
+(17 rows)
+
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <<% t order by sml desc, t;
+ t | sml
+------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.75
+ Abankala | 0.583333
+ Kabakala | 0.583333
+(4 rows)
+
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where t %>> 'Baykal' order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.666667
+ Baykalovo | 0.545455
+ Baykalsko | 0.545455
+ Maloye Baykalovo | 0.545455
+ Baykalikha | 0.5
+ Baykalovsk | 0.5
+(17 rows)
+
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where t %>> 'Kabankala' order by sml desc, t;
+ t | sml
+------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.75
+ Abankala | 0.583333
+ Kabakala | 0.583333
+(4 rows)
+
+select t <->>> 'Alaikallupoddakulam', t from test_trgm2 order by t <->>> 'Alaikallupoddakulam' limit 7;
+ ?column? | t
+----------+--------------------------
+ 0 | Alaikallupoddakulam
+ 0.25 | Alaikallupodda Alankulam
+ 0.32 | Alaikalluppodda Kulam
+ 0.615385 | Mulaikallu Kulam
+ 0.724138 | Koraikalapu Kulam
+ 0.75 | Vaikaliththevakulam
+ 0.766667 | Karaivaikal Kulam
+(7 rows)
+
+create index trgm_idx2 on test_trgm2 using gist (t gist_trgm_ops);
+set enable_seqscan=off;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.666667
+ Baykalovo | 0.545455
+ Baykalsko | 0.545455
+ Maloye Baykalovo | 0.545455
+ Baykalikha | 0.5
+ Baykalovsk | 0.5
+(17 rows)
+
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <<% t order by sml desc, t;
+ t | sml
+------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.75
+ Abankala | 0.583333
+ Kabakala | 0.583333
+(4 rows)
+
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where t %>> 'Baykal' order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.666667
+ Baykalovo | 0.545455
+ Baykalsko | 0.545455
+ Maloye Baykalovo | 0.545455
+ Baykalikha | 0.5
+ Baykalovsk | 0.5
+(17 rows)
+
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where t %>> 'Kabankala' order by sml desc, t;
+ t | sml
+------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.75
+ Abankala | 0.583333
+ Kabakala | 0.583333
+(4 rows)
+
+explain (costs off)
+select t <->>> 'Alaikallupoddakulam', t from test_trgm2 order by t <->>> 'Alaikallupoddakulam' limit 7;
+ QUERY PLAN
+---------------------------------------------------------
+ Limit
+ -> Index Scan using trgm_idx2 on test_trgm2
+ Order By: (t <->>> 'Alaikallupoddakulam'::text)
+(3 rows)
+
+select t <->>> 'Alaikallupoddakulam', t from test_trgm2 order by t <->>> 'Alaikallupoddakulam' limit 7;
+ ?column? | t
+----------+--------------------------
+ 0 | Alaikallupoddakulam
+ 0.25 | Alaikallupodda Alankulam
+ 0.32 | Alaikalluppodda Kulam
+ 0.615385 | Mulaikallu Kulam
+ 0.724138 | Koraikalapu Kulam
+ 0.75 | Vaikaliththevakulam
+ 0.766667 | Karaivaikal Kulam
+(7 rows)
+
+drop index trgm_idx2;
+create index trgm_idx2 on test_trgm2 using gin (t gin_trgm_ops);
+set enable_seqscan=off;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.666667
+ Baykalovo | 0.545455
+ Baykalsko | 0.545455
+ Maloye Baykalovo | 0.545455
+ Baykalikha | 0.5
+ Baykalovsk | 0.5
+(17 rows)
+
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <<% t order by sml desc, t;
+ t | sml
+------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.75
+ Abankala | 0.583333
+ Kabakala | 0.583333
+(4 rows)
+
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where t %>> 'Baykal' order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.666667
+ Baykalovo | 0.545455
+ Baykalsko | 0.545455
+ Maloye Baykalovo | 0.545455
+ Baykalikha | 0.5
+ Baykalovsk | 0.5
+(17 rows)
+
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where t %>> 'Kabankala' order by sml desc, t;
+ t | sml
+------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.75
+ Abankala | 0.583333
+ Kabakala | 0.583333
+(4 rows)
+
+set "pg_trgm.strict_word_similarity_threshold" to 0.4;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.666667
+ Baykalovo | 0.545455
+ Baykalsko | 0.545455
+ Maloye Baykalovo | 0.545455
+ Baykalikha | 0.5
+ Baykalovsk | 0.5
+ Zabaykal | 0.454545
+ Air Bakal-kecil | 0.444444
+ Bakal | 0.444444
+ Bakal Batu | 0.444444
+ Bakal Dos | 0.444444
+ Bakal Julu | 0.444444
+ Bakal Khel | 0.444444
+ Bakal Lama | 0.444444
+ Bakal Tres | 0.444444
+ Bakal Uno | 0.444444
+ Daang Bakal | 0.444444
+ Desa Bakal | 0.444444
+ Eat Bakal | 0.444444
+ Gunung Bakal | 0.444444
+ Sidi Bakal | 0.444444
+ Stantsiya Bakal | 0.444444
+ Sungai Bakal | 0.444444
+ Talang Bakal | 0.444444
+ Uruk Bakal | 0.444444
+ Zaouia Oulad Bakal | 0.444444
+ Baykalovskiy | 0.428571
+ Baykalovskiy Rayon | 0.428571
+ Baikal | 0.4
+ Baikal Airfield | 0.4
+ Baikal Business Centre | 0.4
+ Baikal Hotel Moscow | 0.4
+ Baikal Listvyanka Hotel | 0.4
+ Baikal Mountains | 0.4
+ Baikal Plaza | 0.4
+ Bajkal | 0.4
+ Bankal | 0.4
+ Bankal School | 0.4
+ Barkal | 0.4
+ Jabal Barkal | 0.4
+ Lake Baikal | 0.4
+ Oulad el Bakkal | 0.4
+ Sidi Mohammed Bakkal | 0.4
+(54 rows)
+
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <<% t order by sml desc, t;
+ t | sml
+------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.75
+ Abankala | 0.583333
+ Kabakala | 0.583333
+ Kabikala | 0.461538
+(5 rows)
+
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where t %>> 'Baykal' order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.666667
+ Baykalovo | 0.545455
+ Baykalsko | 0.545455
+ Maloye Baykalovo | 0.545455
+ Baykalikha | 0.5
+ Baykalovsk | 0.5
+ Zabaykal | 0.454545
+ Air Bakal-kecil | 0.444444
+ Bakal | 0.444444
+ Bakal Batu | 0.444444
+ Bakal Dos | 0.444444
+ Bakal Julu | 0.444444
+ Bakal Khel | 0.444444
+ Bakal Lama | 0.444444
+ Bakal Tres | 0.444444
+ Bakal Uno | 0.444444
+ Daang Bakal | 0.444444
+ Desa Bakal | 0.444444
+ Eat Bakal | 0.444444
+ Gunung Bakal | 0.444444
+ Sidi Bakal | 0.444444
+ Stantsiya Bakal | 0.444444
+ Sungai Bakal | 0.444444
+ Talang Bakal | 0.444444
+ Uruk Bakal | 0.444444
+ Zaouia Oulad Bakal | 0.444444
+ Baykalovskiy | 0.428571
+ Baykalovskiy Rayon | 0.428571
+ Baikal | 0.4
+ Baikal Airfield | 0.4
+ Baikal Business Centre | 0.4
+ Baikal Hotel Moscow | 0.4
+ Baikal Listvyanka Hotel | 0.4
+ Baikal Mountains | 0.4
+ Baikal Plaza | 0.4
+ Bajkal | 0.4
+ Bankal | 0.4
+ Bankal School | 0.4
+ Barkal | 0.4
+ Jabal Barkal | 0.4
+ Lake Baikal | 0.4
+ Oulad el Bakkal | 0.4
+ Sidi Mohammed Bakkal | 0.4
+(54 rows)
+
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where t %>> 'Kabankala' order by sml desc, t;
+ t | sml
+------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.75
+ Abankala | 0.583333
+ Kabakala | 0.583333
+ Kabikala | 0.461538
+(5 rows)
+
+set "pg_trgm.strict_word_similarity_threshold" to 0.2;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
+ t | sml
+-----------------------------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.666667
+ Baykalovo | 0.545455
+ Baykalsko | 0.545455
+ Maloye Baykalovo | 0.545455
+ Baykalikha | 0.5
+ Baykalovsk | 0.5
+ Zabaykal | 0.454545
+ Air Bakal-kecil | 0.444444
+ Bakal | 0.444444
+ Bakal Batu | 0.444444
+ Bakal Dos | 0.444444
+ Bakal Julu | 0.444444
+ Bakal Khel | 0.444444
+ Bakal Lama | 0.444444
+ Bakal Tres | 0.444444
+ Bakal Uno | 0.444444
+ Daang Bakal | 0.444444
+ Desa Bakal | 0.444444
+ Eat Bakal | 0.444444
+ Gunung Bakal | 0.444444
+ Sidi Bakal | 0.444444
+ Stantsiya Bakal | 0.444444
+ Sungai Bakal | 0.444444
+ Talang Bakal | 0.444444
+ Uruk Bakal | 0.444444
+ Zaouia Oulad Bakal | 0.444444
+ Baykalovskiy | 0.428571
+ Baykalovskiy Rayon | 0.428571
+ Baikal | 0.4
+ Baikal Airfield | 0.4
+ Baikal Business Centre | 0.4
+ Baikal Hotel Moscow | 0.4
+ Baikal Listvyanka Hotel | 0.4
+ Baikal Mountains | 0.4
+ Baikal Plaza | 0.4
+ Bajkal | 0.4
+ Bankal | 0.4
+ Bankal School | 0.4
+ Barkal | 0.4
+ Jabal Barkal | 0.4
+ Lake Baikal | 0.4
+ Oulad el Bakkal | 0.4
+ Sidi Mohammed Bakkal | 0.4
+ Bay of Backaland | 0.375
+ Boikalakalawa Bay | 0.375
+ Waikalabubu Bay | 0.375
+ Bairkal | 0.363636
+ Bairkal Dhora | 0.363636
+ Bairkal Jabal | 0.363636
+ Batikal | 0.363636
+ Bakaleyka | 0.307692
+ Bakkalmal | 0.307692
+ Bikal | 0.3
+ Al Barkali | 0.285714
+ Zabaykalka | 0.285714
+ Baidal | 0.272727
+ Baihal | 0.272727
+ Baipal | 0.272727
+ Bakala | 0.272727
+ Bakala Koupi | 0.272727
+ Bakale | 0.272727
+ Bakali | 0.272727
+ Bakall | 0.272727
+ Bakaly | 0.272727
+ Bakaly TV Mast | 0.272727
+ Buur Bakale | 0.272727
+ Gory Bakaly | 0.272727
+ Kusu-Bakali | 0.272727
+ Kwala Bakala | 0.272727
+ Mbay Bakala | 0.272727
+ Ngao Bakala | 0.272727
+ Sidi Mohammed el Bakali | 0.272727
+ Sopka Bakaly | 0.272727
+ Sungai Bakala | 0.272727
+ Urochishche Bakaly | 0.272727
+ Alue Bakkala | 0.25
+ Azib el Bakkali | 0.25
+ Ba Kaliin | 0.25
+ Baikaluobbal | 0.25
+ Bakalam | 0.25
+ Bakalan | 0.25
+ Bakalan Barat | 0.25
+ Bakalan Dua | 0.25
+ Bakalan Kidul | 0.25
+ Bakalan Kulon | 0.25
+ Bakalan Lor | 0.25
+ Bakalan River | 0.25
+ Bakalan Tengah | 0.25
+ Bakalan Wetan | 0.25
+ Bakalao Asibi Point | 0.25
+ Bakalao Point | 0.25
+ Bakalar Air Force Base (historical) | 0.25
+ Bakalar Lake | 0.25
+ Bakalar Library | 0.25
+ Bakalda | 0.25
+ Bakaldy | 0.25
+ Bakaley | 0.25
+ Bakalha | 0.25
+ Bakalia Char | 0.25
+ Bakalka | 0.25
+ Bakalod Island | 0.25
+ Bakalou | 0.25
+ Bakalua | 0.25
+ Bakalum | 0.25
+ Bakkala Cemetery | 0.25
+ Bankali | 0.25
+ Barkala | 0.25
+ Barkala Park | 0.25
+ Barkala Rao | 0.25
+ Barkala Reserved Forest | 0.25
+ Barkald | 0.25
+ Barkald stasjon | 0.25
+ Barkale | 0.25
+ Barkali | 0.25
+ Baukala | 0.25
+ Buur Bakaley | 0.25
+ Columbus Bakalar Municipal Airport | 0.25
+ Dakshin Bakalia | 0.25
+ Danau Bakalan | 0.25
+ Desa Bakalan | 0.25
+ Gunung Bakalan | 0.25
+ Kali Bakalan | 0.25
+ Khrebet Batkali | 0.25
+ Kordon Barkalo | 0.25
+ Krajan Bakalan | 0.25
+ Ovrag Bakalda | 0.25
+ Pulau Bakalan | 0.25
+ Selat Bakalan | 0.25
+ Teluk Bakalan | 0.25
+ Tukad Bakalan | 0.25
+ Urochishche Batkali | 0.25
+ Babakale | 0.230769
+ Babakalo | 0.230769
+ Bagkalen | 0.230769
+ Bakalalan Airport | 0.230769
+ Bakalang | 0.230769
+ Bakalarr | 0.230769
+ Bakalawa | 0.230769
+ Bakaldum | 0.230769
+ Bakaleko | 0.230769
+ Bakalica | 0.230769
+ Bakalino | 0.230769
+ Bakalite | 0.230769
+ Bakalovo | 0.230769
+ Bakalsen | 0.230769
+ Bakaltua Bank | 0.230769
+ Bakalukalu | 0.230769
+ Bakalukalu Shan | 0.230769
+ Bakkalia | 0.230769
+ Bankalol | 0.230769
+ Barkaleh | 0.230769
+ Barkalne | 0.230769
+ Barkalow Hollow | 0.230769
+ Bawkalut | 0.230769
+ Bawkalut Chaung | 0.230769
+ Clifton T Barkalow Elementary School | 0.230769
+ Efrejtor Bakalovo | 0.230769
+ Efreytor-Bakalovo | 0.230769
+ Gora Barkalyu | 0.230769
+ Ile Bakalibu | 0.230769
+ Khor Bakallii | 0.230769
+ Nehalla Bankalah Reserved Forest | 0.230769
+ Ragha Bakalzai | 0.230769
+ Tanjung Batikala | 0.230769
+ Teluk Bakalang | 0.230769
+ Urochishche Bakalovo | 0.230769
+ Banjar Kubakal | 0.222222
+ Darreh Pumba Kal | 0.222222
+ Zabaykalovskiy | 0.222222
+ Aparthotel Adagio Premium Dubai Al Barsha | 0.214286
+ Babakalia | 0.214286
+ Bahkalleh | 0.214286
+ Baikalovo | 0.214286
+ Bakalaale | 0.214286
+ Bakalabwa Pans | 0.214286
+ Bakalaeng | 0.214286
+ Bakalauri | 0.214286
+ Bakalbhar | 0.214286
+ Bakalbuah | 0.214286
+ Bakalerek | 0.214286
+ Bakalinga | 0.214286
+ Bakalipur | 0.214286
+ Bakaljaya | 0.214286
+ Bakalnica | 0.214286
+ Bakalongo | 0.214286
+ Bakalovka | 0.214286
+ Bakalrejo | 0.214286
+ Bakkalale | 0.214286
+ Bambakala | 0.214286
+ Bambakalo | 0.214286
+ Barkalare | 0.214286
+ Barkalden | 0.214286
+ Barkallou | 0.214286
+ Barkalova | 0.214286
+ Baskalino | 0.214286
+ Baskaltsi | 0.214286
+ Desa Bakalrejo | 0.214286
+ Doubletree By Hilton Dubai Al Barsha Hotel and Res | 0.214286
+ Doubletree By Hilton Hotel and Apartments Dubai Al Barsha | 0.214286
+ Doubletree Res.Dubai-Al Barsha | 0.214286
+ Gora Barkalova | 0.214286
+ Holiday Inn Dubai Al Barsha | 0.214286
+ Novotel Dubai Al Barsha | 0.214286
+ Park Inn By Radisson Dubai Al Barsha | 0.214286
+ Ramee Rose Hotel Dubai Al Barsha | 0.214286
+ Ras Barkallah | 0.214286
+ Salu Bakalaeng | 0.214286
+ Tanjung Bakalinga | 0.214286
+ Tubu Bakalekuk | 0.214286
+ Baikalakko | 0.2
+ Bakalauri1 | 0.2
+ Bakalauri2 | 0.2
+ Bakalauri3 | 0.2
+ Bakalauri4 | 0.2
+ Bakalauri5 | 0.2
+ Bakalauri6 | 0.2
+ Bakalauri7 | 0.2
+ Bakalauri8 | 0.2
+ Bakalauri9 | 0.2
+ Bakaldalam | 0.2
+ Bakaldukuh | 0.2
+ Bakaloolay | 0.2
+ Bakalovina | 0.2
+ Bakalpokok | 0.2
+ Bakalshile | 0.2
+ Bakalukudu | 0.2
+ Bambakalia | 0.2
+ Barkaladja Pool | 0.2
+ Barkalovka | 0.2
+ Bavkalasis | 0.2
+ Gora Bakalyadyr | 0.2
+ Kampong Bakaladong | 0.2
+ Urochishche Bakalarnyn-Ayasy | 0.2
+ Urochishche Bakaldikha | 0.2
+(245 rows)
+
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <<% t order by sml desc, t;
+ t | sml
+----------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.75
+ Abankala | 0.583333
+ Kabakala | 0.583333
+ Kabikala | 0.461538
+ Ntombankala School | 0.375
+ Nehalla Bankalah Reserved Forest | 0.357143
+ Jabba Kalai | 0.333333
+ Kambakala | 0.333333
+ Ker Samba Kalla | 0.333333
+ Bankal | 0.307692
+ Bankal School | 0.307692
+ Kanampumba-Kalawa | 0.307692
+ Bankali | 0.285714
+ Mwalaba-Kalamba | 0.285714
+ Tumba-Kalamba | 0.285714
+ Darreh Pumba Kal | 0.272727
+ Bankalol | 0.266667
+ Dabakala | 0.266667
+ Purba Kalaujan | 0.266667
+ Kali Purbakala | 0.263158
+ Dalabakala | 0.25
+ Demba Kali | 0.25
+ Gagaba Kalo | 0.25
+ Golba Kalo | 0.25
+ Habakkala | 0.25
+ Kali Bakalan | 0.25
+ Kimbakala | 0.25
+ Kombakala | 0.25
+ Jaba Kalle | 0.235294
+ Kaikalahun Indian Reserve 25 | 0.235294
+ Kwala Bakala | 0.235294
+ Gereba Kaler | 0.230769
+ Goth Soba Kaloi | 0.230769
+ Guba Kaldo | 0.230769
+ Gulba Kalle | 0.230769
+ Guba Kalgalaksha | 0.222222
+ Kalibakalako | 0.222222
+ Ba Kaliin | 0.214286
+ Bakala | 0.214286
+ Bakala Koupi | 0.214286
+ Bikala | 0.214286
+ Bikala Madila | 0.214286
+ Bugor Arba-Kalgan | 0.214286
+ Bumba-Kaloki | 0.214286
+ Guba Kalita | 0.214286
+ Kamba-Kalele | 0.214286
+ Mbay Bakala | 0.214286
+ Ngao Bakala | 0.214286
+ Sungai Bakala | 0.214286
+ Fayzabadkala | 0.210526
+ Gora Fayzabadkala | 0.210526
+ Alue Bakkala | 0.2
+ Bakkala Cemetery | 0.2
+ Barkala | 0.2
+ Barkala Park | 0.2
+ Barkala Rao | 0.2
+ Barkala Reserved Forest | 0.2
+ Baukala | 0.2
+ Beikala | 0.2
+ Bomba-Kalende | 0.2
+ Bumba-Kalumba | 0.2
+ Haikala | 0.2
+ Kahambikalela | 0.2
+ Kaikalapettai | 0.2
+ Kaikale | 0.2
+ Laikala | 0.2
+ Maikala Range | 0.2
+ Matamba-Kalenga | 0.2
+ Matamba-Kalenge | 0.2
+ Naikala | 0.2
+ Tumba-Kalumba | 0.2
+ Tumba-Kalunga | 0.2
+ Waikala | 0.2
+(74 rows)
+
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where t %>> 'Baykal' order by sml desc, t;
+ t | sml
+-----------------------------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.666667
+ Baykalovo | 0.545455
+ Baykalsko | 0.545455
+ Maloye Baykalovo | 0.545455
+ Baykalikha | 0.5
+ Baykalovsk | 0.5
+ Zabaykal | 0.454545
+ Air Bakal-kecil | 0.444444
+ Bakal | 0.444444
+ Bakal Batu | 0.444444
+ Bakal Dos | 0.444444
+ Bakal Julu | 0.444444
+ Bakal Khel | 0.444444
+ Bakal Lama | 0.444444
+ Bakal Tres | 0.444444
+ Bakal Uno | 0.444444
+ Daang Bakal | 0.444444
+ Desa Bakal | 0.444444
+ Eat Bakal | 0.444444
+ Gunung Bakal | 0.444444
+ Sidi Bakal | 0.444444
+ Stantsiya Bakal | 0.444444
+ Sungai Bakal | 0.444444
+ Talang Bakal | 0.444444
+ Uruk Bakal | 0.444444
+ Zaouia Oulad Bakal | 0.444444
+ Baykalovskiy | 0.428571
+ Baykalovskiy Rayon | 0.428571
+ Baikal | 0.4
+ Baikal Airfield | 0.4
+ Baikal Business Centre | 0.4
+ Baikal Hotel Moscow | 0.4
+ Baikal Listvyanka Hotel | 0.4
+ Baikal Mountains | 0.4
+ Baikal Plaza | 0.4
+ Bajkal | 0.4
+ Bankal | 0.4
+ Bankal School | 0.4
+ Barkal | 0.4
+ Jabal Barkal | 0.4
+ Lake Baikal | 0.4
+ Oulad el Bakkal | 0.4
+ Sidi Mohammed Bakkal | 0.4
+ Bay of Backaland | 0.375
+ Boikalakalawa Bay | 0.375
+ Waikalabubu Bay | 0.375
+ Bairkal | 0.363636
+ Bairkal Dhora | 0.363636
+ Bairkal Jabal | 0.363636
+ Batikal | 0.363636
+ Bakaleyka | 0.307692
+ Bakkalmal | 0.307692
+ Bikal | 0.3
+ Al Barkali | 0.285714
+ Zabaykalka | 0.285714
+ Baidal | 0.272727
+ Baihal | 0.272727
+ Baipal | 0.272727
+ Bakala | 0.272727
+ Bakala Koupi | 0.272727
+ Bakale | 0.272727
+ Bakali | 0.272727
+ Bakall | 0.272727
+ Bakaly | 0.272727
+ Bakaly TV Mast | 0.272727
+ Buur Bakale | 0.272727
+ Gory Bakaly | 0.272727
+ Kusu-Bakali | 0.272727
+ Kwala Bakala | 0.272727
+ Mbay Bakala | 0.272727
+ Ngao Bakala | 0.272727
+ Sidi Mohammed el Bakali | 0.272727
+ Sopka Bakaly | 0.272727
+ Sungai Bakala | 0.272727
+ Urochishche Bakaly | 0.272727
+ Alue Bakkala | 0.25
+ Azib el Bakkali | 0.25
+ Ba Kaliin | 0.25
+ Baikaluobbal | 0.25
+ Bakalam | 0.25
+ Bakalan | 0.25
+ Bakalan Barat | 0.25
+ Bakalan Dua | 0.25
+ Bakalan Kidul | 0.25
+ Bakalan Kulon | 0.25
+ Bakalan Lor | 0.25
+ Bakalan River | 0.25
+ Bakalan Tengah | 0.25
+ Bakalan Wetan | 0.25
+ Bakalao Asibi Point | 0.25
+ Bakalao Point | 0.25
+ Bakalar Air Force Base (historical) | 0.25
+ Bakalar Lake | 0.25
+ Bakalar Library | 0.25
+ Bakalda | 0.25
+ Bakaldy | 0.25
+ Bakaley | 0.25
+ Bakalha | 0.25
+ Bakalia Char | 0.25
+ Bakalka | 0.25
+ Bakalod Island | 0.25
+ Bakalou | 0.25
+ Bakalua | 0.25
+ Bakalum | 0.25
+ Bakkala Cemetery | 0.25
+ Bankali | 0.25
+ Barkala | 0.25
+ Barkala Park | 0.25
+ Barkala Rao | 0.25
+ Barkala Reserved Forest | 0.25
+ Barkald | 0.25
+ Barkald stasjon | 0.25
+ Barkale | 0.25
+ Barkali | 0.25
+ Baukala | 0.25
+ Buur Bakaley | 0.25
+ Columbus Bakalar Municipal Airport | 0.25
+ Dakshin Bakalia | 0.25
+ Danau Bakalan | 0.25
+ Desa Bakalan | 0.25
+ Gunung Bakalan | 0.25
+ Kali Bakalan | 0.25
+ Khrebet Batkali | 0.25
+ Kordon Barkalo | 0.25
+ Krajan Bakalan | 0.25
+ Ovrag Bakalda | 0.25
+ Pulau Bakalan | 0.25
+ Selat Bakalan | 0.25
+ Teluk Bakalan | 0.25
+ Tukad Bakalan | 0.25
+ Urochishche Batkali | 0.25
+ Babakale | 0.230769
+ Babakalo | 0.230769
+ Bagkalen | 0.230769
+ Bakalalan Airport | 0.230769
+ Bakalang | 0.230769
+ Bakalarr | 0.230769
+ Bakalawa | 0.230769
+ Bakaldum | 0.230769
+ Bakaleko | 0.230769
+ Bakalica | 0.230769
+ Bakalino | 0.230769
+ Bakalite | 0.230769
+ Bakalovo | 0.230769
+ Bakalsen | 0.230769
+ Bakaltua Bank | 0.230769
+ Bakalukalu | 0.230769
+ Bakalukalu Shan | 0.230769
+ Bakkalia | 0.230769
+ Bankalol | 0.230769
+ Barkaleh | 0.230769
+ Barkalne | 0.230769
+ Barkalow Hollow | 0.230769
+ Bawkalut | 0.230769
+ Bawkalut Chaung | 0.230769
+ Clifton T Barkalow Elementary School | 0.230769
+ Efrejtor Bakalovo | 0.230769
+ Efreytor-Bakalovo | 0.230769
+ Gora Barkalyu | 0.230769
+ Ile Bakalibu | 0.230769
+ Khor Bakallii | 0.230769
+ Nehalla Bankalah Reserved Forest | 0.230769
+ Ragha Bakalzai | 0.230769
+ Tanjung Batikala | 0.230769
+ Teluk Bakalang | 0.230769
+ Urochishche Bakalovo | 0.230769
+ Banjar Kubakal | 0.222222
+ Darreh Pumba Kal | 0.222222
+ Zabaykalovskiy | 0.222222
+ Aparthotel Adagio Premium Dubai Al Barsha | 0.214286
+ Babakalia | 0.214286
+ Bahkalleh | 0.214286
+ Baikalovo | 0.214286
+ Bakalaale | 0.214286
+ Bakalabwa Pans | 0.214286
+ Bakalaeng | 0.214286
+ Bakalauri | 0.214286
+ Bakalbhar | 0.214286
+ Bakalbuah | 0.214286
+ Bakalerek | 0.214286
+ Bakalinga | 0.214286
+ Bakalipur | 0.214286
+ Bakaljaya | 0.214286
+ Bakalnica | 0.214286
+ Bakalongo | 0.214286
+ Bakalovka | 0.214286
+ Bakalrejo | 0.214286
+ Bakkalale | 0.214286
+ Bambakala | 0.214286
+ Bambakalo | 0.214286
+ Barkalare | 0.214286
+ Barkalden | 0.214286
+ Barkallou | 0.214286
+ Barkalova | 0.214286
+ Baskalino | 0.214286
+ Baskaltsi | 0.214286
+ Desa Bakalrejo | 0.214286
+ Doubletree By Hilton Dubai Al Barsha Hotel and Res | 0.214286
+ Doubletree By Hilton Hotel and Apartments Dubai Al Barsha | 0.214286
+ Doubletree Res.Dubai-Al Barsha | 0.214286
+ Gora Barkalova | 0.214286
+ Holiday Inn Dubai Al Barsha | 0.214286
+ Novotel Dubai Al Barsha | 0.214286
+ Park Inn By Radisson Dubai Al Barsha | 0.214286
+ Ramee Rose Hotel Dubai Al Barsha | 0.214286
+ Ras Barkallah | 0.214286
+ Salu Bakalaeng | 0.214286
+ Tanjung Bakalinga | 0.214286
+ Tubu Bakalekuk | 0.214286
+ Baikalakko | 0.2
+ Bakalauri1 | 0.2
+ Bakalauri2 | 0.2
+ Bakalauri3 | 0.2
+ Bakalauri4 | 0.2
+ Bakalauri5 | 0.2
+ Bakalauri6 | 0.2
+ Bakalauri7 | 0.2
+ Bakalauri8 | 0.2
+ Bakalauri9 | 0.2
+ Bakaldalam | 0.2
+ Bakaldukuh | 0.2
+ Bakaloolay | 0.2
+ Bakalovina | 0.2
+ Bakalpokok | 0.2
+ Bakalshile | 0.2
+ Bakalukudu | 0.2
+ Bambakalia | 0.2
+ Barkaladja Pool | 0.2
+ Barkalovka | 0.2
+ Bavkalasis | 0.2
+ Gora Bakalyadyr | 0.2
+ Kampong Bakaladong | 0.2
+ Urochishche Bakalarnyn-Ayasy | 0.2
+ Urochishche Bakaldikha | 0.2
+(245 rows)
+
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where t %>> 'Kabankala' order by sml desc, t;
+ t | sml
+----------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.75
+ Abankala | 0.583333
+ Kabakala | 0.583333
+ Kabikala | 0.461538
+ Ntombankala School | 0.375
+ Nehalla Bankalah Reserved Forest | 0.357143
+ Jabba Kalai | 0.333333
+ Kambakala | 0.333333
+ Ker Samba Kalla | 0.333333
+ Bankal | 0.307692
+ Bankal School | 0.307692
+ Kanampumba-Kalawa | 0.307692
+ Bankali | 0.285714
+ Mwalaba-Kalamba | 0.285714
+ Tumba-Kalamba | 0.285714
+ Darreh Pumba Kal | 0.272727
+ Bankalol | 0.266667
+ Dabakala | 0.266667
+ Purba Kalaujan | 0.266667
+ Kali Purbakala | 0.263158
+ Dalabakala | 0.25
+ Demba Kali | 0.25
+ Gagaba Kalo | 0.25
+ Golba Kalo | 0.25
+ Habakkala | 0.25
+ Kali Bakalan | 0.25
+ Kimbakala | 0.25
+ Kombakala | 0.25
+ Jaba Kalle | 0.235294
+ Kaikalahun Indian Reserve 25 | 0.235294
+ Kwala Bakala | 0.235294
+ Gereba Kaler | 0.230769
+ Goth Soba Kaloi | 0.230769
+ Guba Kaldo | 0.230769
+ Gulba Kalle | 0.230769
+ Guba Kalgalaksha | 0.222222
+ Kalibakalako | 0.222222
+ Ba Kaliin | 0.214286
+ Bakala | 0.214286
+ Bakala Koupi | 0.214286
+ Bikala | 0.214286
+ Bikala Madila | 0.214286
+ Bugor Arba-Kalgan | 0.214286
+ Bumba-Kaloki | 0.214286
+ Guba Kalita | 0.214286
+ Kamba-Kalele | 0.214286
+ Mbay Bakala | 0.214286
+ Ngao Bakala | 0.214286
+ Sungai Bakala | 0.214286
+ Fayzabadkala | 0.210526
+ Gora Fayzabadkala | 0.210526
+ Alue Bakkala | 0.2
+ Bakkala Cemetery | 0.2
+ Barkala | 0.2
+ Barkala Park | 0.2
+ Barkala Rao | 0.2
+ Barkala Reserved Forest | 0.2
+ Baukala | 0.2
+ Beikala | 0.2
+ Bomba-Kalende | 0.2
+ Bumba-Kalumba | 0.2
+ Haikala | 0.2
+ Kahambikalela | 0.2
+ Kaikalapettai | 0.2
+ Kaikale | 0.2
+ Laikala | 0.2
+ Maikala Range | 0.2
+ Matamba-Kalenga | 0.2
+ Matamba-Kalenge | 0.2
+ Naikala | 0.2
+ Tumba-Kalumba | 0.2
+ Tumba-Kalunga | 0.2
+ Waikala | 0.2
+(74 rows)
+
diff --git a/contrib/pg_trgm/expected/pg_trgm.out b/contrib/pg_trgm/expected/pg_trgm.out
new file mode 100644
index 0000000..ce4bf1d
--- /dev/null
+++ b/contrib/pg_trgm/expected/pg_trgm.out
@@ -0,0 +1,5404 @@
+CREATE EXTENSION pg_trgm;
+-- Check whether any of our opclasses fail amvalidate
+SELECT amname, opcname
+FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod
+WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid);
+ amname | opcname
+--------+---------
+(0 rows)
+
+--backslash is used in tests below, installcheck will fail if
+--standard_conforming_string is off
+set standard_conforming_strings=on;
+-- reduce noise
+set extra_float_digits = 0;
+select show_trgm('');
+ show_trgm
+-----------
+ {}
+(1 row)
+
+select show_trgm('(*&^$@%@');
+ show_trgm
+-----------
+ {}
+(1 row)
+
+select show_trgm('a b c');
+ show_trgm
+---------------------------------------
+ {" a"," b"," c"," a "," b "," c "}
+(1 row)
+
+select show_trgm(' a b c ');
+ show_trgm
+---------------------------------------
+ {" a"," b"," c"," a "," b "," c "}
+(1 row)
+
+select show_trgm('aA bB cC');
+ show_trgm
+---------------------------------------------------------
+ {" a"," b"," c"," aa"," bb"," cc","aa ","bb ","cc "}
+(1 row)
+
+select show_trgm(' aA bB cC ');
+ show_trgm
+---------------------------------------------------------
+ {" a"," b"," c"," aa"," bb"," cc","aa ","bb ","cc "}
+(1 row)
+
+select show_trgm('a b C0*%^');
+ show_trgm
+---------------------------------------------
+ {" a"," b"," c"," a "," b "," c0","c0 "}
+(1 row)
+
+select similarity('wow','WOWa ');
+ similarity
+------------
+ 0.5
+(1 row)
+
+select similarity('wow',' WOW ');
+ similarity
+------------
+ 1
+(1 row)
+
+select similarity('---', '####---');
+ similarity
+------------
+ 0
+(1 row)
+
+CREATE TABLE test_trgm(t text COLLATE "C");
+\copy test_trgm from 'data/trgm.data'
+select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 1
+ qwertyu0980 | 0.714286
+ qwertyu0981 | 0.714286
+ qwertyu0982 | 0.714286
+ qwertyu0983 | 0.714286
+ qwertyu0984 | 0.714286
+ qwertyu0985 | 0.714286
+ qwertyu0986 | 0.714286
+ qwertyu0987 | 0.714286
+ qwertyu0989 | 0.714286
+ qwertyu0088 | 0.6
+ qwertyu0098 | 0.6
+ qwertyu0188 | 0.6
+ qwertyu0288 | 0.6
+ qwertyu0388 | 0.6
+ qwertyu0488 | 0.6
+ qwertyu0588 | 0.6
+ qwertyu0688 | 0.6
+ qwertyu0788 | 0.6
+ qwertyu0888 | 0.6
+ qwertyu0900 | 0.6
+ qwertyu0901 | 0.6
+ qwertyu0902 | 0.6
+ qwertyu0903 | 0.6
+ qwertyu0904 | 0.6
+ qwertyu0905 | 0.6
+ qwertyu0906 | 0.6
+ qwertyu0907 | 0.6
+ qwertyu0908 | 0.6
+ qwertyu0909 | 0.6
+ qwertyu0910 | 0.6
+ qwertyu0911 | 0.6
+ qwertyu0912 | 0.6
+ qwertyu0913 | 0.6
+ qwertyu0914 | 0.6
+ qwertyu0915 | 0.6
+ qwertyu0916 | 0.6
+ qwertyu0917 | 0.6
+ qwertyu0918 | 0.6
+ qwertyu0919 | 0.6
+ qwertyu0920 | 0.6
+ qwertyu0921 | 0.6
+ qwertyu0922 | 0.6
+ qwertyu0923 | 0.6
+ qwertyu0924 | 0.6
+ qwertyu0925 | 0.6
+ qwertyu0926 | 0.6
+ qwertyu0927 | 0.6
+ qwertyu0928 | 0.6
+ qwertyu0929 | 0.6
+ qwertyu0930 | 0.6
+ qwertyu0931 | 0.6
+ qwertyu0932 | 0.6
+ qwertyu0933 | 0.6
+ qwertyu0934 | 0.6
+ qwertyu0935 | 0.6
+ qwertyu0936 | 0.6
+ qwertyu0937 | 0.6
+ qwertyu0938 | 0.6
+ qwertyu0939 | 0.6
+ qwertyu0940 | 0.6
+ qwertyu0941 | 0.6
+ qwertyu0942 | 0.6
+ qwertyu0943 | 0.6
+ qwertyu0944 | 0.6
+ qwertyu0945 | 0.6
+ qwertyu0946 | 0.6
+ qwertyu0947 | 0.6
+ qwertyu0948 | 0.6
+ qwertyu0949 | 0.6
+ qwertyu0950 | 0.6
+ qwertyu0951 | 0.6
+ qwertyu0952 | 0.6
+ qwertyu0953 | 0.6
+ qwertyu0954 | 0.6
+ qwertyu0955 | 0.6
+ qwertyu0956 | 0.6
+ qwertyu0957 | 0.6
+ qwertyu0958 | 0.6
+ qwertyu0959 | 0.6
+ qwertyu0960 | 0.6
+ qwertyu0961 | 0.6
+ qwertyu0962 | 0.6
+ qwertyu0963 | 0.6
+ qwertyu0964 | 0.6
+ qwertyu0965 | 0.6
+ qwertyu0966 | 0.6
+ qwertyu0967 | 0.6
+ qwertyu0968 | 0.6
+ qwertyu0969 | 0.6
+ qwertyu0970 | 0.6
+ qwertyu0971 | 0.6
+ qwertyu0972 | 0.6
+ qwertyu0973 | 0.6
+ qwertyu0974 | 0.6
+ qwertyu0975 | 0.6
+ qwertyu0976 | 0.6
+ qwertyu0977 | 0.6
+ qwertyu0978 | 0.6
+ qwertyu0979 | 0.6
+ qwertyu0990 | 0.6
+ qwertyu0991 | 0.6
+ qwertyu0992 | 0.6
+ qwertyu0993 | 0.6
+ qwertyu0994 | 0.6
+ qwertyu0995 | 0.6
+ qwertyu0996 | 0.6
+ qwertyu0997 | 0.6
+ qwertyu0998 | 0.6
+ qwertyu0999 | 0.6
+ qwertyu0001 | 0.5
+ qwertyu0002 | 0.5
+ qwertyu0003 | 0.5
+ qwertyu0004 | 0.5
+ qwertyu0005 | 0.5
+ qwertyu0006 | 0.5
+ qwertyu0007 | 0.5
+ qwertyu0008 | 0.5
+ qwertyu0009 | 0.5
+ qwertyu0010 | 0.5
+ qwertyu0011 | 0.5
+ qwertyu0012 | 0.5
+ qwertyu0013 | 0.5
+ qwertyu0014 | 0.5
+ qwertyu0015 | 0.5
+ qwertyu0016 | 0.5
+ qwertyu0017 | 0.5
+ qwertyu0018 | 0.5
+ qwertyu0019 | 0.5
+ qwertyu0020 | 0.5
+ qwertyu0021 | 0.5
+ qwertyu0022 | 0.5
+ qwertyu0023 | 0.5
+ qwertyu0024 | 0.5
+ qwertyu0025 | 0.5
+ qwertyu0026 | 0.5
+ qwertyu0027 | 0.5
+ qwertyu0028 | 0.5
+ qwertyu0029 | 0.5
+ qwertyu0030 | 0.5
+ qwertyu0031 | 0.5
+ qwertyu0032 | 0.5
+ qwertyu0033 | 0.5
+ qwertyu0034 | 0.5
+ qwertyu0035 | 0.5
+ qwertyu0036 | 0.5
+ qwertyu0037 | 0.5
+ qwertyu0038 | 0.5
+ qwertyu0039 | 0.5
+ qwertyu0040 | 0.5
+ qwertyu0041 | 0.5
+ qwertyu0042 | 0.5
+ qwertyu0043 | 0.5
+ qwertyu0044 | 0.5
+ qwertyu0045 | 0.5
+ qwertyu0046 | 0.5
+ qwertyu0047 | 0.5
+ qwertyu0048 | 0.5
+ qwertyu0049 | 0.5
+ qwertyu0050 | 0.5
+ qwertyu0051 | 0.5
+ qwertyu0052 | 0.5
+ qwertyu0053 | 0.5
+ qwertyu0054 | 0.5
+ qwertyu0055 | 0.5
+ qwertyu0056 | 0.5
+ qwertyu0057 | 0.5
+ qwertyu0058 | 0.5
+ qwertyu0059 | 0.5
+ qwertyu0060 | 0.5
+ qwertyu0061 | 0.5
+ qwertyu0062 | 0.5
+ qwertyu0063 | 0.5
+ qwertyu0064 | 0.5
+ qwertyu0065 | 0.5
+ qwertyu0066 | 0.5
+ qwertyu0067 | 0.5
+ qwertyu0068 | 0.5
+ qwertyu0069 | 0.5
+ qwertyu0070 | 0.5
+ qwertyu0071 | 0.5
+ qwertyu0072 | 0.5
+ qwertyu0073 | 0.5
+ qwertyu0074 | 0.5
+ qwertyu0075 | 0.5
+ qwertyu0076 | 0.5
+ qwertyu0077 | 0.5
+ qwertyu0078 | 0.5
+ qwertyu0079 | 0.5
+ qwertyu0080 | 0.5
+ qwertyu0081 | 0.5
+ qwertyu0082 | 0.5
+ qwertyu0083 | 0.5
+ qwertyu0084 | 0.5
+ qwertyu0085 | 0.5
+ qwertyu0086 | 0.5
+ qwertyu0087 | 0.5
+ qwertyu0089 | 0.5
+ qwertyu0090 | 0.5
+ qwertyu0091 | 0.5
+ qwertyu0092 | 0.5
+ qwertyu0093 | 0.5
+ qwertyu0094 | 0.5
+ qwertyu0095 | 0.5
+ qwertyu0096 | 0.5
+ qwertyu0097 | 0.5
+ qwertyu0099 | 0.5
+ qwertyu0100 | 0.5
+ qwertyu0101 | 0.5
+ qwertyu0102 | 0.5
+ qwertyu0103 | 0.5
+ qwertyu0104 | 0.5
+ qwertyu0105 | 0.5
+ qwertyu0106 | 0.5
+ qwertyu0107 | 0.5
+ qwertyu0108 | 0.5
+ qwertyu0109 | 0.5
+ qwertyu0110 | 0.5
+ qwertyu0111 | 0.5
+ qwertyu0112 | 0.5
+ qwertyu0113 | 0.5
+ qwertyu0114 | 0.5
+ qwertyu0115 | 0.5
+ qwertyu0116 | 0.5
+ qwertyu0117 | 0.5
+ qwertyu0118 | 0.5
+ qwertyu0119 | 0.5
+ qwertyu0120 | 0.5
+ qwertyu0121 | 0.5
+ qwertyu0122 | 0.5
+ qwertyu0123 | 0.5
+ qwertyu0124 | 0.5
+ qwertyu0125 | 0.5
+ qwertyu0126 | 0.5
+ qwertyu0127 | 0.5
+ qwertyu0128 | 0.5
+ qwertyu0129 | 0.5
+ qwertyu0130 | 0.5
+ qwertyu0131 | 0.5
+ qwertyu0132 | 0.5
+ qwertyu0133 | 0.5
+ qwertyu0134 | 0.5
+ qwertyu0135 | 0.5
+ qwertyu0136 | 0.5
+ qwertyu0137 | 0.5
+ qwertyu0138 | 0.5
+ qwertyu0139 | 0.5
+ qwertyu0140 | 0.5
+ qwertyu0141 | 0.5
+ qwertyu0142 | 0.5
+ qwertyu0143 | 0.5
+ qwertyu0144 | 0.5
+ qwertyu0145 | 0.5
+ qwertyu0146 | 0.5
+ qwertyu0147 | 0.5
+ qwertyu0148 | 0.5
+ qwertyu0149 | 0.5
+ qwertyu0150 | 0.5
+ qwertyu0151 | 0.5
+ qwertyu0152 | 0.5
+ qwertyu0153 | 0.5
+ qwertyu0154 | 0.5
+ qwertyu0155 | 0.5
+ qwertyu0156 | 0.5
+ qwertyu0157 | 0.5
+ qwertyu0158 | 0.5
+ qwertyu0159 | 0.5
+ qwertyu0160 | 0.5
+ qwertyu0161 | 0.5
+ qwertyu0162 | 0.5
+ qwertyu0163 | 0.5
+ qwertyu0164 | 0.5
+ qwertyu0165 | 0.5
+ qwertyu0166 | 0.5
+ qwertyu0167 | 0.5
+ qwertyu0168 | 0.5
+ qwertyu0169 | 0.5
+ qwertyu0170 | 0.5
+ qwertyu0171 | 0.5
+ qwertyu0172 | 0.5
+ qwertyu0173 | 0.5
+ qwertyu0174 | 0.5
+ qwertyu0175 | 0.5
+ qwertyu0176 | 0.5
+ qwertyu0177 | 0.5
+ qwertyu0178 | 0.5
+ qwertyu0179 | 0.5
+ qwertyu0180 | 0.5
+ qwertyu0181 | 0.5
+ qwertyu0182 | 0.5
+ qwertyu0183 | 0.5
+ qwertyu0184 | 0.5
+ qwertyu0185 | 0.5
+ qwertyu0186 | 0.5
+ qwertyu0187 | 0.5
+ qwertyu0189 | 0.5
+ qwertyu0190 | 0.5
+ qwertyu0191 | 0.5
+ qwertyu0192 | 0.5
+ qwertyu0193 | 0.5
+ qwertyu0194 | 0.5
+ qwertyu0195 | 0.5
+ qwertyu0196 | 0.5
+ qwertyu0197 | 0.5
+ qwertyu0198 | 0.5
+ qwertyu0199 | 0.5
+ qwertyu0200 | 0.5
+ qwertyu0201 | 0.5
+ qwertyu0202 | 0.5
+ qwertyu0203 | 0.5
+ qwertyu0204 | 0.5
+ qwertyu0205 | 0.5
+ qwertyu0206 | 0.5
+ qwertyu0207 | 0.5
+ qwertyu0208 | 0.5
+ qwertyu0209 | 0.5
+ qwertyu0210 | 0.5
+ qwertyu0211 | 0.5
+ qwertyu0212 | 0.5
+ qwertyu0213 | 0.5
+ qwertyu0214 | 0.5
+ qwertyu0215 | 0.5
+ qwertyu0216 | 0.5
+ qwertyu0217 | 0.5
+ qwertyu0218 | 0.5
+ qwertyu0219 | 0.5
+ qwertyu0220 | 0.5
+ qwertyu0221 | 0.5
+ qwertyu0222 | 0.5
+ qwertyu0223 | 0.5
+ qwertyu0224 | 0.5
+ qwertyu0225 | 0.5
+ qwertyu0226 | 0.5
+ qwertyu0227 | 0.5
+ qwertyu0228 | 0.5
+ qwertyu0229 | 0.5
+ qwertyu0230 | 0.5
+ qwertyu0231 | 0.5
+ qwertyu0232 | 0.5
+ qwertyu0233 | 0.5
+ qwertyu0234 | 0.5
+ qwertyu0235 | 0.5
+ qwertyu0236 | 0.5
+ qwertyu0237 | 0.5
+ qwertyu0238 | 0.5
+ qwertyu0239 | 0.5
+ qwertyu0240 | 0.5
+ qwertyu0241 | 0.5
+ qwertyu0242 | 0.5
+ qwertyu0243 | 0.5
+ qwertyu0244 | 0.5
+ qwertyu0245 | 0.5
+ qwertyu0246 | 0.5
+ qwertyu0247 | 0.5
+ qwertyu0248 | 0.5
+ qwertyu0249 | 0.5
+ qwertyu0250 | 0.5
+ qwertyu0251 | 0.5
+ qwertyu0252 | 0.5
+ qwertyu0253 | 0.5
+ qwertyu0254 | 0.5
+ qwertyu0255 | 0.5
+ qwertyu0256 | 0.5
+ qwertyu0257 | 0.5
+ qwertyu0258 | 0.5
+ qwertyu0259 | 0.5
+ qwertyu0260 | 0.5
+ qwertyu0261 | 0.5
+ qwertyu0262 | 0.5
+ qwertyu0263 | 0.5
+ qwertyu0264 | 0.5
+ qwertyu0265 | 0.5
+ qwertyu0266 | 0.5
+ qwertyu0267 | 0.5
+ qwertyu0268 | 0.5
+ qwertyu0269 | 0.5
+ qwertyu0270 | 0.5
+ qwertyu0271 | 0.5
+ qwertyu0272 | 0.5
+ qwertyu0273 | 0.5
+ qwertyu0274 | 0.5
+ qwertyu0275 | 0.5
+ qwertyu0276 | 0.5
+ qwertyu0277 | 0.5
+ qwertyu0278 | 0.5
+ qwertyu0279 | 0.5
+ qwertyu0280 | 0.5
+ qwertyu0281 | 0.5
+ qwertyu0282 | 0.5
+ qwertyu0283 | 0.5
+ qwertyu0284 | 0.5
+ qwertyu0285 | 0.5
+ qwertyu0286 | 0.5
+ qwertyu0287 | 0.5
+ qwertyu0289 | 0.5
+ qwertyu0290 | 0.5
+ qwertyu0291 | 0.5
+ qwertyu0292 | 0.5
+ qwertyu0293 | 0.5
+ qwertyu0294 | 0.5
+ qwertyu0295 | 0.5
+ qwertyu0296 | 0.5
+ qwertyu0297 | 0.5
+ qwertyu0298 | 0.5
+ qwertyu0299 | 0.5
+ qwertyu0300 | 0.5
+ qwertyu0301 | 0.5
+ qwertyu0302 | 0.5
+ qwertyu0303 | 0.5
+ qwertyu0304 | 0.5
+ qwertyu0305 | 0.5
+ qwertyu0306 | 0.5
+ qwertyu0307 | 0.5
+ qwertyu0308 | 0.5
+ qwertyu0309 | 0.5
+ qwertyu0310 | 0.5
+ qwertyu0311 | 0.5
+ qwertyu0312 | 0.5
+ qwertyu0313 | 0.5
+ qwertyu0314 | 0.5
+ qwertyu0315 | 0.5
+ qwertyu0316 | 0.5
+ qwertyu0317 | 0.5
+ qwertyu0318 | 0.5
+ qwertyu0319 | 0.5
+ qwertyu0320 | 0.5
+ qwertyu0321 | 0.5
+ qwertyu0322 | 0.5
+ qwertyu0323 | 0.5
+ qwertyu0324 | 0.5
+ qwertyu0325 | 0.5
+ qwertyu0326 | 0.5
+ qwertyu0327 | 0.5
+ qwertyu0328 | 0.5
+ qwertyu0329 | 0.5
+ qwertyu0330 | 0.5
+ qwertyu0331 | 0.5
+ qwertyu0332 | 0.5
+ qwertyu0333 | 0.5
+ qwertyu0334 | 0.5
+ qwertyu0335 | 0.5
+ qwertyu0336 | 0.5
+ qwertyu0337 | 0.5
+ qwertyu0338 | 0.5
+ qwertyu0339 | 0.5
+ qwertyu0340 | 0.5
+ qwertyu0341 | 0.5
+ qwertyu0342 | 0.5
+ qwertyu0343 | 0.5
+ qwertyu0344 | 0.5
+ qwertyu0345 | 0.5
+ qwertyu0346 | 0.5
+ qwertyu0347 | 0.5
+ qwertyu0348 | 0.5
+ qwertyu0349 | 0.5
+ qwertyu0350 | 0.5
+ qwertyu0351 | 0.5
+ qwertyu0352 | 0.5
+ qwertyu0353 | 0.5
+ qwertyu0354 | 0.5
+ qwertyu0355 | 0.5
+ qwertyu0356 | 0.5
+ qwertyu0357 | 0.5
+ qwertyu0358 | 0.5
+ qwertyu0359 | 0.5
+ qwertyu0360 | 0.5
+ qwertyu0361 | 0.5
+ qwertyu0362 | 0.5
+ qwertyu0363 | 0.5
+ qwertyu0364 | 0.5
+ qwertyu0365 | 0.5
+ qwertyu0366 | 0.5
+ qwertyu0367 | 0.5
+ qwertyu0368 | 0.5
+ qwertyu0369 | 0.5
+ qwertyu0370 | 0.5
+ qwertyu0371 | 0.5
+ qwertyu0372 | 0.5
+ qwertyu0373 | 0.5
+ qwertyu0374 | 0.5
+ qwertyu0375 | 0.5
+ qwertyu0376 | 0.5
+ qwertyu0377 | 0.5
+ qwertyu0378 | 0.5
+ qwertyu0379 | 0.5
+ qwertyu0380 | 0.5
+ qwertyu0381 | 0.5
+ qwertyu0382 | 0.5
+ qwertyu0383 | 0.5
+ qwertyu0384 | 0.5
+ qwertyu0385 | 0.5
+ qwertyu0386 | 0.5
+ qwertyu0387 | 0.5
+ qwertyu0389 | 0.5
+ qwertyu0390 | 0.5
+ qwertyu0391 | 0.5
+ qwertyu0392 | 0.5
+ qwertyu0393 | 0.5
+ qwertyu0394 | 0.5
+ qwertyu0395 | 0.5
+ qwertyu0396 | 0.5
+ qwertyu0397 | 0.5
+ qwertyu0398 | 0.5
+ qwertyu0399 | 0.5
+ qwertyu0400 | 0.5
+ qwertyu0401 | 0.5
+ qwertyu0402 | 0.5
+ qwertyu0403 | 0.5
+ qwertyu0404 | 0.5
+ qwertyu0405 | 0.5
+ qwertyu0406 | 0.5
+ qwertyu0407 | 0.5
+ qwertyu0408 | 0.5
+ qwertyu0409 | 0.5
+ qwertyu0410 | 0.5
+ qwertyu0411 | 0.5
+ qwertyu0412 | 0.5
+ qwertyu0413 | 0.5
+ qwertyu0414 | 0.5
+ qwertyu0415 | 0.5
+ qwertyu0416 | 0.5
+ qwertyu0417 | 0.5
+ qwertyu0418 | 0.5
+ qwertyu0419 | 0.5
+ qwertyu0420 | 0.5
+ qwertyu0421 | 0.5
+ qwertyu0422 | 0.5
+ qwertyu0423 | 0.5
+ qwertyu0424 | 0.5
+ qwertyu0425 | 0.5
+ qwertyu0426 | 0.5
+ qwertyu0427 | 0.5
+ qwertyu0428 | 0.5
+ qwertyu0429 | 0.5
+ qwertyu0430 | 0.5
+ qwertyu0431 | 0.5
+ qwertyu0432 | 0.5
+ qwertyu0433 | 0.5
+ qwertyu0434 | 0.5
+ qwertyu0435 | 0.5
+ qwertyu0436 | 0.5
+ qwertyu0437 | 0.5
+ qwertyu0438 | 0.5
+ qwertyu0439 | 0.5
+ qwertyu0440 | 0.5
+ qwertyu0441 | 0.5
+ qwertyu0442 | 0.5
+ qwertyu0443 | 0.5
+ qwertyu0444 | 0.5
+ qwertyu0445 | 0.5
+ qwertyu0446 | 0.5
+ qwertyu0447 | 0.5
+ qwertyu0448 | 0.5
+ qwertyu0449 | 0.5
+ qwertyu0450 | 0.5
+ qwertyu0451 | 0.5
+ qwertyu0452 | 0.5
+ qwertyu0453 | 0.5
+ qwertyu0454 | 0.5
+ qwertyu0455 | 0.5
+ qwertyu0456 | 0.5
+ qwertyu0457 | 0.5
+ qwertyu0458 | 0.5
+ qwertyu0459 | 0.5
+ qwertyu0460 | 0.5
+ qwertyu0461 | 0.5
+ qwertyu0462 | 0.5
+ qwertyu0463 | 0.5
+ qwertyu0464 | 0.5
+ qwertyu0465 | 0.5
+ qwertyu0466 | 0.5
+ qwertyu0467 | 0.5
+ qwertyu0468 | 0.5
+ qwertyu0469 | 0.5
+ qwertyu0470 | 0.5
+ qwertyu0471 | 0.5
+ qwertyu0472 | 0.5
+ qwertyu0473 | 0.5
+ qwertyu0474 | 0.5
+ qwertyu0475 | 0.5
+ qwertyu0476 | 0.5
+ qwertyu0477 | 0.5
+ qwertyu0478 | 0.5
+ qwertyu0479 | 0.5
+ qwertyu0480 | 0.5
+ qwertyu0481 | 0.5
+ qwertyu0482 | 0.5
+ qwertyu0483 | 0.5
+ qwertyu0484 | 0.5
+ qwertyu0485 | 0.5
+ qwertyu0486 | 0.5
+ qwertyu0487 | 0.5
+ qwertyu0489 | 0.5
+ qwertyu0490 | 0.5
+ qwertyu0491 | 0.5
+ qwertyu0492 | 0.5
+ qwertyu0493 | 0.5
+ qwertyu0494 | 0.5
+ qwertyu0495 | 0.5
+ qwertyu0496 | 0.5
+ qwertyu0497 | 0.5
+ qwertyu0498 | 0.5
+ qwertyu0499 | 0.5
+ qwertyu0500 | 0.5
+ qwertyu0501 | 0.5
+ qwertyu0502 | 0.5
+ qwertyu0503 | 0.5
+ qwertyu0504 | 0.5
+ qwertyu0505 | 0.5
+ qwertyu0506 | 0.5
+ qwertyu0507 | 0.5
+ qwertyu0508 | 0.5
+ qwertyu0509 | 0.5
+ qwertyu0510 | 0.5
+ qwertyu0511 | 0.5
+ qwertyu0512 | 0.5
+ qwertyu0513 | 0.5
+ qwertyu0514 | 0.5
+ qwertyu0515 | 0.5
+ qwertyu0516 | 0.5
+ qwertyu0517 | 0.5
+ qwertyu0518 | 0.5
+ qwertyu0519 | 0.5
+ qwertyu0520 | 0.5
+ qwertyu0521 | 0.5
+ qwertyu0522 | 0.5
+ qwertyu0523 | 0.5
+ qwertyu0524 | 0.5
+ qwertyu0525 | 0.5
+ qwertyu0526 | 0.5
+ qwertyu0527 | 0.5
+ qwertyu0528 | 0.5
+ qwertyu0529 | 0.5
+ qwertyu0530 | 0.5
+ qwertyu0531 | 0.5
+ qwertyu0532 | 0.5
+ qwertyu0533 | 0.5
+ qwertyu0534 | 0.5
+ qwertyu0535 | 0.5
+ qwertyu0536 | 0.5
+ qwertyu0537 | 0.5
+ qwertyu0538 | 0.5
+ qwertyu0539 | 0.5
+ qwertyu0540 | 0.5
+ qwertyu0541 | 0.5
+ qwertyu0542 | 0.5
+ qwertyu0543 | 0.5
+ qwertyu0544 | 0.5
+ qwertyu0545 | 0.5
+ qwertyu0546 | 0.5
+ qwertyu0547 | 0.5
+ qwertyu0548 | 0.5
+ qwertyu0549 | 0.5
+ qwertyu0550 | 0.5
+ qwertyu0551 | 0.5
+ qwertyu0552 | 0.5
+ qwertyu0553 | 0.5
+ qwertyu0554 | 0.5
+ qwertyu0555 | 0.5
+ qwertyu0556 | 0.5
+ qwertyu0557 | 0.5
+ qwertyu0558 | 0.5
+ qwertyu0559 | 0.5
+ qwertyu0560 | 0.5
+ qwertyu0561 | 0.5
+ qwertyu0562 | 0.5
+ qwertyu0563 | 0.5
+ qwertyu0564 | 0.5
+ qwertyu0565 | 0.5
+ qwertyu0566 | 0.5
+ qwertyu0567 | 0.5
+ qwertyu0568 | 0.5
+ qwertyu0569 | 0.5
+ qwertyu0570 | 0.5
+ qwertyu0571 | 0.5
+ qwertyu0572 | 0.5
+ qwertyu0573 | 0.5
+ qwertyu0574 | 0.5
+ qwertyu0575 | 0.5
+ qwertyu0576 | 0.5
+ qwertyu0577 | 0.5
+ qwertyu0578 | 0.5
+ qwertyu0579 | 0.5
+ qwertyu0580 | 0.5
+ qwertyu0581 | 0.5
+ qwertyu0582 | 0.5
+ qwertyu0583 | 0.5
+ qwertyu0584 | 0.5
+ qwertyu0585 | 0.5
+ qwertyu0586 | 0.5
+ qwertyu0587 | 0.5
+ qwertyu0589 | 0.5
+ qwertyu0590 | 0.5
+ qwertyu0591 | 0.5
+ qwertyu0592 | 0.5
+ qwertyu0593 | 0.5
+ qwertyu0594 | 0.5
+ qwertyu0595 | 0.5
+ qwertyu0596 | 0.5
+ qwertyu0597 | 0.5
+ qwertyu0598 | 0.5
+ qwertyu0599 | 0.5
+ qwertyu0600 | 0.5
+ qwertyu0601 | 0.5
+ qwertyu0602 | 0.5
+ qwertyu0603 | 0.5
+ qwertyu0604 | 0.5
+ qwertyu0605 | 0.5
+ qwertyu0606 | 0.5
+ qwertyu0607 | 0.5
+ qwertyu0608 | 0.5
+ qwertyu0609 | 0.5
+ qwertyu0610 | 0.5
+ qwertyu0611 | 0.5
+ qwertyu0612 | 0.5
+ qwertyu0613 | 0.5
+ qwertyu0614 | 0.5
+ qwertyu0615 | 0.5
+ qwertyu0616 | 0.5
+ qwertyu0617 | 0.5
+ qwertyu0618 | 0.5
+ qwertyu0619 | 0.5
+ qwertyu0620 | 0.5
+ qwertyu0621 | 0.5
+ qwertyu0622 | 0.5
+ qwertyu0623 | 0.5
+ qwertyu0624 | 0.5
+ qwertyu0625 | 0.5
+ qwertyu0626 | 0.5
+ qwertyu0627 | 0.5
+ qwertyu0628 | 0.5
+ qwertyu0629 | 0.5
+ qwertyu0630 | 0.5
+ qwertyu0631 | 0.5
+ qwertyu0632 | 0.5
+ qwertyu0633 | 0.5
+ qwertyu0634 | 0.5
+ qwertyu0635 | 0.5
+ qwertyu0636 | 0.5
+ qwertyu0637 | 0.5
+ qwertyu0638 | 0.5
+ qwertyu0639 | 0.5
+ qwertyu0640 | 0.5
+ qwertyu0641 | 0.5
+ qwertyu0642 | 0.5
+ qwertyu0643 | 0.5
+ qwertyu0644 | 0.5
+ qwertyu0645 | 0.5
+ qwertyu0646 | 0.5
+ qwertyu0647 | 0.5
+ qwertyu0648 | 0.5
+ qwertyu0649 | 0.5
+ qwertyu0650 | 0.5
+ qwertyu0651 | 0.5
+ qwertyu0652 | 0.5
+ qwertyu0653 | 0.5
+ qwertyu0654 | 0.5
+ qwertyu0655 | 0.5
+ qwertyu0656 | 0.5
+ qwertyu0657 | 0.5
+ qwertyu0658 | 0.5
+ qwertyu0659 | 0.5
+ qwertyu0660 | 0.5
+ qwertyu0661 | 0.5
+ qwertyu0662 | 0.5
+ qwertyu0663 | 0.5
+ qwertyu0664 | 0.5
+ qwertyu0665 | 0.5
+ qwertyu0666 | 0.5
+ qwertyu0667 | 0.5
+ qwertyu0668 | 0.5
+ qwertyu0669 | 0.5
+ qwertyu0670 | 0.5
+ qwertyu0671 | 0.5
+ qwertyu0672 | 0.5
+ qwertyu0673 | 0.5
+ qwertyu0674 | 0.5
+ qwertyu0675 | 0.5
+ qwertyu0676 | 0.5
+ qwertyu0677 | 0.5
+ qwertyu0678 | 0.5
+ qwertyu0679 | 0.5
+ qwertyu0680 | 0.5
+ qwertyu0681 | 0.5
+ qwertyu0682 | 0.5
+ qwertyu0683 | 0.5
+ qwertyu0684 | 0.5
+ qwertyu0685 | 0.5
+ qwertyu0686 | 0.5
+ qwertyu0687 | 0.5
+ qwertyu0689 | 0.5
+ qwertyu0690 | 0.5
+ qwertyu0691 | 0.5
+ qwertyu0692 | 0.5
+ qwertyu0693 | 0.5
+ qwertyu0694 | 0.5
+ qwertyu0695 | 0.5
+ qwertyu0696 | 0.5
+ qwertyu0697 | 0.5
+ qwertyu0698 | 0.5
+ qwertyu0699 | 0.5
+ qwertyu0700 | 0.5
+ qwertyu0701 | 0.5
+ qwertyu0702 | 0.5
+ qwertyu0703 | 0.5
+ qwertyu0704 | 0.5
+ qwertyu0705 | 0.5
+ qwertyu0706 | 0.5
+ qwertyu0707 | 0.5
+ qwertyu0708 | 0.5
+ qwertyu0709 | 0.5
+ qwertyu0710 | 0.5
+ qwertyu0711 | 0.5
+ qwertyu0712 | 0.5
+ qwertyu0713 | 0.5
+ qwertyu0714 | 0.5
+ qwertyu0715 | 0.5
+ qwertyu0716 | 0.5
+ qwertyu0717 | 0.5
+ qwertyu0718 | 0.5
+ qwertyu0719 | 0.5
+ qwertyu0720 | 0.5
+ qwertyu0721 | 0.5
+ qwertyu0722 | 0.5
+ qwertyu0723 | 0.5
+ qwertyu0724 | 0.5
+ qwertyu0725 | 0.5
+ qwertyu0726 | 0.5
+ qwertyu0727 | 0.5
+ qwertyu0728 | 0.5
+ qwertyu0729 | 0.5
+ qwertyu0730 | 0.5
+ qwertyu0731 | 0.5
+ qwertyu0732 | 0.5
+ qwertyu0733 | 0.5
+ qwertyu0734 | 0.5
+ qwertyu0735 | 0.5
+ qwertyu0736 | 0.5
+ qwertyu0737 | 0.5
+ qwertyu0738 | 0.5
+ qwertyu0739 | 0.5
+ qwertyu0740 | 0.5
+ qwertyu0741 | 0.5
+ qwertyu0742 | 0.5
+ qwertyu0743 | 0.5
+ qwertyu0744 | 0.5
+ qwertyu0745 | 0.5
+ qwertyu0746 | 0.5
+ qwertyu0747 | 0.5
+ qwertyu0748 | 0.5
+ qwertyu0749 | 0.5
+ qwertyu0750 | 0.5
+ qwertyu0751 | 0.5
+ qwertyu0752 | 0.5
+ qwertyu0753 | 0.5
+ qwertyu0754 | 0.5
+ qwertyu0755 | 0.5
+ qwertyu0756 | 0.5
+ qwertyu0757 | 0.5
+ qwertyu0758 | 0.5
+ qwertyu0759 | 0.5
+ qwertyu0760 | 0.5
+ qwertyu0761 | 0.5
+ qwertyu0762 | 0.5
+ qwertyu0763 | 0.5
+ qwertyu0764 | 0.5
+ qwertyu0765 | 0.5
+ qwertyu0766 | 0.5
+ qwertyu0767 | 0.5
+ qwertyu0768 | 0.5
+ qwertyu0769 | 0.5
+ qwertyu0770 | 0.5
+ qwertyu0771 | 0.5
+ qwertyu0772 | 0.5
+ qwertyu0773 | 0.5
+ qwertyu0774 | 0.5
+ qwertyu0775 | 0.5
+ qwertyu0776 | 0.5
+ qwertyu0777 | 0.5
+ qwertyu0778 | 0.5
+ qwertyu0779 | 0.5
+ qwertyu0780 | 0.5
+ qwertyu0781 | 0.5
+ qwertyu0782 | 0.5
+ qwertyu0783 | 0.5
+ qwertyu0784 | 0.5
+ qwertyu0785 | 0.5
+ qwertyu0786 | 0.5
+ qwertyu0787 | 0.5
+ qwertyu0789 | 0.5
+ qwertyu0790 | 0.5
+ qwertyu0791 | 0.5
+ qwertyu0792 | 0.5
+ qwertyu0793 | 0.5
+ qwertyu0794 | 0.5
+ qwertyu0795 | 0.5
+ qwertyu0796 | 0.5
+ qwertyu0797 | 0.5
+ qwertyu0798 | 0.5
+ qwertyu0799 | 0.5
+ qwertyu0800 | 0.5
+ qwertyu0801 | 0.5
+ qwertyu0802 | 0.5
+ qwertyu0803 | 0.5
+ qwertyu0804 | 0.5
+ qwertyu0805 | 0.5
+ qwertyu0806 | 0.5
+ qwertyu0807 | 0.5
+ qwertyu0808 | 0.5
+ qwertyu0809 | 0.5
+ qwertyu0810 | 0.5
+ qwertyu0811 | 0.5
+ qwertyu0812 | 0.5
+ qwertyu0813 | 0.5
+ qwertyu0814 | 0.5
+ qwertyu0815 | 0.5
+ qwertyu0816 | 0.5
+ qwertyu0817 | 0.5
+ qwertyu0818 | 0.5
+ qwertyu0819 | 0.5
+ qwertyu0820 | 0.5
+ qwertyu0821 | 0.5
+ qwertyu0822 | 0.5
+ qwertyu0823 | 0.5
+ qwertyu0824 | 0.5
+ qwertyu0825 | 0.5
+ qwertyu0826 | 0.5
+ qwertyu0827 | 0.5
+ qwertyu0828 | 0.5
+ qwertyu0829 | 0.5
+ qwertyu0830 | 0.5
+ qwertyu0831 | 0.5
+ qwertyu0832 | 0.5
+ qwertyu0833 | 0.5
+ qwertyu0834 | 0.5
+ qwertyu0835 | 0.5
+ qwertyu0836 | 0.5
+ qwertyu0837 | 0.5
+ qwertyu0838 | 0.5
+ qwertyu0839 | 0.5
+ qwertyu0840 | 0.5
+ qwertyu0841 | 0.5
+ qwertyu0842 | 0.5
+ qwertyu0843 | 0.5
+ qwertyu0844 | 0.5
+ qwertyu0845 | 0.5
+ qwertyu0846 | 0.5
+ qwertyu0847 | 0.5
+ qwertyu0848 | 0.5
+ qwertyu0849 | 0.5
+ qwertyu0850 | 0.5
+ qwertyu0851 | 0.5
+ qwertyu0852 | 0.5
+ qwertyu0853 | 0.5
+ qwertyu0854 | 0.5
+ qwertyu0855 | 0.5
+ qwertyu0856 | 0.5
+ qwertyu0857 | 0.5
+ qwertyu0858 | 0.5
+ qwertyu0859 | 0.5
+ qwertyu0860 | 0.5
+ qwertyu0861 | 0.5
+ qwertyu0862 | 0.5
+ qwertyu0863 | 0.5
+ qwertyu0864 | 0.5
+ qwertyu0865 | 0.5
+ qwertyu0866 | 0.5
+ qwertyu0867 | 0.5
+ qwertyu0868 | 0.5
+ qwertyu0869 | 0.5
+ qwertyu0870 | 0.5
+ qwertyu0871 | 0.5
+ qwertyu0872 | 0.5
+ qwertyu0873 | 0.5
+ qwertyu0874 | 0.5
+ qwertyu0875 | 0.5
+ qwertyu0876 | 0.5
+ qwertyu0877 | 0.5
+ qwertyu0878 | 0.5
+ qwertyu0879 | 0.5
+ qwertyu0880 | 0.5
+ qwertyu0881 | 0.5
+ qwertyu0882 | 0.5
+ qwertyu0883 | 0.5
+ qwertyu0884 | 0.5
+ qwertyu0885 | 0.5
+ qwertyu0886 | 0.5
+ qwertyu0887 | 0.5
+ qwertyu0889 | 0.5
+ qwertyu0890 | 0.5
+ qwertyu0891 | 0.5
+ qwertyu0892 | 0.5
+ qwertyu0893 | 0.5
+ qwertyu0894 | 0.5
+ qwertyu0895 | 0.5
+ qwertyu0896 | 0.5
+ qwertyu0897 | 0.5
+ qwertyu0898 | 0.5
+ qwertyu0899 | 0.5
+ qwertyu1000 | 0.411765
+(1000 rows)
+
+select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 0.6
+ qwertyu0980 | 0.411765
+ qwertyu0981 | 0.411765
+ qwertyu0982 | 0.411765
+ qwertyu0983 | 0.411765
+ qwertyu0984 | 0.411765
+ qwertyu0985 | 0.411765
+ qwertyu0986 | 0.411765
+ qwertyu0987 | 0.411765
+ qwertyu0989 | 0.411765
+ qwertyu0088 | 0.333333
+ qwertyu0098 | 0.333333
+ qwertyu0188 | 0.333333
+ qwertyu0288 | 0.333333
+ qwertyu0388 | 0.333333
+ qwertyu0488 | 0.333333
+ qwertyu0588 | 0.333333
+ qwertyu0688 | 0.333333
+ qwertyu0788 | 0.333333
+ qwertyu0888 | 0.333333
+ qwertyu0900 | 0.333333
+ qwertyu0901 | 0.333333
+ qwertyu0902 | 0.333333
+ qwertyu0903 | 0.333333
+ qwertyu0904 | 0.333333
+ qwertyu0905 | 0.333333
+ qwertyu0906 | 0.333333
+ qwertyu0907 | 0.333333
+ qwertyu0908 | 0.333333
+ qwertyu0909 | 0.333333
+ qwertyu0910 | 0.333333
+ qwertyu0911 | 0.333333
+ qwertyu0912 | 0.333333
+ qwertyu0913 | 0.333333
+ qwertyu0914 | 0.333333
+ qwertyu0915 | 0.333333
+ qwertyu0916 | 0.333333
+ qwertyu0917 | 0.333333
+ qwertyu0918 | 0.333333
+ qwertyu0919 | 0.333333
+ qwertyu0920 | 0.333333
+ qwertyu0921 | 0.333333
+ qwertyu0922 | 0.333333
+ qwertyu0923 | 0.333333
+ qwertyu0924 | 0.333333
+ qwertyu0925 | 0.333333
+ qwertyu0926 | 0.333333
+ qwertyu0927 | 0.333333
+ qwertyu0928 | 0.333333
+ qwertyu0929 | 0.333333
+ qwertyu0930 | 0.333333
+ qwertyu0931 | 0.333333
+ qwertyu0932 | 0.333333
+ qwertyu0933 | 0.333333
+ qwertyu0934 | 0.333333
+ qwertyu0935 | 0.333333
+ qwertyu0936 | 0.333333
+ qwertyu0937 | 0.333333
+ qwertyu0938 | 0.333333
+ qwertyu0939 | 0.333333
+ qwertyu0940 | 0.333333
+ qwertyu0941 | 0.333333
+ qwertyu0942 | 0.333333
+ qwertyu0943 | 0.333333
+ qwertyu0944 | 0.333333
+ qwertyu0945 | 0.333333
+ qwertyu0946 | 0.333333
+ qwertyu0947 | 0.333333
+ qwertyu0948 | 0.333333
+ qwertyu0949 | 0.333333
+ qwertyu0950 | 0.333333
+ qwertyu0951 | 0.333333
+ qwertyu0952 | 0.333333
+ qwertyu0953 | 0.333333
+ qwertyu0954 | 0.333333
+ qwertyu0955 | 0.333333
+ qwertyu0956 | 0.333333
+ qwertyu0957 | 0.333333
+ qwertyu0958 | 0.333333
+ qwertyu0959 | 0.333333
+ qwertyu0960 | 0.333333
+ qwertyu0961 | 0.333333
+ qwertyu0962 | 0.333333
+ qwertyu0963 | 0.333333
+ qwertyu0964 | 0.333333
+ qwertyu0965 | 0.333333
+ qwertyu0966 | 0.333333
+ qwertyu0967 | 0.333333
+ qwertyu0968 | 0.333333
+ qwertyu0969 | 0.333333
+ qwertyu0970 | 0.333333
+ qwertyu0971 | 0.333333
+ qwertyu0972 | 0.333333
+ qwertyu0973 | 0.333333
+ qwertyu0974 | 0.333333
+ qwertyu0975 | 0.333333
+ qwertyu0976 | 0.333333
+ qwertyu0977 | 0.333333
+ qwertyu0978 | 0.333333
+ qwertyu0979 | 0.333333
+ qwertyu0990 | 0.333333
+ qwertyu0991 | 0.333333
+ qwertyu0992 | 0.333333
+ qwertyu0993 | 0.333333
+ qwertyu0994 | 0.333333
+ qwertyu0995 | 0.333333
+ qwertyu0996 | 0.333333
+ qwertyu0997 | 0.333333
+ qwertyu0998 | 0.333333
+ qwertyu0999 | 0.333333
+(110 rows)
+
+select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 0.333333
+(1 row)
+
+select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+ ?column? | t
+----------+-------------
+ 0.411765 | qwertyu0988
+ 0.5 | qwertyu0987
+(2 rows)
+
+select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}';
+ count
+-------
+ 1000
+(1 row)
+
+create index trgm_idx on test_trgm using gist (t gist_trgm_ops);
+set enable_seqscan=off;
+select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 1
+ qwertyu0980 | 0.714286
+ qwertyu0981 | 0.714286
+ qwertyu0982 | 0.714286
+ qwertyu0983 | 0.714286
+ qwertyu0984 | 0.714286
+ qwertyu0985 | 0.714286
+ qwertyu0986 | 0.714286
+ qwertyu0987 | 0.714286
+ qwertyu0989 | 0.714286
+ qwertyu0088 | 0.6
+ qwertyu0098 | 0.6
+ qwertyu0188 | 0.6
+ qwertyu0288 | 0.6
+ qwertyu0388 | 0.6
+ qwertyu0488 | 0.6
+ qwertyu0588 | 0.6
+ qwertyu0688 | 0.6
+ qwertyu0788 | 0.6
+ qwertyu0888 | 0.6
+ qwertyu0900 | 0.6
+ qwertyu0901 | 0.6
+ qwertyu0902 | 0.6
+ qwertyu0903 | 0.6
+ qwertyu0904 | 0.6
+ qwertyu0905 | 0.6
+ qwertyu0906 | 0.6
+ qwertyu0907 | 0.6
+ qwertyu0908 | 0.6
+ qwertyu0909 | 0.6
+ qwertyu0910 | 0.6
+ qwertyu0911 | 0.6
+ qwertyu0912 | 0.6
+ qwertyu0913 | 0.6
+ qwertyu0914 | 0.6
+ qwertyu0915 | 0.6
+ qwertyu0916 | 0.6
+ qwertyu0917 | 0.6
+ qwertyu0918 | 0.6
+ qwertyu0919 | 0.6
+ qwertyu0920 | 0.6
+ qwertyu0921 | 0.6
+ qwertyu0922 | 0.6
+ qwertyu0923 | 0.6
+ qwertyu0924 | 0.6
+ qwertyu0925 | 0.6
+ qwertyu0926 | 0.6
+ qwertyu0927 | 0.6
+ qwertyu0928 | 0.6
+ qwertyu0929 | 0.6
+ qwertyu0930 | 0.6
+ qwertyu0931 | 0.6
+ qwertyu0932 | 0.6
+ qwertyu0933 | 0.6
+ qwertyu0934 | 0.6
+ qwertyu0935 | 0.6
+ qwertyu0936 | 0.6
+ qwertyu0937 | 0.6
+ qwertyu0938 | 0.6
+ qwertyu0939 | 0.6
+ qwertyu0940 | 0.6
+ qwertyu0941 | 0.6
+ qwertyu0942 | 0.6
+ qwertyu0943 | 0.6
+ qwertyu0944 | 0.6
+ qwertyu0945 | 0.6
+ qwertyu0946 | 0.6
+ qwertyu0947 | 0.6
+ qwertyu0948 | 0.6
+ qwertyu0949 | 0.6
+ qwertyu0950 | 0.6
+ qwertyu0951 | 0.6
+ qwertyu0952 | 0.6
+ qwertyu0953 | 0.6
+ qwertyu0954 | 0.6
+ qwertyu0955 | 0.6
+ qwertyu0956 | 0.6
+ qwertyu0957 | 0.6
+ qwertyu0958 | 0.6
+ qwertyu0959 | 0.6
+ qwertyu0960 | 0.6
+ qwertyu0961 | 0.6
+ qwertyu0962 | 0.6
+ qwertyu0963 | 0.6
+ qwertyu0964 | 0.6
+ qwertyu0965 | 0.6
+ qwertyu0966 | 0.6
+ qwertyu0967 | 0.6
+ qwertyu0968 | 0.6
+ qwertyu0969 | 0.6
+ qwertyu0970 | 0.6
+ qwertyu0971 | 0.6
+ qwertyu0972 | 0.6
+ qwertyu0973 | 0.6
+ qwertyu0974 | 0.6
+ qwertyu0975 | 0.6
+ qwertyu0976 | 0.6
+ qwertyu0977 | 0.6
+ qwertyu0978 | 0.6
+ qwertyu0979 | 0.6
+ qwertyu0990 | 0.6
+ qwertyu0991 | 0.6
+ qwertyu0992 | 0.6
+ qwertyu0993 | 0.6
+ qwertyu0994 | 0.6
+ qwertyu0995 | 0.6
+ qwertyu0996 | 0.6
+ qwertyu0997 | 0.6
+ qwertyu0998 | 0.6
+ qwertyu0999 | 0.6
+ qwertyu0001 | 0.5
+ qwertyu0002 | 0.5
+ qwertyu0003 | 0.5
+ qwertyu0004 | 0.5
+ qwertyu0005 | 0.5
+ qwertyu0006 | 0.5
+ qwertyu0007 | 0.5
+ qwertyu0008 | 0.5
+ qwertyu0009 | 0.5
+ qwertyu0010 | 0.5
+ qwertyu0011 | 0.5
+ qwertyu0012 | 0.5
+ qwertyu0013 | 0.5
+ qwertyu0014 | 0.5
+ qwertyu0015 | 0.5
+ qwertyu0016 | 0.5
+ qwertyu0017 | 0.5
+ qwertyu0018 | 0.5
+ qwertyu0019 | 0.5
+ qwertyu0020 | 0.5
+ qwertyu0021 | 0.5
+ qwertyu0022 | 0.5
+ qwertyu0023 | 0.5
+ qwertyu0024 | 0.5
+ qwertyu0025 | 0.5
+ qwertyu0026 | 0.5
+ qwertyu0027 | 0.5
+ qwertyu0028 | 0.5
+ qwertyu0029 | 0.5
+ qwertyu0030 | 0.5
+ qwertyu0031 | 0.5
+ qwertyu0032 | 0.5
+ qwertyu0033 | 0.5
+ qwertyu0034 | 0.5
+ qwertyu0035 | 0.5
+ qwertyu0036 | 0.5
+ qwertyu0037 | 0.5
+ qwertyu0038 | 0.5
+ qwertyu0039 | 0.5
+ qwertyu0040 | 0.5
+ qwertyu0041 | 0.5
+ qwertyu0042 | 0.5
+ qwertyu0043 | 0.5
+ qwertyu0044 | 0.5
+ qwertyu0045 | 0.5
+ qwertyu0046 | 0.5
+ qwertyu0047 | 0.5
+ qwertyu0048 | 0.5
+ qwertyu0049 | 0.5
+ qwertyu0050 | 0.5
+ qwertyu0051 | 0.5
+ qwertyu0052 | 0.5
+ qwertyu0053 | 0.5
+ qwertyu0054 | 0.5
+ qwertyu0055 | 0.5
+ qwertyu0056 | 0.5
+ qwertyu0057 | 0.5
+ qwertyu0058 | 0.5
+ qwertyu0059 | 0.5
+ qwertyu0060 | 0.5
+ qwertyu0061 | 0.5
+ qwertyu0062 | 0.5
+ qwertyu0063 | 0.5
+ qwertyu0064 | 0.5
+ qwertyu0065 | 0.5
+ qwertyu0066 | 0.5
+ qwertyu0067 | 0.5
+ qwertyu0068 | 0.5
+ qwertyu0069 | 0.5
+ qwertyu0070 | 0.5
+ qwertyu0071 | 0.5
+ qwertyu0072 | 0.5
+ qwertyu0073 | 0.5
+ qwertyu0074 | 0.5
+ qwertyu0075 | 0.5
+ qwertyu0076 | 0.5
+ qwertyu0077 | 0.5
+ qwertyu0078 | 0.5
+ qwertyu0079 | 0.5
+ qwertyu0080 | 0.5
+ qwertyu0081 | 0.5
+ qwertyu0082 | 0.5
+ qwertyu0083 | 0.5
+ qwertyu0084 | 0.5
+ qwertyu0085 | 0.5
+ qwertyu0086 | 0.5
+ qwertyu0087 | 0.5
+ qwertyu0089 | 0.5
+ qwertyu0090 | 0.5
+ qwertyu0091 | 0.5
+ qwertyu0092 | 0.5
+ qwertyu0093 | 0.5
+ qwertyu0094 | 0.5
+ qwertyu0095 | 0.5
+ qwertyu0096 | 0.5
+ qwertyu0097 | 0.5
+ qwertyu0099 | 0.5
+ qwertyu0100 | 0.5
+ qwertyu0101 | 0.5
+ qwertyu0102 | 0.5
+ qwertyu0103 | 0.5
+ qwertyu0104 | 0.5
+ qwertyu0105 | 0.5
+ qwertyu0106 | 0.5
+ qwertyu0107 | 0.5
+ qwertyu0108 | 0.5
+ qwertyu0109 | 0.5
+ qwertyu0110 | 0.5
+ qwertyu0111 | 0.5
+ qwertyu0112 | 0.5
+ qwertyu0113 | 0.5
+ qwertyu0114 | 0.5
+ qwertyu0115 | 0.5
+ qwertyu0116 | 0.5
+ qwertyu0117 | 0.5
+ qwertyu0118 | 0.5
+ qwertyu0119 | 0.5
+ qwertyu0120 | 0.5
+ qwertyu0121 | 0.5
+ qwertyu0122 | 0.5
+ qwertyu0123 | 0.5
+ qwertyu0124 | 0.5
+ qwertyu0125 | 0.5
+ qwertyu0126 | 0.5
+ qwertyu0127 | 0.5
+ qwertyu0128 | 0.5
+ qwertyu0129 | 0.5
+ qwertyu0130 | 0.5
+ qwertyu0131 | 0.5
+ qwertyu0132 | 0.5
+ qwertyu0133 | 0.5
+ qwertyu0134 | 0.5
+ qwertyu0135 | 0.5
+ qwertyu0136 | 0.5
+ qwertyu0137 | 0.5
+ qwertyu0138 | 0.5
+ qwertyu0139 | 0.5
+ qwertyu0140 | 0.5
+ qwertyu0141 | 0.5
+ qwertyu0142 | 0.5
+ qwertyu0143 | 0.5
+ qwertyu0144 | 0.5
+ qwertyu0145 | 0.5
+ qwertyu0146 | 0.5
+ qwertyu0147 | 0.5
+ qwertyu0148 | 0.5
+ qwertyu0149 | 0.5
+ qwertyu0150 | 0.5
+ qwertyu0151 | 0.5
+ qwertyu0152 | 0.5
+ qwertyu0153 | 0.5
+ qwertyu0154 | 0.5
+ qwertyu0155 | 0.5
+ qwertyu0156 | 0.5
+ qwertyu0157 | 0.5
+ qwertyu0158 | 0.5
+ qwertyu0159 | 0.5
+ qwertyu0160 | 0.5
+ qwertyu0161 | 0.5
+ qwertyu0162 | 0.5
+ qwertyu0163 | 0.5
+ qwertyu0164 | 0.5
+ qwertyu0165 | 0.5
+ qwertyu0166 | 0.5
+ qwertyu0167 | 0.5
+ qwertyu0168 | 0.5
+ qwertyu0169 | 0.5
+ qwertyu0170 | 0.5
+ qwertyu0171 | 0.5
+ qwertyu0172 | 0.5
+ qwertyu0173 | 0.5
+ qwertyu0174 | 0.5
+ qwertyu0175 | 0.5
+ qwertyu0176 | 0.5
+ qwertyu0177 | 0.5
+ qwertyu0178 | 0.5
+ qwertyu0179 | 0.5
+ qwertyu0180 | 0.5
+ qwertyu0181 | 0.5
+ qwertyu0182 | 0.5
+ qwertyu0183 | 0.5
+ qwertyu0184 | 0.5
+ qwertyu0185 | 0.5
+ qwertyu0186 | 0.5
+ qwertyu0187 | 0.5
+ qwertyu0189 | 0.5
+ qwertyu0190 | 0.5
+ qwertyu0191 | 0.5
+ qwertyu0192 | 0.5
+ qwertyu0193 | 0.5
+ qwertyu0194 | 0.5
+ qwertyu0195 | 0.5
+ qwertyu0196 | 0.5
+ qwertyu0197 | 0.5
+ qwertyu0198 | 0.5
+ qwertyu0199 | 0.5
+ qwertyu0200 | 0.5
+ qwertyu0201 | 0.5
+ qwertyu0202 | 0.5
+ qwertyu0203 | 0.5
+ qwertyu0204 | 0.5
+ qwertyu0205 | 0.5
+ qwertyu0206 | 0.5
+ qwertyu0207 | 0.5
+ qwertyu0208 | 0.5
+ qwertyu0209 | 0.5
+ qwertyu0210 | 0.5
+ qwertyu0211 | 0.5
+ qwertyu0212 | 0.5
+ qwertyu0213 | 0.5
+ qwertyu0214 | 0.5
+ qwertyu0215 | 0.5
+ qwertyu0216 | 0.5
+ qwertyu0217 | 0.5
+ qwertyu0218 | 0.5
+ qwertyu0219 | 0.5
+ qwertyu0220 | 0.5
+ qwertyu0221 | 0.5
+ qwertyu0222 | 0.5
+ qwertyu0223 | 0.5
+ qwertyu0224 | 0.5
+ qwertyu0225 | 0.5
+ qwertyu0226 | 0.5
+ qwertyu0227 | 0.5
+ qwertyu0228 | 0.5
+ qwertyu0229 | 0.5
+ qwertyu0230 | 0.5
+ qwertyu0231 | 0.5
+ qwertyu0232 | 0.5
+ qwertyu0233 | 0.5
+ qwertyu0234 | 0.5
+ qwertyu0235 | 0.5
+ qwertyu0236 | 0.5
+ qwertyu0237 | 0.5
+ qwertyu0238 | 0.5
+ qwertyu0239 | 0.5
+ qwertyu0240 | 0.5
+ qwertyu0241 | 0.5
+ qwertyu0242 | 0.5
+ qwertyu0243 | 0.5
+ qwertyu0244 | 0.5
+ qwertyu0245 | 0.5
+ qwertyu0246 | 0.5
+ qwertyu0247 | 0.5
+ qwertyu0248 | 0.5
+ qwertyu0249 | 0.5
+ qwertyu0250 | 0.5
+ qwertyu0251 | 0.5
+ qwertyu0252 | 0.5
+ qwertyu0253 | 0.5
+ qwertyu0254 | 0.5
+ qwertyu0255 | 0.5
+ qwertyu0256 | 0.5
+ qwertyu0257 | 0.5
+ qwertyu0258 | 0.5
+ qwertyu0259 | 0.5
+ qwertyu0260 | 0.5
+ qwertyu0261 | 0.5
+ qwertyu0262 | 0.5
+ qwertyu0263 | 0.5
+ qwertyu0264 | 0.5
+ qwertyu0265 | 0.5
+ qwertyu0266 | 0.5
+ qwertyu0267 | 0.5
+ qwertyu0268 | 0.5
+ qwertyu0269 | 0.5
+ qwertyu0270 | 0.5
+ qwertyu0271 | 0.5
+ qwertyu0272 | 0.5
+ qwertyu0273 | 0.5
+ qwertyu0274 | 0.5
+ qwertyu0275 | 0.5
+ qwertyu0276 | 0.5
+ qwertyu0277 | 0.5
+ qwertyu0278 | 0.5
+ qwertyu0279 | 0.5
+ qwertyu0280 | 0.5
+ qwertyu0281 | 0.5
+ qwertyu0282 | 0.5
+ qwertyu0283 | 0.5
+ qwertyu0284 | 0.5
+ qwertyu0285 | 0.5
+ qwertyu0286 | 0.5
+ qwertyu0287 | 0.5
+ qwertyu0289 | 0.5
+ qwertyu0290 | 0.5
+ qwertyu0291 | 0.5
+ qwertyu0292 | 0.5
+ qwertyu0293 | 0.5
+ qwertyu0294 | 0.5
+ qwertyu0295 | 0.5
+ qwertyu0296 | 0.5
+ qwertyu0297 | 0.5
+ qwertyu0298 | 0.5
+ qwertyu0299 | 0.5
+ qwertyu0300 | 0.5
+ qwertyu0301 | 0.5
+ qwertyu0302 | 0.5
+ qwertyu0303 | 0.5
+ qwertyu0304 | 0.5
+ qwertyu0305 | 0.5
+ qwertyu0306 | 0.5
+ qwertyu0307 | 0.5
+ qwertyu0308 | 0.5
+ qwertyu0309 | 0.5
+ qwertyu0310 | 0.5
+ qwertyu0311 | 0.5
+ qwertyu0312 | 0.5
+ qwertyu0313 | 0.5
+ qwertyu0314 | 0.5
+ qwertyu0315 | 0.5
+ qwertyu0316 | 0.5
+ qwertyu0317 | 0.5
+ qwertyu0318 | 0.5
+ qwertyu0319 | 0.5
+ qwertyu0320 | 0.5
+ qwertyu0321 | 0.5
+ qwertyu0322 | 0.5
+ qwertyu0323 | 0.5
+ qwertyu0324 | 0.5
+ qwertyu0325 | 0.5
+ qwertyu0326 | 0.5
+ qwertyu0327 | 0.5
+ qwertyu0328 | 0.5
+ qwertyu0329 | 0.5
+ qwertyu0330 | 0.5
+ qwertyu0331 | 0.5
+ qwertyu0332 | 0.5
+ qwertyu0333 | 0.5
+ qwertyu0334 | 0.5
+ qwertyu0335 | 0.5
+ qwertyu0336 | 0.5
+ qwertyu0337 | 0.5
+ qwertyu0338 | 0.5
+ qwertyu0339 | 0.5
+ qwertyu0340 | 0.5
+ qwertyu0341 | 0.5
+ qwertyu0342 | 0.5
+ qwertyu0343 | 0.5
+ qwertyu0344 | 0.5
+ qwertyu0345 | 0.5
+ qwertyu0346 | 0.5
+ qwertyu0347 | 0.5
+ qwertyu0348 | 0.5
+ qwertyu0349 | 0.5
+ qwertyu0350 | 0.5
+ qwertyu0351 | 0.5
+ qwertyu0352 | 0.5
+ qwertyu0353 | 0.5
+ qwertyu0354 | 0.5
+ qwertyu0355 | 0.5
+ qwertyu0356 | 0.5
+ qwertyu0357 | 0.5
+ qwertyu0358 | 0.5
+ qwertyu0359 | 0.5
+ qwertyu0360 | 0.5
+ qwertyu0361 | 0.5
+ qwertyu0362 | 0.5
+ qwertyu0363 | 0.5
+ qwertyu0364 | 0.5
+ qwertyu0365 | 0.5
+ qwertyu0366 | 0.5
+ qwertyu0367 | 0.5
+ qwertyu0368 | 0.5
+ qwertyu0369 | 0.5
+ qwertyu0370 | 0.5
+ qwertyu0371 | 0.5
+ qwertyu0372 | 0.5
+ qwertyu0373 | 0.5
+ qwertyu0374 | 0.5
+ qwertyu0375 | 0.5
+ qwertyu0376 | 0.5
+ qwertyu0377 | 0.5
+ qwertyu0378 | 0.5
+ qwertyu0379 | 0.5
+ qwertyu0380 | 0.5
+ qwertyu0381 | 0.5
+ qwertyu0382 | 0.5
+ qwertyu0383 | 0.5
+ qwertyu0384 | 0.5
+ qwertyu0385 | 0.5
+ qwertyu0386 | 0.5
+ qwertyu0387 | 0.5
+ qwertyu0389 | 0.5
+ qwertyu0390 | 0.5
+ qwertyu0391 | 0.5
+ qwertyu0392 | 0.5
+ qwertyu0393 | 0.5
+ qwertyu0394 | 0.5
+ qwertyu0395 | 0.5
+ qwertyu0396 | 0.5
+ qwertyu0397 | 0.5
+ qwertyu0398 | 0.5
+ qwertyu0399 | 0.5
+ qwertyu0400 | 0.5
+ qwertyu0401 | 0.5
+ qwertyu0402 | 0.5
+ qwertyu0403 | 0.5
+ qwertyu0404 | 0.5
+ qwertyu0405 | 0.5
+ qwertyu0406 | 0.5
+ qwertyu0407 | 0.5
+ qwertyu0408 | 0.5
+ qwertyu0409 | 0.5
+ qwertyu0410 | 0.5
+ qwertyu0411 | 0.5
+ qwertyu0412 | 0.5
+ qwertyu0413 | 0.5
+ qwertyu0414 | 0.5
+ qwertyu0415 | 0.5
+ qwertyu0416 | 0.5
+ qwertyu0417 | 0.5
+ qwertyu0418 | 0.5
+ qwertyu0419 | 0.5
+ qwertyu0420 | 0.5
+ qwertyu0421 | 0.5
+ qwertyu0422 | 0.5
+ qwertyu0423 | 0.5
+ qwertyu0424 | 0.5
+ qwertyu0425 | 0.5
+ qwertyu0426 | 0.5
+ qwertyu0427 | 0.5
+ qwertyu0428 | 0.5
+ qwertyu0429 | 0.5
+ qwertyu0430 | 0.5
+ qwertyu0431 | 0.5
+ qwertyu0432 | 0.5
+ qwertyu0433 | 0.5
+ qwertyu0434 | 0.5
+ qwertyu0435 | 0.5
+ qwertyu0436 | 0.5
+ qwertyu0437 | 0.5
+ qwertyu0438 | 0.5
+ qwertyu0439 | 0.5
+ qwertyu0440 | 0.5
+ qwertyu0441 | 0.5
+ qwertyu0442 | 0.5
+ qwertyu0443 | 0.5
+ qwertyu0444 | 0.5
+ qwertyu0445 | 0.5
+ qwertyu0446 | 0.5
+ qwertyu0447 | 0.5
+ qwertyu0448 | 0.5
+ qwertyu0449 | 0.5
+ qwertyu0450 | 0.5
+ qwertyu0451 | 0.5
+ qwertyu0452 | 0.5
+ qwertyu0453 | 0.5
+ qwertyu0454 | 0.5
+ qwertyu0455 | 0.5
+ qwertyu0456 | 0.5
+ qwertyu0457 | 0.5
+ qwertyu0458 | 0.5
+ qwertyu0459 | 0.5
+ qwertyu0460 | 0.5
+ qwertyu0461 | 0.5
+ qwertyu0462 | 0.5
+ qwertyu0463 | 0.5
+ qwertyu0464 | 0.5
+ qwertyu0465 | 0.5
+ qwertyu0466 | 0.5
+ qwertyu0467 | 0.5
+ qwertyu0468 | 0.5
+ qwertyu0469 | 0.5
+ qwertyu0470 | 0.5
+ qwertyu0471 | 0.5
+ qwertyu0472 | 0.5
+ qwertyu0473 | 0.5
+ qwertyu0474 | 0.5
+ qwertyu0475 | 0.5
+ qwertyu0476 | 0.5
+ qwertyu0477 | 0.5
+ qwertyu0478 | 0.5
+ qwertyu0479 | 0.5
+ qwertyu0480 | 0.5
+ qwertyu0481 | 0.5
+ qwertyu0482 | 0.5
+ qwertyu0483 | 0.5
+ qwertyu0484 | 0.5
+ qwertyu0485 | 0.5
+ qwertyu0486 | 0.5
+ qwertyu0487 | 0.5
+ qwertyu0489 | 0.5
+ qwertyu0490 | 0.5
+ qwertyu0491 | 0.5
+ qwertyu0492 | 0.5
+ qwertyu0493 | 0.5
+ qwertyu0494 | 0.5
+ qwertyu0495 | 0.5
+ qwertyu0496 | 0.5
+ qwertyu0497 | 0.5
+ qwertyu0498 | 0.5
+ qwertyu0499 | 0.5
+ qwertyu0500 | 0.5
+ qwertyu0501 | 0.5
+ qwertyu0502 | 0.5
+ qwertyu0503 | 0.5
+ qwertyu0504 | 0.5
+ qwertyu0505 | 0.5
+ qwertyu0506 | 0.5
+ qwertyu0507 | 0.5
+ qwertyu0508 | 0.5
+ qwertyu0509 | 0.5
+ qwertyu0510 | 0.5
+ qwertyu0511 | 0.5
+ qwertyu0512 | 0.5
+ qwertyu0513 | 0.5
+ qwertyu0514 | 0.5
+ qwertyu0515 | 0.5
+ qwertyu0516 | 0.5
+ qwertyu0517 | 0.5
+ qwertyu0518 | 0.5
+ qwertyu0519 | 0.5
+ qwertyu0520 | 0.5
+ qwertyu0521 | 0.5
+ qwertyu0522 | 0.5
+ qwertyu0523 | 0.5
+ qwertyu0524 | 0.5
+ qwertyu0525 | 0.5
+ qwertyu0526 | 0.5
+ qwertyu0527 | 0.5
+ qwertyu0528 | 0.5
+ qwertyu0529 | 0.5
+ qwertyu0530 | 0.5
+ qwertyu0531 | 0.5
+ qwertyu0532 | 0.5
+ qwertyu0533 | 0.5
+ qwertyu0534 | 0.5
+ qwertyu0535 | 0.5
+ qwertyu0536 | 0.5
+ qwertyu0537 | 0.5
+ qwertyu0538 | 0.5
+ qwertyu0539 | 0.5
+ qwertyu0540 | 0.5
+ qwertyu0541 | 0.5
+ qwertyu0542 | 0.5
+ qwertyu0543 | 0.5
+ qwertyu0544 | 0.5
+ qwertyu0545 | 0.5
+ qwertyu0546 | 0.5
+ qwertyu0547 | 0.5
+ qwertyu0548 | 0.5
+ qwertyu0549 | 0.5
+ qwertyu0550 | 0.5
+ qwertyu0551 | 0.5
+ qwertyu0552 | 0.5
+ qwertyu0553 | 0.5
+ qwertyu0554 | 0.5
+ qwertyu0555 | 0.5
+ qwertyu0556 | 0.5
+ qwertyu0557 | 0.5
+ qwertyu0558 | 0.5
+ qwertyu0559 | 0.5
+ qwertyu0560 | 0.5
+ qwertyu0561 | 0.5
+ qwertyu0562 | 0.5
+ qwertyu0563 | 0.5
+ qwertyu0564 | 0.5
+ qwertyu0565 | 0.5
+ qwertyu0566 | 0.5
+ qwertyu0567 | 0.5
+ qwertyu0568 | 0.5
+ qwertyu0569 | 0.5
+ qwertyu0570 | 0.5
+ qwertyu0571 | 0.5
+ qwertyu0572 | 0.5
+ qwertyu0573 | 0.5
+ qwertyu0574 | 0.5
+ qwertyu0575 | 0.5
+ qwertyu0576 | 0.5
+ qwertyu0577 | 0.5
+ qwertyu0578 | 0.5
+ qwertyu0579 | 0.5
+ qwertyu0580 | 0.5
+ qwertyu0581 | 0.5
+ qwertyu0582 | 0.5
+ qwertyu0583 | 0.5
+ qwertyu0584 | 0.5
+ qwertyu0585 | 0.5
+ qwertyu0586 | 0.5
+ qwertyu0587 | 0.5
+ qwertyu0589 | 0.5
+ qwertyu0590 | 0.5
+ qwertyu0591 | 0.5
+ qwertyu0592 | 0.5
+ qwertyu0593 | 0.5
+ qwertyu0594 | 0.5
+ qwertyu0595 | 0.5
+ qwertyu0596 | 0.5
+ qwertyu0597 | 0.5
+ qwertyu0598 | 0.5
+ qwertyu0599 | 0.5
+ qwertyu0600 | 0.5
+ qwertyu0601 | 0.5
+ qwertyu0602 | 0.5
+ qwertyu0603 | 0.5
+ qwertyu0604 | 0.5
+ qwertyu0605 | 0.5
+ qwertyu0606 | 0.5
+ qwertyu0607 | 0.5
+ qwertyu0608 | 0.5
+ qwertyu0609 | 0.5
+ qwertyu0610 | 0.5
+ qwertyu0611 | 0.5
+ qwertyu0612 | 0.5
+ qwertyu0613 | 0.5
+ qwertyu0614 | 0.5
+ qwertyu0615 | 0.5
+ qwertyu0616 | 0.5
+ qwertyu0617 | 0.5
+ qwertyu0618 | 0.5
+ qwertyu0619 | 0.5
+ qwertyu0620 | 0.5
+ qwertyu0621 | 0.5
+ qwertyu0622 | 0.5
+ qwertyu0623 | 0.5
+ qwertyu0624 | 0.5
+ qwertyu0625 | 0.5
+ qwertyu0626 | 0.5
+ qwertyu0627 | 0.5
+ qwertyu0628 | 0.5
+ qwertyu0629 | 0.5
+ qwertyu0630 | 0.5
+ qwertyu0631 | 0.5
+ qwertyu0632 | 0.5
+ qwertyu0633 | 0.5
+ qwertyu0634 | 0.5
+ qwertyu0635 | 0.5
+ qwertyu0636 | 0.5
+ qwertyu0637 | 0.5
+ qwertyu0638 | 0.5
+ qwertyu0639 | 0.5
+ qwertyu0640 | 0.5
+ qwertyu0641 | 0.5
+ qwertyu0642 | 0.5
+ qwertyu0643 | 0.5
+ qwertyu0644 | 0.5
+ qwertyu0645 | 0.5
+ qwertyu0646 | 0.5
+ qwertyu0647 | 0.5
+ qwertyu0648 | 0.5
+ qwertyu0649 | 0.5
+ qwertyu0650 | 0.5
+ qwertyu0651 | 0.5
+ qwertyu0652 | 0.5
+ qwertyu0653 | 0.5
+ qwertyu0654 | 0.5
+ qwertyu0655 | 0.5
+ qwertyu0656 | 0.5
+ qwertyu0657 | 0.5
+ qwertyu0658 | 0.5
+ qwertyu0659 | 0.5
+ qwertyu0660 | 0.5
+ qwertyu0661 | 0.5
+ qwertyu0662 | 0.5
+ qwertyu0663 | 0.5
+ qwertyu0664 | 0.5
+ qwertyu0665 | 0.5
+ qwertyu0666 | 0.5
+ qwertyu0667 | 0.5
+ qwertyu0668 | 0.5
+ qwertyu0669 | 0.5
+ qwertyu0670 | 0.5
+ qwertyu0671 | 0.5
+ qwertyu0672 | 0.5
+ qwertyu0673 | 0.5
+ qwertyu0674 | 0.5
+ qwertyu0675 | 0.5
+ qwertyu0676 | 0.5
+ qwertyu0677 | 0.5
+ qwertyu0678 | 0.5
+ qwertyu0679 | 0.5
+ qwertyu0680 | 0.5
+ qwertyu0681 | 0.5
+ qwertyu0682 | 0.5
+ qwertyu0683 | 0.5
+ qwertyu0684 | 0.5
+ qwertyu0685 | 0.5
+ qwertyu0686 | 0.5
+ qwertyu0687 | 0.5
+ qwertyu0689 | 0.5
+ qwertyu0690 | 0.5
+ qwertyu0691 | 0.5
+ qwertyu0692 | 0.5
+ qwertyu0693 | 0.5
+ qwertyu0694 | 0.5
+ qwertyu0695 | 0.5
+ qwertyu0696 | 0.5
+ qwertyu0697 | 0.5
+ qwertyu0698 | 0.5
+ qwertyu0699 | 0.5
+ qwertyu0700 | 0.5
+ qwertyu0701 | 0.5
+ qwertyu0702 | 0.5
+ qwertyu0703 | 0.5
+ qwertyu0704 | 0.5
+ qwertyu0705 | 0.5
+ qwertyu0706 | 0.5
+ qwertyu0707 | 0.5
+ qwertyu0708 | 0.5
+ qwertyu0709 | 0.5
+ qwertyu0710 | 0.5
+ qwertyu0711 | 0.5
+ qwertyu0712 | 0.5
+ qwertyu0713 | 0.5
+ qwertyu0714 | 0.5
+ qwertyu0715 | 0.5
+ qwertyu0716 | 0.5
+ qwertyu0717 | 0.5
+ qwertyu0718 | 0.5
+ qwertyu0719 | 0.5
+ qwertyu0720 | 0.5
+ qwertyu0721 | 0.5
+ qwertyu0722 | 0.5
+ qwertyu0723 | 0.5
+ qwertyu0724 | 0.5
+ qwertyu0725 | 0.5
+ qwertyu0726 | 0.5
+ qwertyu0727 | 0.5
+ qwertyu0728 | 0.5
+ qwertyu0729 | 0.5
+ qwertyu0730 | 0.5
+ qwertyu0731 | 0.5
+ qwertyu0732 | 0.5
+ qwertyu0733 | 0.5
+ qwertyu0734 | 0.5
+ qwertyu0735 | 0.5
+ qwertyu0736 | 0.5
+ qwertyu0737 | 0.5
+ qwertyu0738 | 0.5
+ qwertyu0739 | 0.5
+ qwertyu0740 | 0.5
+ qwertyu0741 | 0.5
+ qwertyu0742 | 0.5
+ qwertyu0743 | 0.5
+ qwertyu0744 | 0.5
+ qwertyu0745 | 0.5
+ qwertyu0746 | 0.5
+ qwertyu0747 | 0.5
+ qwertyu0748 | 0.5
+ qwertyu0749 | 0.5
+ qwertyu0750 | 0.5
+ qwertyu0751 | 0.5
+ qwertyu0752 | 0.5
+ qwertyu0753 | 0.5
+ qwertyu0754 | 0.5
+ qwertyu0755 | 0.5
+ qwertyu0756 | 0.5
+ qwertyu0757 | 0.5
+ qwertyu0758 | 0.5
+ qwertyu0759 | 0.5
+ qwertyu0760 | 0.5
+ qwertyu0761 | 0.5
+ qwertyu0762 | 0.5
+ qwertyu0763 | 0.5
+ qwertyu0764 | 0.5
+ qwertyu0765 | 0.5
+ qwertyu0766 | 0.5
+ qwertyu0767 | 0.5
+ qwertyu0768 | 0.5
+ qwertyu0769 | 0.5
+ qwertyu0770 | 0.5
+ qwertyu0771 | 0.5
+ qwertyu0772 | 0.5
+ qwertyu0773 | 0.5
+ qwertyu0774 | 0.5
+ qwertyu0775 | 0.5
+ qwertyu0776 | 0.5
+ qwertyu0777 | 0.5
+ qwertyu0778 | 0.5
+ qwertyu0779 | 0.5
+ qwertyu0780 | 0.5
+ qwertyu0781 | 0.5
+ qwertyu0782 | 0.5
+ qwertyu0783 | 0.5
+ qwertyu0784 | 0.5
+ qwertyu0785 | 0.5
+ qwertyu0786 | 0.5
+ qwertyu0787 | 0.5
+ qwertyu0789 | 0.5
+ qwertyu0790 | 0.5
+ qwertyu0791 | 0.5
+ qwertyu0792 | 0.5
+ qwertyu0793 | 0.5
+ qwertyu0794 | 0.5
+ qwertyu0795 | 0.5
+ qwertyu0796 | 0.5
+ qwertyu0797 | 0.5
+ qwertyu0798 | 0.5
+ qwertyu0799 | 0.5
+ qwertyu0800 | 0.5
+ qwertyu0801 | 0.5
+ qwertyu0802 | 0.5
+ qwertyu0803 | 0.5
+ qwertyu0804 | 0.5
+ qwertyu0805 | 0.5
+ qwertyu0806 | 0.5
+ qwertyu0807 | 0.5
+ qwertyu0808 | 0.5
+ qwertyu0809 | 0.5
+ qwertyu0810 | 0.5
+ qwertyu0811 | 0.5
+ qwertyu0812 | 0.5
+ qwertyu0813 | 0.5
+ qwertyu0814 | 0.5
+ qwertyu0815 | 0.5
+ qwertyu0816 | 0.5
+ qwertyu0817 | 0.5
+ qwertyu0818 | 0.5
+ qwertyu0819 | 0.5
+ qwertyu0820 | 0.5
+ qwertyu0821 | 0.5
+ qwertyu0822 | 0.5
+ qwertyu0823 | 0.5
+ qwertyu0824 | 0.5
+ qwertyu0825 | 0.5
+ qwertyu0826 | 0.5
+ qwertyu0827 | 0.5
+ qwertyu0828 | 0.5
+ qwertyu0829 | 0.5
+ qwertyu0830 | 0.5
+ qwertyu0831 | 0.5
+ qwertyu0832 | 0.5
+ qwertyu0833 | 0.5
+ qwertyu0834 | 0.5
+ qwertyu0835 | 0.5
+ qwertyu0836 | 0.5
+ qwertyu0837 | 0.5
+ qwertyu0838 | 0.5
+ qwertyu0839 | 0.5
+ qwertyu0840 | 0.5
+ qwertyu0841 | 0.5
+ qwertyu0842 | 0.5
+ qwertyu0843 | 0.5
+ qwertyu0844 | 0.5
+ qwertyu0845 | 0.5
+ qwertyu0846 | 0.5
+ qwertyu0847 | 0.5
+ qwertyu0848 | 0.5
+ qwertyu0849 | 0.5
+ qwertyu0850 | 0.5
+ qwertyu0851 | 0.5
+ qwertyu0852 | 0.5
+ qwertyu0853 | 0.5
+ qwertyu0854 | 0.5
+ qwertyu0855 | 0.5
+ qwertyu0856 | 0.5
+ qwertyu0857 | 0.5
+ qwertyu0858 | 0.5
+ qwertyu0859 | 0.5
+ qwertyu0860 | 0.5
+ qwertyu0861 | 0.5
+ qwertyu0862 | 0.5
+ qwertyu0863 | 0.5
+ qwertyu0864 | 0.5
+ qwertyu0865 | 0.5
+ qwertyu0866 | 0.5
+ qwertyu0867 | 0.5
+ qwertyu0868 | 0.5
+ qwertyu0869 | 0.5
+ qwertyu0870 | 0.5
+ qwertyu0871 | 0.5
+ qwertyu0872 | 0.5
+ qwertyu0873 | 0.5
+ qwertyu0874 | 0.5
+ qwertyu0875 | 0.5
+ qwertyu0876 | 0.5
+ qwertyu0877 | 0.5
+ qwertyu0878 | 0.5
+ qwertyu0879 | 0.5
+ qwertyu0880 | 0.5
+ qwertyu0881 | 0.5
+ qwertyu0882 | 0.5
+ qwertyu0883 | 0.5
+ qwertyu0884 | 0.5
+ qwertyu0885 | 0.5
+ qwertyu0886 | 0.5
+ qwertyu0887 | 0.5
+ qwertyu0889 | 0.5
+ qwertyu0890 | 0.5
+ qwertyu0891 | 0.5
+ qwertyu0892 | 0.5
+ qwertyu0893 | 0.5
+ qwertyu0894 | 0.5
+ qwertyu0895 | 0.5
+ qwertyu0896 | 0.5
+ qwertyu0897 | 0.5
+ qwertyu0898 | 0.5
+ qwertyu0899 | 0.5
+ qwertyu1000 | 0.411765
+(1000 rows)
+
+select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 0.6
+ qwertyu0980 | 0.411765
+ qwertyu0981 | 0.411765
+ qwertyu0982 | 0.411765
+ qwertyu0983 | 0.411765
+ qwertyu0984 | 0.411765
+ qwertyu0985 | 0.411765
+ qwertyu0986 | 0.411765
+ qwertyu0987 | 0.411765
+ qwertyu0989 | 0.411765
+ qwertyu0088 | 0.333333
+ qwertyu0098 | 0.333333
+ qwertyu0188 | 0.333333
+ qwertyu0288 | 0.333333
+ qwertyu0388 | 0.333333
+ qwertyu0488 | 0.333333
+ qwertyu0588 | 0.333333
+ qwertyu0688 | 0.333333
+ qwertyu0788 | 0.333333
+ qwertyu0888 | 0.333333
+ qwertyu0900 | 0.333333
+ qwertyu0901 | 0.333333
+ qwertyu0902 | 0.333333
+ qwertyu0903 | 0.333333
+ qwertyu0904 | 0.333333
+ qwertyu0905 | 0.333333
+ qwertyu0906 | 0.333333
+ qwertyu0907 | 0.333333
+ qwertyu0908 | 0.333333
+ qwertyu0909 | 0.333333
+ qwertyu0910 | 0.333333
+ qwertyu0911 | 0.333333
+ qwertyu0912 | 0.333333
+ qwertyu0913 | 0.333333
+ qwertyu0914 | 0.333333
+ qwertyu0915 | 0.333333
+ qwertyu0916 | 0.333333
+ qwertyu0917 | 0.333333
+ qwertyu0918 | 0.333333
+ qwertyu0919 | 0.333333
+ qwertyu0920 | 0.333333
+ qwertyu0921 | 0.333333
+ qwertyu0922 | 0.333333
+ qwertyu0923 | 0.333333
+ qwertyu0924 | 0.333333
+ qwertyu0925 | 0.333333
+ qwertyu0926 | 0.333333
+ qwertyu0927 | 0.333333
+ qwertyu0928 | 0.333333
+ qwertyu0929 | 0.333333
+ qwertyu0930 | 0.333333
+ qwertyu0931 | 0.333333
+ qwertyu0932 | 0.333333
+ qwertyu0933 | 0.333333
+ qwertyu0934 | 0.333333
+ qwertyu0935 | 0.333333
+ qwertyu0936 | 0.333333
+ qwertyu0937 | 0.333333
+ qwertyu0938 | 0.333333
+ qwertyu0939 | 0.333333
+ qwertyu0940 | 0.333333
+ qwertyu0941 | 0.333333
+ qwertyu0942 | 0.333333
+ qwertyu0943 | 0.333333
+ qwertyu0944 | 0.333333
+ qwertyu0945 | 0.333333
+ qwertyu0946 | 0.333333
+ qwertyu0947 | 0.333333
+ qwertyu0948 | 0.333333
+ qwertyu0949 | 0.333333
+ qwertyu0950 | 0.333333
+ qwertyu0951 | 0.333333
+ qwertyu0952 | 0.333333
+ qwertyu0953 | 0.333333
+ qwertyu0954 | 0.333333
+ qwertyu0955 | 0.333333
+ qwertyu0956 | 0.333333
+ qwertyu0957 | 0.333333
+ qwertyu0958 | 0.333333
+ qwertyu0959 | 0.333333
+ qwertyu0960 | 0.333333
+ qwertyu0961 | 0.333333
+ qwertyu0962 | 0.333333
+ qwertyu0963 | 0.333333
+ qwertyu0964 | 0.333333
+ qwertyu0965 | 0.333333
+ qwertyu0966 | 0.333333
+ qwertyu0967 | 0.333333
+ qwertyu0968 | 0.333333
+ qwertyu0969 | 0.333333
+ qwertyu0970 | 0.333333
+ qwertyu0971 | 0.333333
+ qwertyu0972 | 0.333333
+ qwertyu0973 | 0.333333
+ qwertyu0974 | 0.333333
+ qwertyu0975 | 0.333333
+ qwertyu0976 | 0.333333
+ qwertyu0977 | 0.333333
+ qwertyu0978 | 0.333333
+ qwertyu0979 | 0.333333
+ qwertyu0990 | 0.333333
+ qwertyu0991 | 0.333333
+ qwertyu0992 | 0.333333
+ qwertyu0993 | 0.333333
+ qwertyu0994 | 0.333333
+ qwertyu0995 | 0.333333
+ qwertyu0996 | 0.333333
+ qwertyu0997 | 0.333333
+ qwertyu0998 | 0.333333
+ qwertyu0999 | 0.333333
+(110 rows)
+
+select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 0.333333
+(1 row)
+
+explain (costs off)
+select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+ QUERY PLAN
+---------------------------------------------------
+ Limit
+ -> Index Scan using trgm_idx on test_trgm
+ Order By: (t <-> 'q0987wertyu0988'::text)
+(3 rows)
+
+select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+ ?column? | t
+----------+-------------
+ 0.411765 | qwertyu0988
+ 0.5 | qwertyu0987
+(2 rows)
+
+select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}';
+ count
+-------
+ 1000
+(1 row)
+
+drop index trgm_idx;
+create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=0));
+ERROR: value 0 out of bounds for option "siglen"
+DETAIL: Valid values are between "1" and "2024".
+create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=2025));
+ERROR: value 2025 out of bounds for option "siglen"
+DETAIL: Valid values are between "1" and "2024".
+create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=2024));
+set enable_seqscan=off;
+select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 1
+ qwertyu0980 | 0.714286
+ qwertyu0981 | 0.714286
+ qwertyu0982 | 0.714286
+ qwertyu0983 | 0.714286
+ qwertyu0984 | 0.714286
+ qwertyu0985 | 0.714286
+ qwertyu0986 | 0.714286
+ qwertyu0987 | 0.714286
+ qwertyu0989 | 0.714286
+ qwertyu0088 | 0.6
+ qwertyu0098 | 0.6
+ qwertyu0188 | 0.6
+ qwertyu0288 | 0.6
+ qwertyu0388 | 0.6
+ qwertyu0488 | 0.6
+ qwertyu0588 | 0.6
+ qwertyu0688 | 0.6
+ qwertyu0788 | 0.6
+ qwertyu0888 | 0.6
+ qwertyu0900 | 0.6
+ qwertyu0901 | 0.6
+ qwertyu0902 | 0.6
+ qwertyu0903 | 0.6
+ qwertyu0904 | 0.6
+ qwertyu0905 | 0.6
+ qwertyu0906 | 0.6
+ qwertyu0907 | 0.6
+ qwertyu0908 | 0.6
+ qwertyu0909 | 0.6
+ qwertyu0910 | 0.6
+ qwertyu0911 | 0.6
+ qwertyu0912 | 0.6
+ qwertyu0913 | 0.6
+ qwertyu0914 | 0.6
+ qwertyu0915 | 0.6
+ qwertyu0916 | 0.6
+ qwertyu0917 | 0.6
+ qwertyu0918 | 0.6
+ qwertyu0919 | 0.6
+ qwertyu0920 | 0.6
+ qwertyu0921 | 0.6
+ qwertyu0922 | 0.6
+ qwertyu0923 | 0.6
+ qwertyu0924 | 0.6
+ qwertyu0925 | 0.6
+ qwertyu0926 | 0.6
+ qwertyu0927 | 0.6
+ qwertyu0928 | 0.6
+ qwertyu0929 | 0.6
+ qwertyu0930 | 0.6
+ qwertyu0931 | 0.6
+ qwertyu0932 | 0.6
+ qwertyu0933 | 0.6
+ qwertyu0934 | 0.6
+ qwertyu0935 | 0.6
+ qwertyu0936 | 0.6
+ qwertyu0937 | 0.6
+ qwertyu0938 | 0.6
+ qwertyu0939 | 0.6
+ qwertyu0940 | 0.6
+ qwertyu0941 | 0.6
+ qwertyu0942 | 0.6
+ qwertyu0943 | 0.6
+ qwertyu0944 | 0.6
+ qwertyu0945 | 0.6
+ qwertyu0946 | 0.6
+ qwertyu0947 | 0.6
+ qwertyu0948 | 0.6
+ qwertyu0949 | 0.6
+ qwertyu0950 | 0.6
+ qwertyu0951 | 0.6
+ qwertyu0952 | 0.6
+ qwertyu0953 | 0.6
+ qwertyu0954 | 0.6
+ qwertyu0955 | 0.6
+ qwertyu0956 | 0.6
+ qwertyu0957 | 0.6
+ qwertyu0958 | 0.6
+ qwertyu0959 | 0.6
+ qwertyu0960 | 0.6
+ qwertyu0961 | 0.6
+ qwertyu0962 | 0.6
+ qwertyu0963 | 0.6
+ qwertyu0964 | 0.6
+ qwertyu0965 | 0.6
+ qwertyu0966 | 0.6
+ qwertyu0967 | 0.6
+ qwertyu0968 | 0.6
+ qwertyu0969 | 0.6
+ qwertyu0970 | 0.6
+ qwertyu0971 | 0.6
+ qwertyu0972 | 0.6
+ qwertyu0973 | 0.6
+ qwertyu0974 | 0.6
+ qwertyu0975 | 0.6
+ qwertyu0976 | 0.6
+ qwertyu0977 | 0.6
+ qwertyu0978 | 0.6
+ qwertyu0979 | 0.6
+ qwertyu0990 | 0.6
+ qwertyu0991 | 0.6
+ qwertyu0992 | 0.6
+ qwertyu0993 | 0.6
+ qwertyu0994 | 0.6
+ qwertyu0995 | 0.6
+ qwertyu0996 | 0.6
+ qwertyu0997 | 0.6
+ qwertyu0998 | 0.6
+ qwertyu0999 | 0.6
+ qwertyu0001 | 0.5
+ qwertyu0002 | 0.5
+ qwertyu0003 | 0.5
+ qwertyu0004 | 0.5
+ qwertyu0005 | 0.5
+ qwertyu0006 | 0.5
+ qwertyu0007 | 0.5
+ qwertyu0008 | 0.5
+ qwertyu0009 | 0.5
+ qwertyu0010 | 0.5
+ qwertyu0011 | 0.5
+ qwertyu0012 | 0.5
+ qwertyu0013 | 0.5
+ qwertyu0014 | 0.5
+ qwertyu0015 | 0.5
+ qwertyu0016 | 0.5
+ qwertyu0017 | 0.5
+ qwertyu0018 | 0.5
+ qwertyu0019 | 0.5
+ qwertyu0020 | 0.5
+ qwertyu0021 | 0.5
+ qwertyu0022 | 0.5
+ qwertyu0023 | 0.5
+ qwertyu0024 | 0.5
+ qwertyu0025 | 0.5
+ qwertyu0026 | 0.5
+ qwertyu0027 | 0.5
+ qwertyu0028 | 0.5
+ qwertyu0029 | 0.5
+ qwertyu0030 | 0.5
+ qwertyu0031 | 0.5
+ qwertyu0032 | 0.5
+ qwertyu0033 | 0.5
+ qwertyu0034 | 0.5
+ qwertyu0035 | 0.5
+ qwertyu0036 | 0.5
+ qwertyu0037 | 0.5
+ qwertyu0038 | 0.5
+ qwertyu0039 | 0.5
+ qwertyu0040 | 0.5
+ qwertyu0041 | 0.5
+ qwertyu0042 | 0.5
+ qwertyu0043 | 0.5
+ qwertyu0044 | 0.5
+ qwertyu0045 | 0.5
+ qwertyu0046 | 0.5
+ qwertyu0047 | 0.5
+ qwertyu0048 | 0.5
+ qwertyu0049 | 0.5
+ qwertyu0050 | 0.5
+ qwertyu0051 | 0.5
+ qwertyu0052 | 0.5
+ qwertyu0053 | 0.5
+ qwertyu0054 | 0.5
+ qwertyu0055 | 0.5
+ qwertyu0056 | 0.5
+ qwertyu0057 | 0.5
+ qwertyu0058 | 0.5
+ qwertyu0059 | 0.5
+ qwertyu0060 | 0.5
+ qwertyu0061 | 0.5
+ qwertyu0062 | 0.5
+ qwertyu0063 | 0.5
+ qwertyu0064 | 0.5
+ qwertyu0065 | 0.5
+ qwertyu0066 | 0.5
+ qwertyu0067 | 0.5
+ qwertyu0068 | 0.5
+ qwertyu0069 | 0.5
+ qwertyu0070 | 0.5
+ qwertyu0071 | 0.5
+ qwertyu0072 | 0.5
+ qwertyu0073 | 0.5
+ qwertyu0074 | 0.5
+ qwertyu0075 | 0.5
+ qwertyu0076 | 0.5
+ qwertyu0077 | 0.5
+ qwertyu0078 | 0.5
+ qwertyu0079 | 0.5
+ qwertyu0080 | 0.5
+ qwertyu0081 | 0.5
+ qwertyu0082 | 0.5
+ qwertyu0083 | 0.5
+ qwertyu0084 | 0.5
+ qwertyu0085 | 0.5
+ qwertyu0086 | 0.5
+ qwertyu0087 | 0.5
+ qwertyu0089 | 0.5
+ qwertyu0090 | 0.5
+ qwertyu0091 | 0.5
+ qwertyu0092 | 0.5
+ qwertyu0093 | 0.5
+ qwertyu0094 | 0.5
+ qwertyu0095 | 0.5
+ qwertyu0096 | 0.5
+ qwertyu0097 | 0.5
+ qwertyu0099 | 0.5
+ qwertyu0100 | 0.5
+ qwertyu0101 | 0.5
+ qwertyu0102 | 0.5
+ qwertyu0103 | 0.5
+ qwertyu0104 | 0.5
+ qwertyu0105 | 0.5
+ qwertyu0106 | 0.5
+ qwertyu0107 | 0.5
+ qwertyu0108 | 0.5
+ qwertyu0109 | 0.5
+ qwertyu0110 | 0.5
+ qwertyu0111 | 0.5
+ qwertyu0112 | 0.5
+ qwertyu0113 | 0.5
+ qwertyu0114 | 0.5
+ qwertyu0115 | 0.5
+ qwertyu0116 | 0.5
+ qwertyu0117 | 0.5
+ qwertyu0118 | 0.5
+ qwertyu0119 | 0.5
+ qwertyu0120 | 0.5
+ qwertyu0121 | 0.5
+ qwertyu0122 | 0.5
+ qwertyu0123 | 0.5
+ qwertyu0124 | 0.5
+ qwertyu0125 | 0.5
+ qwertyu0126 | 0.5
+ qwertyu0127 | 0.5
+ qwertyu0128 | 0.5
+ qwertyu0129 | 0.5
+ qwertyu0130 | 0.5
+ qwertyu0131 | 0.5
+ qwertyu0132 | 0.5
+ qwertyu0133 | 0.5
+ qwertyu0134 | 0.5
+ qwertyu0135 | 0.5
+ qwertyu0136 | 0.5
+ qwertyu0137 | 0.5
+ qwertyu0138 | 0.5
+ qwertyu0139 | 0.5
+ qwertyu0140 | 0.5
+ qwertyu0141 | 0.5
+ qwertyu0142 | 0.5
+ qwertyu0143 | 0.5
+ qwertyu0144 | 0.5
+ qwertyu0145 | 0.5
+ qwertyu0146 | 0.5
+ qwertyu0147 | 0.5
+ qwertyu0148 | 0.5
+ qwertyu0149 | 0.5
+ qwertyu0150 | 0.5
+ qwertyu0151 | 0.5
+ qwertyu0152 | 0.5
+ qwertyu0153 | 0.5
+ qwertyu0154 | 0.5
+ qwertyu0155 | 0.5
+ qwertyu0156 | 0.5
+ qwertyu0157 | 0.5
+ qwertyu0158 | 0.5
+ qwertyu0159 | 0.5
+ qwertyu0160 | 0.5
+ qwertyu0161 | 0.5
+ qwertyu0162 | 0.5
+ qwertyu0163 | 0.5
+ qwertyu0164 | 0.5
+ qwertyu0165 | 0.5
+ qwertyu0166 | 0.5
+ qwertyu0167 | 0.5
+ qwertyu0168 | 0.5
+ qwertyu0169 | 0.5
+ qwertyu0170 | 0.5
+ qwertyu0171 | 0.5
+ qwertyu0172 | 0.5
+ qwertyu0173 | 0.5
+ qwertyu0174 | 0.5
+ qwertyu0175 | 0.5
+ qwertyu0176 | 0.5
+ qwertyu0177 | 0.5
+ qwertyu0178 | 0.5
+ qwertyu0179 | 0.5
+ qwertyu0180 | 0.5
+ qwertyu0181 | 0.5
+ qwertyu0182 | 0.5
+ qwertyu0183 | 0.5
+ qwertyu0184 | 0.5
+ qwertyu0185 | 0.5
+ qwertyu0186 | 0.5
+ qwertyu0187 | 0.5
+ qwertyu0189 | 0.5
+ qwertyu0190 | 0.5
+ qwertyu0191 | 0.5
+ qwertyu0192 | 0.5
+ qwertyu0193 | 0.5
+ qwertyu0194 | 0.5
+ qwertyu0195 | 0.5
+ qwertyu0196 | 0.5
+ qwertyu0197 | 0.5
+ qwertyu0198 | 0.5
+ qwertyu0199 | 0.5
+ qwertyu0200 | 0.5
+ qwertyu0201 | 0.5
+ qwertyu0202 | 0.5
+ qwertyu0203 | 0.5
+ qwertyu0204 | 0.5
+ qwertyu0205 | 0.5
+ qwertyu0206 | 0.5
+ qwertyu0207 | 0.5
+ qwertyu0208 | 0.5
+ qwertyu0209 | 0.5
+ qwertyu0210 | 0.5
+ qwertyu0211 | 0.5
+ qwertyu0212 | 0.5
+ qwertyu0213 | 0.5
+ qwertyu0214 | 0.5
+ qwertyu0215 | 0.5
+ qwertyu0216 | 0.5
+ qwertyu0217 | 0.5
+ qwertyu0218 | 0.5
+ qwertyu0219 | 0.5
+ qwertyu0220 | 0.5
+ qwertyu0221 | 0.5
+ qwertyu0222 | 0.5
+ qwertyu0223 | 0.5
+ qwertyu0224 | 0.5
+ qwertyu0225 | 0.5
+ qwertyu0226 | 0.5
+ qwertyu0227 | 0.5
+ qwertyu0228 | 0.5
+ qwertyu0229 | 0.5
+ qwertyu0230 | 0.5
+ qwertyu0231 | 0.5
+ qwertyu0232 | 0.5
+ qwertyu0233 | 0.5
+ qwertyu0234 | 0.5
+ qwertyu0235 | 0.5
+ qwertyu0236 | 0.5
+ qwertyu0237 | 0.5
+ qwertyu0238 | 0.5
+ qwertyu0239 | 0.5
+ qwertyu0240 | 0.5
+ qwertyu0241 | 0.5
+ qwertyu0242 | 0.5
+ qwertyu0243 | 0.5
+ qwertyu0244 | 0.5
+ qwertyu0245 | 0.5
+ qwertyu0246 | 0.5
+ qwertyu0247 | 0.5
+ qwertyu0248 | 0.5
+ qwertyu0249 | 0.5
+ qwertyu0250 | 0.5
+ qwertyu0251 | 0.5
+ qwertyu0252 | 0.5
+ qwertyu0253 | 0.5
+ qwertyu0254 | 0.5
+ qwertyu0255 | 0.5
+ qwertyu0256 | 0.5
+ qwertyu0257 | 0.5
+ qwertyu0258 | 0.5
+ qwertyu0259 | 0.5
+ qwertyu0260 | 0.5
+ qwertyu0261 | 0.5
+ qwertyu0262 | 0.5
+ qwertyu0263 | 0.5
+ qwertyu0264 | 0.5
+ qwertyu0265 | 0.5
+ qwertyu0266 | 0.5
+ qwertyu0267 | 0.5
+ qwertyu0268 | 0.5
+ qwertyu0269 | 0.5
+ qwertyu0270 | 0.5
+ qwertyu0271 | 0.5
+ qwertyu0272 | 0.5
+ qwertyu0273 | 0.5
+ qwertyu0274 | 0.5
+ qwertyu0275 | 0.5
+ qwertyu0276 | 0.5
+ qwertyu0277 | 0.5
+ qwertyu0278 | 0.5
+ qwertyu0279 | 0.5
+ qwertyu0280 | 0.5
+ qwertyu0281 | 0.5
+ qwertyu0282 | 0.5
+ qwertyu0283 | 0.5
+ qwertyu0284 | 0.5
+ qwertyu0285 | 0.5
+ qwertyu0286 | 0.5
+ qwertyu0287 | 0.5
+ qwertyu0289 | 0.5
+ qwertyu0290 | 0.5
+ qwertyu0291 | 0.5
+ qwertyu0292 | 0.5
+ qwertyu0293 | 0.5
+ qwertyu0294 | 0.5
+ qwertyu0295 | 0.5
+ qwertyu0296 | 0.5
+ qwertyu0297 | 0.5
+ qwertyu0298 | 0.5
+ qwertyu0299 | 0.5
+ qwertyu0300 | 0.5
+ qwertyu0301 | 0.5
+ qwertyu0302 | 0.5
+ qwertyu0303 | 0.5
+ qwertyu0304 | 0.5
+ qwertyu0305 | 0.5
+ qwertyu0306 | 0.5
+ qwertyu0307 | 0.5
+ qwertyu0308 | 0.5
+ qwertyu0309 | 0.5
+ qwertyu0310 | 0.5
+ qwertyu0311 | 0.5
+ qwertyu0312 | 0.5
+ qwertyu0313 | 0.5
+ qwertyu0314 | 0.5
+ qwertyu0315 | 0.5
+ qwertyu0316 | 0.5
+ qwertyu0317 | 0.5
+ qwertyu0318 | 0.5
+ qwertyu0319 | 0.5
+ qwertyu0320 | 0.5
+ qwertyu0321 | 0.5
+ qwertyu0322 | 0.5
+ qwertyu0323 | 0.5
+ qwertyu0324 | 0.5
+ qwertyu0325 | 0.5
+ qwertyu0326 | 0.5
+ qwertyu0327 | 0.5
+ qwertyu0328 | 0.5
+ qwertyu0329 | 0.5
+ qwertyu0330 | 0.5
+ qwertyu0331 | 0.5
+ qwertyu0332 | 0.5
+ qwertyu0333 | 0.5
+ qwertyu0334 | 0.5
+ qwertyu0335 | 0.5
+ qwertyu0336 | 0.5
+ qwertyu0337 | 0.5
+ qwertyu0338 | 0.5
+ qwertyu0339 | 0.5
+ qwertyu0340 | 0.5
+ qwertyu0341 | 0.5
+ qwertyu0342 | 0.5
+ qwertyu0343 | 0.5
+ qwertyu0344 | 0.5
+ qwertyu0345 | 0.5
+ qwertyu0346 | 0.5
+ qwertyu0347 | 0.5
+ qwertyu0348 | 0.5
+ qwertyu0349 | 0.5
+ qwertyu0350 | 0.5
+ qwertyu0351 | 0.5
+ qwertyu0352 | 0.5
+ qwertyu0353 | 0.5
+ qwertyu0354 | 0.5
+ qwertyu0355 | 0.5
+ qwertyu0356 | 0.5
+ qwertyu0357 | 0.5
+ qwertyu0358 | 0.5
+ qwertyu0359 | 0.5
+ qwertyu0360 | 0.5
+ qwertyu0361 | 0.5
+ qwertyu0362 | 0.5
+ qwertyu0363 | 0.5
+ qwertyu0364 | 0.5
+ qwertyu0365 | 0.5
+ qwertyu0366 | 0.5
+ qwertyu0367 | 0.5
+ qwertyu0368 | 0.5
+ qwertyu0369 | 0.5
+ qwertyu0370 | 0.5
+ qwertyu0371 | 0.5
+ qwertyu0372 | 0.5
+ qwertyu0373 | 0.5
+ qwertyu0374 | 0.5
+ qwertyu0375 | 0.5
+ qwertyu0376 | 0.5
+ qwertyu0377 | 0.5
+ qwertyu0378 | 0.5
+ qwertyu0379 | 0.5
+ qwertyu0380 | 0.5
+ qwertyu0381 | 0.5
+ qwertyu0382 | 0.5
+ qwertyu0383 | 0.5
+ qwertyu0384 | 0.5
+ qwertyu0385 | 0.5
+ qwertyu0386 | 0.5
+ qwertyu0387 | 0.5
+ qwertyu0389 | 0.5
+ qwertyu0390 | 0.5
+ qwertyu0391 | 0.5
+ qwertyu0392 | 0.5
+ qwertyu0393 | 0.5
+ qwertyu0394 | 0.5
+ qwertyu0395 | 0.5
+ qwertyu0396 | 0.5
+ qwertyu0397 | 0.5
+ qwertyu0398 | 0.5
+ qwertyu0399 | 0.5
+ qwertyu0400 | 0.5
+ qwertyu0401 | 0.5
+ qwertyu0402 | 0.5
+ qwertyu0403 | 0.5
+ qwertyu0404 | 0.5
+ qwertyu0405 | 0.5
+ qwertyu0406 | 0.5
+ qwertyu0407 | 0.5
+ qwertyu0408 | 0.5
+ qwertyu0409 | 0.5
+ qwertyu0410 | 0.5
+ qwertyu0411 | 0.5
+ qwertyu0412 | 0.5
+ qwertyu0413 | 0.5
+ qwertyu0414 | 0.5
+ qwertyu0415 | 0.5
+ qwertyu0416 | 0.5
+ qwertyu0417 | 0.5
+ qwertyu0418 | 0.5
+ qwertyu0419 | 0.5
+ qwertyu0420 | 0.5
+ qwertyu0421 | 0.5
+ qwertyu0422 | 0.5
+ qwertyu0423 | 0.5
+ qwertyu0424 | 0.5
+ qwertyu0425 | 0.5
+ qwertyu0426 | 0.5
+ qwertyu0427 | 0.5
+ qwertyu0428 | 0.5
+ qwertyu0429 | 0.5
+ qwertyu0430 | 0.5
+ qwertyu0431 | 0.5
+ qwertyu0432 | 0.5
+ qwertyu0433 | 0.5
+ qwertyu0434 | 0.5
+ qwertyu0435 | 0.5
+ qwertyu0436 | 0.5
+ qwertyu0437 | 0.5
+ qwertyu0438 | 0.5
+ qwertyu0439 | 0.5
+ qwertyu0440 | 0.5
+ qwertyu0441 | 0.5
+ qwertyu0442 | 0.5
+ qwertyu0443 | 0.5
+ qwertyu0444 | 0.5
+ qwertyu0445 | 0.5
+ qwertyu0446 | 0.5
+ qwertyu0447 | 0.5
+ qwertyu0448 | 0.5
+ qwertyu0449 | 0.5
+ qwertyu0450 | 0.5
+ qwertyu0451 | 0.5
+ qwertyu0452 | 0.5
+ qwertyu0453 | 0.5
+ qwertyu0454 | 0.5
+ qwertyu0455 | 0.5
+ qwertyu0456 | 0.5
+ qwertyu0457 | 0.5
+ qwertyu0458 | 0.5
+ qwertyu0459 | 0.5
+ qwertyu0460 | 0.5
+ qwertyu0461 | 0.5
+ qwertyu0462 | 0.5
+ qwertyu0463 | 0.5
+ qwertyu0464 | 0.5
+ qwertyu0465 | 0.5
+ qwertyu0466 | 0.5
+ qwertyu0467 | 0.5
+ qwertyu0468 | 0.5
+ qwertyu0469 | 0.5
+ qwertyu0470 | 0.5
+ qwertyu0471 | 0.5
+ qwertyu0472 | 0.5
+ qwertyu0473 | 0.5
+ qwertyu0474 | 0.5
+ qwertyu0475 | 0.5
+ qwertyu0476 | 0.5
+ qwertyu0477 | 0.5
+ qwertyu0478 | 0.5
+ qwertyu0479 | 0.5
+ qwertyu0480 | 0.5
+ qwertyu0481 | 0.5
+ qwertyu0482 | 0.5
+ qwertyu0483 | 0.5
+ qwertyu0484 | 0.5
+ qwertyu0485 | 0.5
+ qwertyu0486 | 0.5
+ qwertyu0487 | 0.5
+ qwertyu0489 | 0.5
+ qwertyu0490 | 0.5
+ qwertyu0491 | 0.5
+ qwertyu0492 | 0.5
+ qwertyu0493 | 0.5
+ qwertyu0494 | 0.5
+ qwertyu0495 | 0.5
+ qwertyu0496 | 0.5
+ qwertyu0497 | 0.5
+ qwertyu0498 | 0.5
+ qwertyu0499 | 0.5
+ qwertyu0500 | 0.5
+ qwertyu0501 | 0.5
+ qwertyu0502 | 0.5
+ qwertyu0503 | 0.5
+ qwertyu0504 | 0.5
+ qwertyu0505 | 0.5
+ qwertyu0506 | 0.5
+ qwertyu0507 | 0.5
+ qwertyu0508 | 0.5
+ qwertyu0509 | 0.5
+ qwertyu0510 | 0.5
+ qwertyu0511 | 0.5
+ qwertyu0512 | 0.5
+ qwertyu0513 | 0.5
+ qwertyu0514 | 0.5
+ qwertyu0515 | 0.5
+ qwertyu0516 | 0.5
+ qwertyu0517 | 0.5
+ qwertyu0518 | 0.5
+ qwertyu0519 | 0.5
+ qwertyu0520 | 0.5
+ qwertyu0521 | 0.5
+ qwertyu0522 | 0.5
+ qwertyu0523 | 0.5
+ qwertyu0524 | 0.5
+ qwertyu0525 | 0.5
+ qwertyu0526 | 0.5
+ qwertyu0527 | 0.5
+ qwertyu0528 | 0.5
+ qwertyu0529 | 0.5
+ qwertyu0530 | 0.5
+ qwertyu0531 | 0.5
+ qwertyu0532 | 0.5
+ qwertyu0533 | 0.5
+ qwertyu0534 | 0.5
+ qwertyu0535 | 0.5
+ qwertyu0536 | 0.5
+ qwertyu0537 | 0.5
+ qwertyu0538 | 0.5
+ qwertyu0539 | 0.5
+ qwertyu0540 | 0.5
+ qwertyu0541 | 0.5
+ qwertyu0542 | 0.5
+ qwertyu0543 | 0.5
+ qwertyu0544 | 0.5
+ qwertyu0545 | 0.5
+ qwertyu0546 | 0.5
+ qwertyu0547 | 0.5
+ qwertyu0548 | 0.5
+ qwertyu0549 | 0.5
+ qwertyu0550 | 0.5
+ qwertyu0551 | 0.5
+ qwertyu0552 | 0.5
+ qwertyu0553 | 0.5
+ qwertyu0554 | 0.5
+ qwertyu0555 | 0.5
+ qwertyu0556 | 0.5
+ qwertyu0557 | 0.5
+ qwertyu0558 | 0.5
+ qwertyu0559 | 0.5
+ qwertyu0560 | 0.5
+ qwertyu0561 | 0.5
+ qwertyu0562 | 0.5
+ qwertyu0563 | 0.5
+ qwertyu0564 | 0.5
+ qwertyu0565 | 0.5
+ qwertyu0566 | 0.5
+ qwertyu0567 | 0.5
+ qwertyu0568 | 0.5
+ qwertyu0569 | 0.5
+ qwertyu0570 | 0.5
+ qwertyu0571 | 0.5
+ qwertyu0572 | 0.5
+ qwertyu0573 | 0.5
+ qwertyu0574 | 0.5
+ qwertyu0575 | 0.5
+ qwertyu0576 | 0.5
+ qwertyu0577 | 0.5
+ qwertyu0578 | 0.5
+ qwertyu0579 | 0.5
+ qwertyu0580 | 0.5
+ qwertyu0581 | 0.5
+ qwertyu0582 | 0.5
+ qwertyu0583 | 0.5
+ qwertyu0584 | 0.5
+ qwertyu0585 | 0.5
+ qwertyu0586 | 0.5
+ qwertyu0587 | 0.5
+ qwertyu0589 | 0.5
+ qwertyu0590 | 0.5
+ qwertyu0591 | 0.5
+ qwertyu0592 | 0.5
+ qwertyu0593 | 0.5
+ qwertyu0594 | 0.5
+ qwertyu0595 | 0.5
+ qwertyu0596 | 0.5
+ qwertyu0597 | 0.5
+ qwertyu0598 | 0.5
+ qwertyu0599 | 0.5
+ qwertyu0600 | 0.5
+ qwertyu0601 | 0.5
+ qwertyu0602 | 0.5
+ qwertyu0603 | 0.5
+ qwertyu0604 | 0.5
+ qwertyu0605 | 0.5
+ qwertyu0606 | 0.5
+ qwertyu0607 | 0.5
+ qwertyu0608 | 0.5
+ qwertyu0609 | 0.5
+ qwertyu0610 | 0.5
+ qwertyu0611 | 0.5
+ qwertyu0612 | 0.5
+ qwertyu0613 | 0.5
+ qwertyu0614 | 0.5
+ qwertyu0615 | 0.5
+ qwertyu0616 | 0.5
+ qwertyu0617 | 0.5
+ qwertyu0618 | 0.5
+ qwertyu0619 | 0.5
+ qwertyu0620 | 0.5
+ qwertyu0621 | 0.5
+ qwertyu0622 | 0.5
+ qwertyu0623 | 0.5
+ qwertyu0624 | 0.5
+ qwertyu0625 | 0.5
+ qwertyu0626 | 0.5
+ qwertyu0627 | 0.5
+ qwertyu0628 | 0.5
+ qwertyu0629 | 0.5
+ qwertyu0630 | 0.5
+ qwertyu0631 | 0.5
+ qwertyu0632 | 0.5
+ qwertyu0633 | 0.5
+ qwertyu0634 | 0.5
+ qwertyu0635 | 0.5
+ qwertyu0636 | 0.5
+ qwertyu0637 | 0.5
+ qwertyu0638 | 0.5
+ qwertyu0639 | 0.5
+ qwertyu0640 | 0.5
+ qwertyu0641 | 0.5
+ qwertyu0642 | 0.5
+ qwertyu0643 | 0.5
+ qwertyu0644 | 0.5
+ qwertyu0645 | 0.5
+ qwertyu0646 | 0.5
+ qwertyu0647 | 0.5
+ qwertyu0648 | 0.5
+ qwertyu0649 | 0.5
+ qwertyu0650 | 0.5
+ qwertyu0651 | 0.5
+ qwertyu0652 | 0.5
+ qwertyu0653 | 0.5
+ qwertyu0654 | 0.5
+ qwertyu0655 | 0.5
+ qwertyu0656 | 0.5
+ qwertyu0657 | 0.5
+ qwertyu0658 | 0.5
+ qwertyu0659 | 0.5
+ qwertyu0660 | 0.5
+ qwertyu0661 | 0.5
+ qwertyu0662 | 0.5
+ qwertyu0663 | 0.5
+ qwertyu0664 | 0.5
+ qwertyu0665 | 0.5
+ qwertyu0666 | 0.5
+ qwertyu0667 | 0.5
+ qwertyu0668 | 0.5
+ qwertyu0669 | 0.5
+ qwertyu0670 | 0.5
+ qwertyu0671 | 0.5
+ qwertyu0672 | 0.5
+ qwertyu0673 | 0.5
+ qwertyu0674 | 0.5
+ qwertyu0675 | 0.5
+ qwertyu0676 | 0.5
+ qwertyu0677 | 0.5
+ qwertyu0678 | 0.5
+ qwertyu0679 | 0.5
+ qwertyu0680 | 0.5
+ qwertyu0681 | 0.5
+ qwertyu0682 | 0.5
+ qwertyu0683 | 0.5
+ qwertyu0684 | 0.5
+ qwertyu0685 | 0.5
+ qwertyu0686 | 0.5
+ qwertyu0687 | 0.5
+ qwertyu0689 | 0.5
+ qwertyu0690 | 0.5
+ qwertyu0691 | 0.5
+ qwertyu0692 | 0.5
+ qwertyu0693 | 0.5
+ qwertyu0694 | 0.5
+ qwertyu0695 | 0.5
+ qwertyu0696 | 0.5
+ qwertyu0697 | 0.5
+ qwertyu0698 | 0.5
+ qwertyu0699 | 0.5
+ qwertyu0700 | 0.5
+ qwertyu0701 | 0.5
+ qwertyu0702 | 0.5
+ qwertyu0703 | 0.5
+ qwertyu0704 | 0.5
+ qwertyu0705 | 0.5
+ qwertyu0706 | 0.5
+ qwertyu0707 | 0.5
+ qwertyu0708 | 0.5
+ qwertyu0709 | 0.5
+ qwertyu0710 | 0.5
+ qwertyu0711 | 0.5
+ qwertyu0712 | 0.5
+ qwertyu0713 | 0.5
+ qwertyu0714 | 0.5
+ qwertyu0715 | 0.5
+ qwertyu0716 | 0.5
+ qwertyu0717 | 0.5
+ qwertyu0718 | 0.5
+ qwertyu0719 | 0.5
+ qwertyu0720 | 0.5
+ qwertyu0721 | 0.5
+ qwertyu0722 | 0.5
+ qwertyu0723 | 0.5
+ qwertyu0724 | 0.5
+ qwertyu0725 | 0.5
+ qwertyu0726 | 0.5
+ qwertyu0727 | 0.5
+ qwertyu0728 | 0.5
+ qwertyu0729 | 0.5
+ qwertyu0730 | 0.5
+ qwertyu0731 | 0.5
+ qwertyu0732 | 0.5
+ qwertyu0733 | 0.5
+ qwertyu0734 | 0.5
+ qwertyu0735 | 0.5
+ qwertyu0736 | 0.5
+ qwertyu0737 | 0.5
+ qwertyu0738 | 0.5
+ qwertyu0739 | 0.5
+ qwertyu0740 | 0.5
+ qwertyu0741 | 0.5
+ qwertyu0742 | 0.5
+ qwertyu0743 | 0.5
+ qwertyu0744 | 0.5
+ qwertyu0745 | 0.5
+ qwertyu0746 | 0.5
+ qwertyu0747 | 0.5
+ qwertyu0748 | 0.5
+ qwertyu0749 | 0.5
+ qwertyu0750 | 0.5
+ qwertyu0751 | 0.5
+ qwertyu0752 | 0.5
+ qwertyu0753 | 0.5
+ qwertyu0754 | 0.5
+ qwertyu0755 | 0.5
+ qwertyu0756 | 0.5
+ qwertyu0757 | 0.5
+ qwertyu0758 | 0.5
+ qwertyu0759 | 0.5
+ qwertyu0760 | 0.5
+ qwertyu0761 | 0.5
+ qwertyu0762 | 0.5
+ qwertyu0763 | 0.5
+ qwertyu0764 | 0.5
+ qwertyu0765 | 0.5
+ qwertyu0766 | 0.5
+ qwertyu0767 | 0.5
+ qwertyu0768 | 0.5
+ qwertyu0769 | 0.5
+ qwertyu0770 | 0.5
+ qwertyu0771 | 0.5
+ qwertyu0772 | 0.5
+ qwertyu0773 | 0.5
+ qwertyu0774 | 0.5
+ qwertyu0775 | 0.5
+ qwertyu0776 | 0.5
+ qwertyu0777 | 0.5
+ qwertyu0778 | 0.5
+ qwertyu0779 | 0.5
+ qwertyu0780 | 0.5
+ qwertyu0781 | 0.5
+ qwertyu0782 | 0.5
+ qwertyu0783 | 0.5
+ qwertyu0784 | 0.5
+ qwertyu0785 | 0.5
+ qwertyu0786 | 0.5
+ qwertyu0787 | 0.5
+ qwertyu0789 | 0.5
+ qwertyu0790 | 0.5
+ qwertyu0791 | 0.5
+ qwertyu0792 | 0.5
+ qwertyu0793 | 0.5
+ qwertyu0794 | 0.5
+ qwertyu0795 | 0.5
+ qwertyu0796 | 0.5
+ qwertyu0797 | 0.5
+ qwertyu0798 | 0.5
+ qwertyu0799 | 0.5
+ qwertyu0800 | 0.5
+ qwertyu0801 | 0.5
+ qwertyu0802 | 0.5
+ qwertyu0803 | 0.5
+ qwertyu0804 | 0.5
+ qwertyu0805 | 0.5
+ qwertyu0806 | 0.5
+ qwertyu0807 | 0.5
+ qwertyu0808 | 0.5
+ qwertyu0809 | 0.5
+ qwertyu0810 | 0.5
+ qwertyu0811 | 0.5
+ qwertyu0812 | 0.5
+ qwertyu0813 | 0.5
+ qwertyu0814 | 0.5
+ qwertyu0815 | 0.5
+ qwertyu0816 | 0.5
+ qwertyu0817 | 0.5
+ qwertyu0818 | 0.5
+ qwertyu0819 | 0.5
+ qwertyu0820 | 0.5
+ qwertyu0821 | 0.5
+ qwertyu0822 | 0.5
+ qwertyu0823 | 0.5
+ qwertyu0824 | 0.5
+ qwertyu0825 | 0.5
+ qwertyu0826 | 0.5
+ qwertyu0827 | 0.5
+ qwertyu0828 | 0.5
+ qwertyu0829 | 0.5
+ qwertyu0830 | 0.5
+ qwertyu0831 | 0.5
+ qwertyu0832 | 0.5
+ qwertyu0833 | 0.5
+ qwertyu0834 | 0.5
+ qwertyu0835 | 0.5
+ qwertyu0836 | 0.5
+ qwertyu0837 | 0.5
+ qwertyu0838 | 0.5
+ qwertyu0839 | 0.5
+ qwertyu0840 | 0.5
+ qwertyu0841 | 0.5
+ qwertyu0842 | 0.5
+ qwertyu0843 | 0.5
+ qwertyu0844 | 0.5
+ qwertyu0845 | 0.5
+ qwertyu0846 | 0.5
+ qwertyu0847 | 0.5
+ qwertyu0848 | 0.5
+ qwertyu0849 | 0.5
+ qwertyu0850 | 0.5
+ qwertyu0851 | 0.5
+ qwertyu0852 | 0.5
+ qwertyu0853 | 0.5
+ qwertyu0854 | 0.5
+ qwertyu0855 | 0.5
+ qwertyu0856 | 0.5
+ qwertyu0857 | 0.5
+ qwertyu0858 | 0.5
+ qwertyu0859 | 0.5
+ qwertyu0860 | 0.5
+ qwertyu0861 | 0.5
+ qwertyu0862 | 0.5
+ qwertyu0863 | 0.5
+ qwertyu0864 | 0.5
+ qwertyu0865 | 0.5
+ qwertyu0866 | 0.5
+ qwertyu0867 | 0.5
+ qwertyu0868 | 0.5
+ qwertyu0869 | 0.5
+ qwertyu0870 | 0.5
+ qwertyu0871 | 0.5
+ qwertyu0872 | 0.5
+ qwertyu0873 | 0.5
+ qwertyu0874 | 0.5
+ qwertyu0875 | 0.5
+ qwertyu0876 | 0.5
+ qwertyu0877 | 0.5
+ qwertyu0878 | 0.5
+ qwertyu0879 | 0.5
+ qwertyu0880 | 0.5
+ qwertyu0881 | 0.5
+ qwertyu0882 | 0.5
+ qwertyu0883 | 0.5
+ qwertyu0884 | 0.5
+ qwertyu0885 | 0.5
+ qwertyu0886 | 0.5
+ qwertyu0887 | 0.5
+ qwertyu0889 | 0.5
+ qwertyu0890 | 0.5
+ qwertyu0891 | 0.5
+ qwertyu0892 | 0.5
+ qwertyu0893 | 0.5
+ qwertyu0894 | 0.5
+ qwertyu0895 | 0.5
+ qwertyu0896 | 0.5
+ qwertyu0897 | 0.5
+ qwertyu0898 | 0.5
+ qwertyu0899 | 0.5
+ qwertyu1000 | 0.411765
+(1000 rows)
+
+select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 0.6
+ qwertyu0980 | 0.411765
+ qwertyu0981 | 0.411765
+ qwertyu0982 | 0.411765
+ qwertyu0983 | 0.411765
+ qwertyu0984 | 0.411765
+ qwertyu0985 | 0.411765
+ qwertyu0986 | 0.411765
+ qwertyu0987 | 0.411765
+ qwertyu0989 | 0.411765
+ qwertyu0088 | 0.333333
+ qwertyu0098 | 0.333333
+ qwertyu0188 | 0.333333
+ qwertyu0288 | 0.333333
+ qwertyu0388 | 0.333333
+ qwertyu0488 | 0.333333
+ qwertyu0588 | 0.333333
+ qwertyu0688 | 0.333333
+ qwertyu0788 | 0.333333
+ qwertyu0888 | 0.333333
+ qwertyu0900 | 0.333333
+ qwertyu0901 | 0.333333
+ qwertyu0902 | 0.333333
+ qwertyu0903 | 0.333333
+ qwertyu0904 | 0.333333
+ qwertyu0905 | 0.333333
+ qwertyu0906 | 0.333333
+ qwertyu0907 | 0.333333
+ qwertyu0908 | 0.333333
+ qwertyu0909 | 0.333333
+ qwertyu0910 | 0.333333
+ qwertyu0911 | 0.333333
+ qwertyu0912 | 0.333333
+ qwertyu0913 | 0.333333
+ qwertyu0914 | 0.333333
+ qwertyu0915 | 0.333333
+ qwertyu0916 | 0.333333
+ qwertyu0917 | 0.333333
+ qwertyu0918 | 0.333333
+ qwertyu0919 | 0.333333
+ qwertyu0920 | 0.333333
+ qwertyu0921 | 0.333333
+ qwertyu0922 | 0.333333
+ qwertyu0923 | 0.333333
+ qwertyu0924 | 0.333333
+ qwertyu0925 | 0.333333
+ qwertyu0926 | 0.333333
+ qwertyu0927 | 0.333333
+ qwertyu0928 | 0.333333
+ qwertyu0929 | 0.333333
+ qwertyu0930 | 0.333333
+ qwertyu0931 | 0.333333
+ qwertyu0932 | 0.333333
+ qwertyu0933 | 0.333333
+ qwertyu0934 | 0.333333
+ qwertyu0935 | 0.333333
+ qwertyu0936 | 0.333333
+ qwertyu0937 | 0.333333
+ qwertyu0938 | 0.333333
+ qwertyu0939 | 0.333333
+ qwertyu0940 | 0.333333
+ qwertyu0941 | 0.333333
+ qwertyu0942 | 0.333333
+ qwertyu0943 | 0.333333
+ qwertyu0944 | 0.333333
+ qwertyu0945 | 0.333333
+ qwertyu0946 | 0.333333
+ qwertyu0947 | 0.333333
+ qwertyu0948 | 0.333333
+ qwertyu0949 | 0.333333
+ qwertyu0950 | 0.333333
+ qwertyu0951 | 0.333333
+ qwertyu0952 | 0.333333
+ qwertyu0953 | 0.333333
+ qwertyu0954 | 0.333333
+ qwertyu0955 | 0.333333
+ qwertyu0956 | 0.333333
+ qwertyu0957 | 0.333333
+ qwertyu0958 | 0.333333
+ qwertyu0959 | 0.333333
+ qwertyu0960 | 0.333333
+ qwertyu0961 | 0.333333
+ qwertyu0962 | 0.333333
+ qwertyu0963 | 0.333333
+ qwertyu0964 | 0.333333
+ qwertyu0965 | 0.333333
+ qwertyu0966 | 0.333333
+ qwertyu0967 | 0.333333
+ qwertyu0968 | 0.333333
+ qwertyu0969 | 0.333333
+ qwertyu0970 | 0.333333
+ qwertyu0971 | 0.333333
+ qwertyu0972 | 0.333333
+ qwertyu0973 | 0.333333
+ qwertyu0974 | 0.333333
+ qwertyu0975 | 0.333333
+ qwertyu0976 | 0.333333
+ qwertyu0977 | 0.333333
+ qwertyu0978 | 0.333333
+ qwertyu0979 | 0.333333
+ qwertyu0990 | 0.333333
+ qwertyu0991 | 0.333333
+ qwertyu0992 | 0.333333
+ qwertyu0993 | 0.333333
+ qwertyu0994 | 0.333333
+ qwertyu0995 | 0.333333
+ qwertyu0996 | 0.333333
+ qwertyu0997 | 0.333333
+ qwertyu0998 | 0.333333
+ qwertyu0999 | 0.333333
+(110 rows)
+
+select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 0.333333
+(1 row)
+
+explain (costs off)
+select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+ QUERY PLAN
+---------------------------------------------------
+ Limit
+ -> Index Scan using trgm_idx on test_trgm
+ Order By: (t <-> 'q0987wertyu0988'::text)
+(3 rows)
+
+select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+ ?column? | t
+----------+-------------
+ 0.411765 | qwertyu0988
+ 0.5 | qwertyu0987
+(2 rows)
+
+select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}';
+ count
+-------
+ 1000
+(1 row)
+
+drop index trgm_idx;
+create index trgm_idx on test_trgm using gin (t gin_trgm_ops);
+set enable_seqscan=off;
+select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 1
+ qwertyu0980 | 0.714286
+ qwertyu0981 | 0.714286
+ qwertyu0982 | 0.714286
+ qwertyu0983 | 0.714286
+ qwertyu0984 | 0.714286
+ qwertyu0985 | 0.714286
+ qwertyu0986 | 0.714286
+ qwertyu0987 | 0.714286
+ qwertyu0989 | 0.714286
+ qwertyu0088 | 0.6
+ qwertyu0098 | 0.6
+ qwertyu0188 | 0.6
+ qwertyu0288 | 0.6
+ qwertyu0388 | 0.6
+ qwertyu0488 | 0.6
+ qwertyu0588 | 0.6
+ qwertyu0688 | 0.6
+ qwertyu0788 | 0.6
+ qwertyu0888 | 0.6
+ qwertyu0900 | 0.6
+ qwertyu0901 | 0.6
+ qwertyu0902 | 0.6
+ qwertyu0903 | 0.6
+ qwertyu0904 | 0.6
+ qwertyu0905 | 0.6
+ qwertyu0906 | 0.6
+ qwertyu0907 | 0.6
+ qwertyu0908 | 0.6
+ qwertyu0909 | 0.6
+ qwertyu0910 | 0.6
+ qwertyu0911 | 0.6
+ qwertyu0912 | 0.6
+ qwertyu0913 | 0.6
+ qwertyu0914 | 0.6
+ qwertyu0915 | 0.6
+ qwertyu0916 | 0.6
+ qwertyu0917 | 0.6
+ qwertyu0918 | 0.6
+ qwertyu0919 | 0.6
+ qwertyu0920 | 0.6
+ qwertyu0921 | 0.6
+ qwertyu0922 | 0.6
+ qwertyu0923 | 0.6
+ qwertyu0924 | 0.6
+ qwertyu0925 | 0.6
+ qwertyu0926 | 0.6
+ qwertyu0927 | 0.6
+ qwertyu0928 | 0.6
+ qwertyu0929 | 0.6
+ qwertyu0930 | 0.6
+ qwertyu0931 | 0.6
+ qwertyu0932 | 0.6
+ qwertyu0933 | 0.6
+ qwertyu0934 | 0.6
+ qwertyu0935 | 0.6
+ qwertyu0936 | 0.6
+ qwertyu0937 | 0.6
+ qwertyu0938 | 0.6
+ qwertyu0939 | 0.6
+ qwertyu0940 | 0.6
+ qwertyu0941 | 0.6
+ qwertyu0942 | 0.6
+ qwertyu0943 | 0.6
+ qwertyu0944 | 0.6
+ qwertyu0945 | 0.6
+ qwertyu0946 | 0.6
+ qwertyu0947 | 0.6
+ qwertyu0948 | 0.6
+ qwertyu0949 | 0.6
+ qwertyu0950 | 0.6
+ qwertyu0951 | 0.6
+ qwertyu0952 | 0.6
+ qwertyu0953 | 0.6
+ qwertyu0954 | 0.6
+ qwertyu0955 | 0.6
+ qwertyu0956 | 0.6
+ qwertyu0957 | 0.6
+ qwertyu0958 | 0.6
+ qwertyu0959 | 0.6
+ qwertyu0960 | 0.6
+ qwertyu0961 | 0.6
+ qwertyu0962 | 0.6
+ qwertyu0963 | 0.6
+ qwertyu0964 | 0.6
+ qwertyu0965 | 0.6
+ qwertyu0966 | 0.6
+ qwertyu0967 | 0.6
+ qwertyu0968 | 0.6
+ qwertyu0969 | 0.6
+ qwertyu0970 | 0.6
+ qwertyu0971 | 0.6
+ qwertyu0972 | 0.6
+ qwertyu0973 | 0.6
+ qwertyu0974 | 0.6
+ qwertyu0975 | 0.6
+ qwertyu0976 | 0.6
+ qwertyu0977 | 0.6
+ qwertyu0978 | 0.6
+ qwertyu0979 | 0.6
+ qwertyu0990 | 0.6
+ qwertyu0991 | 0.6
+ qwertyu0992 | 0.6
+ qwertyu0993 | 0.6
+ qwertyu0994 | 0.6
+ qwertyu0995 | 0.6
+ qwertyu0996 | 0.6
+ qwertyu0997 | 0.6
+ qwertyu0998 | 0.6
+ qwertyu0999 | 0.6
+ qwertyu0001 | 0.5
+ qwertyu0002 | 0.5
+ qwertyu0003 | 0.5
+ qwertyu0004 | 0.5
+ qwertyu0005 | 0.5
+ qwertyu0006 | 0.5
+ qwertyu0007 | 0.5
+ qwertyu0008 | 0.5
+ qwertyu0009 | 0.5
+ qwertyu0010 | 0.5
+ qwertyu0011 | 0.5
+ qwertyu0012 | 0.5
+ qwertyu0013 | 0.5
+ qwertyu0014 | 0.5
+ qwertyu0015 | 0.5
+ qwertyu0016 | 0.5
+ qwertyu0017 | 0.5
+ qwertyu0018 | 0.5
+ qwertyu0019 | 0.5
+ qwertyu0020 | 0.5
+ qwertyu0021 | 0.5
+ qwertyu0022 | 0.5
+ qwertyu0023 | 0.5
+ qwertyu0024 | 0.5
+ qwertyu0025 | 0.5
+ qwertyu0026 | 0.5
+ qwertyu0027 | 0.5
+ qwertyu0028 | 0.5
+ qwertyu0029 | 0.5
+ qwertyu0030 | 0.5
+ qwertyu0031 | 0.5
+ qwertyu0032 | 0.5
+ qwertyu0033 | 0.5
+ qwertyu0034 | 0.5
+ qwertyu0035 | 0.5
+ qwertyu0036 | 0.5
+ qwertyu0037 | 0.5
+ qwertyu0038 | 0.5
+ qwertyu0039 | 0.5
+ qwertyu0040 | 0.5
+ qwertyu0041 | 0.5
+ qwertyu0042 | 0.5
+ qwertyu0043 | 0.5
+ qwertyu0044 | 0.5
+ qwertyu0045 | 0.5
+ qwertyu0046 | 0.5
+ qwertyu0047 | 0.5
+ qwertyu0048 | 0.5
+ qwertyu0049 | 0.5
+ qwertyu0050 | 0.5
+ qwertyu0051 | 0.5
+ qwertyu0052 | 0.5
+ qwertyu0053 | 0.5
+ qwertyu0054 | 0.5
+ qwertyu0055 | 0.5
+ qwertyu0056 | 0.5
+ qwertyu0057 | 0.5
+ qwertyu0058 | 0.5
+ qwertyu0059 | 0.5
+ qwertyu0060 | 0.5
+ qwertyu0061 | 0.5
+ qwertyu0062 | 0.5
+ qwertyu0063 | 0.5
+ qwertyu0064 | 0.5
+ qwertyu0065 | 0.5
+ qwertyu0066 | 0.5
+ qwertyu0067 | 0.5
+ qwertyu0068 | 0.5
+ qwertyu0069 | 0.5
+ qwertyu0070 | 0.5
+ qwertyu0071 | 0.5
+ qwertyu0072 | 0.5
+ qwertyu0073 | 0.5
+ qwertyu0074 | 0.5
+ qwertyu0075 | 0.5
+ qwertyu0076 | 0.5
+ qwertyu0077 | 0.5
+ qwertyu0078 | 0.5
+ qwertyu0079 | 0.5
+ qwertyu0080 | 0.5
+ qwertyu0081 | 0.5
+ qwertyu0082 | 0.5
+ qwertyu0083 | 0.5
+ qwertyu0084 | 0.5
+ qwertyu0085 | 0.5
+ qwertyu0086 | 0.5
+ qwertyu0087 | 0.5
+ qwertyu0089 | 0.5
+ qwertyu0090 | 0.5
+ qwertyu0091 | 0.5
+ qwertyu0092 | 0.5
+ qwertyu0093 | 0.5
+ qwertyu0094 | 0.5
+ qwertyu0095 | 0.5
+ qwertyu0096 | 0.5
+ qwertyu0097 | 0.5
+ qwertyu0099 | 0.5
+ qwertyu0100 | 0.5
+ qwertyu0101 | 0.5
+ qwertyu0102 | 0.5
+ qwertyu0103 | 0.5
+ qwertyu0104 | 0.5
+ qwertyu0105 | 0.5
+ qwertyu0106 | 0.5
+ qwertyu0107 | 0.5
+ qwertyu0108 | 0.5
+ qwertyu0109 | 0.5
+ qwertyu0110 | 0.5
+ qwertyu0111 | 0.5
+ qwertyu0112 | 0.5
+ qwertyu0113 | 0.5
+ qwertyu0114 | 0.5
+ qwertyu0115 | 0.5
+ qwertyu0116 | 0.5
+ qwertyu0117 | 0.5
+ qwertyu0118 | 0.5
+ qwertyu0119 | 0.5
+ qwertyu0120 | 0.5
+ qwertyu0121 | 0.5
+ qwertyu0122 | 0.5
+ qwertyu0123 | 0.5
+ qwertyu0124 | 0.5
+ qwertyu0125 | 0.5
+ qwertyu0126 | 0.5
+ qwertyu0127 | 0.5
+ qwertyu0128 | 0.5
+ qwertyu0129 | 0.5
+ qwertyu0130 | 0.5
+ qwertyu0131 | 0.5
+ qwertyu0132 | 0.5
+ qwertyu0133 | 0.5
+ qwertyu0134 | 0.5
+ qwertyu0135 | 0.5
+ qwertyu0136 | 0.5
+ qwertyu0137 | 0.5
+ qwertyu0138 | 0.5
+ qwertyu0139 | 0.5
+ qwertyu0140 | 0.5
+ qwertyu0141 | 0.5
+ qwertyu0142 | 0.5
+ qwertyu0143 | 0.5
+ qwertyu0144 | 0.5
+ qwertyu0145 | 0.5
+ qwertyu0146 | 0.5
+ qwertyu0147 | 0.5
+ qwertyu0148 | 0.5
+ qwertyu0149 | 0.5
+ qwertyu0150 | 0.5
+ qwertyu0151 | 0.5
+ qwertyu0152 | 0.5
+ qwertyu0153 | 0.5
+ qwertyu0154 | 0.5
+ qwertyu0155 | 0.5
+ qwertyu0156 | 0.5
+ qwertyu0157 | 0.5
+ qwertyu0158 | 0.5
+ qwertyu0159 | 0.5
+ qwertyu0160 | 0.5
+ qwertyu0161 | 0.5
+ qwertyu0162 | 0.5
+ qwertyu0163 | 0.5
+ qwertyu0164 | 0.5
+ qwertyu0165 | 0.5
+ qwertyu0166 | 0.5
+ qwertyu0167 | 0.5
+ qwertyu0168 | 0.5
+ qwertyu0169 | 0.5
+ qwertyu0170 | 0.5
+ qwertyu0171 | 0.5
+ qwertyu0172 | 0.5
+ qwertyu0173 | 0.5
+ qwertyu0174 | 0.5
+ qwertyu0175 | 0.5
+ qwertyu0176 | 0.5
+ qwertyu0177 | 0.5
+ qwertyu0178 | 0.5
+ qwertyu0179 | 0.5
+ qwertyu0180 | 0.5
+ qwertyu0181 | 0.5
+ qwertyu0182 | 0.5
+ qwertyu0183 | 0.5
+ qwertyu0184 | 0.5
+ qwertyu0185 | 0.5
+ qwertyu0186 | 0.5
+ qwertyu0187 | 0.5
+ qwertyu0189 | 0.5
+ qwertyu0190 | 0.5
+ qwertyu0191 | 0.5
+ qwertyu0192 | 0.5
+ qwertyu0193 | 0.5
+ qwertyu0194 | 0.5
+ qwertyu0195 | 0.5
+ qwertyu0196 | 0.5
+ qwertyu0197 | 0.5
+ qwertyu0198 | 0.5
+ qwertyu0199 | 0.5
+ qwertyu0200 | 0.5
+ qwertyu0201 | 0.5
+ qwertyu0202 | 0.5
+ qwertyu0203 | 0.5
+ qwertyu0204 | 0.5
+ qwertyu0205 | 0.5
+ qwertyu0206 | 0.5
+ qwertyu0207 | 0.5
+ qwertyu0208 | 0.5
+ qwertyu0209 | 0.5
+ qwertyu0210 | 0.5
+ qwertyu0211 | 0.5
+ qwertyu0212 | 0.5
+ qwertyu0213 | 0.5
+ qwertyu0214 | 0.5
+ qwertyu0215 | 0.5
+ qwertyu0216 | 0.5
+ qwertyu0217 | 0.5
+ qwertyu0218 | 0.5
+ qwertyu0219 | 0.5
+ qwertyu0220 | 0.5
+ qwertyu0221 | 0.5
+ qwertyu0222 | 0.5
+ qwertyu0223 | 0.5
+ qwertyu0224 | 0.5
+ qwertyu0225 | 0.5
+ qwertyu0226 | 0.5
+ qwertyu0227 | 0.5
+ qwertyu0228 | 0.5
+ qwertyu0229 | 0.5
+ qwertyu0230 | 0.5
+ qwertyu0231 | 0.5
+ qwertyu0232 | 0.5
+ qwertyu0233 | 0.5
+ qwertyu0234 | 0.5
+ qwertyu0235 | 0.5
+ qwertyu0236 | 0.5
+ qwertyu0237 | 0.5
+ qwertyu0238 | 0.5
+ qwertyu0239 | 0.5
+ qwertyu0240 | 0.5
+ qwertyu0241 | 0.5
+ qwertyu0242 | 0.5
+ qwertyu0243 | 0.5
+ qwertyu0244 | 0.5
+ qwertyu0245 | 0.5
+ qwertyu0246 | 0.5
+ qwertyu0247 | 0.5
+ qwertyu0248 | 0.5
+ qwertyu0249 | 0.5
+ qwertyu0250 | 0.5
+ qwertyu0251 | 0.5
+ qwertyu0252 | 0.5
+ qwertyu0253 | 0.5
+ qwertyu0254 | 0.5
+ qwertyu0255 | 0.5
+ qwertyu0256 | 0.5
+ qwertyu0257 | 0.5
+ qwertyu0258 | 0.5
+ qwertyu0259 | 0.5
+ qwertyu0260 | 0.5
+ qwertyu0261 | 0.5
+ qwertyu0262 | 0.5
+ qwertyu0263 | 0.5
+ qwertyu0264 | 0.5
+ qwertyu0265 | 0.5
+ qwertyu0266 | 0.5
+ qwertyu0267 | 0.5
+ qwertyu0268 | 0.5
+ qwertyu0269 | 0.5
+ qwertyu0270 | 0.5
+ qwertyu0271 | 0.5
+ qwertyu0272 | 0.5
+ qwertyu0273 | 0.5
+ qwertyu0274 | 0.5
+ qwertyu0275 | 0.5
+ qwertyu0276 | 0.5
+ qwertyu0277 | 0.5
+ qwertyu0278 | 0.5
+ qwertyu0279 | 0.5
+ qwertyu0280 | 0.5
+ qwertyu0281 | 0.5
+ qwertyu0282 | 0.5
+ qwertyu0283 | 0.5
+ qwertyu0284 | 0.5
+ qwertyu0285 | 0.5
+ qwertyu0286 | 0.5
+ qwertyu0287 | 0.5
+ qwertyu0289 | 0.5
+ qwertyu0290 | 0.5
+ qwertyu0291 | 0.5
+ qwertyu0292 | 0.5
+ qwertyu0293 | 0.5
+ qwertyu0294 | 0.5
+ qwertyu0295 | 0.5
+ qwertyu0296 | 0.5
+ qwertyu0297 | 0.5
+ qwertyu0298 | 0.5
+ qwertyu0299 | 0.5
+ qwertyu0300 | 0.5
+ qwertyu0301 | 0.5
+ qwertyu0302 | 0.5
+ qwertyu0303 | 0.5
+ qwertyu0304 | 0.5
+ qwertyu0305 | 0.5
+ qwertyu0306 | 0.5
+ qwertyu0307 | 0.5
+ qwertyu0308 | 0.5
+ qwertyu0309 | 0.5
+ qwertyu0310 | 0.5
+ qwertyu0311 | 0.5
+ qwertyu0312 | 0.5
+ qwertyu0313 | 0.5
+ qwertyu0314 | 0.5
+ qwertyu0315 | 0.5
+ qwertyu0316 | 0.5
+ qwertyu0317 | 0.5
+ qwertyu0318 | 0.5
+ qwertyu0319 | 0.5
+ qwertyu0320 | 0.5
+ qwertyu0321 | 0.5
+ qwertyu0322 | 0.5
+ qwertyu0323 | 0.5
+ qwertyu0324 | 0.5
+ qwertyu0325 | 0.5
+ qwertyu0326 | 0.5
+ qwertyu0327 | 0.5
+ qwertyu0328 | 0.5
+ qwertyu0329 | 0.5
+ qwertyu0330 | 0.5
+ qwertyu0331 | 0.5
+ qwertyu0332 | 0.5
+ qwertyu0333 | 0.5
+ qwertyu0334 | 0.5
+ qwertyu0335 | 0.5
+ qwertyu0336 | 0.5
+ qwertyu0337 | 0.5
+ qwertyu0338 | 0.5
+ qwertyu0339 | 0.5
+ qwertyu0340 | 0.5
+ qwertyu0341 | 0.5
+ qwertyu0342 | 0.5
+ qwertyu0343 | 0.5
+ qwertyu0344 | 0.5
+ qwertyu0345 | 0.5
+ qwertyu0346 | 0.5
+ qwertyu0347 | 0.5
+ qwertyu0348 | 0.5
+ qwertyu0349 | 0.5
+ qwertyu0350 | 0.5
+ qwertyu0351 | 0.5
+ qwertyu0352 | 0.5
+ qwertyu0353 | 0.5
+ qwertyu0354 | 0.5
+ qwertyu0355 | 0.5
+ qwertyu0356 | 0.5
+ qwertyu0357 | 0.5
+ qwertyu0358 | 0.5
+ qwertyu0359 | 0.5
+ qwertyu0360 | 0.5
+ qwertyu0361 | 0.5
+ qwertyu0362 | 0.5
+ qwertyu0363 | 0.5
+ qwertyu0364 | 0.5
+ qwertyu0365 | 0.5
+ qwertyu0366 | 0.5
+ qwertyu0367 | 0.5
+ qwertyu0368 | 0.5
+ qwertyu0369 | 0.5
+ qwertyu0370 | 0.5
+ qwertyu0371 | 0.5
+ qwertyu0372 | 0.5
+ qwertyu0373 | 0.5
+ qwertyu0374 | 0.5
+ qwertyu0375 | 0.5
+ qwertyu0376 | 0.5
+ qwertyu0377 | 0.5
+ qwertyu0378 | 0.5
+ qwertyu0379 | 0.5
+ qwertyu0380 | 0.5
+ qwertyu0381 | 0.5
+ qwertyu0382 | 0.5
+ qwertyu0383 | 0.5
+ qwertyu0384 | 0.5
+ qwertyu0385 | 0.5
+ qwertyu0386 | 0.5
+ qwertyu0387 | 0.5
+ qwertyu0389 | 0.5
+ qwertyu0390 | 0.5
+ qwertyu0391 | 0.5
+ qwertyu0392 | 0.5
+ qwertyu0393 | 0.5
+ qwertyu0394 | 0.5
+ qwertyu0395 | 0.5
+ qwertyu0396 | 0.5
+ qwertyu0397 | 0.5
+ qwertyu0398 | 0.5
+ qwertyu0399 | 0.5
+ qwertyu0400 | 0.5
+ qwertyu0401 | 0.5
+ qwertyu0402 | 0.5
+ qwertyu0403 | 0.5
+ qwertyu0404 | 0.5
+ qwertyu0405 | 0.5
+ qwertyu0406 | 0.5
+ qwertyu0407 | 0.5
+ qwertyu0408 | 0.5
+ qwertyu0409 | 0.5
+ qwertyu0410 | 0.5
+ qwertyu0411 | 0.5
+ qwertyu0412 | 0.5
+ qwertyu0413 | 0.5
+ qwertyu0414 | 0.5
+ qwertyu0415 | 0.5
+ qwertyu0416 | 0.5
+ qwertyu0417 | 0.5
+ qwertyu0418 | 0.5
+ qwertyu0419 | 0.5
+ qwertyu0420 | 0.5
+ qwertyu0421 | 0.5
+ qwertyu0422 | 0.5
+ qwertyu0423 | 0.5
+ qwertyu0424 | 0.5
+ qwertyu0425 | 0.5
+ qwertyu0426 | 0.5
+ qwertyu0427 | 0.5
+ qwertyu0428 | 0.5
+ qwertyu0429 | 0.5
+ qwertyu0430 | 0.5
+ qwertyu0431 | 0.5
+ qwertyu0432 | 0.5
+ qwertyu0433 | 0.5
+ qwertyu0434 | 0.5
+ qwertyu0435 | 0.5
+ qwertyu0436 | 0.5
+ qwertyu0437 | 0.5
+ qwertyu0438 | 0.5
+ qwertyu0439 | 0.5
+ qwertyu0440 | 0.5
+ qwertyu0441 | 0.5
+ qwertyu0442 | 0.5
+ qwertyu0443 | 0.5
+ qwertyu0444 | 0.5
+ qwertyu0445 | 0.5
+ qwertyu0446 | 0.5
+ qwertyu0447 | 0.5
+ qwertyu0448 | 0.5
+ qwertyu0449 | 0.5
+ qwertyu0450 | 0.5
+ qwertyu0451 | 0.5
+ qwertyu0452 | 0.5
+ qwertyu0453 | 0.5
+ qwertyu0454 | 0.5
+ qwertyu0455 | 0.5
+ qwertyu0456 | 0.5
+ qwertyu0457 | 0.5
+ qwertyu0458 | 0.5
+ qwertyu0459 | 0.5
+ qwertyu0460 | 0.5
+ qwertyu0461 | 0.5
+ qwertyu0462 | 0.5
+ qwertyu0463 | 0.5
+ qwertyu0464 | 0.5
+ qwertyu0465 | 0.5
+ qwertyu0466 | 0.5
+ qwertyu0467 | 0.5
+ qwertyu0468 | 0.5
+ qwertyu0469 | 0.5
+ qwertyu0470 | 0.5
+ qwertyu0471 | 0.5
+ qwertyu0472 | 0.5
+ qwertyu0473 | 0.5
+ qwertyu0474 | 0.5
+ qwertyu0475 | 0.5
+ qwertyu0476 | 0.5
+ qwertyu0477 | 0.5
+ qwertyu0478 | 0.5
+ qwertyu0479 | 0.5
+ qwertyu0480 | 0.5
+ qwertyu0481 | 0.5
+ qwertyu0482 | 0.5
+ qwertyu0483 | 0.5
+ qwertyu0484 | 0.5
+ qwertyu0485 | 0.5
+ qwertyu0486 | 0.5
+ qwertyu0487 | 0.5
+ qwertyu0489 | 0.5
+ qwertyu0490 | 0.5
+ qwertyu0491 | 0.5
+ qwertyu0492 | 0.5
+ qwertyu0493 | 0.5
+ qwertyu0494 | 0.5
+ qwertyu0495 | 0.5
+ qwertyu0496 | 0.5
+ qwertyu0497 | 0.5
+ qwertyu0498 | 0.5
+ qwertyu0499 | 0.5
+ qwertyu0500 | 0.5
+ qwertyu0501 | 0.5
+ qwertyu0502 | 0.5
+ qwertyu0503 | 0.5
+ qwertyu0504 | 0.5
+ qwertyu0505 | 0.5
+ qwertyu0506 | 0.5
+ qwertyu0507 | 0.5
+ qwertyu0508 | 0.5
+ qwertyu0509 | 0.5
+ qwertyu0510 | 0.5
+ qwertyu0511 | 0.5
+ qwertyu0512 | 0.5
+ qwertyu0513 | 0.5
+ qwertyu0514 | 0.5
+ qwertyu0515 | 0.5
+ qwertyu0516 | 0.5
+ qwertyu0517 | 0.5
+ qwertyu0518 | 0.5
+ qwertyu0519 | 0.5
+ qwertyu0520 | 0.5
+ qwertyu0521 | 0.5
+ qwertyu0522 | 0.5
+ qwertyu0523 | 0.5
+ qwertyu0524 | 0.5
+ qwertyu0525 | 0.5
+ qwertyu0526 | 0.5
+ qwertyu0527 | 0.5
+ qwertyu0528 | 0.5
+ qwertyu0529 | 0.5
+ qwertyu0530 | 0.5
+ qwertyu0531 | 0.5
+ qwertyu0532 | 0.5
+ qwertyu0533 | 0.5
+ qwertyu0534 | 0.5
+ qwertyu0535 | 0.5
+ qwertyu0536 | 0.5
+ qwertyu0537 | 0.5
+ qwertyu0538 | 0.5
+ qwertyu0539 | 0.5
+ qwertyu0540 | 0.5
+ qwertyu0541 | 0.5
+ qwertyu0542 | 0.5
+ qwertyu0543 | 0.5
+ qwertyu0544 | 0.5
+ qwertyu0545 | 0.5
+ qwertyu0546 | 0.5
+ qwertyu0547 | 0.5
+ qwertyu0548 | 0.5
+ qwertyu0549 | 0.5
+ qwertyu0550 | 0.5
+ qwertyu0551 | 0.5
+ qwertyu0552 | 0.5
+ qwertyu0553 | 0.5
+ qwertyu0554 | 0.5
+ qwertyu0555 | 0.5
+ qwertyu0556 | 0.5
+ qwertyu0557 | 0.5
+ qwertyu0558 | 0.5
+ qwertyu0559 | 0.5
+ qwertyu0560 | 0.5
+ qwertyu0561 | 0.5
+ qwertyu0562 | 0.5
+ qwertyu0563 | 0.5
+ qwertyu0564 | 0.5
+ qwertyu0565 | 0.5
+ qwertyu0566 | 0.5
+ qwertyu0567 | 0.5
+ qwertyu0568 | 0.5
+ qwertyu0569 | 0.5
+ qwertyu0570 | 0.5
+ qwertyu0571 | 0.5
+ qwertyu0572 | 0.5
+ qwertyu0573 | 0.5
+ qwertyu0574 | 0.5
+ qwertyu0575 | 0.5
+ qwertyu0576 | 0.5
+ qwertyu0577 | 0.5
+ qwertyu0578 | 0.5
+ qwertyu0579 | 0.5
+ qwertyu0580 | 0.5
+ qwertyu0581 | 0.5
+ qwertyu0582 | 0.5
+ qwertyu0583 | 0.5
+ qwertyu0584 | 0.5
+ qwertyu0585 | 0.5
+ qwertyu0586 | 0.5
+ qwertyu0587 | 0.5
+ qwertyu0589 | 0.5
+ qwertyu0590 | 0.5
+ qwertyu0591 | 0.5
+ qwertyu0592 | 0.5
+ qwertyu0593 | 0.5
+ qwertyu0594 | 0.5
+ qwertyu0595 | 0.5
+ qwertyu0596 | 0.5
+ qwertyu0597 | 0.5
+ qwertyu0598 | 0.5
+ qwertyu0599 | 0.5
+ qwertyu0600 | 0.5
+ qwertyu0601 | 0.5
+ qwertyu0602 | 0.5
+ qwertyu0603 | 0.5
+ qwertyu0604 | 0.5
+ qwertyu0605 | 0.5
+ qwertyu0606 | 0.5
+ qwertyu0607 | 0.5
+ qwertyu0608 | 0.5
+ qwertyu0609 | 0.5
+ qwertyu0610 | 0.5
+ qwertyu0611 | 0.5
+ qwertyu0612 | 0.5
+ qwertyu0613 | 0.5
+ qwertyu0614 | 0.5
+ qwertyu0615 | 0.5
+ qwertyu0616 | 0.5
+ qwertyu0617 | 0.5
+ qwertyu0618 | 0.5
+ qwertyu0619 | 0.5
+ qwertyu0620 | 0.5
+ qwertyu0621 | 0.5
+ qwertyu0622 | 0.5
+ qwertyu0623 | 0.5
+ qwertyu0624 | 0.5
+ qwertyu0625 | 0.5
+ qwertyu0626 | 0.5
+ qwertyu0627 | 0.5
+ qwertyu0628 | 0.5
+ qwertyu0629 | 0.5
+ qwertyu0630 | 0.5
+ qwertyu0631 | 0.5
+ qwertyu0632 | 0.5
+ qwertyu0633 | 0.5
+ qwertyu0634 | 0.5
+ qwertyu0635 | 0.5
+ qwertyu0636 | 0.5
+ qwertyu0637 | 0.5
+ qwertyu0638 | 0.5
+ qwertyu0639 | 0.5
+ qwertyu0640 | 0.5
+ qwertyu0641 | 0.5
+ qwertyu0642 | 0.5
+ qwertyu0643 | 0.5
+ qwertyu0644 | 0.5
+ qwertyu0645 | 0.5
+ qwertyu0646 | 0.5
+ qwertyu0647 | 0.5
+ qwertyu0648 | 0.5
+ qwertyu0649 | 0.5
+ qwertyu0650 | 0.5
+ qwertyu0651 | 0.5
+ qwertyu0652 | 0.5
+ qwertyu0653 | 0.5
+ qwertyu0654 | 0.5
+ qwertyu0655 | 0.5
+ qwertyu0656 | 0.5
+ qwertyu0657 | 0.5
+ qwertyu0658 | 0.5
+ qwertyu0659 | 0.5
+ qwertyu0660 | 0.5
+ qwertyu0661 | 0.5
+ qwertyu0662 | 0.5
+ qwertyu0663 | 0.5
+ qwertyu0664 | 0.5
+ qwertyu0665 | 0.5
+ qwertyu0666 | 0.5
+ qwertyu0667 | 0.5
+ qwertyu0668 | 0.5
+ qwertyu0669 | 0.5
+ qwertyu0670 | 0.5
+ qwertyu0671 | 0.5
+ qwertyu0672 | 0.5
+ qwertyu0673 | 0.5
+ qwertyu0674 | 0.5
+ qwertyu0675 | 0.5
+ qwertyu0676 | 0.5
+ qwertyu0677 | 0.5
+ qwertyu0678 | 0.5
+ qwertyu0679 | 0.5
+ qwertyu0680 | 0.5
+ qwertyu0681 | 0.5
+ qwertyu0682 | 0.5
+ qwertyu0683 | 0.5
+ qwertyu0684 | 0.5
+ qwertyu0685 | 0.5
+ qwertyu0686 | 0.5
+ qwertyu0687 | 0.5
+ qwertyu0689 | 0.5
+ qwertyu0690 | 0.5
+ qwertyu0691 | 0.5
+ qwertyu0692 | 0.5
+ qwertyu0693 | 0.5
+ qwertyu0694 | 0.5
+ qwertyu0695 | 0.5
+ qwertyu0696 | 0.5
+ qwertyu0697 | 0.5
+ qwertyu0698 | 0.5
+ qwertyu0699 | 0.5
+ qwertyu0700 | 0.5
+ qwertyu0701 | 0.5
+ qwertyu0702 | 0.5
+ qwertyu0703 | 0.5
+ qwertyu0704 | 0.5
+ qwertyu0705 | 0.5
+ qwertyu0706 | 0.5
+ qwertyu0707 | 0.5
+ qwertyu0708 | 0.5
+ qwertyu0709 | 0.5
+ qwertyu0710 | 0.5
+ qwertyu0711 | 0.5
+ qwertyu0712 | 0.5
+ qwertyu0713 | 0.5
+ qwertyu0714 | 0.5
+ qwertyu0715 | 0.5
+ qwertyu0716 | 0.5
+ qwertyu0717 | 0.5
+ qwertyu0718 | 0.5
+ qwertyu0719 | 0.5
+ qwertyu0720 | 0.5
+ qwertyu0721 | 0.5
+ qwertyu0722 | 0.5
+ qwertyu0723 | 0.5
+ qwertyu0724 | 0.5
+ qwertyu0725 | 0.5
+ qwertyu0726 | 0.5
+ qwertyu0727 | 0.5
+ qwertyu0728 | 0.5
+ qwertyu0729 | 0.5
+ qwertyu0730 | 0.5
+ qwertyu0731 | 0.5
+ qwertyu0732 | 0.5
+ qwertyu0733 | 0.5
+ qwertyu0734 | 0.5
+ qwertyu0735 | 0.5
+ qwertyu0736 | 0.5
+ qwertyu0737 | 0.5
+ qwertyu0738 | 0.5
+ qwertyu0739 | 0.5
+ qwertyu0740 | 0.5
+ qwertyu0741 | 0.5
+ qwertyu0742 | 0.5
+ qwertyu0743 | 0.5
+ qwertyu0744 | 0.5
+ qwertyu0745 | 0.5
+ qwertyu0746 | 0.5
+ qwertyu0747 | 0.5
+ qwertyu0748 | 0.5
+ qwertyu0749 | 0.5
+ qwertyu0750 | 0.5
+ qwertyu0751 | 0.5
+ qwertyu0752 | 0.5
+ qwertyu0753 | 0.5
+ qwertyu0754 | 0.5
+ qwertyu0755 | 0.5
+ qwertyu0756 | 0.5
+ qwertyu0757 | 0.5
+ qwertyu0758 | 0.5
+ qwertyu0759 | 0.5
+ qwertyu0760 | 0.5
+ qwertyu0761 | 0.5
+ qwertyu0762 | 0.5
+ qwertyu0763 | 0.5
+ qwertyu0764 | 0.5
+ qwertyu0765 | 0.5
+ qwertyu0766 | 0.5
+ qwertyu0767 | 0.5
+ qwertyu0768 | 0.5
+ qwertyu0769 | 0.5
+ qwertyu0770 | 0.5
+ qwertyu0771 | 0.5
+ qwertyu0772 | 0.5
+ qwertyu0773 | 0.5
+ qwertyu0774 | 0.5
+ qwertyu0775 | 0.5
+ qwertyu0776 | 0.5
+ qwertyu0777 | 0.5
+ qwertyu0778 | 0.5
+ qwertyu0779 | 0.5
+ qwertyu0780 | 0.5
+ qwertyu0781 | 0.5
+ qwertyu0782 | 0.5
+ qwertyu0783 | 0.5
+ qwertyu0784 | 0.5
+ qwertyu0785 | 0.5
+ qwertyu0786 | 0.5
+ qwertyu0787 | 0.5
+ qwertyu0789 | 0.5
+ qwertyu0790 | 0.5
+ qwertyu0791 | 0.5
+ qwertyu0792 | 0.5
+ qwertyu0793 | 0.5
+ qwertyu0794 | 0.5
+ qwertyu0795 | 0.5
+ qwertyu0796 | 0.5
+ qwertyu0797 | 0.5
+ qwertyu0798 | 0.5
+ qwertyu0799 | 0.5
+ qwertyu0800 | 0.5
+ qwertyu0801 | 0.5
+ qwertyu0802 | 0.5
+ qwertyu0803 | 0.5
+ qwertyu0804 | 0.5
+ qwertyu0805 | 0.5
+ qwertyu0806 | 0.5
+ qwertyu0807 | 0.5
+ qwertyu0808 | 0.5
+ qwertyu0809 | 0.5
+ qwertyu0810 | 0.5
+ qwertyu0811 | 0.5
+ qwertyu0812 | 0.5
+ qwertyu0813 | 0.5
+ qwertyu0814 | 0.5
+ qwertyu0815 | 0.5
+ qwertyu0816 | 0.5
+ qwertyu0817 | 0.5
+ qwertyu0818 | 0.5
+ qwertyu0819 | 0.5
+ qwertyu0820 | 0.5
+ qwertyu0821 | 0.5
+ qwertyu0822 | 0.5
+ qwertyu0823 | 0.5
+ qwertyu0824 | 0.5
+ qwertyu0825 | 0.5
+ qwertyu0826 | 0.5
+ qwertyu0827 | 0.5
+ qwertyu0828 | 0.5
+ qwertyu0829 | 0.5
+ qwertyu0830 | 0.5
+ qwertyu0831 | 0.5
+ qwertyu0832 | 0.5
+ qwertyu0833 | 0.5
+ qwertyu0834 | 0.5
+ qwertyu0835 | 0.5
+ qwertyu0836 | 0.5
+ qwertyu0837 | 0.5
+ qwertyu0838 | 0.5
+ qwertyu0839 | 0.5
+ qwertyu0840 | 0.5
+ qwertyu0841 | 0.5
+ qwertyu0842 | 0.5
+ qwertyu0843 | 0.5
+ qwertyu0844 | 0.5
+ qwertyu0845 | 0.5
+ qwertyu0846 | 0.5
+ qwertyu0847 | 0.5
+ qwertyu0848 | 0.5
+ qwertyu0849 | 0.5
+ qwertyu0850 | 0.5
+ qwertyu0851 | 0.5
+ qwertyu0852 | 0.5
+ qwertyu0853 | 0.5
+ qwertyu0854 | 0.5
+ qwertyu0855 | 0.5
+ qwertyu0856 | 0.5
+ qwertyu0857 | 0.5
+ qwertyu0858 | 0.5
+ qwertyu0859 | 0.5
+ qwertyu0860 | 0.5
+ qwertyu0861 | 0.5
+ qwertyu0862 | 0.5
+ qwertyu0863 | 0.5
+ qwertyu0864 | 0.5
+ qwertyu0865 | 0.5
+ qwertyu0866 | 0.5
+ qwertyu0867 | 0.5
+ qwertyu0868 | 0.5
+ qwertyu0869 | 0.5
+ qwertyu0870 | 0.5
+ qwertyu0871 | 0.5
+ qwertyu0872 | 0.5
+ qwertyu0873 | 0.5
+ qwertyu0874 | 0.5
+ qwertyu0875 | 0.5
+ qwertyu0876 | 0.5
+ qwertyu0877 | 0.5
+ qwertyu0878 | 0.5
+ qwertyu0879 | 0.5
+ qwertyu0880 | 0.5
+ qwertyu0881 | 0.5
+ qwertyu0882 | 0.5
+ qwertyu0883 | 0.5
+ qwertyu0884 | 0.5
+ qwertyu0885 | 0.5
+ qwertyu0886 | 0.5
+ qwertyu0887 | 0.5
+ qwertyu0889 | 0.5
+ qwertyu0890 | 0.5
+ qwertyu0891 | 0.5
+ qwertyu0892 | 0.5
+ qwertyu0893 | 0.5
+ qwertyu0894 | 0.5
+ qwertyu0895 | 0.5
+ qwertyu0896 | 0.5
+ qwertyu0897 | 0.5
+ qwertyu0898 | 0.5
+ qwertyu0899 | 0.5
+ qwertyu1000 | 0.411765
+(1000 rows)
+
+select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 0.6
+ qwertyu0980 | 0.411765
+ qwertyu0981 | 0.411765
+ qwertyu0982 | 0.411765
+ qwertyu0983 | 0.411765
+ qwertyu0984 | 0.411765
+ qwertyu0985 | 0.411765
+ qwertyu0986 | 0.411765
+ qwertyu0987 | 0.411765
+ qwertyu0989 | 0.411765
+ qwertyu0088 | 0.333333
+ qwertyu0098 | 0.333333
+ qwertyu0188 | 0.333333
+ qwertyu0288 | 0.333333
+ qwertyu0388 | 0.333333
+ qwertyu0488 | 0.333333
+ qwertyu0588 | 0.333333
+ qwertyu0688 | 0.333333
+ qwertyu0788 | 0.333333
+ qwertyu0888 | 0.333333
+ qwertyu0900 | 0.333333
+ qwertyu0901 | 0.333333
+ qwertyu0902 | 0.333333
+ qwertyu0903 | 0.333333
+ qwertyu0904 | 0.333333
+ qwertyu0905 | 0.333333
+ qwertyu0906 | 0.333333
+ qwertyu0907 | 0.333333
+ qwertyu0908 | 0.333333
+ qwertyu0909 | 0.333333
+ qwertyu0910 | 0.333333
+ qwertyu0911 | 0.333333
+ qwertyu0912 | 0.333333
+ qwertyu0913 | 0.333333
+ qwertyu0914 | 0.333333
+ qwertyu0915 | 0.333333
+ qwertyu0916 | 0.333333
+ qwertyu0917 | 0.333333
+ qwertyu0918 | 0.333333
+ qwertyu0919 | 0.333333
+ qwertyu0920 | 0.333333
+ qwertyu0921 | 0.333333
+ qwertyu0922 | 0.333333
+ qwertyu0923 | 0.333333
+ qwertyu0924 | 0.333333
+ qwertyu0925 | 0.333333
+ qwertyu0926 | 0.333333
+ qwertyu0927 | 0.333333
+ qwertyu0928 | 0.333333
+ qwertyu0929 | 0.333333
+ qwertyu0930 | 0.333333
+ qwertyu0931 | 0.333333
+ qwertyu0932 | 0.333333
+ qwertyu0933 | 0.333333
+ qwertyu0934 | 0.333333
+ qwertyu0935 | 0.333333
+ qwertyu0936 | 0.333333
+ qwertyu0937 | 0.333333
+ qwertyu0938 | 0.333333
+ qwertyu0939 | 0.333333
+ qwertyu0940 | 0.333333
+ qwertyu0941 | 0.333333
+ qwertyu0942 | 0.333333
+ qwertyu0943 | 0.333333
+ qwertyu0944 | 0.333333
+ qwertyu0945 | 0.333333
+ qwertyu0946 | 0.333333
+ qwertyu0947 | 0.333333
+ qwertyu0948 | 0.333333
+ qwertyu0949 | 0.333333
+ qwertyu0950 | 0.333333
+ qwertyu0951 | 0.333333
+ qwertyu0952 | 0.333333
+ qwertyu0953 | 0.333333
+ qwertyu0954 | 0.333333
+ qwertyu0955 | 0.333333
+ qwertyu0956 | 0.333333
+ qwertyu0957 | 0.333333
+ qwertyu0958 | 0.333333
+ qwertyu0959 | 0.333333
+ qwertyu0960 | 0.333333
+ qwertyu0961 | 0.333333
+ qwertyu0962 | 0.333333
+ qwertyu0963 | 0.333333
+ qwertyu0964 | 0.333333
+ qwertyu0965 | 0.333333
+ qwertyu0966 | 0.333333
+ qwertyu0967 | 0.333333
+ qwertyu0968 | 0.333333
+ qwertyu0969 | 0.333333
+ qwertyu0970 | 0.333333
+ qwertyu0971 | 0.333333
+ qwertyu0972 | 0.333333
+ qwertyu0973 | 0.333333
+ qwertyu0974 | 0.333333
+ qwertyu0975 | 0.333333
+ qwertyu0976 | 0.333333
+ qwertyu0977 | 0.333333
+ qwertyu0978 | 0.333333
+ qwertyu0979 | 0.333333
+ qwertyu0990 | 0.333333
+ qwertyu0991 | 0.333333
+ qwertyu0992 | 0.333333
+ qwertyu0993 | 0.333333
+ qwertyu0994 | 0.333333
+ qwertyu0995 | 0.333333
+ qwertyu0996 | 0.333333
+ qwertyu0997 | 0.333333
+ qwertyu0998 | 0.333333
+ qwertyu0999 | 0.333333
+(110 rows)
+
+select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t;
+ t | sml
+-------------+----------
+ qwertyu0988 | 0.333333
+(1 row)
+
+select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}';
+ count
+-------
+ 1000
+(1 row)
+
+-- check handling of indexquals that generate no searchable conditions
+explain (costs off)
+select count(*) from test_trgm where t like '%99%' and t like '%qwerty%';
+ QUERY PLAN
+-----------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on test_trgm
+ Recheck Cond: ((t ~~ '%99%'::text) AND (t ~~ '%qwerty%'::text))
+ -> Bitmap Index Scan on trgm_idx
+ Index Cond: ((t ~~ '%99%'::text) AND (t ~~ '%qwerty%'::text))
+(5 rows)
+
+select count(*) from test_trgm where t like '%99%' and t like '%qwerty%';
+ count
+-------
+ 19
+(1 row)
+
+explain (costs off)
+select count(*) from test_trgm where t like '%99%' and t like '%qw%';
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on test_trgm
+ Recheck Cond: ((t ~~ '%99%'::text) AND (t ~~ '%qw%'::text))
+ -> Bitmap Index Scan on trgm_idx
+ Index Cond: ((t ~~ '%99%'::text) AND (t ~~ '%qw%'::text))
+(5 rows)
+
+select count(*) from test_trgm where t like '%99%' and t like '%qw%';
+ count
+-------
+ 19
+(1 row)
+
+-- ensure that pending-list items are handled correctly, too
+create temp table t_test_trgm(t text COLLATE "C");
+create index t_trgm_idx on t_test_trgm using gin (t gin_trgm_ops);
+insert into t_test_trgm values ('qwerty99'), ('qwerty01');
+explain (costs off)
+select count(*) from t_test_trgm where t like '%99%' and t like '%qwerty%';
+ QUERY PLAN
+-----------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on t_test_trgm
+ Recheck Cond: ((t ~~ '%99%'::text) AND (t ~~ '%qwerty%'::text))
+ -> Bitmap Index Scan on t_trgm_idx
+ Index Cond: ((t ~~ '%99%'::text) AND (t ~~ '%qwerty%'::text))
+(5 rows)
+
+select count(*) from t_test_trgm where t like '%99%' and t like '%qwerty%';
+ count
+-------
+ 1
+(1 row)
+
+explain (costs off)
+select count(*) from t_test_trgm where t like '%99%' and t like '%qw%';
+ QUERY PLAN
+-------------------------------------------------------------------------
+ Aggregate
+ -> Bitmap Heap Scan on t_test_trgm
+ Recheck Cond: ((t ~~ '%99%'::text) AND (t ~~ '%qw%'::text))
+ -> Bitmap Index Scan on t_trgm_idx
+ Index Cond: ((t ~~ '%99%'::text) AND (t ~~ '%qw%'::text))
+(5 rows)
+
+select count(*) from t_test_trgm where t like '%99%' and t like '%qw%';
+ count
+-------
+ 1
+(1 row)
+
+-- run the same queries with sequential scan to check the results
+set enable_bitmapscan=off;
+set enable_seqscan=on;
+select count(*) from test_trgm where t like '%99%' and t like '%qwerty%';
+ count
+-------
+ 19
+(1 row)
+
+select count(*) from test_trgm where t like '%99%' and t like '%qw%';
+ count
+-------
+ 19
+(1 row)
+
+select count(*) from t_test_trgm where t like '%99%' and t like '%qwerty%';
+ count
+-------
+ 1
+(1 row)
+
+select count(*) from t_test_trgm where t like '%99%' and t like '%qw%';
+ count
+-------
+ 1
+(1 row)
+
+reset enable_bitmapscan;
+create table test2(t text COLLATE "C");
+insert into test2 values ('abcdef');
+insert into test2 values ('quark');
+insert into test2 values (' z foo bar');
+insert into test2 values ('/123/-45/');
+insert into test2 values ('line 1');
+insert into test2 values ('%line 2');
+insert into test2 values ('line 3%');
+insert into test2 values ('%line 4%');
+insert into test2 values ('%li%ne 5%');
+insert into test2 values ('li_e 6');
+create index test2_idx_gin on test2 using gin (t gin_trgm_ops);
+set enable_seqscan=off;
+explain (costs off)
+ select * from test2 where t like '%BCD%';
+ QUERY PLAN
+------------------------------------------
+ Bitmap Heap Scan on test2
+ Recheck Cond: (t ~~ '%BCD%'::text)
+ -> Bitmap Index Scan on test2_idx_gin
+ Index Cond: (t ~~ '%BCD%'::text)
+(4 rows)
+
+explain (costs off)
+ select * from test2 where t ilike '%BCD%';
+ QUERY PLAN
+-------------------------------------------
+ Bitmap Heap Scan on test2
+ Recheck Cond: (t ~~* '%BCD%'::text)
+ -> Bitmap Index Scan on test2_idx_gin
+ Index Cond: (t ~~* '%BCD%'::text)
+(4 rows)
+
+select * from test2 where t like '%BCD%';
+ t
+---
+(0 rows)
+
+select * from test2 where t like '%bcd%';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t like E'%\\bcd%';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ilike '%BCD%';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ilike 'qua%';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t like '%z foo bar%';
+ t
+-------------
+ z foo bar
+(1 row)
+
+select * from test2 where t like ' z foo%';
+ t
+-------------
+ z foo bar
+(1 row)
+
+explain (costs off)
+ select * from test2 where t ~ '[abc]{3}';
+ QUERY PLAN
+--------------------------------------------
+ Bitmap Heap Scan on test2
+ Recheck Cond: (t ~ '[abc]{3}'::text)
+ -> Bitmap Index Scan on test2_idx_gin
+ Index Cond: (t ~ '[abc]{3}'::text)
+(4 rows)
+
+explain (costs off)
+ select * from test2 where t ~* 'DEF';
+ QUERY PLAN
+------------------------------------------
+ Bitmap Heap Scan on test2
+ Recheck Cond: (t ~* 'DEF'::text)
+ -> Bitmap Index Scan on test2_idx_gin
+ Index Cond: (t ~* 'DEF'::text)
+(4 rows)
+
+select * from test2 where t ~ '[abc]{3}';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ~ 'a[bc]+d';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ~ '(abc)*$';
+ t
+-------------
+ abcdef
+ quark
+ z foo bar
+ /123/-45/
+ line 1
+ %line 2
+ line 3%
+ %line 4%
+ %li%ne 5%
+ li_e 6
+(10 rows)
+
+select * from test2 where t ~* 'DEF';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ~ 'dEf';
+ t
+---
+(0 rows)
+
+select * from test2 where t ~* '^q';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t ~* '[abc]{3}[def]{3}';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ~* 'ab[a-z]{3}';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ~* '(^| )qua';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t ~ 'q.*rk$';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t ~ 'q';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t ~ '[a-z]{3}';
+ t
+-------------
+ abcdef
+ quark
+ z foo bar
+ line 1
+ %line 2
+ line 3%
+ %line 4%
+(7 rows)
+
+select * from test2 where t ~* '(a{10}|b{10}|c{10}){10}';
+ t
+---
+(0 rows)
+
+select * from test2 where t ~ 'z foo bar';
+ t
+-------------
+ z foo bar
+(1 row)
+
+select * from test2 where t ~ ' z foo bar';
+ t
+-------------
+ z foo bar
+(1 row)
+
+select * from test2 where t ~ ' z foo bar';
+ t
+-------------
+ z foo bar
+(1 row)
+
+select * from test2 where t ~ ' z foo';
+ t
+-------------
+ z foo bar
+(1 row)
+
+select * from test2 where t ~ 'qua(?!foo)';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t ~ '/\d+/-\d';
+ t
+-----------
+ /123/-45/
+(1 row)
+
+-- test = operator
+explain (costs off)
+ select * from test2 where t = 'abcdef';
+ QUERY PLAN
+------------------------------------------
+ Bitmap Heap Scan on test2
+ Recheck Cond: (t = 'abcdef'::text)
+ -> Bitmap Index Scan on test2_idx_gin
+ Index Cond: (t = 'abcdef'::text)
+(4 rows)
+
+select * from test2 where t = 'abcdef';
+ t
+--------
+ abcdef
+(1 row)
+
+explain (costs off)
+ select * from test2 where t = '%line%';
+ QUERY PLAN
+------------------------------------------
+ Bitmap Heap Scan on test2
+ Recheck Cond: (t = '%line%'::text)
+ -> Bitmap Index Scan on test2_idx_gin
+ Index Cond: (t = '%line%'::text)
+(4 rows)
+
+select * from test2 where t = '%line%';
+ t
+---
+(0 rows)
+
+select * from test2 where t = 'li_e 1';
+ t
+---
+(0 rows)
+
+select * from test2 where t = '%line 2';
+ t
+---------
+ %line 2
+(1 row)
+
+select * from test2 where t = 'line 3%';
+ t
+---------
+ line 3%
+(1 row)
+
+select * from test2 where t = '%line 3%';
+ t
+---
+(0 rows)
+
+select * from test2 where t = '%line 4%';
+ t
+----------
+ %line 4%
+(1 row)
+
+select * from test2 where t = '%line 5%';
+ t
+---
+(0 rows)
+
+select * from test2 where t = '%li_ne 5%';
+ t
+---
+(0 rows)
+
+select * from test2 where t = '%li%ne 5%';
+ t
+-----------
+ %li%ne 5%
+(1 row)
+
+select * from test2 where t = 'line 6';
+ t
+---
+(0 rows)
+
+select * from test2 where t = 'li_e 6';
+ t
+--------
+ li_e 6
+(1 row)
+
+drop index test2_idx_gin;
+create index test2_idx_gist on test2 using gist (t gist_trgm_ops);
+set enable_seqscan=off;
+explain (costs off)
+ select * from test2 where t like '%BCD%';
+ QUERY PLAN
+------------------------------------------
+ Index Scan using test2_idx_gist on test2
+ Index Cond: (t ~~ '%BCD%'::text)
+(2 rows)
+
+explain (costs off)
+ select * from test2 where t ilike '%BCD%';
+ QUERY PLAN
+------------------------------------------
+ Index Scan using test2_idx_gist on test2
+ Index Cond: (t ~~* '%BCD%'::text)
+(2 rows)
+
+select * from test2 where t like '%BCD%';
+ t
+---
+(0 rows)
+
+select * from test2 where t like '%bcd%';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t like E'%\\bcd%';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ilike '%BCD%';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ilike 'qua%';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t like '%z foo bar%';
+ t
+-------------
+ z foo bar
+(1 row)
+
+select * from test2 where t like ' z foo%';
+ t
+-------------
+ z foo bar
+(1 row)
+
+explain (costs off)
+ select * from test2 where t ~ '[abc]{3}';
+ QUERY PLAN
+------------------------------------------
+ Index Scan using test2_idx_gist on test2
+ Index Cond: (t ~ '[abc]{3}'::text)
+(2 rows)
+
+explain (costs off)
+ select * from test2 where t ~* 'DEF';
+ QUERY PLAN
+------------------------------------------
+ Index Scan using test2_idx_gist on test2
+ Index Cond: (t ~* 'DEF'::text)
+(2 rows)
+
+select * from test2 where t ~ '[abc]{3}';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ~ 'a[bc]+d';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ~ '(abc)*$';
+ t
+-------------
+ abcdef
+ quark
+ z foo bar
+ /123/-45/
+ line 1
+ %line 2
+ line 3%
+ %line 4%
+ %li%ne 5%
+ li_e 6
+(10 rows)
+
+select * from test2 where t ~* 'DEF';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ~ 'dEf';
+ t
+---
+(0 rows)
+
+select * from test2 where t ~* '^q';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t ~* '[abc]{3}[def]{3}';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ~* 'ab[a-z]{3}';
+ t
+--------
+ abcdef
+(1 row)
+
+select * from test2 where t ~* '(^| )qua';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t ~ 'q.*rk$';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t ~ 'q';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t ~ '[a-z]{3}';
+ t
+-------------
+ abcdef
+ quark
+ z foo bar
+ line 1
+ %line 2
+ line 3%
+ %line 4%
+(7 rows)
+
+select * from test2 where t ~* '(a{10}|b{10}|c{10}){10}';
+ t
+---
+(0 rows)
+
+select * from test2 where t ~ 'z foo bar';
+ t
+-------------
+ z foo bar
+(1 row)
+
+select * from test2 where t ~ ' z foo bar';
+ t
+-------------
+ z foo bar
+(1 row)
+
+select * from test2 where t ~ ' z foo bar';
+ t
+-------------
+ z foo bar
+(1 row)
+
+select * from test2 where t ~ ' z foo';
+ t
+-------------
+ z foo bar
+(1 row)
+
+select * from test2 where t ~ 'qua(?!foo)';
+ t
+-------
+ quark
+(1 row)
+
+select * from test2 where t ~ '/\d+/-\d';
+ t
+-----------
+ /123/-45/
+(1 row)
+
+-- test = operator
+explain (costs off)
+ select * from test2 where t = 'abcdef';
+ QUERY PLAN
+------------------------------------------
+ Index Scan using test2_idx_gist on test2
+ Index Cond: (t = 'abcdef'::text)
+(2 rows)
+
+select * from test2 where t = 'abcdef';
+ t
+--------
+ abcdef
+(1 row)
+
+explain (costs off)
+ select * from test2 where t = '%line%';
+ QUERY PLAN
+------------------------------------------
+ Index Scan using test2_idx_gist on test2
+ Index Cond: (t = '%line%'::text)
+(2 rows)
+
+select * from test2 where t = '%line%';
+ t
+---
+(0 rows)
+
+select * from test2 where t = 'li_e 1';
+ t
+---
+(0 rows)
+
+select * from test2 where t = '%line 2';
+ t
+---------
+ %line 2
+(1 row)
+
+select * from test2 where t = 'line 3%';
+ t
+---------
+ line 3%
+(1 row)
+
+select * from test2 where t = '%line 3%';
+ t
+---
+(0 rows)
+
+select * from test2 where t = '%line 4%';
+ t
+----------
+ %line 4%
+(1 row)
+
+select * from test2 where t = '%line 5%';
+ t
+---
+(0 rows)
+
+select * from test2 where t = '%li_ne 5%';
+ t
+---
+(0 rows)
+
+select * from test2 where t = '%li%ne 5%';
+ t
+-----------
+ %li%ne 5%
+(1 row)
+
+select * from test2 where t = 'line 6';
+ t
+---
+(0 rows)
+
+select * from test2 where t = 'li_e 6';
+ t
+--------
+ li_e 6
+(1 row)
+
+-- Check similarity threshold (bug #14202)
+CREATE TEMP TABLE restaurants (city text);
+INSERT INTO restaurants SELECT 'Warsaw' FROM generate_series(1, 10000);
+INSERT INTO restaurants SELECT 'Szczecin' FROM generate_series(1, 10000);
+CREATE INDEX ON restaurants USING gist(city gist_trgm_ops);
+-- Similarity of the two names (for reference).
+SELECT similarity('Szczecin', 'Warsaw');
+ similarity
+------------
+ 0
+(1 row)
+
+-- Should get only 'Warsaw' for either setting of set_limit.
+EXPLAIN (COSTS OFF)
+SELECT DISTINCT city, similarity(city, 'Warsaw'), show_limit()
+ FROM restaurants WHERE city % 'Warsaw';
+ QUERY PLAN
+-------------------------------------------------------
+ HashAggregate
+ Group Key: city, similarity(city, 'Warsaw'::text)
+ -> Bitmap Heap Scan on restaurants
+ Recheck Cond: (city % 'Warsaw'::text)
+ -> Bitmap Index Scan on restaurants_city_idx
+ Index Cond: (city % 'Warsaw'::text)
+(6 rows)
+
+SELECT set_limit(0.3);
+ set_limit
+-----------
+ 0.3
+(1 row)
+
+SELECT DISTINCT city, similarity(city, 'Warsaw'), show_limit()
+ FROM restaurants WHERE city % 'Warsaw';
+ city | similarity | show_limit
+--------+------------+------------
+ Warsaw | 1 | 0.3
+(1 row)
+
+SELECT set_limit(0.5);
+ set_limit
+-----------
+ 0.5
+(1 row)
+
+SELECT DISTINCT city, similarity(city, 'Warsaw'), show_limit()
+ FROM restaurants WHERE city % 'Warsaw';
+ city | similarity | show_limit
+--------+------------+------------
+ Warsaw | 1 | 0.5
+(1 row)
+
diff --git a/contrib/pg_trgm/expected/pg_word_trgm.out b/contrib/pg_trgm/expected/pg_word_trgm.out
new file mode 100644
index 0000000..c66a67f
--- /dev/null
+++ b/contrib/pg_trgm/expected/pg_word_trgm.out
@@ -0,0 +1,1052 @@
+CREATE TABLE test_trgm2(t text COLLATE "C");
+\copy test_trgm2 from 'data/trgm2.data'
+-- reduce noise
+set extra_float_digits = 0;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalikha | 0.857143
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.857143
+ Baykalovo | 0.857143
+ Baykalovsk | 0.857143
+ Baykalovskiy | 0.857143
+ Baykalovskiy Rayon | 0.857143
+ Baykalsko | 0.857143
+ Maloye Baykalovo | 0.857143
+ Zabaykal | 0.714286
+(20 rows)
+
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t;
+ t | sml
+------------------------------+-----
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.9
+ Abankala | 0.7
+ Ntombankala School | 0.6
+(4 rows)
+
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalikha | 0.857143
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.857143
+ Baykalovo | 0.857143
+ Baykalovsk | 0.857143
+ Baykalovskiy | 0.857143
+ Baykalovskiy Rayon | 0.857143
+ Baykalsko | 0.857143
+ Maloye Baykalovo | 0.857143
+ Zabaykal | 0.714286
+(20 rows)
+
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kabankala' order by sml desc, t;
+ t | sml
+------------------------------+-----
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.9
+ Abankala | 0.7
+ Ntombankala School | 0.6
+(4 rows)
+
+select t <->> 'Kabankala', t from test_trgm2 order by t <->> 'Kabankala' limit 7;
+ ?column? | t
+----------+----------------------------------
+ 0 | Kabankala
+ 0.1 | Kabankalan City Public Plaza
+ 0.3 | Abankala
+ 0.4 | Ntombankala School
+ 0.416667 | Kabakala
+ 0.5 | Nehalla Bankalah Reserved Forest
+ 0.538462 | Kabikala
+(7 rows)
+
+create index trgm_idx2 on test_trgm2 using gist (t gist_trgm_ops);
+set enable_seqscan=off;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalikha | 0.857143
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.857143
+ Baykalovo | 0.857143
+ Baykalovsk | 0.857143
+ Baykalovskiy | 0.857143
+ Baykalovskiy Rayon | 0.857143
+ Baykalsko | 0.857143
+ Maloye Baykalovo | 0.857143
+ Zabaykal | 0.714286
+(20 rows)
+
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t;
+ t | sml
+------------------------------+-----
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.9
+ Abankala | 0.7
+ Ntombankala School | 0.6
+(4 rows)
+
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalikha | 0.857143
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.857143
+ Baykalovo | 0.857143
+ Baykalovsk | 0.857143
+ Baykalovskiy | 0.857143
+ Baykalovskiy Rayon | 0.857143
+ Baykalsko | 0.857143
+ Maloye Baykalovo | 0.857143
+ Zabaykal | 0.714286
+(20 rows)
+
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kabankala' order by sml desc, t;
+ t | sml
+------------------------------+-----
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.9
+ Abankala | 0.7
+ Ntombankala School | 0.6
+(4 rows)
+
+explain (costs off)
+select t <->> 'Kabankala', t from test_trgm2 order by t <->> 'Kabankala' limit 7;
+ QUERY PLAN
+------------------------------------------------
+ Limit
+ -> Index Scan using trgm_idx2 on test_trgm2
+ Order By: (t <->> 'Kabankala'::text)
+(3 rows)
+
+select t <->> 'Kabankala', t from test_trgm2 order by t <->> 'Kabankala' limit 7;
+ ?column? | t
+----------+----------------------------------
+ 0 | Kabankala
+ 0.1 | Kabankalan City Public Plaza
+ 0.3 | Abankala
+ 0.4 | Ntombankala School
+ 0.416667 | Kabakala
+ 0.5 | Nehalla Bankalah Reserved Forest
+ 0.538462 | Kabikala
+(7 rows)
+
+drop index trgm_idx2;
+create index trgm_idx2 on test_trgm2 using gin (t gin_trgm_ops);
+set enable_seqscan=off;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalikha | 0.857143
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.857143
+ Baykalovo | 0.857143
+ Baykalovsk | 0.857143
+ Baykalovskiy | 0.857143
+ Baykalovskiy Rayon | 0.857143
+ Baykalsko | 0.857143
+ Maloye Baykalovo | 0.857143
+ Zabaykal | 0.714286
+(20 rows)
+
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t;
+ t | sml
+------------------------------+-----
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.9
+ Abankala | 0.7
+ Ntombankala School | 0.6
+(4 rows)
+
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalikha | 0.857143
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.857143
+ Baykalovo | 0.857143
+ Baykalovsk | 0.857143
+ Baykalovskiy | 0.857143
+ Baykalovskiy Rayon | 0.857143
+ Baykalsko | 0.857143
+ Maloye Baykalovo | 0.857143
+ Zabaykal | 0.714286
+(20 rows)
+
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kabankala' order by sml desc, t;
+ t | sml
+------------------------------+-----
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.9
+ Abankala | 0.7
+ Ntombankala School | 0.6
+(4 rows)
+
+set "pg_trgm.word_similarity_threshold" to 0.5;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalikha | 0.857143
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.857143
+ Baykalovo | 0.857143
+ Baykalovsk | 0.857143
+ Baykalovskiy | 0.857143
+ Baykalovskiy Rayon | 0.857143
+ Baykalsko | 0.857143
+ Maloye Baykalovo | 0.857143
+ Zabaykal | 0.714286
+ Bakal Batu | 0.571429
+ Zabaykalka | 0.571429
+ Zabaykalovskiy | 0.571429
+(23 rows)
+
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t;
+ t | sml
+----------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.9
+ Abankala | 0.7
+ Ntombankala School | 0.6
+ Kabakala | 0.583333
+ Nehalla Bankalah Reserved Forest | 0.5
+(6 rows)
+
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t;
+ t | sml
+-------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalikha | 0.857143
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.857143
+ Baykalovo | 0.857143
+ Baykalovsk | 0.857143
+ Baykalovskiy | 0.857143
+ Baykalovskiy Rayon | 0.857143
+ Baykalsko | 0.857143
+ Maloye Baykalovo | 0.857143
+ Zabaykal | 0.714286
+ Bakal Batu | 0.571429
+ Zabaykalka | 0.571429
+ Zabaykalovskiy | 0.571429
+(23 rows)
+
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kabankala' order by sml desc, t;
+ t | sml
+----------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.9
+ Abankala | 0.7
+ Ntombankala School | 0.6
+ Kabakala | 0.583333
+ Nehalla Bankalah Reserved Forest | 0.5
+(6 rows)
+
+set "pg_trgm.word_similarity_threshold" to 0.3;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
+ t | sml
+-----------------------------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalikha | 0.857143
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.857143
+ Baykalovo | 0.857143
+ Baykalovsk | 0.857143
+ Baykalovskiy | 0.857143
+ Baykalovskiy Rayon | 0.857143
+ Baykalsko | 0.857143
+ Maloye Baykalovo | 0.857143
+ Zabaykal | 0.714286
+ Bakal Batu | 0.571429
+ Zabaykalka | 0.571429
+ Zabaykalovskiy | 0.571429
+ Air Bakal-kecil | 0.444444
+ Bakal | 0.444444
+ Bakal Dos | 0.444444
+ Bakal Julu | 0.444444
+ Bakal Khel | 0.444444
+ Bakal Lama | 0.444444
+ Bakal Tres | 0.444444
+ Bakal Uno | 0.444444
+ Daang Bakal | 0.444444
+ Desa Bakal | 0.444444
+ Eat Bakal | 0.444444
+ Gunung Bakal | 0.444444
+ Sidi Bakal | 0.444444
+ Stantsiya Bakal | 0.444444
+ Sungai Bakal | 0.444444
+ Talang Bakal | 0.444444
+ Uruk Bakal | 0.444444
+ Zaouia Oulad Bakal | 0.444444
+ Al Barkali | 0.428571
+ Aparthotel Adagio Premium Dubai Al Barsha | 0.428571
+ Baikal Business Centre | 0.428571
+ Bay of Backaland | 0.428571
+ Boikalakalawa Bay | 0.428571
+ Doubletree By Hilton Dubai Al Barsha Hotel and Res | 0.428571
+ Doubletree By Hilton Hotel and Apartments Dubai Al Barsha | 0.428571
+ Doubletree Res.Dubai-Al Barsha | 0.428571
+ Holiday Inn Dubai Al Barsha | 0.428571
+ Jabal Barkal | 0.428571
+ Novotel Dubai Al Barsha | 0.428571
+ Park Inn By Radisson Dubai Al Barsha | 0.428571
+ Ramee Rose Hotel Dubai Al Barsha | 0.428571
+ Waikalabubu Bay | 0.428571
+ Baikal | 0.4
+ Baikal Airfield | 0.4
+ Baikal Hotel Moscow | 0.4
+ Baikal Listvyanka Hotel | 0.4
+ Baikal Mountains | 0.4
+ Baikal Plaza | 0.4
+ Bajkal | 0.4
+ Bankal | 0.4
+ Bankal School | 0.4
+ Barkal | 0.4
+ Lake Baikal | 0.4
+ Mbay Bakala | 0.4
+ Oulad el Bakkal | 0.4
+ Sidi Mohammed Bakkal | 0.4
+ Bairkal | 0.363636
+ Bairkal Dhora | 0.363636
+ Bairkal Jabal | 0.363636
+ Batikal | 0.363636
+ Bakala | 0.333333
+ Bakala Koupi | 0.333333
+ Bakalaale | 0.333333
+ Bakalabwa Pans | 0.333333
+ Bakalaeng | 0.333333
+ Bakalafoulou | 0.333333
+ Bakalalan Airport | 0.333333
+ Bakalam | 0.333333
+ Bakalambani | 0.333333
+ Bakalan | 0.333333
+ Bakalan Barat | 0.333333
+ Bakalan Dua | 0.333333
+ Bakalan Kidul | 0.333333
+ Bakalan Kulon | 0.333333
+ Bakalan Lor | 0.333333
+ Bakalan River | 0.333333
+ Bakalan Tengah | 0.333333
+ Bakalan Wetan | 0.333333
+ Bakalang | 0.333333
+ Bakalao Asibi Point | 0.333333
+ Bakalao Point | 0.333333
+ Bakalar Air Force Base (historical) | 0.333333
+ Bakalar Lake | 0.333333
+ Bakalar Library | 0.333333
+ Bakalarr | 0.333333
+ Bakalauri | 0.333333
+ Bakalauri1 | 0.333333
+ Bakalauri2 | 0.333333
+ Bakalauri3 | 0.333333
+ Bakalauri4 | 0.333333
+ Bakalauri5 | 0.333333
+ Bakalauri6 | 0.333333
+ Bakalauri7 | 0.333333
+ Bakalauri8 | 0.333333
+ Bakalauri9 | 0.333333
+ Bakalawa | 0.333333
+ Bakalbhar | 0.333333
+ Bakalbuah | 0.333333
+ Bakalda | 0.333333
+ Bakaldalam | 0.333333
+ Bakaldinskoye | 0.333333
+ Bakaldovshchina | 0.333333
+ Bakaldukuh | 0.333333
+ Bakaldum | 0.333333
+ Bakaldy | 0.333333
+ Bakale | 0.333333
+ Bakaleko | 0.333333
+ Bakalerek | 0.333333
+ Bakaley | 0.333333
+ Bakaleyka | 0.333333
+ Bakalha | 0.333333
+ Bakali | 0.333333
+ Bakalia Char | 0.333333
+ Bakalica | 0.333333
+ Bakalinga | 0.333333
+ Bakalino | 0.333333
+ Bakalinskiy | 0.333333
+ Bakalinskiy Leskhoz | 0.333333
+ Bakalinskiy Rayon | 0.333333
+ Bakalipur | 0.333333
+ Bakalite | 0.333333
+ Bakaljaya | 0.333333
+ Bakalka | 0.333333
+ Bakall | 0.333333
+ Bakalnica | 0.333333
+ Bakalod Island | 0.333333
+ Bakalongo | 0.333333
+ Bakaloolay | 0.333333
+ Bakalou | 0.333333
+ Bakalovina | 0.333333
+ Bakalovka | 0.333333
+ Bakalovo | 0.333333
+ Bakalovskaya Ferma | 0.333333
+ Bakalpakebo | 0.333333
+ Bakalpokok | 0.333333
+ Bakalrejo | 0.333333
+ Bakalsen | 0.333333
+ Bakalshile | 0.333333
+ Bakaltua Bank | 0.333333
+ Bakalua | 0.333333
+ Bakalukalu | 0.333333
+ Bakalukalu Shan | 0.333333
+ Bakalukudu | 0.333333
+ Bakalum | 0.333333
+ Bakaly | 0.333333
+ Bakaly TV Mast | 0.333333
+ Buur Bakale | 0.333333
+ Buur Bakaley | 0.333333
+ Columbus Bakalar Municipal Airport | 0.333333
+ Dakshin Bakalia | 0.333333
+ Danau Bakalan | 0.333333
+ Desa Bakalan | 0.333333
+ Desa Bakalankrajan | 0.333333
+ Desa Bakalankrapyak | 0.333333
+ Desa Bakalanpule | 0.333333
+ Desa Bakalanrayung | 0.333333
+ Desa Bakalanwringinpitu | 0.333333
+ Desa Bakalrejo | 0.333333
+ Efrejtor Bakalovo | 0.333333
+ Efreytor-Bakalovo | 0.333333
+ Gora Bakalyadyr | 0.333333
+ Gory Bakaly | 0.333333
+ Gunung Bakalan | 0.333333
+ Ile Bakalibu | 0.333333
+ Kali Bakalan | 0.333333
+ Kampong Bakaladong | 0.333333
+ Khor Bakallii | 0.333333
+ Krajan Bakalan | 0.333333
+ Kusu-Bakali | 0.333333
+ Kwala Bakala | 0.333333
+ Ngao Bakala | 0.333333
+ Ovrag Bakalda | 0.333333
+ Pematang Bakalpanang | 0.333333
+ Pematang Bakalpanjang | 0.333333
+ Pulau Bakalan | 0.333333
+ Pulau Bakalanpauno | 0.333333
+ Ragha Bakalzai | 0.333333
+ Rodnik Bakalybulak | 0.333333
+ Salu Bakalaeng | 0.333333
+ Selat Bakalan | 0.333333
+ Selat Bakalanpauno | 0.333333
+ Sidi Mohammed el Bakali | 0.333333
+ Sopka Bakaly | 0.333333
+ Sovkhoz Bakalinskiy | 0.333333
+ Sungai Bakala | 0.333333
+ Sungai Bakaladiyan | 0.333333
+ Tanjung Bakalinga | 0.333333
+ Teluk Bakalan | 0.333333
+ Teluk Bakalang | 0.333333
+ Tubu Bakalekuk | 0.333333
+ Tukad Bakalan | 0.333333
+ Urochishche Bakalarnyn-Ayasy | 0.333333
+ Urochishche Bakaldikha | 0.333333
+ Urochishche Bakalovo | 0.333333
+ Urochishche Bakaly | 0.333333
+ Bakkalmal | 0.307692
+ Alue Bakkala | 0.3
+ Azib el Bakkali | 0.3
+ Ba Kaliin | 0.3
+ Bagkalen | 0.3
+ Bahkalleh | 0.3
+ Baikalakko | 0.3
+ Baikalovo | 0.3
+ Baikaluobbal | 0.3
+ Bakkala Cemetery | 0.3
+ Bakkalale | 0.3
+ Bakkalegskardet | 0.3
+ Bakkalia | 0.3
+ Bakkalykkja | 0.3
+ Bankali | 0.3
+ Bankalol | 0.3
+ Barkala | 0.3
+ Barkala Park | 0.3
+ Barkala Rao | 0.3
+ Barkala Reserved Forest | 0.3
+ Barkalabava | 0.3
+ Barkaladja Pool | 0.3
+ Barkalare | 0.3
+ Barkald | 0.3
+ Barkald stasjon | 0.3
+ Barkalden | 0.3
+ Barkaldfossen | 0.3
+ Barkaldvola | 0.3
+ Barkale | 0.3
+ Barkaleh | 0.3
+ Barkaleitet | 0.3
+ Barkali | 0.3
+ Barkallou | 0.3
+ Barkalne | 0.3
+ Barkalova | 0.3
+ Barkalovka | 0.3
+ Barkalow Hollow | 0.3
+ Baskalino | 0.3
+ Baskaltsi | 0.3
+ Baukala | 0.3
+ Bavkalasis | 0.3
+ Bawkalut | 0.3
+ Bawkalut Chaung | 0.3
+ Bikal | 0.3
+ Clifton T Barkalow Elementary School | 0.3
+ Gora Barkalova | 0.3
+ Gora Barkalyu | 0.3
+ Khrebet Batkali | 0.3
+ Kordon Barkalo | 0.3
+ Nehalla Bankalah Reserved Forest | 0.3
+ Ras Barkallah | 0.3
+ Sopka Barkaleptskaya | 0.3
+ Urochishche Batkali | 0.3
+(261 rows)
+
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t;
+ t | sml
+----------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.9
+ Abankala | 0.7
+ Ntombankala School | 0.6
+ Kabakala | 0.583333
+ Nehalla Bankalah Reserved Forest | 0.5
+ Kabikala | 0.461538
+ Mwalaba-Kalamba | 0.454545
+ Bakala Koupi | 0.4
+ Bankal | 0.4
+ Bankal School | 0.4
+ Bankali | 0.4
+ Bankalol | 0.4
+ Jabba Kalai | 0.4
+ Kanampumba-Kalawa | 0.4
+ Purba Kalaujan | 0.4
+ Tumba-Kalamba | 0.4
+ Daba Kalharereh | 0.363636
+ Gagaba Kalo | 0.363636
+ Jaba Kalle | 0.363636
+ Dabakala | 0.333333
+ Dalabakala | 0.333333
+ Kambakala | 0.333333
+ Ker Samba Kalla | 0.333333
+ Fayzabadkala | 0.307692
+ Gora Fayzabadkala | 0.307692
+ Guba Kalgalaksha | 0.307692
+ Habakkala | 0.307692
+ Kaikalahun Indian Reserve 25 | 0.307692
+ Kaikalapettai | 0.307692
+ Alue Bakkala | 0.3
+ Ambadikala | 0.3
+ Ambakala Wewa | 0.3
+ Ataikala | 0.3
+ Ba Kaliin | 0.3
+ Bakala | 0.3
+ Bakkala Cemetery | 0.3
+ Bambakala | 0.3
+ Barkala | 0.3
+ Barkala Park | 0.3
+ Barkala Rao | 0.3
+ Barkala Reserved Forest | 0.3
+ Baukala | 0.3
+ Beikala | 0.3
+ Bikala | 0.3
+ Bikala Madila | 0.3
+ Bomba-Kalende | 0.3
+ Bonagbakala | 0.3
+ Boyagbakala | 0.3
+ Bugor Arba-Kalgan | 0.3
+ Bumba-Kaloki | 0.3
+ Bumba-Kalumba | 0.3
+ Darreh Pumba Kal | 0.3
+ Demba Kali | 0.3
+ Embatkala | 0.3
+ Gereba Kaler | 0.3
+ Golba Kalo | 0.3
+ Goth Soba Kaloi | 0.3
+ Guba Kaldo | 0.3
+ Guba Kalita | 0.3
+ Gulba Kalle | 0.3
+ Haikala | 0.3
+ Kali Bakalan | 0.3
+ Kali Purbakala | 0.3
+ Kalibakal | 0.3
+ Kalibakalako | 0.3
+ Kalimundubakalan | 0.3
+ Kamba-Kalele | 0.3
+ Kimbakala | 0.3
+ Kombakala | 0.3
+ Kwala Bakala | 0.3
+ Laikala | 0.3
+ Maikala Range | 0.3
+ Mambakala | 0.3
+ Matamba-Kalenga | 0.3
+ Matamba-Kalenge | 0.3
+ Mbay Bakala | 0.3
+ Mount Tohebakala | 0.3
+ Naikala | 0.3
+ Ngao Bakala | 0.3
+ Purba Kalmegha | 0.3
+ Sungai Bakala | 0.3
+ Tagobikala | 0.3
+ Tanjung Batikala | 0.3
+ Tombakala | 0.3
+ Tsibakala | 0.3
+ Tumba-Kalumba | 0.3
+ Tumba-Kalunga | 0.3
+ Waikala | 0.3
+(89 rows)
+
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t;
+ t | sml
+-----------------------------------------------------------+----------
+ Baykal | 1
+ Boloto Baykal | 1
+ Boloto Malyy Baykal | 1
+ Kolkhoz Krasnyy Baykal | 1
+ Ozero Baykal | 1
+ Polevoy Stan Baykal | 1
+ Port Baykal | 1
+ Prud Novyy Baykal | 1
+ Sanatoriy Baykal | 1
+ Stantsiya Baykal | 1
+ Zaliv Baykal | 1
+ Baykalikha | 0.857143
+ Baykalo-Amurskaya Zheleznaya Doroga | 0.857143
+ Baykalovo | 0.857143
+ Baykalovsk | 0.857143
+ Baykalovskiy | 0.857143
+ Baykalovskiy Rayon | 0.857143
+ Baykalsko | 0.857143
+ Maloye Baykalovo | 0.857143
+ Zabaykal | 0.714286
+ Bakal Batu | 0.571429
+ Zabaykalka | 0.571429
+ Zabaykalovskiy | 0.571429
+ Air Bakal-kecil | 0.444444
+ Bakal | 0.444444
+ Bakal Dos | 0.444444
+ Bakal Julu | 0.444444
+ Bakal Khel | 0.444444
+ Bakal Lama | 0.444444
+ Bakal Tres | 0.444444
+ Bakal Uno | 0.444444
+ Daang Bakal | 0.444444
+ Desa Bakal | 0.444444
+ Eat Bakal | 0.444444
+ Gunung Bakal | 0.444444
+ Sidi Bakal | 0.444444
+ Stantsiya Bakal | 0.444444
+ Sungai Bakal | 0.444444
+ Talang Bakal | 0.444444
+ Uruk Bakal | 0.444444
+ Zaouia Oulad Bakal | 0.444444
+ Al Barkali | 0.428571
+ Aparthotel Adagio Premium Dubai Al Barsha | 0.428571
+ Baikal Business Centre | 0.428571
+ Bay of Backaland | 0.428571
+ Boikalakalawa Bay | 0.428571
+ Doubletree By Hilton Dubai Al Barsha Hotel and Res | 0.428571
+ Doubletree By Hilton Hotel and Apartments Dubai Al Barsha | 0.428571
+ Doubletree Res.Dubai-Al Barsha | 0.428571
+ Holiday Inn Dubai Al Barsha | 0.428571
+ Jabal Barkal | 0.428571
+ Novotel Dubai Al Barsha | 0.428571
+ Park Inn By Radisson Dubai Al Barsha | 0.428571
+ Ramee Rose Hotel Dubai Al Barsha | 0.428571
+ Waikalabubu Bay | 0.428571
+ Baikal | 0.4
+ Baikal Airfield | 0.4
+ Baikal Hotel Moscow | 0.4
+ Baikal Listvyanka Hotel | 0.4
+ Baikal Mountains | 0.4
+ Baikal Plaza | 0.4
+ Bajkal | 0.4
+ Bankal | 0.4
+ Bankal School | 0.4
+ Barkal | 0.4
+ Lake Baikal | 0.4
+ Mbay Bakala | 0.4
+ Oulad el Bakkal | 0.4
+ Sidi Mohammed Bakkal | 0.4
+ Bairkal | 0.363636
+ Bairkal Dhora | 0.363636
+ Bairkal Jabal | 0.363636
+ Batikal | 0.363636
+ Bakala | 0.333333
+ Bakala Koupi | 0.333333
+ Bakalaale | 0.333333
+ Bakalabwa Pans | 0.333333
+ Bakalaeng | 0.333333
+ Bakalafoulou | 0.333333
+ Bakalalan Airport | 0.333333
+ Bakalam | 0.333333
+ Bakalambani | 0.333333
+ Bakalan | 0.333333
+ Bakalan Barat | 0.333333
+ Bakalan Dua | 0.333333
+ Bakalan Kidul | 0.333333
+ Bakalan Kulon | 0.333333
+ Bakalan Lor | 0.333333
+ Bakalan River | 0.333333
+ Bakalan Tengah | 0.333333
+ Bakalan Wetan | 0.333333
+ Bakalang | 0.333333
+ Bakalao Asibi Point | 0.333333
+ Bakalao Point | 0.333333
+ Bakalar Air Force Base (historical) | 0.333333
+ Bakalar Lake | 0.333333
+ Bakalar Library | 0.333333
+ Bakalarr | 0.333333
+ Bakalauri | 0.333333
+ Bakalauri1 | 0.333333
+ Bakalauri2 | 0.333333
+ Bakalauri3 | 0.333333
+ Bakalauri4 | 0.333333
+ Bakalauri5 | 0.333333
+ Bakalauri6 | 0.333333
+ Bakalauri7 | 0.333333
+ Bakalauri8 | 0.333333
+ Bakalauri9 | 0.333333
+ Bakalawa | 0.333333
+ Bakalbhar | 0.333333
+ Bakalbuah | 0.333333
+ Bakalda | 0.333333
+ Bakaldalam | 0.333333
+ Bakaldinskoye | 0.333333
+ Bakaldovshchina | 0.333333
+ Bakaldukuh | 0.333333
+ Bakaldum | 0.333333
+ Bakaldy | 0.333333
+ Bakale | 0.333333
+ Bakaleko | 0.333333
+ Bakalerek | 0.333333
+ Bakaley | 0.333333
+ Bakaleyka | 0.333333
+ Bakalha | 0.333333
+ Bakali | 0.333333
+ Bakalia Char | 0.333333
+ Bakalica | 0.333333
+ Bakalinga | 0.333333
+ Bakalino | 0.333333
+ Bakalinskiy | 0.333333
+ Bakalinskiy Leskhoz | 0.333333
+ Bakalinskiy Rayon | 0.333333
+ Bakalipur | 0.333333
+ Bakalite | 0.333333
+ Bakaljaya | 0.333333
+ Bakalka | 0.333333
+ Bakall | 0.333333
+ Bakalnica | 0.333333
+ Bakalod Island | 0.333333
+ Bakalongo | 0.333333
+ Bakaloolay | 0.333333
+ Bakalou | 0.333333
+ Bakalovina | 0.333333
+ Bakalovka | 0.333333
+ Bakalovo | 0.333333
+ Bakalovskaya Ferma | 0.333333
+ Bakalpakebo | 0.333333
+ Bakalpokok | 0.333333
+ Bakalrejo | 0.333333
+ Bakalsen | 0.333333
+ Bakalshile | 0.333333
+ Bakaltua Bank | 0.333333
+ Bakalua | 0.333333
+ Bakalukalu | 0.333333
+ Bakalukalu Shan | 0.333333
+ Bakalukudu | 0.333333
+ Bakalum | 0.333333
+ Bakaly | 0.333333
+ Bakaly TV Mast | 0.333333
+ Buur Bakale | 0.333333
+ Buur Bakaley | 0.333333
+ Columbus Bakalar Municipal Airport | 0.333333
+ Dakshin Bakalia | 0.333333
+ Danau Bakalan | 0.333333
+ Desa Bakalan | 0.333333
+ Desa Bakalankrajan | 0.333333
+ Desa Bakalankrapyak | 0.333333
+ Desa Bakalanpule | 0.333333
+ Desa Bakalanrayung | 0.333333
+ Desa Bakalanwringinpitu | 0.333333
+ Desa Bakalrejo | 0.333333
+ Efrejtor Bakalovo | 0.333333
+ Efreytor-Bakalovo | 0.333333
+ Gora Bakalyadyr | 0.333333
+ Gory Bakaly | 0.333333
+ Gunung Bakalan | 0.333333
+ Ile Bakalibu | 0.333333
+ Kali Bakalan | 0.333333
+ Kampong Bakaladong | 0.333333
+ Khor Bakallii | 0.333333
+ Krajan Bakalan | 0.333333
+ Kusu-Bakali | 0.333333
+ Kwala Bakala | 0.333333
+ Ngao Bakala | 0.333333
+ Ovrag Bakalda | 0.333333
+ Pematang Bakalpanang | 0.333333
+ Pematang Bakalpanjang | 0.333333
+ Pulau Bakalan | 0.333333
+ Pulau Bakalanpauno | 0.333333
+ Ragha Bakalzai | 0.333333
+ Rodnik Bakalybulak | 0.333333
+ Salu Bakalaeng | 0.333333
+ Selat Bakalan | 0.333333
+ Selat Bakalanpauno | 0.333333
+ Sidi Mohammed el Bakali | 0.333333
+ Sopka Bakaly | 0.333333
+ Sovkhoz Bakalinskiy | 0.333333
+ Sungai Bakala | 0.333333
+ Sungai Bakaladiyan | 0.333333
+ Tanjung Bakalinga | 0.333333
+ Teluk Bakalan | 0.333333
+ Teluk Bakalang | 0.333333
+ Tubu Bakalekuk | 0.333333
+ Tukad Bakalan | 0.333333
+ Urochishche Bakalarnyn-Ayasy | 0.333333
+ Urochishche Bakaldikha | 0.333333
+ Urochishche Bakalovo | 0.333333
+ Urochishche Bakaly | 0.333333
+ Bakkalmal | 0.307692
+ Alue Bakkala | 0.3
+ Azib el Bakkali | 0.3
+ Ba Kaliin | 0.3
+ Bagkalen | 0.3
+ Bahkalleh | 0.3
+ Baikalakko | 0.3
+ Baikalovo | 0.3
+ Baikaluobbal | 0.3
+ Bakkala Cemetery | 0.3
+ Bakkalale | 0.3
+ Bakkalegskardet | 0.3
+ Bakkalia | 0.3
+ Bakkalykkja | 0.3
+ Bankali | 0.3
+ Bankalol | 0.3
+ Barkala | 0.3
+ Barkala Park | 0.3
+ Barkala Rao | 0.3
+ Barkala Reserved Forest | 0.3
+ Barkalabava | 0.3
+ Barkaladja Pool | 0.3
+ Barkalare | 0.3
+ Barkald | 0.3
+ Barkald stasjon | 0.3
+ Barkalden | 0.3
+ Barkaldfossen | 0.3
+ Barkaldvola | 0.3
+ Barkale | 0.3
+ Barkaleh | 0.3
+ Barkaleitet | 0.3
+ Barkali | 0.3
+ Barkallou | 0.3
+ Barkalne | 0.3
+ Barkalova | 0.3
+ Barkalovka | 0.3
+ Barkalow Hollow | 0.3
+ Baskalino | 0.3
+ Baskaltsi | 0.3
+ Baukala | 0.3
+ Bavkalasis | 0.3
+ Bawkalut | 0.3
+ Bawkalut Chaung | 0.3
+ Bikal | 0.3
+ Clifton T Barkalow Elementary School | 0.3
+ Gora Barkalova | 0.3
+ Gora Barkalyu | 0.3
+ Khrebet Batkali | 0.3
+ Kordon Barkalo | 0.3
+ Nehalla Bankalah Reserved Forest | 0.3
+ Ras Barkallah | 0.3
+ Sopka Barkaleptskaya | 0.3
+ Urochishche Batkali | 0.3
+(261 rows)
+
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kabankala' order by sml desc, t;
+ t | sml
+----------------------------------+----------
+ Kabankala | 1
+ Kabankalan City Public Plaza | 0.9
+ Abankala | 0.7
+ Ntombankala School | 0.6
+ Kabakala | 0.583333
+ Nehalla Bankalah Reserved Forest | 0.5
+ Kabikala | 0.461538
+ Mwalaba-Kalamba | 0.454545
+ Bakala Koupi | 0.4
+ Bankal | 0.4
+ Bankal School | 0.4
+ Bankali | 0.4
+ Bankalol | 0.4
+ Jabba Kalai | 0.4
+ Kanampumba-Kalawa | 0.4
+ Purba Kalaujan | 0.4
+ Tumba-Kalamba | 0.4
+ Daba Kalharereh | 0.363636
+ Gagaba Kalo | 0.363636
+ Jaba Kalle | 0.363636
+ Dabakala | 0.333333
+ Dalabakala | 0.333333
+ Kambakala | 0.333333
+ Ker Samba Kalla | 0.333333
+ Fayzabadkala | 0.307692
+ Gora Fayzabadkala | 0.307692
+ Guba Kalgalaksha | 0.307692
+ Habakkala | 0.307692
+ Kaikalahun Indian Reserve 25 | 0.307692
+ Kaikalapettai | 0.307692
+ Alue Bakkala | 0.3
+ Ambadikala | 0.3
+ Ambakala Wewa | 0.3
+ Ataikala | 0.3
+ Ba Kaliin | 0.3
+ Bakala | 0.3
+ Bakkala Cemetery | 0.3
+ Bambakala | 0.3
+ Barkala | 0.3
+ Barkala Park | 0.3
+ Barkala Rao | 0.3
+ Barkala Reserved Forest | 0.3
+ Baukala | 0.3
+ Beikala | 0.3
+ Bikala | 0.3
+ Bikala Madila | 0.3
+ Bomba-Kalende | 0.3
+ Bonagbakala | 0.3
+ Boyagbakala | 0.3
+ Bugor Arba-Kalgan | 0.3
+ Bumba-Kaloki | 0.3
+ Bumba-Kalumba | 0.3
+ Darreh Pumba Kal | 0.3
+ Demba Kali | 0.3
+ Embatkala | 0.3
+ Gereba Kaler | 0.3
+ Golba Kalo | 0.3
+ Goth Soba Kaloi | 0.3
+ Guba Kaldo | 0.3
+ Guba Kalita | 0.3
+ Gulba Kalle | 0.3
+ Haikala | 0.3
+ Kali Bakalan | 0.3
+ Kali Purbakala | 0.3
+ Kalibakal | 0.3
+ Kalibakalako | 0.3
+ Kalimundubakalan | 0.3
+ Kamba-Kalele | 0.3
+ Kimbakala | 0.3
+ Kombakala | 0.3
+ Kwala Bakala | 0.3
+ Laikala | 0.3
+ Maikala Range | 0.3
+ Mambakala | 0.3
+ Matamba-Kalenga | 0.3
+ Matamba-Kalenge | 0.3
+ Mbay Bakala | 0.3
+ Mount Tohebakala | 0.3
+ Naikala | 0.3
+ Ngao Bakala | 0.3
+ Purba Kalmegha | 0.3
+ Sungai Bakala | 0.3
+ Tagobikala | 0.3
+ Tanjung Batikala | 0.3
+ Tombakala | 0.3
+ Tsibakala | 0.3
+ Tumba-Kalumba | 0.3
+ Tumba-Kalunga | 0.3
+ Waikala | 0.3
+(89 rows)
+
+-- test unsatisfiable pattern
+select * from test_trgm2 where t ~ '.*$x';
+ t
+---
+(0 rows)
+
diff --git a/contrib/pg_trgm/meson.build b/contrib/pg_trgm/meson.build
new file mode 100644
index 0000000..093ac18
--- /dev/null
+++ b/contrib/pg_trgm/meson.build
@@ -0,0 +1,46 @@
+# Copyright (c) 2022-2023, PostgreSQL Global Development Group
+
+pg_trgm_sources = files(
+ 'trgm_gin.c',
+ 'trgm_gist.c',
+ 'trgm_op.c',
+ 'trgm_regexp.c',
+)
+
+if host_system == 'windows'
+ pg_trgm_sources += rc_lib_gen.process(win32ver_rc, extra_args: [
+ '--NAME', 'pg_trgm',
+ '--FILEDESC', 'pg_trgm - trigram matching',])
+endif
+
+pg_trgm = shared_module('pg_trgm',
+ pg_trgm_sources,
+ c_pch: pch_postgres_h,
+ kwargs: contrib_mod_args,
+)
+contrib_targets += pg_trgm
+
+install_data(
+ 'pg_trgm--1.0--1.1.sql',
+ 'pg_trgm--1.1--1.2.sql',
+ 'pg_trgm--1.2--1.3.sql',
+ 'pg_trgm--1.3--1.4.sql',
+ 'pg_trgm--1.3.sql',
+ 'pg_trgm--1.4--1.5.sql',
+ 'pg_trgm--1.5--1.6.sql',
+ 'pg_trgm.control',
+ kwargs: contrib_data_args,
+)
+
+tests += {
+ 'name': 'pg_trgm',
+ 'sd': meson.current_source_dir(),
+ 'bd': meson.current_build_dir(),
+ 'regress': {
+ 'sql': [
+ 'pg_trgm',
+ 'pg_word_trgm',
+ 'pg_strict_word_trgm',
+ ],
+ },
+}
diff --git a/contrib/pg_trgm/pg_trgm--1.0--1.1.sql b/contrib/pg_trgm/pg_trgm--1.0--1.1.sql
new file mode 100644
index 0000000..b4e3e26
--- /dev/null
+++ b/contrib/pg_trgm/pg_trgm--1.0--1.1.sql
@@ -0,0 +1,12 @@
+/* contrib/pg_trgm/pg_trgm--1.0--1.1.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pg_trgm UPDATE TO '1.1'" to load this file. \quit
+
+ALTER OPERATOR FAMILY gist_trgm_ops USING gist ADD
+ OPERATOR 5 pg_catalog.~ (text, text),
+ OPERATOR 6 pg_catalog.~* (text, text);
+
+ALTER OPERATOR FAMILY gin_trgm_ops USING gin ADD
+ OPERATOR 5 pg_catalog.~ (text, text),
+ OPERATOR 6 pg_catalog.~* (text, text);
diff --git a/contrib/pg_trgm/pg_trgm--1.1--1.2.sql b/contrib/pg_trgm/pg_trgm--1.1--1.2.sql
new file mode 100644
index 0000000..ff0f13f
--- /dev/null
+++ b/contrib/pg_trgm/pg_trgm--1.1--1.2.sql
@@ -0,0 +1,74 @@
+/* contrib/pg_trgm/pg_trgm--1.1--1.2.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pg_trgm UPDATE TO '1.2'" to load this file. \quit
+
+CREATE FUNCTION word_similarity(text,text)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION word_similarity_op(text,text)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE; -- stable because depends on pg_trgm.word_similarity_threshold
+
+CREATE FUNCTION word_similarity_commutator_op(text,text)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE; -- stable because depends on pg_trgm.word_similarity_threshold
+
+CREATE FUNCTION word_similarity_dist_op(text,text)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE FUNCTION word_similarity_dist_commutator_op(text,text)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE;
+
+CREATE OPERATOR <% (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = word_similarity_op,
+ COMMUTATOR = '%>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR %> (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = word_similarity_commutator_op,
+ COMMUTATOR = '<%',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR <<-> (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = word_similarity_dist_op,
+ COMMUTATOR = '<->>'
+);
+
+CREATE OPERATOR <->> (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = word_similarity_dist_commutator_op,
+ COMMUTATOR = '<<->'
+);
+
+CREATE FUNCTION gin_trgm_triconsistent(internal, int2, text, int4, internal, internal, internal)
+RETURNS "char"
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT;
+
+ALTER OPERATOR FAMILY gist_trgm_ops USING gist ADD
+ OPERATOR 7 %> (text, text),
+ OPERATOR 8 <->> (text, text) FOR ORDER BY pg_catalog.float_ops;
+
+ALTER OPERATOR FAMILY gin_trgm_ops USING gin ADD
+ OPERATOR 7 %> (text, text),
+ FUNCTION 6 (text, text) gin_trgm_triconsistent (internal, int2, text, int4, internal, internal, internal);
diff --git a/contrib/pg_trgm/pg_trgm--1.2--1.3.sql b/contrib/pg_trgm/pg_trgm--1.2--1.3.sql
new file mode 100644
index 0000000..8dc772c
--- /dev/null
+++ b/contrib/pg_trgm/pg_trgm--1.2--1.3.sql
@@ -0,0 +1,65 @@
+/* contrib/pg_trgm/pg_trgm--1.2--1.3.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pg_trgm UPDATE TO '1.3'" to load this file. \quit
+
+-- Update procedure signatures the hard way.
+-- We use to_regprocedure() so that query doesn't fail if run against 9.6beta1 definitions,
+-- wherein the signatures have been updated already. In that case to_regprocedure() will
+-- return NULL and no updates will happen.
+DO LANGUAGE plpgsql
+$$
+DECLARE
+ my_schema pg_catalog.text := pg_catalog.quote_ident(pg_catalog.current_schema());
+ old_path pg_catalog.text := pg_catalog.current_setting('search_path');
+BEGIN
+-- for safety, transiently set search_path to just pg_catalog+pg_temp
+PERFORM pg_catalog.set_config('search_path', 'pg_catalog, pg_temp', true);
+
+UPDATE pg_catalog.pg_proc SET
+ proargtypes = pg_catalog.array_to_string(newtypes::pg_catalog.oid[], ' ')::pg_catalog.oidvector,
+ pronargs = pg_catalog.array_length(newtypes, 1)
+FROM (VALUES
+(NULL::pg_catalog.text, NULL::pg_catalog.text[]), -- establish column types
+('gtrgm_consistent(internal,text,int4,oid,internal)', '{internal,text,int2,oid,internal}'),
+('gtrgm_distance(internal,text,int4,oid)', '{internal,text,int2,oid,internal}'),
+('gtrgm_union(bytea,internal)', '{internal,internal}')
+) AS update_data (oldproc, newtypestext),
+LATERAL (
+ SELECT array_agg(replace(typ, 'SCH', my_schema)::regtype) as newtypes FROM unnest(newtypestext) typ
+) ls
+WHERE oid = to_regprocedure(my_schema || '.' || replace(oldproc, 'SCH', my_schema));
+
+UPDATE pg_catalog.pg_proc SET
+ prorettype = (my_schema || '.gtrgm')::pg_catalog.regtype
+WHERE oid = pg_catalog.to_regprocedure(my_schema || '.gtrgm_union(internal,internal)');
+
+PERFORM pg_catalog.set_config('search_path', old_path, true);
+END
+$$;
+
+ALTER FUNCTION set_limit(float4) PARALLEL UNSAFE;
+ALTER FUNCTION show_limit() PARALLEL SAFE;
+ALTER FUNCTION show_trgm(text) PARALLEL SAFE;
+ALTER FUNCTION similarity(text, text) PARALLEL SAFE;
+ALTER FUNCTION similarity_op(text, text) PARALLEL SAFE;
+ALTER FUNCTION word_similarity(text, text) PARALLEL SAFE;
+ALTER FUNCTION word_similarity_op(text, text) PARALLEL SAFE;
+ALTER FUNCTION word_similarity_commutator_op(text, text) PARALLEL SAFE;
+ALTER FUNCTION similarity_dist(text, text) PARALLEL SAFE;
+ALTER FUNCTION word_similarity_dist_op(text, text) PARALLEL SAFE;
+ALTER FUNCTION word_similarity_dist_commutator_op(text, text) PARALLEL SAFE;
+ALTER FUNCTION gtrgm_in(cstring) PARALLEL SAFE;
+ALTER FUNCTION gtrgm_out(gtrgm) PARALLEL SAFE;
+ALTER FUNCTION gtrgm_consistent(internal, text, smallint, oid, internal) PARALLEL SAFE;
+ALTER FUNCTION gtrgm_distance(internal, text, smallint, oid, internal) PARALLEL SAFE;
+ALTER FUNCTION gtrgm_compress(internal) PARALLEL SAFE;
+ALTER FUNCTION gtrgm_decompress(internal) PARALLEL SAFE;
+ALTER FUNCTION gtrgm_penalty(internal, internal, internal) PARALLEL SAFE;
+ALTER FUNCTION gtrgm_picksplit(internal, internal) PARALLEL SAFE;
+ALTER FUNCTION gtrgm_union(internal, internal) PARALLEL SAFE;
+ALTER FUNCTION gtrgm_same(gtrgm, gtrgm, internal) PARALLEL SAFE;
+ALTER FUNCTION gin_extract_value_trgm(text, internal) PARALLEL SAFE;
+ALTER FUNCTION gin_extract_query_trgm(text, internal, int2, internal, internal, internal, internal) PARALLEL SAFE;
+ALTER FUNCTION gin_trgm_consistent(internal, int2, text, int4, internal, internal, internal, internal) PARALLEL SAFE;
+ALTER FUNCTION gin_trgm_triconsistent(internal, int2, text, int4, internal, internal, internal) PARALLEL SAFE;
diff --git a/contrib/pg_trgm/pg_trgm--1.3--1.4.sql b/contrib/pg_trgm/pg_trgm--1.3--1.4.sql
new file mode 100644
index 0000000..64a0c21
--- /dev/null
+++ b/contrib/pg_trgm/pg_trgm--1.3--1.4.sql
@@ -0,0 +1,68 @@
+/* contrib/pg_trgm/pg_trgm--1.3--1.4.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pg_trgm UPDATE TO '1.4'" to load this file. \quit
+
+CREATE FUNCTION strict_word_similarity(text,text)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION strict_word_similarity_op(text,text)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE PARALLEL SAFE; -- stable because depends on pg_trgm.word_similarity_threshold
+
+CREATE FUNCTION strict_word_similarity_commutator_op(text,text)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE PARALLEL SAFE; -- stable because depends on pg_trgm.word_similarity_threshold
+
+CREATE OPERATOR <<% (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = strict_word_similarity_op,
+ COMMUTATOR = '%>>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR %>> (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = strict_word_similarity_commutator_op,
+ COMMUTATOR = '<<%',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE FUNCTION strict_word_similarity_dist_op(text,text)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION strict_word_similarity_dist_commutator_op(text,text)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OPERATOR <<<-> (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = strict_word_similarity_dist_op,
+ COMMUTATOR = '<->>>'
+);
+
+CREATE OPERATOR <->>> (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = strict_word_similarity_dist_commutator_op,
+ COMMUTATOR = '<<<->'
+);
+
+ALTER OPERATOR FAMILY gist_trgm_ops USING gist ADD
+ OPERATOR 9 %>> (text, text),
+ OPERATOR 10 <->>> (text, text) FOR ORDER BY pg_catalog.float_ops;
+
+ALTER OPERATOR FAMILY gin_trgm_ops USING gin ADD
+ OPERATOR 9 %>> (text, text);
diff --git a/contrib/pg_trgm/pg_trgm--1.3.sql b/contrib/pg_trgm/pg_trgm--1.3.sql
new file mode 100644
index 0000000..4c6edf8
--- /dev/null
+++ b/contrib/pg_trgm/pg_trgm--1.3.sql
@@ -0,0 +1,254 @@
+/* contrib/pg_trgm/pg_trgm--1.3.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION pg_trgm" to load this file. \quit
+
+-- Deprecated function
+CREATE FUNCTION set_limit(float4)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT VOLATILE PARALLEL UNSAFE;
+
+-- Deprecated function
+CREATE FUNCTION show_limit()
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE PARALLEL SAFE;
+
+CREATE FUNCTION show_trgm(text)
+RETURNS _text
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION similarity(text,text)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION similarity_op(text,text)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE PARALLEL SAFE; -- stable because depends on pg_trgm.similarity_threshold
+
+CREATE OPERATOR % (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = similarity_op,
+ COMMUTATOR = '%',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE FUNCTION word_similarity(text,text)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION word_similarity_op(text,text)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE PARALLEL SAFE; -- stable because depends on pg_trgm.word_similarity_threshold
+
+CREATE FUNCTION word_similarity_commutator_op(text,text)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT STABLE PARALLEL SAFE; -- stable because depends on pg_trgm.word_similarity_threshold
+
+CREATE OPERATOR <% (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = word_similarity_op,
+ COMMUTATOR = '%>',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE OPERATOR %> (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = word_similarity_commutator_op,
+ COMMUTATOR = '<%',
+ RESTRICT = contsel,
+ JOIN = contjoinsel
+);
+
+CREATE FUNCTION similarity_dist(text,text)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OPERATOR <-> (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = similarity_dist,
+ COMMUTATOR = '<->'
+);
+
+CREATE FUNCTION word_similarity_dist_op(text,text)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION word_similarity_dist_commutator_op(text,text)
+RETURNS float4
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE OPERATOR <<-> (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = word_similarity_dist_op,
+ COMMUTATOR = '<->>'
+);
+
+CREATE OPERATOR <->> (
+ LEFTARG = text,
+ RIGHTARG = text,
+ PROCEDURE = word_similarity_dist_commutator_op,
+ COMMUTATOR = '<<->'
+);
+
+-- gist key
+CREATE FUNCTION gtrgm_in(cstring)
+RETURNS gtrgm
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE FUNCTION gtrgm_out(gtrgm)
+RETURNS cstring
+AS 'MODULE_PATHNAME'
+LANGUAGE C STRICT IMMUTABLE PARALLEL SAFE;
+
+CREATE TYPE gtrgm (
+ INTERNALLENGTH = -1,
+ INPUT = gtrgm_in,
+ OUTPUT = gtrgm_out
+);
+
+-- support functions for gist
+CREATE FUNCTION gtrgm_consistent(internal,text,smallint,oid,internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION gtrgm_distance(internal,text,smallint,oid,internal)
+RETURNS float8
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION gtrgm_compress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION gtrgm_decompress(internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION gtrgm_penalty(internal,internal,internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION gtrgm_picksplit(internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION gtrgm_union(internal, internal)
+RETURNS gtrgm
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION gtrgm_same(gtrgm, gtrgm, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+-- create the operator class for gist
+CREATE OPERATOR CLASS gist_trgm_ops
+FOR TYPE text USING gist
+AS
+ OPERATOR 1 % (text, text),
+ FUNCTION 1 gtrgm_consistent (internal, text, smallint, oid, internal),
+ FUNCTION 2 gtrgm_union (internal, internal),
+ FUNCTION 3 gtrgm_compress (internal),
+ FUNCTION 4 gtrgm_decompress (internal),
+ FUNCTION 5 gtrgm_penalty (internal, internal, internal),
+ FUNCTION 6 gtrgm_picksplit (internal, internal),
+ FUNCTION 7 gtrgm_same (gtrgm, gtrgm, internal),
+ STORAGE gtrgm;
+
+-- Add operators and support functions that are new in 9.1. We do it like
+-- this, leaving them "loose" in the operator family rather than bound into
+-- the gist_trgm_ops opclass, because that's the only state that could be
+-- reproduced during an upgrade from 9.0.
+
+ALTER OPERATOR FAMILY gist_trgm_ops USING gist ADD
+ OPERATOR 2 <-> (text, text) FOR ORDER BY pg_catalog.float_ops,
+ OPERATOR 3 pg_catalog.~~ (text, text),
+ OPERATOR 4 pg_catalog.~~* (text, text),
+ FUNCTION 8 (text, text) gtrgm_distance (internal, text, smallint, oid, internal);
+
+-- Add operators that are new in 9.3.
+
+ALTER OPERATOR FAMILY gist_trgm_ops USING gist ADD
+ OPERATOR 5 pg_catalog.~ (text, text),
+ OPERATOR 6 pg_catalog.~* (text, text);
+
+-- Add operators that are new in 9.6 (pg_trgm 1.2).
+
+ALTER OPERATOR FAMILY gist_trgm_ops USING gist ADD
+ OPERATOR 7 %> (text, text),
+ OPERATOR 8 <->> (text, text) FOR ORDER BY pg_catalog.float_ops;
+
+-- support functions for gin
+CREATE FUNCTION gin_extract_value_trgm(text, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION gin_extract_query_trgm(text, internal, int2, internal, internal, internal, internal)
+RETURNS internal
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+CREATE FUNCTION gin_trgm_consistent(internal, int2, text, int4, internal, internal, internal, internal)
+RETURNS bool
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+-- create the operator class for gin
+CREATE OPERATOR CLASS gin_trgm_ops
+FOR TYPE text USING gin
+AS
+ OPERATOR 1 % (text, text),
+ FUNCTION 1 btint4cmp (int4, int4),
+ FUNCTION 2 gin_extract_value_trgm (text, internal),
+ FUNCTION 3 gin_extract_query_trgm (text, internal, int2, internal, internal, internal, internal),
+ FUNCTION 4 gin_trgm_consistent (internal, int2, text, int4, internal, internal, internal, internal),
+ STORAGE int4;
+
+-- Add operators that are new in 9.1.
+
+ALTER OPERATOR FAMILY gin_trgm_ops USING gin ADD
+ OPERATOR 3 pg_catalog.~~ (text, text),
+ OPERATOR 4 pg_catalog.~~* (text, text);
+
+-- Add operators that are new in 9.3.
+
+ALTER OPERATOR FAMILY gin_trgm_ops USING gin ADD
+ OPERATOR 5 pg_catalog.~ (text, text),
+ OPERATOR 6 pg_catalog.~* (text, text);
+
+-- Add functions that are new in 9.6 (pg_trgm 1.2).
+
+CREATE FUNCTION gin_trgm_triconsistent(internal, int2, text, int4, internal, internal, internal)
+RETURNS "char"
+AS 'MODULE_PATHNAME'
+LANGUAGE C IMMUTABLE STRICT PARALLEL SAFE;
+
+ALTER OPERATOR FAMILY gin_trgm_ops USING gin ADD
+ OPERATOR 7 %> (text, text),
+ FUNCTION 6 (text,text) gin_trgm_triconsistent (internal, int2, text, int4, internal, internal, internal);
diff --git a/contrib/pg_trgm/pg_trgm--1.4--1.5.sql b/contrib/pg_trgm/pg_trgm--1.4--1.5.sql
new file mode 100644
index 0000000..db122fc
--- /dev/null
+++ b/contrib/pg_trgm/pg_trgm--1.4--1.5.sql
@@ -0,0 +1,23 @@
+/* contrib/pg_trgm/pg_trgm--1.4--1.5.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pg_trgm UPDATE TO '1.5'" to load this file. \quit
+
+CREATE FUNCTION gtrgm_options(internal)
+RETURNS void
+AS 'MODULE_PATHNAME', 'gtrgm_options'
+LANGUAGE C IMMUTABLE PARALLEL SAFE;
+
+ALTER OPERATOR FAMILY gist_trgm_ops USING gist
+ADD FUNCTION 10 (text) gtrgm_options (internal);
+
+ALTER OPERATOR % (text, text)
+ SET (RESTRICT = matchingsel, JOIN = matchingjoinsel);
+ALTER OPERATOR <% (text, text)
+ SET (RESTRICT = matchingsel, JOIN = matchingjoinsel);
+ALTER OPERATOR %> (text, text)
+ SET (RESTRICT = matchingsel, JOIN = matchingjoinsel);
+ALTER OPERATOR <<% (text, text)
+ SET (RESTRICT = matchingsel, JOIN = matchingjoinsel);
+ALTER OPERATOR %>> (text, text)
+ SET (RESTRICT = matchingsel, JOIN = matchingjoinsel);
diff --git a/contrib/pg_trgm/pg_trgm--1.5--1.6.sql b/contrib/pg_trgm/pg_trgm--1.5--1.6.sql
new file mode 100644
index 0000000..9e74684
--- /dev/null
+++ b/contrib/pg_trgm/pg_trgm--1.5--1.6.sql
@@ -0,0 +1,10 @@
+/* contrib/pg_trgm/pg_trgm--1.5--1.6.sql */
+
+-- complain if script is sourced in psql, rather than via ALTER EXTENSION
+\echo Use "ALTER EXTENSION pg_trgm UPDATE TO '1.6'" to load this file. \quit
+
+ALTER OPERATOR FAMILY gin_trgm_ops USING gin ADD
+ OPERATOR 11 pg_catalog.= (text, text);
+
+ALTER OPERATOR FAMILY gist_trgm_ops USING gist ADD
+ OPERATOR 11 pg_catalog.= (text, text);
diff --git a/contrib/pg_trgm/pg_trgm.control b/contrib/pg_trgm/pg_trgm.control
new file mode 100644
index 0000000..1d6a9dd
--- /dev/null
+++ b/contrib/pg_trgm/pg_trgm.control
@@ -0,0 +1,6 @@
+# pg_trgm extension
+comment = 'text similarity measurement and index searching based on trigrams'
+default_version = '1.6'
+module_pathname = '$libdir/pg_trgm'
+relocatable = true
+trusted = true
diff --git a/contrib/pg_trgm/sql/pg_strict_word_trgm.sql b/contrib/pg_trgm/sql/pg_strict_word_trgm.sql
new file mode 100644
index 0000000..ce0791f
--- /dev/null
+++ b/contrib/pg_trgm/sql/pg_strict_word_trgm.sql
@@ -0,0 +1,45 @@
+DROP INDEX trgm_idx2;
+
+\copy test_trgm3 from 'data/trgm2.data'
+
+-- reduce noise
+set extra_float_digits = 0;
+
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <<% t order by sml desc, t;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where t %>> 'Baykal' order by sml desc, t;
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where t %>> 'Kabankala' order by sml desc, t;
+select t <->>> 'Alaikallupoddakulam', t from test_trgm2 order by t <->>> 'Alaikallupoddakulam' limit 7;
+
+create index trgm_idx2 on test_trgm2 using gist (t gist_trgm_ops);
+set enable_seqscan=off;
+
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <<% t order by sml desc, t;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where t %>> 'Baykal' order by sml desc, t;
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where t %>> 'Kabankala' order by sml desc, t;
+
+explain (costs off)
+select t <->>> 'Alaikallupoddakulam', t from test_trgm2 order by t <->>> 'Alaikallupoddakulam' limit 7;
+select t <->>> 'Alaikallupoddakulam', t from test_trgm2 order by t <->>> 'Alaikallupoddakulam' limit 7;
+
+drop index trgm_idx2;
+create index trgm_idx2 on test_trgm2 using gin (t gin_trgm_ops);
+set enable_seqscan=off;
+
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <<% t order by sml desc, t;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where t %>> 'Baykal' order by sml desc, t;
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where t %>> 'Kabankala' order by sml desc, t;
+
+set "pg_trgm.strict_word_similarity_threshold" to 0.4;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <<% t order by sml desc, t;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where t %>> 'Baykal' order by sml desc, t;
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where t %>> 'Kabankala' order by sml desc, t;
+
+set "pg_trgm.strict_word_similarity_threshold" to 0.2;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <<% t order by sml desc, t;
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <<% t order by sml desc, t;
+select t,strict_word_similarity('Baykal',t) as sml from test_trgm2 where t %>> 'Baykal' order by sml desc, t;
+select t,strict_word_similarity('Kabankala',t) as sml from test_trgm2 where t %>> 'Kabankala' order by sml desc, t;
diff --git a/contrib/pg_trgm/sql/pg_trgm.sql b/contrib/pg_trgm/sql/pg_trgm.sql
new file mode 100644
index 0000000..6a9da24
--- /dev/null
+++ b/contrib/pg_trgm/sql/pg_trgm.sql
@@ -0,0 +1,238 @@
+CREATE EXTENSION pg_trgm;
+
+-- Check whether any of our opclasses fail amvalidate
+SELECT amname, opcname
+FROM pg_opclass opc LEFT JOIN pg_am am ON am.oid = opcmethod
+WHERE opc.oid >= 16384 AND NOT amvalidate(opc.oid);
+
+--backslash is used in tests below, installcheck will fail if
+--standard_conforming_string is off
+set standard_conforming_strings=on;
+
+-- reduce noise
+set extra_float_digits = 0;
+
+select show_trgm('');
+select show_trgm('(*&^$@%@');
+select show_trgm('a b c');
+select show_trgm(' a b c ');
+select show_trgm('aA bB cC');
+select show_trgm(' aA bB cC ');
+select show_trgm('a b C0*%^');
+
+select similarity('wow','WOWa ');
+select similarity('wow',' WOW ');
+
+select similarity('---', '####---');
+
+CREATE TABLE test_trgm(t text COLLATE "C");
+
+\copy test_trgm from 'data/trgm.data'
+
+select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t;
+select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t;
+select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t;
+select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}';
+
+create index trgm_idx on test_trgm using gist (t gist_trgm_ops);
+set enable_seqscan=off;
+
+select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t;
+select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t;
+select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t;
+explain (costs off)
+select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}';
+
+drop index trgm_idx;
+create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=0));
+create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=2025));
+create index trgm_idx on test_trgm using gist (t gist_trgm_ops(siglen=2024));
+set enable_seqscan=off;
+
+select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t;
+select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t;
+select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t;
+explain (costs off)
+select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+select t <-> 'q0987wertyu0988', t from test_trgm order by t <-> 'q0987wertyu0988' limit 2;
+select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}';
+
+drop index trgm_idx;
+create index trgm_idx on test_trgm using gin (t gin_trgm_ops);
+set enable_seqscan=off;
+
+select t,similarity(t,'qwertyu0988') as sml from test_trgm where t % 'qwertyu0988' order by sml desc, t;
+select t,similarity(t,'gwertyu0988') as sml from test_trgm where t % 'gwertyu0988' order by sml desc, t;
+select t,similarity(t,'gwertyu1988') as sml from test_trgm where t % 'gwertyu1988' order by sml desc, t;
+select count(*) from test_trgm where t ~ '[qwerty]{2}-?[qwerty]{2}';
+
+-- check handling of indexquals that generate no searchable conditions
+explain (costs off)
+select count(*) from test_trgm where t like '%99%' and t like '%qwerty%';
+select count(*) from test_trgm where t like '%99%' and t like '%qwerty%';
+explain (costs off)
+select count(*) from test_trgm where t like '%99%' and t like '%qw%';
+select count(*) from test_trgm where t like '%99%' and t like '%qw%';
+-- ensure that pending-list items are handled correctly, too
+create temp table t_test_trgm(t text COLLATE "C");
+create index t_trgm_idx on t_test_trgm using gin (t gin_trgm_ops);
+insert into t_test_trgm values ('qwerty99'), ('qwerty01');
+explain (costs off)
+select count(*) from t_test_trgm where t like '%99%' and t like '%qwerty%';
+select count(*) from t_test_trgm where t like '%99%' and t like '%qwerty%';
+explain (costs off)
+select count(*) from t_test_trgm where t like '%99%' and t like '%qw%';
+select count(*) from t_test_trgm where t like '%99%' and t like '%qw%';
+
+-- run the same queries with sequential scan to check the results
+set enable_bitmapscan=off;
+set enable_seqscan=on;
+select count(*) from test_trgm where t like '%99%' and t like '%qwerty%';
+select count(*) from test_trgm where t like '%99%' and t like '%qw%';
+select count(*) from t_test_trgm where t like '%99%' and t like '%qwerty%';
+select count(*) from t_test_trgm where t like '%99%' and t like '%qw%';
+reset enable_bitmapscan;
+
+create table test2(t text COLLATE "C");
+insert into test2 values ('abcdef');
+insert into test2 values ('quark');
+insert into test2 values (' z foo bar');
+insert into test2 values ('/123/-45/');
+insert into test2 values ('line 1');
+insert into test2 values ('%line 2');
+insert into test2 values ('line 3%');
+insert into test2 values ('%line 4%');
+insert into test2 values ('%li%ne 5%');
+insert into test2 values ('li_e 6');
+create index test2_idx_gin on test2 using gin (t gin_trgm_ops);
+set enable_seqscan=off;
+explain (costs off)
+ select * from test2 where t like '%BCD%';
+explain (costs off)
+ select * from test2 where t ilike '%BCD%';
+select * from test2 where t like '%BCD%';
+select * from test2 where t like '%bcd%';
+select * from test2 where t like E'%\\bcd%';
+select * from test2 where t ilike '%BCD%';
+select * from test2 where t ilike 'qua%';
+select * from test2 where t like '%z foo bar%';
+select * from test2 where t like ' z foo%';
+explain (costs off)
+ select * from test2 where t ~ '[abc]{3}';
+explain (costs off)
+ select * from test2 where t ~* 'DEF';
+select * from test2 where t ~ '[abc]{3}';
+select * from test2 where t ~ 'a[bc]+d';
+select * from test2 where t ~ '(abc)*$';
+select * from test2 where t ~* 'DEF';
+select * from test2 where t ~ 'dEf';
+select * from test2 where t ~* '^q';
+select * from test2 where t ~* '[abc]{3}[def]{3}';
+select * from test2 where t ~* 'ab[a-z]{3}';
+select * from test2 where t ~* '(^| )qua';
+select * from test2 where t ~ 'q.*rk$';
+select * from test2 where t ~ 'q';
+select * from test2 where t ~ '[a-z]{3}';
+select * from test2 where t ~* '(a{10}|b{10}|c{10}){10}';
+select * from test2 where t ~ 'z foo bar';
+select * from test2 where t ~ ' z foo bar';
+select * from test2 where t ~ ' z foo bar';
+select * from test2 where t ~ ' z foo';
+select * from test2 where t ~ 'qua(?!foo)';
+select * from test2 where t ~ '/\d+/-\d';
+-- test = operator
+explain (costs off)
+ select * from test2 where t = 'abcdef';
+select * from test2 where t = 'abcdef';
+explain (costs off)
+ select * from test2 where t = '%line%';
+select * from test2 where t = '%line%';
+select * from test2 where t = 'li_e 1';
+select * from test2 where t = '%line 2';
+select * from test2 where t = 'line 3%';
+select * from test2 where t = '%line 3%';
+select * from test2 where t = '%line 4%';
+select * from test2 where t = '%line 5%';
+select * from test2 where t = '%li_ne 5%';
+select * from test2 where t = '%li%ne 5%';
+select * from test2 where t = 'line 6';
+select * from test2 where t = 'li_e 6';
+drop index test2_idx_gin;
+
+create index test2_idx_gist on test2 using gist (t gist_trgm_ops);
+set enable_seqscan=off;
+explain (costs off)
+ select * from test2 where t like '%BCD%';
+explain (costs off)
+ select * from test2 where t ilike '%BCD%';
+select * from test2 where t like '%BCD%';
+select * from test2 where t like '%bcd%';
+select * from test2 where t like E'%\\bcd%';
+select * from test2 where t ilike '%BCD%';
+select * from test2 where t ilike 'qua%';
+select * from test2 where t like '%z foo bar%';
+select * from test2 where t like ' z foo%';
+explain (costs off)
+ select * from test2 where t ~ '[abc]{3}';
+explain (costs off)
+ select * from test2 where t ~* 'DEF';
+select * from test2 where t ~ '[abc]{3}';
+select * from test2 where t ~ 'a[bc]+d';
+select * from test2 where t ~ '(abc)*$';
+select * from test2 where t ~* 'DEF';
+select * from test2 where t ~ 'dEf';
+select * from test2 where t ~* '^q';
+select * from test2 where t ~* '[abc]{3}[def]{3}';
+select * from test2 where t ~* 'ab[a-z]{3}';
+select * from test2 where t ~* '(^| )qua';
+select * from test2 where t ~ 'q.*rk$';
+select * from test2 where t ~ 'q';
+select * from test2 where t ~ '[a-z]{3}';
+select * from test2 where t ~* '(a{10}|b{10}|c{10}){10}';
+select * from test2 where t ~ 'z foo bar';
+select * from test2 where t ~ ' z foo bar';
+select * from test2 where t ~ ' z foo bar';
+select * from test2 where t ~ ' z foo';
+select * from test2 where t ~ 'qua(?!foo)';
+select * from test2 where t ~ '/\d+/-\d';
+-- test = operator
+explain (costs off)
+ select * from test2 where t = 'abcdef';
+select * from test2 where t = 'abcdef';
+explain (costs off)
+ select * from test2 where t = '%line%';
+select * from test2 where t = '%line%';
+select * from test2 where t = 'li_e 1';
+select * from test2 where t = '%line 2';
+select * from test2 where t = 'line 3%';
+select * from test2 where t = '%line 3%';
+select * from test2 where t = '%line 4%';
+select * from test2 where t = '%line 5%';
+select * from test2 where t = '%li_ne 5%';
+select * from test2 where t = '%li%ne 5%';
+select * from test2 where t = 'line 6';
+select * from test2 where t = 'li_e 6';
+
+-- Check similarity threshold (bug #14202)
+
+CREATE TEMP TABLE restaurants (city text);
+INSERT INTO restaurants SELECT 'Warsaw' FROM generate_series(1, 10000);
+INSERT INTO restaurants SELECT 'Szczecin' FROM generate_series(1, 10000);
+CREATE INDEX ON restaurants USING gist(city gist_trgm_ops);
+
+-- Similarity of the two names (for reference).
+SELECT similarity('Szczecin', 'Warsaw');
+
+-- Should get only 'Warsaw' for either setting of set_limit.
+EXPLAIN (COSTS OFF)
+SELECT DISTINCT city, similarity(city, 'Warsaw'), show_limit()
+ FROM restaurants WHERE city % 'Warsaw';
+SELECT set_limit(0.3);
+SELECT DISTINCT city, similarity(city, 'Warsaw'), show_limit()
+ FROM restaurants WHERE city % 'Warsaw';
+SELECT set_limit(0.5);
+SELECT DISTINCT city, similarity(city, 'Warsaw'), show_limit()
+ FROM restaurants WHERE city % 'Warsaw';
diff --git a/contrib/pg_trgm/sql/pg_word_trgm.sql b/contrib/pg_trgm/sql/pg_word_trgm.sql
new file mode 100644
index 0000000..d2ada49
--- /dev/null
+++ b/contrib/pg_trgm/sql/pg_word_trgm.sql
@@ -0,0 +1,48 @@
+CREATE TABLE test_trgm2(t text COLLATE "C");
+
+\copy test_trgm2 from 'data/trgm2.data'
+
+-- reduce noise
+set extra_float_digits = 0;
+
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t;
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kabankala' order by sml desc, t;
+select t <->> 'Kabankala', t from test_trgm2 order by t <->> 'Kabankala' limit 7;
+
+create index trgm_idx2 on test_trgm2 using gist (t gist_trgm_ops);
+set enable_seqscan=off;
+
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t;
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kabankala' order by sml desc, t;
+
+explain (costs off)
+select t <->> 'Kabankala', t from test_trgm2 order by t <->> 'Kabankala' limit 7;
+select t <->> 'Kabankala', t from test_trgm2 order by t <->> 'Kabankala' limit 7;
+
+drop index trgm_idx2;
+create index trgm_idx2 on test_trgm2 using gin (t gin_trgm_ops);
+set enable_seqscan=off;
+
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t;
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kabankala' order by sml desc, t;
+
+set "pg_trgm.word_similarity_threshold" to 0.5;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t;
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kabankala' order by sml desc, t;
+
+set "pg_trgm.word_similarity_threshold" to 0.3;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where 'Baykal' <% t order by sml desc, t;
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where 'Kabankala' <% t order by sml desc, t;
+select t,word_similarity('Baykal',t) as sml from test_trgm2 where t %> 'Baykal' order by sml desc, t;
+select t,word_similarity('Kabankala',t) as sml from test_trgm2 where t %> 'Kabankala' order by sml desc, t;
+
+-- test unsatisfiable pattern
+select * from test_trgm2 where t ~ '.*$x';
diff --git a/contrib/pg_trgm/trgm.h b/contrib/pg_trgm/trgm.h
new file mode 100644
index 0000000..afb0adb
--- /dev/null
+++ b/contrib/pg_trgm/trgm.h
@@ -0,0 +1,140 @@
+/*
+ * contrib/pg_trgm/trgm.h
+ */
+#ifndef __TRGM_H__
+#define __TRGM_H__
+
+#include "access/gist.h"
+#include "access/itup.h"
+#include "access/stratnum.h"
+#include "storage/bufpage.h"
+
+/*
+ * Options ... but note that trgm_regexp.c effectively assumes these values
+ * of LPADDING and RPADDING.
+ */
+#define LPADDING 2
+#define RPADDING 1
+#define KEEPONLYALNUM
+/*
+ * Caution: IGNORECASE macro means that trigrams are case-insensitive.
+ * If this macro is disabled, the ~* and ~~* operators must be removed from
+ * the operator classes, because we can't handle case-insensitive wildcard
+ * search with case-sensitive trigrams. Failure to do this will result in
+ * "cannot handle ~*(~~*) with case-sensitive trigrams" errors.
+ */
+#define IGNORECASE
+#define DIVUNION
+
+/* operator strategy numbers */
+#define SimilarityStrategyNumber 1
+#define DistanceStrategyNumber 2
+#define LikeStrategyNumber 3
+#define ILikeStrategyNumber 4
+#define RegExpStrategyNumber 5
+#define RegExpICaseStrategyNumber 6
+#define WordSimilarityStrategyNumber 7
+#define WordDistanceStrategyNumber 8
+#define StrictWordSimilarityStrategyNumber 9
+#define StrictWordDistanceStrategyNumber 10
+#define EqualStrategyNumber 11
+
+typedef char trgm[3];
+
+#define CMPCHAR(a,b) ( ((a)==(b)) ? 0 : ( ((a)<(b)) ? -1 : 1 ) )
+#define CMPPCHAR(a,b,i) CMPCHAR( *(((const char*)(a))+i), *(((const char*)(b))+i) )
+#define CMPTRGM(a,b) ( CMPPCHAR(a,b,0) ? CMPPCHAR(a,b,0) : ( CMPPCHAR(a,b,1) ? CMPPCHAR(a,b,1) : CMPPCHAR(a,b,2) ) )
+
+#define CPTRGM(a,b) do { \
+ *(((char*)(a))+0) = *(((char*)(b))+0); \
+ *(((char*)(a))+1) = *(((char*)(b))+1); \
+ *(((char*)(a))+2) = *(((char*)(b))+2); \
+} while(0)
+
+#ifdef KEEPONLYALNUM
+#define ISWORDCHR(c) (t_isalnum(c))
+#define ISPRINTABLECHAR(a) ( isascii( *(unsigned char*)(a) ) && (isalnum( *(unsigned char*)(a) ) || *(unsigned char*)(a)==' ') )
+#else
+#define ISWORDCHR(c) (!t_isspace(c))
+#define ISPRINTABLECHAR(a) ( isascii( *(unsigned char*)(a) ) && isprint( *(unsigned char*)(a) ) )
+#endif
+#define ISPRINTABLETRGM(t) ( ISPRINTABLECHAR( ((char*)(t)) ) && ISPRINTABLECHAR( ((char*)(t))+1 ) && ISPRINTABLECHAR( ((char*)(t))+2 ) )
+
+#define ISESCAPECHAR(x) (*(x) == '\\') /* Wildcard escape character */
+#define ISWILDCARDCHAR(x) (*(x) == '_' || *(x) == '%') /* Wildcard
+ * meta-character */
+
+typedef struct
+{
+ int32 vl_len_; /* varlena header (do not touch directly!) */
+ uint8 flag;
+ char data[FLEXIBLE_ARRAY_MEMBER];
+} TRGM;
+
+#define TRGMHDRSIZE (VARHDRSZ + sizeof(uint8))
+
+/* gist */
+#define SIGLEN_DEFAULT (sizeof(int) * 3)
+#define SIGLEN_MAX GISTMaxIndexKeySize
+#define BITBYTE 8
+
+#define SIGLENBIT(siglen) ((siglen) * BITBYTE - 1) /* see makesign */
+
+typedef char *BITVECP;
+
+#define LOOPBYTE(siglen) \
+ for (i = 0; i < (siglen); i++)
+
+#define GETBYTE(x,i) ( *( (BITVECP)(x) + (int)( (i) / BITBYTE ) ) )
+#define GETBITBYTE(x,i) ( (((char)(x)) >> (i)) & 0x01 )
+#define CLRBIT(x,i) GETBYTE(x,i) &= ~( 0x01 << ( (i) % BITBYTE ) )
+#define SETBIT(x,i) GETBYTE(x,i) |= ( 0x01 << ( (i) % BITBYTE ) )
+#define GETBIT(x,i) ( (GETBYTE(x,i) >> ( (i) % BITBYTE )) & 0x01 )
+
+#define HASHVAL(val, siglen) (((unsigned int)(val)) % SIGLENBIT(siglen))
+#define HASH(sign, val, siglen) SETBIT((sign), HASHVAL(val, siglen))
+
+#define ARRKEY 0x01
+#define SIGNKEY 0x02
+#define ALLISTRUE 0x04
+
+#define ISARRKEY(x) ( ((TRGM*)x)->flag & ARRKEY )
+#define ISSIGNKEY(x) ( ((TRGM*)x)->flag & SIGNKEY )
+#define ISALLTRUE(x) ( ((TRGM*)x)->flag & ALLISTRUE )
+
+#define CALCGTSIZE(flag, len) ( TRGMHDRSIZE + ( ( (flag) & ARRKEY ) ? ((len)*sizeof(trgm)) : (((flag) & ALLISTRUE) ? 0 : (len)) ) )
+#define GETSIGN(x) ( (BITVECP)( (char*)x+TRGMHDRSIZE ) )
+#define GETARR(x) ( (trgm*)( (char*)x+TRGMHDRSIZE ) )
+#define ARRNELEM(x) ( ( VARSIZE(x) - TRGMHDRSIZE )/sizeof(trgm) )
+
+/*
+ * If DIVUNION is defined then similarity formula is:
+ * count / (len1 + len2 - count)
+ * else if DIVUNION is not defined then similarity formula is:
+ * count / max(len1, len2)
+ */
+#ifdef DIVUNION
+#define CALCSML(count, len1, len2) ((float4) (count)) / ((float4) ((len1) + (len2) - (count)))
+#else
+#define CALCSML(count, len1, len2) ((float4) (count)) / ((float4) (((len1) > (len2)) ? (len1) : (len2)))
+#endif
+
+typedef struct TrgmPackedGraph TrgmPackedGraph;
+
+extern double similarity_threshold;
+extern double word_similarity_threshold;
+extern double strict_word_similarity_threshold;
+
+extern double index_strategy_get_limit(StrategyNumber strategy);
+extern uint32 trgm2int(trgm *ptr);
+extern void compact_trigram(trgm *tptr, char *str, int bytelen);
+extern TRGM *generate_trgm(char *str, int slen);
+extern TRGM *generate_wildcard_trgm(const char *str, int slen);
+extern float4 cnt_sml(TRGM *trg1, TRGM *trg2, bool inexact);
+extern bool trgm_contained_by(TRGM *trg1, TRGM *trg2);
+extern bool *trgm_presence_map(TRGM *query, TRGM *key);
+extern TRGM *createTrgmNFA(text *text_re, Oid collation,
+ TrgmPackedGraph **graph, MemoryContext rcontext);
+extern bool trigramsMatchGraph(TrgmPackedGraph *graph, bool *check);
+
+#endif /* __TRGM_H__ */
diff --git a/contrib/pg_trgm/trgm_gin.c b/contrib/pg_trgm/trgm_gin.c
new file mode 100644
index 0000000..29a52ea
--- /dev/null
+++ b/contrib/pg_trgm/trgm_gin.c
@@ -0,0 +1,360 @@
+/*
+ * contrib/pg_trgm/trgm_gin.c
+ */
+#include "postgres.h"
+
+#include "access/gin.h"
+#include "access/stratnum.h"
+#include "fmgr.h"
+#include "trgm.h"
+#include "varatt.h"
+
+PG_FUNCTION_INFO_V1(gin_extract_trgm);
+PG_FUNCTION_INFO_V1(gin_extract_value_trgm);
+PG_FUNCTION_INFO_V1(gin_extract_query_trgm);
+PG_FUNCTION_INFO_V1(gin_trgm_consistent);
+PG_FUNCTION_INFO_V1(gin_trgm_triconsistent);
+
+/*
+ * This function can only be called if a pre-9.1 version of the GIN operator
+ * class definition is present in the catalogs (probably as a consequence
+ * of upgrade-in-place). Cope.
+ */
+Datum
+gin_extract_trgm(PG_FUNCTION_ARGS)
+{
+ if (PG_NARGS() == 3)
+ return gin_extract_value_trgm(fcinfo);
+ if (PG_NARGS() == 7)
+ return gin_extract_query_trgm(fcinfo);
+ elog(ERROR, "unexpected number of arguments to gin_extract_trgm");
+ PG_RETURN_NULL();
+}
+
+Datum
+gin_extract_value_trgm(PG_FUNCTION_ARGS)
+{
+ text *val = (text *) PG_GETARG_TEXT_PP(0);
+ int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
+ Datum *entries = NULL;
+ TRGM *trg;
+ int32 trglen;
+
+ *nentries = 0;
+
+ trg = generate_trgm(VARDATA_ANY(val), VARSIZE_ANY_EXHDR(val));
+ trglen = ARRNELEM(trg);
+
+ if (trglen > 0)
+ {
+ trgm *ptr;
+ int32 i;
+
+ *nentries = trglen;
+ entries = (Datum *) palloc(sizeof(Datum) * trglen);
+
+ ptr = GETARR(trg);
+ for (i = 0; i < trglen; i++)
+ {
+ int32 item = trgm2int(ptr);
+
+ entries[i] = Int32GetDatum(item);
+ ptr++;
+ }
+ }
+
+ PG_RETURN_POINTER(entries);
+}
+
+Datum
+gin_extract_query_trgm(PG_FUNCTION_ARGS)
+{
+ text *val = (text *) PG_GETARG_TEXT_PP(0);
+ int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
+ StrategyNumber strategy = PG_GETARG_UINT16(2);
+
+ /* bool **pmatch = (bool **) PG_GETARG_POINTER(3); */
+ Pointer **extra_data = (Pointer **) PG_GETARG_POINTER(4);
+
+ /* bool **nullFlags = (bool **) PG_GETARG_POINTER(5); */
+ int32 *searchMode = (int32 *) PG_GETARG_POINTER(6);
+ Datum *entries = NULL;
+ TRGM *trg;
+ int32 trglen;
+ trgm *ptr;
+ TrgmPackedGraph *graph;
+ int32 i;
+
+ switch (strategy)
+ {
+ case SimilarityStrategyNumber:
+ case WordSimilarityStrategyNumber:
+ case StrictWordSimilarityStrategyNumber:
+ case EqualStrategyNumber:
+ trg = generate_trgm(VARDATA_ANY(val), VARSIZE_ANY_EXHDR(val));
+ break;
+ case ILikeStrategyNumber:
+#ifndef IGNORECASE
+ elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
+#endif
+ /* FALL THRU */
+ case LikeStrategyNumber:
+
+ /*
+ * For wildcard search we extract all the trigrams that every
+ * potentially-matching string must include.
+ */
+ trg = generate_wildcard_trgm(VARDATA_ANY(val),
+ VARSIZE_ANY_EXHDR(val));
+ break;
+ case RegExpICaseStrategyNumber:
+#ifndef IGNORECASE
+ elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
+#endif
+ /* FALL THRU */
+ case RegExpStrategyNumber:
+ trg = createTrgmNFA(val, PG_GET_COLLATION(),
+ &graph, CurrentMemoryContext);
+ if (trg && ARRNELEM(trg) > 0)
+ {
+ /*
+ * Successful regex processing: store NFA-like graph as
+ * extra_data. GIN API requires an array of nentries
+ * Pointers, but we just put the same value in each element.
+ */
+ trglen = ARRNELEM(trg);
+ *extra_data = (Pointer *) palloc(sizeof(Pointer) * trglen);
+ for (i = 0; i < trglen; i++)
+ (*extra_data)[i] = (Pointer) graph;
+ }
+ else
+ {
+ /* No result: have to do full index scan. */
+ *nentries = 0;
+ *searchMode = GIN_SEARCH_MODE_ALL;
+ PG_RETURN_POINTER(entries);
+ }
+ break;
+ default:
+ elog(ERROR, "unrecognized strategy number: %d", strategy);
+ trg = NULL; /* keep compiler quiet */
+ break;
+ }
+
+ trglen = ARRNELEM(trg);
+ *nentries = trglen;
+
+ if (trglen > 0)
+ {
+ entries = (Datum *) palloc(sizeof(Datum) * trglen);
+ ptr = GETARR(trg);
+ for (i = 0; i < trglen; i++)
+ {
+ int32 item = trgm2int(ptr);
+
+ entries[i] = Int32GetDatum(item);
+ ptr++;
+ }
+ }
+
+ /*
+ * If no trigram was extracted then we have to scan all the index.
+ */
+ if (trglen == 0)
+ *searchMode = GIN_SEARCH_MODE_ALL;
+
+ PG_RETURN_POINTER(entries);
+}
+
+Datum
+gin_trgm_consistent(PG_FUNCTION_ARGS)
+{
+ bool *check = (bool *) PG_GETARG_POINTER(0);
+ StrategyNumber strategy = PG_GETARG_UINT16(1);
+
+ /* text *query = PG_GETARG_TEXT_PP(2); */
+ int32 nkeys = PG_GETARG_INT32(3);
+ Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
+ bool *recheck = (bool *) PG_GETARG_POINTER(5);
+ bool res;
+ int32 i,
+ ntrue;
+ double nlimit;
+
+ /* All cases served by this function are inexact */
+ *recheck = true;
+
+ switch (strategy)
+ {
+ case SimilarityStrategyNumber:
+ case WordSimilarityStrategyNumber:
+ case StrictWordSimilarityStrategyNumber:
+ nlimit = index_strategy_get_limit(strategy);
+
+ /* Count the matches */
+ ntrue = 0;
+ for (i = 0; i < nkeys; i++)
+ {
+ if (check[i])
+ ntrue++;
+ }
+
+ /*--------------------
+ * If DIVUNION is defined then similarity formula is:
+ * c / (len1 + len2 - c)
+ * where c is number of common trigrams and it stands as ntrue in
+ * this code. Here we don't know value of len2 but we can assume
+ * that c (ntrue) is a lower bound of len2, so upper bound of
+ * similarity is:
+ * c / (len1 + c - c) => c / len1
+ * If DIVUNION is not defined then similarity formula is:
+ * c / max(len1, len2)
+ * And again, c (ntrue) is a lower bound of len2, but c <= len1
+ * just by definition and, consequently, upper bound of
+ * similarity is just c / len1.
+ * So, independently on DIVUNION the upper bound formula is the same.
+ */
+ res = (nkeys == 0) ? false :
+ (((((float4) ntrue) / ((float4) nkeys))) >= nlimit);
+ break;
+ case ILikeStrategyNumber:
+#ifndef IGNORECASE
+ elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
+#endif
+ /* FALL THRU */
+ case LikeStrategyNumber:
+ case EqualStrategyNumber:
+ /* Check if all extracted trigrams are presented. */
+ res = true;
+ for (i = 0; i < nkeys; i++)
+ {
+ if (!check[i])
+ {
+ res = false;
+ break;
+ }
+ }
+ break;
+ case RegExpICaseStrategyNumber:
+#ifndef IGNORECASE
+ elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
+#endif
+ /* FALL THRU */
+ case RegExpStrategyNumber:
+ if (nkeys < 1)
+ {
+ /* Regex processing gave no result: do full index scan */
+ res = true;
+ }
+ else
+ res = trigramsMatchGraph((TrgmPackedGraph *) extra_data[0],
+ check);
+ break;
+ default:
+ elog(ERROR, "unrecognized strategy number: %d", strategy);
+ res = false; /* keep compiler quiet */
+ break;
+ }
+
+ PG_RETURN_BOOL(res);
+}
+
+/*
+ * In all cases, GIN_TRUE is at least as favorable to inclusion as
+ * GIN_MAYBE. If no better option is available, simply treat
+ * GIN_MAYBE as if it were GIN_TRUE and apply the same test as the binary
+ * consistent function.
+ */
+Datum
+gin_trgm_triconsistent(PG_FUNCTION_ARGS)
+{
+ GinTernaryValue *check = (GinTernaryValue *) PG_GETARG_POINTER(0);
+ StrategyNumber strategy = PG_GETARG_UINT16(1);
+
+ /* text *query = PG_GETARG_TEXT_PP(2); */
+ int32 nkeys = PG_GETARG_INT32(3);
+ Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4);
+ GinTernaryValue res = GIN_MAYBE;
+ int32 i,
+ ntrue;
+ bool *boolcheck;
+ double nlimit;
+
+ switch (strategy)
+ {
+ case SimilarityStrategyNumber:
+ case WordSimilarityStrategyNumber:
+ case StrictWordSimilarityStrategyNumber:
+ nlimit = index_strategy_get_limit(strategy);
+
+ /* Count the matches */
+ ntrue = 0;
+ for (i = 0; i < nkeys; i++)
+ {
+ if (check[i] != GIN_FALSE)
+ ntrue++;
+ }
+
+ /*
+ * See comment in gin_trgm_consistent() about * upper bound
+ * formula
+ */
+ res = (nkeys == 0)
+ ? GIN_FALSE : (((((float4) ntrue) / ((float4) nkeys)) >= nlimit)
+ ? GIN_MAYBE : GIN_FALSE);
+ break;
+ case ILikeStrategyNumber:
+#ifndef IGNORECASE
+ elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
+#endif
+ /* FALL THRU */
+ case LikeStrategyNumber:
+ case EqualStrategyNumber:
+ /* Check if all extracted trigrams are presented. */
+ res = GIN_MAYBE;
+ for (i = 0; i < nkeys; i++)
+ {
+ if (check[i] == GIN_FALSE)
+ {
+ res = GIN_FALSE;
+ break;
+ }
+ }
+ break;
+ case RegExpICaseStrategyNumber:
+#ifndef IGNORECASE
+ elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
+#endif
+ /* FALL THRU */
+ case RegExpStrategyNumber:
+ if (nkeys < 1)
+ {
+ /* Regex processing gave no result: do full index scan */
+ res = GIN_MAYBE;
+ }
+ else
+ {
+ /*
+ * As trigramsMatchGraph implements a monotonic boolean
+ * function, promoting all GIN_MAYBE keys to GIN_TRUE will
+ * give a conservative result.
+ */
+ boolcheck = (bool *) palloc(sizeof(bool) * nkeys);
+ for (i = 0; i < nkeys; i++)
+ boolcheck[i] = (check[i] != GIN_FALSE);
+ if (!trigramsMatchGraph((TrgmPackedGraph *) extra_data[0],
+ boolcheck))
+ res = GIN_FALSE;
+ pfree(boolcheck);
+ }
+ break;
+ default:
+ elog(ERROR, "unrecognized strategy number: %d", strategy);
+ res = GIN_FALSE; /* keep compiler quiet */
+ break;
+ }
+
+ /* All cases served by this function are inexact */
+ Assert(res != GIN_TRUE);
+ PG_RETURN_GIN_TERNARY_VALUE(res);
+}
diff --git a/contrib/pg_trgm/trgm_gist.c b/contrib/pg_trgm/trgm_gist.c
new file mode 100644
index 0000000..9ef2e38
--- /dev/null
+++ b/contrib/pg_trgm/trgm_gist.c
@@ -0,0 +1,971 @@
+/*
+ * contrib/pg_trgm/trgm_gist.c
+ */
+#include "postgres.h"
+
+#include "access/reloptions.h"
+#include "access/stratnum.h"
+#include "fmgr.h"
+#include "port/pg_bitutils.h"
+#include "trgm.h"
+#include "varatt.h"
+
+/* gist_trgm_ops opclass options */
+typedef struct
+{
+ int32 vl_len_; /* varlena header (do not touch directly!) */
+ int siglen; /* signature length in bytes */
+} TrgmGistOptions;
+
+#define GET_SIGLEN() (PG_HAS_OPCLASS_OPTIONS() ? \
+ ((TrgmGistOptions *) PG_GET_OPCLASS_OPTIONS())->siglen : \
+ SIGLEN_DEFAULT)
+
+typedef struct
+{
+ /* most recent inputs to gtrgm_consistent */
+ StrategyNumber strategy;
+ text *query;
+ /* extracted trigrams for query */
+ TRGM *trigrams;
+ /* if a regex operator, the extracted graph */
+ TrgmPackedGraph *graph;
+
+ /*
+ * The "query" and "trigrams" are stored in the same palloc block as this
+ * cache struct, at MAXALIGN'ed offsets. The graph however isn't.
+ */
+} gtrgm_consistent_cache;
+
+#define GETENTRY(vec,pos) ((TRGM *) DatumGetPointer((vec)->vector[(pos)].key))
+
+
+PG_FUNCTION_INFO_V1(gtrgm_in);
+PG_FUNCTION_INFO_V1(gtrgm_out);
+PG_FUNCTION_INFO_V1(gtrgm_compress);
+PG_FUNCTION_INFO_V1(gtrgm_decompress);
+PG_FUNCTION_INFO_V1(gtrgm_consistent);
+PG_FUNCTION_INFO_V1(gtrgm_distance);
+PG_FUNCTION_INFO_V1(gtrgm_union);
+PG_FUNCTION_INFO_V1(gtrgm_same);
+PG_FUNCTION_INFO_V1(gtrgm_penalty);
+PG_FUNCTION_INFO_V1(gtrgm_picksplit);
+PG_FUNCTION_INFO_V1(gtrgm_options);
+
+
+Datum
+gtrgm_in(PG_FUNCTION_ARGS)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot accept a value of type %s", "gtrgm")));
+
+ PG_RETURN_VOID(); /* keep compiler quiet */
+}
+
+Datum
+gtrgm_out(PG_FUNCTION_ARGS)
+{
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("cannot display a value of type %s", "gtrgm")));
+
+ PG_RETURN_VOID(); /* keep compiler quiet */
+}
+
+static TRGM *
+gtrgm_alloc(bool isalltrue, int siglen, BITVECP sign)
+{
+ int flag = SIGNKEY | (isalltrue ? ALLISTRUE : 0);
+ int size = CALCGTSIZE(flag, siglen);
+ TRGM *res = palloc(size);
+
+ SET_VARSIZE(res, size);
+ res->flag = flag;
+
+ if (!isalltrue)
+ {
+ if (sign)
+ memcpy(GETSIGN(res), sign, siglen);
+ else
+ memset(GETSIGN(res), 0, siglen);
+ }
+
+ return res;
+}
+
+static void
+makesign(BITVECP sign, TRGM *a, int siglen)
+{
+ int32 k,
+ len = ARRNELEM(a);
+ trgm *ptr = GETARR(a);
+ int32 tmp = 0;
+
+ MemSet(sign, 0, siglen);
+ SETBIT(sign, SIGLENBIT(siglen)); /* set last unused bit */
+ for (k = 0; k < len; k++)
+ {
+ CPTRGM(((char *) &tmp), ptr + k);
+ HASH(sign, tmp, siglen);
+ }
+}
+
+Datum
+gtrgm_compress(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ int siglen = GET_SIGLEN();
+ GISTENTRY *retval = entry;
+
+ if (entry->leafkey)
+ { /* trgm */
+ TRGM *res;
+ text *val = DatumGetTextPP(entry->key);
+
+ res = generate_trgm(VARDATA_ANY(val), VARSIZE_ANY_EXHDR(val));
+ retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
+ gistentryinit(*retval, PointerGetDatum(res),
+ entry->rel, entry->page,
+ entry->offset, false);
+ }
+ else if (ISSIGNKEY(DatumGetPointer(entry->key)) &&
+ !ISALLTRUE(DatumGetPointer(entry->key)))
+ {
+ int32 i;
+ TRGM *res;
+ BITVECP sign = GETSIGN(DatumGetPointer(entry->key));
+
+ LOOPBYTE(siglen)
+ {
+ if ((sign[i] & 0xff) != 0xff)
+ PG_RETURN_POINTER(retval);
+ }
+
+ res = gtrgm_alloc(true, siglen, sign);
+ retval = (GISTENTRY *) palloc(sizeof(GISTENTRY));
+ gistentryinit(*retval, PointerGetDatum(res),
+ entry->rel, entry->page,
+ entry->offset, false);
+ }
+ PG_RETURN_POINTER(retval);
+}
+
+Datum
+gtrgm_decompress(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ GISTENTRY *retval;
+ text *key;
+
+ key = DatumGetTextPP(entry->key);
+
+ if (key != (text *) DatumGetPointer(entry->key))
+ {
+ /* need to pass back the decompressed item */
+ retval = palloc(sizeof(GISTENTRY));
+ gistentryinit(*retval, PointerGetDatum(key),
+ entry->rel, entry->page, entry->offset, entry->leafkey);
+ PG_RETURN_POINTER(retval);
+ }
+ else
+ {
+ /* we can return the entry as-is */
+ PG_RETURN_POINTER(entry);
+ }
+}
+
+static int32
+cnt_sml_sign_common(TRGM *qtrg, BITVECP sign, int siglen)
+{
+ int32 count = 0;
+ int32 k,
+ len = ARRNELEM(qtrg);
+ trgm *ptr = GETARR(qtrg);
+ int32 tmp = 0;
+
+ for (k = 0; k < len; k++)
+ {
+ CPTRGM(((char *) &tmp), ptr + k);
+ count += GETBIT(sign, HASHVAL(tmp, siglen));
+ }
+
+ return count;
+}
+
+Datum
+gtrgm_consistent(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ text *query = PG_GETARG_TEXT_P(1);
+ StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ bool *recheck = (bool *) PG_GETARG_POINTER(4);
+ int siglen = GET_SIGLEN();
+ TRGM *key = (TRGM *) DatumGetPointer(entry->key);
+ TRGM *qtrg;
+ bool res;
+ Size querysize = VARSIZE(query);
+ gtrgm_consistent_cache *cache;
+ double nlimit;
+
+ /*
+ * We keep the extracted trigrams in cache, because trigram extraction is
+ * relatively CPU-expensive. When trying to reuse a cached value, check
+ * strategy number not just query itself, because trigram extraction
+ * depends on strategy.
+ *
+ * The cached structure is a single palloc chunk containing the
+ * gtrgm_consistent_cache header, then the input query (4-byte length
+ * word, uncompressed, starting at a MAXALIGN boundary), then the TRGM
+ * value (also starting at a MAXALIGN boundary). However we don't try to
+ * include the regex graph (if any) in that struct. (XXX currently, this
+ * approach can leak regex graphs across index rescans. Not clear if
+ * that's worth fixing.)
+ */
+ cache = (gtrgm_consistent_cache *) fcinfo->flinfo->fn_extra;
+ if (cache == NULL ||
+ cache->strategy != strategy ||
+ VARSIZE(cache->query) != querysize ||
+ memcmp((char *) cache->query, (char *) query, querysize) != 0)
+ {
+ gtrgm_consistent_cache *newcache;
+ TrgmPackedGraph *graph = NULL;
+ Size qtrgsize;
+
+ switch (strategy)
+ {
+ case SimilarityStrategyNumber:
+ case WordSimilarityStrategyNumber:
+ case StrictWordSimilarityStrategyNumber:
+ case EqualStrategyNumber:
+ qtrg = generate_trgm(VARDATA(query),
+ querysize - VARHDRSZ);
+ break;
+ case ILikeStrategyNumber:
+#ifndef IGNORECASE
+ elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
+#endif
+ /* FALL THRU */
+ case LikeStrategyNumber:
+ qtrg = generate_wildcard_trgm(VARDATA(query),
+ querysize - VARHDRSZ);
+ break;
+ case RegExpICaseStrategyNumber:
+#ifndef IGNORECASE
+ elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
+#endif
+ /* FALL THRU */
+ case RegExpStrategyNumber:
+ qtrg = createTrgmNFA(query, PG_GET_COLLATION(),
+ &graph, fcinfo->flinfo->fn_mcxt);
+ /* just in case an empty array is returned ... */
+ if (qtrg && ARRNELEM(qtrg) <= 0)
+ {
+ pfree(qtrg);
+ qtrg = NULL;
+ }
+ break;
+ default:
+ elog(ERROR, "unrecognized strategy number: %d", strategy);
+ qtrg = NULL; /* keep compiler quiet */
+ break;
+ }
+
+ qtrgsize = qtrg ? VARSIZE(qtrg) : 0;
+
+ newcache = (gtrgm_consistent_cache *)
+ MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
+ MAXALIGN(sizeof(gtrgm_consistent_cache)) +
+ MAXALIGN(querysize) +
+ qtrgsize);
+
+ newcache->strategy = strategy;
+ newcache->query = (text *)
+ ((char *) newcache + MAXALIGN(sizeof(gtrgm_consistent_cache)));
+ memcpy((char *) newcache->query, (char *) query, querysize);
+ if (qtrg)
+ {
+ newcache->trigrams = (TRGM *)
+ ((char *) newcache->query + MAXALIGN(querysize));
+ memcpy((char *) newcache->trigrams, (char *) qtrg, qtrgsize);
+ /* release qtrg in case it was made in fn_mcxt */
+ pfree(qtrg);
+ }
+ else
+ newcache->trigrams = NULL;
+ newcache->graph = graph;
+
+ if (cache)
+ pfree(cache);
+ fcinfo->flinfo->fn_extra = (void *) newcache;
+ cache = newcache;
+ }
+
+ qtrg = cache->trigrams;
+
+ switch (strategy)
+ {
+ case SimilarityStrategyNumber:
+ case WordSimilarityStrategyNumber:
+ case StrictWordSimilarityStrategyNumber:
+
+ /*
+ * Similarity search is exact. (Strict) word similarity search is
+ * inexact
+ */
+ *recheck = (strategy != SimilarityStrategyNumber);
+
+ nlimit = index_strategy_get_limit(strategy);
+
+ if (GIST_LEAF(entry))
+ { /* all leafs contains orig trgm */
+ double tmpsml = cnt_sml(qtrg, key, *recheck);
+
+ res = (tmpsml >= nlimit);
+ }
+ else if (ISALLTRUE(key))
+ { /* non-leaf contains signature */
+ res = true;
+ }
+ else
+ { /* non-leaf contains signature */
+ int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
+ int32 len = ARRNELEM(qtrg);
+
+ if (len == 0)
+ res = false;
+ else
+ res = (((((float8) count) / ((float8) len))) >= nlimit);
+ }
+ break;
+ case ILikeStrategyNumber:
+#ifndef IGNORECASE
+ elog(ERROR, "cannot handle ~~* with case-sensitive trigrams");
+#endif
+ /* FALL THRU */
+ case LikeStrategyNumber:
+ case EqualStrategyNumber:
+ /* Wildcard and equal search are inexact */
+ *recheck = true;
+
+ /*
+ * Check if all the extracted trigrams can be present in child
+ * nodes.
+ */
+ if (GIST_LEAF(entry))
+ { /* all leafs contains orig trgm */
+ res = trgm_contained_by(qtrg, key);
+ }
+ else if (ISALLTRUE(key))
+ { /* non-leaf contains signature */
+ res = true;
+ }
+ else
+ { /* non-leaf contains signature */
+ int32 k,
+ tmp = 0,
+ len = ARRNELEM(qtrg);
+ trgm *ptr = GETARR(qtrg);
+ BITVECP sign = GETSIGN(key);
+
+ res = true;
+ for (k = 0; k < len; k++)
+ {
+ CPTRGM(((char *) &tmp), ptr + k);
+ if (!GETBIT(sign, HASHVAL(tmp, siglen)))
+ {
+ res = false;
+ break;
+ }
+ }
+ }
+ break;
+ case RegExpICaseStrategyNumber:
+#ifndef IGNORECASE
+ elog(ERROR, "cannot handle ~* with case-sensitive trigrams");
+#endif
+ /* FALL THRU */
+ case RegExpStrategyNumber:
+ /* Regexp search is inexact */
+ *recheck = true;
+
+ /* Check regex match as much as we can with available info */
+ if (qtrg)
+ {
+ if (GIST_LEAF(entry))
+ { /* all leafs contains orig trgm */
+ bool *check;
+
+ check = trgm_presence_map(qtrg, key);
+ res = trigramsMatchGraph(cache->graph, check);
+ pfree(check);
+ }
+ else if (ISALLTRUE(key))
+ { /* non-leaf contains signature */
+ res = true;
+ }
+ else
+ { /* non-leaf contains signature */
+ int32 k,
+ tmp = 0,
+ len = ARRNELEM(qtrg);
+ trgm *ptr = GETARR(qtrg);
+ BITVECP sign = GETSIGN(key);
+ bool *check;
+
+ /*
+ * GETBIT() tests may give false positives, due to limited
+ * size of the sign array. But since trigramsMatchGraph()
+ * implements a monotone boolean function, false positives
+ * in the check array can't lead to false negative answer.
+ * So we can apply trigramsMatchGraph despite uncertainty,
+ * and that usefully improves the quality of the search.
+ */
+ check = (bool *) palloc(len * sizeof(bool));
+ for (k = 0; k < len; k++)
+ {
+ CPTRGM(((char *) &tmp), ptr + k);
+ check[k] = GETBIT(sign, HASHVAL(tmp, siglen));
+ }
+ res = trigramsMatchGraph(cache->graph, check);
+ pfree(check);
+ }
+ }
+ else
+ {
+ /* trigram-free query must be rechecked everywhere */
+ res = true;
+ }
+ break;
+ default:
+ elog(ERROR, "unrecognized strategy number: %d", strategy);
+ res = false; /* keep compiler quiet */
+ break;
+ }
+
+ PG_RETURN_BOOL(res);
+}
+
+Datum
+gtrgm_distance(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
+ text *query = PG_GETARG_TEXT_P(1);
+ StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
+
+ /* Oid subtype = PG_GETARG_OID(3); */
+ bool *recheck = (bool *) PG_GETARG_POINTER(4);
+ int siglen = GET_SIGLEN();
+ TRGM *key = (TRGM *) DatumGetPointer(entry->key);
+ TRGM *qtrg;
+ float8 res;
+ Size querysize = VARSIZE(query);
+ char *cache = (char *) fcinfo->flinfo->fn_extra;
+
+ /*
+ * Cache the generated trigrams across multiple calls with the same query.
+ */
+ if (cache == NULL ||
+ VARSIZE(cache) != querysize ||
+ memcmp(cache, query, querysize) != 0)
+ {
+ char *newcache;
+
+ qtrg = generate_trgm(VARDATA(query), querysize - VARHDRSZ);
+
+ newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
+ MAXALIGN(querysize) +
+ VARSIZE(qtrg));
+
+ memcpy(newcache, query, querysize);
+ memcpy(newcache + MAXALIGN(querysize), qtrg, VARSIZE(qtrg));
+
+ if (cache)
+ pfree(cache);
+ fcinfo->flinfo->fn_extra = newcache;
+ cache = newcache;
+ }
+
+ qtrg = (TRGM *) (cache + MAXALIGN(querysize));
+
+ switch (strategy)
+ {
+ case DistanceStrategyNumber:
+ case WordDistanceStrategyNumber:
+ case StrictWordDistanceStrategyNumber:
+ /* Only plain trigram distance is exact */
+ *recheck = (strategy != DistanceStrategyNumber);
+ if (GIST_LEAF(entry))
+ { /* all leafs contains orig trgm */
+
+ /*
+ * Prevent gcc optimizing the sml variable using volatile
+ * keyword. Otherwise res can differ from the
+ * word_similarity_dist_op() function.
+ */
+ float4 volatile sml = cnt_sml(qtrg, key, *recheck);
+
+ res = 1.0 - sml;
+ }
+ else if (ISALLTRUE(key))
+ { /* all leafs contains orig trgm */
+ res = 0.0;
+ }
+ else
+ { /* non-leaf contains signature */
+ int32 count = cnt_sml_sign_common(qtrg, GETSIGN(key), siglen);
+ int32 len = ARRNELEM(qtrg);
+
+ res = (len == 0) ? -1.0 : 1.0 - ((float8) count) / ((float8) len);
+ }
+ break;
+ default:
+ elog(ERROR, "unrecognized strategy number: %d", strategy);
+ res = 0; /* keep compiler quiet */
+ break;
+ }
+
+ PG_RETURN_FLOAT8(res);
+}
+
+static int32
+unionkey(BITVECP sbase, TRGM *add, int siglen)
+{
+ int32 i;
+
+ if (ISSIGNKEY(add))
+ {
+ BITVECP sadd = GETSIGN(add);
+
+ if (ISALLTRUE(add))
+ return 1;
+
+ LOOPBYTE(siglen)
+ sbase[i] |= sadd[i];
+ }
+ else
+ {
+ trgm *ptr = GETARR(add);
+ int32 tmp = 0;
+
+ for (i = 0; i < ARRNELEM(add); i++)
+ {
+ CPTRGM(((char *) &tmp), ptr + i);
+ HASH(sbase, tmp, siglen);
+ }
+ }
+ return 0;
+}
+
+
+Datum
+gtrgm_union(PG_FUNCTION_ARGS)
+{
+ GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+ int32 len = entryvec->n;
+ int *size = (int *) PG_GETARG_POINTER(1);
+ int siglen = GET_SIGLEN();
+ int32 i;
+ TRGM *result = gtrgm_alloc(false, siglen, NULL);
+ BITVECP base = GETSIGN(result);
+
+ for (i = 0; i < len; i++)
+ {
+ if (unionkey(base, GETENTRY(entryvec, i), siglen))
+ {
+ result->flag = ALLISTRUE;
+ SET_VARSIZE(result, CALCGTSIZE(ALLISTRUE, siglen));
+ break;
+ }
+ }
+
+ *size = VARSIZE(result);
+
+ PG_RETURN_POINTER(result);
+}
+
+Datum
+gtrgm_same(PG_FUNCTION_ARGS)
+{
+ TRGM *a = (TRGM *) PG_GETARG_POINTER(0);
+ TRGM *b = (TRGM *) PG_GETARG_POINTER(1);
+ bool *result = (bool *) PG_GETARG_POINTER(2);
+ int siglen = GET_SIGLEN();
+
+ if (ISSIGNKEY(a))
+ { /* then b also ISSIGNKEY */
+ if (ISALLTRUE(a) && ISALLTRUE(b))
+ *result = true;
+ else if (ISALLTRUE(a))
+ *result = false;
+ else if (ISALLTRUE(b))
+ *result = false;
+ else
+ {
+ int32 i;
+ BITVECP sa = GETSIGN(a),
+ sb = GETSIGN(b);
+
+ *result = true;
+ LOOPBYTE(siglen)
+ {
+ if (sa[i] != sb[i])
+ {
+ *result = false;
+ break;
+ }
+ }
+ }
+ }
+ else
+ { /* a and b ISARRKEY */
+ int32 lena = ARRNELEM(a),
+ lenb = ARRNELEM(b);
+
+ if (lena != lenb)
+ *result = false;
+ else
+ {
+ trgm *ptra = GETARR(a),
+ *ptrb = GETARR(b);
+ int32 i;
+
+ *result = true;
+ for (i = 0; i < lena; i++)
+ if (CMPTRGM(ptra + i, ptrb + i))
+ {
+ *result = false;
+ break;
+ }
+ }
+ }
+
+ PG_RETURN_POINTER(result);
+}
+
+static int32
+sizebitvec(BITVECP sign, int siglen)
+{
+ return pg_popcount(sign, siglen);
+}
+
+static int
+hemdistsign(BITVECP a, BITVECP b, int siglen)
+{
+ int i,
+ diff,
+ dist = 0;
+
+ LOOPBYTE(siglen)
+ {
+ diff = (unsigned char) (a[i] ^ b[i]);
+ /* Using the popcount functions here isn't likely to win */
+ dist += pg_number_of_ones[diff];
+ }
+ return dist;
+}
+
+static int
+hemdist(TRGM *a, TRGM *b, int siglen)
+{
+ if (ISALLTRUE(a))
+ {
+ if (ISALLTRUE(b))
+ return 0;
+ else
+ return SIGLENBIT(siglen) - sizebitvec(GETSIGN(b), siglen);
+ }
+ else if (ISALLTRUE(b))
+ return SIGLENBIT(siglen) - sizebitvec(GETSIGN(a), siglen);
+
+ return hemdistsign(GETSIGN(a), GETSIGN(b), siglen);
+}
+
+Datum
+gtrgm_penalty(PG_FUNCTION_ARGS)
+{
+ GISTENTRY *origentry = (GISTENTRY *) PG_GETARG_POINTER(0); /* always ISSIGNKEY */
+ GISTENTRY *newentry = (GISTENTRY *) PG_GETARG_POINTER(1);
+ float *penalty = (float *) PG_GETARG_POINTER(2);
+ int siglen = GET_SIGLEN();
+ TRGM *origval = (TRGM *) DatumGetPointer(origentry->key);
+ TRGM *newval = (TRGM *) DatumGetPointer(newentry->key);
+ BITVECP orig = GETSIGN(origval);
+
+ *penalty = 0.0;
+
+ if (ISARRKEY(newval))
+ {
+ char *cache = (char *) fcinfo->flinfo->fn_extra;
+ TRGM *cachedVal = (TRGM *) (cache + MAXALIGN(siglen));
+ Size newvalsize = VARSIZE(newval);
+ BITVECP sign;
+
+ /*
+ * Cache the sign data across multiple calls with the same newval.
+ */
+ if (cache == NULL ||
+ VARSIZE(cachedVal) != newvalsize ||
+ memcmp(cachedVal, newval, newvalsize) != 0)
+ {
+ char *newcache;
+
+ newcache = MemoryContextAlloc(fcinfo->flinfo->fn_mcxt,
+ MAXALIGN(siglen) +
+ newvalsize);
+
+ makesign((BITVECP) newcache, newval, siglen);
+
+ cachedVal = (TRGM *) (newcache + MAXALIGN(siglen));
+ memcpy(cachedVal, newval, newvalsize);
+
+ if (cache)
+ pfree(cache);
+ fcinfo->flinfo->fn_extra = newcache;
+ cache = newcache;
+ }
+
+ sign = (BITVECP) cache;
+
+ if (ISALLTRUE(origval))
+ *penalty = ((float) (SIGLENBIT(siglen) - sizebitvec(sign, siglen))) / (float) (SIGLENBIT(siglen) + 1);
+ else
+ *penalty = hemdistsign(sign, orig, siglen);
+ }
+ else
+ *penalty = hemdist(origval, newval, siglen);
+ PG_RETURN_POINTER(penalty);
+}
+
+typedef struct
+{
+ bool allistrue;
+ BITVECP sign;
+} CACHESIGN;
+
+static void
+fillcache(CACHESIGN *item, TRGM *key, BITVECP sign, int siglen)
+{
+ item->allistrue = false;
+ item->sign = sign;
+ if (ISARRKEY(key))
+ makesign(item->sign, key, siglen);
+ else if (ISALLTRUE(key))
+ item->allistrue = true;
+ else
+ memcpy(item->sign, GETSIGN(key), siglen);
+}
+
+#define WISH_F(a,b,c) (double)( -(double)(((a)-(b))*((a)-(b))*((a)-(b)))*(c) )
+typedef struct
+{
+ OffsetNumber pos;
+ int32 cost;
+} SPLITCOST;
+
+static int
+comparecost(const void *a, const void *b)
+{
+ if (((const SPLITCOST *) a)->cost == ((const SPLITCOST *) b)->cost)
+ return 0;
+ else
+ return (((const SPLITCOST *) a)->cost > ((const SPLITCOST *) b)->cost) ? 1 : -1;
+}
+
+
+static int
+hemdistcache(CACHESIGN *a, CACHESIGN *b, int siglen)
+{
+ if (a->allistrue)
+ {
+ if (b->allistrue)
+ return 0;
+ else
+ return SIGLENBIT(siglen) - sizebitvec(b->sign, siglen);
+ }
+ else if (b->allistrue)
+ return SIGLENBIT(siglen) - sizebitvec(a->sign, siglen);
+
+ return hemdistsign(a->sign, b->sign, siglen);
+}
+
+Datum
+gtrgm_picksplit(PG_FUNCTION_ARGS)
+{
+ GistEntryVector *entryvec = (GistEntryVector *) PG_GETARG_POINTER(0);
+ OffsetNumber maxoff = entryvec->n - 1;
+ GIST_SPLITVEC *v = (GIST_SPLITVEC *) PG_GETARG_POINTER(1);
+ int siglen = GET_SIGLEN();
+ OffsetNumber k,
+ j;
+ TRGM *datum_l,
+ *datum_r;
+ BITVECP union_l,
+ union_r;
+ int32 size_alpha,
+ size_beta;
+ int32 size_waste,
+ waste = -1;
+ int32 nbytes;
+ OffsetNumber seed_1 = 0,
+ seed_2 = 0;
+ OffsetNumber *left,
+ *right;
+ BITVECP ptr;
+ int i;
+ CACHESIGN *cache;
+ char *cache_sign;
+ SPLITCOST *costvector;
+
+ /* cache the sign data for each existing item */
+ cache = (CACHESIGN *) palloc(sizeof(CACHESIGN) * (maxoff + 1));
+ cache_sign = palloc(siglen * (maxoff + 1));
+
+ for (k = FirstOffsetNumber; k <= maxoff; k = OffsetNumberNext(k))
+ fillcache(&cache[k], GETENTRY(entryvec, k), &cache_sign[siglen * k],
+ siglen);
+
+ /* now find the two furthest-apart items */
+ for (k = FirstOffsetNumber; k < maxoff; k = OffsetNumberNext(k))
+ {
+ for (j = OffsetNumberNext(k); j <= maxoff; j = OffsetNumberNext(j))
+ {
+ size_waste = hemdistcache(&(cache[j]), &(cache[k]), siglen);
+ if (size_waste > waste)
+ {
+ waste = size_waste;
+ seed_1 = k;
+ seed_2 = j;
+ }
+ }
+ }
+
+ /* just in case we didn't make a selection ... */
+ if (seed_1 == 0 || seed_2 == 0)
+ {
+ seed_1 = 1;
+ seed_2 = 2;
+ }
+
+ /* initialize the result vectors */
+ nbytes = maxoff * sizeof(OffsetNumber);
+ v->spl_left = left = (OffsetNumber *) palloc(nbytes);
+ v->spl_right = right = (OffsetNumber *) palloc(nbytes);
+ v->spl_nleft = 0;
+ v->spl_nright = 0;
+
+ /* form initial .. */
+ datum_l = gtrgm_alloc(cache[seed_1].allistrue, siglen, cache[seed_1].sign);
+ datum_r = gtrgm_alloc(cache[seed_2].allistrue, siglen, cache[seed_2].sign);
+
+ union_l = GETSIGN(datum_l);
+ union_r = GETSIGN(datum_r);
+
+ /* sort before ... */
+ costvector = (SPLITCOST *) palloc(sizeof(SPLITCOST) * maxoff);
+ for (j = FirstOffsetNumber; j <= maxoff; j = OffsetNumberNext(j))
+ {
+ costvector[j - 1].pos = j;
+ size_alpha = hemdistcache(&(cache[seed_1]), &(cache[j]), siglen);
+ size_beta = hemdistcache(&(cache[seed_2]), &(cache[j]), siglen);
+ costvector[j - 1].cost = abs(size_alpha - size_beta);
+ }
+ qsort(costvector, maxoff, sizeof(SPLITCOST), comparecost);
+
+ for (k = 0; k < maxoff; k++)
+ {
+ j = costvector[k].pos;
+ if (j == seed_1)
+ {
+ *left++ = j;
+ v->spl_nleft++;
+ continue;
+ }
+ else if (j == seed_2)
+ {
+ *right++ = j;
+ v->spl_nright++;
+ continue;
+ }
+
+ if (ISALLTRUE(datum_l) || cache[j].allistrue)
+ {
+ if (ISALLTRUE(datum_l) && cache[j].allistrue)
+ size_alpha = 0;
+ else
+ size_alpha = SIGLENBIT(siglen) -
+ sizebitvec((cache[j].allistrue) ? GETSIGN(datum_l) :
+ GETSIGN(cache[j].sign),
+ siglen);
+ }
+ else
+ size_alpha = hemdistsign(cache[j].sign, GETSIGN(datum_l), siglen);
+
+ if (ISALLTRUE(datum_r) || cache[j].allistrue)
+ {
+ if (ISALLTRUE(datum_r) && cache[j].allistrue)
+ size_beta = 0;
+ else
+ size_beta = SIGLENBIT(siglen) -
+ sizebitvec((cache[j].allistrue) ? GETSIGN(datum_r) :
+ GETSIGN(cache[j].sign),
+ siglen);
+ }
+ else
+ size_beta = hemdistsign(cache[j].sign, GETSIGN(datum_r), siglen);
+
+ if (size_alpha < size_beta + WISH_F(v->spl_nleft, v->spl_nright, 0.1))
+ {
+ if (ISALLTRUE(datum_l) || cache[j].allistrue)
+ {
+ if (!ISALLTRUE(datum_l))
+ memset(GETSIGN(datum_l), 0xff, siglen);
+ }
+ else
+ {
+ ptr = cache[j].sign;
+ LOOPBYTE(siglen)
+ union_l[i] |= ptr[i];
+ }
+ *left++ = j;
+ v->spl_nleft++;
+ }
+ else
+ {
+ if (ISALLTRUE(datum_r) || cache[j].allistrue)
+ {
+ if (!ISALLTRUE(datum_r))
+ memset(GETSIGN(datum_r), 0xff, siglen);
+ }
+ else
+ {
+ ptr = cache[j].sign;
+ LOOPBYTE(siglen)
+ union_r[i] |= ptr[i];
+ }
+ *right++ = j;
+ v->spl_nright++;
+ }
+ }
+
+ v->spl_ldatum = PointerGetDatum(datum_l);
+ v->spl_rdatum = PointerGetDatum(datum_r);
+
+ PG_RETURN_POINTER(v);
+}
+
+Datum
+gtrgm_options(PG_FUNCTION_ARGS)
+{
+ local_relopts *relopts = (local_relopts *) PG_GETARG_POINTER(0);
+
+ init_local_reloptions(relopts, sizeof(TrgmGistOptions));
+ add_local_int_reloption(relopts, "siglen",
+ "signature length in bytes",
+ SIGLEN_DEFAULT, 1, SIGLEN_MAX,
+ offsetof(TrgmGistOptions, siglen));
+
+ PG_RETURN_VOID();
+}
diff --git a/contrib/pg_trgm/trgm_op.c b/contrib/pg_trgm/trgm_op.c
new file mode 100644
index 0000000..49d4497
--- /dev/null
+++ b/contrib/pg_trgm/trgm_op.c
@@ -0,0 +1,1323 @@
+/*
+ * contrib/pg_trgm/trgm_op.c
+ */
+#include "postgres.h"
+
+#include <ctype.h>
+
+#include "catalog/pg_type.h"
+#include "lib/qunique.h"
+#include "miscadmin.h"
+#include "trgm.h"
+#include "tsearch/ts_locale.h"
+#include "utils/guc.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/pg_crc.h"
+
+PG_MODULE_MAGIC;
+
+/* GUC variables */
+double similarity_threshold = 0.3f;
+double word_similarity_threshold = 0.6f;
+double strict_word_similarity_threshold = 0.5f;
+
+PG_FUNCTION_INFO_V1(set_limit);
+PG_FUNCTION_INFO_V1(show_limit);
+PG_FUNCTION_INFO_V1(show_trgm);
+PG_FUNCTION_INFO_V1(similarity);
+PG_FUNCTION_INFO_V1(word_similarity);
+PG_FUNCTION_INFO_V1(strict_word_similarity);
+PG_FUNCTION_INFO_V1(similarity_dist);
+PG_FUNCTION_INFO_V1(similarity_op);
+PG_FUNCTION_INFO_V1(word_similarity_op);
+PG_FUNCTION_INFO_V1(word_similarity_commutator_op);
+PG_FUNCTION_INFO_V1(word_similarity_dist_op);
+PG_FUNCTION_INFO_V1(word_similarity_dist_commutator_op);
+PG_FUNCTION_INFO_V1(strict_word_similarity_op);
+PG_FUNCTION_INFO_V1(strict_word_similarity_commutator_op);
+PG_FUNCTION_INFO_V1(strict_word_similarity_dist_op);
+PG_FUNCTION_INFO_V1(strict_word_similarity_dist_commutator_op);
+
+/* Trigram with position */
+typedef struct
+{
+ trgm trg;
+ int index;
+} pos_trgm;
+
+/* Trigram bound type */
+typedef uint8 TrgmBound;
+#define TRGM_BOUND_LEFT 0x01 /* trigram is left bound of word */
+#define TRGM_BOUND_RIGHT 0x02 /* trigram is right bound of word */
+
+/* Word similarity flags */
+#define WORD_SIMILARITY_CHECK_ONLY 0x01 /* only check existence of similar
+ * search pattern in text */
+#define WORD_SIMILARITY_STRICT 0x02 /* force bounds of extent to match
+ * word bounds */
+
+/*
+ * Module load callback
+ */
+void
+_PG_init(void)
+{
+ /* Define custom GUC variables. */
+ DefineCustomRealVariable("pg_trgm.similarity_threshold",
+ "Sets the threshold used by the % operator.",
+ "Valid range is 0.0 .. 1.0.",
+ &similarity_threshold,
+ 0.3f,
+ 0.0,
+ 1.0,
+ PGC_USERSET,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+ DefineCustomRealVariable("pg_trgm.word_similarity_threshold",
+ "Sets the threshold used by the <% operator.",
+ "Valid range is 0.0 .. 1.0.",
+ &word_similarity_threshold,
+ 0.6f,
+ 0.0,
+ 1.0,
+ PGC_USERSET,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+ DefineCustomRealVariable("pg_trgm.strict_word_similarity_threshold",
+ "Sets the threshold used by the <<% operator.",
+ "Valid range is 0.0 .. 1.0.",
+ &strict_word_similarity_threshold,
+ 0.5f,
+ 0.0,
+ 1.0,
+ PGC_USERSET,
+ 0,
+ NULL,
+ NULL,
+ NULL);
+
+ MarkGUCPrefixReserved("pg_trgm");
+}
+
+/*
+ * Deprecated function.
+ * Use "pg_trgm.similarity_threshold" GUC variable instead of this function.
+ */
+Datum
+set_limit(PG_FUNCTION_ARGS)
+{
+ float4 nlimit = PG_GETARG_FLOAT4(0);
+ char *nlimit_str;
+ Oid func_out_oid;
+ bool is_varlena;
+
+ getTypeOutputInfo(FLOAT4OID, &func_out_oid, &is_varlena);
+
+ nlimit_str = OidOutputFunctionCall(func_out_oid, Float4GetDatum(nlimit));
+
+ SetConfigOption("pg_trgm.similarity_threshold", nlimit_str,
+ PGC_USERSET, PGC_S_SESSION);
+
+ PG_RETURN_FLOAT4(similarity_threshold);
+}
+
+
+/*
+ * Get similarity threshold for given index scan strategy number.
+ */
+double
+index_strategy_get_limit(StrategyNumber strategy)
+{
+ switch (strategy)
+ {
+ case SimilarityStrategyNumber:
+ return similarity_threshold;
+ case WordSimilarityStrategyNumber:
+ return word_similarity_threshold;
+ case StrictWordSimilarityStrategyNumber:
+ return strict_word_similarity_threshold;
+ default:
+ elog(ERROR, "unrecognized strategy number: %d", strategy);
+ break;
+ }
+
+ return 0.0; /* keep compiler quiet */
+}
+
+/*
+ * Deprecated function.
+ * Use "pg_trgm.similarity_threshold" GUC variable instead of this function.
+ */
+Datum
+show_limit(PG_FUNCTION_ARGS)
+{
+ PG_RETURN_FLOAT4(similarity_threshold);
+}
+
+static int
+comp_trgm(const void *a, const void *b)
+{
+ return CMPTRGM(a, b);
+}
+
+/*
+ * Finds first word in string, returns pointer to the word,
+ * endword points to the character after word
+ */
+static char *
+find_word(char *str, int lenstr, char **endword, int *charlen)
+{
+ char *beginword = str;
+
+ while (beginword - str < lenstr && !ISWORDCHR(beginword))
+ beginword += pg_mblen(beginword);
+
+ if (beginword - str >= lenstr)
+ return NULL;
+
+ *endword = beginword;
+ *charlen = 0;
+ while (*endword - str < lenstr && ISWORDCHR(*endword))
+ {
+ *endword += pg_mblen(*endword);
+ (*charlen)++;
+ }
+
+ return beginword;
+}
+
+/*
+ * Reduce a trigram (three possibly multi-byte characters) to a trgm,
+ * which is always exactly three bytes. If we have three single-byte
+ * characters, we just use them as-is; otherwise we form a hash value.
+ */
+void
+compact_trigram(trgm *tptr, char *str, int bytelen)
+{
+ if (bytelen == 3)
+ {
+ CPTRGM(tptr, str);
+ }
+ else
+ {
+ pg_crc32 crc;
+
+ INIT_LEGACY_CRC32(crc);
+ COMP_LEGACY_CRC32(crc, str, bytelen);
+ FIN_LEGACY_CRC32(crc);
+
+ /*
+ * use only 3 upper bytes from crc, hope, it's good enough hashing
+ */
+ CPTRGM(tptr, &crc);
+ }
+}
+
+/*
+ * Adds trigrams from words (already padded).
+ */
+static trgm *
+make_trigrams(trgm *tptr, char *str, int bytelen, int charlen)
+{
+ char *ptr = str;
+
+ if (charlen < 3)
+ return tptr;
+
+ if (bytelen > charlen)
+ {
+ /* Find multibyte character boundaries and apply compact_trigram */
+ int lenfirst = pg_mblen(str),
+ lenmiddle = pg_mblen(str + lenfirst),
+ lenlast = pg_mblen(str + lenfirst + lenmiddle);
+
+ while ((ptr - str) + lenfirst + lenmiddle + lenlast <= bytelen)
+ {
+ compact_trigram(tptr, ptr, lenfirst + lenmiddle + lenlast);
+
+ ptr += lenfirst;
+ tptr++;
+
+ lenfirst = lenmiddle;
+ lenmiddle = lenlast;
+ lenlast = pg_mblen(ptr + lenfirst + lenmiddle);
+ }
+ }
+ else
+ {
+ /* Fast path when there are no multibyte characters */
+ Assert(bytelen == charlen);
+
+ while (ptr - str < bytelen - 2 /* number of trigrams = strlen - 2 */ )
+ {
+ CPTRGM(tptr, ptr);
+ ptr++;
+ tptr++;
+ }
+ }
+
+ return tptr;
+}
+
+/*
+ * Make array of trigrams without sorting and removing duplicate items.
+ *
+ * trg: where to return the array of trigrams.
+ * str: source string, of length slen bytes.
+ * bounds: where to return bounds of trigrams (if needed).
+ *
+ * Returns length of the generated array.
+ */
+static int
+generate_trgm_only(trgm *trg, char *str, int slen, TrgmBound *bounds)
+{
+ trgm *tptr;
+ char *buf;
+ int charlen,
+ bytelen;
+ char *bword,
+ *eword;
+
+ if (slen + LPADDING + RPADDING < 3 || slen == 0)
+ return 0;
+
+ tptr = trg;
+
+ /* Allocate a buffer for case-folded, blank-padded words */
+ buf = (char *) palloc(slen * pg_database_encoding_max_length() + 4);
+
+ if (LPADDING > 0)
+ {
+ *buf = ' ';
+ if (LPADDING > 1)
+ *(buf + 1) = ' ';
+ }
+
+ eword = str;
+ while ((bword = find_word(eword, slen - (eword - str), &eword, &charlen)) != NULL)
+ {
+#ifdef IGNORECASE
+ bword = lowerstr_with_len(bword, eword - bword);
+ bytelen = strlen(bword);
+#else
+ bytelen = eword - bword;
+#endif
+
+ memcpy(buf + LPADDING, bword, bytelen);
+
+#ifdef IGNORECASE
+ pfree(bword);
+#endif
+
+ buf[LPADDING + bytelen] = ' ';
+ buf[LPADDING + bytelen + 1] = ' ';
+
+ /* Calculate trigrams marking their bounds if needed */
+ if (bounds)
+ bounds[tptr - trg] |= TRGM_BOUND_LEFT;
+ tptr = make_trigrams(tptr, buf, bytelen + LPADDING + RPADDING,
+ charlen + LPADDING + RPADDING);
+ if (bounds)
+ bounds[tptr - trg - 1] |= TRGM_BOUND_RIGHT;
+ }
+
+ pfree(buf);
+
+ return tptr - trg;
+}
+
+/*
+ * Guard against possible overflow in the palloc requests below. (We
+ * don't worry about the additive constants, since palloc can detect
+ * requests that are a little above MaxAllocSize --- we just need to
+ * prevent integer overflow in the multiplications.)
+ */
+static void
+protect_out_of_mem(int slen)
+{
+ if ((Size) (slen / 2) >= (MaxAllocSize / (sizeof(trgm) * 3)) ||
+ (Size) slen >= (MaxAllocSize / pg_database_encoding_max_length()))
+ ereport(ERROR,
+ (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+ errmsg("out of memory")));
+}
+
+/*
+ * Make array of trigrams with sorting and removing duplicate items.
+ *
+ * str: source string, of length slen bytes.
+ *
+ * Returns the sorted array of unique trigrams.
+ */
+TRGM *
+generate_trgm(char *str, int slen)
+{
+ TRGM *trg;
+ int len;
+
+ protect_out_of_mem(slen);
+
+ trg = (TRGM *) palloc(TRGMHDRSIZE + sizeof(trgm) * (slen / 2 + 1) * 3);
+ trg->flag = ARRKEY;
+
+ len = generate_trgm_only(GETARR(trg), str, slen, NULL);
+ SET_VARSIZE(trg, CALCGTSIZE(ARRKEY, len));
+
+ if (len == 0)
+ return trg;
+
+ /*
+ * Make trigrams unique.
+ */
+ if (len > 1)
+ {
+ qsort(GETARR(trg), len, sizeof(trgm), comp_trgm);
+ len = qunique(GETARR(trg), len, sizeof(trgm), comp_trgm);
+ }
+
+ SET_VARSIZE(trg, CALCGTSIZE(ARRKEY, len));
+
+ return trg;
+}
+
+/*
+ * Make array of positional trigrams from two trigram arrays trg1 and trg2.
+ *
+ * trg1: trigram array of search pattern, of length len1. trg1 is required
+ * word which positions don't matter and replaced with -1.
+ * trg2: trigram array of text, of length len2. trg2 is haystack where we
+ * search and have to store its positions.
+ *
+ * Returns concatenated trigram array.
+ */
+static pos_trgm *
+make_positional_trgm(trgm *trg1, int len1, trgm *trg2, int len2)
+{
+ pos_trgm *result;
+ int i,
+ len = len1 + len2;
+
+ result = (pos_trgm *) palloc(sizeof(pos_trgm) * len);
+
+ for (i = 0; i < len1; i++)
+ {
+ memcpy(&result[i].trg, &trg1[i], sizeof(trgm));
+ result[i].index = -1;
+ }
+
+ for (i = 0; i < len2; i++)
+ {
+ memcpy(&result[i + len1].trg, &trg2[i], sizeof(trgm));
+ result[i + len1].index = i;
+ }
+
+ return result;
+}
+
+/*
+ * Compare position trigrams: compare trigrams first and position second.
+ */
+static int
+comp_ptrgm(const void *v1, const void *v2)
+{
+ const pos_trgm *p1 = (const pos_trgm *) v1;
+ const pos_trgm *p2 = (const pos_trgm *) v2;
+ int cmp;
+
+ cmp = CMPTRGM(p1->trg, p2->trg);
+ if (cmp != 0)
+ return cmp;
+
+ if (p1->index < p2->index)
+ return -1;
+ else if (p1->index == p2->index)
+ return 0;
+ else
+ return 1;
+}
+
+/*
+ * Iterative search function which calculates maximum similarity with word in
+ * the string. Maximum similarity is only calculated only if the flag
+ * WORD_SIMILARITY_CHECK_ONLY isn't set.
+ *
+ * trg2indexes: array which stores indexes of the array "found".
+ * found: array which stores true of false values.
+ * ulen1: count of unique trigrams of array "trg1".
+ * len2: length of array "trg2" and array "trg2indexes".
+ * len: length of the array "found".
+ * flags: set of boolean flags parameterizing similarity calculation.
+ * bounds: whether each trigram is left/right bound of word.
+ *
+ * Returns word similarity.
+ */
+static float4
+iterate_word_similarity(int *trg2indexes,
+ bool *found,
+ int ulen1,
+ int len2,
+ int len,
+ uint8 flags,
+ TrgmBound *bounds)
+{
+ int *lastpos,
+ i,
+ ulen2 = 0,
+ count = 0,
+ upper = -1,
+ lower;
+ float4 smlr_cur,
+ smlr_max = 0.0f;
+ double threshold;
+
+ Assert(bounds || !(flags & WORD_SIMILARITY_STRICT));
+
+ /* Select appropriate threshold */
+ threshold = (flags & WORD_SIMILARITY_STRICT) ?
+ strict_word_similarity_threshold :
+ word_similarity_threshold;
+
+ /*
+ * Consider first trigram as initial lower bound for strict word
+ * similarity, or initialize it later with first trigram present for plain
+ * word similarity.
+ */
+ lower = (flags & WORD_SIMILARITY_STRICT) ? 0 : -1;
+
+ /* Memorise last position of each trigram */
+ lastpos = (int *) palloc(sizeof(int) * len);
+ memset(lastpos, -1, sizeof(int) * len);
+
+ for (i = 0; i < len2; i++)
+ {
+ int trgindex;
+
+ CHECK_FOR_INTERRUPTS();
+
+ /* Get index of next trigram */
+ trgindex = trg2indexes[i];
+
+ /* Update last position of this trigram */
+ if (lower >= 0 || found[trgindex])
+ {
+ if (lastpos[trgindex] < 0)
+ {
+ ulen2++;
+ if (found[trgindex])
+ count++;
+ }
+ lastpos[trgindex] = i;
+ }
+
+ /*
+ * Adjust upper bound if trigram is upper bound of word for strict
+ * word similarity, or if trigram is present in required substring for
+ * plain word similarity
+ */
+ if ((flags & WORD_SIMILARITY_STRICT) ? (bounds[i] & TRGM_BOUND_RIGHT)
+ : found[trgindex])
+ {
+ int prev_lower,
+ tmp_ulen2,
+ tmp_lower,
+ tmp_count;
+
+ upper = i;
+ if (lower == -1)
+ {
+ lower = i;
+ ulen2 = 1;
+ }
+
+ smlr_cur = CALCSML(count, ulen1, ulen2);
+
+ /* Also try to adjust lower bound for greater similarity */
+ tmp_count = count;
+ tmp_ulen2 = ulen2;
+ prev_lower = lower;
+ for (tmp_lower = lower; tmp_lower <= upper; tmp_lower++)
+ {
+ float smlr_tmp;
+ int tmp_trgindex;
+
+ /*
+ * Adjust lower bound only if trigram is lower bound of word
+ * for strict word similarity, or consider every trigram as
+ * lower bound for plain word similarity.
+ */
+ if (!(flags & WORD_SIMILARITY_STRICT)
+ || (bounds[tmp_lower] & TRGM_BOUND_LEFT))
+ {
+ smlr_tmp = CALCSML(tmp_count, ulen1, tmp_ulen2);
+ if (smlr_tmp > smlr_cur)
+ {
+ smlr_cur = smlr_tmp;
+ ulen2 = tmp_ulen2;
+ lower = tmp_lower;
+ count = tmp_count;
+ }
+
+ /*
+ * If we only check that word similarity is greater than
+ * threshold we do not need to calculate a maximum
+ * similarity.
+ */
+ if ((flags & WORD_SIMILARITY_CHECK_ONLY)
+ && smlr_cur >= threshold)
+ break;
+ }
+
+ tmp_trgindex = trg2indexes[tmp_lower];
+ if (lastpos[tmp_trgindex] == tmp_lower)
+ {
+ tmp_ulen2--;
+ if (found[tmp_trgindex])
+ tmp_count--;
+ }
+ }
+
+ smlr_max = Max(smlr_max, smlr_cur);
+
+ /*
+ * if we only check that word similarity is greater than threshold
+ * we do not need to calculate a maximum similarity.
+ */
+ if ((flags & WORD_SIMILARITY_CHECK_ONLY) && smlr_max >= threshold)
+ break;
+
+ for (tmp_lower = prev_lower; tmp_lower < lower; tmp_lower++)
+ {
+ int tmp_trgindex;
+
+ tmp_trgindex = trg2indexes[tmp_lower];
+ if (lastpos[tmp_trgindex] == tmp_lower)
+ lastpos[tmp_trgindex] = -1;
+ }
+ }
+ }
+
+ pfree(lastpos);
+
+ return smlr_max;
+}
+
+/*
+ * Calculate word similarity.
+ * This function prepare two arrays: "trg2indexes" and "found". Then this arrays
+ * are used to calculate word similarity using iterate_word_similarity().
+ *
+ * "trg2indexes" is array which stores indexes of the array "found".
+ * In other words:
+ * trg2indexes[j] = i;
+ * found[i] = true (or false);
+ * If found[i] == true then there is trigram trg2[j] in array "trg1".
+ * If found[i] == false then there is not trigram trg2[j] in array "trg1".
+ *
+ * str1: search pattern string, of length slen1 bytes.
+ * str2: text in which we are looking for a word, of length slen2 bytes.
+ * flags: set of boolean flags parameterizing similarity calculation.
+ *
+ * Returns word similarity.
+ */
+static float4
+calc_word_similarity(char *str1, int slen1, char *str2, int slen2,
+ uint8 flags)
+{
+ bool *found;
+ pos_trgm *ptrg;
+ trgm *trg1;
+ trgm *trg2;
+ int len1,
+ len2,
+ len,
+ i,
+ j,
+ ulen1;
+ int *trg2indexes;
+ float4 result;
+ TrgmBound *bounds;
+
+ protect_out_of_mem(slen1 + slen2);
+
+ /* Make positional trigrams */
+ trg1 = (trgm *) palloc(sizeof(trgm) * (slen1 / 2 + 1) * 3);
+ trg2 = (trgm *) palloc(sizeof(trgm) * (slen2 / 2 + 1) * 3);
+ if (flags & WORD_SIMILARITY_STRICT)
+ bounds = (TrgmBound *) palloc0(sizeof(TrgmBound) * (slen2 / 2 + 1) * 3);
+ else
+ bounds = NULL;
+
+ len1 = generate_trgm_only(trg1, str1, slen1, NULL);
+ len2 = generate_trgm_only(trg2, str2, slen2, bounds);
+
+ ptrg = make_positional_trgm(trg1, len1, trg2, len2);
+ len = len1 + len2;
+ qsort(ptrg, len, sizeof(pos_trgm), comp_ptrgm);
+
+ pfree(trg1);
+ pfree(trg2);
+
+ /*
+ * Merge positional trigrams array: enumerate each trigram and find its
+ * presence in required word.
+ */
+ trg2indexes = (int *) palloc(sizeof(int) * len2);
+ found = (bool *) palloc0(sizeof(bool) * len);
+
+ ulen1 = 0;
+ j = 0;
+ for (i = 0; i < len; i++)
+ {
+ if (i > 0)
+ {
+ int cmp = CMPTRGM(ptrg[i - 1].trg, ptrg[i].trg);
+
+ if (cmp != 0)
+ {
+ if (found[j])
+ ulen1++;
+ j++;
+ }
+ }
+
+ if (ptrg[i].index >= 0)
+ {
+ trg2indexes[ptrg[i].index] = j;
+ }
+ else
+ {
+ found[j] = true;
+ }
+ }
+ if (found[j])
+ ulen1++;
+
+ /* Run iterative procedure to find maximum similarity with word */
+ result = iterate_word_similarity(trg2indexes, found, ulen1, len2, len,
+ flags, bounds);
+
+ pfree(trg2indexes);
+ pfree(found);
+ pfree(ptrg);
+
+ return result;
+}
+
+
+/*
+ * Extract the next non-wildcard part of a search string, i.e. a word bounded
+ * by '_' or '%' meta-characters, non-word characters or string end.
+ *
+ * str: source string, of length lenstr bytes (need not be null-terminated)
+ * buf: where to return the substring (must be long enough)
+ * *bytelen: receives byte length of the found substring
+ * *charlen: receives character length of the found substring
+ *
+ * Returns pointer to end+1 of the found substring in the source string.
+ * Returns NULL if no word found (in which case buf, bytelen, charlen not set)
+ *
+ * If the found word is bounded by non-word characters or string boundaries
+ * then this function will include corresponding padding spaces into buf.
+ */
+static const char *
+get_wildcard_part(const char *str, int lenstr,
+ char *buf, int *bytelen, int *charlen)
+{
+ const char *beginword = str;
+ const char *endword;
+ char *s = buf;
+ bool in_leading_wildcard_meta = false;
+ bool in_trailing_wildcard_meta = false;
+ bool in_escape = false;
+ int clen;
+
+ /*
+ * Find the first word character, remembering whether preceding character
+ * was wildcard meta-character. Note that the in_escape state persists
+ * from this loop to the next one, since we may exit at a word character
+ * that is in_escape.
+ */
+ while (beginword - str < lenstr)
+ {
+ if (in_escape)
+ {
+ if (ISWORDCHR(beginword))
+ break;
+ in_escape = false;
+ in_leading_wildcard_meta = false;
+ }
+ else
+ {
+ if (ISESCAPECHAR(beginword))
+ in_escape = true;
+ else if (ISWILDCARDCHAR(beginword))
+ in_leading_wildcard_meta = true;
+ else if (ISWORDCHR(beginword))
+ break;
+ else
+ in_leading_wildcard_meta = false;
+ }
+ beginword += pg_mblen(beginword);
+ }
+
+ /*
+ * Handle string end.
+ */
+ if (beginword - str >= lenstr)
+ return NULL;
+
+ /*
+ * Add left padding spaces if preceding character wasn't wildcard
+ * meta-character.
+ */
+ *charlen = 0;
+ if (!in_leading_wildcard_meta)
+ {
+ if (LPADDING > 0)
+ {
+ *s++ = ' ';
+ (*charlen)++;
+ if (LPADDING > 1)
+ {
+ *s++ = ' ';
+ (*charlen)++;
+ }
+ }
+ }
+
+ /*
+ * Copy data into buf until wildcard meta-character, non-word character or
+ * string boundary. Strip escapes during copy.
+ */
+ endword = beginword;
+ while (endword - str < lenstr)
+ {
+ clen = pg_mblen(endword);
+ if (in_escape)
+ {
+ if (ISWORDCHR(endword))
+ {
+ memcpy(s, endword, clen);
+ (*charlen)++;
+ s += clen;
+ }
+ else
+ {
+ /*
+ * Back up endword to the escape character when stopping at an
+ * escaped char, so that subsequent get_wildcard_part will
+ * restart from the escape character. We assume here that
+ * escape chars are single-byte.
+ */
+ endword--;
+ break;
+ }
+ in_escape = false;
+ }
+ else
+ {
+ if (ISESCAPECHAR(endword))
+ in_escape = true;
+ else if (ISWILDCARDCHAR(endword))
+ {
+ in_trailing_wildcard_meta = true;
+ break;
+ }
+ else if (ISWORDCHR(endword))
+ {
+ memcpy(s, endword, clen);
+ (*charlen)++;
+ s += clen;
+ }
+ else
+ break;
+ }
+ endword += clen;
+ }
+
+ /*
+ * Add right padding spaces if next character isn't wildcard
+ * meta-character.
+ */
+ if (!in_trailing_wildcard_meta)
+ {
+ if (RPADDING > 0)
+ {
+ *s++ = ' ';
+ (*charlen)++;
+ if (RPADDING > 1)
+ {
+ *s++ = ' ';
+ (*charlen)++;
+ }
+ }
+ }
+
+ *bytelen = s - buf;
+ return endword;
+}
+
+/*
+ * Generates trigrams for wildcard search string.
+ *
+ * Returns array of trigrams that must occur in any string that matches the
+ * wildcard string. For example, given pattern "a%bcd%" the trigrams
+ * " a", "bcd" would be extracted.
+ */
+TRGM *
+generate_wildcard_trgm(const char *str, int slen)
+{
+ TRGM *trg;
+ char *buf,
+ *buf2;
+ trgm *tptr;
+ int len,
+ charlen,
+ bytelen;
+ const char *eword;
+
+ protect_out_of_mem(slen);
+
+ trg = (TRGM *) palloc(TRGMHDRSIZE + sizeof(trgm) * (slen / 2 + 1) * 3);
+ trg->flag = ARRKEY;
+ SET_VARSIZE(trg, TRGMHDRSIZE);
+
+ if (slen + LPADDING + RPADDING < 3 || slen == 0)
+ return trg;
+
+ tptr = GETARR(trg);
+
+ /* Allocate a buffer for blank-padded, but not yet case-folded, words */
+ buf = palloc(sizeof(char) * (slen + 4));
+
+ /*
+ * Extract trigrams from each substring extracted by get_wildcard_part.
+ */
+ eword = str;
+ while ((eword = get_wildcard_part(eword, slen - (eword - str),
+ buf, &bytelen, &charlen)) != NULL)
+ {
+#ifdef IGNORECASE
+ buf2 = lowerstr_with_len(buf, bytelen);
+ bytelen = strlen(buf2);
+#else
+ buf2 = buf;
+#endif
+
+ /*
+ * count trigrams
+ */
+ tptr = make_trigrams(tptr, buf2, bytelen, charlen);
+
+#ifdef IGNORECASE
+ pfree(buf2);
+#endif
+ }
+
+ pfree(buf);
+
+ if ((len = tptr - GETARR(trg)) == 0)
+ return trg;
+
+ /*
+ * Make trigrams unique.
+ */
+ if (len > 1)
+ {
+ qsort(GETARR(trg), len, sizeof(trgm), comp_trgm);
+ len = qunique(GETARR(trg), len, sizeof(trgm), comp_trgm);
+ }
+
+ SET_VARSIZE(trg, CALCGTSIZE(ARRKEY, len));
+
+ return trg;
+}
+
+uint32
+trgm2int(trgm *ptr)
+{
+ uint32 val = 0;
+
+ val |= *(((unsigned char *) ptr));
+ val <<= 8;
+ val |= *(((unsigned char *) ptr) + 1);
+ val <<= 8;
+ val |= *(((unsigned char *) ptr) + 2);
+
+ return val;
+}
+
+Datum
+show_trgm(PG_FUNCTION_ARGS)
+{
+ text *in = PG_GETARG_TEXT_PP(0);
+ TRGM *trg;
+ Datum *d;
+ ArrayType *a;
+ trgm *ptr;
+ int i;
+
+ trg = generate_trgm(VARDATA_ANY(in), VARSIZE_ANY_EXHDR(in));
+ d = (Datum *) palloc(sizeof(Datum) * (1 + ARRNELEM(trg)));
+
+ for (i = 0, ptr = GETARR(trg); i < ARRNELEM(trg); i++, ptr++)
+ {
+ text *item = (text *) palloc(VARHDRSZ + Max(12, pg_database_encoding_max_length() * 3));
+
+ if (pg_database_encoding_max_length() > 1 && !ISPRINTABLETRGM(ptr))
+ {
+ snprintf(VARDATA(item), 12, "0x%06x", trgm2int(ptr));
+ SET_VARSIZE(item, VARHDRSZ + strlen(VARDATA(item)));
+ }
+ else
+ {
+ SET_VARSIZE(item, VARHDRSZ + 3);
+ CPTRGM(VARDATA(item), ptr);
+ }
+ d[i] = PointerGetDatum(item);
+ }
+
+ a = construct_array_builtin(d, ARRNELEM(trg), TEXTOID);
+
+ for (i = 0; i < ARRNELEM(trg); i++)
+ pfree(DatumGetPointer(d[i]));
+
+ pfree(d);
+ pfree(trg);
+ PG_FREE_IF_COPY(in, 0);
+
+ PG_RETURN_POINTER(a);
+}
+
+float4
+cnt_sml(TRGM *trg1, TRGM *trg2, bool inexact)
+{
+ trgm *ptr1,
+ *ptr2;
+ int count = 0;
+ int len1,
+ len2;
+
+ ptr1 = GETARR(trg1);
+ ptr2 = GETARR(trg2);
+
+ len1 = ARRNELEM(trg1);
+ len2 = ARRNELEM(trg2);
+
+ /* explicit test is needed to avoid 0/0 division when both lengths are 0 */
+ if (len1 <= 0 || len2 <= 0)
+ return (float4) 0.0;
+
+ while (ptr1 - GETARR(trg1) < len1 && ptr2 - GETARR(trg2) < len2)
+ {
+ int res = CMPTRGM(ptr1, ptr2);
+
+ if (res < 0)
+ ptr1++;
+ else if (res > 0)
+ ptr2++;
+ else
+ {
+ ptr1++;
+ ptr2++;
+ count++;
+ }
+ }
+
+ /*
+ * If inexact then len2 is equal to count, because we don't know actual
+ * length of second string in inexact search and we can assume that count
+ * is a lower bound of len2.
+ */
+ return CALCSML(count, len1, inexact ? count : len2);
+}
+
+
+/*
+ * Returns whether trg2 contains all trigrams in trg1.
+ * This relies on the trigram arrays being sorted.
+ */
+bool
+trgm_contained_by(TRGM *trg1, TRGM *trg2)
+{
+ trgm *ptr1,
+ *ptr2;
+ int len1,
+ len2;
+
+ ptr1 = GETARR(trg1);
+ ptr2 = GETARR(trg2);
+
+ len1 = ARRNELEM(trg1);
+ len2 = ARRNELEM(trg2);
+
+ while (ptr1 - GETARR(trg1) < len1 && ptr2 - GETARR(trg2) < len2)
+ {
+ int res = CMPTRGM(ptr1, ptr2);
+
+ if (res < 0)
+ return false;
+ else if (res > 0)
+ ptr2++;
+ else
+ {
+ ptr1++;
+ ptr2++;
+ }
+ }
+ if (ptr1 - GETARR(trg1) < len1)
+ return false;
+ else
+ return true;
+}
+
+/*
+ * Return a palloc'd boolean array showing, for each trigram in "query",
+ * whether it is present in the trigram array "key".
+ * This relies on the "key" array being sorted, but "query" need not be.
+ */
+bool *
+trgm_presence_map(TRGM *query, TRGM *key)
+{
+ bool *result;
+ trgm *ptrq = GETARR(query),
+ *ptrk = GETARR(key);
+ int lenq = ARRNELEM(query),
+ lenk = ARRNELEM(key),
+ i;
+
+ result = (bool *) palloc0(lenq * sizeof(bool));
+
+ /* for each query trigram, do a binary search in the key array */
+ for (i = 0; i < lenq; i++)
+ {
+ int lo = 0;
+ int hi = lenk;
+
+ while (lo < hi)
+ {
+ int mid = (lo + hi) / 2;
+ int res = CMPTRGM(ptrq, ptrk + mid);
+
+ if (res < 0)
+ hi = mid;
+ else if (res > 0)
+ lo = mid + 1;
+ else
+ {
+ result[i] = true;
+ break;
+ }
+ }
+ ptrq++;
+ }
+
+ return result;
+}
+
+Datum
+similarity(PG_FUNCTION_ARGS)
+{
+ text *in1 = PG_GETARG_TEXT_PP(0);
+ text *in2 = PG_GETARG_TEXT_PP(1);
+ TRGM *trg1,
+ *trg2;
+ float4 res;
+
+ trg1 = generate_trgm(VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1));
+ trg2 = generate_trgm(VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2));
+
+ res = cnt_sml(trg1, trg2, false);
+
+ pfree(trg1);
+ pfree(trg2);
+ PG_FREE_IF_COPY(in1, 0);
+ PG_FREE_IF_COPY(in2, 1);
+
+ PG_RETURN_FLOAT4(res);
+}
+
+Datum
+word_similarity(PG_FUNCTION_ARGS)
+{
+ text *in1 = PG_GETARG_TEXT_PP(0);
+ text *in2 = PG_GETARG_TEXT_PP(1);
+ float4 res;
+
+ res = calc_word_similarity(VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1),
+ VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2),
+ 0);
+
+ PG_FREE_IF_COPY(in1, 0);
+ PG_FREE_IF_COPY(in2, 1);
+ PG_RETURN_FLOAT4(res);
+}
+
+Datum
+strict_word_similarity(PG_FUNCTION_ARGS)
+{
+ text *in1 = PG_GETARG_TEXT_PP(0);
+ text *in2 = PG_GETARG_TEXT_PP(1);
+ float4 res;
+
+ res = calc_word_similarity(VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1),
+ VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2),
+ WORD_SIMILARITY_STRICT);
+
+ PG_FREE_IF_COPY(in1, 0);
+ PG_FREE_IF_COPY(in2, 1);
+ PG_RETURN_FLOAT4(res);
+}
+
+Datum
+similarity_dist(PG_FUNCTION_ARGS)
+{
+ float4 res = DatumGetFloat4(DirectFunctionCall2(similarity,
+ PG_GETARG_DATUM(0),
+ PG_GETARG_DATUM(1)));
+
+ PG_RETURN_FLOAT4(1.0 - res);
+}
+
+Datum
+similarity_op(PG_FUNCTION_ARGS)
+{
+ float4 res = DatumGetFloat4(DirectFunctionCall2(similarity,
+ PG_GETARG_DATUM(0),
+ PG_GETARG_DATUM(1)));
+
+ PG_RETURN_BOOL(res >= similarity_threshold);
+}
+
+Datum
+word_similarity_op(PG_FUNCTION_ARGS)
+{
+ text *in1 = PG_GETARG_TEXT_PP(0);
+ text *in2 = PG_GETARG_TEXT_PP(1);
+ float4 res;
+
+ res = calc_word_similarity(VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1),
+ VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2),
+ WORD_SIMILARITY_CHECK_ONLY);
+
+ PG_FREE_IF_COPY(in1, 0);
+ PG_FREE_IF_COPY(in2, 1);
+ PG_RETURN_BOOL(res >= word_similarity_threshold);
+}
+
+Datum
+word_similarity_commutator_op(PG_FUNCTION_ARGS)
+{
+ text *in1 = PG_GETARG_TEXT_PP(0);
+ text *in2 = PG_GETARG_TEXT_PP(1);
+ float4 res;
+
+ res = calc_word_similarity(VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2),
+ VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1),
+ WORD_SIMILARITY_CHECK_ONLY);
+
+ PG_FREE_IF_COPY(in1, 0);
+ PG_FREE_IF_COPY(in2, 1);
+ PG_RETURN_BOOL(res >= word_similarity_threshold);
+}
+
+Datum
+word_similarity_dist_op(PG_FUNCTION_ARGS)
+{
+ text *in1 = PG_GETARG_TEXT_PP(0);
+ text *in2 = PG_GETARG_TEXT_PP(1);
+ float4 res;
+
+ res = calc_word_similarity(VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1),
+ VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2),
+ 0);
+
+ PG_FREE_IF_COPY(in1, 0);
+ PG_FREE_IF_COPY(in2, 1);
+ PG_RETURN_FLOAT4(1.0 - res);
+}
+
+Datum
+word_similarity_dist_commutator_op(PG_FUNCTION_ARGS)
+{
+ text *in1 = PG_GETARG_TEXT_PP(0);
+ text *in2 = PG_GETARG_TEXT_PP(1);
+ float4 res;
+
+ res = calc_word_similarity(VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2),
+ VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1),
+ 0);
+
+ PG_FREE_IF_COPY(in1, 0);
+ PG_FREE_IF_COPY(in2, 1);
+ PG_RETURN_FLOAT4(1.0 - res);
+}
+
+Datum
+strict_word_similarity_op(PG_FUNCTION_ARGS)
+{
+ text *in1 = PG_GETARG_TEXT_PP(0);
+ text *in2 = PG_GETARG_TEXT_PP(1);
+ float4 res;
+
+ res = calc_word_similarity(VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1),
+ VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2),
+ WORD_SIMILARITY_CHECK_ONLY | WORD_SIMILARITY_STRICT);
+
+ PG_FREE_IF_COPY(in1, 0);
+ PG_FREE_IF_COPY(in2, 1);
+ PG_RETURN_BOOL(res >= strict_word_similarity_threshold);
+}
+
+Datum
+strict_word_similarity_commutator_op(PG_FUNCTION_ARGS)
+{
+ text *in1 = PG_GETARG_TEXT_PP(0);
+ text *in2 = PG_GETARG_TEXT_PP(1);
+ float4 res;
+
+ res = calc_word_similarity(VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2),
+ VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1),
+ WORD_SIMILARITY_CHECK_ONLY | WORD_SIMILARITY_STRICT);
+
+ PG_FREE_IF_COPY(in1, 0);
+ PG_FREE_IF_COPY(in2, 1);
+ PG_RETURN_BOOL(res >= strict_word_similarity_threshold);
+}
+
+Datum
+strict_word_similarity_dist_op(PG_FUNCTION_ARGS)
+{
+ text *in1 = PG_GETARG_TEXT_PP(0);
+ text *in2 = PG_GETARG_TEXT_PP(1);
+ float4 res;
+
+ res = calc_word_similarity(VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1),
+ VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2),
+ WORD_SIMILARITY_STRICT);
+
+ PG_FREE_IF_COPY(in1, 0);
+ PG_FREE_IF_COPY(in2, 1);
+ PG_RETURN_FLOAT4(1.0 - res);
+}
+
+Datum
+strict_word_similarity_dist_commutator_op(PG_FUNCTION_ARGS)
+{
+ text *in1 = PG_GETARG_TEXT_PP(0);
+ text *in2 = PG_GETARG_TEXT_PP(1);
+ float4 res;
+
+ res = calc_word_similarity(VARDATA_ANY(in2), VARSIZE_ANY_EXHDR(in2),
+ VARDATA_ANY(in1), VARSIZE_ANY_EXHDR(in1),
+ WORD_SIMILARITY_STRICT);
+
+ PG_FREE_IF_COPY(in1, 0);
+ PG_FREE_IF_COPY(in2, 1);
+ PG_RETURN_FLOAT4(1.0 - res);
+}
diff --git a/contrib/pg_trgm/trgm_regexp.c b/contrib/pg_trgm/trgm_regexp.c
new file mode 100644
index 0000000..1d36946
--- /dev/null
+++ b/contrib/pg_trgm/trgm_regexp.c
@@ -0,0 +1,2358 @@
+/*-------------------------------------------------------------------------
+ *
+ * trgm_regexp.c
+ * Regular expression matching using trigrams.
+ *
+ * The general idea of trigram index support for a regular expression (regex)
+ * search is to transform the regex into a logical expression on trigrams.
+ * For example:
+ *
+ * (ab|cd)efg => ((abe & bef) | (cde & def)) & efg
+ *
+ * If a string matches the regex, then it must match the logical expression on
+ * trigrams. The opposite is not necessarily true, however: a string that
+ * matches the logical expression might not match the original regex. Such
+ * false positives are removed via recheck, by running the regular regex match
+ * operator on the retrieved heap tuple.
+ *
+ * Since the trigram expression involves both AND and OR operators, we can't
+ * expect the core index machinery to evaluate it completely. Instead, the
+ * result of regex analysis is a list of trigrams to be sought in the index,
+ * plus a simplified graph that is used by trigramsMatchGraph() to determine
+ * whether a particular indexed value matches the expression.
+ *
+ * Converting a regex to a trigram expression is based on analysis of an
+ * automaton corresponding to the regex. The algorithm consists of four
+ * stages:
+ *
+ * 1) Compile the regexp to NFA form. This is handled by the PostgreSQL
+ * regexp library, which provides accessors for its opaque regex_t struct
+ * to expose the NFA state graph and the "colors" (sets of equivalent
+ * characters) used as state transition labels.
+ *
+ * 2) Transform the original NFA into an expanded graph, where arcs
+ * are labeled with trigrams that must be present in order to move from
+ * one state to another via the arcs. The trigrams used in this stage
+ * consist of colors, not characters, as in the original NFA.
+ *
+ * 3) Expand the color trigrams into regular trigrams consisting of
+ * characters. If too many distinct trigrams are produced, trigrams are
+ * eliminated and the graph is simplified until it's simple enough.
+ *
+ * 4) Finally, the resulting graph is packed into a TrgmPackedGraph struct,
+ * and returned to the caller.
+ *
+ * 1) Compile the regexp to NFA form
+ * ---------------------------------
+ * The automaton returned by the regexp compiler is a graph where vertices
+ * are "states" and arcs are labeled with colors. Each color represents
+ * a set of characters, so that all characters assigned to the same color
+ * are interchangeable, so far as matching the regexp is concerned. There
+ * are two special states: "initial" and "final". A state can have multiple
+ * outgoing arcs labeled with the same color, which makes the automaton
+ * non-deterministic, because it can be in many states simultaneously.
+ *
+ * Note that this NFA is already lossy compared to the original regexp,
+ * since it ignores some regex features such as lookahead constraints and
+ * backref matching. This is OK for our purposes since it's still the case
+ * that only strings matching the NFA can possibly satisfy the regexp.
+ *
+ * 2) Transform the original NFA into an expanded graph
+ * ----------------------------------------------------
+ * In the 2nd stage, the automaton is transformed into a graph based on the
+ * original NFA. Each state in the expanded graph represents a state from
+ * the original NFA, plus a prefix identifying the last two characters
+ * (colors, to be precise) seen before entering the state. There can be
+ * multiple states in the expanded graph for each state in the original NFA,
+ * depending on what characters can precede it. A prefix position can be
+ * "unknown" if it's uncertain what the preceding character was, or "blank"
+ * if the character was a non-word character (we don't need to distinguish
+ * which non-word character it was, so just think of all of them as blanks).
+ *
+ * For convenience in description, call an expanded-state identifier
+ * (two prefix colors plus a state number from the original NFA) an
+ * "enter key".
+ *
+ * Each arc of the expanded graph is labeled with a trigram that must be
+ * present in the string to match. We can construct this from an out-arc of
+ * the underlying NFA state by combining the expanded state's prefix with the
+ * color label of the underlying out-arc, if neither prefix position is
+ * "unknown". But note that some of the colors in the trigram might be
+ * "blank". This is OK since we want to generate word-boundary trigrams as
+ * the regular trigram machinery would, if we know that some word characters
+ * must be adjacent to a word boundary in all strings matching the NFA.
+ *
+ * The expanded graph can also have fewer states than the original NFA,
+ * because we don't bother to make a separate state entry unless the state
+ * is reachable by a valid arc. When an enter key is reachable from a state
+ * of the expanded graph, but we do not know a complete trigram associated
+ * with that transition, we cannot make a valid arc; instead we insert the
+ * enter key into the enterKeys list of the source state. This effectively
+ * means that the two expanded states are not reliably distinguishable based
+ * on examining trigrams.
+ *
+ * So the expanded graph resembles the original NFA, but the arcs are
+ * labeled with trigrams instead of individual characters, and there may be
+ * more or fewer states. It is a lossy representation of the original NFA:
+ * any string that matches the original regexp must match the expanded graph,
+ * but the reverse is not true.
+ *
+ * We build the expanded graph through a breadth-first traversal of states
+ * reachable from the initial state. At each reachable state, we identify the
+ * states reachable from it without traversing a predictable trigram, and add
+ * those states' enter keys to the current state. Then we generate all
+ * out-arcs leading out of this collection of states that have predictable
+ * trigrams, adding their target states to the queue of states to examine.
+ *
+ * When building the graph, if the number of states or arcs exceed pre-defined
+ * limits, we give up and simply mark any states not yet processed as final
+ * states. Roughly speaking, that means that we make use of some portion from
+ * the beginning of the regexp. Also, any colors that have too many member
+ * characters are treated as "unknown", so that we can't derive trigrams
+ * from them.
+ *
+ * 3) Expand the color trigrams into regular trigrams
+ * --------------------------------------------------
+ * The trigrams in the expanded graph are "color trigrams", consisting
+ * of three consecutive colors that must be present in the string. But for
+ * search, we need regular trigrams consisting of characters. In the 3rd
+ * stage, the color trigrams are expanded into regular trigrams. Since each
+ * color can represent many characters, the total number of regular trigrams
+ * after expansion could be very large. Because searching the index for
+ * thousands of trigrams would be slow, and would likely produce so many
+ * false positives that we would have to traverse a large fraction of the
+ * index, the graph is simplified further in a lossy fashion by removing
+ * color trigrams. When a color trigram is removed, the states connected by
+ * any arcs labeled with that trigram are merged.
+ *
+ * Trigrams do not all have equivalent value for searching: some of them are
+ * more frequent and some of them are less frequent. Ideally, we would like
+ * to know the distribution of trigrams, but we don't. But because of padding
+ * we know for sure that the empty character is more frequent than others,
+ * so we can penalize trigrams according to presence of whitespace. The
+ * penalty assigned to each color trigram is the number of simple trigrams
+ * it would produce, times the penalties[] multiplier associated with its
+ * whitespace content. (The penalties[] constants were calculated by analysis
+ * of some real-life text.) We eliminate color trigrams starting with the
+ * highest-penalty one, until we get to a total penalty of no more than
+ * WISH_TRGM_PENALTY. However, we cannot remove a color trigram if that would
+ * lead to merging the initial and final states, so we may not be able to
+ * reach WISH_TRGM_PENALTY. It's still okay so long as we have no more than
+ * MAX_TRGM_COUNT simple trigrams in total, otherwise we fail.
+ *
+ * 4) Pack the graph into a compact representation
+ * -----------------------------------------------
+ * The 2nd and 3rd stages might have eliminated or merged many of the states
+ * and trigrams created earlier, so in this final stage, the graph is
+ * compacted and packed into a simpler struct that contains only the
+ * information needed to evaluate it.
+ *
+ * ALGORITHM EXAMPLE:
+ *
+ * Consider the example regex "ab[cd]". This regex is transformed into the
+ * following NFA (for simplicity we show colors as their single members):
+ *
+ * 4#
+ * c/
+ * a b /
+ * 1* --- 2 ---- 3
+ * \
+ * d\
+ * 5#
+ *
+ * We use * to mark initial state and # to mark final state. It's not depicted,
+ * but states 1, 4, 5 have self-referencing arcs for all possible characters,
+ * because this pattern can match to any part of a string.
+ *
+ * As the result of stage 2 we will have the following graph:
+ *
+ * abc abd
+ * 2# <---- 1* ----> 3#
+ *
+ * The process for generating this graph is:
+ * 1) Create state 1 with enter key (UNKNOWN, UNKNOWN, 1).
+ * 2) Add key (UNKNOWN, "a", 2) to state 1.
+ * 3) Add key ("a", "b", 3) to state 1.
+ * 4) Create new state 2 with enter key ("b", "c", 4). Add an arc
+ * from state 1 to state 2 with label trigram "abc".
+ * 5) Mark state 2 final because state 4 of source NFA is marked as final.
+ * 6) Create new state 3 with enter key ("b", "d", 5). Add an arc
+ * from state 1 to state 3 with label trigram "abd".
+ * 7) Mark state 3 final because state 5 of source NFA is marked as final.
+ *
+ *
+ * Portions Copyright (c) 1996-2023, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * IDENTIFICATION
+ * contrib/pg_trgm/trgm_regexp.c
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "regex/regexport.h"
+#include "trgm.h"
+#include "tsearch/ts_locale.h"
+#include "utils/hsearch.h"
+#include "utils/memutils.h"
+#include "varatt.h"
+
+/*
+ * Uncomment (or use -DTRGM_REGEXP_DEBUG) to print debug info,
+ * for exploring and debugging the algorithm implementation.
+ * This produces three graph files in /tmp, in Graphviz .gv format.
+ * Some progress information is also printed to postmaster stderr.
+ */
+/* #define TRGM_REGEXP_DEBUG */
+
+/*
+ * These parameters are used to limit the amount of work done.
+ * Otherwise regex processing could be too slow and memory-consuming.
+ *
+ * MAX_EXPANDED_STATES - How many states we allow in expanded graph
+ * MAX_EXPANDED_ARCS - How many arcs we allow in expanded graph
+ * MAX_TRGM_COUNT - How many simple trigrams we allow to be extracted
+ * WISH_TRGM_PENALTY - Maximum desired sum of color trigram penalties
+ * COLOR_COUNT_LIMIT - Maximum number of characters per color
+ */
+#define MAX_EXPANDED_STATES 128
+#define MAX_EXPANDED_ARCS 1024
+#define MAX_TRGM_COUNT 256
+#define WISH_TRGM_PENALTY 16
+#define COLOR_COUNT_LIMIT 256
+
+/*
+ * Penalty multipliers for trigram counts depending on whitespace contents.
+ * Numbers based on analysis of real-life texts.
+ */
+static const float4 penalties[8] = {
+ 1.0f, /* "aaa" */
+ 3.5f, /* "aa " */
+ 0.0f, /* "a a" (impossible) */
+ 0.0f, /* "a " (impossible) */
+ 4.2f, /* " aa" */
+ 2.1f, /* " a " */
+ 25.0f, /* " a" */
+ 0.0f /* " " (impossible) */
+};
+
+/* Struct representing a single pg_wchar, converted back to multibyte form */
+typedef struct
+{
+ char bytes[MAX_MULTIBYTE_CHAR_LEN];
+} trgm_mb_char;
+
+/*
+ * Attributes of NFA colors:
+ *
+ * expandable - we know the character expansion of this color
+ * containsNonWord - color contains non-word characters
+ * (which will not be extracted into trigrams)
+ * wordCharsCount - count of word characters in color
+ * wordChars - array of this color's word characters
+ * (which can be extracted into trigrams)
+ *
+ * When expandable is false, the other attributes don't matter; we just
+ * assume this color represents unknown character(s).
+ */
+typedef struct
+{
+ bool expandable;
+ bool containsNonWord;
+ int wordCharsCount;
+ trgm_mb_char *wordChars;
+} TrgmColorInfo;
+
+/*
+ * A "prefix" is information about the colors of the last two characters read
+ * before reaching a specific NFA state. These colors can have special values
+ * COLOR_UNKNOWN and COLOR_BLANK. COLOR_UNKNOWN means that we have no
+ * information, for example because we read some character of an unexpandable
+ * color. COLOR_BLANK means that we read a non-word character.
+ *
+ * We call a prefix ambiguous if at least one of its colors is unknown. It's
+ * fully ambiguous if both are unknown, partially ambiguous if only the first
+ * is unknown. (The case of first color known, second unknown is not valid.)
+ *
+ * Wholly- or partly-blank prefixes are mostly handled the same as regular
+ * color prefixes. This allows us to generate appropriate partly-blank
+ * trigrams when the NFA requires word character(s) to appear adjacent to
+ * non-word character(s).
+ */
+typedef int TrgmColor;
+
+/* We assume that colors returned by the regexp engine cannot be these: */
+#define COLOR_UNKNOWN (-3)
+#define COLOR_BLANK (-4)
+
+typedef struct
+{
+ TrgmColor colors[2];
+} TrgmPrefix;
+
+/*
+ * Color-trigram data type. Note that some elements of the trigram can be
+ * COLOR_BLANK, but we don't allow COLOR_UNKNOWN.
+ */
+typedef struct
+{
+ TrgmColor colors[3];
+} ColorTrgm;
+
+/*
+ * Key identifying a state of our expanded graph: color prefix, and number
+ * of the corresponding state in the underlying regex NFA. The color prefix
+ * shows how we reached the regex state (to the extent that we know it).
+ */
+typedef struct
+{
+ TrgmPrefix prefix;
+ int nstate;
+} TrgmStateKey;
+
+/*
+ * One state of the expanded graph.
+ *
+ * stateKey - ID of this state
+ * arcs - outgoing arcs of this state (List of TrgmArc)
+ * enterKeys - enter keys reachable from this state without reading any
+ * predictable trigram (List of TrgmStateKey)
+ * flags - flag bits
+ * snumber - number of this state (initially assigned as -1, -2, etc,
+ * for debugging purposes only; then at the packaging stage,
+ * surviving states are renumbered with positive numbers)
+ * parent - parent state, if this state has been merged into another
+ * tentFlags - flags this state would acquire via planned merges
+ * tentParent - planned parent state, if considering a merge
+ */
+#define TSTATE_INIT 0x01 /* flag indicating this state is initial */
+#define TSTATE_FIN 0x02 /* flag indicating this state is final */
+
+typedef struct TrgmState
+{
+ TrgmStateKey stateKey; /* hashtable key: must be first field */
+ List *arcs;
+ List *enterKeys;
+ int flags;
+ int snumber;
+ struct TrgmState *parent;
+ int tentFlags;
+ struct TrgmState *tentParent;
+} TrgmState;
+
+/*
+ * One arc in the expanded graph.
+ */
+typedef struct
+{
+ ColorTrgm ctrgm; /* trigram needed to traverse arc */
+ TrgmState *target; /* next state */
+} TrgmArc;
+
+/*
+ * Information about arc of specific color trigram (used in stage 3)
+ *
+ * Contains pointers to the source and target states.
+ */
+typedef struct
+{
+ TrgmState *source;
+ TrgmState *target;
+} TrgmArcInfo;
+
+/*
+ * Information about color trigram (used in stage 3)
+ *
+ * ctrgm - trigram itself
+ * cnumber - number of this trigram (used in the packaging stage)
+ * count - number of simple trigrams created from this color trigram
+ * expanded - indicates this color trigram is expanded into simple trigrams
+ * arcs - list of all arcs labeled with this color trigram.
+ */
+typedef struct
+{
+ ColorTrgm ctrgm;
+ int cnumber;
+ int count;
+ float4 penalty;
+ bool expanded;
+ List *arcs;
+} ColorTrgmInfo;
+
+/*
+ * Data structure representing all the data we need during regex processing.
+ *
+ * regex - compiled regex
+ * colorInfo - extracted information about regex's colors
+ * ncolors - number of colors in colorInfo[]
+ * states - hashtable of TrgmStates (states of expanded graph)
+ * initState - pointer to initial state of expanded graph
+ * queue - queue of to-be-processed TrgmStates
+ * keysQueue - queue of to-be-processed TrgmStateKeys
+ * arcsCount - total number of arcs of expanded graph (for resource
+ * limiting)
+ * overflowed - we have exceeded resource limit for transformation
+ * colorTrgms - array of all color trigrams present in graph
+ * colorTrgmsCount - count of those color trigrams
+ * totalTrgmCount - total count of extracted simple trigrams
+ */
+typedef struct
+{
+ /* Source regexp, and color information extracted from it (stage 1) */
+ regex_t *regex;
+ TrgmColorInfo *colorInfo;
+ int ncolors;
+
+ /* Expanded graph (stage 2) */
+ HTAB *states;
+ TrgmState *initState;
+ int nstates;
+
+ /* Workspace for stage 2 */
+ List *queue;
+ List *keysQueue;
+ int arcsCount;
+ bool overflowed;
+
+ /* Information about distinct color trigrams in the graph (stage 3) */
+ ColorTrgmInfo *colorTrgms;
+ int colorTrgmsCount;
+ int totalTrgmCount;
+} TrgmNFA;
+
+/*
+ * Final, compact representation of expanded graph.
+ */
+typedef struct
+{
+ int targetState; /* index of target state (zero-based) */
+ int colorTrgm; /* index of color trigram for transition */
+} TrgmPackedArc;
+
+typedef struct
+{
+ int arcsCount; /* number of out-arcs for this state */
+ TrgmPackedArc *arcs; /* array of arcsCount packed arcs */
+} TrgmPackedState;
+
+/* "typedef struct TrgmPackedGraph TrgmPackedGraph" appears in trgm.h */
+struct TrgmPackedGraph
+{
+ /*
+ * colorTrigramsCount and colorTrigramGroups contain information about how
+ * trigrams are grouped into color trigrams. "colorTrigramsCount" is the
+ * count of color trigrams and "colorTrigramGroups" contains number of
+ * simple trigrams for each color trigram. The array of simple trigrams
+ * (stored separately from this struct) is ordered so that the simple
+ * trigrams for each color trigram are consecutive, and they're in order
+ * by color trigram number.
+ */
+ int colorTrigramsCount;
+ int *colorTrigramGroups; /* array of size colorTrigramsCount */
+
+ /*
+ * The states of the simplified NFA. State number 0 is always initial
+ * state and state number 1 is always final state.
+ */
+ int statesCount;
+ TrgmPackedState *states; /* array of size statesCount */
+
+ /* Temporary work space for trigramsMatchGraph() */
+ bool *colorTrigramsActive; /* array of size colorTrigramsCount */
+ bool *statesActive; /* array of size statesCount */
+ int *statesQueue; /* array of size statesCount */
+};
+
+/*
+ * Temporary structure for representing an arc during packaging.
+ */
+typedef struct
+{
+ int sourceState;
+ int targetState;
+ int colorTrgm;
+} TrgmPackArcInfo;
+
+
+/* prototypes for private functions */
+static TRGM *createTrgmNFAInternal(regex_t *regex, TrgmPackedGraph **graph,
+ MemoryContext rcontext);
+static void RE_compile(regex_t *regex, text *text_re,
+ int cflags, Oid collation);
+static void getColorInfo(regex_t *regex, TrgmNFA *trgmNFA);
+static bool convertPgWchar(pg_wchar c, trgm_mb_char *result);
+static void transformGraph(TrgmNFA *trgmNFA);
+static void processState(TrgmNFA *trgmNFA, TrgmState *state);
+static void addKey(TrgmNFA *trgmNFA, TrgmState *state, TrgmStateKey *key);
+static void addKeyToQueue(TrgmNFA *trgmNFA, TrgmStateKey *key);
+static void addArcs(TrgmNFA *trgmNFA, TrgmState *state);
+static void addArc(TrgmNFA *trgmNFA, TrgmState *state, TrgmStateKey *key,
+ TrgmColor co, TrgmStateKey *destKey);
+static bool validArcLabel(TrgmStateKey *key, TrgmColor co);
+static TrgmState *getState(TrgmNFA *trgmNFA, TrgmStateKey *key);
+static bool prefixContains(TrgmPrefix *prefix1, TrgmPrefix *prefix2);
+static bool selectColorTrigrams(TrgmNFA *trgmNFA);
+static TRGM *expandColorTrigrams(TrgmNFA *trgmNFA, MemoryContext rcontext);
+static void fillTrgm(trgm *ptrgm, trgm_mb_char s[3]);
+static void mergeStates(TrgmState *state1, TrgmState *state2);
+static int colorTrgmInfoCmp(const void *p1, const void *p2);
+static int colorTrgmInfoPenaltyCmp(const void *p1, const void *p2);
+static TrgmPackedGraph *packGraph(TrgmNFA *trgmNFA, MemoryContext rcontext);
+static int packArcInfoCmp(const void *a1, const void *a2);
+
+#ifdef TRGM_REGEXP_DEBUG
+static void printSourceNFA(regex_t *regex, TrgmColorInfo *colors, int ncolors);
+static void printTrgmNFA(TrgmNFA *trgmNFA);
+static void printTrgmColor(StringInfo buf, TrgmColor co);
+static void printTrgmPackedGraph(TrgmPackedGraph *packedGraph, TRGM *trigrams);
+#endif
+
+
+/*
+ * Main entry point to process a regular expression.
+ *
+ * Returns an array of trigrams required by the regular expression, or NULL if
+ * the regular expression was too complex to analyze. In addition, a packed
+ * graph representation of the regex is returned into *graph. The results
+ * must be allocated in rcontext (which might or might not be the current
+ * context).
+ */
+TRGM *
+createTrgmNFA(text *text_re, Oid collation,
+ TrgmPackedGraph **graph, MemoryContext rcontext)
+{
+ TRGM *trg;
+ regex_t regex;
+ MemoryContext tmpcontext;
+ MemoryContext oldcontext;
+
+ /*
+ * This processing generates a great deal of cruft, which we'd like to
+ * clean up before returning (since this function may be called in a
+ * query-lifespan memory context). Make a temp context we can work in so
+ * that cleanup is easy.
+ */
+ tmpcontext = AllocSetContextCreate(CurrentMemoryContext,
+ "createTrgmNFA temporary context",
+ ALLOCSET_DEFAULT_SIZES);
+ oldcontext = MemoryContextSwitchTo(tmpcontext);
+
+ /*
+ * Stage 1: Compile the regexp into a NFA, using the regexp library.
+ */
+#ifdef IGNORECASE
+ RE_compile(&regex, text_re,
+ REG_ADVANCED | REG_NOSUB | REG_ICASE, collation);
+#else
+ RE_compile(&regex, text_re,
+ REG_ADVANCED | REG_NOSUB, collation);
+#endif
+
+ trg = createTrgmNFAInternal(&regex, graph, rcontext);
+
+ /* Clean up all the cruft we created (including regex) */
+ MemoryContextSwitchTo(oldcontext);
+ MemoryContextDelete(tmpcontext);
+
+ return trg;
+}
+
+/*
+ * Body of createTrgmNFA, exclusive of regex compilation/freeing.
+ */
+static TRGM *
+createTrgmNFAInternal(regex_t *regex, TrgmPackedGraph **graph,
+ MemoryContext rcontext)
+{
+ TRGM *trg;
+ TrgmNFA trgmNFA;
+
+ trgmNFA.regex = regex;
+
+ /* Collect color information from the regex */
+ getColorInfo(regex, &trgmNFA);
+
+#ifdef TRGM_REGEXP_DEBUG
+ printSourceNFA(regex, trgmNFA.colorInfo, trgmNFA.ncolors);
+#endif
+
+ /*
+ * Stage 2: Create an expanded graph from the source NFA.
+ */
+ transformGraph(&trgmNFA);
+
+#ifdef TRGM_REGEXP_DEBUG
+ printTrgmNFA(&trgmNFA);
+#endif
+
+ /*
+ * Fail if we were unable to make a nontrivial graph, ie it is possible to
+ * get from the initial state to the final state without reading any
+ * predictable trigram.
+ */
+ if (trgmNFA.initState->flags & TSTATE_FIN)
+ return NULL;
+
+ /*
+ * Stage 3: Select color trigrams to expand. Fail if too many trigrams.
+ */
+ if (!selectColorTrigrams(&trgmNFA))
+ return NULL;
+
+ /*
+ * Stage 4: Expand color trigrams and pack graph into final
+ * representation.
+ */
+ trg = expandColorTrigrams(&trgmNFA, rcontext);
+
+ *graph = packGraph(&trgmNFA, rcontext);
+
+#ifdef TRGM_REGEXP_DEBUG
+ printTrgmPackedGraph(*graph, trg);
+#endif
+
+ return trg;
+}
+
+/*
+ * Main entry point for evaluating a graph during index scanning.
+ *
+ * The check[] array is indexed by trigram number (in the array of simple
+ * trigrams returned by createTrgmNFA), and holds true for those trigrams
+ * that are present in the index entry being checked.
+ */
+bool
+trigramsMatchGraph(TrgmPackedGraph *graph, bool *check)
+{
+ int i,
+ j,
+ k,
+ queueIn,
+ queueOut;
+
+ /*
+ * Reset temporary working areas.
+ */
+ memset(graph->colorTrigramsActive, 0,
+ sizeof(bool) * graph->colorTrigramsCount);
+ memset(graph->statesActive, 0, sizeof(bool) * graph->statesCount);
+
+ /*
+ * Check which color trigrams were matched. A match for any simple
+ * trigram associated with a color trigram counts as a match of the color
+ * trigram.
+ */
+ j = 0;
+ for (i = 0; i < graph->colorTrigramsCount; i++)
+ {
+ int cnt = graph->colorTrigramGroups[i];
+
+ for (k = j; k < j + cnt; k++)
+ {
+ if (check[k])
+ {
+ /*
+ * Found one matched trigram in the group. Can skip the rest
+ * of them and go to the next group.
+ */
+ graph->colorTrigramsActive[i] = true;
+ break;
+ }
+ }
+ j = j + cnt;
+ }
+
+ /*
+ * Initialize the statesQueue to hold just the initial state. Note:
+ * statesQueue has room for statesCount entries, which is certainly enough
+ * since no state will be put in the queue more than once. The
+ * statesActive array marks which states have been queued.
+ */
+ graph->statesActive[0] = true;
+ graph->statesQueue[0] = 0;
+ queueIn = 0;
+ queueOut = 1;
+
+ /* Process queued states as long as there are any. */
+ while (queueIn < queueOut)
+ {
+ int stateno = graph->statesQueue[queueIn++];
+ TrgmPackedState *state = &graph->states[stateno];
+ int cnt = state->arcsCount;
+
+ /* Loop over state's out-arcs */
+ for (i = 0; i < cnt; i++)
+ {
+ TrgmPackedArc *arc = &state->arcs[i];
+
+ /*
+ * If corresponding color trigram is present then activate the
+ * corresponding state. We're done if that's the final state,
+ * otherwise queue the state if it's not been queued already.
+ */
+ if (graph->colorTrigramsActive[arc->colorTrgm])
+ {
+ int nextstate = arc->targetState;
+
+ if (nextstate == 1)
+ return true; /* success: final state is reachable */
+
+ if (!graph->statesActive[nextstate])
+ {
+ graph->statesActive[nextstate] = true;
+ graph->statesQueue[queueOut++] = nextstate;
+ }
+ }
+ }
+ }
+
+ /* Queue is empty, so match fails. */
+ return false;
+}
+
+/*
+ * Compile regex string into struct at *regex.
+ * NB: pg_regfree must be applied to regex if this completes successfully.
+ */
+static void
+RE_compile(regex_t *regex, text *text_re, int cflags, Oid collation)
+{
+ int text_re_len = VARSIZE_ANY_EXHDR(text_re);
+ char *text_re_val = VARDATA_ANY(text_re);
+ pg_wchar *pattern;
+ int pattern_len;
+ int regcomp_result;
+ char errMsg[100];
+
+ /* Convert pattern string to wide characters */
+ pattern = (pg_wchar *) palloc((text_re_len + 1) * sizeof(pg_wchar));
+ pattern_len = pg_mb2wchar_with_len(text_re_val,
+ pattern,
+ text_re_len);
+
+ /* Compile regex */
+ regcomp_result = pg_regcomp(regex,
+ pattern,
+ pattern_len,
+ cflags,
+ collation);
+
+ pfree(pattern);
+
+ if (regcomp_result != REG_OKAY)
+ {
+ /* re didn't compile (no need for pg_regfree, if so) */
+ pg_regerror(regcomp_result, regex, errMsg, sizeof(errMsg));
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
+ errmsg("invalid regular expression: %s", errMsg)));
+ }
+}
+
+
+/*---------------------
+ * Subroutines for pre-processing the color map (stage 1).
+ *---------------------
+ */
+
+/*
+ * Fill TrgmColorInfo structure for each color using regex export functions.
+ */
+static void
+getColorInfo(regex_t *regex, TrgmNFA *trgmNFA)
+{
+ int colorsCount = pg_reg_getnumcolors(regex);
+ int i;
+
+ trgmNFA->ncolors = colorsCount;
+ trgmNFA->colorInfo = (TrgmColorInfo *)
+ palloc0(colorsCount * sizeof(TrgmColorInfo));
+
+ /*
+ * Loop over colors, filling TrgmColorInfo about each. Note we include
+ * WHITE (0) even though we know it'll be reported as non-expandable.
+ */
+ for (i = 0; i < colorsCount; i++)
+ {
+ TrgmColorInfo *colorInfo = &trgmNFA->colorInfo[i];
+ int charsCount = pg_reg_getnumcharacters(regex, i);
+ pg_wchar *chars;
+ int j;
+
+ if (charsCount < 0 || charsCount > COLOR_COUNT_LIMIT)
+ {
+ /* Non expandable, or too large to work with */
+ colorInfo->expandable = false;
+ continue;
+ }
+
+ colorInfo->expandable = true;
+ colorInfo->containsNonWord = false;
+ colorInfo->wordChars = (trgm_mb_char *)
+ palloc(sizeof(trgm_mb_char) * charsCount);
+ colorInfo->wordCharsCount = 0;
+
+ /* Extract all the chars in this color */
+ chars = (pg_wchar *) palloc(sizeof(pg_wchar) * charsCount);
+ pg_reg_getcharacters(regex, i, chars, charsCount);
+
+ /*
+ * Convert characters back to multibyte form, and save only those that
+ * are word characters. Set "containsNonWord" if any non-word
+ * character. (Note: it'd probably be nicer to keep the chars in
+ * pg_wchar format for now, but ISWORDCHR wants to see multibyte.)
+ */
+ for (j = 0; j < charsCount; j++)
+ {
+ trgm_mb_char c;
+
+ if (!convertPgWchar(chars[j], &c))
+ continue; /* ok to ignore it altogether */
+ if (ISWORDCHR(c.bytes))
+ colorInfo->wordChars[colorInfo->wordCharsCount++] = c;
+ else
+ colorInfo->containsNonWord = true;
+ }
+
+ pfree(chars);
+ }
+}
+
+/*
+ * Convert pg_wchar to multibyte format.
+ * Returns false if the character should be ignored completely.
+ */
+static bool
+convertPgWchar(pg_wchar c, trgm_mb_char *result)
+{
+ /* "s" has enough space for a multibyte character and a trailing NUL */
+ char s[MAX_MULTIBYTE_CHAR_LEN + 1];
+
+ /*
+ * We can ignore the NUL character, since it can never appear in a PG text
+ * string. This avoids the need for various special cases when
+ * reconstructing trigrams.
+ */
+ if (c == 0)
+ return false;
+
+ /* Do the conversion, making sure the result is NUL-terminated */
+ memset(s, 0, sizeof(s));
+ pg_wchar2mb_with_len(&c, s, 1);
+
+ /*
+ * In IGNORECASE mode, we can ignore uppercase characters. We assume that
+ * the regex engine generated both uppercase and lowercase equivalents
+ * within each color, since we used the REG_ICASE option; so there's no
+ * need to process the uppercase version.
+ *
+ * XXX this code is dependent on the assumption that lowerstr() works the
+ * same as the regex engine's internal case folding machinery. Might be
+ * wiser to expose pg_wc_tolower and test whether c == pg_wc_tolower(c).
+ * On the other hand, the trigrams in the index were created using
+ * lowerstr(), so we're probably screwed if there's any incompatibility
+ * anyway.
+ */
+#ifdef IGNORECASE
+ {
+ char *lowerCased = lowerstr(s);
+
+ if (strcmp(lowerCased, s) != 0)
+ {
+ pfree(lowerCased);
+ return false;
+ }
+ pfree(lowerCased);
+ }
+#endif
+
+ /* Fill result with exactly MAX_MULTIBYTE_CHAR_LEN bytes */
+ memcpy(result->bytes, s, MAX_MULTIBYTE_CHAR_LEN);
+ return true;
+}
+
+
+/*---------------------
+ * Subroutines for expanding original NFA graph into a trigram graph (stage 2).
+ *---------------------
+ */
+
+/*
+ * Transform the graph, given a regex and extracted color information.
+ *
+ * We create and process a queue of expanded-graph states until all the states
+ * are processed.
+ *
+ * This algorithm may be stopped due to resource limitation. In this case we
+ * force every unprocessed branch to immediately finish with matching (this
+ * can give us false positives but no false negatives) by marking all
+ * unprocessed states as final.
+ */
+static void
+transformGraph(TrgmNFA *trgmNFA)
+{
+ HASHCTL hashCtl;
+ TrgmStateKey initkey;
+ TrgmState *initstate;
+ ListCell *lc;
+
+ /* Initialize this stage's workspace in trgmNFA struct */
+ trgmNFA->queue = NIL;
+ trgmNFA->keysQueue = NIL;
+ trgmNFA->arcsCount = 0;
+ trgmNFA->overflowed = false;
+
+ /* Create hashtable for states */
+ hashCtl.keysize = sizeof(TrgmStateKey);
+ hashCtl.entrysize = sizeof(TrgmState);
+ hashCtl.hcxt = CurrentMemoryContext;
+ trgmNFA->states = hash_create("Trigram NFA",
+ 1024,
+ &hashCtl,
+ HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
+ trgmNFA->nstates = 0;
+
+ /* Create initial state: ambiguous prefix, NFA's initial state */
+ MemSet(&initkey, 0, sizeof(initkey));
+ initkey.prefix.colors[0] = COLOR_UNKNOWN;
+ initkey.prefix.colors[1] = COLOR_UNKNOWN;
+ initkey.nstate = pg_reg_getinitialstate(trgmNFA->regex);
+
+ initstate = getState(trgmNFA, &initkey);
+ initstate->flags |= TSTATE_INIT;
+ trgmNFA->initState = initstate;
+
+ /*
+ * Recursively build the expanded graph by processing queue of states
+ * (breadth-first search). getState already put initstate in the queue.
+ * Note that getState will append new states to the queue within the loop,
+ * too; this works as long as we don't do repeat fetches using the "lc"
+ * pointer.
+ */
+ foreach(lc, trgmNFA->queue)
+ {
+ TrgmState *state = (TrgmState *) lfirst(lc);
+
+ /*
+ * If we overflowed then just mark state as final. Otherwise do
+ * actual processing.
+ */
+ if (trgmNFA->overflowed)
+ state->flags |= TSTATE_FIN;
+ else
+ processState(trgmNFA, state);
+
+ /* Did we overflow? */
+ if (trgmNFA->arcsCount > MAX_EXPANDED_ARCS ||
+ hash_get_num_entries(trgmNFA->states) > MAX_EXPANDED_STATES)
+ trgmNFA->overflowed = true;
+ }
+}
+
+/*
+ * Process one state: add enter keys and then add outgoing arcs.
+ */
+static void
+processState(TrgmNFA *trgmNFA, TrgmState *state)
+{
+ ListCell *lc;
+
+ /* keysQueue should be NIL already, but make sure */
+ trgmNFA->keysQueue = NIL;
+
+ /*
+ * Add state's own key, and then process all keys added to keysQueue until
+ * queue is finished. But we can quit if the state gets marked final.
+ */
+ addKey(trgmNFA, state, &state->stateKey);
+ foreach(lc, trgmNFA->keysQueue)
+ {
+ TrgmStateKey *key = (TrgmStateKey *) lfirst(lc);
+
+ if (state->flags & TSTATE_FIN)
+ break;
+ addKey(trgmNFA, state, key);
+ }
+
+ /* Release keysQueue to clean up for next cycle */
+ list_free(trgmNFA->keysQueue);
+ trgmNFA->keysQueue = NIL;
+
+ /*
+ * Add outgoing arcs only if state isn't final (we have no interest in
+ * outgoing arcs if we already match)
+ */
+ if (!(state->flags & TSTATE_FIN))
+ addArcs(trgmNFA, state);
+}
+
+/*
+ * Add the given enter key into the state's enterKeys list, and determine
+ * whether this should result in any further enter keys being added.
+ * If so, add those keys to keysQueue so that processState will handle them.
+ *
+ * If the enter key is for the NFA's final state, mark state as TSTATE_FIN.
+ * This situation means that we can reach the final state from this expanded
+ * state without reading any predictable trigram, so we must consider this
+ * state as an accepting one.
+ *
+ * The given key could be a duplicate of one already in enterKeys, or be
+ * redundant with some enterKeys. So we check that before doing anything.
+ *
+ * Note that we don't generate any actual arcs here. addArcs will do that
+ * later, after we have identified all the enter keys for this state.
+ */
+static void
+addKey(TrgmNFA *trgmNFA, TrgmState *state, TrgmStateKey *key)
+{
+ regex_arc_t *arcs;
+ TrgmStateKey destKey;
+ ListCell *cell;
+ int i,
+ arcsCount;
+
+ /*
+ * Ensure any pad bytes in destKey are zero, since it may get used as a
+ * hashtable key by getState.
+ */
+ MemSet(&destKey, 0, sizeof(destKey));
+
+ /*
+ * Compare key to each existing enter key of the state to check for
+ * redundancy. We can drop either old key(s) or the new key if we find
+ * redundancy.
+ */
+ foreach(cell, state->enterKeys)
+ {
+ TrgmStateKey *existingKey = (TrgmStateKey *) lfirst(cell);
+
+ if (existingKey->nstate == key->nstate)
+ {
+ if (prefixContains(&existingKey->prefix, &key->prefix))
+ {
+ /* This old key already covers the new key. Nothing to do */
+ return;
+ }
+ if (prefixContains(&key->prefix, &existingKey->prefix))
+ {
+ /*
+ * The new key covers this old key. Remove the old key, it's
+ * no longer needed once we add this key to the list.
+ */
+ state->enterKeys = foreach_delete_current(state->enterKeys,
+ cell);
+ }
+ }
+ }
+
+ /* No redundancy, so add this key to the state's list */
+ state->enterKeys = lappend(state->enterKeys, key);
+
+ /* If state is now known final, mark it and we're done */
+ if (key->nstate == pg_reg_getfinalstate(trgmNFA->regex))
+ {
+ state->flags |= TSTATE_FIN;
+ return;
+ }
+
+ /*
+ * Loop through all outgoing arcs of the corresponding state in the
+ * original NFA.
+ */
+ arcsCount = pg_reg_getnumoutarcs(trgmNFA->regex, key->nstate);
+ arcs = (regex_arc_t *) palloc(sizeof(regex_arc_t) * arcsCount);
+ pg_reg_getoutarcs(trgmNFA->regex, key->nstate, arcs, arcsCount);
+
+ for (i = 0; i < arcsCount; i++)
+ {
+ regex_arc_t *arc = &arcs[i];
+
+ if (pg_reg_colorisbegin(trgmNFA->regex, arc->co))
+ {
+ /*
+ * Start of line/string (^). Trigram extraction treats start of
+ * line same as start of word: double space prefix is added.
+ * Hence, make an enter key showing we can reach the arc
+ * destination with all-blank prefix.
+ */
+ destKey.prefix.colors[0] = COLOR_BLANK;
+ destKey.prefix.colors[1] = COLOR_BLANK;
+ destKey.nstate = arc->to;
+
+ /* Add enter key to this state */
+ addKeyToQueue(trgmNFA, &destKey);
+ }
+ else if (pg_reg_colorisend(trgmNFA->regex, arc->co))
+ {
+ /*
+ * End of line/string ($). We must consider this arc as a
+ * transition that doesn't read anything. The reason for adding
+ * this enter key to the state is that if the arc leads to the
+ * NFA's final state, we must mark this expanded state as final.
+ */
+ destKey.prefix.colors[0] = COLOR_UNKNOWN;
+ destKey.prefix.colors[1] = COLOR_UNKNOWN;
+ destKey.nstate = arc->to;
+
+ /* Add enter key to this state */
+ addKeyToQueue(trgmNFA, &destKey);
+ }
+ else if (arc->co >= 0)
+ {
+ /* Regular color (including WHITE) */
+ TrgmColorInfo *colorInfo = &trgmNFA->colorInfo[arc->co];
+
+ if (colorInfo->expandable)
+ {
+ if (colorInfo->containsNonWord &&
+ !validArcLabel(key, COLOR_BLANK))
+ {
+ /*
+ * We can reach the arc destination after reading a
+ * non-word character, but the prefix is not something
+ * that addArc will accept with COLOR_BLANK, so no trigram
+ * arc can get made for this transition. We must make an
+ * enter key to show that the arc destination is
+ * reachable. Set it up with an all-blank prefix, since
+ * that corresponds to what the trigram extraction code
+ * will do at a word starting boundary.
+ */
+ destKey.prefix.colors[0] = COLOR_BLANK;
+ destKey.prefix.colors[1] = COLOR_BLANK;
+ destKey.nstate = arc->to;
+ addKeyToQueue(trgmNFA, &destKey);
+ }
+
+ if (colorInfo->wordCharsCount > 0 &&
+ !validArcLabel(key, arc->co))
+ {
+ /*
+ * We can reach the arc destination after reading a word
+ * character, but the prefix is not something that addArc
+ * will accept, so no trigram arc can get made for this
+ * transition. We must make an enter key to show that the
+ * arc destination is reachable. The prefix for the enter
+ * key should reflect the info we have for this arc.
+ */
+ destKey.prefix.colors[0] = key->prefix.colors[1];
+ destKey.prefix.colors[1] = arc->co;
+ destKey.nstate = arc->to;
+ addKeyToQueue(trgmNFA, &destKey);
+ }
+ }
+ else
+ {
+ /*
+ * Unexpandable color. Add enter key with ambiguous prefix,
+ * showing we can reach the destination from this state, but
+ * the preceding colors will be uncertain. (We do not set the
+ * first prefix color to key->prefix.colors[1], because a
+ * prefix of known followed by unknown is invalid.)
+ */
+ destKey.prefix.colors[0] = COLOR_UNKNOWN;
+ destKey.prefix.colors[1] = COLOR_UNKNOWN;
+ destKey.nstate = arc->to;
+ addKeyToQueue(trgmNFA, &destKey);
+ }
+ }
+ else
+ {
+ /* RAINBOW: treat as unexpandable color */
+ destKey.prefix.colors[0] = COLOR_UNKNOWN;
+ destKey.prefix.colors[1] = COLOR_UNKNOWN;
+ destKey.nstate = arc->to;
+ addKeyToQueue(trgmNFA, &destKey);
+ }
+ }
+
+ pfree(arcs);
+}
+
+/*
+ * Add copy of given key to keysQueue for later processing.
+ */
+static void
+addKeyToQueue(TrgmNFA *trgmNFA, TrgmStateKey *key)
+{
+ TrgmStateKey *keyCopy = (TrgmStateKey *) palloc(sizeof(TrgmStateKey));
+
+ memcpy(keyCopy, key, sizeof(TrgmStateKey));
+ trgmNFA->keysQueue = lappend(trgmNFA->keysQueue, keyCopy);
+}
+
+/*
+ * Add outgoing arcs from given state, whose enter keys are all now known.
+ */
+static void
+addArcs(TrgmNFA *trgmNFA, TrgmState *state)
+{
+ TrgmStateKey destKey;
+ ListCell *cell;
+ regex_arc_t *arcs;
+ int arcsCount,
+ i;
+
+ /*
+ * Ensure any pad bytes in destKey are zero, since it may get used as a
+ * hashtable key by getState.
+ */
+ MemSet(&destKey, 0, sizeof(destKey));
+
+ /*
+ * Iterate over enter keys associated with this expanded-graph state. This
+ * includes both the state's own stateKey, and any enter keys we added to
+ * it during addKey (which represent expanded-graph states that are not
+ * distinguishable from this one by means of trigrams). For each such
+ * enter key, examine all the out-arcs of the key's underlying NFA state,
+ * and try to make a trigram arc leading to where the out-arc leads.
+ * (addArc will deal with whether the arc is valid or not.)
+ */
+ foreach(cell, state->enterKeys)
+ {
+ TrgmStateKey *key = (TrgmStateKey *) lfirst(cell);
+
+ arcsCount = pg_reg_getnumoutarcs(trgmNFA->regex, key->nstate);
+ arcs = (regex_arc_t *) palloc(sizeof(regex_arc_t) * arcsCount);
+ pg_reg_getoutarcs(trgmNFA->regex, key->nstate, arcs, arcsCount);
+
+ for (i = 0; i < arcsCount; i++)
+ {
+ regex_arc_t *arc = &arcs[i];
+ TrgmColorInfo *colorInfo;
+
+ /*
+ * Ignore non-expandable colors; addKey already handled the case.
+ *
+ * We need no special check for WHITE or begin/end pseudocolors
+ * here. We don't need to do any processing for them, and they
+ * will be marked non-expandable since the regex engine will have
+ * reported them that way. We do have to watch out for RAINBOW,
+ * which has a negative color number.
+ */
+ if (arc->co < 0)
+ continue;
+ Assert(arc->co < trgmNFA->ncolors);
+
+ colorInfo = &trgmNFA->colorInfo[arc->co];
+ if (!colorInfo->expandable)
+ continue;
+
+ if (colorInfo->containsNonWord)
+ {
+ /*
+ * Color includes non-word character(s).
+ *
+ * Generate an arc, treating this transition as occurring on
+ * BLANK. This allows word-ending trigrams to be manufactured
+ * if possible.
+ */
+ destKey.prefix.colors[0] = key->prefix.colors[1];
+ destKey.prefix.colors[1] = COLOR_BLANK;
+ destKey.nstate = arc->to;
+
+ addArc(trgmNFA, state, key, COLOR_BLANK, &destKey);
+ }
+
+ if (colorInfo->wordCharsCount > 0)
+ {
+ /*
+ * Color includes word character(s).
+ *
+ * Generate an arc. Color is pushed into prefix of target
+ * state.
+ */
+ destKey.prefix.colors[0] = key->prefix.colors[1];
+ destKey.prefix.colors[1] = arc->co;
+ destKey.nstate = arc->to;
+
+ addArc(trgmNFA, state, key, arc->co, &destKey);
+ }
+ }
+
+ pfree(arcs);
+ }
+}
+
+/*
+ * Generate an out-arc of the expanded graph, if it's valid and not redundant.
+ *
+ * state: expanded-graph state we want to add an out-arc to
+ * key: provides prefix colors (key->nstate is not used)
+ * co: transition color
+ * destKey: identifier for destination state of expanded graph
+ */
+static void
+addArc(TrgmNFA *trgmNFA, TrgmState *state, TrgmStateKey *key,
+ TrgmColor co, TrgmStateKey *destKey)
+{
+ TrgmArc *arc;
+ ListCell *cell;
+
+ /* Do nothing if this wouldn't be a valid arc label trigram */
+ if (!validArcLabel(key, co))
+ return;
+
+ /*
+ * Check if we are going to reach key which is covered by a key which is
+ * already listed in this state. If so arc is useless: the NFA can bypass
+ * it through a path that doesn't require any predictable trigram, so
+ * whether the arc's trigram is present or not doesn't really matter.
+ */
+ foreach(cell, state->enterKeys)
+ {
+ TrgmStateKey *existingKey = (TrgmStateKey *) lfirst(cell);
+
+ if (existingKey->nstate == destKey->nstate &&
+ prefixContains(&existingKey->prefix, &destKey->prefix))
+ return;
+ }
+
+ /* Checks were successful, add new arc */
+ arc = (TrgmArc *) palloc(sizeof(TrgmArc));
+ arc->target = getState(trgmNFA, destKey);
+ arc->ctrgm.colors[0] = key->prefix.colors[0];
+ arc->ctrgm.colors[1] = key->prefix.colors[1];
+ arc->ctrgm.colors[2] = co;
+
+ state->arcs = lappend(state->arcs, arc);
+ trgmNFA->arcsCount++;
+}
+
+/*
+ * Can we make a valid trigram arc label from the given prefix and arc color?
+ *
+ * This is split out so that tests in addKey and addArc will stay in sync.
+ */
+static bool
+validArcLabel(TrgmStateKey *key, TrgmColor co)
+{
+ /*
+ * We have to know full trigram in order to add outgoing arc. So we can't
+ * do it if prefix is ambiguous.
+ */
+ if (key->prefix.colors[0] == COLOR_UNKNOWN)
+ return false;
+
+ /* If key->prefix.colors[0] isn't unknown, its second color isn't either */
+ Assert(key->prefix.colors[1] != COLOR_UNKNOWN);
+ /* And we should not be called with an unknown arc color anytime */
+ Assert(co != COLOR_UNKNOWN);
+
+ /*
+ * We don't bother with making arcs representing three non-word
+ * characters, since that's useless for trigram extraction.
+ */
+ if (key->prefix.colors[0] == COLOR_BLANK &&
+ key->prefix.colors[1] == COLOR_BLANK &&
+ co == COLOR_BLANK)
+ return false;
+
+ /*
+ * We also reject nonblank-blank-anything. The nonblank-blank-nonblank
+ * case doesn't correspond to any trigram the trigram extraction code
+ * would make. The nonblank-blank-blank case is also not possible with
+ * RPADDING = 1. (Note that in many cases we'd fail to generate such a
+ * trigram even if it were valid, for example processing "foo bar" will
+ * not result in considering the trigram "o ". So if you want to support
+ * RPADDING = 2, there's more to do than just twiddle this test.)
+ */
+ if (key->prefix.colors[0] != COLOR_BLANK &&
+ key->prefix.colors[1] == COLOR_BLANK)
+ return false;
+
+ /*
+ * Other combinations involving blank are valid, in particular we assume
+ * blank-blank-nonblank is valid, which presumes that LPADDING is 2.
+ *
+ * Note: Using again the example "foo bar", we will not consider the
+ * trigram " b", though this trigram would be found by the trigram
+ * extraction code. Since we will find " ba", it doesn't seem worth
+ * trying to hack the algorithm to generate the additional trigram.
+ */
+
+ /* arc label is valid */
+ return true;
+}
+
+/*
+ * Get state of expanded graph for given state key,
+ * and queue the state for processing if it didn't already exist.
+ */
+static TrgmState *
+getState(TrgmNFA *trgmNFA, TrgmStateKey *key)
+{
+ TrgmState *state;
+ bool found;
+
+ state = (TrgmState *) hash_search(trgmNFA->states, key, HASH_ENTER,
+ &found);
+ if (!found)
+ {
+ /* New state: initialize and queue it */
+ state->arcs = NIL;
+ state->enterKeys = NIL;
+ state->flags = 0;
+ /* states are initially given negative numbers */
+ state->snumber = -(++trgmNFA->nstates);
+ state->parent = NULL;
+ state->tentFlags = 0;
+ state->tentParent = NULL;
+
+ trgmNFA->queue = lappend(trgmNFA->queue, state);
+ }
+ return state;
+}
+
+/*
+ * Check if prefix1 "contains" prefix2.
+ *
+ * "contains" means that any exact prefix (with no ambiguity) that satisfies
+ * prefix2 also satisfies prefix1.
+ */
+static bool
+prefixContains(TrgmPrefix *prefix1, TrgmPrefix *prefix2)
+{
+ if (prefix1->colors[1] == COLOR_UNKNOWN)
+ {
+ /* Fully ambiguous prefix contains everything */
+ return true;
+ }
+ else if (prefix1->colors[0] == COLOR_UNKNOWN)
+ {
+ /*
+ * Prefix with only first unknown color contains every prefix with
+ * same second color.
+ */
+ if (prefix1->colors[1] == prefix2->colors[1])
+ return true;
+ else
+ return false;
+ }
+ else
+ {
+ /* Exact prefix contains only the exact same prefix */
+ if (prefix1->colors[0] == prefix2->colors[0] &&
+ prefix1->colors[1] == prefix2->colors[1])
+ return true;
+ else
+ return false;
+ }
+}
+
+
+/*---------------------
+ * Subroutines for expanding color trigrams into regular trigrams (stage 3).
+ *---------------------
+ */
+
+/*
+ * Get vector of all color trigrams in graph and select which of them
+ * to expand into simple trigrams.
+ *
+ * Returns true if OK, false if exhausted resource limits.
+ */
+static bool
+selectColorTrigrams(TrgmNFA *trgmNFA)
+{
+ HASH_SEQ_STATUS scan_status;
+ int arcsCount = trgmNFA->arcsCount,
+ i;
+ TrgmState *state;
+ ColorTrgmInfo *colorTrgms;
+ int64 totalTrgmCount;
+ float4 totalTrgmPenalty;
+ int cnumber;
+
+ /* Collect color trigrams from all arcs */
+ colorTrgms = (ColorTrgmInfo *) palloc0(sizeof(ColorTrgmInfo) * arcsCount);
+ trgmNFA->colorTrgms = colorTrgms;
+
+ i = 0;
+ hash_seq_init(&scan_status, trgmNFA->states);
+ while ((state = (TrgmState *) hash_seq_search(&scan_status)) != NULL)
+ {
+ ListCell *cell;
+
+ foreach(cell, state->arcs)
+ {
+ TrgmArc *arc = (TrgmArc *) lfirst(cell);
+ TrgmArcInfo *arcInfo = (TrgmArcInfo *) palloc(sizeof(TrgmArcInfo));
+ ColorTrgmInfo *trgmInfo = &colorTrgms[i];
+
+ arcInfo->source = state;
+ arcInfo->target = arc->target;
+ trgmInfo->ctrgm = arc->ctrgm;
+ trgmInfo->cnumber = -1;
+ /* count and penalty will be set below */
+ trgmInfo->expanded = true;
+ trgmInfo->arcs = list_make1(arcInfo);
+ i++;
+ }
+ }
+ Assert(i == arcsCount);
+
+ /* Remove duplicates, merging their arcs lists */
+ if (arcsCount >= 2)
+ {
+ ColorTrgmInfo *p1,
+ *p2;
+
+ /* Sort trigrams to ease duplicate detection */
+ qsort(colorTrgms, arcsCount, sizeof(ColorTrgmInfo), colorTrgmInfoCmp);
+
+ /* p1 is probe point, p2 is last known non-duplicate. */
+ p2 = colorTrgms;
+ for (p1 = colorTrgms + 1; p1 < colorTrgms + arcsCount; p1++)
+ {
+ if (colorTrgmInfoCmp(p1, p2) > 0)
+ {
+ p2++;
+ *p2 = *p1;
+ }
+ else
+ {
+ p2->arcs = list_concat(p2->arcs, p1->arcs);
+ }
+ }
+ trgmNFA->colorTrgmsCount = (p2 - colorTrgms) + 1;
+ }
+ else
+ {
+ trgmNFA->colorTrgmsCount = arcsCount;
+ }
+
+ /*
+ * Count number of simple trigrams generated by each color trigram, and
+ * also compute a penalty value, which is the number of simple trigrams
+ * times a multiplier that depends on its whitespace content.
+ *
+ * Note: per-color-trigram counts cannot overflow an int so long as
+ * COLOR_COUNT_LIMIT is not more than the cube root of INT_MAX, ie about
+ * 1290. However, the grand total totalTrgmCount might conceivably
+ * overflow an int, so we use int64 for that within this routine. Also,
+ * penalties are calculated in float4 arithmetic to avoid any overflow
+ * worries.
+ */
+ totalTrgmCount = 0;
+ totalTrgmPenalty = 0.0f;
+ for (i = 0; i < trgmNFA->colorTrgmsCount; i++)
+ {
+ ColorTrgmInfo *trgmInfo = &colorTrgms[i];
+ int j,
+ count = 1,
+ typeIndex = 0;
+
+ for (j = 0; j < 3; j++)
+ {
+ TrgmColor c = trgmInfo->ctrgm.colors[j];
+
+ typeIndex *= 2;
+ if (c == COLOR_BLANK)
+ typeIndex++;
+ else
+ count *= trgmNFA->colorInfo[c].wordCharsCount;
+ }
+ trgmInfo->count = count;
+ totalTrgmCount += count;
+ trgmInfo->penalty = penalties[typeIndex] * (float4) count;
+ totalTrgmPenalty += trgmInfo->penalty;
+ }
+
+ /* Sort color trigrams in descending order of their penalties */
+ qsort(colorTrgms, trgmNFA->colorTrgmsCount, sizeof(ColorTrgmInfo),
+ colorTrgmInfoPenaltyCmp);
+
+ /*
+ * Remove color trigrams from the graph so long as total penalty of color
+ * trigrams exceeds WISH_TRGM_PENALTY. (If we fail to get down to
+ * WISH_TRGM_PENALTY, it's OK so long as total count is no more than
+ * MAX_TRGM_COUNT.) We prefer to remove color trigrams with higher
+ * penalty, since those are the most promising for reducing the total
+ * penalty. When removing a color trigram we have to merge states
+ * connected by arcs labeled with that trigram. It's necessary to not
+ * merge initial and final states, because our graph becomes useless if
+ * that happens; so we cannot always remove the trigram we'd prefer to.
+ */
+ for (i = 0; i < trgmNFA->colorTrgmsCount; i++)
+ {
+ ColorTrgmInfo *trgmInfo = &colorTrgms[i];
+ bool canRemove = true;
+ ListCell *cell;
+
+ /* Done if we've reached the target */
+ if (totalTrgmPenalty <= WISH_TRGM_PENALTY)
+ break;
+
+#ifdef TRGM_REGEXP_DEBUG
+ fprintf(stderr, "considering ctrgm %d %d %d, penalty %f, %d arcs\n",
+ trgmInfo->ctrgm.colors[0],
+ trgmInfo->ctrgm.colors[1],
+ trgmInfo->ctrgm.colors[2],
+ trgmInfo->penalty,
+ list_length(trgmInfo->arcs));
+#endif
+
+ /*
+ * Does any arc of this color trigram connect initial and final
+ * states? If so we can't remove it.
+ */
+ foreach(cell, trgmInfo->arcs)
+ {
+ TrgmArcInfo *arcInfo = (TrgmArcInfo *) lfirst(cell);
+ TrgmState *source = arcInfo->source,
+ *target = arcInfo->target;
+ int source_flags,
+ target_flags;
+
+#ifdef TRGM_REGEXP_DEBUG
+ fprintf(stderr, "examining arc to s%d (%x) from s%d (%x)\n",
+ -target->snumber, target->flags,
+ -source->snumber, source->flags);
+#endif
+
+ /* examine parent states, if any merging has already happened */
+ while (source->parent)
+ source = source->parent;
+ while (target->parent)
+ target = target->parent;
+
+#ifdef TRGM_REGEXP_DEBUG
+ fprintf(stderr, " ... after completed merges: to s%d (%x) from s%d (%x)\n",
+ -target->snumber, target->flags,
+ -source->snumber, source->flags);
+#endif
+
+ /* we must also consider merges we are planning right now */
+ source_flags = source->flags | source->tentFlags;
+ while (source->tentParent)
+ {
+ source = source->tentParent;
+ source_flags |= source->flags | source->tentFlags;
+ }
+ target_flags = target->flags | target->tentFlags;
+ while (target->tentParent)
+ {
+ target = target->tentParent;
+ target_flags |= target->flags | target->tentFlags;
+ }
+
+#ifdef TRGM_REGEXP_DEBUG
+ fprintf(stderr, " ... after tentative merges: to s%d (%x) from s%d (%x)\n",
+ -target->snumber, target_flags,
+ -source->snumber, source_flags);
+#endif
+
+ /* would fully-merged state have both INIT and FIN set? */
+ if (((source_flags | target_flags) & (TSTATE_INIT | TSTATE_FIN)) ==
+ (TSTATE_INIT | TSTATE_FIN))
+ {
+ canRemove = false;
+ break;
+ }
+
+ /* ok so far, so remember planned merge */
+ if (source != target)
+ {
+#ifdef TRGM_REGEXP_DEBUG
+ fprintf(stderr, " ... tentatively merging s%d into s%d\n",
+ -target->snumber, -source->snumber);
+#endif
+ target->tentParent = source;
+ source->tentFlags |= target_flags;
+ }
+ }
+
+ /*
+ * We must reset all the tentFlags/tentParent fields before
+ * continuing. tentFlags could only have become set in states that
+ * are the source or parent or tentative parent of one of the current
+ * arcs; likewise tentParent could only have become set in states that
+ * are the target or parent or tentative parent of one of the current
+ * arcs. There might be some overlap between those sets, but if we
+ * clear tentFlags in target states as well as source states, we
+ * should be okay even if we visit a state as target before visiting
+ * it as a source.
+ */
+ foreach(cell, trgmInfo->arcs)
+ {
+ TrgmArcInfo *arcInfo = (TrgmArcInfo *) lfirst(cell);
+ TrgmState *source = arcInfo->source,
+ *target = arcInfo->target;
+ TrgmState *ttarget;
+
+ /* no need to touch previously-merged states */
+ while (source->parent)
+ source = source->parent;
+ while (target->parent)
+ target = target->parent;
+
+ while (source)
+ {
+ source->tentFlags = 0;
+ source = source->tentParent;
+ }
+
+ while ((ttarget = target->tentParent) != NULL)
+ {
+ target->tentParent = NULL;
+ target->tentFlags = 0; /* in case it was also a source */
+ target = ttarget;
+ }
+ }
+
+ /* Now, move on if we can't drop this trigram */
+ if (!canRemove)
+ {
+#ifdef TRGM_REGEXP_DEBUG
+ fprintf(stderr, " ... not ok to merge\n");
+#endif
+ continue;
+ }
+
+ /* OK, merge states linked by each arc labeled by the trigram */
+ foreach(cell, trgmInfo->arcs)
+ {
+ TrgmArcInfo *arcInfo = (TrgmArcInfo *) lfirst(cell);
+ TrgmState *source = arcInfo->source,
+ *target = arcInfo->target;
+
+ while (source->parent)
+ source = source->parent;
+ while (target->parent)
+ target = target->parent;
+ if (source != target)
+ {
+#ifdef TRGM_REGEXP_DEBUG
+ fprintf(stderr, "merging s%d into s%d\n",
+ -target->snumber, -source->snumber);
+#endif
+ mergeStates(source, target);
+ /* Assert we didn't merge initial and final states */
+ Assert((source->flags & (TSTATE_INIT | TSTATE_FIN)) !=
+ (TSTATE_INIT | TSTATE_FIN));
+ }
+ }
+
+ /* Mark trigram unexpanded, and update totals */
+ trgmInfo->expanded = false;
+ totalTrgmCount -= trgmInfo->count;
+ totalTrgmPenalty -= trgmInfo->penalty;
+ }
+
+ /* Did we succeed in fitting into MAX_TRGM_COUNT? */
+ if (totalTrgmCount > MAX_TRGM_COUNT)
+ return false;
+
+ trgmNFA->totalTrgmCount = (int) totalTrgmCount;
+
+ /*
+ * Sort color trigrams by colors (will be useful for bsearch in packGraph)
+ * and enumerate the color trigrams that are expanded.
+ */
+ cnumber = 0;
+ qsort(colorTrgms, trgmNFA->colorTrgmsCount, sizeof(ColorTrgmInfo),
+ colorTrgmInfoCmp);
+ for (i = 0; i < trgmNFA->colorTrgmsCount; i++)
+ {
+ if (colorTrgms[i].expanded)
+ {
+ colorTrgms[i].cnumber = cnumber;
+ cnumber++;
+ }
+ }
+
+ return true;
+}
+
+/*
+ * Expand selected color trigrams into regular trigrams.
+ *
+ * Returns the TRGM array to be passed to the index machinery.
+ * The array must be allocated in rcontext.
+ */
+static TRGM *
+expandColorTrigrams(TrgmNFA *trgmNFA, MemoryContext rcontext)
+{
+ TRGM *trg;
+ trgm *p;
+ int i;
+ TrgmColorInfo blankColor;
+ trgm_mb_char blankChar;
+
+ /* Set up "blank" color structure containing a single zero character */
+ memset(blankChar.bytes, 0, sizeof(blankChar.bytes));
+ blankColor.wordCharsCount = 1;
+ blankColor.wordChars = &blankChar;
+
+ /* Construct the trgm array */
+ trg = (TRGM *)
+ MemoryContextAllocZero(rcontext,
+ TRGMHDRSIZE +
+ trgmNFA->totalTrgmCount * sizeof(trgm));
+ trg->flag = ARRKEY;
+ SET_VARSIZE(trg, CALCGTSIZE(ARRKEY, trgmNFA->totalTrgmCount));
+ p = GETARR(trg);
+ for (i = 0; i < trgmNFA->colorTrgmsCount; i++)
+ {
+ ColorTrgmInfo *colorTrgm = &trgmNFA->colorTrgms[i];
+ TrgmColorInfo *c[3];
+ trgm_mb_char s[3];
+ int j,
+ i1,
+ i2,
+ i3;
+
+ /* Ignore any unexpanded trigrams ... */
+ if (!colorTrgm->expanded)
+ continue;
+
+ /* Get colors, substituting the dummy struct for COLOR_BLANK */
+ for (j = 0; j < 3; j++)
+ {
+ if (colorTrgm->ctrgm.colors[j] != COLOR_BLANK)
+ c[j] = &trgmNFA->colorInfo[colorTrgm->ctrgm.colors[j]];
+ else
+ c[j] = &blankColor;
+ }
+
+ /* Iterate over all possible combinations of colors' characters */
+ for (i1 = 0; i1 < c[0]->wordCharsCount; i1++)
+ {
+ s[0] = c[0]->wordChars[i1];
+ for (i2 = 0; i2 < c[1]->wordCharsCount; i2++)
+ {
+ s[1] = c[1]->wordChars[i2];
+ for (i3 = 0; i3 < c[2]->wordCharsCount; i3++)
+ {
+ s[2] = c[2]->wordChars[i3];
+ fillTrgm(p, s);
+ p++;
+ }
+ }
+ }
+ }
+
+ return trg;
+}
+
+/*
+ * Convert trigram into trgm datatype.
+ */
+static void
+fillTrgm(trgm *ptrgm, trgm_mb_char s[3])
+{
+ char str[3 * MAX_MULTIBYTE_CHAR_LEN],
+ *p;
+ int i,
+ j;
+
+ /* Write multibyte string into "str" (we don't need null termination) */
+ p = str;
+
+ for (i = 0; i < 3; i++)
+ {
+ if (s[i].bytes[0] != 0)
+ {
+ for (j = 0; j < MAX_MULTIBYTE_CHAR_LEN && s[i].bytes[j]; j++)
+ *p++ = s[i].bytes[j];
+ }
+ else
+ {
+ /* Emit a space in place of COLOR_BLANK */
+ *p++ = ' ';
+ }
+ }
+
+ /* Convert "str" to a standard trigram (possibly hashing it) */
+ compact_trigram(ptrgm, str, p - str);
+}
+
+/*
+ * Merge two states of graph.
+ */
+static void
+mergeStates(TrgmState *state1, TrgmState *state2)
+{
+ Assert(state1 != state2);
+ Assert(!state1->parent);
+ Assert(!state2->parent);
+
+ /* state1 absorbs state2's flags */
+ state1->flags |= state2->flags;
+
+ /* state2, and indirectly all its children, become children of state1 */
+ state2->parent = state1;
+}
+
+/*
+ * Compare function for sorting of color trigrams by their colors.
+ */
+static int
+colorTrgmInfoCmp(const void *p1, const void *p2)
+{
+ const ColorTrgmInfo *c1 = (const ColorTrgmInfo *) p1;
+ const ColorTrgmInfo *c2 = (const ColorTrgmInfo *) p2;
+
+ return memcmp(&c1->ctrgm, &c2->ctrgm, sizeof(ColorTrgm));
+}
+
+/*
+ * Compare function for sorting color trigrams in descending order of
+ * their penalty fields.
+ */
+static int
+colorTrgmInfoPenaltyCmp(const void *p1, const void *p2)
+{
+ float4 penalty1 = ((const ColorTrgmInfo *) p1)->penalty;
+ float4 penalty2 = ((const ColorTrgmInfo *) p2)->penalty;
+
+ if (penalty1 < penalty2)
+ return 1;
+ else if (penalty1 == penalty2)
+ return 0;
+ else
+ return -1;
+}
+
+
+/*---------------------
+ * Subroutines for packing the graph into final representation (stage 4).
+ *---------------------
+ */
+
+/*
+ * Pack expanded graph into final representation.
+ *
+ * The result data must be allocated in rcontext.
+ */
+static TrgmPackedGraph *
+packGraph(TrgmNFA *trgmNFA, MemoryContext rcontext)
+{
+ int snumber = 2,
+ arcIndex,
+ arcsCount;
+ HASH_SEQ_STATUS scan_status;
+ TrgmState *state;
+ TrgmPackArcInfo *arcs;
+ TrgmPackedArc *packedArcs;
+ TrgmPackedGraph *result;
+ int i,
+ j;
+
+ /* Enumerate surviving states, giving init and fin reserved numbers */
+ hash_seq_init(&scan_status, trgmNFA->states);
+ while ((state = (TrgmState *) hash_seq_search(&scan_status)) != NULL)
+ {
+ while (state->parent)
+ state = state->parent;
+
+ if (state->snumber < 0)
+ {
+ if (state->flags & TSTATE_INIT)
+ state->snumber = 0;
+ else if (state->flags & TSTATE_FIN)
+ state->snumber = 1;
+ else
+ {
+ state->snumber = snumber;
+ snumber++;
+ }
+ }
+ }
+
+ /* Collect array of all arcs */
+ arcs = (TrgmPackArcInfo *)
+ palloc(sizeof(TrgmPackArcInfo) * trgmNFA->arcsCount);
+ arcIndex = 0;
+ hash_seq_init(&scan_status, trgmNFA->states);
+ while ((state = (TrgmState *) hash_seq_search(&scan_status)) != NULL)
+ {
+ TrgmState *source = state;
+ ListCell *cell;
+
+ while (source->parent)
+ source = source->parent;
+
+ foreach(cell, state->arcs)
+ {
+ TrgmArc *arc = (TrgmArc *) lfirst(cell);
+ TrgmState *target = arc->target;
+
+ while (target->parent)
+ target = target->parent;
+
+ if (source->snumber != target->snumber)
+ {
+ ColorTrgmInfo *ctrgm;
+
+ ctrgm = (ColorTrgmInfo *) bsearch(&arc->ctrgm,
+ trgmNFA->colorTrgms,
+ trgmNFA->colorTrgmsCount,
+ sizeof(ColorTrgmInfo),
+ colorTrgmInfoCmp);
+ Assert(ctrgm != NULL);
+ Assert(ctrgm->expanded);
+
+ arcs[arcIndex].sourceState = source->snumber;
+ arcs[arcIndex].targetState = target->snumber;
+ arcs[arcIndex].colorTrgm = ctrgm->cnumber;
+ arcIndex++;
+ }
+ }
+ }
+
+ /* Sort arcs to ease duplicate detection */
+ qsort(arcs, arcIndex, sizeof(TrgmPackArcInfo), packArcInfoCmp);
+
+ /* We could have duplicates because states were merged. Remove them. */
+ if (arcIndex > 1)
+ {
+ /* p1 is probe point, p2 is last known non-duplicate. */
+ TrgmPackArcInfo *p1,
+ *p2;
+
+ p2 = arcs;
+ for (p1 = arcs + 1; p1 < arcs + arcIndex; p1++)
+ {
+ if (packArcInfoCmp(p1, p2) > 0)
+ {
+ p2++;
+ *p2 = *p1;
+ }
+ }
+ arcsCount = (p2 - arcs) + 1;
+ }
+ else
+ arcsCount = arcIndex;
+
+ /* Create packed representation */
+ result = (TrgmPackedGraph *)
+ MemoryContextAlloc(rcontext, sizeof(TrgmPackedGraph));
+
+ /* Pack color trigrams information */
+ result->colorTrigramsCount = 0;
+ for (i = 0; i < trgmNFA->colorTrgmsCount; i++)
+ {
+ if (trgmNFA->colorTrgms[i].expanded)
+ result->colorTrigramsCount++;
+ }
+ result->colorTrigramGroups = (int *)
+ MemoryContextAlloc(rcontext, sizeof(int) * result->colorTrigramsCount);
+ j = 0;
+ for (i = 0; i < trgmNFA->colorTrgmsCount; i++)
+ {
+ if (trgmNFA->colorTrgms[i].expanded)
+ {
+ result->colorTrigramGroups[j] = trgmNFA->colorTrgms[i].count;
+ j++;
+ }
+ }
+
+ /* Pack states and arcs information */
+ result->statesCount = snumber;
+ result->states = (TrgmPackedState *)
+ MemoryContextAlloc(rcontext, snumber * sizeof(TrgmPackedState));
+ packedArcs = (TrgmPackedArc *)
+ MemoryContextAlloc(rcontext, arcsCount * sizeof(TrgmPackedArc));
+ j = 0;
+ for (i = 0; i < snumber; i++)
+ {
+ int cnt = 0;
+
+ result->states[i].arcs = &packedArcs[j];
+ while (j < arcsCount && arcs[j].sourceState == i)
+ {
+ packedArcs[j].targetState = arcs[j].targetState;
+ packedArcs[j].colorTrgm = arcs[j].colorTrgm;
+ cnt++;
+ j++;
+ }
+ result->states[i].arcsCount = cnt;
+ }
+
+ /* Allocate working memory for trigramsMatchGraph() */
+ result->colorTrigramsActive = (bool *)
+ MemoryContextAlloc(rcontext, sizeof(bool) * result->colorTrigramsCount);
+ result->statesActive = (bool *)
+ MemoryContextAlloc(rcontext, sizeof(bool) * result->statesCount);
+ result->statesQueue = (int *)
+ MemoryContextAlloc(rcontext, sizeof(int) * result->statesCount);
+
+ return result;
+}
+
+/*
+ * Comparison function for sorting TrgmPackArcInfos.
+ *
+ * Compares arcs in following order: sourceState, colorTrgm, targetState.
+ */
+static int
+packArcInfoCmp(const void *a1, const void *a2)
+{
+ const TrgmPackArcInfo *p1 = (const TrgmPackArcInfo *) a1;
+ const TrgmPackArcInfo *p2 = (const TrgmPackArcInfo *) a2;
+
+ if (p1->sourceState < p2->sourceState)
+ return -1;
+ if (p1->sourceState > p2->sourceState)
+ return 1;
+ if (p1->colorTrgm < p2->colorTrgm)
+ return -1;
+ if (p1->colorTrgm > p2->colorTrgm)
+ return 1;
+ if (p1->targetState < p2->targetState)
+ return -1;
+ if (p1->targetState > p2->targetState)
+ return 1;
+ return 0;
+}
+
+
+/*---------------------
+ * Debugging functions
+ *
+ * These are designed to emit GraphViz files.
+ *---------------------
+ */
+
+#ifdef TRGM_REGEXP_DEBUG
+
+/*
+ * Print initial NFA, in regexp library's representation
+ */
+static void
+printSourceNFA(regex_t *regex, TrgmColorInfo *colors, int ncolors)
+{
+ StringInfoData buf;
+ int nstates = pg_reg_getnumstates(regex);
+ int state;
+ int i;
+
+ initStringInfo(&buf);
+
+ appendStringInfoString(&buf, "\ndigraph sourceNFA {\n");
+
+ for (state = 0; state < nstates; state++)
+ {
+ regex_arc_t *arcs;
+ int i,
+ arcsCount;
+
+ appendStringInfo(&buf, "s%d", state);
+ if (pg_reg_getfinalstate(regex) == state)
+ appendStringInfoString(&buf, " [shape = doublecircle]");
+ appendStringInfoString(&buf, ";\n");
+
+ arcsCount = pg_reg_getnumoutarcs(regex, state);
+ arcs = (regex_arc_t *) palloc(sizeof(regex_arc_t) * arcsCount);
+ pg_reg_getoutarcs(regex, state, arcs, arcsCount);
+
+ for (i = 0; i < arcsCount; i++)
+ {
+ appendStringInfo(&buf, " s%d -> s%d [label = \"%d\"];\n",
+ state, arcs[i].to, arcs[i].co);
+ }
+
+ pfree(arcs);
+ }
+
+ appendStringInfoString(&buf, " node [shape = point ]; initial;\n");
+ appendStringInfo(&buf, " initial -> s%d;\n",
+ pg_reg_getinitialstate(regex));
+
+ /* Print colors */
+ appendStringInfoString(&buf, " { rank = sink;\n");
+ appendStringInfoString(&buf, " Colors [shape = none, margin=0, label=<\n");
+
+ for (i = 0; i < ncolors; i++)
+ {
+ TrgmColorInfo *color = &colors[i];
+ int j;
+
+ appendStringInfo(&buf, "<br/>Color %d: ", i);
+ if (color->expandable)
+ {
+ for (j = 0; j < color->wordCharsCount; j++)
+ {
+ char s[MAX_MULTIBYTE_CHAR_LEN + 1];
+
+ memcpy(s, color->wordChars[j].bytes, MAX_MULTIBYTE_CHAR_LEN);
+ s[MAX_MULTIBYTE_CHAR_LEN] = '\0';
+ appendStringInfoString(&buf, s);
+ }
+ }
+ else
+ appendStringInfoString(&buf, "not expandable");
+ appendStringInfoChar(&buf, '\n');
+ }
+
+ appendStringInfoString(&buf, " >];\n");
+ appendStringInfoString(&buf, " }\n");
+ appendStringInfoString(&buf, "}\n");
+
+ {
+ /* dot -Tpng -o /tmp/source.png < /tmp/source.gv */
+ FILE *fp = fopen("/tmp/source.gv", "w");
+
+ fprintf(fp, "%s", buf.data);
+ fclose(fp);
+ }
+
+ pfree(buf.data);
+}
+
+/*
+ * Print expanded graph.
+ */
+static void
+printTrgmNFA(TrgmNFA *trgmNFA)
+{
+ StringInfoData buf;
+ HASH_SEQ_STATUS scan_status;
+ TrgmState *state;
+ TrgmState *initstate = NULL;
+
+ initStringInfo(&buf);
+
+ appendStringInfoString(&buf, "\ndigraph transformedNFA {\n");
+
+ hash_seq_init(&scan_status, trgmNFA->states);
+ while ((state = (TrgmState *) hash_seq_search(&scan_status)) != NULL)
+ {
+ ListCell *cell;
+
+ appendStringInfo(&buf, "s%d", -state->snumber);
+ if (state->flags & TSTATE_FIN)
+ appendStringInfoString(&buf, " [shape = doublecircle]");
+ if (state->flags & TSTATE_INIT)
+ initstate = state;
+ appendStringInfo(&buf, " [label = \"%d\"]", state->stateKey.nstate);
+ appendStringInfoString(&buf, ";\n");
+
+ foreach(cell, state->arcs)
+ {
+ TrgmArc *arc = (TrgmArc *) lfirst(cell);
+
+ appendStringInfo(&buf, " s%d -> s%d [label = \"",
+ -state->snumber, -arc->target->snumber);
+ printTrgmColor(&buf, arc->ctrgm.colors[0]);
+ appendStringInfoChar(&buf, ' ');
+ printTrgmColor(&buf, arc->ctrgm.colors[1]);
+ appendStringInfoChar(&buf, ' ');
+ printTrgmColor(&buf, arc->ctrgm.colors[2]);
+ appendStringInfoString(&buf, "\"];\n");
+ }
+ }
+
+ if (initstate)
+ {
+ appendStringInfoString(&buf, " node [shape = point ]; initial;\n");
+ appendStringInfo(&buf, " initial -> s%d;\n", -initstate->snumber);
+ }
+
+ appendStringInfoString(&buf, "}\n");
+
+ {
+ /* dot -Tpng -o /tmp/transformed.png < /tmp/transformed.gv */
+ FILE *fp = fopen("/tmp/transformed.gv", "w");
+
+ fprintf(fp, "%s", buf.data);
+ fclose(fp);
+ }
+
+ pfree(buf.data);
+}
+
+/*
+ * Print a TrgmColor readably.
+ */
+static void
+printTrgmColor(StringInfo buf, TrgmColor co)
+{
+ if (co == COLOR_UNKNOWN)
+ appendStringInfoChar(buf, 'u');
+ else if (co == COLOR_BLANK)
+ appendStringInfoChar(buf, 'b');
+ else
+ appendStringInfo(buf, "%d", (int) co);
+}
+
+/*
+ * Print final packed representation of trigram-based expanded graph.
+ */
+static void
+printTrgmPackedGraph(TrgmPackedGraph *packedGraph, TRGM *trigrams)
+{
+ StringInfoData buf;
+ trgm *p;
+ int i;
+
+ initStringInfo(&buf);
+
+ appendStringInfoString(&buf, "\ndigraph packedGraph {\n");
+
+ for (i = 0; i < packedGraph->statesCount; i++)
+ {
+ TrgmPackedState *state = &packedGraph->states[i];
+ int j;
+
+ appendStringInfo(&buf, " s%d", i);
+ if (i == 1)
+ appendStringInfoString(&buf, " [shape = doublecircle]");
+
+ appendStringInfo(&buf, " [label = <s%d>];\n", i);
+
+ for (j = 0; j < state->arcsCount; j++)
+ {
+ TrgmPackedArc *arc = &state->arcs[j];
+
+ appendStringInfo(&buf, " s%d -> s%d [label = \"trigram %d\"];\n",
+ i, arc->targetState, arc->colorTrgm);
+ }
+ }
+
+ appendStringInfoString(&buf, " node [shape = point ]; initial;\n");
+ appendStringInfo(&buf, " initial -> s%d;\n", 0);
+
+ /* Print trigrams */
+ appendStringInfoString(&buf, " { rank = sink;\n");
+ appendStringInfoString(&buf, " Trigrams [shape = none, margin=0, label=<\n");
+
+ p = GETARR(trigrams);
+ for (i = 0; i < packedGraph->colorTrigramsCount; i++)
+ {
+ int count = packedGraph->colorTrigramGroups[i];
+ int j;
+
+ appendStringInfo(&buf, "<br/>Trigram %d: ", i);
+
+ for (j = 0; j < count; j++)
+ {
+ if (j > 0)
+ appendStringInfoString(&buf, ", ");
+
+ /*
+ * XXX This representation is nice only for all-ASCII trigrams.
+ */
+ appendStringInfo(&buf, "\"%c%c%c\"", (*p)[0], (*p)[1], (*p)[2]);
+ p++;
+ }
+ }
+
+ appendStringInfoString(&buf, " >];\n");
+ appendStringInfoString(&buf, " }\n");
+ appendStringInfoString(&buf, "}\n");
+
+ {
+ /* dot -Tpng -o /tmp/packed.png < /tmp/packed.gv */
+ FILE *fp = fopen("/tmp/packed.gv", "w");
+
+ fprintf(fp, "%s", buf.data);
+ fclose(fp);
+ }
+
+ pfree(buf.data);
+}
+
+#endif /* TRGM_REGEXP_DEBUG */