mirror of
https://github.com/postgres/postgres.git
synced 2025-12-22 17:42:17 +03:00
Subselects in FROM clause, per ISO syntax: FROM (SELECT ...) [AS] alias.
(Don't forget that an alias is required.) Views reimplemented as expanding to subselect-in-FROM. Grouping, aggregates, DISTINCT in views actually work now (he says optimistically). No UNION support in subselects/views yet, but I have some ideas about that. Rule-related permissions checking moved out of rewriter and into executor. INITDB REQUIRED!
This commit is contained in:
@@ -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 (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);
|
||||
|
||||
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, ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
if (IsA(plan, Append))
|
||||
{
|
||||
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)
|
||||
{
|
||||
List *saved_rtable = es->rtable;
|
||||
List *lst;
|
||||
int whichplan = 0;
|
||||
Append *appendplan = (Append *) plan;
|
||||
List *saved_rtable = es->rtable;
|
||||
int whichplan = 0;
|
||||
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 = makeNode(TypeName);
|
||||
|
||||
typename->name = pstrdup(restypename);
|
||||
typename->typmod = res->restypmod;
|
||||
TypeName *typename = makeNode(TypeName);
|
||||
|
||||
def->colname = pstrdup(resname);
|
||||
|
||||
typename->name = pstrdup(restypename);
|
||||
typename->typmod = res->restypmod;
|
||||
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));
|
||||
|
||||
/*
|
||||
|
||||
Reference in New Issue
Block a user