/* * RenameConstraintById * Rename a constraint. * * Note: this isn't intended to be a user-exposed function; it doesn't check * permissions etc. Currently this is only invoked when renaming an index * that is associated with a constraint, but it's made a little more general * than that with the expectation of someday having ALTER TABLE RENAME * CONSTRAINT. */ void RenameConstraintById(Oid conId, const char *newname) { Relation conDesc; HeapTuple tuple; Form_pg_constraint con; conDesc = heap_open(ConstraintRelationId, RowExclusiveLock); tuple = SearchSysCacheCopy1(CONSTROID, ObjectIdGetDatum(conId)); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for constraint %u", conId); con = (Form_pg_constraint) GETSTRUCT(tuple); /* * We need to check whether the name is already in use --- note that there * currently is not a unique index that would catch this. */ if (OidIsValid(con->conrelid) && ConstraintNameIsUsed(CONSTRAINT_RELATION, con->conrelid, con->connamespace, newname)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("constraint \"%s\" for relation \"%s\" already exists", newname, get_rel_name(con->conrelid)))); if (OidIsValid(con->contypid) && ConstraintNameIsUsed(CONSTRAINT_DOMAIN, con->contypid, con->connamespace, newname)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("constraint \"%s\" for domain %s already exists", newname, format_type_be(con->contypid)))); /* OK, do the rename --- tuple is a copy, so OK to scribble on it */ namestrcpy(&(con->conname), newname); simple_heap_update(conDesc, &tuple->t_self, tuple); /* update the system catalog indexes */ CatalogUpdateIndexes(conDesc, tuple); InvokeObjectPostAlterHook(ConstraintRelationId, conId, 0); heap_freetuple(tuple); heap_close(conDesc, RowExclusiveLock); }
/* * RenameTypeInternal * This renames a type, as well as any associated array type. * * Caller must have already checked privileges. * * Currently this is used for renaming table rowtypes and for * ALTER TYPE RENAME TO command. */ void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace) { Relation pg_type_desc; HeapTuple tuple; Form_pg_type typ; Oid arrayOid; pg_type_desc = heap_open(TypeRelationId, RowExclusiveLock); tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid)); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for type %u", typeOid); typ = (Form_pg_type) GETSTRUCT(tuple); /* We are not supposed to be changing schemas here */ Assert(typeNamespace == typ->typnamespace); arrayOid = typ->typarray; /* Just to give a more friendly error than unique-index violation */ if (SearchSysCacheExists2(TYPENAMENSP, CStringGetDatum(newTypeName), ObjectIdGetDatum(typeNamespace))) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", newTypeName))); /* OK, do the rename --- tuple is a copy, so OK to scribble on it */ namestrcpy(&(typ->typname), newTypeName); simple_heap_update(pg_type_desc, &tuple->t_self, tuple); /* update the system catalog indexes */ CatalogUpdateIndexes(pg_type_desc, tuple); InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0); heap_freetuple(tuple); heap_close(pg_type_desc, RowExclusiveLock); /* If the type has an array type, recurse to handle that */ if (OidIsValid(arrayOid)) { char *arrname = makeArrayTypeName(newTypeName, typeNamespace); RenameTypeInternal(arrayOid, arrname, typeNamespace); pfree(arrname); } }
/* * AlterConstraintNamespaces * Find any constraints belonging to the specified object, * and move them to the specified new namespace. * * isType indicates whether the owning object is a type or a relation. */ void AlterConstraintNamespaces(Oid ownerId, Oid oldNspId, Oid newNspId, bool isType, ObjectAddresses *objsMoved) { Relation conRel; ScanKeyData key[1]; SysScanDesc scan; HeapTuple tup; conRel = heap_open(ConstraintRelationId, RowExclusiveLock); if (isType) { ScanKeyInit(&key[0], Anum_pg_constraint_contypid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(ownerId)); scan = systable_beginscan(conRel, ConstraintTypidIndexId, true, NULL, 1, key); } else { ScanKeyInit(&key[0], Anum_pg_constraint_conrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(ownerId)); scan = systable_beginscan(conRel, ConstraintRelidIndexId, true, NULL, 1, key); } while (HeapTupleIsValid((tup = systable_getnext(scan)))) { Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(tup); ObjectAddress thisobj; thisobj.classId = ConstraintRelationId; thisobj.objectId = HeapTupleGetOid(tup); thisobj.objectSubId = 0; if (object_address_present(&thisobj, objsMoved)) continue; if (conform->connamespace == oldNspId) { tup = heap_copytuple(tup); conform = (Form_pg_constraint) GETSTRUCT(tup); conform->connamespace = newNspId; simple_heap_update(conRel, &tup->t_self, tup); CatalogUpdateIndexes(conRel, tup); /* * Note: currently, the constraint will not have its own * dependency on the namespace, so we don't need to do * changeDependencyFor(). */ } InvokeObjectPostAlterHook(ConstraintRelationId, thisobj.objectId, 0); add_exact_object_address(&thisobj, objsMoved); } systable_endscan(scan); heap_close(conRel, RowExclusiveLock); }
/* * Alter table space options */ Oid AlterTableSpaceOptions(AlterTableSpaceOptionsStmt *stmt) { Relation rel; ScanKeyData entry[1]; HeapScanDesc scandesc; HeapTuple tup; Oid tablespaceoid; Datum datum; Datum newOptions; Datum repl_val[Natts_pg_tablespace]; bool isnull; bool repl_null[Natts_pg_tablespace]; bool repl_repl[Natts_pg_tablespace]; HeapTuple newtuple; /* Search pg_tablespace */ rel = heap_open(TableSpaceRelationId, RowExclusiveLock); ScanKeyInit(&entry[0], Anum_pg_tablespace_spcname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(stmt->tablespacename)); scandesc = heap_beginscan_catalog(rel, 1, entry); tup = heap_getnext(scandesc, ForwardScanDirection); if (!HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", stmt->tablespacename))); tablespaceoid = HeapTupleGetOid(tup); /* Must be owner of the existing object */ if (!pg_tablespace_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE, stmt->tablespacename); /* Generate new proposed spcoptions (text array) */ datum = heap_getattr(tup, Anum_pg_tablespace_spcoptions, RelationGetDescr(rel), &isnull); newOptions = transformRelOptions(isnull ? (Datum) 0 : datum, stmt->options, NULL, NULL, false, stmt->isReset); (void) tablespace_reloptions(newOptions, true); /* Build new tuple. */ memset(repl_null, false, sizeof(repl_null)); memset(repl_repl, false, sizeof(repl_repl)); if (newOptions != (Datum) 0) repl_val[Anum_pg_tablespace_spcoptions - 1] = newOptions; else repl_null[Anum_pg_tablespace_spcoptions - 1] = true; repl_repl[Anum_pg_tablespace_spcoptions - 1] = true; newtuple = heap_modify_tuple(tup, RelationGetDescr(rel), repl_val, repl_null, repl_repl); /* Update system catalog. */ simple_heap_update(rel, &newtuple->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); InvokeObjectPostAlterHook(TableSpaceRelationId, HeapTupleGetOid(tup), 0); heap_freetuple(newtuple); /* Conclude heap scan. */ heap_endscan(scandesc); heap_close(rel, NoLock); return tablespaceoid; }
/* * Rename a tablespace */ ObjectAddress RenameTableSpace(const char *oldname, const char *newname) { Oid tspId; Relation rel; ScanKeyData entry[1]; HeapScanDesc scan; HeapTuple tup; HeapTuple newtuple; Form_pg_tablespace newform; ObjectAddress address; /* Search pg_tablespace */ rel = heap_open(TableSpaceRelationId, RowExclusiveLock); ScanKeyInit(&entry[0], Anum_pg_tablespace_spcname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(oldname)); scan = heap_beginscan_catalog(rel, 1, entry); tup = heap_getnext(scan, ForwardScanDirection); if (!HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("tablespace \"%s\" does not exist", oldname))); tspId = HeapTupleGetOid(tup); newtuple = heap_copytuple(tup); newform = (Form_pg_tablespace) GETSTRUCT(newtuple); heap_endscan(scan); /* Must be owner */ if (!pg_tablespace_ownercheck(HeapTupleGetOid(newtuple), GetUserId())) aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE, oldname); /* Validate new name */ if (!allowSystemTableMods && IsReservedName(newname)) ereport(ERROR, (errcode(ERRCODE_RESERVED_NAME), errmsg("unacceptable tablespace name \"%s\"", newname), errdetail("The prefix \"pg_\" is reserved for system tablespaces."))); /* Make sure the new name doesn't exist */ ScanKeyInit(&entry[0], Anum_pg_tablespace_spcname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(newname)); scan = heap_beginscan_catalog(rel, 1, entry); tup = heap_getnext(scan, ForwardScanDirection); if (HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("tablespace \"%s\" already exists", newname))); heap_endscan(scan); /* OK, update the entry */ namestrcpy(&(newform->spcname), newname); simple_heap_update(rel, &newtuple->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); InvokeObjectPostAlterHook(TableSpaceRelationId, tspId, 0); ObjectAddressSet(address, TableSpaceRelationId, tspId); heap_close(rel, NoLock); return address; }
/* * AlterSequence * * Modify the definition of a sequence relation */ ObjectAddress AlterSequence(AlterSeqStmt *stmt) { Oid relid; SeqTable elm; Relation seqrel; Buffer buf; HeapTupleData seqtuple; Form_pg_sequence seq; FormData_pg_sequence new___; List *owned_by; ObjectAddress address; /* Open and lock sequence. */ relid = RangeVarGetRelid(stmt->sequence, AccessShareLock, stmt->missing_ok); if (relid == InvalidOid) { ereport(NOTICE, (errmsg("relation \"%s\" does not exist, skipping", stmt->sequence->relname))); return InvalidObjectAddress; } init_sequence(relid, &elm, &seqrel); /* allow ALTER to sequence owner only */ if (!pg_class_ownercheck(relid, GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS, stmt->sequence->relname); /* lock page' buffer and read tuple into new___ sequence structure */ seq = read_seq_tuple(elm, seqrel, &buf, &seqtuple); /* Copy old values of options into workspace */ memcpy(&new___, seq, sizeof(FormData_pg_sequence)); /* Check and set new___ values */ init_params(stmt->options, false, &new___, &owned_by); /* Clear local cache so that we don't think we have cached numbers */ /* Note that we do not change the currval() state */ elm->cached = elm->last; /* check the comment above nextval_internal()'s equivalent call. */ if (RelationNeedsWAL(seqrel)) GetTopTransactionId(); /* Now okay to update the on-disk tuple */ START_CRIT_SECTION(); memcpy(seq, &new___, sizeof(FormData_pg_sequence)); MarkBufferDirty(buf); /* XLOG stuff */ if (RelationNeedsWAL(seqrel)) { xl_seq_rec xlrec; XLogRecPtr recptr; Page page = BufferGetPage(buf); XLogBeginInsert(); XLogRegisterBuffer(0, buf, REGBUF_WILL_INIT); xlrec.node = seqrel->rd_node; XLogRegisterData((char *) &xlrec, sizeof(xl_seq_rec)); XLogRegisterData((char *) seqtuple.t_data, seqtuple.t_len); recptr = XLogInsert(RM_SEQ_ID, XLOG_SEQ_LOG); PageSetLSN(page, recptr); } END_CRIT_SECTION(); UnlockReleaseBuffer(buf); /* process OWNED BY if given */ if (owned_by) process_owned_by(seqrel, owned_by); InvokeObjectPostAlterHook(RelationRelationId, relid, 0); ObjectAddressSet(address, RelationRelationId, relid); relation_close(seqrel, NoLock); return address; }
/* * RenameTypeInternal * This renames a type, as well as any associated array type. * * Caller must have already checked privileges. * * Currently this is used for renaming table rowtypes and for * ALTER TYPE RENAME TO command. */ void RenameTypeInternal(Oid typeOid, const char *newTypeName, Oid typeNamespace) { Relation pg_type_desc; HeapTuple tuple; Form_pg_type typ; Oid arrayOid; Oid oldTypeOid; pg_type_desc = table_open(TypeRelationId, RowExclusiveLock); tuple = SearchSysCacheCopy1(TYPEOID, ObjectIdGetDatum(typeOid)); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for type %u", typeOid); typ = (Form_pg_type) GETSTRUCT(tuple); /* We are not supposed to be changing schemas here */ Assert(typeNamespace == typ->typnamespace); arrayOid = typ->typarray; /* Check for a conflicting type name. */ oldTypeOid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid, CStringGetDatum(newTypeName), ObjectIdGetDatum(typeNamespace)); /* * If there is one, see if it's an autogenerated array type, and if so * rename it out of the way. (But we must skip that for a shell type * because moveArrayTypeName will do the wrong thing in that case.) * Otherwise, we can at least give a more friendly error than unique-index * violation. */ if (OidIsValid(oldTypeOid)) { if (get_typisdefined(oldTypeOid) && moveArrayTypeName(oldTypeOid, newTypeName, typeNamespace)) /* successfully dodged the problem */ ; else ereport(ERROR, (errcode(ERRCODE_DUPLICATE_OBJECT), errmsg("type \"%s\" already exists", newTypeName))); } /* OK, do the rename --- tuple is a copy, so OK to scribble on it */ namestrcpy(&(typ->typname), newTypeName); CatalogTupleUpdate(pg_type_desc, &tuple->t_self, tuple); InvokeObjectPostAlterHook(TypeRelationId, typeOid, 0); heap_freetuple(tuple); table_close(pg_type_desc, RowExclusiveLock); /* * If the type has an array type, recurse to handle that. But we don't * need to do anything more if we already renamed that array type above * (which would happen when, eg, renaming "foo" to "_foo"). */ if (OidIsValid(arrayOid) && arrayOid != oldTypeOid) { char *arrname = makeArrayTypeName(newTypeName, typeNamespace); RenameTypeInternal(arrayOid, arrname, typeNamespace); pfree(arrname); } }