Skip to content

Commit bd519e4

Browse files
smarekwilliamdes
authored andcommitted
ANSI_QUOTES lexer and parser test-suite proposal
Ref: phpmyadmin/phpmyadmin#15821
1 parent 1665e9a commit bd519e4

File tree

11 files changed

+282
-26
lines changed

11 files changed

+282
-26
lines changed

src/Context.php

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -417,7 +417,7 @@ public static function isSymbol($str)
417417
}
418418
if ($str[0] === '@') {
419419
return Token::FLAG_SYMBOL_VARIABLE;
420-
} elseif ($str[0] === '`') {
420+
} elseif ($str[0] === self::getIdentifierQuote()) {
421421
return Token::FLAG_SYMBOL_BACKTICK;
422422
} elseif ($str[0] === ':' || $str[0] === '?') {
423423
return Token::FLAG_SYMBOL_PARAMETER;
@@ -443,6 +443,8 @@ public static function isString($str)
443443
}
444444
if ($str[0] === '\'') {
445445
return Token::FLAG_STRING_SINGLE_QUOTES;
446+
} elseif (self::hasMode(self::SQL_MODE_ANSI_QUOTES) && $str[0] === '"') {
447+
return null;
446448
} elseif ($str[0] === '"') {
447449
return Token::FLAG_STRING_DOUBLE_QUOTES;
448450
}
@@ -589,6 +591,29 @@ public static function escape($str, $quote = '`')
589591

590592
return $quote . str_replace($quote, $quote . $quote, $str) . $quote;
591593
}
594+
595+
/**
596+
* Returns char used to quote identifiers based on currently set SQL Mode (ie. standard or ANSI_QUOTES)
597+
* @return string either " (double quote, ansi_quotes mode) or ` (backtick, standard mode)
598+
*/
599+
public static function getIdentifierQuote()
600+
{
601+
return self::hasMode(self::SQL_MODE_ANSI_QUOTES) ? '"' : '`';
602+
}
603+
604+
/**
605+
* Function verifies that given SQL Mode constant is currently set
606+
*
607+
* @return boolean false on empty param, true/false on given constant/int value
608+
* @param int $flag for example Context::SQL_MODE_ANSI_QUOTES
609+
*/
610+
public static function hasMode($flag = null)
611+
{
612+
if (empty($flag)) {
613+
return false;
614+
}
615+
return (self::$MODE & $flag) === $flag;
616+
}
592617
}
593618

594619
// Initializing the default context.

