Skip to content

[fix](protocol) Prevent Connector/J cursor fetch from hanging on empty results - #67520

Merged
CalvinKirs merged 12 commits into
apache:masterfrom
CalvinKirs:fix/cursor-fetch-empty-result
Sep 10, 2026
Merged

CalvinKirs merged 12 commits into
apache:masterfrom
CalvinKirs:fix/cursor-fetch-empty-result

Conversation

@CalvinKirs

@CalvinKirs CalvinKirs commented Sep 4, 2026

Copy link
Copy Markdown
Member

What problem does this PR solve?

Issue Number: None

Related PR: #61050, #61062

After CLIENT_DEPRECATE_EOF is negotiated, affected Connector/J clients using useCursorFetch=true and a positive fetch size can hang when a server-prepared statement returns an empty result. The driver consumes the first terminator after column definitions while checking whether a server cursor was created. With no rows, this consumes the only result-end marker, so the driver waits for a packet that Doris will never send.

The reported Connector/J 8.2.0 case is covered by real-driver tests. This PR preserves the final result marker for affected clients and avoids inserting the compatibility marker for identified Connector/J 9.5+ and MariaDB clients. It also preserves this behavior through FE forwarding and fixes related packet/capability regressions.

What is changed?

  1. Cursor result boundaries. Read CURSOR_TYPE_READ_ONLY from each COM_STMT_EXECUTE, retain it in the request context, and classify driver behavior using connection attributes. For affected cursor clients with deprecated EOF enabled, insert a compatibility ResultSet OK after metadata so the real final marker remains available. Identified modern clients and ordinary non-cursor requests keep the standard sequence.
  2. FE forwarding. Forward cursor intent and negotiated capabilities through optional Thrift fields. The master restores them before serializing results. A new follower adapts buffered results from an older master that has not confirmed protocol adaptation: insert/remove/convert metadata boundaries as appropriate and convert the final legacy EOF when needed. Row payloads are retained; confirmed results are not adapted twice.
  3. Complete OK information. Preserve the original forwarded DML/DDL OK and ERR packets rather than rebuilding a partial successful OK. Retain affected rows, warnings, info, load labels and transaction IDs. Preserve warnings and server status when producing/converting result-set terminators. SQL is not re-executed by this adaptation.
  4. Legacy protocol compatibility. Configure the serializer using the intersection of client/server capabilities, rather than server defaults. Limit the empty OK-info compatibility byte to the applicable negotiated format, preserving legacy OK behavior.
  5. Arrow follower compatibility. Access MySQL-channel capabilities only for MySQL connections, so the shared forwarding path does not call the unsupported MySQL-channel getter on an Arrow Flight SQL context.
  6. Clients without connection attributes. Remove the new fail-fast rejection of anonymous cursor clients. When client behavior is unknown, prioritize the older Connector/J compatibility sequence. This retains the older-client target but cannot simultaneously guarantee compatibility with anonymous clients requiring the standard sequence.
  7. File-load compatibility. In both LOAD handlers, require CLIENT_LOCAL_FILES only for client-side LOCAL INFILE uploads. FE-side file reads do not require a client-upload capability and remain usable when that bit is absent.

Full PR diff against the merged master, at 32d01e5df19:

Category Files Added lines Removed lines Net added lines
Production code, including Thrift IDL 12 218 40 178
Tests and expected output 12 787 13 774

The test total includes 11 automatically generated expected-output lines. Environment configuration and review documents are excluded.

Compatibility boundaries

  • This preserves streamed results; it does not implement MySQL server-side cursors or COM_STMT_FETCH batching.
  • New follower → old master is covered by the mixed-version client matrix. Old follower → new master may have already lost cursor intent; the master cannot reconstruct it. The historical cursor hang on that route remains until the client-facing follower is upgraded. Existing ordinary prepared-statement behavior is retained.
  • Identified Connector/J 9.5+ and MariaDB clients use the standard path. Anonymous clients requiring that sequence remain outside the older-client fallback guarantee.
  • The OIDC provider and authentication routing implementation are not changed by this PR.

Release note

Fix affected Connector/J cursor queries hanging on empty prepared results. Preserve negotiated MySQL packet formats, forwarded DML/DDL OK information, Arrow Flight SQL forwarding and FE-side file loading. Upgrade the client-facing follower to preserve cursor intent during an FE rolling upgrade.

Check List (For Author)

  • Test:
    • Unit Test: 113 targeted FE tests passed, 0 failures/errors, before the final master/JUnit 5 merge. Coverage includes driver classification, cursor boundaries, forwarding, capabilities, packet serialization, authentication routing and both LOAD handlers.
    • Regression test: prepared_stmt_p0/cursor_fetch_empty_result, prepared_stmt_p0/prepared_show, and arrow_flight_sql_p0/test_ddl through a real follower passed. Cursor expected output was generated by the regression runner.
    • Manual test: 120 successful real-JDBC driver/endpoint/transport runs across baseline/candidate direct endpoints, a same-version follower and a new follower targeting an old master, with plaintext/TLS modes. Each driver JAR runs in its own JVM to avoid classpath version collisions.
      • MySQL Connector/J: 5.1.49, 8.0.28, 8.0.33, 8.2.0, 8.4.0, 9.0.0, 9.4.0, 9.5.0, 9.6.0. MariaDB Connector/J: 3.5.6.
      • Each run exercises 12 requested combinations of cursor/server-prepare switches and fetch sizes 0/1/10000, repeated Statement/PreparedStatement empty→nonempty→empty results on reused connections, and wrong-password rejection. Drivers may couple cursor and server-prepare settings internally. Connection/read timeouts bound failures; a timeout is not counted as success.
      • Additional checks passed: explicit TLS 1.2/1.3 (16 groups), MySQL Shell 8/9 ordinary authentication (16), legacy EOF via PyMySQL (8), SQL-error connection reuse (8), and suppressed connection attributes with older drivers (12).
      • Actual baseline/candidate FE-file and client-file imports passed; forwarded INSERT retained label/status/txnId. Real LDAP/local-password routing, rejected credentials and connection reuse passed 20 baseline/candidate checks across plaintext/TLS.
      • Independent FE-only raw-protocol tests passed 12 configurations covering multi-result status, cursor transitions, RESET/CLOSE and reuse after errors. These are packet tests, not additional real JDBC runs or proof of mixed-version multi-statement forwarding.
    • FE build passed before the final master merge. After the merge, standalone mvn checkstyle:check -pl fe-core -Dcheckstyle.skip=false passed with 0 violations. Compilation and unit tests were not rerun after the JUnit 5 migration.
    • The multi-version JDBC matrix was executed locally with retained scripts/logs; it is not an automatic all-version CI matrix.
  • Review and validation limits:
    • The latest independent review of the complete final diff found 0 Blocker / 0 Major production findings. It noted two deterministic SQL-result assertions that still use assertEquals rather than regression qt output, and missing dedicated tests for errors occurring after partial metadata or rows have been buffered. Those error paths were inspected in source, not fault-injected; the OK/ERR preservation unit test does not cover buffered intermediate errors.
    • Connector/J 6.0.6 failed handshakes on both baseline and candidate in six runs; it is not counted as passing or newly supported.
    • Four broader prepared suites failed identically on baseline/candidate with the available older BE because it cannot execute the plan. Authentication-integration metadata regression also remains incomplete with that BE. Four independent SELECT configurations without a BE were blocked and not counted as passing.
    • Full product OIDC-provider login/new TLS-extension E2E and the customer's exact SmartBI environment were not validated. Ordinary password/TLS and authentication unit tests do not replace these checks.
  • Behavior changed:
    • Yes. Correct cursor packet boundaries, preserve complete forwarded OK information and use negotiated capabilities, with the compatibility boundaries above.
  • Does this need documentation?
    • No.

