@@ -175,7 +175,7 @@ static bool estimate_multivariate_ndistinct(PlannerInfo *root,
175
175
static bool convert_to_scalar (Datum value , Oid valuetypid , double * scaledvalue ,
176
176
Datum lobound , Datum hibound , Oid boundstypid ,
177
177
double * scaledlobound , double * scaledhibound );
178
- static double convert_numeric_to_scalar (Datum value , Oid typid );
178
+ static double convert_numeric_to_scalar (Datum value , Oid typid , bool * failure );
179
179
static void convert_string_to_scalar (char * value ,
180
180
double * scaledvalue ,
181
181
char * lobound ,
@@ -192,8 +192,9 @@ static double convert_one_string_to_scalar(char *value,
192
192
int rangelo , int rangehi );
193
193
static double convert_one_bytea_to_scalar (unsigned char * value , int valuelen ,
194
194
int rangelo , int rangehi );
195
- static char * convert_string_datum (Datum value , Oid typid );
196
- static double convert_timevalue_to_scalar (Datum value , Oid typid );
195
+ static char * convert_string_datum (Datum value , Oid typid , bool * failure );
196
+ static double convert_timevalue_to_scalar (Datum value , Oid typid ,
197
+ bool * failure );
197
198
static void examine_simple_variable (PlannerInfo * root , Var * var ,
198
199
VariableStatData * vardata );
199
200
static bool get_variable_range (PlannerInfo * root , VariableStatData * vardata ,
@@ -552,7 +553,8 @@ neqsel(PG_FUNCTION_ARGS)
552
553
*
553
554
* This routine works for any datatype (or pair of datatypes) known to
554
555
* convert_to_scalar(). If it is applied to some other datatype,
555
- * it will return a default estimate.
556
+ * it will return an approximate estimate based on assuming that the constant
557
+ * value falls in the middle of the bin identified by binary search.
556
558
*/
557
559
static double
558
560
scalarineqsel (PlannerInfo * root , Oid operator , bool isgt ,
@@ -3888,10 +3890,15 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3888
3890
Datum lobound , Datum hibound , Oid boundstypid ,
3889
3891
double * scaledlobound , double * scaledhibound )
3890
3892
{
3893
+ bool failure = false;
3894
+
3891
3895
/*
3892
3896
* Both the valuetypid and the boundstypid should exactly match the
3893
- * declared input type(s) of the operator we are invoked for, so we just
3894
- * error out if either is not recognized.
3897
+ * declared input type(s) of the operator we are invoked for. However,
3898
+ * extensions might try to use scalarineqsel as estimator for operators
3899
+ * with input type(s) we don't handle here; in such cases, we want to
3900
+ * return false, not fail. In any case, we mustn't assume that valuetypid
3901
+ * and boundstypid are identical.
3895
3902
*
3896
3903
* XXX The histogram we are interpolating between points of could belong
3897
3904
* to a column that's only binary-compatible with the declared type. In
@@ -3926,10 +3933,13 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3926
3933
case REGDICTIONARYOID :
3927
3934
case REGROLEOID :
3928
3935
case REGNAMESPACEOID :
3929
- * scaledvalue = convert_numeric_to_scalar (value , valuetypid );
3930
- * scaledlobound = convert_numeric_to_scalar (lobound , boundstypid );
3931
- * scaledhibound = convert_numeric_to_scalar (hibound , boundstypid );
3932
- return true;
3936
+ * scaledvalue = convert_numeric_to_scalar (value , valuetypid ,
3937
+ & failure );
3938
+ * scaledlobound = convert_numeric_to_scalar (lobound , boundstypid ,
3939
+ & failure );
3940
+ * scaledhibound = convert_numeric_to_scalar (hibound , boundstypid ,
3941
+ & failure );
3942
+ return !failure ;
3933
3943
3934
3944
/*
3935
3945
* Built-in string types
@@ -3940,9 +3950,20 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3940
3950
case TEXTOID :
3941
3951
case NAMEOID :
3942
3952
{
3943
- char * valstr = convert_string_datum (value , valuetypid );
3944
- char * lostr = convert_string_datum (lobound , boundstypid );
3945
- char * histr = convert_string_datum (hibound , boundstypid );
3953
+ char * valstr = convert_string_datum (value , valuetypid ,
3954
+ & failure );
3955
+ char * lostr = convert_string_datum (lobound , boundstypid ,
3956
+ & failure );
3957
+ char * histr = convert_string_datum (hibound , boundstypid ,
3958
+ & failure );
3959
+
3960
+ /*
3961
+ * Bail out if any of the values is not of string type. We
3962
+ * might leak converted strings for the other value(s), but
3963
+ * that's not worth troubling over.
3964
+ */
3965
+ if (failure )
3966
+ return false;
3946
3967
3947
3968
convert_string_to_scalar (valstr , scaledvalue ,
3948
3969
lostr , scaledlobound ,
@@ -3958,6 +3979,9 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3958
3979
*/
3959
3980
case BYTEAOID :
3960
3981
{
3982
+ /* We only support bytea vs bytea comparison */
3983
+ if (boundstypid != BYTEAOID )
3984
+ return false;
3961
3985
convert_bytea_to_scalar (value , scaledvalue ,
3962
3986
lobound , scaledlobound ,
3963
3987
hibound , scaledhibound );
@@ -3976,10 +4000,13 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3976
4000
case TINTERVALOID :
3977
4001
case TIMEOID :
3978
4002
case TIMETZOID :
3979
- * scaledvalue = convert_timevalue_to_scalar (value , valuetypid );
3980
- * scaledlobound = convert_timevalue_to_scalar (lobound , boundstypid );
3981
- * scaledhibound = convert_timevalue_to_scalar (hibound , boundstypid );
3982
- return true;
4003
+ * scaledvalue = convert_timevalue_to_scalar (value , valuetypid ,
4004
+ & failure );
4005
+ * scaledlobound = convert_timevalue_to_scalar (lobound , boundstypid ,
4006
+ & failure );
4007
+ * scaledhibound = convert_timevalue_to_scalar (hibound , boundstypid ,
4008
+ & failure );
4009
+ return !failure ;
3983
4010
3984
4011
/*
3985
4012
* Built-in network types
@@ -3988,10 +4015,13 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
3988
4015
case CIDROID :
3989
4016
case MACADDROID :
3990
4017
case MACADDR8OID :
3991
- * scaledvalue = convert_network_to_scalar (value , valuetypid );
3992
- * scaledlobound = convert_network_to_scalar (lobound , boundstypid );
3993
- * scaledhibound = convert_network_to_scalar (hibound , boundstypid );
3994
- return true;
4018
+ * scaledvalue = convert_network_to_scalar (value , valuetypid ,
4019
+ & failure );
4020
+ * scaledlobound = convert_network_to_scalar (lobound , boundstypid ,
4021
+ & failure );
4022
+ * scaledhibound = convert_network_to_scalar (hibound , boundstypid ,
4023
+ & failure );
4024
+ return !failure ;
3995
4025
}
3996
4026
/* Don't know how to convert */
3997
4027
* scaledvalue = * scaledlobound = * scaledhibound = 0 ;
@@ -4000,9 +4030,12 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
4000
4030
4001
4031
/*
4002
4032
* Do convert_to_scalar()'s work for any numeric data type.
4033
+ *
4034
+ * On failure (e.g., unsupported typid), set *failure to true;
4035
+ * otherwise, that variable is not changed.
4003
4036
*/
4004
4037
static double
4005
- convert_numeric_to_scalar (Datum value , Oid typid )
4038
+ convert_numeric_to_scalar (Datum value , Oid typid , bool * failure )
4006
4039
{
4007
4040
switch (typid )
4008
4041
{
@@ -4038,11 +4071,7 @@ convert_numeric_to_scalar(Datum value, Oid typid)
4038
4071
return (double ) DatumGetObjectId (value );
4039
4072
}
4040
4073
4041
- /*
4042
- * Can't get here unless someone tries to use scalarltsel/scalargtsel on
4043
- * an operator with one numeric and one non-numeric operand.
4044
- */
4045
- elog (ERROR , "unsupported type: %u" , typid );
4074
+ * failure = true;
4046
4075
return 0 ;
4047
4076
}
4048
4077
@@ -4191,11 +4220,14 @@ convert_one_string_to_scalar(char *value, int rangelo, int rangehi)
4191
4220
/*
4192
4221
* Convert a string-type Datum into a palloc'd, null-terminated string.
4193
4222
*
4223
+ * On failure (e.g., unsupported typid), set *failure to true;
4224
+ * otherwise, that variable is not changed. (We'll return NULL on failure.)
4225
+ *
4194
4226
* When using a non-C locale, we must pass the string through strxfrm()
4195
4227
* before continuing, so as to generate correct locale-specific results.
4196
4228
*/
4197
4229
static char *
4198
- convert_string_datum (Datum value , Oid typid )
4230
+ convert_string_datum (Datum value , Oid typid , bool * failure )
4199
4231
{
4200
4232
char * val ;
4201
4233
@@ -4219,12 +4251,7 @@ convert_string_datum(Datum value, Oid typid)
4219
4251
break ;
4220
4252
}
4221
4253
default :
4222
-
4223
- /*
4224
- * Can't get here unless someone tries to use scalarltsel on an
4225
- * operator with one string and one non-string operand.
4226
- */
4227
- elog (ERROR , "unsupported type: %u" , typid );
4254
+ * failure = true;
4228
4255
return NULL ;
4229
4256
}
4230
4257
@@ -4301,16 +4328,19 @@ convert_bytea_to_scalar(Datum value,
4301
4328
Datum hibound ,
4302
4329
double * scaledhibound )
4303
4330
{
4331
+ bytea * valuep = DatumGetByteaPP (value );
4332
+ bytea * loboundp = DatumGetByteaPP (lobound );
4333
+ bytea * hiboundp = DatumGetByteaPP (hibound );
4304
4334
int rangelo ,
4305
4335
rangehi ,
4306
- valuelen = VARSIZE ( DatumGetPointer ( value )) - VARHDRSZ ,
4307
- loboundlen = VARSIZE ( DatumGetPointer ( lobound )) - VARHDRSZ ,
4308
- hiboundlen = VARSIZE ( DatumGetPointer ( hibound )) - VARHDRSZ ,
4336
+ valuelen = VARSIZE_ANY_EXHDR ( valuep ) ,
4337
+ loboundlen = VARSIZE_ANY_EXHDR ( loboundp ) ,
4338
+ hiboundlen = VARSIZE_ANY_EXHDR ( hiboundp ) ,
4309
4339
i ,
4310
4340
minlen ;
4311
- unsigned char * valstr = (unsigned char * ) VARDATA ( DatumGetPointer ( value )),
4312
- * lostr = (unsigned char * ) VARDATA ( DatumGetPointer ( lobound )),
4313
- * histr = (unsigned char * ) VARDATA ( DatumGetPointer ( hibound ) );
4341
+ unsigned char * valstr = (unsigned char * ) VARDATA_ANY ( valuep );
4342
+ unsigned char * lostr = (unsigned char * ) VARDATA_ANY ( loboundp );
4343
+ unsigned char * histr = (unsigned char * ) VARDATA_ANY ( hiboundp );
4314
4344
4315
4345
/*
4316
4346
* Assume bytea data is uniformly distributed across all byte values.
@@ -4377,9 +4407,12 @@ convert_one_bytea_to_scalar(unsigned char *value, int valuelen,
4377
4407
4378
4408
/*
4379
4409
* Do convert_to_scalar()'s work for any timevalue data type.
4410
+ *
4411
+ * On failure (e.g., unsupported typid), set *failure to true;
4412
+ * otherwise, that variable is not changed.
4380
4413
*/
4381
4414
static double
4382
- convert_timevalue_to_scalar (Datum value , Oid typid )
4415
+ convert_timevalue_to_scalar (Datum value , Oid typid , bool * failure )
4383
4416
{
4384
4417
switch (typid )
4385
4418
{
@@ -4425,11 +4458,7 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
4425
4458
}
4426
4459
}
4427
4460
4428
- /*
4429
- * Can't get here unless someone tries to use scalarltsel/scalargtsel on
4430
- * an operator with one timevalue and one non-timevalue operand.
4431
- */
4432
- elog (ERROR , "unsupported type: %u" , typid );
4461
+ * failure = true;
4433
4462
return 0 ;
4434
4463
}
4435
4464
0 commit comments