1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* tupdesc.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* POSTGRES tuple descriptor support code
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2004-12-31 23:04:05 +01:00
|
|
|
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2005-04-01 00:46:33 +02:00
|
|
|
* $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.110 2005/03/31 22:46:04 tgl Exp $
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
* NOTES
|
1997-09-07 07:04:48 +02:00
|
|
|
* some of the executor utility code such as "ExecTypeFromTL" should be
|
|
|
|
* moved here.
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "postgres.h"
|
1996-11-01 10:41:41 +01:00
|
|
|
|
2002-06-20 19:19:08 +02:00
|
|
|
#include "access/heapam.h"
|
1999-07-16 01:04:24 +02:00
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "parser/parse_type.h"
|
|
|
|
#include "utils/builtins.h"
|
|
|
|
#include "utils/syscache.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1996-10-21 00:04:49 +02:00
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
/*
|
|
|
|
* CreateTemplateTupleDesc
|
|
|
|
* This function allocates an empty tuple descriptor structure.
|
2004-04-01 23:28:47 +02:00
|
|
|
*
|
|
|
|
* Tuple type ID information is initially set for an anonymous record type;
|
|
|
|
* caller can overwrite this if needed.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
TupleDesc
|
2002-09-02 03:05:06 +02:00
|
|
|
CreateTemplateTupleDesc(int natts, bool hasoid)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc desc;
|
2005-03-07 05:42:17 +01:00
|
|
|
char *stg;
|
|
|
|
int attroffset;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* sanity checks
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-09-28 22:00:19 +02:00
|
|
|
AssertArg(natts >= 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-03-07 05:42:17 +01:00
|
|
|
* 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.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2005-03-07 05:42:17 +01:00
|
|
|
attroffset = sizeof(struct tupleDesc) + natts * sizeof(Form_pg_attribute);
|
|
|
|
attroffset = MAXALIGN(attroffset);
|
|
|
|
stg = palloc(attroffset + natts * MAXALIGN(ATTRIBUTE_TUPLE_SIZE));
|
|
|
|
desc = (TupleDesc) stg;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-09-28 22:00:19 +02:00
|
|
|
if (natts > 0)
|
2005-03-07 05:42:17 +01:00
|
|
|
{
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2002-09-28 22:00:19 +02:00
|
|
|
else
|
|
|
|
desc->attrs = NULL;
|
2004-04-01 23:28:47 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize other fields of the tupdesc.
|
|
|
|
*/
|
|
|
|
desc->natts = natts;
|
2002-09-28 22:00:19 +02:00
|
|
|
desc->constr = NULL;
|
2004-04-01 23:28:47 +02:00
|
|
|
desc->tdtypeid = RECORDOID;
|
|
|
|
desc->tdtypmod = -1;
|
|
|
|
desc->tdhasoid = hasoid;
|
2002-09-28 22:00:19 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return desc;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
/*
|
|
|
|
* CreateTupleDesc
|
2002-09-02 03:05:06 +02:00
|
|
|
* This function allocates a new TupleDesc pointing to a given
|
2005-03-07 05:42:17 +01:00
|
|
|
* Form_pg_attribute array.
|
|
|
|
*
|
|
|
|
* Note: if the TupleDesc is ever freed, the Form_pg_attribute array
|
|
|
|
* will not be freed thereby.
|
2004-04-01 23:28:47 +02:00
|
|
|
*
|
|
|
|
* Tuple type ID information is initially set for an anonymous record type;
|
|
|
|
* caller can overwrite this if needed.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
TupleDesc
|
2002-09-02 03:05:06 +02:00
|
|
|
CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc desc;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* sanity checks
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2002-09-28 22:00:19 +02:00
|
|
|
AssertArg(natts >= 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
|
|
|
|
desc->attrs = attrs;
|
|
|
|
desc->natts = natts;
|
|
|
|
desc->constr = NULL;
|
2004-04-01 23:28:47 +02:00
|
|
|
desc->tdtypeid = RECORDOID;
|
|
|
|
desc->tdtypmod = -1;
|
2002-09-02 03:05:06 +02:00
|
|
|
desc->tdhasoid = hasoid;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1998-09-01 05:29:17 +02:00
|
|
|
return desc;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
/*
|
|
|
|
* CreateTupleDescCopy
|
1997-09-07 07:04:48 +02:00
|
|
|
* This function creates a new TupleDesc by copying from an existing
|
2005-03-07 05:42:17 +01:00
|
|
|
* TupleDesc.
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2005-03-07 05:42:17 +01:00
|
|
|
* !!! Constraints and defaults are not copied !!!
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
TupleDesc
|
|
|
|
CreateTupleDescCopy(TupleDesc tupdesc)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc desc;
|
2004-04-01 23:28:47 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);
|
|
|
|
|
|
|
|
for (i = 0; i < desc->natts; i++)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2005-03-07 05:42:17 +01:00
|
|
|
memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
|
|
|
|
desc->attrs[i]->attnotnull = false;
|
|
|
|
desc->attrs[i]->atthasdef = false;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2004-04-01 23:28:47 +02:00
|
|
|
|
|
|
|
desc->tdtypeid = tupdesc->tdtypeid;
|
|
|
|
desc->tdtypmod = tupdesc->tdtypmod;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
return desc;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
/*
|
|
|
|
* CreateTupleDescCopyConstr
|
1997-09-07 07:04:48 +02:00
|
|
|
* This function creates a new TupleDesc by copying from an existing
|
2005-03-07 05:42:17 +01:00
|
|
|
* TupleDesc (including its constraints and defaults).
|
1997-08-22 04:55:39 +02:00
|
|
|
*/
|
|
|
|
TupleDesc
|
|
|
|
CreateTupleDescCopyConstr(TupleDesc tupdesc)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc desc;
|
|
|
|
TupleConstr *constr = tupdesc->constr;
|
2004-04-01 23:28:47 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);
|
|
|
|
|
|
|
|
for (i = 0; i < desc->natts; i++)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2005-03-07 05:42:17 +01:00
|
|
|
memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2004-04-01 23:28:47 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (constr)
|
|
|
|
{
|
2004-04-01 23:28:47 +02:00
|
|
|
TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2004-04-01 23:28:47 +02:00
|
|
|
desc->tdtypeid = tupdesc->tdtypeid;
|
|
|
|
desc->tdtypmod = tupdesc->tdtypmod;
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return desc;
|
1997-08-22 04:55:39 +02:00
|
|
|
}
|
|
|
|
|
2004-04-01 23:28:47 +02:00
|
|
|
/*
|
|
|
|
* Free a TupleDesc including all substructure
|
|
|
|
*/
|
1997-08-22 04:55:39 +02:00
|
|
|
void
|
1997-09-07 07:04:48 +02:00
|
|
|
FreeTupleDesc(TupleDesc tupdesc)
|
1997-08-22 04:55:39 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int i;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
if (tupdesc->constr)
|
|
|
|
{
|
|
|
|
if (tupdesc->constr->num_defval > 0)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
AttrDefault *attrdef = tupdesc->constr->defval;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
ConstrCheck *check = tupdesc->constr->check;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
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);
|
1997-08-22 04:55:39 +02:00
|
|
|
}
|
|
|
|
|
2002-08-30 21:23:20 +02:00
|
|
|
/*
|
|
|
|
* Compare two TupleDesc structures for logical equality
|
2004-04-01 23:28:47 +02:00
|
|
|
*
|
|
|
|
* 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.
|
2002-08-30 21:23:20 +02:00
|
|
|
*/
|
2000-01-31 05:35:57 +01:00
|
|
|
bool
|
|
|
|
equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
|
|
|
|
{
|
2000-11-08 23:10:03 +01:00
|
|
|
int i,
|
|
|
|
j,
|
|
|
|
n;
|
2000-01-31 05:35:57 +01:00
|
|
|
|
|
|
|
if (tupdesc1->natts != tupdesc2->natts)
|
|
|
|
return false;
|
2004-04-01 23:28:47 +02:00
|
|
|
if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
|
|
|
|
return false;
|
2002-07-20 07:16:59 +02:00
|
|
|
if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)
|
|
|
|
return false;
|
2004-04-01 23:28:47 +02:00
|
|
|
|
2000-01-31 05:35:57 +01:00
|
|
|
for (i = 0; i < tupdesc1->natts; i++)
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
Form_pg_attribute attr1 = tupdesc1->attrs[i];
|
|
|
|
Form_pg_attribute attr2 = tupdesc2->attrs[i];
|
2000-01-31 05:35:57 +01:00
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
/*
|
2001-10-25 07:50:21 +02:00
|
|
|
* We do not need to check every single field here: we can
|
|
|
|
* disregard attrelid, attnum (it was used to place the row in the
|
|
|
|
* attrs array) and everything derived from the column datatype.
|
2004-04-01 23:28:47 +02:00
|
|
|
* Also, attcacheoff must NOT be checked since it's possibly not
|
|
|
|
* set in both copies.
|
2000-01-31 05:35:57 +01:00
|
|
|
*/
|
|
|
|
if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
|
|
|
|
return false;
|
|
|
|
if (attr1->atttypid != attr2->atttypid)
|
|
|
|
return false;
|
2001-05-07 02:43:27 +02:00
|
|
|
if (attr1->attstattarget != attr2->attstattarget)
|
|
|
|
return false;
|
2004-04-01 23:28:47 +02:00
|
|
|
if (attr1->attndims != attr2->attndims)
|
|
|
|
return false;
|
2000-01-31 05:35:57 +01:00
|
|
|
if (attr1->atttypmod != attr2->atttypmod)
|
|
|
|
return false;
|
|
|
|
if (attr1->attstorage != attr2->attstorage)
|
|
|
|
return false;
|
|
|
|
if (attr1->attnotnull != attr2->attnotnull)
|
|
|
|
return false;
|
2002-08-30 21:23:20 +02:00
|
|
|
if (attr1->atthasdef != attr2->atthasdef)
|
|
|
|
return false;
|
2002-08-02 20:15:10 +02:00
|
|
|
if (attr1->attisdropped != attr2->attisdropped)
|
|
|
|
return false;
|
2002-09-22 21:42:52 +02:00
|
|
|
if (attr1->attislocal != attr2->attislocal)
|
|
|
|
return false;
|
|
|
|
if (attr1->attinhcount != attr2->attinhcount)
|
2002-08-30 21:23:20 +02:00
|
|
|
return false;
|
2000-01-31 05:35:57 +01:00
|
|
|
}
|
2004-04-01 23:28:47 +02:00
|
|
|
|
2000-01-31 05:35:57 +01:00
|
|
|
if (tupdesc1->constr != NULL)
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
TupleConstr *constr1 = tupdesc1->constr;
|
|
|
|
TupleConstr *constr2 = tupdesc2->constr;
|
2000-01-31 05:35:57 +01:00
|
|
|
|
|
|
|
if (constr2 == NULL)
|
|
|
|
return false;
|
2000-11-08 23:10:03 +01:00
|
|
|
if (constr1->has_not_null != constr2->has_not_null)
|
|
|
|
return false;
|
|
|
|
n = constr1->num_defval;
|
|
|
|
if (n != (int) constr2->num_defval)
|
2000-01-31 05:35:57 +01:00
|
|
|
return false;
|
2000-11-08 23:10:03 +01:00
|
|
|
for (i = 0; i < n; i++)
|
2000-01-31 05:35:57 +01:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
AttrDefault *defval1 = constr1->defval + i;
|
2000-11-08 23:10:03 +01:00
|
|
|
AttrDefault *defval2 = constr2->defval;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We can't assume that the items are always read from the
|
2001-03-22 05:01:46 +01:00
|
|
|
* system catalogs in the same order; so use the adnum field
|
|
|
|
* to identify the matching item to compare.
|
2000-11-08 23:10:03 +01:00
|
|
|
*/
|
|
|
|
for (j = 0; j < n; defval2++, j++)
|
|
|
|
{
|
|
|
|
if (defval1->adnum == defval2->adnum)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (j >= n)
|
2000-01-31 05:35:57 +01:00
|
|
|
return false;
|
|
|
|
if (strcmp(defval1->adbin, defval2->adbin) != 0)
|
|
|
|
return false;
|
|
|
|
}
|
2000-11-08 23:10:03 +01:00
|
|
|
n = constr1->num_check;
|
|
|
|
if (n != (int) constr2->num_check)
|
2000-01-31 05:35:57 +01:00
|
|
|
return false;
|
2000-11-08 23:10:03 +01:00
|
|
|
for (i = 0; i < n; i++)
|
2000-01-31 05:35:57 +01:00
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
ConstrCheck *check1 = constr1->check + i;
|
2000-11-08 23:10:03 +01:00
|
|
|
ConstrCheck *check2 = constr2->check;
|
|
|
|
|
|
|
|
/*
|
2001-03-22 05:01:46 +01:00
|
|
|
* 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...)
|
2000-11-08 23:10:03 +01:00
|
|
|
*/
|
|
|
|
for (j = 0; j < n; check2++, j++)
|
|
|
|
{
|
|
|
|
if (strcmp(check1->ccname, check2->ccname) == 0 &&
|
|
|
|
strcmp(check1->ccbin, check2->ccbin) == 0)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (j >= n)
|
2000-01-31 05:35:57 +01:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (tupdesc2->constr != NULL)
|
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2005-03-07 05:42:17 +01:00
|
|
|
/*
|
|
|
|
* TupleDescInitEntry
|
1997-09-07 07:04:48 +02:00
|
|
|
* This function initializes a single attribute structure in
|
2005-03-07 05:42:17 +01:00
|
|
|
* a previously allocated tuple descriptor.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2002-03-29 20:06:29 +01:00
|
|
|
void
|
1996-07-09 08:22:35 +02:00
|
|
|
TupleDescInitEntry(TupleDesc desc,
|
1997-09-07 07:04:48 +02:00
|
|
|
AttrNumber attributeNumber,
|
2003-08-12 01:04:50 +02:00
|
|
|
const char *attributeName,
|
2000-05-22 04:34:23 +02:00
|
|
|
Oid oidtypeid,
|
1998-07-12 23:29:40 +02:00
|
|
|
int32 typmod,
|
2004-04-01 23:28:47 +02:00
|
|
|
int attdim)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
HeapTuple tuple;
|
1998-09-01 05:29:17 +02:00
|
|
|
Form_pg_type typeForm;
|
|
|
|
Form_pg_attribute att;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* sanity checks
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
AssertArg(PointerIsValid(desc));
|
|
|
|
AssertArg(attributeNumber >= 1);
|
2002-09-28 22:00:19 +02:00
|
|
|
AssertArg(attributeNumber <= desc->natts);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* initialize the attribute fields
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2005-03-07 05:42:17 +01:00
|
|
|
att = desc->attrs[attributeNumber - 1];
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
att->attrelid = 0; /* dummy value */
|
|
|
|
|
2003-08-12 01:04:50 +02:00
|
|
|
/*
|
|
|
|
* Note: attributeName can be NULL, because the planner doesn't always
|
2004-08-29 07:07:03 +02:00
|
|
|
* fill in valid resname values in targetlists, particularly for
|
|
|
|
* resjunk attributes.
|
2003-08-12 01:04:50 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
if (attributeName != NULL)
|
|
|
|
namestrcpy(&(att->attname), attributeName);
|
|
|
|
else
|
1999-11-08 00:08:36 +01:00
|
|
|
MemSet(NameStr(att->attname), 0, NAMEDATALEN);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-07-31 19:19:54 +02:00
|
|
|
att->attstattarget = -1;
|
1997-09-07 07:04:48 +02:00
|
|
|
att->attcacheoff = -1;
|
1998-02-10 05:02:59 +01:00
|
|
|
att->atttypmod = typmod;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
att->attnum = attributeNumber;
|
2001-05-07 02:43:27 +02:00
|
|
|
att->attndims = attdim;
|
1998-02-26 05:46:47 +01:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
att->attnotnull = false;
|
|
|
|
att->atthasdef = false;
|
2002-08-02 20:15:10 +02:00
|
|
|
att->attisdropped = false;
|
2002-09-22 21:42:52 +02:00
|
|
|
att->attislocal = true;
|
|
|
|
att->attinhcount = 0;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
tuple = SearchSysCache(TYPEOID,
|
|
|
|
ObjectIdGetDatum(oidtypeid),
|
|
|
|
0, 0, 0);
|
1997-09-07 07:04:48 +02:00
|
|
|
if (!HeapTupleIsValid(tuple))
|
2003-07-21 22:29:40 +02:00
|
|
|
elog(ERROR, "cache lookup failed for type %u", oidtypeid);
|
1998-09-01 05:29:17 +02:00
|
|
|
typeForm = (Form_pg_type) GETSTRUCT(tuple);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-04-01 23:28:47 +02:00
|
|
|
att->atttypid = oidtypeid;
|
|
|
|
att->attlen = typeForm->typlen;
|
|
|
|
att->attbyval = typeForm->typbyval;
|
|
|
|
att->attalign = typeForm->typalign;
|
|
|
|
att->attstorage = typeForm->typstorage;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
ReleaseSysCache(tuple);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-03-29 20:06:29 +01:00
|
|
|
/*
|
|
|
|
* BuildDescForRelation
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2002-03-29 20:06:29 +01:00
|
|
|
* Given a relation schema (list of ColumnDef nodes), build a TupleDesc.
|
2002-09-02 03:05:06 +02:00
|
|
|
*
|
|
|
|
* Note: the default assumption is no OIDs; caller may modify the returned
|
2004-08-29 07:07:03 +02:00
|
|
|
* TupleDesc if it wants OIDs. Also, tdtypeid will need to be filled in
|
2004-04-01 23:28:47 +02:00
|
|
|
* later on.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
|
|
|
TupleDesc
|
2002-03-29 20:06:29 +01:00
|
|
|
BuildDescForRelation(List *schema)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
int natts;
|
|
|
|
AttrNumber attnum;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *l;
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc desc;
|
|
|
|
AttrDefault *attrdef = NULL;
|
2004-04-01 23:28:47 +02:00
|
|
|
TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
|
1997-09-08 04:41:22 +02:00
|
|
|
char *attname;
|
1998-07-12 23:29:40 +02:00
|
|
|
int32 atttypmod;
|
1997-09-08 04:41:22 +02:00
|
|
|
int attdim;
|
|
|
|
int ndef = 0;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* allocate a new tuple descriptor
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
2004-05-31 01:40:41 +02:00
|
|
|
natts = list_length(schema);
|
2002-09-02 03:05:06 +02:00
|
|
|
desc = CreateTemplateTupleDesc(natts, false);
|
1997-09-07 07:04:48 +02:00
|
|
|
constr->has_not_null = false;
|
1997-08-19 06:46:15 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
attnum = 0;
|
|
|
|
|
2004-05-26 06:41:50 +02:00
|
|
|
foreach(l, schema)
|
1997-08-22 04:55:39 +02:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
ColumnDef *entry = lfirst(l);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* 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.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
|
|
|
attnum++;
|
|
|
|
|
|
|
|
attname = entry->colname;
|
1998-02-10 05:02:59 +01:00
|
|
|
atttypmod = entry->typename->typmod;
|
2004-05-31 01:40:41 +02:00
|
|
|
attdim = list_length(entry->typename->arrayBounds);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-04-01 23:28:47 +02:00
|
|
|
if (entry->typename->setof)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
|
|
|
|
errmsg("column \"%s\" cannot be declared SETOF",
|
|
|
|
attname)));
|
|
|
|
|
2002-03-29 20:06:29 +01:00
|
|
|
TupleDescInitEntry(desc, attnum, attname,
|
|
|
|
typenameTypeId(entry->typename),
|
2004-04-01 23:28:47 +02:00
|
|
|
atttypmod, attdim);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-08-30 21:23:20 +02:00
|
|
|
/* Fill in additional stuff not handled by TupleDescInitEntry */
|
1997-09-07 07:04:48 +02:00
|
|
|
if (entry->is_not_null)
|
|
|
|
constr->has_not_null = true;
|
|
|
|
desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;
|
|
|
|
|
2000-04-12 19:17:23 +02:00
|
|
|
/*
|
|
|
|
* Note we copy only pre-cooked default expressions. Digestion of
|
|
|
|
* raw ones is someone else's problem.
|
1999-10-04 01:55:40 +02:00
|
|
|
*/
|
|
|
|
if (entry->cooked_default != NULL)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
|
|
|
if (attrdef == NULL)
|
|
|
|
attrdef = (AttrDefault *) palloc(natts * sizeof(AttrDefault));
|
|
|
|
attrdef[ndef].adnum = attnum;
|
1999-10-04 01:55:40 +02:00
|
|
|
attrdef[ndef].adbin = pstrdup(entry->cooked_default);
|
1997-09-07 07:04:48 +02:00
|
|
|
ndef++;
|
|
|
|
desc->attrs[attnum - 1]->atthasdef = true;
|
|
|
|
}
|
|
|
|
|
2002-09-22 21:42:52 +02:00
|
|
|
desc->attrs[attnum - 1]->attislocal = entry->is_local;
|
|
|
|
desc->attrs[attnum - 1]->attinhcount = entry->inhcount;
|
1997-08-22 04:55:39 +02:00
|
|
|
}
|
2002-08-30 21:23:20 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (constr->has_not_null || ndef > 0)
|
|
|
|
{
|
|
|
|
desc->constr = constr;
|
1997-08-19 06:46:15 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
if (ndef > 0) /* DEFAULTs */
|
|
|
|
{
|
|
|
|
if (ndef < natts)
|
|
|
|
constr->defval = (AttrDefault *)
|
|
|
|
repalloc(attrdef, ndef * sizeof(AttrDefault));
|
|
|
|
else
|
|
|
|
constr->defval = attrdef;
|
|
|
|
constr->num_defval = ndef;
|
|
|
|
}
|
|
|
|
else
|
1999-10-04 01:55:40 +02:00
|
|
|
{
|
|
|
|
constr->defval = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
constr->num_defval = 0;
|
1999-10-04 01:55:40 +02:00
|
|
|
}
|
|
|
|
constr->check = NULL;
|
1997-09-07 07:04:48 +02:00
|
|
|
constr->num_check = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
pfree(constr);
|
|
|
|
desc->constr = NULL;
|
|
|
|
}
|
2004-04-01 23:28:47 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return desc;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|