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

📄 preptlist.c

📁 关系型数据库 Postgresql 6.5.2
💻 C
字号:
/*------------------------------------------------------------------------- * * preptlist.c *	  Routines to preprocess the parse tree target list * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /usr/local/cvsroot/pgsql/src/backend/optimizer/prep/preptlist.c,v 1.22.2.1 1999/08/02 06:27:05 scrappy Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "catalog/pg_type.h"#include "nodes/makefuncs.h"#include "optimizer/clauses.h"#include "optimizer/prep.h"#include "parser/parsetree.h"#include "utils/lsyscache.h"#include "utils/syscache.h"static List *expand_targetlist(List *tlist, Oid relid, int command_type,				  Index result_relation);static List *replace_matching_resname(List *new_tlist,						 List *old_tlist);static List *new_relation_targetlist(Oid relid, Index rt_index,						NodeTag node_type);/* * preprocess_targetlist *	  Driver for preprocessing the parse tree targetlist. * *	  1. Deal with appends and replaces by filling missing attributes *		 in the target list. *	  2. Reset operator OIDs to the appropriate regproc ids. * *	  Returns the new targetlist. */List *preprocess_targetlist(List *tlist,					  int command_type,					  Index result_relation,					  List *range_table){	List	   *expanded_tlist = NIL;	Oid			relid = InvalidOid;	List	   *t_list = NIL;	List	   *temp = NIL;	if (result_relation >= 1 && command_type != CMD_SELECT)		relid = getrelid(result_relation, range_table);	/*	 * for heap_formtuple to work, the targetlist must match the exact	 * order of the attributes. We also need to fill in the missing	 * attributes here.							-ay 10/94	 */	expanded_tlist = expand_targetlist(tlist, relid, command_type, result_relation);	/* XXX should the fix-opids be this early?? */	/* was mapCAR  */	foreach(temp, expanded_tlist)	{		TargetEntry *tle = lfirst(temp);		if (tle->expr)			fix_opid(tle->expr);	}	t_list = copyObject(expanded_tlist);	/* ------------------	 *	for "replace" or "delete" queries, add ctid of the result	 *	relation into the target list so that the ctid can get	 *	propogate through the execution and in the end ExecReplace()	 *	will find the right tuple to replace or delete.  This	 *	extra field will be removed in ExecReplace().	 *	For convinient, we append this extra field to the end of	 *	the target list.	 * ------------------	 */	if (command_type == CMD_UPDATE || command_type == CMD_DELETE)	{		TargetEntry *ctid;		Resdom	   *resdom;		Var		   *var;		resdom = makeResdom(length(t_list) + 1,							TIDOID,							-1,							"ctid",							0,							0,							true);		var = makeVar(result_relation, -1, TIDOID, -1, 0, result_relation, -1);		ctid = makeTargetEntry(resdom, (Node *) var);		t_list = lappend(t_list, ctid);	}	return t_list;}/***************************************************************************** * *		TARGETLIST EXPANSION * *****************************************************************************//* * expand_targetlist *	  Given a target list as generated by the parser and a result relation, *	  add targetlist entries for the attributes which have not been used. * *	  XXX This code is only supposed to work with unnested relations. * *	  'tlist' is the original target list *	  'relid' is the relid of the result relation *	  'command' is the update command * * Returns the expanded target list, sorted in resno order. */static List *expand_targetlist(List *tlist,				  Oid relid,				  int command_type,				  Index result_relation){	NodeTag		node_type = T_Invalid;	switch (command_type)	{		case CMD_INSERT:			node_type = (NodeTag) T_Const;			break;		case CMD_UPDATE:			node_type = (NodeTag) T_Var;			break;	}	if (node_type != T_Invalid)	{		List	   *ntlist = new_relation_targetlist(relid,													 result_relation,													 node_type);		return replace_matching_resname(ntlist, tlist);	}	else		return tlist;}static List *replace_matching_resname(List *new_tlist, List *old_tlist){	List	   *temp,			   *i;	List	   *t_list = NIL;	foreach(i, new_tlist)	{		TargetEntry *new_tle = (TargetEntry *) lfirst(i);		TargetEntry *matching_old_tl = NULL;		foreach(temp, old_tlist)		{			TargetEntry *old_tle = (TargetEntry *) lfirst(temp);			old_tle = lfirst(temp);			if (!strcmp(old_tle->resdom->resname,						new_tle->resdom->resname))			{				matching_old_tl = old_tle;				break;			}		}		if (matching_old_tl)		{			matching_old_tl->resdom->resno = new_tle->resdom->resno;			t_list = lappend(t_list, matching_old_tl);		}		else			t_list = lappend(t_list, new_tle);	}	/*	 * It is possible that 'old_tlist' has some negative attributes (i.e.	 * negative resnos). This only happens if this is a replace/append	 * command and we explicitly specify a system attribute. Of course	 * this is not a very good idea if this is a user query, but on the	 * other hand the rule manager uses this mechanism to replace rule	 * locks.	 *	 * So, copy all these entries to the end of the target list and set their	 * 'resjunk' value to true to show that these are special attributes	 * and have to be treated specially by the executor!	 */	foreach(temp, old_tlist)	{		TargetEntry *old_tle,				   *new_tl;		Resdom	   *newresno;		old_tle = lfirst(temp);		if (old_tle->resdom->resno < 0)		{			newresno = (Resdom *) copyObject((Node *) old_tle->resdom);			newresno->resno = length(t_list) + 1;			newresno->resjunk = true;			new_tl = makeTargetEntry(newresno, old_tle->expr);			t_list = lappend(t_list, new_tl);		}		/*		 * Also it is possible that the parser or rewriter added some junk		 * attributes to hold GROUP BY expressions which are not part of		 * the result attributes. We can simply identify them by looking		 * at the resgroupref in the TLE's resdom, which is a unique		 * number telling which TLE belongs to which GroupClause.		 */		if (old_tle->resdom->resgroupref > 0)		{			bool		already_there = FALSE;			TargetEntry *new_tle;			Resdom	   *newresno;			/*			 * Check if the tle is already in the new list			 */			foreach(i, t_list)			{				new_tle = (TargetEntry *) lfirst(i);				if (new_tle->resdom->resgroupref ==					old_tle->resdom->resgroupref)				{					already_there = TRUE;					break;				}			}			/*			 * If not, add it and make sure it is now a junk attribute			 */			if (!already_there)			{				newresno = (Resdom *) copyObject((Node *) old_tle->resdom);				newresno->resno = length(t_list) + 1;				newresno->resjunk = true;				new_tl = makeTargetEntry(newresno, old_tle->expr);				t_list = lappend(t_list, new_tl);			}		}	}	return t_list;}/* * new_relation_targetlist *	  Generate a targetlist for the relation with relation OID 'relid' *	  and rangetable index 'rt_index'. * *	  Returns the new targetlist. */static List *new_relation_targetlist(Oid relid, Index rt_index, NodeTag node_type){	List	   *t_list = NIL;	int			natts = get_relnatts(relid);	AttrNumber	attno;	for (attno = 1; attno <= natts; attno++)	{		HeapTuple	tp;		Form_pg_attribute att_tup;		char	   *attname;		Oid			atttype;		int32		atttypmod;		bool		attisset;		tp = SearchSysCacheTuple(ATTNUM,								 ObjectIdGetDatum(relid),								 UInt16GetDatum(attno),								 0, 0);		if (! HeapTupleIsValid(tp))		{			elog(ERROR, "new_relation_targetlist: no attribute tuple %u %d",				 relid, attno);		}		att_tup = (Form_pg_attribute) GETSTRUCT(tp);		attname = pstrdup(att_tup->attname.data);		atttype = att_tup->atttypid;		atttypmod = att_tup->atttypmod;		attisset = att_tup->attisset;		switch (node_type)		{			case T_Const:		/* INSERT command */				{					struct varlena *typedefault = get_typdefault(atttype);					int			typlen;					Const	   *temp_const;					TargetEntry *temp_tle;					if (typedefault == NULL)						typlen = 0;					else					{						/*						 * Since this is an append or replace, the size of						 * any set attribute is the size of the OID used to						 * represent it.						 */						if (attisset)							typlen = get_typlen(OIDOID);						else							typlen = get_typlen(atttype);					}					temp_const = makeConst(atttype,										   typlen,										   (Datum) typedefault,										   (typedefault == NULL),										   /* XXX ? */										   false,										   false, /* not a set */										   false);					temp_tle = makeTargetEntry(makeResdom(attno,														  atttype,														  -1,														  attname,														  0,														  (Oid) 0,														  false),											   (Node *) temp_const);					t_list = lappend(t_list, temp_tle);					break;				}			case T_Var:			/* UPDATE command */				{					Var		   *temp_var;					TargetEntry *temp_tle;					temp_var = makeVar(rt_index, attno, atttype, atttypmod,									   0, rt_index, attno);					temp_tle = makeTargetEntry(makeResdom(attno,														  atttype,														  atttypmod,														  attname,														  0,														  (Oid) 0,														  false),											   (Node *) temp_var);					t_list = lappend(t_list, temp_tle);					break;				}			default:			/* do nothing */				break;		}	}	return t_list;}

⌨️ 快捷键说明

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