parse_target.c 21.4 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*-------------------------------------------------------------------------
 *
 * parse_target.c
 *	  handle target lists
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *	  $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.42 1999/06/17 22:21:41 tgl Exp $
11 12 13 14 15 16
 *
 *-------------------------------------------------------------------------
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
B
Bruce Momjian 已提交
17

18 19 20 21
#include "postgres.h"
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/primnodes.h"
22
#include "nodes/print.h"
23
#include "parser/parse_expr.h"
B
Bruce Momjian 已提交
24
#include "parser/parse_func.h"
B
Bruce Momjian 已提交
25
#include "parser/parse_node.h"
26 27
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
28
#include "parser/parse_coerce.h"
29
#include "utils/builtins.h"
30
#include "utils/lsyscache.h"
31 32
#include "utils/syscache.h"

33

34
static List *ExpandAllTables(ParseState *pstate);
35
static char *FigureColname(Node *expr, Node *resval);
36
static Node *SizeTargetExpr(ParseState *pstate,
37 38
			   Node *expr,
			   Oid attrtype,
39
			   int32 attrtypmod);
40

M
 
Marc G. Fournier 已提交
41

42
/* MakeTargetEntryIdent()
43
 * Transforms an Ident Node to a Target Entry
44 45
 * Created this function to allow the ORDER/GROUP BY clause to be able
 *	to construct a TargetEntry from an Ident.
M
 
Marc G. Fournier 已提交
46
 *
47
 * resjunk = TRUE will hide the target entry in the final result tuple.
48
 *		daveh@insightdist.com	  5/20/98
49 50 51
 *
 * Added more conversion logic to match up types from source to target.
 * - thomas 1998-06-02
M
 
Marc G. Fournier 已提交
52
 */
53
TargetEntry *
54
MakeTargetEntryIdent(ParseState *pstate,
55 56 57 58
					 Node *node,
					 char **resname,
					 char *refname,
					 char *colname,
B
Bruce Momjian 已提交
59
					 bool resjunk)
M
 
Marc G. Fournier 已提交
60
{
61 62
	Node	   *expr = NULL;
	Oid			attrtype_target;
63
	TargetEntry *tent = makeNode(TargetEntry);
64

65
	if (pstate->p_is_insert && !resjunk)
66
	{
B
Bruce Momjian 已提交
67 68 69 70 71 72

		/*
		 * Assign column name of destination column to the new TLE. XXX
		 * this is probably WRONG in INSERT ... SELECT case, since
		 * handling of GROUP BY and so forth probably should use the
		 * source table's names not the destination's names.
73
		 */
74 75
		if (pstate->p_insert_columns != NIL)
		{
76
			Ident	   *id = lfirst(pstate->p_insert_columns);
77 78 79 80 81

			*resname = id->name;
			pstate->p_insert_columns = lnext(pstate->p_insert_columns);
		}
		else
T
Thomas G. Lockhart 已提交
82
			elog(ERROR, "INSERT has more expressions than target columns");
83 84
	}

85
	if ((pstate->p_is_insert || pstate->p_is_update) && !resjunk)
86
	{
87 88
		Oid			attrtype_id;
		int			resdomno_id,
89 90 91
					resdomno_target;
		RangeTblEntry *rte;
		char	   *target_colname;
92
		int32		attrtypmod,
93 94 95 96
					attrtypmod_target;

		target_colname = *resname;

97 98 99 100
		/*
		 * this looks strange to me, returning an empty TargetEntry bjm
		 * 1998/08/24
		 */
101
		if (target_colname == NULL || colname == NULL)
102
			return tent;
103 104 105 106 107 108 109

		if (refname != NULL)
			rte = refnameRangeTableEntry(pstate, refname);
		else
		{
			rte = colnameRangeTableEntry(pstate, colname);
			if (rte == (RangeTblEntry *) NULL)
T
Thomas G. Lockhart 已提交
110
				elog(ERROR, "Attribute %s not found", colname);
111 112 113 114 115 116 117 118 119 120 121 122
			refname = rte->refname;
		}

		resdomno_id = get_attnum(rte->relid, colname);
		attrtype_id = get_atttype(rte->relid, resdomno_id);
		attrtypmod = get_atttypmod(rte->relid, resdomno_id);

		resdomno_target = attnameAttNum(pstate->p_target_relation, target_colname);
		attrtype_target = attnumTypeId(pstate->p_target_relation, resdomno_target);
		attrtypmod_target = get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target);

		if ((attrtype_id != attrtype_target)
123
			|| ((attrtypmod_target >= 0) && (attrtypmod_target != attrtypmod)))
124 125 126
		{
			if (can_coerce_type(1, &attrtype_id, &attrtype_target))
			{
B
Bruce Momjian 已提交
127
				expr = coerce_type(pstate, node, attrtype_id,
B
Bruce Momjian 已提交
128 129
								   attrtype_target,
								   get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target));
130
				expr = transformExpr(pstate, expr, EXPR_COLUMN_FIRST);
B
Bruce Momjian 已提交
131
				tent = MakeTargetEntryExpr(pstate, *resname, expr, false, false);
132 133 134 135 136 137 138 139 140 141
				expr = tent->expr;
			}
			else
			{
				elog(ERROR, "Unable to convert %s to %s for column %s",
					 typeidTypeName(attrtype_id), typeidTypeName(attrtype_target),
					 target_colname);
			}
		}
	}
