Merge branch 'QA_4_5' into QA_4_6

This commit is contained in:
Dan Ungureanu 2016-02-12 23:46:57 +02:00
commit e21fbe665d
14 changed files with 92 additions and 58 deletions

View File

@ -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

View File

@ -172,8 +172,8 @@ class AlterOperation extends Component
$parser,
$list,
array(
'noAlias' => true,
'noBrackets' => true,
'breakOnAlias' => true,
'parseField' => 'column',
)
);
if ($ret->field === null) {

View File

@ -43,6 +43,7 @@ class Condition extends Component
'EXISTS' => 1,
'IF' => 1,
'IN' => 1,
'INTERVAL' => 1,
'IS' => 1,
'LIKE' => 1,
'MATCH' => 1,

View File

@ -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,

View File

@ -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)) {

View File

@ -107,9 +107,8 @@ class IntoKeyword extends Component
$parser,
$list,
array(
'noAlias' => true,
'noBrackets' => true,
'skipColumn' => true,
'parseField' => 'table',
'breakOnAlias' => true,
)
);
$state = 1;

View File

@ -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')) {

View File

@ -169,8 +169,8 @@ class PartitionDefinition extends Component
$parser,
$list,
array(
'bracketsDelimited' => true,
'noAlias' => true,
'parenthesesDelimited' => true,
'breakOnAlias' => true,
)
);
}

View File

@ -121,9 +121,8 @@ class Reference extends Component
$parser,
$list,
array(
'noAlias' => true,
'skipColumn' => true,
'noBrackets' => true,
'parseField' => 'table',
'breakOnAlias' => true,
)
);
$state = 1;

View File

@ -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)) {

View File

@ -100,7 +100,7 @@ class SetOperation extends Component
$parser,
$list,
array(
'noAlias' => true,
'breakOnAlias' => true,
)
);
if ($tmp == null) {

View File

@ -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',

View File

@ -76,8 +76,8 @@ class AlterStatement extends Statement
$parser,
$list,
array(
'noAlias' => true,
'noBrackets' => true,
'parseField' => 'column',
'breakOnAlias' => true,
)
);
++$list->idx; // Skipping field.

View File

@ -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;