Skip to content

Feature ansi mode, partial solution to #284 #294

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 20, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion src/Context.php
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,7 @@ public static function isSymbol($str)
}
if ($str[0] === '@') {
return Token::FLAG_SYMBOL_VARIABLE;
} elseif ($str[0] === '`') {
} elseif ($str[0] === self::getIdentifierQuote()) {
return Token::FLAG_SYMBOL_BACKTICK;
} elseif ($str[0] === ':' || $str[0] === '?') {
return Token::FLAG_SYMBOL_PARAMETER;
Expand All @@ -443,6 +443,8 @@ public static function isString($str)
}
if ($str[0] === '\'') {
return Token::FLAG_STRING_SINGLE_QUOTES;
} elseif (self::hasMode(self::SQL_MODE_ANSI_QUOTES) && $str[0] === '"') {
return null;
} elseif ($str[0] === '"') {
return Token::FLAG_STRING_DOUBLE_QUOTES;
}
Expand Down Expand Up @@ -589,6 +591,29 @@ public static function escape($str, $quote = '`')

return $quote . str_replace($quote, $quote . $quote, $str) . $quote;
}

/**
* Returns char used to quote identifiers based on currently set SQL Mode (ie. standard or ANSI_QUOTES)
* @return string either " (double quote, ansi_quotes mode) or ` (backtick, standard mode)
*/
public static function getIdentifierQuote()
{
return self::hasMode(self::SQL_MODE_ANSI_QUOTES) ? '"' : '`';
}

/**
* Function verifies that given SQL Mode constant is currently set
*
* @return boolean false on empty param, true/false on given constant/int value
* @param int $flag for example Context::SQL_MODE_ANSI_QUOTES
*/
public static function hasMode($flag = null)
{
if (empty($flag)) {
return false;
}
return (self::$MODE & $flag) === $flag;
}
}

