(t *testing.T)
| 1278 | } |
| 1279 | |
| 1280 | func TestStmtCacheInvalidationTx(t *testing.T) { |
| 1281 | ctx := context.Background() |
| 1282 | |
| 1283 | conn := mustConnectString(t, os.Getenv("PGX_TEST_DATABASE")) |
| 1284 | defer closeConn(t, conn) |
| 1285 | |
| 1286 | if conn.PgConn().ParameterStatus("crdb_version") != "" { |
| 1287 | t.Skip("Server has non-standard prepare in errored transaction behavior (https://github.com/cockroachdb/cockroach/issues/84140)") |
| 1288 | } |
| 1289 | |
| 1290 | // create a table and fill it with some data |
| 1291 | _, err := conn.Exec(ctx, ` |
| 1292 | DROP TABLE IF EXISTS drop_cols; |
| 1293 | CREATE TABLE drop_cols ( |
| 1294 | id SERIAL PRIMARY KEY NOT NULL, |
| 1295 | f1 int NOT NULL, |
| 1296 | f2 int NOT NULL |
| 1297 | ); |
| 1298 | `) |
| 1299 | require.NoError(t, err) |
| 1300 | _, err = conn.Exec(ctx, "INSERT INTO drop_cols (f1, f2) VALUES (1, 2)") |
| 1301 | require.NoError(t, err) |
| 1302 | |
| 1303 | tx, err := conn.Begin(ctx) |
| 1304 | require.NoError(t, err) |
| 1305 | |
| 1306 | getSQL := "SELECT * FROM drop_cols WHERE id = $1" |
| 1307 | |
| 1308 | // This query will populate the statement cache. We don't care about the result. |
| 1309 | rows, err := tx.Query(ctx, getSQL, 1) |
| 1310 | require.NoError(t, err) |
| 1311 | rows.Close() |
| 1312 | require.NoError(t, rows.Err()) |
| 1313 | |
| 1314 | // Now, change the schema of the table out from under the statement, making it invalid. |
| 1315 | _, err = tx.Exec(ctx, "ALTER TABLE drop_cols DROP COLUMN f1") |
| 1316 | require.NoError(t, err) |
| 1317 | |
| 1318 | // We must get an error the first time we try to re-execute a bad statement. |
| 1319 | // It is up to the application to determine if it wants to try again. We punt to |
| 1320 | // the application because there is no clear recovery path in the case of failed transactions |
| 1321 | // or batch operations and because automatic retry is tricky and we don't want to get |
| 1322 | // it wrong at such an important layer of the stack. |
| 1323 | rows, err = tx.Query(ctx, getSQL, 1) |
| 1324 | require.NoError(t, err) |
| 1325 | rows.Next() |
| 1326 | nextErr := rows.Err() |
| 1327 | rows.Close() |
| 1328 | for _, err := range []error{nextErr, rows.Err()} { |
| 1329 | if err == nil { |
| 1330 | t.Fatal(`expected "cached plan must not change result type": no error`) |
| 1331 | } |
| 1332 | if !strings.Contains(err.Error(), "cached plan must not change result type") { |
| 1333 | t.Fatalf(`expected "cached plan must not change result type", got: "%s"`, err.Error()) |
| 1334 | } |
| 1335 | } |
| 1336 | |
| 1337 | rows, _ = tx.Query(ctx, getSQL, 1) |
nothing calls this directly
no test coverage detected