Check List (For Reviewer who merge this PR)

  • Confirm the release note
  • Confirm test cases
  • Confirm document
  • Add branch pick label

@hello-stephen

Copy link
Copy Markdown
Contributor

Thank you for your contribution to Apache Doris.
Don't know what should be done next? See How to process your PR.

Please clearly describe your PR:

  1. What problem was fixed (it's best to include specific error reporting information). How it was fixed.
  2. Which behaviors were modified. What was the previous behavior, what is it now, why was it modified, and what possible impacts might there be.
  3. What features were added. Why was this function added?
  4. Which code was refactored and why was this part of the code refactored?
  5. Which functions were optimized and what is the difference before and after the optimization?

@CalvinKirs

Copy link
Copy Markdown
Member Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review status: REQUEST_CHANGES. I completed the full review on head 53cf2d7d400f508f08c514df3934fbeeba4d3157; the bounded review loop converged after two rounds with two distinct P1 findings.

Critical checkpoint conclusions:

  • Goal and proof: The new packet fixes the direct Connector/J 8.0.28 empty-result hang, but the implementation does not complete the stated pre-9.5 compatibility goal for legacy 5.1/6.0 clients (first inline finding), and forwarded zero-placeholder executions can still return malformed non-empty results (second inline finding).
  • Scope and clarity: The per-command flag, optional forwarding field, shared metadata helper, and focused tests are otherwise small and localized.
  • Concurrency: The new state is connection-local and commands are processed serially on a connection; no new shared mutable state, locking, lock-order, or deadlock concern was found.
  • Lifecycle and initialization: The cursor flag survives local/RPC retries and is cleared after command finalization. The new static constants have no cross-initialization dependency. The zero-placeholder forwarding lifecycle remains incomplete as described inline.
  • Configuration: No configuration item is added.
  • Compatibility: Thrift field 1008 is optional and wire-skippable during rolling FE upgrades. Protocol compatibility is incomplete for the verified legacy Connector/J identities and versions.
  • Parallel paths: FE-local and coordinator/cache/short-circuit metadata paths both use the helper exactly once, and proxy packet ordering preserves the compatibility marker before rows and the real final marker afterward. The follower-to-master zero-placeholder path fails to restore binary execute mode.
  • Conditional checks: Cursor-bit masking and the deprecated-EOF gate are sound and locally explained. The client-name/version condition is too narrow for affected released drivers.
  • Test coverage: The unit test checks the inserted packet shape, and the regression covers direct-master Connector/J 8.0.28 empty and one-row results. Coverage misses legacy driver attributes and a follower-to-master non-empty zero-placeholder result, which correspond to the two findings.
  • Test results: The checked-in output matches the suite's two queries, but I did not execute or regenerate tests because this review environment explicitly prohibits builds and test execution.
  • Observability: This narrowly gated packet path does not need new metrics or INFO logging; existing connection/packet diagnostics are sufficient.
  • Transactions, persistence, and data writes: None are introduced or modified.
  • FE/BE variable propagation: The new field is FE-to-FE. Existing mysql_row_binary_format propagation to BE depends on the master's command state and is wrong in the forwarded zero-placeholder case.
  • Performance: One connection-attribute lookup and one precompiled regex match per result metadata sequence is negligible; no material CPU or memory regression was found.
  • Other issues and user focus: No additional user focus was supplied, and no other distinct correctness, error-handling, memory-safety, cloud-mode, or coverage issue survived the final changed-file and candidate sweep.

return false;
}
Map<String, String> connectAttributes = context.getConnectAttributes();
if (!MYSQL_CONNECTOR_J.equals(connectAttributes.get("_client_name"))) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Cover the legacy Connector/J cursor consumers

Connector/J 5.1.49 and 6.0.6 have the same cursor-probe behavior this workaround targets: when Doris advertises CLIENT_DEPRECATE_EOF, they consume the packet after column definitions for a cursor request. Those releases send _client_name=MySQL Connector Java (and 5.x/6.x versions), so this predicate never inserts the compatibility terminator. An empty result therefore still consumes its only final OK and waits for another packet; a non-empty result can consume its first binary row as status. Please include the verified legacy identity/version families (or classify by the affected protocol behavior) and add a boundary test.

if (null != ctx.getPrepareExecuteBuffer()) {
params.setPrepareExecuteBuffer(ctx.getPrepareExecuteBuffer());
}
params.setCursorFetchRequested(ctx.isCursorFetchRequested());

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Preserve binary execute mode without parameters

For a zero-placeholder prepared SELECT, handleExecute never sets prepareExecuteBuffer, so this forwards cursor_fetch_requested=true without any marker that makes the master take its prepared-execute branch. proxyExecute then leaves the fresh context as COM_SLEEP; both coordinator paths set mysql_row_binary_format=false, and non-empty rows are serialized as text even though Connector/J is reading a COM_STMT_EXECUTE binary result. The new regression uses getServerPrepareJdbcUrl, which connects directly to the master, so it misses this path. Please forward execute/binary-result intent independently of parameter bytes (or always carry an empty execute buffer) and cover a follower-to-master non-empty result.

@CalvinKirs
CalvinKirs force-pushed the fix/cursor-fetch-empty-result branch from b745f71 to 12e48c4 Compare September 4, 2026 08:24
@CalvinKirs CalvinKirs changed the title [fix](fe) Prevent cursor fetch from hanging on empty results [fix](protocol) Prevent Connector/J cursor fetch from hanging on empty results Sep 4, 2026
@CalvinKirs

Copy link
Copy Markdown
Member Author

/review

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review status: capped/incomplete — the third and final convergence round added an accepted scoping constraint, which is included in the P1 old-master finding below; the workflow permits no fourth round.

Request changes. The direct Connector/J classifier and compatibility-terminator sequence are localized and coherent, but the end-to-end goal is not met across the production handshake and mixed-version FE paths.

Critical checkpoints:

  • Goal and proof: direct empty/nonempty cursor results and classifier boundaries have tests, but real serializer negotiation, real proxy EOF status, both mixed-version directions, and old-master warning/info are not proved. The already-threaded zero-placeholder forwarding path also remains broken.
  • Scope and clarity: production changes are focused on MySQL classification, connection state, packet framing, and FE forwarding. The Arrow Flight DDL smoke test is ancillary and does not validate this fix.
  • Concurrency and lifecycle: the new state is connection-thread-owned, reset per command, and copied into fresh per-RPC proxy contexts. No new lock, deadlock, shared-mutation, circular-ownership, or static-initialization risk was found.
  • Configuration and compatibility: no configuration is added. Optional Thrift fields are wire-skippable, but their absent-value and runtime-result semantics fail in both rolling-upgrade directions.
  • Parallel paths and conditions: direct, new/new, new/old, old/new, coordinator, point-query, cached, FE-local, parameterized, zero-placeholder, legacy/deprecated EOF, affected/standard/unknown, and multi-statement paths were traced. The special gates have the inline defects below.
  • Tests and results: the classifier, packet, request, and context tests are internally consistent and the regression output is deterministic, but mocks bypass the production capability and EOF-status flows. I did not run builds or tests because this review environment explicitly prohibits them.
  • Observability and performance: the compatibility errors are actionable; no new metric is needed, and the classifier/boolean/packet overhead is negligible.
  • Transactions, persistence, writes, and transport: no EditLog, storage format, FE-BE variable, or atomicity change exists. Forwarded DML executes once, but its protocol-visible result is degraded; FE-to-FE transport has the mixed-version defects below.
  • Other correctness: warning/status serialization, binary/text selection, packet order, partial errors, and multi-result sequencing were checked. Four distinct inline issues remain. Existing threads r3930709957 and r3930709964 were treated as duplicate fences; the former is fixed on this head and the latter was not repeated.

User focus: no additional review focus was provided, so the full PR was reviewed.

