]> granicus.if.org Git - postgresql/blob - src/backend/access/common/tupdesc.c
Reimplement parsing and storage of default expressions and constraint
[postgresql] / src / backend / access / common / tupdesc.c
1 /*-------------------------------------------------------------------------
2  *
3  * tupdesc.c
4  *        POSTGRES tuple descriptor support code
5  *
6  * Copyright (c) 1994, Regents of the University of California
7  *
8  *
9  * IDENTIFICATION
10  *        $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.55 1999/10/03 23:55:25 tgl Exp $
11  *
12  * NOTES
13  *        some of the executor utility code such as "ExecTypeFromTL" should be
14  *        moved here.
15  *
16  *-------------------------------------------------------------------------
17  */
18
19 #include "postgres.h"
20
21 #include "catalog/pg_type.h"
22 #include "nodes/parsenodes.h"
23 #include "parser/parse_type.h"
24 #include "utils/builtins.h"
25 #include "utils/syscache.h"
26
27
28 /* ----------------------------------------------------------------
29  *              CreateTemplateTupleDesc
30  *
31  *              This function allocates and zeros a tuple descriptor structure.
32  * ----------------------------------------------------------------
33  */
34 TupleDesc
35 CreateTemplateTupleDesc(int natts)
36 {
37         uint32          size;
38         TupleDesc       desc;
39
40         /* ----------------
41          *      sanity checks
42          * ----------------
43          */
44         AssertArg(natts >= 1);
45
46         /* ----------------
47          *      allocate enough memory for the tuple descriptor and
48          *      zero it as TupleDescInitEntry assumes that the descriptor
49          *      is filled with NULL pointers.
50          * ----------------
51          */
52         size = natts * sizeof(Form_pg_attribute);
53         desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
54         desc->attrs = (Form_pg_attribute *) palloc(size);
55         desc->constr = NULL;
56         MemSet(desc->attrs, 0, size);
57
58         desc->natts = natts;
59
60         return desc;
61 }
62
63 /* ----------------------------------------------------------------
64  *              CreateTupleDesc
65  *
66  *              This function allocates a new TupleDesc from Form_pg_attribute array
67  * ----------------------------------------------------------------
68  */
69 TupleDesc
70 CreateTupleDesc(int natts, Form_pg_attribute *attrs)
71 {
72         TupleDesc       desc;
73
74         /* ----------------
75          *      sanity checks
76          * ----------------
77          */
78         AssertArg(natts >= 1);
79
80         desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
81         desc->attrs = attrs;
82         desc->natts = natts;
83         desc->constr = NULL;
84
85         return desc;
86 }
87
88 /* ----------------------------------------------------------------
89  *              CreateTupleDescCopy
90  *
91  *              This function creates a new TupleDesc by copying from an existing
92  *              TupleDesc
93  *
94  *              !!! Constraints are not copied !!!
95  * ----------------------------------------------------------------
96  */
97 TupleDesc
98 CreateTupleDescCopy(TupleDesc tupdesc)
99 {
100         TupleDesc       desc;
101         int                     i,
102                                 size;
103
104         desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
105         desc->natts = tupdesc->natts;
106         size = desc->natts * sizeof(Form_pg_attribute);
107         desc->attrs = (Form_pg_attribute *) palloc(size);
108         for (i = 0; i < desc->natts; i++)
109         {
110                 desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
111                 memmove(desc->attrs[i],
112                                 tupdesc->attrs[i],
113                                 ATTRIBUTE_TUPLE_SIZE);
114                 desc->attrs[i]->attnotnull = false;
115                 desc->attrs[i]->atthasdef = false;
116         }
117         desc->constr = NULL;
118
119         return desc;
120 }
121
122 /* ----------------------------------------------------------------
123  *              CreateTupleDescCopyConstr
124  *
125  *              This function creates a new TupleDesc by copying from an existing
126  *              TupleDesc (with Constraints)
127  *
128  * ----------------------------------------------------------------
129  */
130 TupleDesc
131 CreateTupleDescCopyConstr(TupleDesc tupdesc)
132 {
133         TupleDesc       desc;
134         TupleConstr *constr = tupdesc->constr;
135         int                     i,
136                                 size;
137
138         desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
139         desc->natts = tupdesc->natts;
140         size = desc->natts * sizeof(Form_pg_attribute);
141         desc->attrs = (Form_pg_attribute *) palloc(size);
142         for (i = 0; i < desc->natts; i++)
143         {
144                 desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
145                 memmove(desc->attrs[i],
146                                 tupdesc->attrs[i],
147                                 ATTRIBUTE_TUPLE_SIZE);
148         }
149         if (constr)
150         {
151                 TupleConstr *cpy = (TupleConstr *) palloc(sizeof(TupleConstr));
152
153                 cpy->has_not_null = constr->has_not_null;
154
155                 if ((cpy->num_defval = constr->num_defval) > 0)
156                 {
157                         cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
158                         memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
159                         for (i = cpy->num_defval - 1; i >= 0; i--)
160                         {
161                                 if (constr->defval[i].adbin)
162                                         cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
163                         }
164                 }
165
166                 if ((cpy->num_check = constr->num_check) > 0)
167                 {
168                         cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
169                         memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
170                         for (i = cpy->num_check - 1; i >= 0; i--)
171                         {
172                                 if (constr->check[i].ccname)
173                                         cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
174                                 if (constr->check[i].ccbin)
175                                         cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
176                         }
177                 }
178
179                 desc->constr = cpy;
180         }
181         else
182                 desc->constr = NULL;
183
184         return desc;
185 }
186
187 void
188 FreeTupleDesc(TupleDesc tupdesc)
189 {
190         int                     i;
191
192         for (i = 0; i < tupdesc->natts; i++)
193                 pfree(tupdesc->attrs[i]);
194         pfree(tupdesc->attrs);
195         if (tupdesc->constr)
196         {
197                 if (tupdesc->constr->num_defval > 0)
198                 {
199                         AttrDefault *attrdef = tupdesc->constr->defval;
200
201                         for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
202                         {
203                                 if (attrdef[i].adbin)
204                                         pfree(attrdef[i].adbin);
205                         }
206                         pfree(attrdef);
207                 }
208                 if (tupdesc->constr->num_check > 0)
209                 {
210                         ConstrCheck *check = tupdesc->constr->check;
211
212                         for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
213                         {
214                                 if (check[i].ccname)
215                                         pfree(check[i].ccname);
216                                 if (check[i].ccbin)
217                                         pfree(check[i].ccbin);
218                         }
219                         pfree(check);
220                 }
221                 pfree(tupdesc->constr);
222         }
223
224         pfree(tupdesc);
225
226 }
227
228 /* ----------------------------------------------------------------
229  *              TupleDescInitEntry
230  *
231  *              This function initializes a single attribute structure in
232  *              a preallocated tuple descriptor.
233  * ----------------------------------------------------------------
234  */
235 bool
236 TupleDescInitEntry(TupleDesc desc,
237                                    AttrNumber attributeNumber,
238                                    char *attributeName,
239                                    Oid typeid,
240                                    int32 typmod,
241                                    int attdim,
242                                    bool attisset)
243 {
244         HeapTuple       tuple;
245         Form_pg_type typeForm;
246         Form_pg_attribute att;
247
248         /* ----------------
249          *      sanity checks
250          * ----------------
251          */
252         AssertArg(PointerIsValid(desc));
253         AssertArg(attributeNumber >= 1);
254
255         /*
256          * attributeName's are sometimes NULL, from resdom's.  I don't know
257          * why that is, though -- Jolly
258          */
259 /*        AssertArg(NameIsValid(attributeName));*/
260
261         AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1]));
262
263
264         /* ----------------
265          *      allocate storage for this attribute
266          * ----------------
267          */
268
269         att = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
270         desc->attrs[attributeNumber - 1] = att;
271
272         /* ----------------
273          *      initialize some of the attribute fields
274          * ----------------
275          */
276         att->attrelid = 0;                      /* dummy value */
277
278         if (attributeName != NULL)
279                 namestrcpy(&(att->attname), attributeName);
280         else
281                 MemSet(att->attname.data, 0, NAMEDATALEN);
282
283
284         att->attdisbursion = 0;         /* dummy value */
285         att->attcacheoff = -1;
286         att->atttypmod = typmod;
287
288         att->attnum = attributeNumber;
289         att->attnelems = attdim;
290         att->attisset = attisset;
291
292         att->attnotnull = false;
293         att->atthasdef = false;
294
295         /* ----------------
296          *      search the system cache for the type tuple of the attribute
297          *      we are creating so that we can get the typeid and some other
298          *      stuff.
299          *
300          *      Note: in the special case of
301          *
302          *              create EMP (name = text, manager = EMP)
303          *
304          *      RelationNameCreateHeapRelation() calls BuildDesc() which
305          *      calls this routine and since EMP does not exist yet, the
306          *      system cache lookup below fails.  That's fine, but rather
307          *      then doing a elog(ERROR) we just leave that information
308          *      uninitialized, return false, then fix things up later.
309          *      -cim 6/14/90
310          * ----------------
311          */
312         tuple = SearchSysCacheTuple(TYPOID,
313                                                                 ObjectIdGetDatum(typeid),
314                                                                 0, 0, 0);
315         if (!HeapTupleIsValid(tuple))
316         {
317                 /* ----------------
318                  *       here type info does not exist yet so we just fill
319                  *       the attribute with dummy information and return false.
320                  * ----------------
321                  */
322                 att->atttypid = InvalidOid;
323                 att->attlen = (int16) 0;
324                 att->attbyval = (bool) 0;
325                 att->attalign = 'i';
326                 return false;
327         }
328
329         /* ----------------
330          *      type info exists so we initialize our attribute
331          *      information from the type tuple we found..
332          * ----------------
333          */
334         typeForm = (Form_pg_type) GETSTRUCT(tuple);
335
336         att->atttypid = tuple->t_data->t_oid;
337         att->attalign = typeForm->typalign;
338
339         /* ------------------------
340            If this attribute is a set, what is really stored in the
341            attribute is the OID of a tuple in the pg_proc catalog.
342            The pg_proc tuple contains the query string which defines
343            this set - i.e., the query to run to get the set.
344            So the atttypid (just assigned above) refers to the type returned
345            by this query, but the actual length of this attribute is the
346            length (size) of an OID.
347
348            Why not just make the atttypid point to the OID type, instead
349            of the type the query returns?  Because the executor uses the atttypid
350            to tell the front end what type will be returned (in BeginCommand),
351            and in the end the type returned will be the result of the query, not
352            an OID.
353
354            Why not wait until the return type of the set is known (i.e., the
355            recursive call to the executor to execute the set has returned)
356            before telling the front end what the return type will be?  Because
357            the executor is a delicate thing, and making sure that the correct
358            order of front-end commands is maintained is messy, especially
359            considering that target lists may change as inherited attributes
360            are considered, etc.  Ugh.
361            -----------------------------------------
362            */
363         if (attisset)
364         {
365                 Type            t = typeidType(OIDOID);
366
367                 att->attlen = typeLen(t);
368                 att->attbyval = typeByVal(t);
369         }
370         else
371         {
372                 att->attlen = typeForm->typlen;
373                 att->attbyval = typeForm->typbyval;
374         }
375
376
377         return true;
378 }
379
380
381 /* ----------------------------------------------------------------
382  *              TupleDescMakeSelfReference
383  *
384  *              This function initializes a "self-referential" attribute like
385  *              manager in "create EMP (name=text, manager = EMP)".
386  *              It calls TypeShellMake() which inserts a "shell" type
387  *              tuple into pg_type.  A self-reference is one kind of set, so
388  *              its size and byval are the same as for a set.  See the comments
389  *              above in TupleDescInitEntry.
390  * ----------------------------------------------------------------
391  */
392 static void
393 TupleDescMakeSelfReference(TupleDesc desc,
394                                                    AttrNumber attnum,
395                                                    char *relname)
396 {
397         Form_pg_attribute att;
398         Type            t = typeidType(OIDOID);
399
400         att = desc->attrs[attnum - 1];
401         att->atttypid = TypeShellMake(relname);
402         att->attlen = typeLen(t);
403         att->attbyval = typeByVal(t);
404         att->attnelems = 0;
405 }
406
407 /* ----------------------------------------------------------------
408  *              BuildDescForRelation
409  *
410  *              This is a general purpose function identical to BuildDesc
411  *              but is used by the DefineRelation() code to catch the
412  *              special case where you
413  *
414  *                              create FOO ( ..., x = FOO )
415  *
416  *              here, the initial type lookup for "x = FOO" will fail
417  *              because FOO isn't in the catalogs yet.  But since we
418  *              are creating FOO, instead of doing an elog() we add
419  *              a shell type tuple to pg_type and fix things later
420  *              in amcreate().
421  * ----------------------------------------------------------------
422  */
423 TupleDesc
424 BuildDescForRelation(List *schema, char *relname)
425 {
426         int                     natts;
427         AttrNumber      attnum;
428         List       *p;
429         TupleDesc       desc;
430         AttrDefault *attrdef = NULL;
431         TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr));
432         char       *attname;
433         char            typename[NAMEDATALEN];
434         int32           atttypmod;
435         int                     attdim;
436         int                     ndef = 0;
437         bool            attisset;
438
439         /* ----------------
440          *      allocate a new tuple descriptor
441          * ----------------
442          */
443         natts = length(schema);
444         desc = CreateTemplateTupleDesc(natts);
445         constr->has_not_null = false;
446
447         attnum = 0;
448
449         foreach(p, schema)
450         {
451                 ColumnDef  *entry = lfirst(p);
452                 List       *arry;
453
454                 /* ----------------
455                  *              for each entry in the list, get the name and type
456                  *              information from the list and have TupleDescInitEntry
457                  *              fill in the attribute information we need.
458                  * ----------------
459                  */
460                 attnum++;
461
462                 attname = entry->colname;
463                 arry = entry->typename->arrayBounds;
464                 attisset = entry->typename->setof;
465                 atttypmod = entry->typename->typmod;
466
467                 if (arry != NIL)
468                 {
469                         /* array of XXX is _XXX */
470                         snprintf(typename, NAMEDATALEN,
471                                          "_%.*s", NAMEDATALEN - 2, entry->typename->name);
472                         attdim = length(arry);
473                 }
474                 else
475                 {
476                         StrNCpy(typename, entry->typename->name, NAMEDATALEN);
477                         attdim = 0;
478                 }
479
480                 if (!TupleDescInitEntry(desc, attnum, attname,
481                                                                 typeTypeId(typenameType(typename)),
482                                                                 atttypmod, attdim, attisset))
483                 {
484                         /* ----------------
485                          *      if TupleDescInitEntry() fails, it means there is
486                          *      no type in the system catalogs.  So now we check if
487                          *      the type name equals the relation name.  If so we
488                          *      have a self reference, otherwise it's an error.
489                          * ----------------
490                          */
491                         if (!strcmp(typename, relname))
492                                 TupleDescMakeSelfReference(desc, attnum, relname);
493                         else
494                                 elog(ERROR, "DefineRelation: no such type %s",
495                                          typename);
496                 }
497
498                 desc->attrs[attnum - 1]->atttypmod = entry->typename->typmod;
499
500                 /* This is for constraints */
501                 if (entry->is_not_null)
502                         constr->has_not_null = true;
503                 desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;
504
505                 /* Note we copy only pre-cooked default expressions.
506                  * Digestion of raw ones is someone else's problem.
507                  */
508                 if (entry->cooked_default != NULL)
509                 {
510                         if (attrdef == NULL)
511                                 attrdef = (AttrDefault *) palloc(natts * sizeof(AttrDefault));
512                         attrdef[ndef].adnum = attnum;
513                         attrdef[ndef].adbin = pstrdup(entry->cooked_default);
514                         ndef++;
515                         desc->attrs[attnum - 1]->atthasdef = true;
516                 }
517
518         }
519         if (constr->has_not_null || ndef > 0)
520         {
521                 desc->constr = constr;
522
523                 if (ndef > 0)                   /* DEFAULTs */
524                 {
525                         if (ndef < natts)
526                                 constr->defval = (AttrDefault *)
527                                         repalloc(attrdef, ndef * sizeof(AttrDefault));
528                         else
529                                 constr->defval = attrdef;
530                         constr->num_defval = ndef;
531                 }
532                 else
533                 {
534                         constr->defval = NULL;
535                         constr->num_defval = 0;
536                 }
537                 constr->check = NULL;
538                 constr->num_check = 0;
539         }
540         else
541         {
542                 pfree(constr);
543                 desc->constr = NULL;
544         }
545         return desc;
546 }