mirror of
https://github.com/postgres/postgres.git
synced 2025-04-24 10:47:04 +03:00
Tweak selectivity and related routines to cope with domains. Per report
from Andreas Pflug.
This commit is contained in:
parent
8f5fb5f24e
commit
efeffae245
@ -9,7 +9,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.135 2003/02/08 20:20:54 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.136 2003/03/23 01:49:02 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -2039,7 +2039,7 @@ expand_indexqual_conditions(List *indexquals)
|
|||||||
* Given a fixed prefix that all the "leftop" values must have,
|
* Given a fixed prefix that all the "leftop" values must have,
|
||||||
* generate suitable indexqual condition(s). expr_op is the original
|
* generate suitable indexqual condition(s). expr_op is the original
|
||||||
* LIKE or regex operator; we use it to deduce the appropriate comparison
|
* LIKE or regex operator; we use it to deduce the appropriate comparison
|
||||||
* operators.
|
* operators and operand datatypes.
|
||||||
*/
|
*/
|
||||||
static List *
|
static List *
|
||||||
prefix_quals(Node *leftop, Oid expr_op,
|
prefix_quals(Node *leftop, Oid expr_op,
|
||||||
@ -2094,10 +2094,13 @@ prefix_quals(Node *leftop, Oid expr_op,
|
|||||||
return NIL;
|
return NIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (prefix_const->consttype != BYTEAOID)
|
/* Prefix constant is text for all except BYTEA_LIKE */
|
||||||
prefix = DatumGetCString(DirectFunctionCall1(textout, prefix_const->constvalue));
|
if (datatype != BYTEAOID)
|
||||||
|
prefix = DatumGetCString(DirectFunctionCall1(textout,
|
||||||
|
prefix_const->constvalue));
|
||||||
else
|
else
|
||||||
prefix = DatumGetCString(DirectFunctionCall1(byteaout, prefix_const->constvalue));
|
prefix = DatumGetCString(DirectFunctionCall1(byteaout,
|
||||||
|
prefix_const->constvalue));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If we found an exact-match pattern, generate an "=" indexqual.
|
* If we found an exact-match pattern, generate an "=" indexqual.
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.132 2003/02/08 20:20:55 tgl Exp $
|
* $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.133 2003/03/23 01:49:02 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -94,6 +94,7 @@
|
|||||||
#include "optimizer/prep.h"
|
#include "optimizer/prep.h"
|
||||||
#include "optimizer/tlist.h"
|
#include "optimizer/tlist.h"
|
||||||
#include "optimizer/var.h"
|
#include "optimizer/var.h"
|
||||||
|
#include "parser/parse_expr.h"
|
||||||
#include "parser/parse_func.h"
|
#include "parser/parse_func.h"
|
||||||
#include "parser/parse_oper.h"
|
#include "parser/parse_oper.h"
|
||||||
#include "parser/parsetree.h"
|
#include "parser/parsetree.h"
|
||||||
@ -176,7 +177,8 @@ static bool get_restriction_var(List *args, int varRelid,
|
|||||||
Var **var, Node **other,
|
Var **var, Node **other,
|
||||||
bool *varonleft);
|
bool *varonleft);
|
||||||
static void get_join_vars(List *args, Var **var1, Var **var2);
|
static void get_join_vars(List *args, Var **var1, Var **var2);
|
||||||
static Selectivity prefix_selectivity(Query *root, Var *var, Const *prefix);
|
static Selectivity prefix_selectivity(Query *root, Var *var, Oid vartype,
|
||||||
|
Const *prefix);
|
||||||
static Selectivity pattern_selectivity(Const *patt, Pattern_Type ptype);
|
static Selectivity pattern_selectivity(Const *patt, Pattern_Type ptype);
|
||||||
static bool string_lessthan(const char *str1, const char *str2,
|
static bool string_lessthan(const char *str1, const char *str2,
|
||||||
Oid datatype);
|
Oid datatype);
|
||||||
@ -227,7 +229,8 @@ eqsel(PG_FUNCTION_ARGS)
|
|||||||
* If the something is a NULL constant, assume operator is strict and
|
* If the something is a NULL constant, assume operator is strict and
|
||||||
* return zero, ie, operator will never return TRUE.
|
* return zero, ie, operator will never return TRUE.
|
||||||
*/
|
*/
|
||||||
if (IsA(other, Const) &&((Const *) other)->constisnull)
|
if (IsA(other, Const) &&
|
||||||
|
((Const *) other)->constisnull)
|
||||||
PG_RETURN_FLOAT8(0.0);
|
PG_RETURN_FLOAT8(0.0);
|
||||||
|
|
||||||
/* get stats for the attribute, if available */
|
/* get stats for the attribute, if available */
|
||||||
@ -834,6 +837,8 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
|
|||||||
bool varonleft;
|
bool varonleft;
|
||||||
Oid relid;
|
Oid relid;
|
||||||
Datum constval;
|
Datum constval;
|
||||||
|
Oid consttype;
|
||||||
|
Oid vartype;
|
||||||
Pattern_Prefix_Status pstatus;
|
Pattern_Prefix_Status pstatus;
|
||||||
Const *patt = NULL;
|
Const *patt = NULL;
|
||||||
Const *prefix = NULL;
|
Const *prefix = NULL;
|
||||||
@ -861,13 +866,25 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
|
|||||||
if (((Const *) other)->constisnull)
|
if (((Const *) other)->constisnull)
|
||||||
return 0.0;
|
return 0.0;
|
||||||
constval = ((Const *) other)->constvalue;
|
constval = ((Const *) other)->constvalue;
|
||||||
|
consttype = ((Const *) other)->consttype;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* the right-hand const is type text or bytea for all supported
|
* The right-hand const is type text or bytea for all supported
|
||||||
* operators
|
* operators. We do not expect to see binary-compatible types here,
|
||||||
|
* since const-folding should have relabeled the const to exactly match
|
||||||
|
* the operator's declared type.
|
||||||
*/
|
*/
|
||||||
Assert(((Const *) other)->consttype == TEXTOID ||
|
if (consttype != TEXTOID && consttype != BYTEAOID)
|
||||||
((Const *) other)->consttype == BYTEAOID);
|
return DEFAULT_MATCH_SEL;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The var, on the other hand, might be a binary-compatible type;
|
||||||
|
* particularly a domain. Try to fold it if it's not recognized
|
||||||
|
* immediately.
|
||||||
|
*/
|
||||||
|
vartype = var->vartype;
|
||||||
|
if (vartype != consttype)
|
||||||
|
vartype = getBaseType(vartype);
|
||||||
|
|
||||||
/* divide pattern into fixed prefix and remainder */
|
/* divide pattern into fixed prefix and remainder */
|
||||||
patt = (Const *) other;
|
patt = (Const *) other;
|
||||||
@ -878,12 +895,12 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
|
|||||||
/*
|
/*
|
||||||
* Pattern specifies an exact match, so pretend operator is '='
|
* Pattern specifies an exact match, so pretend operator is '='
|
||||||
*/
|
*/
|
||||||
Oid eqopr = find_operator("=", var->vartype);
|
Oid eqopr = find_operator("=", vartype);
|
||||||
List *eqargs;
|
List *eqargs;
|
||||||
|
|
||||||
if (eqopr == InvalidOid)
|
if (eqopr == InvalidOid)
|
||||||
elog(ERROR, "patternsel: no = operator for type %u",
|
elog(ERROR, "patternsel: no = operator for type %u",
|
||||||
var->vartype);
|
vartype);
|
||||||
eqargs = makeList2(var, prefix);
|
eqargs = makeList2(var, prefix);
|
||||||
result = DatumGetFloat8(DirectFunctionCall4(eqsel,
|
result = DatumGetFloat8(DirectFunctionCall4(eqsel,
|
||||||
PointerGetDatum(root),
|
PointerGetDatum(root),
|
||||||
@ -903,7 +920,7 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
|
|||||||
Selectivity selec;
|
Selectivity selec;
|
||||||
|
|
||||||
if (pstatus == Pattern_Prefix_Partial)
|
if (pstatus == Pattern_Prefix_Partial)
|
||||||
prefixsel = prefix_selectivity(root, var, prefix);
|
prefixsel = prefix_selectivity(root, var, vartype, prefix);
|
||||||
else
|
else
|
||||||
prefixsel = 1.0;
|
prefixsel = 1.0;
|
||||||
restsel = pattern_selectivity(rest, ptype);
|
restsel = pattern_selectivity(rest, ptype);
|
||||||
@ -1033,7 +1050,8 @@ booltestsel(Query *root, BoolTestType booltesttype, Node *arg,
|
|||||||
if (IsA(arg, RelabelType))
|
if (IsA(arg, RelabelType))
|
||||||
arg = (Node *) ((RelabelType *) arg)->arg;
|
arg = (Node *) ((RelabelType *) arg)->arg;
|
||||||
|
|
||||||
if (IsA(arg, Var) &&(varRelid == 0 || varRelid == ((Var *) arg)->varno))
|
if (IsA(arg, Var) &&
|
||||||
|
(varRelid == 0 || varRelid == ((Var *) arg)->varno))
|
||||||
var = (Var *) arg;
|
var = (Var *) arg;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1775,6 +1793,8 @@ mergejoinscansel(Query *root, Node *clause,
|
|||||||
{
|
{
|
||||||
Var *left,
|
Var *left,
|
||||||
*right;
|
*right;
|
||||||
|
Oid lefttype,
|
||||||
|
righttype;
|
||||||
Oid opno,
|
Oid opno,
|
||||||
lsortop,
|
lsortop,
|
||||||
rsortop,
|
rsortop,
|
||||||
@ -1799,6 +1819,24 @@ mergejoinscansel(Query *root, Node *clause,
|
|||||||
if (!right)
|
if (!right)
|
||||||
return; /* shouldn't happen */
|
return; /* shouldn't happen */
|
||||||
|
|
||||||
|
/* Save the direct input types of the operator */
|
||||||
|
lefttype = exprType((Node *) left);
|
||||||
|
righttype = exprType((Node *) right);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Now skip any binary-compatible relabeling; there can only be one level
|
||||||
|
* since constant-expression folder eliminates adjacent RelabelTypes.
|
||||||
|
*
|
||||||
|
* XXX can't enable this quite yet, it exposes regproc uncertainty problems
|
||||||
|
* in regression tests. FIXME soon.
|
||||||
|
*/
|
||||||
|
#if 0
|
||||||
|
if (IsA(left, RelabelType))
|
||||||
|
left = (Var *) ((RelabelType *) left)->arg;
|
||||||
|
if (IsA(right, RelabelType))
|
||||||
|
right = (Var *) ((RelabelType *) right)->arg;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Can't do anything if inputs are not Vars */
|
/* Can't do anything if inputs are not Vars */
|
||||||
if (!IsA(left, Var) ||
|
if (!IsA(left, Var) ||
|
||||||
!IsA(right, Var))
|
!IsA(right, Var))
|
||||||
@ -1841,13 +1879,13 @@ mergejoinscansel(Query *root, Node *clause,
|
|||||||
* non-default estimates, else stick with our 1.0.
|
* non-default estimates, else stick with our 1.0.
|
||||||
*/
|
*/
|
||||||
selec = scalarineqsel(root, leop, false, left,
|
selec = scalarineqsel(root, leop, false, left,
|
||||||
rightmax, right->vartype);
|
rightmax, righttype);
|
||||||
if (selec != DEFAULT_INEQ_SEL)
|
if (selec != DEFAULT_INEQ_SEL)
|
||||||
*leftscan = selec;
|
*leftscan = selec;
|
||||||
|
|
||||||
/* And similarly for the right variable. */
|
/* And similarly for the right variable. */
|
||||||
selec = scalarineqsel(root, revleop, false, right,
|
selec = scalarineqsel(root, revleop, false, right,
|
||||||
leftmax, left->vartype);
|
leftmax, lefttype);
|
||||||
if (selec != DEFAULT_INEQ_SEL)
|
if (selec != DEFAULT_INEQ_SEL)
|
||||||
*rightscan = selec;
|
*rightscan = selec;
|
||||||
|
|
||||||
@ -2263,6 +2301,19 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
|
|||||||
Datum lobound, Datum hibound, Oid boundstypid,
|
Datum lobound, Datum hibound, Oid boundstypid,
|
||||||
double *scaledlobound, double *scaledhibound)
|
double *scaledlobound, double *scaledhibound)
|
||||||
{
|
{
|
||||||
|
/*
|
||||||
|
* In present usage, we can assume that the valuetypid exactly matches
|
||||||
|
* the declared input type of the operator we are invoked for (because
|
||||||
|
* constant-folding will ensure that any Const passed to the operator
|
||||||
|
* has been reduced to the correct type). However, the boundstypid is
|
||||||
|
* the type of some variable that might be only binary-compatible with
|
||||||
|
* the declared type; in particular it might be a domain type. Must
|
||||||
|
* fold the variable type down to base type so we can recognize it.
|
||||||
|
* (But we can skip that lookup if the variable type matches the const.)
|
||||||
|
*/
|
||||||
|
if (boundstypid != valuetypid)
|
||||||
|
boundstypid = getBaseType(boundstypid);
|
||||||
|
|
||||||
switch (valuetypid)
|
switch (valuetypid)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
@ -3234,13 +3285,18 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype,
|
|||||||
* A fixed prefix "foo" is estimated as the selectivity of the expression
|
* A fixed prefix "foo" is estimated as the selectivity of the expression
|
||||||
* "var >= 'foo' AND var < 'fop'" (see also indxqual.c).
|
* "var >= 'foo' AND var < 'fop'" (see also indxqual.c).
|
||||||
*
|
*
|
||||||
|
* Because of constant-folding, we can assume that the prefixcon constant's
|
||||||
|
* type exactly matches the operator's declared input type; but it's not
|
||||||
|
* safe to make the same assumption for the Var, so the type to use for the
|
||||||
|
* Var must be passed in separately.
|
||||||
|
*
|
||||||
* XXX Note: we make use of the upper bound to estimate operator selectivity
|
* XXX Note: we make use of the upper bound to estimate operator selectivity
|
||||||
* even if the locale is such that we cannot rely on the upper-bound string.
|
* even if the locale is such that we cannot rely on the upper-bound string.
|
||||||
* The selectivity only needs to be approximately right anyway, so it seems
|
* The selectivity only needs to be approximately right anyway, so it seems
|
||||||
* more useful to use the upper-bound code than not.
|
* more useful to use the upper-bound code than not.
|
||||||
*/
|
*/
|
||||||
static Selectivity
|
static Selectivity
|
||||||
prefix_selectivity(Query *root, Var *var, Const *prefixcon)
|
prefix_selectivity(Query *root, Var *var, Oid vartype, Const *prefixcon)
|
||||||
{
|
{
|
||||||
Selectivity prefixsel;
|
Selectivity prefixsel;
|
||||||
Oid cmpopr;
|
Oid cmpopr;
|
||||||
@ -3248,17 +3304,17 @@ prefix_selectivity(Query *root, Var *var, Const *prefixcon)
|
|||||||
List *cmpargs;
|
List *cmpargs;
|
||||||
Const *greaterstrcon;
|
Const *greaterstrcon;
|
||||||
|
|
||||||
cmpopr = find_operator(">=", var->vartype);
|
cmpopr = find_operator(">=", vartype);
|
||||||
if (cmpopr == InvalidOid)
|
if (cmpopr == InvalidOid)
|
||||||
elog(ERROR, "prefix_selectivity: no >= operator for type %u",
|
elog(ERROR, "prefix_selectivity: no >= operator for type %u",
|
||||||
var->vartype);
|
vartype);
|
||||||
if (prefixcon->consttype != BYTEAOID)
|
if (prefixcon->consttype != BYTEAOID)
|
||||||
prefix = DatumGetCString(DirectFunctionCall1(textout, prefixcon->constvalue));
|
prefix = DatumGetCString(DirectFunctionCall1(textout, prefixcon->constvalue));
|
||||||
else
|
else
|
||||||
prefix = DatumGetCString(DirectFunctionCall1(byteaout, prefixcon->constvalue));
|
prefix = DatumGetCString(DirectFunctionCall1(byteaout, prefixcon->constvalue));
|
||||||
|
|
||||||
/* If var is type NAME, must adjust type of comparison constant */
|
/* If var is type NAME, must adjust type of comparison constant */
|
||||||
if (var->vartype == NAMEOID)
|
if (vartype == NAMEOID)
|
||||||
prefixcon = string_to_const(prefix, NAMEOID);
|
prefixcon = string_to_const(prefix, NAMEOID);
|
||||||
|
|
||||||
cmpargs = makeList2(var, prefixcon);
|
cmpargs = makeList2(var, prefixcon);
|
||||||
@ -3279,10 +3335,10 @@ prefix_selectivity(Query *root, Var *var, Const *prefixcon)
|
|||||||
{
|
{
|
||||||
Selectivity topsel;
|
Selectivity topsel;
|
||||||
|
|
||||||
cmpopr = find_operator("<", var->vartype);
|
cmpopr = find_operator("<", vartype);
|
||||||
if (cmpopr == InvalidOid)
|
if (cmpopr == InvalidOid)
|
||||||
elog(ERROR, "prefix_selectivity: no < operator for type %u",
|
elog(ERROR, "prefix_selectivity: no < operator for type %u",
|
||||||
var->vartype);
|
vartype);
|
||||||
cmpargs = makeList2(var, greaterstrcon);
|
cmpargs = makeList2(var, greaterstrcon);
|
||||||
/* Assume scalarltsel is appropriate for all supported types */
|
/* Assume scalarltsel is appropriate for all supported types */
|
||||||
topsel = DatumGetFloat8(DirectFunctionCall4(scalarltsel,
|
topsel = DatumGetFloat8(DirectFunctionCall4(scalarltsel,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user