packet = executor.getOutputPacket();
if (ctx.getMysqlChannel().clientDeprecatedEOF()
&& !executor.isForwardedClientDeprecatedEofApplied()
&& executor.getProxyStatusCode() == 0) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Classify successful old-master reads without widening this guard

A real forwarded SELECT cannot satisfy this gate: result producers finish with QueryState.setEof(), while proxyExecute assigns status 0 only to OK and maps successful EOF to 1105. The follower therefore replays the unsafe cursor packets; the unit test mocks the impossible combination of query buffers plus status 0. Simply accepting EOF here would also reject safe old-master COM_QUERY and Connector/J 9.5+ results because this predicate never checks cursor intent or the compatibility class. Please recognize real result-set success, scope rejection to requests that need the cursor shim, test through real proxyExecute construction, and ensure a non-final multi-statement sends the local ERR only once.

} else {
// An old master has already completed a DDL/DML operation. Rebuild its final OK locally
// instead of returning an upgrade error that could make the client retry side effects.
ctx.getState().setOk(executor.getForwardedAffectedRows(), 0, null);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Preserve the old master's complete OK result

This rolling-upgrade branch rebuilds a successful DML response with only affectedRows, discarding the warning count and info string already encoded in the master's final OK packet. A normal forwarded INSERT calls OlapInsertExecutor.setReturnInfo(), which reports filteredRows as warnings and includes label/status/txnId in info; through an old master this branch changes those to zero warnings and no message. Please preserve or decode all protocol-visible OK fields (or safely reuse the ordinary OK packet) and cover a response with nonzero warnings and nonempty info.

if (request.isSetClientDeprecatedEOF() && request.isClientDeprecatedEOF()) {
ctx.getMysqlChannel().setClientDeprecatedEOF();
}
ctx.setCursorFetchRequested(request.isSetCursorFetchRequested()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P1] Handle cursor intent from old forwarding FEs

During a rolling upgrade an old follower cannot set the new optional cursor_fetch_requested field, so this silently records false. It still forwards CLIENT_DEPRECATE_EOF, Connector/J attributes, and, for parameterized statements, the execute buffer; the new master then emits binary rows but omits the compatibility metadata marker. An affected Connector/J cursor SELECT forwarded through that old FE can therefore still consume the final marker and hang. Please treat an absent cursor-intent field as an explicit mixed-version/unknown execute mode and fail safely when the affected combination cannot be disambiguated, with an old-sender/new-master parameterized cursor test.

}
} else if (!Strings.isNullOrEmpty(infoMessage)) {
serializer.writeLenEncodedString(infoMessage);
} else if (capability.isDeprecatedEOF()) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[P2] Read the negotiated EOF capability here

This condition is false in the new unit test, but it remains true for real legacy-EOF connections. MysqlProto.negotiate records the client's bit only in MysqlChannel, then sets the serializer capability to context.getServerCapability(); that default mask always includes CLIENT_DEPRECATE_EOF. ProxyMysqlChannel starts with the same default as well. Consequently an authenticated client that did not negotiate the flag still gets the trailing zero byte this change intends to remove. Please key this from the negotiated/channel capability, and propagate it to proxy serialization, or store the negotiated mask in the serializer, with a handshake-level test.

CalvinKirs added a commit to CalvinKirs/incubator-doris that referenced this pull request Sep 7, 2026
### What problem does this PR solve?

Related PR: apache#67520

Problem Summary: Cursor queries forwarded to an older master can lose the
metadata terminator required by older Connector/J clients. Normalize buffered
old-master result boundaries at the follower while retaining complete DML/DDL
OK packets. Forward negotiated capabilities and avoid MySQL channel access for
Arrow requests. Preserve anonymous older-client cursor behavior and require
LOCAL_FILES only for client-side uploads, keeping FE file loads compatible.

### Release note

Preserve cursor result boundaries and DML/DDL status information during FE
rolling upgrades, and retain Arrow forwarding and server-side file loading.
Old followers must be upgraded to preserve cursor intent.

### Check List (For Author)

- Test: FE build with Checkstyle; 113 targeted unit tests passed across the
  complete run and corrected load-test rerun; cursor and prepared SHOW
  regression; Arrow follower DDL; baseline/candidate real JDBC, Shell, TLS,
  legacy EOF, file loading and connection-reuse probes. Four broader prepared
  suites fail identically on baseline/candidate with the available older BE;
  auth metadata regression and product OIDC E2E remain unverified. See v7 report.
- Behavior changed: Yes, preserve forwarded protocol and negotiated capabilities
- Does this need documentation: No (compatibility fix; validation report included)
CalvinKirs added a commit to CalvinKirs/incubator-doris that referenced this pull request Sep 7, 2026
### What problem does this PR solve?

Related PR: apache#67520

Problem Summary: Remove local review and validation documents from the PR
as requested. Production code and tests are unchanged.

### Release note

None

### Check List (For Author)

- Test: No need to test (documentation removal only)
- Behavior changed: No
- Does this need documentation: No
CalvinKirs added a commit to CalvinKirs/incubator-doris that referenced this pull request Sep 7, 2026
### What problem does this PR solve?

Related PR: apache#67520

Problem Summary: Merge current master and resolve MysqlOkPacketTest's
conflict with the JUnit 5 migration. Retain exact legacy/deprecated-EOF
packet assertions and migrate the PR's remaining JUnit 4 imports and
assertions so the tests match the upstream test framework.

### Release note

None

### Check List (For Author)

- Test: Standalone FE Core Checkstyle; source checks for JUnit 4 references,
  conflict markers and retained packet assertions. No compilation or unit-test
  rerun, as requested.
- Behavior changed: No (conflict resolution and test framework migration)
- Does this need documentation: No
@CalvinKirs

Copy link
Copy Markdown
Member Author

run buildall

@CalvinKirs

Copy link
Copy Markdown
Member Author

/review

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Your access token could not be refreshed because your refresh token was already used. Please log out and sign in again.
Workflow run: https://github.com/apache/doris/actions/runs/34091096744

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@morrySnow

Copy link
Copy Markdown
Contributor

/review

@github-actions

github-actions Bot commented Sep 7, 2026

Copy link
Copy Markdown
Contributor

Codex automated review failed and did not complete.

Error: Selected model is at capacity. Please try a different model.
Workflow run: https://github.com/apache/doris/actions/runs/34093093591

Please inspect the workflow logs and rerun the review after the underlying issue is resolved.

@hello-stephen

Copy link
Copy Markdown
Contributor

Cloud UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 77.69% (2055/2645)
Line Coverage 65.72% (37563/57152)
Region Coverage 52.97% (35047/66167)
Branch Coverage 56.46% (11266/19954)

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 16944 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 32d01e5df19180f8b01c0f9e1112d5d42b02bab3, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17012	3087	3117	3087
q2	2108	262	233	233
q3	10061	895	523	523
q4	4661	247	200	200
q5	7759	573	385	385
q6	139	112	92	92
q7	522	498	385	385
q8	9315	896	921	896
q9	3447	2392	2363	2363
q10	6509	864	715	715
q11	396	195	184	184
q12	623	256	197	197
q13	18125	1563	1169	1169
q14	173	144	138	138
q15	q16	449	394	368	368
q17	1375	888	831	831
q18	3105	2231	2222	2222
q19	1413	879	808	808
q20	378	285	205	205
q21	5299	1717	1827	1717
q22	319	263	226	226
Total cold run time: 93188 ms
Total hot run time: 16944 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3486	3407	3379	3379
q2	497	381	384	381
q3	2224	2289	2209	2209
q4	1188	1159	904	904
q5	2183	2082	2070	2070
q6	167	119	84	84
q7	1020	926	832	832
q8	1609	1429	1437	1429
q9	3130	3091	3099	3091
q10	1836	1791	1670	1670
q11	360	270	252	252
q12	467	434	350	350
q13	1491	1541	1160	1160
q14	167	174	172	172
q15	q16	386	388	356	356
q17	3586	3350	3145	3145
q18	4800	4368	4747	4368
q19	855	823	908	823
q20	1017	946	808	808
q21	3908	3108	3385	3108
q22	392	354	316	316
Total cold run time: 34769 ms
Total hot run time: 30907 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 81954 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit 32d01e5df19180f8b01c0f9e1112d5d42b02bab3, data reload: false

