From f2e7c6e133efe2ec0789a95e91d5808c9326f6ef Mon Sep 17 00:00:00 2001 From: Dan Ungureanu Date: Sun, 16 Aug 2015 02:57:19 +0300 Subject: [PATCH] Fixes #11397. Added support for partitions. Fixes #11398. Added support for 'SERIAL' data type. Updated sql-parser to udan11/sql-parser@3d3b03b25b67212ba0447b2b010bba5a4471bb44. Signed-off-by: Dan Ungureanu --- .../src/Components/AlterOperation.php | 5 +- .../sql-parser/src/Components/Array2d.php | 21 +- .../sql-parser/src/Components/ArrayObj.php | 46 +++- .../sql-parser/src/Components/Condition.php | 5 +- .../src/Components/CreateDefinition.php | 4 +- .../sql-parser/src/Components/DataType.php | 4 +- .../sql-parser/src/Components/Expression.php | 7 + .../src/Components/ExpressionArray.php | 6 +- .../src/Components/FunctionCall.php | 6 +- .../sql-parser/src/Components/IntoKeyword.php | 22 +- .../sql-parser/src/Components/JoinKeyword.php | 4 +- libraries/sql-parser/src/Components/Key.php | 4 +- libraries/sql-parser/src/Components/Limit.php | 2 + .../src/Components/OptionsArray.php | 8 +- .../src/Components/OrderKeyword.php | 4 +- .../src/Components/ParameterDefinition.php | 6 +- .../src/Components/PartitionDefinition.php | 219 ++++++++++++++++ .../sql-parser/src/Components/Reference.php | 6 +- .../src/Components/RenameOperation.php | 27 +- .../src/Components/SetOperation.php | 4 +- libraries/sql-parser/src/Context.php | 1 + .../src/Contexts/ContextMySql50000.php | 22 +- .../src/Contexts/ContextMySql50100.php | 17 +- .../src/Contexts/ContextMySql50500.php | 17 +- .../src/Contexts/ContextMySql50600.php | 17 +- .../src/Contexts/ContextMySql50700.php | 17 +- libraries/sql-parser/src/Lexer.php | 17 +- libraries/sql-parser/src/Parser.php | 248 ++++++++++-------- libraries/sql-parser/src/Statement.php | 14 +- .../src/Statements/AlterStatement.php | 4 +- .../src/Statements/CreateStatement.php | 151 ++++++++++- libraries/sql-parser/src/Token.php | 8 +- .../sql-parser/src/Utils/BufferedQuery.php | 5 + libraries/sql-parser/src/Utils/Formatter.php | 32 ++- libraries/sql-parser/src/Utils/Misc.php | 3 +- libraries/sql-parser/src/Utils/Query.php | 14 +- 36 files changed, 796 insertions(+), 201 deletions(-) create mode 100644 libraries/sql-parser/src/Components/PartitionDefinition.php diff --git a/libraries/sql-parser/src/Components/AlterOperation.php b/libraries/sql-parser/src/Components/AlterOperation.php index d704f25ba2..6b81a46235 100644 --- a/libraries/sql-parser/src/Components/AlterOperation.php +++ b/libraries/sql-parser/src/Components/AlterOperation.php @@ -108,6 +108,7 @@ class AlterOperation extends Component /** * Counts brackets. + * * @var int $brackets */ $brackets = 0; @@ -123,13 +124,15 @@ class AlterOperation extends Component * * 2 -------------------------[ , ]-----------------------> 0 * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/Array2d.php b/libraries/sql-parser/src/Components/Array2d.php index c53c8be9e6..268dcea9b0 100644 --- a/libraries/sql-parser/src/Components/Array2d.php +++ b/libraries/sql-parser/src/Components/Array2d.php @@ -38,7 +38,8 @@ class Array2d extends Component /** * The number of values in each set. - * @var int + * + * @var int $count */ $count = -1; @@ -47,18 +48,20 @@ class Array2d extends Component * * Below are the states of the parser. * - * 0 ----------------------[ array ]---------------------> 1 + * 0 ----------------------[ array ]----------------------> 1 * * 1 ------------------------[ , ]------------------------> 0 - * 1 -----------------------[ else ]----------------------> -1 + * 1 -----------------------[ else ]----------------------> (END) * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; @@ -118,4 +121,14 @@ class Array2d extends Component --$list->idx; return $ret; } + + /** + * @param ArrayObj[] $component The component to be built. + * + * @return string + */ + public static function build($component) + { + return ArrayObj::build($component); + } } diff --git a/libraries/sql-parser/src/Components/ArrayObj.php b/libraries/sql-parser/src/Components/ArrayObj.php index 8dde51857a..0e0b1830ed 100644 --- a/libraries/sql-parser/src/Components/ArrayObj.php +++ b/libraries/sql-parser/src/Components/ArrayObj.php @@ -56,11 +56,11 @@ class ArrayObj extends Component * @param TokensList $list The list of tokens that are being parsed. * @param array $options Parameters for parsing. * - * @return ArrayObj + * @return mixed */ public static function parse(Parser $parser, TokensList $list, array $options = array()) { - $ret = new ArrayObj(); + $ret = empty($options['type']) ? new ArrayObj() : array(); /** * The state of the parser. @@ -72,15 +72,17 @@ class ArrayObj extends Component * 1 ------------------[ array element ]-----------------> 2 * * 2 ------------------------[ , ]-----------------------> 1 - * 2 ------------------------[ ) ]-----------------------> -1 + * 2 ------------------------[ ) ]-----------------------> (END) * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; @@ -109,8 +111,16 @@ class ArrayObj extends Component // Empty array. break; } - $ret->values[] = $token->value; - $ret->raw[] = $token->token; + if (empty($options['type'])) { + $ret->values[] = $token->value; + $ret->raw[] = $token->token; + } else { + $ret[] = $options['type']::parse( + $parser, + $list, + empty($options['typeOptions']) ? array() : $options['typeOptions'] + ); + } $state = 2; } elseif ($state === 2) { if (($token->type !== Token::TYPE_OPERATOR) || (($token->value !== ',') && ($token->value !== ')'))) { @@ -133,20 +143,28 @@ class ArrayObj extends Component } /** - * @param ArrayObj $component The component to be built. + * @param ArrayObj|ArrayObj[] $component The component to be built. * * @return string */ public static function build($component) { - $values = array(); - if (!empty($component->raw)) { - $values = $component->raw; - } else { - foreach ($component->values as $value) { - $values[] = $value; + if (is_array($component)) { + $values = array(); + foreach ($component as $c) { + $values[] = static::build($c); } + return implode(', ', $values); + } else { + $values = array(); + if (!empty($component->raw)) { + $values = $component->raw; + } else { + foreach ($component->values as $value) { + $values[] = $value; + } + } + return '(' . implode(', ', $values) . ')'; } - return '(' . implode(', ', $values) . ')'; } } diff --git a/libraries/sql-parser/src/Components/Condition.php b/libraries/sql-parser/src/Components/Condition.php index 46cab2ad1a..1f515dcfd4 100644 --- a/libraries/sql-parser/src/Components/Condition.php +++ b/libraries/sql-parser/src/Components/Condition.php @@ -95,6 +95,7 @@ class Condition extends Component /** * Counts brackets. + * * @var int $brackets */ $brackets = 0; @@ -104,7 +105,8 @@ class Condition extends Component * It is required to keep track of them because their structure contains * the keyword `AND`, which is also an operator that delimits * expressions. - * @var bool + * + * @var bool $betweenBefore */ $betweenBefore = false; @@ -112,6 +114,7 @@ class Condition extends Component /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/CreateDefinition.php b/libraries/sql-parser/src/Components/CreateDefinition.php index 4dfbb7ae11..5671801a35 100644 --- a/libraries/sql-parser/src/Components/CreateDefinition.php +++ b/libraries/sql-parser/src/Components/CreateDefinition.php @@ -173,13 +173,15 @@ class CreateDefinition extends Component * 5 ------------------------[ , ]-----------------------> 1 * 5 ------------------------[ ) ]-----------------------> 6 (-1) * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/DataType.php b/libraries/sql-parser/src/Components/DataType.php index 99c3918ebe..48ce5b702b 100644 --- a/libraries/sql-parser/src/Components/DataType.php +++ b/libraries/sql-parser/src/Components/DataType.php @@ -103,13 +103,15 @@ class DataType extends Component * * 1 ----------------[ size and options ]----------------> 2 * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/Expression.php b/libraries/sql-parser/src/Components/Expression.php index 60f85544ba..11e713217e 100644 --- a/libraries/sql-parser/src/Components/Expression.php +++ b/libraries/sql-parser/src/Components/Expression.php @@ -122,24 +122,28 @@ class Expression extends Component /** * Whether current tokens make an expression or a table reference. + * * @var bool $isExpr */ $isExpr = false; /** * Whether a period was previously found. + * * @var bool $dot */ $dot = false; /** * Whether an alias is expected. Is 2 if `AS` keyword was found. + * * @var int $alias */ $alias = 0; /** * Counts brackets. + * * @var int $brackets */ $brackets = 0; @@ -150,13 +154,16 @@ class Expression extends Component * string, if function was previously found; * true, if opening bracket was previously found; * null, in any other case. + * * @var string|bool $prev */ $prev = null; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/ExpressionArray.php b/libraries/sql-parser/src/Components/ExpressionArray.php index 309972a2c4..82e67c9ffc 100644 --- a/libraries/sql-parser/src/Components/ExpressionArray.php +++ b/libraries/sql-parser/src/Components/ExpressionArray.php @@ -44,15 +44,17 @@ class ExpressionArray extends Component * 0 ----------------------[ array ]---------------------> 1 * * 1 ------------------------[ , ]------------------------> 0 - * 1 -----------------------[ else ]----------------------> -1 + * 1 -----------------------[ else ]----------------------> (END) * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/FunctionCall.php b/libraries/sql-parser/src/Components/FunctionCall.php index b86eeb8513..43eb082ea9 100644 --- a/libraries/sql-parser/src/Components/FunctionCall.php +++ b/libraries/sql-parser/src/Components/FunctionCall.php @@ -73,15 +73,17 @@ class FunctionCall extends Component * * 0 ----------------------[ name ]-----------------------> 1 * - * 1 --------------------[ parameters ]-------------------> -1 + * 1 --------------------[ parameters ]-------------------> (END) * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/IntoKeyword.php b/libraries/sql-parser/src/Components/IntoKeyword.php index cb2548110c..7a91064b31 100644 --- a/libraries/sql-parser/src/Components/IntoKeyword.php +++ b/libraries/sql-parser/src/Components/IntoKeyword.php @@ -65,17 +65,19 @@ class IntoKeyword extends Component * 0 -----------------------[ name ]----------------------> 1 * 0 ---------------------[ OUTFILE ]---------------------> 2 * - * 1 ------------------------[ ( ]------------------------> -1 + * 1 ------------------------[ ( ]------------------------> (END) * * 2 ---------------------[ filename ]--------------------> 1 * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; @@ -128,4 +130,20 @@ class IntoKeyword extends Component --$list->idx; return $ret; } + + /** + * @param IntoKeyword $component The component to be built. + * + * @return string + */ + public static function build($component) + { + if ($component->type === 'OUTFILE') { + return 'OUTFILE "' . $component->dest . '"'; + } else { + $columns = !empty($component->columns) ? + '(' . implode(', ', $component->columns) . ')' : ''; + return Expression::build($component->dest) . $columns; + } + } } diff --git a/libraries/sql-parser/src/Components/JoinKeyword.php b/libraries/sql-parser/src/Components/JoinKeyword.php index 171ad98db3..237022a16c 100644 --- a/libraries/sql-parser/src/Components/JoinKeyword.php +++ b/libraries/sql-parser/src/Components/JoinKeyword.php @@ -86,7 +86,7 @@ class JoinKeyword extends Component * * 3 --------------------[ conditions ]-------------------> 0 * - * @var int + * @var int $state */ $state = 0; @@ -98,8 +98,10 @@ class JoinKeyword extends Component } for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/Key.php b/libraries/sql-parser/src/Components/Key.php index bb8bbf02ed..1364a8ceef 100644 --- a/libraries/sql-parser/src/Components/Key.php +++ b/libraries/sql-parser/src/Components/Key.php @@ -107,13 +107,15 @@ class Key extends Component * * 2 ---------------------[ options ]---------------------> 3 * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/Limit.php b/libraries/sql-parser/src/Components/Limit.php index a821b9fe79..8622c96d9e 100644 --- a/libraries/sql-parser/src/Components/Limit.php +++ b/libraries/sql-parser/src/Components/Limit.php @@ -65,8 +65,10 @@ class Limit extends Component $offset = false; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/OptionsArray.php b/libraries/sql-parser/src/Components/OptionsArray.php index da2ec8dbee..6b43844c24 100644 --- a/libraries/sql-parser/src/Components/OptionsArray.php +++ b/libraries/sql-parser/src/Components/OptionsArray.php @@ -57,24 +57,28 @@ class OptionsArray extends Component /** * The ID that will be assigned to duplicate options. + * * @var int $lastAssignedId */ $lastAssignedId = count($options) + 1; /** * The option that was processed last time. + * * @var array $lastOption */ $lastOption = null; /** * The index of the option that was processed last time. + * * @var int $lastOptionId */ $lastOptionId = 0; /** * Counts brackets. + * * @var int $brackets */ $brackets = 0; @@ -90,13 +94,15 @@ class OptionsArray extends Component * * 2 ----------------------[ value ]----------------------> 0 * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/OrderKeyword.php b/libraries/sql-parser/src/Components/OrderKeyword.php index b8b05c15b6..81bff2f7a2 100644 --- a/libraries/sql-parser/src/Components/OrderKeyword.php +++ b/libraries/sql-parser/src/Components/OrderKeyword.php @@ -74,13 +74,15 @@ class OrderKeyword extends Component * 1 ------------------------[ , ]------------------------> 0 * 1 -------------------[ ASC / DESC ]--------------------> 1 * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/ParameterDefinition.php b/libraries/sql-parser/src/Components/ParameterDefinition.php index d10a460f38..79b4845e22 100644 --- a/libraries/sql-parser/src/Components/ParameterDefinition.php +++ b/libraries/sql-parser/src/Components/ParameterDefinition.php @@ -73,15 +73,17 @@ class ParameterDefinition extends Component * 2 -------------------[ data type ]--------------------> 3 * * 3 ------------------------[ , ]-----------------------> 1 - * 3 ------------------------[ ) ]-----------------------> -1 + * 3 ------------------------[ ) ]-----------------------> (END) * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/PartitionDefinition.php b/libraries/sql-parser/src/Components/PartitionDefinition.php new file mode 100644 index 0000000000..c46252d9fd --- /dev/null +++ b/libraries/sql-parser/src/Components/PartitionDefinition.php @@ -0,0 +1,219 @@ + + * @license http://opensource.org/licenses/GPL-2.0 GNU Public License + */ +class PartitionDefinition extends Component +{ + + /** + * All field options. + * + * @var array + */ + public static $OPTIONS = array( + 'STORAGE' => array(1, 'var'), + 'STORAGE ENGINE' => array(1, 'var'), + 'COMMENT' => array(2, 'var'), + 'DATA DIRECTORY' => array(3, 'var'), + 'INDEX DIRECTORY' => array(4, 'var'), + 'MAX_ROWS' => array(5, 'var'), + 'MIN_ROWS' => array(6, 'var'), + 'TABLESPACE' => array(7, 'var'), + 'NODEGROUP' => array(8, 'var'), + ); + + /** + * Whether this entry is a subpartition or a partition. + * + * @var bool + */ + public $isSubpartition; + + /** + * The name of this partition. + * + * @var string + */ + public $name; + + /** + * The type of this partition (what follows the `VALUES` keyword). + * + * @var string + */ + public $type; + + /** + * The expression used to defined this partition. + * + * @var Expression + */ + public $expr; + + /** + * The subpartitions of this partition. + * + * @var PartitionDefinition[] + */ + public $subpartitions; + + /** + * The options of this field. + * + * @var OptionsArray + */ + public $options; + + /** + * @param Parser $parser The parser that serves as context. + * @param TokensList $list The list of tokens that are being parsed. + * @param array $options Parameters for parsing. + * + * @return PartitionDefinition + */ + public static function parse(Parser $parser, TokensList $list, array $options = array()) + { + $ret = new PartitionDefinition(); + + /** + * The state of the parser. + * + * Below are the states of the parser. + * + * 0 -------------[ PARTITION | SUBPARTITION ]------------> 1 + * + * 1 -----------------------[ name ]----------------------> 2 + * + * 2 ----------------------[ VALUES ]---------------------> 3 + * + * 3 ---------------------[ LESS THAN ]-------------------> 4 + * 3 ------------------------[ IN ]-----------------------> 4 + * + * 4 -----------------------[ expr ]----------------------> 5 + * + * 5 ----------------------[ options ]--------------------> 6 + * + * 6 ------------------[ subpartitions ]------------------> (END) + * + * @var int $state + */ + $state = 0; + + for (; $list->idx < $list->count; ++$list->idx) { + + /** + * Token parsed at this moment. + * + * @var Token $token + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === Token::TYPE_DELIMITER) { + break; + } + + // Skipping whitespaces and comments. + if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) { + continue; + } + + if ($state === 0) { + $ret->isSubpartition = ($token->type === Token::TYPE_KEYWORD) && ($token->value === 'SUBPARTITION'); + $state = 1; + } elseif ($state === 1) { + $ret->name = $token->value; + $state = $ret->isSubpartition ? 5 : 2; + } elseif ($state === 2) { + $state = 3; + } elseif ($state === 3) { + $ret->type = $token->value; + $state = 4; + } elseif ($state === 4) { + if ($token->value === 'MAXVALUE') { + $ret->expr = $token->value; + } else { + $ret->expr = Expression::parse( + $parser, + $list, + array( + 'bracketsDelimited' => true, + 'noAlias' => true, + ) + ); + } + $state = 5; + } elseif ($state === 5) { + $ret->options = OptionsArray::parse($parser, $list, static::$OPTIONS); + $state = 6; + } elseif ($state === 6) { + if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) { + $ret->subpartitions = ArrayObj::parse( + $parser, + $list, + array( + 'type' => 'SqlParser\\Components\\PartitionDefinition' + ) + ); + ++$list->idx; + } + break; + } + } + + --$list->idx; + return $ret; + } + + /** + * @param PartitionDefinition|PartitionDefinition[] $component The component to be built. + * + * @return string + */ + public static function build($component) + { + if (is_array($component)) { + $ret = array(); + foreach ($component as $c) { + $ret[] = static::build($c); + } + return "(\n" . implode(",\n", $ret) . "\n)"; + } else { + if ($component->isSubpartition) { + return 'SUBPARTITION ' . $component->name; + } else { + $subpartitions = empty($component->subpartitions) + ? '' : ' ' . PartitionDefinition::build($component->subpartitions); + return 'PARTITION ' . $component->name + . ' VALUES ' . $component->type . ' ' . $component->expr + . $subpartitions; + } + + } + } +} diff --git a/libraries/sql-parser/src/Components/Reference.php b/libraries/sql-parser/src/Components/Reference.php index fa468875ac..36d3971477 100644 --- a/libraries/sql-parser/src/Components/Reference.php +++ b/libraries/sql-parser/src/Components/Reference.php @@ -92,15 +92,17 @@ class Reference extends Component * * 1 ---------------------[ columns ]--------------------> 2 * - * 2 ---------------------[ options ]--------------------> -1 + * 2 ---------------------[ options ]--------------------> (END) * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Components/RenameOperation.php b/libraries/sql-parser/src/Components/RenameOperation.php index 7d115fb330..34c62bb415 100644 --- a/libraries/sql-parser/src/Components/RenameOperation.php +++ b/libraries/sql-parser/src/Components/RenameOperation.php @@ -44,7 +44,7 @@ class RenameOperation extends Component * @param TokensList $list The list of tokens that are being parsed. * @param array $options Parameters for parsing. * - * @return RenameOperation + * @return RenameOperation[] */ public static function parse(Parser $parser, TokensList $list, array $options = array()) { @@ -64,15 +64,17 @@ class RenameOperation extends Component * 2 ---------------------[ old name ]--------------------> 3 * * 3 ------------------------[ , ]------------------------> 0 - * 3 -----------------------[ else ]----------------------> -1 + * 3 -----------------------[ else ]----------------------> (END) * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; @@ -157,4 +159,23 @@ class RenameOperation extends Component --$list->idx; return $ret; } + + /** + * @param RenameOperation $component The component to be built. + * + * @return string + */ + public static function build($component) + { + if (is_array($component)) { + $values = array(); + foreach ($component as $c) { + $values[] = static::build($c); + } + return implode(', ', $values); + } else { + return Expression::build($component->old) . ' TO ' + . Expression::build($component->new); + } + } } diff --git a/libraries/sql-parser/src/Components/SetOperation.php b/libraries/sql-parser/src/Components/SetOperation.php index 25bb9e4231..8b6af87458 100644 --- a/libraries/sql-parser/src/Components/SetOperation.php +++ b/libraries/sql-parser/src/Components/SetOperation.php @@ -62,13 +62,15 @@ class SetOperation extends Component * 1 ------------------------[ , ]------------------------> 0 * 1 ----------------------[ value ]----------------------> 1 * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Context.php b/libraries/sql-parser/src/Context.php index c355534978..d6602ce29d 100644 --- a/libraries/sql-parser/src/Context.php +++ b/libraries/sql-parser/src/Context.php @@ -450,6 +450,7 @@ abstract class Context /** * The number of replaces done by `preg_replace`. * This actually represents whether a new context was generated or not. + * * @var int $count */ $count = 0; diff --git a/libraries/sql-parser/src/Contexts/ContextMySql50000.php b/libraries/sql-parser/src/Contexts/ContextMySql50000.php index ed86320ac4..42366983fe 100644 --- a/libraries/sql-parser/src/Contexts/ContextMySql50000.php +++ b/libraries/sql-parser/src/Contexts/ContextMySql50000.php @@ -54,9 +54,8 @@ class ContextMySql50000 extends Context 'EVENTS' => 1, 'FAULTS' => 1, 'FIELDS' => 1, 'GLOBAL' => 1, 'GRANTS' => 1, 'IMPORT' => 1, 'INNODB' => 1, 'ISSUER' => 1, 'LEAVES' => 1, 'MASTER' => 1, 'MEDIUM' => 1, 'MEMORY' => 1, 'MODIFY' => 1, 'OFFSET' => 1, 'RELOAD' => 1, - 'REPAIR' => 1, 'RESUME' => 1, 'ROLLUP' => 1, 'SERIAL' => 1, 'SIGNED' => 1, - 'SIMPLE' => 1, 'SOUNDS' => 1, 'SOURCE' => 1, 'STATUS' => 1, 'STRING' => 1, - 'TABLES' => 1, + 'REPAIR' => 1, 'RESUME' => 1, 'ROLLUP' => 1, 'SIGNED' => 1, 'SIMPLE' => 1, + 'SOUNDS' => 1, 'SOURCE' => 1, 'STATUS' => 1, 'STRING' => 1, 'TABLES' => 1, 'AGAINST' => 1, 'CHANGED' => 1, 'COLUMNS' => 1, 'COMMENT' => 1, 'COMPACT' => 1, 'CONTEXT' => 1, 'DEFINER' => 1, 'DISABLE' => 1, 'DISCARD' => 1, 'DYNAMIC' => 1, 'ENGINES' => 1, 'EXECUTE' => 1, 'HANDLER' => 1, 'INDEXES' => 1, 'INVOKER' => 1, @@ -77,8 +76,8 @@ class ContextMySql50000 extends Context 'VARIABLES' => 1, 'BERKELEYDB' => 1, 'COMPRESSED' => 1, 'CONCURRENT' => 1, 'CONNECTION' => 1, 'CONSISTENT' => 1, 'DEALLOCATE' => 1, 'IDENTIFIED' => 1, 'MASTER_SSL' => 1, - 'NDBCLUSTER' => 1, 'PERSISTENT' => 1, 'PRIVILEGES' => 1, 'REPEATABLE' => 1, - 'ROW_FORMAT' => 1, 'SQL_THREAD' => 1, 'TABLESPACE' => 1, + 'NDBCLUSTER' => 1, 'PARTITIONS' => 1, 'PERSISTENT' => 1, 'PRIVILEGES' => 1, + 'REPEATABLE' => 1, 'ROW_FORMAT' => 1, 'SQL_THREAD' => 1, 'TABLESPACE' => 1, 'FRAC_SECOND' => 1, 'MASTER_HOST' => 1, 'MASTER_PORT' => 1, 'MASTER_USER' => 1, 'PROCESSLIST' => 1, 'RAID_CHUNKS' => 1, 'REPLICATION' => 1, 'SQL_TSI_DAY' => 1, 'TRANSACTION' => 1, 'UNCOMMITTED' => 1, @@ -86,7 +85,7 @@ class ContextMySql50000 extends Context 'SQL_NO_CACHE' => 1, 'SQL_TSI_HOUR' => 1, 'SQL_TSI_WEEK' => 1, 'SQL_TSI_YEAR' => 1, 'INSERT_METHOD' => 1, 'MASTER_SSL_CA' => 1, 'RELAY_LOG_POS' => 1, - 'SQL_TSI_MONTH' => 1, + 'SQL_TSI_MONTH' => 1, 'SUBPARTITIONS' => 1, 'AUTO_INCREMENT' => 1, 'AVG_ROW_LENGTH' => 1, 'MASTER_LOG_POS' => 1, 'MASTER_SSL_KEY' => 1, 'RAID_CHUNKSIZE' => 1, 'RELAY_LOG_FILE' => 1, 'SQL_TSI_MINUTE' => 1, 'SQL_TSI_SECOND' => 1, 'USER_RESOURCES' => 1, @@ -145,12 +144,16 @@ class ContextMySql50000 extends Context 'GROUP BY' => 7, 'NOT NULL' => 7, 'ORDER BY' => 7, 'SET NULL' => 7, 'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7, - 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7, - 'INNER JOIN' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7, - 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'SQL SECURITY' => 7, + 'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7, + 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, + 'RIGHT JOIN' => 7, + 'LINEAR HASH' => 7, + 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7, + 'SQL SECURITY' => 7, 'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7, 'DATA DIRECTORY' => 7, 'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7, + 'SUBPARTITION BY' => 7, 'GENERATED ALWAYS' => 7, 'START TRANSACTION' => 7, 'SELECT TRANSACTION' => 7, @@ -160,6 +163,7 @@ class ContextMySql50000 extends Context 'XML' => 9, 'ENUM' => 9, 'TEXT' => 9, 'ARRAY' => 9, + 'SERIAL' => 9, 'BOOLEAN' => 9, 'DATETIME' => 9, 'MULTISET' => 9, diff --git a/libraries/sql-parser/src/Contexts/ContextMySql50100.php b/libraries/sql-parser/src/Contexts/ContextMySql50100.php index c71ff6cc22..8da3d06152 100644 --- a/libraries/sql-parser/src/Contexts/ContextMySql50100.php +++ b/libraries/sql-parser/src/Contexts/ContextMySql50100.php @@ -57,9 +57,9 @@ class ContextMySql50100 extends Context 'IMPORT' => 1, 'INNODB' => 1, 'ISSUER' => 1, 'LEAVES' => 1, 'MASTER' => 1, 'MEDIUM' => 1, 'MEMORY' => 1, 'MODIFY' => 1, 'OFFSET' => 1, 'PARSER' => 1, 'PLUGIN' => 1, 'RELOAD' => 1, 'REMOVE' => 1, 'REPAIR' => 1, 'RESUME' => 1, - 'ROLLUP' => 1, 'SERIAL' => 1, 'SERVER' => 1, 'SIGNED' => 1, 'SIMPLE' => 1, - 'SOCKET' => 1, 'SONAME' => 1, 'SOUNDS' => 1, 'SOURCE' => 1, 'STARTS' => 1, - 'STATUS' => 1, 'STRING' => 1, 'TABLES' => 1, + 'ROLLUP' => 1, 'SERVER' => 1, 'SIGNED' => 1, 'SIMPLE' => 1, 'SOCKET' => 1, + 'SONAME' => 1, 'SOUNDS' => 1, 'SOURCE' => 1, 'STARTS' => 1, 'STATUS' => 1, + 'STRING' => 1, 'TABLES' => 1, 'AGAINST' => 1, 'AUTHORS' => 1, 'CHANGED' => 1, 'COLUMNS' => 1, 'COMMENT' => 1, 'COMPACT' => 1, 'CONTEXT' => 1, 'DEFINER' => 1, 'DISABLE' => 1, 'DISCARD' => 1, 'DYNAMIC' => 1, 'ENGINES' => 1, 'EXECUTE' => 1, 'HANDLER' => 1, 'INDEXES' => 1, @@ -157,12 +157,16 @@ class ContextMySql50100 extends Context 'GROUP BY' => 7, 'NOT NULL' => 7, 'ORDER BY' => 7, 'SET NULL' => 7, 'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7, - 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7, - 'INNER JOIN' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7, - 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'SQL SECURITY' => 7, + 'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7, + 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, + 'RIGHT JOIN' => 7, + 'LINEAR HASH' => 7, + 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7, + 'SQL SECURITY' => 7, 'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7, 'DATA DIRECTORY' => 7, 'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7, + 'SUBPARTITION BY' => 7, 'GENERATED ALWAYS' => 7, 'START TRANSACTION' => 7, 'SELECT TRANSACTION' => 7, @@ -172,6 +176,7 @@ class ContextMySql50100 extends Context 'XML' => 9, 'ENUM' => 9, 'TEXT' => 9, 'ARRAY' => 9, + 'SERIAL' => 9, 'BOOLEAN' => 9, 'DATETIME' => 9, 'MULTISET' => 9, diff --git a/libraries/sql-parser/src/Contexts/ContextMySql50500.php b/libraries/sql-parser/src/Contexts/ContextMySql50500.php index 6f6bb66af6..16207dcb15 100644 --- a/libraries/sql-parser/src/Contexts/ContextMySql50500.php +++ b/libraries/sql-parser/src/Contexts/ContextMySql50500.php @@ -57,9 +57,9 @@ class ContextMySql50500 extends Context 'IMPORT' => 1, 'INNODB' => 1, 'ISSUER' => 1, 'LEAVES' => 1, 'MASTER' => 1, 'MEDIUM' => 1, 'MEMORY' => 1, 'MODIFY' => 1, 'OFFSET' => 1, 'PARSER' => 1, 'PLUGIN' => 1, 'RELOAD' => 1, 'REMOVE' => 1, 'REPAIR' => 1, 'RESUME' => 1, - 'ROLLUP' => 1, 'SERIAL' => 1, 'SERVER' => 1, 'SIGNED' => 1, 'SIMPLE' => 1, - 'SOCKET' => 1, 'SONAME' => 1, 'SOUNDS' => 1, 'SOURCE' => 1, 'STARTS' => 1, - 'STATUS' => 1, 'STRING' => 1, 'TABLES' => 1, + 'ROLLUP' => 1, 'SERVER' => 1, 'SIGNED' => 1, 'SIMPLE' => 1, 'SOCKET' => 1, + 'SONAME' => 1, 'SOUNDS' => 1, 'SOURCE' => 1, 'STARTS' => 1, 'STATUS' => 1, + 'STRING' => 1, 'TABLES' => 1, 'AGAINST' => 1, 'AUTHORS' => 1, 'CHANGED' => 1, 'COLUMNS' => 1, 'COMMENT' => 1, 'COMPACT' => 1, 'CONTEXT' => 1, 'DEFINER' => 1, 'DISABLE' => 1, 'DISCARD' => 1, 'DYNAMIC' => 1, 'ENGINES' => 1, 'EXECUTE' => 1, 'GENERAL' => 1, 'HANDLER' => 1, @@ -162,12 +162,16 @@ class ContextMySql50500 extends Context 'GROUP BY' => 7, 'NOT NULL' => 7, 'ORDER BY' => 7, 'SET NULL' => 7, 'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7, - 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7, - 'INNER JOIN' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7, - 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'SQL SECURITY' => 7, + 'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7, + 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, + 'RIGHT JOIN' => 7, + 'LINEAR HASH' => 7, + 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7, + 'SQL SECURITY' => 7, 'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7, 'DATA DIRECTORY' => 7, 'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7, + 'SUBPARTITION BY' => 7, 'GENERATED ALWAYS' => 7, 'START TRANSACTION' => 7, 'SELECT TRANSACTION' => 7, @@ -177,6 +181,7 @@ class ContextMySql50500 extends Context 'XML' => 9, 'ENUM' => 9, 'TEXT' => 9, 'ARRAY' => 9, + 'SERIAL' => 9, 'BOOLEAN' => 9, 'DATETIME' => 9, 'MULTISET' => 9, diff --git a/libraries/sql-parser/src/Contexts/ContextMySql50600.php b/libraries/sql-parser/src/Contexts/ContextMySql50600.php index 62b75abae1..4165140516 100644 --- a/libraries/sql-parser/src/Contexts/ContextMySql50600.php +++ b/libraries/sql-parser/src/Contexts/ContextMySql50600.php @@ -57,9 +57,9 @@ class ContextMySql50600 extends Context 'GLOBAL' => 1, 'GRANTS' => 1, 'IMPORT' => 1, 'ISSUER' => 1, 'LEAVES' => 1, 'MASTER' => 1, 'MEDIUM' => 1, 'MEMORY' => 1, 'MODIFY' => 1, 'NUMBER' => 1, 'OFFSET' => 1, 'PARSER' => 1, 'PLUGIN' => 1, 'RELOAD' => 1, 'REMOVE' => 1, - 'REPAIR' => 1, 'RESUME' => 1, 'ROLLUP' => 1, 'SERIAL' => 1, 'SERVER' => 1, - 'SIGNED' => 1, 'SIMPLE' => 1, 'SOCKET' => 1, 'SONAME' => 1, 'SOUNDS' => 1, - 'SOURCE' => 1, 'STARTS' => 1, 'STATUS' => 1, 'STRING' => 1, 'TABLES' => 1, + 'REPAIR' => 1, 'RESUME' => 1, 'ROLLUP' => 1, 'SERVER' => 1, 'SIGNED' => 1, + 'SIMPLE' => 1, 'SOCKET' => 1, 'SONAME' => 1, 'SOUNDS' => 1, 'SOURCE' => 1, + 'STARTS' => 1, 'STATUS' => 1, 'STRING' => 1, 'TABLES' => 1, 'AGAINST' => 1, 'ANALYSE' => 1, 'AUTHORS' => 1, 'CHANGED' => 1, 'COLUMNS' => 1, 'COMMENT' => 1, 'COMPACT' => 1, 'CONTEXT' => 1, 'CURRENT' => 1, 'DEFINER' => 1, 'DISABLE' => 1, 'DISCARD' => 1, 'DYNAMIC' => 1, 'ENGINES' => 1, 'EXECUTE' => 1, @@ -167,12 +167,16 @@ class ContextMySql50600 extends Context 'GROUP BY' => 7, 'NOT NULL' => 7, 'ORDER BY' => 7, 'SET NULL' => 7, 'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7, - 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7, - 'INNER JOIN' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7, - 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'SQL SECURITY' => 7, + 'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7, + 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, + 'RIGHT JOIN' => 7, + 'LINEAR HASH' => 7, + 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7, + 'SQL SECURITY' => 7, 'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7, 'DATA DIRECTORY' => 7, 'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7, + 'SUBPARTITION BY' => 7, 'GENERATED ALWAYS' => 7, 'START TRANSACTION' => 7, 'SELECT TRANSACTION' => 7, @@ -182,6 +186,7 @@ class ContextMySql50600 extends Context 'XML' => 9, 'ENUM' => 9, 'TEXT' => 9, 'ARRAY' => 9, + 'SERIAL' => 9, 'BOOLEAN' => 9, 'DATETIME' => 9, 'MULTISET' => 9, diff --git a/libraries/sql-parser/src/Contexts/ContextMySql50700.php b/libraries/sql-parser/src/Contexts/ContextMySql50700.php index 8b0568b0cd..7d75a728a0 100644 --- a/libraries/sql-parser/src/Contexts/ContextMySql50700.php +++ b/libraries/sql-parser/src/Contexts/ContextMySql50700.php @@ -58,9 +58,9 @@ class ContextMySql50700 extends Context 'ISSUER' => 1, 'LEAVES' => 1, 'MASTER' => 1, 'MEDIUM' => 1, 'MEMORY' => 1, 'MODIFY' => 1, 'NUMBER' => 1, 'OFFSET' => 1, 'PARSER' => 1, 'PLUGIN' => 1, 'RELOAD' => 1, 'REMOVE' => 1, 'REPAIR' => 1, 'RESUME' => 1, 'ROLLUP' => 1, - 'SERIAL' => 1, 'SERVER' => 1, 'SIGNED' => 1, 'SIMPLE' => 1, 'SOCKET' => 1, - 'SONAME' => 1, 'SOUNDS' => 1, 'SOURCE' => 1, 'STARTS' => 1, 'STATUS' => 1, - 'STRING' => 1, 'TABLES' => 1, + 'SERVER' => 1, 'SIGNED' => 1, 'SIMPLE' => 1, 'SOCKET' => 1, 'SONAME' => 1, + 'SOUNDS' => 1, 'SOURCE' => 1, 'STARTS' => 1, 'STATUS' => 1, 'STRING' => 1, + 'TABLES' => 1, 'ACCOUNT' => 1, 'AGAINST' => 1, 'ANALYSE' => 1, 'CHANGED' => 1, 'CHANNEL' => 1, 'COLUMNS' => 1, 'COMMENT' => 1, 'COMPACT' => 1, 'CONTEXT' => 1, 'CURRENT' => 1, 'DEFINER' => 1, 'DISABLE' => 1, 'DISCARD' => 1, 'DYNAMIC' => 1, 'ENGINES' => 1, @@ -175,12 +175,16 @@ class ContextMySql50700 extends Context 'GROUP BY' => 7, 'NOT NULL' => 7, 'ORDER BY' => 7, 'SET NULL' => 7, 'AND CHAIN' => 7, 'FULL JOIN' => 7, 'IF EXISTS' => 7, 'LEFT JOIN' => 7, - 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7, - 'INNER JOIN' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, 'RIGHT JOIN' => 7, - 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'SQL SECURITY' => 7, + 'LESS THAN' => 7, 'NO ACTION' => 7, 'ON DELETE' => 7, 'ON UPDATE' => 7, + 'INNER JOIN' => 7, 'LINEAR KEY' => 7, 'NO RELEASE' => 7, 'OR REPLACE' => 7, + 'RIGHT JOIN' => 7, + 'LINEAR HASH' => 7, + 'AND NO CHAIN' => 7, 'FOR EACH ROW' => 7, 'PARTITION BY' => 7, + 'SQL SECURITY' => 7, 'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7, 'DATA DIRECTORY' => 7, 'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7, + 'SUBPARTITION BY' => 7, 'GENERATED ALWAYS' => 7, 'START TRANSACTION' => 7, 'SELECT TRANSACTION' => 7, @@ -190,6 +194,7 @@ class ContextMySql50700 extends Context 'XML' => 9, 'ENUM' => 9, 'TEXT' => 9, 'ARRAY' => 9, + 'SERIAL' => 9, 'BOOLEAN' => 9, 'DATETIME' => 9, 'MULTISET' => 9, diff --git a/libraries/sql-parser/src/Lexer.php b/libraries/sql-parser/src/Lexer.php index b969a1959a..1d1839957e 100644 --- a/libraries/sql-parser/src/Lexer.php +++ b/libraries/sql-parser/src/Lexer.php @@ -42,6 +42,7 @@ namespace SqlParser { /** * Forces usage of `UtfString` if the string is multibyte. * `UtfString` may be slower, but it gives better results. + * * @var bool */ define('USE_UTF_STRINGS', true); @@ -242,13 +243,16 @@ namespace SqlParser { /** * Last processed token. + * * @var Token $lastToken */ $lastToken = null; for ($this->last = 0, $lastIdx = 0; $this->last < $this->len; $lastIdx = ++$this->last) { + /** * The new token. + * * @var Token $token */ $token = null; @@ -392,23 +396,27 @@ namespace SqlParser { /** * Value to be returned. + * * @var Token $ret */ $ret = null; /** * The value of `$this->last` where `$token` ends in `$this->str`. + * * @var int $iEnd */ $iEnd = $this->last; /** * Whether last parsed character is a whitespace. + * * @var bool $lastSpace */ $lastSpace = false; for ($j = 1; $j < Context::KEYWORD_MAX_LENGTH && $this->last < $this->len; ++$j, ++$this->last) { + // Composed keywords shouldn't have more than one whitespace between // keywords. if (Context::isWhitespace($this->str[$this->last])) { @@ -426,6 +434,7 @@ namespace SqlParser { if (($flags = Context::isKeyword($token))) { $ret = new Token($token, Token::TYPE_KEYWORD, $flags); $iEnd = $this->last; + // We don't break so we find longest keyword. // For example, `OR` and `ORDER` have a common prefix `OR`. // If we stopped at `OR`, the parsing would be invalid. @@ -448,12 +457,14 @@ namespace SqlParser { /** * Value to be returned. + * * @var Token $ret */ $ret = null; /** * The value of `$this->last` where `$token` ends in `$this->str`. + * * @var int $iEnd */ $iEnd = $this->last; @@ -799,7 +810,11 @@ namespace SqlParser { } if ($flags & Token::FLAG_SYMBOL_VARIABLE) { - ++$this->last; + if ($this->str[++$this->last] === '@') { + // This is a system variable (e.g. `@@hostname`). + $token .= $this->str[$this->last++]; + $flags |= Token::FLAG_SYMBOL_SYSTEM; + } } else { $token = ''; } diff --git a/libraries/sql-parser/src/Parser.php b/libraries/sql-parser/src/Parser.php index d6d391bd7c..5b74f33982 100644 --- a/libraries/sql-parser/src/Parser.php +++ b/libraries/sql-parser/src/Parser.php @@ -113,153 +113,158 @@ namespace SqlParser { */ public static $KEYWORD_PARSERS = array( - // This is not a proper keyword and was added here to help the builder. - '_OPTIONS' => array( - 'class' => 'SqlParser\\Components\\OptionsArray', - 'field' => 'options', + // This is not a proper keyword and was added here to help the + // formatter. + 'PARTITION BY' => array(), + 'SUBPARTITION BY' => array(), + + // This is not a proper keyword and was added here to help the + // builder. + '_OPTIONS' => array( + 'class' => 'SqlParser\\Components\\OptionsArray', + 'field' => 'options', + ), + 'UNION' => array( + 'class' => 'SqlParser\\Components\\UnionKeyword', + 'field' => 'union', ), - // This is used only for building. - 'UNION' => array( - 'class' => 'SqlParser\\Components\\UnionKeyword', - 'field' => 'union', + // Actual clause parsers. + 'ALTER' => array( + 'class' => 'SqlParser\\Components\\Expression', + 'field' => 'table', + 'options' => array('skipColumn' => true), ), - - 'ALTER' => array( - 'class' => 'SqlParser\\Components\\Expression', - 'field' => 'table', - 'options' => array('skipColumn' => true), + 'ANALYZE' => array( + 'class' => 'SqlParser\\Components\\ExpressionArray', + 'field' => 'tables', + 'options' => array('skipColumn' => true), ), - 'ANALYZE' => array( - 'class' => 'SqlParser\\Components\\ExpressionArray', - 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'BACKUP' => array( + 'class' => 'SqlParser\\Components\\ExpressionArray', + 'field' => 'tables', + 'options' => array('skipColumn' => true), ), - 'BACKUP' => array( - 'class' => 'SqlParser\\Components\\ExpressionArray', - 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'CALL' => array( + 'class' => 'SqlParser\\Components\\FunctionCall', + 'field' => 'call', ), - 'CALL' => array( - 'class' => 'SqlParser\\Components\\FunctionCall', - 'field' => 'call', + 'CHECK' => array( + 'class' => 'SqlParser\\Components\\ExpressionArray', + 'field' => 'tables', + 'options' => array('skipColumn' => true), ), - 'CHECK' => array( - 'class' => 'SqlParser\\Components\\ExpressionArray', - 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'CHECKSUM' => array( + 'class' => 'SqlParser\\Components\\ExpressionArray', + 'field' => 'tables', + 'options' => array('skipColumn' => true), ), - 'CHECKSUM' => array( - 'class' => 'SqlParser\\Components\\ExpressionArray', - 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'DROP' => array( + 'class' => 'SqlParser\\Components\\ExpressionArray', + 'field' => 'fields', + 'options' => array('skipColumn' => true), ), - 'DROP' => array( - 'class' => 'SqlParser\\Components\\ExpressionArray', - 'field' => 'fields', - 'options' => array('skipColumn' => true), + 'FROM' => array( + 'class' => 'SqlParser\\Components\\ExpressionArray', + 'field' => 'from', + 'options' => array('skipColumn' => true), ), - 'FROM' => array( - 'class' => 'SqlParser\\Components\\ExpressionArray', - 'field' => 'from', - 'options' => array('skipColumn' => true), + 'GROUP BY' => array( + 'class' => 'SqlParser\\Components\\OrderKeyword', + 'field' => 'group', ), - 'GROUP BY' => array( - 'class' => 'SqlParser\\Components\\OrderKeyword', - 'field' => 'group', + 'HAVING' => array( + 'class' => 'SqlParser\\Components\\Condition', + 'field' => 'having', ), - 'HAVING' => array( - 'class' => 'SqlParser\\Components\\Condition', - 'field' => 'having', + 'INTO' => array( + 'class' => 'SqlParser\\Components\\IntoKeyword', + 'field' => 'into', ), - 'INTO' => array( - 'class' => 'SqlParser\\Components\\IntoKeyword', - 'field' => 'into', + 'JOIN' => array( + 'class' => 'SqlParser\\Components\\JoinKeyword', + 'field' => 'join', ), - 'JOIN' => array( - 'class' => 'SqlParser\\Components\\JoinKeyword', - 'field' => 'join', + 'LEFT JOIN' => array( + 'class' => 'SqlParser\\Components\\JoinKeyword', + 'field' => 'join', ), - 'LEFT JOIN' => array( - 'class' => 'SqlParser\\Components\\JoinKeyword', - 'field' => 'join', + 'RIGHT JOIN' => array( + 'class' => 'SqlParser\\Components\\JoinKeyword', + 'field' => 'join', ), - 'RIGHT JOIN' => array( - 'class' => 'SqlParser\\Components\\JoinKeyword', - 'field' => 'join', + 'INNER JOIN' => array( + 'class' => 'SqlParser\\Components\\JoinKeyword', + 'field' => 'join', ), - 'INNER JOIN' => array( - 'class' => 'SqlParser\\Components\\JoinKeyword', - 'field' => 'join', + 'FULL JOIN' => array( + 'class' => 'SqlParser\\Components\\JoinKeyword', + 'field' => 'join', ), - 'FULL JOIN' => array( - 'class' => 'SqlParser\\Components\\JoinKeyword', - 'field' => 'join', + 'LIMIT' => array( + 'class' => 'SqlParser\\Components\\Limit', + 'field' => 'limit', ), - 'LIMIT' => array( - 'class' => 'SqlParser\\Components\\Limit', - 'field' => 'limit', + 'OPTIMIZE' => array( + 'class' => 'SqlParser\\Components\\ExpressionArray', + 'field' => 'tables', + 'options' => array('skipColumn' => true), ), - 'OPTIMIZE' => array( - 'class' => 'SqlParser\\Components\\ExpressionArray', - 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'ORDER BY' => array( + 'class' => 'SqlParser\\Components\\OrderKeyword', + 'field' => 'order', ), - 'ORDER BY' => array( - 'class' => 'SqlParser\\Components\\OrderKeyword', - 'field' => 'order', + 'PARTITION' => array( + 'class' => 'SqlParser\\Components\\ArrayObj', + 'field' => 'partition', ), - 'PARTITION' => array( - 'class' => 'SqlParser\\Components\\ArrayObj', - 'field' => 'partition', + 'PROCEDURE' => array( + 'class' => 'SqlParser\\Components\\FunctionCall', + 'field' => 'procedure', ), - 'PROCEDURE' => array( - 'class' => 'SqlParser\\Components\\FunctionCall', - 'field' => 'procedure', + 'RENAME' => array( + 'class' => 'SqlParser\\Components\\RenameOperation', + 'field' => 'renames', ), - 'RENAME' => array( - 'class' => 'SqlParser\\Components\\RenameOperation', - 'field' => 'renames', + 'REPAIR' => array( + 'class' => 'SqlParser\\Components\\ExpressionArray', + 'field' => 'tables', + 'options' => array('skipColumn' => true), ), - 'REPAIR' => array( - 'class' => 'SqlParser\\Components\\ExpressionArray', - 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'RESTORE' => array( + 'class' => 'SqlParser\\Components\\ExpressionArray', + 'field' => 'tables', + 'options' => array('skipColumn' => true), ), - 'RESTORE' => array( - 'class' => 'SqlParser\\Components\\ExpressionArray', - 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'SET' => array( + 'class' => 'SqlParser\\Components\\SetOperation', + 'field' => 'set', ), - 'SET' => array( - 'class' => 'SqlParser\\Components\\SetOperation', - 'field' => 'set', + 'SELECT' => array( + 'class' => 'SqlParser\\Components\\ExpressionArray', + 'field' => 'expr', ), - 'SELECT' => array( - 'class' => 'SqlParser\\Components\\ExpressionArray', - 'field' => 'expr', + 'TRUNCATE' => array( + 'class' => 'SqlParser\\Components\\Expression', + 'field' => 'table', + 'options' => array('skipColumn' => true), ), - 'TRUNCATE' => array( - 'class' => 'SqlParser\\Components\\Expression', - 'field' => 'table', - 'options' => array('skipColumn' => true), + 'UPDATE' => array( + 'class' => 'SqlParser\\Components\\ExpressionArray', + 'field' => 'tables', + 'options' => array('skipColumn' => true), ), - 'UPDATE' => array( - 'class' => 'SqlParser\\Components\\ExpressionArray', - 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'VALUE' => array( + 'class' => 'SqlParser\\Components\\Array2d', + 'field' => 'values', ), - 'VALUE' => array( - 'class' => 'SqlParser\\Components\\Array2d', - 'field' => 'values', + 'VALUES' => array( + 'class' => 'SqlParser\\Components\\Array2d', + 'field' => 'values', ), - 'VALUES' => array( - 'class' => 'SqlParser\\Components\\Array2d', - 'field' => 'values', - ), - 'WHERE' => array( - 'class' => 'SqlParser\\Components\\Condition', - 'field' => 'where', + 'WHERE' => array( + 'class' => 'SqlParser\\Components\\Condition', + 'field' => 'where', ), ); @@ -304,7 +309,7 @@ namespace SqlParser { * Constructor. * * @param string|UtfString|TokensList $list The list of tokens to be parsed. - * @param bool $strict Whether strict mode should be enabled or not. + * @param bool $strict Whether strict mode should be enabled or not. */ public function __construct($list = null, $strict = false) { @@ -332,30 +337,35 @@ namespace SqlParser { /** * Last transaction. + * * @var TransactionStatement $lastTransaction */ $lastTransaction = null; /** * Last parsed statement. + * * @var Statement $lastStatement */ $lastStatement = null; /** * Whether a union is parsed or not. + * * @var bool $inUnion */ $inUnion = false; /** * The index of the last token from the last statement. + * * @var int $prevLastIdx */ $prevLastIdx = -1; /** * The list of tokens. + * * @var TokensList $list */ $list = &$this->list; @@ -364,6 +374,7 @@ namespace SqlParser { /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; @@ -419,12 +430,14 @@ namespace SqlParser { /** * The name of the class that is used for parsing. + * * @var string $class */ $class = static::$STATEMENT_PARSERS[$token->value]; /** * Processed statement. + * * @var Statement $statement */ $statement = new $class($this, $this->list); @@ -445,13 +458,16 @@ namespace SqlParser { && ($lastStatement instanceof SelectStatement) && ($statement instanceof SelectStatement) ) { + /** * This SELECT statement. + * * @var SelectStatement $statement */ /** * Last SELECT statement. + * * @var SelectStatement $lastStatement */ $lastStatement->union[] = $statement; diff --git a/libraries/sql-parser/src/Statement.php b/libraries/sql-parser/src/Statement.php index 8bf3d24ef2..0568d93773 100644 --- a/libraries/sql-parser/src/Statement.php +++ b/libraries/sql-parser/src/Statement.php @@ -103,6 +103,7 @@ abstract class Statement { /** * Query to be returned. + * * @var string $query */ $query = ''; @@ -111,12 +112,14 @@ abstract class Statement /** * The name of the clause. + * * @var string $name */ $name = $clause[0]; /** * The type of the clause. + * * @see self::$CLAUSES * @var int $type */ @@ -124,6 +127,7 @@ abstract class Statement /** * The builder (parser) of this clause. + * * @var Component $class */ $class = Parser::$KEYWORD_PARSERS[$name]['class']; @@ -131,6 +135,7 @@ abstract class Statement /** * The name of the field that is used as source for the builder. * Same field is used to store the result of parsing. + * * @var string $field */ $field = Parser::$KEYWORD_PARSERS[$name]['field']; @@ -167,7 +172,8 @@ abstract class Statement /** * Array containing all list of clauses parsed. * This is used to check for duplicates. - * @var array + * + * @var array $parsedClauses */ $parsedClauses = array(); @@ -178,13 +184,16 @@ abstract class Statement * Whether options were parsed or not. * For statements that do not have any options this is set to `true` by * default. + * * @var bool $parsedOptions */ $parsedOptions = empty(static::$OPTIONS); for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; @@ -213,18 +222,21 @@ abstract class Statement /** * The name of the class that is used for parsing. + * * @var Component $class */ $class = null; /** * The name of the field where the result of the parsing is stored. + * * @var string $field */ $field = null; /** * Parser's options. + * * @var array $options */ $options = array(); diff --git a/libraries/sql-parser/src/Statements/AlterStatement.php b/libraries/sql-parser/src/Statements/AlterStatement.php index 2c48181152..31bbcb4540 100644 --- a/libraries/sql-parser/src/Statements/AlterStatement.php +++ b/libraries/sql-parser/src/Statements/AlterStatement.php @@ -89,13 +89,15 @@ class AlterStatement extends Statement * * 1 -------------------------[ , ]-----------------------> 0 * - * @var int + * @var int $state */ $state = 0; for (; $list->idx < $list->count; ++$list->idx) { + /** * Token parsed at this moment. + * * @var Token $token */ $token = $list->tokens[$list->idx]; diff --git a/libraries/sql-parser/src/Statements/CreateStatement.php b/libraries/sql-parser/src/Statements/CreateStatement.php index 4c0d985d47..bc7cf7355f 100644 --- a/libraries/sql-parser/src/Statements/CreateStatement.php +++ b/libraries/sql-parser/src/Statements/CreateStatement.php @@ -15,6 +15,7 @@ use SqlParser\TokensList; use SqlParser\Components\ArrayObj; use SqlParser\Components\DataType; use SqlParser\Components\CreateDefinition; +use SqlParser\Components\PartitionDefinition; use SqlParser\Components\Expression; use SqlParser\Components\OptionsArray; use SqlParser\Components\ParameterDefinition; @@ -173,6 +174,41 @@ class CreateStatement extends Statement */ public $fields; + /** + * Expression used for partitioning. + * + * @var string + */ + public $partitionBy; + + /** + * The number of partitions. + * + * @var int + */ + public $partitionsNum; + + /** + * Expression used for subpartitioning. + * + * @var string + */ + public $subpartitionBy; + + /** + * The number of subpartitions. + * + * @var int + */ + public $subpartitionsNum; + + /** + * The partition of the new table. + * + * @var PartitionDefinition[] + */ + public $partitions; + /** * If `CREATE TRIGGER` the name of the table. * @@ -229,11 +265,30 @@ class CreateStatement extends Statement . Expression::build($this->name) . ' ' . OptionsArray::build($this->entityOptions); } elseif ($this->options->has('TABLE')) { + $partition = ''; + + if (!empty($this->partitionBy)) { + $partition .= "\nPARTITION BY " . $this->partitionBy; + } + if (!empty($this->partitionsNum)) { + $partition .= "\nPARTITIONS " . $this->partitionsNum; + } + if (!empty($this->subpartitionBy)) { + $partition .= "\nSUBPARTITION BY " . $this->subpartitionBy; + } + if (!empty($this->subpartitionsNum)) { + $partition .= "\nSUBPARTITIONS " . $this->subpartitionsNum; + } + if (!empty($this->partitions)) { + $partition .= "\n" . PartitionDefinition::build($this->partitions); + } + return 'CREATE ' . OptionsArray::build($this->options) . ' ' . Expression::build($this->name) . ' ' . $fields - . OptionsArray::build($this->entityOptions); + . OptionsArray::build($this->entityOptions) + . $partition; } elseif ($this->options->has('VIEW')) { return 'CREATE ' . OptionsArray::build($this->options) . ' ' @@ -318,6 +373,100 @@ class CreateStatement extends Statement $list, static::$TABLE_OPTIONS ); + + /** + * The field that is being filled (`partitionBy` or + * `subpartitionBy`). + * + * @var string $field + */ + $field = null; + + /** + * The number of brackets. `false` means no bracket was found + * previously. At least one bracket is required to validate the + * expression. + * + * @var int|bool $brackets + */ + $brackets = false; + + /* + * Handles partitions. + */ + for (; $list->idx < $list->count; ++$list->idx) { + + /** + * Token parsed at this moment. + * + * @var Token $token + */ + $token = $list->tokens[$list->idx]; + + // End of statement. + if ($token->type === Token::TYPE_DELIMITER) { + break; + } + + // Skipping comments. + if ($token->type === Token::TYPE_COMMENT) { + continue; + } + + if (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'PARTITION BY')) { + $field = 'partitionBy'; + $brackets = false; + } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'SUBPARTITION BY')) { + $field = 'subpartitionBy'; + $brackets = false; + } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'PARTITIONS')) { + $token = $list->getNextOfType(Token::TYPE_NUMBER); + --$list->idx; // `getNextOfType` also advances one position. + $this->partitionsNum = $token->value; + } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'SUBPARTITIONS')) { + $token = $list->getNextOfType(Token::TYPE_NUMBER); + --$list->idx; // `getNextOfType` also advances one position. + $this->subpartitionsNum = $token->value; + } elseif (!empty($field)) { + + /* + * Handling the content of `PARTITION BY` and `SUBPARTITION BY`. + */ + + // Counting brackets. + if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) { + // This is used instead of `++$brackets` because, + // initially, `$brackets` is `false` cannot be + // incremented. + $brackets = $brackets + 1; + } elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === ')')) { + --$brackets; + } + + // Building the expression used for partitioning. + $this->$field .= ($token->type === Token::TYPE_WHITESPACE) ? ' ' : $token->token; + + // Last bracket was read, the expression ended. + // Comparing with `0` and not `false`, because `false` means + // that no bracket was found and at least one must is + // required. + if ($brackets === 0) { + $this->$field = trim($this->$field); + $field = null; + } + } elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) { + if (!empty($this->partitionBy)) { + $this->partitions = ArrayObj::parse( + $parser, + $list, + array( + 'type' => 'SqlParser\\Components\\PartitionDefinition' + ) + ); + } + break; + } + } } elseif (($this->options->has('PROCEDURE')) || ($this->options->has('FUNCTION')) ) { diff --git a/libraries/sql-parser/src/Token.php b/libraries/sql-parser/src/Token.php index 3c36d1c375..d5343212cb 100644 --- a/libraries/sql-parser/src/Token.php +++ b/libraries/sql-parser/src/Token.php @@ -157,6 +157,7 @@ class Token const FLAG_SYMBOL_VARIABLE = 1; const FLAG_SYMBOL_BACKTICK = 2; const FLAG_SYMBOL_USER = 4; + const FLAG_SYMBOL_SYSTEM = 8; /** * The token it its raw string representation. @@ -256,7 +257,12 @@ class Token if ((isset($str[0])) && ($str[0] === '@')) { // `mb_strlen($str)` must be used instead of `null` because // in PHP 5.3- the `null` parameter isn't handled correctly. - $str = mb_substr($str, 1, mb_strlen($str), 'UTF-8'); + $str = mb_substr( + $str, + ((!empty($str[1])) && ($str[1] === '@')) ? 2 : 1, + mb_strlen($str), + 'UTF-8' + ); } if ((isset($str[0])) && (($str[0] === '`') || ($str[0] === '"') || ($str[0] === '\'')) diff --git a/libraries/sql-parser/src/Utils/BufferedQuery.php b/libraries/sql-parser/src/Utils/BufferedQuery.php index e308fb2248..e58165ab27 100644 --- a/libraries/sql-parser/src/Utils/BufferedQuery.php +++ b/libraries/sql-parser/src/Utils/BufferedQuery.php @@ -91,14 +91,17 @@ class BufferedQuery // Merges specified options with defaults. $this->options = array_merge( array( + /** * The starting delimiter. + * * @var string */ 'delimiter' => ';', /** * Whether `DELIMITER` statements should be parsed. + * * @var bool */ 'parse_delimiter' => false, @@ -106,6 +109,7 @@ class BufferedQuery /** * Whether a delimiter should be added at the end of the * statement. + * * @var bool */ 'add_delimiter' => false, @@ -156,6 +160,7 @@ class BufferedQuery /** * The length of the buffer. + * * @var int $len */ $len = strlen($this->query); diff --git a/libraries/sql-parser/src/Utils/Formatter.php b/libraries/sql-parser/src/Utils/Formatter.php index dc8c3af31f..998d94b2b6 100644 --- a/libraries/sql-parser/src/Utils/Formatter.php +++ b/libraries/sql-parser/src/Utils/Formatter.php @@ -41,8 +41,12 @@ class Formatter */ public static $INLINE_CLAUSES = array( 'CREATE' => true, - 'PROCEDURE' => true, 'LIMIT' => true, + 'PARTITION BY' => true, + 'PARTITION' => true, + 'PROCEDURE' => true, + 'SUBPARTITION BY' => true, + 'VALUES' => true, ); /** @@ -58,6 +62,7 @@ class Formatter /** * The format of the result. + * * @var string The type ('text', 'cli' or 'html') */ 'type' => php_sapi_name() == 'cli' ? 'cli' : 'text', @@ -65,24 +70,28 @@ class Formatter /** * The line ending used. * By default, for text this is "\n" and for HTML this is "
". + * * @var string */ 'line_ending' => $this->options['type'] == 'html' ? '
' : "\n", /** * The string used for indentation. + * * @var string */ 'indentation' => " ", /** * Whether comments should be removed or not. + * * @var bool */ 'remove_comments' => false, /** * Whether each clause should be on a new line. + * * @var bool */ 'clause_newline' => true, @@ -90,12 +99,14 @@ class Formatter /** * Whether each part should be on a new line. * Parts are delimited by brackets and commas. + * * @var bool */ 'parts_newline' => true, /** * Whether each part of each clause should be indented. + * * @var bool */ 'indent_parts' => true, @@ -103,6 +114,7 @@ class Formatter /** * The styles used for HTML formatting. * array($type, $flags, $span, $callback) + * * @var array[] */ 'formats' => array( @@ -176,24 +188,28 @@ class Formatter /** * The query to be returned. + * * @var string $ret */ $ret = ''; /** * The indentation level. + * * @var int $indent */ $indent = 0; /** * Whether the line ended. + * * @var bool $lineEnded */ $lineEnded = false; /** * The name of the last clause. + * * @var string $lastClause */ $lastClause = ''; @@ -201,6 +217,7 @@ class Formatter /** * A stack that keeps track of the indentation level every time a new * block is found. + * * @var array $blocksIndentation */ $blocksIndentation = array(); @@ -208,18 +225,21 @@ class Formatter /** * A stack that keeps track of the line endings every time a new block * is found. + * * @var array $blocksLineEndings */ $blocksLineEndings = array(); /** * Whether clause's options were formatted. + * * @var bool $formattedOptions */ $formattedOptions = false; /** * Previously parsed token. + * * @var Token $prev */ $prev = null; @@ -227,6 +247,7 @@ class Formatter /** * Comments are being formatted separately to maintain the whitespaces * before and after them. + * * @var string $comment */ $comment = ''; @@ -239,6 +260,7 @@ class Formatter /** * Token parsed at this moment. + * * @var Token $curr */ $curr = $list->tokens[$list->idx]; @@ -368,7 +390,7 @@ class Formatter if (!((($prev->type === Token::TYPE_OPERATOR) && (($prev->value === '.') || ($prev->value === '('))) // No space after . ( || (($curr->type === Token::TYPE_OPERATOR) && (($curr->value === '.') || ($curr->value === ',') || ($curr->value === '(') || ($curr->value === ')'))) - // No space before . , ) + // No space before . , ( ) || (($curr->type === Token::TYPE_DELIMITER)) && (mb_strlen($curr->value, 'UTF-8') < 2)) // A space after delimiters that are longer than 2 characters. || ($prev->value === 'DELIMITER') @@ -461,13 +483,15 @@ class Formatter * This counter starts at one because by the time this function called, * the list already advanced one position and the opening bracket was * already parsed. - * @var int + * + * @var int $count */ $count = 1; /** * The length of this group. - * @var int + * + * @var int $length */ $length = 0; diff --git a/libraries/sql-parser/src/Utils/Misc.php b/libraries/sql-parser/src/Utils/Misc.php index 2107172317..1597648500 100644 --- a/libraries/sql-parser/src/Utils/Misc.php +++ b/libraries/sql-parser/src/Utils/Misc.php @@ -47,7 +47,8 @@ class Misc /** * Expressions that may contain aliases. * These are extracted from `FROM` and `JOIN` keywords. - * @var Expression[] + * + * @var Expression[] $expressions */ $expressions = $statement->from; diff --git a/libraries/sql-parser/src/Utils/Query.php b/libraries/sql-parser/src/Utils/Query.php index 6aff11de1d..5723ec6363 100644 --- a/libraries/sql-parser/src/Utils/Query.php +++ b/libraries/sql-parser/src/Utils/Query.php @@ -510,6 +510,7 @@ class Query /** * The index of the current clause. + * * @var int $currIdx */ $currIdx = 0; @@ -517,18 +518,21 @@ class Query /** * The count of brackets. * We keep track of them so we won't insert the clause in a subquery. + * * @var int $brackets */ $brackets = 0; /** * The string to be returned. + * * @var string $ret */ $ret = ''; /** * The clauses of this type of statement and their index. + * * @var array $clauses */ $clauses = array_flip(array_keys($statement::$CLAUSES)); @@ -543,18 +547,21 @@ class Query /** * Lexer used for lexing the clause. + * * @var Lexer $lexer */ $lexer = new Lexer($clause); /** * The type of this clause. + * * @var string $clauseType */ $clauseType = $lexer->list->getNextOfType(Token::TYPE_KEYWORD)->value; /** * The index of this clause. + * * @var int $clauseIdx */ $clauseIdx = $clauses[$clauseType]; @@ -680,6 +687,7 @@ class Query /** * Value to be returned. + * * @var string $ret */ $ret = ''; @@ -730,13 +738,15 @@ class Query /** * Whether a full statement was found. - * @var bool + * + * @var bool $fullStatement */ $fullStatement = false; /** * The first full statement. - * @var string + * + * @var string $statement */ $statement = '';