@@ -167,7 +167,7 @@ static double eqjoinsel_semi(Oid operator,
167
167
static bool convert_to_scalar (Datum value , Oid valuetypid , double * scaledvalue ,
168
168
Datum lobound , Datum hibound , Oid boundstypid ,
169
169
double * scaledlobound , double * scaledhibound );
170
- static double convert_numeric_to_scalar (Datum value , Oid typid );
170
+ static double convert_numeric_to_scalar (Datum value , Oid typid , bool * failure );
171
171
static void convert_string_to_scalar (char * value ,
172
172
double * scaledvalue ,
173
173
char * lobound ,
@@ -184,8 +184,9 @@ static double convert_one_string_to_scalar(char *value,
184
184
int rangelo , int rangehi );
185
185
static double convert_one_bytea_to_scalar (unsigned char * value , int valuelen ,
186
186
int rangelo , int rangehi );
187
- static char * convert_string_datum (Datum value , Oid typid );
188
- static double convert_timevalue_to_scalar (Datum value , Oid typid );
187
+ static char * convert_string_datum (Datum value , Oid typid , bool * failure );
188
+ static double convert_timevalue_to_scalar (Datum value , Oid typid ,
189
+ bool * failure );
189
190
static void examine_simple_variable (PlannerInfo * root , Var * var ,
190
191
VariableStatData * vardata );
191
192
static bool get_variable_range (PlannerInfo * root , VariableStatData * vardata ,
@@ -530,7 +531,8 @@ neqsel(PG_FUNCTION_ARGS)
530
531
*
531
532
* This routine works for any datatype (or pair of datatypes) known to
532
533
* convert_to_scalar(). If it is applied to some other datatype,
533
- * it will return a default estimate.
534
+ * it will return an approximate estimate based on assuming that the constant
535
+ * value falls in the middle of the bin identified by binary search.
534
536
*/
535
537
static double
536
538
scalarineqsel (PlannerInfo * root , Oid operator , bool isgt ,
@@ -3707,10 +3709,15 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3707
3709
Datum lobound , Datum hibound , Oid boundstypid ,
3708
3710
double * scaledlobound , double * scaledhibound )
3709
3711
{
3712
+ bool failure = false;
3713
+
3710
3714
/*
3711
3715
* Both the valuetypid and the boundstypid should exactly match the
3712
- * declared input type(s) of the operator we are invoked for, so we just
3713
- * error out if either is not recognized.
3716
+ * declared input type(s) of the operator we are invoked for. However,
3717
+ * extensions might try to use scalarineqsel as estimator for operators
3718
+ * with input type(s) we don't handle here; in such cases, we want to
3719
+ * return false, not fail. In any case, we mustn't assume that valuetypid
3720
+ * and boundstypid are identical.
3714
3721
*
3715
3722
* XXX The histogram we are interpolating between points of could belong
3716
3723
* to a column that's only binary-compatible with the declared type. In
@@ -3745,10 +3752,13 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3745
3752
case REGDICTIONARYOID :
3746
3753
case REGROLEOID :
3747
3754
case REGNAMESPACEOID :
3748
- * scaledvalue = convert_numeric_to_scalar (value , valuetypid );
3749
- * scaledlobound = convert_numeric_to_scalar (lobound , boundstypid );
3750
- * scaledhibound = convert_numeric_to_scalar (hibound , boundstypid );
3751
- return true;
3755
+ * scaledvalue = convert_numeric_to_scalar (value , valuetypid ,
3756
+ & failure );
3757
+ * scaledlobound = convert_numeric_to_scalar (lobound , boundstypid ,
3758
+ & failure );
3759
+ * scaledhibound = convert_numeric_to_scalar (hibound , boundstypid ,
3760
+ & failure );
3761
+ return !failure ;
3752
3762
3753
3763
/*
3754
3764
* Built-in string types
@@ -3759,9 +3769,20 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3759
3769
case TEXTOID :
3760
3770
case NAMEOID :
3761
3771
{
3762
- char * valstr = convert_string_datum (value , valuetypid );
3763
- char * lostr = convert_string_datum (lobound , boundstypid );
3764
- char * histr = convert_string_datum (hibound , boundstypid );
3772
+ char * valstr = convert_string_datum (value , valuetypid ,
3773
+ & failure );
3774
+ char * lostr = convert_string_datum (lobound , boundstypid ,
3775
+ & failure );
3776
+ char * histr = convert_string_datum (hibound , boundstypid ,
3777
+ & failure );
3778
+
3779
+ /*
3780
+ * Bail out if any of the values is not of string type. We
3781
+ * might leak converted strings for the other value(s), but
3782
+ * that's not worth troubling over.
3783
+ */
3784
+ if (failure )
3785
+ return false;
3765
3786
3766
3787
convert_string_to_scalar (valstr , scaledvalue ,
3767
3788
lostr , scaledlobound ,
@@ -3777,6 +3798,9 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3777
3798
*/
3778
3799
case BYTEAOID :
3779
3800
{
3801
+ /* We only support bytea vs bytea comparison */
3802
+ if (boundstypid != BYTEAOID )
3803
+ return false;
3780
3804
convert_bytea_to_scalar (value , scaledvalue ,
3781
3805
lobound , scaledlobound ,
3782
3806
hibound , scaledhibound );
@@ -3795,21 +3819,27 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3795
3819
case TINTERVALOID :
3796
3820
case TIMEOID :
3797
3821
case TIMETZOID :
3798
- * scaledvalue = convert_timevalue_to_scalar (value , valuetypid );
3799
- * scaledlobound = convert_timevalue_to_scalar (lobound , boundstypid );
3800
- * scaledhibound = convert_timevalue_to_scalar (hibound , boundstypid );
3801
- return true;
3822
+ * scaledvalue = convert_timevalue_to_scalar (value , valuetypid ,
3823
+ & failure );
3824
+ * scaledlobound = convert_timevalue_to_scalar (lobound , boundstypid ,
3825
+ & failure );
3826
+ * scaledhibound = convert_timevalue_to_scalar (hibound , boundstypid ,
3827
+ & failure );
3828
+ return !failure ;
3802
3829
3803
3830
/*
3804
3831
* Built-in network types
3805
3832
*/
3806
3833
case INETOID :
3807
3834
case CIDROID :
3808
3835
case MACADDROID :
3809
- * scaledvalue = convert_network_to_scalar (value , valuetypid );
3810
- * scaledlobound = convert_network_to_scalar (lobound , boundstypid );
3811
- * scaledhibound = convert_network_to_scalar (hibound , boundstypid );
3812
- return true;
3836
+ * scaledvalue = convert_network_to_scalar (value , valuetypid ,
3837
+ & failure );
3838
+ * scaledlobound = convert_network_to_scalar (lobound , boundstypid ,
3839
+ & failure );
3840
+ * scaledhibound = convert_network_to_scalar (hibound , boundstypid ,
3841
+ & failure );
3842
+ return !failure ;
3813
3843
}
3814
3844
/* Don't know how to convert */
3815
3845
* scaledvalue = * scaledlobound = * scaledhibound = 0 ;
@@ -3818,9 +3848,12 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3818
3848
3819
3849
/*
3820
3850
* Do convert_to_scalar()'s work for any numeric data type.
3851
+ *
3852
+ * On failure (e.g., unsupported typid), set *failure to true;
3853
+ * otherwise, that variable is not changed.
3821
3854
*/
3822
3855
static double
3823
- convert_numeric_to_scalar (Datum value , Oid typid )
3856
+ convert_numeric_to_scalar (Datum value , Oid typid , bool * failure )
3824
3857
{
3825
3858
switch (typid )
3826
3859
{
@@ -3856,11 +3889,7 @@ convert_numeric_to_scalar(Datum value, Oid typid)
3856
3889
return (double ) DatumGetObjectId (value );
3857
3890
}
3858
3891
3859
- /*
3860
- * Can't get here unless someone tries to use scalarltsel/scalargtsel on
3861
- * an operator with one numeric and one non-numeric operand.
3862
- */
3863
- elog (ERROR , "unsupported type: %u" , typid );
3892
+ * failure = true;
3864
3893
return 0 ;
3865
3894
}
3866
3895
@@ -4009,11 +4038,14 @@ convert_one_string_to_scalar(char *value, int rangelo, int rangehi)
4009
4038
/*
4010
4039
* Convert a string-type Datum into a palloc'd, null-terminated string.
4011
4040
*
4041
+ * On failure (e.g., unsupported typid), set *failure to true;
4042
+ * otherwise, that variable is not changed. (We'll return NULL on failure.)
4043
+ *
4012
4044
* When using a non-C locale, we must pass the string through strxfrm()
4013
4045
* before continuing, so as to generate correct locale-specific results.
4014
4046
*/
4015
4047
static char *
4016
- convert_string_datum (Datum value , Oid typid )
4048
+ convert_string_datum (Datum value , Oid typid , bool * failure )
4017
4049
{
4018
4050
char * val ;
4019
4051
@@ -4037,12 +4069,7 @@ convert_string_datum(Datum value, Oid typid)
4037
4069
break ;
4038
4070
}
4039
4071
default :
4040
-
4041
- /*
4042
- * Can't get here unless someone tries to use scalarltsel on an
4043
- * operator with one string and one non-string operand.
4044
- */
4045
- elog (ERROR , "unsupported type: %u" , typid );
4072
+ * failure = true;
4046
4073
return NULL ;
4047
4074
}
4048
4075
@@ -4119,16 +4146,19 @@ convert_bytea_to_scalar(Datum value,
4119
4146
Datum hibound ,
4120
4147
double * scaledhibound )
4121
4148
{
4149
+ bytea * valuep = DatumGetByteaPP (value );
4150
+ bytea * loboundp = DatumGetByteaPP (lobound );
4151
+ bytea * hiboundp = DatumGetByteaPP (hibound );
4122
4152
int rangelo ,
4123
4153
rangehi ,
4124
- valuelen = VARSIZE ( DatumGetPointer ( value )) - VARHDRSZ ,
4125
- loboundlen = VARSIZE ( DatumGetPointer ( lobound )) - VARHDRSZ ,
4126
- hiboundlen = VARSIZE ( DatumGetPointer ( hibound )) - VARHDRSZ ,
4154
+ valuelen = VARSIZE_ANY_EXHDR ( valuep ) ,
4155
+ loboundlen = VARSIZE_ANY_EXHDR ( loboundp ) ,
4156
+ hiboundlen = VARSIZE_ANY_EXHDR ( hiboundp ) ,
4127
4157
i ,
4128
4158
minlen ;
4129
- unsigned char * valstr = (unsigned char * ) VARDATA ( DatumGetPointer ( value )),
4130
- * lostr = (unsigned char * ) VARDATA ( DatumGetPointer ( lobound )),
4131
- * histr = (unsigned char * ) VARDATA ( DatumGetPointer ( hibound ) );
4159
+ unsigned char * valstr = (unsigned char * ) VARDATA_ANY ( valuep );
4160
+ unsigned char * lostr = (unsigned char * ) VARDATA_ANY ( loboundp );
4161
+ unsigned char * histr = (unsigned char * ) VARDATA_ANY ( hiboundp );
4132
4162
4133
4163
/*
4134
4164
* Assume bytea data is uniformly distributed across all byte values.
@@ -4195,9 +4225,12 @@ convert_one_bytea_to_scalar(unsigned char *value, int valuelen,
4195
4225
4196
4226
/*
4197
4227
* Do convert_to_scalar()'s work for any timevalue data type.
4228
+ *
4229
+ * On failure (e.g., unsupported typid), set *failure to true;
4230
+ * otherwise, that variable is not changed.
4198
4231
*/
4199
4232
static double
4200
- convert_timevalue_to_scalar (Datum value , Oid typid )
4233
+ convert_timevalue_to_scalar (Datum value , Oid typid , bool * failure )
4201
4234
{
4202
4235
switch (typid )
4203
4236
{
@@ -4261,11 +4294,7 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
4261
4294
}
4262
4295
}
4263
4296
4264
- /*
4265
- * Can't get here unless someone tries to use scalarltsel/scalargtsel on
4266
- * an operator with one timevalue and one non-timevalue operand.
4267
- */
4268
- elog (ERROR , "unsupported type: %u" , typid );
4297
+ * failure = true;
4269
4298
return 0 ;
4270
4299
}
4271
4300
0 commit comments