M
 
Marc G. Fournier 已提交
142 143

	/*
144 145
	 * here we want to look for column names only, not relation names
	 * (even though they can be stored in Ident nodes, too)
M
 
Marc G. Fournier 已提交
146
	 */
147 148
	if (expr == NULL)
	{
149 150
		char	   *name;
		int32		type_mod;
M
 
Marc G. Fournier 已提交
151

152
		name = ((*resname != NULL) ? *resname : colname);
M
 
Marc G. Fournier 已提交
153

154
		expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);
M
 
Marc G. Fournier 已提交
155

156 157 158 159 160
		attrtype_target = exprType(expr);
		if (nodeTag(expr) == T_Var)
			type_mod = ((Var *) expr)->vartypmod;
		else
			type_mod = -1;
M
 
Marc G. Fournier 已提交
161

162 163 164 165 166 167 168 169 170 171
		tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
								  (Oid) attrtype_target,
								  type_mod,
								  name,
								  (Index) 0,
								  (Oid) 0,
								  resjunk);
		tent->expr = expr;
	}

172
	return tent;
173
}	/* MakeTargetEntryIdent() */
174 175


176
/* MakeTargetEntryExpr()
B
cleanup  
Bruce Momjian 已提交
177 178 179 180
 * Make a TargetEntry from an expression.
 * arrayRef is a list of transformed A_Indices.
 *
 * For type mismatches between expressions and targets, use the same
181
 *	techniques as for function and operator type coersion.
B
cleanup  
Bruce Momjian 已提交
182 183 184
 * - thomas 1998-05-08
 *
 * Added resjunk flag and made extern so that it can be use by GROUP/
T
Thomas G. Lockhart 已提交
185
 * ORDER BY a function or expression not in the target_list
186
 * -  daveh@insightdist.com 1998-07-31
B
cleanup  
Bruce Momjian 已提交
187 188
 */
TargetEntry *
189
MakeTargetEntryExpr(ParseState *pstate,
190 191 192
					char *colname,
					Node *expr,
					List *arrayRef,
B
Bruce Momjian 已提交
193
					bool resjunk)
