*** src/backend/parser/parse_func.c.orig Fri Dec 15 14:22:03 2000 --- src/backend/parser/parse_func.c Tue Dec 26 14:17:09 2000 *************** *** 442,451 **** /* * for func(relname), the param to the function is the tuple ! * under consideration. we build a special VarNode to reflect * this -- it has varno set to the correct range table entry, * but has varattno == 0 to signal that the whole tuple is the ! * argument. */ if (rte->relname == NULL) elog(ERROR, --- 442,453 ---- /* * for func(relname), the param to the function is the tuple ! * under consideration. We build a special VarNode to reflect * this -- it has varno set to the correct range table entry, * but has varattno == 0 to signal that the whole tuple is the ! * argument. Also, it has typmod set to sizeof(Pointer) to ! * signal that the runtime representation will be a pointer ! * not an Oid. */ if (rte->relname == NULL) elog(ERROR, *************** *** 453,459 **** toid = typenameTypeId(rte->relname); /* replace it in the arg list */ ! lfirst(i) = makeVar(vnum, 0, toid, -1, sublevels_up); } else if (!attisset) toid = exprType(arg); --- 455,465 ---- toid = typenameTypeId(rte->relname); /* replace it in the arg list */ ! lfirst(i) = makeVar(vnum, ! InvalidAttrNumber, ! toid, ! sizeof(Pointer), ! sublevels_up); } else if (!attisset) toid = exprType(arg); *** src/backend/access/common/tupdesc.c.orig Thu Nov 16 17:30:15 2000 --- src/backend/access/common/tupdesc.c Tue Dec 26 14:16:06 2000 *************** *** 352,358 **** AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1])); - /* ---------------- * allocate storage for this attribute * ---------------- --- 352,357 ---- *************** *** 362,368 **** desc->attrs[attributeNumber - 1] = att; /* ---------------- ! * initialize some of the attribute fields * ---------------- */ att->attrelid = 0; /* dummy value */ --- 361,367 ---- desc->attrs[attributeNumber - 1] = att; /* ---------------- ! * initialize the attribute fields * ---------------- */ att->attrelid = 0; /* dummy value */ *************** *** 372,378 **** else MemSet(NameStr(att->attname), 0, NAMEDATALEN); - att->attdispersion = 0; /* dummy value */ att->attcacheoff = -1; att->atttypmod = typmod; --- 371,376 ---- *************** *** 414,421 **** att->atttypid = InvalidOid; att->attlen = (int16) 0; att->attbyval = (bool) 0; - att->attstorage = 'p'; att->attalign = 'i'; return false; } --- 412,419 ---- att->atttypid = InvalidOid; att->attlen = (int16) 0; att->attbyval = (bool) 0; att->attalign = 'i'; + att->attstorage = 'p'; return false; } *************** *** 427,468 **** typeForm = (Form_pg_type) GETSTRUCT(tuple); att->atttypid = tuple->t_data->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) { att->attlen = sizeof(Oid); att->attbyval = true; att->attstorage = 'p'; } else { att->attlen = typeForm->typlen; att->attbyval = typeForm->typbyval; att->attstorage = typeForm->typstorage; } --- 425,487 ---- typeForm = (Form_pg_type) GETSTRUCT(tuple); att->atttypid = tuple->t_data->t_oid; ! /*------------------------ ! * 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 (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.) ! * ! * 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; } *** src/backend/executor/execTuples.c.orig Sat Nov 11 19:36:57 2000 --- src/backend/executor/execTuples.c Tue Dec 26 14:17:30 2000 *************** *** 835,841 **** return tupType; } ! /* TupleDesc ExecCopyTupType(TupleDesc td, int natts) { --- 835,841 ---- return tupType; } ! #ifdef NOT_USED TupleDesc ExecCopyTupType(TupleDesc td, int natts) { *************** *** 852,881 **** } return newTd; } ! */ /* ---------------------------------------------------------------- * ExecTypeFromTL * * Currently there are about 4 different places where we create * TupleDescriptors. They should all be merged, or perhaps * be rewritten to call BuildDesc(). - * - * old comments - * Forms attribute type info from the target list in the node. - * It assumes all domains are individually specified in the target list. - * It fails if the target list contains something like Emp.all - * which represents all the attributes from EMP relation. - * - * Conditions: - * The inner and outer subtrees should be initialized because it - * might be necessary to know the type infos of the subtrees. * ---------------------------------------------------------------- */ TupleDesc ExecTypeFromTL(List *targetList) { ! List *tlcdr; TupleDesc typeInfo; Resdom *resdom; Oid restype; --- 852,874 ---- } return newTd; } ! #endif /* ---------------------------------------------------------------- * ExecTypeFromTL * + * Generate a tuple descriptor for the result tuple of a targetlist. + * Note that resjunk columns, if any, are included in the result. + * * Currently there are about 4 different places where we create * TupleDescriptors. They should all be merged, or perhaps * be rewritten to call BuildDesc(). * ---------------------------------------------------------------- */ TupleDesc ExecTypeFromTL(List *targetList) { ! List *tlitem; TupleDesc typeInfo; Resdom *resdom; Oid restype; *************** *** 897,910 **** typeInfo = CreateTemplateTupleDesc(len); /* ---------------- ! * notes: get resdom from (resdom expr) ! * get_typbyval comes from src/lib/l-lisp/lsyscache.c * ---------------- */ ! tlcdr = targetList; ! while (tlcdr != NIL) { ! TargetEntry *tle = lfirst(tlcdr); if (tle->resdom != NULL) { --- 890,901 ---- typeInfo = CreateTemplateTupleDesc(len); /* ---------------- ! * scan list, generate type info for each entry * ---------------- */ ! foreach(tlitem, targetList) { ! TargetEntry *tle = lfirst(tlitem); if (tle->resdom != NULL) { *************** *** 920,926 **** 0, false); ! /* ExecSetTypeInfo(resdom->resno - 1, typeInfo, (Oid) restype, --- 911,917 ---- 0, false); ! #ifdef NOT_USED ExecSetTypeInfo(resdom->resno - 1, typeInfo, (Oid) restype, *************** *** 929,941 **** NameStr(*resdom->resname), get_typbyval(restype), get_typalign(restype)); ! */ } else { Resdom *fjRes; List *fjTlistP; ! List *fjList = lfirst(tlcdr); #ifdef SETS_FIXED TargetEntry *tle; --- 920,933 ---- NameStr(*resdom->resname), get_typbyval(restype), get_typalign(restype)); ! #endif } else { + /* XXX this branch looks fairly broken ... tgl 12/2000 */ Resdom *fjRes; List *fjTlistP; ! List *fjList = lfirst(tlitem); #ifdef SETS_FIXED TargetEntry *tle; *************** *** 953,959 **** fjRes->restypmod, 0, false); ! /* ExecSetTypeInfo(fjRes->resno - 1, typeInfo, (Oid) restype, --- 945,951 ---- fjRes->restypmod, 0, false); ! #ifdef NOT_USED ExecSetTypeInfo(fjRes->resno - 1, typeInfo, (Oid) restype, *************** *** 962,968 **** (char *) fjRes->resname, get_typbyval(restype), get_typalign(restype)); ! */ foreach(fjTlistP, lnext(fjList)) { --- 954,960 ---- (char *) fjRes->resname, get_typbyval(restype), get_typalign(restype)); ! #endif foreach(fjTlistP, lnext(fjList)) { *************** *** 978,984 **** 0, false); ! /* ExecSetTypeInfo(fjRes->resno - 1, typeInfo, (Oid) fjRes->restype, --- 970,976 ---- 0, false); ! #ifdef NOT_USED ExecSetTypeInfo(fjRes->resno - 1, typeInfo, (Oid) fjRes->restype, *************** *** 987,997 **** (char *) fjRes->resname, get_typbyval(fjRes->restype), get_typalign(fjRes->restype)); ! */ } } - - tlcdr = lnext(tlcdr); } return typeInfo; --- 979,987 ---- (char *) fjRes->resname, get_typbyval(fjRes->restype), get_typalign(fjRes->restype)); ! #endif } } } return typeInfo; *** src/backend/executor/execUtils.c.orig Thu Nov 16 17:30:20 2000 --- src/backend/executor/execUtils.c Tue Dec 26 14:17:26 2000 *************** *** 274,289 **** { List *targetList; TupleDesc tupDesc; - int len; targetList = node->targetlist; tupDesc = ExecTypeFromTL(targetList); ! len = ExecTargetListLength(targetList); ! ! if (len > 0) ! ExecAssignResultType(commonstate, tupDesc); ! else ! ExecAssignResultType(commonstate, (TupleDesc) NULL); } /* ---------------- --- 274,283 ---- { List *targetList; TupleDesc tupDesc; targetList = node->targetlist; tupDesc = ExecTypeFromTL(targetList); ! ExecAssignResultType(commonstate, tupDesc); } /* ---------------- *************** *** 582,589 **** } /* ---------------- ! * ExecFreeTypeInfo frees the array of attrbutes ! * created by ExecMakeTypeInfo and returned by ExecTypeFromTL... * ---------------- */ void --- 576,583 ---- } /* ---------------- ! * ExecFreeTypeInfo frees the array of attributes ! * created by ExecMakeTypeInfo and returned by ExecTypeFromTL * ---------------- */ void