https://github.com/jackc/pgx/issues/2223
(t *testing.T)
| 471 | |
| 472 | // https://github.com/jackc/pgx/issues/2223 |
| 473 | func TestPrepareHandlesTimeoutBetweenParseAndDescribe(t *testing.T) { |
| 474 | // Not parallel because it is a timing sensitive test. |
| 475 | |
| 476 | config, err := pgx.ParseConfig(os.Getenv("PGX_TEST_DATABASE")) |
| 477 | require.NoError(t, err) |
| 478 | |
| 479 | var faultyConn *faultyconn.Conn |
| 480 | config.AfterNetConnect = func(ctx context.Context, config *pgconn.Config, conn net.Conn) (net.Conn, error) { |
| 481 | faultyConn = faultyconn.New(conn) |
| 482 | return faultyConn, nil |
| 483 | } |
| 484 | |
| 485 | ctx := context.Background() |
| 486 | conn, err := pgx.ConnectConfig(ctx, config) |
| 487 | require.NoError(t, err) |
| 488 | defer closeConn(t, conn) |
| 489 | require.NotNil(t, faultyConn) |
| 490 | |
| 491 | pgxtest.SkipCockroachDB(t, conn, "Induced error does not occur on CockroachDB") |
| 492 | |
| 493 | _, err = conn.Exec(ctx, "set statement_timeout = '100ms'") |
| 494 | require.NoError(t, err) |
| 495 | |
| 496 | faultyConn.HandleFrontendMessage = func(backendWriter io.Writer, msg pgproto3.FrontendMessage) error { |
| 497 | if _, ok := msg.(*pgproto3.Describe); ok { |
| 498 | time.Sleep(200 * time.Millisecond) |
| 499 | } |
| 500 | buf, err := msg.Encode(nil) |
| 501 | if err != nil { |
| 502 | return err |
| 503 | } |
| 504 | _, err = backendWriter.Write(buf) |
| 505 | return err |
| 506 | } |
| 507 | |
| 508 | psd, err := conn.Prepare(ctx, "test", "select $1::varchar") |
| 509 | var pgErr *pgconn.PgError |
| 510 | require.ErrorAs(t, err, &pgErr) |
| 511 | require.Equal(t, "57014", pgErr.Code) |
| 512 | require.Nil(t, psd) |
| 513 | |
| 514 | faultyConn.HandleFrontendMessage = nil |
| 515 | |
| 516 | _, err = conn.Exec(ctx, "set statement_timeout = default") |
| 517 | require.NoError(t, err) |
| 518 | |
| 519 | var existsOnServer bool |
| 520 | err = conn.QueryRow( |
| 521 | ctx, |
| 522 | "select exists(select 1 from pg_prepared_statements where name = 'test')", |
| 523 | // Avoid using the prepared statement cache or it will clear the broken statement before we can check for its |
| 524 | // existence. |
| 525 | pgx.QueryExecModeExec, |
| 526 | ).Scan(&existsOnServer) |
| 527 | require.NoError(t, err) |
| 528 | require.True(t, existsOnServer) |
| 529 | |
| 530 | psd, err = conn.Prepare(ctx, "test", "select $1::varchar") |