B
cleanup  
Bruce Momjian 已提交
194 195 196 197 198 199 200 201 202 203 204
{
	Oid			type_id,
				attrtype;
	int32		type_mod,
				attrtypmod;
	int			resdomno;
	Relation	rd;
	bool		attrisset;
	Resdom	   *resnode;

	if (expr == NULL)
T
Thomas G. Lockhart 已提交
205
		elog(ERROR, "Invalid use of NULL expression (internal error)");
B
cleanup  
Bruce Momjian 已提交
206 207 208 209 210 211 212

	type_id = exprType(expr);
	if (nodeTag(expr) == T_Var)
		type_mod = ((Var *) expr)->vartypmod;
	else
		type_mod = -1;

213
	/* Process target columns that will be receiving results */
214
	if ((pstate->p_is_insert || pstate->p_is_update) && !resjunk)
B
cleanup  
Bruce Momjian 已提交
215
	{
216

B
cleanup  
Bruce Momjian 已提交
217 218 219 220 221 222 223
		/*
		 * insert or update query -- insert, update work only on one
		 * relation, so multiple occurence of same resdomno is bogus
		 */
		rd = pstate->p_target_relation;
		Assert(rd != NULL);
		resdomno = attnameAttNum(rd, colname);
224 225
		if (resdomno <= 0)
			elog(ERROR, "Cannot assign to system attribute '%s'", colname);
B
cleanup  
Bruce Momjian 已提交
226 227 228 229 230 231
		attrisset = attnameIsSet(rd, colname);
		attrtype = attnumTypeId(rd, resdomno);
		if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL))
			attrtype = GetArrayElementType(attrtype);
		attrtypmod = rd->rd_att->attrs[resdomno - 1]->atttypmod;

232 233 234 235
		/*
		 * Check for InvalidOid since that seems to indicate a NULL
		 * constant...
		 */
B
cleanup  
Bruce Momjian 已提交
236 237 238 239 240
		if (type_id != InvalidOid)
		{
			/* Mismatch on types? then try to coerce to target...  */
			if (attrtype != type_id)
			{
241
				Oid			typelem;
B
cleanup  
Bruce Momjian 已提交
242 243

				if (arrayRef && !(((A_Indices *) lfirst(arrayRef))->lidx))
244
					typelem = typeTypElem(typeidType(attrtype));
B
cleanup  
Bruce Momjian 已提交
245 246 247 248 249 250
				else
					typelem = attrtype;

				expr = CoerceTargetExpr(pstate, expr, type_id, typelem);

				if (!HeapTupleIsValid(expr))
T
Thomas G. Lockhart 已提交
251
					elog(ERROR, "Attribute '%s' is of type '%s'"
B
cleanup  
Bruce Momjian 已提交
252
						 " but expression is of type '%s'"
B
Bruce Momjian 已提交
253
					"\n\tYou will need to rewrite or cast the expression",
B
cleanup  
Bruce Momjian 已提交
254 255 256 257 258
						 colname,
						 typeidTypeName(attrtype),
						 typeidTypeName(type_id));
			}

259 260 261
			/*
			 * Apparently going to a fixed-length string? Then explicitly
			 * size for storage...
B
cleanup  
Bruce Momjian 已提交
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
			 */
			if (attrtypmod > 0)
				expr = SizeTargetExpr(pstate, expr, attrtype, attrtypmod);
		}

		if (arrayRef != NIL)
		{
			Expr	   *target_expr;
			Attr	   *att = makeNode(Attr);
			List	   *ar = arrayRef;
			List	   *upperIndexpr = NIL;
			List	   *lowerIndexpr = NIL;

			att->relname = pstrdup(RelationGetRelationName(rd)->data);
			att->attrs = lcons(makeString(colname), NIL);
			target_expr = (Expr *) ParseNestedFuncOrColumn(pstate, att,
278 279
												   &pstate->p_last_resno,
													  EXPR_COLUMN_FIRST);
B
cleanup  
Bruce Momjian 已提交
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319
			while (ar != NIL)
			{
				A_Indices  *ind = lfirst(ar);

				if (lowerIndexpr || (!upperIndexpr && ind->lidx))
				{

					/*
					 * XXX assume all lowerIndexpr is non-null in this
					 * case
					 */
					lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
				}
				upperIndexpr = lappend(upperIndexpr, ind->uidx);
				ar = lnext(ar);
			}

			expr = (Node *) make_array_set(target_expr,
										   upperIndexpr,
										   lowerIndexpr,
										   (Expr *) expr);
			attrtype = attnumTypeId(rd, resdomno);
			attrtypmod = get_atttypmod(RelationGetRelid(rd), resdomno);
		}
	}
	else
	{
		resdomno = pstate->p_last_resno++;
		attrtype = type_id;
		attrtypmod = type_mod;
	}

	resnode = makeResdom((AttrNumber) resdomno,
						 (Oid) attrtype,
						 attrtypmod,
						 colname,
						 (Index) 0,
						 (Oid) 0,
						 resjunk);

