@@ -1529,6 +1529,48 @@ func TestStmtCacheInvalidationTxWithBatch(t *testing.T) {
15291529 ensureConnValid (t , conn )
15301530}
15311531
1532+ // https://github.com/jackc/pgx/issues/2442
1533+ func TestStmtCacheInvalidationExec (t * testing.T ) {
1534+ ctx := context .Background ()
1535+
1536+ conn := mustConnectString (t , os .Getenv ("PGX_TEST_DATABASE" ))
1537+ defer closeConn (t , conn )
1538+
1539+ // create a table and fill it with some data
1540+ _ , err := conn .Exec (ctx , `
1541+ DROP TABLE IF EXISTS drop_cols;
1542+ CREATE TABLE drop_cols (
1543+ id SERIAL PRIMARY KEY NOT NULL,
1544+ f1 int NOT NULL,
1545+ f2 int NOT NULL
1546+ );
1547+ ` )
1548+ require .NoError (t , err )
1549+
1550+ insertSQL := "INSERT INTO drop_cols (f1, f2) VALUES ($1, $2)"
1551+ // This query will populate the statement cache.
1552+ _ , err = conn .Exec (ctx , insertSQL , 1 , 2 )
1553+ require .NoError (t , err )
1554+
1555+ // Now, change the schema of the table out from under the statement, making it invalid.
1556+ _ , err = conn .Exec (ctx , "ALTER TABLE drop_cols ALTER COLUMN f1 TYPE boolean USING f1::boolean" )
1557+ require .NoError (t , err )
1558+
1559+ // We must get an error the first time we try to re-execute a bad statement.
1560+ // It is up to the application to determine if it wants to try again. We punt to
1561+ // the application because there is no clear recovery path in the case of failed transactions
1562+ // or batch operations and because automatic retry is tricky and we don't want to get
1563+ // it wrong at such an importaint layer of the stack.
1564+ _ , err = conn .Exec (ctx , insertSQL , true , 2 )
1565+ require .ErrorContains (t , err , "failed to encode args[0]" )
1566+
1567+ // On retry, the statement should have been flushed from the cache.
1568+ _ , err = conn .Exec (ctx , insertSQL , true , 2 )
1569+ require .NoError (t , err )
1570+
1571+ ensureConnValid (t , conn )
1572+ }
1573+
15321574func TestInsertDurationInterval (t * testing.T ) {
15331575 ctx , cancel := context .WithTimeout (context .Background (), 120 * time .Second )
15341576 defer cancel ()
0 commit comments