📄 tupdesc.c
字号:
TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim, bool attisset){ HeapTuple tuple; Form_pg_type typeForm; Form_pg_attribute att; /* * sanity checks */ AssertArg(PointerIsValid(desc)); AssertArg(attributeNumber >= 1); AssertArg(attributeNumber <= desc->natts); AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1])); /* * allocate storage for this attribute */ att = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); desc->attrs[attributeNumber - 1] = att; /* * initialize the attribute fields */ 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->attisset = attisset; 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); /* * type info exists so we initialize our attribute information from * the type tuple we found.. */ typeForm = (Form_pg_type) GETSTRUCT(tuple); att->atttypid = HeapTupleGetOid(tuple); /* * There are a couple of cases where we must override the information * stored in pg_type. * * First: 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, 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.) * * Second: if we are dealing with a complex type (a tuple type), then * pg_type will say that the representation is the same as Oid. But * if typmod is sizeof(Pointer) then the internal representation is * actually a pointer to a TupleTableSlot, and we have to substitute * that information. * * A set of complex type is first and foremost a set, so its * representation is Oid not pointer. So, test that case first. */ if (attisset) { att->attlen = sizeof(Oid); att->attbyval = true; att->attalign = 'i'; att->attstorage = 'p'; } else if (typeForm->typtype == 'c' && typmod == sizeof(Pointer)) { att->attlen = sizeof(Pointer); att->attbyval = true; att->attalign = 'd'; /* kluge to work with 8-byte pointers */ /* XXX ought to have a separate attalign value for pointers ... */ att->attstorage = 'p'; } else { 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. */TupleDescBuildDescForRelation(List *schema){ int natts; AttrNumber attnum; List *p; TupleDesc desc; AttrDefault *attrdef = NULL; TupleConstr *constr = (TupleConstr *) palloc(sizeof(TupleConstr)); char *attname; int32 atttypmod; int attdim; int ndef = 0; bool attisset; /* * allocate a new tuple descriptor */ natts = length(schema); desc = CreateTemplateTupleDesc(natts, false); constr->has_not_null = false; attnum = 0; foreach(p, schema) { ColumnDef *entry = lfirst(p); /* * 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; attisset = entry->typename->setof; atttypmod = entry->typename->typmod; attdim = length(entry->typename->arrayBounds); TupleDescInitEntry(desc, attnum, attname, typenameTypeId(entry->typename), atttypmod, attdim, attisset); /* 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;}/* * RelationNameGetTupleDesc * * Given a (possibly qualified) relation name, build a TupleDesc. */TupleDescRelationNameGetTupleDesc(const char *relname){ RangeVar *relvar; Relation rel; TupleDesc tupdesc; List *relname_list; /* Open relation and get the tuple description */ relname_list = stringToQualifiedNameList(relname, "RelationNameGetTupleDesc"); relvar = makeRangeVarFromNameList(relname_list); rel = relation_openrv(relvar, AccessShareLock); tupdesc = CreateTupleDescCopy(RelationGetDescr(rel)); relation_close(rel, AccessShareLock); return tupdesc;}/* * TypeGetTupleDesc * * Given a type Oid, build a TupleDesc. * * If the type is composite, *and* a colaliases List is provided, *and* * the List is of natts length, use the aliases instead of the relation * attnames. * * If the type is a base type, a single item alias List is required. */TupleDescTypeGetTupleDesc(Oid typeoid, List *colaliases){ char functyptype = get_typtype(typeoid); TupleDesc tupdesc = NULL; /* * Build a suitable tupledesc representing the output rows */ if (functyptype == 'c') { /* Composite data type, i.e. a table's row type */ Oid relid = typeidTypeRelid(typeoid); Relation rel; int natts; if (!OidIsValid(relid)) elog(ERROR, "invalid typrelid for complex type %u", typeoid); rel = relation_open(relid, AccessShareLock); tupdesc = CreateTupleDescCopy(RelationGetDescr(rel)); natts = tupdesc->natts; relation_close(rel, AccessShareLock); /* XXX should we hold the lock to ensure table doesn't change? */ if (colaliases != NIL) { int varattno; /* does the list length match the number of attributes? */ if (length(colaliases) != natts) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("number of aliases does not match number of columns"))); /* OK, use the aliases instead */ for (varattno = 0; varattno < natts; varattno++) { char *label = strVal(nth(varattno, colaliases)); if (label != NULL) namestrcpy(&(tupdesc->attrs[varattno]->attname), label); } } } else if (functyptype == 'b' || functyptype == 'd') { /* Must be a base data type, i.e. scalar */ char *attname; /* the alias list is required for base types */ if (colaliases == NIL) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("no column alias was provided"))); /* the alias list length must be 1 */ if (length(colaliases) != 1) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("number of aliases does not match number of columns"))); /* OK, get the column alias */ attname = strVal(lfirst(colaliases)); tupdesc = CreateTemplateTupleDesc(1, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, attname, typeoid, -1, 0, false); } else if (functyptype == 'p' && typeoid == RECORDOID) ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("could not determine row description for function returning record"))); else { /* crummy error message, but parser should have caught this */ elog(ERROR, "function in FROM has unsupported return type"); } return tupdesc;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -