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

📄 parse_target.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------------- * * parse_target.c *	  handle target lists * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.42 1999/06/17 22:21:41 tgl Exp $ * *------------------------------------------------------------------------- */#include <stdio.h>#include <stdlib.h>#include <string.h>#include "postgres.h"#include "catalog/pg_type.h"#include "nodes/makefuncs.h"#include "nodes/primnodes.h"#include "nodes/print.h"#include "parser/parse_expr.h"#include "parser/parse_func.h"#include "parser/parse_node.h"#include "parser/parse_relation.h"#include "parser/parse_target.h"#include "parser/parse_coerce.h"#include "utils/builtins.h"#include "utils/lsyscache.h"#include "utils/syscache.h"static List *ExpandAllTables(ParseState *pstate);static char *FigureColname(Node *expr, Node *resval);static Node *SizeTargetExpr(ParseState *pstate,			   Node *expr,			   Oid attrtype,			   int32 attrtypmod);/* MakeTargetEntryIdent() * Transforms an Ident Node to a Target Entry * Created this function to allow the ORDER/GROUP BY clause to be able *	to construct a TargetEntry from an Ident. * * resjunk = TRUE will hide the target entry in the final result tuple. *		daveh@insightdist.com	  5/20/98 * * Added more conversion logic to match up types from source to target. * - thomas 1998-06-02 */TargetEntry *MakeTargetEntryIdent(ParseState *pstate,					 Node *node,					 char **resname,					 char *refname,					 char *colname,					 bool resjunk){	Node	   *expr = NULL;	Oid			attrtype_target;	TargetEntry *tent = makeNode(TargetEntry);	if (pstate->p_is_insert && !resjunk)	{		/*		 * 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.		 */		if (pstate->p_insert_columns != NIL)		{			Ident	   *id = lfirst(pstate->p_insert_columns);			*resname = id->name;			pstate->p_insert_columns = lnext(pstate->p_insert_columns);		}		else			elog(ERROR, "INSERT has more expressions than target columns");	}	if ((pstate->p_is_insert || pstate->p_is_update) && !resjunk)	{		Oid			attrtype_id;		int			resdomno_id,					resdomno_target;		RangeTblEntry *rte;		char	   *target_colname;		int32		attrtypmod,					attrtypmod_target;		target_colname = *resname;		/*		 * this looks strange to me, returning an empty TargetEntry bjm		 * 1998/08/24		 */		if (target_colname == NULL || colname == NULL)			return tent;		if (refname != NULL)			rte = refnameRangeTableEntry(pstate, refname);		else		{			rte = colnameRangeTableEntry(pstate, colname);			if (rte == (RangeTblEntry *) NULL)				elog(ERROR, "Attribute %s not found", colname);			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)			|| ((attrtypmod_target >= 0) && (attrtypmod_target != attrtypmod)))		{			if (can_coerce_type(1, &attrtype_id, &attrtype_target))			{				expr = coerce_type(pstate, node, attrtype_id,								   attrtype_target,								   get_atttypmod(pstate->p_target_relation->rd_id, resdomno_target));				expr = transformExpr(pstate, expr, EXPR_COLUMN_FIRST);				tent = MakeTargetEntryExpr(pstate, *resname, expr, false, false);				expr = tent->expr;			}			else			{				elog(ERROR, "Unable to convert %s to %s for column %s",					 typeidTypeName(attrtype_id), typeidTypeName(attrtype_target),					 target_colname);			}		}	}	/*	 * here we want to look for column names only, not relation names	 * (even though they can be stored in Ident nodes, too)	 */	if (expr == NULL)	{		char	   *name;		int32		type_mod;		name = ((*resname != NULL) ? *resname : colname);		expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);		attrtype_target = exprType(expr);		if (nodeTag(expr) == T_Var)			type_mod = ((Var *) expr)->vartypmod;		else			type_mod = -1;		tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,								  (Oid) attrtype_target,								  type_mod,								  name,								  (Index) 0,								  (Oid) 0,								  resjunk);		tent->expr = expr;	}	return tent;}	/* MakeTargetEntryIdent() *//* MakeTargetEntryExpr() * Make a TargetEntry from an expression. * arrayRef is a list of transformed A_Indices. * * For type mismatches between expressions and targets, use the same *	techniques as for function and operator type coersion. * - thomas 1998-05-08 * * Added resjunk flag and made extern so that it can be use by GROUP/ * ORDER BY a function or expression not in the target_list * -  daveh@insightdist.com 1998-07-31 */TargetEntry *MakeTargetEntryExpr(ParseState *pstate,					char *colname,					Node *expr,					List *arrayRef,					bool resjunk){	Oid			type_id,				attrtype;	int32		type_mod,				attrtypmod;	int			resdomno;	Relation	rd;	bool		attrisset;	Resdom	   *resnode;	if (expr == NULL)		elog(ERROR, "Invalid use of NULL expression (internal error)");	type_id = exprType(expr);	if (nodeTag(expr) == T_Var)		type_mod = ((Var *) expr)->vartypmod;	else		type_mod = -1;	/* Process target columns that will be receiving results */	if ((pstate->p_is_insert || pstate->p_is_update) && !resjunk)	{		/*		 * 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);		if (resdomno <= 0)			elog(ERROR, "Cannot assign to system attribute '%s'", colname);		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;		/*		 * Check for InvalidOid since that seems to indicate a NULL		 * constant...		 */		if (type_id != InvalidOid)		{			/* Mismatch on types? then try to coerce to target...  */			if (attrtype != type_id)			{				Oid			typelem;				if (arrayRef && !(((A_Indices *) lfirst(arrayRef))->lidx))					typelem = typeTypElem(typeidType(attrtype));				else					typelem = attrtype;				expr = CoerceTargetExpr(pstate, expr, type_id, typelem);				if (!HeapTupleIsValid(expr))					elog(ERROR, "Attribute '%s' is of type '%s'"						 " but expression is of type '%s'"					"\n\tYou will need to rewrite or cast the expression",						 colname,						 typeidTypeName(attrtype),						 typeidTypeName(type_id));			}			/*			 * Apparently going to a fixed-length string? Then explicitly			 * size for storage...			 */			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,												   &pstate->p_last_resno,													  EXPR_COLUMN_FIRST);			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);	return makeTargetEntry(resnode, expr);}	/* MakeTargetEntryExpr() *//* *	MakeTargetEntryCase() *	Make a TargetEntry from a case node. */static TargetEntry *MakeTargetEntryCase(ParseState *pstate,					ResTarget *res){	TargetEntry *tent;	CaseExpr   *expr;	Resdom	   *resnode;	int			resdomno;	Oid			type_id;	int32		type_mod;	expr = (CaseExpr *) transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);	type_id = expr->casetype;	type_mod = -1;	handleTargetColname(pstate, &res->name, NULL, NULL);	if (res->name == NULL)		res->name = FigureColname((Node *) expr, res->val);	resdomno = pstate->p_last_resno++;	resnode = makeResdom((AttrNumber) resdomno,						 (Oid) type_id,						 type_mod,						 res->name,						 (Index) 0,						 (Oid) 0,						 false);	tent = makeNode(TargetEntry);	tent->resdom = resnode;	tent->expr = (Node *) expr;	return tent;}	/* MakeTargetEntryCase() *//* *	MakeTargetEntryComplex() *	Make a TargetEntry from a complex node. */static TargetEntry *MakeTargetEntryComplex(ParseState *pstate,					   ResTarget *res){	Node	   *expr = transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);	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))			elog(ERROR, "String constant expected (internal error)");		val = (char *) textout((struct varlena *)							   ((Const *) expr)->constvalue);		str = save_str = (char *) palloc(strlen(val) + MAXDIM * 25 + 2);		foreach(elt, res->indirection)		{			A_Indices  *aind = (A_Indices *) lfirst(elt);			aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);			if (!IsA(aind->uidx, Const))				elog(ERROR, "Array Index for Append should be a constant");			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])				elog(ERROR, "Lower index cannot be greater than upper index");			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)			elog(ERROR, "Array dimensions do not match");		constval = makeNode(Value);		constval->type = T_String;		constval->val.str = save_str;		return MakeTargetEntryExpr(pstate, res->name,								   (Node *) make_const(constval),								   NULL, false);		pfree(save_str);	}	else	{		/* this is not an array assignment */		char	   *colname = res->name;		if (colname == NULL)		{			/*			 * if you're wondering why this is here, look at the yacc			 * grammar for why a name can be missing. -ay			 */			colname = FigureColname(expr, res->val);		}		if (res->indirection)		{			List	   *ilist = res->indirection;

⌨️ 快捷键说明

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