Skip to content

[fix](sqlcache) Do not replay the MySQL sql cache on an Arrow Flight connection - #67381

Merged
morningman merged 1 commit into
apache:masterfrom
morningman:wt-adbc-67364
Sep 2, 2026
Merged

[fix](sqlcache) Do not replay the MySQL sql cache on an Arrow Flight connection#67381
morningman merged 1 commit into
apache:masterfrom
morningman:wt-adbc-67364

Conversation

@morningman

Copy link
Copy Markdown
Contributor

What problem does this PR solve?

Issue Number: close#67364

Related PR: #65182, #65615

Problem Summary:

Reading anything over Arrow Flight SQL fails with INTERNAL / IllegalStateException as soon as the query hits the FE sql cache.

The FE sql cache is keyed by <catalog>.<db>:<user>:<sql text> (NereidsSqlCacheManager.generateCacheKey) and is shared by every protocol, but its rows are MySQL wire protocol packets that StmtExecutor.sendCachedValues replays through a MysqlChannel. An Arrow Flight SQL connection has no channel, so an entry created by an identical MySQL query makes handleQueryStmt take the cached-plan branch and fail Preconditions.checkState(connectType == MYSQL) in sendFields(). The client sees:

INTERNAL: get flight info statement failed, after executeQueryStatement handleQuery,
error code: ERR_UNKNOWN_ERROR, error msg: IllegalStateException, msg: null

The CacheAnalyzer branch right below it is already gated on channel != null with a // TODO support arrow flight sql; only this cached-plan replay was left unguarded.

This is not about HLL / QUANTILE_STATE. The issue was reported on raw aggregate-state columns, but both the FE schema helper and the BE map HLL / BITMAP / QUANTILE_STATE to Arrow binary and have Arrow writers for them, and they read back correctly once the query is actually executed. They only looked special because that sql text was the one primed through the MySQL control session; select 1 fails exactly the same way.

Two conditions have to line up, which is why this is not seen more often:

  1. The same sql text must have been run on a MySQL connection first (an Arrow Flight connection never populates the cache).
  2. Both sessions must agree on every session variable the cache compares (NereidsSqlCacheManager.usedVariablesChanged over the affectQueryResult* set). The MySQL JDBC driver adds STRICT_TRANS_TABLES to sql_mode at connect time while the Arrow Flight JDBC driver does not, so a JDBC control session masks the bug -- a mysql CLI session, or any client that leaves sql_mode alone, does not.

What is changed

  • ConnectProcessor.executeQuery: look the sql cache up only for a MySQL connection. Any other protocol re-executes the query and gets its result from the BE. Such a connection never populates the cache either, so this only removes a broken read path; it does not change MySQL behaviour.
  • StmtExecutor.handleQueryStmt: assert the channel in the cached-plan branch, so a future regression names the protocol instead of throwing a bare IllegalStateException.
  • SessionVariable: mark return_object_data_as_binary as affectQueryResultInExecution. It is forwarded to the BE and decides whether the MySQL result writer serializes HLL / BITMAP / QUANTILE_STATE as their raw bytes or as NULL, so it changes the cached rows and must take part in the cache key comparison. Without it, a session that turns it on is served the NULLs cached by a session that had it off -- a separate, pure-MySQL-protocol correctness bug in the same family.

Release note

Fix an IllegalStateException when an Arrow Flight SQL query hits the FE sql cache, and fix return_object_data_as_binary not being part of the sql cache key.

Check List (For Author)

  • Test

    • Regression test

    regression-test/suites/arrow_flight_sql_p0/test_sql_cache_over_arrow_flight.groovy primes the cache on a MySQL connection and reads the identical statement back over Arrow Flight, for a FE-cached constant result, a table scalar, the raw HLL / QUANTILE_STATE columns from the issue, and their hll_cardinality / quantile_percent conversions.

    regression-test/suites/query_p0/cache/sql_cache_object_type.groovy covers the return_object_data_as_binary cache key.

    Both were verified to actually catch their bug: reverted individually against a live single-FE/single-BE cluster, test_sql_cache_over_arrow_flight fails with the exact reported IllegalStateException and sql_cache_object_type fails on return_object_data_as_binary=true must not reuse the entry cached with it off. Note for anyone extending these: Suite.arrow_flight_sql() prepends USE <db>; to the statement, which changes the sql text and therefore the cache key, so the flight statements are sent on the raw flight connection, and both sessions align sql_mode explicitly.

    • Unit Test
    • Manual test (add detailed scripts or steps below)
    • No need to test or manual test. Explain why:
  • Behavior changed:

    • Yes. An Arrow Flight SQL connection no longer reads the FE sql cache (it never wrote to it), so such a query is always executed instead of failing. A session whose return_object_data_as_binary differs from the one that populated the cache now gets its own entry instead of the other session's rows.
  • Does this need documentation?

    • No.

