parse_target.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 672 行 · 第 1/2 页

C
672
字号
	 * 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	 * an array element with DEFAULT, since there can't be any default for	 * individual elements of a column.	 */	if (tle->expr && IsA(tle->expr, SetToDefault))	{		SetToDefault *def = (SetToDefault *) tle->expr;		def->typeId = attrtype;		def->typeMod = attrtypmod;		if (indirection)			ereport(ERROR,					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),					 errmsg("cannot set an array element to DEFAULT")));	}	/* Now we can use exprType() safely. */	type_id = exprType((Node *) tle->expr);	/*	 * If there are subscripts on the target column, prepare an array	 * assignment expression.  This will generate an array value that the	 * source value has been inserted into, which can then be placed in	 * the new tuple constructed by INSERT or UPDATE. Note that	 * transformArraySubscripts takes care of type coercion.	 */	if (indirection)	{		Node	   *arrayBase;		ArrayRef   *aref;		if (pstate->p_is_insert)		{			/*			 * The command is INSERT INTO table (arraycol[subscripts]) ...			 * so there is not really a source array value to work with.			 * Let the executor do something reasonable, if it can. Notice			 * that we force transformArraySubscripts to treat the			 * subscripting op as an array-slice op below, so the source			 * data will have been coerced to the array type.			 */			arrayBase = NULL;	/* signal there is no source array */		}		else		{			/*			 * Build a Var for the array to be updated.			 */			arrayBase = (Node *) make_var(pstate,										  pstate->p_target_rangetblentry,										  attrno);		}		aref = transformArraySubscripts(pstate,										arrayBase,										attrtype,										attrtypmod,										indirection,										pstate->p_is_insert,										(Node *) tle->expr);		tle->expr = (Expr *) aref;	}	else	{		/*		 * For normal non-subscripted target column, do type checking and		 * coercion.  But accept InvalidOid, which indicates the source is		 * a NULL constant.  (XXX is that still true?)		 */		if (type_id != InvalidOid)		{			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.")));		}	}	/*	 * The result of the target expression should now match the	 * destination column's type.	 */	resnode->restype = attrtype;	resnode->restypmod = attrtypmod;	/*	 * 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.)	 */	resnode->resno = (AttrNumber) attrno;	resnode->resname = colname;}/* * checkInsertTargets - *	  generate a list of INSERT column targets if not supplied, or *	  test supplied column names to make sure they are in target table. *	  Also return an integer list of the columns' attribute numbers. */List *checkInsertTargets(ParseState *pstate, List *cols, List **attrnos){	*attrnos = NIL;	if (cols == NIL)	{		/*		 * Generate default column list for INSERT.		 */		Form_pg_attribute *attr = pstate->p_target_relation->rd_att->attrs;		int			numcol = pstate->p_target_relation->rd_rel->relnatts;		int			i;		for (i = 0; i < numcol; i++)		{			ResTarget  *col;			if (attr[i]->attisdropped)				continue;			col = makeNode(ResTarget);			col->name = pstrdup(NameStr(attr[i]->attname));			col->indirection = NIL;			col->val = NULL;			cols = lappend(cols, col);			*attrnos = lappendi(*attrnos, i + 1);		}	}	else	{		/*		 * Do initial validation of user-supplied INSERT column list.		 */		List	   *tl;		foreach(tl, cols)		{			char	   *name = ((ResTarget *) lfirst(tl))->name;			int			attrno;			/* Lookup column name, ereport on failure */			attrno = attnameAttNum(pstate->p_target_relation, name, false);			/* Check for duplicates */			if (intMember(attrno, *attrnos))				ereport(ERROR,						(errcode(ERRCODE_DUPLICATE_COLUMN),					  errmsg("column \"%s\" specified more than once",							 name)));			*attrnos = lappendi(*attrnos, attrno);		}	}	return cols;}/* ExpandAllTables() * Turns '*' (in the target list) into a list of targetlist entries. * * tlist entries are generated for each relation appearing at the top level * of the query's namespace, except for RTEs marked not inFromCl.  (These * may include NEW/OLD pseudo-entries, implicit RTEs, etc.) */static List *ExpandAllTables(ParseState *pstate){	List	   *target = NIL;	bool		found_table = false;	List	   *ns;	foreach(ns, pstate->p_namespace)	{		Node	   *n = (Node *) lfirst(ns);		RangeTblEntry *rte;		if (IsA(n, RangeTblRef))			rte = rt_fetch(((RangeTblRef *) n)->rtindex,						   pstate->p_rtable);		else if (IsA(n, JoinExpr))			rte = rt_fetch(((JoinExpr *) n)->rtindex,						   pstate->p_rtable);		else		{			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(n));			rte = NULL;			/* keep compiler quiet */		}		/*		 * Ignore added-on relations that were not listed in the FROM		 * clause.		 */		if (!rte->inFromCl)			continue;		found_table = true;		target = nconc(target, expandRelAttrs(pstate, rte));	}	/* Check for SELECT *; */	if (!found_table)		ereport(ERROR,				(errcode(ERRCODE_SYNTAX_ERROR),			  errmsg("SELECT * with no tables specified is not valid")));	return target;}/* * FigureColname - *	  if the name of the resulting column is not specified in the target *	  list, we have to guess a suitable name.  The SQL spec provides some *	  guidance, but not much... * * Note that the argument is the *untransformed* parse tree for the target * item.  This is a shade easier to work with than the transformed tree. */static char *FigureColname(Node *node){	char	   *name = NULL;	FigureColnameInternal(node, &name);	if (name != NULL)		return name;	/* default result if we can't guess anything */	return "?column?";}static intFigureColnameInternal(Node *node, char **name){	int			strength = 0;	if (node == NULL)		return strength;	switch (nodeTag(node))	{		case T_ColumnRef:			{				char	   *cname = strVal(llast(((ColumnRef *) node)->fields));				if (strcmp(cname, "*") != 0)				{					*name = cname;					return 2;				}			}			break;		case T_ExprFieldSelect:			{				ExprFieldSelect *efs = (ExprFieldSelect *) node;				if (efs->fields)				{					char	   *fname = strVal(llast(efs->fields));					if (strcmp(fname, "*") != 0)					{						*name = fname;						return 2;					}				}				return FigureColnameInternal(efs->arg, name);			}			break;		case T_FuncCall:			*name = strVal(llast(((FuncCall *) node)->funcname));			return 2;		case T_A_Expr:			/* make nullif() act like a regular function */			if (((A_Expr *) node)->kind == AEXPR_NULLIF)			{				*name = "nullif";				return 2;			}			break;		case T_A_Const:			if (((A_Const *) node)->typename != NULL)			{				*name = strVal(llast(((A_Const *) node)->typename->names));				return 1;			}			break;		case T_TypeCast:			strength = FigureColnameInternal(((TypeCast *) node)->arg,											 name);			if (strength <= 1)			{				if (((TypeCast *) node)->typename != NULL)				{					*name = strVal(llast(((TypeCast *) node)->typename->names));					return 1;				}			}			break;		case T_CaseExpr:			strength = FigureColnameInternal((Node *) ((CaseExpr *) node)->defresult,											 name);			if (strength <= 1)			{				*name = "case";				return 1;			}			break;		case T_ArrayExpr:			/* make ARRAY[] act like a function */			*name = "array";			return 2;		case T_CoalesceExpr:			/* make coalesce() act like a regular function */			*name = "coalesce";			return 2;		default:			break;	}	return strength;}

⌨️ 快捷键说明

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