Skip to content

feat(tidb-stmt-cache): add a streamed-BLOB fixture for SEND_LONG_DATA - #151

Merged
slayerjain merged 1 commit into
mainfrom
feat/tidb-streamed-blob-fixture
Aug 18, 2026
Merged

feat(tidb-stmt-cache): add a streamed-BLOB fixture for SEND_LONG_DATA#151
slayerjain merged 1 commit into
mainfrom
feat/tidb-streamed-blob-fixture

Conversation

@slayerjain

Copy link
Copy Markdown
Member

Describe the changes that are made

Adds the fixture that reproduces keploy/keploy#4262.

Writing a BLOB through PreparedStatement.setBinaryStream on a server-side prepared statement makes Connector/J 8.x send the value out of band and pipeline three commands per re-execution, without reading a response in between:

COM_STMT_RESET  ->  COM_STMT_SEND_LONG_DATA  ->  COM_STMT_EXECUTE

A long-sent parameter is absent from the EXECUTE payload while still being non-NULL in the null bitmap. A decoder that reads a value for every non-NULL parameter therefore runs off the end and rejects the command — so the EXECUTE never reaches the recorder at all, and replay fails with Can not read response from server.

Nothing in the suite wrote a BLOB through a stream setter, which is why the sequence was never recorded.

SchemaInitializer — adds a blob_stream table alongside kv.

QueryControllerGET /api/blob/{size} inserts a payload with setBinaryStream (deliberately not setBytes; the stream setter is what triggers SEND_LONG_DATA), then reads LENGTH(payload) back.

The endpoint must be driven more than once: the RESET only appears when the statement is re-executed from Connector/J's cache. This sample already enables that via useServerPrepStmts=true&cachePrepStmts=true.

Verification

Run locally against TiDB with keploy 05b4eada and with the #4262 fix:

keploy 05b4eada with the fix
COM_STMT_EXECUTE mocks 0 6
COM_STMT_SEND_LONG_DATA mocks 3 3
replay (TiDB stopped) 1 passed / 3 failed 4 passed / 0 failed
Can not read response from server 6 occurrences none

On the buggy build the EXECUTEs' OKs are attributed to the COM_STMT_RESET mocks and the EXECUTE requests are dropped entirely — exactly the symptom the issue describes.

Consumer

The keploy-side PR drives /api/blob/2048 three times from .github/workflows/test_workflow_scripts/java/tidb_stmt_cache/java-linux.sh and asserts on the recorded artifact that COM_STMT_EXECUTE mocks exist alongside the SEND_LONG_DATA ones — record and replay were wrong in the same direction, so a report-status check alone can pass while the trace is missing every EXECUTE.

This PR needs to merge first, otherwise the keploy-side guard runs against an endpoint that does not exist yet.

keploy/keploy#4262: writing a BLOB through PreparedStatement.setBinaryStream
on a server-side prepared statement makes Connector/J 8.x send the value out
of band and pipeline three commands per re-execution without reading a
response in between:

  COM_STMT_RESET -> COM_STMT_SEND_LONG_DATA -> COM_STMT_EXECUTE

A long-sent parameter is absent from the EXECUTE payload while still being
non-NULL in the null bitmap, so a decoder that reads a value for every
non-NULL parameter runs off the end and rejects the command. The EXECUTE
never reaches the recorder, and replay fails with "Can not read response
from server".

Nothing in the suite wrote a BLOB through a stream setter, so the sequence
was never recorded. This adds the fixture that produces it:

  - blob_stream table in SchemaInitializer, alongside kv.
  - GET /api/blob/{size} inserts a payload with setBinaryStream (not
    setBytes — the stream setter is what triggers SEND_LONG_DATA), then
    reads LENGTH(payload) back.

The endpoint has to be driven more than once: the RESET only appears when
the statement is re-executed from Connector/J's cache, which this sample
already enables via useServerPrepStmts + cachePrepStmts.

Verified against keploy at 05b4eada and against the #4262 fix — the recorded
mocks go from 0 COM_STMT_EXECUTE to 6, and replay with TiDB stopped goes from
1 passed / 3 failed (6 "Can not read response from server") to 4 passed.

Signed-off-by: slayerjain <shubham@keploy.io>
@slayerjain
slayerjain merged commit 2718589 into main Aug 18, 2026
2 checks passed
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.

1 participant