@@ -164,7 +164,7 @@ static double eqjoinsel_semi(Oid operator,
164
164
static bool convert_to_scalar (Datum value , Oid valuetypid , double * scaledvalue ,
165
165
Datum lobound , Datum hibound , Oid boundstypid ,
166
166
double * scaledlobound , double * scaledhibound );
167
- static double convert_numeric_to_scalar (Datum value , Oid typid );
167
+ static double convert_numeric_to_scalar (Datum value , Oid typid , bool * failure );
168
168
static void convert_string_to_scalar (char * value ,
169
169
double * scaledvalue ,
170
170
char * lobound ,
@@ -181,8 +181,9 @@ static double convert_one_string_to_scalar(char *value,
181
181
int rangelo , int rangehi );
182
182
static double convert_one_bytea_to_scalar (unsigned char * value , int valuelen ,
183
183
int rangelo , int rangehi );
184
- static char * convert_string_datum (Datum value , Oid typid );
185
- static double convert_timevalue_to_scalar (Datum value , Oid typid );
184
+ static char * convert_string_datum (Datum value , Oid typid , bool * failure );
185
+ static double convert_timevalue_to_scalar (Datum value , Oid typid ,
186
+ bool * failure );
186
187
static void examine_simple_variable (PlannerInfo * root , Var * var ,
187
188
VariableStatData * vardata );
188
189
static bool get_variable_range (PlannerInfo * root , VariableStatData * vardata ,
@@ -527,7 +528,8 @@ neqsel(PG_FUNCTION_ARGS)
527
528
*
528
529
* This routine works for any datatype (or pair of datatypes) known to
529
530
* convert_to_scalar(). If it is applied to some other datatype,
530
- * it will return a default estimate.
531
+ * it will return an approximate estimate based on assuming that the constant
532
+ * value falls in the middle of the bin identified by binary search.
531
533
*/
532
534
static double
533
535
scalarineqsel (PlannerInfo * root , Oid operator , bool isgt ,
@@ -3605,10 +3607,15 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3605
3607
Datum lobound , Datum hibound , Oid boundstypid ,
3606
3608
double * scaledlobound , double * scaledhibound )
3607
3609
{
3610
+ bool failure = false;
3611
+
3608
3612
/*
3609
3613
* Both the valuetypid and the boundstypid should exactly match the
3610
- * declared input type(s) of the operator we are invoked for, so we just
3611
- * error out if either is not recognized.
3614
+ * declared input type(s) of the operator we are invoked for. However,
3615
+ * extensions might try to use scalarineqsel as estimator for operators
3616
+ * with input type(s) we don't handle here; in such cases, we want to
3617
+ * return false, not fail. In any case, we mustn't assume that valuetypid
3618
+ * and boundstypid are identical.
3612
3619
*
3613
3620
* XXX The histogram we are interpolating between points of could belong
3614
3621
* to a column that's only binary-compatible with the declared type. In
@@ -3641,10 +3648,13 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3641
3648
case REGTYPEOID :
3642
3649
case REGCONFIGOID :
3643
3650
case REGDICTIONARYOID :
3644
- * scaledvalue = convert_numeric_to_scalar (value , valuetypid );
3645
- * scaledlobound = convert_numeric_to_scalar (lobound , boundstypid );
3646
- * scaledhibound = convert_numeric_to_scalar (hibound , boundstypid );
3647
- return true;
3651
+ * scaledvalue = convert_numeric_to_scalar (value , valuetypid ,
3652
+ & failure );
3653
+ * scaledlobound = convert_numeric_to_scalar (lobound , boundstypid ,
3654
+ & failure );
3655
+ * scaledhibound = convert_numeric_to_scalar (hibound , boundstypid ,
3656
+ & failure );
3657
+ return !failure ;
3648
3658
3649
3659
/*
3650
3660
* Built-in string types
@@ -3655,9 +3665,20 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3655
3665
case TEXTOID :
3656
3666
case NAMEOID :
3657
3667
{
3658
- char * valstr = convert_string_datum (value , valuetypid );
3659
- char * lostr = convert_string_datum (lobound , boundstypid );
3660
- char * histr = convert_string_datum (hibound , boundstypid );
3668
+ char * valstr = convert_string_datum (value , valuetypid ,
3669
+ & failure );
3670
+ char * lostr = convert_string_datum (lobound , boundstypid ,
3671
+ & failure );
3672
+ char * histr = convert_string_datum (hibound , boundstypid ,
3673
+ & failure );
3674
+
3675
+ /*
3676
+ * Bail out if any of the values is not of string type. We
3677
+ * might leak converted strings for the other value(s), but
3678
+ * that's not worth troubling over.
3679
+ */
3680
+ if (failure )
3681
+ return false;
3661
3682
3662
3683
convert_string_to_scalar (valstr , scaledvalue ,
3663
3684
lostr , scaledlobound ,
@@ -3673,6 +3694,9 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3673
3694
*/
3674
3695
case BYTEAOID :
3675
3696
{
3697
+ /* We only support bytea vs bytea comparison */
3698
+ if (boundstypid != BYTEAOID )
3699
+ return false;
3676
3700
convert_bytea_to_scalar (value , scaledvalue ,
3677
3701
lobound , scaledlobound ,
3678
3702
hibound , scaledhibound );
@@ -3691,21 +3715,27 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3691
3715
case TINTERVALOID :
3692
3716
case TIMEOID :
3693
3717
case TIMETZOID :
3694
- * scaledvalue = convert_timevalue_to_scalar (value , valuetypid );
3695
- * scaledlobound = convert_timevalue_to_scalar (lobound , boundstypid );
3696
- * scaledhibound = convert_timevalue_to_scalar (hibound , boundstypid );
3697
- return true;
3718
+ * scaledvalue = convert_timevalue_to_scalar (value , valuetypid ,
3719
+ & failure );
3720
+ * scaledlobound = convert_timevalue_to_scalar (lobound , boundstypid ,
3721
+ & failure );
3722
+ * scaledhibound = convert_timevalue_to_scalar (hibound , boundstypid ,
3723
+ & failure );
3724
+ return !failure ;
3698
3725
3699
3726
/*
3700
3727
* Built-in network types
3701
3728
*/
3702
3729
case INETOID :
3703
3730
case CIDROID :
3704
3731
case MACADDROID :
3705
- * scaledvalue = convert_network_to_scalar (value , valuetypid );
3706
- * scaledlobound = convert_network_to_scalar (lobound , boundstypid );
3707
- * scaledhibound = convert_network_to_scalar (hibound , boundstypid );
3708
- return true;
3732
+ * scaledvalue = convert_network_to_scalar (value , valuetypid ,
3733
+ & failure );
3734
+ * scaledlobound = convert_network_to_scalar (lobound , boundstypid ,
3735
+ & failure );
3736
+ * scaledhibound = convert_network_to_scalar (hibound , boundstypid ,
3737
+ & failure );
3738
+ return !failure ;
3709
3739
}
3710
3740
/* Don't know how to convert */
3711
3741
* scaledvalue = * scaledlobound = * scaledhibound = 0 ;
@@ -3714,9 +3744,12 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3714
3744
3715
3745
/*
3716
3746
* Do convert_to_scalar()'s work for any numeric data type.
3747
+ *
3748
+ * On failure (e.g., unsupported typid), set *failure to true;
3749
+ * otherwise, that variable is not changed.
3717
3750
*/
3718
3751
static double
3719
- convert_numeric_to_scalar (Datum value , Oid typid )
3752
+ convert_numeric_to_scalar (Datum value , Oid typid , bool * failure )
3720
3753
{
3721
3754
switch (typid )
3722
3755
{
@@ -3750,11 +3783,7 @@ convert_numeric_to_scalar(Datum value, Oid typid)
3750
3783
return (double ) DatumGetObjectId (value );
3751
3784
}
3752
3785
3753
- /*
3754
- * Can't get here unless someone tries to use scalarltsel/scalargtsel on
3755
- * an operator with one numeric and one non-numeric operand.
3756
- */
3757
- elog (ERROR , "unsupported type: %u" , typid );
3786
+ * failure = true;
3758
3787
return 0 ;
3759
3788
}
3760
3789
@@ -3897,11 +3926,14 @@ convert_one_string_to_scalar(char *value, int rangelo, int rangehi)
3897
3926
/*
3898
3927
* Convert a string-type Datum into a palloc'd, null-terminated string.
3899
3928
*
3929
+ * On failure (e.g., unsupported typid), set *failure to true;
3930
+ * otherwise, that variable is not changed. (We'll return NULL on failure.)
3931
+ *
3900
3932
* When using a non-C locale, we must pass the string through strxfrm()
3901
3933
* before continuing, so as to generate correct locale-specific results.
3902
3934
*/
3903
3935
static char *
3904
- convert_string_datum (Datum value , Oid typid )
3936
+ convert_string_datum (Datum value , Oid typid , bool * failure )
3905
3937
{
3906
3938
char * val ;
3907
3939
@@ -3925,12 +3957,7 @@ convert_string_datum(Datum value, Oid typid)
3925
3957
break ;
3926
3958
}
3927
3959
default :
3928
-
3929
- /*
3930
- * Can't get here unless someone tries to use scalarltsel on an
3931
- * operator with one string and one non-string operand.
3932
- */
3933
- elog (ERROR , "unsupported type: %u" , typid );
3960
+ * failure = true;
3934
3961
return NULL ;
3935
3962
}
3936
3963
@@ -4010,16 +4037,19 @@ convert_bytea_to_scalar(Datum value,
4010
4037
Datum hibound ,
4011
4038
double * scaledhibound )
4012
4039
{
4040
+ bytea * valuep = DatumGetByteaPP (value );
4041
+ bytea * loboundp = DatumGetByteaPP (lobound );
4042
+ bytea * hiboundp = DatumGetByteaPP (hibound );
4013
4043
int rangelo ,
4014
4044
rangehi ,
4015
- valuelen = VARSIZE ( DatumGetPointer ( value )) - VARHDRSZ ,
4016
- loboundlen = VARSIZE ( DatumGetPointer ( lobound )) - VARHDRSZ ,
4017
- hiboundlen = VARSIZE ( DatumGetPointer ( hibound )) - VARHDRSZ ,
4045
+ valuelen = VARSIZE_ANY_EXHDR ( valuep ) ,
4046
+ loboundlen = VARSIZE_ANY_EXHDR ( loboundp ) ,
4047
+ hiboundlen = VARSIZE_ANY_EXHDR ( hiboundp ) ,
4018
4048
i ,
4019
4049
minlen ;
4020
- unsigned char * valstr = (unsigned char * ) VARDATA ( DatumGetPointer ( value )),
4021
- * lostr = (unsigned char * ) VARDATA ( DatumGetPointer ( lobound )),
4022
- * histr = (unsigned char * ) VARDATA ( DatumGetPointer ( hibound ) );
4050
+ unsigned char * valstr = (unsigned char * ) VARDATA_ANY ( valuep );
4051
+ unsigned char * lostr = (unsigned char * ) VARDATA_ANY ( loboundp );
4052
+ unsigned char * histr = (unsigned char * ) VARDATA_ANY ( hiboundp );
4023
4053
4024
4054
/*
4025
4055
* Assume bytea data is uniformly distributed across all byte values.
@@ -4086,9 +4116,12 @@ convert_one_bytea_to_scalar(unsigned char *value, int valuelen,
4086
4116
4087
4117
/*
4088
4118
* Do convert_to_scalar()'s work for any timevalue data type.
4119
+ *
4120
+ * On failure (e.g., unsupported typid), set *failure to true;
4121
+ * otherwise, that variable is not changed.
4089
4122
*/
4090
4123
static double
4091
- convert_timevalue_to_scalar (Datum value , Oid typid )
4124
+ convert_timevalue_to_scalar (Datum value , Oid typid , bool * failure )
4092
4125
{
4093
4126
switch (typid )
4094
4127
{
@@ -4152,11 +4185,7 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
4152
4185
}
4153
4186
}
4154
4187
4155
- /*
4156
- * Can't get here unless someone tries to use scalarltsel/scalargtsel on
4157
- * an operator with one timevalue and one non-timevalue operand.
4158
- */
4159
- elog (ERROR , "unsupported type: %u" , typid );
4188
+ * failure = true;
4160
4189
return 0 ;
4161
4190
}
4162
4191
0 commit comments