320
	return makeTargetEntry(resnode, expr);
321
}	/* MakeTargetEntryExpr() */
B
cleanup  
Bruce Momjian 已提交
322

T
Thomas G. Lockhart 已提交
323 324 325 326 327 328 329 330
/*
 *	MakeTargetEntryCase()
 *	Make a TargetEntry from a case node.
 */
static TargetEntry *
MakeTargetEntryCase(ParseState *pstate,
					ResTarget *res)
{
B
Bruce Momjian 已提交
331 332 333 334 335 336
	TargetEntry *tent;
	CaseExpr   *expr;
	Resdom	   *resnode;
	int			resdomno;
	Oid			type_id;
	int32		type_mod;
T
Thomas G. Lockhart 已提交
337

B
Bruce Momjian 已提交
338
	expr = (CaseExpr *) transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
T
Thomas G. Lockhart 已提交
339 340 341 342 343

	type_id = expr->casetype;
	type_mod = -1;
	handleTargetColname(pstate, &res->name, NULL, NULL);
	if (res->name == NULL)
B
Bruce Momjian 已提交
344
		res->name = FigureColname((Node *) expr, res->val);
T
Thomas G. Lockhart 已提交
345 346 347 348 349 350 351 352

	resdomno = pstate->p_last_resno++;
	resnode = makeResdom((AttrNumber) resdomno,
						 (Oid) type_id,
						 type_mod,
						 res->name,
						 (Index) 0,
						 (Oid) 0,
B
Bruce Momjian 已提交
353
						 false);
T
Thomas G. Lockhart 已提交
354 355 356

	tent = makeNode(TargetEntry);
	tent->resdom = resnode;
B
Bruce Momjian 已提交
357
	tent->expr = (Node *) expr;
T
Thomas G. Lockhart 已提交
358 359 360 361

	return tent;
}	/* MakeTargetEntryCase() */

362
/*
363 364
 *	MakeTargetEntryComplex()
 *	Make a TargetEntry from a complex node.
365 366 367
 */
static TargetEntry *
MakeTargetEntryComplex(ParseState *pstate,
368
					   ResTarget *res)
369
{
370
	Node	   *expr = transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389

	handleTargetColname(pstate, &res->name, NULL, NULL);
	/* note indirection has not been transformed */
	if (pstate->p_is_insert && res->indirection != NIL)
	{
		/* this is an array assignment */
		char	   *val;
		char	   *str,
				   *save_str;
		List	   *elt;
		int			i = 0,
					ndims;
		int			lindx[MAXDIM],
					uindx[MAXDIM];
		int			resdomno;
		Relation	rd;
		Value	   *constval;

		if (exprType(expr) != UNKNOWNOID || !IsA(expr, Const))
T
Thomas G. Lockhart 已提交
390
			elog(ERROR, "String constant expected (internal error)");
391 392

		val = (char *) textout((struct varlena *)
393
							   ((Const *) expr)->constvalue);
394 395 396 397
		str = save_str = (char *) palloc(strlen(val) + MAXDIM * 25 + 2);
		foreach(elt, res->indirection)
		{
			A_Indices  *aind = (A_Indices *) lfirst(elt);
B
cleanup  
Bruce Momjian 已提交
398

399 400 401
			aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);
			if (!IsA(aind->uidx, Const))
				elog(ERROR, "Array Index for Append should be a constant");
B
cleanup  
Bruce Momjian 已提交
402

403 404 405 406 407 408 409 410 411 412 413 414
			uindx[i] = ((Const *) aind->uidx)->constvalue;
			if (aind->lidx != NULL)
			{
				aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST);
				if (!IsA(aind->lidx, Const))
					elog(ERROR, "Array Index for Append should be a constant");

				lindx[i] = ((Const *) aind->lidx)->constvalue;
			}
			else
				lindx[i] = 1;
			if (lindx[i] > uindx[i])
T
Thomas G. Lockhart 已提交
415
				elog(ERROR, "Lower index cannot be greater than upper index");
416 417 418 419 420 421 422 423 424 425 426

			sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
			str += strlen(str);
			i++;
		}
		sprintf(str, "=%s", val);
		rd = pstate->p_target_relation;
		Assert(rd != NULL);
		resdomno = attnameAttNum(rd, res->name);
		ndims = attnumAttNelems(rd, resdomno);
		if (i != ndims)
