tupdesc.c 10.9 KB
Newer Older
1 2 3 4 5 6 7 8 9
/*-------------------------------------------------------------------------
 *
 * tupdesc.c--
 *    POSTGRES tuple descriptor support code
 *
 * Copyright (c) 1994, Regents of the University of California
 *
 *
 * IDENTIFICATION
10
 *    $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.13 1997/08/18 20:51:31 momjian Exp $
11 12 13 14 15 16 17 18
 *
 * NOTES
 *    some of the executor utility code such as "ExecTypeFromTL" should be
 *    moved here.
 *
 *-------------------------------------------------------------------------
 */

19 20
#include <stdio.h>

Marc G. Fournier's avatar
Marc G. Fournier committed
21
#include <postgres.h>
22

Marc G. Fournier's avatar
Marc G. Fournier committed
23 24 25 26 27 28
#include <parser/catalog_utils.h>
#include <nodes/parsenodes.h>
#include <utils/builtins.h>
#include <utils/fcache.h>
#include <utils/tqual.h>
#include <utils/syscache.h>
29

Marc G. Fournier's avatar
Marc G. Fournier committed
30
#ifndef HAVE_MEMMOVE
Marc G. Fournier's avatar
Marc G. Fournier committed
31
# include <regex/utils.h>
32 33
#else
# include <string.h>
Marc G. Fournier's avatar
Marc G. Fournier committed
34 35
#endif

36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330
/* ----------------------------------------------------------------
 *	CreateTemplateTupleDesc
 *
 *	This function allocates and zeros a tuple descriptor structure.
 * ----------------------------------------------------------------
 */
TupleDesc
CreateTemplateTupleDesc(int natts)
{
    uint32	size;
    TupleDesc desc;
    
    /* ----------------
     *	sanity checks
     * ----------------
     */
    AssertArg(natts >= 1);
    
    /* ----------------
     *  allocate enough memory for the tuple descriptor and
     *  zero it as TupleDescInitEntry assumes that the descriptor
     *  is filled with NULL pointers.
     * ----------------
     */
    size = natts * sizeof (AttributeTupleForm);
    desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
    desc->attrs = (AttributeTupleForm*) palloc(size);
    memset(desc->attrs, 0, size);

    desc->natts = natts;

    return (desc);
}

/* ----------------------------------------------------------------
 *	CreateTupleDesc
 *
 *	This function allocates a new TupleDesc from AttributeTupleForm array
 * ----------------------------------------------------------------
 */
TupleDesc
CreateTupleDesc(int natts, AttributeTupleForm* attrs)
{
    TupleDesc desc;
    
    /* ----------------
     *	sanity checks
     * ----------------
     */
    AssertArg(natts >= 1);
    
    desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
    desc->attrs = attrs;
    desc->natts = natts;    


    return (desc);
}

/* ----------------------------------------------------------------
 *	CreateTupleDescCopy
 *
 *	This function creates a new TupleDesc by copying from an existing
 *      TupleDesc
 * 
 * ----------------------------------------------------------------
 */
TupleDesc
CreateTupleDescCopy(TupleDesc tupdesc)
{
    TupleDesc desc;
    int i, size;

    desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
    desc->natts = tupdesc->natts;
    size = desc->natts * sizeof (AttributeTupleForm);
    desc->attrs = (AttributeTupleForm*) palloc(size);
    for (i=0;i<desc->natts;i++) {
	desc->attrs[i] = 
	    (AttributeTupleForm)palloc(ATTRIBUTE_TUPLE_SIZE);
	memmove(desc->attrs[i],
		tupdesc->attrs[i],
		ATTRIBUTE_TUPLE_SIZE);
    }
    return desc;
}

/* ----------------------------------------------------------------
 *	TupleDescInitEntry
 *
 *	This function initializes a single attribute structure in
 *	a preallocated tuple descriptor.
 * ----------------------------------------------------------------
 */
