mirror of
https://github.com/postgres/postgres.git
synced 2025-11-07 19:06:32 +03:00
Postgres95 1.01 Distribution - Virgin Sources
This commit is contained in:
14
src/backend/optimizer/prep/Makefile.inc
Normal file
14
src/backend/optimizer/prep/Makefile.inc
Normal file
@@ -0,0 +1,14 @@
|
||||
#-------------------------------------------------------------------------
|
||||
#
|
||||
# Makefile.inc--
|
||||
# Makefile for optimizer/prep
|
||||
#
|
||||
# Copyright (c) 1994, Regents of the University of California
|
||||
#
|
||||
#
|
||||
# IDENTIFICATION
|
||||
# $Header: /cvsroot/pgsql/src/backend/optimizer/prep/Attic/Makefile.inc,v 1.1.1.1 1996/07/09 06:21:37 scrappy Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
SUBSRCS+= archive.c prepqual.c preptlist.c prepunion.c
|
||||
66
src/backend/optimizer/prep/archive.c
Normal file
66
src/backend/optimizer/prep/archive.c
Normal file
@@ -0,0 +1,66 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* archive.c--
|
||||
* Support for planning scans on archived relations
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/Attic/archive.c,v 1.1.1.1 1996/07/09 06:21:38 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include <stdio.h> /* for sprintf() */
|
||||
#include <sys/types.h> /* for u_int in relcache.h */
|
||||
#include "postgres.h"
|
||||
|
||||
#include "utils/rel.h"
|
||||
#include "utils/elog.h"
|
||||
#include "utils/palloc.h"
|
||||
#include "utils/relcache.h"
|
||||
#include "catalog/pg_class.h"
|
||||
#include "nodes/pg_list.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
#include "optimizer/prep.h"
|
||||
#include "commands/creatinh.h"
|
||||
|
||||
void
|
||||
plan_archive(List *rt)
|
||||
{
|
||||
List *rtitem;
|
||||
RangeTblEntry *rte;
|
||||
TimeRange *trange;
|
||||
Relation r;
|
||||
Oid reloid;
|
||||
|
||||
foreach(rtitem, rt) {
|
||||
rte = lfirst(rtitem);
|
||||
trange = rte->timeRange;
|
||||
if (trange) {
|
||||
reloid = rte->relid;
|
||||
r = RelationIdGetRelation(reloid);
|
||||
if (r->rd_rel->relarch != 'n') {
|
||||
rte->archive = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* find_archive_rels -- Given a particular relid, find the archive
|
||||
* relation's relid.
|
||||
*/
|
||||
List *
|
||||
find_archive_rels(Oid relid)
|
||||
{
|
||||
Relation arel;
|
||||
char *arelName;
|
||||
|
||||
arelName = MakeArchiveName(relid);
|
||||
arel = RelationNameGetRelation(arelName);
|
||||
pfree(arelName);
|
||||
|
||||
return lconsi(arel->rd_id, lconsi(relid, NIL));
|
||||
}
|
||||
582
src/backend/optimizer/prep/prepqual.c
Normal file
582
src/backend/optimizer/prep/prepqual.c
Normal file
@@ -0,0 +1,582 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* prepqual.c--
|
||||
* Routines for preprocessing the parse tree qualification
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepqual.c,v 1.1.1.1 1996/07/09 06:21:38 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "nodes/pg_list.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
|
||||
#include "optimizer/internal.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/prep.h"
|
||||
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
static Expr *pull_args(Expr *qual);
|
||||
static List *pull_ors(List *orlist);
|
||||
static List *pull_ands(List *andlist);
|
||||
static Expr *find_nots(Expr *qual);
|
||||
static Expr *push_nots(Expr *qual);
|
||||
static Expr *normalize(Expr *qual);
|
||||
static List *or_normalize(List *orlist);
|
||||
static List *distribute_args(List *item, List *args);
|
||||
static List *qualcleanup(Expr *qual);
|
||||
static List *remove_ands(Expr *qual);
|
||||
static List *remove_duplicates(List *list);
|
||||
|
||||
/*
|
||||
* preprocess-qualification--
|
||||
* Driver routine for modifying the parse tree qualification.
|
||||
*
|
||||
* Returns the new base qualification and the existential qualification
|
||||
* in existentialQualPtr.
|
||||
*
|
||||
* XXX right now, update_clauses() does nothing so
|
||||
* preprocess-qualification simply converts the qual in conjunctive
|
||||
* normal form (see cnfify() below )
|
||||
*/
|
||||
List *
|
||||
preprocess_qualification(Expr *qual, List *tlist, List **existentialQualPtr)
|
||||
{
|
||||
List *cnf_qual = cnfify(qual, true);
|
||||
/*
|
||||
List *existential_qual =
|
||||
update_clauses(intCons(_query_result_relation_,
|
||||
update_relations(tlist)),
|
||||
cnf_qual,
|
||||
_query_command_type_);
|
||||
if (existential_qual) {
|
||||
*existentialQualPtr = existential_qual;
|
||||
return set_difference(cnf_qual, existential_qual);
|
||||
} else {
|
||||
*existentialQualPtr = NIL;
|
||||
return cnf_qual;
|
||||
}
|
||||
*/
|
||||
/* update_clauses() is not working right now */
|
||||
*existentialQualPtr = NIL;
|
||||
return cnf_qual;
|
||||
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* CNF CONVERSION ROUTINES
|
||||
*
|
||||
* NOTES:
|
||||
* The basic algorithms for normalizing the qualification are taken
|
||||
* from ingres/source/qrymod/norml.c
|
||||
*
|
||||
* Remember that the initial qualification may consist of ARBITRARY
|
||||
* combinations of clauses. In addition, before this routine is called,
|
||||
* the qualification will contain explicit "AND"s.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
/*
|
||||
* cnfify--
|
||||
* Convert a qualification to conjunctive normal form by applying
|
||||
* successive normalizations.
|
||||
*
|
||||
* Returns the modified qualification with an extra level of nesting.
|
||||
*
|
||||
* If 'removeAndFlag' is true then it removes the explicit ANDs.
|
||||
*
|
||||
* NOTE: this routine is called by the planner (removeAndFlag = true)
|
||||
* and from the rule manager (removeAndFlag = false).
|
||||
*
|
||||
*/
|
||||
List *
|
||||
cnfify(Expr *qual, bool removeAndFlag)
|
||||
{
|
||||
Expr *newqual = NULL;
|
||||
|
||||
if (qual != NULL) {
|
||||
newqual = find_nots(pull_args(qual));
|
||||
newqual = normalize(pull_args(newqual));
|
||||
newqual = (Expr*)qualcleanup(pull_args(newqual));
|
||||
newqual = pull_args(newqual);;
|
||||
|
||||
if (removeAndFlag) {
|
||||
if(and_clause((Node*)newqual))
|
||||
newqual=(Expr*)remove_ands(newqual);
|
||||
else
|
||||
newqual=(Expr*)remove_ands(make_andclause(lcons(newqual,NIL)));
|
||||
}
|
||||
}
|
||||
else if (qual!=NULL)
|
||||
newqual = (Expr*)lcons(qual, NIL);
|
||||
|
||||
return (List*)(newqual);
|
||||
}
|
||||
|
||||
/*
|
||||
* pull-args--
|
||||
* Given a qualification, eliminate nested 'and' and 'or' clauses.
|
||||
*
|
||||
* Returns the modified qualification.
|
||||
*
|
||||
*/
|
||||
static Expr *
|
||||
pull_args(Expr *qual)
|
||||
{
|
||||
if (qual==NULL)
|
||||
return (NULL);
|
||||
|
||||
if (is_opclause((Node*)qual)) {
|
||||
return(make_clause(qual->opType, qual->oper,
|
||||
lcons(pull_args((Expr*)get_leftop(qual)),
|
||||
lcons(pull_args((Expr*)get_rightop(qual)),
|
||||
NIL))));
|
||||
} else if (and_clause((Node*)qual)) {
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
|
||||
foreach (temp, qual->args)
|
||||
t_list = lappend (t_list, pull_args(lfirst(temp)));
|
||||
return (make_andclause (pull_ands (t_list)));
|
||||
}else if (or_clause((Node*)qual)) {
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
|
||||
foreach (temp, qual->args)
|
||||
t_list = lappend (t_list, pull_args(lfirst(temp)));
|
||||
return (make_orclause (pull_ors (t_list)));
|
||||
} else if (not_clause((Node*)qual)) {
|
||||
return (make_notclause (pull_args (get_notclausearg (qual))));
|
||||
} else {
|
||||
return (qual);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* pull-ors--
|
||||
* Pull the arguments of an 'or' clause nested within another 'or'
|
||||
* clause up into the argument list of the parent.
|
||||
*
|
||||
* Returns the modified list.
|
||||
*/
|
||||
static List *
|
||||
pull_ors(List *orlist)
|
||||
{
|
||||
if (orlist==NIL)
|
||||
return (NIL);
|
||||
|
||||
if (or_clause(lfirst(orlist))) {
|
||||
List *args = ((Expr*)lfirst(orlist))->args;
|
||||
return (pull_ors(nconc(copyObject((Node*)args),
|
||||
copyObject((Node*)lnext(orlist)))));
|
||||
} else {
|
||||
return (lcons(lfirst(orlist), pull_ors(lnext(orlist))));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* pull-ands--
|
||||
* Pull the arguments of an 'and' clause nested within another 'and'
|
||||
* clause up into the argument list of the parent.
|
||||
*
|
||||
* Returns the modified list.
|
||||
*/
|
||||
static List *
|
||||
pull_ands(List *andlist)
|
||||
{
|
||||
if (andlist==NIL)
|
||||
return (NIL);
|
||||
|
||||
if (and_clause (lfirst(andlist))) {
|
||||
List *args = ((Expr*)lfirst(andlist))->args;
|
||||
return (pull_ands(nconc(copyObject((Node*)args),
|
||||
copyObject((Node*)lnext(andlist)))));
|
||||
} else {
|
||||
return (lcons(lfirst(andlist), pull_ands(lnext(andlist))));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* find-nots--
|
||||
* Traverse the qualification, looking for 'not's to take care of.
|
||||
* For 'not' clauses, remove the 'not' and push it down to the clauses'
|
||||
* descendants.
|
||||
* For all other clause types, simply recurse.
|
||||
*
|
||||
* Returns the modified qualification.
|
||||
*
|
||||
*/
|
||||
static Expr *
|
||||
find_nots(Expr *qual)
|
||||
{
|
||||
if (qual==NULL)
|
||||
return (NULL);
|
||||
|
||||
if (is_opclause((Node*)qual)) {
|
||||
return (make_clause(qual->opType, qual->oper,
|
||||
lcons(find_nots((Expr*)get_leftop(qual)),
|
||||
lcons(find_nots((Expr*)get_rightop(qual)),
|
||||
NIL))));
|
||||
} else if (and_clause ((Node*)qual)) {
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
|
||||
foreach (temp, qual->args) {
|
||||
t_list = lappend(t_list,find_nots(lfirst(temp)));
|
||||
}
|
||||
|
||||
return (make_andclause(t_list));
|
||||
} else if (or_clause((Node*)qual)) {
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
|
||||
foreach (temp, qual->args) {
|
||||
t_list = lappend(t_list,find_nots(lfirst(temp)));
|
||||
}
|
||||
return (make_orclause (t_list));
|
||||
} else if (not_clause((Node*)qual))
|
||||
return (push_nots(get_notclausearg (qual)));
|
||||
else
|
||||
return (qual);
|
||||
}
|
||||
|
||||
/*
|
||||
* push-nots--
|
||||
* Negate the descendants of a 'not' clause.
|
||||
*
|
||||
* Returns the modified qualification.
|
||||
*
|
||||
*/
|
||||
static Expr *
|
||||
push_nots(Expr *qual)
|
||||
{
|
||||
if (qual==NULL)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* Negate an operator clause if possible:
|
||||
* ("NOT" (< A B)) => (> A B)
|
||||
* Otherwise, retain the clause as it is (the 'not' can't be pushed
|
||||
* down any farther).
|
||||
*/
|
||||
if (is_opclause((Node*)qual)) {
|
||||
Oper *oper = (Oper*)((Expr*)qual)->oper;
|
||||
Oid negator = get_negator(oper->opno);
|
||||
|
||||
if(negator) {
|
||||
Oper *op = (Oper*) makeOper(negator,
|
||||
InvalidOid,
|
||||
oper->opresulttype,
|
||||
0, NULL);
|
||||
op->op_fcache = (FunctionCache *) NULL;
|
||||
return
|
||||
(make_opclause(op, get_leftop(qual), get_rightop(qual)));
|
||||
} else {
|
||||
return (make_notclause(qual));
|
||||
}
|
||||
} else if (and_clause((Node*)qual)) {
|
||||
/* Apply DeMorgan's Laws:
|
||||
* ("NOT" ("AND" A B)) => ("OR" ("NOT" A) ("NOT" B))
|
||||
* ("NOT" ("OR" A B)) => ("AND" ("NOT" A) ("NOT" B))
|
||||
* i.e., continue negating down through the clause's descendants.
|
||||
*/
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
|
||||
foreach(temp, qual->args) {
|
||||
t_list = lappend(t_list,push_nots(lfirst(temp)));
|
||||
}
|
||||
return (make_orclause (t_list));
|
||||
} else if (or_clause((Node*)qual)) {
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
|
||||
foreach(temp, qual->args) {
|
||||
t_list = lappend(t_list,push_nots(lfirst(temp)));
|
||||
}
|
||||
return (make_andclause (t_list));
|
||||
} else if (not_clause((Node*)qual))
|
||||
/* Another 'not' cancels this 'not', so eliminate the 'not' and
|
||||
* stop negating this branch.
|
||||
*/
|
||||
return (find_nots (get_notclausearg (qual)));
|
||||
else
|
||||
/* We don't know how to negate anything else, place a 'not' at this
|
||||
* level.
|
||||
*/
|
||||
return (make_notclause (qual));
|
||||
}
|
||||
|
||||
/*
|
||||
* normalize--
|
||||
* Given a qualification tree with the 'not's pushed down, convert it
|
||||
* to a tree in CNF by repeatedly applying the rule:
|
||||
* ("OR" A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C))
|
||||
* bottom-up.
|
||||
* Note that 'or' clauses will always be turned into 'and' clauses.
|
||||
*
|
||||
* Returns the modified qualification.
|
||||
*
|
||||
*/
|
||||
static Expr *
|
||||
normalize(Expr *qual)
|
||||
{
|
||||
if (qual==NULL)
|
||||
return (NULL);
|
||||
|
||||
if (is_opclause((Node*)qual)) {
|
||||
Expr *expr = (Expr*)qual;
|
||||
return (make_clause(expr->opType, expr->oper,
|
||||
lcons(normalize((Expr*)get_leftop(qual)),
|
||||
lcons(normalize((Expr*)get_rightop(qual)),
|
||||
NIL))));
|
||||
} else if (and_clause((Node*)qual)) {
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
|
||||
foreach (temp, qual->args) {
|
||||
t_list = lappend(t_list,normalize(lfirst(temp)));
|
||||
}
|
||||
return (make_andclause (t_list));
|
||||
} else if (or_clause((Node*)qual)) {
|
||||
/* XXX - let form, maybe incorrect */
|
||||
List *orlist = NIL;
|
||||
List *temp = NIL;
|
||||
bool has_andclause = FALSE;
|
||||
|
||||
foreach(temp, qual->args) {
|
||||
orlist = lappend(orlist,normalize(lfirst(temp)));
|
||||
}
|
||||
foreach (temp, orlist) {
|
||||
if (and_clause (lfirst(temp))) {
|
||||
has_andclause = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (has_andclause == TRUE)
|
||||
return (make_andclause(or_normalize(orlist)));
|
||||
else
|
||||
return (make_orclause(orlist));
|
||||
|
||||
} else if (not_clause((Node*)qual))
|
||||
return (make_notclause (normalize (get_notclausearg (qual))));
|
||||
else
|
||||
return (qual);
|
||||
}
|
||||
|
||||
/*
|
||||
* or-normalize--
|
||||
* Given a list of exprs which are 'or'ed together, distribute any
|
||||
* 'and' clauses.
|
||||
*
|
||||
* Returns the modified list.
|
||||
*
|
||||
*/
|
||||
static List *
|
||||
or_normalize(List *orlist)
|
||||
{
|
||||
List *distributable = NIL;
|
||||
List *new_orlist = NIL;
|
||||
List *temp = NIL;
|
||||
|
||||
if (orlist==NIL)
|
||||
return NIL;
|
||||
|
||||
foreach(temp, orlist) {
|
||||
if (and_clause(lfirst(temp)))
|
||||
distributable = lfirst(temp);
|
||||
}
|
||||
if (distributable)
|
||||
new_orlist = LispRemove(distributable,orlist);
|
||||
|
||||
if(new_orlist) {
|
||||
return
|
||||
(or_normalize(lcons(distribute_args(lfirst(new_orlist),
|
||||
((Expr*)distributable)->args),
|
||||
lnext(new_orlist))));
|
||||
}else {
|
||||
return (orlist);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* distribute-args--
|
||||
* Create new 'or' clauses by or'ing 'item' with each element of 'args'.
|
||||
* E.g.: (distribute-args A ("AND" B C)) => ("AND" ("OR" A B) ("OR" A C))
|
||||
*
|
||||
* Returns an 'and' clause.
|
||||
*
|
||||
*/
|
||||
static List *
|
||||
distribute_args(List *item, List *args)
|
||||
{
|
||||
List *or_list = NIL;
|
||||
List *n_list = NIL;
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
|
||||
if (args==NULL)
|
||||
return (item);
|
||||
|
||||
foreach (temp,args) {
|
||||
n_list = or_normalize(pull_ors(lcons(item,
|
||||
lcons(lfirst(temp),NIL))));
|
||||
or_list = (List*)make_orclause(n_list);
|
||||
t_list = lappend(t_list,or_list);
|
||||
}
|
||||
return ((List*)make_andclause(t_list));
|
||||
}
|
||||
|
||||
/*
|
||||
* qualcleanup--
|
||||
* Fix up a qualification by removing duplicate entries (left over from
|
||||
* normalization), and by removing 'and' and 'or' clauses which have only
|
||||
* one valid expr (e.g., ("AND" A) => A).
|
||||
*
|
||||
* Returns the modified qualfication.
|
||||
*
|
||||
*/
|
||||
static List *
|
||||
qualcleanup(Expr *qual)
|
||||
{
|
||||
if (qual==NULL)
|
||||
return (NIL);
|
||||
|
||||
if (is_opclause((Node*)qual)) {
|
||||
return ((List*)make_clause(qual->opType, qual->oper,
|
||||
lcons(qualcleanup((Expr*)get_leftop(qual)),
|
||||
lcons(qualcleanup((Expr*)get_rightop(qual)),
|
||||
NIL))));
|
||||
} else if (and_clause((Node*)qual)) {
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
List *new_and_args = NIL;
|
||||
|
||||
foreach(temp, qual->args)
|
||||
t_list = lappend(t_list,qualcleanup(lfirst(temp)));
|
||||
|
||||
new_and_args = remove_duplicates(t_list);
|
||||
|
||||
if(length (new_and_args) > 1)
|
||||
return ((List*)make_andclause(new_and_args));
|
||||
else
|
||||
return (lfirst(new_and_args));
|
||||
}
|
||||
else if (or_clause((Node*)qual)) {
|
||||
List *temp = NIL;
|
||||
List *t_list = NIL;
|
||||
List *new_or_args = NIL;
|
||||
|
||||
foreach (temp, qual->args)
|
||||
t_list = lappend(t_list,qualcleanup(lfirst(temp)));
|
||||
|
||||
new_or_args = remove_duplicates(t_list);
|
||||
|
||||
|
||||
if(length (new_or_args) > 1)
|
||||
return ((List*)make_orclause (new_or_args));
|
||||
else
|
||||
return (lfirst (new_or_args));
|
||||
} else if (not_clause((Node*)qual))
|
||||
return ((List*)make_notclause((Expr*)qualcleanup((Expr*)get_notclausearg(qual))));
|
||||
|
||||
else
|
||||
return ((List*)qual);
|
||||
}
|
||||
|
||||
/*
|
||||
* remove-ands--
|
||||
* Remove the explicit "AND"s from the qualification:
|
||||
* ("AND" A B) => (A B)
|
||||
*
|
||||
* RETURNS : qual
|
||||
* MODIFIES: qual
|
||||
*/
|
||||
static List *
|
||||
remove_ands(Expr *qual)
|
||||
{
|
||||
List *t_list = NIL;
|
||||
|
||||
if (qual==NULL)
|
||||
return (NIL);
|
||||
if (is_opclause((Node*)qual)) {
|
||||
return ((List*)make_clause(qual->opType, qual->oper,
|
||||
lcons(remove_ands((Expr*)get_leftop(qual)),
|
||||
lcons(remove_ands((Expr*)get_rightop(qual)),
|
||||
NIL))));
|
||||
} else if (and_clause((Node*)qual)) {
|
||||
List *temp = NIL;
|
||||
foreach (temp, qual->args)
|
||||
t_list = lappend(t_list,remove_ands(lfirst(temp)));
|
||||
return(t_list);
|
||||
} else if (or_clause((Node*)qual)) {
|
||||
List *temp = NIL;
|
||||
foreach (temp, qual->args)
|
||||
t_list = lappend(t_list,remove_ands(lfirst(temp)));
|
||||
return ((List*)make_orclause((List*)t_list));
|
||||
} else if (not_clause((Node*)qual)) {
|
||||
return ((List*)make_notclause((Expr*)remove_ands((Expr*)get_notclausearg (qual))));
|
||||
} else {
|
||||
return ((List*)qual);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* EXISTENTIAL QUALIFICATIONS
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* update-relations--
|
||||
* Returns the range table indices (i.e., varnos) for all relations which
|
||||
* are referenced in the target list.
|
||||
*
|
||||
*/
|
||||
#if 0
|
||||
static List *
|
||||
update_relations(List *tlist)
|
||||
{
|
||||
return(NIL);
|
||||
}
|
||||
#endif
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
*
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
static List *
|
||||
remove_duplicates(List *list)
|
||||
{
|
||||
List *i;
|
||||
List *j;
|
||||
List *result = NIL;
|
||||
bool there_exists_duplicate = false;
|
||||
|
||||
if (length(list) == 1)
|
||||
return(list);
|
||||
|
||||
foreach (i, list) {
|
||||
if (i != NIL) {
|
||||
foreach (j, lnext(i)) {
|
||||
if (equal(lfirst(i), lfirst(j)))
|
||||
there_exists_duplicate = true;
|
||||
}
|
||||
if (!there_exists_duplicate)
|
||||
result = lappend(result, lfirst(i));
|
||||
|
||||
there_exists_duplicate = false;
|
||||
}
|
||||
}
|
||||
return(result);
|
||||
}
|
||||
322
src/backend/optimizer/prep/preptlist.c
Normal file
322
src/backend/optimizer/prep/preptlist.c
Normal file
@@ -0,0 +1,322 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* preptlist.c--
|
||||
* Routines to preprocess the parse tree target list
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.1.1.1 1996/07/09 06:21:38 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "postgres.h"
|
||||
|
||||
#include "nodes/pg_list.h"
|
||||
#include "nodes/relation.h"
|
||||
#include "nodes/primnodes.h"
|
||||
#include "nodes/parsenodes.h"
|
||||
|
||||
#include "nodes/makefuncs.h"
|
||||
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/palloc.h"
|
||||
|
||||
#include "parser/parsetree.h" /* for getrelid() */
|
||||
#include "parser/catalog_utils.h"
|
||||
|
||||
#include "optimizer/internal.h"
|
||||
#include "optimizer/prep.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/tlist.h"
|
||||
|
||||
static List *expand_targetlist(List *tlist, Oid relid, int command_type,
|
||||
Index result_relation);
|
||||
static List *replace_matching_resname(List *new_tlist,
|
||||
List *old_tlist);
|
||||
static List *new_relation_targetlist(Oid relid, Index rt_index,
|
||||
NodeTag node_type);
|
||||
|
||||
|
||||
/*
|
||||
* preprocess-targetlist--
|
||||
* Driver for preprocessing the parse tree targetlist.
|
||||
*
|
||||
* 1. Deal with appends and replaces by filling missing attributes
|
||||
* in the target list.
|
||||
* 2. Reset operator OIDs to the appropriate regproc ids.
|
||||
*
|
||||
* Returns the new targetlist.
|
||||
*/
|
||||
List *
|
||||
preprocess_targetlist(List *tlist,
|
||||
int command_type,
|
||||
Index result_relation,
|
||||
List *range_table)
|
||||
{
|
||||
List *expanded_tlist = NIL;
|
||||
Oid relid = InvalidOid;
|
||||
List *t_list = NIL;
|
||||
List *temp = NIL;
|
||||
|
||||
if (result_relation>=1 && command_type != CMD_SELECT) {
|
||||
relid = getrelid(result_relation, range_table);
|
||||
}
|
||||
|
||||
/*
|
||||
* for heap_formtuple to work, the targetlist must match the exact
|
||||
* order of the attributes. We also need to fill in the missing
|
||||
* attributes here. -ay 10/94
|
||||
*/
|
||||
expanded_tlist =
|
||||
expand_targetlist(tlist, relid, command_type, result_relation);
|
||||
|
||||
/* XXX should the fix-opids be this early?? */
|
||||
/* was mapCAR */
|
||||
foreach (temp,expanded_tlist) {
|
||||
TargetEntry *tle = lfirst(temp);
|
||||
if (tle->expr)
|
||||
fix_opid(tle->expr);
|
||||
}
|
||||
t_list = copyObject(expanded_tlist);
|
||||
|
||||
/* ------------------
|
||||
* for "replace" or "delete" queries, add ctid of the result
|
||||
* relation into the target list so that the ctid can get
|
||||
* propogate through the execution and in the end ExecReplace()
|
||||
* will find the right tuple to replace or delete. This
|
||||
* extra field will be removed in ExecReplace().
|
||||
* For convinient, we append this extra field to the end of
|
||||
* the target list.
|
||||
* ------------------
|
||||
*/
|
||||
if (command_type == CMD_UPDATE || command_type == CMD_DELETE) {
|
||||
TargetEntry *ctid;
|
||||
Resdom *resdom;
|
||||
Var *var;
|
||||
|
||||
resdom = makeResdom(length(t_list) + 1,
|
||||
27,
|
||||
6,
|
||||
"ctid",
|
||||
0,
|
||||
0,
|
||||
1);
|
||||
|
||||
var = makeVar(result_relation, -1, 27, result_relation, -1);
|
||||
|
||||
ctid = makeNode(TargetEntry);
|
||||
ctid->resdom = resdom;
|
||||
ctid->expr = (Node *)var;
|
||||
t_list = lappend(t_list, ctid);
|
||||
}
|
||||
|
||||
return(t_list);
|
||||
}
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* TARGETLIST EXPANSION
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
/*
|
||||
* expand-targetlist--
|
||||
* Given a target list as generated by the parser and a result relation,
|
||||
* add targetlist entries for the attributes which have not been used.
|
||||
*
|
||||
* XXX This code is only supposed to work with unnested relations.
|
||||
*
|
||||
* 'tlist' is the original target list
|
||||
* 'relid' is the relid of the result relation
|
||||
* 'command' is the update command
|
||||
*
|
||||
* Returns the expanded target list, sorted in resno order.
|
||||
*/
|
||||
static List *
|
||||
expand_targetlist(List *tlist,
|
||||
Oid relid,
|
||||
int command_type,
|
||||
Index result_relation)
|
||||
{
|
||||
NodeTag node_type = T_Invalid;
|
||||
|
||||
switch (command_type) {
|
||||
case CMD_INSERT:
|
||||
node_type = (NodeTag)T_Const;
|
||||
break;
|
||||
case CMD_UPDATE:
|
||||
node_type = (NodeTag)T_Var;
|
||||
break;
|
||||
}
|
||||
|
||||
if(node_type != T_Invalid) {
|
||||
List *ntlist = new_relation_targetlist(relid,
|
||||
result_relation,
|
||||
node_type);
|
||||
|
||||
return (replace_matching_resname(ntlist, tlist));
|
||||
} else {
|
||||
return (tlist);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static List *
|
||||
replace_matching_resname(List *new_tlist, List *old_tlist)
|
||||
{
|
||||
List *temp, *i;
|
||||
List *t_list = NIL;
|
||||
|
||||
foreach (i,new_tlist) {
|
||||
TargetEntry *new_tle = (TargetEntry *)lfirst(i);
|
||||
TargetEntry *matching_old_tl = NULL;
|
||||
|
||||
foreach (temp, old_tlist) {
|
||||
TargetEntry *old_tle = (TargetEntry *)lfirst(temp);
|
||||
|
||||
old_tle = lfirst(temp);
|
||||
if (!strcmp(old_tle->resdom->resname,
|
||||
new_tle->resdom->resname)) {
|
||||
matching_old_tl = old_tle;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(matching_old_tl) {
|
||||
matching_old_tl->resdom->resno =
|
||||
new_tle->resdom->resno;
|
||||
t_list = lappend(t_list, matching_old_tl);
|
||||
}
|
||||
else {
|
||||
t_list = lappend(t_list, new_tle);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* It is possible that 'old_tlist' has some negative
|
||||
* attributes (i.e. negative resnos). This only happens
|
||||
* if this is a replace/append command and we explicitly
|
||||
* specify a system attribute. Of course this is not a very good
|
||||
* idea if this is a user query, but on the other hand the rule
|
||||
* manager uses this mechanism to replace rule locks.
|
||||
*
|
||||
* So, copy all these entries to the end of the target list
|
||||
* and set their 'resjunk' value to 1 to show that these are
|
||||
* special attributes and have to be treated specially by the
|
||||
* executor!
|
||||
*/
|
||||
foreach (temp, old_tlist) {
|
||||
TargetEntry *old_tle, *new_tl;
|
||||
Resdom *newresno;
|
||||
|
||||
old_tle = lfirst(temp);
|
||||
if (old_tle->resdom->resno < 0) {
|
||||
newresno = (Resdom*) copyObject((Node*)old_tle->resdom);
|
||||
newresno->resno = length(t_list) +1;
|
||||
newresno->resjunk = 1;
|
||||
new_tl = MakeTLE(newresno, old_tle->expr);
|
||||
t_list = lappend(t_list, new_tl);
|
||||
}
|
||||
}
|
||||
|
||||
return (t_list);
|
||||
}
|
||||
|
||||
/*
|
||||
* new-relation-targetlist--
|
||||
* Generate a targetlist for the relation with relation OID 'relid'
|
||||
* and rangetable index 'rt-index'.
|
||||
*
|
||||
* Returns the new targetlist.
|
||||
*/
|
||||
static List *
|
||||
new_relation_targetlist(Oid relid, Index rt_index, NodeTag node_type)
|
||||
{
|
||||
AttrNumber attno;
|
||||
List *t_list = NIL;
|
||||
char *attname;
|
||||
Oid atttype = 0;
|
||||
int16 typlen = 0;
|
||||
bool attisset = false;
|
||||
/* Oid type_id; */
|
||||
/* type_id = RelationIdGetTypeId(relid); */
|
||||
|
||||
for(attno=1; attno <= get_relnatts(relid); attno++) {
|
||||
attname = get_attname(/*type_id,*/ relid, attno);
|
||||
atttype = get_atttype(/*type_id,*/ relid, attno);
|
||||
/*
|
||||
* Since this is an append or replace, the size of any set
|
||||
* attribute is the size of the OID used to represent it.
|
||||
*/
|
||||
attisset = get_attisset(/* type_id,*/ relid, attname);
|
||||
if (attisset) {
|
||||
typlen = tlen(type("oid"));
|
||||
} else {
|
||||
typlen = get_typlen(atttype);
|
||||
}
|
||||
|
||||
switch (node_type) {
|
||||
case T_Const:
|
||||
{
|
||||
struct varlena *typedefault = get_typdefault(atttype);
|
||||
int temp = 0;
|
||||
Const *temp2 = (Const*)NULL;
|
||||
TargetEntry *temp3 = (TargetEntry *)NULL;
|
||||
|
||||
if (typedefault==NULL)
|
||||
temp = 0;
|
||||
else
|
||||
temp = typlen;
|
||||
|
||||
temp2 = makeConst (atttype,
|
||||
temp,
|
||||
(Datum)typedefault,
|
||||
(typedefault == (struct varlena *)NULL),
|
||||
/* XXX this is bullshit */
|
||||
false,
|
||||
false /* not a set */);
|
||||
|
||||
temp3 = MakeTLE (makeResdom(attno,
|
||||
atttype,
|
||||
typlen,
|
||||
attname,
|
||||
0,
|
||||
(Oid)0,
|
||||
0),
|
||||
(Node*)temp2);
|
||||
t_list = lappend(t_list,temp3);
|
||||
break;
|
||||
}
|
||||
case T_Var:
|
||||
{
|
||||
Var *temp_var = (Var*)NULL;
|
||||
TargetEntry *temp_list = NULL;
|
||||
|
||||
temp_var =
|
||||
makeVar(rt_index, attno, atttype, rt_index, attno);
|
||||
|
||||
temp_list = MakeTLE(makeResdom(attno,
|
||||
atttype,
|
||||
typlen,
|
||||
attname,
|
||||
0,
|
||||
(Oid)0,
|
||||
0),
|
||||
(Node*)temp_var);
|
||||
t_list = lappend(t_list,temp_list);
|
||||
break;
|
||||
}
|
||||
default: /* do nothing */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(t_list);
|
||||
}
|
||||
|
||||
|
||||
400
src/backend/optimizer/prep/prepunion.c
Normal file
400
src/backend/optimizer/prep/prepunion.c
Normal file
@@ -0,0 +1,400 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* prepunion.c--
|
||||
* Routines to plan archive, inheritance, union, and version queries
|
||||
*
|
||||
* Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.1.1.1 1996/07/09 06:21:38 scrappy Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "nodes/nodes.h"
|
||||
#include "nodes/pg_list.h"
|
||||
#include "nodes/execnodes.h"
|
||||
#include "nodes/plannodes.h"
|
||||
#include "nodes/relation.h"
|
||||
|
||||
#include "parser/parse_query.h"
|
||||
#include "parser/parsetree.h"
|
||||
|
||||
#include "utils/elog.h"
|
||||
#include "utils/lsyscache.h"
|
||||
|
||||
#include "optimizer/internal.h"
|
||||
#include "optimizer/prep.h"
|
||||
#include "optimizer/plancat.h"
|
||||
#include "optimizer/planner.h"
|
||||
#include "optimizer/prep.h"
|
||||
|
||||
static List *plan_union_query(List *relids, Index rt_index,
|
||||
RangeTblEntry *rt_entry, Query *parse, UnionFlag flag,
|
||||
List **union_rtentriesPtr);
|
||||
static RangeTblEntry *new_rangetable_entry(Oid new_relid,
|
||||
RangeTblEntry *old_entry);
|
||||
static Query *subst_rangetable(Query *root, Index index,
|
||||
RangeTblEntry *new_entry);
|
||||
static void fix_parsetree_attnums(Index rt_index, Oid old_relid,
|
||||
Oid new_relid, Query *parsetree);
|
||||
static Append *make_append(List *unionplans, Index rt_index,
|
||||
List *union_rt_entries, List *tlist);
|
||||
|
||||
|
||||
/*
|
||||
* find-all-inheritors -
|
||||
* Returns a list of relids corresponding to relations that inherit
|
||||
* attributes from any relations listed in either of the argument relid
|
||||
* lists.
|
||||
*/
|
||||
List *
|
||||
find_all_inheritors(List *unexamined_relids,
|
||||
List *examined_relids)
|
||||
{
|
||||
List *new_inheritors = NIL;
|
||||
List *new_examined_relids = NIL;
|
||||
List *new_unexamined_relids = NIL;
|
||||
|
||||
/* Find all relations which inherit from members of
|
||||
* 'unexamined-relids' and store them in 'new-inheritors'.
|
||||
*/
|
||||
List *rels = NIL;
|
||||
List *newrels = NIL;
|
||||
|
||||
foreach(rels,unexamined_relids) {
|
||||
newrels = (List*)LispUnioni(find_inheritance_children(lfirsti(rels)),
|
||||
newrels);
|
||||
}
|
||||
new_inheritors = newrels;
|
||||
|
||||
new_examined_relids = (List*)LispUnioni(examined_relids,unexamined_relids);
|
||||
new_unexamined_relids = set_differencei(new_inheritors,
|
||||
new_examined_relids);
|
||||
|
||||
if (new_unexamined_relids==NULL) {
|
||||
return(new_examined_relids);
|
||||
} else {
|
||||
return (find_all_inheritors (new_unexamined_relids,
|
||||
new_examined_relids));
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* first-matching-rt-entry -
|
||||
* Given a rangetable, find the first rangetable entry that represents
|
||||
* the appropriate special case.
|
||||
*
|
||||
* Returns a rangetable index., Returns -1 if no matches
|
||||
*/
|
||||
int
|
||||
first_matching_rt_entry (List *rangetable, UnionFlag flag)
|
||||
{
|
||||
int count = 0;
|
||||
List *temp = NIL;
|
||||
|
||||
foreach(temp, rangetable) {
|
||||
RangeTblEntry *rt_entry = lfirst(temp);
|
||||
|
||||
switch(flag) {
|
||||
case INHERITS_FLAG:
|
||||
if (rt_entry->inh)
|
||||
return count+1;
|
||||
break;
|
||||
case ARCHIVE_FLAG:
|
||||
if (rt_entry->archive)
|
||||
return count+1;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
|
||||
return(-1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* plan-union-queries--
|
||||
*
|
||||
* Plans the queries for a given parent relation.
|
||||
*
|
||||
* Returns a list containing a list of plans and a list of rangetable
|
||||
* entries to be inserted into an APPEND node.
|
||||
* XXX - what exactly does this mean, look for make_append
|
||||
*/
|
||||
Append *
|
||||
plan_union_queries(Index rt_index,
|
||||
Query *parse,
|
||||
UnionFlag flag)
|
||||
{
|
||||
List *rangetable = parse->rtable;
|
||||
RangeTblEntry *rt_entry = rt_fetch(rt_index,rangetable);
|
||||
List *union_relids = NIL;
|
||||
List *union_plans = NIL;
|
||||
List *union_rt_entries = NIL;
|
||||
|
||||
switch (flag) {
|
||||
case INHERITS_FLAG:
|
||||
union_relids =
|
||||
find_all_inheritors(lconsi(rt_entry->relid,
|
||||
NIL),
|
||||
NIL);
|
||||
break;
|
||||
|
||||
#if 0
|
||||
case UNION_FLAG:
|
||||
{
|
||||
Index rt_index = 0;
|
||||
union_plans = handleunion(root,rangetable,tlist,qual);
|
||||
return (make_append (union_plans,
|
||||
rt_index, rangetable,
|
||||
((Plan*)lfirst(union_plans))->targetlist ));
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
||||
case VERSION_FLAG:
|
||||
union_relids = VersionGetParents(rt_entry->relid);
|
||||
break;
|
||||
|
||||
case ARCHIVE_FLAG:
|
||||
union_relids = find_archive_rels(rt_entry->relid);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* do nothing */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Remove the flag for this relation, since we're about to handle it
|
||||
* (do it before recursing!).
|
||||
* XXX destructive parse tree change
|
||||
*/
|
||||
switch(flag) {
|
||||
case INHERITS_FLAG:
|
||||
rt_fetch(rt_index,rangetable)->inh = false;
|
||||
break;
|
||||
case ARCHIVE_FLAG:
|
||||
rt_fetch(rt_index,rangetable)->archive = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
/* XXX - can't find any reason to sort union-relids
|
||||
* as paul did, so we're leaving it out for now
|
||||
* (maybe forever) - jeff & lp
|
||||
*
|
||||
* [maybe so. btw, jeff & lp did the lisp conversion, according to Paul.
|
||||
* -- ay 10/94.]
|
||||
*/
|
||||
union_plans = plan_union_query(union_relids, rt_index, rt_entry,
|
||||
parse, flag, &union_rt_entries);
|
||||
|
||||
return (make_append(union_plans,
|
||||
rt_index,
|
||||
union_rt_entries,
|
||||
((Plan*)lfirst(union_plans))->targetlist));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* plan-union-query--
|
||||
* Returns a list of plans for 'relids' and a list of range table entries
|
||||
* in union_rtentries.
|
||||
*/
|
||||
static List *
|
||||
plan_union_query(List *relids,
|
||||
Index rt_index,
|
||||
RangeTblEntry *rt_entry,
|
||||
Query *root,
|
||||
UnionFlag flag,
|
||||
List **union_rtentriesPtr)
|
||||
{
|
||||
List *i;
|
||||
List *union_plans = NIL;
|
||||
List *union_rtentries = NIL;
|
||||
|
||||
foreach (i, relids) {
|
||||
int relid = lfirsti(i);
|
||||
RangeTblEntry *new_rt_entry = new_rangetable_entry(relid,
|
||||
rt_entry);
|
||||
Query *new_root = subst_rangetable(root,
|
||||
rt_index,
|
||||
new_rt_entry);
|
||||
|
||||
/* reset the uniqueflag and sortclause in parse tree root, so that
|
||||
* sorting will only be done once after append
|
||||
*/
|
||||
/* new_root->uniqueFlag = false; */
|
||||
new_root->uniqueFlag = NULL;
|
||||
new_root->sortClause = NULL;
|
||||
if (flag == ARCHIVE_FLAG) {
|
||||
/*
|
||||
* the entire union query uses the same (most recent) schema.
|
||||
* to do otherwise would require either ragged tuples or careful
|
||||
* archiving and interpretation of pg_attribute...
|
||||
*/
|
||||
} else {
|
||||
fix_parsetree_attnums(rt_index,
|
||||
rt_entry->relid,
|
||||
relid,
|
||||
new_root);
|
||||
}
|
||||
|
||||
union_plans = lappend(union_plans, planner(new_root));
|
||||
union_rtentries = lappend(union_rtentries, new_rt_entry);
|
||||
}
|
||||
|
||||
*union_rtentriesPtr = union_rtentries;
|
||||
return(union_plans);
|
||||
}
|
||||
|
||||
/*
|
||||
* new-rangetable-entry -
|
||||
* Replaces the name and relid of 'old-entry' with the values for
|
||||
* 'new-relid'.
|
||||
*
|
||||
* Returns a copy of 'old-entry' with the parameters substituted.
|
||||
*/
|
||||
static RangeTblEntry *
|
||||
new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry)
|
||||
{
|
||||
RangeTblEntry *new_entry = copyObject(old_entry);
|
||||
|
||||
/* ??? someone tell me what the following is doing! - ay 11/94 */
|
||||
if (!strcmp(new_entry->refname, "*CURRENT*") ||
|
||||
!strcmp(new_entry->refname, "*NEW*"))
|
||||
new_entry->refname = get_rel_name(new_relid);
|
||||
else
|
||||
new_entry->relname = get_rel_name(new_relid);
|
||||
|
||||
new_entry->relid = new_relid;
|
||||
return(new_entry);
|
||||
}
|
||||
|
||||
/*
|
||||
* subst-rangetable--
|
||||
* Replaces the 'index'th rangetable entry in 'root' with 'new-entry'.
|
||||
*
|
||||
* Returns a new copy of 'root'.
|
||||
*/
|
||||
static Query *
|
||||
subst_rangetable(Query *root, Index index, RangeTblEntry *new_entry)
|
||||
{
|
||||
Query *new_root = copyObject(root);
|
||||
List *temp = NIL;
|
||||
int i = 0;
|
||||
|
||||
for(temp = new_root->rtable,i =1; i < index; temp =lnext(temp),i++)
|
||||
;
|
||||
lfirst(temp) = new_entry;
|
||||
|
||||
return (new_root);
|
||||
}
|
||||
|
||||
static void
|
||||
fix_parsetree_attnums_nodes(Index rt_index,
|
||||
Oid old_relid,
|
||||
Oid new_relid,
|
||||
Node *node)
|
||||
{
|
||||
if (node==NULL)
|
||||
return;
|
||||
|
||||
switch(nodeTag(node)) {
|
||||
case T_TargetEntry:
|
||||
{
|
||||
TargetEntry *tle = (TargetEntry *)node;
|
||||
|
||||
fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
|
||||
tle->expr);
|
||||
}
|
||||
break;
|
||||
case T_Expr:
|
||||
{
|
||||
Expr *expr = (Expr *)node;
|
||||
fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
|
||||
(Node*)expr->args);
|
||||
}
|
||||
break;
|
||||
case T_Var:
|
||||
{
|
||||
Var *var = (Var *)node;
|
||||
Oid old_typeid, new_typeid;
|
||||
|
||||
/* old_typeid = RelationIdGetTypeId(old_relid);*/
|
||||
/* new_typeid = RelationIdGetTypeId(new_relid);*/
|
||||
old_typeid = old_relid;
|
||||
new_typeid = new_relid;
|
||||
|
||||
if (var->varno == rt_index && var->varattno != 0) {
|
||||
var->varattno =
|
||||
get_attnum(new_typeid,
|
||||
get_attname(old_typeid, var->varattno));
|
||||
}
|
||||
}
|
||||
break;
|
||||
case T_List:
|
||||
{
|
||||
List *l;
|
||||
foreach(l, (List*)node) {
|
||||
fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
|
||||
(Node*)lfirst(l));
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* fix-parsetree-attnums--
|
||||
* Replaces attribute numbers from the relation represented by
|
||||
* 'old-relid' in 'parsetree' with the attribute numbers from
|
||||
* 'new-relid'.
|
||||
*
|
||||
* Returns the destructively-modified parsetree.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
fix_parsetree_attnums(Index rt_index,
|
||||
Oid old_relid,
|
||||
Oid new_relid,
|
||||
Query *parsetree)
|
||||
{
|
||||
if (old_relid == new_relid)
|
||||
return;
|
||||
|
||||
fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
|
||||
(Node*)parsetree->targetList);
|
||||
fix_parsetree_attnums_nodes(rt_index, old_relid, new_relid,
|
||||
parsetree->qual);
|
||||
}
|
||||
|
||||
static Append *
|
||||
make_append(List *unionplans,
|
||||
Index rt_index,
|
||||
List *union_rt_entries,
|
||||
List *tlist)
|
||||
{
|
||||
Append *node = makeNode(Append);
|
||||
|
||||
node->unionplans = unionplans;
|
||||
node->unionrelid = rt_index;
|
||||
node->unionrtentries = union_rt_entries;
|
||||
node->plan.cost = 0.0;
|
||||
node->plan.state = (EState*)NULL;
|
||||
node->plan.targetlist = tlist;
|
||||
node->plan.qual = NIL;
|
||||
node->plan.lefttree = (Plan*)NULL;
|
||||
node->plan.righttree = (Plan*)NULL;
|
||||
|
||||
return(node);
|
||||
}
|
||||
Reference in New Issue
Block a user