From aa88e59ade282c41dd03a1ab386a0a408e4a43af Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 12 Feb 2001 20:07:21 +0000 Subject: [PATCH] Rearrange order of operations in heap_create_with_catalog so that if two transactions create the same table name concurrently, the one that fails will complain about unique index pg_class_relname_index, rather than about pg_type_typname_index which'll confuse most people. Free side benefit: pg_class.reltype is correctly linked to the pg_type entry now. It's been zero in all but the preloaded pg_class entries since who knows when. --- src/backend/catalog/heap.c | 134 +++++++++++++++++----------------- src/backend/catalog/pg_type.c | 52 +++++++------ src/backend/commands/define.c | 6 +- src/include/catalog/pg_type.h | 6 +- 4 files changed, 107 insertions(+), 91 deletions(-) diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c index bdb32b5dcc..c67f7f3543 100644 --- a/src/backend/catalog/heap.c +++ b/src/backend/catalog/heap.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.158 2001/01/24 19:42:51 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.159 2001/02/12 20:07:21 tgl Exp $ * * * INTERFACE ROUTINES @@ -68,15 +68,15 @@ static void AddNewRelationTuple(Relation pg_class_desc, - Relation new_rel_desc, Oid new_rel_oid, - int natts, - char relkind, char *temp_relname); + Relation new_rel_desc, Oid new_rel_oid, Oid new_type_oid, + int natts, char relkind, char *temp_relname); static void DeleteAttributeTuples(Relation rel); static void DeleteRelationTuple(Relation rel); static void DeleteTypeTuple(Relation rel); static void RelationRemoveIndexes(Relation relation); static void RelationRemoveInheritance(Relation relation); -static void AddNewRelationType(char *typeName, Oid new_rel_oid); +static void AddNewRelationType(char *typeName, Oid new_rel_oid, + Oid new_type_oid); static void StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin, bool updatePgAttribute); static void StoreRelCheck(Relation rel, char *ccname, char *ccbin); @@ -317,6 +317,7 @@ heap_create(char *relname, strcpy(RelationGetPhysicalRelationName(rel), relname); rel->rd_rel->relkind = RELKIND_UNCATALOGED; rel->rd_rel->relnatts = natts; + rel->rd_rel->reltype = InvalidOid; if (tupDesc->constr) rel->rd_rel->relchecks = tupDesc->constr->num_check; @@ -325,12 +326,6 @@ heap_create(char *relname, RelationGetRelid(rel) = relid; - if (nailme) - { - /* for system relations, set the reltype field here */ - rel->rd_rel->reltype = relid; - } - rel->rd_node.tblNode = tblNode; rel->rd_node.relNode = relid; rel->rd_rel->relfilenode = relid; @@ -373,18 +368,17 @@ heap_storage_create(Relation rel) * performs a scan to ensure that no relation with the * same name already exists. * - * 3) heap_create_with_catalog() is called to create the new relation - * on disk. + * 3) heap_create() is called to create the new relation on disk. * - * 4) TypeDefine() is called to define a new type corresponding + * 4) AddNewRelationTuple() is called to register the + * relation in pg_class. + * + * 5) TypeCreate() is called to define a new type corresponding * to the new relation. * - * 5) AddNewAttributeTuples() is called to register the + * 6) AddNewAttributeTuples() is called to register the * new relation's schema in pg_attribute. * - * 6) AddNewRelationTuple() is called to register the - * relation itself in the catalogs. - * * 7) StoreConstraints is called () - vadim 08/22/97 * * 8) the relations are closed and the new relation's oid @@ -656,6 +650,7 @@ static void AddNewRelationTuple(Relation pg_class_desc, Relation new_rel_desc, Oid new_rel_oid, + Oid new_type_oid, int natts, char relkind, char *temp_relname) @@ -665,7 +660,7 @@ AddNewRelationTuple(Relation pg_class_desc, Relation idescs[Num_pg_class_indices]; /* ---------------- - * first we munge some of the information in our + * first we update some of the information in our * uncataloged relation's relation descriptor. * ---------------- */ @@ -694,6 +689,7 @@ AddNewRelationTuple(Relation pg_class_desc, new_rel_reltup->reltuples = 1000; new_rel_reltup->relowner = GetUserId(); + new_rel_reltup->reltype = new_type_oid; new_rel_reltup->relkind = relkind; new_rel_reltup->relnatts = natts; @@ -705,6 +701,8 @@ AddNewRelationTuple(Relation pg_class_desc, tup = heap_addheader(Natts_pg_class_fixed, CLASS_TUPLE_SIZE, (char *) new_rel_reltup); + + /* force tuple to have the desired OID */ tup->t_data->t_oid = new_rel_oid; /* @@ -738,10 +736,8 @@ AddNewRelationTuple(Relation pg_class_desc, * -------------------------------- */ static void -AddNewRelationType(char *typeName, Oid new_rel_oid) +AddNewRelationType(char *typeName, Oid new_rel_oid, Oid new_type_oid) { - Oid new_type_oid; - /* * The sizes are set to oid size because it makes implementing sets * MUCH easier, and no one (we hope) uses these fields to figure out @@ -750,23 +746,25 @@ AddNewRelationType(char *typeName, Oid new_rel_oid) * actually get is the oid of a tuple in the pg_proc catalog, so the * size of the "set" is the size of an oid. Similarly, byval being * true makes sets much easier, and it isn't used by anything else. - * Note the assumption that OIDs are the same size as int4s. - */ - new_type_oid = TypeCreate(typeName, /* type name */ - new_rel_oid, /* relation oid */ - sizeof(Oid), /* internal size */ - sizeof(Oid), /* external size */ - 'c', /* type-type (catalog) */ - ',', /* default array delimiter */ - "int4in", /* input procedure */ - "int4out", /* output procedure */ - "int4in", /* receive procedure */ - "int4out", /* send procedure */ - NULL, /* array element type - irrelevent */ - "-", /* default type value */ - (bool) 1, /* passed by value */ - 'i', /* default alignment */ - 'p'); /* Not TOASTable */ + * + * XXX Note the assumption that OIDs are the same size as int4s. + */ + TypeCreate(typeName, /* type name */ + new_type_oid, /* preassigned oid for type */ + new_rel_oid, /* relation oid */ + sizeof(Oid), /* internal size */ + sizeof(Oid), /* external size */ + 'c', /* type-type (catalog) */ + ',', /* default array delimiter */ + "int4in", /* input procedure */ + "int4out", /* output procedure */ + "int4in", /* receive procedure */ + "int4out", /* send procedure */ + NULL, /* array element type - irrelevant */ + "-", /* default type value */ + true, /* passed by value */ + 'i', /* default alignment */ + 'p'); /* Not TOASTable */ } /* -------------------------------- @@ -785,6 +783,7 @@ heap_create_with_catalog(char *relname, Relation pg_class_desc; Relation new_rel_desc; Oid new_rel_oid; + Oid new_type_oid; int natts = tupdesc->natts; char *temp_relname = NULL; @@ -814,18 +813,10 @@ heap_create_with_catalog(char *relname, } /* ---------------- - * RelnameFindRelid couldn't detect simultaneous - * creation. Uniqueness will be really checked by unique - * indexes of system tables but we couldn't check it here. - * We have to postpone creating the disk file for this - * relation. - * Another boolean parameter "storage_create" was added - * to heap_create() function. If the parameter is false - * heap_create() only registers an uncataloged relation - * to relation cache and heap_storage_create() should be - * called later. - * We could pull its relation oid from the newly formed - * relation descriptor. + * Tell heap_create not to create a physical file; we'll do that + * below after all our catalog updates are done. (This isn't really + * necessary anymore, but we may as well avoid the cycles of creating + * and deleting the file in case we fail.) * * Note: The call to heap_create() changes relname for * temp tables; it becomes the true physical relname. @@ -836,24 +827,18 @@ heap_create_with_catalog(char *relname, new_rel_desc = heap_create(relname, tupdesc, istemp, false, allow_system_table_mods); + /* Fetch the relation OID assigned by heap_create */ new_rel_oid = new_rel_desc->rd_att->attrs[0]->attrelid; - /* ---------------- - * since defining a relation also defines a complex type, - * we add a new system type corresponding to the new relation. - * ---------------- - */ - AddNewRelationType(relname, new_rel_oid); + /* Assign an OID for the relation's tuple type */ + new_type_oid = newoid(); /* ---------------- - * now add tuples to pg_attribute for the attributes in - * our new relation. - * ---------------- - */ - AddNewAttributeTuples(new_rel_oid, tupdesc); - - /* ---------------- - * now update the information in pg_class. + * now create an entry in pg_class for the relation. + * + * NOTE: we could get a unique-index failure here, in case someone else + * is creating the same relation name in parallel but hadn't committed + * yet when we checked for a duplicate name above. * ---------------- */ pg_class_desc = heap_openr(RelationRelationName, RowExclusiveLock); @@ -861,10 +846,28 @@ heap_create_with_catalog(char *relname, AddNewRelationTuple(pg_class_desc, new_rel_desc, new_rel_oid, + new_type_oid, natts, relkind, temp_relname); + /* ---------------- + * since defining a relation also defines a complex type, + * we add a new system type corresponding to the new relation. + * + * NOTE: we could get a unique-index failure here, in case the same name + * has already been used for a type. + * ---------------- + */ + AddNewRelationType(relname, new_rel_oid, new_type_oid); + + /* ---------------- + * now add tuples to pg_attribute for the attributes in + * our new relation. + * ---------------- + */ + AddNewAttributeTuples(new_rel_oid, tupdesc); + StoreConstraints(new_rel_desc); if (istemp) @@ -912,7 +915,6 @@ heap_create_with_catalog(char *relname, * attribute catalog (needed?). (Anything else?) * * get proper relation from relation catalog (if not arg) - * check if relation is vital (strcmp()/reltype?) * scan attribute catalog deleting attributes of reldesc * (necessary?) * delete relation from relation catalog diff --git a/src/backend/catalog/pg_type.c b/src/backend/catalog/pg_type.c index f941717485..714ea737ae 100644 --- a/src/backend/catalog/pg_type.c +++ b/src/backend/catalog/pg_type.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.58 2001/01/24 19:42:52 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_type.c,v 1.59 2001/02/12 20:07:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -46,18 +46,17 @@ TypeGetWithOpenRelation(Relation pg_type_desc, HeapScanDesc scan; HeapTuple tup; Oid typoid; - - static ScanKeyData typeKey[1] = { - {0, Anum_pg_type_typname, F_NAMEEQ} - }; + ScanKeyData typeKey[1]; /* ---------------- * initialize the scan key and begin a scan of pg_type * ---------------- */ - fmgr_info(F_NAMEEQ, &typeKey[0].sk_func); - typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs; - typeKey[0].sk_argument = PointerGetDatum(typeName); + ScanKeyEntryInitialize(typeKey, + 0, + Anum_pg_type_typname, + F_NAMEEQ, + PointerGetDatum(typeName)); scan = heap_beginscan(pg_type_desc, 0, @@ -269,10 +268,16 @@ TypeShellMake(char *typeName) * TypeCreate * * This does all the necessary work needed to define a new type. + * + * NOTE: if assignedTypeOid is not InvalidOid, then that OID is assigned to + * the new type (which, therefore, cannot already exist as a shell type). + * This hack is only intended for use in creating a relation's associated + * type, where we need to have created the relation tuple already. * ---------------------------------------------------------------- */ Oid TypeCreate(char *typeName, + Oid assignedTypeOid, Oid relationOid, /* only for 'c'atalog typeTypes */ int16 internalSize, int16 externalSize, @@ -292,35 +297,28 @@ TypeCreate(char *typeName, j; Relation pg_type_desc; HeapScanDesc pg_type_scan; - Oid typeObjectId; Oid elementObjectId = InvalidOid; - HeapTuple tup; char nulls[Natts_pg_type]; char replaces[Natts_pg_type]; Datum values[Natts_pg_type]; - char *procname; char *procs[4]; bool defined; NameData name; TupleDesc tupDesc; Oid argList[FUNC_MAX_ARGS]; - - static ScanKeyData typeKey[1] = { - {0, Anum_pg_type_typname, F_NAMEEQ} - }; - - fmgr_info(F_NAMEEQ, &typeKey[0].sk_func); - typeKey[0].sk_nargs = typeKey[0].sk_func.fn_nargs; + ScanKeyData typeKey[1]; /* ---------------- - * check that the type is not already defined. + * check that the type is not already defined. It might exist as + * a shell type, however (but only if assignedTypeOid is not given). * ---------------- */ typeObjectId = TypeGet(typeName, &defined); - if (OidIsValid(typeObjectId) && defined) + if (OidIsValid(typeObjectId) && + (defined || assignedTypeOid != InvalidOid)) elog(ERROR, "TypeCreate: type %s already defined", typeName); /* ---------------- @@ -468,7 +466,12 @@ TypeCreate(char *typeName, */ pg_type_desc = heap_openr(TypeRelationName, RowExclusiveLock); - typeKey[0].sk_argument = PointerGetDatum(typeName); + ScanKeyEntryInitialize(typeKey, + 0, + Anum_pg_type_typname, + F_NAMEEQ, + PointerGetDatum(typeName)); + pg_type_scan = heap_beginscan(pg_type_desc, 0, SnapshotSelf, /* cache? */ @@ -484,6 +487,10 @@ TypeCreate(char *typeName, tup = heap_getnext(pg_type_scan, 0); if (HeapTupleIsValid(tup)) { + /* should not happen given prior test? */ + if (assignedTypeOid != InvalidOid) + elog(ERROR, "TypeCreate: type %s already defined", typeName); + tup = heap_modifytuple(tup, pg_type_desc, values, @@ -502,6 +509,9 @@ TypeCreate(char *typeName, values, nulls); + /* preassign tuple Oid, if one was given */ + tup->t_data->t_oid = assignedTypeOid; + heap_insert(pg_type_desc, tup); typeObjectId = tup->t_data->t_oid; diff --git a/src/backend/commands/define.c b/src/backend/commands/define.c index 01fd53a16a..4f5f8a47f6 100644 --- a/src/backend/commands/define.c +++ b/src/backend/commands/define.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.51 2001/01/24 19:42:52 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/define.c,v 1.52 2001/02/12 20:07:21 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -640,6 +640,7 @@ DefineType(char *typeName, List *parameters) * ---------------- */ TypeCreate(typeName, /* type name */ + InvalidOid, /* preassigned type oid (not done here) */ InvalidOid, /* relation oid (n/a here) */ internalLength, /* internal size */ externalLength, /* external size */ @@ -652,7 +653,7 @@ DefineType(char *typeName, List *parameters) elemName, /* element type name */ defaultValue, /* default type value */ byValue, /* passed by value */ - alignment, + alignment, /* required alignment */ storage); /* TOAST strategy */ /* ---------------- @@ -663,6 +664,7 @@ DefineType(char *typeName, List *parameters) shadow_type = makeArrayTypeName(typeName); TypeCreate(shadow_type, /* type name */ + InvalidOid, /* preassigned type oid (not done here) */ InvalidOid, /* relation oid (n/a here) */ -1, /* internal size */ -1, /* external size */ diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h index 83af133d1b..e429047542 100644 --- a/src/include/catalog/pg_type.h +++ b/src/include/catalog/pg_type.h @@ -8,7 +8,7 @@ * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $Id: pg_type.h,v 1.100 2001/01/24 19:43:22 momjian Exp $ + * $Id: pg_type.h,v 1.101 2001/02/12 20:07:20 tgl Exp $ * * NOTES * the genbki.sh script reads this file and generates .bki @@ -420,6 +420,7 @@ DESCR("numeric(precision, decimal), arbitrary precision number"); extern Oid TypeGet(char *typeName, bool *defined); extern Oid TypeShellMake(char *typeName); extern Oid TypeCreate(char *typeName, + Oid assignedTypeOid, Oid relationOid, int16 internalSize, int16 externalSize, @@ -431,7 +432,8 @@ extern Oid TypeCreate(char *typeName, char *sendProcedure, char *elementTypeName, char *defaultTypeValue, - bool passedByValue, char alignment, + bool passedByValue, + char alignment, char storage); extern void TypeRename(const char *oldTypeName, const char *newTypeName); extern char *makeArrayTypeName(char *typeName); -- 2.40.0