bool
TupleDescInitEntry(TupleDesc desc,
		   AttrNumber attributeNumber,
		   char *attributeName,
		   char *typeName,
		   int attdim,
		   bool attisset)
{
    HeapTuple		tuple;
    TypeTupleForm	typeForm;
    AttributeTupleForm	att;
    
    /* ----------------
     *	sanity checks
     * ----------------
     */
    AssertArg(PointerIsValid(desc));
    AssertArg(attributeNumber >= 1);
    /* attributeName's are sometimes NULL, 
       from resdom's.  I don't know why that is, though -- Jolly */
/*    AssertArg(NameIsValid(attributeName));*/
/*    AssertArg(NameIsValid(typeName));*/
    
    AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1]));
    

    /* ----------------
     *	allocate storage for this attribute
     * ----------------
     */

    att = (AttributeTupleForm) palloc(ATTRIBUTE_TUPLE_SIZE);
    desc->attrs[attributeNumber - 1] = att;

    /* ----------------
     *	initialize some of the attribute fields
     * ----------------
     */
    att->attrelid  = 0;				/* dummy value */
    
    if (attributeName != NULL)
	namestrcpy(&(att->attname), attributeName);
    else
	memset(att->attname.data,0,NAMEDATALEN);

    
    att->attdefrel = 	0;			/* dummy value */
    att->attnvals  = 	0;			/* dummy value */
    att->atttyparg = 	0;			/* dummy value */
    att->attbound = 	0;			/* dummy value */
    att->attcanindex = 	0;			/* dummy value */
    att->attproc = 	0;			/* dummy value */
    att->attcacheoff = 	-1;
    
    att->attnum = attributeNumber;
    att->attnelems = attdim;
    att->attisset = attisset;
    
    /* ----------------
     *	search the system cache for the type tuple of the attribute
     *  we are creating so that we can get the typeid and some other
     *  stuff.
     *
     *  Note: in the special case of 
     *
     *	    create EMP (name = char16, manager = EMP)
     *
     *  RelationNameCreateHeapRelation() calls BuildDesc() which
     *  calls this routine and since EMP does not exist yet, the
     *  system cache lookup below fails.  That's fine, but rather
     *  then doing a elog(WARN) we just leave that information
     *  uninitialized, return false, then fix things up later.
     *  -cim 6/14/90
     * ----------------
     */
    tuple = SearchSysCacheTuple(TYPNAME, PointerGetDatum(typeName),
				0,0,0);
    if (! HeapTupleIsValid(tuple)) {
	/* ----------------
	 *   here type info does not exist yet so we just fill
	 *   the attribute with dummy information and return false.
	 * ----------------
	 */
	att->atttypid = InvalidOid;
	att->attlen   = (int16)	0;
	att->attbyval = (bool) 0;
	att->attalign = 'i';
	return false;
    }
    
    /* ----------------
     *	type info exists so we initialize our attribute
     *  information from the type tuple we found..
     * ----------------
     */
    typeForm = (TypeTupleForm) GETSTRUCT(tuple);
    
    att->atttypid = tuple->t_oid;
    att->attalign = typeForm->typalign;
    
    /* ------------------------
       If this attribute is a set, what is really stored in the
       attribute is the OID of a tuple in the pg_proc catalog.
       The pg_proc tuple contains the query string which defines
       this set - i.e., the query to run to get the set.
       So the atttypid (just assigned above) refers to the type returned
       by this query, but the actual length of this attribute is the
       length (size) of an OID.
       
       Why not just make the atttypid point to the OID type, instead
       of the type the query returns?  Because the executor uses the atttypid
       to tell the front end what type will be returned (in BeginCommand),
       and in the end the type returned will be the result of the query, not
       an OID.
       
       Why not wait until the return type of the set is known (i.e., the
       recursive call to the executor to execute the set has returned) 
       before telling the front end what the return type will be?  Because
       the executor is a delicate thing, and making sure that the correct
       order of front-end commands is maintained is messy, especially 
       considering that target lists may change as inherited attributes
       are considered, etc.  Ugh.
       -----------------------------------------
       */
    if (attisset) {
	Type t = type("oid");
	att->attlen = tlen(t);
	att->attbyval = tbyval(t);
    } else {
	att->attlen   = typeForm->typlen;
	att->attbyval = typeForm->typbyval;
    }
    
    
    return true;
}


