Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit58d9acc

Browse files
committed
Fix assorted issues in convert_to_scalar().
If convert_to_scalar is passed a pair of datatypes it can't cope with,its former behavior was just to elog(ERROR). While this is OK so far asthe core code is concerned, there's extension code that would like to usescalarltsel/scalargtsel/etc as selectivity estimators for operators thatwork on non-core datatypes, and this behavior is a show-stopper for thatuse-case. If we simply allow convert_to_scalar to return FALSE instead ofoutright failing, then the main logic of scalarltsel/scalargtsel will workfine for any operator that behaves like a scalar inequality comparison.The lack of conversion capability will mean that we can't estimate tobetter than histogram-bin-width precision, since the code will effectivelyassume that the comparison constant falls at the middle of its bin. Butthat's still a lot better than nothing. (Someday we should provide a wayfor extension code to supply a custom version of convert_to_scalar, buttoday is not that day.)While poking at this issue, we noted that the existing code for handlingtype bytea in convert_to_scalar is several bricks shy of a load.It assumes without checking that if the comparison value is type bytea,the bounds values are too; in the worst case this could lead to a crash.It also fails to detoast the input values, so that the comparison result iscomplete garbage if any input is toasted out-of-line, compressed, or evenjust short-header. I'm not sure how often such cases actually occur ---the bounds values, at least, are probably safe since they are elements ofan array and hence can't be toasted. But that doesn't make this code OK.Back-patch to all supported branches, partly because author requested that,but mostly because of the bytea bugs. The change in API for the exposedroutine convert_network_to_scalar() is theoretically a back-patch hazard,but it seems pretty unlikely that any third-party code is calling thatfunction directly.Tomas Vondra, with some adjustments by meDiscussion:https://postgr.es/m/b68441b6-d18f-13ab-b43b-9a72188a4e02@2ndquadrant.com
1 parent7726147 commit58d9acc

File tree

4 files changed

+90
-57
lines changed

4 files changed

+90
-57
lines changed

