⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parse_target.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
/*------------------------------------------------------------------------- * * parse_target.c *	  handle target lists * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/parser/parse_target.c,v 1.138.2.2 2006/01/17 17:33:20 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "commands/dbcommands.h"#include "funcapi.h"#include "miscadmin.h"#include "nodes/bitmapset.h"#include "nodes/makefuncs.h"#include "parser/parsetree.h"#include "parser/parse_coerce.h"#include "parser/parse_expr.h"#include "parser/parse_func.h"#include "parser/parse_relation.h"#include "parser/parse_target.h"#include "parser/parse_type.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/typcache.h"static void markTargetListOrigin(ParseState *pstate, TargetEntry *tle,					 Var *var, int levelsup);static Node *transformAssignmentIndirection(ParseState *pstate,							   Node *basenode,							   const char *targetName,							   bool targetIsArray,							   Oid targetTypeId,							   int32 targetTypMod,							   ListCell *indirection,							   Node *rhs);static List *ExpandColumnRefStar(ParseState *pstate, ColumnRef *cref);static List *ExpandAllTables(ParseState *pstate);static List *ExpandIndirectionStar(ParseState *pstate, A_Indirection *ind);static int	FigureColnameInternal(Node *node, char **name);/* * transformTargetEntry() *	Transform any ordinary "expression-type" node into a targetlist entry. *	This is exported so that parse_clause.c can generate targetlist entries *	for ORDER/GROUP BY items that are not already in the targetlist. * * node		the (untransformed) parse tree for the value expression. * expr		the transformed expression, or NULL if caller didn't do it yet. * colname	the column name to be assigned, or NULL if none yet set. * resjunk	true if the target should be marked resjunk, ie, it is not *			wanted in the final projected tuple. */TargetEntry *transformTargetEntry(ParseState *pstate,					 Node *node,					 Node *expr,					 char *colname,					 bool resjunk){	/* Transform the node if caller didn't do it already */	if (expr == NULL)		expr = transformExpr(pstate, node);	if (colname == NULL && !resjunk)	{		/*		 * Generate a suitable column name for a column without any explicit		 * 'AS ColumnName' clause.		 */		colname = FigureColname(node);	}	return makeTargetEntry((Expr *) expr,						   (AttrNumber) pstate->p_next_resno++,						   colname,						   resjunk);}/* * transformTargetList() * Turns a list of ResTarget's into a list of TargetEntry's. * * At this point, we don't care whether we are doing SELECT, INSERT, * or UPDATE; we just transform the given expressions (the "val" fields). */List *transformTargetList(ParseState *pstate, List *targetlist){	List	   *p_target = NIL;	ListCell   *o_target;	foreach(o_target, targetlist)	{		ResTarget  *res = (ResTarget *) lfirst(o_target);		/*		 * Check for "something.*".  Depending on the complexity of the		 * "something", the star could appear as the last name in ColumnRef,		 * or as the last indirection item in A_Indirection.		 */		if (IsA(res->val, ColumnRef))		{			ColumnRef  *cref = (ColumnRef *) res->val;			if (strcmp(strVal(llast(cref->fields)), "*") == 0)			{				/* It is something.*, expand into multiple items */				p_target = list_concat(p_target,									   ExpandColumnRefStar(pstate, cref));				continue;			}		}		else if (IsA(res->val, A_Indirection))		{			A_Indirection *ind = (A_Indirection *) res->val;			Node	   *lastitem = llast(ind->indirection);			if (IsA(lastitem, String) &&				strcmp(strVal(lastitem), "*") == 0)			{				/* It is something.*, expand into multiple items */				p_target = list_concat(p_target,									   ExpandIndirectionStar(pstate, ind));				continue;			}		}		/*		 * Not "something.*", so transform as a single expression		 */		p_target = lappend(p_target,						   transformTargetEntry(pstate,												res->val,												NULL,												res->name,												false));	}	return p_target;}/* * markTargetListOrigins() *		Mark targetlist columns that are simple Vars with the source *		table's OID and column number. * * Currently, this is done only for SELECT targetlists, since we only * need the info if we are going to send it to the frontend. */voidmarkTargetListOrigins(ParseState *pstate, List *targetlist){	ListCell   *l;	foreach(l, targetlist)	{		TargetEntry *tle = (TargetEntry *) lfirst(l);		markTargetListOrigin(pstate, tle, (Var *) tle->expr, 0);	}}/* * markTargetListOrigin() *		If 'var' is a Var of a plain relation, mark 'tle' with its origin * * levelsup is an extra offset to interpret the Var's varlevelsup correctly. * * This is split out so it can recurse for join references.  Note that we * do not drill down into views, but report the view as the column owner. */static voidmarkTargetListOrigin(ParseState *pstate, TargetEntry *tle,					 Var *var, int levelsup){	int			netlevelsup;	RangeTblEntry *rte;	AttrNumber	attnum;	if (var == NULL || !IsA(var, Var))		return;	netlevelsup = var->varlevelsup + levelsup;	rte = GetRTEByRangeTablePosn(pstate, var->varno, netlevelsup);	attnum = var->varattno;	switch (rte->rtekind)	{		case RTE_RELATION:			/* It's a table or view, report it */			tle->resorigtbl = rte->relid;			tle->resorigcol = attnum;			break;		case RTE_SUBQUERY:			/* Subselect-in-FROM: copy up from the subselect */			if (attnum != InvalidAttrNumber)			{				TargetEntry *ste = get_tle_by_resno(rte->subquery->targetList,													attnum);				if (ste == NULL || ste->resjunk)					elog(ERROR, "subquery %s does not have attribute %d",						 rte->eref->aliasname, attnum);				tle->resorigtbl = ste->resorigtbl;				tle->resorigcol = ste->resorigcol;			}			break;		case RTE_JOIN:			/* Join RTE --- recursively inspect the alias variable */			if (attnum != InvalidAttrNumber)			{				Var		   *aliasvar;				Assert(attnum > 0 && attnum <= list_length(rte->joinaliasvars));				aliasvar = (Var *) list_nth(rte->joinaliasvars, attnum - 1);				markTargetListOrigin(pstate, tle, aliasvar, netlevelsup);			}			break;		case RTE_SPECIAL:		case RTE_FUNCTION:			/* not a simple relation, leave it unmarked */			break;	}}/* * updateTargetListEntry() *	This is used in INSERT and UPDATE statements only.	It prepares a *	TargetEntry for assignment to a column of the target table. *	This includes coercing the given value to the target column's type *	(if necessary), and dealing with any subfield names or subscripts *	attached to the target column itself. * * pstate		parse state * tle			target list entry to be modified * colname		target column name (ie, name of attribute to be assigned to) * attrno		target attribute number * indirection	subscripts/field names for target column, if any */voidupdateTargetListEntry(ParseState *pstate,					  TargetEntry *tle,					  char *colname,					  int attrno,					  List *indirection){	Oid			type_id;		/* type of value provided */	Oid			attrtype;		/* type of target column */	int32		attrtypmod;	Relation	rd = pstate->p_target_relation;	Assert(rd != NULL);	if (attrno <= 0)		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("cannot assign to system column \"%s\"",						colname)));	attrtype = attnumTypeId(rd, attrno);	attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;	/*	 * If the expression is a DEFAULT placeholder, insert the attribute's	 * type/typmod into it so that exprType will report the right things. (We	 * expect that the eventually substituted default expression will in fact	 * have this type and typmod.)	Also, reject trying to update a subfield	 * or array element with DEFAULT, since there can't be any default for	 * portions of a column.	 */	if (tle->expr && IsA(tle->expr, SetToDefault))	{		SetToDefault *def = (SetToDefault *) tle->expr;		def->typeId = attrtype;		def->typeMod = attrtypmod;		if (indirection)		{			if (IsA(linitial(indirection), A_Indices))				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("cannot set an array element to DEFAULT")));			else				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("cannot set a subfield to DEFAULT")));		}	}	/* Now we can use exprType() safely. */	type_id = exprType((Node *) tle->expr);	/*	 * If there is indirection on the target column, prepare an array or	 * subfield assignment expression.	This will generate a new column value	 * that the source value has been inserted into, which can then be placed	 * in the new tuple constructed by INSERT or UPDATE.	 */	if (indirection)	{		Node	   *colVar;		if (pstate->p_is_insert)		{			/*			 * The command is INSERT INTO table (col.something) ... so there			 * is not really a source value to work with. Insert a NULL			 * constant as the source value.			 */			colVar = (Node *) makeNullConst(attrtype);		}		else		{			/*			 * Build a Var for the column to be updated.			 */			colVar = (Node *) make_var(pstate,									   pstate->p_target_rangetblentry,									   attrno);		}		tle->expr = (Expr *)			transformAssignmentIndirection(pstate,										   colVar,										   colname,										   false,										   attrtype,										   attrtypmod,										   list_head(indirection),										   (Node *) tle->expr);	}	else	{		/*		 * For normal non-qualified target column, do type checking and		 * coercion.		 */		tle->expr = (Expr *)			coerce_to_target_type(pstate,								  (Node *) tle->expr, type_id,								  attrtype, attrtypmod,								  COERCION_ASSIGNMENT,								  COERCE_IMPLICIT_CAST);		if (tle->expr == NULL)			ereport(ERROR,					(errcode(ERRCODE_DATATYPE_MISMATCH),					 errmsg("column \"%s\" is of type %s"							" but expression is of type %s",							colname,							format_type_be(attrtype),							format_type_be(type_id)),			   errhint("You will need to rewrite or cast the expression.")));	}	/*	 * Set the resno to identify the target column --- the rewriter and	 * planner depend on this.	We also set the resname to identify the target	 * column, but this is only for debugging purposes; it should not be	 * relied on.  (In particular, it might be out of date in a stored rule.)	 */	tle->resno = (AttrNumber) attrno;	tle->resname = colname;}/* * Process indirection (field selection or subscripting) of the target * column in INSERT/UPDATE.  This routine recurses for multiple levels * of indirection --- but note that several adjacent A_Indices nodes in * the indirection list are treated as a single multidimensional subscript * operation. * * In the initial call, basenode is a Var for the target column in UPDATE, * or a null Const of the target's type in INSERT.  In recursive calls, * basenode is NULL, indicating that a substitute node should be consed up if

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -