On Fri, May 15, 2015 at 3:53 PM, Robert Haas <robertmh...@gmail.com> wrote: > On Thu, May 14, 2015 at 8:25 AM, Pavel Stehule <pavel.steh...@gmail.com> > 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 (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers