parse-started.pt 2.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970
  1. # Regression test if the global timestamp has progressed during multiple
  2. # Parse/Bind/Execute commands that don't have a Sync between them.
  3. # This is a bit of an edge case in the Postgres protocol documentation and its
  4. # implementation and code comments. The protocol docs say:
  5. #
  6. # At completion of each series of extended-query messages, the frontend should
  7. # issue a Sync message. This parameterless message causes the backend to close
  8. # the current transaction...
  9. #
  10. # In postgres.c's exec_parse_message function, a transaction is started
  11. # via start_xact_command which will put the transaction into TBLOCK_STARTED
  12. # and set a boolean to prevent doing that a second time. The comments for
  13. # TBLOCK_STARTED say "running single-query transaction". The most common
  14. # scenario is after Parse, a user will Bind the portal, Execute the portal,
  15. # then Sync, which commits the transaction.
  16. #
  17. # However it is also completely within spec for clients to issue another
  18. # Parse/Bind/Execute trio before the Sync. The protocol docs (until recently)
  19. # don't specifically describe how the transaction handling should function
  20. # in this situation (in contrast to the simple query workflow, which has
  21. # a long description about how to handle multiple statements in the same
  22. # query string). The comments for TBLOCK_STARTED imply it's a single-query
  23. # transaction, but that is not always the case.
  24. #
  25. # In practice, the Npgsql .NET driver does exactly this on its startup when
  26. # fetching from the catalog tables. Our code previously made assumptions that
  27. # transactions in the TBLOCK_STARTED were always single statement, and would
  28. # thus skip some work. However it is possible that there are other stataments
  29. # issued in that block, so we eagerly commit all statements after receiving an
  30. # Execute message.
  31. #
  32. # The bug motivating this test was caused by sequence_peek adding a
  33. # second transaction operation at a different timestamp to an existing
  34. # transaction. The sleep here was required to force the global timestamp
  35. # forward, which was the cause of the initial panic. See:
  36. # https://github.com/MaterializeInc/materialize/blob/5afec7c55867d1d1a0a8f1e81c088b84dcff81d8/src/adapter/src/coord/sequencer.rs#L1955
  37. #
  38. # See: https://git.postgresql.org/gitweb/?p=postgresql.git&a=commitdiff&h=f92944137
  39. # See: https://www.postgresql.org/message-id/flat/17434-d9f7a064ce2a88a3%40postgresql.org
  40. send
  41. Parse {"query": "SELECT 1 FROM pg_type LIMIT 1"}
  42. Bind
  43. Execute
  44. Parse {"query": "SELECT mz_unsafe.mz_sleep(1) FROM pg_type LIMIT 1"}
  45. Bind
  46. Execute
  47. Parse {"query": "SELECT 1 FROM pg_type LIMIT 1"}
  48. Bind
  49. Execute
  50. Sync
  51. ----
  52. until
  53. ReadyForQuery
  54. ----
  55. ParseComplete
  56. BindComplete
  57. DataRow {"fields":["1"]}
  58. CommandComplete {"tag":"SELECT 1"}
  59. ParseComplete
  60. BindComplete
  61. DataRow {"fields":["NULL"]}
  62. CommandComplete {"tag":"SELECT 1"}
  63. ParseComplete
  64. BindComplete
  65. DataRow {"fields":["1"]}
  66. CommandComplete {"tag":"SELECT 1"}
  67. ReadyForQuery {"status":"I"}