⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dbcommands.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 3 页
字号:
		/*		 * We deliberately set datconfig and datacl to defaults (NULL), rather		 * than copying them from the template database.  Copying datacl would		 * be a bad idea when the owner is not the same as the template's		 * owner. It's more debatable whether datconfig should be copied.		 */		new_record_nulls[Anum_pg_database_datconfig - 1] = 'n';		new_record_nulls[Anum_pg_database_datacl - 1] = 'n';		tuple = heap_formtuple(pg_database_dsc, new_record, new_record_nulls);		HeapTupleSetOid(tuple, dboid);	/* override heap_insert's OID										 * selection */		simple_heap_insert(pg_database_rel, tuple);		/* Update indexes */		CatalogUpdateIndexes(pg_database_rel, tuple);		/* Register owner dependency */		recordDependencyOnOwner(DatabaseRelationId, dboid, datdba);		/* Create pg_shdepend entries for objects within database */		copyTemplateDependencies(src_dboid, dboid);		/*		 * We force a checkpoint before committing.  This effectively means		 * that committed XLOG_DBASE_CREATE operations will never need to be		 * replayed (at least not in ordinary crash recovery; we still have to		 * make the XLOG entry for the benefit of PITR operations). This		 * avoids two nasty scenarios:		 *		 * #1: When PITR is off, we don't XLOG the contents of newly created		 * indexes; therefore the drop-and-recreate-whole-directory behavior		 * of DBASE_CREATE replay would lose such indexes.		 *		 * #2: Since we have to recopy the source database during DBASE_CREATE		 * replay, we run the risk of copying changes in it that were		 * committed after the original CREATE DATABASE command but before the		 * system crash that led to the replay.  This is at least unexpected		 * and at worst could lead to inconsistencies, eg duplicate table		 * names.		 *		 * (Both of these were real bugs in releases 8.0 through 8.0.3.)		 *		 * In PITR replay, the first of these isn't an issue, and the second		 * is only a risk if the CREATE DATABASE and subsequent template		 * database change both occur while a base backup is being taken.		 * There doesn't seem to be much we can do about that except document		 * it as a limitation.		 *		 * Perhaps if we ever implement CREATE DATABASE in a less cheesy way,		 * we can avoid this.		 */		RequestCheckpoint(true, false);		/*		 * Set flag to update flat database file at commit.		 */		database_file_update_needed();	}	PG_CATCH();	{		/* Don't hold pg_database lock while doing recursive remove */		if (pg_database_rel != NULL)			heap_close(pg_database_rel, ExclusiveLock);		/* Throw away any successfully copied subdirectories */		remove_dbtablespaces(dboid);		PG_RE_THROW();	}	PG_END_TRY();	/* Close pg_database, but keep exclusive lock till commit */	/* This has to be outside the PG_TRY */	heap_close(pg_database_rel, NoLock);}/* * DROP DATABASE */voiddropdb(const char *dbname){	Oid			db_id;	bool		db_istemplate;	Relation	pgdbrel;	SysScanDesc pgdbscan;	ScanKeyData key;	HeapTuple	tup;	PreventTransactionChain((void *) dbname, "DROP DATABASE");	AssertArg(dbname);	if (strcmp(dbname, get_database_name(MyDatabaseId)) == 0)		ereport(ERROR,				(errcode(ERRCODE_OBJECT_IN_USE),				 errmsg("cannot drop the currently open database")));	/*	 * Obtain exclusive lock on pg_database.  We need this to ensure that no	 * new backend starts up in the target database while we are deleting it.	 * (Actually, a new backend might still manage to start up, because it	 * isn't able to lock pg_database while starting.  But it will detect its	 * error in ReverifyMyDatabase and shut down before any serious damage is	 * done.  See postinit.c.)	 *	 * An ExclusiveLock, rather than AccessExclusiveLock, is sufficient since	 * ReverifyMyDatabase takes RowShareLock.  This allows ordinary readers of	 * pg_database to proceed in parallel.	 */	pgdbrel = heap_open(DatabaseRelationId, ExclusiveLock);	if (!get_db_info(dbname, &db_id, NULL, NULL,					 &db_istemplate, NULL, NULL, NULL, NULL, NULL))		ereport(ERROR,				(errcode(ERRCODE_UNDEFINED_DATABASE),				 errmsg("database \"%s\" does not exist", dbname)));	if (!pg_database_ownercheck(db_id, GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,					   dbname);	/*	 * Disallow dropping a DB that is marked istemplate.  This is just to	 * prevent people from accidentally dropping template0 or template1; they	 * can do so if they're really determined ...	 */	if (db_istemplate)		ereport(ERROR,				(errcode(ERRCODE_WRONG_OBJECT_TYPE),				 errmsg("cannot drop a template database")));	/*	 * Check for active backends in the target database.	 */	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).	 */	ScanKeyInit(&key,				ObjectIdAttributeNumber,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(db_id));	pgdbscan = systable_beginscan(pgdbrel, DatabaseOidIndexId, 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, DatabaseRelationId, 0);	/*	 * Remove shared dependency references for the database.	 */	dropDatabaseDependencies(db_id);	/*	 * 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);	/*	 * On Windows, force a checkpoint so that the bgwriter doesn't hold any	 * open files, which would cause rmdir() to fail.	 */#ifdef WIN32	RequestCheckpoint(true, false);#endif	/*	 * Remove all tablespace subdirs belonging to the database.	 */	remove_dbtablespaces(db_id);	/* Close pg_database, but keep exclusive lock till commit */	heap_close(pgdbrel, NoLock);	/*	 * Set flag to update flat database file at commit.	 */	database_file_update_needed();}/* * Rename database */voidRenameDatabase(const char *oldname, const char *newname){	HeapTuple	tup,				newtup;	Relation	rel;	SysScanDesc scan,				scan2;	ScanKeyData key,				key2;	/*	 * Obtain ExclusiveLock so that no new session gets started while the	 * rename is in progress.	 */	rel = heap_open(DatabaseRelationId, ExclusiveLock);	ScanKeyInit(&key,				Anum_pg_database_datname,				BTEqualStrategyNumber, F_NAMEEQ,				NameGetDatum(oldname));	scan = systable_beginscan(rel, DatabaseNameIndexId, 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 */	ScanKeyInit(&key2,				Anum_pg_database_datname,				BTEqualStrategyNumber, F_NAMEEQ,				NameGetDatum(newname));	scan2 = systable_beginscan(rel, DatabaseNameIndexId, 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 rights */	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, &newtup->t_self, newtup);	CatalogUpdateIndexes(rel, newtup);	systable_endscan(scan);	/* Close pg_database, but keep exclusive lock till commit */	heap_close(rel, NoLock);	/*	 * Set flag to update flat database file at commit.	 */	database_file_update_needed();}/* * ALTER DATABASE name ... */voidAlterDatabase(AlterDatabaseStmt *stmt){	Relation	rel;	HeapTuple	tuple,				newtuple;	ScanKeyData scankey;	SysScanDesc scan;	ListCell   *option;	int			connlimit = -1;	DefElem    *dconnlimit = NULL;	Datum		new_record[Natts_pg_database];	char		new_record_nulls[Natts_pg_database];	char		new_record_repl[Natts_pg_database];	/* Extract options from the statement node tree */	foreach(option, stmt->options)	{		DefElem    *defel = (DefElem *) lfirst(option);		if (strcmp(defel->defname, "connectionlimit") == 0)		{			if (dconnlimit)				ereport(ERROR,						(errcode(ERRCODE_SYNTAX_ERROR),						 errmsg("conflicting or redundant options")));			dconnlimit = defel;		}		else			elog(ERROR, "option \"%s\" not recognized",				 defel->defname);	}	if (dconnlimit)		connlimit = intVal(dconnlimit->arg);	/*	 * 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(stmt->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", stmt->dbname)));	if (!pg_database_ownercheck(HeapTupleGetOid(tuple), GetUserId()))		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,					   stmt->dbname);	/*	 * Build an updated tuple, perusing the information just obtained	 */	MemSet(new_record, 0, sizeof(new_record));	MemSet(new_record_nulls, ' ', sizeof(new_record_nulls));	MemSet(new_record_repl, ' ', sizeof(new_record_repl));	if (dconnlimit)	{		new_record[Anum_pg_database_datconnlimit - 1] = Int32GetDatum(connlimit);		new_record_repl[Anum_pg_database_datconnlimit - 1] = 'r';	}	newtuple = heap_modifytuple(tuple, RelationGetDescr(rel), new_record,								new_record_nulls, new_record_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 the existing options for	 * ALTER DATABASE don't affect it.	 */}/* * 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);	/*	 * 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(stmt->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", stmt->dbname)));	if (!pg_database_ownercheck(HeapTupleGetOid(tuple), 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 ? NULL : DatumGetArrayTypeP(datum);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -