Skip to content

DBD::Pg Async Query Ownership and Data Preservation Fixes#150

Open
oetiker wants to merge 4 commits intobucardo:masterfrom
oetiker:oetiker-async-regressions
Open

DBD::Pg Async Query Ownership and Data Preservation Fixes#150
oetiker wants to merge 4 commits intobucardo:masterfrom
oetiker:oetiker-async-regressions

Conversation

@oetiker
Copy link

@oetiker oetiker commented Sep 19, 2025

DBD::Pg Async Query Ownership and Data Preservation Fixes

Caveat! I developed this code and the tests tests using Claude code in order to fix to #105 and mojolicious/mojo#2276

Overview

This document describes the comprehensive fixes for DBD::Pg's asynchronous query handling, addressing GitHub issue #105 and related problems with PG_OLDQUERY_WAIT data loss.

Problems Addressed

1. GitHub Issue #105: Statement Destruction Cancels Unrelated Async Queries

Problem: Destroying any statement handle would cancel the active async query of another statement, even if the destroyed statement never executed an async query.

Root Cause: The dbd_st_destroy() and dbd_st_finish() functions unconditionally cleared the global imp_dbh->async_sth pointer and called handle_old_async() without checking if the statement being destroyed actually owned the async query.

Impact: Applications using multiple statement handles with async queries would experience random query cancellations when unrelated statements were destroyed or went out of scope.

2. PG_OLDQUERY_WAIT Data Loss

Problem: Using PG_OLDQUERY_WAIT to wait for a previous async query would successfully wait but would discard the query results instead of preserving them.

Root Cause: The handle_old_async() function would consume and discard results when waiting, with no mechanism to preserve them for the owning statement.

Impact: Data loss - results from async queries would be irretrievably lost when another query used PG_OLDQUERY_WAIT.

3. Missing Ownership Verification

Problem: Any statement handle could call pg_result() and retrieve another statement's async results, violating ownership semantics.

Root Cause: The pg_db_result() function did not verify that the calling statement was the one that initiated the async query.

Impact: Race conditions, incorrect data retrieval, and unpredictable behavior in multi-statement applications.

Technical Background

PostgreSQL's async query limitations:

  • Only ONE async query can be active per database connection at any time
  • DBD::Pg provides a statement-level API despite the connection-level limitation
  • The module tracks ownership via imp_dbh->async_sth pointing to the statement that owns the current async query

The Fixes

Fix 1: Ownership Checking in Statement Lifecycle Functions

Location: dbdimp.c - dbd_st_finish() (lines 3977-3980)

/* Only clear async_sth if THIS statement is the current async statement */
if (imp_dbh->async_sth == imp_sth) {
    imp_dbh->async_sth = NULL;
    imp_dbh->async_status = 0;
}

Location: dbdimp.c - dbd_st_destroy() (lines 4122-4127, 4194-4197)

/* Only call handle_old_async if THIS statement owns the async query */
if (imp_dbh->async_status && imp_dbh->async_sth == imp_sth) {
    handle_old_async(aTHX_ sth, imp_dbh, PG_OLDQUERY_WAIT);
}

/* Only clear async_sth if THIS statement owns it */
if (imp_dbh->async_sth == imp_sth) {
    imp_dbh->async_sth = NULL;
}

Fix 2: Auto-Retrieve Mechanism for PG_OLDQUERY_WAIT

Location: dbdimp.c - handle_old_async() (line ~5715)

Instead of discarding results, the function now:

  1. Retrieves the pending async query results
  2. Stores them in the owning statement's structure
  3. Sets async_status = 100 to indicate auto-retrieved results
  4. Preserves row count and result data for later access

Fix 3: Ownership Verification in pg_db_result()

Location: dbdimp.c - pg_db_result() (lines 5292-5397)

Added comprehensive ownership checking:

/* Determine if called from statement or database handle */
D_imp_xxh(h);
imp_sth_t *imp_sth = NULL;
if (DBIc_TYPE(imp_xxh) == DBIt_ST) {
    imp_sth = (imp_sth_t*)imp_xxh;
}

/* Check ownership BEFORE consuming the result */
if (imp_sth && imp_dbh->async_sth && imp_sth != imp_dbh->async_sth) {
    pg_error(aTHX_ h, PGRES_FATAL_ERROR,
             "pg_result() called on wrong statement handle - "
             "this statement does not own the async query\n");
    return -2;
}

Fix 4: Auto-Retrieved Result Handling

Location: dbdimp.c - pg_db_result()

Special handling for auto-retrieved results:

/* Check if this statement had auto-retrieved results from PG_OLDQUERY_WAIT */
if (imp_sth && imp_sth->async_status == STH_ASYNC_AUTORETRIEVED) {
    /* Results were auto-retrieved - return the stored row count */
    imp_sth->async_status = STH_NO_ASYNC;  /* Clear the auto-retrieved flag */
    return imp_sth->rows;
}
else if (imp_sth && imp_sth->async_status == STH_ASYNC_AUTOERROR) {
    /* This statement has auto-retrieved error result */
    /* Report the error from the stored result */
    ...
}

New Async Status Values

The implementation uses named constants for async_status values on statement handles:

enum {
    STH_ASYNC_AUTOERROR = -2,    /* PG_OLDQUERY_WAIT auto-retrieved an error result */
    STH_ASYNC_CANCELLED = -1,
    STH_NO_ASYNC,                /* 0 - No async query */
    STH_ASYNC,                   /* 1 - Active async query */
    STH_ASYNC_PREPARE,           /* 2 - Async prepare in progress */
    STH_ASYNC_AUTORETRIEVED = 100 /* PG_OLDQUERY_WAIT auto-retrieved results */
};

Test Coverage

The fix includes comprehensive test coverage in t/08async_regression.t with 7 test scenarios:

  1. Basic ownership - Prevents wrong statements from stealing results
  2. $dbh->pg_result ownership - Database handle can retrieve, finished statements cannot
  3. Statement destruction - Destroying unrelated statements doesn't affect async queries
  4. Cross-statement interference - Multiple statements don't interfere
  5. Interleaved operations - OLDQUERY_WAIT preserves data correctly
  6. Error attribution - Errors are properly attributed to correct statements
  7. Data preservation - OLDQUERY_WAIT auto-retrieves and preserves data

Behavior Changes

Before the Fix

  • Destroying any statement could cancel another's async query
  • PG_OLDQUERY_WAIT would discard previous query results
  • Any statement could steal another's async results
  • Unpredictable behavior with multiple async statements

After the Fix

  • Only the owning statement can affect its async query
  • PG_OLDQUERY_WAIT auto-retrieves and preserves results
  • Strict ownership verification prevents result theft
  • Predictable, safe multi-statement async operations

Migration Notes

The fixes are backward compatible with one exception:

  • Code that relied on the broken behavior of stealing async results from wrong statements will now correctly fail with an error

