Skip to content

Commit dec667f

Browse files
authored
Fix confusion between CHARACTER data type and CHARACTER SET issue (#376)
* Confusion between CHARACTER type and CHARACTER SET In an attempt to fix the character set issue introduced by me in #355 This change separates out the CHARACTER check to do a look ahead to see if the next keyword is SET and splits the logic appropriately. An alternative would be to look back at the constructed expression array ($expr) to see if a ExpressionType::DATA_TYPE has already been defined. This is an alternative fix to the fix proposed by #366 * Updated removed PHPUnit expect function. * Added additional tests for explicit conditions.
1 parent 924ee80 commit dec667f

File tree

3 files changed

+77
-3
lines changed

3 files changed

+77
-3
lines changed

src/PHPSQLParser/processors/ColumnDefinitionProcessor.php

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,19 @@ protected function buildColDef($expr, $base_expr, $options, $refs, $key) {
8282
return $expr;
8383
}
8484

85+
protected function peekAtNextToken($tokens, $index)
86+
{
87+
$offset = $index + 1;
88+
while (isset($tokens[$offset])) {
89+
$token = trim($tokens[$offset]);
90+
if ($token !== '') {
91+
return strtoupper($token);
92+
}
93+
$offset++;
94+
}
95+
return '';
96+
}
97+
8598
public function process($tokens) {
8699

87100
$trim = '';
@@ -187,7 +200,6 @@ public function process($tokens) {
187200
continue 2;
188201

189202
case 'CHAR':
190-
case 'CHARACTER': // Alias for CHAR
191203
$expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'length' => false);
192204
$currCategory = 'SINGLE_PARAM_PARENTHESIS';
193205
$prevCategory = 'TEXT';
@@ -259,11 +271,25 @@ public function process($tokens) {
259271
// spatial types
260272
continue 2;
261273

262-
case 'CHARACTER':
274+
case 'CHARSET':
263275
$currCategory = 'CHARSET';
264276
$options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
265277
continue 2;
266278

279+
case 'CHARACTER':
280+
// Alias of CHAR as well as pre-running for CHARACTER SET
281+
// To determine which we peek at the next token to see if it's a SET or not.
282+
if ($this->peekAtNextToken($tokens, $key) == 'SET') {
283+
$currCategory = 'CHARSET';
284+
$options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);
285+
// If it's not a SET we assume that it is a CHARACTER type definition
286+
} else {
287+
$expr[] = array('expr_type' => ExpressionType::DATA_TYPE, 'base_expr' => $trim, 'length' => false);
288+
$currCategory = 'SINGLE_PARAM_PARENTHESIS';
289+
$prevCategory = 'TEXT';
290+
}
291+
continue 2;
292+
267293
case 'SET':
268294
if ($currCategory == 'CHARSET') {
269295
$options['sub_tree'][] = array('expr_type' => ExpressionType::RESERVED, 'base_expr' => $trim);

tests/cases/parser/issue320Test.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public function test_no_warning_is_issued_when_help_table_is_used()
5151
// there currently is an exception because `HELP` is a keyword
5252
// but this query seems valid at least in mysql and mssql
5353
// so ideally PHPSQLParser would be able to parse it
54-
$this->setExpectedException(
54+
$this->expectException(
5555
'\PHPSQLParser\exceptions\UnableToCalculatePositionException'
5656
);
5757

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?php
2+
/**
3+
* issue265.php
4+
*
5+
* Test case for PHPSQLCreator.
6+
*/
7+
8+
namespace PHPSQLParser\Test\Creator;
9+
10+
use PHPSQLParser\PHPSQLParser;
11+
use PHPSQLParser\PHPSQLCreator;
12+
13+
class Issue365Test extends \PHPUnit\Framework\TestCase
14+
{
15+
/*
16+
* https://github.com/greenlion/PHP-SQL-Parser/issues/365
17+
* Data type alias of character broken the CHARACTER SET parsing
18+
*/
19+
public function testIssue365()
20+
{
21+
$sql = "CREATE TABLE IF NOT EXISTS example (`type` CHARACTER (255) CHARACTER SET utf8)";
22+
23+
$parser = new PHPSQLParser($sql);
24+
$parsed = $parser->parsed;
25+
$create_def = $parsed['TABLE']['create-def'];
26+
$sub_tree = $create_def['sub_tree'][0]['sub_tree'][1];
27+
28+
$this->assertEquals('utf8', $sub_tree['charset'], 'CHARACTER SET utf8');
29+
$expected_type = [
30+
'expr_type' => 'data-type',
31+
'base_expr' => 'CHARACTER',
32+
'length' => 255
33+
];
34+
$this->assertEquals($expected_type, $sub_tree['sub_tree'][0], 'CHARACTER data type definition');
35+
}
36+
37+
public function testIssue365BonusCharset()
38+
{
39+
$sql = "CREATE TABLE IF NOT EXISTS example (`type` CHARACTER (255) CHARSET utf8)";
40+
41+
$parser = new PHPSQLParser($sql);
42+
$parsed = $parser->parsed;
43+
$create_def = $parsed['TABLE']['create-def'];
44+
$sub_tree = $create_def['sub_tree'][0]['sub_tree'][1];
45+
46+
$this->assertEquals('utf8', $sub_tree['charset'], 'CHARACTER SET utf8');
47+
}
48+
}

0 commit comments

Comments
 (0)