diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index d7257e4056..e459c1172f 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -567,6 +567,8 @@ int postmaster_alive_fds[2] = {-1, -1}; HANDLE PostmasterHandle; #endif +FailedConnection_hook_type FailedConnection_hook = NULL; + /* * Postmaster main entry point */ @@ -4461,8 +4463,11 @@ BackendInitialize(Port *port) * Stop here if it was bad or a cancel packet. ProcessStartupPacket * already did any appropriate error reporting. */ - if (status != STATUS_OK) + if (status != STATUS_OK) { + if (FailedConnection_hook) + (*FailedConnection_hook) (FCET_BSP, port); proc_exit(0); + } /* * Now that we have the user and database name, we can set the process @@ -5322,6 +5327,11 @@ dummy_handler(SIGNAL_ARGS) static void StartupPacketTimeoutHandler(void) { + if (FailedConnection_hook) + (*FailedConnection_hook) (FCET_SPT, MyProcPort); + ereport(COMMERROR, + (errcode(ERRCODE_PROTOCOL_VIOLATION), + errmsg("timeout while processing startup packet"))); _exit(1); } diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c index 6b9082604f..a064966f67 100644 --- a/src/backend/utils/init/postinit.c +++ b/src/backend/utils/init/postinit.c @@ -360,10 +360,14 @@ CheckMyDatabase(const char *name, bool am_superuser, bool override_allow_connect if (!am_superuser && pg_database_aclcheck(MyDatabaseId, GetUserId(), ACL_CONNECT) != ACLCHECK_OK) + { + if (FailedConnection_hook) + (*FailedConnection_hook) (FCET_BDP, MyProcPort); ereport(FATAL, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for database \"%s\"", name), errdetail("User does not have CONNECT privilege."))); + } /* * Check connection limit for this database. @@ -918,9 +922,13 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, tuple = GetDatabaseTuple(in_dbname); if (!HeapTupleIsValid(tuple)) + { + if (FailedConnection_hook) + (*FailedConnection_hook) (FCET_BDN, MyProcPort); ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database \"%s\" does not exist", in_dbname))); + } dbform = (Form_pg_database) GETSTRUCT(tuple); MyDatabaseId = dbform->oid; MyDatabaseTableSpace = dbform->dattablespace; @@ -935,9 +943,13 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, tuple = GetDatabaseTupleByOid(dboid); if (!HeapTupleIsValid(tuple)) + { + if (FailedConnection_hook) + (*FailedConnection_hook) (FCET_BDO, MyProcPort); ereport(FATAL, (errcode(ERRCODE_UNDEFINED_DATABASE), errmsg("database %u does not exist", dboid))); + } dbform = (Form_pg_database) GETSTRUCT(tuple); MyDatabaseId = dbform->oid; MyDatabaseTableSpace = dbform->dattablespace; diff --git a/src/include/fmgr.h b/src/include/fmgr.h index 5314b73705..5425e778bf 100644 --- a/src/include/fmgr.h +++ b/src/include/fmgr.h @@ -778,4 +778,22 @@ extern PGDLLIMPORT fmgr_hook_type fmgr_hook; #define FmgrHookIsNeeded(fn_oid) \ (!needs_fmgr_hook ? false : (*needs_fmgr_hook)(fn_oid)) + +/* + * The failed connection events to be used in the FailedConnection_hook. + */ +typedef enum FailedConnectionEventType +{ + FCET_SPT, /* startup packet timeout */ + FCET_BSP, /* bad startup packet */ + FCET_BDN, /* bad database name */ + FCET_BDO, /* bad database Oid */ + FCET_BDP /* bad database permission */ +} FailedConnectionEventType; + +/* kluge to avoid including libpq/libpq-be.h here */ +struct Port; +typedef void (*FailedConnection_hook_type) (FailedConnectionEventType event, const struct Port *port); +extern PGDLLIMPORT FailedConnection_hook_type FailedConnection_hook; + #endif /* FMGR_H */ diff --git a/src/tools/pgindent/typedefs.list b/src/tools/pgindent/typedefs.list index 4fb746930a..4fadafbddb 100644 --- a/src/tools/pgindent/typedefs.list +++ b/src/tools/pgindent/typedefs.list @@ -717,6 +717,7 @@ FPI FSMAddress FSMPage FSMPageData +FailedConnection_hook_type FakeRelCacheEntry FakeRelCacheEntryData FastPathStrongRelationLockData