mirror of
https://github.com/postgres/postgres.git
synced 2025-11-22 12:22:45 +03:00
Subselects in FROM clause, per ISO syntax: FROM (SELECT ...) [AS] alias.
(Don't forget that an alias is required.) Views reimplemented as expanding to subselect-in-FROM. Grouping, aggregates, DISTINCT in views actually work now (he says optimistically). No UNION support in subselects/views yet, but I have some ideas about that. Rule-related permissions checking moved out of rewriter and into executor. INITDB REQUIRED!
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: execnodes.h,v 1.49 2000/09/12 21:07:10 tgl Exp $
|
||||
* $Id: execnodes.h,v 1.50 2000/09/29 18:21:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -453,6 +453,24 @@ typedef struct TidScanState
|
||||
HeapTupleData tss_htup;
|
||||
} TidScanState;
|
||||
|
||||
/* ----------------
|
||||
* SubqueryScanState information
|
||||
*
|
||||
* SubqueryScanState is used for scanning a sub-query in the range table.
|
||||
* The sub-query will have its own EState, which we save here.
|
||||
* ScanTupleSlot references the current output tuple of the sub-query.
|
||||
*
|
||||
* SubQueryDesc queryDesc for sub-query
|
||||
* SubEState exec state for sub-query
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct SubqueryScanState
|
||||
{
|
||||
CommonScanState csstate; /* its first field is NodeTag */
|
||||
struct QueryDesc *sss_SubQueryDesc;
|
||||
EState *sss_SubEState;
|
||||
} SubqueryScanState;
|
||||
|
||||
/* ----------------------------------------------------------------
|
||||
* Join State Information
|
||||
* ----------------------------------------------------------------
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: nodes.h,v 1.76 2000/09/12 21:07:10 tgl Exp $
|
||||
* $Id: nodes.h,v 1.77 2000/09/29 18:21:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -49,6 +49,7 @@ typedef enum NodeTag
|
||||
T_Group,
|
||||
T_SubPlan,
|
||||
T_TidScan,
|
||||
T_SubqueryScan,
|
||||
|
||||
/*---------------------
|
||||
* TAGS FOR PRIMITIVE NODES (primnodes.h)
|
||||
@@ -69,6 +70,7 @@ typedef enum NodeTag
|
||||
T_Iter,
|
||||
T_RelabelType,
|
||||
T_RangeTblRef,
|
||||
T_FromExpr,
|
||||
T_JoinExpr,
|
||||
|
||||
/*---------------------
|
||||
@@ -118,6 +120,7 @@ typedef enum NodeTag
|
||||
T_UniqueState,
|
||||
T_HashState,
|
||||
T_TidScanState,
|
||||
T_SubqueryScanState,
|
||||
|
||||
/*---------------------
|
||||
* TAGS FOR MEMORY NODES (memnodes.h)
|
||||
@@ -222,7 +225,7 @@ typedef enum NodeTag
|
||||
T_oldJoinExprXXX, /* not used anymore; this tag# is available */
|
||||
T_CaseExpr,
|
||||
T_CaseWhen,
|
||||
T_RowMark,
|
||||
T_RowMarkXXX, /* not used anymore; this tag# is available */
|
||||
T_FkConstraint,
|
||||
|
||||
/*---------------------
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: parsenodes.h,v 1.113 2000/09/12 21:07:10 tgl Exp $
|
||||
* $Id: parsenodes.h,v 1.114 2000/09/29 18:21:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -50,11 +50,12 @@ typedef struct Query
|
||||
bool hasSubLinks; /* has subquery SubLink */
|
||||
|
||||
List *rtable; /* list of range table entries */
|
||||
List *jointree; /* table join tree (from the FROM clause) */
|
||||
FromExpr *jointree; /* table join tree (FROM and WHERE clauses) */
|
||||
|
||||
List *targetList; /* target list (of TargetEntry) */
|
||||
Node *qual; /* qualifications applied to tuples */
|
||||
List *rowMark; /* list of RowMark entries */
|
||||
|
||||
List *rowMarks; /* integer list of RT indexes of relations
|
||||
* that are selected FOR UPDATE */
|
||||
|
||||
List *distinctClause; /* a list of SortClause's */
|
||||
|
||||
@@ -1087,7 +1088,7 @@ typedef struct RangeSubselect
|
||||
{
|
||||
NodeTag type;
|
||||
Node *subquery; /* the untransformed sub-select clause */
|
||||
Attr *name; /* optional table alias & column aliases */
|
||||
Attr *name; /* table alias & optional column aliases */
|
||||
} RangeSubselect;
|
||||
|
||||
/*
|
||||
@@ -1141,15 +1142,22 @@ typedef struct TargetEntry
|
||||
* RangeTblEntry -
|
||||
* A range table is a List of RangeTblEntry nodes.
|
||||
*
|
||||
* Some of the following are only used in one of
|
||||
* the parsing, optimizing, execution stages.
|
||||
* Currently we use the same node type for both plain relation references
|
||||
* and sub-selects in the FROM clause. It might be cleaner to abstract
|
||||
* the common fields into a "superclass" nodetype.
|
||||
*
|
||||
* alias is an Attr node representing the AS alias-clause attached to the
|
||||
* FROM expression, or NULL if no clause.
|
||||
*
|
||||
* eref is the table reference name and column reference names (either
|
||||
* real or aliases). This is filled in during parse analysis. Note that
|
||||
* system columns (OID etc) are not included in the column list.
|
||||
* real or aliases). Note that system columns (OID etc) are not included
|
||||
* in the column list.
|
||||
* eref->relname is required to be present, and should generally be used
|
||||
* to identify the RTE for error messages etc.
|
||||
*
|
||||
* inh is TRUE for relation references that should be expanded to include
|
||||
* inheritance children, if the rel has any. This *must* be FALSE for
|
||||
* subquery RTEs.
|
||||
*
|
||||
* inFromCl marks those range variables that are listed in the FROM clause.
|
||||
* In SQL, the query can only refer to range variables listed in the
|
||||
@@ -1160,18 +1168,37 @@ typedef struct TargetEntry
|
||||
* implicitly-added RTE shouldn't change the namespace for unqualified
|
||||
* column names processed later, and it also shouldn't affect the
|
||||
* expansion of '*'.
|
||||
*
|
||||
* checkForRead, checkForWrite, and checkAsUser control run-time access
|
||||
* permissions checks. A rel will be checked for read or write access
|
||||
* (or both, or neither) per checkForRead and checkForWrite. If
|
||||
* checkAsUser is not InvalidOid, then do the permissions checks using
|
||||
* the access rights of that user, not the current effective user ID.
|
||||
* (This allows rules to act as setuid gateways.)
|
||||
*--------------------
|
||||
*/
|
||||
typedef struct RangeTblEntry
|
||||
{
|
||||
NodeTag type;
|
||||
/*
|
||||
* Fields valid for a plain relation RTE (else NULL/zero):
|
||||
*/
|
||||
char *relname; /* real name of the relation */
|
||||
Oid relid; /* OID of the relation */
|
||||
/*
|
||||
* Fields valid for a subquery RTE (else NULL):
|
||||
*/
|
||||
Query *subquery; /* the sub-query */
|
||||
/*
|
||||
* Fields valid in all RTEs:
|
||||
*/
|
||||
Attr *alias; /* user-written alias clause, if any */
|
||||
Attr *eref; /* expanded reference names */
|
||||
bool inh; /* inheritance requested? */
|
||||
bool inFromCl; /* present in FROM clause */
|
||||
bool skipAcl; /* skip ACL check in executor */
|
||||
bool checkForRead; /* check rel for read access */
|
||||
bool checkForWrite; /* check rel for write access */
|
||||
Oid checkAsUser; /* if not zero, check access as this user */
|
||||
} RangeTblEntry;
|
||||
|
||||
/*
|
||||
@@ -1206,14 +1233,4 @@ typedef struct SortClause
|
||||
*/
|
||||
typedef SortClause GroupClause;
|
||||
|
||||
#define ROW_MARK_FOR_UPDATE (1 << 0)
|
||||
#define ROW_ACL_FOR_UPDATE (1 << 1)
|
||||
|
||||
typedef struct RowMark
|
||||
{
|
||||
NodeTag type;
|
||||
Index rti; /* index in Query->rtable */
|
||||
bits8 info; /* as above */
|
||||
} RowMark;
|
||||
|
||||
#endif /* PARSENODES_H */
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: pg_list.h,v 1.19 2000/09/12 21:07:10 tgl Exp $
|
||||
* $Id: pg_list.h,v 1.20 2000/09/29 18:21:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -92,6 +92,18 @@ typedef struct List
|
||||
#define foreach(_elt_,_list_) \
|
||||
for(_elt_=(_list_); _elt_!=NIL; _elt_=lnext(_elt_))
|
||||
|
||||
/*
|
||||
* Convenience macros for building fixed-length lists
|
||||
*/
|
||||
#define makeList1(x1) lcons(x1, NIL)
|
||||
#define makeList2(x1,x2) lcons(x1, makeList1(x2))
|
||||
#define makeList3(x1,x2,x3) lcons(x1, makeList2(x2,x3))
|
||||
#define makeList4(x1,x2,x3,x4) lcons(x1, makeList3(x2,x3,x4))
|
||||
|
||||
#define makeListi1(x1) lconsi(x1, NIL)
|
||||
#define makeListi2(x1,x2) lconsi(x1, makeListi1(x2))
|
||||
#define makeListi3(x1,x2,x3) lconsi(x1, makeListi2(x2,x3))
|
||||
#define makeListi4(x1,x2,x3,x4) lconsi(x1, makeListi3(x2,x3,x4))
|
||||
|
||||
/*
|
||||
* function prototypes in nodes/list.c
|
||||
@@ -106,11 +118,11 @@ extern bool intMember(int datum, List *list);
|
||||
extern Value *makeInteger(long i);
|
||||
extern Value *makeFloat(char *numericStr);
|
||||
extern Value *makeString(char *str);
|
||||
extern List *makeList(void *elem,...);
|
||||
extern List *lappend(List *list, void *datum);
|
||||
extern List *lappendi(List *list, int datum);
|
||||
extern List *lremove(void *elem, List *list);
|
||||
extern List *LispRemove(void *elem, List *list);
|
||||
extern List *lremovei(int elem, List *list);
|
||||
extern List *ltruncate(int n, List *list);
|
||||
|
||||
extern void *nth(int n, List *l);
|
||||
@@ -120,8 +132,8 @@ extern void set_nth(List *l, int n, void *elem);
|
||||
extern List *set_difference(List *list1, List *list2);
|
||||
extern List *set_differencei(List *list1, List *list2);
|
||||
extern List *lreverse(List *l);
|
||||
extern List *LispUnion(List *list1, List *list2);
|
||||
extern List *LispUnioni(List *list1, List *list2);
|
||||
extern List *set_union(List *list1, List *list2);
|
||||
extern List *set_unioni(List *list1, List *list2);
|
||||
|
||||
extern bool sameseti(List *list1, List *list2);
|
||||
extern bool nonoverlap_setsi(List *list1, List *list2);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: plannodes.h,v 1.42 2000/09/12 21:07:10 tgl Exp $
|
||||
* $Id: plannodes.h,v 1.43 2000/09/29 18:21:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -31,6 +31,7 @@
|
||||
*
|
||||
* Scan *** CommonScanState scanstate;
|
||||
* IndexScan IndexScanState indxstate;
|
||||
* SubqueryScan SubqueryScanState subquerystate;
|
||||
*
|
||||
* (*** nodes which inherit Scan also inherit scanstate)
|
||||
*
|
||||
@@ -202,6 +203,26 @@ typedef struct TidScan
|
||||
TidScanState *tidstate;
|
||||
} TidScan;
|
||||
|
||||
/* ----------------
|
||||
* subquery scan node
|
||||
*
|
||||
* SubqueryScan is for scanning the output of a sub-query in the range table.
|
||||
* We need a special plan node above the sub-query's plan as a place to switch
|
||||
* execution contexts. Although we are not scanning a physical relation,
|
||||
* we make this a descendant of Scan anyway for code-sharing purposes.
|
||||
*
|
||||
* Note: we store the sub-plan in the type-specific subplan field, not in
|
||||
* the generic lefttree field as you might expect. This is because we do
|
||||
* not want plan-tree-traversal routines to recurse into the subplan without
|
||||
* knowing that they are changing Query contexts.
|
||||
* ----------------
|
||||
*/
|
||||
typedef struct SubqueryScan
|
||||
{
|
||||
Scan scan;
|
||||
Plan *subplan;
|
||||
} SubqueryScan;
|
||||
|
||||
/*
|
||||
* ==========
|
||||
* Join nodes
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: primnodes.h,v 1.48 2000/09/12 21:07:10 tgl Exp $
|
||||
* $Id: primnodes.h,v 1.49 2000/09/29 18:21:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -495,24 +495,32 @@ typedef struct RelabelType
|
||||
*
|
||||
* The leaves of a join tree structure are RangeTblRef nodes. Above
|
||||
* these, JoinExpr nodes can appear to denote a specific kind of join
|
||||
* or qualified join. A join tree can also contain List nodes --- a list
|
||||
* implies an unqualified cross-product join of its members. The planner
|
||||
* is allowed to combine the elements of a list using whatever join order
|
||||
* seems good to it. At present, JoinExpr nodes are always joined in
|
||||
* exactly the order implied by the tree structure (except the planner
|
||||
* may choose to swap inner and outer members of a join pair).
|
||||
* or qualified join. Also, FromExpr nodes can appear to denote an
|
||||
* ordinary cross-product join ("FROM foo, bar, baz WHERE ...").
|
||||
* FromExpr is like a JoinExpr of jointype JOIN_INNER, except that it
|
||||
* may have any number of child nodes, not just two. Also, there is an
|
||||
* implementation-defined difference: the planner is allowed to join the
|
||||
* children of a FromExpr using whatever join order seems good to it.
|
||||
* At present, JoinExpr nodes are always joined in exactly the order
|
||||
* implied by the jointree structure (except the planner may choose to
|
||||
* swap inner and outer members of a join pair).
|
||||
*
|
||||
* NOTE: currently, the planner only supports a List at the top level of
|
||||
* a join tree. Should generalize this to allow Lists at lower levels.
|
||||
* NOTE: the top level of a Query's jointree is always a FromExpr.
|
||||
* Even if the jointree contains no rels, there will be a FromExpr.
|
||||
*
|
||||
* NOTE: the qualification expressions present in JoinExpr nodes are
|
||||
* *in addition to* the query's main WHERE clause. For outer joins there
|
||||
* is a real semantic difference between a join qual and a WHERE clause,
|
||||
* though if all joins are inner joins they are interchangeable.
|
||||
* *in addition to* the query's main WHERE clause, which appears as the
|
||||
* qual of the top-level FromExpr. The reason for associating quals with
|
||||
* specific nodes in the jointree is that the position of a qual is critical
|
||||
* when outer joins are present. (If we enforce a qual too soon or too late,
|
||||
* that may cause the outer join to produce the wrong set of NULL-extended
|
||||
* rows.) If all joins are inner joins then all the qual positions are
|
||||
* semantically interchangeable.
|
||||
*
|
||||
* NOTE: in the raw output of gram.y, a join tree contains RangeVar and
|
||||
* RangeSubselect nodes, which are both replaced by RangeTblRef nodes
|
||||
* during the parse analysis phase.
|
||||
* during the parse analysis phase. Also, the top-level FromExpr is added
|
||||
* during parse analysis; the grammar regards FROM and WHERE as separate.
|
||||
* ----------------------------------------------------------------
|
||||
*/
|
||||
|
||||
@@ -561,4 +569,20 @@ typedef struct JoinExpr
|
||||
List *colvars; /* output column nodes (list of expressions) */
|
||||
} JoinExpr;
|
||||
|
||||
/*----------
|
||||
* FromExpr - represents a FROM ... WHERE ... construct
|
||||
*
|
||||
* This is both more flexible than a JoinExpr (it can have any number of
|
||||
* children, including zero) and less so --- we don't need to deal with
|
||||
* aliases and so on. The output column set is implicitly just the union
|
||||
* of the outputs of the children.
|
||||
*----------
|
||||
*/
|
||||
typedef struct FromExpr
|
||||
{
|
||||
NodeTag type;
|
||||
List *fromlist; /* List of join subtrees */
|
||||
Node *quals; /* qualifiers on join, if any */
|
||||
} FromExpr;
|
||||
|
||||
#endif /* PRIMNODES_H */
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $Id: relation.h,v 1.48 2000/09/12 21:07:10 tgl Exp $
|
||||
* $Id: relation.h,v 1.49 2000/09/29 18:21:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -35,10 +35,20 @@ typedef enum CostSelector
|
||||
STARTUP_COST, TOTAL_COST
|
||||
} CostSelector;
|
||||
|
||||
/*
|
||||
/*----------
|
||||
* RelOptInfo
|
||||
* Per-relation information for planning/optimization
|
||||
*
|
||||
* For planning purposes, a "base rel" is either a plain relation (a
|
||||
* table) or the output of a sub-SELECT that appears in the range table.
|
||||
* In either case it is uniquely identified by an RT index. A "joinrel"
|
||||
* is the joining of two or more base rels. A joinrel is identified by
|
||||
* the set of RT indexes for its component baserels.
|
||||
*
|
||||
* Note that there is only one joinrel for any given set of component
|
||||
* baserels, no matter what order we assemble them in; so an unordered
|
||||
* set is the right datatype to identify it with.
|
||||
*
|
||||
* Parts of this data structure are specific to various scan and join
|
||||
* mechanisms. It didn't seem worth creating new node types for them.
|
||||
*
|
||||
@@ -61,9 +71,16 @@ typedef enum CostSelector
|
||||
*
|
||||
* * If the relation is a base relation it will have these fields set:
|
||||
*
|
||||
* indexed - true if the relation has secondary indices
|
||||
* pages - number of disk pages in relation
|
||||
* 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)
|
||||
* 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)
|
||||
*
|
||||
* Note: for a subquery, tuples and subplan are not set immediately
|
||||
* upon creation of the RelOptInfo object; they are filled in when
|
||||
* set_base_rel_pathlist processes the object.
|
||||
*
|
||||
* * The presence of the remaining fields depends on the restrictions
|
||||
* and joins that the relation participates in:
|
||||
@@ -101,6 +118,7 @@ typedef enum CostSelector
|
||||
* outerjoinset is used to ensure correct placement of WHERE clauses that
|
||||
* apply to outer-joined relations; we must not apply such WHERE clauses
|
||||
* until after the outer join is performed.
|
||||
*----------
|
||||
*/
|
||||
|
||||
typedef struct RelOptInfo
|
||||
@@ -122,10 +140,12 @@ typedef struct RelOptInfo
|
||||
struct Path *cheapest_total_path;
|
||||
bool pruneable;
|
||||
|
||||
/* statistics from pg_class (only valid if it's a base rel!) */
|
||||
/* information about a base rel (not set for join rels!) */
|
||||
bool issubquery;
|
||||
bool indexed;
|
||||
long pages;
|
||||
double tuples;
|
||||
struct Plan *subplan;
|
||||
|
||||
/* used by various scans and joins: */
|
||||
List *baserestrictinfo; /* RestrictInfo structures (if
|
||||
@@ -272,7 +292,8 @@ typedef struct Path
|
||||
* included in the outer joinrel in order to make a usable join.
|
||||
*
|
||||
* 'alljoinquals' is also used only for inner paths of nestloop joins.
|
||||
* This flag is TRUE iff all the indexquals came from JOIN/ON conditions.
|
||||
* This flag is TRUE iff all the indexquals came from non-pushed-down
|
||||
* JOIN/ON conditions, which means the path is safe to use for an outer join.
|
||||
*
|
||||
* 'rows' is the estimated result tuple count for the indexscan. This
|
||||
* is the same as path.parent->rows for a simple indexscan, but it is
|
||||
@@ -375,10 +396,10 @@ typedef struct HashPath
|
||||
* Restriction clause info.
|
||||
*
|
||||
* We create one of these for each AND sub-clause of a restriction condition
|
||||
* (WHERE clause). Since the restriction clauses are logically ANDed, we
|
||||
* can use any one of them or any subset of them to filter out tuples,
|
||||
* without having to evaluate the rest. The RestrictInfo node itself stores
|
||||
* data used by the optimizer while choosing the best query plan.
|
||||
* (WHERE or JOIN/ON clause). Since the restriction clauses are logically
|
||||
* ANDed, we can use any one of them or any subset of them to filter out
|
||||
* tuples, without having to evaluate the rest. The RestrictInfo node itself
|
||||
* stores data used by the optimizer while choosing the best query plan.
|
||||
*
|
||||
* If a restriction clause references a single base relation, it will appear
|
||||
* in the baserestrictinfo list of the RelOptInfo for that base rel.
|
||||
@@ -405,6 +426,31 @@ typedef struct HashPath
|
||||
* sequence we use. So, these clauses cannot be associated directly with
|
||||
* the join RelOptInfo, but must be kept track of on a per-join-path basis.
|
||||
*
|
||||
* When dealing with outer joins we have to be very careful about pushing qual
|
||||
* clauses up and down the tree. An outer join's own JOIN/ON conditions must
|
||||
* be evaluated exactly at that join node, and any quals appearing in WHERE or
|
||||
* in a JOIN above the outer join cannot be pushed down below the outer join.
|
||||
* Otherwise the outer join will produce wrong results because it will see the
|
||||
* wrong sets of input rows. All quals are stored as RestrictInfo nodes
|
||||
* during planning, but there's a flag to indicate whether a qual has been
|
||||
* pushed down to a lower level than its original syntactic placement in the
|
||||
* join tree would suggest. If an outer join prevents us from pushing a qual
|
||||
* down to its "natural" semantic level (the level associated with just the
|
||||
* base rels used in the qual) then the qual will appear in JoinInfo lists
|
||||
* that reference more than just the base rels it actually uses. By
|
||||
* pretending that the qual references all the rels appearing in the outer
|
||||
* join, we prevent it from being evaluated below the outer join's joinrel.
|
||||
* When we do form the outer join's joinrel, we still need to distinguish
|
||||
* those quals that are actually in that join's JOIN/ON condition from those
|
||||
* that appeared higher in the tree and were pushed down to the join rel
|
||||
* because they used no other rels. That's what the ispusheddown flag is for;
|
||||
* it tells us that a qual came from a point above the join of the specific
|
||||
* set of base rels that it uses (or that the JoinInfo structures claim it
|
||||
* uses). A clause that originally came from WHERE will *always* have its
|
||||
* ispusheddown flag set; a clause that came from an INNER JOIN condition,
|
||||
* but doesn't use all the rels being joined, will also have ispusheddown set
|
||||
* because it will get attached to some lower joinrel.
|
||||
*
|
||||
* In general, the referenced clause might be arbitrarily complex. The
|
||||
* kinds of clauses we can handle as indexscan quals, mergejoin clauses,
|
||||
* or hashjoin clauses are fairly limited --- the code for each kind of
|
||||
@@ -415,16 +461,6 @@ typedef struct HashPath
|
||||
* qual-expression-evaluation code. (But we are still entitled to count
|
||||
* their selectivity when estimating the result tuple count, if we
|
||||
* can guess what it is...)
|
||||
*
|
||||
* When dealing with outer joins we must distinguish between qual clauses
|
||||
* that came from WHERE and those that came from JOIN/ON or JOIN/USING.
|
||||
* (For inner joins there's no semantic difference and we can treat the
|
||||
* clauses interchangeably.) Both kinds of quals are stored as RestrictInfo
|
||||
* nodes during planning, but there's a flag to indicate where they came from.
|
||||
* Note also that when outer joins are present, a qual clause may be treated
|
||||
* as referencing more rels than it really does. This trick ensures that the
|
||||
* qual will be evaluated at the right level of the join tree --- we don't
|
||||
* want quals from WHERE to be evaluated until after the outer join is done.
|
||||
*/
|
||||
|
||||
typedef struct RestrictInfo
|
||||
@@ -433,7 +469,7 @@ typedef struct RestrictInfo
|
||||
|
||||
Expr *clause; /* the represented clause of WHERE or JOIN */
|
||||
|
||||
bool isjoinqual; /* TRUE if clause came from JOIN/ON */
|
||||
bool ispusheddown; /* TRUE if clause was pushed down in level */
|
||||
|
||||
/* only used if clause is an OR clause: */
|
||||
List *subclauseindices; /* indexes matching subclauses */
|
||||
|
||||
Reference in New Issue
Block a user