aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/btree_gist/btree_inet.c11
-rw-r--r--src/backend/utils/adt/network.c13
-rw-r--r--src/backend/utils/adt/selfuncs.c121
-rw-r--r--src/include/utils/builtins.h2
4 files changed, 90 insertions, 57 deletions
diff --git a/contrib/btree_gist/btree_inet.c b/contrib/btree_gist/btree_inet.c
index 86c27ca9556..34308cc6408 100644
--- a/contrib/btree_gist/btree_inet.c
+++ b/contrib/btree_gist/btree_inet.c
@@ -99,9 +99,11 @@ gbt_inet_compress(PG_FUNCTION_ARGS)
if (entry->leafkey)
{
inetKEY *r = (inetKEY *) palloc(sizeof(inetKEY));
+ bool failure = false;
retval = palloc(sizeof(GISTENTRY));
- r->lower = convert_network_to_scalar(entry->key, INETOID);
+ r->lower = convert_network_to_scalar(entry->key, INETOID, &failure);
+ Assert(!failure);
r->upper = r->lower;
gistentryinit(*retval, PointerGetDatum(r),
entry->rel, entry->page,
@@ -118,13 +120,18 @@ Datum
gbt_inet_consistent(PG_FUNCTION_ARGS)
{
GISTENTRY *entry = (GISTENTRY *) PG_GETARG_POINTER(0);
- double query = convert_network_to_scalar(PG_GETARG_DATUM(1), INETOID);
+ Datum dquery = PG_GETARG_DATUM(1);
StrategyNumber strategy = (StrategyNumber) PG_GETARG_UINT16(2);
/* Oid subtype = PG_GETARG_OID(3); */
bool *recheck = (bool *) PG_GETARG_POINTER(4);
inetKEY *kkk = (inetKEY *) DatumGetPointer(entry->key);
GBT_NUMKEY_R key;
+ double query;
+ bool failure = false;
+
+ query = convert_network_to_scalar(dquery, INETOID, &failure);
+ Assert(!failure);
/* All cases served by this function are inexact */
*recheck = true;
diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c
index aac76217173..350b1a63d21 100644
--- a/src/backend/utils/adt/network.c
+++ b/src/backend/utils/adt/network.c
@@ -902,9 +902,12 @@ inet_merge(PG_FUNCTION_ARGS)
* Convert a value of a network datatype to an approximate scalar value.
* This is used for estimating selectivities of inequality operators
* involving network types.
+ *
+ * On failure (e.g., unsupported typid), set *failure to true;
+ * otherwise, that variable is not changed.
*/
double
-convert_network_to_scalar(Datum value, Oid typid)
+convert_network_to_scalar(Datum value, Oid typid, bool *failure)
{
switch (typid)
{
@@ -931,8 +934,6 @@ convert_network_to_scalar(Datum value, Oid typid)
res += ip_addr(ip)[i];
}
return res;
-
- break;
}
case MACADDROID:
{
@@ -956,11 +957,7 @@ convert_network_to_scalar(Datum value, Oid typid)
}
}
- /*
- * Can't get here unless someone tries to use scalarineqsel() on an
- * operator with one network and one non-network operand.
- */
- elog(ERROR, "unsupported type: %u", typid);
+ *failure = true;
return 0;
}
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index fcc8323f626..bf240aa9c5a 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -176,7 +176,7 @@ static bool estimate_multivariate_ndistinct(PlannerInfo *root,
static bool convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
Datum lobound, Datum hibound, Oid boundstypid,
double *scaledlobound, double *scaledhibound);
-static double convert_numeric_to_scalar(Datum value, Oid typid);
+static double convert_numeric_to_scalar(Datum value, Oid typid, bool *failure);
static void convert_string_to_scalar(char *value,
double *scaledvalue,
char *lobound,
@@ -193,8 +193,9 @@ static double convert_one_string_to_scalar(char *value,
int rangelo, int rangehi);
static double convert_one_bytea_to_scalar(unsigned char *value, int valuelen,
int rangelo, int rangehi);
-static char *convert_string_datum(Datum value, Oid typid);
-static double convert_timevalue_to_scalar(Datum value, Oid typid);
+static char *convert_string_datum(Datum value, Oid typid, bool *failure);
+static double convert_timevalue_to_scalar(Datum value, Oid typid,
+ bool *failure);
static void examine_simple_variable(PlannerInfo *root, Var *var,
VariableStatData *vardata);
static bool get_variable_range(PlannerInfo *root, VariableStatData *vardata,
@@ -556,7 +557,8 @@ neqsel(PG_FUNCTION_ARGS)
*
* This routine works for any datatype (or pair of datatypes) known to
* convert_to_scalar(). If it is applied to some other datatype,
- * it will return a default estimate.
+ * it will return an approximate estimate based on assuming that the constant
+ * value falls in the middle of the bin identified by binary search.
*/
static double
scalarineqsel(PlannerInfo *root, Oid operator, bool isgt, bool iseq,
@@ -4033,10 +4035,15 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
Datum lobound, Datum hibound, Oid boundstypid,
double *scaledlobound, double *scaledhibound)
{
+ bool failure = false;
+
/*
* Both the valuetypid and the boundstypid should exactly match the
- * declared input type(s) of the operator we are invoked for, so we just
- * error out if either is not recognized.
+ * declared input type(s) of the operator we are invoked for. However,
+ * extensions might try to use scalarineqsel as estimator for operators
+ * with input type(s) we don't handle here; in such cases, we want to
+ * return false, not fail. In any case, we mustn't assume that valuetypid
+ * and boundstypid are identical.
*
* XXX The histogram we are interpolating between points of could belong
* 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,
case REGDICTIONARYOID:
case REGROLEOID:
case REGNAMESPACEOID:
- *scaledvalue = convert_numeric_to_scalar(value, valuetypid);
- *scaledlobound = convert_numeric_to_scalar(lobound, boundstypid);
- *scaledhibound = convert_numeric_to_scalar(hibound, boundstypid);
- return true;
+ *scaledvalue = convert_numeric_to_scalar(value, valuetypid,
+ &failure);
+ *scaledlobound = convert_numeric_to_scalar(lobound, boundstypid,
+ &failure);
+ *scaledhibound = convert_numeric_to_scalar(hibound, boundstypid,
+ &failure);
+ return !failure;
/*
* Built-in string types
@@ -4085,9 +4095,20 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
case TEXTOID:
case NAMEOID:
{
- char *valstr = convert_string_datum(value, valuetypid);
- char *lostr = convert_string_datum(lobound, boundstypid);
- char *histr = convert_string_datum(hibound, boundstypid);
+ char *valstr = convert_string_datum(value, valuetypid,
+ &failure);
+ char *lostr = convert_string_datum(lobound, boundstypid,
+ &failure);
+ char *histr = convert_string_datum(hibound, boundstypid,
+ &failure);
+
+ /*
+ * Bail out if any of the values is not of string type. We
+ * might leak converted strings for the other value(s), but
+ * that's not worth troubling over.
+ */
+ if (failure)
+ return false;
convert_string_to_scalar(valstr, scaledvalue,
lostr, scaledlobound,
@@ -4103,6 +4124,9 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
*/
case BYTEAOID:
{
+ /* We only support bytea vs bytea comparison */
+ if (boundstypid != BYTEAOID)
+ return false;
convert_bytea_to_scalar(value, scaledvalue,
lobound, scaledlobound,
hibound, scaledhibound);
@@ -4121,10 +4145,13 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
case TINTERVALOID:
case TIMEOID:
case TIMETZOID:
- *scaledvalue = convert_timevalue_to_scalar(value, valuetypid);
- *scaledlobound = convert_timevalue_to_scalar(lobound, boundstypid);
- *scaledhibound = convert_timevalue_to_scalar(hibound, boundstypid);
- return true;
+ *scaledvalue = convert_timevalue_to_scalar(value, valuetypid,
+ &failure);
+ *scaledlobound = convert_timevalue_to_scalar(lobound, boundstypid,
+ &failure);
+ *scaledhibound = convert_timevalue_to_scalar(hibound, boundstypid,
+ &failure);
+ return !failure;
/*
* Built-in network types
@@ -4133,10 +4160,13 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
case CIDROID:
case MACADDROID:
case MACADDR8OID:
- *scaledvalue = convert_network_to_scalar(value, valuetypid);
- *scaledlobound = convert_network_to_scalar(lobound, boundstypid);
- *scaledhibound = convert_network_to_scalar(hibound, boundstypid);
- return true;
+ *scaledvalue = convert_network_to_scalar(value, valuetypid,
+ &failure);
+ *scaledlobound = convert_network_to_scalar(lobound, boundstypid,
+ &failure);
+ *scaledhibound = convert_network_to_scalar(hibound, boundstypid,
+ &failure);
+ return !failure;
}
/* Don't know how to convert */
*scaledvalue = *scaledlobound = *scaledhibound = 0;
@@ -4145,9 +4175,12 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
/*
* Do convert_to_scalar()'s work for any numeric data type.
+ *
+ * On failure (e.g., unsupported typid), set *failure to true;
+ * otherwise, that variable is not changed.
*/
static double
-convert_numeric_to_scalar(Datum value, Oid typid)
+convert_numeric_to_scalar(Datum value, Oid typid, bool *failure)
{
switch (typid)
{
@@ -4183,11 +4216,7 @@ convert_numeric_to_scalar(Datum value, Oid typid)
return (double) DatumGetObjectId(value);
}
- /*
- * Can't get here unless someone tries to use scalarineqsel() on an
- * operator with one numeric and one non-numeric operand.
- */
- elog(ERROR, "unsupported type: %u", typid);
+ *failure = true;
return 0;
}
@@ -4336,11 +4365,14 @@ convert_one_string_to_scalar(char *value, int rangelo, int rangehi)
/*
* Convert a string-type Datum into a palloc'd, null-terminated string.
*
+ * On failure (e.g., unsupported typid), set *failure to true;
+ * otherwise, that variable is not changed. (We'll return NULL on failure.)
+ *
* When using a non-C locale, we must pass the string through strxfrm()
* before continuing, so as to generate correct locale-specific results.
*/
static char *
-convert_string_datum(Datum value, Oid typid)
+convert_string_datum(Datum value, Oid typid, bool *failure)
{
char *val;
@@ -4364,12 +4396,7 @@ convert_string_datum(Datum value, Oid typid)
break;
}
default:
-
- /*
- * Can't get here unless someone tries to use scalarineqsel() on
- * an operator with one string and one non-string operand.
- */
- elog(ERROR, "unsupported type: %u", typid);
+ *failure = true;
return NULL;
}
@@ -4446,16 +4473,19 @@ convert_bytea_to_scalar(Datum value,
Datum hibound,
double *scaledhibound)
{
+ bytea *valuep = DatumGetByteaPP(value);
+ bytea *loboundp = DatumGetByteaPP(lobound);
+ bytea *hiboundp = DatumGetByteaPP(hibound);
int rangelo,
rangehi,
- valuelen = VARSIZE(DatumGetPointer(value)) - VARHDRSZ,
- loboundlen = VARSIZE(DatumGetPointer(lobound)) - VARHDRSZ,
- hiboundlen = VARSIZE(DatumGetPointer(hibound)) - VARHDRSZ,
+ valuelen = VARSIZE_ANY_EXHDR(valuep),
+ loboundlen = VARSIZE_ANY_EXHDR(loboundp),
+ hiboundlen = VARSIZE_ANY_EXHDR(hiboundp),
i,
minlen;
- unsigned char *valstr = (unsigned char *) VARDATA(DatumGetPointer(value)),
- *lostr = (unsigned char *) VARDATA(DatumGetPointer(lobound)),
- *histr = (unsigned char *) VARDATA(DatumGetPointer(hibound));
+ unsigned char *valstr = (unsigned char *) VARDATA_ANY(valuep);
+ unsigned char *lostr = (unsigned char *) VARDATA_ANY(loboundp);
+ unsigned char *histr = (unsigned char *) VARDATA_ANY(hiboundp);
/*
* Assume bytea data is uniformly distributed across all byte values.
@@ -4522,9 +4552,12 @@ convert_one_bytea_to_scalar(unsigned char *value, int valuelen,
/*
* Do convert_to_scalar()'s work for any timevalue data type.
+ *
+ * On failure (e.g., unsupported typid), set *failure to true;
+ * otherwise, that variable is not changed.
*/
static double
-convert_timevalue_to_scalar(Datum value, Oid typid)
+convert_timevalue_to_scalar(Datum value, Oid typid, bool *failure)
{
switch (typid)
{
@@ -4570,11 +4603,7 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
}
}
- /*
- * Can't get here unless someone tries to use scalarineqsel() on an
- * operator with one timevalue and one non-timevalue operand.
- */
- elog(ERROR, "unsupported type: %u", typid);
+ *failure = true;
return 0;
}
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 3e462f1a9cf..01e76aea091 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -103,7 +103,7 @@ extern int inet_net_pton(int af, const char *src,
void *dst, size_t size);
/* network.c */
-extern double convert_network_to_scalar(Datum value, Oid typid);
+extern double convert_network_to_scalar(Datum value, Oid typid, bool *failure);
extern Datum network_scan_first(Datum in);
extern Datum network_scan_last(Datum in);
extern void clean_ipv6_addr(int addr_family, char *addr);