@@ -218,6 +218,90 @@ public function sendRequest(RequestInterface $request): ResponseInterface
218218 $ client ->executeQuery ('OPTIMIZE TABLE events ' );
219219 }
220220
221+ public function testExecuteQueryClosesNonOkResponseBody (): void
222+ {
223+ $ psr17Factory = new Psr17Factory ();
224+
225+ $ body = $ this ->createMock (StreamInterface::class);
226+ $ body ->expects (self ::once ())
227+ ->method ('__toString ' )
228+ ->willReturn ('Code: 60. DB::Exception: Table events does not exist. (UNKNOWN_TABLE) ' );
229+ $ body ->expects (self ::once ())
230+ ->method ('close ' );
231+
232+ $ response = $ psr17Factory ->createResponse (404 )
233+ ->withBody ($ body );
234+
235+ $ httpClient = new class ($ response ) implements ClientInterface {
236+ public function __construct (private ResponseInterface $ response )
237+ {
238+ }
239+
240+ public function sendRequest (RequestInterface $ request ): ResponseInterface
241+ {
242+ return $ this ->response ;
243+ }
244+ };
245+
246+ $ client = new PsrClickHouseClient (
247+ $ httpClient ,
248+ new RequestFactory (
249+ new ParamValueConverterRegistry (),
250+ $ psr17Factory ,
251+ $ psr17Factory ,
252+ $ psr17Factory ,
253+ ),
254+ );
255+
256+ $ this ->expectException (ServerError::class);
257+
258+ $ client ->executeQuery ('OPTIMIZE TABLE events ' );
259+ }
260+
261+ public function testSelectClosesResponseBodyWhenOkResponseContainsStreamedException (): void
262+ {
263+ $ psr17Factory = new Psr17Factory ();
264+
265+ $ body = $ this ->createMock (StreamInterface::class);
266+ $ body ->expects (self ::once ())
267+ ->method ('isSeekable ' )
268+ ->willReturn (true );
269+ $ body ->expects (self ::once ())
270+ ->method ('__toString ' )
271+ ->willReturn (self ::streamedExceptionBody ());
272+ $ body ->expects (self ::once ())
273+ ->method ('close ' );
274+
275+ $ response = $ psr17Factory ->createResponse (200 )
276+ ->withHeader ('X-ClickHouse-Exception-Tag ' , 'abcdefghijklmnop ' )
277+ ->withBody ($ body );
278+
279+ $ httpClient = new class ($ response ) implements ClientInterface {
280+ public function __construct (private ResponseInterface $ response )
281+ {
282+ }
283+
284+ public function sendRequest (RequestInterface $ request ): ResponseInterface
285+ {
286+ return $ this ->response ;
287+ }
288+ };
289+
290+ $ client = new PsrClickHouseClient (
291+ $ httpClient ,
292+ new RequestFactory (
293+ new ParamValueConverterRegistry (),
294+ $ psr17Factory ,
295+ $ psr17Factory ,
296+ $ psr17Factory ,
297+ ),
298+ );
299+
300+ $ this ->expectException (ServerError::class);
301+
302+ $ client ->select ('SELECT throwIf(number = 2) FROM numbers(5) ' , new TabSeparated ());
303+ }
304+
221305 public function testSelectThrowsWhenStreamedExceptionInspectionWouldConsumeNonSeekableBody (): void
222306 {
223307 $ psr17Factory = new Psr17Factory ();
0 commit comments