OSDN Git Service

Tweak selectivity and related routines to cope with domains. Per report
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 23 Mar 2003 01:49:02 +0000 (01:49 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 23 Mar 2003 01:49:02 +0000 (01:49 +0000)
from Andreas Pflug.

src/backend/optimizer/path/indxpath.c
src/backend/utils/adt/selfuncs.c

index 5d16067..6d6d4db 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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,
  * generate suitable indexqual condition(s).  expr_op is the original
  * LIKE or regex operator; we use it to deduce the appropriate comparison
- * operators.
+ * operators and operand datatypes.
  */
 static List *
 prefix_quals(Node *leftop, Oid expr_op,
@@ -2094,10 +2094,13 @@ prefix_quals(Node *leftop, Oid expr_op,
                        return NIL;
        }
 
-       if (prefix_const->consttype != BYTEAOID)
-               prefix = DatumGetCString(DirectFunctionCall1(textout, prefix_const->constvalue));
+       /* Prefix constant is text for all except BYTEA_LIKE */
+       if (datatype != BYTEAOID)
+               prefix = DatumGetCString(DirectFunctionCall1(textout,
+                                                                                                        prefix_const->constvalue));
        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.
index 5955252..208b7eb 100644 (file)
@@ -15,7 +15,7 @@
  *
  *
  * 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/tlist.h"
 #include "optimizer/var.h"
+#include "parser/parse_expr.h"
 #include "parser/parse_func.h"
 #include "parser/parse_oper.h"
 #include "parser/parsetree.h"
@@ -176,7 +177,8 @@ static bool get_restriction_var(List *args, int varRelid,
                                        Var **var, Node **other,
                                        bool *varonleft);
 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 bool string_lessthan(const char *str1, const char *str2,
                                Oid datatype);
@@ -227,7 +229,8 @@ eqsel(PG_FUNCTION_ARGS)
         * If the something is a NULL constant, assume operator is strict and
         * 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);
 
        /* get stats for the attribute, if available */
@@ -834,6 +837,8 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
        bool            varonleft;
        Oid                     relid;
        Datum           constval;
+       Oid                     consttype;
+       Oid                     vartype;
        Pattern_Prefix_Status pstatus;
        Const      *patt = NULL;
        Const      *prefix = NULL;
@@ -861,13 +866,25 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
        if (((Const *) other)->constisnull)
                return 0.0;
        constval = ((Const *) other)->constvalue;
+       consttype = ((Const *) other)->consttype;
+
+       /*
+        * The right-hand const is type text or bytea for all supported
+        * 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.
+        */
+       if (consttype != TEXTOID && consttype != BYTEAOID)
+               return DEFAULT_MATCH_SEL;
 
        /*
-        * the right-hand const is type text or bytea for all supported
-        * operators
+        * 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.
         */
-       Assert(((Const *) other)->consttype == TEXTOID ||
-                  ((Const *) other)->consttype == BYTEAOID);
+       vartype = var->vartype;
+       if (vartype != consttype)
+               vartype = getBaseType(vartype);
 
        /* divide pattern into fixed prefix and remainder */
        patt = (Const *) other;
@@ -878,12 +895,12 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
                /*
                 * Pattern specifies an exact match, so pretend operator is '='
                 */
-               Oid                     eqopr = find_operator("=", var->vartype);
+               Oid                     eqopr = find_operator("=", vartype);
                List       *eqargs;
 
                if (eqopr == InvalidOid)
                        elog(ERROR, "patternsel: no = operator for type %u",
-                                var->vartype);
+                                vartype);
                eqargs = makeList2(var, prefix);
                result = DatumGetFloat8(DirectFunctionCall4(eqsel,
                                                                                                        PointerGetDatum(root),
@@ -903,7 +920,7 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
                Selectivity selec;
 
                if (pstatus == Pattern_Prefix_Partial)
-                       prefixsel = prefix_selectivity(root, var, prefix);
+                       prefixsel = prefix_selectivity(root, var, vartype, prefix);
                else
                        prefixsel = 1.0;
                restsel = pattern_selectivity(rest, ptype);
@@ -1033,7 +1050,8 @@ booltestsel(Query *root, BoolTestType booltesttype, Node *arg,
        if (IsA(arg, RelabelType))
                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;
        else
        {
@@ -1775,6 +1793,8 @@ mergejoinscansel(Query *root, Node *clause,
 {
        Var                *left,
                           *right;
+       Oid                     lefttype,
+                               righttype;
        Oid                     opno,
                                lsortop,
                                rsortop,
@@ -1799,6 +1819,24 @@ mergejoinscansel(Query *root, Node *clause,
        if (!right)
                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 */
        if (!IsA(left, Var) ||
                !IsA(right, Var))
@@ -1841,13 +1879,13 @@ mergejoinscansel(Query *root, Node *clause,
         * non-default estimates, else stick with our 1.0.
         */
        selec = scalarineqsel(root, leop, false, left,
-                                                 rightmax, right->vartype);
+                                                 rightmax, righttype);
        if (selec != DEFAULT_INEQ_SEL)
                *leftscan = selec;
 
        /* And similarly for the right variable. */
        selec = scalarineqsel(root, revleop, false, right,
-                                                 leftmax, left->vartype);
+                                                 leftmax, lefttype);
        if (selec != DEFAULT_INEQ_SEL)
                *rightscan = selec;
 
@@ -2263,6 +2301,19 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
                                  Datum lobound, Datum hibound, Oid boundstypid,
                                  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)
        {
                        /*
@@ -3234,13 +3285,18 @@ pattern_fixed_prefix(Const *patt, Pattern_Type ptype,
  * A fixed prefix "foo" is estimated as the selectivity of the expression
  * "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
  * 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
  * more useful to use the upper-bound code than not.
  */
 static Selectivity
-prefix_selectivity(Query *root, Var *var, Const *prefixcon)
+prefix_selectivity(Query *root, Var *var, Oid vartype, Const *prefixcon)
 {
        Selectivity prefixsel;
        Oid                     cmpopr;
@@ -3248,17 +3304,17 @@ prefix_selectivity(Query *root, Var *var, Const *prefixcon)
        List       *cmpargs;
        Const      *greaterstrcon;
 
-       cmpopr = find_operator(">=", var->vartype);
+       cmpopr = find_operator(">=", vartype);
        if (cmpopr == InvalidOid)
                elog(ERROR, "prefix_selectivity: no >= operator for type %u",
-                        var->vartype);
+                        vartype);
        if (prefixcon->consttype != BYTEAOID)
                prefix = DatumGetCString(DirectFunctionCall1(textout, prefixcon->constvalue));
        else
                prefix = DatumGetCString(DirectFunctionCall1(byteaout, prefixcon->constvalue));
 
        /* If var is type NAME, must adjust type of comparison constant */
-       if (var->vartype == NAMEOID)
+       if (vartype == NAMEOID)
                prefixcon = string_to_const(prefix, NAMEOID);
 
        cmpargs = makeList2(var, prefixcon);
@@ -3279,10 +3335,10 @@ prefix_selectivity(Query *root, Var *var, Const *prefixcon)
        {
                Selectivity topsel;
 
-               cmpopr = find_operator("<", var->vartype);
+               cmpopr = find_operator("<", vartype);
                if (cmpopr == InvalidOid)
                        elog(ERROR, "prefix_selectivity: no < operator for type %u",
-                                var->vartype);
+                                vartype);
                cmpargs = makeList2(var, greaterstrcon);
                /* Assume scalarltsel is appropriate for all supported types */
                topsel = DatumGetFloat8(DirectFunctionCall4(scalarltsel,