@oetiker oetiker changed the title DBD::Pg Async Query Ownership and Data Preservation Fixes (Fix for #105 and hopefully https://github.com/mojolicious/mojo/issues/2276) DBD::Pg Async Query Ownership and Data Preservation Fixes (Fix for #105 and https://github.com/mojolicious/mojo/issues/2276) Sep 19, 2025
@oetiker oetiker changed the title DBD::Pg Async Query Ownership and Data Preservation Fixes (Fix for #105 and https://github.com/mojolicious/mojo/issues/2276) DBD::Pg Async Query Ownership and Data Preservation Fixes Sep 19, 2025
@oetiker
Copy link
Author

oetiker commented Oct 20, 2025

ping ?

@turnstep
Copy link
Contributor

Please pull the recent async-related changes and retest.

@esabol
Copy link
Collaborator

esabol commented Dec 12, 2025

Also, this PR has merge conflicts. Please rebase/resolve, @oetiker.

@oetiker
Copy link
Author

oetiker commented Dec 13, 2025

Also, this PR has merge conflicts. Please rebase/resolve, @oetiker.

I will have to re-evaluate after the changes ...

@oetiker oetiker force-pushed the oetiker-async-regressions branch from e40cc86 to fe5c547 Compare December 15, 2025 09:14
@oetiker
Copy link
Author

oetiker commented Dec 15, 2025

The PR is rebased and the entire testsuite is passing including the new testfile.
Note I added a fix for a test which was trying to connect without password even when a password was supplied.

@esabol
Copy link
Collaborator

esabol commented Dec 15, 2025

@turnstep : Could you approve the CI workflow to run for this PR?

@esabol
Copy link
Collaborator

esabol commented Dec 15, 2025

The PR is rebased and the entire testsuite is passing including the new testfile. Note I added a fix for a test which was trying to connect without password even when a password was supplied.

Thank you, @oetiker ! Looks promising.

@esabol esabol mentioned this pull request Dec 15, 2025
@esabol
Copy link
Collaborator

esabol commented Feb 9, 2026

Unfortunately, the CI workflow didn't run because a maintainer didn't approve it before the request expired. 😿 I think git commit --no-edit --amend; git push -f can retrigger the CI workflow, but this PR will probably need to be rebased (again 😿) anyway after PRs #156 and #155 are merged.

@oetiker
Copy link
Author

oetiker commented Feb 10, 2026

@esabol well, let me know when you are of a mind to merge this, or find issues. I do have other fish to fry in the meantime. Once you are ready I will rebase. If this were my code base it would bother me extremely to know that these bugs persist.

@esabol
Copy link
Collaborator

esabol commented Feb 10, 2026

@esabol well, let me know when you are of a mind to merge this, or find issues. I do have other fish to fry in the meantime. Once you are ready I will rebase. If this were my code base it would bother me extremely to know that these bugs persist.

To be clear, I can't merge anything, unfortunately. I'm not a maintainer. I'm just trying to help things along where I can.

Copy link
Contributor

@turnstep turnstep left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! Will review the other sections shortly

dbdimp.c Outdated
STH_ASYNC,
STH_ASYNC_PREPARE
STH_ASYNC_PREPARE,
STH_ASYNC_AUTORETRIEVED = 100 /* PG_OLDQUERY_WAIT auto-retrieved results */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why this is being set to 100 rather than leaving it to autonumber?

dbdimp.c Outdated
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Need the new check here too?

dbdimp.c Outdated
statement. This prevents finishing an unrelated statement from invalidating a pending async query. */
if (imp_dbh->async_sth == imp_sth) {
imp_dbh->async_sth = NULL;
imp_dbh->async_status = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

async_status already set above - and it should use the named constant, not 0

dbdimp.c Outdated
/* Ownership will be checked below for statement-based calls when needed */

/* Check if this statement had auto-retrieved results from PG_OLDQUERY_WAIT */
if (imp_sth && imp_sth->async_status == STH_ASYNC_AUTORETRIEVED) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put constants on the left for comparisons.

dbdimp.c Outdated
TRC(DBILOGFP, "%sProcessing auto-retrieved results (rows: %ld)\n",
THEADER_slow, imp_sth->rows);
}
/* Don't return early - let the full processing happen below */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed.

dbdimp.c Outdated
TRACE_PQERRORMESSAGE;
pg_error(aTHX_ h, status, PQerrorMessage(imp_dbh->conn));
rows = -2;
imp_sth->async_status = STH_NO_ASYNC; /* Mark as consumed */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All three branches do this, so move to a single call.

dbdimp.c Outdated

if (NULL != imp_dbh->async_sth) {
/* Store metadata in the appropriate statement handle */
/* CRITICAL: Only store results if the calling statement owns the async query */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't need things like upper case "critical" :)

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's all critical, ha ha ha!

dbdimp.c Outdated
/* Free the last_result as needed */
if (imp_dbh->last_result && imp_dbh->result_clearable) {
TRACE_PQCLEAR;
#if DEBUG_LAST_RESULT
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's remove this please

dbdimp.c Outdated
}

/* Mark as auto-retrieved, not discarded */
orig_sth->async_status = STH_ASYNC_AUTORETRIEVED; /* Special value: auto-retrieved */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not need comments like this.

dbdimp.c Outdated

imp_sth_t *orig_sth = imp_dbh->async_sth;

/* Store the error result for the original statement to discover */
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This comment doesn't really match the code

Copy link
Contributor

@turnstep turnstep left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wordy in the wrong places, but very thorough coverage.

use strict;
use warnings;
use Test::More;
use DBI;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know we are inconsistent, but should leave this out as we want to make sure use DBD::Pg does it for us always.

use DBI;
use DBD::Pg qw(:async);

my $dsn = $ENV{DBI_DSN} || "dbi:Pg:dbname=postgres;host=localhost";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why all of this instead of connect_database() like the other tests have?

plan skip_all => "Cannot connect to PostgreSQL: $DBI::errstr";
}

# Test 1: Basic ownership - wrong statement cannot steal results
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wayyy too wordy. The test names should be most of the documentation. See the other tests.

# BEHAVIOR:
# - BEFORE: sth2->pg_result() would successfully steal sth1's pending results
# - AFTER: sth2->pg_result() fails with "wrong statement handle" error
subtest 'Basic ownership - wrong statement' => sub {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not need subtests - just make the test names verbose


$sth1->finish;
$sth2->finish;
};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like these tests.


# Also start a good query
my $good = $dbh->prepare(q{SELECT 42}, { pg_async => PG_ASYNC + PG_OLDQUERY_WAIT });
ok($good->execute, 'good executes');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really poor test name. Compare to a random one from 04misc.t:

Method 'private_attribute_info' is available without a database handle and returns an empty hashref

ok($sth2->execute, 'sth2 executes with WAIT');

# sth1's results should have been auto-retrieved and preserved
# This is the critical test - data must not be lost
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Claude sure loves the word "critical", doesn't it? 😆

@turnstep turnstep self-assigned this Feb 10, 2026
@oetiker oetiker force-pushed the oetiker-async-regressions branch from 82292d2 to 5c9c691 Compare February 17, 2026 13:25
@oetiker
Copy link
Author

oetiker commented Feb 17, 2026

Thanks for the thorough review @turnstep! I've rebased onto current master and addressed all your feedback in a single squashed commit:

C code (dbdimp.c):

  • Removed = 100 from STH_ASYNC_AUTORETRIEVED — auto-numbers now
  • Fixed the ownership check in dbd_st_finish() at the spot you flagged — now checks imp_dbh->async_sth == imp_sth instead of just imp_sth->async_status
  • Replaced literal 0 with DBH_NO_ASYNC / STH_NO_ASYNC constants
  • Applied Yoda conditions throughout (NULL == ptr, STH_ASYNC_AUTORETRIEVED == status, etc.)
  • Merged the identical PGRES_TUPLES_OK / PGRES_COMMAND_OK branches into one, factored out the common async_status = STH_NO_ASYNC call
  • Removed all "CRITICAL" comments (Claude does indeed love that word 😅)
  • Cleaned up redundant/verbose comments, removed the unnecessary trace block
  • Simplified the auto-retrieved result handling by eliminating a duplicate check

Test file (t/08async_regression.t):

  • Switched to connect_database() / require 'dbdpg_test_setup.pl'
  • Dropped use strict; use warnings;
  • Removed all subtest blocks — flat structure with verbose test names
  • Trimmed the wordy comment blocks
  • Squashed the lib path fix into the test commit
  • 57 tests, all passing against the full suite (3719 tests total)

@oetiker oetiker force-pushed the oetiker-async-regressions branch 2 times, most recently from 898f315 to 28413ed Compare February 17, 2026 13:43
@turnstep
Copy link
Contributor

Thanks for the changes, will look those over soon. Debating releasing a 3.19.0 then making this part of 3.20.0 with a short turnaround.

Copy link
Contributor

@turnstep turnstep left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a few questions

@esabol
Copy link
Collaborator

esabol commented Feb 18, 2026

@turnstep : Please scroll down to the bottom and approve running the CI workflow for this PR. Click on "Approve workflows to run."

oetiker added a commit to oetiker/dbdpg that referenced this pull request Feb 18, 2026
- Fix double-free when imp_sth->result and imp_dbh->last_result
  point to the same PGresult by adding pointer equality checks
- Remove redundant NULL assignments before immediate reassignment
- Remove unreachable wrong-statement-handle branch in PGRES_TUPLES_OK
  (already caught by ownership check that returns -2)
- Use PQcmdTuples for PGRES_COMMAND_OK row count in auto-retrieve
  path instead of hardcoding 0
- Pass imp_sth->result directly to _sqlstate instead of via local var
- Add TRACE_PQERRORMESSAGE before pg_error in AUTOERROR null-check
- Use -2 (error convention) for auto-error rows placeholder
- Rewrite OLDQUERY_WAIT test with named variables instead of
  confusing array index arithmetic
- Add skip_all for failed second DB connection in regression tests
- Remove redundant isnt connection tests (covered by skip_all)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@turnstep
Copy link
Contributor

I've been tinkering with dbdimp.c a lot - can you rebase?

oetiker added a commit to oetiker/dbdpg that referenced this pull request Feb 27, 2026
- Fix double-free when imp_sth->result and imp_dbh->last_result
  point to the same PGresult by adding pointer equality checks
- Remove redundant NULL assignments before immediate reassignment
- Remove unreachable wrong-statement-handle branch in PGRES_TUPLES_OK
  (already caught by ownership check that returns -2)
- Use PQcmdTuples for PGRES_COMMAND_OK row count in auto-retrieve
  path instead of hardcoding 0
- Pass imp_sth->result directly to _sqlstate instead of via local var
- Add TRACE_PQERRORMESSAGE before pg_error in AUTOERROR null-check
- Use -2 (error convention) for auto-error rows placeholder
- Rewrite OLDQUERY_WAIT test with named variables instead of
  confusing array index arithmetic
- Add skip_all for failed second DB connection in regression tests
- Remove redundant isnt connection tests (covered by skip_all)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@oetiker oetiker force-pushed the oetiker-async-regressions branch from 8f1e267 to a86053a Compare February 27, 2026 10:36
@esabol
Copy link
Collaborator

esabol commented Feb 27, 2026

CI tests all failed with 3 failures in t/99_lint.t:

# Failure at line 5471: Found no matching TRACE for PQresultErrorMessage
# Failure at line 5859: Found no matching TRACE for PQntuples
# Failure at line 5862: Found no matching TRACE for PQcmdTuples
# Failure at line 5868: Found no matching TRACE for PQnfields

#   Failed test 'File "./dbdimp.c" does not have TRACE cals for each PQ function'
#   at t/99_lint.t line 126.
fatal: detected dubious ownership in repository at '/__w/dbdpg/dbdpg'
To add an exception for this directory, call:

	git config --global --add safe.directory /__w/dbdpg/dbdpg
# Looks like you failed 1 test of 728.
t/99_lint.t ............. 
Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/728 subtests 

Seems to be the result of changes made by @turnstep ? No, latest CI run on master passes. https://github.com/bucardo/dbdpg/actions/runs/22487948562

detected dubious ownership in repository at '/__w/dbdpg/dbdpg' should have been fixed by the change to checkout@v4. Are you sure you rebased on latest master branch commits, @oetiker ?

@esabol
Copy link
Collaborator

esabol commented Feb 27, 2026

Looking into this more closely, I think 99_lint.t line 153 should be changed to this:

       my %gitfiles = map { chomp; $_, 1 } qx{git -c 'safe.directory=*' ls-files};

in order to eliminate the detected dubious ownership in repository at '/__w/dbdpg/dbdpg' message.

@oetiker
Copy link
Author

oetiker commented Feb 27, 2026

hmmm it looks as if pg has died during the tests ?

@esabol
Copy link
Collaborator

esabol commented Feb 27, 2026

hmmm it looks as if pg has died during the tests ?

It's an intentional test. The problem comes from changes @turnstep made this morning in 74d0612, and it's unrelated to the work in this PR. The check @turnstep added doesn't work on Perl 5.36+. Once that's fixed, you'll need to rebase again, unfortunately, @oetiker.

@turnstep
Copy link
Contributor

turnstep commented Feb 27, 2026 via email

@esabol
Copy link
Collaborator

esabol commented Feb 27, 2026

@oetiker , the CI has been fixed. Please rebase one more time.

oetiker and others added 3 commits March 2, 2026 09:28
…#105)

- Only clear async_sth if the statement being finished/destroyed owns it
- Add ownership verification in pg_db_result() to prevent result theft
- Auto-retrieve results in handle_old_async() when PG_OLDQUERY_WAIT is
  used, instead of discarding them
- Add STH_ASYNC_AUTORETRIEVED and STH_ASYNC_AUTOERROR status values
- Support both $sth->pg_result and $dbh->pg_result patterns
- Add regression tests in t/08async_regression.t
- Fix double-free when imp_sth->result and imp_dbh->last_result
  point to the same PGresult by adding pointer equality checks
- Remove redundant NULL assignments before immediate reassignment
- Remove unreachable wrong-statement-handle branch in PGRES_TUPLES_OK
  (already caught by ownership check that returns -2)
- Use PQcmdTuples for PGRES_COMMAND_OK row count in auto-retrieve
  path instead of hardcoding 0
- Pass imp_sth->result directly to _sqlstate instead of via local var
- Add TRACE_PQERRORMESSAGE before pg_error in AUTOERROR null-check
- Use -2 (error convention) for auto-error rows placeholder
- Rewrite OLDQUERY_WAIT test with named variables instead of
  confusing array index arithmetic
- Add skip_all for failed second DB connection in regression tests
- Remove redundant isnt connection tests (covered by skip_all)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@oetiker oetiker force-pushed the oetiker-async-regressions branch from c74c7f1 to 5f6f84e Compare March 2, 2026 08:29
@oetiker
Copy link
Author

oetiker commented Mar 2, 2026

claude fortunately is unperturbed ...

@oetiker oetiker requested a review from turnstep March 2, 2026 08:30
@esabol
Copy link
Collaborator

esabol commented Mar 2, 2026

All the CI tests pass! There's just one thing that seems a bit odd, and it's the message

NOTICE: table "async_test_constraints" does not exist, skipping

in the test output. It's completely harmless and expected whenever you do a DROP TABLE IF EXISTS and the table doesn't exist, of course, but it seems less than ideal. @oetiker and @turnstep, what do you think about adding the following right before the DROP TABLE IF EXISTS line?

$dbh_noerr->do(q{SET LOCAL client_min_messages = 'WARNING'});

@turnstep
Copy link
Contributor

turnstep commented Mar 2, 2026

Few early-morning thoughts on that table:

  • We try to keep all artifacts with the dbd_pg_ prefix
  • Tables should go in t/dbdpg_test_setup.pl - and thus no need to worry about IF EXISTS
  • For something as simple as this, we can probably use dbd_pg_test table directly?

@esabol
Copy link
Collaborator

esabol commented Mar 3, 2026

All of those things make sense to me. @oetiker , can you get Claude to either rename the async_test_constraints table to dbd_pg_async_constraints (or something like that) and add it to t/dbdpg_test_setup.pl or switch to using the existing dbd_pg_test table (if that's feasible)?

The table was created and dropped but never referenced by any query,
producing a spurious NOTICE and using a non-standard name (missing
the dbd_pg_ prefix). Addresses PR bucardo#150 review feedback.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@oetiker
Copy link
Author

oetiker commented Mar 5, 2026

done

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.

3 participants