query5	4260	402	334	334
query6	386	134	122	122
query7	4969	421	228	228
query8	287	119	124	119
query9	8667	2875	2888	2875
query10	382	218	208	208
query11	5378	1033	932	932
query12	118	68	70	68
query13	1187	451	315	315
query14	6052	2207	2083	2083
query14_1	1958	1969	1957	1957
query15	172	125	109	109
query16	921	366	358	358
query17	813	456	378	378
query18	2320	322	224	224
query19	157	133	107	107
query20	81	69	75	69
query21	198	103	89	89
query22	5393	5303	5295	5295
query23	6677	6268	6040	6040
query23_1	5935	6155	6229	6155
query24	7156	1117	764	764
query24_1	767	756	763	756
query25	412	279	238	238
query26	1234	224	126	126
query27	2797	430	266	266
query28	4609	1474	1489	1474
query29	911	421	340	340
query30	258	153	127	127
query31	844	389	327	327
query32	133	72	70	70
query33	457	224	171	171
query34	1018	860	468	468
query35	397	404	341	341
query36	566	589	530	530
query37	116	77	67	67
query38	1009	836	790	790
query39	521	485	470	470
query39_1	470	454	465	454
query40	195	88	75	75
query41	57	58	58	58
query42	76	72	72	72
query43	247	246	214	214
query44	1044	545	557	545
query45	106	113	104	104
query46	795	829	538	538
query47	777	786	730	730
query48	338	297	236	236
query49	539	240	195	195
query50	774	274	196	196
query51	8152	8183	8115	8115
query52	67	65	59	59
query53	199	202	152	152
query54	250	217	184	184
query55	78	68	57	57
query56	205	190	175	175
query57	699	754	644	644
query58	214	166	165	165
query59	1277	1226	1121	1121
query60	240	190	182	182
query61	131	122	123	122
query62	396	205	181	181
query63	164	147	134	134
query64	2652	670	558	558
query65	1657	1588	1620	1588
query66	1885	257	202	202
query67	9922	9568	9544	9544
query68	3026	1225	690	690
query69	342	231	194	194
query70	698	643	613	613
query71	245	174	158	158
query72	2316	1803	1591	1591
query73	640	580	330	330
query74	1997	1215	1127	1127
query75	1166	1088	952	952
query76	2318	732	520	520
query77	249	251	214	214
query78	3984	3690	3243	3243
query79	2787	870	576	576
query80	1579	329	292	292
query81	525	154	136	136
query82	620	117	95	95
query83	274	206	195	195
query84	296	110	87	87
query85	867	352	290	290
query86	397	177	173	173
query87	1004	979	889	889
query88	2837	2100	2090	2090
query89	288	198	177	177
query90	1950	133	131	131
query91	132	122	98	98
query92	79	71	71	71
query93	1761	1071	667	667
query94	650	257	225	225
query95	512	247	226	226
query96	754	564	281	281
query97	1067	1062	1019	1019
query98	171	136	132	132
query99	415	350	304	304
Total cold run time: 178583 ms
Total hot run time: 81954 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 14.68 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 32d01e5df19180f8b01c0f9e1112d5d42b02bab3, data reload: false

query1	0.01	0.01	0.00
query2	0.07	0.04	0.03
query3	0.25	0.11	0.10
query4	1.59	0.09	0.10
query5	0.17	0.16	0.16
query6	1.28	0.66	0.69
query7	0.03	0.00	0.01
query8	0.05	0.04	0.03
query9	0.28	0.21	0.21
query10	0.34	0.35	0.34
query11	0.16	0.12	0.12
query12	0.15	0.12	0.12
query13	0.29	0.31	0.31
query14	0.44	0.44	0.44
query15	0.36	0.35	0.34
query16	0.23	0.22	0.21
query17	0.69	0.70	0.68
query18	0.18	0.17	0.16
query19	1.18	1.09	1.16
query20	0.02	0.01	0.01
query21	15.44	0.15	0.11
query22	5.12	0.04	0.05
query23	16.18	0.25	0.10
query24	2.98	0.31	0.26
query25	0.08	0.04	0.04
query26	0.79	0.16	0.11
query27	0.04	0.04	0.03
query28	3.65	0.54	0.29
query29	12.46	3.20	2.57
query30	0.25	0.10	0.12
query31	2.75	0.39	0.17
query32	3.50	0.31	0.23
query33	1.38	1.47	1.56
query34	15.37	2.19	1.80
query35	1.73	1.74	1.72
query36	0.47	0.30	0.30
query37	0.06	0.04	0.03
query38	0.05	0.03	0.03
query39	0.03	0.02	0.02
query40	0.11	0.08	0.08
query41	0.08	0.02	0.03
query42	0.04	0.03	0.03
query43	0.04	0.03	0.03
Total cold run time: 90.37 s
Total hot run time: 14.68 s

@CalvinKirs

Copy link
Copy Markdown
Member Author

Local agent review result — reviewed local commit, not current PR head

Completed a local review using the official apache/doris-skills workflow at 8c13ef3c96124232c6679b6d8764c33f937cf660, with a lead and two coverage reviewers, all running gpt-6-astra / xhigh.

  • Reviewed commit: 291281c122d03b1d51bc08f85a5708e784501a88 (local, not yet pushed).
  • Remote PR head at publication: 32d01e5df19180f8b01c0f9e1112d5d42b02bab3.
  • Review base: eea19b3f3cfef9e1bbbd559f9ea42954d8891e0f.
  • Local verdict: APPROVE; 0 Blocker / 0 Major / 0 Minor / 0 Nit. All 24 changed files covered; converged in round 1. The original document verifier passed.

The local commit addresses the previously identified zero-parameter prepared-forwarding issue by preserving the empty execute payload, exercises the actual plain Statement entry, and corrects the two SQL-result assertions identified in the previous review. The updated regression disables JDBC preparation fallback and prepares on a follower before enabling forwarding.

Limits: These fixes and this verdict apply to the reviewed local commit, not the current remote PR head. This comment is not an exact-head PASS receipt or a human Apache approval. No build or tests were run during this review. Checkstyle had passed for the local fix, but the new unit/regression tests and strengthened JDBC probe have not been executed; the historical JDBC successes do not prove the newly covered forwarding path. Follower coverage is explicitly skipped when no live non-master FE exists.

A separate, pre-existing parameter-type caching issue in repeated parameterized prepared forwarding remains unresolved and is outside this zero-parameter fix. It is not counted as a newly introduced finding.

@CalvinKirs

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 63.05% (29598/46944)
Line Coverage 48.11% (310594/645563)
Region Coverage 43.70% (250946/574211)
Branch Coverage 45.28% (116840/258038)

CalvinKirs added a commit to CalvinKirs/incubator-doris that referenced this pull request Sep 7, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#67520

Problem Summary: A zero-parameter server-prepared statement can be prepared on
 a readable follower and later forwarded during execution. The follower saved
 the execute payload only for statements with parameters, so the master treated
 the request as a text query. Preserve the empty payload as the existing binary
 execution marker. Add coverage for empty-payload Thrift serialization and the
 direct-to-forwarded execution transition, and prevent JDBC fallback from hiding
 missing server-prepared coverage. Exercise the actual plain Statement entry.

### Release note

