📄 dbcommands.c
字号:
if (valuestr) a = GUCArrayAdd(a, stmt->variable, valuestr); else a = GUCArrayDelete(a, stmt->variable); if (a) repl_val[Anum_pg_database_datconfig - 1] = PointerGetDatum(a); else repl_null[Anum_pg_database_datconfig - 1] = 'n'; } newtuple = heap_modifytuple(tuple, RelationGetDescr(rel), repl_val, repl_null, repl_repl); simple_heap_update(rel, &tuple->t_self, newtuple); /* Update indexes */ CatalogUpdateIndexes(rel, newtuple); systable_endscan(scan); /* Close pg_database, but keep lock till commit */ heap_close(rel, NoLock); /* * We don't bother updating the flat file since ALTER DATABASE SET doesn't * affect it. */}/* * ALTER DATABASE name OWNER TO newowner */voidAlterDatabaseOwner(const char *dbname, Oid newOwnerId){ HeapTuple tuple; Relation rel; ScanKeyData scankey; SysScanDesc scan; Form_pg_database datForm; /* * We don't need ExclusiveLock since we aren't updating the flat file. */ rel = heap_open(DatabaseRelationId, RowExclusiveLock); ScanKeyInit(&scankey, Anum_pg_database_datname, BTEqualStrategyNumber, F_NAMEEQ, NameGetDatum(dbname)); scan = systable_beginscan(rel, DatabaseNameIndexId, true, SnapshotNow, 1, &scankey); tuple = systable_getnext(scan); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", dbname))); datForm = (Form_pg_database) GETSTRUCT(tuple); /* * If the new owner is the same as the existing owner, consider the * command to have succeeded. This is to be consistent with other * objects. */ if (datForm->datdba != newOwnerId) { Datum repl_val[Natts_pg_database]; char repl_null[Natts_pg_database]; char repl_repl[Natts_pg_database]; Acl *newAcl; Datum aclDatum; bool isNull; HeapTuple newtuple; /* Otherwise, must be owner of the existing object */ if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, dbname); /* Must be able to become new owner */ check_is_member_of_role(GetUserId(), newOwnerId); /* * must have createdb rights * * NOTE: This is different from other alter-owner checks in that the * current user is checked for createdb privileges instead of the * destination owner. This is consistent with the CREATE case for * databases. Because superusers will always have this right, we need * no special case for them. */ if (!have_createdb_privilege()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to change owner of database"))); memset(repl_null, ' ', sizeof(repl_null)); memset(repl_repl, ' ', sizeof(repl_repl)); repl_repl[Anum_pg_database_datdba - 1] = 'r'; repl_val[Anum_pg_database_datdba - 1] = ObjectIdGetDatum(newOwnerId); /* * Determine the modified ACL for the new owner. This is only * necessary when the ACL is non-null. */ aclDatum = heap_getattr(tuple, Anum_pg_database_datacl, RelationGetDescr(rel), &isNull); if (!isNull) { newAcl = aclnewowner(DatumGetAclP(aclDatum), datForm->datdba, newOwnerId); repl_repl[Anum_pg_database_datacl - 1] = 'r'; repl_val[Anum_pg_database_datacl - 1] = PointerGetDatum(newAcl); } newtuple = heap_modifytuple(tuple, RelationGetDescr(rel), repl_val, repl_null, repl_repl); simple_heap_update(rel, &newtuple->t_self, newtuple); CatalogUpdateIndexes(rel, newtuple); heap_freetuple(newtuple); /* Update owner dependency reference */ changeDependencyOnOwner(DatabaseRelationId, HeapTupleGetOid(tuple), newOwnerId); } systable_endscan(scan); /* Close pg_database, but keep lock till commit */ heap_close(rel, NoLock); /* * We don't bother updating the flat file since ALTER DATABASE OWNER * doesn't affect it. */}/* * Helper functions */static boolget_db_info(const char *name, Oid *dbIdP, Oid *ownerIdP, int *encodingP, bool *dbIsTemplateP, bool *dbAllowConnP, Oid *dbLastSysOidP, TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP, Oid *dbTablespace){ Relation relation; ScanKeyData scanKey; SysScanDesc scan; HeapTuple tuple; bool gottuple; AssertArg(name); /* Caller may wish to grab a better lock on pg_database beforehand... */ relation = heap_open(DatabaseRelationId, AccessShareLock); ScanKeyInit(&scanKey, Anum_pg_database_datname, BTEqualStrategyNumber, F_NAMEEQ, NameGetDatum(name)); scan = systable_beginscan(relation, DatabaseNameIndexId, true, SnapshotNow, 1, &scanKey); tuple = systable_getnext(scan); gottuple = HeapTupleIsValid(tuple); if (gottuple) { Form_pg_database dbform = (Form_pg_database) GETSTRUCT(tuple); /* oid of the database */ if (dbIdP) *dbIdP = HeapTupleGetOid(tuple); /* oid of the owner */ if (ownerIdP) *ownerIdP = dbform->datdba; /* character encoding */ if (encodingP) *encodingP = dbform->encoding; /* allowed as template? */ if (dbIsTemplateP) *dbIsTemplateP = dbform->datistemplate; /* allowing connections? */ if (dbAllowConnP) *dbAllowConnP = dbform->datallowconn; /* last system OID used in database */ if (dbLastSysOidP) *dbLastSysOidP = dbform->datlastsysoid; /* limit of vacuumed XIDs */ if (dbVacuumXidP) *dbVacuumXidP = dbform->datvacuumxid; /* limit of frozen XIDs */ if (dbFrozenXidP) *dbFrozenXidP = dbform->datfrozenxid; /* default tablespace for this database */ if (dbTablespace) *dbTablespace = dbform->dattablespace; } systable_endscan(scan); heap_close(relation, AccessShareLock); return gottuple;}/* Check if current user has createdb privileges */static boolhave_createdb_privilege(void){ bool result = false; HeapTuple utup; /* Superusers can always do everything */ if (superuser()) return true; utup = SearchSysCache(AUTHOID, ObjectIdGetDatum(GetUserId()), 0, 0, 0); if (HeapTupleIsValid(utup)) { result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreatedb; ReleaseSysCache(utup); } return result;}/* * Remove tablespace directories * * We don't know what tablespaces db_id is using, so iterate through all * tablespaces removing <tablespace>/db_id */static voidremove_dbtablespaces(Oid db_id){ Relation rel; HeapScanDesc scan; HeapTuple tuple; rel = heap_open(TableSpaceRelationId, AccessShareLock); scan = heap_beginscan(rel, SnapshotNow, 0, NULL); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL) { Oid dsttablespace = HeapTupleGetOid(tuple); char *dstpath; struct stat st; /* Don't mess with the global tablespace */ if (dsttablespace == GLOBALTABLESPACE_OID) continue; dstpath = GetDatabasePath(db_id, dsttablespace); if (stat(dstpath, &st) < 0 || !S_ISDIR(st.st_mode)) { /* Assume we can ignore it */ pfree(dstpath); continue; } if (!rmtree(dstpath, true)) ereport(WARNING, (errmsg("could not remove database directory \"%s\"", dstpath))); /* Record the filesystem change in XLOG */ { xl_dbase_drop_rec xlrec; XLogRecData rdata[1]; xlrec.db_id = db_id; xlrec.tablespace_id = dsttablespace; rdata[0].data = (char *) &xlrec; rdata[0].len = sizeof(xl_dbase_drop_rec); rdata[0].buffer = InvalidBuffer; rdata[0].next = NULL; (void) XLogInsert(RM_DBASE_ID, XLOG_DBASE_DROP, rdata); } pfree(dstpath); } heap_endscan(scan); heap_close(rel, AccessShareLock);}/* * get_database_oid - given a database name, look up the OID * * Returns InvalidOid if database name not found. * * This is not actually used in this file, but is exported for use elsewhere. */Oidget_database_oid(const char *dbname){ Relation pg_database; ScanKeyData entry[1]; SysScanDesc scan; HeapTuple dbtuple; Oid oid; /* There's no syscache for pg_database, so must look the hard way */ pg_database = heap_open(DatabaseRelationId, AccessShareLock); ScanKeyInit(&entry[0], Anum_pg_database_datname, BTEqualStrategyNumber, F_NAMEEQ, CStringGetDatum(dbname)); scan = systable_beginscan(pg_database, DatabaseNameIndexId, true, SnapshotNow, 1, entry); dbtuple = systable_getnext(scan); /* We assume that there can be at most one matching tuple */ if (HeapTupleIsValid(dbtuple)) oid = HeapTupleGetOid(dbtuple); else oid = InvalidOid; systable_endscan(scan); heap_close(pg_database, AccessShareLock); return oid;}/* * get_database_name - given a database OID, look up the name * * Returns a palloc'd string, or NULL if no such database. * * This is not actually used in this file, but is exported for use elsewhere. */char *get_database_name(Oid dbid){ Relation pg_database; ScanKeyData entry[1]; SysScanDesc scan; HeapTuple dbtuple; char *result; /* There's no syscache for pg_database, so must look the hard way */ pg_database = heap_open(DatabaseRelationId, AccessShareLock); ScanKeyInit(&entry[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(dbid)); scan = systable_beginscan(pg_database, DatabaseOidIndexId, true, SnapshotNow, 1, entry); dbtuple = systable_getnext(scan); /* We assume that there can be at most one matching tuple */ if (HeapTupleIsValid(dbtuple)) result = pstrdup(NameStr(((Form_pg_database) GETSTRUCT(dbtuple))->datname)); else result = NULL; systable_endscan(scan); heap_close(pg_database, AccessShareLock); return result;}/* * DATABASE resource manager's routines */voiddbase_redo(XLogRecPtr lsn, XLogRecord *record){ uint8 info = record->xl_info & ~XLR_INFO_MASK; if (info == XLOG_DBASE_CREATE) { xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) XLogRecGetData(record); char *src_path; char *dst_path; struct stat st; src_path = GetDatabasePath(xlrec->src_db_id, xlrec->src_tablespace_id); dst_path = GetDatabasePath(xlrec->db_id, xlrec->tablespace_id); /* * Our theory for replaying a CREATE is to forcibly drop the target * subdirectory if present, then re-copy the source data. This may be * more work than needed, but it is simple to implement. */ if (stat(dst_path, &st) == 0 && S_ISDIR(st.st_mode)) { if (!rmtree(dst_path, true)) ereport(WARNING, (errmsg("could not remove database directory \"%s\"", dst_path))); } /* * Force dirty buffers out to disk, to ensure source database is * up-to-date for the copy. (We really only need to flush buffers for * the source database, but bufmgr.c provides no API for that.) */ BufferSync(); /* * Copy this subdirectory to the new location * * We don't need to copy subdirectories */ copydir(src_path, dst_path, false); } else if (info == XLOG_DBASE_DROP) { xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) XLogRecGetData(record); char *dst_path; dst_path = GetDatabasePath(xlrec->db_id, xlrec->tablespace_id); /* * Drop pages for this database that are in the shared buffer cache */ DropBuffers(xlrec->db_id); if (!rmtree(dst_path, true)) ereport(WARNING, (errmsg("could not remove database directory \"%s\"", dst_path))); } else elog(PANIC, "dbase_redo: unknown op code %u", info);}voiddbase_desc(char *buf, uint8 xl_info, char *rec){ uint8 info = xl_info & ~XLR_INFO_MASK; if (info == XLOG_DBASE_CREATE) { xl_dbase_create_rec *xlrec = (xl_dbase_create_rec *) rec; sprintf(buf + strlen(buf), "create db: copy dir %u/%u to %u/%u", xlrec->src_db_id, xlrec->src_tablespace_id, xlrec->db_id, xlrec->tablespace_id); } else if (info == XLOG_DBASE_DROP) { xl_dbase_drop_rec *xlrec = (xl_dbase_drop_rec *) rec; sprintf(buf + strlen(buf), "drop db: dir %u/%u", xlrec->db_id, xlrec->tablespace_id); } else strcat(buf, "UNKNOWN");}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -