24
24
#include "catalog/pg_opfamily.h"
25
25
#include "catalog/pg_type.h"
26
26
#include "nodes/makefuncs.h"
27
- #include "nodes/nodeFuncs.h"
28
27
#include "optimizer/clauses.h"
29
28
#include "optimizer/cost.h"
30
29
#include "optimizer/pathnode.h"
@@ -101,6 +100,7 @@ static bool is_indexable_operator(Oid expr_op, Oid opfamily,
101
100
static bool match_rowcompare_to_indexcol (IndexOptInfo * index ,
102
101
int indexcol ,
103
102
Oid opfamily ,
103
+ Oid idxcollation ,
104
104
RowCompareExpr * clause ,
105
105
Relids outer_relids );
106
106
static List * match_index_to_pathkeys (IndexOptInfo * index , List * pathkeys );
@@ -113,11 +113,13 @@ static List *find_clauses_for_join(PlannerInfo *root, RelOptInfo *rel,
113
113
Relids outer_relids , bool isouterjoin );
114
114
static bool match_boolean_index_clause (Node * clause , int indexcol ,
115
115
IndexOptInfo * index );
116
- static bool match_special_index_operator (Expr * clause , Oid idxcolcollation , Oid opfamily ,
116
+ static bool match_special_index_operator (Expr * clause ,
117
+ Oid opfamily , Oid idxcollation ,
117
118
bool indexkey_on_left );
118
119
static Expr * expand_boolean_index_clause (Node * clause , int indexcol ,
119
120
IndexOptInfo * index );
120
- static List * expand_indexqual_opclause (RestrictInfo * rinfo , Oid opfamily , Oid collation );
121
+ static List * expand_indexqual_opclause (RestrictInfo * rinfo ,
122
+ Oid opfamily , Oid idxcollation );
121
123
static RestrictInfo * expand_indexqual_rowcompare (RestrictInfo * rinfo ,
122
124
IndexOptInfo * index ,
123
125
int indexcol );
@@ -1158,7 +1160,7 @@ group_clauses_by_indexkey(IndexOptInfo *index,
1158
1160
* operator for this column, or is a "special" operator as recognized
1159
1161
* by match_special_index_operator();
1160
1162
* and
1161
- * (3) must match the collation of the index.
1163
+ * (3) must match the collation of the index, if collation is relevant .
1162
1164
*
1163
1165
* Our definition of "const" is pretty liberal: we allow Vars belonging
1164
1166
* to the caller-specified outer_relids relations (which had better not
@@ -1215,7 +1217,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
1215
1217
{
1216
1218
Expr * clause = rinfo -> clause ;
1217
1219
Oid opfamily = index -> opfamily [indexcol ];
1218
- Oid collation = index -> indexcollations [indexcol ];
1220
+ Oid idxcollation = index -> indexcollations [indexcol ];
1219
1221
Node * leftop ,
1220
1222
* rightop ;
1221
1223
Relids left_relids ;
@@ -1276,7 +1278,8 @@ match_clause_to_indexcol(IndexOptInfo *index,
1276
1278
}
1277
1279
else if (clause && IsA (clause , RowCompareExpr ))
1278
1280
{
1279
- return match_rowcompare_to_indexcol (index , indexcol , opfamily ,
1281
+ return match_rowcompare_to_indexcol (index , indexcol ,
1282
+ opfamily , idxcollation ,
1280
1283
(RowCompareExpr * ) clause ,
1281
1284
outer_relids );
1282
1285
}
@@ -1300,7 +1303,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
1300
1303
bms_is_subset (right_relids , outer_relids ) &&
1301
1304
!contain_volatile_functions (rightop ))
1302
1305
{
1303
- if (collation == expr_coll &&
1306
+ if (idxcollation == expr_coll &&
1304
1307
is_indexable_operator (expr_op , opfamily , true))
1305
1308
return true;
1306
1309
@@ -1309,7 +1312,7 @@ match_clause_to_indexcol(IndexOptInfo *index,
1309
1312
* is a "special" indexable operator.
1310
1313
*/
1311
1314
if (plain_op &&
1312
- match_special_index_operator (clause , collation , opfamily , true))
1315
+ match_special_index_operator (clause , opfamily , idxcollation , true))
1313
1316
return true;
1314
1317
return false;
1315
1318
}
@@ -1319,15 +1322,15 @@ match_clause_to_indexcol(IndexOptInfo *index,
1319
1322
bms_is_subset (left_relids , outer_relids ) &&
1320
1323
!contain_volatile_functions (leftop ))
1321
1324
{
1322
- if (collation == expr_coll &&
1325
+ if (idxcollation == expr_coll &&
1323
1326
is_indexable_operator (expr_op , opfamily , false))
1324
1327
return true;
1325
1328
1326
1329
/*
1327
1330
* If we didn't find a member of the index's opfamily, see whether it
1328
1331
* is a "special" indexable operator.
1329
1332
*/
1330
- if (match_special_index_operator (clause , collation , opfamily , false))
1333
+ if (match_special_index_operator (clause , opfamily , idxcollation , false))
1331
1334
return true;
1332
1335
return false;
1333
1336
}
@@ -1367,12 +1370,14 @@ static bool
1367
1370
match_rowcompare_to_indexcol (IndexOptInfo * index ,
1368
1371
int indexcol ,
1369
1372
Oid opfamily ,
1373
+ Oid idxcollation ,
1370
1374
RowCompareExpr * clause ,
1371
1375
Relids outer_relids )
1372
1376
{
1373
1377
Node * leftop ,
1374
1378
* rightop ;
1375
1379
Oid expr_op ;
1380
+ Oid expr_coll ;
1376
1381
1377
1382
/* Forget it if we're not dealing with a btree index */
1378
1383
if (index -> relam != BTREE_AM_OID )
@@ -1391,6 +1396,11 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
1391
1396
leftop = (Node * ) linitial (clause -> largs );
1392
1397
rightop = (Node * ) linitial (clause -> rargs );
1393
1398
expr_op = linitial_oid (clause -> opnos );
1399
+ expr_coll = linitial_oid (clause -> inputcollids );
1400
+
1401
+ /* Collations must match */
1402
+ if (expr_coll != idxcollation )
1403
+ return false;
1394
1404
1395
1405
/*
1396
1406
* These syntactic tests are the same as in match_clause_to_indexcol()
@@ -1413,9 +1423,6 @@ match_rowcompare_to_indexcol(IndexOptInfo *index,
1413
1423
else
1414
1424
return false;
1415
1425
1416
- if (index -> indexcollations [indexcol ] != linitial_oid (clause -> inputcollids ))
1417
- return false;
1418
-
1419
1426
/* We're good if the operator is the right type of opfamily member */
1420
1427
switch (get_op_opfamily_strategy (expr_op , opfamily ))
1421
1428
{
@@ -1525,6 +1532,12 @@ match_index_to_pathkeys(IndexOptInfo *index, List *pathkeys)
1525
1532
* 'clause' is the ordering expression to be tested.
1526
1533
* 'pk_opfamily' is the btree opfamily describing the required sort order.
1527
1534
*
1535
+ * Note that we currently do not consider the collation of the ordering
1536
+ * operator's result. In practical cases the result type will be numeric
1537
+ * and thus have no collation, and it's not very clear what to match to
1538
+ * if it did have a collation. The index's collation should match the
1539
+ * ordering operator's input collation, not its result.
1540
+ *
1528
1541
* If successful, return 'clause' as-is if the indexkey is on the left,
1529
1542
* otherwise a commuted copy of 'clause'. If no match, return NULL.
1530
1543
*/
@@ -1535,9 +1548,11 @@ match_clause_to_ordering_op(IndexOptInfo *index,
1535
1548
Oid pk_opfamily )
1536
1549
{
1537
1550
Oid opfamily = index -> opfamily [indexcol ];
1551
+ Oid idxcollation = index -> indexcollations [indexcol ];
1538
1552
Node * leftop ,
1539
1553
* rightop ;
1540
1554
Oid expr_op ;
1555
+ Oid expr_coll ;
1541
1556
Oid sortfamily ;
1542
1557
bool commuted ;
1543
1558
@@ -1551,6 +1566,13 @@ match_clause_to_ordering_op(IndexOptInfo *index,
1551
1566
if (!leftop || !rightop )
1552
1567
return NULL ;
1553
1568
expr_op = ((OpExpr * ) clause )-> opno ;
1569
+ expr_coll = ((OpExpr * ) clause )-> inputcollid ;
1570
+
1571
+ /*
1572
+ * We can forget the whole thing right away if wrong collation.
1573
+ */
1574
+ if (expr_coll != idxcollation )
1575
+ return NULL ;
1554
1576
1555
1577
/*
1556
1578
* Check for clauses of the form: (indexkey operator constant) or
@@ -2175,6 +2197,12 @@ relation_has_unique_index_for(PlannerInfo *root, RelOptInfo *rel,
2175
2197
if (!list_member_oid (rinfo -> mergeopfamilies , ind -> opfamily [c ]))
2176
2198
continue ;
2177
2199
2200
+ /*
2201
+ * XXX at some point we may need to check collations here
2202
+ * too. For the moment we assume all collations reduce to
2203
+ * the same notion of equality.
2204
+ */
2205
+
2178
2206
/* OK, see if the condition operand matches the index key */
2179
2207
if (rinfo -> outer_is_left )
2180
2208
rexpr = get_rightop (rinfo -> clause );
@@ -2235,6 +2263,9 @@ flatten_clausegroups_list(List *clausegroups)
2235
2263
* operand: the nodetree to be compared to the index
2236
2264
* indexcol: the column number of the index (counting from 0)
2237
2265
* index: the index of interest
2266
+ *
2267
+ * Note that we aren't interested in collations here; the caller must check
2268
+ * for a collation match, if it's dealing with an operator where that matters.
2238
2269
*/
2239
2270
bool
2240
2271
match_index_to_operand (Node * operand ,
@@ -2409,7 +2440,7 @@ match_boolean_index_clause(Node *clause,
2409
2440
* Return 'true' if we can do something with it anyway.
2410
2441
*/
2411
2442
static bool
2412
- match_special_index_operator (Expr * clause , Oid idxcolcollation , Oid opfamily ,
2443
+ match_special_index_operator (Expr * clause , Oid opfamily , Oid idxcollation ,
2413
2444
bool indexkey_on_left )
2414
2445
{
2415
2446
bool isIndexable = false;
@@ -2513,7 +2544,10 @@ match_special_index_operator(Expr *clause, Oid idxcolcollation, Oid opfamily,
2513
2544
*
2514
2545
* The non-pattern opclasses will not sort the way we need in most non-C
2515
2546
* locales. We can use such an index anyway for an exact match (simple
2516
- * equality), but not for prefix-match cases.
2547
+ * equality), but not for prefix-match cases. Note that we are looking
2548
+ * at the index's collation, not the expression's collation -- this test
2549
+ * is not dependent on the LIKE/regex operator's collation (which would
2550
+ * only affect case folding behavior of ILIKE, anyway).
2517
2551
*/
2518
2552
switch (expr_op )
2519
2553
{
@@ -2524,7 +2558,7 @@ match_special_index_operator(Expr *clause, Oid idxcolcollation, Oid opfamily,
2524
2558
isIndexable =
2525
2559
(opfamily == TEXT_PATTERN_BTREE_FAM_OID ) ||
2526
2560
(opfamily == TEXT_BTREE_FAM_OID &&
2527
- (pstatus == Pattern_Prefix_Exact || lc_collate_is_c (idxcolcollation )));
2561
+ (pstatus == Pattern_Prefix_Exact || lc_collate_is_c (idxcollation )));
2528
2562
break ;
2529
2563
2530
2564
case OID_BPCHAR_LIKE_OP :
@@ -2534,7 +2568,7 @@ match_special_index_operator(Expr *clause, Oid idxcolcollation, Oid opfamily,
2534
2568
isIndexable =
2535
2569
(opfamily == BPCHAR_PATTERN_BTREE_FAM_OID ) ||
2536
2570
(opfamily == BPCHAR_BTREE_FAM_OID &&
2537
- (pstatus == Pattern_Prefix_Exact || lc_collate_is_c (idxcolcollation )));
2571
+ (pstatus == Pattern_Prefix_Exact || lc_collate_is_c (idxcollation )));
2538
2572
break ;
2539
2573
2540
2574
case OID_NAME_LIKE_OP :
@@ -2555,25 +2589,6 @@ match_special_index_operator(Expr *clause, Oid idxcolcollation, Oid opfamily,
2555
2589
break ;
2556
2590
}
2557
2591
2558
- if (!isIndexable )
2559
- return false;
2560
-
2561
- /*
2562
- * For case-insensitive matching, we also need to check that the
2563
- * collations match.
2564
- */
2565
- switch (expr_op )
2566
- {
2567
- case OID_TEXT_ICLIKE_OP :
2568
- case OID_TEXT_ICREGEXEQ_OP :
2569
- case OID_BPCHAR_ICLIKE_OP :
2570
- case OID_BPCHAR_ICREGEXEQ_OP :
2571
- case OID_NAME_ICLIKE_OP :
2572
- case OID_NAME_ICREGEXEQ_OP :
2573
- isIndexable = (idxcolcollation == exprCollation ((Node * ) clause ));
2574
- break ;
2575
- }
2576
-
2577
2592
return isIndexable ;
2578
2593
}
2579
2594
@@ -2747,7 +2762,7 @@ expand_boolean_index_clause(Node *clause,
2747
2762
* expand special cases that were accepted by match_special_index_operator().
2748
2763
*/
2749
2764
static List *
2750
- expand_indexqual_opclause (RestrictInfo * rinfo , Oid opfamily , Oid collation )
2765
+ expand_indexqual_opclause (RestrictInfo * rinfo , Oid opfamily , Oid idxcollation )
2751
2766
{
2752
2767
Expr * clause = rinfo -> clause ;
2753
2768
@@ -2778,7 +2793,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid collation)
2778
2793
{
2779
2794
pstatus = pattern_fixed_prefix (patt , Pattern_Type_Like ,
2780
2795
& prefix , & rest );
2781
- return prefix_quals (leftop , opfamily , collation , prefix , pstatus );
2796
+ return prefix_quals (leftop , opfamily , idxcollation , prefix , pstatus );
2782
2797
}
2783
2798
break ;
2784
2799
@@ -2790,7 +2805,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid collation)
2790
2805
/* the right-hand const is type text for all of these */
2791
2806
pstatus = pattern_fixed_prefix (patt , Pattern_Type_Like_IC ,
2792
2807
& prefix , & rest );
2793
- return prefix_quals (leftop , opfamily , collation , prefix , pstatus );
2808
+ return prefix_quals (leftop , opfamily , idxcollation , prefix , pstatus );
2794
2809
}
2795
2810
break ;
2796
2811
@@ -2802,7 +2817,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid collation)
2802
2817
/* the right-hand const is type text for all of these */
2803
2818
pstatus = pattern_fixed_prefix (patt , Pattern_Type_Regex ,
2804
2819
& prefix , & rest );
2805
- return prefix_quals (leftop , opfamily , collation , prefix , pstatus );
2820
+ return prefix_quals (leftop , opfamily , idxcollation , prefix , pstatus );
2806
2821
}
2807
2822
break ;
2808
2823
@@ -2814,7 +2829,7 @@ expand_indexqual_opclause(RestrictInfo *rinfo, Oid opfamily, Oid collation)
2814
2829
/* the right-hand const is type text for all of these */
2815
2830
pstatus = pattern_fixed_prefix (patt , Pattern_Type_Regex_IC ,
2816
2831
& prefix , & rest );
2817
- return prefix_quals (leftop , opfamily , collation , prefix , pstatus );
2832
+ return prefix_quals (leftop , opfamily , idxcollation , prefix , pstatus );
2818
2833
}
2819
2834
break ;
2820
2835
@@ -2965,6 +2980,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
2965
2980
largs_cell = lnext (largs_cell );
2966
2981
rargs_cell = lnext (rargs_cell );
2967
2982
opnos_cell = lnext (opnos_cell );
2983
+ collids_cell = lnext (collids_cell );
2968
2984
}
2969
2985
2970
2986
/* Return clause as-is if it's all usable as index quals */
@@ -3158,7 +3174,10 @@ prefix_quals(Node *leftop, Oid opfamily, Oid collation,
3158
3174
3159
3175
/*-------
3160
3176
* If we can create a string larger than the prefix, we can say
3161
- * "x < greaterstr".
3177
+ * "x < greaterstr". NB: we rely on make_greater_string() to generate
3178
+ * a guaranteed-greater string, not just a probably-greater string.
3179
+ * In general this is only guaranteed in C locale, so we'd better be
3180
+ * using a C-locale index collation.
3162
3181
*-------
3163
3182
*/
3164
3183
oproid = get_opfamily_member (opfamily , datatype , datatype ,
0 commit comments