Fix incorrect result encoding when zero-parameter server-prepared queries are
forwarded from a follower FE.

### Check List (For Author)

- Test: Checkstyle passed with 0 violations; git diff --check passed. Unit and
  regression tests added but not executed; compilation was excluded by request.
- Behavior changed: Yes; preserve binary result encoding for zero-parameter
  prepared execution forwarded to the master FE.
- Does this need documentation: No
CalvinKirs added a commit to CalvinKirs/incubator-doris that referenced this pull request Sep 7, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#67520

Problem Summary: Forwarding now reads the negotiated MySQL capability. The
delegated credential test constructs a context without a handshake and leaves
that capability null, causing an NPE before its credential assertions. Initialize
the test context consistently with the protocol forwarding tests.

### Release note

None

### Check List (For Author)

- Test: Checkstyle passed with 0 violations; git diff --check passed. Unit tests
  not run locally; buildall requested on the PR after pushing.
- Behavior changed: No
- Does this need documentation: No
@hello-stephen

Copy link
Copy Markdown
Contributor

BE UT Coverage Report

Increment line coverage 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 63.36% (29867/47135)
Line Coverage 48.41% (313608/647829)
Region Coverage 43.90% (252866/576012)
Branch Coverage 45.54% (117949/259000)

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100% (0/0) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.29% (34832/45658)
Line Coverage 61.39% (393179/640454)
Region Coverage 57.37% (329196/573809)
Branch Coverage 58.40% (150829/258259)

@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 42.20% (46/109) 🎉
Increment coverage report
Complete coverage report

hubgeter
hubgeter previously approved these changes Sep 9, 2026
### What problem does this PR solve?

Issue Number: None

Related PR: apache#67520, apache#67569

Problem Summary: Merge master into the cursor-fetch fix branch. Resolve the overlapping FEOpExecutor changes by preserving the upstream MySQL connection guard and the negotiated capability propagation needed by cursor forwarding. Initialize negotiated capabilities in the upstream MySQL forwarding tests, which otherwise fail with a null capability after the merge. Preserve Arrow Flight SQL forwarding without accessing a MySQL channel.

### Release note

None

### Check List (For Author)

- Test: Unit Test / Build
    - ./build.sh --fe passed with DISABLE_BUILD_UI=ON and FE_MAVEN_THREADS=4.
    - ./run-fe-ut.sh --run passed all 28 tests in FEOpExecutorMysqlProtocolTest, FEOpExecutorFlightForwardTest, ConnectProcessorFlightForwardOutcomeTest, ConnectProcessorForwardProtocolTest, MysqlConnectProcessorCursorFetchTest, MysqlCursorFetchCompatibilityTest and MysqlResultSetEndPacketTest.
    - Final fe-core Checkstyle passed with 0 violations; git diff --cached --check passed.