T
Thomas G. Lockhart 已提交
427
			elog(ERROR, "Array dimensions do not match");
428 429 430 431 432

		constval = makeNode(Value);
		constval->type = T_String;
		constval->val.str = save_str;
		return MakeTargetEntryExpr(pstate, res->name,
433
								   (Node *) make_const(constval),
B
Bruce Momjian 已提交
434
								   NULL, false);
435 436 437 438 439
		pfree(save_str);
	}
	else
	{
		/* this is not an array assignment */
B
Bruce Momjian 已提交
440
		char	   *colname = res->name;
T
Thomas G. Lockhart 已提交
441

442 443
		if (colname == NULL)
		{
444

445
			/*
446 447
			 * if you're wondering why this is here, look at the yacc
			 * grammar for why a name can be missing. -ay
448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465
			 */
			colname = FigureColname(expr, res->val);
		}
		if (res->indirection)
		{
			List	   *ilist = res->indirection;

			while (ilist != NIL)
			{
				A_Indices  *ind = lfirst(ilist);

				ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
				ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
				ilist = lnext(ilist);
			}
		}
		res->name = colname;
		return MakeTargetEntryExpr(pstate, res->name, expr,
B
Bruce Momjian 已提交
466
								   res->indirection, false);
467 468 469 470
	}
}

/*
471 472
 *	MakeTargetEntryAttr()
 *	Make a TargetEntry from a complex node.
473 474 475
 */
static TargetEntry *
MakeTargetEntryAttr(ParseState *pstate,
476
					ResTarget *res)
477 478 479 480 481 482 483 484 485 486
{
	Oid			type_id;
	int32		type_mod;
	Attr	   *att = (Attr *) res->val;
	Node	   *result;
	char	   *attrname;
	char	   *resname;
	Resdom	   *resnode;
	int			resdomno;
	List	   *attrs = att->attrs;
487
	TargetEntry *tent;
488 489

	attrname = strVal(lfirst(att->attrs));
490

491
	/*
492
	 * Target item is fully specified: ie. relation.attribute
493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520
	 */
	result = ParseNestedFuncOrColumn(pstate, att, &pstate->p_last_resno, EXPR_COLUMN_FIRST);
	handleTargetColname(pstate, &res->name, att->relname, attrname);
	if (att->indirection != NIL)
	{
		List	   *ilist = att->indirection;

		while (ilist != NIL)
		{
			A_Indices  *ind = lfirst(ilist);

			ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
			ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
			ilist = lnext(ilist);
		}
		result = (Node *) make_array_ref(result, att->indirection);
	}
	type_id = exprType(result);
	if (nodeTag(result) == T_Var)
		type_mod = ((Var *) result)->vartypmod;
	else
		type_mod = -1;
	/* move to last entry */
	while (lnext(attrs) != NIL)
		attrs = lnext(attrs);
	resname = (res->name) ? res->name : strVal(lfirst(attrs));
	if (pstate->p_is_insert || pstate->p_is_update)
	{
521 522
		Relation	rd;

523 524 525 526
		/*
		 * insert or update query -- insert, update work only on one
		 * relation, so multiple occurence of same resdomno is bogus
		 */
B
Bruce Momjian 已提交
527 528 529
		rd = pstate->p_target_relation;
		Assert(rd != NULL);
		resdomno = attnameAttNum(rd, res->name);
530 531
	}
	else
532
		resdomno = pstate->p_last_resno++;
533 534 535 536 537 538
	resnode = makeResdom((AttrNumber) resdomno,
						 (Oid) type_id,
						 type_mod,
						 resname,
						 (Index) 0,
						 (Oid) 0,
B
Bruce Momjian 已提交
539
						 false);
540 541 542 543 544 545
	tent = makeNode(TargetEntry);
	tent->resdom = resnode;
	tent->expr = result;
	return tent;
}

