*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.7 1996/10/14 03:53:53 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.8 1996/10/30 02:01:51 momjian Exp $
*
*-------------------------------------------------------------------------
*/
static void makeRangeTable(ParseState *pstate, char *relname, List *frmList);
static List *expandAllTables(ParseState *pstate);
static char *figureColname(Node *expr, Node *resval);
-static List *makeTargetList(ParseState *pstate, List *cols, List *exprs);
-static List *transformTargetList(ParseState *pstate,
- List *targetlist, bool isInsert,
- bool isUpdate);
+static List *makeTargetNames(ParseState *pstate, List *cols);
+static List *transformTargetList(ParseState *pstate, List *targetlist);
static TargetEntry *make_targetlist_expr(ParseState *pstate,
- char *name, Node *expr,
- List *arrayRef,
- bool ResdomNoIsAttrNo);
+ char *colname, Node *expr,
+ List *arrayRef);
static Node *transformWhereClause(ParseState *pstate, Node *a_expr);
static List *transformGroupClause(ParseState *pstate, List *grouplist);
static List *transformSortClause(ParseState *pstate,
static void parseFromClause(ParseState *pstate, List *frmList);
static Node *ParseFunc(ParseState *pstate, char *funcname,
List *fargs, int *curr_resno);
-static char *ParseColumnName(ParseState *pstate, char *name, bool *isRelName);
static List *setup_tlist(char *attname, Oid relid);
static List *setup_base_tlist(Oid typeid);
-static void make_arguments(int nargs, List *fargs, Oid *input_typeids, Oid *function_typeids);
+static void make_arguments(int nargs, List *fargs, Oid *input_typeids,
+ Oid *function_typeids);
static void AddAggToParseState(ParseState *pstate, Aggreg *aggreg);
static void finalizeAggregates(ParseState *pstate, Query *qry);
static void parseCheckAggregates(ParseState *pstate, Query *qry);
pstate = malloc(sizeof(ParseState));
pstate->p_last_resno = 1;
- pstate->p_target_resnos = NIL;
- pstate->p_current_rel = NULL;
pstate->p_rtable = NIL;
- pstate->p_query_is_rule = 0;
pstate->p_numAgg = 0;
pstate->p_aggs = NIL;
+ pstate->p_is_insert = false;
+ pstate->p_insert_columns = NIL;
+ pstate->p_is_update = false;
+ pstate->p_is_rule = false;
+ pstate->p_target_relation = NULL;
+ pstate->p_target_rangetblentry = NULL;
return (pstate);
}
+
/*
* parse_analyze -
* analyze a list of parse trees and transform them if necessary.
pstate = makeParseState();
result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
pl = lnext(pl);
- if (pstate->p_current_rel != NULL)
- heap_close(pstate->p_current_rel);
+ if (pstate->p_target_relation != NULL)
+ heap_close(pstate->p_target_relation);
free(pstate);
}
/* set up a range table */
makeRangeTable(pstate, stmt->relname, NULL);
-/* qry->uniqueFlag = FALSE; */
qry->uniqueFlag = NULL;
/* fix where clause */
qry->qual = transformWhereClause(pstate, stmt->whereClause);
qry->rtable = pstate->p_rtable;
- qry->resultRelation = RangeTablePosn(pstate->p_rtable, stmt->relname);
+ qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
/* make sure we don't have aggregates in the where clause */
if (pstate->p_numAgg > 0)
List *targetlist;
qry->commandType = CMD_INSERT;
+ pstate->p_is_insert = true;
/* set up a range table */
makeRangeTable(pstate, stmt->relname, stmt->fromClause);
-/* qry->uniqueFlag = FALSE; */
qry->uniqueFlag = NULL;
/* fix the target list */
- targetlist = makeTargetList(pstate, stmt->cols, stmt->exprs);
- qry->targetList = transformTargetList(pstate,
- targetlist,
- TRUE /* is insert */,
- FALSE /*not update*/);
+ pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
+
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
/* fix where clause */
qry->qual = transformWhereClause(pstate, stmt->whereClause);
/* now the range table will not change */
qry->rtable = pstate->p_rtable;
- qry->resultRelation = RangeTablePosn(pstate->p_rtable, stmt->relname);
+ qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
if (pstate->p_numAgg > 0)
finalizeAggregates(pstate, qry);
* transform each statment, like parse_analyze()
*/
while (actions != NIL) {
- RangeTblEntry *curEnt, *newEnt;
-
/*
* NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
* equal to 2.
*/
- curEnt = makeRangeTableEntry(stmt->object->relname, FALSE,
- NULL, "*CURRENT*");
- newEnt = makeRangeTableEntry(stmt->object->relname, FALSE,
- NULL, "*NEW*");
- pstate->p_rtable = makeList(curEnt, newEnt, -1);
+ addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
+ FALSE, FALSE, NULL);
+ addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
+ FALSE, FALSE, NULL);
pstate->p_last_resno = 1;
- pstate->p_target_resnos = NIL;
- pstate->p_query_is_rule = 1; /* for expand all */
+ pstate->p_is_rule = true; /* for expand all */
pstate->p_numAgg = 0;
pstate->p_aggs = NULL;
qry->isPortal = FALSE;
/* fix the target list */
- qry->targetList = transformTargetList(pstate,
- stmt->targetList,
- FALSE, /*is insert */
- FALSE /*not update*/);
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
/* fix where clause */
qry->qual = transformWhereClause(pstate,stmt->whereClause);
Query *qry = makeNode(Query);
qry->commandType = CMD_UPDATE;
-
+ pstate->p_is_update = true;
/*
* the FROM clause is non-standard SQL syntax. We used to be able to
* do this with REPLACE in POSTQUEL so we keep the feature.
makeRangeTable(pstate, stmt->relname, stmt->fromClause);
/* fix the target list */
- qry->targetList = transformTargetList(pstate,
- stmt->targetList,
- FALSE, /* not insert */
- TRUE /* is update */);
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
/* fix where clause */
qry->qual = transformWhereClause(pstate,stmt->whereClause);
qry->rtable = pstate->p_rtable;
- qry->resultRelation = RangeTablePosn(pstate->p_rtable, stmt->relname);
+ qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
/* make sure we don't have aggregates in the where clause */
if (pstate->p_numAgg > 0)
qry->isBinary = stmt->binary; /* internal portal */
/* fix the target list */
- qry->targetList = transformTargetList(pstate,
- stmt->targetList,
- FALSE, /*is insert */
- FALSE /*not update*/);
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
/* fix where clause */
qry->qual = transformWhereClause(pstate,stmt->whereClause);
}
case T_Ident: {
Ident *ident = (Ident*)expr;
- bool isrel;
- char *reln= ParseColumnName(pstate,ident->name, &isrel);
+ RangeTblEntry *rte;
- /* could be a column name or a relation_name */
- if (reln==NULL) {
- /*
- * may be a relation_name
- *
- * ??? in fact, every ident left after transfromExpr() is called
- * will be assumed to be a relation.
- */
- if (isrel) {
+ /* could be a column name or a relation_name */
+ if (refnameRangeTableEntry(pstate->p_rtable, ident->name) != NULL) {
ident->isRel = TRUE;
result = (Node*)ident;
- } else {
- elog(WARN, "attribute \"%s\" not found", ident->name);
- }
- }else {
+ }
+ else if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL)
+ {
Attr *att = makeNode(Attr);
- att->relname = reln;
+
+ att->relname = rte->refname;
att->attrs = lcons(makeString(ident->name), NIL);
- /*
- * a column name
- */
result =
(Node*)handleNestedDots(pstate, att, &pstate->p_last_resno);
- }
+ } else
+ elog(WARN, "attribute \"%s\" not found", ident->name);
break;
}
case T_FuncCall: {
List *args;
/* transform the list of arguments */
- foreach(args, fn->args) {
+ foreach(args, fn->args)
lfirst(args) = transformExpr(pstate, (Node*)lfirst(args));
- }
result = ParseFunc(pstate,
fn->funcname, fn->args, &pstate->p_last_resno);
break;
static void
parseFromClause(ParseState *pstate, List *frmList)
{
- List *fl= frmList;
+ List *fl;
- while(fl!=NIL) {
+ foreach(fl, frmList)
+ {
RangeVar *r = lfirst(fl);
RelExpr *baserel = r->relExpr;
- RangeTblEntry *ent;
char *relname = baserel->relname;
char *refname = r->name;
-
- if (refname==NULL) {
+ RangeTblEntry *rte;
+
+ if (refname==NULL)
refname = relname;
- } else {
- /*
- * check whether refname exists already
- */
- if (RangeTablePosn(pstate->p_rtable, refname) != 0)
- elog(WARN, "parser: range variable \"%s\" duplicated",
- refname);
- }
- ent = makeRangeTableEntry(relname, baserel->inh,
- baserel->timeRange, refname);
/*
- * marks this entry to indicate it comes from the from clause. In
+ * marks this entry to indicate it comes from the FROM clause. In
* SQL, the target list can only refer to range variables specified
* in the from clause but we follow the more powerful POSTQUEL
* semantics and automatically generate the range variable if not
* eg. select * from foo f where f.x = 1; will generate wrong answer
* if we expand * to foo.x.
*/
- ent->inFromCl = true;
-
- pstate->p_rtable = lappend(pstate->p_rtable, ent);
- fl= lnext(fl);
+ rte = addRangeTableEntry(pstate, relname, refname, baserel->inh, TRUE,
+ baserel->timeRange);
}
}
static void
makeRangeTable(ParseState *pstate, char *relname, List *frmList)
{
- int x;
+ RangeTblEntry *rte;
parseFromClause(pstate, frmList);
if (relname == NULL)
return;
- if (RangeTablePosn(pstate->p_rtable, relname) < 1) {
- RangeTblEntry *ent;
-
- ent = makeRangeTableEntry(relname, FALSE, NULL, relname);
- pstate->p_rtable = lappend(pstate->p_rtable, ent);
- }
- x = RangeTablePosn(pstate->p_rtable, relname);
- if (pstate->p_current_rel != NULL)
- heap_close(pstate->p_current_rel);
- pstate->p_current_rel = heap_openr(VarnoGetRelname(pstate,x));
- if (pstate->p_current_rel == NULL)
- elog(WARN,"invalid relation name");
+ if (refnameRangeTablePosn(pstate->p_rtable, relname) < 1)
+ rte = addRangeTableEntry(pstate, relname, relname, FALSE, FALSE, NULL);
+ else
+ rte = refnameRangeTableEntry(pstate->p_rtable, relname);
+
+ pstate->p_target_rangetblentry = rte;
+ Assert(pstate->p_target_relation == NULL);
+ pstate->p_target_relation = heap_open(rte->relid);
+ Assert(pstate->p_target_relation != NULL);
+ /* will close relation later */
}
/*
List *rt, *rtable;
rtable = pstate->p_rtable;
- if (pstate->p_query_is_rule) {
+ if (pstate->p_is_rule) {
/*
* skip first two entries, "*new*" and "*current*"
*/
foreach(rt, legit_rtable) {
RangeTblEntry *rte = lfirst(rt);
- char *rt_name= rte->refname; /* use refname here so that we
- refer to the right entry */
List *temp = target;
if(temp == NIL )
- target = expandAll(pstate, rt_name, &pstate->p_last_resno);
+ target = expandAll(pstate, rte->relname, rte->refname,
+ &pstate->p_last_resno);
else {
while (temp != NIL && lnext(temp) != NIL)
temp = lnext(temp);
- lnext(temp) = expandAll(pstate, rt_name, &pstate->p_last_resno);
+ lnext(temp) = expandAll(pstate, rte->relname, rte->refname,
+ &pstate->p_last_resno);
}
}
return target;
*****************************************************************************/
/*
- * makeTargetList -
- * turn a list of column names and expressions (in the same order) into
- * a target list (used exclusively for inserts)
+ * makeTargetNames -
+ * generate a list of column names if not supplied or
+ * test supplied column names to make sure they are in target table
+ * (used exclusively for inserts)
*/
static List *
-makeTargetList(ParseState *pstate, List *cols, List *exprs)
+makeTargetNames(ParseState *pstate, List *cols)
{
- List *tlist, *tl=NULL;
- if (cols != NIL) {
- /* has to transform colElem too (opt_indirection can be exprs) */
- while(cols!=NIL) {
- ResTarget *res = makeNode(ResTarget);
- Ident *id = lfirst(cols);
- /* Id opt_indirection */
- res->name = id->name;
- res->indirection = id->indirection;
- if (exprs == NIL) {
- elog(WARN, "insert: number of expressions less than columns");
- }else {
- res->val = (Node *)lfirst(exprs);
- }
- if (tl==NIL) {
- tlist = tl = lcons(res, NIL);
- }else {
- lnext(tl) = lcons(res,NIL);
- tl = lnext(tl);
- }
- cols = lnext(cols);
- exprs = lnext(exprs);
- }
- if (cols != NIL) {
- elog(WARN, "insert: number of columns more than expressions");
- }
- }else {
- bool has_star = false;
+ List *tl=NULL;
+
+ /* Generate ResTarget if not supplied */
+
+ if (cols == NIL) {
+ int numcol;
+ int i;
+ AttributeTupleForm *attr = pstate->p_target_relation->rd_att->attrs;
- if (exprs==NIL)
- return NIL;
- if (IsA(lfirst(exprs),Attr)) {
- Attr *att = lfirst(exprs);
-
- if ((att->relname!=NULL && !strcmp(att->relname,"*")) ||
- (att->attrs!=NIL && !strcmp(strVal(lfirst(att->attrs)),"*")))
- has_star = true;
- }
- if (has_star) {
- /*
- * right now, these better be 'relname.*' or '*' (this can happen
- * in eg. insert into tenk2 values (tenk1.*); or
- * insert into tenk2 select * from tenk1;
- */
- while(exprs!=NIL) {
- ResTarget *res = makeNode(ResTarget);
- res->name = NULL;
- res->indirection = NULL;
- res->val = (Node *)lfirst(exprs);
- if (tl==NIL) {
- tlist = tl = lcons(res, NIL);
- }else {
- lnext(tl) = lcons(res,NIL);
- tl = lnext(tl);
- }
- exprs = lnext(exprs);
- }
- } else {
- Relation insertRel = pstate->p_current_rel;
- int numcol;
- int i;
- AttributeTupleForm *attr = insertRel->rd_att->attrs;
-
- numcol = Min(length(exprs), insertRel->rd_rel->relnatts);
- for(i=0; i < numcol; i++) {
- ResTarget *res = makeNode(ResTarget);
-
- res->name = palloc(NAMEDATALEN+1);
- strncpy(res->name, attr[i]->attname.data, NAMEDATALEN);
- res->name[NAMEDATALEN]='\0';
- res->indirection = NULL;
- res->val = (Node *)lfirst(exprs);
- if (tl==NIL) {
- tlist = tl = lcons(res, NIL);
- }else {
- lnext(tl) = lcons(res,NIL);
- tl = lnext(tl);
- }
- exprs = lnext(exprs);
+ numcol = pstate->p_target_relation->rd_rel->relnatts;
+ for(i=0; i < numcol; i++) {
+ Ident *id = makeNode(Ident);
+
+ id->name = palloc(NAMEDATALEN+1);
+ strncpy(id->name, attr[i]->attname.data, NAMEDATALEN);
+ id->name[NAMEDATALEN]='\0';
+ id->indirection = NIL;
+ id->isRel = false;
+ if (tl == NIL)
+ cols = tl = lcons(id, NIL);
+ else {
+ lnext(tl) = lcons(id,NIL);
+ tl = lnext(tl);
}
}
}
- return tlist;
+ else
+ foreach(tl, cols)
+ /* elog on failure */
+ (void)varattno(pstate->p_target_relation,((Ident *)lfirst(tl))->name);
+
+ return cols;
}
/*
* turns a list of ResTarget's into a list of TargetEntry's
*/
static List *
-transformTargetList(ParseState *pstate,
- List *targetlist,
- bool isInsert,
- bool isUpdate)
+transformTargetList(ParseState *pstate, List *targetlist)
{
List *p_target= NIL;
- List *temp = NIL;
+ List *tail_p_target = NIL;
while(targetlist != NIL) {
ResTarget *res= (ResTarget *)lfirst(targetlist);
int type_len;
char *identname;
char *resname;
-
+
identname = ((Ident*)res->val)->name;
+ handleTargetColname(pstate, &res->name, NULL, res->name);
expr = transformExpr(pstate, (Node*)res->val);
type_id = exprType(expr);
type_len = tlen(get_id_type(type_id));
case T_A_Expr: {
Node *expr = transformExpr(pstate, (Node *)res->val);
- if (isInsert && res->name==NULL)
- elog(WARN, "Sorry, have to specify the column list");
-
+ handleTargetColname(pstate, &res->name, NULL, NULL);
/* note indirection has not been transformed */
- if (isInsert && res->indirection!=NIL) {
+ if (pstate->p_is_insert && res->indirection!=NIL) {
/* this is an array assignment */
char *val;
char *str, *save_str;
i++;
}
sprintf(str, "=%s", val);
- rd = pstate->p_current_rel;
+ rd = pstate->p_target_relation;
Assert(rd != NULL);
resdomno = varattno(rd, res->name);
ndims = att_attnelems(rd, resdomno);
constval->val.str = save_str;
tent = make_targetlist_expr(pstate, res->name,
(Node*)make_const(constval),
- NULL,
- (isInsert||isUpdate));
+ NULL);
pfree(save_str);
} else {
char *colname= res->name;
ilist = lnext(ilist);
}
}
- tent = make_targetlist_expr(pstate, colname, expr,
- res->indirection,
- (isInsert||isUpdate));
+ res->name = colname;
+ tent = make_targetlist_expr(pstate, res->name, expr,
+ res->indirection);
}
break;
}
char *resname;
Resdom *resnode;
List *attrs = att->attrs;
-
/*
* Target item is a single '*', expand all tables
*/
attrname = strVal(lfirst(att->attrs));
if (att->attrs!=NIL && !strcmp(attrname,"*")) {
- /* temp is the target list we're building in the while
+ /* tail_p_target is the target list we're building in the while
* loop. Make sure we fix it after appending more nodes.
*/
- if (temp == NIL) {
- p_target = temp =
- expandAll(pstate, att->relname, &pstate->p_last_resno);
+ if (tail_p_target == NIL) {
+ p_target = tail_p_target = expandAll(pstate, att->relname,
+ att->relname, &pstate->p_last_resno);
} else {
- lnext(temp) =
- expandAll(pstate, att->relname, &pstate->p_last_resno);
+ lnext(tail_p_target) =
+ expandAll(pstate, att->relname, att->relname,
+ &pstate->p_last_resno);
}
- while(lnext(temp)!=NIL)
- temp = lnext(temp); /* make sure we point to the last
- target entry */
+ while(lnext(tail_p_target)!=NIL)
+ /* make sure we point to the last target entry */
+ tail_p_target = lnext(tail_p_target);
/*
* skip the rest of the while loop
*/
* Target item is fully specified: ie. relation.attribute
*/
result = handleNestedDots(pstate, att, &pstate->p_last_resno);
+ handleTargetColname(pstate, &res->name, att->relname, attrname);
if (att->indirection != NIL) {
List *ilist = att->indirection;
while (ilist!=NIL) {
}
type_id = exprType(result);
type_len = tlen(get_id_type(type_id));
+ /* move to last entry */
while(lnext(attrs)!=NIL)
attrs=lnext(attrs);
resname = (res->name) ? res->name : strVal(lfirst(attrs));
break;
}
- if (p_target==NIL) {
- p_target = temp = lcons(tent, NIL);
+ if (p_target == NIL) {
+ p_target = tail_p_target = lcons(tent, NIL);
}else {
- lnext(temp) = lcons(tent, NIL);
- temp = lnext(temp);
+ lnext(tail_p_target) = lcons(tent, NIL);
+ tail_p_target = lnext(tail_p_target);
}
targetlist = lnext(targetlist);
}
+
return p_target;
}
/*
* make_targetlist_expr -
- * make a TargetEntry
+ * make a TargetEntry from an expression
*
* arrayRef is a list of transformed A_Indices
*/
static TargetEntry *
make_targetlist_expr(ParseState *pstate,
- char *name,
+ char *colname,
Node *expr,
- List *arrayRef,
- bool ResdomNoIsAttrNo)
+ List *arrayRef)
{
int type_id, type_len, attrtype, attrlen;
int resdomno;
type_len = tlen(get_id_type(type_id));
/* I have no idea what the following does! */
- if (ResdomNoIsAttrNo) {
+ /* It appears to process target columns that will be receiving results */
+ if (pstate->p_is_insert||pstate->p_is_update) {
/*
* append or replace query --
* append, replace work only on one relation,
* so multiple occurence of same resdomno is bogus
*/
- rd = pstate->p_current_rel;
+ rd = pstate->p_target_relation;
Assert(rd != NULL);
- resdomno = varattno(rd,name);
- attrisset = varisset(rd,name);
+ resdomno = varattno(rd,colname);
+ attrisset = varisset(rd,colname);
attrtype = att_typeid(rd,resdomno);
if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL))
attrtype = GetArrayElementType(attrtype);
lfirst(expr) = lispInteger (FLOAT4OID);
else
elog(WARN, "unequal type in tlist : %s \n",
- name));
+ colname));
}
Input_is_string = false;
Input_is_integer = false;
Typecast_ok = true;
#endif
+
if (attrtype != type_id) {
if (IsA(expr,Const)) {
/* try to cast the constant */
} else {
/* currently, we can't handle casting of expressions */
elog(WARN, "parser: attribute '%s' is of type '%.*s' but expression is of type '%.*s'",
- name,
+ colname,
NAMEDATALEN, get_id_typname(attrtype),
NAMEDATALEN, get_id_typname(type_id));
}
}
- if (intMember(resdomno, pstate->p_target_resnos)) {
- elog(WARN,"two or more occurrences of same attr");
- } else {
- pstate->p_target_resnos = lconsi(resdomno,
- pstate->p_target_resnos);
- }
if (arrayRef != NIL) {
Expr *target_expr;
Attr *att = makeNode(Attr);
List *lowerIndexpr = NIL;
att->relname = pstrdup(RelationGetRelationName(rd)->data);
- att->attrs = lcons(makeString(name), NIL);
+ att->attrs = lcons(makeString(colname), NIL);
target_expr = (Expr*)handleNestedDots(pstate, att,
&pstate->p_last_resno);
while(ar!=NIL) {
resnode = makeResdom((AttrNumber)resdomno,
(Oid) attrtype,
(Size) attrlen,
- name,
+ colname,
(Index)0,
(Oid)0,
0);
*
*/
static Resdom *
-find_tl_elt(ParseState *pstate, char *range, char *varname, List *tlist)
+find_tl_elt(ParseState *pstate, char *refname, char *colname, List *tlist)
{
List *i;
int real_rtable_pos;
- if(range) {
- real_rtable_pos = RangeTablePosn(pstate->p_rtable, range);
- }
+ if(refname)
+ real_rtable_pos = refnameRangeTablePosn(pstate->p_rtable, refname);
foreach(i, tlist) {
TargetEntry *target = (TargetEntry *)lfirst(i);
char *resname = resnode->resname;
int test_rtable_pos = var->varno;
- if (!strcmp(resname, varname)) {
- if(range) {
+ if (!strcmp(resname, colname)) {
+ if(refname) {
if(real_rtable_pos == test_rtable_pos) {
return (resnode);
}
Oid funcid = (Oid)0;
List *i = NIL;
Node *first_arg= NULL;
- char *relname, *oldname;
+ char *relname;
+ char *refname;
Relation rd;
Oid relid;
int nargs;
** type, then the function could be a projection.
*/
if (length(fargs) == 1) {
+
if (nodeTag(first_arg)==T_Ident && ((Ident*)first_arg)->isRel) {
+ RangeTblEntry *rte;
Ident *ident = (Ident*)first_arg;
/*
* first arg is a relation. This could be a projection.
*/
- relname = ident->name;
- if (RangeTablePosn(pstate->p_rtable, relname)== 0) {
- RangeTblEntry *ent;
-
- ent =
- makeRangeTableEntry(relname,
- FALSE, NULL, relname);
- pstate->p_rtable = lappend(pstate->p_rtable, ent);
- }
- oldname = relname;
- relname = VarnoGetRelname(pstate,
- RangeTablePosn(pstate->p_rtable,
- oldname));
- rd = heap_openr(relname);
- relid = RelationGetRelationId(rd);
- heap_close(rd);
+ refname = ident->name;
+
+ rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+ if (rte == NULL)
+ rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE,NULL);
+
+ relname = rte->relname;
+ relid = rte->relid;
+
/* If the attr isn't a set, just make a var for it. If
* it is a set, treat it like a function and drop through.
*/
return
((Node*)make_var(pstate,
- oldname,
+ refname,
funcname,
&dummyTypeId));
} else {
tname(get_id_type(toid)));
argrelid = typeid_get_relid(toid);
/* A projection contains either an attribute name or the
- * word "all".
+ * "*".
*/
if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)
- && strcmp(funcname, "all")) {
+ && strcmp(funcname, "*")) {
elog(WARN, "Functions on sets are not yet supported");
}
}
nargs=0;
foreach ( i , fargs ) {
int vnum;
+ RangeTblEntry *rte;
Node *pair = lfirst(i);
-
+
if (nodeTag(pair)==T_Ident && ((Ident*)pair)->isRel) {
/*
* a relation
*/
- relname = ((Ident*)pair)->name;
-
- /* get the range table entry for the var node */
- vnum = RangeTablePosn(pstate->p_rtable, relname);
- if (vnum == 0) {
- pstate->p_rtable =
- lappend(pstate->p_rtable ,
- makeRangeTableEntry(relname, FALSE,
- NULL, relname));
- vnum = RangeTablePosn (pstate->p_rtable, relname);
- }
+ refname = ((Ident*)pair)->name;
- /*
- * We have to do this because the relname in the pair
- * may have been a range table variable name, rather
- * than a real relation name.
- */
- relname = VarnoGetRelname(pstate, vnum);
-
- rd = heap_openr(relname);
- relid = RelationGetRelationId(rd);
- heap_close(rd);
-
+ rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+ if (rte == NULL)
+ rte = addRangeTableEntry(pstate, refname, refname,
+ FALSE, FALSE, NULL);
+ relname = rte->relname;
+
+ vnum = refnameRangeTablePosn (pstate->p_rtable, rte->refname);
+
/*
* for func(relname), the param to the function
* is the tuple under consideration. we build a special
* attribute of the set tuples.
*/
if (attisset) {
- if (!strcmp(funcname, "all")) {
+ if (!strcmp(funcname, "*")) {
funcnode->func_tlist =
- expandAll(pstate, (char*)relname, curr_resno);
+ expandAll(pstate, relname, refname, curr_resno);
} else {
funcnode->func_tlist = setup_tlist(funcname,argrelid);
rettype = find_atttype(argrelid, funcname);
return(retval);
}
-/*
- * returns (relname) if found, NIL if not a column
- */
-static char*
-ParseColumnName(ParseState *pstate, char *name, bool *isRelName)
-{
- List *et;
- Relation rd;
- List *rtable;
-
- /*
- * see if it is a relation name. If so, leave it as it is
- */
- if (RangeTablePosn(pstate->p_rtable, name)!=0) {
- *isRelName = TRUE;
- return NULL;
- }
-
- if (pstate->p_query_is_rule) {
- rtable = lnext(lnext(pstate->p_rtable));
- } else {
- rtable = pstate->p_rtable;
- }
- /*
- * search each relation in the FROM list and see if we have a match
- */
- foreach(et, rtable) {
- RangeTblEntry *rte = lfirst(et);
- char *relname= rte->relname;
- char *refname= rte->refname;
- Oid relid;
-
- rd= heap_openr(relname);
- relid = RelationGetRelationId(rd);
- heap_close(rd);
- if (get_attnum(relid, name) != InvalidAttrNumber) {
- /* found */
- *isRelName = FALSE;
- return refname;
- }
-
- }
-
- /* attribute not found */
- *isRelName = FALSE;
- return NULL;
-}
-
-
/*****************************************************************************
*
*****************************************************************************/
qry->qry_aggs =
(Aggreg **)palloc(sizeof(Aggreg *) * qry->qry_numAgg);
i = 0;
- foreach(l, pstate->p_aggs) {
+ foreach(l, pstate->p_aggs)
qry->qry_aggs[i++] = (Aggreg*)lfirst(l);
- }
}
/*
else if (or_clause(clause)) {
List *temp;
- foreach (temp, ((Expr*)clause)->args) {
+ foreach (temp, ((Expr*)clause)->args)
if (contain_agg_clause(lfirst(temp)))
return TRUE;
- }
return FALSE;
} else if (is_funcclause (clause)) {
List *temp;
- foreach(temp, ((Expr *)clause)->args) {
+ foreach(temp, ((Expr *)clause)->args)
if (contain_agg_clause(lfirst(temp)))
return TRUE;
- }
return FALSE;
} else if (IsA(clause,ArrayRef)) {
List *temp;
- foreach(temp, ((ArrayRef*)clause)->refupperindexpr) {
+ foreach(temp, ((ArrayRef*)clause)->refupperindexpr)
if (contain_agg_clause(lfirst(temp)))
return TRUE;
- }
- foreach(temp, ((ArrayRef*)clause)->reflowerindexpr) {
+ foreach(temp, ((ArrayRef*)clause)->reflowerindexpr)
if (contain_agg_clause(lfirst(temp)))
return TRUE;
- }
if (contain_agg_clause(((ArrayRef*)clause)->refexpr))
return TRUE;
if (contain_agg_clause(((ArrayRef*)clause)->refassgnexpr))
else if (IsA(expr,Expr)) {
List *temp;
- foreach (temp, ((Expr*)expr)->args) {
+ foreach (temp, ((Expr*)expr)->args)
if (!exprIsAggOrGroupCol(lfirst(temp),groupClause))
return FALSE;
- }
return TRUE;
}
return;
}
-
-
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.4 1996/08/28 22:50:24 scrappy Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.5 1996/10/30 02:01:59 momjian Exp $
*
*-------------------------------------------------------------------------
*/
Oid *param_type_info;
int pfunc_num_args;
-extern int Quiet;
+/* given refname, return a pointer to the range table entry */
+RangeTblEntry *
+refnameRangeTableEntry(List *rtable, char *refname)
+{
+ List *temp;
+
+ foreach(temp, rtable) {
+ RangeTblEntry *rte = lfirst(temp);
+ if (!strcmp(rte->refname, refname))
+ return rte;
+ }
+ return NULL;
+}
-/* given range variable, return id of variable; position starts with 1 */
+/* given refname, return id of variable; position starts with 1 */
int
-RangeTablePosn(List *rtable, char *rangevar)
+refnameRangeTablePosn(List *rtable, char *refname)
{
int index;
List *temp;
index = 1;
-/* temp = pstate->p_rtable; */
- temp = rtable;
- while (temp != NIL) {
- RangeTblEntry *rt_entry = lfirst(temp);
+ foreach(temp, rtable) {
+ RangeTblEntry *rte = lfirst(temp);
- if (!strcmp(rt_entry->refname, rangevar))
+ if (!strcmp(rte->refname, refname))
return index;
-
- temp = lnext(temp);
index++;
}
return(0);
}
-char*
-VarnoGetRelname(ParseState *pstate, int vnum)
+/*
+ * returns range entry if found, else NULL
+ */
+RangeTblEntry *
+colnameRangeTableEntry(ParseState *pstate, char *colname)
{
- int i;
- List *temp = pstate->p_rtable;
- for( i = 1; i < vnum ; i++)
- temp = lnext(temp);
- return(((RangeTblEntry*)lfirst(temp))->relname);
+ List *et;
+ List *rtable;
+ RangeTblEntry *rte_result;
+
+ if (pstate->p_is_rule)
+ rtable = lnext(lnext(pstate->p_rtable));
+ else
+ rtable = pstate->p_rtable;
+
+ rte_result = NULL;
+ foreach(et, rtable) {
+ RangeTblEntry *rte = lfirst(et);
+
+ /* only entries on outer(non-function?) scope */
+ if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
+ continue;
+
+ if (get_attnum(rte->relid, colname) != InvalidAttrNumber) {
+ if (rte_result != NULL) {
+ if (!pstate->p_is_insert ||
+ rte != pstate->p_target_rangetblentry)
+ elog(WARN, "Column %s is ambiguous", colname);
+ }
+ else rte_result = rte;
+ }
+ }
+ return rte_result;
}
-
+/*
+ * put new entry in pstate p_rtable structure, or return pointer
+ * if pstate null
+*/
RangeTblEntry *
-makeRangeTableEntry(char *relname,
- bool inh,
- TimeRange *timeRange,
- char *refname)
+addRangeTableEntry(ParseState *pstate,
+ char *relname,
+ char *refname,
+ bool inh, bool inFromCl,
+ TimeRange *timeRange)
{
Relation relation;
- RangeTblEntry *ent = makeNode(RangeTblEntry);
+ RangeTblEntry *rte = makeNode(RangeTblEntry);
- ent->relname = pstrdup(relname);
- ent->refname = refname;
+ if (pstate != NULL &&
+ refnameRangeTableEntry(pstate->p_rtable, refname) != NULL)
+ elog(WARN,"Table name %s specified more than once",refname);
+
+ rte->relname = pstrdup(relname);
+ rte->refname = pstrdup(refname);
- relation = heap_openr(ent->relname);
+ relation = heap_openr(relname);
if (relation == NULL) {
elog(WARN,"%s: %s",
relname, ACL_NO_PRIV_WARNING);
* or recursive (transitive closure)
* [we don't support them all -- ay 9/94 ]
*/
- ent->inh = inh;
+ rte->inh = inh;
- ent->timeRange = timeRange;
+ rte->timeRange = timeRange;
/* RelOID */
- ent->relid = RelationGetRelationId(relation);
+ rte->relid = RelationGetRelationId(relation);
+
+ rte->archive = false;
+
+ rte->inFromCl = inFromCl;
/*
* close the relation we're done with it for now.
*/
+ if (pstate != NULL)
+ pstate->p_rtable = lappend(pstate->p_rtable, rte);
+
heap_close(relation);
- return ent;
+
+ return rte;
}
/*
* assumes reldesc caching works
*/
List *
-expandAll(ParseState* pstate, char *relname, int *this_resno)
+expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
{
Relation rdesc;
- List *tall = NIL;
+ List *te_tail = NIL, *te_head = NIL;
Var *varnode;
- int i, maxattrs, first_resno;
- int type_id, type_len, vnum;
- char *physical_relname;
-
- first_resno = *this_resno;
-
- /* printf("\nExpanding %.*s.all\n", NAMEDATALEN, relname); */
- vnum = RangeTablePosn(pstate->p_rtable, relname);
- if ( vnum == 0 ) {
- pstate->p_rtable = lappend(pstate->p_rtable,
- makeRangeTableEntry(relname, FALSE, NULL,
- relname));
- vnum = RangeTablePosn(pstate->p_rtable, relname);
- }
-
- physical_relname = VarnoGetRelname(pstate, vnum);
+ int varattno, maxattrs;
+ int type_id, type_len;
+ RangeTblEntry *rte;
+
+ rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+ if (rte == NULL)
+ rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE, NULL);
- rdesc = heap_openr(physical_relname);
+ rdesc = heap_open(rte->relid);
if (rdesc == NULL ) {
- elog(WARN,"Unable to expand all -- heap_openr failed on %s",
- physical_relname);
+ elog(WARN,"Unable to expand all -- heap_open failed on %s",
+ rte->refname);
return NIL;
}
maxattrs = RelationGetNumberOfAttributes(rdesc);
- for ( i = maxattrs-1 ; i > -1 ; --i ) {
+ for ( varattno = 0; varattno <= maxattrs-1 ; varattno++ ) {
char *attrname;
- TargetEntry *rte = makeNode(TargetEntry);
+ char *resname = NULL;
+ TargetEntry *te = makeNode(TargetEntry);
- attrname = pstrdup ((rdesc->rd_att->attrs[i]->attname).data);
- varnode = (Var*)make_var(pstate, relname, attrname, &type_id);
+ attrname = pstrdup ((rdesc->rd_att->attrs[varattno]->attname).data);
+ varnode = (Var*)make_var(pstate, refname, attrname, &type_id);
type_len = (int)tlen(get_id_type(type_id));
+ handleTargetColname(pstate, &resname, refname, attrname);
+ if (resname != NULL)
+ attrname = resname;
+
/* Even if the elements making up a set are complex, the
* set itself is not. */
- rte->resdom = makeResdom((AttrNumber) i + first_resno,
+ te->resdom = makeResdom((AttrNumber) (*this_resno)++,
(Oid)type_id,
(Size)type_len,
attrname,
(Index)0,
(Oid)0,
0);
- rte->expr = (Node *)varnode;
- tall = lcons(rte, tall);
+ te->expr = (Node *)varnode;
+ if (te_head == NIL)
+ te_head = te_tail = lcons(te, NIL);
+ else te_tail = lappend(te_tail, te);
}
- /*
- * Close the reldesc - we're done with it now
- */
heap_close(rdesc);
- *this_resno = first_resno + maxattrs;
- return(tall);
+ return(te_head);
}
TimeQual
Var *
-make_var(ParseState *pstate, char *relname, char *attrname, int *type_id)
+make_var(ParseState *pstate, char *refname, char *attrname, int *type_id)
{
Var *varnode;
int vnum, attid, vartypeid;
Relation rd;
-
- vnum = RangeTablePosn(pstate->p_rtable, relname);
-
- if (vnum == 0) {
- pstate->p_rtable =
- lappend(pstate->p_rtable,
- makeRangeTableEntry(relname, FALSE,
- NULL, relname));
- vnum = RangeTablePosn (pstate->p_rtable, relname);
- relname = VarnoGetRelname(pstate, vnum);
- } else {
- relname = VarnoGetRelname(pstate, vnum);
- }
-
- rd = heap_openr(relname);
-/* relid = RelationGetRelationId(rd); */
+ RangeTblEntry *rte;
+
+ rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+ if (rte == NULL)
+ rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE, NULL);
+
+ vnum = refnameRangeTablePosn(pstate->p_rtable, refname);
+
+ rd = heap_open(rte->relid);
+
attid = nf_varattno(rd, (char *) attrname);
if (attid == InvalidAttrNumber)
elog(WARN, "Invalid attribute %s\n", attrname);
varnode = makeVar(vnum, attid, vartypeid, vnum, attid);
- /*
- * close relation we're done with it now
- */
heap_close(rd);
*type_id = vartypeid;
return param_type_info[t-1];
}
+/*
+ * handleTargetColname -
+ * use column names from insert
+ */
+void
+handleTargetColname(ParseState *pstate, char **resname,
+ char *refname, char *colname)
+{
+ if (pstate->p_is_insert) {
+ if (pstate->p_insert_columns != NIL ) {
+ Ident *id = lfirst(pstate->p_insert_columns);
+ Assert(lfirst(pstate->p_insert_columns) != NIL);
+ *resname = id->name;
+ pstate->p_insert_columns = lnext(pstate->p_insert_columns);
+ }
+ else
+ elog(WARN, "insert: more expressions than target columns");
+ }
+ if (pstate->p_is_insert||pstate->p_is_update)
+ checkTargetTypes(pstate, *resname, refname, colname);
+}
+
+/*
+ * checkTargetTypes -
+ * checks value and target column types
+ */
+void
+checkTargetTypes(ParseState *pstate, char *target_colname,
+ char *refname, char *colname)
+{
+ int attrtype_id, attrtype_target, resdomno_id, resdomno_target;
+ Relation rd;
+ RangeTblEntry *rte;
+
+ if (target_colname == NULL || colname == NULL)
+ return;
+
+ if (refname != NULL)
+ rte = refnameRangeTableEntry(pstate->p_rtable, refname);
+ else {
+ rte = colnameRangeTableEntry(pstate, colname);
+ refname = rte->refname;
+ }
+
+ Assert(refname != NULL && rte != NULL);
+
+ Assert(rte != NULL);
+/*
+ if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry)
+ elog(WARN, "%s not available in this context", colname);
+*/
+ rd = heap_open(rte->relid);
+ Assert(RelationIsValid(rd));
+
+ resdomno_id = varattno(rd,colname);
+ attrtype_id = att_typeid(rd,resdomno_id);
+
+ resdomno_target = varattno(pstate->p_target_relation,target_colname);
+ attrtype_target = att_typeid(pstate->p_target_relation, resdomno_target);
+
+ if (attrtype_id != attrtype_target)
+ elog(WARN, "Type of %s does not match target column %s",
+ colname, target_colname);
+
+ if ((attrtype_id == BPCHAROID || attrtype_id == VARCHAROID) &&
+ rd->rd_att->attrs[resdomno_id-1]->attlen !=
+ pstate->p_target_relation->rd_att->attrs[resdomno_target-1]->attlen)
+ elog(WARN, "Length of %s does not match length of target column %s",
+ colname, target_colname);
+
+ heap_close(rd);
+}
+