From b8c66ef1dfff42ea88e1f2e542a49a2b899b33d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Fri, 8 May 2026 12:05:34 +0200 Subject: [PATCH] fix: handle localized duplicate-database errors on restart (#13) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `pg0 start` failed to restart an existing instance when PostgreSQL returned a localized duplicate-database error (e.g. on Windows with a Chinese locale: `数据库 "x" 已经存在`). The previous logic relied on the English substring `already exists` to swallow the error, which never matched on non-English builds. Replaced the post-hoc string match with a `database_exists()` pre-check so the create path is locale-independent, and added a Python regression test that starts → stops → restarts an instance with a custom database. --- sdk/python/tests/test_pg0.py | 23 +++++++++++++++++++++++ src/main.rs | 13 ++++++------- 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/sdk/python/tests/test_pg0.py b/sdk/python/tests/test_pg0.py index bf4ad40..2c12779 100644 --- a/sdk/python/tests/test_pg0.py +++ b/sdk/python/tests/test_pg0.py @@ -152,6 +152,29 @@ def test_port_conflict_error(self, clean_instance): pg2.stop() pg0.drop(f"{TEST_NAME}-2") + def test_restart_with_custom_database(self, clean_instance): + """Restarting an instance with a non-default database must be idempotent. + + Regression test for https://github.com/vectorize-io/pg0/issues/13 + Previously, the second start failed because pg0 only matched the English + substring "already exists" when CREATE DATABASE returned a duplicate + error, so restarts on PostgreSQL builds with a non-English lc_messages + (e.g. Chinese on Windows: `数据库 "x" 已经存在`) crashed startup. + """ + pg = Pg0(name=TEST_NAME, port=TEST_PORT, database="testdb") + pg.start() + pg.execute("CREATE TABLE restart_test (id int);") + pg.execute("INSERT INTO restart_test VALUES (42);") + pg.stop() + + # Second start must succeed and preserve data + info = pg.start() + assert info.running is True + assert "testdb" in info.uri + result = pg.execute("SELECT id FROM restart_test;") + assert "42" in result + pg.stop() + @pytest.mark.skipif( sys.platform == "win32", reason="signal.SIGKILL does not exist on Windows; crash-recovery behavior is exercised by the Unix matrix.", diff --git a/src/main.rs b/src/main.rs index 2a85de3..64b7a58 100644 --- a/src/main.rs +++ b/src/main.rs @@ -893,13 +893,12 @@ fn start( // Create the database if it doesn't exist and it's not the default 'postgres' if database != "postgres" { - println!("Creating database '{}'...", database); - if let Err(e) = postgresql.create_database(&database) { - // Ignore error if database already exists - let err_str = e.to_string(); - if !err_str.contains("already exists") { - return Err(e.into()); - } + // Pre-check existence rather than relying on the duplicate-database error + // string, which is localized by PostgreSQL's lc_messages (e.g. on Windows + // with a Chinese locale: `数据库 "x" 已经存在`). See vectorize-io/pg0#13. + if !postgresql.database_exists(&database)? { + println!("Creating database '{}'...", database); + postgresql.create_database(&database)?; } // Grant privileges to the user on the database if username != "postgres" {