OSDN Git Service

Modify optimizer data structures so that IndexOptInfo lists built for
authorTom Lane <tgl@sss.pgh.pa.us>
Sun, 20 May 2001 20:28:20 +0000 (20:28 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sun, 20 May 2001 20:28:20 +0000 (20:28 +0000)
create_index_paths are not immediately discarded, but are available for
subsequent planner work.  This allows avoiding redundant syscache lookups
in several places.  Change interface to operator selectivity estimation
procedures to allow faster and more flexible estimation.
Initdb forced due to change of pg_proc entries for selectivity functions!

32 files changed:
src/backend/catalog/pg_operator.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/path/allpaths.c
src/backend/optimizer/path/clausesel.c
src/backend/optimizer/path/costsize.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/path/joinrels.c
src/backend/optimizer/path/orindxpath.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/initsplan.c
src/backend/optimizer/plan/planmain.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/pathnode.c
src/backend/optimizer/util/plancat.c
src/backend/optimizer/util/relnode.c
src/backend/utils/adt/selfuncs.c
src/include/catalog/catversion.h
src/include/catalog/pg_proc.h
src/include/nodes/parsenodes.h
src/include/nodes/relation.h
src/include/optimizer/clauses.h
src/include/optimizer/pathnode.h
src/include/optimizer/paths.h
src/include/optimizer/plancat.h
src/include/optimizer/prep.h
src/test/regress/expected/opr_sanity.out
src/test/regress/sql/opr_sanity.sql

index 11494b0..db54cee 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.57 2001/03/22 06:16:10 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/catalog/pg_operator.c,v 1.58 2001/05/20 20:28:17 tgl Exp $
  *
  * NOTES
  *       these routines moved here from commands/define.c and somewhat cleaned up.
@@ -69,7 +69,7 @@ static void OperatorUpd(Oid baseId, Oid commId, Oid negId);
 /* ----------------------------------------------------------------
  *             OperatorGetWithOpenRelation
  *
- *             preforms a scan on pg_operator for an operator tuple
+ *             performs a scan on pg_operator for an operator tuple
  *             with given name and left/right type oids.
  * ----------------------------------------------------------------
  *       pg_operator_desc      -- reldesc for pg_operator
@@ -570,26 +570,25 @@ OperatorDef(char *operatorName,
        ReleaseSysCache(tup);
 
        /*
-        * find restriction
+        * find restriction estimator
         */
        if (restrictionName)
        {                                                       /* optional */
                Oid                     restOid;
 
                MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
-               typeId[0] = OIDOID;             /* operator OID */
-               typeId[1] = OIDOID;             /* relation OID */
-               typeId[2] = INT2OID;    /* attribute number */
-               typeId[3] = 0;                  /* value - can be any type      */
-               typeId[4] = INT4OID;    /* flags - left or right selectivity */
+               typeId[0] = 0;                  /* Query (opaque type) */
+               typeId[1] = OIDOID;             /* operator OID */
+               typeId[2] = 0;                  /* args list (opaque type) */
+               typeId[3] = INT4OID;    /* varRelid */
 
                restOid = GetSysCacheOid(PROCNAME,
                                                                 PointerGetDatum(restrictionName),
-                                                                Int32GetDatum(5),
+                                                                Int32GetDatum(4),
                                                                 PointerGetDatum(typeId),
                                                                 0);
                if (!OidIsValid(restOid))
-                       func_error("OperatorDef", restrictionName, 5, typeId, NULL);
+                       func_error("OperatorDef", restrictionName, 4, typeId, NULL);
 
                values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(restOid);
        }
@@ -597,26 +596,24 @@ OperatorDef(char *operatorName,
                values[Anum_pg_operator_oprrest - 1] = ObjectIdGetDatum(InvalidOid);
 
        /*
-        * find join - only valid for binary operators
+        * find join estimator
         */
        if (joinName)
        {                                                       /* optional */
                Oid                     joinOid;
 
                MemSet(typeId, 0, FUNC_MAX_ARGS * sizeof(Oid));
-               typeId[0] = OIDOID;             /* operator OID */
-               typeId[1] = OIDOID;             /* relation OID 1 */
-               typeId[2] = INT2OID;    /* attribute number 1 */
-               typeId[3] = OIDOID;             /* relation OID 2 */
-               typeId[4] = INT2OID;    /* attribute number 2 */
+               typeId[0] = 0;                  /* Query (opaque type) */
+               typeId[1] = OIDOID;             /* operator OID */
+               typeId[2] = 0;                  /* args list (opaque type) */
 
                joinOid = GetSysCacheOid(PROCNAME,
                                                                 PointerGetDatum(joinName),
-                                                                Int32GetDatum(5),
+                                                                Int32GetDatum(3),
                                                                 PointerGetDatum(typeId),
                                                                 0);
                if (!OidIsValid(joinOid))
-                       func_error("OperatorDef", joinName, 5, typeId, NULL);
+                       func_error("OperatorDef", joinName, 3, typeId, NULL);
 
                values[Anum_pg_operator_oprjoin - 1] = ObjectIdGetDatum(joinOid);
        }
@@ -1044,10 +1041,8 @@ OperatorCreate(char *operatorName,
                /* If it's not a binary op, these things mustn't be set: */
                if (commutatorName)
                        elog(ERROR, "OperatorCreate: only binary operators can have commutators");
-               if (negatorName)
-                       elog(ERROR, "OperatorCreate: only binary operators can have negators");
-               if (restrictionName || joinName)
-                       elog(ERROR, "OperatorCreate: only binary operators can have selectivity");
+               if (joinName)
+                       elog(ERROR, "OperatorCreate: only binary operators can have join selectivity");
                if (canHash)
                        elog(ERROR, "OperatorCreate: only binary operators can hash");
                if (leftSortName || rightSortName)
index ee5a803..a5a9685 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.141 2001/05/07 00:43:18 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.142 2001/05/20 20:28:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1071,7 +1071,7 @@ _copyRelOptInfo(RelOptInfo *from)
        newnode->pruneable = from->pruneable;
 
        newnode->issubquery = from->issubquery;
-       newnode->indexed = from->indexed;
+       Node_Copy(from, newnode, indexlist);
        newnode->pages = from->pages;
        newnode->tuples = from->tuples;
        Node_Copy(from, newnode, subplan);
@@ -1093,47 +1093,44 @@ static IndexOptInfo *
 _copyIndexOptInfo(IndexOptInfo *from)
 {
        IndexOptInfo *newnode = makeNode(IndexOptInfo);
-       int                     i,
-                               len;
+       Size            len;
 
        newnode->indexoid = from->indexoid;
        newnode->pages = from->pages;
        newnode->tuples = from->tuples;
 
+       newnode->ncolumns = from->ncolumns;
+       newnode->nkeys = from->nkeys;
+
        if (from->classlist)
        {
-               for (len = 0; from->classlist[len] != 0; len++)
-                       ;
-               newnode->classlist = (Oid *) palloc(sizeof(Oid) * (len + 1));
-               for (i = 0; i < len; i++)
-                       newnode->classlist[i] = from->classlist[i];
-               newnode->classlist[len] = 0;
+               /* copy the trailing zero too */
+               len = (from->ncolumns + 1) * sizeof(Oid);
+               newnode->classlist = (Oid *) palloc(len);
+               memcpy(newnode->classlist, from->classlist, len);
        }
 
        if (from->indexkeys)
        {
-               for (len = 0; from->indexkeys[len] != 0; len++)
-                       ;
-               newnode->indexkeys = (int *) palloc(sizeof(int) * (len + 1));
-               for (i = 0; i < len; i++)
-                       newnode->indexkeys[i] = from->indexkeys[i];
-               newnode->indexkeys[len] = 0;
+               /* copy the trailing zero too */
+               len = (from->nkeys + 1) * sizeof(int);
+               newnode->indexkeys = (int *) palloc(len);
+               memcpy(newnode->indexkeys, from->indexkeys, len);
        }
 
        if (from->ordering)
        {
-               for (len = 0; from->ordering[len] != 0; len++)
-                       ;
-               newnode->ordering = (Oid *) palloc(sizeof(Oid) * (len + 1));
-               for (i = 0; i < len; i++)
-                       newnode->ordering[i] = from->ordering[i];
-               newnode->ordering[len] = 0;
+               /* copy the trailing zero too */
+               len = (from->ncolumns + 1) * sizeof(Oid);
+               newnode->ordering = (Oid *) palloc(len);
+               memcpy(newnode->ordering, from->ordering, len);
        }
 
        newnode->relam = from->relam;
        newnode->amcostestimate = from->amcostestimate;
        newnode->indproc = from->indproc;
        Node_Copy(from, newnode, indpred);
+       newnode->unique = from->unique;
        newnode->lossy = from->lossy;
 
        return newnode;
@@ -1196,7 +1193,7 @@ _copyIndexPath(IndexPath *from)
        /*
         * copy remainder of node
         */
-       newnode->indexid = listCopy(from->indexid);
+       Node_Copy(from, newnode, indexinfo);
        Node_Copy(from, newnode, indexqual);
        newnode->indexscandir = from->indexscandir;
        newnode->joinrelids = listCopy(from->joinrelids);
@@ -1749,8 +1746,8 @@ _copyQuery(Query *from)
 
        /*
         * We do not copy the planner internal fields: base_rel_list,
-        * join_rel_list, equi_key_list, query_pathkeys. Not entirely clear if
-        * this is right?
+        * other_rel_list, join_rel_list, equi_key_list, query_pathkeys.
+        * Not entirely clear if this is right?
         */
 
        return newnode;
index 284a534..a89a8f7 100644 (file)
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.89 2001/05/07 00:43:19 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.90 2001/05/20 20:28:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -405,7 +405,7 @@ _equalIndexPath(IndexPath *a, IndexPath *b)
 {
        if (!_equalPath((Path *) a, (Path *) b))
                return false;
-       if (!equali(a->indexid, b->indexid))
+       if (!equal(a->indexinfo, b->indexinfo))
                return false;
        if (!equal(a->indexqual, b->indexqual))
                return false;
@@ -623,9 +623,9 @@ _equalQuery(Query *a, Query *b)
 
        /*
         * We do not check the internal-to-the-planner fields: base_rel_list,
-        * join_rel_list, equi_key_list, query_pathkeys. They might not be set
-        * yet, and in any case they should be derivable from the other
-        * fields.
+        * other_rel_list, join_rel_list, equi_key_list, query_pathkeys.
+        * They might not be set yet, and in any case they should be derivable
+        * from the other fields.
         */
        return true;
 }
index 2c0cfed..ebcacd4 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.140 2001/03/22 03:59:32 momjian Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.141 2001/05/20 20:28:18 tgl Exp $
  *
  * NOTES
  *       Every (plan) node in POSTGRES has an associated "out" routine which
@@ -953,56 +953,6 @@ _outJoinExpr(StringInfo str, JoinExpr *node)
 }
 
 /*
- *     Stuff from relation.h
- */
-
-static void
-_outRelOptInfo(StringInfo str, RelOptInfo *node)
-{
-       appendStringInfo(str, " RELOPTINFO :relids ");
-       _outIntList(str, node->relids);
-
-       appendStringInfo(str, " :rows %.0f :width %d :targetlist ",
-                                        node->rows,
-                                        node->width);
-       _outNode(str, node->targetlist);
-
-       appendStringInfo(str, " :pathlist ");
-       _outNode(str, node->pathlist);
-       appendStringInfo(str, " :cheapest_startup_path ");
-       _outNode(str, node->cheapest_startup_path);
-       appendStringInfo(str, " :cheapest_total_path ");
-       _outNode(str, node->cheapest_total_path);
-
-       appendStringInfo(str, " :pruneable %s :issubquery %s :indexed %s :pages %ld :tuples %.0f :subplan ",
-                                        booltostr(node->pruneable),
-                                        booltostr(node->issubquery),
-                                        booltostr(node->indexed),
-                                        node->pages,
-                                        node->tuples);
-       _outNode(str, node->subplan);
-
-       appendStringInfo(str, " :baserestrictinfo ");
-       _outNode(str, node->baserestrictinfo);
-       appendStringInfo(str, " :baserestrictcost %.2f :outerjoinset ",
-                                        node->baserestrictcost);
-       _outIntList(str, node->outerjoinset);
-       appendStringInfo(str, " :joininfo ");
-       _outNode(str, node->joininfo);
-       appendStringInfo(str, " :innerjoin ");
-       _outNode(str, node->innerjoin);
-}
-
-static void
-_outIndexOptInfo(StringInfo str, IndexOptInfo *node)
-{
-       appendStringInfo(str, " INDEXOPTINFO :indexoid %u :pages %ld :tuples %g ",
-                                        node->indexoid,
-                                        node->pages,
-                                        node->tuples);
-}
-
-/*
  *     TargetEntry is a subclass of Node.
  */
 static void
@@ -1064,8 +1014,8 @@ _outIndexPath(StringInfo str, IndexPath *node)
                                         node->path.total_cost);
        _outNode(str, node->path.pathkeys);
 
-       appendStringInfo(str, " :indexid ");
-       _outOidList(str, node->indexid);
+       appendStringInfo(str, " :indexinfo ");
+       _outNode(str, node->indexinfo);
 
        appendStringInfo(str, " :indexqual ");
        _outNode(str, node->indexqual);
@@ -1629,12 +1579,6 @@ _outNode(StringInfo str, void *obj)
                        case T_JoinExpr:
                                _outJoinExpr(str, obj);
                                break;
-                       case T_RelOptInfo:
-                               _outRelOptInfo(str, obj);
-                               break;
-                       case T_IndexOptInfo:
-                               _outIndexOptInfo(str, obj);
-                               break;
                        case T_TargetEntry:
                                _outTargetEntry(str, obj);
                                break;
index 4c0c1b0..ad832d7 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.108 2001/05/07 00:43:19 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.109 2001/05/20 20:28:18 tgl Exp $
  *
  * NOTES
  *       Most of the read functions for plan nodes are tested. (In fact, they
@@ -1318,88 +1318,6 @@ _readJoinExpr(void)
        return local_node;
 }
 
-/*
- *     Stuff from relation.h
- */
-
-/* ----------------
- *             _readRelOptInfo
- * ----------------
- */
-static RelOptInfo *
-_readRelOptInfo(void)
-{
-       RelOptInfo *local_node;
-       char       *token;
-       int                     length;
-
-       local_node = makeNode(RelOptInfo);
-
-       token = pg_strtok(&length); /* get :relids */
-       local_node->relids = toIntList(nodeRead(true));         /* now read it */
-
-       token = pg_strtok(&length); /* get :rows */
-       token = pg_strtok(&length); /* now read it */
-       local_node->rows = atof(token);
-
-       token = pg_strtok(&length); /* get :width */
-       token = pg_strtok(&length); /* now read it */
-       local_node->width = atoi(token);
-
-       token = pg_strtok(&length); /* get :targetlist */
-       local_node->targetlist = nodeRead(true);        /* now read it */
-
-       token = pg_strtok(&length); /* get :pathlist */
-       local_node->pathlist = nodeRead(true);          /* now read it */
-
-       token = pg_strtok(&length); /* get :cheapest_startup_path */
-       local_node->cheapest_startup_path = nodeRead(true); /* now read it */
-
-       token = pg_strtok(&length); /* get :cheapest_total_path */
-       local_node->cheapest_total_path = nodeRead(true);       /* now read it */
-
-       token = pg_strtok(&length); /* eat :pruneable */
-       token = pg_strtok(&length); /* get :pruneable */
-       local_node->pruneable = strtobool(token);
-
-       token = pg_strtok(&length); /* get :issubquery */
-       token = pg_strtok(&length); /* now read it */
-       local_node->issubquery = strtobool(token);
-
-       token = pg_strtok(&length); /* get :indexed */
-       token = pg_strtok(&length); /* now read it */
-       local_node->indexed = strtobool(token);
-
-       token = pg_strtok(&length); /* get :pages */
-       token = pg_strtok(&length); /* now read it */
-       local_node->pages = atol(token);
-
-       token = pg_strtok(&length); /* get :tuples */
-       token = pg_strtok(&length); /* now read it */
-       local_node->tuples = atof(token);
-
-       token = pg_strtok(&length); /* get :subplan */
-       local_node->subplan = nodeRead(true);           /* now read it */
-
-       token = pg_strtok(&length); /* get :baserestrictinfo */
-       local_node->baserestrictinfo = nodeRead(true);          /* now read it */
-
-       token = pg_strtok(&length); /* get :baserestrictcost */
-       token = pg_strtok(&length); /* now read it */
-       local_node->baserestrictcost = (Cost) atof(token);
-
-       token = pg_strtok(&length); /* get :outerjoinset */
-       local_node->outerjoinset = toIntList(nodeRead(true));           /* now read it */
-
-       token = pg_strtok(&length); /* get :joininfo */
-       local_node->joininfo = nodeRead(true);          /* now read it */
-
-       token = pg_strtok(&length); /* get :innerjoin */
-       local_node->innerjoin = nodeRead(true);         /* now read it */
-
-       return local_node;
-}
-
 /* ----------------
  *             _readTargetEntry
  * ----------------
@@ -1557,8 +1475,8 @@ _readIndexPath(void)
        token = pg_strtok(&length); /* get :pathkeys */
        local_node->path.pathkeys = nodeRead(true); /* now read it */
 
-       token = pg_strtok(&length); /* get :indexid */
-       local_node->indexid = toOidList(nodeRead(true));
+       token = pg_strtok(&length); /* get :indexinfo */
+       local_node->indexinfo = nodeRead(true);         /* now read it */
 
        token = pg_strtok(&length); /* get :indexqual */
        local_node->indexqual = nodeRead(true);         /* now read it */
@@ -2008,8 +1926,6 @@ parsePlanString(void)
                return_value = _readOper();
        else if (length == 5 && strncmp(token, "PARAM", length) == 0)
                return_value = _readParam();
-       else if (length == 10 && strncmp(token, "RELOPTINFO", length) == 0)
-               return_value = _readRelOptInfo();
        else if (length == 11 && strncmp(token, "TARGETENTRY", length) == 0)
                return_value = _readTargetEntry();
        else if (length == 3 && strncmp(token, "RTE", length) == 0)
index 243ff7c..afb3259 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.73 2001/05/08 17:25:28 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.74 2001/05/20 20:28:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,8 +35,8 @@ static void set_base_rel_pathlists(Query *root);
 static void set_plain_rel_pathlist(Query *root, RelOptInfo *rel,
                                           RangeTblEntry *rte);
 static void set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
-                                                  RangeTblEntry *rte,
-                                                  List *inheritlist);
+                                                                          Index rti, RangeTblEntry *rte,
+                                                                          List *inheritlist);
 static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed,
                                          List *initial_rels);
 
@@ -69,7 +69,7 @@ make_one_rel(Query *root)
        rel = make_fromexpr_rel(root, root->jointree);
 
        /*
-        * The result should join all the query's rels.
+        * The result should join all the query's base rels.
         */
        Assert(length(rel->relids) == length(root->base_rel_list));
 
@@ -190,10 +190,11 @@ set_base_rel_pathlists(Query *root)
                        /* Select cheapest path (pretty easy in this case...) */
                        set_cheapest(rel);
                }
-               else if ((inheritlist = expand_inherted_rtentry(root, rti)) != NIL)
+               else if ((inheritlist = expand_inherted_rtentry(root, rti, true))
+                                != NIL)
                {
                        /* Relation is root of an inheritance tree, process specially */
-                       set_inherited_rel_pathlist(root, rel, rte, inheritlist);
+                       set_inherited_rel_pathlist(root, rel, rti, rte, inheritlist);
                }
                else
                {
@@ -210,8 +211,6 @@ set_base_rel_pathlists(Query *root)
 static void
 set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
 {
-       List       *indices = find_secondary_indexes(rte->relid);
-
        /* Mark rel with estimated output rows, width, etc */
        set_baserel_size_estimates(root, rel);
 
@@ -230,13 +229,9 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
        create_tidscan_paths(root, rel);
 
        /* Consider index paths for both simple and OR index clauses */
-       create_index_paths(root, rel, indices);
+       create_index_paths(root, rel);
 
-       /*
-        * Note: create_or_index_paths depends on create_index_paths to have
-        * marked OR restriction clauses with relevant indices; this is why it
-        * doesn't need to be given the list of indices.
-        */
+       /* create_index_paths must be done before create_or_index_paths */
        create_or_index_paths(root, rel, rel->baserestrictinfo);
 
        /* Now find the cheapest of the paths for this rel */
@@ -248,14 +243,26 @@ set_plain_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte)
  *       Build access paths for a inheritance tree rooted at rel
  *
  * inheritlist is a list of RT indexes of all tables in the inheritance tree,
- * including the parent itself.  Note we will not come here unless there's
- * at least one child in addition to the parent.
+ * including a duplicate of the parent itself.  Note we will not come here
+ * unless there's at least one child in addition to the parent.
+ *
+ * NOTE: the passed-in rel and RTE will henceforth represent the appended
+ * result of the whole inheritance tree.  The members of inheritlist represent
+ * the individual tables --- in particular, the inheritlist member that is a
+ * duplicate of the parent RTE represents the parent table alone.
+ * We will generate plans to scan the individual tables that refer to
+ * the inheritlist RTEs, whereas Vars elsewhere in the plan tree that
+ * refer to the original RTE are taken to refer to the append output.
+ * In particular, this means we have separate RelOptInfos for the parent
+ * table and for the append output, which is a good thing because they're
+ * not the same size.
  */
 static void
-set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte,
+set_inherited_rel_pathlist(Query *root, RelOptInfo *rel,
+                                                  Index rti, RangeTblEntry *rte,
                                                   List *inheritlist)
 {
-       int                     parentRTindex = lfirsti(rel->relids);
+       int                     parentRTindex = rti;
        Oid                     parentOID = rte->relid;
        List       *subpaths = NIL;
        List       *il;
@@ -268,7 +275,15 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte,
                elog(ERROR, "SELECT FOR UPDATE is not supported for inherit queries");
 
        /*
-        * Recompute size estimates for whole inheritance tree
+        * The executor will check the parent table's access permissions when it
+        * examines the parent's inheritlist entry.  There's no need to check
+        * twice, so turn off access check bits in the original RTE.
+        */
+       rte->checkForRead = false;
+       rte->checkForWrite = false;
+
+       /*
+        * Initialize to compute size estimates for whole inheritance tree
         */
        rel->rows = 0;
        rel->width = 0;
@@ -289,21 +304,17 @@ set_inherited_rel_pathlist(Query *root, RelOptInfo *rel, RangeTblEntry *rte,
 
                /*
                 * Make a RelOptInfo for the child so we can do planning.  Do NOT
-                * attach the RelOptInfo to the query's base_rel_list, however.
-                *
-                * NOTE: when childRTindex == parentRTindex, we create a second
-                * RelOptInfo for the same relation.  This RelOptInfo will
-                * represent the parent table alone, whereas the original
-                * RelOptInfo represents the union of the inheritance tree
-                * members.
+                * attach the RelOptInfo to the query's base_rel_list, however,
+                * since the child is not part of the main join tree.  Instead,
+                * the child RelOptInfo is added to other_rel_list.
                 */
-               childrel = make_base_rel(root, childRTindex);
+               childrel = build_other_rel(root, childRTindex);
 
                /*
                 * Copy the parent's targetlist and restriction quals to the
-                * child, with attribute-number adjustment if needed.  We don't
+                * child, with attribute-number adjustment as needed.  We don't
                 * bother to copy the join quals, since we can't do any joining
-                * here.
+                * of the individual tables.
                 */
                childrel->targetlist = (List *)
                        adjust_inherited_attrs((Node *) rel->targetlist,
index 2699b56..78407fb 100644 (file)
@@ -8,13 +8,15 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.43 2001/03/23 04:49:53 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/clausesel.c,v 1.44 2001/05/20 20:28:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include "catalog/pg_operator.h"
+#include "catalog/pg_type.h"
+#include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
 #include "optimizer/plancat.h"
 #include "utils/lsyscache.h"
 
 
+/* note that pg_type.h hardwires size of bool as 1 ... duplicate it */
+#define MAKEBOOLCONST(val,isnull) \
+       ((Node *) makeConst(BOOLOID, 1, (Datum) (val), \
+                                               (isnull), true, false, false))
+
+
 /*
  * Data structure for accumulating info about possible range-query
  * clause pairs in clauselist_selectivity.
@@ -39,7 +47,7 @@ typedef struct RangeQueryClause
 } RangeQueryClause;
 
 static void addRangeClause(RangeQueryClause **rqlist, Node *clause,
-                          int flag, bool isLTsel, Selectivity s2);
+                                                  bool varonleft, bool isLTsel, Selectivity s2);
 static Selectivity clause_selectivity(Query *root,
                                   Node *clause,
                                   int varRelid);
@@ -131,35 +139,24 @@ clauselist_selectivity(Query *root,
                 * match what clause_selectivity() would do in the cases it
                 * handles.
                 */
-               if (varRelid != 0 || NumRelids(clause) == 1)
+               if (is_opclause(clause) &&
+                       (varRelid != 0 || NumRelids(clause) == 1))
                {
-                       int                     relidx;
-                       AttrNumber      attno;
-                       Datum           constval;
-                       int                     flag;
-
-                       get_relattval(clause, varRelid,
-                                                 &relidx, &attno, &constval, &flag);
-                       if (relidx != 0)
+                       Expr       *expr = (Expr *) clause;
+
+                       if (length(expr->args) == 2)
                        {
-                               /* if get_relattval succeeded, it must be an opclause */
-                               Var                *other;
+                               bool            varonleft = true;
 
-                               other = (flag & SEL_RIGHT) ? get_rightop((Expr *) clause) :
-                                       get_leftop((Expr *) clause);
-                               if (is_pseudo_constant_clause((Node *) other))
+                               if (is_pseudo_constant_clause(lsecond(expr->args)) ||
+                                       (varonleft = false,
+                                        is_pseudo_constant_clause(lfirst(expr->args))))
                                {
-                                       Oid                     opno = ((Oper *) ((Expr *) clause)->oper)->opno;
+                                       Oid                     opno = ((Oper *) expr->oper)->opno;
                                        RegProcedure oprrest = get_oprrest(opno);
 
-                                       if (!oprrest)
-                                               s2 = (Selectivity) 0.5;
-                                       else
-                                               s2 = restriction_selectivity(oprrest, opno,
-                                                                                                        getrelid(relidx,
-                                                                                                                  root->rtable),
-                                                                                                        attno,
-                                                                                                        constval, flag);
+                                       s2 = restriction_selectivity(root, opno,
+                                                                                                expr->args, varRelid);
 
                                        /*
                                         * If we reach here, we have computed the same result
@@ -171,10 +168,12 @@ clauselist_selectivity(Query *root,
                                        switch (oprrest)
                                        {
                                                case F_SCALARLTSEL:
-                                                       addRangeClause(&rqlist, clause, flag, true, s2);
+                                                       addRangeClause(&rqlist, clause,
+                                                                                  varonleft, true, s2);
                                                        break;
                                                case F_SCALARGTSEL:
-                                                       addRangeClause(&rqlist, clause, flag, false, s2);
+                                                       addRangeClause(&rqlist, clause,
+                                                                                  varonleft, false, s2);
                                                        break;
                                                default:
                                                        /* Just merge the selectivity in generically */
@@ -220,7 +219,7 @@ clauselist_selectivity(Query *root,
                                         * No data available --- use a default estimate that
                                         * is small, but not real small.
                                         */
-                                       s2 = 0.01;
+                                       s2 = 0.005;
                                }
                                else
                                {
@@ -259,14 +258,13 @@ clauselist_selectivity(Query *root,
  */
 static void
 addRangeClause(RangeQueryClause **rqlist, Node *clause,
-                          int flag, bool isLTsel, Selectivity s2)
+                          bool varonleft, bool isLTsel, Selectivity s2)
 {
        RangeQueryClause *rqelem;
        Node       *var;
        bool            is_lobound;
 
-       /* get_relattval sets flag&SEL_RIGHT if the var is on the LEFT. */
-       if (flag & SEL_RIGHT)
+       if (varonleft)
        {
                var = (Node *) get_leftop((Expr *) clause);
                is_lobound = !isLTsel;  /* x < something is high bound */
@@ -405,12 +403,12 @@ clause_selectivity(Query *root,
                                 * is equivalent to the clause reln.attribute = 't', so we
                                 * compute the selectivity as if that is what we have.
                                 */
-                               s1 = restriction_selectivity(F_EQSEL,
+                               s1 = restriction_selectivity(root,
                                                                                         BooleanEqualOperator,
-                                                                                        rte->relid,
-                                                                                        var->varattno,
-                                                                                        BoolGetDatum(true),
-                                                                                        SEL_CONSTANT | SEL_RIGHT);
+                                                                                        makeList2(var,
+                                                                                                          MAKEBOOLCONST(true,
+                                                                                                                                        false)),
+                                                                                        varRelid);
                        }
                }
        }
@@ -486,57 +484,14 @@ clause_selectivity(Query *root,
                if (is_join_clause)
                {
                        /* Estimate selectivity for a join clause. */
-                       RegProcedure oprjoin = get_oprjoin(opno);
-
-                       /*
-                        * if the oprjoin procedure is missing for whatever reason,
-                        * use a selectivity of 0.5
-                        */
-                       if (!oprjoin)
-                               s1 = (Selectivity) 0.5;
-                       else
-                       {
-                               int                     relid1,
-                                                       relid2;
-                               AttrNumber      attno1,
-                                                       attno2;
-                               Oid                     reloid1,
-                                                       reloid2;
-
-                               get_rels_atts(clause, &relid1, &attno1, &relid2, &attno2);
-                               reloid1 = relid1 ? getrelid(relid1, root->rtable) : InvalidOid;
-                               reloid2 = relid2 ? getrelid(relid2, root->rtable) : InvalidOid;
-                               s1 = join_selectivity(oprjoin, opno,
-                                                                         reloid1, attno1,
-                                                                         reloid2, attno2);
-                       }
+                       s1 = join_selectivity(root, opno, 
+                                                                 ((Expr *) clause)->args);
                }
                else
                {
                        /* Estimate selectivity for a restriction clause. */
-                       RegProcedure oprrest = get_oprrest(opno);
-
-                       /*
-                        * if the oprrest procedure is missing for whatever reason,
-                        * use a selectivity of 0.5
-                        */
-                       if (!oprrest)
-                               s1 = (Selectivity) 0.5;
-                       else
-                       {
-                               int                     relidx;
-                               AttrNumber      attno;
-                               Datum           constval;
-                               int                     flag;
-                               Oid                     reloid;
-
-                               get_relattval(clause, varRelid,
-                                                         &relidx, &attno, &constval, &flag);
-                               reloid = relidx ? getrelid(relidx, root->rtable) : InvalidOid;
-                               s1 = restriction_selectivity(oprrest, opno,
-                                                                                        reloid, attno,
-                                                                                        constval, flag);
-                       }
+                       s1 = restriction_selectivity(root, opno, 
+                                                                                ((Expr *) clause)->args, varRelid);
                }
        }
        else if (is_funcclause(clause))
@@ -555,7 +510,7 @@ clause_selectivity(Query *root,
                /*
                 * Just for the moment! FIX ME! - vadim 02/04/98
                 */
-               s1 = 1.0;
+               s1 = (Selectivity) 0.5;
        }
        else if (IsA(clause, RelabelType))
        {
index dddca24..b4379e4 100644 (file)
@@ -42,7 +42,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.73 2001/05/09 23:13:34 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.74 2001/05/20 20:28:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -773,7 +773,7 @@ estimate_hash_bucketsize(Query *root, Var *var)
        if (relid == InvalidOid)
                return 0.1;
 
-       rel = get_base_rel(root, var->varno);
+       rel = find_base_rel(root, var->varno);
 
        if (rel->tuples <= 0.0 || rel->rows <= 0.0)
                return 0.1;                             /* ensure we can divide below */
index ca19465..a5f5bb1 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.104 2001/03/23 04:49:53 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.105 2001/05/20 20:28:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -127,18 +127,15 @@ static Const *string_to_const(const char *str, Oid datatype);
  * consideration in nested-loop joins.
  *
  * 'rel' is the relation for which we want to generate index paths
- * 'indices' is a list of available indexes for 'rel'
  */
 void
-create_index_paths(Query *root,
-                                  RelOptInfo *rel,
-                                  List *indices)
+create_index_paths(Query *root, RelOptInfo *rel)
 {
        List       *restrictinfo_list = rel->baserestrictinfo;
        List       *joininfo_list = rel->joininfo;
        List       *ilist;
 
-       foreach(ilist, indices)
+       foreach(ilist, rel->indexlist)
        {
                IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
                List       *restrictclauses;
@@ -1435,10 +1432,10 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
 
                /*
                 * Note that we are making a pathnode for a single-scan indexscan;
-                * therefore, both indexid and indexqual should be single-element
+                * therefore, both indexinfo and indexqual should be single-element
                 * lists.
                 */
-               pathnode->indexid = makeListi1(index->indexoid);
+               pathnode->indexinfo = makeList1(index);
                pathnode->indexqual = makeList1(indexquals);
 
                /* We don't actually care what order the index scans in ... */
@@ -2030,7 +2027,6 @@ find_operator(const char *opname, Oid datatype)
 static Datum
 string_to_datum(const char *str, Oid datatype)
 {
-
        /*
         * We cheat a little by assuming that textin() will do for bpchar and
         * varchar constants too...
index 929a977..3bde257 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.52 2001/03/22 03:59:35 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.53 2001/05/20 20:28:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -332,7 +332,7 @@ make_rels_by_clauseless_joins(Query *root,
 
 /*
  * make_jointree_rel
- *             Find or build a RelOptInfojoin rel representing a specific
+ *             Find or build a RelOptInfo join rel representing a specific
  *             jointree item.  For JoinExprs, we only consider the construction
  *             path that corresponds exactly to what the user wrote.
  */
@@ -343,7 +343,7 @@ make_jointree_rel(Query *root, Node *jtnode)
        {
                int                     varno = ((RangeTblRef *) jtnode)->rtindex;
 
-               return get_base_rel(root, varno);
+               return build_base_rel(root, varno);
        }
        else if (IsA(jtnode, FromExpr))
        {
@@ -402,7 +402,7 @@ make_join_rel(Query *root, RelOptInfo *rel1, RelOptInfo *rel2,
         * Find or build the join RelOptInfo, and compute the restrictlist
         * that goes with this particular joining.
         */
-       joinrel = get_join_rel(root, rel1, rel2, jointype, &restrictlist);
+       joinrel = build_join_rel(root, rel1, rel2, jointype, &restrictlist);
 
        /*
         * Consider paths using each rel as both outer and inner.
index d4e467c..25cbc3e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.42 2001/01/24 19:42:58 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/path/orindxpath.c,v 1.43 2001/05/20 20:28:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,8 +26,8 @@ static void best_or_subclause_indices(Query *root, RelOptInfo *rel,
                                                  IndexPath *pathnode);
 static void best_or_subclause_index(Query *root, RelOptInfo *rel,
                                                Expr *subclause, List *indices,
+                                               IndexOptInfo **retIndexInfo,
                                                List **retIndexQual,
-                                               Oid *retIndexid,
                                                Cost *retStartupCost,
                                                Cost *retTotalCost);
 
@@ -122,14 +122,14 @@ create_or_index_paths(Query *root,
  *       of an 'or' clause and the cost of scanning a relation using these
  *       indices.      The cost is the sum of the individual index costs, since
  *       the executor will perform a scan for each subclause of the 'or'.
+ *       Returns a list of IndexOptInfo nodes, one per scan.
  *
- * This routine also creates the indexqual and indexid lists that will
- * be needed by the executor.  The indexqual list has one entry for each
- * scan of the base rel, which is a sublist of indexqual conditions to
- * apply in that scan. The implicit semantics are AND across each sublist
- * of quals, and OR across the toplevel list (note that the executor
- * takes care not to return any single tuple more than once).  The indexid
- * list gives the OID of the index to be used in each scan.
+ * This routine also creates the indexqual list that will be needed by
+ * the executor.  The indexqual list has one entry for each scan of the base
+ * rel, which is a sublist of indexqual conditions to apply in that scan.
+ * The implicit semantics are AND across each sublist of quals, and OR across
+ * the toplevel list (note that the executor takes care not to return any
+ * single tuple more than once).
  *
  * 'rel' is the node of the relation on which the indexes are defined
  * 'subclauses' are the subclauses of the 'or' clause
@@ -138,9 +138,9 @@ create_or_index_paths(Query *root,
  * 'pathnode' is the IndexPath node being built.
  *
  * Results are returned by setting these fields of the passed pathnode:
+ * 'indexinfo' gets a list of the index IndexOptInfo nodes, one per scan
  * 'indexqual' gets the constructed indexquals for the path (a list
  *             of sublists of clauses, one sublist per scan of the base rel)
- * 'indexid' gets a list of the index OIDs for each scan of the rel
  * 'startup_cost' and 'total_cost' get the complete path costs.
  *
  * 'startup_cost' is the startup cost for the first index scan only;
@@ -161,28 +161,28 @@ best_or_subclause_indices(Query *root,
 {
        List       *slist;
 
+       pathnode->indexinfo = NIL;
        pathnode->indexqual = NIL;
-       pathnode->indexid = NIL;
        pathnode->path.startup_cost = 0;
        pathnode->path.total_cost = 0;
 
        foreach(slist, subclauses)
        {
                Expr       *subclause = lfirst(slist);
+               IndexOptInfo *best_indexinfo;
                List       *best_indexqual;
-               Oid                     best_indexid;
                Cost            best_startup_cost;
                Cost            best_total_cost;
 
                best_or_subclause_index(root, rel, subclause, lfirst(indices),
-                                                               &best_indexqual, &best_indexid,
+                                                               &best_indexinfo, &best_indexqual,
                                                                &best_startup_cost, &best_total_cost);
 
-               Assert(best_indexid != InvalidOid);
+               Assert(best_indexinfo != NULL);
 
+               pathnode->indexinfo = lappend(pathnode->indexinfo, best_indexinfo);
                pathnode->indexqual = lappend(pathnode->indexqual, best_indexqual);
-               pathnode->indexid = lappendi(pathnode->indexid, best_indexid);
-               if (slist == subclauses)/* first scan? */
+               if (slist == subclauses) /* first scan? */
                        pathnode->path.startup_cost = best_startup_cost;
                pathnode->path.total_cost += best_total_cost;
 
@@ -199,8 +199,8 @@ best_or_subclause_indices(Query *root,
  * 'rel' is the node of the relation on which the index is defined
  * 'subclause' is the OR subclause being considered
  * 'indices' is a list of IndexOptInfo nodes that match the subclause
+ * '*retIndexInfo' gets the IndexOptInfo of the best index
  * '*retIndexQual' gets a list of the indexqual conditions for the best index
- * '*retIndexid' gets the OID of the best index
  * '*retStartupCost' gets the startup cost of a scan with that index
  * '*retTotalCost' gets the total cost of a scan with that index
  */
@@ -209,8 +209,8 @@ best_or_subclause_index(Query *root,
                                                RelOptInfo *rel,
                                                Expr *subclause,
                                                List *indices,
+                                               IndexOptInfo **retIndexInfo, /* return value */
                                                List **retIndexQual,    /* return value */
-                                               Oid *retIndexid,                /* return value */
                                                Cost *retStartupCost,   /* return value */
                                                Cost *retTotalCost)             /* return value */
 {
@@ -218,8 +218,8 @@ best_or_subclause_index(Query *root,
        List       *ilist;
 
        /* if we don't match anything, return zeros */
+       *retIndexInfo = NULL;
        *retIndexQual = NIL;
-       *retIndexid = InvalidOid;
        *retStartupCost = 0;
        *retTotalCost = 0;
 
@@ -238,8 +238,8 @@ best_or_subclause_index(Query *root,
 
                if (first_time || subclause_path.total_cost < *retTotalCost)
                {
+                       *retIndexInfo = index;
                        *retIndexQual = indexqual;
-                       *retIndexid = index->indexoid;
                        *retStartupCost = subclause_path.startup_cost;
                        *retTotalCost = subclause_path.total_cost;
                        first_time = false;
index 2d264c4..81e7fec 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.105 2001/05/07 00:43:20 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.106 2001/05/20 20:28:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -18,7 +18,6 @@
 
 #include <sys/types.h>
 
-#include "catalog/pg_index.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
@@ -27,6 +26,7 @@
 #include "optimizer/planmain.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/tlist.h"
+#include "optimizer/var.h"
 #include "parser/parse_expr.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
@@ -56,11 +56,11 @@ static HashJoin *create_hashjoin_plan(HashPath *best_path, List *tlist,
                                         Plan *outer_plan, List *outer_tlist,
                                         Plan *inner_plan, List *inner_tlist);
 static List *fix_indxqual_references(List *indexquals, IndexPath *index_path);
-static List *fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
-                                        Form_pg_index index);
+static List *fix_indxqual_sublist(List *indexqual, int baserelid,
+                                                                 IndexOptInfo *index);
 static Node *fix_indxqual_operand(Node *node, int baserelid,
-                                        Form_pg_index index,
-                                        Oid *opclass);
+                                                                 IndexOptInfo *index,
+                                                                 Oid *opclass);
 static List *switch_outer(List *clauses);
 static void copy_path_costsize(Plan *dest, Path *src);
 static void copy_plan_costsize(Plan *dest, Plan *src);
@@ -365,7 +365,7 @@ create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses)
  * The indexqual of the path contains a sublist of implicitly-ANDed qual
  * conditions for each scan of the index(es); if there is more than one
  * scan then the retrieved tuple sets are ORed together.  The indexqual
- * and indexid lists must have the same length, ie, the number of scans
+ * and indexinfo lists must have the same length, ie, the number of scans
  * that will occur.  Note it is possible for a qual condition sublist
  * to be empty --- then no index restrictions will be applied during that
  * scan.
@@ -380,9 +380,10 @@ create_indexscan_plan(Query *root,
        Index           baserelid;
        List       *qpqual;
        List       *fixed_indxqual;
-       List       *ixid;
+       List       *indexids;
+       List       *ixinfo;
        IndexScan  *scan_plan;
-       bool            lossy = false;
+       bool            lossy;
 
        /* there should be exactly one base rel involved... */
        Assert(length(best_path->path.parent->relids) == 1);
@@ -390,25 +391,18 @@ create_indexscan_plan(Query *root,
 
        baserelid = lfirsti(best_path->path.parent->relids);
 
-       /* check to see if any of the indices are lossy */
-       foreach(ixid, best_path->indexid)
+       /*
+        * Build list of index OIDs, and check to see if any of the indices
+        * are lossy.
+        */
+       indexids = NIL;
+       lossy = false;
+       foreach(ixinfo, best_path->indexinfo)
        {
-               HeapTuple       indexTuple;
-               Form_pg_index index;
-
-               indexTuple = SearchSysCache(INDEXRELID,
-                                                                       ObjectIdGetDatum(lfirsti(ixid)),
-                                                                       0, 0, 0);
-               if (!HeapTupleIsValid(indexTuple))
-                       elog(ERROR, "create_plan: index %u not found", lfirsti(ixid));
-               index = (Form_pg_index) GETSTRUCT(indexTuple);
-               if (index->indislossy)
-               {
-                       lossy = true;
-                       ReleaseSysCache(indexTuple);
-                       break;
-               }
-               ReleaseSysCache(indexTuple);
+               IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
+
+               indexids = lappendi(indexids, index->indexoid);
+               lossy |= index->lossy;
        }
 
        /*
@@ -471,7 +465,7 @@ create_indexscan_plan(Query *root,
        scan_plan = make_indexscan(tlist,
                                                           qpqual,
                                                           baserelid,
-                                                          best_path->indexid,
+                                                          indexids,
                                                           fixed_indxqual,
                                                           indxqual,
                                                           best_path->indexscandir);
@@ -895,45 +889,19 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
 {
        List       *fixed_quals = NIL;
        int                     baserelid = lfirsti(index_path->path.parent->relids);
-       List       *indexids = index_path->indexid;
+       List       *ixinfo = index_path->indexinfo;
        List       *i;
 
        foreach(i, indexquals)
        {
                List       *indexqual = lfirst(i);
-               Oid                     indexid = lfirsti(indexids);
-               HeapTuple       indexTuple;
-               Oid                     relam;
-               Form_pg_index index;
-
-               /* Get the relam from the index's pg_class entry */
-               indexTuple = SearchSysCache(RELOID,
-                                                                       ObjectIdGetDatum(indexid),
-                                                                       0, 0, 0);
-               if (!HeapTupleIsValid(indexTuple))
-                       elog(ERROR, "fix_indxqual_references: index %u not found in pg_class",
-                                indexid);
-               relam = ((Form_pg_class) GETSTRUCT(indexTuple))->relam;
-               ReleaseSysCache(indexTuple);
-
-               /* Need the index's pg_index entry for other stuff */
-               indexTuple = SearchSysCache(INDEXRELID,
-                                                                       ObjectIdGetDatum(indexid),
-                                                                       0, 0, 0);
-               if (!HeapTupleIsValid(indexTuple))
-                       elog(ERROR, "fix_indxqual_references: index %u not found in pg_index",
-                                indexid);
-               index = (Form_pg_index) GETSTRUCT(indexTuple);
+               IndexOptInfo *index = (IndexOptInfo *) lfirst(ixinfo);
 
                fixed_quals = lappend(fixed_quals,
                                                          fix_indxqual_sublist(indexqual,
                                                                                                   baserelid,
-                                                                                                  relam,
                                                                                                   index));
-
-               ReleaseSysCache(indexTuple);
-
-               indexids = lnext(indexids);
+               ixinfo = lnext(ixinfo);
        }
        return fixed_quals;
 }
@@ -946,8 +914,7 @@ fix_indxqual_references(List *indexquals, IndexPath *index_path)
  * of the clause.)     Also change the operator if necessary.
  */
 static List *
-fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
-                                        Form_pg_index index)
+fix_indxqual_sublist(List *indexqual, int baserelid, IndexOptInfo *index)
 {
        List       *fixed_qual = NIL;
        List       *i;
@@ -955,27 +922,15 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
        foreach(i, indexqual)
        {
                Expr       *clause = (Expr *) lfirst(i);
-               int                     relid;
-               AttrNumber      attno;
-               Datum           constval;
-               int                     flag;
                Expr       *newclause;
+               List       *leftvarnos;
                Oid                     opclass,
                                        newopno;
 
-               if (!is_opclause((Node *) clause) ||
-                       length(clause->args) != 2)
+               if (!is_opclause((Node *) clause) || length(clause->args) != 2)
                        elog(ERROR, "fix_indxqual_sublist: indexqual clause is not binary opclause");
 
                /*
-                * Which side is the indexkey on?
-                *
-                * get_relattval sets flag&SEL_RIGHT if the indexkey is on the LEFT.
-                */
-               get_relattval((Node *) clause, baserelid,
-                                         &relid, &attno, &constval, &flag);
-
-               /*
                 * Make a copy that will become the fixed clause.
                 *
                 * We used to try to do a shallow copy here, but that fails if there
@@ -984,9 +939,15 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
                 */
                newclause = (Expr *) copyObject((Node *) clause);
 
-               /* If the indexkey is on the right, commute the clause. */
-               if ((flag & SEL_RIGHT) == 0)
+               /*
+                * Check to see if the indexkey is on the right; if so, commute
+                * the clause.  The indexkey should be the side that refers to
+                * (only) the base relation.
+                */
+               leftvarnos = pull_varnos((Node *) lfirst(newclause->args));
+               if (length(leftvarnos) != 1 || lfirsti(leftvarnos) != baserelid)
                        CommuteClause(newclause);
+               freeList(leftvarnos);
 
                /*
                 * Now, determine which index attribute this is, change the
@@ -1002,7 +963,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
                 * is merely binary-compatible with the index.  This shouldn't
                 * fail, since indxpath.c found it before...
                 */
-               newopno = indexable_operator(newclause, opclass, relam, true);
+               newopno = indexable_operator(newclause, opclass, index->relam, true);
                if (newopno == InvalidOid)
                        elog(ERROR, "fix_indxqual_sublist: failed to find substitute op");
                ((Oper *) newclause->oper)->opno = newopno;
@@ -1013,7 +974,7 @@ fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam,
 }
 
 static Node *
-fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index,
+fix_indxqual_operand(Node *node, int baserelid, IndexOptInfo *index,
                                         Oid *opclass)
 {
 
@@ -1033,27 +994,29 @@ fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index,
        if (IsA(node, Var))
        {
                /* If it's a var, find which index key position it occupies */
+               Assert(index->indproc == InvalidOid);
+
                if (((Var *) node)->varno == baserelid)
                {
                        int                     varatt = ((Var *) node)->varattno;
                        int                     pos;
 
-                       for (pos = 0; pos < INDEX_MAX_KEYS; pos++)
+                       for (pos = 0; pos < index->nkeys; pos++)
                        {
-                               if (index->indkey[pos] == varatt)
+                               if (index->indexkeys[pos] == varatt)
                                {
                                        Node       *newnode = copyObject(node);
 
                                        ((Var *) newnode)->varattno = pos + 1;
                                        /* return the correct opclass, too */
-                                       *opclass = index->indclass[pos];
+                                       *opclass = index->classlist[pos];
                                        return newnode;
                                }
                        }
                }
 
                /*
-                * Oops, this Var isn't the indexkey!
+                * Oops, this Var isn't an indexkey!
                 */
                elog(ERROR, "fix_indxqual_operand: var is not index attribute");
        }
@@ -1063,11 +1026,11 @@ fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index,
         * Since we currently only support single-column functional indexes,
         * the returned varattno must be 1.
         */
+       Assert(index->indproc != InvalidOid);
+       Assert(is_funcclause(node)); /* not a very thorough check, but easy */
 
-       Assert(is_funcclause(node));/* not a very thorough check, but easy */
-
-       /* indclass[0] is the only class of a functional index */
-       *opclass = index->indclass[0];
+       /* classlist[0] is the only class of a functional index */
+       *opclass = index->classlist[0];
 
        return (Node *) makeVar(baserelid, 1, exprType(node), -1, 0);
 }
index c62fd5e..3b3c761 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.61 2001/05/14 20:25:00 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.62 2001/05/20 20:28:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -73,8 +73,8 @@ build_base_rel_tlists(Query *root, List *tlist)
 /*
  * add_vars_to_targetlist
  *       For each variable appearing in the list, add it to the relation's
- *       targetlist if not already present.  Rel nodes will also be created
- *       if not already present.
+ *       targetlist if not already present.  Corresponding base rel nodes
+ *       will be created if not already present.
  */
 static void
 add_vars_to_targetlist(Query *root, List *vars)
@@ -84,7 +84,7 @@ add_vars_to_targetlist(Query *root, List *vars)
        foreach(temp, vars)
        {
                Var                *var = (Var *) lfirst(temp);
-               RelOptInfo *rel = get_base_rel(root, var->varno);
+               RelOptInfo *rel = build_base_rel(root, var->varno);
 
                add_var_to_tlist(rel, var);
        }
@@ -120,8 +120,8 @@ add_missing_rels_to_query(Query *root, Node *jtnode)
        {
                int                     varno = ((RangeTblRef *) jtnode)->rtindex;
 
-               /* This call to get_base_rel does the primary work... */
-               RelOptInfo *rel = get_base_rel(root, varno);
+               /* This call to build_base_rel does the primary work... */
+               RelOptInfo *rel = build_base_rel(root, varno);
 
                result = makeList1(rel);
        }
@@ -299,7 +299,7 @@ mark_baserels_for_outer_join(Query *root, Relids rels, Relids outerrels)
        foreach(relid, rels)
        {
                int                     relno = lfirsti(relid);
-               RelOptInfo *rel = get_base_rel(root, relno);
+               RelOptInfo *rel = build_base_rel(root, relno);
 
                /*
                 * Since we do this bottom-up, any outer-rels previously marked
@@ -422,7 +422,7 @@ distribute_qual_to_rels(Query *root, Node *clause,
                can_be_equijoin = true;
                foreach(relid, relids)
                {
-                       RelOptInfo *rel = get_base_rel(root, lfirsti(relid));
+                       RelOptInfo *rel = build_base_rel(root, lfirsti(relid));
 
                        if (rel->outerjoinset &&
                                !is_subseti(rel->outerjoinset, relids))
@@ -454,12 +454,11 @@ distribute_qual_to_rels(Query *root, Node *clause,
 
        if (length(relids) == 1)
        {
-
                /*
                 * There is only one relation participating in 'clause', so
                 * 'clause' is a restriction clause for that relation.
                 */
-               RelOptInfo *rel = get_base_rel(root, lfirsti(relids));
+               RelOptInfo *rel = build_base_rel(root, lfirsti(relids));
 
                rel->baserestrictinfo = lappend(rel->baserestrictinfo,
                                                                                restrictinfo);
@@ -564,7 +563,7 @@ add_join_info_to_rels(Query *root, RestrictInfo *restrictinfo,
                 * Find or make the joininfo node for this combination of rels,
                 * and add the restrictinfo node to it.
                 */
-               joininfo = find_joininfo_node(get_base_rel(root, cur_relid),
+               joininfo = find_joininfo_node(build_base_rel(root, cur_relid),
                                                                          unjoined_relids);
                joininfo->jinfo_restrictinfo = lappend(joininfo->jinfo_restrictinfo,
                                                                                           restrictinfo);
@@ -609,8 +608,11 @@ process_implied_equality(Query *root, Node *item1, Node *item2,
         * If both vars belong to same rel, we need to look at that rel's
         * baserestrictinfo list.  If different rels, each will have a
         * joininfo node for the other, and we can scan either list.
+        *
+        * All baserel entries should already exist at this point, so use
+        * find_base_rel not build_base_rel.
         */
-       rel1 = get_base_rel(root, irel1);
+       rel1 = find_base_rel(root, irel1);
        if (irel1 == irel2)
                restrictlist = rel1->baserestrictinfo;
        else
index b2b362e..2f52e69 100644 (file)
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.64 2001/03/22 03:59:37 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.65 2001/05/20 20:28:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -194,6 +194,7 @@ subplanner(Query *root,
         * construction.
         */
        root->base_rel_list = NIL;
+       root->other_rel_list = NIL;
        root->join_rel_list = NIL;
        root->equi_key_list = NIL;
 
index 0aba480..fbed3d6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.106 2001/05/07 00:43:21 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planner.c,v 1.107 2001/05/20 20:28:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -206,7 +206,8 @@ subquery_planner(Query *parse, double tuple_fraction)
         * grouping_planner.
         */
        if (parse->resultRelation &&
-       (lst = expand_inherted_rtentry(parse, parse->resultRelation)) != NIL)
+               (lst = expand_inherted_rtentry(parse, parse->resultRelation, false))
+               != NIL)
                plan = inheritance_planner(parse, lst);
        else
                plan = grouping_planner(parse, tuple_fraction);
index ede4159..42cc47f 100644 (file)
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.63 2001/05/07 00:43:22 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.64 2001/05/20 20:28:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -515,6 +515,11 @@ find_all_inheritors(Oid parentrel)
  *             whole inheritance set (parent and children).
  *             If not, return NIL.
  *
+ * When dup_parent is false, the initially given RT index is part of the
+ * returned list (if any).  When dup_parent is true, the given RT index
+ * is *not* in the returned list; a duplicate RTE will be made for the
+ * parent table.
+ *
  * A childless table is never considered to be an inheritance set; therefore
  * the result will never be a one-element list.  It'll be either empty
  * or have two or more elements.
@@ -525,7 +530,7 @@ find_all_inheritors(Oid parentrel)
  * for the case of an inherited UPDATE/DELETE target relation.
  */
 List *
-expand_inherted_rtentry(Query *parse, Index rti)
+expand_inherted_rtentry(Query *parse, Index rti, bool dup_parent)
 {
        RangeTblEntry *rte = rt_fetch(rti, parse->rtable);
        Oid                     parentOID = rte->relid;
@@ -544,7 +549,6 @@ expand_inherted_rtentry(Query *parse, Index rti)
                return NIL;
        /* Scan for all members of inheritance set */
        inhOIDs = find_all_inheritors(parentOID);
-
        /*
         * Check that there's at least one descendant, else treat as no-child
         * case.  This could happen despite above has_subclass() check, if
@@ -553,15 +557,19 @@ expand_inherted_rtentry(Query *parse, Index rti)
        if (lnext(inhOIDs) == NIL)
                return NIL;
        /* OK, it's an inheritance set; expand it */
-       inhRTIs = makeListi1(rti);
+       if (dup_parent)
+               inhRTIs = NIL;
+       else
+               inhRTIs = makeListi1(rti); /* include original RTE in result */
+
        foreach(l, inhOIDs)
        {
                Oid                     childOID = (Oid) lfirsti(l);
                RangeTblEntry *childrte;
                Index           childRTindex;
 
-               /* parent will be in the list too, so ignore it */
-               if (childOID == parentOID)
+               /* parent will be in the list too; skip it if not dup requested */
+               if (childOID == parentOID && !dup_parent)
                        continue;
 
                /*
@@ -578,6 +586,7 @@ expand_inherted_rtentry(Query *parse, Index rti)
 
                inhRTIs = lappendi(inhRTIs, childRTindex);
        }
+
        return inhRTIs;
 }
 
index 8bd6ef6..e0cc97e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.84 2001/03/27 17:12:34 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.85 2001/05/20 20:28:19 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -46,7 +46,6 @@ static bool pull_subplans_walker(Node *node, List **listptr);
 static bool check_subplans_for_ungrouped_vars_walker(Node *node,
                                                                                 Query *context);
 static bool contain_noncachable_functions_walker(Node *node, void *context);
-static int     is_single_func(Node *node);
 static Node *eval_const_expressions_mutator(Node *node, void *context);
 static Expr *simplify_op_or_func(Expr *expr, List *args);
 
@@ -797,202 +796,6 @@ NumRelids(Node *clause)
        return result;
 }
 
-/*
- * get_relattval
- *             Extract information from a restriction or join clause for
- *             selectivity estimation.  The inputs are an expression
- *             and a relation number (which can be 0 if we don't care which
- *             relation is used; that'd normally be the case for restriction
- *             clauses, where the caller already knows that only one relation
- *             is referenced in the clause).  The routine checks that the
- *             expression is of the form (var op something) or (something op var)
- *             where the var is an attribute of the specified relation, or
- *             a function of a var of the specified relation.  If so, it
- *             returns the following info:
- *                     the found relation number (same as targetrelid unless that is 0)
- *                     the found var number (or InvalidAttrNumber if a function)
- *                     if the "something" is a constant, the value of the constant
- *                     flags indicating whether a constant was found, and on which side.
- *             Default values are returned if the expression is too complicated,
- *             specifically 0 for the relid and attno, 0 for the constant value.
- *
- *             Note that negative attno values are *not* invalid, but represent
- *             system attributes such as OID.  It's sufficient to check for relid=0
- *             to determine whether the routine succeeded.
- */
-void
-get_relattval(Node *clause,
-                         int targetrelid,
-                         int *relid,
-                         AttrNumber *attno,
-                         Datum *constval,
-                         int *flag)
-{
-       Var                *left,
-                          *right,
-                          *other;
-       int                     funcvarno;
-
-       /* Careful; the passed clause might not be a binary operator at all */
-
-       if (!is_opclause(clause))
-               goto default_results;
-
-       left = get_leftop((Expr *) clause);
-       right = get_rightop((Expr *) clause);
-
-       if (!right)
-               goto default_results;
-
-       /* Ignore any binary-compatible relabeling */
-
-       if (IsA(left, RelabelType))
-               left = (Var *) ((RelabelType *) left)->arg;
-       if (IsA(right, RelabelType))
-               right = (Var *) ((RelabelType *) right)->arg;
-
-       /* First look for the var or func */
-
-       if (IsA(left, Var) &&
-               (targetrelid == 0 || targetrelid == left->varno))
-       {
-               *relid = left->varno;
-               *attno = left->varattno;
-               *flag = SEL_RIGHT;
-       }
-       else if (IsA(right, Var) &&
-                        (targetrelid == 0 || targetrelid == right->varno))
-       {
-               *relid = right->varno;
-               *attno = right->varattno;
-               *flag = 0;
-       }
-       else if ((funcvarno = is_single_func((Node *) left)) != 0 &&
-                        (targetrelid == 0 || targetrelid == funcvarno))
-       {
-               *relid = funcvarno;
-               *attno = InvalidAttrNumber;
-               *flag = SEL_RIGHT;
-       }
-       else if ((funcvarno = is_single_func((Node *) right)) != 0 &&
-                        (targetrelid == 0 || targetrelid == funcvarno))
-       {
-               *relid = funcvarno;
-               *attno = InvalidAttrNumber;
-               *flag = 0;
-       }
-       else
-       {
-               /* Duh, it's too complicated for me... */
-default_results:
-               *relid = 0;
-               *attno = 0;
-               *constval = 0;
-               *flag = 0;
-               return;
-       }
-
-       /* OK, we identified the var or func; now look at the other side */
-
-       other = (*flag == 0) ? left : right;
-
-       if (IsA(other, Const) &&
-               !((Const *) other)->constisnull)
-       {
-               *constval = ((Const *) other)->constvalue;
-               *flag |= SEL_CONSTANT;
-       }
-       else
-               *constval = 0;
-}
-
-/*
- * is_single_func
- *      If the given expression is a function of a single relation,
- *      return the relation number; else return 0
- */
-static int
-is_single_func(Node *node)
-{
-       if (is_funcclause(node))
-       {
-               List       *varnos = pull_varnos(node);
-
-               if (length(varnos) == 1)
-               {
-                       int                     funcvarno = lfirsti(varnos);
-
-                       freeList(varnos);
-                       return funcvarno;
-               }
-               freeList(varnos);
-       }
-       return 0;
-}
-
-/*
- * get_rels_atts
- *
- * Returns the info
- *                             ( relid1 attno1 relid2 attno2 )
- *             for a joinclause.
- *
- * If the clause is not of the form (var op var) or if any of the vars
- * refer to nested attributes, then zeroes are returned.
- */
-void
-get_rels_atts(Node *clause,
-                         int *relid1,
-                         AttrNumber *attno1,
-                         int *relid2,
-                         AttrNumber *attno2)
-{
-       /* set default values */
-       *relid1 = 0;
-       *attno1 = 0;
-       *relid2 = 0;
-       *attno2 = 0;
-
-       if (is_opclause(clause))
-       {
-               Var                *left = get_leftop((Expr *) clause);
-               Var                *right = get_rightop((Expr *) clause);
-
-               if (left && right)
-               {
-                       int                     funcvarno;
-
-                       /* Ignore any binary-compatible relabeling */
-                       if (IsA(left, RelabelType))
-                               left = (Var *) ((RelabelType *) left)->arg;
-                       if (IsA(right, RelabelType))
-                               right = (Var *) ((RelabelType *) right)->arg;
-
-                       if (IsA(left, Var))
-                       {
-                               *relid1 = left->varno;
-                               *attno1 = left->varattno;
-                       }
-                       else if ((funcvarno = is_single_func((Node *) left)) != 0)
-                       {
-                               *relid1 = funcvarno;
-                               *attno1 = InvalidAttrNumber;
-                       }
-
-                       if (IsA(right, Var))
-                       {
-                               *relid2 = right->varno;
-                               *attno2 = right->varattno;
-                       }
-                       else if ((funcvarno = is_single_func((Node *) right)) != 0)
-                       {
-                               *relid2 = funcvarno;
-                               *attno2 = InvalidAttrNumber;
-                       }
-               }
-       }
-}
-
 /*--------------------
  * CommuteClause: commute a binary operator clause
  *
index 407c132..801b328 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.72 2001/05/07 00:43:22 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.73 2001/05/20 20:28:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -346,9 +346,9 @@ create_index_path(Query *root,
 
        /*
         * We are making a pathnode for a single-scan indexscan; therefore,
-        * both indexid and indexqual should be single-element lists.
+        * both indexinfo and indexqual should be single-element lists.
         */
-       pathnode->indexid = makeListi1(index->indexoid);
+       pathnode->indexinfo = makeList1(index);
        pathnode->indexqual = makeList1(indexquals);
 
        pathnode->indexscandir = indexscandir;
index ee35235..749390a 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.65 2001/05/07 00:43:22 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.66 2001/05/20 20:28:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "catalog/pg_amop.h"
 #include "catalog/pg_inherits.h"
 #include "catalog/pg_index.h"
+#include "optimizer/clauses.h"
 #include "optimizer/plancat.h"
+#include "parser/parsetree.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
 #include "utils/relcache.h"
 #include "utils/syscache.h"
 #include "catalog/catalog.h"
@@ -33,7 +36,7 @@
 
 
 /*
- * relation_info -
+ * get_relation_info -
  *       Retrieves catalog information for a given relation.
  *       Given the Oid of the relation, return the following info:
  *                             whether the relation has secondary indices
@@ -41,8 +44,8 @@
  *                             number of tuples
  */
 void
-relation_info(Oid relationObjectId,
-                         bool *hasindex, long *pages, double *tuples)
+get_relation_info(Oid relationObjectId,
+                                 bool *hasindex, long *pages, double *tuples)
 {
        HeapTuple       relationTuple;
        Form_pg_class relation;
@@ -51,16 +54,19 @@ relation_info(Oid relationObjectId,
                                                                   ObjectIdGetDatum(relationObjectId),
                                                                   0, 0, 0);
        if (!HeapTupleIsValid(relationTuple))
-               elog(ERROR, "relation_info: Relation %u not found",
+               elog(ERROR, "get_relation_info: Relation %u not found",
                         relationObjectId);
        relation = (Form_pg_class) GETSTRUCT(relationTuple);
 
-       if (IsIgnoringSystemIndexes() && IsSystemRelationName(NameStr(relation->relname)))
+       if (IsIgnoringSystemIndexes() &&
+               IsSystemRelationName(NameStr(relation->relname)))
                *hasindex = false;
        else
-               *hasindex = (relation->relhasindex) ? true : false;
+               *hasindex = relation->relhasindex;
+
        *pages = relation->relpages;
        *tuples = relation->reltuples;
+
        ReleaseSysCache(relationTuple);
 }
 
@@ -110,8 +116,8 @@ find_secondary_indexes(Oid relationObjectId)
                info = makeNode(IndexOptInfo);
 
                /*
-                * Need to make these arrays large enough to be sure there is a
-                * terminating 0 at the end of each one.
+                * Need to make these arrays large enough to be sure there is
+                * room for a terminating 0 at the end of each one.
                 */
                info->classlist = (Oid *) palloc(sizeof(Oid) * (INDEX_MAX_KEYS + 1));
                info->indexkeys = (int *) palloc(sizeof(int) * (INDEX_MAX_KEYS + 1));
@@ -131,14 +137,26 @@ find_secondary_indexes(Oid relationObjectId)
                }
                else
                        info->indpred = NIL;
+               info->unique = index->indisunique;
                info->lossy = index->indislossy;
 
                for (i = 0; i < INDEX_MAX_KEYS; i++)
-                       info->indexkeys[i] = index->indkey[i];
-               info->indexkeys[INDEX_MAX_KEYS] = 0;
-               for (i = 0; i < INDEX_MAX_KEYS; i++)
+               {
+                       if (index->indclass[i] == (Oid) 0)
+                               break;
                        info->classlist[i] = index->indclass[i];
-               info->classlist[INDEX_MAX_KEYS] = (Oid) 0;
+               }
+               info->classlist[i] = (Oid) 0;
+               info->ncolumns = i;
+
+               for (i = 0; i < INDEX_MAX_KEYS; i++)
+               {
+                       if (index->indkey[i] == 0)
+                               break;
+                       info->indexkeys[i] = index->indkey[i];
+               }
+               info->indexkeys[i] = 0;
+               info->nkeys = i;
 
                /* Extract info from the relation descriptor for the index */
                indexRelation = index_open(index->indexrelid);
@@ -156,7 +174,7 @@ find_secondary_indexes(Oid relationObjectId)
                MemSet(info->ordering, 0, sizeof(Oid) * (INDEX_MAX_KEYS + 1));
                if (amorderstrategy != 0)
                {
-                       for (i = 0; i < INDEX_MAX_KEYS && index->indclass[i]; i++)
+                       for (i = 0; i < info->ncolumns; i++)
                        {
                                HeapTuple       amopTuple;
                                Form_pg_amop amop;
@@ -193,30 +211,34 @@ find_secondary_indexes(Oid relationObjectId)
 /*
  * restriction_selectivity
  *
- * Returns the selectivity of a specified operator.
+ * Returns the selectivity of a specified restriction operator clause.
  * This code executes registered procedures stored in the
  * operator relation, by calling the function manager.
  *
- * XXX The assumption in the selectivity procedures is that if the
- *             relation OIDs or attribute numbers are 0, then the clause
- *             isn't of the form (op var const).
+ * varRelid is either 0 or a rangetable index.  See clause_selectivity()
+ * for details about its meaning.
  */
 Selectivity
-restriction_selectivity(Oid functionObjectId,
-                                               Oid operatorObjectId,
-                                               Oid relationObjectId,
-                                               AttrNumber attributeNumber,
-                                               Datum constValue,
-                                               int constFlag)
+restriction_selectivity(Query *root,
+                                               Oid operator,
+                                               List *args,
+                                               int varRelid)
 {
+       RegProcedure oprrest = get_oprrest(operator);
        float8          result;
 
-       result = DatumGetFloat8(OidFunctionCall5(functionObjectId,
-                                                                         ObjectIdGetDatum(operatorObjectId),
-                                                                         ObjectIdGetDatum(relationObjectId),
-                                                                                 Int16GetDatum(attributeNumber),
-                                                                                        constValue,
-                                                                                        Int32GetDatum(constFlag)));
+       /*
+        * if the oprrest procedure is missing for whatever reason,
+        * use a selectivity of 0.5
+        */
+       if (!oprrest)
+               return (Selectivity) 0.5;
+
+       result = DatumGetFloat8(OidFunctionCall4(oprrest,
+                                                                                        PointerGetDatum(root),
+                                                                                        ObjectIdGetDatum(operator),
+                                                                                        PointerGetDatum(args),
+                                                                                        Int32GetDatum(varRelid)));
 
        if (result < 0.0 || result > 1.0)
                elog(ERROR, "restriction_selectivity: bad value %f", result);
@@ -227,29 +249,29 @@ restriction_selectivity(Oid functionObjectId,
 /*
  * join_selectivity
  *
- * Returns the selectivity of an operator, given the join clause
- * information.
- *
- * XXX The assumption in the selectivity procedures is that if the
- *             relation OIDs or attribute numbers are 0, then the clause
- *             isn't of the form (op var var).
+ * Returns the selectivity of a specified join operator clause.
+ * This code executes registered procedures stored in the
+ * operator relation, by calling the function manager.
  */
 Selectivity
-join_selectivity(Oid functionObjectId,
-                                Oid operatorObjectId,
-                                Oid relationObjectId1,
-                                AttrNumber attributeNumber1,
-                                Oid relationObjectId2,
-                                AttrNumber attributeNumber2)
+join_selectivity(Query *root,
+                                Oid operator,
+                                List *args)
 {
+       RegProcedure oprjoin = get_oprjoin(operator);
        float8          result;
 
-       result = DatumGetFloat8(OidFunctionCall5(functionObjectId,
-                                                                         ObjectIdGetDatum(operatorObjectId),
-                                                                        ObjectIdGetDatum(relationObjectId1),
-                                                                                Int16GetDatum(attributeNumber1),
-                                                                        ObjectIdGetDatum(relationObjectId2),
-                                                                          Int16GetDatum(attributeNumber2)));
+       /*
+        * if the oprjoin procedure is missing for whatever reason,
+        * use a selectivity of 0.5
+        */
+       if (!oprjoin)
+               return (Selectivity) 0.5;
+
+       result = DatumGetFloat8(OidFunctionCall3(oprjoin,
+                                                                                        PointerGetDatum(root),
+                                                                                        ObjectIdGetDatum(operator),
+                                                                                        PointerGetDatum(args)));
 
        if (result < 0.0 || result > 1.0)
                elog(ERROR, "join_selectivity: bad value %f", result);
@@ -330,3 +352,36 @@ has_subclass(Oid relationId)
        ReleaseSysCache(tuple);
        return result;
 }
+
+/*
+ * has_unique_index
+ *
+ * Detect whether there is a unique index on the specified attribute
+ * of the specified relation, thus allowing us to conclude that all
+ * the (non-null) values of the attribute are distinct.
+ */
+bool
+has_unique_index(RelOptInfo *rel, AttrNumber attno)
+{
+       List       *ilist;
+
+       foreach(ilist, rel->indexlist)
+       {
+               IndexOptInfo *index = (IndexOptInfo *) lfirst(ilist);
+
+               /*
+                * Note: ignore functional, partial, or lossy indexes, since they
+                * don't allow us to conclude that all attr values are distinct.
+                * Also, a multicolumn unique index doesn't allow us to conclude
+                * that just the specified attr is unique.
+                */
+               if (index->unique &&
+                       index->nkeys == 1 &&
+                       index->indexkeys[0] == attno &&
+                       index->indproc == InvalidOid &&
+                       index->indpred == NIL &&
+                       !index->lossy)
+                       return true;
+       }
+       return false;
+}
index b4764ab..86d9231 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.32 2001/02/16 00:03:08 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/relnode.c,v 1.33 2001/05/20 20:28:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -22,6 +22,7 @@
 #include "parser/parsetree.h"
 
 
+static RelOptInfo *make_base_rel(Query *root, int relid);
 static List *new_join_tlist(List *tlist, int first_resdomno);
 static List *build_joinrel_restrictlist(RelOptInfo *joinrel,
                                                   RelOptInfo *outer_rel,
@@ -36,28 +37,35 @@ static void subbuild_joinrel_joinlist(RelOptInfo *joinrel,
 
 
 /*
- * get_base_rel
+ * build_base_rel
  *       Returns relation entry corresponding to 'relid', creating a new one
  *       if necessary.  This is for base relations.
  */
 RelOptInfo *
-get_base_rel(Query *root, int relid)
+build_base_rel(Query *root, int relid)
 {
-       List       *baserels;
+       List       *rels;
        RelOptInfo *rel;
 
-       foreach(baserels, root->base_rel_list)
+       /* Already made? */
+       foreach(rels, root->base_rel_list)
        {
-               rel = (RelOptInfo *) lfirst(baserels);
+               rel = (RelOptInfo *) lfirst(rels);
 
-               /*
-                * We know length(rel->relids) == 1 for all members of
-                * base_rel_list
-                */
+               /* length(rel->relids) == 1 for all members of base_rel_list */
                if (lfirsti(rel->relids) == relid)
                        return rel;
        }
 
+       /* It should not exist as an "other" rel */
+       foreach(rels, root->other_rel_list)
+       {
+               rel = (RelOptInfo *) lfirst(rels);
+
+               if (lfirsti(rel->relids) == relid)
+                       elog(ERROR, "build_base_rel: rel already exists as 'other' rel");
+       }
+
        /* No existing RelOptInfo for this base rel, so make a new one */
        rel = make_base_rel(root, relid);
 
@@ -68,16 +76,52 @@ get_base_rel(Query *root, int relid)
 }
 
 /*
+ * build_other_rel
+ *       Returns relation entry corresponding to 'relid', creating a new one
+ *       if necessary.  This is for 'other' relations, which are just like
+ *       base relations except that they live in a different list.
+ */
+RelOptInfo *
+build_other_rel(Query *root, int relid)
+{
+       List       *rels;
+       RelOptInfo *rel;
+
+       /* Already made? */
+       foreach(rels, root->other_rel_list)
+       {
+               rel = (RelOptInfo *) lfirst(rels);
+
+               /* length(rel->relids) == 1 for all members of other_rel_list */
+               if (lfirsti(rel->relids) == relid)
+                       return rel;
+       }
+
+       /* It should not exist as a base rel */
+       foreach(rels, root->base_rel_list)
+       {
+               rel = (RelOptInfo *) lfirst(rels);
+
+               if (lfirsti(rel->relids) == relid)
+                       elog(ERROR, "build_other_rel: rel already exists as base rel");
+       }
+
+       /* No existing RelOptInfo for this other rel, so make a new one */
+       rel = make_base_rel(root, relid);
+
+       /* and add it to the list */
+       root->other_rel_list = lcons(rel, root->other_rel_list);
+
+       return rel;
+}
+
+/*
  * make_base_rel
  *       Construct a base-relation RelOptInfo for the specified rangetable index.
  *
- * This is split out of get_base_rel so that inheritance-tree processing can
- * construct baserel nodes for child tables.  We need a RelOptInfo so we can
- * plan a suitable access path for each child table, but we do NOT want to
- * enter the child nodes into base_rel_list.  In most contexts, get_base_rel
- * should be called instead.
+ * Common code for build_base_rel and build_other_rel.
  */
-RelOptInfo *
+static RelOptInfo *
 make_base_rel(Query *root, int relid)
 {
        RelOptInfo *rel = makeNode(RelOptInfo);
@@ -92,7 +136,7 @@ make_base_rel(Query *root, int relid)
        rel->cheapest_total_path = NULL;
        rel->pruneable = true;
        rel->issubquery = false;
-       rel->indexed = false;
+       rel->indexlist = NIL;
        rel->pages = 0;
        rel->tuples = 0;
        rel->subplan = NULL;
@@ -108,8 +152,12 @@ make_base_rel(Query *root, int relid)
        if (relationObjectId != InvalidOid)
        {
                /* Plain relation --- retrieve statistics from the system catalogs */
-               relation_info(relationObjectId,
-                                         &rel->indexed, &rel->pages, &rel->tuples);
+               bool    indexed;
+
+               get_relation_info(relationObjectId,
+                                                 &indexed, &rel->pages, &rel->tuples);
+               if (indexed)
+                       rel->indexlist = find_secondary_indexes(relationObjectId);
        }
        else
        {
@@ -121,12 +169,45 @@ make_base_rel(Query *root, int relid)
 }
 
 /*
+ * find_base_rel
+ *       Find a base or other relation entry, which must already exist
+ *       (since we'd have no idea which list to add it to).
+ */
+RelOptInfo *
+find_base_rel(Query *root, int relid)
+{
+       List       *rels;
+       RelOptInfo *rel;
+
+       foreach(rels, root->base_rel_list)
+       {
+               rel = (RelOptInfo *) lfirst(rels);
+
+               /* length(rel->relids) == 1 for all members of base_rel_list */
+               if (lfirsti(rel->relids) == relid)
+                       return rel;
+       }
+
+       foreach(rels, root->other_rel_list)
+       {
+               rel = (RelOptInfo *) lfirst(rels);
+
+               if (lfirsti(rel->relids) == relid)
+                       return rel;
+       }
+
+       elog(ERROR, "find_base_rel: no relation entry for relid %d", relid);
+
+       return NULL;                            /* keep compiler quiet */
+}
+
+/*
  * find_join_rel
  *       Returns relation entry corresponding to 'relids' (a list of RT indexes),
  *       or NULL if none exists.  This is for join relations.
  *
  * Note: there is probably no good reason for this to be called from
- * anywhere except get_join_rel, but keep it as a separate routine
+ * anywhere except build_join_rel, but keep it as a separate routine
  * just in case.
  */
 static RelOptInfo *
@@ -146,7 +227,7 @@ find_join_rel(Query *root, Relids relids)
 }
 
 /*
- * get_join_rel
+ * build_join_rel
  *       Returns relation entry corresponding to the union of two given rels,
  *       creating a new relation entry if none already exists.
  *
@@ -161,11 +242,11 @@ find_join_rel(Query *root, Relids relids)
  * duplicated calculation of the restrictlist...
  */
 RelOptInfo *
-get_join_rel(Query *root,
-                        RelOptInfo *outer_rel,
-                        RelOptInfo *inner_rel,
-                        JoinType jointype,
-                        List **restrictlist_ptr)
+build_join_rel(Query *root,
+                          RelOptInfo *outer_rel,
+                          RelOptInfo *inner_rel,
+                          JoinType jointype,
+                          List **restrictlist_ptr)
 {
        List       *joinrelids;
        RelOptInfo *joinrel;
@@ -212,7 +293,7 @@ get_join_rel(Query *root,
        joinrel->cheapest_total_path = NULL;
        joinrel->pruneable = true;
        joinrel->issubquery = false;
-       joinrel->indexed = false;
+       joinrel->indexlist = NIL;
        joinrel->pages = 0;
        joinrel->tuples = 0;
        joinrel->subplan = NULL;
index d7633dc..07c4da1 100644 (file)
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.89 2001/05/09 23:13:35 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/selfuncs.c,v 1.90 2001/05/20 20:28:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
+/*----------
+ * Operator selectivity estimation functions are called to estimate the
+ * selectivity of WHERE clauses whose top-level operator is their operator.
+ * We divide the problem into two cases:
+ *             Restriction clause estimation: the clause involves vars of just
+ *                     one relation.
+ *             Join clause estimation: the clause involves vars of multiple rels.
+ * Join selectivity estimation is far more difficult and usually less accurate
+ * than restriction estimation.
+ *
+ * When dealing with the inner scan of a nestloop join, we consider the
+ * join's joinclauses as restriction clauses for the inner relation, and
+ * treat vars of the outer relation as parameters (a/k/a constants of unknown
+ * values).  So, restriction estimators need to be able to accept an argument
+ * telling which relation is to be treated as the variable.
+ *
+ * The call convention for a restriction estimator (oprrest function) is
+ *
+ *             Selectivity oprrest (Query *root,
+ *                                                      Oid operator,
+ *                                                      List *args,
+ *                                                      int varRelid);
+ *
+ * root: general information about the query (rtable and RelOptInfo lists
+ * are particularly important for the estimator).
+ * operator: OID of the specific operator in question.
+ * args: argument list from the operator clause.
+ * varRelid: if not zero, the relid (rtable index) of the relation to
+ * be treated as the variable relation.  May be zero if the args list
+ * is known to contain vars of only one relation.
+ *
+ * This is represented at the SQL level (in pg_proc) as
+ *
+ *             float8 oprrest (opaque, oid, opaque, int4);
+ *
+ * The call convention for a join estimator (oprjoin function) is similar
+ * except that varRelid is not needed:
+ *
+ *             Selectivity oprjoin (Query *root,
+ *                                                      Oid operator,
+ *                                                      List *args);
+ *
+ *             float8 oprjoin (opaque, oid, opaque);
+ *----------
+ */
+
 #include "postgres.h"
 
 #include <ctype.h>
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
 #include "mb/pg_wchar.h"
+#include "nodes/makefuncs.h"
 #include "optimizer/clauses.h"
 #include "optimizer/cost.h"
+#include "optimizer/pathnode.h"
+#include "optimizer/plancat.h"
 #include "parser/parse_func.h"
 #include "parser/parse_oper.h"
 #include "parser/parsetree.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
-/* N is not a valid var/constant or relation id */
-#define NONVALUE(N)            ((N) == 0)
+/*
+ * Note: the default selectivity estimates are not chosen entirely at random.
+ * We want them to be small enough to ensure that indexscans will be used if
+ * available, for typical table densities of ~100 tuples/page.  Thus, for
+ * example, 0.01 is not quite small enough, since that makes it appear that
+ * nearly all pages will be hit anyway.  Also, since we sometimes estimate
+ * eqsel as 1/num_distinct, we probably want DEFAULT_NUM_DISTINCT to equal
+ * 1/DEFAULT_EQ_SEL.
+ */
 
 /* default selectivity estimate for equalities such as "A = b" */
-#define DEFAULT_EQ_SEL 0.01
+#define DEFAULT_EQ_SEL 0.005
 
 /* default selectivity estimate for inequalities such as "A < b" */
 #define DEFAULT_INEQ_SEL  (1.0 / 3.0)
 
 /* default selectivity estimate for pattern-match operators such as LIKE */
-#define DEFAULT_MATCH_SEL      0.01
+#define DEFAULT_MATCH_SEL      0.005
+
+/* default number of distinct values in a table */
+#define DEFAULT_NUM_DISTINCT  200
+
 
 static bool convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
                                  Datum lobound, Datum hibound, Oid boundstypid,
@@ -72,19 +132,19 @@ static double convert_one_string_to_scalar(unsigned char *value,
                                                         int rangelo, int rangehi);
 static unsigned char *convert_string_datum(Datum value, Oid typid);
 static double convert_timevalue_to_scalar(Datum value, Oid typid);
-static void getattproperties(Oid relid, AttrNumber attnum,
-                                                        Oid *typid, int32 *typmod);
-static double get_att_numdistinct(Oid relid, AttrNumber attnum, Oid typid,
+static double get_att_numdistinct(Query *root, Var *var,
                                                                  Form_pg_statistic stats);
-static Selectivity prefix_selectivity(char *prefix,
-                                  Oid relid,
-                                  AttrNumber attno,
-                                  Oid datatype);
+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, char *prefix);
 static Selectivity pattern_selectivity(char *patt, Pattern_Type ptype);
 static bool string_lessthan(const char *str1, const char *str2,
                                Oid datatype);
 static Oid     find_operator(const char *opname, Oid datatype);
 static Datum string_to_datum(const char *str, Oid datatype);
+static Const *string_to_const(const char *str, Oid datatype);
 
 
 /*
@@ -93,20 +153,19 @@ static Datum string_to_datum(const char *str, Oid datatype);
  * Note: this routine is also used to estimate selectivity for some
  * operators that are not "=" but have comparable selectivity behavior,
  * such as "~=" (geometric approximate-match). Even for "=", we must
- * keep in mind that the left and right datatypes may differ, so the type
- * of the given constant "value" may be different from the type of the
- * attribute.
+ * keep in mind that the left and right datatypes may differ.
  */
 Datum
 eqsel(PG_FUNCTION_ARGS)
 {
-       Oid                     opid = PG_GETARG_OID(0);
-       Oid                     relid = PG_GETARG_OID(1);
-       AttrNumber      attno = PG_GETARG_INT16(2);
-       Datum           value = PG_GETARG_DATUM(3);
-       int32           flag = PG_GETARG_INT32(4);
-       Oid                     typid;
-       int32           typmod;
+       Query      *root = (Query *) PG_GETARG_POINTER(0);
+       Oid                     operator = PG_GETARG_OID(1);
+       List       *args = (List *) PG_GETARG_POINTER(2);
+       int                     varRelid = PG_GETARG_INT32(3);
+       Var                *var;
+       Node       *other;
+       bool            varonleft;
+       Oid                     relid;
        HeapTuple       statsTuple;
        Datum      *values;
        int                     nvalues;
@@ -114,16 +173,29 @@ eqsel(PG_FUNCTION_ARGS)
        int                     nnumbers;
        double          selec;
 
-       if (NONVALUE(relid) || NONVALUE(attno))
+       /*
+        * If expression is not var = something or something = var for
+        * a simple var of a real relation (no subqueries, for now),
+        * then punt and return a default estimate.
+        */
+       if (!get_restriction_var(args, varRelid,
+                                                        &var, &other, &varonleft))
+               PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+       relid = getrelid(var->varno, root->rtable);
+       if (relid == InvalidOid)
                PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
 
-       /* get info about the attribute */
-       getattproperties(relid, attno, &typid, &typmod);
+       /*
+        * 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)
+               PG_RETURN_FLOAT8(0.0);
 
        /* get stats for the attribute, if available */
        statsTuple = SearchSysCache(STATRELATT,
                                                                ObjectIdGetDatum(relid),
-                                                               Int16GetDatum(attno),
+                                                               Int16GetDatum(var->varattno),
                                                                0, 0);
        if (HeapTupleIsValid(statsTuple))
        {
@@ -131,8 +203,10 @@ eqsel(PG_FUNCTION_ARGS)
 
                stats = (Form_pg_statistic) GETSTRUCT(statsTuple);
 
-               if (flag & SEL_CONSTANT)
+               if (IsA(other, Const))
                {
+                       /* Var is being compared to a known non-null constant */
+                       Datum   constval = ((Const *) other)->constvalue;
                        bool    match = false;
                        int             i;
 
@@ -143,25 +217,25 @@ eqsel(PG_FUNCTION_ARGS)
                         * is an appropriate test.  If you don't like this, maybe you
                         * shouldn't be using eqsel for your operator...)
                         */
-                       if (get_attstatsslot(statsTuple, typid, typmod,
+                       if (get_attstatsslot(statsTuple, var->vartype, var->vartypmod,
                                                                 STATISTIC_KIND_MCV, InvalidOid,
                                                                 &values, &nvalues,
                                                                 &numbers, &nnumbers))
                        {
                                FmgrInfo        eqproc;
 
-                               fmgr_info(get_opcode(opid), &eqproc);
+                               fmgr_info(get_opcode(operator), &eqproc);
 
                                for (i = 0; i < nvalues; i++)
                                {
                                        /* be careful to apply operator right way 'round */
-                                       if (flag & SEL_RIGHT)
+                                       if (varonleft)
                                                match = DatumGetBool(FunctionCall2(&eqproc,
                                                                                                                   values[i],
-                                                                                                                  value));
+                                                                                                                  constval));
                                        else
                                                match = DatumGetBool(FunctionCall2(&eqproc,
-                                                                                                                  value,
+                                                                                                                  constval,
                                                                                                                   values[i]));
                                        if (match)
                                                break;
@@ -203,8 +277,7 @@ eqsel(PG_FUNCTION_ARGS)
                                 * share this remaining fraction equally, so we
                                 * divide by the number of other distinct values.
                                 */
-                               otherdistinct = get_att_numdistinct(relid, attno,
-                                                                                                       typid, stats)
+                               otherdistinct = get_att_numdistinct(root, var, stats)
                                        - nnumbers;
                                if (otherdistinct > 1)
                                        selec /= otherdistinct;
@@ -217,7 +290,8 @@ eqsel(PG_FUNCTION_ARGS)
                                        selec = numbers[nnumbers-1];
                        }
 
-                       free_attstatsslot(typid, values, nvalues, numbers, nnumbers);
+                       free_attstatsslot(var->vartype, values, nvalues,
+                                                         numbers, nnumbers);
                }
                else
                {
@@ -234,21 +308,21 @@ eqsel(PG_FUNCTION_ARGS)
                         * frequency in the table.  Is that a good idea?)
                         */
                        selec = 1.0 - stats->stanullfrac;
-                       ndistinct = get_att_numdistinct(relid, attno, typid, stats);
+                       ndistinct = get_att_numdistinct(root, var, stats);
                        if (ndistinct > 1)
                                selec /= ndistinct;
                        /*
                         * Cross-check: selectivity should never be
                         * estimated as more than the most common value's.
                         */
-                       if (get_attstatsslot(statsTuple, typid, typmod,
+                       if (get_attstatsslot(statsTuple, var->vartype, var->vartypmod,
                                                                 STATISTIC_KIND_MCV, InvalidOid,
                                                                 NULL, NULL,
                                                                 &numbers, &nnumbers))
                        {
                                if (nnumbers > 0 && selec > numbers[0])
                                        selec = numbers[0];
-                               free_attstatsslot(typid, NULL, 0, numbers, nnumbers);
+                               free_attstatsslot(var->vartype, NULL, 0, numbers, nnumbers);
                        }
                }
 
@@ -262,7 +336,7 @@ eqsel(PG_FUNCTION_ARGS)
                 * equally common.  (The guess is unlikely to be very good,
                 * but we do know a few special cases.)
                 */
-               selec = 1.0 / get_att_numdistinct(relid, attno, typid, NULL);
+               selec = 1.0 / get_att_numdistinct(root, var, NULL);
        }
 
        /* result should be in range, but make sure... */
@@ -284,27 +358,25 @@ eqsel(PG_FUNCTION_ARGS)
 Datum
 neqsel(PG_FUNCTION_ARGS)
 {
-       Oid                     opid = PG_GETARG_OID(0);
-       Oid                     relid = PG_GETARG_OID(1);
-       AttrNumber      attno = PG_GETARG_INT16(2);
-       Datum           value = PG_GETARG_DATUM(3);
-       int32           flag = PG_GETARG_INT32(4);
-       Oid                     eqopid;
+       Query      *root = (Query *) PG_GETARG_POINTER(0);
+       Oid                     operator = PG_GETARG_OID(1);
+       List       *args = (List *) PG_GETARG_POINTER(2);
+       int                     varRelid = PG_GETARG_INT32(3);
+       Oid                     eqop;
        float8          result;
 
        /*
         * We want 1 - eqsel() where the equality operator is the one
         * associated with this != operator, that is, its negator.
         */
-       eqopid = get_negator(opid);
-       if (eqopid)
+       eqop = get_negator(operator);
+       if (eqop)
        {
-               result = DatumGetFloat8(DirectFunctionCall5(eqsel,
-                                                                                               ObjectIdGetDatum(eqopid),
-                                                                                                ObjectIdGetDatum(relid),
-                                                                                                       Int16GetDatum(attno),
-                                                                                                       value,
-                                                                                                       Int32GetDatum(flag)));
+               result = DatumGetFloat8(DirectFunctionCall4(eqsel,
+                                                                                        PointerGetDatum(root),
+                                                                                        ObjectIdGetDatum(eqop),
+                                                                                        PointerGetDatum(args),
+                                                                                        Int32GetDatum(varRelid)));
        }
        else
        {
@@ -316,28 +388,26 @@ neqsel(PG_FUNCTION_ARGS)
 }
 
 /*
- *             scalarltsel             - Selectivity of "<" (also "<=") for scalars.
+ *     scalarineqsel           - Selectivity of "<", "<=", ">", ">=" for scalars.
+ *
+ * This is the guts of both scalarltsel and scalargtsel.  The caller has
+ * commuted the clause, if necessary, so that we can treat the Var as
+ * being on the left.
  *
  * 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.
  */
-Datum
-scalarltsel(PG_FUNCTION_ARGS)
+static double
+scalarineqsel(Query *root, Oid operator, bool isgt,
+                         Var *var, Node *other)
 {
-       Oid                     opid = PG_GETARG_OID(0);
-       Oid                     relid = PG_GETARG_OID(1);
-       AttrNumber      attno = PG_GETARG_INT16(2);
-       Datum           value = PG_GETARG_DATUM(3);
-       int32           flag = PG_GETARG_INT32(4);
-       bool            isgt;
-       HeapTuple       oprTuple;
+       Oid                     relid;
+       Datum           constval;
+       Oid                     consttype;
        HeapTuple       statsTuple;
        Form_pg_statistic stats;
-       Oid                     contype;
        FmgrInfo        opproc;
-       Oid                     typid;
-       int32           typmod;
        Datum      *values;
        int                     nvalues;
        float4     *numbers;
@@ -348,62 +418,44 @@ scalarltsel(PG_FUNCTION_ARGS)
        double          selec;
        int                     i;
 
-       if (NONVALUE(relid) || NONVALUE(attno))
-               PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
-
-       /* Can't do anything useful if no constant to compare against, either */
-       if (!(flag & SEL_CONSTANT))
-               PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
+       /*
+        * If expression is not var op something or something op var for
+        * a simple var of a real relation (no subqueries, for now),
+        * then punt and return a default estimate.
+        */
+       relid = getrelid(var->varno, root->rtable);
+       if (relid == InvalidOid)
+               return DEFAULT_INEQ_SEL;
 
        /*
-        * Force the constant to be on the right to simplify later logic.
-        * This means that we may be dealing with either "<" or ">" cases.
+        * Can't do anything useful if the something is not a constant, either.
         */
-       if (flag & SEL_RIGHT)
-       {
-               /* we have x < const */
-               isgt = false;
-       }
-       else
-       {
-               /* we have const < x, commute to make x > const */
-               opid = get_commutator(opid);
-               if (!opid)
-               {
-                       /* Use default selectivity (should we raise an error instead?) */
-                       PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
-               }
-               isgt = true;
-       }
+       if (! IsA(other, Const))
+               return DEFAULT_INEQ_SEL;
 
        /*
-        * The constant might not be the same datatype as the column;
-        * look at the operator's input types to find out what it is.
-        * Also set up to be able to call the operator's execution proc.
+        * If the constant is NULL, assume operator is strict
+        * and return zero, ie, operator will never return TRUE.
         */
-       oprTuple = SearchSysCache(OPEROID,
-                                                         ObjectIdGetDatum(opid),
-                                                         0, 0, 0);
-       if (!HeapTupleIsValid(oprTuple))
-               elog(ERROR, "scalarltsel: no tuple for operator %u", opid);
-       contype = ((Form_pg_operator) GETSTRUCT(oprTuple))->oprright;
-       fmgr_info(((Form_pg_operator) GETSTRUCT(oprTuple))->oprcode, &opproc);
-       ReleaseSysCache(oprTuple);
-
-       /* Now get info and stats about the attribute */
-       getattproperties(relid, attno, &typid, &typmod);
+       if (((Const *) other)->constisnull)
+               return 0.0;
+       constval = ((Const *) other)->constvalue;
+       consttype = ((Const *) other)->consttype;
 
+       /* get stats for the attribute */
        statsTuple = SearchSysCache(STATRELATT,
                                                                ObjectIdGetDatum(relid),
-                                                               Int16GetDatum(attno),
+                                                               Int16GetDatum(var->varattno),
                                                                0, 0);
        if (!HeapTupleIsValid(statsTuple))
        {
                /* no stats available, so default result */
-               PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
+               return DEFAULT_INEQ_SEL;
        }
        stats = (Form_pg_statistic) GETSTRUCT(statsTuple);
 
+       fmgr_info(get_opcode(operator), &opproc);
+
        /*
         * If we have most-common-values info, add up the fractions of the
         * MCV entries that satisfy MCV OP CONST.  These fractions contribute
@@ -413,7 +465,7 @@ scalarltsel(PG_FUNCTION_ARGS)
        mcv_selec = 0.0;
        sumcommon = 0.0;
 
-       if (get_attstatsslot(statsTuple, typid, typmod,
+       if (get_attstatsslot(statsTuple, var->vartype, var->vartypmod,
                                                 STATISTIC_KIND_MCV, InvalidOid,
                                                 &values, &nvalues,
                                                 &numbers, &nnumbers))
@@ -422,11 +474,11 @@ scalarltsel(PG_FUNCTION_ARGS)
                {
                        if (DatumGetBool(FunctionCall2(&opproc,
                                                                                   values[i],
-                                                                                  value)))
+                                                                                  constval)))
                                mcv_selec += numbers[i];
                        sumcommon += numbers[i];
                }
-               free_attstatsslot(typid, values, nvalues, numbers, nnumbers);
+               free_attstatsslot(var->vartype, values, nvalues, numbers, nnumbers);
        }
 
        /*
@@ -440,11 +492,11 @@ scalarltsel(PG_FUNCTION_ARGS)
         * have at hand!  (For example, we might have a '<=' operator rather
         * than the '<' operator that will appear in staop.)  For now, assume
         * that whatever appears in pg_statistic is sorted the same way our
-        * operator sorts.
+        * operator sorts, or the reverse way if isgt is TRUE.
         */
        hist_selec = 0.0;
 
-       if (get_attstatsslot(statsTuple, typid, typmod,
+       if (get_attstatsslot(statsTuple, var->vartype, var->vartypmod,
                                                 STATISTIC_KIND_HISTOGRAM, InvalidOid,
                                                 &values, &nvalues,
                                                 NULL, NULL))
@@ -456,7 +508,7 @@ scalarltsel(PG_FUNCTION_ARGS)
 
                        ltcmp = DatumGetBool(FunctionCall2(&opproc,
                                                                                           values[0],
-                                                                                          value));
+                                                                                          constval));
                        if (isgt)
                                ltcmp = !ltcmp;
                        if (!ltcmp)
@@ -475,7 +527,7 @@ scalarltsel(PG_FUNCTION_ARGS)
                                {
                                        ltcmp = DatumGetBool(FunctionCall2(&opproc,
                                                                                                           values[i],
-                                                                                                          value));
+                                                                                                          constval));
                                        if (isgt)
                                                ltcmp = !ltcmp;
                                        if (!ltcmp)
@@ -500,8 +552,9 @@ scalarltsel(PG_FUNCTION_ARGS)
                                         * values to a uniform comparison scale, and do a linear
                                         * interpolation within this bin.
                                         */
-                                       if (convert_to_scalar(value, contype, &val,
-                                                                                 values[i-1], values[i], typid,
+                                       if (convert_to_scalar(constval, consttype, &val,
+                                                                                 values[i-1], values[i],
+                                                                                 var->vartype,
                                                                                  &low, &high))
                                        {
                                                if (high <= low)
@@ -520,10 +573,10 @@ scalarltsel(PG_FUNCTION_ARGS)
                                        {
                                                /*
                                                 * Ideally we'd produce an error here, on the grounds
-                                                * that the given operator shouldn't have scalarltsel
+                                                * that the given operator shouldn't have scalarXXsel
                                                 * registered as its selectivity func unless we can
                                                 * deal with its operand types.  But currently, all
-                                                * manner of stuff is invoking scalarltsel, so give a
+                                                * manner of stuff is invoking scalarXXsel, so give a
                                                 * default estimate until that can be fixed.
                                                 */
                                                binfrac = 0.5;
@@ -549,13 +602,13 @@ scalarltsel(PG_FUNCTION_ARGS)
                         * don't believe extremely small or large selectivity
                         * estimates.
                         */
-                       if (hist_selec < 0.001)
-                               hist_selec = 0.001;
-                       else if (hist_selec > 0.999)
-                               hist_selec = 0.999;
+                       if (hist_selec < 0.0001)
+                               hist_selec = 0.0001;
+                       else if (hist_selec > 0.9999)
+                               hist_selec = 0.9999;
                }
 
-               free_attstatsslot(typid, values, nvalues, NULL, 0);
+               free_attstatsslot(var->vartype, values, nvalues, NULL, 0);
        }
 
        /*
@@ -586,141 +639,210 @@ scalarltsel(PG_FUNCTION_ARGS)
        else if (selec > 1.0)
                selec = 1.0;
 
+       return selec;
+}
+
+/*
+ *             scalarltsel             - Selectivity of "<" (also "<=") for scalars.
+ */
+Datum
+scalarltsel(PG_FUNCTION_ARGS)
+{
+       Query      *root = (Query *) PG_GETARG_POINTER(0);
+       Oid                     operator = PG_GETARG_OID(1);
+       List       *args = (List *) PG_GETARG_POINTER(2);
+       int                     varRelid = PG_GETARG_INT32(3);
+       Var                *var;
+       Node       *other;
+       bool            varonleft;
+       bool            isgt;
+       double          selec;
+
+       /*
+        * If expression is not var op something or something op var for
+        * a simple var of a real relation (no subqueries, for now),
+        * then punt and return a default estimate.
+        */
+       if (!get_restriction_var(args, varRelid,
+                                                        &var, &other, &varonleft))
+               PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
+
+       /*
+        * Force the var to be on the left to simplify logic in scalarineqsel.
+        */
+       if (varonleft)
+       {
+               /* we have var < other */
+               isgt = false;
+       }
+       else
+       {
+               /* we have other < var, commute to make var > other */
+               operator = get_commutator(operator);
+               if (!operator)
+               {
+                       /* Use default selectivity (should we raise an error instead?) */
+                       PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
+               }
+               isgt = true;
+       }
+
+       selec = scalarineqsel(root, operator, isgt, var, other);
+
        PG_RETURN_FLOAT8((float8) selec);
 }
 
 /*
  *             scalargtsel             - Selectivity of ">" (also ">=") for integers.
- *
- * See above comments for scalarltsel.
  */
 Datum
 scalargtsel(PG_FUNCTION_ARGS)
 {
-       Oid                     opid = PG_GETARG_OID(0);
-       Oid                     relid = PG_GETARG_OID(1);
-       AttrNumber      attno = PG_GETARG_INT16(2);
-       Datum           value = PG_GETARG_DATUM(3);
-       int32           flag = PG_GETARG_INT32(4);
-       Oid                     ltopid;
+       Query      *root = (Query *) PG_GETARG_POINTER(0);
+       Oid                     operator = PG_GETARG_OID(1);
+       List       *args = (List *) PG_GETARG_POINTER(2);
+       int                     varRelid = PG_GETARG_INT32(3);
+       Var                *var;
+       Node       *other;
+       bool            varonleft;
+       bool            isgt;
+       double          selec;
 
        /*
-        * Commute so that we have a "<" or "<=" operator, then apply
-        * scalarltsel.
+        * If expression is not var op something or something op var for
+        * a simple var of a real relation (no subqueries, for now),
+        * then punt and return a default estimate.
         */
-       ltopid = get_commutator(opid);
-       if (!ltopid)
-       {
-               /* Use default selectivity (should we raise an error instead?) */
+       if (!get_restriction_var(args, varRelid,
+                                                        &var, &other, &varonleft))
                PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
+
+       /*
+        * Force the var to be on the left to simplify logic in scalarineqsel.
+        */
+       if (varonleft)
+       {
+               /* we have var > other */
+               isgt = true;
+       }
+       else
+       {
+               /* we have other > var, commute to make var < other */
+               operator = get_commutator(operator);
+               if (!operator)
+               {
+                       /* Use default selectivity (should we raise an error instead?) */
+                       PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
+               }
+               isgt = false;
        }
 
-       flag ^= SEL_RIGHT;
-       return DirectFunctionCall5(scalarltsel,
-                                                          ObjectIdGetDatum(ltopid),
-                                                          ObjectIdGetDatum(relid),
-                                                          Int16GetDatum(attno),
-                                                          value,
-                                                          Int32GetDatum(flag));
+       selec = scalarineqsel(root, operator, isgt, var, other);
+
+       PG_RETURN_FLOAT8((float8) selec);
 }
 
 /*
  * patternsel                  - Generic code for pattern-match selectivity.
  */
-static Datum
+static double
 patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
 {
-       Oid                     opid = PG_GETARG_OID(0);
-       Oid                     relid = PG_GETARG_OID(1);
-       AttrNumber      attno = PG_GETARG_INT16(2);
-       Datum           value = PG_GETARG_DATUM(3);
-       int32           flag = PG_GETARG_INT32(4);
-       float8          result;
+       Query      *root = (Query *) PG_GETARG_POINTER(0);
+#ifdef NOT_USED
+       Oid                     operator = PG_GETARG_OID(1);
+#endif
+       List       *args = (List *) PG_GETARG_POINTER(2);
+       int                     varRelid = PG_GETARG_INT32(3);
+       Var                *var;
+       Node       *other;
+       bool            varonleft;
+       Oid                     relid;
+       Datum           constval;
+       char       *patt;
+       Pattern_Prefix_Status pstatus;
+       char       *prefix;
+       char       *rest;
+       double          result;
+
+       /*
+        * If expression is not var op constant for
+        * a simple var of a real relation (no subqueries, for now),
+        * then punt and return a default estimate.
+        */
+       if (!get_restriction_var(args, varRelid,
+                                                        &var, &other, &varonleft))
+               return DEFAULT_MATCH_SEL;
+       if (!varonleft || !IsA(other, Const))
+               return DEFAULT_MATCH_SEL;
+       relid = getrelid(var->varno, root->rtable);
+       if (relid == InvalidOid)
+               return DEFAULT_MATCH_SEL;
+
+       /*
+        * If the constant is NULL, assume operator is strict
+        * and return zero, ie, operator will never return TRUE.
+        */
+       if (((Const *) other)->constisnull)
+               return 0.0;
+       constval = ((Const *) other)->constvalue;
+       /* the right-hand const is type text for all supported operators */
+       Assert(((Const *) other)->consttype == TEXTOID);
+       patt = DatumGetCString(DirectFunctionCall1(textout, constval));
 
-       /* Must have a constant for the pattern, or cannot learn anything */
-       if ((flag & (SEL_CONSTANT | SEL_RIGHT)) != (SEL_CONSTANT | SEL_RIGHT))
-               result = DEFAULT_MATCH_SEL;
+       /* divide pattern into fixed prefix and remainder */
+       pstatus = pattern_fixed_prefix(patt, ptype, &prefix, &rest);
+
+       if (pstatus == Pattern_Prefix_Exact)
+       {
+               /*
+                * Pattern specifies an exact match, so pretend operator is '='
+                */
+               Oid                     eqopr = find_operator("=", var->vartype);
+               Const      *eqcon;
+               List       *eqargs;
+
+               if (eqopr == InvalidOid)
+                       elog(ERROR, "patternsel: no = operator for type %u",
+                                var->vartype);
+               eqcon = string_to_const(prefix, var->vartype);
+               eqargs = makeList2(var, eqcon);
+               result = DatumGetFloat8(DirectFunctionCall4(eqsel,
+                                                                                                       PointerGetDatum(root),
+                                                                                                       ObjectIdGetDatum(eqopr),
+                                                                                                       PointerGetDatum(eqargs),
+                                                                                                       Int32GetDatum(varRelid)));
+       }
        else
        {
-               HeapTuple       oprTuple;
-               Oid                     ltype,
-                                       rtype;
-               char       *patt;
-               Pattern_Prefix_Status pstatus;
-               char       *prefix;
-               char       *rest;
-
                /*
-                * Get left and right datatypes of the operator so we know what
-                * type the attribute is.
+                * Not exact-match pattern.  We estimate selectivity of the
+                * fixed prefix and remainder of pattern separately, then
+                * combine the two.
                 */
-               oprTuple = SearchSysCache(OPEROID,
-                                                                 ObjectIdGetDatum(opid),
-                                                                 0, 0, 0);
-               if (!HeapTupleIsValid(oprTuple))
-                       elog(ERROR, "patternsel: no tuple for operator %u", opid);
-               ltype = ((Form_pg_operator) GETSTRUCT(oprTuple))->oprleft;
-               rtype = ((Form_pg_operator) GETSTRUCT(oprTuple))->oprright;
-               ReleaseSysCache(oprTuple);
-
-               /* the right-hand const is type text for all supported operators */
-               Assert(rtype == TEXTOID);
-               patt = DatumGetCString(DirectFunctionCall1(textout, value));
-
-               /* divide pattern into fixed prefix and remainder */
-               pstatus = pattern_fixed_prefix(patt, ptype, &prefix, &rest);
-
-               if (pstatus == Pattern_Prefix_Exact)
-               {
+               Selectivity prefixsel;
+               Selectivity restsel;
+               Selectivity selec;
 
-                       /*
-                        * Pattern specifies an exact match, so pretend operator is
-                        * '='
-                        */
-                       Oid                     eqopr = find_operator("=", ltype);
-                       Datum           eqcon;
-
-                       if (eqopr == InvalidOid)
-                               elog(ERROR, "patternsel: no = operator for type %u", ltype);
-                       eqcon = string_to_datum(prefix, ltype);
-                       result = DatumGetFloat8(DirectFunctionCall5(eqsel,
-                                                                                                ObjectIdGetDatum(eqopr),
-                                                                                                ObjectIdGetDatum(relid),
-                                                                                                       Int16GetDatum(attno),
-                                                                                                               eqcon,
-                                                          Int32GetDatum(SEL_CONSTANT | SEL_RIGHT)));
-                       pfree(DatumGetPointer(eqcon));
-               }
+               if (pstatus == Pattern_Prefix_Partial)
+                       prefixsel = prefix_selectivity(root, var, prefix);
                else
-               {
+                       prefixsel = 1.0;
+               restsel = pattern_selectivity(rest, ptype);
+               selec = prefixsel * restsel;
+               /* result should be in range, but make sure... */
+               if (selec < 0.0)
+                       selec = 0.0;
+               else if (selec > 1.0)
+                       selec = 1.0;
+               result = selec;
+       }
 
-                       /*
-                        * Not exact-match pattern.  We estimate selectivity of the
-                        * fixed prefix and remainder of pattern separately, then
-                        * combine the two.
-                        */
-                       Selectivity prefixsel;
-                       Selectivity restsel;
-                       Selectivity selec;
+       if (prefix)
+               pfree(prefix);
+       pfree(patt);
 
-                       if (pstatus == Pattern_Prefix_Partial)
-                               prefixsel = prefix_selectivity(prefix, relid, attno, ltype);
-                       else
-                               prefixsel = 1.0;
-                       restsel = pattern_selectivity(rest, ptype);
-                       selec = prefixsel * restsel;
-                       /* result should be in range, but make sure... */
-                       if (selec < 0.0)
-                               selec = 0.0;
-                       else if (selec > 1.0)
-                               selec = 1.0;
-                       result = (float8) selec;
-               }
-               if (prefix)
-                       pfree(prefix);
-               pfree(patt);
-       }
-       PG_RETURN_FLOAT8(result);
+       return result;
 }
 
 /*
@@ -729,7 +851,7 @@ patternsel(PG_FUNCTION_ARGS, Pattern_Type ptype)
 Datum
 regexeqsel(PG_FUNCTION_ARGS)
 {
-       return patternsel(fcinfo, Pattern_Type_Regex);
+       PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Regex));
 }
 
 /*
@@ -738,7 +860,7 @@ regexeqsel(PG_FUNCTION_ARGS)
 Datum
 icregexeqsel(PG_FUNCTION_ARGS)
 {
-       return patternsel(fcinfo, Pattern_Type_Regex_IC);
+       PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Regex_IC));
 }
 
 /*
@@ -747,7 +869,7 @@ icregexeqsel(PG_FUNCTION_ARGS)
 Datum
 likesel(PG_FUNCTION_ARGS)
 {
-       return patternsel(fcinfo, Pattern_Type_Like);
+       PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Like));
 }
 
 /*
@@ -756,7 +878,7 @@ likesel(PG_FUNCTION_ARGS)
 Datum
 iclikesel(PG_FUNCTION_ARGS)
 {
-       return patternsel(fcinfo, Pattern_Type_Like_IC);
+       PG_RETURN_FLOAT8(patternsel(fcinfo, Pattern_Type_Like_IC));
 }
 
 /*
@@ -765,9 +887,9 @@ iclikesel(PG_FUNCTION_ARGS)
 Datum
 regexnesel(PG_FUNCTION_ARGS)
 {
-       float8          result;
+       double          result;
 
-       result = DatumGetFloat8(patternsel(fcinfo, Pattern_Type_Regex));
+       result = patternsel(fcinfo, Pattern_Type_Regex);
        result = 1.0 - result;
        PG_RETURN_FLOAT8(result);
 }
@@ -778,9 +900,9 @@ regexnesel(PG_FUNCTION_ARGS)
 Datum
 icregexnesel(PG_FUNCTION_ARGS)
 {
-       float8          result;
+       double          result;
 
-       result = DatumGetFloat8(patternsel(fcinfo, Pattern_Type_Regex_IC));
+       result = patternsel(fcinfo, Pattern_Type_Regex_IC);
        result = 1.0 - result;
        PG_RETURN_FLOAT8(result);
 }
@@ -791,9 +913,9 @@ icregexnesel(PG_FUNCTION_ARGS)
 Datum
 nlikesel(PG_FUNCTION_ARGS)
 {
-       float8          result;
+       double          result;
 
-       result = DatumGetFloat8(patternsel(fcinfo, Pattern_Type_Like));
+       result = patternsel(fcinfo, Pattern_Type_Like);
        result = 1.0 - result;
        PG_RETURN_FLOAT8(result);
 }
@@ -804,9 +926,9 @@ nlikesel(PG_FUNCTION_ARGS)
 Datum
 icnlikesel(PG_FUNCTION_ARGS)
 {
-       float8          result;
+       double          result;
 
-       result = DatumGetFloat8(patternsel(fcinfo, Pattern_Type_Like_IC));
+       result = patternsel(fcinfo, Pattern_Type_Like_IC);
        result = 1.0 - result;
        PG_RETURN_FLOAT8(result);
 }
@@ -817,25 +939,21 @@ icnlikesel(PG_FUNCTION_ARGS)
 Datum
 eqjoinsel(PG_FUNCTION_ARGS)
 {
+       Query      *root = (Query *) PG_GETARG_POINTER(0);
 #ifdef NOT_USED                                        /* see neqjoinsel() before removing me! */
-       Oid                     opid = PG_GETARG_OID(0);
+       Oid                     operator = PG_GETARG_OID(1);
 #endif
-       Oid                     relid1 = PG_GETARG_OID(1);
-       AttrNumber      attno1 = PG_GETARG_INT16(2);
-       Oid                     relid2 = PG_GETARG_OID(3);
-       AttrNumber      attno2 = PG_GETARG_INT16(4);
-       bool            unknown1 = NONVALUE(relid1) || NONVALUE(attno1);
-       bool            unknown2 = NONVALUE(relid2) || NONVALUE(attno2);
+       List       *args = (List *) PG_GETARG_POINTER(2);
+       Var                *var1;
+       Var                *var2;
        double          selec;
 
-       if (unknown1 && unknown2)
+       get_join_vars(args, &var1, &var2);
+
+       if (var1 == NULL && var2 == NULL)
                selec = DEFAULT_EQ_SEL;
        else
        {
-               Oid                     typid1;
-               Oid                     typid2;
-               int32           typmod1;
-               int32           typmod2;
                HeapTuple       statsTuple1 = NULL;
                HeapTuple       statsTuple2 = NULL;
                Form_pg_statistic stats1 = NULL;
@@ -843,44 +961,52 @@ eqjoinsel(PG_FUNCTION_ARGS)
                double          nd1,
                                        nd2;
 
-               if (unknown1)
+               if (var1 == NULL)
                {
-                       nd1 = 100.0;
+                       nd1 = DEFAULT_NUM_DISTINCT;
                }
                else
                {
-                       /* get info about the attribute */
-                       getattproperties(relid1, attno1, &typid1, &typmod1);
-
                        /* get stats for the attribute, if available */
-                       statsTuple1 = SearchSysCache(STATRELATT,
-                                                                                ObjectIdGetDatum(relid1),
-                                                                                Int16GetDatum(attno1),
-                                                                                0, 0);
-                       if (HeapTupleIsValid(statsTuple1))
-                               stats1 = (Form_pg_statistic) GETSTRUCT(statsTuple1);
-
-                       nd1 = get_att_numdistinct(relid1, attno1, typid1, stats1);
+                       Oid             relid1 = getrelid(var1->varno, root->rtable);
+
+                       if (relid1 == InvalidOid)
+                               nd1 = DEFAULT_NUM_DISTINCT;
+                       else
+                       {
+                               statsTuple1 = SearchSysCache(STATRELATT,
+                                                                                        ObjectIdGetDatum(relid1),
+                                                                                        Int16GetDatum(var1->varattno),
+                                                                                        0, 0);
+                               if (HeapTupleIsValid(statsTuple1))
+                                       stats1 = (Form_pg_statistic) GETSTRUCT(statsTuple1);
+
+                               nd1 = get_att_numdistinct(root, var1, stats1);
+                       }
                }
 
-               if (unknown2)
+               if (var2 == NULL)
                {
-                       nd2 = 100.0;
+                       nd2 = DEFAULT_NUM_DISTINCT;
                }
                else
                {
-                       /* get info about the attribute */
-                       getattproperties(relid2, attno2, &typid2, &typmod2);
-
                        /* get stats for the attribute, if available */
-                       statsTuple2 = SearchSysCache(STATRELATT,
-                                                                                ObjectIdGetDatum(relid2),
-                                                                                Int16GetDatum(attno2),
-                                                                                0, 0);
-                       if (HeapTupleIsValid(statsTuple2))
-                               stats2 = (Form_pg_statistic) GETSTRUCT(statsTuple2);
-
-                       nd2 = get_att_numdistinct(relid2, attno2, typid2, stats2);
+                       Oid             relid2 = getrelid(var2->varno, root->rtable);
+
+                       if (relid2 == InvalidOid)
+                               nd2 = DEFAULT_NUM_DISTINCT;
+                       else
+                       {
+                               statsTuple2 = SearchSysCache(STATRELATT,
+                                                                                        ObjectIdGetDatum(relid2),
+                                                                                        Int16GetDatum(var2->varattno),
+                                                                                        0, 0);
+                               if (HeapTupleIsValid(statsTuple2))
+                                       stats2 = (Form_pg_statistic) GETSTRUCT(statsTuple2);
+
+                               nd2 = get_att_numdistinct(root, var2, stats2);
+                       }
                }
 
                /*
@@ -903,7 +1029,6 @@ eqjoinsel(PG_FUNCTION_ARGS)
                        ReleaseSysCache(statsTuple1);
                if (HeapTupleIsValid(statsTuple2))
                        ReleaseSysCache(statsTuple2);
-
        }
        PG_RETURN_FLOAT8((float8) selec);
 }
@@ -1062,27 +1187,26 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 {
        switch (valuetypid)
        {
-
-                       /*
-                        * Built-in numeric types
-                        */
-                       case BOOLOID:
-                       case INT2OID:
-                       case INT4OID:
-                       case INT8OID:
-                       case FLOAT4OID:
-                       case FLOAT8OID:
-                       case NUMERICOID:
-                       case OIDOID:
-                       case REGPROCOID:
+               /*
+                * Built-in numeric types
+                */
+               case BOOLOID:
+               case INT2OID:
+               case INT4OID:
+               case INT8OID:
+               case FLOAT4OID:
+               case FLOAT8OID:
+               case NUMERICOID:
+               case OIDOID:
+               case REGPROCOID:
                        *scaledvalue = convert_numeric_to_scalar(value, valuetypid);
                        *scaledlobound = convert_numeric_to_scalar(lobound, boundstypid);
                        *scaledhibound = convert_numeric_to_scalar(hibound, boundstypid);
                        return true;
 
-                       /*
-                        * Built-in string types
-                        */
+               /*
+                * Built-in string types
+                */
                case CHAROID:
                case BPCHAROID:
                case VARCHAROID:
@@ -1102,9 +1226,9 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
                                return true;
                        }
 
-                       /*
-                        * Built-in time types
-                        */
+               /*
+                * Built-in time types
+                */
                case TIMESTAMPOID:
                case ABSTIMEOID:
                case DATEOID:
@@ -1376,7 +1500,7 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
 {
        switch (typid)
        {
-                       case TIMESTAMPOID:
+               case TIMESTAMPOID:
                        return DatumGetTimestamp(value);
                case ABSTIMEOID:
                        return DatumGetTimestamp(DirectFunctionCall1(abstime_timestamp,
@@ -1420,50 +1544,16 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
 
 
 /*
- * getattproperties
- *       Retrieve pg_attribute properties for an attribute,
- *       including type OID and typmod.
- */
-static void
-getattproperties(Oid relid, AttrNumber attnum,
-                                Oid *typid, int32 *typmod)
-{
-       HeapTuple       atp;
-       Form_pg_attribute att_tup;
-
-       atp = SearchSysCache(ATTNUM,
-                                                ObjectIdGetDatum(relid),
-                                                Int16GetDatum(attnum),
-                                                0, 0);
-       if (!HeapTupleIsValid(atp))
-               elog(ERROR, "getattproperties: no attribute tuple %u %d",
-                        relid, (int) attnum);
-       att_tup = (Form_pg_attribute) GETSTRUCT(atp);
-
-       *typid = att_tup->atttypid;
-       *typmod = att_tup->atttypmod;
-
-       ReleaseSysCache(atp);
-}
-
-/*
  * get_att_numdistinct
- *
  *       Estimate the number of distinct values of an attribute.
  *
- * relid, attnum: identify the attribute to examine.
- * typid: type of attribute.
+ * var: identifies the attribute to examine.
  * stats: pg_statistic tuple for attribute, or NULL if not available.
- *
- * XXX possible future improvement: look to see if there is a unique
- * index on the attribute.  If so, we can estimate ndistinct = ntuples.
- * This should probably override any info from pg_statistic.
  */
 static double
-get_att_numdistinct(Oid relid, AttrNumber attnum, Oid typid,
-                                       Form_pg_statistic stats)
+get_att_numdistinct(Query *root, Var *var, Form_pg_statistic stats)
 {
-       HeapTuple       reltup;
+       RelOptInfo *rel;
        double          ntuples;
 
        /*
@@ -1471,42 +1561,42 @@ get_att_numdistinct(Oid relid, AttrNumber attnum, Oid typid,
         *
         * Are there any other cases we should wire in special estimates for?
         */
-       if (typid == BOOLOID)
+       if (var->vartype == BOOLOID)
                return 2.0;
 
        /*
-        * If VACUUM ANALYZE determined a fixed estimate, use it.
-        */
-       if (stats && stats->stadistinct > 0.0)
-               return stats->stadistinct;
-
-       /*
         * Otherwise we need to get the relation size.
         */
-       reltup = SearchSysCache(RELOID,
-                                                       ObjectIdGetDatum(relid),
-                                                       0, 0, 0);
-       if (!HeapTupleIsValid(reltup))
-               elog(ERROR, "get_att_numdistinct: no relation tuple %u", relid);
-
-       ntuples = ((Form_pg_class) GETSTRUCT(reltup))->reltuples;
-
-       ReleaseSysCache(reltup);
+       rel = find_base_rel(root, var->varno);
+       ntuples = rel->tuples;
 
        if (ntuples <= 0.0)
-               return 100.0;                   /* no data available; return a default */
+               return DEFAULT_NUM_DISTINCT; /* no data available; return a default */
 
        /*
-        * If VACUUM ANALYZE determined a scaled estimate, use it.
+        * Look to see if there is a unique index on the attribute.
+        * If so, we assume it's distinct, ignoring pg_statistic info
+        * which could be out of date.
         */
-       if (stats && stats->stadistinct < 0.0)
-               return - stats->stadistinct * ntuples;
+       if (has_unique_index(rel, var->varattno))
+               return ntuples;
 
        /*
-        * VACUUM ANALYZE does not compute stats for system attributes,
+        * If ANALYZE determined a fixed or scaled estimate, use it.
+        */
+       if (stats)
+       {
+               if (stats->stadistinct > 0.0)
+                       return stats->stadistinct;
+               if (stats->stadistinct < 0.0)
+                       return - stats->stadistinct * ntuples;
+       }
+
+       /*
+        * ANALYZE does not compute stats for system attributes,
         * but some of them can reasonably be assumed unique anyway.
         */
-       switch (attnum)
+       switch (var->varattno)
        {
                case ObjectIdAttributeNumber:
                case SelfItemPointerAttributeNumber:
@@ -1516,12 +1606,116 @@ get_att_numdistinct(Oid relid, AttrNumber attnum, Oid typid,
        }
 
        /*
-        * Estimate ndistinct = ntuples if the table is small, else 100.
+        * Estimate ndistinct = ntuples if the table is small, else use default.
         */
-       if (ntuples < 100.0)
+       if (ntuples < DEFAULT_NUM_DISTINCT)
                return ntuples;
 
-       return 100.0;
+       return DEFAULT_NUM_DISTINCT;
+}
+
+/*
+ * get_restriction_var
+ *             Examine the args of a restriction clause to see if it's of the
+ *             form (var op something) or (something op var).  If so, extract
+ *             and return the var and the other argument.
+ *
+ * Inputs:
+ *     args: clause argument list
+ *     varRelid: see specs for restriction selectivity functions
+ *
+ * Outputs: (these are set only if TRUE is returned)
+ *     *var: gets Var node
+ *     *other: gets other clause argument
+ *     *varonleft: set TRUE if var is on the left, FALSE if on the right
+ *
+ * Returns TRUE if a Var is identified, otherwise FALSE.
+ */
+static bool
+get_restriction_var(List *args,
+                                       int varRelid,
+                                       Var **var,
+                                       Node **other,
+                                       bool *varonleft)
+{
+       Node       *left,
+                          *right;
+
+       if (length(args) != 2)
+               return false;
+
+       left = (Node *) lfirst(args);
+       right = (Node *) lsecond(args);
+
+       /* Ignore any binary-compatible relabeling */
+
+       if (IsA(left, RelabelType))
+               left = ((RelabelType *) left)->arg;
+       if (IsA(right, RelabelType))
+               right = ((RelabelType *) right)->arg;
+
+       /* Look for the var */
+
+       if (IsA(left, Var) &&
+               (varRelid == 0 || varRelid == ((Var *) left)->varno))
+       {
+               *var = (Var *) left;
+               *other = right;
+               *varonleft = true;
+       }
+       else if (IsA(right, Var) &&
+                        (varRelid == 0 || varRelid == ((Var *) right)->varno))
+       {
+               *var = (Var *) right;
+               *other = left;
+               *varonleft = false;
+       }
+       else
+       {
+               /* Duh, it's too complicated for me... */
+               return false;
+       }
+
+       return true;
+}
+
+/*
+ * get_join_vars
+ *
+ * Extract the two Vars from a join clause's argument list.  Returns
+ * NULL for arguments that are not simple vars.
+ */
+static void
+get_join_vars(List *args, Var **var1, Var **var2)
+{
+       Node       *left,
+                          *right;
+
+       if (length(args) != 2)
+       {
+               *var1 = NULL;
+               *var2 = NULL;
+               return;
+       }
+
+       left = (Node *) lfirst(args);
+       right = (Node *) lsecond(args);
+
+       /* Ignore any binary-compatible relabeling */
+       if (IsA(left, RelabelType))
+               left = ((RelabelType *) left)->arg;
+       if (IsA(right, RelabelType))
+               right = ((RelabelType *) right)->arg;
+
+       if (IsA(left, Var))
+               *var1 = (Var *) left;
+       else
+               *var1 = NULL;
+
+       if (IsA(right, Var))
+               *var2 = (Var *) right;
+       else
+               *var2 = NULL;
 }
 
 /*-------------------------------------------------------------------------
@@ -1755,54 +1949,49 @@ pattern_fixed_prefix(char *patt, Pattern_Type ptype,
  * more useful to use the upper-bound code than not.
  */
 static Selectivity
-prefix_selectivity(char *prefix,
-                                  Oid relid,
-                                  AttrNumber attno,
-                                  Oid datatype)
+prefix_selectivity(Query *root, Var *var, char *prefix)
 {
        Selectivity prefixsel;
        Oid                     cmpopr;
-       Datum           prefixcon;
+       Const      *prefixcon;
+       List       *cmpargs;
        char       *greaterstr;
 
-       cmpopr = find_operator(">=", datatype);
+       cmpopr = find_operator(">=", var->vartype);
        if (cmpopr == InvalidOid)
                elog(ERROR, "prefix_selectivity: no >= operator for type %u",
-                        datatype);
-       prefixcon = string_to_datum(prefix, datatype);
+                        var->vartype);
+       prefixcon = string_to_const(prefix, var->vartype);
+       cmpargs = makeList2(var, prefixcon);
        /* Assume scalargtsel is appropriate for all supported types */
-       prefixsel = DatumGetFloat8(DirectFunctionCall5(scalargtsel,
-                                                                                               ObjectIdGetDatum(cmpopr),
-                                                                                                ObjectIdGetDatum(relid),
-                                                                                                  Int16GetDatum(attno),
-                                                                                                  prefixcon,
-                                                          Int32GetDatum(SEL_CONSTANT | SEL_RIGHT)));
-       pfree(DatumGetPointer(prefixcon));
+       prefixsel = DatumGetFloat8(DirectFunctionCall4(scalargtsel,
+                                                                                                  PointerGetDatum(root),
+                                                                                                  ObjectIdGetDatum(cmpopr),
+                                                                                                  PointerGetDatum(cmpargs),
+                                                                                                  Int32GetDatum(0)));
 
        /*-------
         * If we can create a string larger than the prefix, say
         *      "x < greaterstr".
         *-------
         */
-       greaterstr = make_greater_string(prefix, datatype);
+       greaterstr = make_greater_string(prefix, var->vartype);
        if (greaterstr)
        {
                Selectivity topsel;
 
-               cmpopr = find_operator("<", datatype);
+               cmpopr = find_operator("<", var->vartype);
                if (cmpopr == InvalidOid)
                        elog(ERROR, "prefix_selectivity: no < operator for type %u",
-                                datatype);
-               prefixcon = string_to_datum(greaterstr, datatype);
+                                var->vartype);
+               prefixcon = string_to_const(greaterstr, var->vartype);
+               cmpargs = makeList2(var, prefixcon);
                /* Assume scalarltsel is appropriate for all supported types */
-               topsel = DatumGetFloat8(DirectFunctionCall5(scalarltsel,
-                                                                                               ObjectIdGetDatum(cmpopr),
-                                                                                                ObjectIdGetDatum(relid),
-                                                                                                       Int16GetDatum(attno),
-                                                                                                       prefixcon,
-                                                          Int32GetDatum(SEL_CONSTANT | SEL_RIGHT)));
-               pfree(DatumGetPointer(prefixcon));
-               pfree(greaterstr);
+               topsel = DatumGetFloat8(DirectFunctionCall4(scalarltsel,
+                                                                                                       PointerGetDatum(root),
+                                                                                                       ObjectIdGetDatum(cmpopr),
+                                                                                                       PointerGetDatum(cmpargs),
+                                                                                                       Int32GetDatum(0)));
 
                /*
                 * Merge the two selectivities in the same way as for a range
@@ -1828,7 +2017,7 @@ prefix_selectivity(char *prefix,
                                 * No data available --- use a default estimate that is
                                 * small, but not real small.
                                 */
-                               prefixsel = 0.01;
+                               prefixsel = 0.005;
                        }
                        else
                        {
@@ -2074,7 +2263,7 @@ locale_is_like_safe(void)
                result = false;
        return (bool) result;
 #else                                                  /* not USE_LOCALE */
-                               return true;    /* We must be in C locale, which is OK */
+       return true;                            /* We must be in C locale, which is OK */
 #endif  /* USE_LOCALE */
 }
 
@@ -2208,7 +2397,6 @@ find_operator(const char *opname, Oid datatype)
 static Datum
 string_to_datum(const char *str, Oid datatype)
 {
-
        /*
         * We cheat a little by assuming that textin() will do for bpchar and
         * varchar constants too...
@@ -2219,6 +2407,18 @@ string_to_datum(const char *str, Oid datatype)
                return DirectFunctionCall1(textin, CStringGetDatum(str));
 }
 
+/*
+ * Generate a Const node of the appropriate type from a C string.
+ */
+static Const *
+string_to_const(const char *str, Oid datatype)
+{
+       Datum           conval = string_to_datum(str, datatype);
+
+       return makeConst(datatype, ((datatype == NAMEOID) ? NAMEDATALEN : -1),
+                                        conval, false, false, false, false);
+}
+
 /*-------------------------------------------------------------------------
  *
  * Index cost estimation functions
index 44ddb76..e04f97e 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: catversion.h,v 1.78 2001/05/15 03:49:35 momjian Exp $
+ * $Id: catversion.h,v 1.79 2001/05/20 20:28:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200105145
+#define CATALOG_VERSION_NO     200105191
 
 #endif
index 7d7acf9..f905a06 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pg_proc.h,v 1.185 2001/05/09 23:13:35 tgl Exp $
+ * $Id: pg_proc.h,v 1.186 2001/05/20 20:28:19 tgl Exp $
  *
  * NOTES
  *       The script catalog/genbki.sh reads this file and generates .bki
@@ -219,21 +219,21 @@ DESCR("btree cost estimator");
 
 DATA(insert OID = 100 (  int8fac                  PGUID 12 f t t t 1 f 20 "20" 100 0 0 100  int8fac - ));
 DESCR("factorial");
-DATA(insert OID = 101 (  eqsel                    PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  eqsel - ));
+DATA(insert OID = 101 (  eqsel                    PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  eqsel - ));
 DESCR("restriction selectivity of = and related operators");
-DATA(insert OID = 102 (  neqsel                           PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  neqsel - ));
+DATA(insert OID = 102 (  neqsel                           PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  neqsel - ));
 DESCR("restriction selectivity of <> and related operators");
-DATA(insert OID = 103 (  scalarltsel      PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  scalarltsel - ));
+DATA(insert OID = 103 (  scalarltsel      PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  scalarltsel - ));
 DESCR("restriction selectivity of < and related operators on scalar datatypes");
-DATA(insert OID = 104 (  scalargtsel      PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  scalargtsel - ));
+DATA(insert OID = 104 (  scalargtsel      PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  scalargtsel - ));
 DESCR("restriction selectivity of > and related operators on scalar datatypes");
-DATA(insert OID = 105 (  eqjoinsel                PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100        eqjoinsel - ));
+DATA(insert OID = 105 (  eqjoinsel                PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100        eqjoinsel - ));
 DESCR("join selectivity of = and related operators");
-DATA(insert OID = 106 (  neqjoinsel               PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100        neqjoinsel - ));
+DATA(insert OID = 106 (  neqjoinsel               PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100        neqjoinsel - ));
 DESCR("join selectivity of <> and related operators");
-DATA(insert OID = 107 (  scalarltjoinsel   PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100       scalarltjoinsel - ));
+DATA(insert OID = 107 (  scalarltjoinsel   PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100       scalarltjoinsel - ));
 DESCR("join selectivity of < and related operators on scalar datatypes");
-DATA(insert OID = 108 (  scalargtjoinsel   PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100       scalargtjoinsel - ));
+DATA(insert OID = 108 (  scalargtjoinsel   PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100       scalargtjoinsel - ));
 DESCR("join selectivity of > and related operators on scalar datatypes");
 
 DATA(insert OID = 112 (  text                     PGUID 12 f t t t 1 f  25 "23" 100 0 0 100    int4_text - ));
@@ -292,9 +292,9 @@ DATA(insert OID = 137 (  on_ppath              PGUID 12 f t t t 2 f 16 "600 602" 100 0 0
 DESCR("contained in");
 DATA(insert OID = 138 (  box_center               PGUID 12 f t t t 1 f 600 "603" 100 0 0 100  box_center - ));
 DESCR("center of");
-DATA(insert OID = 139 (  areasel                  PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  areasel - ));
+DATA(insert OID = 139 (  areasel                  PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  areasel - ));
 DESCR("restriction selectivity for area-comparison operators");
-DATA(insert OID = 140 (  areajoinsel      PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100        areajoinsel - ));
+DATA(insert OID = 140 (  areajoinsel      PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100        areajoinsel - ));
 DESCR("join selectivity for area-comparison operators");
 DATA(insert OID = 141 (  int4mul                  PGUID 12 f t t t 2 f 23 "23 23" 100 0 0 100  int4mul - ));
 DESCR("multiply");
@@ -1562,13 +1562,13 @@ DESCR("current transaction time");
 
 /* OIDS 1300 - 1399 */
 
-DATA(insert OID = 1300 (  positionsel             PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  positionsel - ));
+DATA(insert OID = 1300 (  positionsel             PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  positionsel - ));
 DESCR("restriction selectivity for position-comparison operators");
-DATA(insert OID = 1301 (  positionjoinsel         PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100        positionjoinsel - ));
+DATA(insert OID = 1301 (  positionjoinsel         PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100        positionjoinsel - ));
 DESCR("join selectivity for position-comparison operators");
-DATA(insert OID = 1302 (  contsel                 PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  contsel - ));
+DATA(insert OID = 1302 (  contsel                 PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  contsel - ));
 DESCR("restriction selectivity for containment comparison operators");
-DATA(insert OID = 1303 (  contjoinsel     PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100        contjoinsel - ));
+DATA(insert OID = 1303 (  contjoinsel     PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100        contjoinsel - ));
 DESCR("join selectivity for containment comparison operators");
 
 DATA(insert OID = 1304 ( overlaps                       PGUID 12 f t t f 4 f 16 "1184 1184 1184 1184" 100 0 0 100      overlaps_timestamp - ));
@@ -2465,37 +2465,37 @@ DATA(insert OID = 1799 (  oidout                   PGUID 12 f t t t 1 f 23 "0" 100 0 0 100      oid
 DESCR("(internal)");
 
 /* Selectivity estimators for LIKE and related operators */
-DATA(insert OID = 1814 ( iclikesel                     PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  iclikesel - ));
+DATA(insert OID = 1814 ( iclikesel                     PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  iclikesel - ));
 DESCR("restriction selectivity of ILIKE");
-DATA(insert OID = 1815 ( icnlikesel                    PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  icnlikesel - ));
+DATA(insert OID = 1815 ( icnlikesel                    PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  icnlikesel - ));
 DESCR("restriction selectivity of NOT ILIKE");
-DATA(insert OID = 1816 ( iclikejoinsel         PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100   iclikejoinsel - ));
+DATA(insert OID = 1816 ( iclikejoinsel         PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100   iclikejoinsel - ));
 DESCR("join selectivity of ILIKE");
-DATA(insert OID = 1817 ( icnlikejoinsel                PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100   icnlikejoinsel - ));
+DATA(insert OID = 1817 ( icnlikejoinsel                PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100   icnlikejoinsel - ));
 DESCR("join selectivity of NOT ILIKE");
-DATA(insert OID = 1818 ( regexeqsel                    PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  regexeqsel - ));
+DATA(insert OID = 1818 ( regexeqsel                    PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  regexeqsel - ));
 DESCR("restriction selectivity of regex match");
-DATA(insert OID = 1819 ( likesel                       PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  likesel - ));
+DATA(insert OID = 1819 ( likesel                       PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  likesel - ));
 DESCR("restriction selectivity of LIKE");
-DATA(insert OID = 1820 ( icregexeqsel          PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  icregexeqsel - ));
+DATA(insert OID = 1820 ( icregexeqsel          PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  icregexeqsel - ));
 DESCR("restriction selectivity of case-insensitive regex match");
-DATA(insert OID = 1821 ( regexnesel                    PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  regexnesel - ));
+DATA(insert OID = 1821 ( regexnesel                    PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  regexnesel - ));
 DESCR("restriction selectivity of regex non-match");
-DATA(insert OID = 1822 ( nlikesel                      PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  nlikesel - ));
+DATA(insert OID = 1822 ( nlikesel                      PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  nlikesel - ));
 DESCR("restriction selectivity of NOT LIKE");
-DATA(insert OID = 1823 ( icregexnesel          PGUID 12 f t f t 5 f 701 "26 26 21 0 23" 100 0 0 100  icregexnesel - ));
+DATA(insert OID = 1823 ( icregexnesel          PGUID 12 f t f t 4 f 701 "0 26 0 23" 100 0 0 100  icregexnesel - ));
 DESCR("restriction selectivity of case-insensitive regex non-match");
-DATA(insert OID = 1824 ( regexeqjoinsel                PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100   regexeqjoinsel - ));
+DATA(insert OID = 1824 ( regexeqjoinsel                PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100   regexeqjoinsel - ));
 DESCR("join selectivity of regex match");
-DATA(insert OID = 1825 ( likejoinsel           PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100   likejoinsel - ));
+DATA(insert OID = 1825 ( likejoinsel           PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100   likejoinsel - ));
 DESCR("join selectivity of LIKE");
-DATA(insert OID = 1826 ( icregexeqjoinsel      PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100   icregexeqjoinsel - ));
+DATA(insert OID = 1826 ( icregexeqjoinsel      PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100   icregexeqjoinsel - ));
 DESCR("join selectivity of case-insensitive regex match");
-DATA(insert OID = 1827 ( regexnejoinsel                PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100   regexnejoinsel - ));
+DATA(insert OID = 1827 ( regexnejoinsel                PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100   regexnejoinsel - ));
 DESCR("join selectivity of regex non-match");
-DATA(insert OID = 1828 ( nlikejoinsel          PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100   nlikejoinsel - ));
+DATA(insert OID = 1828 ( nlikejoinsel          PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100   nlikejoinsel - ));
 DESCR("join selectivity of NOT LIKE");
-DATA(insert OID = 1829 ( icregexnejoinsel      PGUID 12 f t f t 5 f 701 "26 26 21 26 21" 100 0 0 100   icregexnejoinsel - ));
+DATA(insert OID = 1829 ( icregexnejoinsel      PGUID 12 f t f t 3 f 701 "0 26 0" 100 0 0 100   icregexnejoinsel - ));
 DESCR("join selectivity of case-insensitive regex non-match");
 
 /* Aggregate-related functions */
index 63b1b10..cfea522 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.127 2001/05/07 00:43:25 tgl Exp $
+ * $Id: parsenodes.h,v 1.128 2001/05/20 20:28:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -83,6 +83,7 @@ typedef struct Query
 
        /* internal to planner */
        List       *base_rel_list;      /* list of base-relation RelOptInfos */
+       List       *other_rel_list;     /* list of other 1-relation RelOptInfos */
        List       *join_rel_list;      /* list of join-relation RelOptInfos */
        List       *equi_key_list;      /* list of lists of equijoined
                                                                 * PathKeyItems */
index c76d9b4..33927ed 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: relation.h,v 1.55 2001/05/07 00:43:26 tgl Exp $
+ * $Id: relation.h,v 1.56 2001/05/20 20:28:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -72,8 +72,8 @@ typedef enum CostSelector
  *      * If the relation is a base relation it will have these fields set:
  *
  *             issubquery - true if baserel is a subquery RTE rather than a table
- *             indexed - true if the relation has secondary indices (always false
- *                               if it's a subquery)
+ *             indexlist - list of IndexOptInfo nodes for relation's indexes
+ *                                     (always NIL if it's a subquery)
  *             pages - number of disk pages in relation (zero if a subquery)
  *             tuples - number of tuples in relation (not considering restrictions)
  *             subplan - plan for subquery (NULL if it's a plain table)
@@ -150,7 +150,7 @@ typedef struct RelOptInfo
 
        /* information about a base rel (not set for join rels!) */
        bool            issubquery;
-       bool            indexed;
+       List       *indexlist;
        long            pages;
        double          tuples;
        struct Plan *subplan;
@@ -178,20 +178,30 @@ typedef struct RelOptInfo
  *             and indexes, but that created confusion without actually doing anything
  *             useful.  So now we have a separate IndexOptInfo struct for indexes.
  *
- *             indexoid - OID of the index relation itself
- *             pages - number of disk pages in index
- *             tuples - number of index tuples in index
+ *             indexoid  - OID of the index relation itself
+ *             pages     - number of disk pages in index
+ *             tuples    - number of index tuples in index
+ *             ncolumns  - number of columns in index
+ *             nkeys     - number of keys used by index (input columns)
  *             classlist - List of PG_AMOPCLASS OIDs for the index
  *             indexkeys - List of base-relation attribute numbers that are index keys
- *             ordering - List of PG_OPERATOR OIDs which order the indexscan result
- *             relam     - the OID of the pg_am of the index
+ *             ordering  - List of PG_OPERATOR OIDs which order the indexscan result
+ *             relam     - the OID of the pg_am of the index
  *             amcostestimate - OID of the relam's cost estimator
  *             indproc   - OID of the function if a functional index, else 0
  *             indpred   - index predicate if a partial index, else NULL
+ *             unique    - true if index is unique
  *             lossy     - true if index is lossy (may return non-matching tuples)
  *
- *             NB. the last element of the arrays classlist, indexkeys and ordering
- *                     is always 0.
+ *             ncolumns and nkeys are the same except for a functional index,
+ *             wherein ncolumns is 1 (the single function output) while nkeys
+ *             is the number of table columns passed to the function. classlist[]
+ *             and ordering[] have ncolumns entries, while indexkeys[] has nkeys
+ *             entries.
+ * 
+ *             Note: for historical reasons, the arrays classlist, indexkeys and
+ *             ordering have an extra entry that is always zero.  Some code scans
+ *             until it sees a zero rather than looking at ncolumns or nkeys.
  */
 
 typedef struct IndexOptInfo
@@ -205,15 +215,18 @@ typedef struct IndexOptInfo
        double          tuples;
 
        /* index descriptor information */
-       Oid                *classlist;          /* classes of AM operators */
-       int                *indexkeys;          /* keys over which we're indexing */
-       Oid                *ordering;           /* OIDs of sort operators for each key */
+       int                     ncolumns;               /* number of columns in index */
+       int                     nkeys;                  /* number of keys used by index */
+       Oid                *classlist;          /* AM operator classes for columns */
+       int                *indexkeys;          /* column numbers of index's keys */
+       Oid                *ordering;           /* OIDs of sort operators for each column */
        Oid                     relam;                  /* OID of the access method (in pg_am) */
 
        RegProcedure amcostestimate;/* OID of the access method's cost fcn */
 
        Oid                     indproc;                /* if a functional index */
        List       *indpred;            /* if a partial index */
+       bool            unique;                 /* if a unique index */
        bool            lossy;                  /* if a lossy index */
 } IndexOptInfo;
 
@@ -275,7 +288,7 @@ typedef struct Path
  * tuples matched during any scan.     (The executor is smart enough not to return
  * the same tuple more than once, even if it is matched in multiple scans.)
  *
- * 'indexid' is a list of index relation OIDs, one per scan to be performed.
+ * 'indexinfo' is a list of IndexOptInfo nodes, one per scan to be performed.
  *
  * 'indexqual' is a list of index qualifications, also one per scan.
  * Each entry in 'indexqual' is a sublist of qualification expressions with
@@ -313,7 +326,7 @@ typedef struct Path
 typedef struct IndexPath
 {
        Path            path;
-       List       *indexid;
+       List       *indexinfo;
        List       *indexqual;
        ScanDirection indexscandir;
        Relids          joinrelids;             /* other rels mentioned in indexqual */
@@ -533,7 +546,7 @@ typedef struct RestrictInfo
 typedef struct JoinInfo
 {
        NodeTag         type;
-       Relids          unjoined_relids;/* some rels not yet part of my RelOptInfo */
+       Relids          unjoined_relids; /* some rels not yet part of my RelOptInfo */
        List       *jinfo_restrictinfo;         /* relevant RestrictInfos */
 } JoinInfo;
 
index a02ef9c..79bb7a1 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: clauses.h,v 1.43 2001/03/22 04:00:53 momjian Exp $
+ * $Id: clauses.h,v 1.44 2001/05/20 20:28:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "nodes/relation.h"
 
-/*
- *     Flag bits returned by get_relattval().
- *     These are used in selectivity-estimation routines, too.
- */
-#define SEL_CONSTANT   1               /* operator's non-var arg is a constant */
-#define SEL_RIGHT              2               /* operator's non-var arg is on the right */
-
-
 extern Expr *make_clause(int type, Node *oper, List *args);
 
 extern bool is_opclause(Node *clause);
@@ -61,11 +53,6 @@ extern List *pull_constant_clauses(List *quals, List **constantQual);
 
 extern void clause_get_relids_vars(Node *clause, Relids *relids, List **vars);
 extern int     NumRelids(Node *clause);
-extern void get_relattval(Node *clause, int targetrelid,
-                         int *relid, AttrNumber *attno,
-                         Datum *constval, int *flag);
-extern void get_rels_atts(Node *clause, int *relid1,
-                         AttrNumber *attno1, int *relid2, AttrNumber *attno2);
 extern void CommuteClause(Expr *clause);
 
 extern Node *eval_const_expressions(Node *node);
index 0839feb..85ba693 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: pathnode.h,v 1.36 2001/05/07 00:43:26 tgl Exp $
+ * $Id: pathnode.h,v 1.37 2001/05/20 20:28:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -64,9 +64,10 @@ extern HashPath *create_hashjoin_path(RelOptInfo *joinrel,
 /*
  * prototypes for relnode.c
  */
-extern RelOptInfo *get_base_rel(Query *root, int relid);
-extern RelOptInfo *make_base_rel(Query *root, int relid);
-extern RelOptInfo *get_join_rel(Query *root,
+extern RelOptInfo *build_base_rel(Query *root, int relid);
+extern RelOptInfo *build_other_rel(Query *root, int relid);
+extern RelOptInfo *find_base_rel(Query *root, int relid);
+extern RelOptInfo *build_join_rel(Query *root,
                         RelOptInfo *outer_rel,
                         RelOptInfo *inner_rel,
                         JoinType jointype,
index ac67f6a..39afe74 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: paths.h,v 1.52 2001/03/22 04:00:54 momjian Exp $
+ * $Id: paths.h,v 1.53 2001/05/20 20:28:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,7 +35,7 @@ extern RelOptInfo *make_fromexpr_rel(Query *root, FromExpr *from);
  * indxpath.c
  *       routines to generate index paths
  */
-extern void create_index_paths(Query *root, RelOptInfo *rel, List *indices);
+extern void create_index_paths(Query *root, RelOptInfo *rel);
 extern Oid indexable_operator(Expr *clause, Oid opclass, Oid relam,
                                   bool indexkey_on_left);
 extern List *extract_or_indexqual_conditions(RelOptInfo *rel,
index 5d3062d..a103f51 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: plancat.h,v 1.22 2001/03/22 04:00:55 momjian Exp $
+ * $Id: plancat.h,v 1.23 2001/05/20 20:28:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,7 +17,7 @@
 #include "nodes/relation.h"
 
 
-extern void relation_info(Oid relationObjectId,
+extern void get_relation_info(Oid relationObjectId,
                          bool *hasindex, long *pages, double *tuples);
 
 extern List *find_secondary_indexes(Oid relationObjectId);
@@ -26,15 +26,15 @@ extern List *find_inheritance_children(Oid inhparent);
 
 extern bool has_subclass(Oid relationId);
 
-extern Selectivity restriction_selectivity(Oid functionObjectId,
-                                               Oid operatorObjectId,
-                                               Oid relationObjectId,
-                                               AttrNumber attributeNumber,
-                                               Datum constValue,
-                                               int constFlag);
+extern bool has_unique_index(RelOptInfo *rel, AttrNumber attno);
 
-extern Selectivity join_selectivity(Oid functionObjectId, Oid operatorObjectId,
-                                Oid relationObjectId1, AttrNumber attributeNumber1,
-                                Oid relationObjectId2, AttrNumber attributeNumber2);
+extern Selectivity restriction_selectivity(Query *root,
+                                                                                  Oid operator,
+                                                                                  List *args,
+                                                                                  int varRelid);
+
+extern Selectivity join_selectivity(Query *root,
+                                                                       Oid operator,
+                                                                       List *args);
 
 #endif  /* PLANCAT_H */
index b1ca99f..1888248 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: prep.h,v 1.27 2001/03/22 04:00:55 momjian Exp $
+ * $Id: prep.h,v 1.28 2001/05/20 20:28:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,7 +35,9 @@ extern List *preprocess_targetlist(List *tlist, int command_type,
 extern Plan *plan_set_operations(Query *parse);
 
 extern List *find_all_inheritors(Oid parentrel);
-extern List *expand_inherted_rtentry(Query *parse, Index rti);
+
+extern List *expand_inherted_rtentry(Query *parse, Index rti,
+                                                                        bool dup_parent);
 
 extern Node *adjust_inherited_attrs(Node *node,
                                           Index old_rt_index, Oid old_relid,
index 33deafd..cc71f44 100644 (file)
@@ -418,16 +418,15 @@ WHERE p1.oprcode = p2.oid AND
 -- If oprrest is set, the operator must return boolean,
 -- and it must link to a proc with the right signature
 -- to be a restriction selectivity estimator.
--- The proc signature we want is: float8 proc(oid, oid, int2, <any>, int4)
+-- The proc signature we want is: float8 proc(opaque, oid, opaque, int4)
 SELECT p1.oid, p1.oprname, p2.oid, p2.proname
 FROM pg_operator AS p1, pg_proc AS p2
 WHERE p1.oprrest = p2.oid AND
     (p1.oprresult != 16 OR
      p2.prorettype != 701 OR p2.proretset OR
-     p2.pronargs != 5 OR
-     p2.proargtypes[0] != 26 OR p2.proargtypes[1] != 26 OR
-     p2.proargtypes[2] != 21 OR p2.proargtypes[3] != 0 OR
-     p2.proargtypes[4] != 23);
+     p2.pronargs != 4 OR
+     p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
+     p2.proargtypes[2] != 0 OR p2.proargtypes[3] != 23);
  oid | oprname | oid | proname 
 -----+---------+-----+---------
 (0 rows)
@@ -435,16 +434,15 @@ WHERE p1.oprrest = p2.oid AND
 -- If oprjoin is set, the operator must be a binary boolean op,
 -- and it must link to a proc with the right signature
 -- to be a join selectivity estimator.
--- The proc signature we want is: float8 proc(oid, oid, int2, oid, int2)
+-- The proc signature we want is: float8 proc(opaque, oid, opaque)
 SELECT p1.oid, p1.oprname, p2.oid, p2.proname
 FROM pg_operator AS p1, pg_proc AS p2
 WHERE p1.oprjoin = p2.oid AND
     (p1.oprkind != 'b' OR p1.oprresult != 16 OR
      p2.prorettype != 701 OR p2.proretset OR
-     p2.pronargs != 5 OR
-     p2.proargtypes[0] != 26 OR p2.proargtypes[1] != 26 OR
-     p2.proargtypes[2] != 21 OR p2.proargtypes[3] != 26 OR
-     p2.proargtypes[4] != 21);
+     p2.pronargs != 3 OR
+     p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
+     p2.proargtypes[2] != 0);
  oid | oprname | oid | proname 
 -----+---------+-----+---------
 (0 rows)
index a79d0ea..1cb5cd1 100644 (file)
@@ -349,32 +349,30 @@ WHERE p1.oprcode = p2.oid AND
 -- If oprrest is set, the operator must return boolean,
 -- and it must link to a proc with the right signature
 -- to be a restriction selectivity estimator.
--- The proc signature we want is: float8 proc(oid, oid, int2, <any>, int4)
+-- The proc signature we want is: float8 proc(opaque, oid, opaque, int4)
 
 SELECT p1.oid, p1.oprname, p2.oid, p2.proname
 FROM pg_operator AS p1, pg_proc AS p2
 WHERE p1.oprrest = p2.oid AND
     (p1.oprresult != 16 OR
      p2.prorettype != 701 OR p2.proretset OR
-     p2.pronargs != 5 OR
-     p2.proargtypes[0] != 26 OR p2.proargtypes[1] != 26 OR
-     p2.proargtypes[2] != 21 OR p2.proargtypes[3] != 0 OR
-     p2.proargtypes[4] != 23);
+     p2.pronargs != 4 OR
+     p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
+     p2.proargtypes[2] != 0 OR p2.proargtypes[3] != 23);
 
 -- If oprjoin is set, the operator must be a binary boolean op,
 -- and it must link to a proc with the right signature
 -- to be a join selectivity estimator.
--- The proc signature we want is: float8 proc(oid, oid, int2, oid, int2)
+-- The proc signature we want is: float8 proc(opaque, oid, opaque)
 
 SELECT p1.oid, p1.oprname, p2.oid, p2.proname
 FROM pg_operator AS p1, pg_proc AS p2
 WHERE p1.oprjoin = p2.oid AND
     (p1.oprkind != 'b' OR p1.oprresult != 16 OR
      p2.prorettype != 701 OR p2.proretset OR
-     p2.pronargs != 5 OR
-     p2.proargtypes[0] != 26 OR p2.proargtypes[1] != 26 OR
-     p2.proargtypes[2] != 21 OR p2.proargtypes[3] != 26 OR
-     p2.proargtypes[4] != 21);
+     p2.pronargs != 3 OR
+     p2.proargtypes[0] != 0 OR p2.proargtypes[1] != 26 OR
+     p2.proargtypes[2] != 0);
 
 -- **************** pg_aggregate ****************