Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 9ff5b69

Browse files
committed
Sync patternsel_common's operator selection logic with pattern_prefix's.
Make patternsel_common() select the comparison operators to use with hardwired logic that matches pattern_prefix()'s new logic, eliminating its dependencies on particular index opfamilies. This shouldn't change any behavior, as it's just replacing runtime operator lookups with the same values hard-wired. But it makes these closely-related functions look more alike, and saving some runtime syscache lookups is worth something. Actually, it's not quite true that this is zero behavioral change: when estimating for a column of type "name", the comparison constant will be kept as "text" not coerced to "name". But that's more correct anyway, and it allows additional simplification of the coercion logic, again syncing this more closely with pattern_prefix(). Per consideration of a report from Manuel Rigger. Discussion: https://postgr.es/m/CA+u7OA7nnGYy8rY0vdTe811NuA+Frr9nbcBO9u2Z+JxqNaud+g@mail.gmail.com
1 parent 9f0f12a commit 9ff5b69

File tree

1 file changed

+58
-61
lines changed

1 file changed

+58
-61
lines changed

src/backend/utils/adt/like_support.c

+58-61
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,8 @@ static Pattern_Prefix_Status pattern_fixed_prefix(Const *patt,
9191
Selectivity *rest_selec);
9292
static Selectivity prefix_selectivity(PlannerInfo *root,
9393
VariableStatData *vardata,
94-
Oid vartype, Oid opfamily, Const *prefixcon);
94+
Oid eqopr, Oid ltopr, Oid geopr,
95+
Const *prefixcon);
9596
static Selectivity like_selectivity(const char *patt, int pattlen,
9697
bool case_insensitive);
9798
static Selectivity regex_selectivity(const char *patt, int pattlen,
@@ -470,7 +471,10 @@ patternsel_common(PlannerInfo *root,
470471
Datum constval;
471472
Oid consttype;
472473
Oid vartype;
473-
Oid opfamily;
474+
Oid rdatatype;
475+
Oid eqopr;
476+
Oid ltopr;
477+
Oid geopr;
474478
Pattern_Prefix_Status pstatus;
475479
Const *patt;
476480
Const *prefix = NULL;
@@ -527,29 +531,51 @@ patternsel_common(PlannerInfo *root,
527531
/*
528532
* Similarly, the exposed type of the left-hand side should be one of
529533
* those we know. (Do not look at vardata.atttype, which might be
530-
* something binary-compatible but different.) We can use it to choose
531-
* the index opfamily from which we must draw the comparison operators.
534+
* something binary-compatible but different.) We can use it to identify
535+
* the comparison operators and the required type of the comparison
536+
* constant, much as in match_pattern_prefix().
532537
*
533-
* NOTE: It would be more correct to use the PATTERN opfamilies than the
534-
* simple ones, but at the moment ANALYZE will not generate statistics for
535-
* the PATTERN operators. But our results are so approximate anyway that
536-
* it probably hardly matters.
538+
* NOTE: this logic does not consider collations. Ideally we'd force use
539+
* of "C" collation, but since ANALYZE only generates statistics for the
540+
* column's specified collation, we have little choice but to use those.
541+
* But our results are so approximate anyway that it probably hardly
542+
* matters.
537543
*/
538544
vartype = vardata.vartype;
539545

540546
switch (vartype)
541547
{
542548
case TEXTOID:
549+
eqopr = TextEqualOperator;
550+
ltopr = TextLessOperator;
551+
geopr = TextGreaterEqualOperator;
552+
rdatatype = TEXTOID;
553+
break;
543554
case NAMEOID:
544-
opfamily = TEXT_BTREE_FAM_OID;
555+
556+
/*
557+
* Note that here, we need the RHS type to be text, so that the
558+
* comparison value isn't improperly truncated to NAMEDATALEN.
559+
*/
560+
eqopr = NameEqualTextOperator;
561+
ltopr = NameLessTextOperator;
562+
geopr = NameGreaterEqualTextOperator;
563+
rdatatype = TEXTOID;
545564
break;
546565
case BPCHAROID:
547-
opfamily = BPCHAR_BTREE_FAM_OID;
566+
eqopr = BpcharEqualOperator;
567+
ltopr = BpcharLessOperator;
568+
geopr = BpcharGreaterEqualOperator;
569+
rdatatype = BPCHAROID;
548570
break;
549571
case BYTEAOID:
550-
opfamily = BYTEA_BTREE_FAM_OID;
572+
eqopr = ByteaEqualOperator;
573+
ltopr = ByteaLessOperator;
574+
geopr = ByteaGreaterEqualOperator;
575+
rdatatype = BYTEAOID;
551576
break;
552577
default:
578+
/* Can't get here unless we're attached to the wrong operator */
553579
ReleaseVariableStats(vardata);
554580
return result;
555581
}
@@ -579,41 +605,23 @@ patternsel_common(PlannerInfo *root,
579605
&prefix, &rest_selec);
580606

581607
/*
582-
* If necessary, coerce the prefix constant to the right type.
608+
* If necessary, coerce the prefix constant to the right type. The only
609+
* case where we need to do anything is when converting text to bpchar.
610+
* Those two types are binary-compatible, so relabeling the Const node is
611+
* sufficient.
583612
*/
584-
if (prefix && prefix->consttype != vartype)
613+
if (prefix && prefix->consttype != rdatatype)
585614
{
586-
char *prefixstr;
587-
588-
switch (prefix->consttype)
589-
{
590-
case TEXTOID:
591-
prefixstr = TextDatumGetCString(prefix->constvalue);
592-
break;
593-
case BYTEAOID:
594-
prefixstr = DatumGetCString(DirectFunctionCall1(byteaout,
595-
prefix->constvalue));
596-
break;
597-
default:
598-
elog(ERROR, "unrecognized consttype: %u",
599-
prefix->consttype);
600-
ReleaseVariableStats(vardata);
601-
return result;
602-
}
603-
prefix = string_to_const(prefixstr, vartype);
604-
pfree(prefixstr);
615+
Assert(prefix->consttype == TEXTOID &&
616+
rdatatype == BPCHAROID);
617+
prefix->consttype = rdatatype;
605618
}
606619

607620
if (pstatus == Pattern_Prefix_Exact)
608621
{
609622
/*
610-
* Pattern specifies an exact match, so pretend operator is '='
623+
* Pattern specifies an exact match, so estimate as for '='
611624
*/
612-
Oid eqopr = get_opfamily_member(opfamily, vartype, vartype,
613-
BTEqualStrategyNumber);
614-
615-
if (eqopr == InvalidOid)
616-
elog(ERROR, "no = operator for opfamily %u", opfamily);
617625
result = var_eq_const(&vardata, eqopr, prefix->constvalue,
618626
false, true, false);
619627
}
@@ -656,8 +664,9 @@ patternsel_common(PlannerInfo *root,
656664
Selectivity prefixsel;
657665

658666
if (pstatus == Pattern_Prefix_Partial)
659-
prefixsel = prefix_selectivity(root, &vardata, vartype,
660-
opfamily, prefix);
667+
prefixsel = prefix_selectivity(root, &vardata,
668+
eqopr, ltopr, geopr,
669+
prefix);
661670
else
662671
prefixsel = 1.0;
663672
heursel = prefixsel * rest_selec;
@@ -1181,15 +1190,14 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype, Oid collation,
11811190
* Estimate the selectivity of a fixed prefix for a pattern match.
11821191
*
11831192
* A fixed prefix "foo" is estimated as the selectivity of the expression
1184-
* "variable >= 'foo' AND variable < 'fop'" (see also indxpath.c).
1193+
* "variable >= 'foo' AND variable < 'fop'".
11851194
*
11861195
* The selectivity estimate is with respect to the portion of the column
11871196
* population represented by the histogram --- the caller must fold this
11881197
* together with info about MCVs and NULLs.
11891198
*
1190-
* We use the >= and < operators from the specified btree opfamily to do the
1191-
* estimation. The given variable and Const must be of the associated
1192-
* datatype.
1199+
* We use the specified btree comparison operators to do the estimation.
1200+
* The given variable and Const must be of the associated datatype(s).
11931201
*
11941202
* XXX Note: we make use of the upper bound to estimate operator selectivity
11951203
* even if the locale is such that we cannot rely on the upper-bound string.
@@ -1198,20 +1206,17 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype, Oid collation,
11981206
*/
11991207
static Selectivity
12001208
prefix_selectivity(PlannerInfo *root, VariableStatData *vardata,
1201-
Oid vartype, Oid opfamily, Const *prefixcon)
1209+
Oid eqopr, Oid ltopr, Oid geopr,
1210+
Const *prefixcon)
12021211
{
12031212
Selectivity prefixsel;
1204-
Oid cmpopr;
12051213
FmgrInfo opproc;
12061214
AttStatsSlot sslot;
12071215
Const *greaterstrcon;
12081216
Selectivity eq_sel;
12091217

1210-
cmpopr = get_opfamily_member(opfamily, vartype, vartype,
1211-
BTGreaterEqualStrategyNumber);
1212-
if (cmpopr == InvalidOid)
1213-
elog(ERROR, "no >= operator for opfamily %u", opfamily);
1214-
fmgr_info(get_opcode(cmpopr), &opproc);
1218+
/* Estimate the selectivity of "x >= prefix" */
1219+
fmgr_info(get_opcode(geopr), &opproc);
12151220

12161221
prefixsel = ineq_histogram_selectivity(root, vardata,
12171222
&opproc, true, true,
@@ -1237,11 +1242,7 @@ prefix_selectivity(PlannerInfo *root, VariableStatData *vardata,
12371242
/* sslot.stacoll is set up */ ;
12381243
else
12391244
sslot.stacoll = DEFAULT_COLLATION_OID;
1240-
cmpopr = get_opfamily_member(opfamily, vartype, vartype,
1241-
BTLessStrategyNumber);
1242-
if (cmpopr == InvalidOid)
1243-
elog(ERROR, "no < operator for opfamily %u", opfamily);
1244-
fmgr_info(get_opcode(cmpopr), &opproc);
1245+
fmgr_info(get_opcode(ltopr), &opproc);
12451246
greaterstrcon = make_greater_string(prefixcon, &opproc, sslot.stacoll);
12461247
if (greaterstrcon)
12471248
{
@@ -1277,11 +1278,7 @@ prefix_selectivity(PlannerInfo *root, VariableStatData *vardata,
12771278
* probably off the end of the histogram, and thus we probably got a very
12781279
* small estimate from the >= condition; so we still need to clamp.
12791280
*/
1280-
cmpopr = get_opfamily_member(opfamily, vartype, vartype,
1281-
BTEqualStrategyNumber);
1282-
if (cmpopr == InvalidOid)
1283-
elog(ERROR, "no = operator for opfamily %u", opfamily);
1284-
eq_sel = var_eq_const(vardata, cmpopr, prefixcon->constvalue,
1281+
eq_sel = var_eq_const(vardata, eqopr, prefixcon->constvalue,
12851282
false, true, false);
12861283

12871284
prefixsel = Max(prefixsel, eq_sel);

0 commit comments

Comments
 (0)