1 /*-------------------------------------------------------------------------
4 * POSTGRES tuple descriptor support code
6 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
14 * some of the executor utility code such as "ExecTypeFromTL" should be
17 *-------------------------------------------------------------------------
22 #include "catalog/pg_type.h"
23 #include "parser/parse_type.h"
24 #include "utils/builtins.h"
25 #include "utils/resowner.h"
26 #include "utils/syscache.h"
30 * CreateTemplateTupleDesc
31 * This function allocates an empty tuple descriptor structure.
33 * Tuple type ID information is initially set for an anonymous record type;
34 * caller can overwrite this if needed.
37 CreateTemplateTupleDesc(int natts
, bool hasoid
)
46 AssertArg(natts
>= 0);
49 * Allocate enough memory for the tuple descriptor, including the
50 * attribute rows, and set up the attribute row pointers.
52 * Note: we assume that sizeof(struct tupleDesc) is a multiple of the
53 * struct pointer alignment requirement, and hence we don't need to insert
54 * alignment padding between the struct and the array of attribute row
57 attroffset
= sizeof(struct tupleDesc
) + natts
* sizeof(Form_pg_attribute
);
58 attroffset
= MAXALIGN(attroffset
);
59 stg
= palloc(attroffset
+ natts
* MAXALIGN(ATTRIBUTE_TUPLE_SIZE
));
60 desc
= (TupleDesc
) stg
;
64 Form_pg_attribute
*attrs
;
67 attrs
= (Form_pg_attribute
*) (stg
+ sizeof(struct tupleDesc
));
70 for (i
= 0; i
< natts
; i
++)
72 attrs
[i
] = (Form_pg_attribute
) stg
;
73 stg
+= MAXALIGN(ATTRIBUTE_TUPLE_SIZE
);
80 * Initialize other fields of the tupdesc.
84 desc
->tdtypeid
= RECORDOID
;
86 desc
->tdhasoid
= hasoid
;
87 desc
->tdrefcount
= -1; /* assume not reference-counted */
94 * This function allocates a new TupleDesc pointing to a given
95 * Form_pg_attribute array.
97 * Note: if the TupleDesc is ever freed, the Form_pg_attribute array
98 * will not be freed thereby.
100 * Tuple type ID information is initially set for an anonymous record type;
101 * caller can overwrite this if needed.
104 CreateTupleDesc(int natts
, bool hasoid
, Form_pg_attribute
*attrs
)
111 AssertArg(natts
>= 0);
113 desc
= (TupleDesc
) palloc(sizeof(struct tupleDesc
));
117 desc
->tdtypeid
= RECORDOID
;
119 desc
->tdhasoid
= hasoid
;
120 desc
->tdrefcount
= -1; /* assume not reference-counted */
126 * CreateTupleDescCopy
127 * This function creates a new TupleDesc by copying from an existing
130 * !!! Constraints and defaults are not copied !!!
133 CreateTupleDescCopy(TupleDesc tupdesc
)
138 desc
= CreateTemplateTupleDesc(tupdesc
->natts
, tupdesc
->tdhasoid
);
140 for (i
= 0; i
< desc
->natts
; i
++)
142 memcpy(desc
->attrs
[i
], tupdesc
->attrs
[i
], ATTRIBUTE_TUPLE_SIZE
);
143 desc
->attrs
[i
]->attnotnull
= false;
144 desc
->attrs
[i
]->atthasdef
= false;
147 desc
->tdtypeid
= tupdesc
->tdtypeid
;
148 desc
->tdtypmod
= tupdesc
->tdtypmod
;
154 * CreateTupleDescCopyConstr
155 * This function creates a new TupleDesc by copying from an existing
156 * TupleDesc (including its constraints and defaults).
159 CreateTupleDescCopyConstr(TupleDesc tupdesc
)
162 TupleConstr
*constr
= tupdesc
->constr
;
165 desc
= CreateTemplateTupleDesc(tupdesc
->natts
, tupdesc
->tdhasoid
);
167 for (i
= 0; i
< desc
->natts
; i
++)
169 memcpy(desc
->attrs
[i
], tupdesc
->attrs
[i
], ATTRIBUTE_TUPLE_SIZE
);
174 TupleConstr
*cpy
= (TupleConstr
*) palloc0(sizeof(TupleConstr
));
176 cpy
->has_not_null
= constr
->has_not_null
;
178 if ((cpy
->num_defval
= constr
->num_defval
) > 0)
180 cpy
->defval
= (AttrDefault
*) palloc(cpy
->num_defval
* sizeof(AttrDefault
));
181 memcpy(cpy
->defval
, constr
->defval
, cpy
->num_defval
* sizeof(AttrDefault
));
182 for (i
= cpy
->num_defval
- 1; i
>= 0; i
--)
184 if (constr
->defval
[i
].adbin
)
185 cpy
->defval
[i
].adbin
= pstrdup(constr
->defval
[i
].adbin
);
189 if ((cpy
->num_check
= constr
->num_check
) > 0)
191 cpy
->check
= (ConstrCheck
*) palloc(cpy
->num_check
* sizeof(ConstrCheck
));
192 memcpy(cpy
->check
, constr
->check
, cpy
->num_check
* sizeof(ConstrCheck
));
193 for (i
= cpy
->num_check
- 1; i
>= 0; i
--)
195 if (constr
->check
[i
].ccname
)
196 cpy
->check
[i
].ccname
= pstrdup(constr
->check
[i
].ccname
);
197 if (constr
->check
[i
].ccbin
)
198 cpy
->check
[i
].ccbin
= pstrdup(constr
->check
[i
].ccbin
);
205 desc
->tdtypeid
= tupdesc
->tdtypeid
;
206 desc
->tdtypmod
= tupdesc
->tdtypmod
;
212 * Free a TupleDesc including all substructure
215 FreeTupleDesc(TupleDesc tupdesc
)
220 * Possibly this should assert tdrefcount == 0, to disallow explicit
221 * freeing of un-refcounted tupdescs?
223 Assert(tupdesc
->tdrefcount
<= 0);
227 if (tupdesc
->constr
->num_defval
> 0)
229 AttrDefault
*attrdef
= tupdesc
->constr
->defval
;
231 for (i
= tupdesc
->constr
->num_defval
- 1; i
>= 0; i
--)
233 if (attrdef
[i
].adbin
)
234 pfree(attrdef
[i
].adbin
);
238 if (tupdesc
->constr
->num_check
> 0)
240 ConstrCheck
*check
= tupdesc
->constr
->check
;
242 for (i
= tupdesc
->constr
->num_check
- 1; i
>= 0; i
--)
245 pfree(check
[i
].ccname
);
247 pfree(check
[i
].ccbin
);
251 pfree(tupdesc
->constr
);
258 * Increment the reference count of a tupdesc, and log the reference in
259 * CurrentResourceOwner.
261 * Do not apply this to tupdescs that are not being refcounted. (Use the
262 * macro PinTupleDesc for tupdescs of uncertain status.)
265 IncrTupleDescRefCount(TupleDesc tupdesc
)
267 Assert(tupdesc
->tdrefcount
>= 0);
269 ResourceOwnerEnlargeTupleDescs(CurrentResourceOwner
);
270 tupdesc
->tdrefcount
++;
271 ResourceOwnerRememberTupleDesc(CurrentResourceOwner
, tupdesc
);
275 * Decrement the reference count of a tupdesc, remove the corresponding
276 * reference from CurrentResourceOwner, and free the tupdesc if no more
279 * Do not apply this to tupdescs that are not being refcounted. (Use the
280 * macro ReleaseTupleDesc for tupdescs of uncertain status.)
283 DecrTupleDescRefCount(TupleDesc tupdesc
)
285 Assert(tupdesc
->tdrefcount
> 0);
287 ResourceOwnerForgetTupleDesc(CurrentResourceOwner
, tupdesc
);
288 if (--tupdesc
->tdrefcount
== 0)
289 FreeTupleDesc(tupdesc
);
293 * Compare two TupleDesc structures for logical equality
295 * Note: we deliberately do not check the attrelid and tdtypmod fields.
296 * This allows typcache.c to use this routine to see if a cached record type
297 * matches a requested type, and is harmless for relcache.c's uses.
298 * We don't compare tdrefcount, either.
301 equalTupleDescs(TupleDesc tupdesc1
, TupleDesc tupdesc2
)
307 if (tupdesc1
->natts
!= tupdesc2
->natts
)
309 if (tupdesc1
->tdtypeid
!= tupdesc2
->tdtypeid
)
311 if (tupdesc1
->tdhasoid
!= tupdesc2
->tdhasoid
)
314 for (i
= 0; i
< tupdesc1
->natts
; i
++)
316 Form_pg_attribute attr1
= tupdesc1
->attrs
[i
];
317 Form_pg_attribute attr2
= tupdesc2
->attrs
[i
];
320 * We do not need to check every single field here: we can disregard
321 * attrelid and attnum (which were used to place the row in the attrs
322 * array in the first place). It might look like we could dispense
323 * with checking attlen/attbyval/attalign, since these are derived
324 * from atttypid; but in the case of dropped columns we must check
325 * them (since atttypid will be zero for all dropped columns) and in
326 * general it seems safer to check them always.
328 * attcacheoff must NOT be checked since it's possibly not set in both
331 if (strcmp(NameStr(attr1
->attname
), NameStr(attr2
->attname
)) != 0)
333 if (attr1
->atttypid
!= attr2
->atttypid
)
335 if (attr1
->attstattarget
!= attr2
->attstattarget
)
337 if (attr1
->attlen
!= attr2
->attlen
)
339 if (attr1
->attndims
!= attr2
->attndims
)
341 if (attr1
->atttypmod
!= attr2
->atttypmod
)
343 if (attr1
->attbyval
!= attr2
->attbyval
)
345 if (attr1
->attstorage
!= attr2
->attstorage
)
347 if (attr1
->attalign
!= attr2
->attalign
)
349 if (attr1
->attnotnull
!= attr2
->attnotnull
)
351 if (attr1
->atthasdef
!= attr2
->atthasdef
)
353 if (attr1
->attisdropped
!= attr2
->attisdropped
)
355 if (attr1
->attislocal
!= attr2
->attislocal
)
357 if (attr1
->attinhcount
!= attr2
->attinhcount
)
361 if (tupdesc1
->constr
!= NULL
)
363 TupleConstr
*constr1
= tupdesc1
->constr
;
364 TupleConstr
*constr2
= tupdesc2
->constr
;
368 if (constr1
->has_not_null
!= constr2
->has_not_null
)
370 n
= constr1
->num_defval
;
371 if (n
!= (int) constr2
->num_defval
)
373 for (i
= 0; i
< n
; i
++)
375 AttrDefault
*defval1
= constr1
->defval
+ i
;
376 AttrDefault
*defval2
= constr2
->defval
;
379 * We can't assume that the items are always read from the system
380 * catalogs in the same order; so use the adnum field to identify
381 * the matching item to compare.
383 for (j
= 0; j
< n
; defval2
++, j
++)
385 if (defval1
->adnum
== defval2
->adnum
)
390 if (strcmp(defval1
->adbin
, defval2
->adbin
) != 0)
393 n
= constr1
->num_check
;
394 if (n
!= (int) constr2
->num_check
)
396 for (i
= 0; i
< n
; i
++)
398 ConstrCheck
*check1
= constr1
->check
+ i
;
399 ConstrCheck
*check2
= constr2
->check
;
402 * Similarly, don't assume that the checks are always read in the
403 * same order; match them up by name and contents. (The name
404 * *should* be unique, but...)
406 for (j
= 0; j
< n
; check2
++, j
++)
408 if (strcmp(check1
->ccname
, check2
->ccname
) == 0 &&
409 strcmp(check1
->ccbin
, check2
->ccbin
) == 0)
416 else if (tupdesc2
->constr
!= NULL
)
423 * This function initializes a single attribute structure in
424 * a previously allocated tuple descriptor.
427 TupleDescInitEntry(TupleDesc desc
,
428 AttrNumber attributeNumber
,
429 const char *attributeName
,
435 Form_pg_type typeForm
;
436 Form_pg_attribute att
;
441 AssertArg(PointerIsValid(desc
));
442 AssertArg(attributeNumber
>= 1);
443 AssertArg(attributeNumber
<= desc
->natts
);
446 * initialize the attribute fields
448 att
= desc
->attrs
[attributeNumber
- 1];
450 att
->attrelid
= 0; /* dummy value */
453 * Note: attributeName can be NULL, because the planner doesn't always
454 * fill in valid resname values in targetlists, particularly for resjunk
457 if (attributeName
!= NULL
)
458 namestrcpy(&(att
->attname
), attributeName
);
460 MemSet(NameStr(att
->attname
), 0, NAMEDATALEN
);
462 att
->attstattarget
= -1;
463 att
->attcacheoff
= -1;
464 att
->atttypmod
= typmod
;
466 att
->attnum
= attributeNumber
;
467 att
->attndims
= attdim
;
469 att
->attnotnull
= false;
470 att
->atthasdef
= false;
471 att
->attisdropped
= false;
472 att
->attislocal
= true;
473 att
->attinhcount
= 0;
475 tuple
= SearchSysCache(TYPEOID
,
476 ObjectIdGetDatum(oidtypeid
),
478 if (!HeapTupleIsValid(tuple
))
479 elog(ERROR
, "cache lookup failed for type %u", oidtypeid
);
480 typeForm
= (Form_pg_type
) GETSTRUCT(tuple
);
482 att
->atttypid
= oidtypeid
;
483 att
->attlen
= typeForm
->typlen
;
484 att
->attbyval
= typeForm
->typbyval
;
485 att
->attalign
= typeForm
->typalign
;
486 att
->attstorage
= typeForm
->typstorage
;
488 ReleaseSysCache(tuple
);
493 * BuildDescForRelation
495 * Given a relation schema (list of ColumnDef nodes), build a TupleDesc.
497 * Note: the default assumption is no OIDs; caller may modify the returned
498 * TupleDesc if it wants OIDs. Also, tdtypeid will need to be filled in
502 BuildDescForRelation(List
*schema
)
515 * allocate a new tuple descriptor
517 natts
= list_length(schema
);
518 desc
= CreateTemplateTupleDesc(natts
, false);
519 has_not_null
= false;
525 ColumnDef
*entry
= lfirst(l
);
528 * for each entry in the list, get the name and type information from
529 * the list and have TupleDescInitEntry fill in the attribute
530 * information we need.
534 attname
= entry
->colname
;
535 atttypid
= typenameTypeId(NULL
, entry
->typename
, &atttypmod
);
536 attdim
= list_length(entry
->typename
->arrayBounds
);
538 if (entry
->typename
->setof
)
540 (errcode(ERRCODE_INVALID_TABLE_DEFINITION
),
541 errmsg("column \"%s\" cannot be declared SETOF",
544 TupleDescInitEntry(desc
, attnum
, attname
,
545 atttypid
, atttypmod
, attdim
);
547 /* Fill in additional stuff not handled by TupleDescInitEntry */
548 desc
->attrs
[attnum
- 1]->attnotnull
= entry
->is_not_null
;
549 has_not_null
|= entry
->is_not_null
;
550 desc
->attrs
[attnum
- 1]->attislocal
= entry
->is_local
;
551 desc
->attrs
[attnum
- 1]->attinhcount
= entry
->inhcount
;
556 TupleConstr
*constr
= (TupleConstr
*) palloc0(sizeof(TupleConstr
));
558 constr
->has_not_null
= true;
559 constr
->defval
= NULL
;
560 constr
->num_defval
= 0;
561 constr
->check
= NULL
;
562 constr
->num_check
= 0;
563 desc
->constr
= constr
;
576 * Build a TupleDesc given lists of column names (as String nodes),
577 * column type OIDs, and column typmods. No constraints are generated.
579 * This is essentially a cut-down version of BuildDescForRelation for use
580 * with functions returning RECORD.
583 BuildDescFromLists(List
*names
, List
*types
, List
*typmods
)
592 natts
= list_length(names
);
593 Assert(natts
== list_length(types
));
594 Assert(natts
== list_length(typmods
));
597 * allocate a new tuple descriptor
599 desc
= CreateTemplateTupleDesc(natts
, false);
603 l2
= list_head(types
);
604 l3
= list_head(typmods
);
607 char *attname
= strVal(lfirst(l1
));
611 atttypid
= lfirst_oid(l2
);
613 atttypmod
= lfirst_int(l3
);
618 TupleDescInitEntry(desc
, attnum
, attname
, atttypid
, atttypmod
, 0);