@@ -176,7 +176,7 @@ static bool estimate_multivariate_ndistinct(PlannerInfo *root,
176176static bool convert_to_scalar (Datum value , Oid valuetypid , double * scaledvalue ,
177177 Datum lobound , Datum hibound , Oid boundstypid ,
178178 double * scaledlobound , double * scaledhibound );
179- static double convert_numeric_to_scalar (Datum value , Oid typid );
179+ static double convert_numeric_to_scalar (Datum value , Oid typid , bool * failure );
180180static void convert_string_to_scalar (char * value ,
181181 double * scaledvalue ,
182182 char * lobound ,
@@ -193,8 +193,9 @@ static double convert_one_string_to_scalar(char *value,
193193 int rangelo , int rangehi );
194194static double convert_one_bytea_to_scalar (unsigned char * value , int valuelen ,
195195 int rangelo , int rangehi );
196- static char * convert_string_datum (Datum value , Oid typid );
197- static double convert_timevalue_to_scalar (Datum value , Oid typid );
196+ static char * convert_string_datum (Datum value , Oid typid , bool * failure );
197+ static double convert_timevalue_to_scalar (Datum value , Oid typid ,
198+ bool * failure );
198199static void examine_simple_variable (PlannerInfo * root , Var * var ,
199200 VariableStatData * vardata );
200201static bool get_variable_range (PlannerInfo * root , VariableStatData * vardata ,
@@ -556,7 +557,8 @@ neqsel(PG_FUNCTION_ARGS)
556557 *
557558 * This routine works for any datatype (or pair of datatypes) known to
558559 * convert_to_scalar(). If it is applied to some other datatype,
559- * it will return a default estimate.
560+ * it will return an approximate estimate based on assuming that the constant
561+ * value falls in the middle of the bin identified by binary search.
560562 */
561563static double
562564scalarineqsel (PlannerInfo * root , Oid operator , bool isgt , bool iseq ,
@@ -4033,10 +4035,15 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
40334035 Datum lobound , Datum hibound , Oid boundstypid ,
40344036 double * scaledlobound , double * scaledhibound )
40354037{
4038+ bool failure = false;
4039+
40364040 /*
40374041 * Both the valuetypid and the boundstypid should exactly match the
4038- * declared input type(s) of the operator we are invoked for, so we just
4039- * error out if either is not recognized.
4042+ * declared input type(s) of the operator we are invoked for. However,
4043+ * extensions might try to use scalarineqsel as estimator for operators
4044+ * with input type(s) we don't handle here; in such cases, we want to
4045+ * return false, not fail. In any case, we mustn't assume that valuetypid
4046+ * and boundstypid are identical.
40404047 *
40414048 * XXX The histogram we are interpolating between points of could belong
40424049 * to a column that's only binary-compatible with the declared type. In
@@ -4071,10 +4078,13 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
40714078 case REGDICTIONARYOID :
40724079 case REGROLEOID :
40734080 case REGNAMESPACEOID :
4074- * scaledvalue = convert_numeric_to_scalar (value , valuetypid );
4075- * scaledlobound = convert_numeric_to_scalar (lobound , boundstypid );
4076- * scaledhibound = convert_numeric_to_scalar (hibound , boundstypid );
4077- return true;
4081+ * scaledvalue = convert_numeric_to_scalar (value , valuetypid ,
4082+ & failure );
4083+ * scaledlobound = convert_numeric_to_scalar (lobound , boundstypid ,
4084+ & failure );
4085+ * scaledhibound = convert_numeric_to_scalar (hibound , boundstypid ,
4086+ & failure );
4087+ return !failure ;
40784088
40794089 /*
40804090 * Built-in string types
@@ -4085,9 +4095,20 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
40854095 case TEXTOID :
40864096 case NAMEOID :
40874097 {
4088- char * valstr = convert_string_datum (value , valuetypid );
4089- char * lostr = convert_string_datum (lobound , boundstypid );
4090- char * histr = convert_string_datum (hibound , boundstypid );
4098+ char * valstr = convert_string_datum (value , valuetypid ,
4099+ & failure );
4100+ char * lostr = convert_string_datum (lobound , boundstypid ,
4101+ & failure );
4102+ char * histr = convert_string_datum (hibound , boundstypid ,
4103+ & failure );
4104+
4105+ /*
4106+ * Bail out if any of the values is not of string type. We
4107+ * might leak converted strings for the other value(s), but
4108+ * that's not worth troubling over.
4109+ */
4110+ if (failure )
4111+ return false;
40914112
40924113 convert_string_to_scalar (valstr , scaledvalue ,
40934114 lostr , scaledlobound ,
@@ -4103,6 +4124,9 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
41034124 */
41044125 case BYTEAOID :
41054126 {
4127+ /* We only support bytea vs bytea comparison */
4128+ if (boundstypid != BYTEAOID )
4129+ return false;
41064130 convert_bytea_to_scalar (value , scaledvalue ,
41074131 lobound , scaledlobound ,
41084132 hibound , scaledhibound );
@@ -4121,10 +4145,13 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
41214145 case TINTERVALOID :
41224146 case TIMEOID :
41234147 case TIMETZOID :
4124- * scaledvalue = convert_timevalue_to_scalar (value , valuetypid );
4125- * scaledlobound = convert_timevalue_to_scalar (lobound , boundstypid );
4126- * scaledhibound = convert_timevalue_to_scalar (hibound , boundstypid );
4127- return true;
4148+ * scaledvalue = convert_timevalue_to_scalar (value , valuetypid ,
4149+ & failure );
4150+ * scaledlobound = convert_timevalue_to_scalar (lobound , boundstypid ,
4151+ & failure );
4152+ * scaledhibound = convert_timevalue_to_scalar (hibound , boundstypid ,
4153+ & failure );
4154+ return !failure ;
41284155
41294156 /*
41304157 * Built-in network types
@@ -4133,10 +4160,13 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
41334160 case CIDROID :
41344161 case MACADDROID :
41354162 case MACADDR8OID :
4136- * scaledvalue = convert_network_to_scalar (value , valuetypid );
4137- * scaledlobound = convert_network_to_scalar (lobound , boundstypid );
4138- * scaledhibound = convert_network_to_scalar (hibound , boundstypid );
4139- return true;
4163+ * scaledvalue = convert_network_to_scalar (value , valuetypid ,
4164+ & failure );
4165+ * scaledlobound = convert_network_to_scalar (lobound , boundstypid ,
4166+ & failure );
4167+ * scaledhibound = convert_network_to_scalar (hibound , boundstypid ,
4168+ & failure );
4169+ return !failure ;
41404170 }
41414171 /* Don't know how to convert */
41424172 * scaledvalue = * scaledlobound = * scaledhibound = 0 ;
@@ -4145,9 +4175,12 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
41454175
41464176/*
41474177 * Do convert_to_scalar()'s work for any numeric data type.
4178+ *
4179+ * On failure (e.g., unsupported typid), set *failure to true;
4180+ * otherwise, that variable is not changed.
41484181 */
41494182static double
4150- convert_numeric_to_scalar (Datum value , Oid typid )
4183+ convert_numeric_to_scalar (Datum value , Oid typid , bool * failure )
41514184{
41524185 switch (typid )
41534186 {
@@ -4183,11 +4216,7 @@ convert_numeric_to_scalar(Datum value, Oid typid)
41834216 return (double ) DatumGetObjectId (value );
41844217 }
41854218
4186- /*
4187- * Can't get here unless someone tries to use scalarineqsel() on an
4188- * operator with one numeric and one non-numeric operand.
4189- */
4190- elog (ERROR , "unsupported type: %u" , typid );
4219+ * failure = true;
41914220 return 0 ;
41924221}
41934222
@@ -4336,11 +4365,14 @@ convert_one_string_to_scalar(char *value, int rangelo, int rangehi)
43364365/*
43374366 * Convert a string-type Datum into a palloc'd, null-terminated string.
43384367 *
4368+ * On failure (e.g., unsupported typid), set *failure to true;
4369+ * otherwise, that variable is not changed. (We'll return NULL on failure.)
4370+ *
43394371 * When using a non-C locale, we must pass the string through strxfrm()
43404372 * before continuing, so as to generate correct locale-specific results.
43414373 */
43424374static char *
4343- convert_string_datum (Datum value , Oid typid )
4375+ convert_string_datum (Datum value , Oid typid , bool * failure )
43444376{
43454377 char * val ;
43464378
@@ -4364,12 +4396,7 @@ convert_string_datum(Datum value, Oid typid)
43644396 break ;
43654397 }
43664398 default :
4367-
4368- /*
4369- * Can't get here unless someone tries to use scalarineqsel() on
4370- * an operator with one string and one non-string operand.
4371- */
4372- elog (ERROR , "unsupported type: %u" , typid );
4399+ * failure = true;
43734400 return NULL ;
43744401 }
43754402
@@ -4446,16 +4473,19 @@ convert_bytea_to_scalar(Datum value,
44464473 Datum hibound ,
44474474 double * scaledhibound )
44484475{
4476+ bytea * valuep = DatumGetByteaPP (value );
4477+ bytea * loboundp = DatumGetByteaPP (lobound );
4478+ bytea * hiboundp = DatumGetByteaPP (hibound );
44494479 int rangelo ,
44504480 rangehi ,
4451- valuelen = VARSIZE ( DatumGetPointer ( value )) - VARHDRSZ ,
4452- loboundlen = VARSIZE ( DatumGetPointer ( lobound )) - VARHDRSZ ,
4453- hiboundlen = VARSIZE ( DatumGetPointer ( hibound )) - VARHDRSZ ,
4481+ valuelen = VARSIZE_ANY_EXHDR ( valuep ) ,
4482+ loboundlen = VARSIZE_ANY_EXHDR ( loboundp ) ,
4483+ hiboundlen = VARSIZE_ANY_EXHDR ( hiboundp ) ,
44544484 i ,
44554485 minlen ;
4456- unsigned char * valstr = (unsigned char * ) VARDATA ( DatumGetPointer ( value )),
4457- * lostr = (unsigned char * ) VARDATA ( DatumGetPointer ( lobound )),
4458- * histr = (unsigned char * ) VARDATA ( DatumGetPointer ( hibound ) );
4486+ unsigned char * valstr = (unsigned char * ) VARDATA_ANY ( valuep );
4487+ unsigned char * lostr = (unsigned char * ) VARDATA_ANY ( loboundp );
4488+ unsigned char * histr = (unsigned char * ) VARDATA_ANY ( hiboundp );
44594489
44604490 /*
44614491 * Assume bytea data is uniformly distributed across all byte values.
@@ -4522,9 +4552,12 @@ convert_one_bytea_to_scalar(unsigned char *value, int valuelen,
45224552
45234553/*
45244554 * Do convert_to_scalar()'s work for any timevalue data type.
4555+ *
4556+ * On failure (e.g., unsupported typid), set *failure to true;
4557+ * otherwise, that variable is not changed.
45254558 */
45264559static double
4527- convert_timevalue_to_scalar (Datum value , Oid typid )
4560+ convert_timevalue_to_scalar (Datum value , Oid typid , bool * failure )
45284561{
45294562 switch (typid )
45304563 {
@@ -4570,11 +4603,7 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
45704603 }
45714604 }
45724605
4573- /*
4574- * Can't get here unless someone tries to use scalarineqsel() on an
4575- * operator with one timevalue and one non-timevalue operand.
4576- */
4577- elog (ERROR , "unsupported type: %u" , typid );
4606+ * failure = true;
45784607 return 0 ;
45794608}
45804609
0 commit comments