1 /*-------------------------------------------------------------------------
6 * Copyright (c) 1994, Regents of the University of California
10 * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.9 1998/02/10 16:03:41 momjian Exp $
12 *-------------------------------------------------------------------------
19 #include "catalog/pg_type.h"
20 #include "nodes/makefuncs.h"
21 #include "nodes/primnodes.h"
22 #include "parser/parse_expr.h"
23 #include "parser/parse_func.h"
24 #include "parser/parse_node.h"
25 #include "parser/parse_relation.h"
26 #include "parser/parse_target.h"
27 #include "utils/builtins.h"
28 #include "utils/lsyscache.h"
30 static List *expandAllTables(ParseState *pstate);
31 static char *figureColname(Node *expr, Node *resval);
32 static TargetEntry *make_targetlist_expr(ParseState *pstate,
38 * transformTargetList -
39 * turns a list of ResTarget's into a list of TargetEntry's
42 transformTargetList(ParseState *pstate, List *targetlist)
45 List *tail_p_target = NIL;
47 while (targetlist != NIL)
49 ResTarget *res = (ResTarget *) lfirst(targetlist);
50 TargetEntry *tent = makeNode(TargetEntry);
52 switch (nodeTag(res->val))
62 identname = ((Ident *) res->val)->name;
63 handleTargetColname(pstate, &res->name, NULL, identname);
66 * here we want to look for column names only, not relation
67 * names (even though they can be stored in Ident nodes, too)
69 expr = transformIdent(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
70 type_id = exprType(expr);
71 if (nodeTag(expr) == T_Var)
72 type_mod = ((Var *)expr)->vartypmod;
75 resname = (res->name) ? res->name : identname;
76 tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
92 Node *expr = transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
94 handleTargetColname(pstate, &res->name, NULL, NULL);
95 /* note indirection has not been transformed */
96 if (pstate->p_is_insert && res->indirection != NIL)
98 /* this is an array assignment */
111 if (exprType(expr) != UNKNOWNOID ||
113 elog(ERROR, "yyparse: string constant expected");
115 val = (char *) textout((struct varlena *)
116 ((Const *) expr)->constvalue);
117 str = save_str = (char *) palloc(strlen(val) + MAXDIM * 25 + 2);
118 foreach(elt, res->indirection)
120 A_Indices *aind = (A_Indices *) lfirst(elt);
122 aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);
123 if (!IsA(aind->uidx, Const))
125 "Array Index for Append should be a constant");
126 uindx[i] = ((Const *) aind->uidx)->constvalue;
127 if (aind->lidx != NULL)
129 aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST);
130 if (!IsA(aind->lidx, Const))
132 "Array Index for Append should be a constant");
133 lindx[i] = ((Const *) aind->lidx)->constvalue;
139 if (lindx[i] > uindx[i])
140 elog(ERROR, "yyparse: lower index cannot be greater than upper index");
141 sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
145 sprintf(str, "=%s", val);
146 rd = pstate->p_target_relation;
148 resdomno = attnameAttNum(rd, res->name);
149 ndims = attnumAttNelems(rd, resdomno);
151 elog(ERROR, "yyparse: array dimensions do not match");
152 constval = makeNode(Value);
153 constval->type = T_String;
154 constval->val.str = save_str;
155 tent = make_targetlist_expr(pstate, res->name,
156 (Node *) make_const(constval),
162 char *colname = res->name;
164 /* this is not an array assignment */
169 * if you're wondering why this is here, look
170 * at the yacc grammar for why a name can be
173 colname = figureColname(expr, res->val);
175 if (res->indirection)
177 List *ilist = res->indirection;
181 A_Indices *ind = lfirst(ilist);
183 ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
184 ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
185 ilist = lnext(ilist);
189 tent = make_targetlist_expr(pstate, res->name, expr,
198 Attr *att = (Attr *) res->val;
203 List *attrs = att->attrs;
206 * Target item is a single '*', expand all tables (eg.
209 if (att->relname != NULL && !strcmp(att->relname, "*"))
211 if (tail_p_target == NIL)
212 p_target = tail_p_target = expandAllTables(pstate);
214 lnext(tail_p_target) = expandAllTables(pstate);
216 while (lnext(tail_p_target) != NIL)
217 /* make sure we point to the last target entry */
218 tail_p_target = lnext(tail_p_target);
221 * skip rest of while loop
223 targetlist = lnext(targetlist);
228 * Target item is relation.*, expand the table (eg.
229 * SELECT emp.*, dname FROM emp, dept)
231 attrname = strVal(lfirst(att->attrs));
232 if (att->attrs != NIL && !strcmp(attrname, "*"))
236 * tail_p_target is the target list we're building
237 * in the while loop. Make sure we fix it after
238 * appending more nodes.
240 if (tail_p_target == NIL)
241 p_target = tail_p_target = expandAll(pstate, att->relname,
242 att->relname, &pstate->p_last_resno);
244 lnext(tail_p_target) =
245 expandAll(pstate, att->relname, att->relname,
246 &pstate->p_last_resno);
247 while (lnext(tail_p_target) != NIL)
248 /* make sure we point to the last target entry */
249 tail_p_target = lnext(tail_p_target);
252 * skip the rest of the while loop
254 targetlist = lnext(targetlist);
260 * Target item is fully specified: ie. relation.attribute
262 result = ParseNestedFuncOrColumn(pstate, att, &pstate->p_last_resno,EXPR_COLUMN_FIRST);
263 handleTargetColname(pstate, &res->name, att->relname, attrname);
264 if (att->indirection != NIL)
266 List *ilist = att->indirection;
270 A_Indices *ind = lfirst(ilist);
272 ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
273 ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
274 ilist = lnext(ilist);
276 result = (Node *) make_array_ref(result, att->indirection);
278 type_id = exprType(result);
279 if (nodeTag(result) == T_Var)
280 type_mod = ((Var *)result)->vartypmod;
283 /* move to last entry */
284 while (lnext(attrs) != NIL)
285 attrs = lnext(attrs);
286 resname = (res->name) ? res->name : strVal(lfirst(attrs));
287 resnode = makeResdom((AttrNumber) pstate->p_last_resno++,
294 tent->resdom = resnode;
301 "internal error: do not know how to transform targetlist");
307 p_target = tail_p_target = lcons(tent, NIL);
311 lnext(tail_p_target) = lcons(tent, NIL);
312 tail_p_target = lnext(tail_p_target);
314 targetlist = lnext(targetlist);
322 * make_targetlist_expr -
323 * make a TargetEntry from an expression
325 * arrayRef is a list of transformed A_Indices
328 make_targetlist_expr(ParseState *pstate,
344 elog(ERROR, "make_targetlist_expr: invalid use of NULL expression");
346 type_id = exprType(expr);
347 if (nodeTag(expr) == T_Var)
348 type_mod = ((Var *)expr)->vartypmod;
352 /* Processes target columns that will be receiving results */
353 if (pstate->p_is_insert || pstate->p_is_update)
357 * insert or update query -- insert, update work only on one
358 * relation, so multiple occurence of same resdomno is bogus
360 rd = pstate->p_target_relation;
362 resdomno = attnameAttNum(rd, colname);
363 attrisset = attnameIsSet(rd, colname);
364 attrtype = attnumTypeId(rd, resdomno);
365 if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL))
366 attrtype = GetArrayElementType(attrtype);
367 attrtypmod = rd->rd_att->attrs[resdomno - 1]->atttypmod;
369 if (Input_is_string && Typecast_ok)
373 if (type_id == typeTypeId(type("unknown")))
375 val = (Datum) textout((struct varlena *)
376 ((Const) lnext(expr))->constvalue);
380 val = ((Const) lnext(expr))->constvalue;
384 lnext(expr) = makeConst(attrtype,
397 (Datum) fmgr(typeidRetinfunc(attrtype),
398 val, typeidTypElem(attrtype), -1),
400 true /* Maybe correct-- 80% chance */ ,
401 false, /* is not a set */
405 else if ((Typecast_ok) && (attrtype != type_id))
408 parser_typecast2(expr, typeidType(attrtype));
410 else if (attrtype != type_id)
412 if ((attrtype == INT2OID) && (type_id == INT4OID))
413 lfirst(expr) = lispInteger(INT2OID); /* handle CASHOID too */
414 else if ((attrtype == FLOAT4OID) && (type_id == FLOAT8OID))
415 lfirst(expr) = lispInteger(FLOAT4OID);
417 elog(ERROR, "unequal type in tlist : %s \n", colname);
420 Input_is_string = false;
421 Input_is_integer = false;
425 if (attrtype != type_id)
427 if (IsA(expr, Const))
429 /* try to cast the constant */
430 if (arrayRef && !(((A_Indices *) lfirst(arrayRef))->lidx))
432 /* updating a single item */
433 Oid typelem = typeidTypElem(attrtype);
435 expr = (Node *) parser_typecast2(expr,
441 expr = (Node *) parser_typecast2(expr,
443 typeidType(attrtype),
448 /* currently, we can't handle casting of expressions */
449 elog(ERROR, "parser: attribute '%s' is of type '%s' but expression is of type '%s'",
451 typeidTypeName(attrtype),
452 typeidTypeName(type_id));
459 Attr *att = makeNode(Attr);
461 List *upperIndexpr = NIL;
462 List *lowerIndexpr = NIL;
464 att->relname = pstrdup(RelationGetRelationName(rd)->data);
465 att->attrs = lcons(makeString(colname), NIL);
466 target_expr = (Expr *) ParseNestedFuncOrColumn(pstate, att,
467 &pstate->p_last_resno,
471 A_Indices *ind = lfirst(ar);
473 if (lowerIndexpr || (!upperIndexpr && ind->lidx))
477 * XXX assume all lowerIndexpr is non-null in this
480 lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
482 upperIndexpr = lappend(upperIndexpr, ind->uidx);
486 expr = (Node *) make_array_set(target_expr,
490 attrtype = attnumTypeId(rd, resdomno);
491 attrtypmod = get_atttypmod(rd->rd_id, resdomno);
496 resdomno = pstate->p_last_resno++;
498 attrtypmod = type_mod;
500 tent = makeNode(TargetEntry);
502 resnode = makeResdom((AttrNumber) resdomno,
510 tent->resdom = resnode;
518 * generate a list of column names if not supplied or
519 * test supplied column names to make sure they are in target table
520 * (used exclusively for inserts)
523 makeTargetNames(ParseState *pstate, List *cols)
527 /* Generate ResTarget if not supplied */
533 AttributeTupleForm *attr = pstate->p_target_relation->rd_att->attrs;
535 numcol = pstate->p_target_relation->rd_rel->relnatts;
536 for (i = 0; i < numcol; i++)
538 Ident *id = makeNode(Ident);
540 id->name = palloc(NAMEDATALEN);
541 StrNCpy(id->name, attr[i]->attname.data, NAMEDATALEN);
542 id->indirection = NIL;
545 cols = tl = lcons(id, NIL);
548 lnext(tl) = lcons(id, NIL);
558 char *name = ((Ident *) lfirst(tl))->name;
560 /* elog on failure */
561 attnameAttNum(pstate->p_target_relation, name);
562 foreach(nxt, lnext(tl))
563 if (!strcmp(name, ((Ident *) lfirst(nxt))->name))
564 elog(ERROR, "Attribute '%s' should be specified only once", name);
573 * turns '*' (in the target list) into a list of attributes
574 * (of all relations in the range table)
577 expandAllTables(ParseState *pstate)
580 List *legit_rtable = NIL;
584 rtable = pstate->p_rtable;
585 if (pstate->p_is_rule)
589 * skip first two entries, "*new*" and "*current*"
591 rtable = lnext(lnext(pstate->p_rtable));
594 /* this should not happen */
596 elog(ERROR, "cannot expand: null p_rtable");
599 * go through the range table and make a list of range table entries
600 * which we will expand.
604 RangeTblEntry *rte = lfirst(rt);
607 * we only expand those specify in the from clause. (This will
608 * also prevent us from using the wrong table in inserts: eg.
609 * tenk2 in "insert into tenk2 select * from tenk1;")
613 legit_rtable = lappend(legit_rtable, rte);
616 foreach(rt, legit_rtable)
618 RangeTblEntry *rte = lfirst(rt);
622 target = expandAll(pstate, rte->relname, rte->refname,
623 &pstate->p_last_resno);
626 while (temp != NIL && lnext(temp) != NIL)
628 lnext(temp) = expandAll(pstate, rte->relname, rte->refname,
629 &pstate->p_last_resno);
637 * if the name of the resulting column is not specified in the target
638 * list, we have to guess.
642 figureColname(Node *expr, Node *resval)
644 switch (nodeTag(expr))
647 return (char *) ((Aggreg *) expr)->aggname;
649 if (((Expr *) expr)->opType == FUNC_EXPR)
651 if (nodeTag(resval) == T_FuncCall)
652 return ((FuncCall *) resval)->funcname;