// Initializing the default context.
Expand Down
4 changes: 3 additions & 1 deletion src/Lexer.php
Original file line number Diff line number Diff line change
Expand Up @@ -863,6 +863,7 @@ public function parseNumber()
* @param string $quote additional starting symbol
*
* @return null|Token
* @throws LexerException
*/
public function parseString($quote = '')
{
Expand Down Expand Up @@ -908,6 +909,7 @@ public function parseString($quote = '')
* Parses a symbol.
*
* @return null|Token
* @throws LexerException
*/
public function parseSymbol()
{
Expand All @@ -933,7 +935,7 @@ public function parseSymbol()
$str = null;

if ($this->last < $this->len) {
if (($str = $this->parseString('`')) === null) {
if (($str = $this->parseString(Context::getIdentifierQuote())) === null) {
if (($str = $this->parseUnknown()) === null) {
$this->error(
'Variable name was expected.',
Expand Down
33 changes: 24 additions & 9 deletions src/Utils/CLI.php
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ public function mergeLongOpts(&$params, &$longopts)

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

Expand All @@ -45,10 +45,11 @@ public function parseHighlight()
$longopts = array(
'help',
'query:',
'format:'
'format:',
'ansi'
);
$params = $this->getopt(
'hq:f:',
'hq:f:a',
$longopts
);
if ($params === false) {
Expand Down Expand Up @@ -83,6 +84,10 @@ public function runHighlight()
$params['q'] = $stdIn;
}
}

if (isset($params['a'])) {
Context::setMode('ANSI_QUOTES');
}
if (isset($params['q'])) {
echo Formatter::format(
$params['q'],
Expand All @@ -100,7 +105,7 @@ public function runHighlight()

public function usageLint()
{
echo "Usage: lint-query --query SQL\n";
echo "Usage: lint-query --query SQL [--ansi]\n";
echo " cat file.sql | lint-query\n";
}

Expand All @@ -109,10 +114,11 @@ public function parseLint()
$longopts = array(
'help',
'query:',
'context:'
'context:',
'ansi'
);
$params = $this->getopt(
'hq:c:',
'hq:c:a',
$longopts
);
$this->mergeLongOpts($params, $longopts);
Expand All @@ -139,6 +145,10 @@ public function runLint()
$params['q'] = $stdIn;
}
}
if (isset($params['a'])) {
Context::setMode('ANSI_QUOTES');
}

if (isset($params['q'])) {
$lexer = new Lexer($params['q'], false);
$parser = new Parser($lexer->list);
Expand All @@ -160,18 +170,19 @@ public function runLint()

public function usageTokenize()
{
echo "Usage: tokenize-query --query SQL\n";
echo "Usage: tokenize-query --query SQL [--ansi]\n";
echo " cat file.sql | tokenize-query\n";
}

public function parseTokenize()
{
$longopts = array(
'help',
'query:'
'query:',
'ansi'
);
$params = $this->getopt(
'hq:',
'hq:a',
$longopts
);
$this->mergeLongOpts($params, $longopts);
Expand All @@ -195,6 +206,10 @@ public function runTokenize()
$params['q'] = $stdIn;
}
}

if (isset($params['a'])) {
Context::setMode('ANSI_QUOTES');
}
if (isset($params['q'])) {
$lexer = new Lexer($params['q'], false);
foreach ($lexer->list->tokens as $idx => $token) {
Expand Down
3 changes: 2 additions & 1 deletion tests/Parser/ParserTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,8 @@ public function parseProvider()
return array(
array('parser/parse'),
array('parser/parse2'),
array('parser/parseDelimiter')
array('parser/parseDelimiter'),
array('parser/ansi/parseAnsi')
);
}

Expand Down
9 changes: 9 additions & 0 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
use PhpMyAdmin\SqlParser\Lexer;
use PhpMyAdmin\SqlParser\Parser;
use PhpMyAdmin\SqlParser\TokensList;
use PhpMyAdmin\SqlParser\Context;
use PHPUnit\Framework\TestCase as BaseTestCase;

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

if (strpos($name, '/ansi/') !== false) {
// set mode if appropriate
Context::setMode('ANSI_QUOTES');
}

// Lexer.
$lexer = new Lexer($data['query']);
$lexerErrors = $this->getErrorsAsArray($lexer);
Expand All @@ -118,5 +124,8 @@ public function runParserTest($name)
// Testing errors.
$this->assertEquals($data['errors']['parser'], $parserErrors);
$this->assertEquals($data['errors']['lexer'], $lexerErrors);

// reset mode after test run
Context::setMode();
}
}
24 changes: 12 additions & 12 deletions tests/Utils/CLITest.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,14 +90,14 @@ public function highlightParams()
),
array(
array('h' => true),
'Usage: highlight-query --query SQL [--format html|cli|text]' . "\n" .
'Usage: highlight-query --query SQL [--format html|cli|text] [--ansi]' . "\n" .
' cat file.sql | highlight-query' . "\n",
0
),
array(
array(),
'ERROR: Missing parameters!' . "\n" .
'Usage: highlight-query --query SQL [--format html|cli|text]' . "\n" .
'Usage: highlight-query --query SQL [--format html|cli|text] [--ansi]' . "\n" .
' cat file.sql | highlight-query' . "\n",
1,
),
Expand Down Expand Up @@ -162,15 +162,15 @@ public function highlightParamsStdIn()
array(
'',
array('h' => true),
'Usage: highlight-query --query SQL [--format html|cli|text]' . "\n" .
'Usage: highlight-query --query SQL [--format html|cli|text] [--ansi]' . "\n" .
' cat file.sql | highlight-query' . "\n",
0
),
array(
'',
array(),
'ERROR: Missing parameters!' . "\n" .
'Usage: highlight-query --query SQL [--format html|cli|text]' . "\n" .
'Usage: highlight-query --query SQL [--format html|cli|text] [--ansi]' . "\n" .
' cat file.sql | highlight-query' . "\n",
1,
),
Expand Down Expand Up @@ -227,14 +227,14 @@ public function lintParamsStdIn()
'',
array(),
'ERROR: Missing parameters!' . "\n" .
'Usage: lint-query --query SQL' . "\n" .
'Usage: lint-query --query SQL [--ansi]' . "\n" .
' cat file.sql | lint-query' . "\n",
1,
),
array(
'',
array('h' => true),
'Usage: lint-query --query SQL' . "\n" .
'Usage: lint-query --query SQL [--ansi]' . "\n" .
' cat file.sql | lint-query' . "\n",
0,
),
Expand Down Expand Up @@ -290,14 +290,14 @@ public function lintParams()
),
array(
array('h' => true),
'Usage: lint-query --query SQL' . "\n" .
'Usage: lint-query --query SQL [--ansi]' . "\n" .
' cat file.sql | lint-query' . "\n",
0,
),
array(
array(),
'ERROR: Missing parameters!' . "\n" .
'Usage: lint-query --query SQL' . "\n" .
'Usage: lint-query --query SQL [--ansi]' . "\n" .
' cat file.sql | lint-query' . "\n",
1,
),
Expand Down Expand Up @@ -345,14 +345,14 @@ public function tokenizeParams()
),
array(
array('h' => true),
'Usage: tokenize-query --query SQL' . "\n" .
'Usage: tokenize-query --query SQL [--ansi]' . "\n" .
' cat file.sql | tokenize-query' . "\n",
0,
),
array(
array(),
'ERROR: Missing parameters!' . "\n" .
'Usage: tokenize-query --query SQL' . "\n" .
'Usage: tokenize-query --query SQL [--ansi]' . "\n" .
' cat file.sql | tokenize-query' . "\n",
1,
),
Expand Down Expand Up @@ -398,15 +398,15 @@ public function tokenizeParamsStdIn()
array(
'',
array('h' => true),
'Usage: tokenize-query --query SQL' . "\n" .
'Usage: tokenize-query --query SQL [--ansi]' . "\n" .
' cat file.sql | tokenize-query' . "\n",
0,
),
array(
'',
array(),
'ERROR: Missing parameters!' . "\n" .
'Usage: tokenize-query --query SQL' . "\n" .
'Usage: tokenize-query --query SQL [--ansi]' . "\n" .
' cat file.sql | tokenize-query' . "\n",
1,
),
Expand Down
24 changes: 24 additions & 0 deletions tests/data/lexer/ansi/lexAnsi.in
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
CREATE TABLE "addresses" (
"id" int(11) NOT NULL AUTO_INCREMENT,
"country_id" int(11) NOT NULL,
"company_id" int(11) DEFAULT NULL,
"censored" int(11) DEFAULT NULL,
"company_name" varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL,
"address_type_id" int(11) DEFAULT NULL,
"street" varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
"city" varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
"postal_code" varchar(12) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
"country_region" varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci DEFAULT NULL,
"modified" datetime DEFAULT NULL,
"created" datetime DEFAULT NULL,
PRIMARY KEY ("id"),
UNIQUE KEY "censored" ("censored"),
KEY "country_id" ("country_id"),
KEY "company_id" ("company_id"),
KEY "address_type_id" ("address_type_id"),
KEY "censored" ("censored"),
CONSTRAINT "addresses_ibfk_1" FOREIGN KEY ("address_type_id") REFERENCES "address_types" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "addresses_ibfk_2" FOREIGN KEY ("company_id") REFERENCES "companies" ("id") ON DELETE CASCADE ON UPDATE CASCADE,
CONSTRAINT "addresses_ibfk_3" FOREIGN KEY ("country_id") REFERENCES "countries" ("id"),
CONSTRAINT "addresses_ibfk_4" FOREIGN KEY ("censored") REFERENCES "censored" ("id") ON DELETE CASCADE ON UPDATE CASCADE
)
Loading