546

547 548
/* transformTargetList()
 * Turns a list of ResTarget's into a list of TargetEntry's.
549 550 551 552 553 554 555 556 557
 */
List *
transformTargetList(ParseState *pstate, List *targetlist)
{
	List	   *p_target = NIL;
	List	   *tail_p_target = NIL;

	while (targetlist != NIL)
	{
558 559
		ResTarget  *res = (ResTarget *) lfirst(targetlist);
		TargetEntry *tent = NULL;
560 561 562 563 564 565 566 567

		switch (nodeTag(res->val))
		{
			case T_Ident:
				{
					char	   *identname;

					identname = ((Ident *) res->val)->name;
B
Bruce Momjian 已提交
568
					tent = MakeTargetEntryIdent(pstate,
B
Bruce Momjian 已提交
569
												(Node *) res->val, &res->name, NULL, identname, false);
570 571 572 573 574 575 576
					break;
				}
			case T_ParamNo:
			case T_FuncCall:
			case T_A_Const:
			case T_A_Expr:
				{
577
					tent = MakeTargetEntryComplex(pstate, res);
578 579
					break;
				}
T
Thomas G. Lockhart 已提交
580 581 582 583 584
			case T_CaseExpr:
				{
					tent = MakeTargetEntryCase(pstate, res);
					break;
				}
585 586
			case T_Attr:
				{
587
					bool		expand_star = false;
588
					char	   *attrname;
589
					Attr	   *att = (Attr *) res->val;
590

591 592 593 594 595 596 597
					/*
					 * Target item is a single '*', expand all tables (eg.
					 * SELECT * FROM emp)
					 */
					if (att->relname != NULL && !strcmp(att->relname, "*"))
					{
						if (tail_p_target == NIL)
598
							p_target = tail_p_target = ExpandAllTables(pstate);
599
						else
600
							lnext(tail_p_target) = ExpandAllTables(pstate);
601
						expand_star = true;
602
					}
B
Bruce Momjian 已提交
603
					else
604
					{
605

606
						/*
607 608
						 * Target item is relation.*, expand the table
						 * (eg. SELECT emp.*, dname FROM emp, dept)
609
						 */
B
Bruce Momjian 已提交
610 611 612
						attrname = strVal(lfirst(att->attrs));
						if (att->attrs != NIL && !strcmp(attrname, "*"))
						{
613

B
Bruce Momjian 已提交
614
							/*
615 616 617
							 * tail_p_target is the target list we're
							 * building in the while loop. Make sure we
							 * fix it after appending more nodes.
B
Bruce Momjian 已提交
618 619 620
							 */
							if (tail_p_target == NIL)
								p_target = tail_p_target = expandAll(pstate, att->relname,
621
									att->relname, &pstate->p_last_resno);
B
Bruce Momjian 已提交
622
							else
623
								lnext(tail_p_target) = expandAll(pstate, att->relname, att->relname,
B
Bruce Momjian 已提交
624
												  &pstate->p_last_resno);
B
Bruce Momjian 已提交
625 626
							expand_star = true;
						}
627 628 629
					}
					if (expand_star)
					{
630 631 632
						while (lnext(tail_p_target) != NIL)
							/* make sure we point to the last target entry */
							tail_p_target = lnext(tail_p_target);
633

634
						/*
635
						 * skip rest of while loop
636 637 638 639
						 */
						targetlist = lnext(targetlist);
						continue;
					}
640
					else
641
					{
642 643
						tent = MakeTargetEntryAttr(pstate, res);
						break;
644 645 646 647
					}
				}
			default:
				/* internal error */
T
Thomas G. Lockhart 已提交
648
				elog(ERROR, "Unable to transform targetlist (internal error)");
649 650 651 652 653 654 655 656 657 658 659 660 661 662
				break;
		}

		if (p_target == NIL)
			p_target = tail_p_target = lcons(tent, NIL);
		else
		{
			lnext(tail_p_target) = lcons(tent, NIL);
			tail_p_target = lnext(tail_p_target);
		}
		targetlist = lnext(targetlist);
	}

	return p_target;
663
}	/* transformTargetList() */
664 665


