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

📄 tupdesc.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
字号:
/*------------------------------------------------------------------------- * * tupdesc.c *	  POSTGRES tuple descriptor support code * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.112.2.1 2005/11/22 18:23:03 momjian Exp $ * * NOTES *	  some of the executor utility code such as "ExecTypeFromTL" should be *	  moved here. * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/pg_type.h"#include "parser/parse_type.h"#include "utils/builtins.h"#include "utils/syscache.h"/* * CreateTemplateTupleDesc *		This function allocates an empty tuple descriptor structure. * * Tuple type ID information is initially set for an anonymous record type; * caller can overwrite this if needed. */TupleDescCreateTemplateTupleDesc(int natts, bool hasoid){	TupleDesc	desc;	char	   *stg;	int			attroffset;	/*	 * sanity checks	 */	AssertArg(natts >= 0);	/*	 * Allocate enough memory for the tuple descriptor, including the	 * attribute rows, and set up the attribute row pointers.	 *	 * Note: we assume that sizeof(struct tupleDesc) is a multiple of the	 * struct pointer alignment requirement, and hence we don't need to insert	 * alignment padding between the struct and the array of attribute row	 * pointers.	 */	attroffset = sizeof(struct tupleDesc) + natts * sizeof(Form_pg_attribute);	attroffset = MAXALIGN(attroffset);	stg = palloc(attroffset + natts * MAXALIGN(ATTRIBUTE_TUPLE_SIZE));	desc = (TupleDesc) stg;	if (natts > 0)	{		Form_pg_attribute *attrs;		int			i;		attrs = (Form_pg_attribute *) (stg + sizeof(struct tupleDesc));		desc->attrs = attrs;		stg += attroffset;		for (i = 0; i < natts; i++)		{			attrs[i] = (Form_pg_attribute) stg;			stg += MAXALIGN(ATTRIBUTE_TUPLE_SIZE);		}	}	else		desc->attrs = NULL;	/*	 * Initialize other fields of the tupdesc.	 */	desc->natts = natts;	desc->constr = NULL;	desc->tdtypeid = RECORDOID;	desc->tdtypmod = -1;	desc->tdhasoid = hasoid;	return desc;}/* * CreateTupleDesc *		This function allocates a new TupleDesc pointing to a given *		Form_pg_attribute array. * * Note: if the TupleDesc is ever freed, the Form_pg_attribute array * will not be freed thereby. * * Tuple type ID information is initially set for an anonymous record type; * caller can overwrite this if needed. */TupleDescCreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs){	TupleDesc	desc;	/*	 * sanity checks	 */	AssertArg(natts >= 0);	desc = (TupleDesc) palloc(sizeof(struct tupleDesc));	desc->attrs = attrs;	desc->natts = natts;	desc->constr = NULL;	desc->tdtypeid = RECORDOID;	desc->tdtypmod = -1;	desc->tdhasoid = hasoid;	return desc;}/* * CreateTupleDescCopy *		This function creates a new TupleDesc by copying from an existing *		TupleDesc. * * !!! Constraints and defaults are not copied !!! */TupleDescCreateTupleDescCopy(TupleDesc tupdesc){	TupleDesc	desc;	int			i;	desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);	for (i = 0; i < desc->natts; i++)	{		memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);		desc->attrs[i]->attnotnull = false;		desc->attrs[i]->atthasdef = false;	}	desc->tdtypeid = tupdesc->tdtypeid;	desc->tdtypmod = tupdesc->tdtypmod;	return desc;}/* * CreateTupleDescCopyConstr *		This function creates a new TupleDesc by copying from an existing *		TupleDesc (including its constraints and defaults). */TupleDescCreateTupleDescCopyConstr(TupleDesc tupdesc){	TupleDesc	desc;	TupleConstr *constr = tupdesc->constr;	int			i;	desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);	for (i = 0; i < desc->natts; i++)	{		memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);	}	if (constr)	{		TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));		cpy->has_not_null = constr->has_not_null;		if ((cpy->num_defval = constr->num_defval) > 0)		{			cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));			memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));			for (i = cpy->num_defval - 1; i >= 0; i--)			{				if (constr->defval[i].adbin)					cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);			}		}		if ((cpy->num_check = constr->num_check) > 0)		{			cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));			memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));			for (i = cpy->num_check - 1; i >= 0; i--)			{				if (constr->check[i].ccname)					cpy->check[i].ccname = pstrdup(constr->check[i].ccname);				if (constr->check[i].ccbin)					cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);			}		}		desc->constr = cpy;	}	desc->tdtypeid = tupdesc->tdtypeid;	desc->tdtypmod = tupdesc->tdtypmod;	return desc;}/* * Free a TupleDesc including all substructure */voidFreeTupleDesc(TupleDesc tupdesc){	int			i;	if (tupdesc->constr)	{		if (tupdesc->constr->num_defval > 0)		{			AttrDefault *attrdef = tupdesc->constr->defval;			for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)			{				if (attrdef[i].adbin)					pfree(attrdef[i].adbin);			}			pfree(attrdef);		}		if (tupdesc->constr->num_check > 0)		{			ConstrCheck *check = tupdesc->constr->check;			for (i = tupdesc->constr->num_check - 1; i >= 0; i--)			{				if (check[i].ccname)					pfree(check[i].ccname);				if (check[i].ccbin)					pfree(check[i].ccbin);			}			pfree(check);		}		pfree(tupdesc->constr);	}	pfree(tupdesc);}/* * Compare two TupleDesc structures for logical equality * * Note: we deliberately do not check the attrelid and tdtypmod fields. * This allows typcache.c to use this routine to see if a cached record type * matches a requested type, and is harmless for relcache.c's uses. */boolequalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2){	int			i,				j,				n;	if (tupdesc1->natts != tupdesc2->natts)		return false;	if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)		return false;	if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)		return false;	for (i = 0; i < tupdesc1->natts; i++)	{		Form_pg_attribute attr1 = tupdesc1->attrs[i];		Form_pg_attribute attr2 = tupdesc2->attrs[i];		/*		 * We do not need to check every single field here: we can disregard		 * attrelid and attnum (which were used to place the row in the attrs		 * array in the first place).  It might look like we could dispense		 * with checking attlen/attbyval/attalign, since these are derived		 * from atttypid; but in the case of dropped columns we must check		 * them (since atttypid will be zero for all dropped columns) and in		 * general it seems safer to check them always.		 *		 * attcacheoff must NOT be checked since it's possibly not set in both		 * copies.		 */		if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)			return false;		if (attr1->atttypid != attr2->atttypid)			return false;		if (attr1->attstattarget != attr2->attstattarget)			return false;		if (attr1->attlen != attr2->attlen)			return false;		if (attr1->attndims != attr2->attndims)			return false;		if (attr1->atttypmod != attr2->atttypmod)			return false;		if (attr1->attbyval != attr2->attbyval)			return false;		if (attr1->attstorage != attr2->attstorage)			return false;		if (attr1->attalign != attr2->attalign)			return false;		if (attr1->attnotnull != attr2->attnotnull)			return false;		if (attr1->atthasdef != attr2->atthasdef)			return false;		if (attr1->attisdropped != attr2->attisdropped)			return false;		if (attr1->attislocal != attr2->attislocal)			return false;		if (attr1->attinhcount != attr2->attinhcount)			return false;	}	if (tupdesc1->constr != NULL)	{		TupleConstr *constr1 = tupdesc1->constr;		TupleConstr *constr2 = tupdesc2->constr;		if (constr2 == NULL)			return false;		if (constr1->has_not_null != constr2->has_not_null)			return false;		n = constr1->num_defval;		if (n != (int) constr2->num_defval)			return false;		for (i = 0; i < n; i++)		{			AttrDefault *defval1 = constr1->defval + i;			AttrDefault *defval2 = constr2->defval;			/*			 * We can't assume that the items are always read from the system			 * catalogs in the same order; so use the adnum field to identify			 * the matching item to compare.			 */			for (j = 0; j < n; defval2++, j++)			{				if (defval1->adnum == defval2->adnum)					break;			}			if (j >= n)				return false;			if (strcmp(defval1->adbin, defval2->adbin) != 0)				return false;		}		n = constr1->num_check;		if (n != (int) constr2->num_check)			return false;		for (i = 0; i < n; i++)		{			ConstrCheck *check1 = constr1->check + i;			ConstrCheck *check2 = constr2->check;			/*			 * Similarly, don't assume that the checks are always read in the			 * same order; match them up by name and contents. (The name			 * *should* be unique, but...)			 */			for (j = 0; j < n; check2++, j++)			{				if (strcmp(check1->ccname, check2->ccname) == 0 &&					strcmp(check1->ccbin, check2->ccbin) == 0)					break;			}			if (j >= n)				return false;		}	}	else if (tupdesc2->constr != NULL)		return false;	return true;}/* * TupleDescInitEntry *		This function initializes a single attribute structure in *		a previously allocated tuple descriptor. */voidTupleDescInitEntry(TupleDesc desc,				   AttrNumber attributeNumber,				   const char *attributeName,				   Oid oidtypeid,				   int32 typmod,				   int attdim){	HeapTuple	tuple;	Form_pg_type typeForm;	Form_pg_attribute att;	/*	 * sanity checks	 */	AssertArg(PointerIsValid(desc));	AssertArg(attributeNumber >= 1);	AssertArg(attributeNumber <= desc->natts);	/*	 * initialize the attribute fields	 */	att = desc->attrs[attributeNumber - 1];	att->attrelid = 0;			/* dummy value */	/*	 * Note: attributeName can be NULL, because the planner doesn't always	 * fill in valid resname values in targetlists, particularly for resjunk	 * attributes.	 */	if (attributeName != NULL)		namestrcpy(&(att->attname), attributeName);	else		MemSet(NameStr(att->attname), 0, NAMEDATALEN);	att->attstattarget = -1;	att->attcacheoff = -1;	att->atttypmod = typmod;	att->attnum = attributeNumber;	att->attndims = attdim;	att->attnotnull = false;	att->atthasdef = false;	att->attisdropped = false;	att->attislocal = true;	att->attinhcount = 0;	tuple = SearchSysCache(TYPEOID,						   ObjectIdGetDatum(oidtypeid),						   0, 0, 0);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "cache lookup failed for type %u", oidtypeid);	typeForm = (Form_pg_type) GETSTRUCT(tuple);	att->atttypid = oidtypeid;	att->attlen = typeForm->typlen;	att->attbyval = typeForm->typbyval;	att->attalign = typeForm->typalign;	att->attstorage = typeForm->typstorage;	ReleaseSysCache(tuple);}/* * BuildDescForRelation * * Given a relation schema (list of ColumnDef nodes), build a TupleDesc. * * Note: the default assumption is no OIDs; caller may modify the returned * TupleDesc if it wants OIDs.	Also, tdtypeid will need to be filled in * later on. */TupleDescBuildDescForRelation(List *schema){	int			natts;	AttrNumber	attnum;	ListCell   *l;	TupleDesc	desc;	AttrDefault *attrdef = NULL;	TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));	char	   *attname;	int32		atttypmod;	int			attdim;	int			ndef = 0;	/*	 * allocate a new tuple descriptor	 */	natts = list_length(schema);	desc = CreateTemplateTupleDesc(natts, false);	constr->has_not_null = false;	attnum = 0;	foreach(l, schema)	{		ColumnDef  *entry = lfirst(l);		/*		 * for each entry in the list, get the name and type information from		 * the list and have TupleDescInitEntry fill in the attribute		 * information we need.		 */		attnum++;		attname = entry->colname;		atttypmod = entry->typename->typmod;		attdim = list_length(entry->typename->arrayBounds);		if (entry->typename->setof)			ereport(ERROR,					(errcode(ERRCODE_INVALID_TABLE_DEFINITION),					 errmsg("column \"%s\" cannot be declared SETOF",							attname)));		TupleDescInitEntry(desc, attnum, attname,						   typenameTypeId(entry->typename),						   atttypmod, attdim);		/* Fill in additional stuff not handled by TupleDescInitEntry */		if (entry->is_not_null)			constr->has_not_null = true;		desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;		/*		 * Note we copy only pre-cooked default expressions. Digestion of raw		 * ones is someone else's problem.		 */		if (entry->cooked_default != NULL)		{			if (attrdef == NULL)				attrdef = (AttrDefault *) palloc(natts * sizeof(AttrDefault));			attrdef[ndef].adnum = attnum;			attrdef[ndef].adbin = pstrdup(entry->cooked_default);			ndef++;			desc->attrs[attnum - 1]->atthasdef = true;		}		desc->attrs[attnum - 1]->attislocal = entry->is_local;		desc->attrs[attnum - 1]->attinhcount = entry->inhcount;	}	if (constr->has_not_null || ndef > 0)	{		desc->constr = constr;		if (ndef > 0)			/* DEFAULTs */		{			if (ndef < natts)				constr->defval = (AttrDefault *)					repalloc(attrdef, ndef * sizeof(AttrDefault));			else				constr->defval = attrdef;			constr->num_defval = ndef;		}		else		{			constr->defval = NULL;			constr->num_defval = 0;		}		constr->check = NULL;		constr->num_check = 0;	}	else	{		pfree(constr);		desc->constr = NULL;	}	return desc;}

⌨️ 快捷键说明

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