Tom Lane <[EMAIL PROTECTED]> writes: > That would be okay with me. It might be a good idea to change the > name completely (perhaps CopyTupleDesc() ?) as a means of catching > places that aren't correctly updated.
Done, and done -- a revised patch is attached. -Neil
Index: src/backend/access/common/tupdesc.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/backend/access/common/tupdesc.c,v retrieving revision 1.100 diff -c -r1.100 tupdesc.c *** src/backend/access/common/tupdesc.c 25 Sep 2003 06:57:56 -0000 1.100 --- src/backend/access/common/tupdesc.c 20 Nov 2003 21:43:47 -0000 *************** *** 96,204 **** } /* ---------------------------------------------------------------- ! * CreateTupleDescCopy * ! * This function creates a new TupleDesc by copying from an existing ! * TupleDesc ! * ! * !!! Constraints are not copied !!! * ---------------------------------------------------------------- */ TupleDesc ! CreateTupleDescCopy(TupleDesc tupdesc) { ! TupleDesc desc; ! int i, ! size; ! desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); ! desc->natts = tupdesc->natts; ! if (desc->natts > 0) ! { ! size = desc->natts * sizeof(Form_pg_attribute); ! desc->attrs = (Form_pg_attribute *) palloc(size); ! for (i = 0; i < desc->natts; i++) ! { ! desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); ! memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE); ! desc->attrs[i]->attnotnull = false; ! desc->attrs[i]->atthasdef = false; ! } ! } ! else ! desc->attrs = NULL; ! desc->constr = NULL; ! desc->tdhasoid = tupdesc->tdhasoid; ! return desc; ! } ! ! /* ---------------------------------------------------------------- ! * CreateTupleDescCopyConstr ! * ! * This function creates a new TupleDesc by copying from an existing ! * TupleDesc (with Constraints) ! * ---------------------------------------------------------------- ! */ ! TupleDesc ! CreateTupleDescCopyConstr(TupleDesc tupdesc) ! { ! TupleDesc desc; ! TupleConstr *constr = tupdesc->constr; ! int i, ! size; ! desc = (TupleDesc) palloc(sizeof(struct tupleDesc)); ! desc->natts = tupdesc->natts; ! if (desc->natts > 0) ! { ! size = desc->natts * sizeof(Form_pg_attribute); ! desc->attrs = (Form_pg_attribute *) palloc(size); ! for (i = 0; i < desc->natts; i++) { ! desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); ! memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE); } } else ! desc->attrs = NULL; ! if (constr) { ! TupleConstr *cpy = (TupleConstr *) palloc(sizeof(TupleConstr)); ! cpy->has_not_null = constr->has_not_null; ! if ((cpy->num_defval = constr->num_defval) > 0) { ! cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault)); ! memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault)); ! for (i = cpy->num_defval - 1; i >= 0; i--) { if (constr->defval[i].adbin) ! cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin); } } ! if ((cpy->num_check = constr->num_check) > 0) { ! cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck)); ! memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck)); ! for (i = cpy->num_check - 1; i >= 0; i--) { if (constr->check[i].ccname) ! cpy->check[i].ccname = pstrdup(constr->check[i].ccname); if (constr->check[i].ccbin) ! cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin); } } ! desc->constr = cpy; } - else - desc->constr = NULL; ! desc->tdhasoid = tupdesc->tdhasoid; ! return desc; } void --- 96,183 ---- } /* ---------------------------------------------------------------- ! * CopyTupleDesc * ! * This function creates a new TupleDesc by copying from an ! * existing TupleDesc. Iff 'copyConstr' is true, the constraints ! * on the input TupleDesc are also copied. * ---------------------------------------------------------------- */ TupleDesc ! CopyTupleDesc(TupleDesc tupDesc, bool copyConstr) { ! TupleDesc result; ! int i; ! result = (TupleDesc) palloc(sizeof(*result)); ! result->natts = tupDesc->natts; ! result->tdhasoid = tupDesc->tdhasoid; ! result->constr = NULL; ! if (result->natts > 0) ! { ! int size; ! size = result->natts * sizeof(Form_pg_attribute); ! result->attrs = (Form_pg_attribute *) palloc(size); ! for (i = 0; i < result->natts; i++) { ! result->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE); ! memcpy(result->attrs[i], tupDesc->attrs[i], ATTRIBUTE_TUPLE_SIZE); ! ! /* ! * If we're not copying constraints, fix up the attributes ! * to remove NOT NULL or DEFAULT indicators. ! */ ! if (!copyConstr) ! { ! result->attrs[i]->attnotnull = false; ! result->attrs[i]->atthasdef = false; ! } } } else ! result->attrs = NULL; ! ! if (copyConstr && tupDesc->constr) { ! TupleConstr *constr; ! constr = (TupleConstr *) palloc(sizeof(*constr)); ! memcpy(constr, tupDesc->constr, sizeof(*constr)); ! constr->defval = NULL; ! constr->check = NULL; ! if (constr->num_defval > 0) { ! constr->defval = (AttrDefault *) palloc(constr->num_defval * sizeof(AttrDefault)); ! memcpy(constr->defval, tupDesc->constr->defval, ! constr->num_defval * sizeof(AttrDefault)); ! for (i = constr->num_defval - 1; i >= 0; i--) { if (constr->defval[i].adbin) ! constr->defval[i].adbin = pstrdup(constr->defval[i].adbin); } } ! if (constr->num_check > 0) { ! constr->check = (ConstrCheck *) palloc(constr->num_check * sizeof(ConstrCheck)); ! memcpy(constr->check, tupDesc->constr->check, ! constr->num_check * sizeof(ConstrCheck)); ! for (i = constr->num_check - 1; i >= 0; i--) { if (constr->check[i].ccname) ! constr->check[i].ccname = pstrdup(constr->check[i].ccname); if (constr->check[i].ccbin) ! constr->check[i].ccbin = pstrdup(constr->check[i].ccbin); } } ! result->constr = constr; } ! return result; } void *************** *** 607,613 **** relname_list = stringToQualifiedNameList(relname, "RelationNameGetTupleDesc"); relvar = makeRangeVarFromNameList(relname_list); rel = relation_openrv(relvar, AccessShareLock); ! tupdesc = CreateTupleDescCopy(RelationGetDescr(rel)); relation_close(rel, AccessShareLock); return tupdesc; --- 586,592 ---- relname_list = stringToQualifiedNameList(relname, "RelationNameGetTupleDesc"); relvar = makeRangeVarFromNameList(relname_list); rel = relation_openrv(relvar, AccessShareLock); ! tupdesc = CopyTupleDesc(RelationGetDescr(rel), false); relation_close(rel, AccessShareLock); return tupdesc; *************** *** 644,650 **** 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? */ --- 623,629 ---- elog(ERROR, "invalid typrelid for complex type %u", typeoid); rel = relation_open(relid, AccessShareLock); ! tupdesc = CopyTupleDesc(RelationGetDescr(rel), false); natts = tupdesc->natts; relation_close(rel, AccessShareLock); /* XXX should we hold the lock to ensure table doesn't change? */ Index: src/backend/commands/cluster.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/backend/commands/cluster.c,v retrieving revision 1.118 diff -c -r1.118 cluster.c *** src/backend/commands/cluster.c 12 Nov 2003 21:15:49 -0000 1.118 --- src/backend/commands/cluster.c 20 Nov 2003 21:19:36 -0000 *************** *** 494,500 **** * Need to make a copy of the tuple descriptor, since * heap_create_with_catalog modifies it. */ ! tupdesc = CreateTupleDescCopyConstr(OldHeapDesc); OIDNewHeap = heap_create_with_catalog(NewName, RelationGetNamespace(OldHeap), --- 494,500 ---- * Need to make a copy of the tuple descriptor, since * heap_create_with_catalog modifies it. */ ! tupdesc = CopyTupleDesc(OldHeapDesc, true); OIDNewHeap = heap_create_with_catalog(NewName, RelationGetNamespace(OldHeap), Index: src/backend/commands/portalcmds.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/backend/commands/portalcmds.c,v retrieving revision 1.24 diff -c -r1.24 portalcmds.c *** src/backend/commands/portalcmds.c 24 Aug 2003 21:02:43 -0000 1.24 --- src/backend/commands/portalcmds.c 20 Nov 2003 21:27:24 -0000 *************** *** 295,301 **** */ oldcxt = MemoryContextSwitchTo(portal->holdContext); ! portal->tupDesc = CreateTupleDescCopy(portal->tupDesc); MemoryContextSwitchTo(oldcxt); --- 295,301 ---- */ oldcxt = MemoryContextSwitchTo(portal->holdContext); ! portal->tupDesc = CopyTupleDesc(portal->tupDesc, false); MemoryContextSwitchTo(oldcxt); Index: src/backend/executor/execMain.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/backend/executor/execMain.c,v retrieving revision 1.221 diff -c -r1.221 execMain.c *** src/backend/executor/execMain.c 6 Nov 2003 22:08:14 -0000 1.221 --- src/backend/executor/execMain.c 20 Nov 2003 21:29:16 -0000 *************** *** 804,810 **** /* * have to copy tupType to get rid of constraints */ ! tupdesc = CreateTupleDescCopy(tupType); intoRelationId = heap_create_with_catalog(intoName, namespaceId, --- 804,810 ---- /* * have to copy tupType to get rid of constraints */ ! tupdesc = CopyTupleDesc(tupType, false); intoRelationId = heap_create_with_catalog(intoName, namespaceId, Index: src/backend/executor/execQual.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/backend/executor/execQual.c,v retrieving revision 1.150 diff -c -r1.150 execQual.c *** src/backend/executor/execQual.c 13 Oct 2003 22:47:15 -0000 1.150 --- src/backend/executor/execQual.c 20 Nov 2003 21:29:58 -0000 *************** *** 1074,1080 **** ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("function returning row did not return a valid tuple slot"))); ! tupdesc = CreateTupleDescCopy(slot->ttc_tupleDescriptor); returnsTuple = true; } else --- 1074,1080 ---- ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("function returning row did not return a valid tuple slot"))); ! tupdesc = CopyTupleDesc(slot->ttc_tupleDescriptor, false); returnsTuple = true; } else Index: src/backend/executor/functions.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/backend/executor/functions.c,v retrieving revision 1.75 diff -c -r1.75 functions.c *** src/backend/executor/functions.c 25 Sep 2003 18:58:35 -0000 1.75 --- src/backend/executor/functions.c 20 Nov 2003 21:30:17 -0000 *************** *** 389,395 **** */ if (funcSlot->ttc_tupleDescriptor == NULL) { ! resultTd = CreateTupleDescCopy(resultSlot->ttc_tupleDescriptor); ExecSetSlotDescriptor(funcSlot, resultTd, true); ExecSetSlotDescriptorIsNew(funcSlot, true); } --- 389,395 ---- */ if (funcSlot->ttc_tupleDescriptor == NULL) { ! resultTd = CopyTupleDesc(resultSlot->ttc_tupleDescriptor, false); ExecSetSlotDescriptor(funcSlot, resultTd, true); ExecSetSlotDescriptorIsNew(funcSlot, true); } Index: src/backend/executor/nodeFunctionscan.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/backend/executor/nodeFunctionscan.c,v retrieving revision 1.22 diff -c -r1.22 nodeFunctionscan.c *** src/backend/executor/nodeFunctionscan.c 25 Sep 2003 23:02:12 -0000 1.22 --- src/backend/executor/nodeFunctionscan.c 20 Nov 2003 21:30:35 -0000 *************** *** 205,211 **** elog(ERROR, "invalid typrelid for complex type %u", funcrettype); rel = relation_open(funcrelid, AccessShareLock); ! tupdesc = CreateTupleDescCopy(RelationGetDescr(rel)); relation_close(rel, AccessShareLock); } else if (functyptype == 'b' || functyptype == 'd') --- 205,211 ---- elog(ERROR, "invalid typrelid for complex type %u", funcrettype); rel = relation_open(funcrelid, AccessShareLock); ! tupdesc = CopyTupleDesc(RelationGetDescr(rel), false); relation_close(rel, AccessShareLock); } else if (functyptype == 'b' || functyptype == 'd') Index: src/backend/executor/spi.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/backend/executor/spi.c,v retrieving revision 1.107 diff -c -r1.107 spi.c *** src/backend/executor/spi.c 1 Oct 2003 21:30:52 -0000 1.107 --- src/backend/executor/spi.c 20 Nov 2003 21:31:30 -0000 *************** *** 386,392 **** oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); } ! ctupdesc = CreateTupleDescCopy(tupdesc); if (oldcxt) MemoryContextSwitchTo(oldcxt); --- 386,392 ---- oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt); } ! ctupdesc = CopyTupleDesc(tupdesc, false); if (oldcxt) MemoryContextSwitchTo(oldcxt); *************** *** 416,422 **** } ctuple = heap_copytuple(tuple); ! ctupdesc = CreateTupleDescCopy(tupdesc); cslot = MakeTupleTableSlot(); ExecSetSlotDescriptor(cslot, ctupdesc, true); --- 416,422 ---- } ctuple = heap_copytuple(tuple); ! ctupdesc = CopyTupleDesc(tupdesc, false); cslot = MakeTupleTableSlot(); ExecSetSlotDescriptor(cslot, ctupdesc, true); *************** *** 950,956 **** tuptable->tuptabcxt = tuptabcxt; tuptable->alloced = tuptable->free = 128; tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple)); ! tuptable->tupdesc = CreateTupleDescCopy(typeinfo); MemoryContextSwitchTo(oldcxt); } --- 950,956 ---- tuptable->tuptabcxt = tuptabcxt; tuptable->alloced = tuptable->free = 128; tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple)); ! tuptable->tupdesc = CopyTupleDesc(typeinfo, false); MemoryContextSwitchTo(oldcxt); } Index: src/backend/tcop/utility.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/backend/tcop/utility.c,v retrieving revision 1.208 diff -c -r1.208 utility.c *** src/backend/tcop/utility.c 2 Oct 2003 06:34:04 -0000 1.208 --- src/backend/tcop/utility.c 20 Nov 2003 21:31:51 -0000 *************** *** 1119,1125 **** portal = GetPortalByName(stmt->portalname); if (!PortalIsValid(portal)) return NULL; /* not our business to raise error */ ! return CreateTupleDescCopy(portal->tupDesc); } case T_ExecuteStmt: --- 1119,1125 ---- portal = GetPortalByName(stmt->portalname); if (!PortalIsValid(portal)) return NULL; /* not our business to raise error */ ! return CopyTupleDesc(portal->tupDesc, false); } case T_ExecuteStmt: Index: src/backend/utils/cache/catcache.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/backend/utils/cache/catcache.c,v retrieving revision 1.110 diff -c -r1.110 catcache.c *** src/backend/utils/cache/catcache.c 12 Nov 2003 21:15:55 -0000 1.110 --- src/backend/utils/cache/catcache.c 20 Nov 2003 21:37:56 -0000 *************** *** 913,919 **** /* * copy the relcache's tuple descriptor to permanent cache storage */ ! tupdesc = CreateTupleDescCopyConstr(RelationGetDescr(relation)); /* * get the relation's OID and relisshared flag, too --- 913,919 ---- /* * copy the relcache's tuple descriptor to permanent cache storage */ ! tupdesc = CopyTupleDesc(RelationGetDescr(relation), true); /* * get the relation's OID and relisshared flag, too Index: src/backend/utils/cache/relcache.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/backend/utils/cache/relcache.c,v retrieving revision 1.192 diff -c -r1.192 relcache.c *** src/backend/utils/cache/relcache.c 12 Nov 2003 21:15:56 -0000 1.192 --- src/backend/utils/cache/relcache.c 20 Nov 2003 21:32:12 -0000 *************** *** 2132,2138 **** * multiple system catalogs. We can copy attnotnull constraints here, * however. */ ! rel->rd_att = CreateTupleDescCopy(tupDesc); has_not_null = false; for (i = 0; i < natts; i++) { --- 2132,2138 ---- * multiple system catalogs. We can copy attnotnull constraints here, * however. */ ! rel->rd_att = CopyTupleDesc(tupDesc, false); has_not_null = false; for (i = 0; i < natts; i++) { Index: src/include/access/tupdesc.h =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/include/access/tupdesc.h,v retrieving revision 1.41 diff -c -r1.41 tupdesc.h *** src/include/access/tupdesc.h 11 Aug 2003 23:04:50 -0000 1.41 --- src/include/access/tupdesc.h 20 Nov 2003 21:18:21 -0000 *************** *** 60,68 **** extern TupleDesc CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs); ! extern TupleDesc CreateTupleDescCopy(TupleDesc tupdesc); ! ! extern TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc); extern void FreeTupleDesc(TupleDesc tupdesc); --- 60,66 ---- extern TupleDesc CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs); ! extern TupleDesc CopyTupleDesc(TupleDesc tupdesc, bool copyConstr); extern void FreeTupleDesc(TupleDesc tupdesc); Index: src/pl/plpgsql/src/pl_comp.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/pl/plpgsql/src/pl_comp.c,v retrieving revision 1.69 diff -c -r1.69 pl_comp.c *** src/pl/plpgsql/src/pl_comp.c 30 Sep 2003 00:59:51 -0000 1.69 --- src/pl/plpgsql/src/pl_comp.c 20 Nov 2003 21:33:44 -0000 *************** *** 1494,1500 **** * memory context ... */ oldcxt = MemoryContextSwitchTo(TopMemoryContext); ! row->rowtupdesc = CreateTupleDescCopy(RelationGetDescr(rel)); MemoryContextSwitchTo(oldcxt); row->nfields = classStruct->relnatts; --- 1494,1500 ---- * memory context ... */ oldcxt = MemoryContextSwitchTo(TopMemoryContext); ! row->rowtupdesc = CopyTupleDesc(RelationGetDescr(rel), false); MemoryContextSwitchTo(oldcxt); row->nfields = classStruct->relnatts; Index: src/pl/plpgsql/src/pl_exec.c =================================================================== RCS file: /var/lib/cvs/pgsql-server/src/pl/plpgsql/src/pl_exec.c,v retrieving revision 1.93 diff -c -r1.93 pl_exec.c *** src/pl/plpgsql/src/pl_exec.c 1 Oct 2003 21:47:42 -0000 1.93 --- src/pl/plpgsql/src/pl_exec.c 20 Nov 2003 21:34:54 -0000 *************** *** 352,358 **** MemoryContext oldcxt; oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt); ! rsi->setDesc = CreateTupleDescCopy(estate.rettupdesc); MemoryContextSwitchTo(oldcxt); } } --- 352,358 ---- MemoryContext oldcxt; oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt); ! rsi->setDesc = CopyTupleDesc(estate.rettupdesc, false); MemoryContextSwitchTo(oldcxt); } } *************** *** 3390,3396 **** if (tupdesc) { ! rec->tupdesc = CreateTupleDescCopy(tupdesc); rec->freetupdesc = true; } else --- 3390,3396 ---- if (tupdesc) { ! rec->tupdesc = CopyTupleDesc(tupdesc, false); rec->freetupdesc = true; } else
---------------------------(end of broadcast)--------------------------- TIP 5: Have you checked our extensive FAQ? http://www.postgresql.org/docs/faqs/FAQ.html