666
Node *
667 668 669 670
CoerceTargetExpr(ParseState *pstate,
				 Node *expr,
				 Oid type_id,
				 Oid attrtype)
671 672
{
	if (can_coerce_type(1, &type_id, &attrtype))
B
Bruce Momjian 已提交
673
		expr = coerce_type(pstate, expr, type_id, attrtype, -1);
674 675

#ifndef DISABLE_STRING_HACKS
676 677 678 679 680

	/*
	 * string hacks to get transparent conversions w/o explicit
	 * conversions
	 */
681 682
	else if ((attrtype == BPCHAROID) || (attrtype == VARCHAROID))
	{
683 684
		Oid			text_id = TEXTOID;

685 686 687 688
		if (type_id == TEXTOID)
		{
		}
		else if (can_coerce_type(1, &type_id, &text_id))
B
Bruce Momjian 已提交
689
			expr = coerce_type(pstate, expr, type_id, text_id, -1);
690 691 692 693 694 695 696 697 698
		else
			expr = NULL;
	}
#endif

	else
		expr = NULL;

	return expr;
699
}	/* CoerceTargetExpr() */
700 701


702
/* SizeTargetExpr()
703 704 705
 * Apparently going to a fixed-length string?
 * Then explicitly size for storage...
 */
706
static Node *
707 708 709
SizeTargetExpr(ParseState *pstate,
			   Node *expr,
			   Oid attrtype,
710
			   int32 attrtypmod)
711 712 713 714
{
	int			i;
	HeapTuple	ftup;
	char	   *funcname;
715
	Oid			oid_array[MAXFARGS];
716 717

	FuncCall   *func;
718
	A_Const    *cons;
719 720 721 722

	funcname = typeidTypeName(attrtype);
	oid_array[0] = attrtype;
	oid_array[1] = INT4OID;
723
	for (i = 2; i < MAXFARGS; i++)
724
		oid_array[i] = InvalidOid;
725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740

	/* attempt to find with arguments exactly as specified... */
	ftup = SearchSysCacheTuple(PRONAME,
							   PointerGetDatum(funcname),
							   Int32GetDatum(2),
							   PointerGetDatum(oid_array),
							   0);

	if (HeapTupleIsValid(ftup))
	{
		func = makeNode(FuncCall);
		func->funcname = funcname;

		cons = makeNode(A_Const);
		cons->val.type = T_Integer;
		cons->val.val.ival = attrtypmod;
741
		func->args = lappend(lcons(expr, NIL), cons);
742 743 744 745 746

		expr = transformExpr(pstate, (Node *) func, EXPR_COLUMN_FIRST);
	}

	return expr;
747
}	/* SizeTargetExpr() */
748 749


750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766
/*
 * 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)
 */