/* ----------------------------------------------------------------
 *	TupleDescMakeSelfReference
 *
 *	This function initializes a "self-referential" attribute like
 *      manager in "create EMP (name=text, manager = EMP)".
 *	It calls TypeShellMake() which inserts a "shell" type
 *	tuple into pg_type.  A self-reference is one kind of set, so
 *      its size and byval are the same as for a set.  See the comments
 *      above in TupleDescInitEntry.
 * ----------------------------------------------------------------
 */
static void
TupleDescMakeSelfReference(TupleDesc desc,
			   AttrNumber attnum,
			   char *relname)
{
    AttributeTupleForm att;
    Type t = type("oid");
    
    att = desc->attrs[attnum-1];
    att->atttypid = TypeShellMake(relname);
    att->attlen   = tlen(t);
    att->attbyval = tbyval(t);
    att->attnelems = 0;
}

/* ----------------------------------------------------------------
 *	BuildDescForRelation
 *
 *	This is a general purpose function identical to BuildDesc
 *	but is used by the DefineRelation() code to catch the
 *	special case where you
 *
 *		create FOO ( ..., x = FOO )
 *
 *	here, the initial type lookup for "x = FOO" will fail
 *	because FOO isn't in the catalogs yet.  But since we
 *	are creating FOO, instead of doing an elog() we add
 *	a shell type tuple to pg_type and fix things later
 *	in amcreate().
 * ----------------------------------------------------------------
 */
TupleDesc
BuildDescForRelation(List *schema, char *relname)
{
    int			natts;
    AttrNumber		attnum;
    List		*p;
    TupleDesc		desc;
    char               *attname;
    char               *typename;
    int			attdim;
    bool                attisset;
    
    /* ----------------
     *	allocate a new tuple descriptor
     * ----------------
     */
    natts = 	length(schema);
    desc = 	CreateTemplateTupleDesc(natts);
    
    attnum = 0;
    
Bruce Momjian's avatar
Bruce Momjian committed
331
    typename = palloc(NAMEDATALEN);
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349

    foreach(p, schema) {
	ColumnDef *entry;
	List	*arry;

	/* ----------------
	 *	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++;
	
	entry = 	lfirst(p);
	attname = 	entry->colname;
	arry = entry->typename->arrayBounds;
	attisset = entry->typename->setof;

350 351
	strNcpy(typename, entry->typename->name,NAMEDATALEN-1);
	if (arry != NIL)
352
	    attdim = length(arry);
353
	else
354 355 356 357 358 359 360 361 362 363 364 365 366 367
	    attdim = 0;
	
	if (! TupleDescInitEntry(desc, attnum, attname, 
				 typename, attdim, attisset)) {
	    /* ----------------
	     *	if TupleDescInitEntry() fails, it means there is
	     *  no type in the system catalogs.  So now we check if
	     *  the type name equals the relation name.  If so we
	     *  have a self reference, otherwise it's an error.
	     * ----------------
	     */
	    if (!strcmp(typename, relname)) {
		TupleDescMakeSelfReference(desc, attnum, relname);
	    } else
368 369
		elog(WARN, "DefineRelation: no such type %s", 
		     typename);
370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
	}

	/*
	 * this is for char() and varchar(). When an entry is of type
	 * char() or varchar(), typlen is set to the appropriate length,
	 * which we'll use here instead. (The catalog lookup only returns
	 * the length of bpchar and varchar which is not what we want!)
	 *						- ay 6/95
	 */
	if (entry->typename->typlen > 0) {
	    desc->attrs[attnum - 1]->attlen = entry->typename->typlen;
	}
    }
    return desc;
}