summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Ungureanu <udan1107@gmail.com>2015-06-23 19:06:11 +0300
committerDan Ungureanu <udan1107@gmail.com>2015-06-23 19:06:11 +0300
commit22f167b6fe82809c33e49a3a23dd500178282985 (patch)
tree1437b3de48840ab77a895dfafcbdbf27bde966fd
parente316e267117a38e59040002154f2f980b1a6501d (diff)
downloadsql-parser-22f167b6fe82809c33e49a3a23dd500178282985.zip
sql-parser-22f167b6fe82809c33e49a3a23dd500178282985.tar.gz
sql-parser-22f167b6fe82809c33e49a3a23dd500178282985.tar.bz2
Added table utilities.
Implemented better support for keys in FieldDefFragment. Improved contexts' documentation and definition.
-rw-r--r--src/Context.php19
-rw-r--r--src/Contexts/ContextMySql50000.php19
-rw-r--r--src/Contexts/ContextMySql50100.php19
-rw-r--r--src/Contexts/ContextMySql50500.php19
-rw-r--r--src/Contexts/ContextMySql50600.php19
-rw-r--r--src/Contexts/ContextMySql50700.php19
-rw-r--r--src/Fragments/FieldDefFragment.php76
-rw-r--r--src/Fragments/KeyFragment.php132
-rw-r--r--src/Fragments/ReferencesKeyword.php115
-rw-r--r--src/Utils/Table.php45
-rw-r--r--tests/data/parseCreateTable.out2
11 files changed, 420 insertions, 64 deletions
diff --git a/src/Context.php b/src/Context.php
index eed10d3..cbe666d 100644
--- a/src/Context.php
+++ b/src/Context.php
@@ -53,30 +53,22 @@ abstract class Context
*/
public static $contextPrefix = '\\SqlParser\\Contexts\\Context';
- // -------------------------------------------------------------------------
- // Keywords.
-
/**
* List of keywords.
*
* Because, PHP's associative arrays are basically hash tables, it is more
* efficient to store keywords as keys instead of values.
*
- * There are multiple types of keyword, depending on the value associated:
- * 1 - reserved keywords
- * 2 - keyword
- * 3 - composite keyword (unofficial); used to make the job of the lexer
- * much easier by grouping keywords that may appear together
+ * The value associated to each keyword represents its flags.
*
- * Keywords below are sorted by type, length and keyword.
+ * @see Token::FLAG_KEYWORD_*
+ *
+ * Elements are sorted by flags, length and keyword.
*
* @var array
*/
public static $KEYWORDS = array();
- // -------------------------------------------------------------------------
- // Operators.
-
/**
* List of operators and their flags.
*
@@ -110,9 +102,6 @@ abstract class Context
'(' => 16, ')' => 16, '.' => 16, ',' => 16,
);
- // -------------------------------------------------------------------------
- // SQL Modes.
-
/*
* Server SQL Modes
* https://dev.mysql.com/doc/refman/5.0/en/sql-mode.html
diff --git a/src/Contexts/ContextMySql50000.php b/src/Contexts/ContextMySql50000.php
index b81d687..f2357f2 100644
--- a/src/Contexts/ContextMySql50000.php
+++ b/src/Contexts/ContextMySql50000.php
@@ -1,5 +1,11 @@
<?php
+/**
+ * Context for MySQL 5.
+ *
+ * @link https://dev.mysql.com/doc/refman/5.0/en/keywords.html
+ */
+
namespace SqlParser\Contexts;
use SqlParser\Context;
@@ -16,6 +22,15 @@ use SqlParser\Context;
class ContextMySql50000 extends Context
{
+ /**
+ * List of keywords.
+ *
+ * The value associated to each keyword represents its flags.
+ *
+ * @see Token::FLAG_KEYWORD_*
+ *
+ * @var array
+ */
public static $KEYWORDS = array(
'DO' => 1, 'IO' => 1, 'NO' => 1, 'XA' => 1,
@@ -137,8 +152,8 @@ class ContextMySql50000 extends Context
'MINUTE_MICROSECOND' => 3, 'NO_WRITE_TO_BINLOG' => 3, 'SECOND_MICROSECOND' => 3,
'SQL_CALC_FOUND_ROWS' => 3,
- 'NOT NULL' => 5,
- 'ON UPDATE' => 5,
+ 'NOT NULL' => 5, 'SET NULL' => 5,
+ 'NO ACTION' => 5, 'ON DELETE' => 5, 'ON UPDATE' => 5,
'CHARACTER SET' => 5, 'IF NOT EXISTS' => 5,
'DATA DIRECTORY' => 5,
'DEFAULT COLLATE' => 5, 'INDEX DIRECTORY' => 5,
diff --git a/src/Contexts/ContextMySql50100.php b/src/Contexts/ContextMySql50100.php
index 260925e..dcdce84 100644
--- a/src/Contexts/ContextMySql50100.php
+++ b/src/Contexts/ContextMySql50100.php
@@ -1,5 +1,11 @@
<?php
+/**
+ * Context for MySQL 5.1.
+ *
+ * @link https://dev.mysql.com/doc/refman/5.1/en/keywords.html
+ */
+
namespace SqlParser\Contexts;
use SqlParser\Context;
@@ -16,6 +22,15 @@ use SqlParser\Context;
class ContextMySql50100 extends Context
{
+ /**
+ * List of keywords.
+ *
+ * The value associated to each keyword represents its flags.
+ *
+ * @see Token::FLAG_KEYWORD_*
+ *
+ * @var array
+ */
public static $KEYWORDS = array(
'AT' => 1, 'DO' => 1, 'IO' => 1, 'NO' => 1, 'XA' => 1,
@@ -151,8 +166,8 @@ class ContextMySql50100 extends Context
'SQL_CALC_FOUND_ROWS' => 3,
'MASTER_SSL_VERIFY_SERVER_CERT' => 3,
- 'NOT NULL' => 5,
- 'ON UPDATE' => 5,
+ 'NOT NULL' => 5, 'SET NULL' => 5,
+ 'NO ACTION' => 5, 'ON DELETE' => 5, 'ON UPDATE' => 5,
'CHARACTER SET' => 5, 'IF NOT EXISTS' => 5,
'DATA DIRECTORY' => 5,
'DEFAULT COLLATE' => 5, 'INDEX DIRECTORY' => 5,
diff --git a/src/Contexts/ContextMySql50500.php b/src/Contexts/ContextMySql50500.php
index e70b931..15e079e 100644
--- a/src/Contexts/ContextMySql50500.php
+++ b/src/Contexts/ContextMySql50500.php
@@ -1,5 +1,11 @@
<?php
+/**
+ * Context for MySQL 5.5.
+ *
+ * @link https://dev.mysql.com/doc/refman/5.5/en/keywords.html
+ */
+
namespace SqlParser\Contexts;
use SqlParser\Context;
@@ -16,6 +22,15 @@ use SqlParser\Context;
class ContextMySql50500 extends Context
{
+ /**
+ * List of keywords.
+ *
+ * The value associated to each keyword represents its flags.
+ *
+ * @see Token::FLAG_KEYWORD_*
+ *
+ * @var array
+ */
public static $KEYWORDS = array(
'AT' => 1, 'DO' => 1, 'IO' => 1, 'NO' => 1, 'XA' => 1,
@@ -154,8 +169,8 @@ class ContextMySql50500 extends Context
'SQL_CALC_FOUND_ROWS' => 3,
'MASTER_SSL_VERIFY_SERVER_CERT' => 3,
- 'NOT NULL' => 5,
- 'ON UPDATE' => 5,
+ 'NOT NULL' => 5, 'SET NULL' => 5,
+ 'NO ACTION' => 5, 'ON DELETE' => 5, 'ON UPDATE' => 5,
'CHARACTER SET' => 5, 'IF NOT EXISTS' => 5,
'DATA DIRECTORY' => 5,
'DEFAULT COLLATE' => 5, 'INDEX DIRECTORY' => 5,
diff --git a/src/Contexts/ContextMySql50600.php b/src/Contexts/ContextMySql50600.php
index 819ec1c..1135e52 100644
--- a/src/Contexts/ContextMySql50600.php
+++ b/src/Contexts/ContextMySql50600.php
@@ -1,5 +1,11 @@
<?php
+/**
+ * Context for MySQL 5.6.
+ *
+ * @link https://dev.mysql.com/doc/refman/5.6/en/keywords.html
+ */
+
namespace SqlParser\Contexts;
use SqlParser\Context;
@@ -16,6 +22,15 @@ use SqlParser\Context;
class ContextMySql50600 extends Context
{
+ /**
+ * List of keywords.
+ *
+ * The value associated to each keyword represents its flags.
+ *
+ * @see Token::FLAG_KEYWORD_*
+ *
+ * @var array
+ */
public static $KEYWORDS = array(
'AT' => 1, 'DO' => 1, 'IO' => 1, 'NO' => 1, 'XA' => 1,
@@ -165,8 +180,8 @@ class ContextMySql50600 extends Context
'SQL_CALC_FOUND_ROWS' => 3,
'MASTER_SSL_VERIFY_SERVER_CERT' => 3,
- 'NOT NULL' => 5,
- 'ON UPDATE' => 5,
+ 'NOT NULL' => 5, 'SET NULL' => 5,
+ 'NO ACTION' => 5, 'ON DELETE' => 5, 'ON UPDATE' => 5,
'CHARACTER SET' => 5, 'IF NOT EXISTS' => 5,
'DATA DIRECTORY' => 5,
'DEFAULT COLLATE' => 5, 'INDEX DIRECTORY' => 5,
diff --git a/src/Contexts/ContextMySql50700.php b/src/Contexts/ContextMySql50700.php
index db047b1..799ae1b 100644
--- a/src/Contexts/ContextMySql50700.php
+++ b/src/Contexts/ContextMySql50700.php
@@ -1,5 +1,11 @@
<?php
+/**
+ * Context for MySQL 5.7.
+ *
+ * @link https://dev.mysql.com/doc/refman/5.7/en/keywords.html
+ */
+
namespace SqlParser\Contexts;
use SqlParser\Context;
@@ -16,6 +22,15 @@ use SqlParser\Context;
class ContextMySql50700 extends Context
{
+ /**
+ * List of keywords.
+ *
+ * The value associated to each keyword represents its flags.
+ *
+ * @see Token::FLAG_KEYWORD_*
+ *
+ * @var array
+ */
public static $KEYWORDS = array(
'AT' => 1, 'DO' => 1, 'IO' => 1, 'NO' => 1, 'XA' => 1,
@@ -170,8 +185,8 @@ class ContextMySql50700 extends Context
'SQL_CALC_FOUND_ROWS' => 3,
'MASTER_SSL_VERIFY_SERVER_CERT' => 3,
- 'NOT NULL' => 5,
- 'ON UPDATE' => 5,
+ 'NOT NULL' => 5, 'SET NULL' => 5,
+ 'NO ACTION' => 5, 'ON DELETE' => 5, 'ON UPDATE' => 5,
'CHARACTER SET' => 5, 'IF NOT EXISTS' => 5,
'DATA DIRECTORY' => 5,
'DEFAULT COLLATE' => 5, 'INDEX DIRECTORY' => 5,
diff --git a/src/Fragments/FieldDefFragment.php b/src/Fragments/FieldDefFragment.php
index f4a08bd..20983e9 100644
--- a/src/Fragments/FieldDefFragment.php
+++ b/src/Fragments/FieldDefFragment.php
@@ -49,6 +49,13 @@ class FieldDefFragment extends Fragment
public $name;
/**
+ * Whether this field is a constraint or not.
+ *
+ * @var bool
+ */
+ public $isConstraint;
+
+ /**
* The data type of thew new column.
*
* @var DataTypeFragment
@@ -56,11 +63,18 @@ class FieldDefFragment extends Fragment
public $type;
/**
- * The array of indexes.
+ * The key.
*
- * @var ArrayFragment
+ * @var KeyFragment
*/
- public $indexes;
+ public $key;
+
+ /**
+ * The table that is referenced.
+ *
+ * @var ReferencesKeyword
+ */
+ public $references;
/**
* The options of the new field fragment.
@@ -89,22 +103,18 @@ class FieldDefFragment extends Fragment
*
* 0 -----------------------[ ( ]------------------------> 1
*
- * 1 -------------------[ CONSTRAINT ]-------------------> 4
- * 1 --------------------[ key type ]--------------------> 5
- * 1 -------------------[ column name ]------------------> 2
+ * 1 --------------------[ CONSTRAINT ]------------------> 1
+ * 1 -----------------------[ key ]----------------------> 2
+ * 1 -------------[ constraint / column name ]-----------> 2
*
- * 2 -------------------[ data type ]--------------------> 3
+ * 2 --------------------[ data type ]-------------------> 3
*
- * 3 ---------------------[ size ]---------------------> 3
* 3 ---------------------[ options ]--------------------> 4
*
- * 4 -----------------[ CONSTRAINT name ]----------------> 4
- * 4 -----------------[ CONSTRAINT type ]----------------> 5
- *
- * 5 -------------------[ index names ]------------------> 6
+ * 4 --------------------[ REFERENCES ]------------------> 4
*
- * 6 ------------------------[ , ]-----------------------> 1
- * 6 ------------------------[ ) ]-----------------------> -1
+ * 5 ------------------------[ , ]-----------------------> 1
+ * 5 ------------------------[ ) ]-----------------------> -1
*
* @var int
*/
@@ -132,42 +142,34 @@ class FieldDefFragment extends Fragment
if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
$state = 1;
}
- continue;
} elseif ($state === 1) {
if (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'CONSTRAINT')) {
- $state = 4;
+ $expr->isConstraint = true;
} elseif (($token->type === Token::TYPE_KEYWORD) && ($token->flags & Token::FLAG_KEYWORD_KEY)) {
- $expr->type = $token->value;
- $state = 5;
- } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->flags & Token::FLAG_KEYWORD_RESERVED)) {
- $parser->error('Unexpected keyword.', $token);
- break; // TODO: Skip to the end of the query.
+ $expr->key = KeyFragment::parse($parser, $list);
+ $state = 4;
} else {
$expr->name = $token->value;
- $state = 2;
+ if (!$expr->isConstraint) {
+ $state = 2;
+ }
}
} elseif ($state === 2) {
$expr->type = DataTypeFragment::parse($parser, $list);
$state = 3;
} elseif ($state === 3) {
$expr->options = OptionsFragment::parse($parser, $list, static::$FIELD_OPTIONS);
- $state = 6;
+ $state = 4;
} elseif ($state === 4) {
- if (($token->type !== Token::TYPE_KEYWORD) || (!($token->flags & Token::FLAG_KEYWORD_KEY))) {
- $expr->name = $token->value;
+ if (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'REFERENCES')) {
+ ++$list->idx; // Skipping keyword 'REFERENCES'.
+ $expr->references = ReferencesKeyword::parse($parser, $list);
} else {
- $expr->type = $token->value;
- $state = 5;
- }
- } elseif ($state === 5) {
- if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
- $expr->indexes = ArrayFragment::parse($parser, $list);
- $state = 6;
- } else {
- $expr->name = $token->value;
+ --$list->idx;
}
- } elseif ($state === 6) {
- if (!empty($expr->type)) {
+ $state = 5;
+ } else if ($state === 5) {
+ if ((!empty($expr->type)) || (!empty($expr->key))) {
$ret[] = $expr;
}
$expr = new FieldDefFragment();
@@ -183,7 +185,7 @@ class FieldDefFragment extends Fragment
}
// Last iteration was not saved.
- if (!empty($expr->type)) {
+ if ((!empty($expr->type)) || (!empty($expr->key))) {
$ret[] = $expr;
}
diff --git a/src/Fragments/KeyFragment.php b/src/Fragments/KeyFragment.php
new file mode 100644
index 0000000..9685f9e
--- /dev/null
+++ b/src/Fragments/KeyFragment.php
@@ -0,0 +1,132 @@
+<?php
+
+namespace SqlParser\Fragments;
+
+use SqlParser\Context;
+use SqlParser\Fragment;
+use SqlParser\Parser;
+use SqlParser\Token;
+use SqlParser\TokensList;
+
+/**
+ * Parses the definition of a key.
+ *
+ * Used for parsing `CREATE TABLE` statement.
+ *
+ * @category Fragments
+ * @package SqlParser
+ * @subpackage Fragments
+ * @author Dan Ungureanu <udan1107@gmail.com>
+ * @license http://opensource.org/licenses/GPL-2.0 GNU Public License
+ */
+class KeyFragment extends Fragment
+{
+
+ /**
+ * All key options.
+ *
+ * @var array
+ */
+ public static $KEY_OPTIONS = array(
+ 'KEY_BLOCK_SIZE' => array(1, 'var'),
+ 'USING' => array(2, 'var'),
+ 'WITH PARSER' => array(3, 'var'),
+ );
+
+ /**
+ * The name of this key.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * Columns.
+ *
+ * @var array
+ */
+ public $columns;
+
+ /**
+ * The type of this key.
+ *
+ * @var string
+ */
+ public $type;
+
+ /**
+ * @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 KeyFragment[]
+ */
+ public static function parse(Parser $parser, TokensList $list, array $options = array())
+ {
+ $ret = new KeyFragment();
+
+ /**
+ * The state of the parser.
+ *
+ * Below are the states of the parser.
+ *
+ * 0 -----------------------[ ( ]------------------------> 1
+ *
+ * 1 --------------------[ CONSTRAINT ]------------------> 1
+ * 1 -----------------------[ key ]----------------------> 2
+ * 1 -------------[ constraint / column name ]-----------> 2
+ *
+ * 2 --------------------[ data type ]-------------------> 3
+ *
+ * 3 ---------------------[ options ]--------------------> 4
+ *
+ * 4 --------------------[ REFERENCES ]------------------> 4
+ *
+ * 5 ------------------------[ , ]-----------------------> 1
+ * 5 ------------------------[ ) ]-----------------------> -1
+ *
+ * @var int
+ */
+ $state = 0;
+
+ 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;
+ }
+
+ if ($state === 0) {
+ $ret->type = $token->value;
+ $state = 1;
+ } elseif ($state === 1) {
+ if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
+ $ret->columns = ArrayFragment::parse($parser, $list)->array;
+ $state = 2;
+ } else {
+ $ret->name = $token->value;
+ }
+ } elseif ($state === 2) {
+ $ret->options = OptionsFragment::parse($parser, $list, static::$KEY_OPTIONS);
+ ++$list->idx;
+ break;
+ }
+
+ }
+
+ --$list->idx;
+ return $ret;
+
+ }
+}
diff --git a/src/Fragments/ReferencesKeyword.php b/src/Fragments/ReferencesKeyword.php
new file mode 100644
index 0000000..fbd69ba
--- /dev/null
+++ b/src/Fragments/ReferencesKeyword.php
@@ -0,0 +1,115 @@
+<?php
+
+namespace SqlParser\Fragments;
+
+use SqlParser\Fragment;
+use SqlParser\Parser;
+use SqlParser\Token;
+use SqlParser\TokensList;
+
+/**
+ * `REFERENCES` 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 ReferencesKeyword extends Fragment
+{
+
+ /**
+ * All references options.
+ *
+ * @var array
+ */
+ public static $REFERENCES_OPTIONS = array(
+ 'MATCH' => array(1, 'var'),
+ 'ON DELETE' => array(2, 'var'),
+ 'ON UPDATE' => array(3, 'var'),
+ );
+
+ /**
+ * The referenced table.
+ *
+ * @var string
+ */
+ public $table;
+
+ /**
+ * The referenced columns.
+ *
+ * @var array
+ */
+ public $columns;
+
+ /**
+ * The options of the referencing.
+ *
+ * @var OptionsFragment
+ */
+ public $options;
+
+ /**
+ * @param Parser $parser The parser that serves as context.
+ * @param TokensList $list The list of tokens that are being parsed.
+ * @param array $options Parameters for parsing.
+ *
+ * @return ReferencesKeyword
+ */
+ public static function parse(Parser $parser, TokensList $list, array $options = array())
+ {
+ $ret = new ReferencesKeyword();
+
+ /**
+ * The state of the parser.
+ *
+ * Below are the states of the parser.
+ *
+ * 0 ----------------------[ table ]---------------------> 1
+ *
+ * 1 ---------------------[ columns ]--------------------> 2
+ *
+ * 2 ---------------------[ options ]--------------------> -1
+ *
+ * @var int
+ */
+ $state = 0;
+
+ 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;
+ }
+
+ if ($state === 0) {
+ $ret->table = $token->value;
+ $state = 1;
+ } else if ($state === 1) {
+ $ret->columns = ArrayFragment::parse($parser, $list)->array;
+ $state = 2;
+ } else if ($state === 2) {
+ $ret->options = OptionsFragment::parse($parser, $list, static::$REFERENCES_OPTIONS);
+ ++$list->idx;
+ break;
+ }
+
+ }
+
+ --$list->idx;
+ return $ret;
+ }
+}
diff --git a/src/Utils/Table.php b/src/Utils/Table.php
index 7560f9d..1e88297 100644
--- a/src/Utils/Table.php
+++ b/src/Utils/Table.php
@@ -20,6 +20,49 @@ use SqlParser\Statements\CreateStatement;
class Table
{
+ public static function getForeignKeys(CreateStatement $tree)
+ {
+ if (($tree->fields === null) || (!$tree->options->has('TABLE'))) {
+ return array();
+ }
+
+ $ret = array();
+
+ foreach ($tree->fields as $field) {
+
+ if ((empty($field->key)) || ($field->key->type !== 'FOREIGN KEY')) {
+ continue;
+ }
+
+ $tmp = array(
+ 'constraint' => $field->name,
+ 'index_list' => $field->key->columns,
+ );
+
+ if (!empty($field->references)) {
+ $tmp['ref_table_name'] = $field->references->table;
+ $tmp['ref_index_list'] = $field->references->columns;
+
+ if (($opt = $field->references->options->has('ON UPDATE'))) {
+ $tmp['on_update'] = str_replace(' ', '_', $opt);
+ }
+
+ if (($opt = $field->references->options->has('ON DELETE'))) {
+ $tmp['on_delete'] = str_replace(' ', '_', $opt);
+ }
+
+ if (($opt = $field->references->options->has('MATCH'))) {
+ $tmp['match'] = str_replace(' ', '_', $opt);
+ }
+ }
+
+ $ret[] = $tmp;
+
+ }
+
+ return $ret;
+ }
+
public static function getFields(CreateStatement $tree)
{
if (($tree->fields === null) || (!$tree->options->has('TABLE'))) {
@@ -31,7 +74,7 @@ class Table
foreach ($tree->fields as $field) {
// Skipping keys.
- if (is_string($field->type)) {
+ if (empty($field->type)) {
continue;
}
diff --git a/tests/data/parseCreateTable.out b/tests/data/parseCreateTable.out
index 500bfb3..a607f9e 100644
--- a/tests/data/parseCreateTable.out
+++ b/tests/data/parseCreateTable.out
@@ -4,4 +4,4 @@ a:2:{s:6:"parser";O:16:"SqlParser\Parser":4:{s:4:"list";O:20:"SqlParser\TokensLi
";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:103;}i:29;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"`password`";s:5:"value";s:8:"password";s:4:"type";i:8;s:5:"flags";i:2;s:8:"position";i:108;}i:30;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:118;}i:31;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:119;}i:32;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:126;}i:33;O:15:"SqlParser\Token":5:{s:5:"token";s:3:"256";s:5:"value";i:256;s:4:"type";i:6;s:5:"flags";i:0;s:8:"position";i:127;}i:34;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:130;}i:35;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:131;}i:36;O:15:"SqlParser\Token":5:{s:5:"token";s:7:"DEFAULT";s:5:"value";s:7:"DEFAULT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:132;}i:37;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:139;}i:38;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"'123456'";s:5:"value";s:6:"123456";s:4:"type";i:7;s:5:"flags";i:1;s:8:"position";i:140;}i:39;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:148;}i:40;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:149;}i:41;O:15:"SqlParser\Token":5:{s:5:"token";s:10:"CONSTRAINT";s:5:"value";s:10:"CONSTRAINT";s:4:"type";i:1;s:5:"flags";i:3;s:8:"position";i:154;}i:42;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:164;}i:43;O:15:"SqlParser\Token":5:{s:5:"token";s:5:"pk_id";s:5:"value";s:5:"pk_id";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:165;}i:44;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:170;}i:45;O:15:"SqlParser\Token":5:{s:5:"token";s:11:"PRIMARY KEY";s:5:"value";s:11:"PRIMARY KEY";s:4:"type";i:1;s:5:"flags";i:21;s:8:"position";i:171;}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:182;}i:47;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:183;}i:48;O:15:"SqlParser\Token":5:{s:5:"token";s:4:"`id`";s:5:"value";s:2:"id";s:4:"type";i:8;s:5:"flags";i:2;s:8:"position";i:184;}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:188;}i:50;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:189;}i:51;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:190;}i:52;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"UNIQUE";s:5:"value";s:6:"UNIQUE";s:4:"type";i:1;s:5:"flags";i:19;s:8:"position";i:195;}i:53;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:201;}i:54;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:202;}i:55;O:15:"SqlParser\Token":5:{s:5:"token";s:8:"username";s:5:"value";s:8:"username";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:203;}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:211;}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:212;}i:58;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:213;}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:214;}i:60;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"ENGINE";s:5:"value";s:6:"ENGINE";s:4:"type";i:1;s:5:"flags";i:1;s:8:"position";i:215;}i:61;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"=";s:5:"value";s:1:"=";s:4:"type";i:2;s:5:"flags";i:2;s:8:"position";i:221;}i:62;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"InnoDB";s:5:"value";s:6:"InnoDB";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:222;}i:63;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:228;}i:64;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:65;s:3:"idx";i:65;}s:6:"strict";b:0;s:6:"errors";a:0:{}s:10:"statements";a:1:{i:0;O:36:"SqlParser\Statements\CreateStatement":8:{s:4:"name";O:37:"SqlParser\Fragments\CreateDefFragment":1:{s:4:"name";s:5:"users";}s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:2:{i:1;s:5:"TABLE";i:3;s:13:"IF NOT EXISTS";}}s:10:"parameters";N;s:12:"tableOptions";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:1:{i:1;a:2:{s:4:"name";s:6:"ENGINE";s:5:"value";s:6:"InnoDB";}}}s:6:"fields";a:5:{i:0;O:36:"SqlParser\Fragments\FieldDefFragment":4:{s:4:"name";s:2:"id";s:4:"type";O:36:"SqlParser\Fragments\DataTypeFragment":3:{s:4:"name";s:3:"INT";s:4:"size";a:0:{}s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:0:{}}}s:7:"indexes";N;s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:2:{i:1;s:8:"NOT NULL";i:3;s:14:"AUTO_INCREMENT";}}}i:1;O:36:"SqlParser\Fragments\FieldDefFragment":4:{s:4:"name";s:8:"username";s:4:"type";O:36:"SqlParser\Fragments\DataTypeFragment":3:{s:4:"name";s:7:"VARCHAR";s:4:"size";a:1:{i:0;i:64;}s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:0:{}}}s:7:"indexes";N;s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:1:{i:1;s:4:"NULL";}}}i:2;O:36:"SqlParser\Fragments\FieldDefFragment":4:{s:4:"name";s:8:"password";s:4:"type";O:36:"SqlParser\Fragments\DataTypeFragment":3:{s:4:"name";s:7:"VARCHAR";s:4:"size";a:1:{i:0;i:256;}s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:0:{}}}s:7:"indexes";N;s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:1:{i:2;a:2:{s:4:"name";s:7:"DEFAULT";s:5:"value";s:6:"123456";}}}}i:3;O:36:"SqlParser\Fragments\FieldDefFragment":4:{s:4:"name";s:5:"pk_id";s:4:"type";s:11:"PRIMARY KEY";s:7:"indexes";O:33:"SqlParser\Fragments\ArrayFragment":2:{s:5:"array";a:1:{i:0;s:2:"id";}s:3:"raw";a:1:{i:0;s:4:"`id`";}}s:7:"options";N;}i:4;O:36:"SqlParser\Fragments\FieldDefFragment":4:{s:4:"name";N;s:4:"type";s:6:"UNIQUE";s:7:"indexes";O:33:"SqlParser\Fragments\ArrayFragment":2:{s:5:"array";a:1:{i:0;s:8:"username";}s:3:"raw";a:1:{i:0;s:8:"username";}}s:7:"options";N;}}s:4:"body";N;s:5:"first";N;s:4:"last";i:62;}}}s:6:"errors";a:0:{}} \ No newline at end of file
+";s:5:"value";s:1:" ";s:4:"type";i:3;s:5:"flags";i:0;s:8:"position";i:212;}i:58;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:213;}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:214;}i:60;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"ENGINE";s:5:"value";s:6:"ENGINE";s:4:"type";i:1;s:5:"flags";i:1;s:8:"position";i:215;}i:61;O:15:"SqlParser\Token":5:{s:5:"token";s:1:"=";s:5:"value";s:1:"=";s:4:"type";i:2;s:5:"flags";i:2;s:8:"position";i:221;}i:62;O:15:"SqlParser\Token":5:{s:5:"token";s:6:"InnoDB";s:5:"value";s:6:"InnoDB";s:4:"type";i:0;s:5:"flags";i:0;s:8:"position";i:222;}i:63;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:228;}i:64;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:65;s:3:"idx";i:65;}s:6:"strict";b:0;s:6:"errors";a:0:{}s:10:"statements";a:1:{i:0;O:36:"SqlParser\Statements\CreateStatement":8:{s:4:"name";O:37:"SqlParser\Fragments\CreateDefFragment":1:{s:4:"name";s:5:"users";}s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:2:{i:1;s:5:"TABLE";i:3;s:13:"IF NOT EXISTS";}}s:10:"parameters";N;s:12:"tableOptions";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:1:{i:1;a:2:{s:4:"name";s:6:"ENGINE";s:5:"value";s:6:"InnoDB";}}}s:6:"fields";a:5:{i:0;O:36:"SqlParser\Fragments\FieldDefFragment":6:{s:4:"name";s:2:"id";s:12:"isConstraint";N;s:4:"type";O:36:"SqlParser\Fragments\DataTypeFragment":3:{s:4:"name";s:3:"INT";s:4:"size";a:0:{}s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:0:{}}}s:3:"key";N;s:10:"references";N;s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:2:{i:1;s:8:"NOT NULL";i:3;s:14:"AUTO_INCREMENT";}}}i:1;O:36:"SqlParser\Fragments\FieldDefFragment":6:{s:4:"name";s:8:"username";s:12:"isConstraint";N;s:4:"type";O:36:"SqlParser\Fragments\DataTypeFragment":3:{s:4:"name";s:7:"VARCHAR";s:4:"size";a:1:{i:0;i:64;}s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:0:{}}}s:3:"key";N;s:10:"references";N;s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:1:{i:1;s:4:"NULL";}}}i:2;O:36:"SqlParser\Fragments\FieldDefFragment":6:{s:4:"name";s:8:"password";s:12:"isConstraint";N;s:4:"type";O:36:"SqlParser\Fragments\DataTypeFragment":3:{s:4:"name";s:7:"VARCHAR";s:4:"size";a:1:{i:0;i:256;}s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:0:{}}}s:3:"key";N;s:10:"references";N;s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:1:{i:2;a:2:{s:4:"name";s:7:"DEFAULT";s:5:"value";s:6:"123456";}}}}i:3;O:36:"SqlParser\Fragments\FieldDefFragment":6:{s:4:"name";s:5:"pk_id";s:12:"isConstraint";b:1;s:4:"type";N;s:3:"key";O:31:"SqlParser\Fragments\KeyFragment":4:{s:4:"name";N;s:7:"columns";a:1:{i:0;s:2:"id";}s:4:"type";s:11:"PRIMARY KEY";s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:0:{}}}s:10:"references";N;s:7:"options";N;}i:4;O:36:"SqlParser\Fragments\FieldDefFragment":6:{s:4:"name";N;s:12:"isConstraint";N;s:4:"type";N;s:3:"key";O:31:"SqlParser\Fragments\KeyFragment":4:{s:4:"name";N;s:7:"columns";a:1:{i:0;s:8:"username";}s:4:"type";s:6:"UNIQUE";s:7:"options";O:35:"SqlParser\Fragments\OptionsFragment":1:{s:7:"options";a:0:{}}}s:10:"references";N;s:7:"options";N;}}s:4:"body";N;s:5:"first";N;s:4:"last";i:62;}}}s:6:"errors";a:0:{}} \ No newline at end of file