… connection
The FE sql cache is keyed by "<catalog>.<db>:<user>:<sql text>" and is
shared by every protocol, but its rows are MySQL wire protocol packets
that StmtExecutor.sendCachedValues replays through a MysqlChannel. An
Arrow Flight SQL connection has no channel, so a cache entry created by
an identical MySQL query made handleQueryStmt take the cached-plan
branch and fail Preconditions.checkState(connectType == MYSQL) in
sendFields(), reaching the client as
"INTERNAL ... IllegalStateException, msg: null" for any result type.
The report was on raw HLL / QUANTILE_STATE columns, but those types are
not the cause: both the FE schema helper and the BE map them to Arrow
binary and have Arrow writers, and they read back fine once the query is
actually executed. They only looked special because that sql text was
the one primed through the MySQL control session.
Look the sql cache up only for a MySQL connection, so any other protocol
re-executes the query and gets its result from the BE. Such a connection
never populates the cache either, so this only removes a broken read
path. Also assert the channel in the cached-plan branch so a future
regression names the protocol instead of throwing a bare
IllegalStateException.
While here, mark return_object_data_as_binary as
affectQueryResultInExecution. It is forwarded to the BE and decides
whether the MySQL result writer serializes HLL / BITMAP /
QUANTILE_STATE as their raw bytes or as NULL, so it changes the cached
rows and must take part in the cache key comparison; without it a
session that turns it on is served the NULLs cached by a session that
had it off.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LPwhYhsSio1HYk2kFnx7KY
@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?

@morningman

Copy link
Copy Markdown
ContributorAuthor

run buildall

1 similar comment
@morningman

Copy link
Copy Markdown
ContributorAuthor

run buildall

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-H: Total hot run time: 16737 ms
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/tpch-tools
Tpch sf100 test result on commit 25258580535aececd5b96f35b2a947b1478491d3, data reload: false
------ Round 1 ----------------------------------
============================================
q1	17600	3011	2999	2999
q2	2141	263	239	239
q3	10180	868	513	513
q4	4669	246	195	195
q5	7686	553	374	374
q6	137	115	97	97
q7	518	510	384	384
q8	9242	926	1021	926
q9	3460	2389	2366	2366
q10	6506	857	705	705
q11	402	194	177	177
q12	611	265	199	199
q13	18119	1544	1166	1166
q14	157	146	139	139
q15	q16	446	398	362	362
q17	1365	919	826	826
q18	3056	2251	2261	2251
q19	1284	924	809	809
q20	377	280	201	201
q21	5590	1582	1839	1582
q22	327	264	227	227
Total cold run time: 93873 ms
Total hot run time: 16737 ms
----- Round 2, with runtime_filter_mode=off -----
============================================
q1	3396	3312	3298	3298
q2	497	404	354	354
q3	2192	2333	2355	2333
q4	1204	1189	897	897
q5	2185	2153	2147	2147
q6	168	119	86	86
q7	1059	1028	869	869
q8	1604	1419	1416	1416
q9	3161	3120	3065	3065
q10	1885	1798	1627	1627
q11	358	268	246	246
q12	445	438	344	344
q13	1445	1513	1178	1178
q14	173	179	177	177
q15	q16	395	404	357	357
q17	3586	3353	3235	3235
q18	4795	4404	4680	4404
q19	857	939	864	864
q20	1010	950	822	822
q21	3770	3120	3187	3120
q22	393	345	322	322
Total cold run time: 34578 ms
Total hot run time: 31161 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
TPC-DS: Total hot run time: 81625 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 25258580535aececd5b96f35b2a947b1478491d3, data reload: false
query5	4270	408	328	328
query6	411	138	126	126
query7	4955	425	221	221
query8	292	122	112	112
query9	8686	2842	2860	2842
query10	378	215	178	178
query11	5372	1034	912	912
query12	123	71	71	71
query13	1226	453	333	333
query14	6079	2184	2066	2066
query14_1	1966	1952	1951	1951
query15	171	119	112	112
query16	917	367	357	357
query17	800	462	366	366
query18	2349	350	243	243
query19	167	148	114	114
query20	95	70	70	70
query21	204	101	87	87
query22	5362	5426	5278	5278
query23	6768	6262	5846	5846
query23_1	6068	6146	6150	6146
query24	7302	1094	770	770
query24_1	777	776	775	775
query25	432	308	266	266
query26	1236	243	132	132
query27	2776	422	242	242
query28	4701	1463	1504	1463
query29	941	455	356	356
query30	261	154	134	134
query31	820	404	339	339
query32	127	75	77	75
query33	464	227	182	182
query34	996	813	479	479
query35	396	391	345	345
query36	590	571	542	542
query37	126	78	74	74
query38	1017	845	823	823
query39	539	484	485	484
query39_1	488	454	450	450
query40	206	92	79	79
query41	58	57	55	55
query42	74	71	74	71
query43	236	240	209	209
query44	1020	550	575	550
query45	109	105	97	97
query46	769	869	535	535
query47	762	751	709	709
query48	305	293	229	229
query49	533	234	185	185
query50	730	266	189	189
query51	7977	7945	8021	7945
query52	66	65	64	64
query53	191	204	146	146
query54	235	183	176	176
query55	79	59	56	56
query56	194	176	167	167
query57	660	742	613	613
query58	221	161	152	152
query59	1238	1197	1098	1098
query60	232	176	161	161
query61	116	124	119	119
query62	373	212	195	195
query63	173	147	146	146
query64	2834	727	634	634
query65	1643	1552	1570	1552
query66	1899	261	209	209
query67	9990	9725	9678	9678
query68	2998	1186	725	725
query69	347	211	195	195
query70	673	633	614	614
query71	255	167	184	167
query72	2320	1715	1576	1576
query73	668	633	333	333
query74	2006	1243	1126	1126
query75	1179	1079	959	959
query76	2384	732	548	548
query77	258	256	206	206
query78	4100	3632	3211	3211
query79	2730	817	581	581
query80	1590	325	283	283
query81	518	151	131	131
query82	645	123	98	98
query83	277	209	188	188
query84	297	102	92	92
query85	808	344	297	297
query86	481	177	167	167
query87	1013	978	863	863
query88	2958	2101	2112	2101
query89	276	196	173	173
query90	2129	128	126	126
query91	129	123	98	98
query92	99	73	70	70
query93	1904	1156	673	673
query94	758	277	240	240
query95	538	319	234	234
query96	854	564	261	261
query97	1037	1044	995	995
query98	177	133	126	126
query99	430	341	303	303
Total cold run time: 179846 ms
Total hot run time: 81625 ms

@hello-stephen

Copy link
Copy Markdown
Contributor
ClickBench: Total hot run time: 14.58 s
machine: 'aliyun_ecs.c7a.8xlarge_32C64G'
scripts: https://github.com/apache/doris/tree/master/tools/clickbench-tools
ClickBench test result on commit 25258580535aececd5b96f35b2a947b1478491d3, data reload: false
query1	0.00	0.00	0.00
query2	0.08	0.04	0.04
query3	0.25	0.10	0.10
query4	1.61	0.10	0.10
query5	0.18	0.17	0.15
query6	1.24	0.67	0.68
query7	0.03	0.01	0.00
query8	0.05	0.03	0.03
query9	0.28	0.23	0.21
query10	0.36	0.35	0.35
query11	0.16	0.11	0.12
query12	0.15	0.13	0.12
query13	0.30	0.30	0.31
query14	0.44	0.45	0.45
query15	0.36	0.37	0.35
query16	0.21	0.22	0.24
query17	0.67	0.67	0.72
query18	0.18	0.16	0.17
query19	1.11	1.12	1.16
query20	0.01	0.01	0.01
query21	15.46	0.15	0.11
query22	5.09	0.04	0.04
query23	16.16	0.26	0.10
query24	3.01	0.30	0.29
query25	0.11	0.04	0.04
query26	0.81	0.17	0.12
query27	0.03	0.03	0.02
query28	3.67	0.54	0.26
query29	12.45	3.17	2.54
query30	0.26	0.11	0.13
query31	2.77	0.36	0.17
query32	3.54	0.31	0.23
query33	1.42	1.40	1.59
query34	15.37	2.16	1.75
query35	1.74	1.74	1.72
query36	0.47	0.29	0.28
query37	0.06	0.04	0.04
query38	0.04	0.03	0.03
query39	0.03	0.02	0.02
query40	0.12	0.08	0.08
query41	0.07	0.02	0.03
query42	0.03	0.03	0.02
query43	0.03	0.03	0.03
Total cold run time: 90.41 s
Total hot run time: 14.58 s

@morningman

Copy link
Copy Markdown
ContributorAuthor

run external_p0

@morningmanmorningman changed the title [fix](sql-cache) Do not replay the MySQL sql cache on an Arrow Flight connection[fix](sqlcache) Do not replay the MySQL sql cache on an Arrow Flight connectionSep 2, 2026
@morningman

Copy link
Copy Markdown
ContributorAuthor

run external

@morningmanmorningman reopened this Sep 2, 2026
@morningman

Copy link
Copy Markdown
ContributorAuthor

run external

@morningman
morningman merged commit 1250443 into apache:masterSep 2, 2026
51 of 54 checks passed
@hello-stephen

Copy link
Copy Markdown
Contributor

FE Regression Coverage Report

Increment line coverage 2.23% (4/179) 🎉
Increment coverage report
Complete coverage report

morningman added a commit that referenced this pull request Sep 4, 2026
…rrow Flight connection (#67487)
### What problem does this PR solve?
Issue Number: close#67368
Related PR: #67381 (sibling fix in the same tracking series), #62259
Problem Summary:
A `UNIQUE KEY` point query that qualifies for the short-circuit path
returned no Flight endpoint over Arrow Flight SQL. The client failed
with
```
fetch arrow flight schema failed, no FlightSqlEndpointsLocations
```
and the row was silently dropped. The identical query with
`SET_VAR(enable_short_circuit_query=false)` returned it on the same
connection.
**Root cause** — the short circuit produces no Arrow result at either
end, and nothing prevented an Arrow Flight connection from planning one:
* It executes on `PointQueryExecutor`, not a `Coordinator`, and
`Coordinator`/`NereidsCoordinator` are the only places that register a
`FlightSqlEndpointsLocation`. `StmtExecutor.executeAndSendResult` then
returns early through its Arrow Flight branch with nothing registered
and without ever calling `getNext()`, so `GetFlightInfo` found an empty
endpoint list.
* The BE cannot be pointed at either. `tablet_fetch_data` serializes
with `VMysqlResultWriter` into `PTabletKeyLookupResponse.row_batch` and
runs no fragment, so the `ArrowFlightResultBlockBuffer` that
`fetch_arrow_flight_schema` looks up by finst id never exists.
`LogicalResultSinkToShortCircuitPointQuery` did not look at the connect
type, and `enable_short_circuit_query` defaults to `true`, so every ADBC
/ Arrow Flight JDBC point query on a MoW + light-schema-change +
`store_row_column` table hit this. Prepared statements go through the
same `executeQueryStatement` and failed identically.
**Fix** — keep Arrow Flight SQL on the normal execution path.
This has to be decided at plan time rather than when picking the
executor: `OlapScanNode.computeTabletInfo` and several rewrite/property
rules (`ChildOutputPropertyDeriver`, `ShuffleKeyPruner`,
`NestedColumnPruning`, `PruneOlapScanPartition`) read
`StatementContext.isShortCircuitQuery()` while the plan is being built,
so flipping the flag later would run a coordinator over a plan shaped
for a different execution mode. MySQL connections keep the short circuit
unchanged.
Returning the point-query result from the FE instead was considered and
rejected for now: `FlightSqlChannel.addResult` builds varchar vectors
only, so every column would come back as `Utf8`, inconsistent with the
normal Flight path. Full support (Arrow serialization in the BE lookup
RPC plus a result buffer to hand out an endpoint) is a larger change and
out of scope here.
Also refreshes a now-stale comment in `StmtExecutor` that said point
queries reach the Arrow Flight deferral gate.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] Arrow Flight SQL: reading raw HLL / QUANTILE_STATE columns fails with INTERNAL (IllegalStateException)

3 participants

@morningman@hello-stephen@924060929