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 + -
显示快捷键?