morningman commented on code in PR #69867:
URL: https://github.com/apache/doris/pull/69867#discussion_r4432228191


##########
fe/fe-core/src/main/java/org/apache/doris/arrowflight/DorisFlightSqlProducer.java:
##########
@@ -368,19 +392,126 @@ public FlightInfo getFlightInfoStatement(final 
CommandStatementQuery request, fi
     @Override
     public FlightInfo getFlightInfoPreparedStatement(final 
CommandPreparedStatementQuery command,
             final CallContext context, final FlightDescriptor descriptor) {
-        String[] handleParts = 
command.getPreparedStatementHandle().toStringUtf8().split(":");
-        String executedPeerIdentity = handleParts[0];
-        String preparedStatementId = handleParts[1];
-        ConnectContext connectContext = 
flightSessionsManager.getConnectContext(executedPeerIdentity);
+        String preparedStatementId = preparedStatementId(context, 
command.getPreparedStatementHandle());
+        ConnectContext connectContext = 
flightSessionsManager.getConnectContext(context.peerIdentity());
         return 
FlightProtocolAdapter.of(connectContext).callCommand(connectContext,
-                () -> executeQueryStatement(executedPeerIdentity, 
connectContext,
-                        connectContext.getPreparedQuery(preparedStatementId), 
descriptor));
+                () -> executePreparedStatement(context.peerIdentity(), 
connectContext, preparedStatementId,

Review Comment:
   Fixed in be929ac2e82. Confirmed: `executePreparedStatement` ran 
`preparedQuery()` and `checkPreparedSchema()` before `executeQueryStatement()` 
reached `FlightProtocolAdapter.beginRequest()`, and 
`getFlightInfoPreparedStatement` has no catch of its own. A handle refused 
there (missing, prepared in another namespace, a changed schema, a failed 
re-analysis) therefore left the previous request's deferred coordinator, its 
frontend-side result and its endpoints in place. Without this PR, every 
prepared GetFlightInfo reached `executeQueryStatement()`; even a missing handle 
failed inside its try, and the catch cancelled and finalized the previous 
request's deferred coordinator.
   
   `executePreparedStatement` now calls `beginRequest()` before the checks. A 
prepared GetFlightInfo is the session's next request whatever the checks find, 
and the call in `executeQueryStatement()` then finds nothing left. The call is 
not in the command lock (`runCommand` / `callCommand`) or in `preparedQuery()`: 
Prepare, GetSchema and the other metadata requests go through those too, and 
they must leave the previous request alone (`FlightProtocolAdapter`'s class 
comment, `FlightSessionOptionsTest#testTheOptionsLeaveTheLastRequestAlone`).
   
   Two parts of the description go further than what happens:
   - The state is not kept until the idle timeout whatever comes next. The 
session's next statement, or its next prepared execution that passes the 
checks, drops it, and so does session teardown. Only when neither arrives does 
the timeout checker finalize the deferred coordinator, and its bound is 
`arrow_flight_deferred_query_idle_timeout_second` (3600 s) or the query's own 
execution timeout, whichever is longer, counted from that query's start, not 
`wait_timeout`.
   - Only a query whose coordinator must outlive GetFlightInfo, a batch-mode 
external-table scan or a remote Doris scan (`coord.mustOutliveDispatch()`), 
leaves a deferred coordinator; every other query closes its coordinator before 
GetFlightInfo returns. As for the `sql_mode` example: `SET sql_mode = ...` is 
itself a GetFlightInfo, which already dropped the previous query's coordinator 
and leaves only its own OK result. For a schema change to leave a coordinator 
behind, it has to come from outside the session's requests, such as 
SetSessionOptions or another session's DDL or REVOKE.
   
   The same commit expires a checked handle whose statement can no longer be 
described when it is re-analyzed, for example after a column grant was revoked 
so that the analyzed plan is denied, or after a DDL that turned a result column 
into an untyped NULL. Such a handle answered UNIMPLEMENTED and was kept, so 
every later execution failed the same way. The check now compares the schema 
Prepare would advertise now, which for such a statement is the placeholder: the 
handle is removed, the request answers NOT_FOUND "Prepared statement schema 
changed; prepare again", and the statement prepared again keeps the placeholder 
and runs unchecked.
   
   Tests: `DorisFlightSqlSchemaTest` adds one test for each way the checks 
refuse a handle: a missing handle, a namespace change, a sql_mode drift, a 
dropped view (INVALID_ARGUMENT, the handle is kept) and a revoked column grant 
(NOT_FOUND, the handle is removed, and preparing again gives the placeholder). 
Each sends GetSchema and GetFlightInfo after a previous request left a deferred 
executor, a frontend-side result and an endpoint, and checks the status, 
whether the handle is kept, and that GetFlightInfo finalized and dropped all 
three while GetSchema left them. Without the new `beginRequest()` call, the 
five tests fail at GetFlightInfo; with the call in `preparedQuery()` instead, 
they fail at GetSchema; with the previous UNIMPLEMENTED for a re-analysis that 
cannot describe the result, only the revoked-grant test fails. branch-4.1 and 
branch-4.2 check the handle in the same order.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to