Skip to content

PostgreSQL: connect directly to the configured database when told not to create it - #562

Closed
DutchmanNL wants to merge 2 commits into
ioBroker:masterfrom
DutchmanNL:fix/pg-do-not-create-database
Closed

DutchmanNL wants to merge 2 commits into
ioBroker:masterfrom
DutchmanNL:fix/pg-do-not-create-database

Conversation

@DutchmanNL

Copy link
Copy Markdown
Contributor

Fixes #404 and #285, and is what makes the Supabase request in #481 work on the normal postgresql dbtype.

The bug

The two-phase PostgreSQL connect always opens the maintenance database postgres first. With "do not create database" set, it connected there, did nothing, disconnected and reconnected:

if (this.config.doNotCreateDatabase) {
    _client.disconnect();          // connected to "postgres" for nothing
    this.postgresDbCreated = true;
    this.reconnectTimeout = setTimeout(() => this.connect(callback), 100);
} else {
    _client.execute(`CREATE DATABASE ${this.config.dbname};` ...

So the option avoided the CREATE DATABASE, but not the connection that needs a privilege nobody grants on a managed PostgreSQL.

A role without CONNECT on postgres therefore never reached its own database at all — the first phase was refused and the adapter looped on the 30 s reconnect forever:

error: Cannot connect to 127.0.0.1: error: permission denied for database "postgres" (code: 42501)
debug: Cannot connect to 127.0.0.1: ... (attempt 2)
debug: Cannot connect to 127.0.0.1: ... (attempt 3)

The fix

With the option set, connect() skips the maintenance phase entirely and goes straight to the configured database. The default path is untouched.

Table creation is unaffected either way: init() only ever returns CREATE TABLE statements, runs against the configured database, and tolerates tables that already exist — so the option means "do not create the database", exactly as it says.

The admin "Test connection" button had the same hardcoded database, which is the actual defect behind #285: it tested postgres rather than the configured database, and so reported a failure for a perfectly good configuration. It now tests the configured database when the option is set.

Test

test/testPostgreSQLNoCreateDb.js builds the situation it guards, rather than assuming it: as superuser it creates a role with no CONNECT on postgres plus a pre-existing database of its own, then runs the adapter as that role with the option enabled. It asserts the adapter connects, created its six tables in the configured database, and round-trips a value. It restores CONNECT and drops the fixture afterwards, so it is self-contained and CI-portable.

result
unfixed master + this test 0 passing, 3 failing — permission denied for database "postgres" (code: 42501), "adapter never reported a connection"
this branch 3 passing (16 s) — tables ["datapoints","sources","ts_bool","ts_counter","ts_number","ts_string"], getHistory returns the written 4711

Worth noting: a test that enables this option as the superuser passes either way, because the superuser can open postgres — which is why the test uses a restricted role.

npm run check:ts and npx prettier --check clean (including the new test file — npm run lint does not cover test/**/*.js). (npm run lint reports 3 errors in src-admin/, all pre-existing on unmodified master in files this PR does not touch.)

Relation to #561

This is the other half of the same original change; #561 covers the info.connection reporting (#374). They are independent and can land in either order.

🤖 Generated with Claude Code

DutchmanNL and others added 2 commits October 2, 2026 01:36
…to create it

The two-phase PostgreSQL connect always opened the maintenance database
"postgres" first. With "do not create database" set it connected there,
did nothing, disconnected and reconnected - so the option avoided the
CREATE DATABASE, but not the connection that needs privileges nobody grants
on a managed PostgreSQL.

A role without CONNECT on "postgres" therefore never reached its own
database at all: the first phase was refused with 42501 and the adapter
looped on the 30 s reconnect forever (ioBroker#404). That is also what makes the
Supabase request in ioBroker#481 fail on the normal postgresql dbtype.

With the option set, connect() now skips the maintenance phase entirely.
The default path is unchanged. Table creation is unaffected either way:
init() only ever returns CREATE TABLE statements and runs against the
configured database, tolerating tables that already exist.

The admin "Test connection" button had the same hardcoded database, which
is the actual defect behind ioBroker#285 - it reported a failure for a perfectly
good configuration. It now tests the configured database when the option
is set.

Adds test/testPostgreSQLNoCreateDb.js, which builds the situation it
guards: a role with no CONNECT on "postgres" and a pre-existing database of
its own. It asserts the adapter connects, creates its six tables in the
configured database and round-trips a value. On the unfixed code it fails
with "permission denied for database postgres" and the adapter never
connects.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@GermanBluefox

Copy link
Copy Markdown
Contributor

Reimplemented: #568

@GermanBluefox

Copy link
Copy Markdown
Contributor

Merged via #568, which carries your commit with authorship intact (f4233fd). The fix is in master as of 5672156.

Thank you — the diagnosis was precise, and the part that turned out to matter most was one you found rather than the one in the title: the admin "Test connection" button had database: 'postgres' hardcoded, so it reported a failure for configurations that were perfectly fine. That is the actual defect behind #285.

Two things happened on the way, for the record:

  • Rebased onto current master. src/main.ts merged cleanly; only README.md (both sides added a WORK IN PROGRESS section) and the generated build/main.js.map conflicted. The map was resolved by rebuilding rather than by hand, so the committed output matches the source.
  • The new test was not reaching CI. The Postgres job named one exact file, test/testPostgreSQL.js, so testPostgreSQLNoCreateDb.js would never have run. The job now uses a glob. Worth knowing for future test files — the unit-test step has the same shape and bit us in Add support for MySQL unix sockets (#104) #565 as well.

Closing in favour of #568.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants