@@ -899,6 +899,54 @@ def test_get_execution_result_owning_handle_failure_can_retry_owning_handle():
899899 c ._kernel_session .attach_async_statement .assert_not_called ()
900900
901901
902+ def test_get_execution_result_construction_failure_retains_marker_and_attaches_by_id ():
903+ """If the owning handle's ``await_result()`` succeeds but result-set
904+ construction then raises, the ``_async_result_stream_started`` marker
905+ is deliberately left set (the owning stream may be partially
906+ consumed, so re-awaiting it is unsafe). A subsequent call must route
907+ through the attach-by-id fallback rather than re-awaiting the owning
908+ handle."""
909+ c = _make_client ()
910+ c ._kernel_session = MagicMock ()
911+ owning_stream = MagicMock ()
912+ # ``KernelResultSet.__init__`` calls ``arrow_schema()``; make that
913+ # raise so ``_make_result_set`` fails after a successful await.
914+ owning_stream .arrow_schema .side_effect = _FakeKernelError (code = "Internal" )
915+ owning_handle = MagicMock ()
916+ owning_handle .await_result .return_value = owning_stream
917+ cid = CommandId .from_sea_statement_id ("async-construct-fail" )
918+ c ._async_handles [cid .guid ] = owning_handle
919+
920+ with pytest .raises (DatabaseError ):
921+ c .get_execution_result (cid , cursor = MagicMock ())
922+
923+ # Marker stays set even though construction failed.
924+ assert cid .guid in c ._async_result_stream_started
925+ owning_handle .await_result .assert_called_once_with ()
926+ c ._kernel_session .attach_async_statement .assert_not_called ()
927+
928+ # A retry now attaches by id (fresh stream) instead of re-awaiting
929+ # the partially-consumed owning handle.
930+ retry_stream = MagicMock ()
931+ retry_stream .arrow_schema .return_value = pa .schema ([("n" , pa .int64 ())])
932+ attached_handle = MagicMock ()
933+ attached_handle .await_result .return_value = retry_stream
934+ c ._kernel_session .attach_async_statement .return_value = attached_handle
935+ cursor = MagicMock ()
936+ cursor .arraysize = 100
937+ cursor .buffer_size_bytes = 1024
938+
939+ rs = c .get_execution_result (cid , cursor = cursor )
940+
941+ assert rs is not None
942+ c ._kernel_session .attach_async_statement .assert_called_once_with (
943+ "async-construct-fail"
944+ )
945+ attached_handle .await_result .assert_called_once_with ()
946+ # The owning handle was not re-awaited on the retry.
947+ owning_handle .await_result .assert_called_once_with ()
948+
949+
902950def test_get_execution_result_maps_not_found_to_programming_error ():
903951 """An unknown / aged-out id surfaces the kernel's NotFound as a
904952 mapped PEP 249 exception rather than a raw error."""
0 commit comments