Commit 3a94e789 authored by Tom Lane's avatar Tom Lane

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!
parent 6f64c2e5
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.144 2000/09/12 21:06:46 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.145 2000/09/29 18:21:25 tgl Exp $
*
*
* INTERFACE ROUTINES
......@@ -1543,8 +1543,7 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin,
rte->eref->relname = RelationGetRelationName(rel);
rte->inh = false;
rte->inFromCl = true;
rte->skipAcl = false;
adsrc = deparse_expression(expr, lcons(lcons(rte, NIL), NIL), false);
adsrc = deparse_expression(expr, makeList1(makeList1(rte)), false);
values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);
values[Anum_pg_attrdef_adnum - 1] = attnum;
......@@ -1626,8 +1625,7 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin)
rte->eref->relname = RelationGetRelationName(rel);
rte->inh = false;
rte->inFromCl = true;
rte->skipAcl = false;
ccsrc = deparse_expression(expr, lcons(lcons(rte, NIL), NIL), false);
ccsrc = deparse_expression(expr, makeList1(makeList1(rte)), false);
values[Anum_pg_relcheck_rcrelid - 1] = RelationGetRelid(rel);
values[Anum_pg_relcheck_rcname - 1] = DirectFunctionCall1(namein,
......@@ -1750,7 +1748,7 @@ AddRelationRawConstraints(Relation rel,
pstate = make_parsestate(NULL);
makeRangeTable(pstate, NULL);
rte = addRangeTableEntry(pstate, relname, NULL, false, true);
addRTEtoJoinTree(pstate, rte);
addRTEtoJoinList(pstate, rte);
/*
* Process column default expressions.
......@@ -1774,6 +1772,14 @@ AddRelationRawConstraints(Relation rel,
if (contain_var_clause(expr))
elog(ERROR, "Cannot use attribute(s) in DEFAULT clause");
/*
* No subplans or aggregates, either...
*/
if (contain_subplans(expr))
elog(ERROR, "Cannot use subselect in DEFAULT clause");
if (contain_agg_clause(expr))
elog(ERROR, "Cannot use aggregate in DEFAULT clause");
/*
* Check that it will be possible to coerce the expression to the
* column's type. We store the expression without coercion,
......@@ -1884,9 +1890,17 @@ AddRelationRawConstraints(Relation rel,
* Make sure no outside relations are referred to.
*/
if (length(pstate->p_rtable) != 1)
elog(ERROR, "Only relation '%s' can be referenced in CHECK",
elog(ERROR, "Only relation \"%s\" can be referenced in CHECK",
relname);
/*
* No subplans or aggregates, either...
*/
if (contain_subplans(expr))
elog(ERROR, "Cannot use subselect in CHECK clause");
if (contain_agg_clause(expr))
elog(ERROR, "Cannot use aggregate in CHECK clause");
/*
* Might as well try to reduce any constant expressions.
*/
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.103 2000/09/12 21:06:47 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.104 2000/09/29 18:21:26 tgl Exp $
*
* NOTES
* The PerformAddAttribute() code, like most of the relation
......@@ -1135,7 +1135,7 @@ AlterTableAddConstraint(char *relationName,
else
name="<unnamed>";
constlist=lcons(constr, NIL);
constlist = makeList1(constr);
rel = heap_openr(relationName, AccessExclusiveLock);
......@@ -1158,10 +1158,11 @@ AlterTableAddConstraint(char *relationName,
makeRangeTable(pstate, NULL);
rte = addRangeTableEntry(pstate, relationName, NULL,
false, true);
addRTEtoJoinTree(pstate, rte);
addRTEtoJoinList(pstate, rte);
/* Convert the A_EXPR in raw_expr into an EXPR */
expr = transformExpr(pstate, constr->raw_expr, EXPR_COLUMN_FIRST);
expr = transformExpr(pstate, constr->raw_expr,
EXPR_COLUMN_FIRST);
/*
* Make sure it yields a boolean result.
......@@ -1185,14 +1186,14 @@ AlterTableAddConstraint(char *relationName,
/* And fix the opids */
fix_opids(expr);
qual = lcons(expr, NIL);
qual = makeList1(expr);
rte = makeNode(RangeTblEntry);
rte->relname = relationName;
rte->relid = RelationGetRelid(rel);
rte->eref = makeNode(Attr);
rte->eref->relname = relationName;
rtlist = lcons(rte, NIL);
rtlist = makeList1(rte);
/*
* Scan through the rows now, making the necessary things
......
......@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.58 2000/09/12 21:06:47 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.59 2000/09/29 18:21:26 tgl Exp $
*
*/
......@@ -176,6 +176,12 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
case T_IndexScan:
pname = "Index Scan";
break;
case T_TidScan:
pname = "Tid Scan";
break;
case T_SubqueryScan:
pname = "Subquery Scan";
break;
case T_Material:
pname = "Materialize";
break;
......@@ -194,9 +200,6 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
case T_Hash:
pname = "Hash";
break;
case T_TidScan:
pname = "Tid Scan";
break;
default:
pname = "???";
break;
......@@ -225,37 +228,27 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
case T_TidScan:
if (((Scan *) plan)->scanrelid > 0)
{
RangeTblEntry *rte = nth(((Scan *) plan)->scanrelid - 1, es->rtable);
RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
es->rtable);
/* Assume it's on a real relation */
Assert(rte->relname);
appendStringInfo(str, " on %s",
stringStringInfo(rte->relname));
if (rte->alias != NULL)
{
if ((strcmp(rte->alias->relname, rte->relname) != 0)
|| (length(rte->alias->attrs) > 0))
{
appendStringInfo(str, " %s",
stringStringInfo(rte->alias->relname));
if (length(rte->alias->attrs) > 0)
{
List *c;
int firstEntry = true;
appendStringInfo(str, " (");
foreach(c, rte->alias->attrs)
{
if (!firstEntry)
{
appendStringInfo(str, ", ");
firstEntry = false;
}
appendStringInfo(str, "%s", strVal(lfirst(c)));
}
appendStringInfo(str, ")");
}
}
}
if (strcmp(rte->eref->relname, rte->relname) != 0)
appendStringInfo(str, " %s",
stringStringInfo(rte->eref->relname));
}
break;
case T_SubqueryScan:
if (((Scan *) plan)->scanrelid > 0)
{
RangeTblEntry *rte = rt_fetch(((Scan *) plan)->scanrelid,
es->rtable);
appendStringInfo(str, " %s",
stringStringInfo(rte->eref->relname));
}
break;
default:
......@@ -284,7 +277,8 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 2, es);
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan,
indent + 4, es);
}
es->rtable = saved_rtable;
}
......@@ -307,32 +301,12 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
explain_outNode(str, innerPlan(plan), indent + 3, es);
}
/* subPlan-s */
if (plan->subPlan)
{
List *saved_rtable = es->rtable;
List *lst;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " SubPlan\n");
foreach(lst, plan->subPlan)
{
es->rtable = ((SubPlan *) lfirst(lst))->rtable;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan, indent + 4, es);
}
es->rtable = saved_rtable;
}
if (nodeTag(plan) == T_Append)
if (IsA(plan, Append))
{
Append *appendplan = (Append *) plan;
List *saved_rtable = es->rtable;
List *lst;
int whichplan = 0;
Append *appendplan = (Append *) plan;
List *lst;
foreach(lst, appendplan->appendplans)
{
......@@ -351,14 +325,55 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
appendStringInfo(str, " -> ");
explain_outNode(str, subnode, indent + 4, es);
explain_outNode(str, subnode, indent + 3, es);
whichplan++;
}
es->rtable = saved_rtable;
}
if (IsA(plan, SubqueryScan))
{
SubqueryScan *subqueryscan = (SubqueryScan *) plan;
Plan *subnode = subqueryscan->subplan;
RangeTblEntry *rte = rt_fetch(subqueryscan->scan.scanrelid,
es->rtable);
List *saved_rtable = es->rtable;
Assert(rte->subquery != NULL);
es->rtable = rte->subquery->rtable;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, subnode, indent + 3, es);
es->rtable = saved_rtable;
}
/* subPlan-s */
if (plan->subPlan)
{
List *saved_rtable = es->rtable;
List *lst;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " SubPlan\n");
foreach(lst, plan->subPlan)
{
es->rtable = ((SubPlan *) lfirst(lst))->rtable;
for (i = 0; i < indent; i++)
appendStringInfo(str, " ");
appendStringInfo(str, " -> ");
explain_outNode(str, ((SubPlan *) lfirst(lst))->plan,
indent + 4, es);
}
es->rtable = saved_rtable;
}
}
static char *
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: view.c,v 1.48 2000/09/12 21:06:47 tgl Exp $
* $Id: view.c,v 1.49 2000/09/29 18:21:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -39,70 +39,60 @@
static void
DefineVirtualRelation(char *relname, List *tlist)
{
CreateStmt createStmt;
CreateStmt *createStmt = makeNode(CreateStmt);
List *attrList,
*t;
TargetEntry *entry;
Resdom *res;
char *resname;
char *restypename;
/*
* create a list with one entry per attribute of this relation. Each
* entry is a two element list. The first element is the name of the
* attribute (a string) and the second the name of the type (NOTE: a
* string, not a type id!).
* create a list of ColumnDef nodes based on the names and types of
* the (non-junk) targetlist items from the view's SELECT list.
*/
attrList = NIL;
if (tlist != NIL)
foreach(t, tlist)
{
foreach(t, tlist)
TargetEntry *entry = lfirst(t);
Resdom *res = entry->resdom;
if (! res->resjunk)
{
char *resname = res->resname;
char *restypename = typeidTypeName(res->restype);
ColumnDef *def = makeNode(ColumnDef);
TypeName *typename;
/*
* find the names of the attribute & its type
*/
entry = lfirst(t);
res = entry->resdom;
resname = res->resname;
restypename = typeidTypeName(res->restype);
TypeName *typename = makeNode(TypeName);
typename = makeNode(TypeName);
def->colname = pstrdup(resname);
typename->name = pstrdup(restypename);
typename->typmod = res->restypmod;
def->colname = pstrdup(resname);
def->typename = typename;
def->is_not_null = false;
def->is_sequence = false;
def->raw_default = NULL;
def->cooked_default = NULL;
def->constraints = NIL;
attrList = lappend(attrList, def);
}
}
else
if (attrList == NIL)
elog(ERROR, "attempted to define virtual relation with no attrs");
/*
* now create the parametesr for keys/inheritance etc. All of them are
* now create the parameters for keys/inheritance etc. All of them are
* nil...
*/
createStmt.relname = relname;
createStmt.istemp = false;
createStmt.tableElts = attrList;
/* createStmt.tableType = NULL;*/
createStmt.inhRelnames = NIL;
createStmt.constraints = NIL;
createStmt->relname = relname;
createStmt->istemp = false;
createStmt->tableElts = attrList;
createStmt->inhRelnames = NIL;
createStmt->constraints = NIL;
/*
* finally create the relation...
*/
DefineRelation(&createStmt, RELKIND_VIEW);
DefineRelation(createStmt, RELKIND_VIEW);
}
/*------------------------------------------------------------------
......@@ -149,13 +139,12 @@ FormViewRetrieveRule(char *viewName, Query *viewParse)
attr = makeNode(Attr);
attr->relname = pstrdup(viewName);
/* attr->refname = pstrdup(viewName);*/
rule->rulename = pstrdup(rname);
rule->whereClause = NULL;
rule->event = CMD_SELECT;
rule->object = attr;
rule->instead = true;
rule->actions = lcons(viewParse, NIL);
rule->actions = makeList1(viewParse);
return rule;
}
......@@ -231,6 +220,10 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
rt_entry2 = addRangeTableEntry(NULL, viewName,
makeAttr("*NEW*", NULL),
false, false);
/* Must override addRangeTableEntry's default access-check flags */
rt_entry1->checkForRead = false;
rt_entry2->checkForRead = false;
new_rt = lcons(rt_entry1, lcons(rt_entry2, viewParse->rtable));
/*
......
......@@ -4,7 +4,7 @@
# Makefile for executor
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.13 2000/08/31 16:09:56 petere Exp $
# $Header: /cvsroot/pgsql/src/backend/executor/Makefile,v 1.14 2000/09/29 18:21:28 tgl Exp $
#
#-------------------------------------------------------------------------
......@@ -18,7 +18,7 @@ OBJS = execAmi.o execFlatten.o execJunk.o execMain.o \
nodeHashjoin.o nodeIndexscan.o nodeMaterial.o nodeMergejoin.o \
nodeNestloop.o nodeResult.o nodeSeqscan.o nodeSort.o \
nodeUnique.o nodeGroup.o spi.o nodeSubplan.o \
nodeTidscan.o
nodeSubqueryscan.o nodeTidscan.o
all: SUBSYS.o
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: execAmi.c,v 1.51 2000/08/03 19:19:30 tgl Exp $
* $Id: execAmi.c,v 1.52 2000/09/29 18:21:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -44,6 +44,7 @@
#include "executor/nodeSeqscan.h"
#include "executor/nodeSort.h"
#include "executor/nodeSubplan.h"
#include "executor/nodeSubqueryscan.h"
#include "executor/nodeUnique.h"
static Pointer ExecBeginScan(Relation relation, int nkeys, ScanKey skeys,
......@@ -304,6 +305,14 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
ExecIndexReScan((IndexScan *) node, exprCtxt, parent);
break;
case T_TidScan:
ExecTidReScan((TidScan *) node, exprCtxt, parent);
break;
case T_SubqueryScan:
ExecSubqueryReScan((SubqueryScan *) node, exprCtxt, parent);
break;
case T_Material:
ExecMaterialReScan((Material *) node, exprCtxt, parent);
break;
......@@ -348,10 +357,6 @@ ExecReScan(Plan *node, ExprContext *exprCtxt, Plan *parent)
ExecReScanAppend((Append *) node, exprCtxt, parent);
break;
case T_TidScan:
ExecTidReScan((TidScan *) node, exprCtxt, parent);
break;
default:
elog(ERROR, "ExecReScan: node type %d not supported",
nodeTag(node));
......
This diff is collapsed.
......@@ -12,7 +12,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.19 2000/08/13 02:50:03 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execProcnode.c,v 1.20 2000/09/29 18:21:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -90,6 +90,7 @@
#include "executor/nodeSeqscan.h"
#include "executor/nodeSort.h"
#include "executor/nodeSubplan.h"
#include "executor/nodeSubqueryscan.h"
#include "executor/nodeUnique.h"
#include "miscadmin.h"
#include "tcop/tcopprot.h"
......@@ -153,6 +154,15 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
result = ExecInitIndexScan((IndexScan *) node, estate, parent);
break;
case T_TidScan:
result = ExecInitTidScan((TidScan *) node, estate, parent);
break;
case T_SubqueryScan:
result = ExecInitSubqueryScan((SubqueryScan *) node, estate,
parent);
break;
/* ----------------
* join nodes
* ----------------
......@@ -165,6 +175,14 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
result = ExecInitMergeJoin((MergeJoin *) node, estate, parent);
break;
case T_Hash:
result = ExecInitHash((Hash *) node, estate, parent);
break;
case T_HashJoin:
result = ExecInitHashJoin((HashJoin *) node, estate, parent);
break;
/* ----------------
* materialization nodes
* ----------------
......@@ -189,18 +207,6 @@ ExecInitNode(Plan *node, EState *estate, Plan *parent)
result = ExecInitAgg((Agg *) node, estate, parent);
break;
case T_Hash:
result = ExecInitHash((Hash *) node, estate, parent);
break;
case T_HashJoin:
result = ExecInitHashJoin((HashJoin *) node, estate, parent);
break;
case T_TidScan:
result = ExecInitTidScan((TidScan *) node, estate, parent);
break;
default:
elog(ERROR, "ExecInitNode: node %d unsupported", nodeTag(node));
result = FALSE;
......@@ -272,6 +278,14 @@ ExecProcNode(Plan *node, Plan *parent)
result = ExecIndexScan((IndexScan *) node);
break;
case T_TidScan:
result = ExecTidScan((TidScan *) node);
break;
case T_SubqueryScan:
result = ExecSubqueryScan((SubqueryScan *) node);
break;
/* ----------------
* join nodes
* ----------------
......@@ -284,6 +298,14 @@ ExecProcNode(Plan *node, Plan *parent)
result = ExecMergeJoin((MergeJoin *) node);
break;
case T_Hash:
result = ExecHash((Hash *) node);
break;
case T_HashJoin:
result = ExecHashJoin((HashJoin *) node);
break;
/* ----------------
* materialization nodes
* ----------------
......@@ -308,18 +330,6 @@ ExecProcNode(Plan *node, Plan *parent)
result = ExecAgg((Agg *) node);
break;
case T_Hash:
result = ExecHash((Hash *) node);
break;
case T_HashJoin:
result = ExecHashJoin((HashJoin *) node);
break;
case T_TidScan:
result = ExecTidScan((TidScan *) node);
break;
default:
elog(ERROR, "ExecProcNode: node %d unsupported", nodeTag(node));
result = NULL;
......@@ -356,6 +366,12 @@ ExecCountSlotsNode(Plan *node)
case T_IndexScan:
return ExecCountSlotsIndexScan((IndexScan *) node);
case T_TidScan:
return ExecCountSlotsTidScan((TidScan *) node);
case T_SubqueryScan:
return ExecCountSlotsSubqueryScan((SubqueryScan *) node);
/* ----------------
* join nodes
* ----------------
......@@ -366,6 +382,12 @@ ExecCountSlotsNode(Plan *node)
case T_MergeJoin:
return ExecCountSlotsMergeJoin((MergeJoin *) node);
case T_Hash:
return ExecCountSlotsHash((Hash *) node);
case T_HashJoin:
return ExecCountSlotsHashJoin((HashJoin *) node);
/* ----------------
* materialization nodes
* ----------------
......@@ -385,15 +407,6 @@ ExecCountSlotsNode(Plan *node)
case T_Agg:
return ExecCountSlotsAgg((Agg *) node);
case T_Hash:
return ExecCountSlotsHash((Hash *) node);
case T_HashJoin:
return ExecCountSlotsHashJoin((HashJoin *) node);
case T_TidScan:
return ExecCountSlotsTidScan((TidScan *) node);
default:
elog(ERROR, "ExecCountSlotsNode: node not yet supported: %d",
nodeTag(node));
......@@ -462,6 +475,14 @@ ExecEndNode(Plan *node, Plan *parent)
ExecEndIndexScan((IndexScan *) node);
break;
case T_TidScan:
ExecEndTidScan((TidScan *) node);
break;
case T_SubqueryScan:
ExecEndSubqueryScan((SubqueryScan *) node);
break;
/* ----------------
* join nodes
* ----------------
......@@ -474,6 +495,14 @@ ExecEndNode(Plan *node, Plan *parent)
ExecEndMergeJoin((MergeJoin *) node);
break;
case T_Hash:
ExecEndHash((Hash *) node);
break;
case T_HashJoin:
ExecEndHashJoin((HashJoin *) node);
break;
/* ----------------
* materialization nodes
* ----------------
......@@ -498,22 +527,6 @@ ExecEndNode(Plan *node, Plan *parent)
ExecEndAgg((Agg *) node);
break;
/* ----------------
* XXX add hooks to these
* ----------------
*/
case T_Hash:
ExecEndHash((Hash *) node);
break;
case T_HashJoin:
ExecEndHashJoin((HashJoin *) node);
break;
case T_TidScan:
ExecEndTidScan((TidScan *) node);
break;
default:
elog(ERROR, "ExecEndNode: node %d unsupported", nodeTag(node));
break;
......
......@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.39 2000/09/12 21:06:48 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.40 2000/09/29 18:21:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -698,6 +698,22 @@ NodeGetResultTupleSlot(Plan *node)
}
break;
case T_TidScan:
{
CommonScanState *scanstate = ((TidScan *) node)->scan.scanstate;
slot = scanstate->cstate.cs_ResultTupleSlot;
}
break;
case T_SubqueryScan:
{
CommonScanState *scanstate = ((SubqueryScan *) node)->scan.scanstate;
slot = scanstate->cstate.cs_ResultTupleSlot;
}
break;
case T_Material:
{
MaterialState *matstate = ((Material *) node)->matstate;
......@@ -762,14 +778,6 @@ NodeGetResultTupleSlot(Plan *node)
}
break;
case T_TidScan:
{
CommonScanState *scanstate = ((IndexScan *) node)->scan.scanstate;
slot = scanstate->cstate.cs_ResultTupleSlot;
}
break;
default:
/* ----------------
* should never get here
......
/*-------------------------------------------------------------------------
*
* nodeSubqueryscan.c
* Support routines for scanning subqueries (subselects in rangetable).
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/executor/nodeSubqueryscan.c,v 1.1 2000/09/29 18:21:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* ExecSubqueryScan scans a subquery.
* ExecSubqueryNext retrieve next tuple in sequential order.
* ExecInitSubqueryScan creates and initializes a subqueryscan node.
* ExecEndSubqueryScan releases any storage allocated.
* ExecSubqueryReScan rescans the relation
*
*/
#include "postgres.h"
#include "catalog/pg_type.h"
#include "executor/execdebug.h"
#include "executor/execdefs.h"
#include "executor/execdesc.h"
#include "executor/nodeSubqueryscan.h"
#include "parser/parsetree.h"
#include "tcop/pquery.h"
static TupleTableSlot *SubqueryNext(SubqueryScan *node);
/* ----------------------------------------------------------------
* Scan Support
* ----------------------------------------------------------------
*/
/* ----------------------------------------------------------------
* SubqueryNext
*
* This is a workhorse for ExecSubqueryScan
* ----------------------------------------------------------------
*/
static TupleTableSlot *
SubqueryNext(SubqueryScan *node)
{
SubqueryScanState *subquerystate;
EState *estate;
ScanDirection direction;
int execdir;
TupleTableSlot *slot;
Const countOne;
/* ----------------
* get information from the estate and scan state
* ----------------
*/
estate = node->scan.plan.state;
subquerystate = (SubqueryScanState *) node->scan.scanstate;
direction = estate->es_direction;
execdir = ScanDirectionIsBackward(direction) ? EXEC_BACK : EXEC_FOR;
slot = subquerystate->csstate.css_ScanTupleSlot;
/*
* Check if we are evaluating PlanQual for tuple of this relation.
* Additional checking is not good, but no other way for now. We could
* introduce new nodes for this case and handle SubqueryScan --> NewNode
* switching in Init/ReScan plan...
*/
if (estate->es_evTuple != NULL &&
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
{
ExecClearTuple(slot);
if (estate->es_evTupleNull[node->scan.scanrelid - 1])
return slot; /* return empty slot */
/* probably ought to use ExecStoreTuple here... */
slot->val = estate->es_evTuple[node->scan.scanrelid - 1];
slot->ttc_shouldFree = false;
/* Flag for the next call that no more tuples */
estate->es_evTupleNull[node->scan.scanrelid - 1] = true;
return (slot);
}
memset(&countOne, 0, sizeof(countOne));
countOne.type = T_Const;
countOne.consttype = INT4OID;
countOne.constlen = sizeof(int4);
countOne.constvalue = Int32GetDatum(1);
countOne.constisnull = false;
countOne.constbyval = true;
countOne.constisset = false;
countOne.constiscast = false;
/* ----------------
* get the next tuple from the sub-query
* ----------------
*/
slot = ExecutorRun(subquerystate->sss_SubQueryDesc,
subquerystate->sss_SubEState,
execdir,
NULL, /* offset */
(Node *) &countOne);
subquerystate->csstate.css_ScanTupleSlot = slot;
return slot;
}
/* ----------------------------------------------------------------
* ExecSubqueryScan(node)
*
* Scans the subquery sequentially and returns the next qualifying
* tuple.
* It calls the ExecScan() routine and passes it the access method
* which retrieve tuples sequentially.
*
*/
TupleTableSlot *
ExecSubqueryScan(SubqueryScan *node)
{
/* ----------------
* use SubqueryNext as access method
* ----------------
*/
return ExecScan(&node->scan, (ExecScanAccessMtd) SubqueryNext);
}
/* ----------------------------------------------------------------
* ExecInitSubqueryScan
* ----------------------------------------------------------------
*/
bool
ExecInitSubqueryScan(SubqueryScan *node, EState *estate, Plan *parent)
{
SubqueryScanState *subquerystate;
RangeTblEntry *rte;
/* ----------------
* SubqueryScan should not have any "normal" children.
* ----------------
*/
Assert(outerPlan((Plan *) node) == NULL);
Assert(innerPlan((Plan *) node) == NULL);
/* ----------------
* assign the node's execution state
* ----------------
*/
node->scan.plan.state = estate;
/* ----------------
* create new SubqueryScanState for node
* ----------------
*/
subquerystate = makeNode(SubqueryScanState);
node->scan.scanstate = (CommonScanState *) subquerystate;
/* ----------------
* Miscellaneous initialization
*
* + create expression context for node
* ----------------
*/
ExecAssignExprContext(estate, &subquerystate->csstate.cstate);
#define SUBQUERYSCAN_NSLOTS 2
/* ----------------
* tuple table initialization
* ----------------
*/
ExecInitResultTupleSlot(estate, &subquerystate->csstate.cstate);
/* ----------------
* initialize subquery
* ----------------
*/
rte = rt_fetch(node->scan.scanrelid, estate->es_range_table);
Assert(rte->subquery != NULL);
subquerystate->sss_SubQueryDesc = CreateQueryDesc(rte->subquery,
node->subplan,
None);
subquerystate->sss_SubEState = CreateExecutorState();
ExecutorStart(subquerystate->sss_SubQueryDesc,
subquerystate->sss_SubEState);
subquerystate->csstate.css_ScanTupleSlot = NULL;
subquerystate->csstate.cstate.cs_TupFromTlist = false;
/* ----------------
* initialize tuple type
* ----------------
*/
ExecAssignResultTypeFromTL((Plan *) node, &subquerystate->csstate.cstate);
ExecAssignProjectionInfo((Plan *) node, &subquerystate->csstate.cstate);
return TRUE;
}
int
ExecCountSlotsSubqueryScan(SubqueryScan *node)
{
/*
* The subplan has its own tuple table and must not be counted here!
*/
return ExecCountSlotsNode(outerPlan(node)) +
ExecCountSlotsNode(innerPlan(node)) +
SUBQUERYSCAN_NSLOTS;
}
/* ----------------------------------------------------------------
* ExecEndSubqueryScan
*
* frees any storage allocated through C routines.
* ----------------------------------------------------------------
*/
void
ExecEndSubqueryScan(SubqueryScan *node)
{
SubqueryScanState *subquerystate;
/* ----------------
* get information from node
* ----------------
*/
subquerystate = (SubqueryScanState *) node->scan.scanstate;
/* ----------------
* Free the projection info and the scan attribute info
*
* Note: we don't ExecFreeResultType(subquerystate)
* because the rule manager depends on the tupType
* returned by ExecMain(). So for now, this
* is freed at end-transaction time. -cim 6/2/91
* ----------------
*/
ExecFreeProjectionInfo(&subquerystate->csstate.cstate);
ExecFreeExprContext(&subquerystate->csstate.cstate);
/* ----------------
* close down subquery
* ----------------
*/
ExecutorEnd(subquerystate->sss_SubQueryDesc,
subquerystate->sss_SubEState);
/* XXX we seem to be leaking the querydesc and sub-EState... */
subquerystate->csstate.css_ScanTupleSlot = NULL;
/* ----------------
* clean out the tuple table
* ----------------
*/
ExecClearTuple(subquerystate->csstate.cstate.cs_ResultTupleSlot);
}
/* ----------------------------------------------------------------
* ExecSubqueryReScan
*
* Rescans the relation.
* ----------------------------------------------------------------
*/
void
ExecSubqueryReScan(SubqueryScan *node, ExprContext *exprCtxt, Plan *parent)
{
SubqueryScanState *subquerystate;
EState *estate;
subquerystate = (SubqueryScanState *) node->scan.scanstate;
estate = node->scan.plan.state;
/* If this is re-scanning of PlanQual ... */
if (estate->es_evTuple != NULL &&
estate->es_evTuple[node->scan.scanrelid - 1] != NULL)
{
estate->es_evTupleNull[node->scan.scanrelid - 1] = false;
return;
}
ExecReScan(node->subplan, NULL, NULL);
subquerystate->csstate.css_ScanTupleSlot = NULL;
}
......@@ -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.122 2000/09/20 15:28:01 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.123 2000/09/29 18:21:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -300,6 +300,31 @@ _copyTidScan(TidScan *from)
return newnode;
}
/* ----------------
* _copySubqueryScan
* ----------------
*/
static SubqueryScan *
_copySubqueryScan(SubqueryScan *from)
{
SubqueryScan *newnode = makeNode(SubqueryScan);
/* ----------------
* copy node superclass fields
* ----------------
*/
CopyPlanFields((Plan *) from, (Plan *) newnode);
CopyScanFields((Scan *) from, (Scan *) newnode);
/* ----------------
* copy remainder of node
* ----------------
*/
Node_Copy(from, newnode, subplan);
return newnode;
}
/* ----------------
* CopyJoinFields
......@@ -913,6 +938,17 @@ _copyRangeTblRef(RangeTblRef *from)
return newnode;
}
static FromExpr *
_copyFromExpr(FromExpr *from)
{
FromExpr *newnode = makeNode(FromExpr);
Node_Copy(from, newnode, fromlist);
Node_Copy(from, newnode, quals);
return newnode;
}
static JoinExpr *
_copyJoinExpr(JoinExpr *from)
{
......@@ -1025,9 +1061,11 @@ _copyRelOptInfo(RelOptInfo *from)
Node_Copy(from, newnode, cheapest_total_path);
newnode->pruneable = from->pruneable;
newnode->issubquery = from->issubquery;
newnode->indexed = from->indexed;
newnode->pages = from->pages;
newnode->tuples = from->tuples;
Node_Copy(from, newnode, subplan);
Node_Copy(from, newnode, baserestrictinfo);
newnode->baserestrictcost = from->baserestrictcost;
......@@ -1306,7 +1344,7 @@ _copyRestrictInfo(RestrictInfo *from)
* ----------------
*/
Node_Copy(from, newnode, clause);
newnode->isjoinqual = from->isjoinqual;
newnode->ispusheddown = from->ispusheddown;
Node_Copy(from, newnode, subclauseindices);
newnode->mergejoinoperator = from->mergejoinoperator;
newnode->left_sortop = from->left_sortop;
......@@ -1392,22 +1430,14 @@ _copyRangeTblEntry(RangeTblEntry *from)
if (from->relname)
newnode->relname = pstrdup(from->relname);
newnode->relid = from->relid;
Node_Copy(from, newnode, subquery);
Node_Copy(from, newnode, alias);
Node_Copy(from, newnode, eref);
newnode->inh = from->inh;
newnode->inFromCl = from->inFromCl;
newnode->skipAcl = from->skipAcl;
return newnode;
}
static RowMark *
_copyRowMark(RowMark *from)
{
RowMark *newnode = makeNode(RowMark);
newnode->rti = from->rti;
newnode->info = from->info;
newnode->checkForRead = from->checkForRead;
newnode->checkForWrite = from->checkForWrite;
newnode->checkAsUser = from->checkAsUser;
return newnode;
}
......@@ -1674,8 +1704,8 @@ _copyQuery(Query *from)
Node_Copy(from, newnode, jointree);
Node_Copy(from, newnode, targetList);
Node_Copy(from, newnode, qual);
Node_Copy(from, newnode, rowMark);
newnode->rowMarks = listCopy(from->rowMarks);
Node_Copy(from, newnode, distinctClause);
Node_Copy(from, newnode, sortClause);
......@@ -2493,6 +2523,9 @@ copyObject(void *from)
case T_TidScan:
retval = _copyTidScan(from);
break;
case T_SubqueryScan:
retval = _copySubqueryScan(from);
break;
case T_Join:
retval = _copyJoin(from);
break;
......@@ -2575,6 +2608,9 @@ copyObject(void *from)
case T_RangeTblRef:
retval = _copyRangeTblRef(from);
break;
case T_FromExpr:
retval = _copyFromExpr(from);
break;
case T_JoinExpr:
retval = _copyJoinExpr(from);
break;
......@@ -2881,9 +2917,6 @@ copyObject(void *from)
case T_CaseWhen:
retval = _copyCaseWhen(from);
break;
case T_RowMark:
retval = _copyRowMark(from);
break;
case T_FkConstraint:
retval = _copyFkConstraint(from);
break;
......
......@@ -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.73 2000/09/12 21:06:49 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.74 2000/09/29 18:21:29 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -311,6 +311,17 @@ _equalRangeTblRef(RangeTblRef *a, RangeTblRef *b)
return true;
}
static bool
_equalFromExpr(FromExpr *a, FromExpr *b)
{
if (!equal(a->fromlist, b->fromlist))
return false;
if (!equal(a->quals, b->quals))
return false;
return true;
}
static bool
_equalJoinExpr(JoinExpr *a, JoinExpr *b)
{
......@@ -346,7 +357,7 @@ _equalRelOptInfo(RelOptInfo *a, RelOptInfo *b)
/*
* We treat RelOptInfos as equal if they refer to the same base rels
* joined in the same order. Is this sufficient?
* joined in the same order. Is this appropriate/sufficient?
*/
return equali(a->relids, b->relids);
}
......@@ -495,7 +506,7 @@ _equalRestrictInfo(RestrictInfo *a, RestrictInfo *b)
{
if (!equal(a->clause, b->clause))
return false;
if (a->isjoinqual != b->isjoinqual)
if (a->ispusheddown != b->ispusheddown)
return false;
if (!equal(a->subclauseindices, b->subclauseindices))
return false;
......@@ -601,9 +612,7 @@ _equalQuery(Query *a, Query *b)
return false;
if (!equal(a->targetList, b->targetList))
return false;
if (!equal(a->qual, b->qual))
return false;
if (!equal(a->rowMark, b->rowMark))
if (!equali(a->rowMarks, b->rowMarks))
return false;
if (!equal(a->distinctClause, b->distinctClause))
return false;
......@@ -1651,6 +1660,8 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
return false;
if (a->relid != b->relid)
return false;
if (!equal(a->subquery, b->subquery))
return false;
if (!equal(a->alias, b->alias))
return false;
if (!equal(a->eref, b->eref))
......@@ -1659,7 +1670,11 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
return false;
if (a->inFromCl != b->inFromCl)
return false;
if (a->skipAcl != b->skipAcl)
if (a->checkForRead != b->checkForRead)
return false;
if (a->checkForWrite != b->checkForWrite)
return false;
if (a->checkAsUser != b->checkAsUser)
return false;
return true;
......@@ -1676,17 +1691,6 @@ _equalSortClause(SortClause *a, SortClause *b)
return true;
}
static bool
_equalRowMark(RowMark *a, RowMark *b)
{
if (a->rti != b->rti)
return false;
if (a->info != b->info)
return false;
return true;
}
static bool
_equalFkConstraint(FkConstraint *a, FkConstraint *b)
{
......@@ -1835,6 +1839,9 @@ equal(void *a, void *b)
case T_RangeTblRef:
retval = _equalRangeTblRef(a, b);
break;
case T_FromExpr:
retval = _equalFromExpr(a, b);
break;
case T_JoinExpr:
retval = _equalJoinExpr(a, b);
break;
......@@ -2140,9 +2147,6 @@ equal(void *a, void *b)
case T_CaseWhen:
retval = _equalCaseWhen(a, b);
break;
case T_RowMark:
retval = _equalRowMark(a, b);
break;
case T_FkConstraint:
retval = _equalFkConstraint(a, b);
break;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.33 2000/09/12 21:06:49 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/list.c,v 1.34 2000/09/29 18:21:29 tgl Exp $
*
* NOTES
* XXX a few of the following functions are duplicated to handle
......@@ -23,40 +23,9 @@
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "nodes/parsenodes.h"
/*
* makeList
*
* Take varargs, terminated by -1, and make a List
*/
List *
makeList(void *elem,...)
{
va_list args;
List *retval = NIL;
List *temp = NIL;
List *tempcons = NIL;
va_start(args, elem);
temp = elem;
while (temp != (void *) -1)
{
temp = lcons(temp, NIL);
if (tempcons == NIL)
retval = temp;
else
lnext(tempcons) = temp;
tempcons = temp;
temp = va_arg(args, void *);
}
va_end(args);
#include "nodes/parsenodes.h"
return retval;
}
/*
* makeInteger
......@@ -307,7 +276,7 @@ sameseti(List *list1, List *list2)
* as were in the inputs.
*/
List *
LispUnion(List *l1, List *l2)
set_union(List *l1, List *l2)
{
List *retval = listCopy(l1);
List *i;
......@@ -321,7 +290,7 @@ LispUnion(List *l1, List *l2)
}
List *
LispUnioni(List *l1, List *l2)
set_unioni(List *l1, List *l2)
{
List *retval = listCopy(l1);
List *i;
......@@ -385,7 +354,8 @@ intMember(int l1, List *l2)
/*
* lremove
* Removes 'elem' from the the linked list.
* Removes 'elem' from the linked list (destructively changing the list!).
*
* This version matches 'elem' using simple pointer comparison.
* See also LispRemove.
*/
......@@ -414,7 +384,8 @@ lremove(void *elem, List *list)
/*
* LispRemove
* Removes 'elem' from the the linked list.
* Removes 'elem' from the linked list (destructively changing the list!).
*
* This version matches 'elem' using equal().
* (If there is more than one equal list member, the first is removed.)
* See also lremove.
......@@ -442,10 +413,12 @@ LispRemove(void *elem, List *list)
return result;
}
#ifdef NOT_USED
/*
* lremovei
* lremove() for integer lists.
*/
List *
intLispRemove(int elem, List *list)
lremovei(int elem, List *list)
{
List *l;
List *prev = NIL;
......@@ -467,8 +440,6 @@ intLispRemove(int elem, List *list)
return result;
}
#endif
/*
* ltruncate
* Truncate a list to n elements.
......
......@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.126 2000/09/12 21:06:49 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.127 2000/09/29 18:21:29 tgl Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
......@@ -220,6 +220,9 @@ _outQuery(StringInfo str, Query *node)
if (node->utilityStmt)
{
/*
* Hack to make up for lack of outfuncs for utility-stmt nodes
*/
switch (nodeTag(node->utilityStmt))
{
case T_CreateStmt:
......@@ -239,7 +242,7 @@ _outQuery(StringInfo str, Query *node)
break;
case T_NotifyStmt:
appendStringInfo(str, " :utility ");
appendStringInfo(str, " :notify ");
_outToken(str, ((NotifyStmt *) (node->utilityStmt))->relname);
break;
......@@ -250,32 +253,34 @@ _outQuery(StringInfo str, Query *node)
else
appendStringInfo(str, " :utility <>");
appendStringInfo(str, " :resultRelation %u :into ",
appendStringInfo(str, " :resultRelation %d :into ",
node->resultRelation);
_outToken(str, node->into);
appendStringInfo(str,
" :isPortal %s :isBinary %s :isTemp %s :unionall %s :distinctClause ",
appendStringInfo(str, " :isPortal %s :isBinary %s :isTemp %s"
" :unionall %s :hasAggs %s :hasSubLinks %s :rtable ",
node->isPortal ? "true" : "false",
node->isBinary ? "true" : "false",
node->isTemp ? "true" : "false",
node->unionall ? "true" : "false");
_outNode(str, node->distinctClause);
appendStringInfo(str, " :sortClause ");
_outNode(str, node->sortClause);
appendStringInfo(str, " :rtable ");
node->unionall ? "true" : "false",
node->hasAggs ? "true" : "false",
node->hasSubLinks ? "true" : "false");
_outNode(str, node->rtable);
appendStringInfo(str, " :jointree ");
_outNode(str, node->jointree);
appendStringInfo(str, " :targetlist ");
appendStringInfo(str, " :targetList ");
_outNode(str, node->targetList);
appendStringInfo(str, " :qual ");
_outNode(str, node->qual);
appendStringInfo(str, " :rowMarks ");
_outIntList(str, node->rowMarks);
appendStringInfo(str, " :distinctClause ");
_outNode(str, node->distinctClause);
appendStringInfo(str, " :sortClause ");
_outNode(str, node->sortClause);
appendStringInfo(str, " :groupClause ");
_outNode(str, node->groupClause);
......@@ -283,23 +288,17 @@ _outQuery(StringInfo str, Query *node)
appendStringInfo(str, " :havingQual ");
_outNode(str, node->havingQual);
appendStringInfo(str, " :hasAggs %s :hasSubLinks %s :unionClause ",
node->hasAggs ? "true" : "false",
node->hasSubLinks ? "true" : "false");
_outNode(str, node->unionClause);
appendStringInfo(str, " :intersectClause ");
_outNode(str, node->intersectClause);
appendStringInfo(str, " :unionClause ");
_outNode(str, node->unionClause);
appendStringInfo(str, " :limitOffset ");
_outNode(str, node->limitOffset);
appendStringInfo(str, " :limitCount ");
_outNode(str, node->limitCount);
appendStringInfo(str, " :rowMark ");
_outNode(str, node->rowMark);
}
static void
......@@ -535,6 +534,19 @@ _outTidScan(StringInfo str, TidScan *node)
}
/*
* SubqueryScan is a subclass of Scan
*/
static void
_outSubqueryScan(StringInfo str, SubqueryScan *node)
{
appendStringInfo(str, " SUBQUERYSCAN ");
_outPlanInfo(str, (Plan *) node);
appendStringInfo(str, " :scanrelid %u :subplan ", node->scan.scanrelid);
_outNode(str, node->subplan);
}
/*
* Material is a subclass of Plan
*/
......@@ -863,6 +875,18 @@ _outRangeTblRef(StringInfo str, RangeTblRef *node)
node->rtindex);
}
/*
* FromExpr
*/
static void
_outFromExpr(StringInfo str, FromExpr *node)
{
appendStringInfo(str, " FROMEXPR :fromlist ");
_outNode(str, node->fromlist);
appendStringInfo(str, " :quals ");
_outNode(str, node->quals);
}
/*
* JoinExpr
*/
......@@ -916,36 +940,33 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node)
appendStringInfo(str, " RELOPTINFO :relids ");
_outIntList(str, node->relids);
appendStringInfo(str,
" :rows %.0f :width %d :indexed %s :pages %ld :tuples %.0f :targetlist ",
appendStringInfo(str, " :rows %.0f :width %d :targetlist ",
node->rows,
node->width,
node->indexed ? "true" : "false",
node->pages,
node->tuples);
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 :baserestrictinfo ",
node->pruneable ? "true" : "false");
_outNode(str, node->baserestrictinfo);
appendStringInfo(str, " :pruneable %s :issubquery %s :indexed %s :pages %ld :tuples %.0f :subplan ",
node->pruneable ? "true" : "false",
node->issubquery ? "true" : "false",
node->indexed ? "true" : "false",
node->pages,
node->tuples);
_outNode(str, node->subplan);
appendStringInfo(str,
" :baserestrictcost %.2f :outerjoinset ",
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);
}
......@@ -977,21 +998,21 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
{
appendStringInfo(str, " RTE :relname ");
_outToken(str, node->relname);
appendStringInfo(str, " :relid %u :alias ",
appendStringInfo(str, " :relid %u ",
node->relid);
appendStringInfo(str, " :subquery ");
_outNode(str, node->subquery);
appendStringInfo(str, " :alias ");
_outNode(str, node->alias);
appendStringInfo(str, " :eref ");
_outNode(str, node->eref);
appendStringInfo(str, " :inh %s :inFromCl %s :skipAcl %s",
appendStringInfo(str, " :inh %s :inFromCl %s :checkForRead %s"
" :checkForWrite %s :checkAsUser %u",
node->inh ? "true" : "false",
node->inFromCl ? "true" : "false",
node->skipAcl ? "true" : "false");
}
static void
_outRowMark(StringInfo str, RowMark *node)
{
appendStringInfo(str, " ROWMARK :rti %u :info %u", node->rti, node->info);
node->checkForRead ? "true" : "false",
node->checkForWrite ? "true" : "false",
node->checkAsUser);
}
/*
......@@ -1151,8 +1172,8 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
appendStringInfo(str, " RESTRICTINFO :clause ");
_outNode(str, node->clause);
appendStringInfo(str, " :isjoinqual %s :subclauseindices ",
node->isjoinqual ? "true" : "false");
appendStringInfo(str, " :ispusheddown %s :subclauseindices ",
node->ispusheddown ? "true" : "false");
_outNode(str, node->subclauseindices);
appendStringInfo(str, " :mergejoinoperator %u ", node->mergejoinoperator);
......@@ -1492,6 +1513,9 @@ _outNode(StringInfo str, void *obj)
case T_TidScan:
_outTidScan(str, obj);
break;
case T_SubqueryScan:
_outSubqueryScan(str, obj);
break;
case T_Material:
_outMaterial(str, obj);
break;
......@@ -1555,6 +1579,9 @@ _outNode(StringInfo str, void *obj)
case T_RangeTblRef:
_outRangeTblRef(str, obj);
break;
case T_FromExpr:
_outFromExpr(str, obj);
break;
case T_JoinExpr:
_outJoinExpr(str, obj);
break;
......@@ -1573,9 +1600,6 @@ _outNode(StringInfo str, void *obj)
case T_RangeTblEntry:
_outRangeTblEntry(str, obj);
break;
case T_RowMark:
_outRowMark(str, obj);
break;
case T_Path:
_outPath(str, obj);
break;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.41 2000/09/25 18:14:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.42 2000/09/29 18:21:29 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -39,7 +39,6 @@ print(void *obj)
s = nodeToString(obj);
printf("%s\n", s);
fflush(stdout);
return;
}
/*
......@@ -132,10 +131,15 @@ print_rt(List *rtable)
{
RangeTblEntry *rte = lfirst(l);
printf("%d\t%s(%s)\t%u\t%d\t%s\n",
i, rte->relname, rte->eref->relname, rte->relid,
rte->inFromCl,
(rte->inh ? "inh" : ""));
if (rte->relname)
printf("%d\t%s (%s)\t%u",
i, rte->relname, rte->eref->relname, rte->relid);
else
printf("%d\t[subquery] (%s)\t",
i, rte->eref->relname);
printf("\t%s\t%s\n",
(rte->inh ? "inh" : ""),
(rte->inFromCl ? "inFromCl" : ""));
i++;
}
}
......@@ -286,7 +290,7 @@ plannode_type(Plan *p)
{
switch (nodeTag(p))
{
case T_Plan:
case T_Plan:
return "PLAN";
break;
case T_Result:
......@@ -304,6 +308,12 @@ plannode_type(Plan *p)
case T_IndexScan:
return "INDEXSCAN";
break;
case T_TidScan:
return "TIDSCAN";
break;
case T_SubqueryScan:
return "SUBQUERYSCAN";
break;
case T_Join:
return "JOIN";
break;
......@@ -334,9 +344,6 @@ plannode_type(Plan *p)
case T_Group:
return "GROUP";
break;
case T_TidScan:
return "TIDSCAN";
break;
default:
return "UNKNOWN";
break;
......@@ -372,10 +379,10 @@ print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
}
else if (IsA(p, IndexScan))
{
StrNCpy(extraInfo,
((RangeTblEntry *) (nth(((IndexScan *) p)->scan.scanrelid - 1,
parsetree->rtable)))->relname,
NAMEDATALEN);
RangeTblEntry *rte;
rte = rt_fetch(((IndexScan *) p)->scan.scanrelid, parsetree->rtable);
StrNCpy(extraInfo, rte->relname, NAMEDATALEN);
}
else
extraInfo[0] = '\0';
......@@ -386,7 +393,7 @@ print_plan_recursive(Plan *p, Query *parsetree, int indentLevel, char *label)
print_plan_recursive(p->lefttree, parsetree, indentLevel + 3, "l: ");
print_plan_recursive(p->righttree, parsetree, indentLevel + 3, "r: ");
if (nodeTag(p) == T_Append)
if (IsA(p, Append))
{
List *lst;
int whichplan = 0;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.96 2000/09/12 21:06:49 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.97 2000/09/29 18:21:29 tgl Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
......@@ -70,13 +70,16 @@ _readQuery()
local_node->commandType = atoi(token);
token = lsptok(NULL, &length); /* skip :utility */
/* we can't get create or index here, can we? */
token = lsptok(NULL, &length); /* get the notify name if any */
token = lsptok(NULL, &length);
if (length == 0)
local_node->utilityStmt = NULL;
else
{
/*
* Hack to make up for lack of readfuncs for utility-stmt nodes
*
* we can't get create or index here, can we?
*/
NotifyStmt *n = makeNode(NotifyStmt);
n->relname = debackslash(token, length);
......@@ -110,11 +113,13 @@ _readQuery()
token = lsptok(NULL, &length); /* get unionall */
local_node->unionall = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* skip :distinctClause */
local_node->distinctClause = nodeRead(true);
token = lsptok(NULL, &length); /* skip the :hasAggs */
token = lsptok(NULL, &length); /* get hasAggs */
local_node->hasAggs = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* skip :sortClause */
local_node->sortClause = nodeRead(true);
token = lsptok(NULL, &length); /* skip the :hasSubLinks */
token = lsptok(NULL, &length); /* get hasSubLinks */
local_node->hasSubLinks = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* skip :rtable */
local_node->rtable = nodeRead(true);
......@@ -125,8 +130,14 @@ _readQuery()
token = lsptok(NULL, &length); /* skip :targetlist */
local_node->targetList = nodeRead(true);
token = lsptok(NULL, &length); /* skip :qual */
local_node->qual = nodeRead(true);
token = lsptok(NULL, &length); /* skip :rowMarks */
local_node->rowMarks = toIntList(nodeRead(true));
token = lsptok(NULL, &length); /* skip :distinctClause */
local_node->distinctClause = nodeRead(true);
token = lsptok(NULL, &length); /* skip :sortClause */
local_node->sortClause = nodeRead(true);
token = lsptok(NULL, &length); /* skip :groupClause */
local_node->groupClause = nodeRead(true);
......@@ -134,20 +145,11 @@ _readQuery()
token = lsptok(NULL, &length); /* skip :havingQual */
local_node->havingQual = nodeRead(true);
token = lsptok(NULL, &length); /* skip the :hasAggs */
token = lsptok(NULL, &length); /* get hasAggs */
local_node->hasAggs = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* skip the :hasSubLinks */
token = lsptok(NULL, &length); /* get hasSubLinks */
local_node->hasSubLinks = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* skip :unionClause */
local_node->unionClause = nodeRead(true);
token = lsptok(NULL, &length); /* skip :intersectClause */
local_node->intersectClause = nodeRead(true);
token = lsptok(NULL, &length); /* skip :unionClause */
local_node->unionClause = nodeRead(true);
token = lsptok(NULL, &length); /* skip :limitOffset */
local_node->limitOffset = nodeRead(true);
......@@ -155,9 +157,6 @@ _readQuery()
token = lsptok(NULL, &length); /* skip :limitCount */
local_node->limitCount = nodeRead(true);
token = lsptok(NULL, &length); /* skip :rowMark */
local_node->rowMark = nodeRead(true);
return local_node;
}
......@@ -561,6 +560,29 @@ _readTidScan()
return local_node;
}
/* ----------------
* _readSubqueryScan
*
* SubqueryScan is a subclass of Scan
* ----------------
*/
static SubqueryScan *
_readSubqueryScan()
{
SubqueryScan *local_node;
char *token;
int length;
local_node = makeNode(SubqueryScan);
_getScan((Scan *) local_node);
token = lsptok(NULL, &length); /* eat :subplan */
local_node->subplan = nodeRead(true); /* now read it */
return local_node;
}
/* ----------------
* _readSort
*
......@@ -1181,6 +1203,30 @@ _readRangeTblRef()
return local_node;
}
/* ----------------
* _readFromExpr
*
* FromExpr is a subclass of Node
* ----------------
*/
static FromExpr *
_readFromExpr()
{
FromExpr *local_node;
char *token;
int length;
local_node = makeNode(FromExpr);
token = lsptok(NULL, &length); /* eat :fromlist */
local_node->fromlist = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* eat :quals */
local_node->quals = nodeRead(true); /* now read it */
return local_node;
}
/* ----------------
* _readJoinExpr
*
......@@ -1293,22 +1339,6 @@ _readRelOptInfo()
token = lsptok(NULL, &length); /* now read it */
local_node->width = atoi(token);
token = lsptok(NULL, &length); /* get :indexed */
token = lsptok(NULL, &length); /* now read it */
if (!strncmp(token, "true", 4))
local_node->indexed = true;
else
local_node->indexed = false;
token = lsptok(NULL, &length); /* get :pages */
token = lsptok(NULL, &length); /* now read it */
local_node->pages = atol(token);
token = lsptok(NULL, &length); /* get :tuples */
token = lsptok(NULL, &length); /* now read it */
local_node->tuples = atof(token);
token = lsptok(NULL, &length); /* get :targetlist */
local_node->targetlist = nodeRead(true); /* now read it */
......@@ -1325,6 +1355,25 @@ _readRelOptInfo()
token = lsptok(NULL, &length); /* get :pruneable */
local_node->pruneable = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* get :issubquery */
token = lsptok(NULL, &length); /* now read it */
local_node->issubquery = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* get :indexed */
token = lsptok(NULL, &length); /* now read it */
local_node->indexed = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* get :pages */
token = lsptok(NULL, &length); /* now read it */
local_node->pages = atol(token);
token = lsptok(NULL, &length); /* get :tuples */
token = lsptok(NULL, &length); /* now read it */
local_node->tuples = atof(token);
token = lsptok(NULL, &length); /* get :subplan */
local_node->subplan = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* get :baserestrictinfo */
local_node->baserestrictinfo = nodeRead(true); /* now read it */
......@@ -1409,6 +1458,9 @@ _readRangeTblEntry()
token = lsptok(NULL, &length); /* get :relid */
local_node->relid = strtoul(token, NULL, 10);
token = lsptok(NULL, &length); /* eat :subquery */
local_node->subquery = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* eat :alias */
local_node->alias = nodeRead(true); /* now read it */
......@@ -1423,27 +1475,17 @@ _readRangeTblEntry()
token = lsptok(NULL, &length); /* get :inFromCl */
local_node->inFromCl = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* eat :skipAcl */
token = lsptok(NULL, &length); /* get :skipAcl */
local_node->skipAcl = (token[0] == 't') ? true : false;
return local_node;
}
static RowMark *
_readRowMark()
{
RowMark *local_node = makeNode(RowMark);
char *token;
int length;
token = lsptok(NULL, &length); /* eat :checkForRead */
token = lsptok(NULL, &length); /* get :checkForRead */
local_node->checkForRead = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* eat :rti */
token = lsptok(NULL, &length); /* get :rti */
local_node->rti = strtoul(token, NULL, 10);
token = lsptok(NULL, &length); /* eat :checkForWrite */
token = lsptok(NULL, &length); /* get :checkForWrite */
local_node->checkForWrite = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* eat :info */
token = lsptok(NULL, &length); /* get :info */
local_node->info = strtoul(token, NULL, 10);
token = lsptok(NULL, &length); /* eat :checkAsUser */
token = lsptok(NULL, &length); /* get :checkAsUser */
local_node->checkAsUser = strtoul(token, NULL, 10);
return local_node;
}
......@@ -1768,9 +1810,9 @@ _readRestrictInfo()
token = lsptok(NULL, &length); /* get :clause */
local_node->clause = nodeRead(true); /* now read it */
token = lsptok(NULL, &length); /* get :isjoinqual */
token = lsptok(NULL, &length); /* get :ispusheddown */
token = lsptok(NULL, &length); /* now read it */
local_node->isjoinqual = (token[0] == 't') ? true : false;
local_node->ispusheddown = (token[0] == 't') ? true : false;
token = lsptok(NULL, &length); /* get :subclauseindices */
local_node->subclauseindices = nodeRead(true); /* now read it */
......@@ -1879,6 +1921,8 @@ parsePlanString(void)
return_value = _readIndexScan();
else if (length == 7 && strncmp(token, "TIDSCAN", length) == 0)
return_value = _readTidScan();
else if (length == 12 && strncmp(token, "SUBQUERYSCAN", length) == 0)
return_value = _readSubqueryScan();
else if (length == 4 && strncmp(token, "SORT", length) == 0)
return_value = _readSort();
else if (length == 6 && strncmp(token, "AGGREG", length) == 0)
......@@ -1891,6 +1935,8 @@ parsePlanString(void)
return_value = _readRelabelType();
else if (length == 11 && strncmp(token, "RANGETBLREF", length) == 0)
return_value = _readRangeTblRef();
else if (length == 8 && strncmp(token, "FROMEXPR", length) == 0)
return_value = _readFromExpr();
else if (length == 8 && strncmp(token, "JOINEXPR", length) == 0)
return_value = _readJoinExpr();
else if (length == 3 && strncmp(token, "AGG", length) == 0)
......@@ -1953,10 +1999,8 @@ parsePlanString(void)
return_value = _readCaseExpr();
else if (length == 4 && strncmp(token, "WHEN", length) == 0)
return_value = _readCaseWhen();
else if (length == 7 && strncmp(token, "ROWMARK", length) == 0)
return_value = _readRowMark();
else
elog(ERROR, "badly formatted planstring \"%.10s\"...\n", token);
elog(ERROR, "badly formatted planstring \"%.10s\"...", token);
return (Node *) return_value;
}
......
This diff is collapsed.
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Id: geqo_main.c,v 1.24 2000/09/19 18:42:33 tgl Exp $
* $Id: geqo_main.c,v 1.25 2000/09/29 18:21:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -245,9 +245,9 @@ geqo(Query *root, int number_of_rels, List *initial_rels)
best_tour = (Gene *) pool->data[0].string;
/* root->join_rel_list will be modified during this ! */
best_rel = (RelOptInfo *) gimme_tree(root, initial_rels,
best_tour, pool->string_length,
0, NULL);
best_rel = gimme_tree(root, initial_rels,
best_tour, pool->string_length,
0, NULL);
/* DBG: show the query plan
print_plan(best_plan, root);
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.64 2000/09/19 18:42:34 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/allpaths.c,v 1.65 2000/09/29 18:21:31 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -19,6 +19,9 @@
#include "optimizer/geqo.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
#include "optimizer/plancat.h"
#include "optimizer/planner.h"
#include "parser/parsetree.h"
bool enable_geqo = true;
......@@ -26,7 +29,6 @@ int geqo_rels = DEFAULT_GEQO_RELS;
static void set_base_rel_pathlist(Query *root);
static List *build_jointree_rels(Query *root);
static RelOptInfo *make_one_rel_by_joins(Query *root, int levels_needed,
List *initial_rels);
......@@ -44,20 +46,7 @@ static void debug_print_rel(Query *root, RelOptInfo *rel);
RelOptInfo *
make_one_rel(Query *root)
{
int levels_needed;
List *initial_rels;
/*
* Count the number of top-level jointree nodes. This is the depth
* of the dynamic-programming algorithm we must employ to consider
* all ways of joining the top-level nodes. Currently, we build
* JoinExpr joins in exactly the order implied by the join expression,
* so no dynamic-programming search is needed within a JoinExpr.
*/
levels_needed = length(root->jointree);
if (levels_needed <= 0)
return NULL; /* nothing to do? */
RelOptInfo *rel;
/*
* Generate access paths for the base rels.
......@@ -65,27 +54,18 @@ make_one_rel(Query *root)
set_base_rel_pathlist(root);
/*
* Construct a list of rels corresponding to the toplevel jointree nodes.
* This may contain both base rels and rels constructed according to
* explicit JOIN directives.
* Generate access paths for the entire join tree.
*/
initial_rels = build_jointree_rels(root);
Assert(root->jointree != NULL && IsA(root->jointree, FromExpr));
if (levels_needed == 1)
{
/*
* Single jointree node, so we're done.
*/
return (RelOptInfo *) lfirst(initial_rels);
}
else
{
rel = make_fromexpr_rel(root, root->jointree);
/*
* Generate join tree.
*/
return make_one_rel_by_joins(root, levels_needed, initial_rels);
}
/*
* The result should join all the query's rels.
*/
Assert(length(rel->relids) == length(root->base_rel_list));
return rel;
}
/*
......@@ -102,36 +82,67 @@ set_base_rel_pathlist(Query *root)
foreach(rellist, root->base_rel_list)
{
RelOptInfo *rel = (RelOptInfo *) lfirst(rellist);
List *indices = find_relation_indices(root, rel);
RangeTblEntry *rte;
/* Mark rel with estimated output rows, width, etc */
set_baserel_size_estimates(root, rel);
Assert(length(rel->relids) == 1); /* better be base rel */
rte = rt_fetch(lfirsti(rel->relids), root->rtable);
/*
* Generate paths and add them to the rel's pathlist.
*
* Note: add_path() will discard any paths that are dominated by
* another available path, keeping only those paths that are
* superior along at least one dimension of cost or sortedness.
*/
if (rel->issubquery)
{
/* Subquery --- generate a separate plan for it */
/* Consider sequential scan */
add_path(rel, create_seqscan_path(rel));
/*
* XXX for now, we just apply any restrict clauses that came
* from the outer query as qpquals of the SubqueryScan node.
* Later, think about pushing them down into the subquery itself.
*/
/* Consider TID scans */
create_tidscan_paths(root, rel);
/* Generate the plan for the subquery */
rel->subplan = planner(rte->subquery);
/* Consider index paths for both simple and OR index clauses */
create_index_paths(root, rel, indices,
rel->baserestrictinfo,
rel->joininfo);
/* Copy number of output rows from subplan */
rel->tuples = rel->subplan->plan_rows;
/*
* 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_or_index_paths(root, rel, rel->baserestrictinfo);
/* Mark rel with estimated output rows, width, etc */
set_baserel_size_estimates(root, rel);
/* Generate appropriate path */
add_path(rel, create_subqueryscan_path(rel));
}
else
{
/* Plain relation */
List *indices = find_secondary_indexes(rte->relid);
/* Mark rel with estimated output rows, width, etc */
set_baserel_size_estimates(root, rel);
/*
* Generate paths and add them to the rel's pathlist.
*
* Note: add_path() will discard any paths that are dominated by
* another available path, keeping only those paths that are
* superior along at least one dimension of cost or sortedness.
*/
/* Consider sequential scan */
add_path(rel, create_seqscan_path(rel));
/* Consider TID scans */
create_tidscan_paths(root, rel);
/* Consider index paths for both simple and OR index clauses */
create_index_paths(root, rel, indices,
rel->baserestrictinfo,
rel->joininfo);
/*
* 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_or_index_paths(root, rel, rel->baserestrictinfo);
}
/* Now find the cheapest of the paths for this rel */
set_cheapest(rel);
......@@ -139,26 +150,57 @@ set_base_rel_pathlist(Query *root)
}
/*
* build_jointree_rels
* Construct a RelOptInfo for each item in the query's jointree.
*
* At present, we handle explicit joins in the FROM clause exactly as
* specified, with no search for other join orders. Only the cross-product
* joins at the top level are involved in the dynamic-programming search.
* make_fromexpr_rel
* Build access paths for a FromExpr jointree node.
*/
static List *
build_jointree_rels(Query *root)
RelOptInfo *
make_fromexpr_rel(Query *root, FromExpr *from)
{
List *rels = NIL;
int levels_needed;
List *initial_rels = NIL;
List *jt;
foreach(jt, root->jointree)
/*
* Count the number of child jointree nodes. This is the depth
* of the dynamic-programming algorithm we must employ to consider
* all ways of joining the child nodes.
*/
levels_needed = length(from->fromlist);
if (levels_needed <= 0)
return NULL; /* nothing to do? */
/*
* Construct a list of rels corresponding to the child jointree nodes.
* This may contain both base rels and rels constructed according to
* explicit JOIN directives.
*/
foreach(jt, from->fromlist)
{
Node *jtnode = (Node *) lfirst(jt);
rels = lappend(rels, make_rel_from_jointree(root, jtnode));
initial_rels = lappend(initial_rels,
make_jointree_rel(root, jtnode));
}
if (levels_needed == 1)
{
/*
* Single jointree node, so we're done.
*/
return (RelOptInfo *) lfirst(initial_rels);
}
else
{
/*
* Consider the different orders in which we could join the rels,
* using either GEQO or regular optimizer.
*/
if (enable_geqo && levels_needed >= geqo_rels)
return geqo(root, levels_needed, initial_rels);
else
return make_one_rel_by_joins(root, levels_needed, initial_rels);
}
return rels;
}
/*
......@@ -182,14 +224,6 @@ make_one_rel_by_joins(Query *root, int levels_needed, List *initial_rels)
int lev;
RelOptInfo *rel;
/*******************************************
* genetic query optimizer entry point *
* <utesch@aut.tu-freiberg.de> *
* rest will be skipped in case of GEQO *
*******************************************/
if (enable_geqo && levels_needed >= geqo_rels)
return geqo(root, levels_needed, initial_rels);
/*
* We employ a simple "dynamic programming" algorithm: we first find
* all ways to build joins of two jointree items, then all ways to
......@@ -243,12 +277,11 @@ make_one_rel_by_joins(Query *root, int levels_needed, List *initial_rels)
}
/*
* We should have a single rel at the final level,
* representing the join of all the base rels.
* We should have a single rel at the final level.
*/
Assert(length(joinitems[levels_needed]) == 1);
rel = (RelOptInfo *) lfirst(joinitems[levels_needed]);
Assert(length(rel->relids) == length(root->base_rel_list));
return rel;
}
......
......@@ -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.62 2000/06/18 22:44:06 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/costsize.c,v 1.63 2000/09/29 18:21:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -115,6 +115,7 @@ cost_seqscan(Path *path, RelOptInfo *baserel)
/* Should only be applied to base relations */
Assert(length(baserel->relids) == 1);
Assert(!baserel->issubquery);
if (!enable_seqscan)
startup_cost += disable_cost;
......@@ -223,6 +224,7 @@ cost_index(Path *path, Query *root,
/* Should only be applied to base relations */
Assert(IsA(baserel, RelOptInfo) &&IsA(index, IndexOptInfo));
Assert(length(baserel->relids) == 1);
Assert(!baserel->issubquery);
if (!enable_indexscan && !is_injoin)
startup_cost += disable_cost;
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.96 2000/09/15 18:45:25 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/indxpath.c,v 1.97 2000/09/29 18:21:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -464,7 +464,7 @@ extract_or_indexqual_conditions(RelOptInfo *rel,
else
{
/* we assume the caller passed a valid indexable qual */
quals = lcons(orsubclause, NIL);
quals = makeList1(orsubclause);
}
return expand_indexqual_conditions(quals);
......@@ -1504,7 +1504,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
RestrictInfo *clause = (RestrictInfo *) lfirst(temp);
indexquals = lappend(indexquals, clause->clause);
if (! clause->isjoinqual)
if (clause->ispusheddown)
alljoinquals = false;
}
......@@ -1516,8 +1516,8 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
* therefore, both indexid and indexqual should be single-element
* lists.
*/
pathnode->indexid = lconsi(index->indexoid, NIL);
pathnode->indexqual = lcons(indexquals, NIL);
pathnode->indexid = makeListi1(index->indexoid);
pathnode->indexqual = makeList1(indexquals);
/* We don't actually care what order the index scans in ... */
pathnode->indexscandir = NoMovementScanDirection;
......@@ -1541,7 +1541,7 @@ index_innerjoin(Query *root, RelOptInfo *rel, IndexOptInfo *index,
*/
pathnode->rows = rel->tuples *
restrictlist_selectivity(root,
LispUnion(rel->baserestrictinfo,
set_union(rel->baserestrictinfo,
clausegroup),
lfirsti(rel->relids));
/* Like costsize.c, force estimate to be at least one row */
......@@ -2034,7 +2034,7 @@ prefix_quals(Var *leftop, Oid expr_op,
con = string_to_const(prefix, datatype);
op = makeOper(oproid, InvalidOid, BOOLOID);
expr = make_opclause(op, leftop, (Var *) con);
result = lcons(expr, NIL);
result = makeList1(expr);
return result;
}
......@@ -2049,7 +2049,7 @@ prefix_quals(Var *leftop, Oid expr_op,
con = string_to_const(prefix, datatype);
op = makeOper(oproid, InvalidOid, BOOLOID);
expr = make_opclause(op, leftop, (Var *) con);
result = lcons(expr, NIL);
result = makeList1(expr);
/*
* If we can create a string larger than the prefix, say "x <
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.56 2000/09/12 21:06:53 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinpath.c,v 1.57 2000/09/29 18:21:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -643,10 +643,10 @@ hash_inner_and_outer(Query *root,
continue; /* not hashjoinable */
/*
* If processing an outer join, only use explicit join clauses for
* If processing an outer join, only use its own join clauses for
* hashing. For inner joins we need not be so picky.
*/
if (isouterjoin && !restrictinfo->isjoinqual)
if (isouterjoin && restrictinfo->ispusheddown)
continue;
clause = restrictinfo->clause;
......@@ -665,7 +665,7 @@ hash_inner_and_outer(Query *root,
continue; /* no good for these input relations */
/* always a one-element list of hash clauses */
hashclauses = lcons(restrictinfo, NIL);
hashclauses = makeList1(restrictinfo);
/* estimate disbursion of inner var for costing purposes */
innerdisbursion = estimate_disbursion(root, inner);
......@@ -820,7 +820,7 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
*right;
/*
* If processing an outer join, only use explicit join clauses in the
* If processing an outer join, only use its own join clauses in the
* merge. For inner joins we need not be so picky.
*
* Furthermore, if it is a right/full join then *all* the explicit
......@@ -832,7 +832,7 @@ select_mergejoin_clauses(RelOptInfo *joinrel,
*/
if (isouterjoin)
{
if (!restrictinfo->isjoinqual)
if (restrictinfo->ispusheddown)
continue;
switch (jointype)
{
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.47 2000/09/12 21:06:53 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/joinrels.c,v 1.48 2000/09/29 18:21:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -307,13 +307,13 @@ make_rels_by_clauseless_joins(Query *root,
/*
* make_rel_from_jointree
* make_jointree_rel
* Find or build a RelOptInfojoin rel representing a specific
* jointree item. For JoinExprs, we only consider the construction
* path that corresponds exactly to what the user wrote.
*/
RelOptInfo *
make_rel_from_jointree(Query *root, Node *jtnode)
make_jointree_rel(Query *root, Node *jtnode)
{
if (IsA(jtnode, RangeTblRef))
{
......@@ -321,6 +321,13 @@ make_rel_from_jointree(Query *root, Node *jtnode)
return get_base_rel(root, varno);
}
else if (IsA(jtnode, FromExpr))
{
FromExpr *f = (FromExpr *) jtnode;
/* Recurse back to multi-way-join planner */
return make_fromexpr_rel(root, f);
}
else if (IsA(jtnode, JoinExpr))
{
JoinExpr *j = (JoinExpr *) jtnode;
......@@ -329,8 +336,8 @@ make_rel_from_jointree(Query *root, Node *jtnode)
*rrel;
/* Recurse */
lrel = make_rel_from_jointree(root, j->larg);
rrel = make_rel_from_jointree(root, j->rarg);
lrel = make_jointree_rel(root, j->larg);
rrel = make_jointree_rel(root, j->rarg);
/* Make this join rel */
rel = make_join_rel(root, lrel, rrel, j->jointype);
......@@ -346,7 +353,7 @@ make_rel_from_jointree(Query *root, Node *jtnode)
return rel;
}
else
elog(ERROR, "make_rel_from_jointree: unexpected node type %d",
elog(ERROR, "make_jointree_rel: unexpected node type %d",
nodeTag(jtnode));
return NULL; /* keep compiler quiet */
}
......
......@@ -11,7 +11,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.25 2000/09/12 21:06:53 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/path/pathkeys.c,v 1.26 2000/09/29 18:21:32 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -122,7 +122,7 @@ add_equijoined_keys(Query *root, RestrictInfo *restrictinfo)
newset = lcons(item1, lcons(item2, NIL));
/* Found a set to merge into our new set */
newset = LispUnion(newset, curset);
newset = set_union(newset, curset);
/*
* Remove old set from equi_key_list. NOTE this does not
......
......@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.96 2000/09/12 21:06:53 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.97 2000/09/29 18:21:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -41,6 +41,8 @@ static IndexScan *create_indexscan_node(Query *root, IndexPath *best_path,
List *tlist, List *scan_clauses);
static TidScan *create_tidscan_node(TidPath *best_path, List *tlist,
List *scan_clauses);
static SubqueryScan *create_subqueryscan_node(Path *best_path,
List *tlist, List *scan_clauses);
static NestLoop *create_nestloop_node(NestPath *best_path, List *tlist,
List *joinclauses, List *otherclauses,
Plan *outer_node, List *outer_tlist,
......@@ -66,6 +68,8 @@ static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid,
ScanDirection indexscandir);
static TidScan *make_tidscan(List *qptlist, List *qpqual, Index scanrelid,
List *tideval);
static SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual,
Index scanrelid, Plan *subplan);
static NestLoop *make_nestloop(List *tlist,
List *joinclauses, List *otherclauses,
Plan *lefttree, Plan *righttree,
......@@ -110,6 +114,7 @@ create_plan(Query *root, Path *best_path)
case T_IndexScan:
case T_SeqScan:
case T_TidScan:
case T_SubqueryScan:
plan_node = (Plan *) create_scan_node(root, best_path, tlist);
break;
case T_HashJoin:
......@@ -164,7 +169,9 @@ create_scan_node(Query *root, Path *best_path, List *tlist)
switch (best_path->pathtype)
{
case T_SeqScan:
node = (Scan *) create_seqscan_node(best_path, tlist, scan_clauses);
node = (Scan *) create_seqscan_node(best_path,
tlist,
scan_clauses);
break;
case T_IndexScan:
......@@ -180,6 +187,12 @@ create_scan_node(Query *root, Path *best_path, List *tlist)
scan_clauses);
break;
case T_SubqueryScan:
node = (Scan *) create_subqueryscan_node(best_path,
tlist,
scan_clauses);
break;
default:
elog(ERROR, "create_scan_node: unknown node type: %d",
best_path->pathtype);
......@@ -301,6 +314,7 @@ create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses)
/* there should be exactly one base rel involved... */
Assert(length(best_path->parent->relids) == 1);
Assert(! best_path->parent->issubquery);
scan_relid = (Index) lfirsti(best_path->parent->relids);
......@@ -342,6 +356,8 @@ create_indexscan_node(Query *root,
/* there should be exactly one base rel involved... */
Assert(length(best_path->path.parent->relids) == 1);
Assert(! best_path->path.parent->issubquery);
baserelid = lfirsti(best_path->path.parent->relids);
/* check to see if any of the indices are lossy */
......@@ -391,8 +407,7 @@ create_indexscan_node(Query *root,
make_ands_explicit(lfirst(orclause)));
indxqual_expr = make_orclause(orclauses);
qpqual = set_difference(scan_clauses,
lcons(indxqual_expr, NIL));
qpqual = set_difference(scan_clauses, makeList1(indxqual_expr));
if (lossy)
qpqual = lappend(qpqual, copyObject(indxqual_expr));
......@@ -449,6 +464,7 @@ create_tidscan_node(TidPath *best_path, List *tlist, List *scan_clauses)
/* there should be exactly one base rel involved... */
Assert(length(best_path->path.parent->relids) == 1);
Assert(! best_path->path.parent->issubquery);
scan_relid = (Index) lfirsti(best_path->path.parent->relids);
......@@ -465,6 +481,34 @@ create_tidscan_node(TidPath *best_path, List *tlist, List *scan_clauses)
return scan_node;
}
/*
* create_subqueryscan_node
* Returns a subqueryscan node for the base relation scanned by 'best_path'
* with restriction clauses 'scan_clauses' and targetlist 'tlist'.
*/
static SubqueryScan *
create_subqueryscan_node(Path *best_path, List *tlist, List *scan_clauses)
{
SubqueryScan *scan_node;
Index scan_relid;
/* there should be exactly one base rel involved... */
Assert(length(best_path->parent->relids) == 1);
/* and it must be a subquery */
Assert(best_path->parent->issubquery);
scan_relid = (Index) lfirsti(best_path->parent->relids);
scan_node = make_subqueryscan(tlist,
scan_clauses,
scan_relid,
best_path->parent->subplan);
copy_path_costsize(&scan_node->scan.plan, best_path);
return scan_node;
}
/*****************************************************************************
*
* JOIN METHODS
......@@ -1162,6 +1206,28 @@ make_tidscan(List *qptlist,
return node;
}
static SubqueryScan *
make_subqueryscan(List *qptlist,
List *qpqual,
Index scanrelid,
Plan *subplan)
{
SubqueryScan *node = makeNode(SubqueryScan);
Plan *plan = &node->scan.plan;
/* cost should be inserted by caller */
plan->state = (EState *) NULL;
plan->targetlist = qptlist;
plan->qual = qpqual;
plan->lefttree = NULL;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
node->subplan = subplan;
node->scan.scanstate = (CommonScanState *) NULL;
return node;
}
static NestLoop *
make_nestloop(List *tlist,
......@@ -1405,7 +1471,11 @@ make_agg(List *tlist, List *qual, Plan *lefttree)
* mode, so it didn't reduce its row count already.)
*/
if (IsA(lefttree, Group))
{
plan->plan_rows *= 0.1;
if (plan->plan_rows < 1)
plan->plan_rows = 1;
}
else
{
plan->plan_rows = 1;
......@@ -1447,7 +1517,11 @@ make_group(List *tlist,
* --- bogus, but how to do better?
*/
if (!tuplePerGroup)
{
plan->plan_rows *= 0.1;
if (plan->plan_rows < 1)
plan->plan_rows = 1;
}
plan->state = (EState *) NULL;
plan->qual = NULL;
......@@ -1489,6 +1563,8 @@ make_unique(List *tlist, Plan *lefttree, List *distinctList)
* 10% as many tuples out as in.
*/
plan->plan_rows *= 0.1;
if (plan->plan_rows < 1)
plan->plan_rows = 1;
plan->state = (EState *) NULL;
plan->targetlist = tlist;
......
This diff is collapsed.
......@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.59 2000/09/12 21:06:54 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/planmain.c,v 1.60 2000/09/29 18:21:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -32,8 +32,8 @@
#include "utils/memutils.h"
static Plan *subplanner(Query *root, List *flat_tlist, List *qual,
double tuple_fraction);
static Plan *subplanner(Query *root, List *flat_tlist,
double tuple_fraction);
/*--------------------
......@@ -75,46 +75,36 @@ query_planner(Query *root,
List *tlist,
double tuple_fraction)
{
List *normal_qual;
List *noncachable_qual;
List *constant_qual;
List *constant_quals;
List *var_only_tlist;
Plan *subplan;
/*
* If the query contains no relation references at all, it must be
* something like "SELECT 2+2;". Build a trivial "Result" plan.
* If the query has an empty join tree, then it's something easy like
* "SELECT 2+2;" or "INSERT ... VALUES()". Fall through quickly.
*/
if (root->rtable == NIL)
if (root->jointree->fromlist == NIL)
{
/* If it's not a select, it should have had a target relation... */
if (root->commandType != CMD_SELECT)
elog(ERROR, "Empty range table for non-SELECT query");
root->query_pathkeys = NIL; /* signal unordered result */
/* Make childless Result node to evaluate given tlist. */
return (Plan *) make_result(tlist, root->qual, (Plan *) NULL);
return (Plan *) make_result(tlist, root->jointree->quals,
(Plan *) NULL);
}
/*
* Pull out any non-variable qual clauses so these can be put in a
* Pull out any non-variable WHERE clauses so these can be put in a
* toplevel "Result" node, where they will gate execution of the whole
* plan (the Result will not invoke its descendant plan unless the
* quals are true). Note that any *really* non-variable quals will
* have been optimized away by eval_const_expressions(). What we're
* mostly interested in here is quals that depend only on outer-level
* vars, although if the qual reduces to "WHERE FALSE" this path will
* also be taken. We also need a special case for quals that contain
* noncachable functions but no vars, such as "WHERE random() < 0.5".
* These cannot be treated as normal restriction or join quals, but
* they're not constants either. Instead, attach them to the qpqual
* of the top plan, so that they get evaluated once per potential
* output tuple.
* also be taken.
*/
normal_qual = pull_constant_clauses((List *) root->qual,
&noncachable_qual,
&constant_qual);
root->jointree->quals = (Node *)
pull_constant_clauses((List *) root->jointree->quals,
&constant_quals);
/*
* Create a target list that consists solely of (resdom var) target
......@@ -132,18 +122,12 @@ query_planner(Query *root,
/*
* Choose the best access path and build a plan for it.
*/
subplan = subplanner(root, var_only_tlist, normal_qual, tuple_fraction);
/*
* Handle the noncachable quals.
*/
if (noncachable_qual)
subplan->qual = nconc(subplan->qual, noncachable_qual);
subplan = subplanner(root, var_only_tlist, tuple_fraction);
/*
* Build a result node to control the plan if we have constant quals.
*/
if (constant_qual)
if (constant_quals)
{
/*
......@@ -151,7 +135,7 @@ query_planner(Query *root,
* originally requested tlist.
*/
subplan = (Plan *) make_result(tlist,
(Node *) constant_qual,
(Node *) constant_quals,
subplan);
}
else
......@@ -175,7 +159,6 @@ query_planner(Query *root,
* for processing a single level of attributes.
*
* flat_tlist is the flattened target list
* qual is the qualification to be satisfied (restrict and join quals only)
* tuple_fraction is the fraction of tuples we expect will be retrieved
*
* See query_planner() comments about the interpretation of tuple_fraction.
......@@ -185,7 +168,6 @@ query_planner(Query *root,
static Plan *
subplanner(Query *root,
List *flat_tlist,
List *qual,
double tuple_fraction)
{
List *joined_rels;
......@@ -210,9 +192,8 @@ subplanner(Query *root,
root->equi_key_list = NIL;
build_base_rel_tlists(root, flat_tlist);
(void) add_join_quals_to_rels(root, (Node *) root->jointree);
/* this must happen after add_join_quals_to_rels: */
add_restrict_and_join_to_rels(root, qual);
(void) distribute_quals_to_rels(root, (Node *) root->jointree);
/*
* Make sure we have RelOptInfo nodes for all relations to be joined.
......@@ -270,26 +251,7 @@ subplanner(Query *root,
final_rel = make_one_rel(root);
if (!final_rel)
{
/*
* We expect to end up here for a trivial INSERT ... VALUES query
* (which will have a target relation, so it gets past
* query_planner's check for empty range table; but the target rel
* is not in the join tree, so we find there is nothing to join).
*
* It's also possible to get here if the query was rewritten by the
* rule processor (creating dummy rangetable entries that are not in
* the join tree) but the rules either did nothing or were simplified
* to nothing by constant-expression folding. So, don't complain.
*/
root->query_pathkeys = NIL; /* signal unordered result */
/* Make childless Result node to evaluate given tlist. */
resultplan = (Plan *) make_result(flat_tlist, (Node *) qual,
(Plan *) NULL);
goto plan_built;
}
elog(ERROR, "subplanner: failed to construct a relation");
#ifdef NOT_USED /* fix xfunc */
......@@ -395,7 +357,10 @@ plan_built:
/*
* Must copy the completed plan tree and its pathkeys out of temporary
* context.
* context. We also have to copy the rtable in case it contains any
* subqueries. (If it does, they'll have been modified during the
* recursive invocation of planner.c, and hence will contain substructure
* allocated in my temporary context...)
*/
MemoryContextSwitchTo(oldcxt);
......@@ -403,6 +368,8 @@ plan_built:
root->query_pathkeys = copyObject(root->query_pathkeys);
root->rtable = copyObject(root->rtable);
/*
* Now we can release the Path storage.
*/
......
This diff is collapsed.
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.65 2000/09/12 21:06:54 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/setrefs.c,v 1.66 2000/09/29 18:21:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -102,6 +102,11 @@ set_plan_references(Plan *plan)
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
break;
case T_SubqueryScan:
fix_expr_references(plan, (Node *) plan->targetlist);
fix_expr_references(plan, (Node *) plan->qual);
/* No need to recurse into the subplan, it's fixed already */
break;
case T_NestLoop:
set_join_references((Join *) plan);
fix_expr_references(plan, (Node *) plan->targetlist);
......
......@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.41 2000/09/12 21:06:54 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/plan/subselect.c,v 1.42 2000/09/29 18:21:33 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -453,19 +453,6 @@ make_subplan(SubLink *slink)
return result;
}
/* this oughta be merged with LispUnioni */
static List *
set_unioni(List *l1, List *l2)
{
if (l1 == NULL)
return l2;
if (l2 == NULL)
return l1;
return nconc(l1, set_differencei(l2, l1));
}
/*
* finalize_primnode: build lists of subplans and params appearing
* in the given expression tree. NOTE: items are added to lists passed in,
......@@ -680,6 +667,7 @@ SS_finalize_plan(Plan *plan)
case T_Agg:
case T_SeqScan:
case T_SubqueryScan:
case T_Material:
case T_Sort:
case T_Unique:
......
......@@ -85,19 +85,14 @@ transformKeySetQuery(Query *origNode)
/*************************/
/* Qualify where clause */
/*************************/
if (!inspectOrNode((Expr *) origNode->qual) || TotalExpr < 9)
if (!inspectOrNode((Expr *) origNode->jointree->quals) || TotalExpr < 9)
return;
/* Copy essential elements into a union node */
while (((Expr *) origNode->qual)->opType == OR_EXPR)
while (((Expr *) origNode->jointree->quals)->opType == OR_EXPR)
{
Query *unionNode = makeNode(Query);
/* Pull up Expr = */
unionNode->qual = lsecond(((Expr *) origNode->qual)->args);
/* Pull up balance of tree */
origNode->qual = lfirst(((Expr *) origNode->qual)->args);
List *qualargs = ((Expr *) origNode->jointree->quals)->args;
unionNode->commandType = origNode->commandType;
unionNode->resultRelation = origNode->resultRelation;
......@@ -107,9 +102,16 @@ transformKeySetQuery(Query *origNode)
Node_Copy(origNode, unionNode, distinctClause);
Node_Copy(origNode, unionNode, sortClause);
Node_Copy(origNode, unionNode, rtable);
origNode->jointree->quals = NULL; /* avoid unnecessary copying */
Node_Copy(origNode, unionNode, jointree);
Node_Copy(origNode, unionNode, targetList);
/* Pull up Expr = */
unionNode->jointree->quals = lsecond(qualargs);
/* Pull up balance of tree */
origNode->jointree->quals = lfirst(qualargs);
origNode->unionClause = lappend(origNode->unionClause, unionNode);
}
return;
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.52 2000/09/12 21:06:57 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.53 2000/09/29 18:21:34 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -411,7 +411,7 @@ find_all_inheritors(Oid parentrel)
* there can't be any cycles in the inheritance graph anyway.)
*/
currentchildren = set_differencei(currentchildren, examined_relids);
unexamined_relids = LispUnioni(unexamined_relids, currentchildren);
unexamined_relids = set_unioni(unexamined_relids, currentchildren);
}
return examined_relids;
......
......@@ -4,7 +4,7 @@
# Makefile for optimizer/util
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/backend/optimizer/util/Makefile,v 1.13 2000/08/31 16:10:14 petere Exp $
# $Header: /cvsroot/pgsql/src/backend/optimizer/util/Makefile,v 1.14 2000/09/29 18:21:23 tgl Exp $
#
#-------------------------------------------------------------------------
......@@ -12,7 +12,7 @@ subdir = src/backend/optimizer/util
top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global
OBJS = restrictinfo.o clauses.o indexnode.o plancat.o \
OBJS = restrictinfo.o clauses.o plancat.o \
joininfo.o pathnode.o relnode.o tlist.o var.o
all: SUBSYS.o
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.75 2000/09/25 18:14:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.76 2000/09/29 18:21:23 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
......@@ -119,9 +119,9 @@ make_opclause(Oper *op, Var *leftop, Var *rightop)
expr->opType = OP_EXPR;
expr->oper = (Node *) op;
if (rightop)
expr->args = lcons(leftop, lcons(rightop, NIL));
expr->args = makeList2(leftop, rightop);
else
expr->args = lcons(leftop, NIL);
expr->args = makeList1(leftop);
return expr;
}
......@@ -264,7 +264,7 @@ make_notclause(Expr *notclause)
expr->typeOid = BOOLOID;
expr->opType = NOT_EXPR;
expr->oper = NULL;
expr->args = lcons(notclause, NIL);
expr->args = makeList1(notclause);
return expr;
}
......@@ -303,7 +303,6 @@ and_clause(Node *clause)
* make_andclause
*
* Create an 'and' clause given its arguments in a list.
*
*/
Expr *
make_andclause(List *andclauses)
......@@ -317,6 +316,23 @@ make_andclause(List *andclauses)
return expr;
}
/*
* make_and_qual
*
* Variant of make_andclause for ANDing two qual conditions together.
* Qual conditions have the property that a NULL nodetree is interpreted
* as 'true'.
*/
Node *
make_and_qual(Node *qual1, Node *qual2)
{
if (qual1 == NULL)
return qual2;
if (qual2 == NULL)
return qual1;
return (Node *) make_andclause(makeList2(qual1, qual2));
}
/*
* Sometimes (such as in the result of canonicalize_qual or the input of
* ExecQual), we use lists of expression nodes with implicit AND semantics.
......@@ -356,7 +372,7 @@ make_ands_implicit(Expr *clause)
DatumGetBool(((Const *) clause)->constvalue))
return NIL; /* constant TRUE input -> NIL list */
else
return lcons(clause, NIL);
return makeList1(clause);
}
......@@ -676,49 +692,32 @@ is_pseudo_constant_clause(Node *clause)
return false;
}
/*----------
/*
* pull_constant_clauses
* Scan through a list of qualifications and separate "constant" quals
* from those that are not.
*
* The input qual list is divided into three parts:
* * The function's return value is a list of all those quals that contain
* variable(s) of the current query level. (These quals will become
* restrict and join quals.)
* * *noncachableQual receives a list of quals that have no Vars, yet
* cannot be treated as constants because they contain noncachable
* function calls. (Example: WHERE random() < 0.5)
* * *constantQual receives a list of the remaining quals, which can be
* treated as constants for any one scan of the current query level.
* (They are really only pseudo-constant, since they may contain
* Params or outer-level Vars.)
*----------
* Returns a list of the pseudo-constant clauses in constantQual and the
* remaining quals as the return value.
*/
List *
pull_constant_clauses(List *quals,
List **noncachableQual,
List **constantQual)
pull_constant_clauses(List *quals, List **constantQual)
{
List *q;
List *normqual = NIL;
List *noncachequal = NIL;
List *constqual = NIL;
List *restqual = NIL;
List *q;
foreach(q, quals)
{
Node *qual = (Node *) lfirst(q);
Node *qual = (Node *) lfirst(q);
if (contain_var_clause(qual))
normqual = lappend(normqual, qual);
else if (contain_noncachable_functions(qual))
noncachequal = lappend(noncachequal, qual);
else
if (is_pseudo_constant_clause(qual))
constqual = lappend(constqual, qual);
else
restqual = lappend(restqual, qual);
}
*noncachableQual = noncachequal;
*constantQual = constqual;
return normqual;
return restqual;
}
......@@ -1636,9 +1635,9 @@ simplify_op_or_func(Expr *expr, List *args)
* will have List structure at the top level, and it handles TargetEntry nodes
* so that a scan of a target list can be handled without additional code.
* (But only the "expr" part of a TargetEntry is examined, unless the walker
* chooses to process TargetEntry nodes specially.) Also, RangeTblRef and
* JoinExpr nodes are handled, so that qual expressions in a jointree can be
* processed without additional code.
* chooses to process TargetEntry nodes specially.) Also, RangeTblRef,
* FromExpr, and JoinExpr nodes are handled, so that qual expressions in a
* jointree can be processed without additional code.
*
* expression_tree_walker will handle SubLink and SubPlan nodes by recursing
* normally into the "lefthand" arguments (which belong to the outer plan).
......@@ -1801,6 +1800,16 @@ expression_tree_walker(Node *node,
break;
case T_TargetEntry:
return walker(((TargetEntry *) node)->expr, context);
case T_FromExpr:
{
FromExpr *from = (FromExpr *) node;
if (walker(from->fromlist, context))
return true;
if (walker(from->quals, context))
return true;
}
break;
case T_JoinExpr:
{
JoinExpr *join = (JoinExpr *) node;
......@@ -1844,14 +1853,12 @@ query_tree_walker(Query *query,
if (walker((Node *) query->targetList, context))
return true;
if (walker(query->qual, context))
if (walker((Node *) query->jointree, context))
return true;
if (walker(query->havingQual, context))
return true;
if (walker((Node *) query->jointree, context))
return true;
/*
* XXX for subselect-in-FROM, may need to examine rtable as well
* XXX for subselect-in-FROM, may need to examine rtable as well?
*/
return false;
}
......@@ -2126,6 +2133,17 @@ expression_tree_mutator(Node *node,
return (Node *) newnode;
}
break;
case T_FromExpr:
{
FromExpr *from = (FromExpr *) node;
FromExpr *newnode;
FLATCOPY(newnode, from, FromExpr);
MUTATE(newnode->fromlist, from->fromlist, List *);
MUTATE(newnode->quals, from->quals, Node *);
return (Node *) newnode;
}
break;
case T_JoinExpr:
{
JoinExpr *join = (JoinExpr *) node;
......
/*-------------------------------------------------------------------------
*
* indexnode.c
* Routines to find all indices on a relation
*
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/Attic/indexnode.c,v 1.22 2000/01/26 05:56:40 momjian Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "optimizer/pathnode.h"
#include "optimizer/plancat.h"
/*
* find_relation_indices
* Returns a list of index nodes containing appropriate information for
* each (secondary) index defined on a relation.
*
*/
List *
find_relation_indices(Query *root, RelOptInfo *rel)
{
if (rel->indexed)
return find_secondary_indexes(root, lfirsti(rel->relids));
else
return NIL;
}
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.65 2000/09/12 21:06:58 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/pathnode.c,v 1.66 2000/09/29 18:21:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -16,6 +16,7 @@
#include "postgres.h"
#include "nodes/plannodes.h"
#include "optimizer/cost.h"
#include "optimizer/pathnode.h"
#include "optimizer/paths.h"
......@@ -272,7 +273,6 @@ add_path(RelOptInfo *parent_rel, Path *new_path)
* create_seqscan_path
* Creates a path corresponding to a sequential scan, returning the
* pathnode.
*
*/
Path *
create_seqscan_path(RelOptInfo *rel)
......@@ -343,8 +343,8 @@ 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.
*/
pathnode->indexid = lconsi(index->indexoid, NIL);
pathnode->indexqual = lcons(indexquals, NIL);
pathnode->indexid = makeListi1(index->indexoid);
pathnode->indexqual = makeList1(indexquals);
pathnode->indexscandir = indexscandir;
......@@ -390,6 +390,27 @@ create_tidscan_path(RelOptInfo *rel, List *tideval)
return pathnode;
}
/*
* create_subqueryscan_path
* Creates a path corresponding to a sequential scan of a subquery,
* returning the pathnode.
*/
Path *
create_subqueryscan_path(RelOptInfo *rel)
{
Path *pathnode = makeNode(Path);
pathnode->pathtype = T_SubqueryScan;
pathnode->parent = rel;
pathnode->pathkeys = NIL; /* for now, assume unordered result */
/* just copy the subplan's cost estimates */
pathnode->startup_cost = rel->subplan->startup_cost;
pathnode->total_cost = rel->subplan->total_cost;
return pathnode;
}
/*
* create_nestloop_path
* Creates a pathnode corresponding to a nestloop join between two
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.60 2000/07/27 23:16:04 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/optimizer/util/plancat.c,v 1.61 2000/09/29 18:21:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -25,7 +25,6 @@
#include "catalog/pg_inherits.h"
#include "catalog/pg_index.h"
#include "optimizer/plancat.h"
#include "parser/parsetree.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/relcache.h"
......@@ -37,16 +36,15 @@
/*
* relation_info -
* Retrieves catalog information for a given relation.
* Given the rangetable index of the relation, return the following info:
* Given the Oid of the relation, return the following info:
* whether the relation has secondary indices
* number of pages
* number of tuples
*/
void
relation_info(Query *root, Index relid,
relation_info(Oid relationObjectId,
bool *hasindex, long *pages, double *tuples)
{
Oid relationObjectId = getrelid(relid, root->rtable);
HeapTuple relationTuple;
Form_pg_class relation;
......@@ -69,19 +67,18 @@ relation_info(Query *root, Index relid,
/*
* find_secondary_indexes
* Creates a list of IndexOptInfo nodes containing information for each
* secondary index defined on the given relation.
* secondary index defined on the specified relation.
*
* 'relid' is the RT index of the relation for which indices are being located
* 'relationObjectId' is the OID of the relation for which indices are wanted
*
* Returns a list of new IndexOptInfo nodes.
*/
List *
find_secondary_indexes(Query *root, Index relid)
find_secondary_indexes(Oid relationObjectId)
{
List *indexinfos = NIL;
List *indexoidlist,
*indexoidscan;
Oid indrelid = getrelid(relid, root->rtable);
Relation relation;
/*
......@@ -89,12 +86,12 @@ find_secondary_indexes(Query *root, Index relid)
* a cached list of OID indexes for each relation. So, get that list
* and then use the syscache to obtain pg_index entries.
*/
relation = heap_open(indrelid, AccessShareLock);
relation = heap_open(relationObjectId, AccessShareLock);
indexoidlist = RelationGetIndexList(relation);
foreach(indexoidscan, indexoidlist)
{
Oid indexoid = lfirsti(indexoidscan);
Oid indexoid = lfirsti(indexoidscan);
HeapTuple indexTuple;
Form_pg_index index;
IndexOptInfo *info;
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
......@@ -221,7 +221,7 @@ drop rule 314159;
ERROR: parser: parse error at or near "314159"
-- no such rule
drop rule nonesuch;
ERROR: Rule or view 'nonesuch' not found
ERROR: Rule or view "nonesuch" not found
-- bad keyword
drop tuple rule nonesuch;
ERROR: parser: parse error at or near "tuple"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment