Skip to content

Commit 3fd27ac

Browse files
committed
preliminary support for MySQL DELIMITER commands
1 parent 7575f33 commit 3fd27ac

2 files changed

Lines changed: 64 additions & 9 deletions

File tree

src/SQLTokenizer.php

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,11 @@ class SQLTokenizer
1616
*/
1717
protected $input;
1818

19+
/**
20+
* @var string
21+
*/
22+
protected $delimiter_pattern = ";";
23+
1924
/**
2025
* @param string $input
2126
*
@@ -60,18 +65,36 @@ protected function statement()
6065

6166
$tokens = [];
6267

63-
while ($token = $this->token()) {
68+
while ("" !== $token = $this->token()) {
69+
if (is_string($token) && preg_match('/^delimiter$/i', $token) === 1) {
70+
$this->consume('[ ]*');
71+
72+
$delimiter = trim($this->consume('.*?[\r\n]+'));
73+
74+
if ($delimiter === "") {
75+
$this->fail("expected delimiter character(s)");
76+
}
77+
78+
$this->delimiter_pattern = preg_quote($delimiter);
79+
80+
continue; // omits DELIMITER command - it isn't part of SQL statement syntax
81+
}
82+
6483
$tokens[] = $token;
6584
}
6685

6786
return $tokens;
6887
}
6988

7089
/**
71-
* @return string|array
90+
* @return array|string
7291
*/
7392
protected function token()
7493
{
94+
if ($this->consume($this->delimiter_pattern)) {
95+
return ""; // end of statement
96+
}
97+
7598
if ("" !== $token = $this->consume('\w+')) {
7699
return $token;
77100
}
@@ -84,7 +107,11 @@ protected function token()
84107
return $token;
85108
}
86109

87-
if ($token = $this->consume('[\*,.+-\/=]')) {
110+
if ($token = $this->consume('[\*,.+-\/=;<>]')) {
111+
return $token;
112+
}
113+
114+
if ($token = $this->consume('\@\w+')) {
88115
return $token;
89116
}
90117

@@ -108,10 +135,6 @@ protected function token()
108135
return ""; // end of file/statement
109136
}
110137

111-
if ($this->consume(";")) {
112-
return ""; // end of statement
113-
}
114-
115138
$this->fail("expected SQL token");
116139
}
117140

@@ -181,7 +204,7 @@ protected function grouped()
181204
if ($this->is($closing)) {
182205
$tokens[] = $closing;
183206

184-
$this->offset +=1 ;
207+
$this->offset +=1;
185208

186209
return $tokens;
187210
}

test/test.php

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ function () {
203203
EXECUTE PROCEDURE "blocks".delete_orphaned_blocks();
204204
SQL;
205205

206-
test("complex real-world use-case", function () use ($sql_template) {
206+
test("postgres use-case", function () use ($sql_template) {
207207
$expected_statements = array_map(
208208
function (string $sql) {
209209
return rtrim(trim($sql), ";");
@@ -218,4 +218,36 @@ function (string $sql) {
218218
}
219219
});
220220

221+
$mysql_script = <<<SQL
222+
-- delimiter test
223+
DELIMITER $$
224+
225+
CREATE PROCEDURE dorepeat(p1 INT)
226+
BEGIN
227+
SET @x = 0; -- comment
228+
REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
229+
END $$
230+
231+
DELIMITER ;
232+
-- comment
233+
CALL dorepeat(1000);
234+
SELECT @x;
235+
SQL;
236+
237+
$mysql_statements = <<<SQL
238+
CREATE PROCEDURE dorepeat(p1 INT)
239+
BEGIN
240+
SET @x = 0;
241+
REPEAT SET @x = @x + 1; UNTIL @x > p1 END REPEAT;
242+
END
243+
-----
244+
CALL dorepeat(1000)
245+
-----
246+
SELECT @x
247+
SQL;
248+
249+
test("mysql use-case", function () use ($mysql_script, $mysql_statements) {
250+
eq(SQLSplitter::split($mysql_script), array_map("trim", explode("-----", $mysql_statements)));
251+
});
252+
221253
exit(run());

0 commit comments

Comments
 (0)