Skip to content

Commit 3b6ab60

Browse files
authored
Merge pull request #158 from clue-labs/resultset-err
Fix parsing ERR after result set
2 parents 7b4428d + 7ce30f4 commit 3b6ab60

File tree

2 files changed

+75
-4
lines changed

2 files changed

+75
-4
lines changed

src/Io/Parser.php

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public function parse($data)
127127

128128
$len = $this->buffer->length();
129129
if ($len < $this->pctSize) {
130-
$this->debug('Buffer not enouth, return');
130+
$this->debug('Waiting for complete packet with ' . $len . '/' . $this->pctSize . ' bytes');
131131

132132
return;
133133
}
@@ -277,6 +277,9 @@ private function onResultRow($row)
277277

278278
private function onError(Exception $error)
279279
{
280+
$this->rsState = self::RS_STATE_HEADER;
281+
$this->resultFields = [];
282+
280283
// reject current command with error if we're currently executing any commands
281284
// ignore unsolicited server error in case we're not executing any commands (connection will be dropped)
282285
if ($this->currCommand !== null) {

tests/Io/ParserTest.php

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,12 @@
33
namespace React\Tests\MySQL\Io;
44

55
use React\MySQL\Commands\QueryCommand;
6+
use React\MySQL\Exception;
67
use React\MySQL\Io\Executor;
78
use React\MySQL\Io\Parser;
9+
use React\Stream\CompositeStream;
810
use React\Stream\ThroughStream;
911
use React\Tests\MySQL\BaseTestCase;
10-
use React\MySQL\Exception;
1112

1213
class ParserTest extends BaseTestCase
1314
{
@@ -56,7 +57,7 @@ public function testUnexpectedErrorWithoutCurrentCommandWillBeIgnored()
5657
$stream->write("\x17\0\0\0" . "\xFF" . "\x10\x04" . "Too many connections");
5758
}
5859

59-
public function testSendingErrorFrameDuringHandshakeShouldEmitErrorOnFollowingCommand()
60+
public function testReceivingErrorFrameDuringHandshakeShouldEmitErrorOnFollowingCommand()
6061
{
6162
$stream = new ThroughStream();
6263

@@ -81,7 +82,74 @@ public function testSendingErrorFrameDuringHandshakeShouldEmitErrorOnFollowingCo
8182
$this->assertEquals('Too many connections', $error->getMessage());
8283
}
8384

84-
public function testSendingIncompleteErrorFrameDuringHandshakeShouldNotEmitError()
85+
public function testReceivingErrorFrameForQueryShouldEmitError()
86+
{
87+
$stream = new ThroughStream();
88+
89+
$command = new QueryCommand();
90+
$command->on('error', $this->expectCallableOnce());
91+
92+
$error = null;
93+
$command->on('error', function ($e) use (&$error) {
94+
$error = $e;
95+
});
96+
97+
$executor = new Executor();
98+
$executor->enqueue($command);
99+
100+
$parser = new Parser($stream, $executor);
101+
$parser->start();
102+
103+
$stream->on('close', $this->expectCallableNever());
104+
105+
$stream->write("\x33\0\0\0" . "\x0a" . "mysql\0" . str_repeat("\0", 44));
106+
$stream->write("\x1E\0\0\1" . "\xFF" . "\x46\x04" . "#abcde" . "Unknown thread id: 42");
107+
108+
$this->assertTrue($error instanceof Exception);
109+
$this->assertEquals(1094, $error->getCode());
110+
$this->assertEquals('Unknown thread id: 42', $error->getMessage());
111+
}
112+
113+
public function testReceivingErrorFrameForQueryAfterResultSetHeadersShouldEmitError()
114+
{
115+
$stream = new ThroughStream();
116+
117+
$command = new QueryCommand();
118+
$command->on('error', $this->expectCallableOnce());
119+
120+
$error = null;
121+
$command->on('error', function ($e) use (&$error) {
122+
$error = $e;
123+
});
124+
125+
$executor = new Executor();
126+
$executor->enqueue($command);
127+
128+
$parser = new Parser(new CompositeStream($stream, new ThroughStream()), $executor);
129+
$parser->start();
130+
131+
$stream->on('close', $this->expectCallableNever());
132+
133+
$stream->write("\x33\0\0\0" . "\x0a" . "mysql\0" . str_repeat("\0", 44));
134+
$stream->write("\x01\0\0\1" . "\x01");
135+
$stream->write("\x1E\0\0\2" . "\x03" . "def" . "\0" . "\0" . "\0" . "\x09" . "sleep(10)" . "\0" . "\xC0" . "\x3F\0" . "\1\0\0\0" . "\3" . "\x81\0". "\0" . "\0\0");
136+
$stream->write("\x05\0\0\3" . "\xFE" . "\0\0\2\0");
137+
$stream->write("\x28\0\0\4" . "\xFF" . "\x25\x05" . "#abcde" . "Query execution was interrupted");
138+
139+
$this->assertTrue($error instanceof Exception);
140+
$this->assertEquals(1317, $error->getCode());
141+
$this->assertEquals('Query execution was interrupted', $error->getMessage());
142+
143+
$ref = new \ReflectionProperty($parser, 'rsState');
144+
$ref->setAccessible(true);
145+
$this->assertEquals(0, $ref->getValue($parser));
146+
147+
$ref = new \ReflectionProperty($parser, 'resultFields');
148+
$ref->setAccessible(true);
149+
$this->assertEquals([], $ref->getValue($parser));
150+
}
151+
152+
public function testReceivingIncompleteErrorFrameDuringHandshakeShouldNotEmitError()
85153
{
86154
$stream = new ThroughStream();
87155

0 commit comments

Comments
 (0)