On Fri, May 15, 2015 at 3:53 PM, Robert Haas <[email protected]> wrote:
> On Thu, May 14, 2015 at 8:25 AM, Pavel Stehule <[email protected]>
> wrote:
>> The documentation (or this feature) is broken still
>>
>> If dbname is NULL or dboid is InvalidOid, the session is not connected to
>> any particular database, but shared catalogs can be accessed. If username is
>> NULL or useroid is InvalidOid, the process will run as the superuser created
>> during initdb. A background worker can only call one of these two functions,
>> and only once. It is not possible to switch databases.
>>
>> But it fails with error:
>>
>> FATAL: database 0 does not exist
>
> Ugh. I think that's a bug.
>
> Patch attached.
>
> The test code I used to verify that this works is also attached.
>
> If there are no objections, I will commit and back-patch.
Oops. Really attached this time.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
diff --git a/src/backend/utils/init/postinit.c b/src/backend/utils/init/postinit.c
index debadf0..28a4966 100644
--- a/src/backend/utils/init/postinit.c
+++ b/src/backend/utils/init/postinit.c
@@ -827,7 +827,7 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
/* take database name from the caller, just for paranoia */
strlcpy(dbname, in_dbname, sizeof(dbname));
}
- else
+ else if (OidIsValid(dboid))
{
/* caller specified database by OID */
HeapTuple tuple;
@@ -847,6 +847,18 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
if (out_dbname)
strcpy(out_dbname, dbname);
}
+ else
+ {
+ /*
+ * If this is a background worker not bound to any particular
+ * database, we're done now. Everything that follows only makes
+ * sense if we are bound to a specific database. We do need to
+ * close the transaction we started before returning.
+ */
+ if (!bootstrap)
+ CommitTransactionCommand();
+ return;
+ }
/* Now we can mark our PGPROC entry with the database ID */
/* (We assume this is an atomic store so no lock is needed) */
diff --git a/contrib/no_db_worker/Makefile b/contrib/no_db_worker/Makefile
new file mode 100644
index 0000000..2085c95
--- /dev/null
+++ b/contrib/no_db_worker/Makefile
@@ -0,0 +1,18 @@
+# contrib/no_db_worker
+
+MODULES = no_db_worker
+
+EXTENSION = no_db_worker
+DATA = no_db_worker--1.0.sql
+PGFILEDESC = "no_db_worker - background worker without database"
+
+ifdef USE_PGXS
+PG_CONFIG = pg_config
+PGXS := $(shell $(PG_CONFIG) --pgxs)
+include $(PGXS)
+else
+subdir = contrib/no_db_worker
+top_builddir = ../..
+include $(top_builddir)/src/Makefile.global
+include $(top_srcdir)/contrib/contrib-global.mk
+endif
diff --git a/contrib/no_db_worker/no_db_worker--1.0.sql b/contrib/no_db_worker/no_db_worker--1.0.sql
new file mode 100644
index 0000000..a38ec63
--- /dev/null
+++ b/contrib/no_db_worker/no_db_worker--1.0.sql
@@ -0,0 +1,7 @@
+/* contrib/no_db_worker/no_db_worker--1.0.sql */
+
+-- complain if script is sourced in psql, rather than via CREATE EXTENSION
+\echo Use "CREATE EXTENSION no_db_worker" to load this file. \quit
+
+CREATE FUNCTION no_db_worker_launch() RETURNS pg_catalog.int4 STRICT
+AS 'MODULE_PATHNAME' LANGUAGE C;
diff --git a/contrib/no_db_worker/no_db_worker.c b/contrib/no_db_worker/no_db_worker.c
new file mode 100644
index 0000000..2a09bc4
--- /dev/null
+++ b/contrib/no_db_worker/no_db_worker.c
@@ -0,0 +1,103 @@
+/* -------------------------------------------------------------------------
+ *
+ * no_db_worker.c
+ * A database worker that does not connect to any particular database.
+ *
+ * Copyright (C) 2015, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * contrib/no_db_worker/no_db_worker.c
+ *
+ * -------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/relscan.h"
+#include "access/xact.h"
+#include "catalog/pg_database.h"
+#include "fmgr.h"
+#include "miscadmin.h"
+#include "postmaster/bgworker.h"
+#include "storage/ipc.h"
+#include "utils/rel.h"
+#include "utils/snapmgr.h"
+
+PG_MODULE_MAGIC;
+
+PG_FUNCTION_INFO_V1(no_db_worker_launch);
+
+extern void no_db_worker_main(Datum main_arg);
+
+void
+no_db_worker_main(Datum main_arg)
+{
+ Relation rel;
+ HeapScanDesc scan;
+ HeapTuple tup;
+
+ BackgroundWorkerInitializeConnection(NULL, NULL);
+
+ StartTransactionCommand();
+ (void) GetTransactionSnapshot();
+
+ rel = heap_open(DatabaseRelationId, AccessShareLock);
+ scan = heap_beginscan_catalog(rel, 0, NULL);
+
+ while (HeapTupleIsValid(tup = heap_getnext(scan, ForwardScanDirection)))
+ {
+ Form_pg_database pgdatabase = (Form_pg_database) GETSTRUCT(tup);
+
+ elog(LOG, "found database with OID %u and name \"%s\"",
+ HeapTupleGetOid(tup), NameStr(pgdatabase->datname));
+ }
+
+ elog(LOG, "done scanning pg_database");
+
+ heap_endscan(scan);
+ heap_close(rel, AccessShareLock);
+
+ proc_exit(1);
+}
+
+/*
+ * Dynamically launch an SPI worker.
+ */
+Datum
+no_db_worker_launch(PG_FUNCTION_ARGS)
+{
+ BackgroundWorker worker;
+ BackgroundWorkerHandle *handle;
+ BgwHandleStatus status;
+ pid_t pid;
+
+ worker.bgw_flags = BGWORKER_SHMEM_ACCESS |
+ BGWORKER_BACKEND_DATABASE_CONNECTION;
+ worker.bgw_start_time = BgWorkerStart_RecoveryFinished;
+ worker.bgw_restart_time = BGW_NEVER_RESTART;
+ worker.bgw_main = NULL; /* new worker might not have library loaded */
+ sprintf(worker.bgw_library_name, "no_db_worker");
+ sprintf(worker.bgw_function_name, "no_db_worker_main");
+ sprintf(worker.bgw_name, "no_db_worker");
+ worker.bgw_main_arg = 0;
+ /* set bgw_notify_pid so that we can use WaitForBackgroundWorkerStartup */
+ worker.bgw_notify_pid = MyProcPid;
+
+ if (!RegisterDynamicBackgroundWorker(&worker, &handle))
+ PG_RETURN_NULL();
+
+ status = WaitForBackgroundWorkerStartup(handle, &pid);
+
+ if (status == BGWH_STOPPED)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
+ errmsg("could not start background process"),
+ errhint("More details may be available in the server log.")));
+ if (status == BGWH_POSTMASTER_DIED)
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_RESOURCES),
+ errmsg("cannot start background processes without postmaster"),
+ errhint("Kill all remaining database processes and restart the database.")));
+ Assert(status == BGWH_STARTED);
+
+ PG_RETURN_INT32(pid);
+}
diff --git a/contrib/no_db_worker/no_db_worker.control b/contrib/no_db_worker/no_db_worker.control
new file mode 100644
index 0000000..c9e0d0c
--- /dev/null
+++ b/contrib/no_db_worker/no_db_worker.control
@@ -0,0 +1,5 @@
+# no_db_worker extension
+comment = 'No-database background worker'
+default_version = '1.0'
+module_pathname = '$libdir/no_db_worker'
+relocatable = true
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers