diff --git a/ChangeLog b/ChangeLog index 3538af8853..122544049d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -72,6 +72,8 @@ phpMyAdmin - ChangeLog - issue #11951 Silent errors on checking for writable folders - issue #11952 Silent warning on invalid file upload - issue #11953 Do not fail getting filename with open_basedir limitations +- issue #11956 unrecognized keyword interval +- issue Field names and aliases are being correctly parsed now. 4.5.4.1 (2016-01-29) - issue #11892 Error with PMA 4.4.15.3 diff --git a/libraries/sql-parser/src/Components/AlterOperation.php b/libraries/sql-parser/src/Components/AlterOperation.php index 8dad8e888e..d0b09f18bd 100644 --- a/libraries/sql-parser/src/Components/AlterOperation.php +++ b/libraries/sql-parser/src/Components/AlterOperation.php @@ -172,8 +172,8 @@ class AlterOperation extends Component $parser, $list, array( - 'noAlias' => true, - 'noBrackets' => true, + 'breakOnAlias' => true, + 'parseField' => 'column', ) ); if ($ret->field === null) { diff --git a/libraries/sql-parser/src/Components/Condition.php b/libraries/sql-parser/src/Components/Condition.php index f820c93439..f3179ead44 100644 --- a/libraries/sql-parser/src/Components/Condition.php +++ b/libraries/sql-parser/src/Components/Condition.php @@ -43,6 +43,7 @@ class Condition extends Component 'EXISTS' => 1, 'IF' => 1, 'IN' => 1, + 'INTERVAL' => 1, 'IS' => 1, 'LIKE' => 1, 'MATCH' => 1, diff --git a/libraries/sql-parser/src/Components/CreateDefinition.php b/libraries/sql-parser/src/Components/CreateDefinition.php index 66ea4b2116..13e5e83a59 100644 --- a/libraries/sql-parser/src/Components/CreateDefinition.php +++ b/libraries/sql-parser/src/Components/CreateDefinition.php @@ -55,7 +55,7 @@ class CreateDefinition extends Component // Generated columns options. 'GENERATED ALWAYS' => 8, - 'AS' => array(9, 'expr', array('bracketsDelimited' => true)), + 'AS' => array(9, 'expr', array('parenthesesDelimited' => true)), 'VIRTUAL' => 10, 'PERSISTENT' => 11, 'STORED' => 11, diff --git a/libraries/sql-parser/src/Components/Expression.php b/libraries/sql-parser/src/Components/Expression.php index a365d321a1..f6d3895479 100644 --- a/libraries/sql-parser/src/Components/Expression.php +++ b/libraries/sql-parser/src/Components/Expression.php @@ -119,6 +119,31 @@ class Expression extends Component } /** + * Possible options: + * + * `field` + * + * First field to be filled. + * If this is not specified, it takes the value of `parseField`. + * + * `parseField` + * + * Specifies the type of the field parsed. It may be `database`, + * `table` or `column`. These expressions may not include + * parentheses. + * + * `breakOnAlias` + * + * If not empty, breaks when the alias occurs (it is not included). + * + * `breakOnParentheses` + * + * If not empty, breaks when the first parentheses occurs. + * + * `parenthesesDelimited` + * + * If not empty, breaks after last parentheses occurred. + * * @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. @@ -164,6 +189,12 @@ class Expression extends Component */ $prev = array(null, null); + // When a field is parsed, no parentheses are expected. + if (!empty($options['parseField'])) { + $options['breakOnParentheses'] = true; + $options['field'] = $options['parseField']; + } + for (; $list->idx < $list->count; ++$list->idx) { /** @@ -195,7 +226,9 @@ class Expression extends Component // A `(` was previously found and this keyword is the // beginning of a statement, so this is a subquery. $ret->subquery = $token->value; - } elseif ($token->flags & Token::FLAG_KEYWORD_FUNCTION) { + } elseif (($token->flags & Token::FLAG_KEYWORD_FUNCTION) + && (empty($options['parseField'])) + ) { $isExpr = true; } elseif (($token->flags & Token::FLAG_KEYWORD_RESERVED) && ($brackets === 0) @@ -207,7 +240,7 @@ class Expression extends Component break; } if ($token->value === 'AS') { - if (!empty($options['noAlias'])) { + if (!empty($options['breakOnAlias'])) { break; } if (!empty($ret->alias)) { @@ -224,8 +257,24 @@ class Expression extends Component } } + if (($token->type === Token::TYPE_NUMBER) + || ($token->type === Token::TYPE_BOOL) + || (($token->type === Token::TYPE_SYMBOL) + && ($token->flags & Token::FLAG_SYMBOL_VARIABLE)) + || (($token->type === Token::TYPE_OPERATOR) + && ($token->value !== '.')) + ) { + if (!empty($options['parseField'])) { + break; + } + + // Numbers, booleans and operators (except dot) are usually part + // of expressions. + $isExpr = true; + } + if ($token->type === Token::TYPE_OPERATOR) { - if ((!empty($options['noBrackets'])) + if ((!empty($options['breakOnParentheses'])) && (($token->value === '(') || ($token->value === ')')) ) { // No brackets were expected. @@ -244,7 +293,7 @@ class Expression extends Component } elseif ($token->value === ')') { --$brackets; if ($brackets === 0) { - if (!empty($options['bracketsDelimited'])) { + if (!empty($options['parenthesesDelimited'])) { // The current token is the last bracket, the next // one will be outside the expression. $ret->expr .= $token->token; @@ -264,19 +313,7 @@ class Expression extends Component } } - if (($token->type === Token::TYPE_NUMBER) - || ($token->type === Token::TYPE_BOOL) - || (($token->type === Token::TYPE_SYMBOL) - && ($token->flags & Token::FLAG_SYMBOL_VARIABLE)) - || (($token->type === Token::TYPE_OPERATOR) - && ($token->value !== '.')) - ) { - // Numbers, booleans and operators (except dot) are usually part - // of expressions. - $isExpr = true; - } - - // Saving the previous token. + // Saving the previous tokens. $prev[0] = $prev[1]; $prev[1] = $token; @@ -323,14 +360,14 @@ class Expression extends Component $dot = true; $ret->expr .= $token->token; } else { - $field = (!empty($options['skipColumn'])) ? 'table' : 'column'; + $field = empty($options['field']) ? 'column' : $options['field']; if (empty($ret->$field)) { $ret->$field = $token->value; $ret->expr .= $token->token; $dot = false; } else { // No alias is expected. - if (!empty($options['noAlias'])) { + if (!empty($options['breakOnAlias'])) { break; } if (!empty($ret->alias)) { diff --git a/libraries/sql-parser/src/Components/IntoKeyword.php b/libraries/sql-parser/src/Components/IntoKeyword.php index 1ac7be82e9..56f349feb6 100644 --- a/libraries/sql-parser/src/Components/IntoKeyword.php +++ b/libraries/sql-parser/src/Components/IntoKeyword.php @@ -107,9 +107,8 @@ class IntoKeyword extends Component $parser, $list, array( - 'noAlias' => true, - 'noBrackets' => true, - 'skipColumn' => true, + 'parseField' => 'table', + 'breakOnAlias' => true, ) ); $state = 1; diff --git a/libraries/sql-parser/src/Components/JoinKeyword.php b/libraries/sql-parser/src/Components/JoinKeyword.php index 224e802736..d8e6ee916b 100644 --- a/libraries/sql-parser/src/Components/JoinKeyword.php +++ b/libraries/sql-parser/src/Components/JoinKeyword.php @@ -128,7 +128,7 @@ class JoinKeyword extends Component break; } } elseif ($state === 1) { - $expr->expr = Expression::parse($parser, $list, array('skipColumn' => true)); + $expr->expr = Expression::parse($parser, $list, array('field' => 'table')); $state = 2; } elseif ($state === 2) { if (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'ON')) { diff --git a/libraries/sql-parser/src/Components/PartitionDefinition.php b/libraries/sql-parser/src/Components/PartitionDefinition.php index 8c54e22f83..06dc5fc0d8 100644 --- a/libraries/sql-parser/src/Components/PartitionDefinition.php +++ b/libraries/sql-parser/src/Components/PartitionDefinition.php @@ -169,8 +169,8 @@ class PartitionDefinition extends Component $parser, $list, array( - 'bracketsDelimited' => true, - 'noAlias' => true, + 'parenthesesDelimited' => true, + 'breakOnAlias' => true, ) ); } diff --git a/libraries/sql-parser/src/Components/Reference.php b/libraries/sql-parser/src/Components/Reference.php index 7dce16672f..7acd92e042 100644 --- a/libraries/sql-parser/src/Components/Reference.php +++ b/libraries/sql-parser/src/Components/Reference.php @@ -121,9 +121,8 @@ class Reference extends Component $parser, $list, array( - 'noAlias' => true, - 'skipColumn' => true, - 'noBrackets' => true, + 'parseField' => 'table', + 'breakOnAlias' => true, ) ); $state = 1; diff --git a/libraries/sql-parser/src/Components/RenameOperation.php b/libraries/sql-parser/src/Components/RenameOperation.php index 8776963ea5..c0ecf6c01b 100644 --- a/libraries/sql-parser/src/Components/RenameOperation.php +++ b/libraries/sql-parser/src/Components/RenameOperation.php @@ -93,9 +93,8 @@ class RenameOperation extends Component $parser, $list, array( - 'noAlias' => true, - 'noBrackets' => true, - 'skipColumn' => true, + 'breakOnAlias' => true, + 'parseField' => 'table', ) ); if (empty($expr->old)) { @@ -120,9 +119,8 @@ class RenameOperation extends Component $parser, $list, array( - 'noBrackets' => true, - 'skipColumn' => true, - 'noAlias' => true, + 'breakOnAlias' => true, + 'parseField' => 'table', ) ); if (empty($expr->new)) { diff --git a/libraries/sql-parser/src/Components/SetOperation.php b/libraries/sql-parser/src/Components/SetOperation.php index 38aa7f6262..9306d43995 100644 --- a/libraries/sql-parser/src/Components/SetOperation.php +++ b/libraries/sql-parser/src/Components/SetOperation.php @@ -100,7 +100,7 @@ class SetOperation extends Component $parser, $list, array( - 'noAlias' => true, + 'breakOnAlias' => true, ) ); if ($tmp == null) { diff --git a/libraries/sql-parser/src/Parser.php b/libraries/sql-parser/src/Parser.php index 2aca938a21..e878570b19 100644 --- a/libraries/sql-parser/src/Parser.php +++ b/libraries/sql-parser/src/Parser.php @@ -125,17 +125,17 @@ class Parser 'ALTER' => array( 'class' => 'SqlParser\\Components\\Expression', 'field' => 'table', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'ANALYZE' => array( 'class' => 'SqlParser\\Components\\ExpressionArray', 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'BACKUP' => array( 'class' => 'SqlParser\\Components\\ExpressionArray', 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'CALL' => array( 'class' => 'SqlParser\\Components\\FunctionCall', @@ -144,22 +144,22 @@ class Parser 'CHECK' => array( 'class' => 'SqlParser\\Components\\ExpressionArray', 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'CHECKSUM' => array( 'class' => 'SqlParser\\Components\\ExpressionArray', 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'DROP' => array( 'class' => 'SqlParser\\Components\\ExpressionArray', 'field' => 'fields', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'FROM' => array( 'class' => 'SqlParser\\Components\\ExpressionArray', 'field' => 'from', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'GROUP BY' => array( 'class' => 'SqlParser\\Components\\OrderKeyword', @@ -212,7 +212,7 @@ class Parser 'OPTIMIZE' => array( 'class' => 'SqlParser\\Components\\ExpressionArray', 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'ORDER BY' => array( 'class' => 'SqlParser\\Components\\OrderKeyword', @@ -233,12 +233,12 @@ class Parser 'REPAIR' => array( 'class' => 'SqlParser\\Components\\ExpressionArray', 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'RESTORE' => array( 'class' => 'SqlParser\\Components\\ExpressionArray', 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'SET' => array( 'class' => 'SqlParser\\Components\\SetOperation', @@ -251,12 +251,12 @@ class Parser 'TRUNCATE' => array( 'class' => 'SqlParser\\Components\\Expression', 'field' => 'table', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'UPDATE' => array( 'class' => 'SqlParser\\Components\\ExpressionArray', 'field' => 'tables', - 'options' => array('skipColumn' => true), + 'options' => array('parseField' => 'table'), ), 'VALUE' => array( 'class' => 'SqlParser\\Components\\Array2d', diff --git a/libraries/sql-parser/src/Statements/AlterStatement.php b/libraries/sql-parser/src/Statements/AlterStatement.php index 275eae7011..c8786bd603 100644 --- a/libraries/sql-parser/src/Statements/AlterStatement.php +++ b/libraries/sql-parser/src/Statements/AlterStatement.php @@ -76,8 +76,8 @@ class AlterStatement extends Statement $parser, $list, array( - 'noAlias' => true, - 'noBrackets' => true, + 'parseField' => 'column', + 'breakOnAlias' => true, ) ); ++$list->idx; // Skipping field. diff --git a/libraries/sql-parser/src/Statements/CreateStatement.php b/libraries/sql-parser/src/Statements/CreateStatement.php index fe6693bf9d..d5e23ad421 100644 --- a/libraries/sql-parser/src/Statements/CreateStatement.php +++ b/libraries/sql-parser/src/Statements/CreateStatement.php @@ -342,9 +342,8 @@ class CreateStatement extends Statement $parser, $list, array( - 'noAlias' => true, - 'noBrackets' => true, - 'skipColumn' => true, + 'parseField' => 'table', + 'breakOnAlias' => true, ) ); @@ -538,9 +537,8 @@ class CreateStatement extends Statement $parser, $list, array( - 'noAlias' => true, - 'noBrackets' => true, - 'skipColumn' => true, + 'parseField' => 'table', + 'breakOnAlias' => true, ) ); ++$list->idx;