‎contrib/btree_gist/btree_inet.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,11 @@ gbt_inet_compress(PG_FUNCTION_ARGS)
9999
if (entry->leafkey)
100100
{
101101
inetKEY*r= (inetKEY*)palloc(sizeof(inetKEY));
102+
boolfailure= false;
102103

103104
retval=palloc(sizeof(GISTENTRY));
104-
r->lower=convert_network_to_scalar(entry->key,INETOID);
105+
r->lower=convert_network_to_scalar(entry->key,INETOID,&failure);
106+
Assert(!failure);
105107
r->upper=r->lower;
106108
gistentryinit(*retval,PointerGetDatum(r),
107109
entry->rel,entry->page,
@@ -118,13 +120,18 @@ Datum
118120
gbt_inet_consistent(PG_FUNCTION_ARGS)
119121
{
120122
GISTENTRY*entry= (GISTENTRY*)PG_GETARG_POINTER(0);
121-
doublequery=convert_network_to_scalar(PG_GETARG_DATUM(1),INETOID);
123+
Datumdquery=PG_GETARG_DATUM(1);
122124
StrategyNumberstrategy= (StrategyNumber)PG_GETARG_UINT16(2);
123125

124126
/* Oidsubtype = PG_GETARG_OID(3); */
125127
bool*recheck= (bool*)PG_GETARG_POINTER(4);
126128
inetKEY*kkk= (inetKEY*)DatumGetPointer(entry->key);
127129
GBT_NUMKEY_Rkey;
130+
doublequery;
131+
boolfailure= false;
132+
133+
query=convert_network_to_scalar(dquery,INETOID,&failure);
134+
Assert(!failure);
128135

129136
/* All cases served by this function are inexact */
130137
*recheck= true;

‎src/backend/utils/adt/network.c

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -902,9 +902,12 @@ inet_merge(PG_FUNCTION_ARGS)
902902
* Convert a value of a network datatype to an approximate scalar value.
903903
* This is used for estimating selectivities of inequality operators
904904
* involving network types.
905+
*
906+
* On failure (e.g., unsupported typid), set *failure to true;
907+
* otherwise, that variable is not changed.
905908
*/
906909
double
907-
convert_network_to_scalar(Datumvalue,Oidtypid)
910+
convert_network_to_scalar(Datumvalue,Oidtypid,bool*failure)
908911
{
909912
switch (typid)
910913
{
@@ -931,8 +934,6 @@ convert_network_to_scalar(Datum value, Oid typid)
931934
res+=ip_addr(ip)[i];
932935
}
933936
returnres;
934-
935-
break;
936937
}
937938
caseMACADDROID:
938939
{
@@ -956,11 +957,7 @@ convert_network_to_scalar(Datum value, Oid typid)
956957
}
957958
}
958959

959-
/*
960-
* Can't get here unless someone tries to use scalarineqsel() on an
961-
* operator with one network and one non-network operand.
962-
*/
963-
elog(ERROR,"unsupported type: %u",typid);
960+
*failure= true;
964961
return0;
965962
}
966963

‎src/backend/utils/adt/selfuncs.c

Lines changed: 75 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ static bool estimate_multivariate_ndistinct(PlannerInfo *root,
176176
staticboolconvert_to_scalar(Datumvalue,Oidvaluetypid,double*scaledvalue,
177177
Datumlobound,Datumhibound,Oidboundstypid,
178178
double*scaledlobound,double*scaledhibound);
179-
staticdoubleconvert_numeric_to_scalar(Datumvalue,Oidtypid);
179+
staticdoubleconvert_numeric_to_scalar(Datumvalue,Oidtypid,bool*failure);
180180
staticvoidconvert_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
intrangelo,intrangehi);
194194
staticdoubleconvert_one_bytea_to_scalar(unsignedchar*value,intvaluelen,
195195
intrangelo,intrangehi);
196-
staticchar*convert_string_datum(Datumvalue,Oidtypid);
197-
staticdoubleconvert_timevalue_to_scalar(Datumvalue,Oidtypid);
196+
staticchar*convert_string_datum(Datumvalue,Oidtypid,bool*failure);
197+
staticdoubleconvert_timevalue_to_scalar(Datumvalue,Oidtypid,
198+
bool*failure);
198199
staticvoidexamine_simple_variable(PlannerInfo*root,Var*var,
199200
VariableStatData*vardata);
200201
staticboolget_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
*/
561563
staticdouble
562564
scalarineqsel(PlannerInfo*root,Oidoperator,boolisgt,booliseq,
@@ -4033,10 +4035,15 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
40334035
Datumlobound,Datumhibound,Oidboundstypid,
40344036
double*scaledlobound,double*scaledhibound)
40354037
{
4038+
boolfailure= 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
caseREGDICTIONARYOID:
40724079
caseREGROLEOID:
40734080
caseREGNAMESPACEOID:
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
caseTEXTOID:
40864096
caseNAMEOID:
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
caseBYTEAOID:
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
caseTINTERVALOID:
41224146
caseTIMEOID:
41234147
caseTIMETZOID:
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
caseCIDROID:
41344161
caseMACADDROID:
41354162
caseMACADDR8OID:
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
*/
41494182
staticdouble
4150-
convert_numeric_to_scalar(Datumvalue,Oidtypid)
4183+
convert_numeric_to_scalar(Datumvalue,Oidtypid,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
return0;
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
*/
43424374
staticchar*
4343-
convert_string_datum(Datumvalue,Oidtypid)
4375+
convert_string_datum(Datumvalue,Oidtypid,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
returnNULL;
43744401
}
43754402

@@ -4446,16 +4473,19 @@ convert_bytea_to_scalar(Datum value,
44464473
Datumhibound,
44474474
double*scaledhibound)
44484475
{
4476+
bytea*valuep=DatumGetByteaPP(value);
4477+
bytea*loboundp=DatumGetByteaPP(lobound);
4478+
bytea*hiboundp=DatumGetByteaPP(hibound);
44494479
intrangelo,
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-
unsignedchar*valstr= (unsignedchar*)VARDATA(DatumGetPointer(value)),
4457-
*lostr= (unsignedchar*)VARDATA(DatumGetPointer(lobound)),
4458-
*histr= (unsignedchar*)VARDATA(DatumGetPointer(hibound));
4486+
unsignedchar*valstr= (unsignedchar*)VARDATA_ANY(valuep);
4487+
unsignedchar*lostr= (unsignedchar*)VARDATA_ANY(loboundp);
4488+
unsignedchar*histr= (unsignedchar*)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
*/
45264559
staticdouble
4527-
convert_timevalue_to_scalar(Datumvalue,Oidtypid)
4560+
convert_timevalue_to_scalar(Datumvalue,Oidtypid,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
return0;
45794608
}
45804609

‎src/include/utils/builtins.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ extern int inet_net_pton(int af, const char *src,
103103
void*dst,size_tsize);
104104

105105
/* network.c */
106-
externdoubleconvert_network_to_scalar(Datumvalue,Oidtypid);
106+
externdoubleconvert_network_to_scalar(Datumvalue,Oidtypid,bool*failure);
107107
externDatumnetwork_scan_first(Datumin);
108108
externDatumnetwork_scan_last(Datumin);
109109
externvoidclean_ipv6_addr(intaddr_family,char*addr);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp