dbcommands.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,044 行 · 第 1/2 页
C
1,044 行
*/ if (DatabaseHasActiveBackends(db_id, false)) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("database \"%s\" is being accessed by other users", dbname))); /* * Find the database's tuple by OID (should be unique). */ ScanKeyEntryInitialize(&key, 0, ObjectIdAttributeNumber, F_OIDEQ, ObjectIdGetDatum(db_id)); pgdbscan = systable_beginscan(pgdbrel, DatabaseOidIndex, true, SnapshotNow, 1, &key); tup = systable_getnext(pgdbscan); if (!HeapTupleIsValid(tup)) { /* * This error should never come up since the existence of the * database is checked earlier */ elog(ERROR, "database \"%s\" doesn't exist despite earlier reports to the contrary", dbname); } /* Remove the database's tuple from pg_database */ simple_heap_delete(pgdbrel, &tup->t_self); systable_endscan(pgdbscan); /* * Delete any comments associated with the database * * NOTE: this is probably dead code since any such comments should have * been in that database, not mine. */ DeleteComments(db_id, RelationGetRelid(pgdbrel), 0); /* * Close pg_database, but keep exclusive lock till commit to ensure * that any new backend scanning pg_database will see the tuple dead. */ heap_close(pgdbrel, NoLock); /* * Drop pages for this database that are in the shared buffer cache. * This is important to ensure that no remaining backend tries to * write out a dirty buffer to the dead database later... */ DropBuffers(db_id); /* * Also, clean out any entries in the shared free space map. */ FreeSpaceMapForgetDatabase(db_id); /* * Remove the database's subdirectory and everything in it. */ remove_dbdirs(nominal_loc, alt_loc); /* * Force dirty buffers out to disk, so that newly-connecting backends * will see the database tuple marked dead in pg_database right away. * (They'll see an uncommitted deletion, but they don't care; see * GetRawDatabaseInfo.) */ BufferSync();}/* * Rename database */voidRenameDatabase(const char *oldname, const char *newname){ HeapTuple tup, newtup; Relation rel; SysScanDesc scan, scan2; ScanKeyData key, key2; /* * Obtain AccessExclusiveLock so that no new session gets started * while the rename is in progress. */ rel = heap_openr(DatabaseRelationName, AccessExclusiveLock); ScanKeyEntryInitialize(&key, 0, Anum_pg_database_datname, F_NAMEEQ, NameGetDatum(oldname)); scan = systable_beginscan(rel, DatabaseNameIndex, true, SnapshotNow, 1, &key); tup = systable_getnext(scan); if (!HeapTupleIsValid(tup)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", oldname))); /* * XXX Client applications probably store the current database * somewhere, so renaming it could cause confusion. On the other * hand, there may not be an actual problem besides a little * confusion, so think about this and decide. */ if (HeapTupleGetOid(tup) == MyDatabaseId) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("current database may not be renamed"))); /* * Make sure the database does not have active sessions. Might not be * necessary, but it's consistent with other database operations. */ if (DatabaseHasActiveBackends(HeapTupleGetOid(tup), false)) ereport(ERROR, (errcode(ERRCODE_OBJECT_IN_USE), errmsg("database \"%s\" is being accessed by other users", oldname))); /* make sure the new name doesn't exist */ ScanKeyEntryInitialize(&key2, 0, Anum_pg_database_datname, F_NAMEEQ, NameGetDatum(newname)); scan2 = systable_beginscan(rel, DatabaseNameIndex, true, SnapshotNow, 1, &key2); if (HeapTupleIsValid(systable_getnext(scan2))) ereport(ERROR, (errcode(ERRCODE_DUPLICATE_DATABASE), errmsg("database \"%s\" already exists", newname))); systable_endscan(scan2); /* must be owner */ if (!pg_database_ownercheck(HeapTupleGetOid(tup), GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, oldname); /* must have createdb */ if (!have_createdb_privilege()) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied to rename database"))); /* rename */ newtup = heap_copytuple(tup); namestrcpy(&(((Form_pg_database) GETSTRUCT(newtup))->datname), newname); simple_heap_update(rel, &tup->t_self, newtup); CatalogUpdateIndexes(rel, newtup); systable_endscan(scan); heap_close(rel, NoLock); /* * Force dirty buffers out to disk, so that newly-connecting backends * will see the renamed database in pg_database right away. (They'll * see an uncommitted tuple, but they don't care; see * GetRawDatabaseInfo.) */ BufferSync();}/* * ALTER DATABASE name SET ... */voidAlterDatabaseSet(AlterDatabaseSetStmt *stmt){ char *valuestr; HeapTuple tuple, newtuple; Relation rel; ScanKeyData scankey; SysScanDesc scan; Datum repl_val[Natts_pg_database]; char repl_null[Natts_pg_database]; char repl_repl[Natts_pg_database]; valuestr = flatten_set_variable_args(stmt->variable, stmt->value); rel = heap_openr(DatabaseRelationName, RowExclusiveLock); ScanKeyEntryInitialize(&scankey, 0, Anum_pg_database_datname, F_NAMEEQ, NameGetDatum(stmt->dbname)); scan = systable_beginscan(rel, DatabaseNameIndex, true, SnapshotNow, 1, &scankey); tuple = systable_getnext(scan); if (!HeapTupleIsValid(tuple)) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", stmt->dbname))); if (!(superuser() || ((Form_pg_database) GETSTRUCT(tuple))->datdba == GetUserId())) aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE, stmt->dbname); MemSet(repl_repl, ' ', sizeof(repl_repl)); repl_repl[Anum_pg_database_datconfig - 1] = 'r'; if (strcmp(stmt->variable, "all") == 0 && valuestr == NULL) { /* RESET ALL */ repl_null[Anum_pg_database_datconfig - 1] = 'n'; repl_val[Anum_pg_database_datconfig - 1] = (Datum) 0; } else { Datum datum; bool isnull; ArrayType *a; repl_null[Anum_pg_database_datconfig - 1] = ' '; datum = heap_getattr(tuple, Anum_pg_database_datconfig, RelationGetDescr(rel), &isnull); a = isnull ? ((ArrayType *) NULL) : DatumGetArrayTypeP(datum); 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, rel, repl_val, repl_null, repl_repl); simple_heap_update(rel, &tuple->t_self, newtuple); /* Update indexes */ CatalogUpdateIndexes(rel, newtuple); systable_endscan(scan); heap_close(rel, RowExclusiveLock);}/* * Helper functions */static boolget_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP, int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP, TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP, char *dbpath){ 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_openr(DatabaseRelationName, AccessShareLock); ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname, F_NAMEEQ, NameGetDatum(name)); scan = systable_beginscan(relation, DatabaseNameIndex, 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); /* sysid of the owner */ if (ownerIdP) *ownerIdP = dbform->datdba; /* character encoding */ if (encodingP) *encodingP = dbform->encoding; /* allowed as template? */ if (dbIsTemplateP) *dbIsTemplateP = dbform->datistemplate; /* 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; /* database path (as registered in pg_database) */ if (dbpath) { Datum datum; bool isnull; datum = heap_getattr(tuple, Anum_pg_database_datpath, RelationGetDescr(relation), &isnull); if (!isnull) { text *pathtext = DatumGetTextP(datum); int pathlen = VARSIZE(pathtext) - VARHDRSZ; Assert(pathlen >= 0 && pathlen < MAXPGPATH); strncpy(dbpath, VARDATA(pathtext), pathlen); *(dbpath + pathlen) = '\0'; } else strcpy(dbpath, ""); } } systable_endscan(scan); heap_close(relation, AccessShareLock); return gottuple;}static boolhave_createdb_privilege(void){ HeapTuple utup; bool retval; utup = SearchSysCache(SHADOWSYSID, Int32GetDatum(GetUserId()), 0, 0, 0); if (!HeapTupleIsValid(utup)) retval = false; else retval = ((Form_pg_shadow) GETSTRUCT(utup))->usecreatedb; ReleaseSysCache(utup); return retval;}static char *resolve_alt_dbpath(const char *dbpath, Oid dboid){ const char *prefix; char *ret; size_t len; if (dbpath == NULL || dbpath[0] == '\0') return NULL; if (first_path_separator(dbpath)) { if (!is_absolute_path(dbpath)) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("relative paths are not allowed as database locations")));#ifndef ALLOW_ABSOLUTE_DBPATHS ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("absolute paths are not allowed as database locations")));#endif prefix = dbpath; } else { /* must be environment variable */ char *var = getenv(dbpath); if (!var) ereport(ERROR, (errcode(ERRCODE_UNDEFINED_OBJECT), errmsg("postmaster environment variable \"%s\" not found", dbpath))); if (!is_absolute_path(var)) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("postmaster environment variable \"%s\" must be absolute path", dbpath))); prefix = var; } len = strlen(prefix) + 6 + sizeof(Oid) * 8 + 1; if (len >= MAXPGPATH - 100) ereport(ERROR, (errcode(ERRCODE_INVALID_NAME), errmsg("alternative path is too long"))); ret = palloc(len); snprintf(ret, len, "%s/base/%u", prefix, dboid); return ret;}static boolremove_dbdirs(const char *nominal_loc, const char *alt_loc){ const char *target_dir; char buf[MAXPGPATH + 100]; bool success = true; target_dir = alt_loc ? alt_loc : nominal_loc; /* * Close virtual file descriptors so the kernel has more available for * the system() call below. */ closeAllVfds(); if (alt_loc) { /* remove symlink */ if (unlink(nominal_loc) != 0) { ereport(WARNING, (errcode_for_file_access(), errmsg("could not remove file \"%s\": %m", nominal_loc))); success = false; } }#ifndef WIN32 snprintf(buf, sizeof(buf), "rm -rf '%s'", target_dir);#else snprintf(buf, sizeof(buf), "rmdir /s /q \"%s\"", target_dir);#endif if (system(buf) != 0) { ereport(WARNING, (errmsg("could not remove database directory \"%s\"", target_dir), errdetail("Failing system command was: %s", buf), errhint("Look in the postmaster's stderr log for more information."))); success = false; } return success;}/* * 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_openr(DatabaseRelationName, AccessShareLock); ScanKeyEntryInitialize(&entry[0], 0x0, Anum_pg_database_datname, F_NAMEEQ, CStringGetDatum(dbname)); scan = systable_beginscan(pg_database, DatabaseNameIndex, 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 InvalidOid if database name not found. * * 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_openr(DatabaseRelationName, AccessShareLock); ScanKeyEntryInitialize(&entry[0], 0x0, ObjectIdAttributeNumber, F_OIDEQ, ObjectIdGetDatum(dbid)); scan = systable_beginscan(pg_database, DatabaseOidIndex, 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;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?