Fix failing tests.
Updated sql-parser library. Signed-off-by: Dan Ungureanu <udan1107@gmail.com>
This commit is contained in:
parent
46e44ed0d5
commit
d2b5498565
@ -28,8 +28,7 @@ extract($analyzed_sql_results);
|
||||
if (!empty($analyzed_sql_results['select_tables'])) {
|
||||
|
||||
// Previous table and database name is stored to check if it changed.
|
||||
$prevDb = $db;
|
||||
$prevTable = $table;
|
||||
$prev_db = $db;
|
||||
|
||||
if (count($analyzed_sql_results['select_tables']) > 1) {
|
||||
|
||||
@ -50,9 +49,8 @@ if (!empty($analyzed_sql_results['select_tables'])) {
|
||||
// There is no point checking if a reload is required if we already decided
|
||||
// to reload. Also, no reload is required for AJAX requests.
|
||||
if ((empty($reload)) && (empty($GLOBALS['is_ajax_request']))) {
|
||||
// NOTE: Tables are case-insensitive.
|
||||
$reload = ((strcasecmp($db, $prevDb) == 0)
|
||||
|| (strcasecmp($table, $prevTable)) == 0) ? false : true;
|
||||
// NOTE: Database names are case-insensitive.
|
||||
$reload = strcasecmp($db, $prev_db) != 0;
|
||||
}
|
||||
|
||||
// Updating the array as well.
|
||||
|
||||
84
libraries/sql-parser/src/Builder.php
Normal file
84
libraries/sql-parser/src/Builder.php
Normal file
@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This is one of the most important components, along with the lexer and the
|
||||
* parser.
|
||||
*
|
||||
* @package SqlParser
|
||||
*/
|
||||
namespace SqlParser;
|
||||
|
||||
use SqlParser\Exceptions\ParserException;
|
||||
|
||||
/**
|
||||
* Builds the string representation of a Statement.
|
||||
*
|
||||
* @category Parser
|
||||
* @package SqlParser
|
||||
* @author Dan Ungureanu <udan1107@gmail.com>
|
||||
* @license http://opensource.org/licenses/GPL-2.0 GNU Public License
|
||||
*/
|
||||
class Builder
|
||||
{
|
||||
|
||||
/**
|
||||
* Statement to be build.
|
||||
*
|
||||
* @var Statement
|
||||
*/
|
||||
public $statement;
|
||||
|
||||
/**
|
||||
* Built query.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $query;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Statement $statement
|
||||
*/
|
||||
public function __construct($statement = null)
|
||||
{
|
||||
$this->statement = $statement;
|
||||
|
||||
if ($this->statement != null) {
|
||||
$this->build();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the statement.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function build()
|
||||
{
|
||||
$statement = $this->statement;
|
||||
foreach ($statement::$CLAUSES as $clause) {
|
||||
$name = $clause[0];
|
||||
$type = $clause[1];
|
||||
|
||||
if (empty(Parser::$KEYWORD_PARSERS[$name])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$class = Parser::$KEYWORD_PARSERS[$name]['class'];
|
||||
$field = Parser::$KEYWORD_PARSERS[$name]['field'];
|
||||
|
||||
if (empty($statement->$field)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($type & 2) {
|
||||
$this->query .= $name . ' ';
|
||||
}
|
||||
|
||||
if ($type & 1) {
|
||||
$this->query .= $class::build($statement->$field) . ' ';
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -38,4 +38,15 @@ abstract class Fragment
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds the string representation of a fragment of this type.
|
||||
*
|
||||
* @param Fragment $fragment The fragment to be built.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function build(Fragment $fragment)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -25,6 +25,13 @@ use SqlParser\TokensList;
|
||||
class ArrayFragment extends Fragment
|
||||
{
|
||||
|
||||
/**
|
||||
* The array that contains the unprocessed value of each token.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public $raw = array();
|
||||
|
||||
/**
|
||||
* The array that contains the processed value of each token.
|
||||
*
|
||||
@ -33,11 +40,16 @@ class ArrayFragment extends Fragment
|
||||
public $values = array();
|
||||
|
||||
/**
|
||||
* The array that contains the unprocessed value of each token.
|
||||
* Constructor.
|
||||
*
|
||||
* @var array
|
||||
* @param array $raw The unprocessed values.
|
||||
* @param array $values The processed values.
|
||||
*/
|
||||
public $raw = array();
|
||||
public function __construct(array $raw = array(), array $values = array())
|
||||
{
|
||||
$this->raw = $raw;
|
||||
$this->values = $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Parser $parser The parser that serves as context.
|
||||
@ -67,7 +79,6 @@ class ArrayFragment extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -114,4 +125,22 @@ class ArrayFragment extends Fragment
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ArrayFragment $fragment The fragment to be built.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function build(ArrayFragment $fragment)
|
||||
{
|
||||
$values = array();
|
||||
if (!empty($fragment->raw)) {
|
||||
$values = $fragment->raw;
|
||||
} else {
|
||||
foreach ($fragment->values as $value) {
|
||||
$values[] = $value;
|
||||
}
|
||||
}
|
||||
return '(' . implode(', ', $values) . ')';
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,9 +35,25 @@ class CallKeyword extends Fragment
|
||||
/**
|
||||
* The list of parameters
|
||||
*
|
||||
* @var array
|
||||
* @var ArrayFragment
|
||||
*/
|
||||
public $parameters = array();
|
||||
public $parameters;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $name The name of the function to be called.
|
||||
* @param array|ArrayFragment $parameters The parameters of this function.
|
||||
*/
|
||||
public function __construct($name = null, $parameters = null)
|
||||
{
|
||||
$this->name = $name;
|
||||
if (is_array($parameters)) {
|
||||
$this->parameters = new ArrayFragment($parameters);
|
||||
} elseif ($parameters instanceof ArrayFragment) {
|
||||
$this->parameters = $parameters;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Parser $parser The parser that serves as context.
|
||||
@ -64,7 +80,6 @@ class CallKeyword extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -86,7 +101,7 @@ class CallKeyword extends Fragment
|
||||
$state = 1;
|
||||
} elseif ($state === 1) {
|
||||
if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
|
||||
$ret->parameters = ArrayFragment::parse($parser, $list)->values;
|
||||
$ret->parameters = ArrayFragment::parse($parser, $list);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -95,4 +110,14 @@ class CallKeyword extends Fragment
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param CallKeyword $fragment The fragment to be built.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function build(CallKeyword $fragment)
|
||||
{
|
||||
return $fragment->name . ArrayFragment::build($fragment->parameters);
|
||||
}
|
||||
}
|
||||
|
||||
@ -92,7 +92,6 @@ class CreateDefFragment extends Fragment
|
||||
$ret = new CreateDefFragment();
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
|
||||
@ -94,7 +94,6 @@ class DataTypeFragment extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
|
||||
@ -129,7 +129,6 @@ class FieldDefFragment extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -176,7 +175,7 @@ class FieldDefFragment extends Fragment
|
||||
--$list->idx;
|
||||
}
|
||||
$state = 5;
|
||||
} else if ($state === 5) {
|
||||
} elseif ($state === 5) {
|
||||
if ((!empty($expr->type)) || (!empty($expr->key))) {
|
||||
$ret[] = $expr;
|
||||
}
|
||||
|
||||
@ -74,6 +74,38 @@ class FieldFragment extends Fragment
|
||||
*/
|
||||
public $subquery;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Syntax:
|
||||
* new FieldFragment('expr')
|
||||
* new FieldFragment('expr', 'alias')
|
||||
* new FieldFragment('database', 'table', 'column')
|
||||
* new FieldFragment('database', 'table', 'column', 'alias')
|
||||
*
|
||||
* If the database, table or column name is not required, pass an empty
|
||||
* string.
|
||||
*
|
||||
* @param string $database The name of the database or the the expression.
|
||||
* the the expression.
|
||||
* @param string $table The name of the table or the alias of the expression.
|
||||
* the alias of the expression.
|
||||
* @param string $column The name of the column.
|
||||
* @param string $alias The name of the alias.
|
||||
*/
|
||||
public function __construct($database = null, $table = null, $column = null, $alias = null)
|
||||
{
|
||||
if (($column === null) && ($alias === null)) {
|
||||
$this->expr = $database; // case 1
|
||||
$this->alias = $table; // case 2
|
||||
} else {
|
||||
$this->database = $database; // case 3
|
||||
$this->table = $table; // case 3
|
||||
$this->column = $column; // case 3
|
||||
$this->alias = $alias; // case 4
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Parser $parser The parser that serves as context.
|
||||
* @param TokensList $list The list of tokens that are being parsed.
|
||||
@ -120,7 +152,6 @@ class FieldFragment extends Fragment
|
||||
$prev = null;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -150,8 +181,10 @@ class FieldFragment extends Fragment
|
||||
$alias = 2;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
} else if ($prev === true) {
|
||||
if (!($token->flags & Token::FLAG_KEYWORD_FUNCTION)) {
|
||||
break;
|
||||
}
|
||||
} elseif ($prev === true) {
|
||||
if ((empty($ret->subquery) && (!empty(Parser::$STATEMENT_PARSERS[$token->value])))) {
|
||||
// A `(` was previously found and this keyword is the
|
||||
// beginning of a statement, so this is a subquery.
|
||||
@ -236,7 +269,7 @@ class FieldFragment extends Fragment
|
||||
|
||||
if (($token->type === Token::TYPE_KEYWORD) && ($token->flags & Token::FLAG_KEYWORD_FUNCTION)) {
|
||||
$prev = strtoupper($token->value);
|
||||
} else if (($token->type === Token::TYPE_OPERATOR) || ($token->value === '(')) {
|
||||
} elseif (($token->type === Token::TYPE_OPERATOR) || ($token->value === '(')) {
|
||||
$prev = true;
|
||||
} else {
|
||||
$prev = null;
|
||||
@ -258,4 +291,36 @@ class FieldFragment extends Fragment
|
||||
--$list->idx;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param FieldFragment $fragment The fragment to be built.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function build($fragment)
|
||||
{
|
||||
$ret = '';
|
||||
|
||||
if (!empty($fragment->expr)) {
|
||||
$ret = $fragment->expr;
|
||||
} else {
|
||||
$fields = array();
|
||||
if (!empty($fragment->database)) {
|
||||
$fields[] = $fragment->database;
|
||||
}
|
||||
if (!empty($fragment->table)) {
|
||||
$fields[] = $fragment->table;
|
||||
}
|
||||
if (!empty($fragment->column)) {
|
||||
$fields[] = $fragment->column;
|
||||
}
|
||||
$ret = implode('.', $fields);
|
||||
}
|
||||
|
||||
if (!empty($fragment->alias)) {
|
||||
$ret .= ' AS ' . $fragment->alias;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,7 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* `SELECT` keyword parser.
|
||||
* Parses a a list of fields delimited by a single comma.
|
||||
*
|
||||
* @package SqlParser
|
||||
* @subpackage Fragments
|
||||
@ -14,7 +14,7 @@ use SqlParser\Token;
|
||||
use SqlParser\TokensList;
|
||||
|
||||
/**
|
||||
* `SELECT` keyword parser.
|
||||
* Parses a a list of fields delimited by a single comma.
|
||||
*
|
||||
* @category Keywords
|
||||
* @package SqlParser
|
||||
@ -22,7 +22,7 @@ use SqlParser\TokensList;
|
||||
* @author Dan Ungureanu <udan1107@gmail.com>
|
||||
* @license http://opensource.org/licenses/GPL-2.0 GNU Public License
|
||||
*/
|
||||
class SelectKeyword extends Fragment
|
||||
class FieldListFragment extends Fragment
|
||||
{
|
||||
|
||||
/**
|
||||
@ -39,7 +39,6 @@ class SelectKeyword extends Fragment
|
||||
$expr = null;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -64,7 +63,7 @@ class SelectKeyword extends Fragment
|
||||
if (($token->type === Token::TYPE_OPERATOR) && ($token->value === ',')) {
|
||||
$ret[] = $expr;
|
||||
} else {
|
||||
$expr = FieldFragment::parse($parser, $list);
|
||||
$expr = FieldFragment::parse($parser, $list, $options);
|
||||
if ($expr === null) {
|
||||
break;
|
||||
}
|
||||
@ -80,4 +79,13 @@ class SelectKeyword extends Fragment
|
||||
--$list->idx;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
public static function build($fragment)
|
||||
{
|
||||
$ret = array();
|
||||
foreach ($fragment as $frag) {
|
||||
$ret[] = $frag::build($frag);
|
||||
}
|
||||
return implode($ret, ', ');
|
||||
}
|
||||
}
|
||||
@ -1,83 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* `FROM` keyword parser.
|
||||
*
|
||||
* @package SqlParser
|
||||
* @subpackage Fragments
|
||||
*/
|
||||
namespace SqlParser\Fragments;
|
||||
|
||||
use SqlParser\Fragment;
|
||||
use SqlParser\Parser;
|
||||
use SqlParser\Token;
|
||||
use SqlParser\TokensList;
|
||||
|
||||
/**
|
||||
* `FROM` keyword parser.
|
||||
*
|
||||
* @category Keywords
|
||||
* @package SqlParser
|
||||
* @subpackage Fragments
|
||||
* @author Dan Ungureanu <udan1107@gmail.com>
|
||||
* @license http://opensource.org/licenses/GPL-2.0 GNU Public License
|
||||
*/
|
||||
class FromKeyword extends Fragment
|
||||
{
|
||||
|
||||
/**
|
||||
* @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 FieldFragment[]
|
||||
*/
|
||||
public static function parse(Parser $parser, TokensList $list, array $options = array())
|
||||
{
|
||||
$ret = array();
|
||||
|
||||
$expr = new FieldFragment();
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var 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;
|
||||
}
|
||||
|
||||
// No keyword is expected.
|
||||
if (($token->type === Token::TYPE_KEYWORD) && ($token->flags & Token::FLAG_KEYWORD_RESERVED)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (($token->type === Token::TYPE_OPERATOR) && ($token->value === ',')) {
|
||||
$ret[] = $expr;
|
||||
} else {
|
||||
$expr = FieldFragment::parse($parser, $list, array('skipColumn' => true));
|
||||
if ($expr === null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Last iteration was not saved.
|
||||
if ($expr !== null) {
|
||||
$ret[] = $expr;
|
||||
}
|
||||
|
||||
--$list->idx;
|
||||
return $ret;
|
||||
}
|
||||
}
|
||||
@ -74,7 +74,6 @@ class IntoKeyword extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -105,13 +104,13 @@ class IntoKeyword extends Fragment
|
||||
if ($state === 0) {
|
||||
$ret->name = $token->value;
|
||||
$state = 1;
|
||||
} else if ($state === 1) {
|
||||
} elseif ($state === 1) {
|
||||
if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
|
||||
$ret->fields = ArrayFragment::parse($parser, $list)->values;
|
||||
++$list->idx;
|
||||
}
|
||||
break;
|
||||
} else if ($state === 2) {
|
||||
} elseif ($state === 2) {
|
||||
$ret->name = $token->value;
|
||||
++$list->idx;
|
||||
break;
|
||||
|
||||
@ -66,7 +66,6 @@ class JoinKeyword extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
|
||||
@ -95,7 +95,6 @@ class KeyFragment extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
|
||||
@ -39,6 +39,18 @@ class LimitKeyword extends Fragment
|
||||
*/
|
||||
public $rowCount;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param int $rowCount The row count.
|
||||
* @param int $offset The offset.
|
||||
*/
|
||||
public function __construct($rowCount = null, $offset = null)
|
||||
{
|
||||
$this->rowCount = $rowCount;
|
||||
$this->offset = $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Parser $parser The parser that serves as context.
|
||||
* @param TokensList $list The list of tokens that are being parsed.
|
||||
@ -53,7 +65,6 @@ class LimitKeyword extends Fragment
|
||||
$offset = false;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -103,4 +114,18 @@ class LimitKeyword extends Fragment
|
||||
--$list->idx;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param LimitKeyword $fragment The fragment to be built.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function build($fragment)
|
||||
{
|
||||
if (empty($fragment->offset)) {
|
||||
return $fragment->rowCount;
|
||||
} else {
|
||||
return $fragment->offset . ', ' . $fragment->rowCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -32,6 +32,17 @@ class OptionsFragment extends Fragment
|
||||
*/
|
||||
public $options = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $options The array of options. Options that have a value
|
||||
* must be an array with two keys 'name' and 'value'.
|
||||
*/
|
||||
public function __construct(array $options = array())
|
||||
{
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Parser $parser The parser that serves as context.
|
||||
* @param TokensList $list The list of tokens that are being parsed.
|
||||
@ -59,7 +70,6 @@ class OptionsFragment extends Fragment
|
||||
$brackets = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -127,6 +137,24 @@ class OptionsFragment extends Fragment
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param OptionsFragment $fragment The fragment to be built.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function build(OptionsFragment $fragment)
|
||||
{
|
||||
$options = array();
|
||||
foreach ($fragment->options as $option) {
|
||||
if (is_array($option)) {
|
||||
$options[] = $option['name'] . '=' . $option['value'];
|
||||
} else {
|
||||
$options[] = $option;
|
||||
}
|
||||
}
|
||||
return implode(' ', $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if it has the specified option and returns it value or true.
|
||||
*
|
||||
@ -158,7 +186,7 @@ class OptionsFragment extends Fragment
|
||||
{
|
||||
if (is_array($options)) {
|
||||
$this->options = array_merge_recursive($this->options, $options);
|
||||
} else if ($options instanceof OptionsFragment) {
|
||||
} elseif ($options instanceof OptionsFragment) {
|
||||
$this->options = array_merge_recursive($this->options, $options->options);
|
||||
}
|
||||
}
|
||||
|
||||
@ -67,7 +67,6 @@ class OrderKeyword extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -90,7 +89,7 @@ class OrderKeyword extends Fragment
|
||||
} elseif ($state === 1) {
|
||||
if (($token->type === Token::TYPE_KEYWORD) && (($token->value === 'ASC') || ($token->value === 'DESC'))) {
|
||||
$expr->type = $token->value;
|
||||
} else if (($token->type === Token::TYPE_OPERATOR) && ($token->value === ',')) {
|
||||
} elseif (($token->type === Token::TYPE_OPERATOR) && ($token->value === ',')) {
|
||||
if (!empty($expr->field)) {
|
||||
$ret[] = $expr;
|
||||
}
|
||||
|
||||
@ -80,7 +80,6 @@ class ParamDefFragment extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
|
||||
@ -84,7 +84,6 @@ class ReferencesKeyword extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -104,10 +103,10 @@ class ReferencesKeyword extends Fragment
|
||||
if ($state === 0) {
|
||||
$ret->table = $token->value;
|
||||
$state = 1;
|
||||
} else if ($state === 1) {
|
||||
} elseif ($state === 1) {
|
||||
$ret->columns = ArrayFragment::parse($parser, $list)->values;
|
||||
$state = 2;
|
||||
} else if ($state === 2) {
|
||||
} elseif ($state === 2) {
|
||||
$ret->options = OptionsFragment::parse($parser, $list, static::$REFERENCES_OPTIONS);
|
||||
++$list->idx;
|
||||
break;
|
||||
|
||||
@ -71,7 +71,6 @@ class RenameKeyword extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
|
||||
@ -67,7 +67,6 @@ class SetKeyword extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
|
||||
@ -65,7 +65,6 @@ class ValuesKeyword extends Fragment
|
||||
$state = 0;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
|
||||
@ -46,6 +46,16 @@ class WhereKeyword extends Fragment
|
||||
*/
|
||||
public $condition;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $condition The condition or the operator.
|
||||
*/
|
||||
public function __construct($condition = null)
|
||||
{
|
||||
$this->condition = trim($condition);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Parser $parser The parser that serves as context.
|
||||
* @param TokensList $list The list of tokens that are being parsed.
|
||||
@ -57,10 +67,13 @@ class WhereKeyword extends Fragment
|
||||
{
|
||||
$ret = array();
|
||||
|
||||
$expr = new WhereKeyword();
|
||||
/**
|
||||
* The condition that was parsed so far.
|
||||
* @var string
|
||||
*/
|
||||
$condition = '';
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -73,23 +86,23 @@ class WhereKeyword extends Fragment
|
||||
}
|
||||
|
||||
// Skipping whitespaces and comments.
|
||||
if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
|
||||
if ($token->type === Token::TYPE_COMMENT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Conditions are delimited by logical operators.
|
||||
if (in_array($token->value, static::$OPERATORS, true)) {
|
||||
if (!empty($expr->condition)) {
|
||||
$ret[] = $expr;
|
||||
if (!empty(trim($condition))) {
|
||||
// Adding the condition that is delimited by this operator.
|
||||
$ret[] = new WhereKeyword($condition);
|
||||
$condition = '';
|
||||
}
|
||||
|
||||
$expr = new WhereKeyword();
|
||||
// Adding the operator.
|
||||
$expr = new WhereKeyword($token->value);
|
||||
$expr->isOperator = true;
|
||||
$expr->condition = $token->value;
|
||||
$ret[] = $expr;
|
||||
|
||||
$expr = new WhereKeyword();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -98,16 +111,30 @@ class WhereKeyword extends Fragment
|
||||
break;
|
||||
}
|
||||
|
||||
$expr->condition .= $token->token;
|
||||
$condition .= $token->token;
|
||||
|
||||
}
|
||||
|
||||
// Last iteration was not processed.
|
||||
if (!empty($expr->condition)) {
|
||||
$ret[] = $expr;
|
||||
if (!empty(trim($condition))) {
|
||||
$ret[] = new WhereKeyword($condition);
|
||||
}
|
||||
|
||||
--$list->idx;
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param WhereKeyword $fragment The fragment to be built.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function build($fragment)
|
||||
{
|
||||
$conditions = array();
|
||||
foreach ($fragment as $f) {
|
||||
$conditions[] = $f->condition;
|
||||
}
|
||||
return implode(' ', $conditions);
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,7 +168,6 @@ class Lexer
|
||||
$lastToken = null;
|
||||
|
||||
for ($this->last = 0, $lastIdx = 0; $this->last < $this->len; $lastIdx = ++$this->last) {
|
||||
|
||||
/**
|
||||
* The new token.
|
||||
* @var Token
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
*/
|
||||
namespace SqlParser;
|
||||
|
||||
use SqlParser\Statements\SelectStatement;
|
||||
use SqlParser\Exceptions\ParserException;
|
||||
|
||||
/**
|
||||
@ -37,7 +38,7 @@ class Parser
|
||||
'ANALYZE' => 'SqlParser\\Statements\\AnalyzeStatement',
|
||||
'BACKUP' => 'SqlParser\\Statements\\BackupStatement',
|
||||
'CHECK' => 'SqlParser\\Statements\\CheckStatement',
|
||||
'CHECKSUM' => 'SqlParser\\Statements\\ChecsumStatement',
|
||||
'CHECKSUM' => 'SqlParser\\Statements\\ChecksumStatement',
|
||||
'OPTIMIZE' => 'SqlParser\\Statements\\OptimizeStatement',
|
||||
'REPAIR' => 'SqlParser\\Statements\\RepairStatement',
|
||||
'RESTORE' => 'SqlParser\\Statements\\RestoreStatement',
|
||||
@ -79,38 +80,51 @@ class Parser
|
||||
* @var array
|
||||
*/
|
||||
public static $KEYWORD_PARSERS = array(
|
||||
|
||||
// This is not a proper keyword and was added here to help the builder.
|
||||
'_OPTIONS' => array(
|
||||
'class' => 'SqlParser\\Fragments\\OptionsFragment',
|
||||
'field' => 'options',
|
||||
),
|
||||
|
||||
'ALTER' => array(
|
||||
'class' => 'SqlParser\\Fragments\\FieldFragment',
|
||||
'field' => 'table',
|
||||
'options' => array('skipColumn' => true),
|
||||
),
|
||||
'ANALYZE' => array(
|
||||
'class' => 'SqlParser\\Fragments\\FromKeyword',
|
||||
'class' => 'SqlParser\\Fragments\\FieldListFragment',
|
||||
'field' => 'tables',
|
||||
'options' => array('skipColumn' => true),
|
||||
),
|
||||
'BACKUP' => array(
|
||||
'class' => 'SqlParser\\Fragments\\FromKeyword',
|
||||
'class' => 'SqlParser\\Fragments\\FieldListFragment',
|
||||
'field' => 'tables',
|
||||
'options' => array('skipColumn' => true),
|
||||
),
|
||||
'CALL' => array(
|
||||
'class' => 'SqlParser\\Fragments\\CallKeyword',
|
||||
'field' => 'call',
|
||||
),
|
||||
'CHECK' => array(
|
||||
'class' => 'SqlParser\\Fragments\\FromKeyword',
|
||||
'class' => 'SqlParser\\Fragments\\FieldListFragment',
|
||||
'field' => 'tables',
|
||||
'options' => array('skipColumn' => true),
|
||||
),
|
||||
'CHECKSUM' => array(
|
||||
'class' => 'SqlParser\\Fragments\\FromKeyword',
|
||||
'class' => 'SqlParser\\Fragments\\FieldListFragment',
|
||||
'field' => 'tables',
|
||||
'options' => array('skipColumn' => true),
|
||||
),
|
||||
'DROP' => array(
|
||||
'class' => 'SqlParser\\Fragments\\FromKeyword',
|
||||
'field' => 'fields'
|
||||
'class' => 'SqlParser\\Fragments\\FieldListFragment',
|
||||
'field' => 'fields',
|
||||
'options' => array('skipColumn' => true),
|
||||
),
|
||||
'FROM' => array(
|
||||
'class' => 'SqlParser\\Fragments\\FromKeyword',
|
||||
'class' => 'SqlParser\\Fragments\\FieldListFragment',
|
||||
'field' => 'from',
|
||||
'options' => array('skipColumn' => true),
|
||||
),
|
||||
'GROUP BY' => array(
|
||||
'class' => 'SqlParser\\Fragments\\OrderKeyword',
|
||||
@ -133,8 +147,9 @@ class Parser
|
||||
'field' => 'limit',
|
||||
),
|
||||
'OPTIMIZE' => array(
|
||||
'class' => 'SqlParser\\Fragments\\FromKeyword',
|
||||
'class' => 'SqlParser\\Fragments\\FieldListFragment',
|
||||
'field' => 'tables',
|
||||
'options' => array('skipColumn' => true),
|
||||
),
|
||||
'ORDER BY' => array(
|
||||
'class' => 'SqlParser\\Fragments\\OrderKeyword',
|
||||
@ -153,24 +168,27 @@ class Parser
|
||||
'field' => 'renames',
|
||||
),
|
||||
'REPAIR' => array(
|
||||
'class' => 'SqlParser\\Fragments\\FromKeyword',
|
||||
'class' => 'SqlParser\\Fragments\\FieldListFragment',
|
||||
'field' => 'tables',
|
||||
'options' => array('skipColumn' => true),
|
||||
),
|
||||
'RESTORE' => array(
|
||||
'class' => 'SqlParser\\Fragments\\FromKeyword',
|
||||
'class' => 'SqlParser\\Fragments\\FieldListFragment',
|
||||
'field' => 'tables',
|
||||
'options' => array('skipColumn' => true),
|
||||
),
|
||||
'SET' => array(
|
||||
'class' => 'SqlParser\\Fragments\\SetKeyword',
|
||||
'field' => 'set',
|
||||
),
|
||||
'SELECT' => array(
|
||||
'class' => 'SqlParser\\Fragments\\SelectKeyword',
|
||||
'class' => 'SqlParser\\Fragments\\FieldListFragment',
|
||||
'field' => 'expr',
|
||||
),
|
||||
'UPDATE' => array(
|
||||
'class' => 'SqlParser\\Fragments\\FromKeyword',
|
||||
'class' => 'SqlParser\\Fragments\\FieldListFragment',
|
||||
'field' => 'from',
|
||||
'options' => array('skipColumn' => true),
|
||||
),
|
||||
'VALUE' => array(
|
||||
'class' => 'SqlParser\\Fragments\\ValuesKeyword',
|
||||
@ -252,6 +270,29 @@ class Parser
|
||||
*/
|
||||
public function parse()
|
||||
{
|
||||
|
||||
/**
|
||||
* Last parsed statement.
|
||||
* @var Statement
|
||||
*/
|
||||
$lastStatement = null;
|
||||
|
||||
/**
|
||||
* Whether a union is parsed or not.
|
||||
* @var bool
|
||||
*/
|
||||
$inUnion = true;
|
||||
|
||||
/**
|
||||
* The index of the last token from the last statement.
|
||||
* @var int
|
||||
*/
|
||||
$prevLastIdx = -1;
|
||||
|
||||
/**
|
||||
* The list of tokens.
|
||||
* @var TokensList
|
||||
*/
|
||||
$list = &$this->list;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
@ -268,13 +309,21 @@ class Parser
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($token->value === 'UNION') {
|
||||
$inUnion = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Checking if it is a known statement that can be parsed.
|
||||
if (empty(static::$STATEMENT_PARSERS[$token->value])) {
|
||||
$this->error(
|
||||
'Unrecognized statement type "' . $token->value . '".',
|
||||
$token
|
||||
);
|
||||
// Skipping to the end of this statement.
|
||||
$list->getNextOfType(Token::TYPE_DELIMITER);
|
||||
//
|
||||
$prevLastIdx = $list->idx;
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -290,8 +339,32 @@ class Parser
|
||||
*/
|
||||
$stmt = new $class();
|
||||
|
||||
// The first token that is a part of this token is the next token
|
||||
// unprocessed by the previous statement.
|
||||
// There might be brackets around statements and this shouldn't
|
||||
// affect the parser
|
||||
$stmt->first = $prevLastIdx + 1;
|
||||
|
||||
// Parsing the actual statement.
|
||||
$stmt->parse($this, $this->list);
|
||||
$this->statements[] = $stmt;
|
||||
|
||||
// Storing the index of the last token parsed and updating the old
|
||||
// index.
|
||||
$stmt->last = $list->idx;
|
||||
$prevLastIdx = $list->idx;
|
||||
|
||||
// Finally, storing the statement.
|
||||
if (($inUnion)
|
||||
&& ($lastStatement instanceof SelectStatement)
|
||||
&& ($stmt instanceof SelectStatement)
|
||||
) {
|
||||
$lastStatement->union[] = $stmt;
|
||||
$inUnion = false;
|
||||
} else {
|
||||
$this->statements[] = $stmt;
|
||||
$lastStatement = $stmt;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -26,6 +26,20 @@ use SqlParser\Fragments\OptionsFragment;
|
||||
abstract class Statement
|
||||
{
|
||||
|
||||
/**
|
||||
* The clauses of this statement, in order.
|
||||
*
|
||||
* The value attributed to each clause is used by the builder and it may
|
||||
* have one of the following values:
|
||||
*
|
||||
* - 1 = 01 - add the clause only
|
||||
* - 2 = 10 - add the keyword
|
||||
* - 3 = 11 - add both the keyword and the clause
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $CLAUSES;
|
||||
|
||||
/**
|
||||
* The options of this query.
|
||||
*
|
||||
@ -59,8 +73,6 @@ abstract class Statement
|
||||
*/
|
||||
public function parse(Parser $parser, TokensList $list)
|
||||
{
|
||||
$this->first = $list->idx;
|
||||
|
||||
/**
|
||||
* Whether options were parsed or not.
|
||||
* For statements that do not have any options this is set to `true` by
|
||||
@ -70,7 +82,6 @@ abstract class Statement
|
||||
$parsedOptions = isset(static::$OPTIONS) ? false : true;
|
||||
|
||||
for (; $list->idx < $list->count; ++$list->idx) {
|
||||
|
||||
/**
|
||||
* Token parsed at this moment.
|
||||
* @var Token
|
||||
@ -88,6 +99,12 @@ abstract class Statement
|
||||
continue;
|
||||
}
|
||||
|
||||
// Unions are parsed by the parser because they represent more than
|
||||
// one statement.
|
||||
if ($token->value === 'UNION') {
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* The name of the class that is used for parsing.
|
||||
* @var string
|
||||
@ -124,7 +141,7 @@ abstract class Statement
|
||||
);
|
||||
$parsedOptions = true;
|
||||
}
|
||||
} else if ($class === null) {
|
||||
} elseif ($class === null) {
|
||||
// There is no parser for this keyword and isn't the beggining
|
||||
// of a statement (so no options) either.
|
||||
$parser->error(
|
||||
@ -145,11 +162,11 @@ abstract class Statement
|
||||
$this->after($parser, $list, $token);
|
||||
}
|
||||
|
||||
$this->last = $list->idx--; // Go back to last used token.
|
||||
--$list->idx; // Go back to last used token.
|
||||
}
|
||||
|
||||
/**
|
||||
* Function called before the token was processed.
|
||||
* Function called before the token is processed.
|
||||
*
|
||||
* @param Parser $parser The instance that requests parsing.
|
||||
* @param TokensList $list The list of tokens to be parsed.
|
||||
@ -175,5 +192,4 @@ abstract class Statement
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -97,6 +97,8 @@ class AlterStatement extends NotImplementedStatement
|
||||
);
|
||||
|
||||
/**
|
||||
* Function called after the token was processed.
|
||||
*
|
||||
* Extracts the name of affected column.
|
||||
*
|
||||
* @param Parser $parser The instance that requests parsing.
|
||||
@ -124,5 +126,4 @@ class AlterStatement extends NotImplementedStatement
|
||||
//
|
||||
parent::after($parser, $list, $token);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -100,6 +100,8 @@ class CreateStatement extends Statement
|
||||
public $body;
|
||||
|
||||
/**
|
||||
* Function called before the token is processed.
|
||||
*
|
||||
* Parsing the `CREATE` statement.
|
||||
*
|
||||
* @param Parser $parser The instance that requests parsing.
|
||||
|
||||
@ -37,6 +37,8 @@ class MaintenanceStatement extends Statement
|
||||
public $tables;
|
||||
|
||||
/**
|
||||
* Function called after the token was processed.
|
||||
*
|
||||
* Parses the additional options fragment at the end.
|
||||
*
|
||||
* @param Parser $parser The instance that requests parsing.
|
||||
|
||||
@ -28,6 +28,8 @@ class NotImplementedStatement extends Statement
|
||||
{
|
||||
|
||||
/**
|
||||
* Function called after the token was processed.
|
||||
*
|
||||
* Jump to the end of the delimiter.
|
||||
*
|
||||
* @param Parser $parser The instance that requests parsing.
|
||||
|
||||
@ -36,6 +36,8 @@ class RenameStatement extends Statement
|
||||
public $renames;
|
||||
|
||||
/**
|
||||
* Function called before the token is processed.
|
||||
*
|
||||
* Skips the `TABLE` keyword after `RENAME`.
|
||||
*
|
||||
* @param Parser $parser The instance that requests parsing.
|
||||
|
||||
@ -68,17 +68,29 @@ class SelectStatement extends Statement
|
||||
);
|
||||
|
||||
/**
|
||||
* The sections of this statement, in order.
|
||||
* The clauses of this statement, in order.
|
||||
*
|
||||
* Used by the query builder to arrange the clauses.
|
||||
* @see Statement::$CLAUSES
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
public static $SECTIONS = array(
|
||||
'SELECT' => 0, '%OPTIONS' => 1,'FROM' => 2, 'PARTITION' => 3,
|
||||
'WHERE' => 4, 'GROUP BY' => 5, 'HAVING' => 6, 'ORDER BY' => 7,
|
||||
'LIMIT' => 8, 'PROCEDURE' => 9, 'INTO' => 10, 'UNION' => 11,
|
||||
'JOIN' => 12, '%OPTIONS' => 13
|
||||
public static $CLAUSES = array(
|
||||
'SELECT' => array('SELECT', 2),
|
||||
// Used for options.
|
||||
'_OPTIONS' => array('_OPTIONS', 1),
|
||||
// Used for select expressions.
|
||||
'_SELECT' => array('SELECT', 1),
|
||||
'FROM' => array('FROM', 3),
|
||||
'PARTITION' => array('PARTITION', 3),
|
||||
'WHERE' => array('WHERE', 3),
|
||||
'GROUP BY' => array('GROUP BY', 3),
|
||||
'HAVING' => array('HAVING', 3),
|
||||
'ORDER BY' => array('ORDER BY', 3),
|
||||
'LIMIT' => array('LIMIT', 3),
|
||||
'PROCEDURE' => array('PROCEDURE', 3),
|
||||
'INTO' => array('INTO', 3),
|
||||
'UNION' => array('UNION', 3),
|
||||
'JOIN' => array('JOIN', 3),
|
||||
);
|
||||
|
||||
/**
|
||||
@ -86,33 +98,33 @@ class SelectStatement extends Statement
|
||||
*
|
||||
* @var FieldFragment[]
|
||||
*/
|
||||
public $expr;
|
||||
public $expr = array();
|
||||
|
||||
/**
|
||||
* Tables used as sources for this statement.
|
||||
*
|
||||
* @var FieldFragment[]
|
||||
*/
|
||||
public $from;
|
||||
public $from = array();
|
||||
|
||||
/**
|
||||
* Partitions used as source for this statement.
|
||||
*
|
||||
* @var ArrayFragment[]
|
||||
* @var ArrayFragment
|
||||
*/
|
||||
public $partition;
|
||||
|
||||
/**
|
||||
* Conditions used for filtering each row of the result set.
|
||||
*
|
||||
* @var WhereKeyword
|
||||
* @var WhereKeyword[]
|
||||
*/
|
||||
public $where;
|
||||
|
||||
/**
|
||||
* Conditions used for grouping the result set.
|
||||
*
|
||||
* @var GroupKeyword
|
||||
* @var OrderKeyword[]
|
||||
*/
|
||||
public $group;
|
||||
|
||||
@ -157,4 +169,11 @@ class SelectStatement extends Statement
|
||||
* @var JoinKeyword
|
||||
*/
|
||||
public $join;
|
||||
|
||||
/**
|
||||
* Unions.
|
||||
*
|
||||
* @var SelectStatement[]
|
||||
*/
|
||||
public $union = array();
|
||||
}
|
||||
|
||||
@ -217,52 +217,52 @@ class Token
|
||||
public function extract()
|
||||
{
|
||||
switch ($this->type) {
|
||||
case Token::TYPE_KEYWORD:
|
||||
if (!($this->flags & Token::FLAG_KEYWORD_RESERVED)) {
|
||||
// Unreserved keywords should stay the way they are because they
|
||||
// might represent field names.
|
||||
return $this->token;
|
||||
}
|
||||
return strtoupper($this->token);
|
||||
case Token::TYPE_WHITESPACE:
|
||||
return ' ';
|
||||
case Token::TYPE_BOOL:
|
||||
return strtoupper($this->token) === 'TRUE';
|
||||
case Token::TYPE_NUMBER:
|
||||
$ret = str_replace('--', '', $this->token); // e.g. ---42 === -42
|
||||
if ($this->flags & Token::FLAG_NUMBER_HEX) {
|
||||
if ($this->flags & Token::FLAG_NUMBER_NEGATIVE) {
|
||||
$ret = str_replace('-', '', $this->token);
|
||||
sscanf($ret, "%x", $ret);
|
||||
$ret = -$ret;
|
||||
} else {
|
||||
sscanf($ret, "%x", $ret);
|
||||
case Token::TYPE_KEYWORD:
|
||||
if (!($this->flags & Token::FLAG_KEYWORD_RESERVED)) {
|
||||
// Unreserved keywords should stay the way they are because they
|
||||
// might represent field names.
|
||||
return $this->token;
|
||||
}
|
||||
} elseif (($this->flags & Token::FLAG_NUMBER_APPROXIMATE)
|
||||
return strtoupper($this->token);
|
||||
case Token::TYPE_WHITESPACE:
|
||||
return ' ';
|
||||
case Token::TYPE_BOOL:
|
||||
return strtoupper($this->token) === 'TRUE';
|
||||
case Token::TYPE_NUMBER:
|
||||
$ret = str_replace('--', '', $this->token); // e.g. ---42 === -42
|
||||
if ($this->flags & Token::FLAG_NUMBER_HEX) {
|
||||
if ($this->flags & Token::FLAG_NUMBER_NEGATIVE) {
|
||||
$ret = str_replace('-', '', $this->token);
|
||||
sscanf($ret, "%x", $ret);
|
||||
$ret = -$ret;
|
||||
} else {
|
||||
sscanf($ret, "%x", $ret);
|
||||
}
|
||||
} elseif (($this->flags & Token::FLAG_NUMBER_APPROXIMATE)
|
||||
|| ($this->flags & Token::FLAG_NUMBER_FLOAT)
|
||||
) {
|
||||
sscanf($ret, "%f", $ret);
|
||||
} else {
|
||||
sscanf($ret, "%d", $ret);
|
||||
}
|
||||
return $ret;
|
||||
case Token::TYPE_STRING:
|
||||
$quote = $this->token[0];
|
||||
$str = str_replace($quote . $quote, $quote, $this->token);
|
||||
return mb_substr($str, 1, -1); // trims quotes
|
||||
case Token::TYPE_SYMBOL:
|
||||
$str = $this->token;
|
||||
if ((isset($str[0])) && ($str[0] === '@')) {
|
||||
$str = mb_substr($str, 1);
|
||||
}
|
||||
if ((isset($str[0])) && (($str[0] === '`')
|
||||
) {
|
||||
sscanf($ret, "%f", $ret);
|
||||
} else {
|
||||
sscanf($ret, "%d", $ret);
|
||||
}
|
||||
return $ret;
|
||||
case Token::TYPE_STRING:
|
||||
$quote = $this->token[0];
|
||||
$str = str_replace($quote . $quote, $quote, $this->token);
|
||||
return mb_substr($str, 1, -1); // trims quotes
|
||||
case Token::TYPE_SYMBOL:
|
||||
$str = $this->token;
|
||||
if ((isset($str[0])) && ($str[0] === '@')) {
|
||||
$str = mb_substr($str, 1);
|
||||
}
|
||||
if ((isset($str[0])) && (($str[0] === '`')
|
||||
|| ($str[0] === '"') || ($str[0] === '\''))
|
||||
) {
|
||||
$quote = $str[0];
|
||||
$str = str_replace($quote . $quote, $quote, $str);
|
||||
$str = mb_substr($str, 1, -1);
|
||||
}
|
||||
return $str;
|
||||
) {
|
||||
$quote = $str[0];
|
||||
$str = str_replace($quote . $quote, $quote, $str);
|
||||
$str = mb_substr($str, 1, -1);
|
||||
}
|
||||
return $str;
|
||||
}
|
||||
return $this->token;
|
||||
}
|
||||
|
||||
@ -222,32 +222,32 @@ class Query
|
||||
if ($statement instanceof AlterStatement) {
|
||||
$flags['querytype'] = 'ALTER';
|
||||
$flags['reload'] = true;
|
||||
} else if ($statement instanceof CreateStatement) {
|
||||
} elseif ($statement instanceof CreateStatement) {
|
||||
$flags['querytype'] = 'CREATE';
|
||||
$flags['reload'] = true;
|
||||
} else if ($statement instanceof AnalyzeStatement) {
|
||||
} elseif ($statement instanceof AnalyzeStatement) {
|
||||
$flags['querytype'] = 'ANALYZE';
|
||||
$flags['is_maint'] = true;
|
||||
} else if ($statement instanceof CheckStatement) {
|
||||
} elseif ($statement instanceof CheckStatement) {
|
||||
$flags['querytype'] = 'CHECK';
|
||||
$flags['is_maint'] = true;
|
||||
} else if ($statement instanceof ChecksumStatement) {
|
||||
} elseif ($statement instanceof ChecksumStatement) {
|
||||
$flags['querytype'] = 'CHECKSUM';
|
||||
$flags['is_maint'] = true;
|
||||
} else if ($statement instanceof OptimizeStatement) {
|
||||
} elseif ($statement instanceof OptimizeStatement) {
|
||||
$flags['querytype'] = 'OPTIMIZE';
|
||||
$flags['is_maint'] = true;
|
||||
} else if ($statement instanceof RepairStatement) {
|
||||
} elseif ($statement instanceof RepairStatement) {
|
||||
$flags['querytype'] = 'REPAIR';
|
||||
$flags['is_maint'] = true;
|
||||
} else if ($statement instanceof CallStatement) {
|
||||
} elseif ($statement instanceof CallStatement) {
|
||||
$flags['querytype'] = 'CALL';
|
||||
$flags['is_procedure'] = true;
|
||||
} else if ($statement instanceof DeleteStatement) {
|
||||
} elseif ($statement instanceof DeleteStatement) {
|
||||
$flags['querytype'] = 'DELETE';
|
||||
$flags['is_delete'] = true;
|
||||
$flags['is_affected'] = true;
|
||||
} else if ($statement instanceof DropStatement) {
|
||||
} elseif ($statement instanceof DropStatement) {
|
||||
$flags['querytype'] = 'DROP';
|
||||
$flags['reload'] = true;
|
||||
|
||||
@ -256,19 +256,19 @@ class Query
|
||||
) {
|
||||
$flags['drop_database'] = true;
|
||||
}
|
||||
} else if ($statement instanceof ExplainStatement) {
|
||||
} elseif ($statement instanceof ExplainStatement) {
|
||||
$flags['querytype'] = 'EXPLAIN';
|
||||
$flags['is_explain'] = true;
|
||||
} else if ($statement instanceof InsertStatement) {
|
||||
} elseif ($statement instanceof InsertStatement) {
|
||||
$flags['querytype'] = 'INSERT';
|
||||
$flags['is_affected'] = true;
|
||||
$flags['is_insert'] = true;
|
||||
} else if ($statement instanceof ReplaceStatement) {
|
||||
} elseif ($statement instanceof ReplaceStatement) {
|
||||
$flags['querytype'] = 'REPLACE';
|
||||
$flags['is_affected'] = true;
|
||||
$flags['is_replace'] = true;
|
||||
$flags['is_insert'] = true;
|
||||
} else if ($statement instanceof SelectStatement) {
|
||||
} elseif ($statement instanceof SelectStatement) {
|
||||
$flags['querytype'] = 'SELECT';
|
||||
$flags['is_select'] = true;
|
||||
|
||||
@ -294,7 +294,7 @@ class Query
|
||||
if (!empty($expr->function)) {
|
||||
if ($expr->function === 'COUNT') {
|
||||
$flags['is_count'] = true;
|
||||
} else if (in_array($expr->function, static::$FUNCTIONS)) {
|
||||
} elseif (in_array($expr->function, static::$FUNCTIONS)) {
|
||||
$flags['is_func'] = true;
|
||||
}
|
||||
}
|
||||
@ -325,10 +325,10 @@ class Query
|
||||
$flags['join'] = true;
|
||||
}
|
||||
|
||||
} else if ($statement instanceof ShowStatement) {
|
||||
} elseif ($statement instanceof ShowStatement) {
|
||||
$flags['querytype'] = 'SHOW';
|
||||
$flags['is_show'] = true;
|
||||
} else if ($statement instanceof UpdateStatement) {
|
||||
} elseif ($statement instanceof UpdateStatement) {
|
||||
$flags['querytype'] = 'UPDATE';
|
||||
$flags['is_affected'] = true;
|
||||
}
|
||||
@ -409,7 +409,7 @@ class Query
|
||||
/**
|
||||
* Gets the type of clause.
|
||||
*
|
||||
* @param string $clause The clause.
|
||||
* @param string $clause The clause.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@ -450,7 +450,7 @@ class Query
|
||||
{
|
||||
|
||||
/**
|
||||
* Current location.
|
||||
* The index of the current clause.
|
||||
* @var int
|
||||
*/
|
||||
$currIdx = 0;
|
||||
@ -469,19 +469,20 @@ class Query
|
||||
$ret = '';
|
||||
|
||||
/**
|
||||
* The place where the clause should be added.
|
||||
* The clauses of this type of statement and their index.
|
||||
* @var array
|
||||
*/
|
||||
$clauses = array_flip(array_keys($statement::$CLAUSES));
|
||||
|
||||
/**
|
||||
* The index of this clause.
|
||||
* @var int
|
||||
*/
|
||||
$clauseIdx = $statement::$SECTIONS[static::getClauseType($clause)];
|
||||
$clauseIdx = $clauses[static::getClauseType($clause)];
|
||||
|
||||
for ($i = $statement->first; $i <= $statement->last; ++$i) {
|
||||
|
||||
$token = $list->tokens[$i];
|
||||
|
||||
if ($token->type === Token::TYPE_DELIMITER) {
|
||||
break;
|
||||
}
|
||||
|
||||
if ($token->type === Token::TYPE_OPERATOR) {
|
||||
if ($token->value === '(') {
|
||||
++$brackets;
|
||||
@ -493,9 +494,9 @@ class Query
|
||||
if ($brackets == 0) {
|
||||
// Checking if we changed sections.
|
||||
if ($token->type === Token::TYPE_KEYWORD) {
|
||||
if (isset($statement::$SECTIONS[$token->value])) {
|
||||
if ($statement::$SECTIONS[$token->value] >= $currIdx) {
|
||||
$currIdx = $statement::$SECTIONS[$token->value];
|
||||
if (isset($clauses[$token->value])) {
|
||||
if ($clauses[$token->value] >= $currIdx) {
|
||||
$currIdx = $clauses[$token->value];
|
||||
if (($skipFirst) && ($currIdx == $clauseIdx)) {
|
||||
// This token is skipped (not added to the old
|
||||
// clause) because it will be replaced.
|
||||
@ -546,5 +547,4 @@ class Query
|
||||
$clause . ' ' .
|
||||
static::getClause($statement, $list, $clause, 1, false);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -43,7 +43,6 @@ class Table
|
||||
$ret = array();
|
||||
|
||||
foreach ($statement->fields as $field) {
|
||||
|
||||
if ((empty($field->key)) || ($field->key->type !== 'FOREIGN KEY')) {
|
||||
continue;
|
||||
}
|
||||
@ -93,7 +92,6 @@ class Table
|
||||
$ret = array();
|
||||
|
||||
foreach ($statement->fields as $field) {
|
||||
|
||||
// Skipping keys.
|
||||
if (empty($field->type)) {
|
||||
continue;
|
||||
@ -105,7 +103,6 @@ class Table
|
||||
);
|
||||
|
||||
if ($field->options) {
|
||||
|
||||
if ($field->type->name === 'TIMESTAMP') {
|
||||
if ($field->options->has('NOT NULL')) {
|
||||
$ret[$field->name]['timestamp_not_null'] = true;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user