summaryrefslogtreecommitdiffstats
path: root/src/Components/CreateDefinition.php
diff options
context:
space:
mode:
authorDan Ungureanu <udan1107@gmail.com>2015-08-08 20:38:04 +0300
committerDan Ungureanu <udan1107@gmail.com>2015-08-08 20:38:04 +0300
commitab778e942d8f3b3950cbd1eaf7fa10ea21aeea9f (patch)
tree6601dba770d512b51f503aa05ff4d88a045de512 /src/Components/CreateDefinition.php
parent1abbd1dc1ae48330bef8ebc73bef53572f092c2b (diff)
downloadsql-parser-ab778e942d8f3b3950cbd1eaf7fa10ea21aeea9f.zip
sql-parser-ab778e942d8f3b3950cbd1eaf7fa10ea21aeea9f.tar.gz
sql-parser-ab778e942d8f3b3950cbd1eaf7fa10ea21aeea9f.tar.bz2
Refactored field to something more appropriate depending on the context in which it is used.
Diffstat (limited to 'src/Components/CreateDefinition.php')
-rw-r--r--src/Components/CreateDefinition.php312
1 files changed, 312 insertions, 0 deletions
diff --git a/src/Components/CreateDefinition.php b/src/Components/CreateDefinition.php
new file mode 100644
index 0000000..4dfbb7a
--- /dev/null
+++ b/src/Components/CreateDefinition.php
@@ -0,0 +1,312 @@
+<?php
+
+/**
+ * Parses the create definition of a column or a key.
+ *
+ * Used for parsing `CREATE TABLE` statement.
+ *
+ * @package SqlParser
+ * @subpackage Components
+ */
+namespace SqlParser\Components;
+
+use SqlParser\Context;
+use SqlParser\Component;
+use SqlParser\Parser;
+use SqlParser\Token;
+use SqlParser\TokensList;
+
+/**
+ * Parses the create definition of a column or a key.
+ *
+ * Used for parsing `CREATE TABLE` statement.
+ *
+ * @category Components
+ * @package SqlParser
+ * @subpackage Components
+ * @author Dan Ungureanu <udan1107@gmail.com>
+ * @license http://opensource.org/licenses/GPL-2.0 GNU Public License
+ */
+class CreateDefinition extends Component
+{
+
+ /**
+ * All field options.
+ *
+ * @var array
+ */
+ public static $FIELD_OPTIONS = array(
+
+ // Tells the `OptionsArray` to not sort the options.
+ // See the note below.
+ '_UNSORTED' => true,
+
+ 'NOT NULL' => 1,
+ 'NULL' => 1,
+ 'DEFAULT' => array(2, 'var'),
+ 'AUTO_INCREMENT' => 3,
+ 'PRIMARY' => 4,
+ 'PRIMARY KEY' => 4,
+ 'UNIQUE' => 4,
+ 'UNIQUE KEY' => 4,
+ 'COMMENT' => array(5, 'var'),
+ 'COLUMN_FORMAT' => array(6, 'var'),
+ 'ON UPDATE' => array(7, 'var'),
+
+ // Generated columns options.
+ 'GENERATED ALWAYS' => 8,
+ 'AS' => array(9, 'expr', array('bracketsDelimited' => true)),
+ 'VIRTUAL' => 10,
+ 'PERSISTENT' => 11,
+ 'STORED' => 11,
+ // Common entries.
+ //
+ // NOTE: Some of the common options are not in the same order which
+ // causes troubles when checking if the options are in the right order.
+ // I should find a way to define multiple sets of options and make the
+ // parser select the right set.
+ //
+ // 'UNIQUE' => 4,
+ // 'UNIQUE KEY' => 4,
+ // 'COMMENT' => array(5, 'var'),
+ // 'NOT NULL' => 1,
+ // 'NULL' => 1,
+ // 'PRIMARY' => 4,
+ // 'PRIMARY KEY' => 4,
+ );
+
+ /**
+ * The name of the new column.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * Whether this field is a constraint or not.
+ *
+ * @var bool
+ */
+ public $isConstraint;
+
+ /**
+ * The data type of thew new column.
+ *
+ * @var DataType
+ */
+ public $type;
+
+ /**
+ * The key.
+ *
+ * @var Key
+ */
+ public $key;
+
+ /**
+ * The table that is referenced.
+ *
+ * @var Reference
+ */
+ public $references;
+
+ /**
+ * The options of this field.
+ *
+ * @var OptionsArray
+ */
+ public $options;
+
+ /**
+ * Constructor.
+ *
+ * @param string $name The name of the field.
+ * @param OptionsArray $options The options of this field.
+ * @param DataType|Key $type The data type of this field or the key.
+ * @param bool $isConstraint Whether this field is a constraint or not.
+ * @param Reference $references References.
+ */
+ public function __construct($name = null, $options = null, $type = null,
+ $isConstraint = false, $references = null
+ ) {
+ $this->name = $name;
+ $this->options = $options;
+ if ($type instanceof DataType) {
+ $this->type = $type;
+ } elseif ($type instanceof Key) {
+ $this->key = $type;
+ $this->isConstraint = $isConstraint;
+ $this->references = $references;
+ }
+ }
+
+ /**
+ * @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 CreateDefinition[]
+ */
+ public static function parse(Parser $parser, TokensList $list, array $options = array())
+ {
+ $ret = array();
+
+ $expr = new CreateDefinition();
+
+ /**
+ * 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 ------------------------[ ) ]-----------------------> 6 (-1)
+ *
+ * @var int
+ */
+ $state = 0;
+
+ for (; $list->idx < $list->count; ++$list->idx) {
+ /**
+ * Token parsed at this moment.
+ * @var Token $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) {
+ if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '(')) {
+ $state = 1;
+ } else {
+ $parser->error(
+ __('An opening bracket was expected.'),
+ $token
+ );
+ break;
+ }
+ } elseif ($state === 1) {
+ if (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'CONSTRAINT')) {
+ $expr->isConstraint = true;
+ } elseif (($token->type === Token::TYPE_KEYWORD) && ($token->flags & Token::FLAG_KEYWORD_KEY)) {
+ $expr->key = Key::parse($parser, $list);
+ $state = 4;
+ } else {
+ $expr->name = $token->value;
+ if (!$expr->isConstraint) {
+ $state = 2;
+ }
+ }
+ } elseif ($state === 2) {
+ $expr->type = DataType::parse($parser, $list);
+ $state = 3;
+ } elseif ($state === 3) {
+ $expr->options = OptionsArray::parse($parser, $list, static::$FIELD_OPTIONS);
+ $state = 4;
+ } elseif ($state === 4) {
+ if (($token->type === Token::TYPE_KEYWORD) && ($token->value === 'REFERENCES')) {
+ ++$list->idx; // Skipping keyword 'REFERENCES'.
+ $expr->references = Reference::parse($parser, $list);
+ } else {
+ --$list->idx;
+ }
+ $state = 5;
+ } elseif ($state === 5) {
+ if ((!empty($expr->type)) || (!empty($expr->key))) {
+ $ret[] = $expr;
+ }
+ $expr = new CreateDefinition();
+ if ($token->value === ',') {
+ $state = 1;
+ } elseif ($token->value === ')') {
+ $state = 6;
+ ++$list->idx;
+ break;
+ } else {
+ $parser->error(
+ __('A comma or a closing bracket was expected.'),
+ $token
+ );
+ $state = 0;
+ break;
+ }
+ }
+ }
+
+ // Last iteration was not saved.
+ if ((!empty($expr->type)) || (!empty($expr->key))) {
+ $ret[] = $expr;
+ }
+
+ if (($state !== 0) && ($state !== 6)) {
+ $parser->error(
+ __('A closing bracket was expected.'),
+ $list->tokens[$list->idx - 1]
+ );
+ }
+
+ --$list->idx;
+ return $ret;
+ }
+
+ /**
+ * @param CreateDefinition|CreateDefinition[] $component The component to be built.
+ *
+ * @return string
+ */
+ public static function build($component)
+ {
+ if (is_array($component)) {
+ $ret = array();
+ foreach ($component as $c) {
+ $ret[] = static::build($c);
+ }
+ return "(\n" . implode(",\n", $ret) . "\n)";
+ } else {
+ $tmp = '';
+
+ if ($component->isConstraint) {
+ $tmp .= 'CONSTRAINT ';
+ }
+
+ if (!empty($component->name)) {
+ $tmp .= Context::escape($component->name) . ' ';
+ }
+
+ if (!empty($component->type)) {
+ $tmp .= DataType::build($component->type) . ' ';
+ }
+
+ if (!empty($component->key)) {
+ $tmp .= Key::build($component->key) . ' ';
+ }
+
+ if (!empty($component->references)) {
+ $tmp .= 'REFERENCES ' . Reference::build($component->references) . ' ';
+ }
+
+ $tmp .= OptionsArray::build($component->options);
+
+ return trim($tmp);
+ }
+ }
+}