src/Lexer.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -863,6 +863,7 @@ public function parseNumber()
863863
* @param string $quote additional starting symbol
864864
*
865865
* @return null|Token
866+
* @throws LexerException
866867
*/
867868
public function parseString($quote = '')
868869
{
@@ -908,6 +909,7 @@ public function parseString($quote = '')
908909
* Parses a symbol.
909910
*
910911
* @return null|Token
912+
* @throws LexerException
911913
*/
912914
public function parseSymbol()
913915
{
@@ -933,7 +935,7 @@ public function parseSymbol()
933935
$str = null;
934936

935937
if ($this->last < $this->len) {
936-
if (($str = $this->parseString('`')) === null) {
938+
if (($str = $this->parseString(Context::getIdentifierQuote())) === null) {
937939
if (($str = $this->parseUnknown()) === null) {
938940
$this->error(
939941
'Variable name was expected.',

src/Utils/CLI.php

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function mergeLongOpts(&$params, &$longopts)
3131

3232
public function usageHighlight()
3333
{
34-
echo "Usage: highlight-query --query SQL [--format html|cli|text]\n";
34+
echo "Usage: highlight-query --query SQL [--format html|cli|text] [--ansi]\n";
3535
echo " cat file.sql | highlight-query\n";
3636
}
3737

@@ -45,10 +45,11 @@ public function parseHighlight()
4545
$longopts = array(
4646
'help',
4747
'query:',
48-
'format:'
48+
'format:',
49+
'ansi'
4950
);
5051
$params = $this->getopt(
51-
'hq:f:',
52+
'hq:f:a',
5253
$longopts
5354
);
5455
if ($params === false) {
@@ -83,6 +84,10 @@ public function runHighlight()
8384
$params['q'] = $stdIn;
8485
}
8586
}
87+
88+
if (isset($params['a'])) {
89+
Context::setMode('ANSI_QUOTES');
90+
}
8691
if (isset($params['q'])) {
8792
echo Formatter::format(
8893
$params['q'],
@@ -100,7 +105,7 @@ public function runHighlight()
100105

101106
public function usageLint()
102107
{
103-
echo "Usage: lint-query --query SQL\n";
108+
echo "Usage: lint-query --query SQL [--ansi]\n";
104109
echo " cat file.sql | lint-query\n";
105110
}
106111

@@ -109,10 +114,11 @@ public function parseLint()
109114
$longopts = array(
110115
'help',
111116
'query:',
112-
'context:'
117+
'context:',
118+
'ansi'
113119
);
114120
$params = $this->getopt(
115-
'hq:c:',
121+
'hq:c:a',
116122
$longopts
117123
);
118124
$this->mergeLongOpts($params, $longopts);
@@ -139,6 +145,10 @@ public function runLint()
139145
$params['q'] = $stdIn;
140146
}
141147
}
148+
if (isset($params['a'])) {
149+
Context::setMode('ANSI_QUOTES');
150+
}
151+
142152
if (isset($params['q'])) {
143153
$lexer = new Lexer($params['q'], false);
144154
$parser = new Parser($lexer->list);
@@ -160,18 +170,19 @@ public function runLint()
160170

161171
public function usageTokenize()
162172
{
163-
echo "Usage: tokenize-query --query SQL\n";
173+
echo "Usage: tokenize-query --query SQL [--ansi]\n";
164174
echo " cat file.sql | tokenize-query\n";
165175
}
166176

167177
public function parseTokenize()
168178
{
169179
$longopts = array(
170180
'help',
171-
'query:'
181+
'query:',
182+
'ansi'
172183
);
173184
$params = $this->getopt(
174-
'hq:',
185+
'hq:a',
175186
$longopts
176187
);
177188
$this->mergeLongOpts($params, $longopts);
@@ -195,6 +206,10 @@ public function runTokenize()
195206
$params['q'] = $stdIn;
196207
}
197208
}
209+
210+
if (isset($params['a'])) {
211+
Context::setMode('ANSI_QUOTES');
212+
}
198213
if (isset($params['q'])) {
199214
$lexer = new Lexer($params['q'], false);
200215
foreach ($lexer->list->tokens as $idx => $token) {

tests/Parser/ParserTest.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ public function parseProvider()
2525
return array(
2626
array('parser/parse'),
2727
array('parser/parse2'),
28-
array('parser/parseDelimiter')
28+
array('parser/parseDelimiter'),
29+
array('parser/ansi/parseAnsi')
2930
);
3031
}
3132

tests/TestCase.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
use PhpMyAdmin\SqlParser\Lexer;
1010
use PhpMyAdmin\SqlParser\Parser;
1111
use PhpMyAdmin\SqlParser\TokensList;
12+
use PhpMyAdmin\SqlParser\Context;
1213
use PHPUnit\Framework\TestCase as BaseTestCase;
1314

1415
$GLOBALS['lang'] = 'en';
@@ -98,6 +99,11 @@ public function runParserTest($name)
9899
*/
99100
$data = $this->getData($name);
100101

102+
if (strpos($name, '/ansi/') !== false) {
103+
// set mode if appropriate
104+
Context::setMode('ANSI_QUOTES');
105+
}
106+
101107
// Lexer.
102108
$lexer = new Lexer($data['query']);
103109
$lexerErrors = $this->getErrorsAsArray($lexer);
@@ -118,5 +124,8 @@ public function runParserTest($name)
118124
// Testing errors.
119125
$this->assertEquals($data['errors']['parser'], $parserErrors);
120126
$this->assertEquals($data['errors']['lexer'], $lexerErrors);
127+
128+
// reset mode after test run
129+
Context::setMode();
121130
}
122131
}

tests/Utils/CLITest.php

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -90,14 +90,14 @@ public function highlightParams()
9090
),
9191
array(
9292
array('h' => true),
93-
'Usage: highlight-query --query SQL [--format html|cli|text]' . "\n" .
93+
'Usage: highlight-query --query SQL [--format html|cli|text] [--ansi]' . "\n" .
9494
' cat file.sql | highlight-query' . "\n",
9595
0
9696
),
9797
array(
9898
array(),
9999
'ERROR: Missing parameters!' . "\n" .
100-
'Usage: highlight-query --query SQL [--format html|cli|text]' . "\n" .
100+
'Usage: highlight-query --query SQL [--format html|cli|text] [--ansi]' . "\n" .
101101
' cat file.sql | highlight-query' . "\n",
102102
1,
103103
),
@@ -162,15 +162,15 @@ public function highlightParamsStdIn()
162162
array(
163163
'',
164164
array('h' => true),
165-
'Usage: highlight-query --query SQL [--format html|cli|text]' . "\n" .
165+
'Usage: highlight-query --query SQL [--format html|cli|text] [--ansi]' . "\n" .
166166
' cat file.sql | highlight-query' . "\n",
167167
0
168168
),
169169
array(
170170
'',
171171
array(),
172172
'ERROR: Missing parameters!' . "\n" .
173-
'Usage: highlight-query --query SQL [--format html|cli|text]' . "\n" .
173+
'Usage: highlight-query --query SQL [--format html|cli|text] [--ansi]' . "\n" .
174174
' cat file.sql | highlight-query' . "\n",
175175
1,
176176
),
@@ -227,14 +227,14 @@ public function lintParamsStdIn()
227227
'',
228228
array(),
229229
'ERROR: Missing parameters!' . "\n" .
230-
'Usage: lint-query --query SQL' . "\n" .
230+
'Usage: lint-query --query SQL [--ansi]' . "\n" .
231231
' cat file.sql | lint-query' . "\n",
232232
1,
233233
),
234234
array(
235235
'',
236236
array('h' => true),
237-
'Usage: lint-query --query SQL' . "\n" .
237+
'Usage: lint-query --query SQL [--ansi]' . "\n" .
238238
' cat file.sql | lint-query' . "\n",
239239
0,
240240
),
@@ -290,14 +290,14 @@ public function lintParams()
290290
),
291291
array(
292292
array('h' => true),
293-
'Usage: lint-query --query SQL' . "\n" .
293+
'Usage: lint-query --query SQL [--ansi]' . "\n" .
294294
' cat file.sql | lint-query' . "\n",
295295
0,
296296
),
297297
array(
298298
array(),
299299
'ERROR: Missing parameters!' . "\n" .
300-
'Usage: lint-query --query SQL' . "\n" .
300+
'Usage: lint-query --query SQL [--ansi]' . "\n" .
301301
' cat file.sql | lint-query' . "\n",
302302
1,
303303
),
@@ -345,14 +345,14 @@ public function tokenizeParams()
345345
),
346346
array(
347347
array('h' => true),
348-
'Usage: tokenize-query --query SQL' . "\n" .
348+
'Usage: tokenize-query --query SQL [--ansi]' . "\n" .
349349
' cat file.sql | tokenize-query' . "\n",
350350
0,
351351
),
352352
array(
353353
array(),
354354
'ERROR: Missing parameters!' . "\n" .
355-
'Usage: tokenize-query --query SQL' . "\n" .
355+
'Usage: tokenize-query --query SQL [--ansi]' . "\n" .
356356
' cat file.sql | tokenize-query' . "\n",
357357
1,
358358
),
@@ -398,15 +398,15 @@ public function tokenizeParamsStdIn()
398398
array(
399399
'',
400400
array('h' => true),
401-
'Usage: tokenize-query --query SQL' . "\n" .
401+
'Usage: tokenize-query --query SQL [--ansi]' . "\n" .
402402
' cat file.sql | tokenize-query' . "\n",
403403
0,
404404
),
405405
array(
406406
'',
407407
array(),
408408
'ERROR: Missing parameters!' . "\n" .
409-
'Usage: tokenize-query --query SQL' . "\n" .
409+
'Usage: tokenize-query --query SQL [--ansi]' . "\n" .
410410
' cat file.sql | tokenize-query' . "\n",
411411
1,
412412
),

tests/data/lexer/ansi/lexAnsi.in

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
CREATE TABLE "addresses" (
2+
"id" int(11) NOT NULL AUTO_INCREMENT,
3+
"country_id" int(11) NOT NULL,
4+
"company_id" int(11) DEFAULT NULL,
5+
"censored" int(11) DEFAULT NULL,
6+
"company_name" varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
7+
"address_type_id" int(11) DEFAULT NULL,
8+
"street" varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
9+
"city" varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
10+
"postal_code" varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
11+
"country_region" varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
12+
"modified" datetime DEFAULT NULL,
13+
"created" datetime DEFAULT NULL,
14+
PRIMARY KEY ("id"),
15+
UNIQUE KEY "censored" ("censored"),
16+
KEY "country_id" ("country_id"),
17+
KEY "company_id" ("company_id"),
18+
KEY "address_type_id" ("address_type_id"),
19+
KEY "censored" ("censored"),
20+
CONSTRAINT "addresses_ibfk_1" FOREIGN KEY ("address_type_id") REFERENCES "address_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
21+
CONSTRAINT "addresses_ibfk_2" FOREIGN KEY ("company_id") REFERENCES "companies" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
22+
CONSTRAINT "addresses_ibfk_3" FOREIGN KEY ("country_id") REFERENCES "countries" ("id"),
23+
CONSTRAINT "addresses_ibfk_4" FOREIGN KEY ("censored") REFERENCES "censored" ("id") ON DELETE CASCADE ON UPDATE CASCADE
24+
)

0 commit comments

Comments
 (0)