- Behavior changed: No (conflict resolution preserves both branches' intended behavior)
- Does this need documentation: No
@CalvinKirs

Copy link
Copy Markdown
Member Author

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 16959 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit cc7259b59da79ce68560d7cf915f113049eedd83, data reload: false

------ Round 1 ----------------------------------
============================================
q1	17594	3020	3005	3005
q2	2152	261	234	234
q3	10161	861	521	521
q4	4672	259	202	202
q5	7674	584	389	389
q6	142	119	94	94
q7	535	520	388	388
q8	9234	946	962	946
q9	3477	2407	2417	2407
q10	6510	846	701	701
q11	396	204	181	181
q12	612	256	202	202
q13	18125	1618	1241	1241
q14	168	154	135	135
q15	q16	431	395	388	388
q17	1441	859	723	723
q18	3245	2296	2258	2258
q19	1122	887	764	764
q20	407	284	206	206
q21	5232	1746	1939	1746
q22	345	270	228	228
Total cold run time: 93675 ms
Total hot run time: 16959 ms

----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3368	3291	3263	3263
q2	497	392	357	357
q3	2223	2283	2180	2180
q4	1189	1178	901	901
q5	2176	2098	2100	2098
q6	173	120	88	88
q7	1036	911	842	842
q8	1596	1381	1366	1366
q9	3110	3076	3077	3076
q10	1902	1816	1646	1646
q11	355	268	247	247
q12	460	435	338	338
q13	1585	1604	1211	1211
q14	170	161	156	156
q15	q16	407	401	352	352
q17	3557	3271	3155	3155
q18	4818	4409	4748	4409
q19	890	814	969	814
q20	1007	963	834	834
q21	3881	3098	3300	3098
q22	411	343	338	338
Total cold run time: 34811 ms
Total hot run time: 30769 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 81871 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpcds-tools
TPC-DS sf100 test result on commit cc7259b59da79ce68560d7cf915f113049eedd83, data reload: false

query5	4252	435	351	351
query6	380	135	129	129
query7	4917	420	230	230
query8	282	126	122	122
query9	8699	2895	2901	2895
query10	386	222	176	176
query11	5381	1043	919	919
query12	120	76	69	69
query13	1199	446	329	329
query14	6129	2196	2059	2059
query14_1	1961	1969	1946	1946
query15	174	121	110	110
query16	917	358	341	341
query17	788	448	365	365
query18	2337	323	239	239
query19	166	134	111	111
query20	73	73	72	72
query21	201	101	91	91
query22	5567	5396	5377	5377
query23	6693	6135	5966	5966
query23_1	6062	6198	6059	6059
query24	7291	1111	788	788
query24_1	766	777	786	777
query25	424	296	231	231
query26	1233	238	122	122
query27	2801	420	251	251
query28	4673	1479	1503	1479
query29	905	422	326	326
query30	247	155	131	131
query31	807	391	324	324
query32	123	74	68	68
query33	449	215	174	174
query34	995	835	466	466
query35	403	397	341	341
query36	566	562	544	544
query37	119	82	67	67
query38	993	839	817	817
query39	495	489	479	479
query39_1	443	477	470	470
query40	198	90	79	79
query41	56	51	52	51
query42	73	73	72	72
query43	236	238	208	208
query44	1005	536	547	536
query45	107	103	100	100
query46	770	830	510	510
query47	756	740	701	701
query48	297	315	222	222
query49	538	231	189	189
query50	707	258	203	203
query51	7996	7900	7989	7900
query52	69	67	60	60
query53	193	204	146	146
query54	234	151	143	143
query55	73	64	62	62
query56	192	173	183	173
query57	707	710	668	668
query58	189	189	194	189
query59	1196	1214	1100	1100
query60	235	180	168	168
query61	113	112	113	112
query62	364	197	181	181
query63	172	137	150	137
query64	2698	747	596	596
query65	1635	1613	1669	1613
query66	1884	279	194	194
query67	10120	9700	9803	9700
query68	2799	1141	731	731
query69	341	223	201	201
query70	680	600	627	600
query71	258	180	158	158
query72	2264	1673	1496	1496
query73	639	584	330	330
query74	1585	1202	1126	1126
query75	1169	1086	956	956
query76	2300	733	556	556
query77	261	277	228	228
query78	3806	3625	3191	3191
query79	1216	818	588	588
query80	1237	342	292	292
query81	477	162	132	132
query82	636	124	100	100
query83	307	216	200	200
query84	289	111	94	94
query85	834	407	341	341
query86	382	194	174	174
query87	1030	989	885	885
query88	2759	2138	2142	2138
query89	281	196	176	176
query90	1922	129	125	125
query91	131	123	97	97
query92	81	72	71	71
query93	1310	1075	697	697
query94	628	246	209	209
query95	523	262	304	262
query96	798	629	267	267
query97	1095	1063	1018	1018
query98	142	136	132	132
query99	413	353	311	311
Total cold run time: 175198 ms
Total hot run time: 81871 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 14.74 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit cc7259b59da79ce68560d7cf915f113049eedd83, data reload: false

query1	0.00	0.00	0.00
query2	0.07	0.03	0.04
query3	0.25	0.10	0.11
query4	1.60	0.10	0.10
query5	0.17	0.15	0.16
query6	1.26	0.68	0.70
query7	0.03	0.01	0.01
query8	0.05	0.03	0.02
query9	0.29	0.21	0.22
query10	0.35	0.34	0.37
query11	0.16	0.12	0.11
query12	0.14	0.12	0.12
query13	0.32	0.31	0.32
query14	0.45	0.47	0.47
query15	0.35	0.35	0.35
query16	0.21	0.23	0.23
query17	0.69	0.72	0.76
query18	0.16	0.16	0.16
query19	1.22	1.19	1.18
query20	0.01	0.01	0.01
query21	15.47	0.16	0.12
query22	5.09	0.04	0.04
query23	16.19	0.25	0.10
query24	3.01	0.33	0.26
query25	0.11	0.05	0.03
query26	0.78	0.16	0.13
query27	0.04	0.03	0.03
query28	3.67	0.53	0.28
query29	12.41	3.20	2.57
query30	0.27	0.11	0.12
query31	2.75	0.37	0.17
query32	3.52	0.31	0.24
query33	1.49	1.39	1.47
query34	15.38	2.18	1.78
query35	1.76	1.71	1.70
query36	0.45	0.30	0.27
query37	0.06	0.04	0.04
query38	0.04	0.03	0.02
query39	0.04	0.03	0.02
query40	0.11	0.08	0.08
query41	0.08	0.03	0.02
query42	0.03	0.02	0.02
query43	0.04	0.03	0.02
Total cold run time: 90.57 s
Total hot run time: 14.74 s

@hello-stephen

Copy link
Copy Markdown
Contributor

BE Regression && UT Coverage Report

Increment line coverage 100% (0/0) 🎉

Increment coverage report
Complete coverage report

Category Coverage
Function Coverage 76.27% (34831/45667)
Line Coverage 61.37% (393122/640589)
Region Coverage 57.49% (329993/573953)
Branch Coverage 58.37% (150807/258378)

@CalvinKirs
CalvinKirs merged commit 958aaf4 into apache:master Sep 10, 2026
35 of 37 checks passed
@CalvinKirs
CalvinKirs deleted the fix/cursor-fetch-empty-result branch September 10, 2026 02:44
@github-actions github-actions Bot added the approved Indicates a PR has been approved by one committer. label Sep 10, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR approved by at least one committer and no changes requested.

morningman added a commit that referenced this pull request Sep 11, 2026
…on PRs from master in merge order (#67533 #67594 #67646 #67669 #67665 #67710 #67775 #67575 #67480) (#67830)

Cherry-picked from #67533, #67594, #67646, #67669, #67665, #67710,
#67775, #67575, #67480

Batch pick of every merged PR carrying the `incremental-computation`
label that `branch-incremental-computation` does not have yet, in the
order they landed on master (`git log --first-parent`). One commit per
PR, each created with `git cherry-pick -x` so the message ends with
`(cherry picked from commit <master sha>)`.

| # | Master commit | PR | Title |
|---|---|---|---|
| 1 | 300d532 | #67533 | [fix](table stream) Preserve table stream
offsets during cleanup |
| 2 | bfe46ec | #67594 | [fix](row binlog) make time-based
incremental reads use a safe fence |
| 3 | c1bff0d | #67646 | [fix](ivm) Fail aggregate IVM refresh when
the previous refresh txn is not visible yet |
| 4 | 4f3abce | #67669 | [fix](ivm) Resolve IVM identity keys by
slot identity and materialize unprojected keys |
| 5 | 7129a3e | #67665 | [fix](ivm) Propagate and compensate
failures of the IVM excluded-trigger-tables ALTER |
| 6 | a565aca | #67710 | [fix](regression) Stop MTMV task waits from
latching onto the previous task |
| 7 | 8565db2 | #67775 | [fix](ivm) Repair the removed
rewrite-context constructor call in IvmNormalizeMTMVJoinTest |
| 8 | 0ded66a | #67575 | [feature](ivm) Support incremental refresh
for array_agg and collect_list aggregates |
| 9 | efc929a | #67480 | [fix](table stream) fix table stream TSO
boundary semantics |

Not included on purpose:
- #62606 (IVM feature) is already in the branch's fork point
(`efedf10c7e3`).
- #67508 already landed on this branch via #67712.

### Cherry-pick notes

- All nine picks applied without conflicts. Each pick's diff is
identical to its master commit (compared with `index`/`@@` lines
stripped).
- Every touched file is byte-identical to master at `efc929aa7af` except
`Env.java`, `FrontendServiceImpl.java` and `FrontendService.thrift`,
whose remaining differences come only from unrelated master commits that
are not part of this label (#67708, #66770, #67572, #67520).
- #67594 is the safe-read-fence prerequisite of #67480; picking both in
master order is what makes #67480 apply cleanly here (it replaces the
earlier stand-alone attempt #67828, which had to hand-adapt around the
missing fence).
- #67775 is needed because #67646 (removes the `IvmRewriteContext`
constructor) and #67669 (test that still used it) are both picked.

### Verification

- `be/src/exec/scan/olap_scanner.cpp` (the only BE change): syntax-only
compile with the Release flags, clean. The new thrift RPC
`acquireTimeBasedChangeReadFence` is FE-only; nothing in `be/` or
`cloud/` references it.
- FE: `run-fe-ut.sh --run` on this branch (regenerates thrift, compiles
fe-core main + test) with the 19 test classes touched by the picks:
  19 classes, 450 tests, 0 failures, 0 errors, BUILD SUCCESS —
`TableStreamManagerCleanupTest` 9, `CloudGlobalTransactionMgrTest` 22,
`AlterMTMVTest` 24, `IvmAggArrayAggProcessorTest` 2,
`IvmAggCollectListProcessorTest` 1, `IvmAggDeltaHandlerTest` 33,
`IvmDeltaRewriterTest` 20, `IvmJoinDeltaHandlerTest` 23,
`IvmLinearDeltaHandlerTest` 39, `IvmNormalizeMTMVJoinTest` 44,
`PhysicalPlanTranslatorTest` 17, `IvmIncrRefreshMTMVTest` 13,
`IvmNormalizeMTMVTest` 52, `CreateMTMVCommandTest` 94,
`ExplainTableStreamPlanTest` 23, `OlapScanNodeTest` 12,
`TimeBasedChangeVisibleWaiterTest` 7, `TransactionIdGeneratorTest` 1,
`TSOTimestampTest` 14.
- Regression suites touched parse cleanly (groovy parser check).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

https://claude.ai/code/session_018m1ARNXtGSWucJTy34uwe1

---------

Co-authored-by: TsukiokaKogane <cby141994@gmail.com>
Co-authored-by: Luwei <814383175@qq.com>
Co-authored-by: yujun <yujun@selectdb.com>
morningman added a commit that referenced this pull request Sep 11, 2026
…ead of a Flight subclass (#67835)

### What problem does this PR solve?

Issue Number: #67577 -- the tracking issue for the protocol-agnostic
session and execution
layer. This is the second PR of its Stage 1 (after the golden baseline
#67789) and does not close it.

The shape after this PR:

```
  +---------------------------+                             +-----------------------------+
  |       MySQL client        |                             |   Arrow Flight SQL client   |
  +-------------+-------------+                             +--------------+--------------+
                |                                                          |
                v                                                          v
  +---------------------------+                             +-----------------------------+
  | MysqlServer               |                             | DorisFlightSqlProducer      |
  |   AcceptListener          |                             |   every call goes through   |
  |   ReadListener            |                             |   adapter.runCommand()      |
  |   (xnio: one command      |                             |   (lock: one command        |
  |    at a time)             |                             |    at a time)               |
  +-------------+-------------+                             +--------------+--------------+
                |                                                          |
                v                                                          v
  +---------------------------+                             +-----------------------------+
  |   MysqlConnectProcessor   |                             |  FlightSqlConnectProcessor  |
  +-------------+-------------+                             +--------------+--------------+
                |                                                          |
                +----------------------------+-----------------------------+
                                             |
                                             v
  +-------------------------------------------------------------------------------------------+
  | ConnectContext  --  the session, one per connection                                       |
  |                                                                                           |
  |   user, catalog / db, SessionVariable, transaction, prepared statements,                  |
  |   queryId / stmtId, executor, audit, ...                                                  |
  |                                                                                           |
  |   protocolAdapter : ProtocolAdapter                                                       |
  |       bound once, by  forMysql() | forMysqlProxy() | forFlight() | new ConnectContext()   |
  |                                                                                           |
  |   getMysqlChannel()  getCapability()  getFlightSqlChannel()  isReturnResultFromLocal() .. |
  |       same signatures as before, now delegate to protocolAdapter                          |
  +---------------------------------------------+---------------------------------------------+
                                                |
                                                v
                       +-----------------------------------------------+
                       |  <<interface>>  qe.protocol.ProtocolAdapter   |
                       |                                               |
                       |   type()                                      |
                       |   remoteHostPortString(ctx)                   |
                       |   resultSinkType()                            |
                       |   connectPool(scheduler)                      |
                       |   afterStatement(ctx)                         |
                       |   closeConnection(ctx)                        |
                       +-----------------------+-----------------------+
                                               |
                          +--------------------+----------------------------+
                          |                                                 |
  +-----------------------+----------------------+  +-----------------------+----------------------+
  | mysql.protocol.MysqlProtocolAdapter          |  | service.arrowflight.protocol                 |
  |                                              |  |   .FlightProtocolAdapter                     |
  |   MysqlChannel:                              |  |                                              |
  |     a socket                                 |  |   peerIdentity (the bearer token)            |
  |     ProxyMysqlChannel (statement forwarded   |  |   FlightSqlChannel (FE-side result cache)    |
  |       to the master)                         |  |   endpoints of the last query                |
  |     DummyMysqlChannel (internal context)     |  |   returnResultFromLocal                      |
  |   server / negotiated MysqlCapability        |  |   prepared queries                           |
  |   handshake packet, MysqlSslContext          |  |   deferred executors + idle bound            |
  |   COM_STMT_EXECUTE packet, cursor flag       |  |     (#62259, #67503)                         |
  |   clientConsumesCursorMetadataTerminator()   |  |   per-session command lock:                  |
  |   accept-query loop                          |  |     runCommand() / callCommand()             |
  |     (start / suspend / resume / stop)        |  |                                              |
  +----------------------------------------------+  +----------------------------------------------+

  Not touched by this PR: ConnectProcessor / StmtExecutor / Coordinator keep calling the
  ConnectContext getters. The result-encoding half (ResultSender) and the capability
  predicates that replace the remaining ConnectType branches come in the next PRs.
```

**In plain terms.** A client session in the frontend is a
`ConnectContext`. Today that one class
holds the state of both wire protocols at the same time: the MySQL
socket, the capabilities
negotiated with the MySQL client, the handshake and SSL state, the
prepared-statement packet being
executed -- and, next to them, the Arrow Flight SQL result cache, the
backend endpoints of the last
Flight query, the prepared queries and the deferred coordinators. Which
half is real is decided by a
subclass, `FlightSqlConnectContext`, that overrides six methods and
leaves every other Flight member
sitting on the base class, where a MySQL connection carries it as dead
weight and a Flight session
throws from the MySQL ones. This PR gives each protocol its own object,
a `ProtocolAdapter`, and
binds a session to exactly one of them when it is created. Nothing a
client sees changes: the golden
byte-for-byte baseline recorded in #67789 is identical before and after.

Problem Summary:

`ConnectContext` mixes three things: the session (user, catalog and
database, session variables,
transaction, prepared statements, the running statement), the MySQL
protocol state, and the Arrow
Flight SQL protocol state. The next steps of #67577 move the result path
of both protocols onto one
shared implementation, which needs a place for "what only this protocol
knows" that is not the
session itself. This PR creates that place and moves the state, without
touching the execution layer
yet: `StmtExecutor`, `ConnectProcessor` and the coordinators still call
the same `ConnectContext`
getters, which now delegate.

### What is changed?

**`qe/protocol/ProtocolAdapter`** -- the wire-protocol half of a
connection: `type()`, the client
address for processlist and the audit log, the result sink type the
backend must use, the pool the
connection is registered in (there is still one per protocol), a
per-statement cleanup hook and
`closeConnection`. `qe/protocol` holds only the interface; each front
end implements it in a
`protocol` subpackage of its own package (`mysql/protocol`,
`service/arrowflight/protocol`), which is
also where the result senders of the next step go.

**`mysql/protocol/MysqlProtocolAdapter`** -- owns the `MysqlChannel` (a
socket, the
`ProxyMysqlChannel` of a forwarded statement on the master, or the
`DummyMysqlChannel` of an
internal context), the server and negotiated capabilities, the handshake
packet, the SSL context,
the `COM_STMT_EXECUTE` packet and its cursor flag, and the xnio
accept-query loop that
`AcceptListener` / `ReadListener` drive. It also owns the decision
`StmtExecutor` and `FEOpExecutor`
used to compute from `ConnectContext` fields -- whether the Connector/J
release on the other end
consumes the metadata terminator of a cursor result (#67520) -- as
`clientConsumesCursorMetadataTerminator`.

**`service/arrowflight/protocol/FlightProtocolAdapter`** -- owns the
peer identity (bearer token), the
`FlightSqlChannel`, the prepared queries, the endpoints of the last
query, `returnResultFromLocal`
and the deferred executors of #62259 / #67503, together with their idle
bound. `ConnectContext`
keeps `checkTimeout` and the idle reaper unchanged; only the list moved.

It also serializes the commands of a session. gRPC runs each call of a
session on whatever thread it
likes and nothing in the Flight transport orders them, while
`ConnectContext` is not thread-safe
(the existing `DorisFlightSqlProducerTest` spells that out).
`runCommand` / `callCommand` take a
per-session lock, make the session the thread's current `ConnectContext`
for the duration, restore
the previous one afterwards, and give up with `UNAVAILABLE` after the
session's query timeout if
another command is still running. `DorisFlightSqlProducer` runs
statement execution, prepared
statement creation and close, DoGet of a frontend-side result and the
catalog / schema / table
metadata requests through it. DoGet of a frontend-side result streams
under the lock on purpose: the
next statement of the session resets the channel, whose removal listener
closes the
`VectorSchemaRoot` being streamed. Session teardown (token expiry,
`CloseSession`, `KILL`) does not
take the lock; that path is reworked when the token becomes the session
credential.

**`ConnectContext`** -- gets `protocolAdapter` and three factories:
`forMysql(StreamConnection)`,
`forMysqlProxy(sessionId)` (replaces the `new ConnectContext(null, true,
sessionId)` call in
`FrontendServiceImpl`) and `forFlight(peerIdentity)` (replaces the
subclass in
`FlightSessionsManager`). The existing constructors stay as thin
wrappers, so the ~115 test files that
call `new ConnectContext()` are untouched. Every protocol-specific
getter keeps its signature and
delegates: `getMysqlChannel()`, `getCapability()`,
`getFlightSqlChannel()`, `isReturnResultFromLocal()`
and so on. A getter that only makes sense on the other protocol throws
`IllegalStateException`
naming the actual protocol (the subclass used to throw a
`RuntimeException` for `getMysqlChannel()`;
the base class used to return `null` / an empty list for the Flight
ones, which no caller relied on).
`FlightSqlConnectContext` is deleted: its `getClientIP` /
`getRemoteHostPortString` /
`closeChannel` / `setQueryId` overrides are the adapter's
`remoteHostPortString` / `closeConnection`
/ `connectPool`, and its `kill` override only differed in log text.

Removed as dead code while touching the class: `isSend` / `setIsSend`
(nothing read them; the real
flag lives on `MysqlChannel`), `cloneContext()` (no caller, and it would
have to share a channel
between two adapters), and the two lines of `resetConnection()` that
cleared Flight-only fields
(`COM_RESET_CONNECTION` is only sent by MySQL clients).

Not in this PR, deliberately: the execution layer still branches on
`ConnectType`, and an internal
context is still a MySQL context over a `DummyMysqlChannel`, exactly as
before. Both go away in the
follow-up PRs that introduce the result sender and the capability bits.

### Verification

- **Golden baseline of #67789**: `MysqlPacketGoldenTest` (27 cases, byte
for byte) and
`FlightResultGoldenTest` pass unchanged. Not a byte of the recorded
traffic moved.
- New unit tests: `FlightProtocolAdapterTest` (commands of one session
run one at a time, a waiting
command fails with `UNAVAILABLE` after the query timeout, the thread's
current context is set and
restored, a failing command releases the session, `KILL` unregisters the
session from the Flight
pool, the trace id lands in the Flight pool) and
`MysqlProtocolAdapterTest` (internal and proxy
contexts, the cursor-terminator decision and its per-statement reset,
the accept-query loop and
  close going through the channel).
- Existing tests adjusted to the factories: the ones that built a
`FlightSqlConnectContext`, poked
`mysqlChannel` / `connectType` through reflection, or used a plain `new
ConnectContext()` as a
Flight session (`ShortCircuitPointQueryTest`,
`AuditLogWorkloadGroupTest`, `StmtExecutorTest`,
`ConnectContextTest`, `MysqlProtoTest`, `ConnectionExceedTest`). 26 test
classes around the
session, the MySQL channel and the Flight producer: 166 tests, 0
failures.
- Regression on a local cluster built from this branch:
`arrow_flight_sql_p0` (8 suites, including
the forward-to-master, query-release, point-query, SQL cache and
`DatabaseMetaData.getColumns`
paths) and `prepared_stmt_p0` (cursor fetch and server-side prepare over
MySQL).
- `checkstyle:check` on fe-core (main and test sources): 0 violations.
morningman added a commit that referenced this pull request Sep 15, 2026
…on PRs from master in merge order (#67753 #67802 #67814 #67837 #67853 #67876) (#68017)

Cherry-picked from #67753, #67802, #67814, #67837, #67853, #67876

Batch pick of every merged PR carrying the `incremental-computation`
label that `branch-incremental-computation` does not have yet (no
`incremental-computation-picked` label), in the order they landed on
master (`git log --first-parent`). One commit per PR, each created with
`git cherry-pick -x` so the message ends with `(cherry picked from
commit <master sha>)`. Follows the same convention as #67830.

| # | Master commit | PR | Title |
|---|---|---|---|
| 1 | fe39f5b | #67753 | [fix](ivm) Answer FE-computable dry runs on
the frontend instead of a placeholder backend |
| 2 | f8ed33f | #67802 | [fix](ivm) Refresh the surviving partitions
after an IVM baseline rebuild |
| 3 | 7bd89a0 | #67814 | [fix](ivm) Stop the incremental delta from
reading partitions the MV dropped |
| 4 | 3050a9a | #67837 | [fix](ivm) Invalidate the baseline when a
column used by the MV is dropped |
| 5 | 22c95eb | #67853 | [fix](ivm) Carry the row-binlog hidden
columns in the analyzed MTMV schema |
| 6 | 3390a7a | #67876 | [test](ivm) Remove unnecessary cloud skips
from IVM suites |

Not included on purpose:
- The 11 labelled PRs that already carry
`incremental-computation-picked` (#62606 in the fork point, #67508 via
#67712, the nine of #67830).
- #67820 is still open on master; this branch already carries its
content via #67861.

### Prerequisite check

None of the six PRs declares a prerequisite, and none of them needs
another master PR for its behavior. The only master commits that touch
the same files and are not on this branch are unrelated to incremental
computation (#66761 TIMESTAMP_NS, #67545 DLF, #67569 / #67520 / #67835
MySQL-protocol and session refactors, #67186 Hive partition batching,
#67787 SQL cache user variables); they were left out, and two picks
needed a mechanical adaptation because of that:

- **#67753** conflicted in `StmtExecutor.sendMetaData`: master had
already extracted the post-metadata EOF into
`sendMetadataTerminatorIfNeeded(channel)` (#67520, a Connector/J
cursor-fetch fix). The branch keeps its inline EOF block and now sends
it on the given `channel` instead of `context.getMysqlChannel()`, which
is exactly what the extracted helper does on master. Everything else in
the pick is identical to the master commit.
- **#67814** applied cleanly but did not compile: the new
`MTMVPartitionUtil.generateRelatedBasePartitionIds()` returns an
`Optional`, and on master `import java.util.Optional;` came with #67186.
The import was added to the pick commit; that is the only difference
from the master commit.

The other four picks applied without conflicts and are byte-identical to
their master commits (diffs compared with `index`/`@@` lines stripped).
Both adaptations are recorded in the respective commit messages.

### Drift check against master

After the six picks, every touched file is byte-identical to master at
`3390a7a721f` except `MTMV.java`, `MTMVTask.java`,
`MTMVPartitionUtil.java`, `MTMVPartitionUtilTest.java`,
`MTMVTaskTest.java` (differences = #67186 + #67545 + #66761),
`CreateTableInfo.java` (= #67787) and `StmtExecutor.java` (= #67520 +
#67569 + #66761 + the later session refactors #67835 / #67883 + this
branch's #67861). For the first six files, applying those unrelated
master commits on top of the branch's versions reproduces master's files
exactly; for `StmtExecutor.java`, the diff against master right after
#67753 (`fe39f5b6a42`) consists only of #67520 / #67569 / #66761 /
#67861 hunks. So nothing IVM-related is missing. The regression
framework, plugins and the whole `mtmv_p0/ivm` suite/data directories
are identical to master.

### Verification

- FE: `run-fe-ut.sh --run` on this branch (regenerates thrift, compiles
fe-core main + test) with the 17 test classes touched by the picks or
extending the touched `IvmDeltaTestBase`:
17 classes, 404 tests, 0 failures, 0 errors, BUILD SUCCESS (5:19 min) —
`MTMVPlanUtilTest` 24, `IvmAggDeltaHandlerTest` 33,
`IvmDeltaRewriteHelperTest` 17, `IvmNormalizeMTMVJoinTest` 44,
`IvmJoinDeltaHandlerTest` 23, `IvmDeltaRewriteStateTest` 10,
`IvmPlanSignatureGeneratorTest` 22, `IvmBaselineRebuildTest` 28,
`IvmLinearDeltaHandlerTest` 39, `IvmDeltaRewriterTest` 23,
`IvmNormalizeMTMVUnionTest` 10, `MTMVTaskTest` 50,
`MTMVPropertyUtilTest` 13, `MTMVPartitionUtilTest` 16,
`SchemaChangeHandlerTest` 22, `StmtExecutorInternalQueryTest` 3,
`StmtExecutorTest` 27.
- FE checkstyle on fe-core: 0 violations.
- No BE, cloud or thrift changes in this batch.
- All 18 touched groovy files (framework `Suite.groovy`,
`plugin_planner.groovy`, 16 suites) parse cleanly (groovy parser check).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: yujun <yujun@selectdb.com>
yiguolei pushed a commit that referenced this pull request Sep 17, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by one committer. dev/4.0.x dev/4.1.5-merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants