summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Ungureanu <udan1107@gmail.com>2015-07-14 01:39:29 +0300
committerDan Ungureanu <udan1107@gmail.com>2015-07-14 01:39:29 +0300
commit68ad40b4f30c0ff55d662413729fec4a535a3fec (patch)
tree3fd7c3570de3aa9962aab9c2670d7306318c4148
parentc1ee1ce4f2de7100c19127d2a96a02b4a7ef133a (diff)
downloadsql-parser-68ad40b4f30c0ff55d662413729fec4a535a3fec.zip
sql-parser-68ad40b4f30c0ff55d662413729fec4a535a3fec.tar.gz
sql-parser-68ad40b4f30c0ff55d662413729fec4a535a3fec.tar.bz2
Added MariaDB's options for virtual fields. Updated contexts to contain relevant keywords.
Added magic method '__toString()' for components and statements for building. Fixed a bug that caused the function name to be incorrectly detected in an expression. Fixed a bug that ignored the 'noAlias' option in expressions. Options may be expressions now.
-rw-r--r--src/Component.php11
-rw-r--r--src/Components/Expression.php15
-rw-r--r--src/Components/FieldDefinition.php6
-rw-r--r--src/Components/OptionsArray.php146
-rw-r--r--src/Contexts/ContextMySql50000.php7
-rw-r--r--src/Contexts/ContextMySql50100.php10
-rw-r--r--src/Contexts/ContextMySql50500.php10
-rw-r--r--src/Contexts/ContextMySql50600.php9
-rw-r--r--src/Contexts/ContextMySql50700.php7
-rw-r--r--src/Statement.php13
-rw-r--r--tests/Builder/StatementTest.php2
-rw-r--r--tests/Components/OptionsArrayTest.php22
-rw-r--r--tests/Parser/CreateStatementTest.php1
-rw-r--r--tests/data/parseCreateTable3.in6
-rw-r--r--tests/data/parseCreateTable3.out6
-rw-r--r--tests/data/parseSelect2.out2
16 files changed, 212 insertions, 61 deletions
diff --git a/src/Component.php b/src/Component.php
index 3505f3d..599784a 100644
--- a/src/Component.php
+++ b/src/Component.php
@@ -57,4 +57,15 @@ abstract class Component
// abstract.
return null;
}
+
+ /**
+ * Builds the string representation of a component of this type.
+ *
+ * @see static::build
+ *
+ * @return string
+ */
+ public function __toString() {
+ return static::build($this);
+ }
}
diff --git a/src/Components/Expression.php b/src/Components/Expression.php
index 29b5635..065810c 100644
--- a/src/Components/Expression.php
+++ b/src/Components/Expression.php
@@ -205,7 +205,7 @@ class Expression extends Component
// We don't check to see if `$prev` is `true` (open bracket
// was found before) because the brackets count is one (the
// only bracket we found is this one).
- if (($brackets === 1) && (empty($ret->function)) && ($prev !== null) && ($prev !== true)) {
+ if ((empty($ret->function)) && ($prev !== null) && ($prev !== true)) {
// A function name was previously found and now an open
// bracket, so this is a function call.
$ret->function = $prev;
@@ -213,7 +213,15 @@ class Expression extends Component
$isExpr = true;
} elseif ($token->value === ')') {
--$brackets;
- if ($brackets < 0) {
+ if ($brackets === 0) {
+ if (!empty($options['bracketsDelimited'])) {
+ // The current token is the last brackets, the next
+ // one will be outside.
+ $ret->expr .= $token->token;
+ ++$list->idx;
+ break;
+ }
+ } elseif ($brackets < 0) {
$parser->error('Unexpected bracket.', $token);
$brackets = 0;
}
@@ -268,11 +276,12 @@ class Expression extends Component
} else {
// Parsing aliases without `AS` keyword.
// Example: SELECT 'foo' `bar`
- if ($brackets === 0) {
+ if (($brackets === 0) && (empty($options['noAlias']))) {
if (($token->type === Token::TYPE_NONE) || ($token->type === Token::TYPE_STRING)
|| (($token->type === Token::TYPE_SYMBOL) && ($token->flags & Token::FLAG_SYMBOL_BACKTICK))
) {
$ret->alias = $token->value;
+ continue;
}
}
}
diff --git a/src/Components/FieldDefinition.php b/src/Components/FieldDefinition.php
index 0c3ea4f..22719eb 100644
--- a/src/Components/FieldDefinition.php
+++ b/src/Components/FieldDefinition.php
@@ -47,6 +47,12 @@ class FieldDefinition extends Component
'COMMENT' => array(5, 'var'),
'COLUMN_FORMAT' => array(6, 'var'),
'ON UPDATE' => array(7, 'var'),
+
+ // MariaDB options.
+ 'GENERATED ALWAYS' => 1,
+ 'AS' => array(2, 'expr', array('bracketsDelimited' => true)),
+ 'VIRTUAL' => 3,
+ 'PERSISTENT' => 3,
);
/**
diff --git a/src/Components/OptionsArray.php b/src/Components/OptionsArray.php
index d691e86..1bd68c5 100644
--- a/src/Components/OptionsArray.php
+++ b/src/Components/OptionsArray.php
@@ -72,8 +72,27 @@ class OptionsArray extends Component
*/
$lastOptionId = 0;
+ /**
+ * Counts brackets.
+ * @var int $brackets
+ */
$brackets = 0;
+ /**
+ * The state of the parser.
+ *
+ * Below are the states of the parser.
+ *
+ * 0 ---------------------[ option ]----------------------> 1
+ *
+ * 1 -------------------[ = (optional) ]------------------> 2
+ *
+ * 2 ----------------------[ value ]----------------------> 0
+ *
+ * @var int
+ */
+ $state = 0;
+
for (; $list->idx < $list->count; ++$list->idx) {
/**
* Token parsed at this moment.
@@ -86,23 +105,36 @@ class OptionsArray extends Component
break;
}
- // Skipping whitespaces and comments.
- if (($token->type === Token::TYPE_WHITESPACE) || ($token->type === Token::TYPE_COMMENT)) {
+ // Skipping comments.
+ if ($token->type === Token::TYPE_COMMENT) {
+ continue;
+ }
+
+ // Skipping whitespaces if not parsing value.
+ if (($token->type === Token::TYPE_WHITESPACE) && ($brackets === 0)) {
continue;
}
if ($lastOption === null) {
- if (isset($options[strtoupper($token->token)])) {
- $lastOption = $options[strtoupper($token->token)];
- $lastOptionId = is_array($lastOption) ? $lastOption[0] : $lastOption;
+ $upper = strtoupper($token->token);
+ if (isset($options[$upper])) {
+ $lastOption = $options[$upper];
+ $lastOptionId = is_array($lastOption) ?
+ $lastOption[0] : $lastOption;
+ $state = 0;
// Checking for option conflicts.
- // For example, in `SELECT` statements the keywords `ALL` and `DISTINCT`
- // conflict and if used together, they produce an invalid query.
- // Usually, tokens can be identified in the array by the option ID,
- // but if conflicts occur, a generated option ID is used.
- // The first pseudo duplicate ID is the maximum value of the real
- // options (e.g. if there are 5 options, the first fake ID is 6).
+ // For example, in `SELECT` statements the keywords `ALL`
+ // and `DISTINCT` conflict and if used together, they
+ // produce an invalid query.
+ //
+ // Usually, tokens can be identified in the array by the
+ // option ID, but if conflicts occur, a generated option ID
+ // is used.
+ //
+ // The first pseudo duplicate ID is the maximum value of the
+ // real options (e.g. if there are 5 options, the first
+ // fake ID is 6).
if (isset($ret->options[$lastOptionId])) {
$parser->error('This option conflicts with \'' . $ret->options[$lastOptionId] . '\'.', $token);
$lastOptionId = $lastAssignedId++;
@@ -113,33 +145,79 @@ class OptionsArray extends Component
}
}
- if (is_array($lastOption)) {
- if (empty($ret->options[$lastOptionId])) {
+ if ($state === 0) {
+ if (!is_array($lastOption)) {
+ // This is a just keyword option without any value.
+ // This is the beginning and the end of it.
+ $ret->options[$lastOptionId] = $token->value;
+ $lastOption = null;
+ $state = 0;
+ } elseif (($lastOption[1] === 'var') || ($lastOption[1] === 'var=')) {
+ // This is a keyword that is followewd by a value.
+ // This is only the beginning. The value is parsed in state
+ // 1 and 2. State 1 is used to skip the first equals sign
+ // and state 2 to parse the actual value.
$ret->options[$lastOptionId] = array(
+ // @var The name of the option.
'name' => $token->value,
+ // @var Whether it contains an equal sign.
+ // This is used by the builder to rebuild it.
'equal' => $lastOption[1] === 'var=',
+ // @var Raw value.
'value' => '',
+ // @var Processed value.
'value_' => '',
);
+ $state = 1;
+ } elseif ($lastOption[1] === 'expr') {
+ // This is a keyword that is followed by an expression.
+ // The expression is used by the specialized parser.
+
+ // Skipping this option in order to parse the expression.
+ ++$list->idx;
+ $ret->options[$lastOptionId] = array(
+ 'name' => $token->value,
+ 'value' => null,
+ );
+ $state = 1;
+ }
+ } elseif ($state === 1) {
+ $state = 2;
+ if ($token->value === '=') {
+ $ret->options[$lastOptionId]['equal'] = true;
+ continue;
+ }
+ }
+
+ // This is outside the `elseif` group above because the change might
+ // change this iteration.
+ if ($state === 2) {
+ if ($lastOption[1] === 'expr') {
+ $ret->options[$lastOptionId]['value'] = Expression::parse(
+ $parser,
+ $list,
+ empty($lastOption[2]) ? array() : $lastOption[2]
+ );
+ $lastOption = null;
+ $state = 0;
} else {
- if ($token->value !== '=') {
- if ($token->value === '(') {
- ++$brackets;
- } elseif ($token->value === ')') {
- --$brackets;
- } else {
- // Raw and processed value.
- $ret->options[$lastOptionId]['value'] .= $token->token;
- $ret->options[$lastOptionId]['value_'] .= $token->value;
- }
- if ($brackets === 0) {
- $lastOption = null;
- }
+ if ($token->token === '(') {
+ ++$brackets;
+ } elseif ($token->token === ')') {
+ --$brackets;
+ }
+
+ // Raw value.
+ $ret->options[$lastOptionId]['value'] .= $token->token;
+
+ // Processed value.
+ $ret->options[$lastOptionId]['value_'] .= $token->value;
+
+ // Checking if we finished parsing.
+ if ($brackets === 0) {
+ $lastOption = null;
}
}
- } else {
- $ret->options[$lastOptionId] = $token->value;
- $lastOption = null;
}
}
@@ -161,12 +239,14 @@ class OptionsArray extends Component
}
$options = array();
foreach ($component->options as $option) {
- if (is_array($option)) {
+ if (!is_array($option)) {
+ $options[] = $option;
+ } else {
$options[] = $option['name']
. (!empty($option['equal']) ? '=' : ' ')
- . $option['value'];
- } else {
- $options[] = $option;
+ . ((string) $option['value']);
+ // If `$option['value']` happens to be a component, the magic
+ // method will build it automatically.
}
}
return implode(' ', $options);
diff --git a/src/Contexts/ContextMySql50000.php b/src/Contexts/ContextMySql50000.php
index 48a928c..5069b91 100644
--- a/src/Contexts/ContextMySql50000.php
+++ b/src/Contexts/ContextMySql50000.php
@@ -63,7 +63,7 @@ class ContextMySql50000 extends Context
'MIGRATE' => 1, 'PARTIAL' => 1, 'PREPARE' => 1, 'PROFILE' => 1, 'RECOVER' => 1,
'RESTORE' => 1, 'RETURNS' => 1, 'ROUTINE' => 1, 'SESSION' => 1, 'STORAGE' => 1,
'STRIPED' => 1, 'SUBJECT' => 1, 'SUSPEND' => 1, 'UNICODE' => 1, 'UNKNOWN' => 1,
- 'UPGRADE' => 1, 'USE_FRM' => 1,
+ 'UPGRADE' => 1, 'USE_FRM' => 1, 'VIRTUAL' => 1,
'CASCADED' => 1, 'CHECKSUM' => 1, 'DUMPFILE' => 1, 'EXTENDED' => 1,
'FUNCTION' => 1, 'GEOMETRY' => 1, 'INNOBASE' => 1, 'LANGUAGE' => 1,
'MAX_ROWS' => 1, 'MIN_ROWS' => 1, 'NATIONAL' => 1, 'NVARCHAR' => 1,
@@ -77,8 +77,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, 'PRIVILEGES' => 1, 'REPEATABLE' => 1, 'ROW_FORMAT' => 1,
- 'SQL_THREAD' => 1, 'TABLESPACE' => 1,
+ 'NDBCLUSTER' => 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,
@@ -151,6 +151,7 @@ class ContextMySql50000 extends Context
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
'DATA DIRECTORY' => 7,
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7,
+ 'GENERATED ALWAYS' => 7,
'DEFAULT CHARACTER SET' => 7,
'XML' => 9,
diff --git a/src/Contexts/ContextMySql50100.php b/src/Contexts/ContextMySql50100.php
index fa43a6f..ad39eb7 100644
--- a/src/Contexts/ContextMySql50100.php
+++ b/src/Contexts/ContextMySql50100.php
@@ -67,7 +67,8 @@ class ContextMySql50100 extends Context
'OPTIONS' => 1, 'PARTIAL' => 1, 'PLUGINS' => 1, 'PREPARE' => 1, 'PROFILE' => 1,
'REBUILD' => 1, 'RECOVER' => 1, 'RESTORE' => 1, 'RETURNS' => 1, 'ROUTINE' => 1,
'SESSION' => 1, 'STORAGE' => 1, 'STRIPED' => 1, 'SUBJECT' => 1, 'SUSPEND' => 1,
- 'UNICODE' => 1, 'UNKNOWN' => 1, 'UPGRADE' => 1, 'USE_FRM' => 1, 'WRAPPER' => 1,
+ 'UNICODE' => 1, 'UNKNOWN' => 1, 'UPGRADE' => 1, 'USE_FRM' => 1, 'VIRTUAL' => 1,
+ 'WRAPPER' => 1,
'CASCADED' => 1, 'CHECKSUM' => 1, 'DATAFILE' => 1, 'DUMPFILE' => 1,
'EXTENDED' => 1, 'FUNCTION' => 1, 'GEOMETRY' => 1, 'INNOBASE' => 1,
'LANGUAGE' => 1, 'MAXVALUE' => 1, 'MAX_ROWS' => 1, 'MAX_SIZE' => 1,
@@ -83,9 +84,9 @@ class ContextMySql50100 extends Context
'UNINSTALL' => 1, 'VARIABLES' => 1,
'BERKELEYDB' => 1, 'COMPLETION' => 1, 'COMPRESSED' => 1, 'CONCURRENT' => 1,
'CONNECTION' => 1, 'CONSISTENT' => 1, 'DEALLOCATE' => 1, 'IDENTIFIED' => 1,
- 'MASTER_SSL' => 1, 'NDBCLUSTER' => 1, 'PARTITIONS' => 1, 'PRIVILEGES' => 1,
- 'REORGANISE' => 1, 'REORGANIZE' => 1, 'REPEATABLE' => 1, 'ROW_FORMAT' => 1,
- 'SQL_THREAD' => 1, 'TABLESPACE' => 1,
+ 'MASTER_SSL' => 1, 'NDBCLUSTER' => 1, 'PARTITIONS' => 1, 'PERSISTENT' => 1,
+ 'PRIVILEGES' => 1, 'REORGANISE' => 1, 'REORGANIZE' => 1, 'REPEATABLE' => 1,
+ 'ROW_FORMAT' => 1, 'SQL_THREAD' => 1, 'TABLESPACE' => 1,
'EXTENT_SIZE' => 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,
@@ -162,6 +163,7 @@ class ContextMySql50100 extends Context
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
'DATA DIRECTORY' => 7,
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7,
+ 'GENERATED ALWAYS' => 7,
'DEFAULT CHARACTER SET' => 7,
'XML' => 9,
diff --git a/src/Contexts/ContextMySql50500.php b/src/Contexts/ContextMySql50500.php
index 49afca3..c0074c7 100644
--- a/src/Contexts/ContextMySql50500.php
+++ b/src/Contexts/ContextMySql50500.php
@@ -67,7 +67,8 @@ class ContextMySql50500 extends Context
'NO_WAIT' => 1, 'OPTIONS' => 1, 'PARTIAL' => 1, 'PLUGINS' => 1, 'PREPARE' => 1,
'PROFILE' => 1, 'REBUILD' => 1, 'RECOVER' => 1, 'RESTORE' => 1, 'RETURNS' => 1,
'ROUTINE' => 1, 'SESSION' => 1, 'STORAGE' => 1, 'SUBJECT' => 1, 'SUSPEND' => 1,
- 'UNICODE' => 1, 'UNKNOWN' => 1, 'UPGRADE' => 1, 'USE_FRM' => 1, 'WRAPPER' => 1,
+ 'UNICODE' => 1, 'UNKNOWN' => 1, 'UPGRADE' => 1, 'USE_FRM' => 1, 'VIRTUAL' => 1,
+ 'WRAPPER' => 1,
'CASCADED' => 1, 'CHECKSUM' => 1, 'DATAFILE' => 1, 'DUMPFILE' => 1,
'EXTENDED' => 1, 'FUNCTION' => 1, 'GEOMETRY' => 1, 'INNOBASE' => 1,
'LANGUAGE' => 1, 'MAX_ROWS' => 1, 'MAX_SIZE' => 1, 'MIN_ROWS' => 1,
@@ -82,9 +83,9 @@ class ContextMySql50500 extends Context
'TEMPTABLE' => 1, 'UNDEFINED' => 1, 'UNINSTALL' => 1, 'VARIABLES' => 1,
'COMPLETION' => 1, 'COMPRESSED' => 1, 'CONCURRENT' => 1, 'CONNECTION' => 1,
'CONSISTENT' => 1, 'DEALLOCATE' => 1, 'IDENTIFIED' => 1, 'MASTER_SSL' => 1,
- 'NDBCLUSTER' => 1, 'PARTITIONS' => 1, 'PRIVILEGES' => 1, 'REORGANIZE' => 1,
- 'REPEATABLE' => 1, 'ROW_FORMAT' => 1, 'SQL_THREAD' => 1, 'TABLESPACE' => 1,
- 'TABLE_NAME' => 1,
+ 'NDBCLUSTER' => 1, 'PARTITIONS' => 1, 'PERSISTENT' => 1, 'PRIVILEGES' => 1,
+ 'REORGANIZE' => 1, 'REPEATABLE' => 1, 'ROW_FORMAT' => 1, 'SQL_THREAD' => 1,
+ 'TABLESPACE' => 1, 'TABLE_NAME' => 1,
'COLUMN_NAME' => 1, 'CURSOR_NAME' => 1, 'EXTENT_SIZE' => 1, 'FRAC_SECOND' => 1,
'MASTER_HOST' => 1, 'MASTER_PORT' => 1, 'MASTER_USER' => 1, 'MYSQL_ERRNO' => 1,
'PROCESSLIST' => 1, 'REPLICATION' => 1, 'SCHEMA_NAME' => 1, 'SQL_TSI_DAY' => 1,
@@ -167,6 +168,7 @@ class ContextMySql50500 extends Context
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
'DATA DIRECTORY' => 7,
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7,
+ 'GENERATED ALWAYS' => 7,
'DEFAULT CHARACTER SET' => 7,
'XML' => 9,
diff --git a/src/Contexts/ContextMySql50600.php b/src/Contexts/ContextMySql50600.php
index 8c91bdb..453d9e2 100644
--- a/src/Contexts/ContextMySql50600.php
+++ b/src/Contexts/ContextMySql50600.php
@@ -68,7 +68,7 @@ class ContextMySql50600 extends Context
'PLUGINS' => 1, 'PREPARE' => 1, 'PROFILE' => 1, 'REBUILD' => 1, 'RECOVER' => 1,
'RESTORE' => 1, 'RETURNS' => 1, 'ROUTINE' => 1, 'SESSION' => 1, 'STORAGE' => 1,
'SUBJECT' => 1, 'SUSPEND' => 1, 'UNICODE' => 1, 'UNKNOWN' => 1, 'UPGRADE' => 1,
- 'USE_FRM' => 1, 'WRAPPER' => 1,
+ 'USE_FRM' => 1, 'VIRTUAL' => 1, 'WRAPPER' => 1,
'CASCADED' => 1, 'CHECKSUM' => 1, 'DATAFILE' => 1, 'DUMPFILE' => 1,
'EXCHANGE' => 1, 'EXTENDED' => 1, 'FUNCTION' => 1, 'GEOMETRY' => 1,
'LANGUAGE' => 1, 'MAX_ROWS' => 1, 'MAX_SIZE' => 1, 'MIN_ROWS' => 1,
@@ -83,9 +83,9 @@ class ContextMySql50600 extends Context
'UNDEFINED' => 1, 'UNINSTALL' => 1, 'VARIABLES' => 1,
'COMPLETION' => 1, 'COMPRESSED' => 1, 'CONCURRENT' => 1, 'CONNECTION' => 1,
'CONSISTENT' => 1, 'DEALLOCATE' => 1, 'IDENTIFIED' => 1, 'MASTER_SSL' => 1,
- 'NDBCLUSTER' => 1, 'PARTITIONS' => 1, 'PLUGIN_DIR' => 1, 'PRIVILEGES' => 1,
- 'REORGANIZE' => 1, 'REPEATABLE' => 1, 'ROW_FORMAT' => 1, 'SQL_THREAD' => 1,
- 'TABLESPACE' => 1, 'TABLE_NAME' => 1,
+ 'NDBCLUSTER' => 1, 'PARTITIONS' => 1, 'PERSISTENT' => 1, 'PLUGIN_DIR' => 1,
+ 'PRIVILEGES' => 1, 'REORGANIZE' => 1, 'REPEATABLE' => 1, 'ROW_FORMAT' => 1,
+ 'SQL_THREAD' => 1, 'TABLESPACE' => 1, 'TABLE_NAME' => 1,
'COLUMN_NAME' => 1, 'CURSOR_NAME' => 1, 'DIAGNOSTICS' => 1, 'EXTENT_SIZE' => 1,
'MASTER_HOST' => 1, 'MASTER_PORT' => 1, 'MASTER_USER' => 1, 'MYSQL_ERRNO' => 1,
'PROCESSLIST' => 1, 'REPLICATION' => 1, 'SCHEMA_NAME' => 1, 'SQL_TSI_DAY' => 1,
@@ -173,6 +173,7 @@ class ContextMySql50600 extends Context
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
'DATA DIRECTORY' => 7,
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7,
+ 'GENERATED ALWAYS' => 7,
'DEFAULT CHARACTER SET' => 7,
'XML' => 9,
diff --git a/src/Contexts/ContextMySql50700.php b/src/Contexts/ContextMySql50700.php
index b522e82..9946a26 100644
--- a/src/Contexts/ContextMySql50700.php
+++ b/src/Contexts/ContextMySql50700.php
@@ -85,9 +85,9 @@ class ContextMySql50700 extends Context
'UNDEFINED' => 1, 'UNINSTALL' => 1, 'VARIABLES' => 1,
'COMPLETION' => 1, 'COMPRESSED' => 1, 'CONCURRENT' => 1, 'CONNECTION' => 1,
'CONSISTENT' => 1, 'DEALLOCATE' => 1, 'IDENTIFIED' => 1, 'MASTER_SSL' => 1,
- 'NDBCLUSTER' => 1, 'PARTITIONS' => 1, 'PLUGIN_DIR' => 1, 'PRIVILEGES' => 1,
- 'REORGANIZE' => 1, 'REPEATABLE' => 1, 'ROW_FORMAT' => 1, 'SQL_THREAD' => 1,
- 'TABLESPACE' => 1, 'TABLE_NAME' => 1, 'VALIDATION' => 1,
+ 'NDBCLUSTER' => 1, 'PARTITIONS' => 1, 'PERSISTENT' => 1, 'PLUGIN_DIR' => 1,
+ 'PRIVILEGES' => 1, 'REORGANIZE' => 1, 'REPEATABLE' => 1, 'ROW_FORMAT' => 1,
+ 'SQL_THREAD' => 1, 'TABLESPACE' => 1, 'TABLE_NAME' => 1, 'VALIDATION' => 1,
'COLUMN_NAME' => 1, 'COMPRESSION' => 1, 'CURSOR_NAME' => 1, 'DIAGNOSTICS' => 1,
'EXTENT_SIZE' => 1, 'MASTER_HOST' => 1, 'MASTER_PORT' => 1, 'MASTER_USER' => 1,
'MYSQL_ERRNO' => 1, 'NONBLOCKING' => 1, 'PROCESSLIST' => 1, 'REPLICATION' => 1,
@@ -181,6 +181,7 @@ class ContextMySql50700 extends Context
'CHARACTER SET' => 7, 'IF NOT EXISTS' => 7,
'DATA DIRECTORY' => 7,
'DEFAULT CHARSET' => 7, 'DEFAULT COLLATE' => 7, 'INDEX DIRECTORY' => 7,
+ 'GENERATED ALWAYS' => 7,
'DEFAULT CHARACTER SET' => 7,
'XML' => 9,
diff --git a/src/Statement.php b/src/Statement.php
index a9ee3d3..f2d72b3 100644
--- a/src/Statement.php
+++ b/src/Statement.php
@@ -95,7 +95,7 @@ abstract class Statement
}
/**
- * Builds the statement.
+ * Builds the string representation of this statement.
*
* @return string
*/
@@ -292,4 +292,15 @@ abstract class Statement
{
}
+
+ /**
+ * Builds the string representation of this statement.
+ *
+ * @see static::build
+ *
+ * @return string
+ */
+ public function __toString() {
+ return static::build($this);
+ }
}
diff --git a/tests/Builder/StatementTest.php b/tests/Builder/StatementTest.php
index e02324d..0dff320 100644
--- a/tests/Builder/StatementTest.php
+++ b/tests/Builder/StatementTest.php
@@ -36,7 +36,7 @@ class StatementTest extends TestCase
'FROM `film`, `actor` ' .
'WHERE film_id > 10 OR actor.age > 25 ' .
'LIMIT 10, 1 ',
- $stmt->build()
+ (string) $stmt
);
}
}
diff --git a/tests/Components/OptionsArrayTest.php b/tests/Components/OptionsArrayTest.php
index 42f54dd..8c24e3b 100644
--- a/tests/Components/OptionsArrayTest.php
+++ b/tests/Components/OptionsArrayTest.php
@@ -14,7 +14,7 @@ class OptionsArrayTest extends TestCase
{
$component = OptionsArray::parse(
new Parser(),
- $this->getTokensList('A B = (test) C'),
+ $this->getTokensList('A B = /*comment*/ (test) C'),
array(
'A' => 1,
'B' => array(2, 'var'),
@@ -26,9 +26,9 @@ class OptionsArrayTest extends TestCase
1 => 'A',
2 => array(
'name' => 'B',
- 'value' => 'test',
- 'value_' => 'test',
- 'equal' => false,
+ 'value' => '(test)',
+ 'value_' => '(test)',
+ 'equal' => true,
),
3 => 'C',
),
@@ -36,6 +36,20 @@ class OptionsArrayTest extends TestCase
);
}
+ public function testParseExpr()
+ {
+ $component = OptionsArray::parse(
+ new Parser(),
+ $this->getTokensList('SUM = (3 + 5) RESULT = 8'),
+ array(
+ 'SUM' => array(1, 'expr', array('bracketsDelimited' => true)),
+ 'RESULT' => array(2, 'var'),
+ )
+ );
+ $this->assertEquals('(3 + 5)', (string) $component->has('SUM'));
+ $this->assertEquals('8', $component->has('RESULT'));
+ }
+
public function testHas()
{
$component = new OptionsArray(
diff --git a/tests/Parser/CreateStatementTest.php b/tests/Parser/CreateStatementTest.php
index eef8183..9f56a6b 100644
--- a/tests/Parser/CreateStatementTest.php
+++ b/tests/Parser/CreateStatementTest.php
@@ -25,6 +25,7 @@ class CreateStatementTest extends TestCase
array('parseCreateProcedure2'),
array('parseCreateTable'),
array('parseCreateTable2'),
+ array('parseCreateTable3'),
array('parseCreateTableErr1'),
array('parseCreateTrigger'),
array('parseCreateUser'),
diff --git a/tests/data/parseCreateTable3.in b/tests/data/parseCreateTable3.in
new file mode 100644
index 0000000..05f2bc0
--- /dev/null
+++ b/tests/data/parseCreateTable3.in
@@ -0,0 +1,6 @@
+CREATE TABLE table1 (
+ a INT NOT NULL,
+ b VARCHAR(32),
+ c INT AS (a mod 10) VIRTUAL,
+ d VARCHAR(5) AS (left(b,5)) PERSISTENT
+); \ No newline at end of file
diff --git a/tests/data/parseCreateTable3.out b/tests/data/parseCreateTable3.out
new file mode 100644
index 0000000..6a629f0
--- /dev/null
+++ b/tests/data/parseCreateTable3.out
@@ -0,0 +1,6 @@
+a:2:{s:6:"parser";O:16:"SqlParser\Parser":4:{s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:63:{i:0;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"CREATE";s:5:"value";s:6:"CREATE";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:0;}i:1;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:6;}i:2;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"TABLE";s:5:"value";s:5:"TABLE";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:7;}i:3;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:12;}i:4;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"table1";s:5:"value";s:6:"table1";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:13;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:19;}i:6;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:20;}i:7;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:21;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"a";s:5:"value";s:1:"a";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:26;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:27;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"INT";s:5:"value";s:3:"INT";s:4:"type";i:1;s:5:"flags";i:11;s:8:"position";i:28;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:31;}i:12;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"NOT NULL";s:5:"value";s:8:"NOT NULL";s:4:"type";i:1;s:5:"flags";i:7;s:8:"position";i:32;}i:13;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:40;}i:14;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:41;}i:15;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"b";s:5:"value";s:1:"b";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:46;}i:16;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:47;}i:17;O:15:"SqlParser\Token":5:{s:5:"token";s:7:"VARCHAR";s:5:"value";s:7:"VARCHAR";s:4:"type";i:1;s:5:"flags";i:11;s:8:"position";i:48;}i:18;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:55;}i:19;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"32";s:5:"value";i:32;s:4:"type";i:6;s:5:"flags";i:0;s:8:"position";i:56;}i:20;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:58;}i:21;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:59;}i:22;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:60;}i:23;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"c";s:5:"value";s:1:"c";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:65;}i:24;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:66;}i:25;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"INT";s:5:"value";s:3:"INT";s:4:"type";i:1;s:5:"flags";i:11;s:8:"position";i:67;}i:26;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:70;}i:27;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"AS";s:5:"value";s:2:"AS";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:71;}i:28;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:73;}i:29;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:74;}i:30;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"a";s:5:"value";s:1:"a";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:75;}i:31;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:76;}i:32;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"mod";s:5:"value";s:3:"MOD";s:4:"type";i:1;s:5:"flags";i:35;s:8:"position";i:77;}i:33;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:80;}i:34;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"10";s:5:"value";i:10;s:4:"type";i:6;s:5:"flags";i:0;s:8:"position";i:81;}i:35;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:83;}i:36;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:84;}i:37;O:15:"SqlParser\Token":5:{s:5:"token";s:7:"VIRTUAL";s:5:"value";s:7:"VIRTUAL";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:85;}i:38;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:92;}i:39;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"
+ ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:93;}i:40;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"d";s:5:"value";s:1:"d";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:98;}i:41;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:99;}i:42;O:15:"SqlParser\Token":5:{s:5:"token";s:7:"VARCHAR";s:5:"value";s:7:"VARCHAR";s:4:"type";i:1;s:5:"flags";i:11;s:8:"position";i:100;}i:43;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:107;}i:44;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"5";s:5:"value";i:5;s:4:"type";i:6;s:5:"flags";i:0;s:8:"position";i:108;}i:45;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:109;}i:46;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:110;}i:47;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"AS";s:5:"value";s:2:"AS";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:111;}i:48;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:113;}i:49;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:114;}i:50;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"left";s:5:"value";s:4:"LEFT";s:4:"type";i:1;s:5:"flags";i:35;s:8:"position";i:115;}i:51;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:119;}i:52;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"b";s:5:"value";s:1:"b";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:120;}i:53;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:121;}i:54;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"5";s:5:"value";i:5;s:4:"type";i:6;s:5:"flags";i:0;s:8:"position";i:122;}i:55;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:123;}i:56;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:124;}i:57;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:125;}i:58;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"PERSISTENT";s:5:"value";s:10:"PERSISTENT";s:4:"type";i:1;s:5:"flags";i:1;s:8:"position";i:126;}i:59;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"
+";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:136;}i:60;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:137;}i:61;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:138;}i:62;O:15:"SqlParser\Token":5:{s:5:"token";N;s:5:"value";N;s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";N;}}s:5:"count";i:63;s:3:"idx";i:63;}s:6:"strict";b:0;s:6:"errors";a:0:{}s:10:"statements";a:1:{i:0;O:36:"SqlParser\Statements\CreateStatement":10:{s:4:"name";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:6:"table1";s:6:"column";N;s:4:"expr";s:6:"table1";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}s:13:"entityOptions";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:6:"fields";a:4:{i:0;O:36:"SqlParser\Components\FieldDefinition":6:{s:4:"name";s:1:"a";s:12:"isConstraint";N;s:4:"type";O:29:"SqlParser\Components\DataType":3:{s:4:"name";s:3:"INT";s:10:"parameters";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}}s:3:"key";N;s:10:"references";N;s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:1:{i:1;s:8:"NOT NULL";}}}i:1;O:36:"SqlParser\Components\FieldDefinition":6:{s:4:"name";s:1:"b";s:12:"isConstraint";N;s:4:"type";O:29:"SqlParser\Components\DataType":3:{s:4:"name";s:7:"VARCHAR";s:10:"parameters";a:1:{i:0;i:32;}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}}s:3:"key";N;s:10:"references";N;s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}}i:2;O:36:"SqlParser\Components\FieldDefinition":6:{s:4:"name";s:1:"c";s:12:"isConstraint";N;s:4:"type";O:29:"SqlParser\Components\DataType":3:{s:4:"name";s:3:"INT";s:10:"parameters";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}}s:3:"key";N;s:10:"references";N;s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:2:{i:2;a:2:{s:4:"name";s:2:"AS";s:5:"value";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";N;s:4:"expr";s:10:"(a mod 10)";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}i:3;s:7:"VIRTUAL";}}}i:3;O:36:"SqlParser\Components\FieldDefinition":6:{s:4:"name";s:1:"d";s:12:"isConstraint";N;s:4:"type";O:29:"SqlParser\Components\DataType":3:{s:4:"name";s:7:"VARCHAR";s:10:"parameters";a:1:{i:0;i:5;}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}}s:3:"key";N;s:10:"references";N;s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:2:{i:2;a:2:{s:4:"name";s:2:"AS";s:5:"value";O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";N;s:4:"expr";s:11:"(left(b,5))";s:5:"alias";N;s:8:"function";s:4:"LEFT";s:8:"subquery";N;}}i:3;s:10:"PERSISTENT";}}}}s:5:"table";N;s:6:"return";N;s:10:"parameters";N;s:4:"body";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:1:{i:6;s:5:"TABLE";}}s:5:"first";i:0;s:4:"last";i:60;}}}s:6:"errors";a:0:{}} \ No newline at end of file
diff --git a/tests/data/parseSelect2.out b/tests/data/parseSelect2.out
index a5d09c3..47a5cd9 100644
--- a/tests/data/parseSelect2.out
+++ b/tests/data/parseSelect2.out
@@ -1 +1 @@
-a:2:{s:6:"parser";O:16:"SqlParser\Parser":4:{s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:33:{i:0;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"SELECT";s:5:"value";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:0;}i:1;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:6;}i:2;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:7;}i:3;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"SELECT";s:5:"value";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:8;}i:4;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:14;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"'foo'";s:5:"value";s:3:"foo";s:4:"type";i:7;s:5:"flags";i:1;s:8:"position";i:15;}i:6;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:20;}i:7;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:21;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"bar";s:5:"value";s:3:"bar";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:22;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:25;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:26;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:27;}i:12;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"SELECT";s:5:"value";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:28;}i:13;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:34;}i:14;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"'baz'";s:5:"value";s:3:"baz";s:4:"type";i:7;s:5:"flags";i:1;s:8:"position";i:35;}i:15;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:40;}i:16;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:41;}i:17;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"AS";s:5:"value";s:2:"AS";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:42;}i:18;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:44;}i:19;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"qux";s:5:"value";s:3:"qux";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:45;}i:20;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:48;}i:21;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:49;}i:22;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"a";s:5:"value";s:1:"a";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:50;}i:23;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:51;}i:24;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"as";s:5:"value";s:2:"AS";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:52;}i:25;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:54;}i:26;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"b";s:5:"value";s:1:"b";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:55;}i:27;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:56;}i:28;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"FROM";s:5:"value";s:4:"FROM";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:57;}i:29;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:61;}i:30;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"tabl";s:5:"value";s:4:"tabl";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:62;}i:31;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:66;}i:32;O:15:"SqlParser\Token":5:{s:5:"token";N;s:5:"value";N;s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";N;}}s:5:"count";i:33;s:3:"idx";i:33;}s:6:"strict";b:0;s:6:"errors";a:0:{}s:10:"statements";a:1:{i:0;O:36:"SqlParser\Statements\SelectStatement":15:{s:4:"expr";a:3:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";N;s:4:"expr";s:18:"(SELECT 'foo') bar";s:5:"alias";s:3:"bar";s:8:"function";N;s:8:"subquery";s:6:"SELECT";}i:1;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";N;s:4:"expr";s:14:"(SELECT 'baz')";s:5:"alias";s:3:"qux";s:8:"function";N;s:8:"subquery";s:6:"SELECT";}i:2;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";s:1:"a";s:4:"expr";s:1:"a";s:5:"alias";s:1:"b";s:8:"function";N;s:8:"subquery";N;}}s:4:"from";a:1:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:4:"tabl";s:6:"column";N;s:4:"expr";s:4:"tabl";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}s:9:"partition";N;s:5:"where";N;s:5:"group";N;s:6:"having";N;s:5:"order";N;s:5:"limit";N;s:9:"procedure";N;s:4:"into";N;s:4:"join";N;s:5:"union";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:30;}}}s:6:"errors";a:0:{}} \ No newline at end of file
+a:2:{s:6:"parser";O:16:"SqlParser\Parser":4:{s:4:"list";O:20:"SqlParser\TokensList":3:{s:6:"tokens";a:33:{i:0;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"SELECT";s:5:"value";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:0;}i:1;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:6;}i:2;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:7;}i:3;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"SELECT";s:5:"value";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:8;}i:4;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:14;}i:5;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"'foo'";s:5:"value";s:3:"foo";s:4:"type";i:7;s:5:"flags";i:1;s:8:"position";i:15;}i:6;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:20;}i:7;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:21;}i:8;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"bar";s:5:"value";s:3:"bar";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:22;}i:9;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:25;}i:10;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:26;}i:11;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"(";s:5:"value";s:1:"(";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:27;}i:12;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"SELECT";s:5:"value";s:6:"SELECT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:28;}i:13;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:34;}i:14;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"'baz'";s:5:"value";s:3:"baz";s:4:"type";i:7;s:5:"flags";i:1;s:8:"position";i:35;}i:15;O:15:"SqlParser\Token":5:{s:5:"token";s:1:")";s:5:"value";s:1:")";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:40;}i:16;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:41;}i:17;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"AS";s:5:"value";s:2:"AS";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:42;}i:18;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:44;}i:19;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"qux";s:5:"value";s:3:"qux";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:45;}i:20;O:15:"SqlParser\Token":5:{s:5:"token";s:1:",";s:5:"value";s:1:",";s:4:"type";i:2;s:5:"flags";i:16;s:8:"position";i:48;}i:21;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:49;}i:22;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"a";s:5:"value";s:1:"a";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:50;}i:23;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:51;}i:24;O:15:"SqlParser\Token":5:{s:5:"token";s:2:"as";s:5:"value";s:2:"AS";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:52;}i:25;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:54;}i:26;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"b";s:5:"value";s:1:"b";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:55;}i:27;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:56;}i:28;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"FROM";s:5:"value";s:4:"FROM";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:57;}i:29;O:15:"SqlParser\Token":5:{s:5:"token";s:1:" ";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:61;}i:30;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"tabl";s:5:"value";s:4:"tabl";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:62;}i:31;O:15:"SqlParser\Token":5:{s:5:"token";s:1:";";s:5:"value";s:1:";";s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";i:66;}i:32;O:15:"SqlParser\Token":5:{s:5:"token";N;s:5:"value";N;s:4:"type";i:9;s:5:"flags";i:0;s:8:"position";N;}}s:5:"count";i:33;s:3:"idx";i:33;}s:6:"strict";b:0;s:6:"errors";a:0:{}s:10:"statements";a:1:{i:0;O:36:"SqlParser\Statements\SelectStatement":15:{s:4:"expr";a:3:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";N;s:4:"expr";s:14:"(SELECT 'foo')";s:5:"alias";s:3:"bar";s:8:"function";N;s:8:"subquery";s:6:"SELECT";}i:1;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";N;s:4:"expr";s:14:"(SELECT 'baz')";s:5:"alias";s:3:"qux";s:8:"function";N;s:8:"subquery";s:6:"SELECT";}i:2;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";N;s:6:"column";s:1:"a";s:4:"expr";s:1:"a";s:5:"alias";s:1:"b";s:8:"function";N;s:8:"subquery";N;}}s:4:"from";a:1:{i:0;O:31:"SqlParser\Components\Expression":7:{s:8:"database";N;s:5:"table";s:4:"tabl";s:6:"column";N;s:4:"expr";s:4:"tabl";s:5:"alias";N;s:8:"function";N;s:8:"subquery";N;}}s:9:"partition";N;s:5:"where";N;s:5:"group";N;s:6:"having";N;s:5:"order";N;s:5:"limit";N;s:9:"procedure";N;s:4:"into";N;s:4:"join";N;s:5:"union";a:0:{}s:7:"options";O:33:"SqlParser\Components\OptionsArray":1:{s:7:"options";a:0:{}}s:5:"first";i:0;s:4:"last";i:30;}}}s:6:"errors";a:0:{}} \ No newline at end of file