List *
makeTargetNames(ParseState *pstate, List *cols)
{
	List	   *tl = NULL;

	/* Generate ResTarget if not supplied */

	if (cols == NIL)
	{
		int			numcol;
		int			i;
767
		Form_pg_attribute *attr = pstate->p_target_relation->rd_att->attrs;
768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792

		numcol = pstate->p_target_relation->rd_rel->relnatts;
		for (i = 0; i < numcol; i++)
		{
			Ident	   *id = makeNode(Ident);

			id->name = palloc(NAMEDATALEN);
			StrNCpy(id->name, attr[i]->attname.data, NAMEDATALEN);
			id->indirection = NIL;
			id->isRel = false;
			if (tl == NIL)
				cols = tl = lcons(id, NIL);
			else
			{
				lnext(tl) = lcons(id, NIL);
				tl = lnext(tl);
			}
		}
	}
	else
	{
		foreach(tl, cols)
		{
			List	   *nxt;
			char	   *name = ((Ident *) lfirst(tl))->name;
793

794 795 796 797
			/* elog on failure */
			attnameAttNum(pstate->p_target_relation, name);
			foreach(nxt, lnext(tl))
				if (!strcmp(name, ((Ident *) lfirst(nxt))->name))
798
				elog(ERROR, "Attribute '%s' should be specified only once", name);
799 800
		}
	}
801

802 803 804 805
	return cols;
}

/*
806
 * ExpandAllTables -
807 808 809
 *	  turns '*' (in the target list) into a list of attributes
 *	   (of all relations in the range table)
 */
810
static List *
811
ExpandAllTables(ParseState *pstate)
812 813 814 815 816 817 818 819 820
{
	List	   *target = NIL;
	List	   *legit_rtable = NIL;
	List	   *rt,
			   *rtable;

	rtable = pstate->p_rtable;
	if (pstate->p_is_rule)
	{
B
Bruce Momjian 已提交
821

822 823 824 825 826 827
		/*
		 * skip first two entries, "*new*" and "*current*"
		 */
		rtable = lnext(lnext(pstate->p_rtable));
	}

B
Bruce Momjian 已提交
828
	/* SELECT *; */
829
	if (rtable == NULL)
B
Bruce Momjian 已提交
830
		elog(ERROR, "Wildcard with no tables specified.");
831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869

	/*
	 * go through the range table and make a list of range table entries
	 * which we will expand.
	 */
	foreach(rt, rtable)
	{
		RangeTblEntry *rte = lfirst(rt);

		/*
		 * we only expand those specify in the from clause. (This will
		 * also prevent us from using the wrong table in inserts: eg.
		 * tenk2 in "insert into tenk2 select * from tenk1;")
		 */
		if (!rte->inFromCl)
			continue;
		legit_rtable = lappend(legit_rtable, rte);
	}

	foreach(rt, legit_rtable)
	{
		RangeTblEntry *rte = lfirst(rt);
		List	   *temp = target;

		if (temp == NIL)
			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, rte->relname, rte->refname,
									&pstate->p_last_resno);
		}
	}
	return target;
}

/*
870
 * FigureColname -
871 872 873 874
 *	  if the name of the resulting column is not specified in the target
 *	  list, we have to guess.
 *
 */
875
static char *
876
FigureColname(Node *expr, Node *resval)
877 878 879
{
	switch (nodeTag(expr))
	{
B
Bruce Momjian 已提交
880
			case T_Aggref:
B
Bruce Momjian 已提交
881
			return (char *) ((Aggref *) expr)->aggname;
882 883 884 885 886 887 888
		case T_Expr:
			if (((Expr *) expr)->opType == FUNC_EXPR)
			{
				if (nodeTag(resval) == T_FuncCall)
					return ((FuncCall *) resval)->funcname;
			}
			break;
889 890
		case T_CaseExpr:
			{
B
Bruce Momjian 已提交
891 892
				char	   *name;

893 894 895 896 897 898
				name = FigureColname(((CaseExpr *) expr)->defresult, resval);
				if (!strcmp(name, "?column?"))
					name = "case";
				return name;
			}
			break;
899 900 901 902 903 904
		default:
			break;
	}

	return "?column?";
}