Inheritance: extends SqlParser\Component
 /**
  * Function called after the token was processed.
  *
  * Parses the additional options from the end.
  *
  * @param Parser     $parser The instance that requests parsing.
  * @param TokensList $list   The list of tokens to be parsed.
  * @param Token      $token  The token that is being parsed.
  *
  * @return void
  */
 public function after(Parser $parser, TokensList $list, Token $token)
 {
     // [some options] is going to be parsed first.
     //
     // There is a parser specified in `Parser::$KEYWORD_PARSERS`
     // which parses the name of the tables.
     //
     // Finally, we parse here [some more options] and that's all.
     ++$list->idx;
     $this->options->merge(OptionsArray::parse($parser, $list, static::$OPTIONS));
 }
 /**
  * @return string
  */
 public function build()
 {
     $ret = OptionsArray::build($this->options);
     if ($this->type === TransactionStatement::TYPE_BEGIN) {
         foreach ($this->statements as $statement) {
             $ret .= ';' . $statement->build();
         }
         $ret .= ';' . $this->end->build();
     }
     return $ret;
 }
Example #3
0
 /**
  * @param FieldDefinition|FieldDefinition[] $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);
     }
 }
Example #4
0
 /**
  * @param Key $component The component to be built.
  *
  * @return string
  */
 public static function build($component)
 {
     $ret = $component->type . ' ';
     if (!empty($component->name)) {
         $ret .= Context::escape($component->name) . ' ';
     }
     $ret .= '(' . implode(',', Context::escape($component->columns)) . ')';
     $ret .= OptionsArray::build($component->options);
     return trim($ret);
 }
Example #5
0
 /**
  * @return string
  */
 public function build()
 {
     return 'SET ' . OptionsArray::build($this->options) . ' ' . SetOperation::build($this->set);
 }
 /**
  * @param Parser     $parser The instance that requests parsing.
  * @param TokensList $list   The list of tokens to be parsed.
  *
  * @return void
  */
 public function parse(Parser $parser, TokensList $list)
 {
     ++$list->idx;
     // Skipping `CREATE`.
     // Parsing options.
     $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
     ++$list->idx;
     // Skipping last option.
     // Parsing the field name.
     $this->name = Expression::parse($parser, $list, array('noAlias' => true, 'noBrackets' => true, 'skipColumn' => true));
     if (!isset($this->name) || $this->name === '') {
         $parser->error(__('The name of the entity was expected.'), $list->tokens[$list->idx]);
     } else {
         ++$list->idx;
         // Skipping field.
     }
     if ($this->options->has('DATABASE')) {
         $this->entityOptions = OptionsArray::parse($parser, $list, static::$DB_OPTIONS);
     } elseif ($this->options->has('TABLE')) {
         $this->fields = CreateDefinition::parse($parser, $list);
         if (empty($this->fields)) {
             $parser->error(__('At least one column definition was expected.'), $list->tokens[$list->idx]);
         }
         ++$list->idx;
         $this->entityOptions = OptionsArray::parse($parser, $list, static::$TABLE_OPTIONS);
         /**
          * The field that is being filled (`partitionBy` or
          * `subpartitionBy`).
          *
          * @var string $field
          */
         $field = null;
         /**
          * The number of brackets. `false` means no bracket was found
          * previously. At least one bracket is required to validate the
          * expression.
          *
          * @var int|bool $brackets
          */
         $brackets = false;
         /*
          * Handles partitions.
          */
         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 comments.
             if ($token->type === Token::TYPE_COMMENT) {
                 continue;
             }
             if ($token->type === Token::TYPE_KEYWORD && $token->value === 'PARTITION BY') {
                 $field = 'partitionBy';
                 $brackets = false;
             } elseif ($token->type === Token::TYPE_KEYWORD && $token->value === 'SUBPARTITION BY') {
                 $field = 'subpartitionBy';
                 $brackets = false;
             } elseif ($token->type === Token::TYPE_KEYWORD && $token->value === 'PARTITIONS') {
                 $token = $list->getNextOfType(Token::TYPE_NUMBER);
                 --$list->idx;
                 // `getNextOfType` also advances one position.
                 $this->partitionsNum = $token->value;
             } elseif ($token->type === Token::TYPE_KEYWORD && $token->value === 'SUBPARTITIONS') {
                 $token = $list->getNextOfType(Token::TYPE_NUMBER);
                 --$list->idx;
                 // `getNextOfType` also advances one position.
                 $this->subpartitionsNum = $token->value;
             } elseif (!empty($field)) {
                 /*
                  * Handling the content of `PARTITION BY` and `SUBPARTITION BY`.
                  */
                 // Counting brackets.
                 if ($token->type === Token::TYPE_OPERATOR && $token->value === '(') {
                     // This is used instead of `++$brackets` because,
                     // initially, `$brackets` is `false` cannot be
                     // incremented.
                     $brackets = $brackets + 1;
                 } elseif ($token->type === Token::TYPE_OPERATOR && $token->value === ')') {
                     --$brackets;
                 }
                 // Building the expression used for partitioning.
                 $this->{$field} .= $token->type === Token::TYPE_WHITESPACE ? ' ' : $token->token;
                 // Last bracket was read, the expression ended.
                 // Comparing with `0` and not `false`, because `false` means
                 // that no bracket was found and at least one must is
                 // required.
                 if ($brackets === 0) {
                     $this->{$field} = trim($this->{$field});
                     $field = null;
                 }
             } elseif ($token->type === Token::TYPE_OPERATOR && $token->value === '(') {
                 if (!empty($this->partitionBy)) {
                     $this->partitions = ArrayObj::parse($parser, $list, array('type' => 'SqlParser\\Components\\PartitionDefinition'));
                 }
                 break;
             }
         }
     } elseif ($this->options->has('PROCEDURE') || $this->options->has('FUNCTION')) {
         $this->parameters = ParameterDefinition::parse($parser, $list);
         if ($this->options->has('FUNCTION')) {
             $token = $list->getNextOfType(Token::TYPE_KEYWORD);
             if ($token->value !== 'RETURNS') {
                 $parser->error(__('A "RETURNS" keyword was expected.'), $token);
             } else {
                 ++$list->idx;
                 $this->return = DataType::parse($parser, $list);
             }
         }
         ++$list->idx;
         $this->entityOptions = OptionsArray::parse($parser, $list, static::$FUNC_OPTIONS);
         ++$list->idx;
         for (; $list->idx < $list->count; ++$list->idx) {
             $token = $list->tokens[$list->idx];
             $this->body[] = $token;
         }
     } elseif ($this->options->has('VIEW')) {
         $token = $list->getNext();
         // Skipping whitespaces and comments.
         // Parsing columns list.
         if ($token->type === Token::TYPE_OPERATOR && $token->value === '(') {
             --$list->idx;
             // getNext() also goes forward one field.
             $this->fields = ArrayObj::parse($parser, $list);
             ++$list->idx;
             // Skipping last token from the array.
             $list->getNext();
         }
         // Parsing the `AS` keyword.
         for (; $list->idx < $list->count; ++$list->idx) {
             $token = $list->tokens[$list->idx];
             if ($token->type === Token::TYPE_DELIMITER) {
                 break;
             }
             $this->body[] = $token;
         }
     } elseif ($this->options->has('TRIGGER')) {
         // Parsing the time and the event.
         $this->entityOptions = OptionsArray::parse($parser, $list, static::$TRIGGER_OPTIONS);
         ++$list->idx;
         $list->getNextOfTypeAndValue(Token::TYPE_KEYWORD, 'ON');
         ++$list->idx;
         // Skipping `ON`.
         // Parsing the name of the table.
         $this->table = Expression::parse($parser, $list, array('noAlias' => true, 'noBrackets' => true, 'skipColumn' => true));
         ++$list->idx;
         $list->getNextOfTypeAndValue(Token::TYPE_KEYWORD, 'FOR EACH ROW');
         ++$list->idx;
         // Skipping `FOR EACH ROW`.
         for (; $list->idx < $list->count; ++$list->idx) {
             $token = $list->tokens[$list->idx];
             $this->body[] = $token;
         }
     } else {
         for (; $list->idx < $list->count; ++$list->idx) {
             $token = $list->tokens[$list->idx];
             if ($token->type === Token::TYPE_DELIMITER) {
                 break;
             }
             $this->body[] = $token;
         }
     }
 }
Example #7
0
 /**
  * Parses the statements defined by the tokens list.
  *
  * @param Parser     $parser The instance that requests parsing.
  * @param TokensList $list   The list of tokens to be parsed.
  *
  * @return void
  */
 public function parse(Parser $parser, TokensList $list)
 {
     /**
      * Whether the beginning of this statement was previously parsed.
      *
      * This is used to delimit statements that don't use the usual
      * delimiters.
      *
      * @var bool
      */
     $parsedBeginning = false;
     // This may be corrected by the parser.
     $this->first = $list->idx;
     /**
      * Whether options were parsed or not.
      * For statements that do not have any options this is set to `true` by
      * default.
      * @var bool $parsedOptions
      */
     $parsedOptions = empty(static::$OPTIONS);
     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;
         }
         // Only keywords are relevant here. Other parts of the query are
         // processed in the functions below.
         if ($token->type !== Token::TYPE_KEYWORD) {
             if ($token->type !== TOKEN::TYPE_COMMENT && $token->type !== Token::TYPE_WHITESPACE) {
                 $parser->error(__('Unexpected token.'), $token);
             }
             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 $class
          */
         $class = null;
         /**
          * The name of the field where the result of the parsing is stored.
          * @var string $field
          */
         $field = null;
         /**
          * Parser's options.
          * @var array $options
          */
         $options = array();
         if (!empty(Parser::$KEYWORD_PARSERS[$token->value])) {
             $class = Parser::$KEYWORD_PARSERS[$token->value]['class'];
             $field = Parser::$KEYWORD_PARSERS[$token->value]['field'];
             if (!empty(Parser::$KEYWORD_PARSERS[$token->value]['options'])) {
                 $options = Parser::$KEYWORD_PARSERS[$token->value]['options'];
             }
         }
         if (!empty(Parser::$STATEMENT_PARSERS[$token->value])) {
             if ($parsedBeginning) {
                 // New statement has started. We let the parser construct a
                 // new statement and parse that one
                 $parser->error(__('A new statement was found, but no delimiter between them.'), $token);
                 break;
             }
             $parsedBeginning = true;
             if (!$parsedOptions) {
                 if (empty(static::$OPTIONS[$token->value])) {
                     // Skipping keyword because if it is not a option.
                     ++$list->idx;
                 }
                 $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
                 $parsedOptions = true;
             }
         } elseif ($class === null) {
             // There is no parser for this keyword and isn't the beginning
             // of a statement (so no options) either.
             $parser->error(__('Unrecognized keyword.'), $token);
             continue;
         }
         $this->before($parser, $list, $token);
         // Parsing this keyword.
         if ($class !== null) {
             ++$list->idx;
             // Skipping keyword or last option.
             $this->{$field} = $class::parse($parser, $list, $options);
         }
         $this->after($parser, $list, $token);
     }
     // This may be corrected by the parser.
     $this->last = --$list->idx;
     // Go back to last used token.
 }
 public function testBuild()
 {
     $component = new OptionsArray(array('ALL', 'SQL_CALC_FOUND_ROWS', array('name' => 'MAX_STATEMENT_TIME', 'value' => '42', 'equals' => true)));
     $this->assertEquals(OptionsArray::build($component), 'ALL SQL_CALC_FOUND_ROWS MAX_STATEMENT_TIME=42');
 }
 /**
  * @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 Key[]
  */
 public static function parse(Parser $parser, TokensList $list, array $options = array())
 {
     $ret = new Key();
     /**
      * Last parsed column.
      *
      * @var array
      */
     $lastColumn = array();
     /**
      * The state of the parser.
      *
      * Below are the states of the parser.
      *
      *      0 ----------------------[ type ]-----------------------> 1
      *
      *      1 ----------------------[ name ]-----------------------> 1
      *      1 ---------------------[ columns ]---------------------> 2
      *
      *      2 ---------------------[ options ]---------------------> 3
      *
      * @var int $state
      */
     $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) {
             $ret->type = $token->value;
             $state = 1;
         } elseif ($state === 1) {
             if ($token->type === Token::TYPE_OPERATOR && $token->value === '(') {
                 $state = 2;
             } else {
                 $ret->name = $token->value;
             }
         } elseif ($state === 2) {
             if ($token->type === Token::TYPE_OPERATOR) {
                 if ($token->value === '(') {
                     $state = 3;
                 } elseif ($token->value === ',' || $token->value === ')') {
                     $state = $token->value === ',' ? 2 : 4;
                     if (!empty($lastColumn)) {
                         $ret->columns[] = $lastColumn;
                         $lastColumn = array();
                     }
                 }
             } else {
                 $lastColumn['name'] = $token->value;
             }
         } elseif ($state === 3) {
             if ($token->type === Token::TYPE_OPERATOR && $token->value === ')') {
                 $state = 2;
             } else {
                 $lastColumn['length'] = $token->value;
             }
         } elseif ($state === 4) {
             $ret->options = OptionsArray::parse($parser, $list, static::$KEY_OPTIONS);
             ++$list->idx;
             break;
         }
     }
     --$list->idx;
     return $ret;
 }
Example #10
0
 /**
  * @param Parser     $parser The instance that requests parsing.
  * @param TokensList $list   The list of tokens to be parsed.
  *
  * @return void
  */
 public function parse(Parser $parser, TokensList $list)
 {
     ++$list->idx;
     // Skipping `INSERT`.
     // parse any options if provided
     $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
     ++$list->idx;
     $token = $list->tokens[$list->idx];
     /**
      * The state of the parser.
      *
      * Below are the states of the parser.
      *
      *      0 ---------------------------------[ INTO ]----------------------------------> 1
      *
      *      1 -------------------------[ VALUES/VALUE/SET/SELECT ]-----------------------> 2
      *
      *      2 -------------------------[ ON DUPLICATE KEY UPDATE ]-----------------------> 3
      *
      * @var int $state
      */
     $state = 0;
     /**
      * For keeping track of semi-states on encountering
      * ON DUPLICATE KEY UPDATE ...
      *
      */
     $miniState = 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_KEYWORD && $token->value !== 'INTO') {
                 $parser->error(__('Unexpected keyword.'), $token);
                 break;
             } else {
                 ++$list->idx;
                 $this->into = IntoKeyword::parse($parser, $list);
             }
             $state = 1;
         } elseif ($state === 1) {
             if ($token->type === Token::TYPE_KEYWORD) {
                 if ($token->value === 'VALUE' || $token->value === 'VALUES') {
                     ++$list->idx;
                     // skip VALUES
                     $this->values = Array2d::parse($parser, $list);
                 } elseif ($token->value === 'SET') {
                     ++$list->idx;
                     // skip SET
                     $this->set = SetOperation::parse($parser, $list);
                 } elseif ($token->value === 'SELECT') {
                     $this->select = new SelectStatement($parser, $list);
                 } else {
                     $parser->error(__('Unexpected keyword.'), $token);
                     break;
                 }
                 $state = 2;
                 $miniState = 1;
             } else {
                 $parser->error(__('Unexpected token.'), $token);
                 break;
             }
         } elseif ($state == 2) {
             $lastCount = $miniState;
             if ($miniState === 1 && $token->value === 'ON') {
                 $miniState++;
             } elseif ($miniState === 2 && $token->value === 'DUPLICATE') {
                 $miniState++;
             } elseif ($miniState === 3 && $token->value === 'KEY') {
                 $miniState++;
             } elseif ($miniState === 4 && $token->value === 'UPDATE') {
                 $miniState++;
             }
             if ($lastCount === $miniState) {
                 $parser->error(__('Unexpected token.'), $token);
                 break;
             }
             if ($miniState === 5) {
                 ++$list->idx;
                 $this->onDuplicateSet = SetOperation::parse($parser, $list);
                 $state = 3;
             }
         }
     }
     --$list->idx;
 }
Example #11
0
 /**
  * @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 AlterOperation
  */
 public static function parse(Parser $parser, TokensList $list, array $options = array())
 {
     $ret = new AlterOperation();
     /**
      * Counts brackets.
      *
      * @var int $brackets
      */
     $brackets = 0;
     /**
      * The state of the parser.
      *
      * Below are the states of the parser.
      *
      *      0 ---------------------[ options ]---------------------> 1
      *
      *      1 ----------------------[ field ]----------------------> 2
      *
      *      2 -------------------------[ , ]-----------------------> 0
      *
      * @var int $state
      */
     $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 comments.
         if ($token->type === Token::TYPE_COMMENT) {
             continue;
         }
         // Skipping whitespaces.
         if ($token->type === Token::TYPE_WHITESPACE) {
             if ($state === 2) {
                 // When parsing the unknown part, the whitespaces are
                 // included to not break anything.
                 $ret->unknown[] = $token;
             }
             continue;
         }
         if ($state === 0) {
             $ret->options = OptionsArray::parse($parser, $list, $options);
             if ($ret->options->has('AS')) {
                 for (; $list->idx < $list->count; ++$list->idx) {
                     if ($list->tokens[$list->idx]->type === Token::TYPE_DELIMITER) {
                         break;
                     }
                     $ret->unknown[] = $list->tokens[$list->idx];
                 }
                 break;
             }
             $state = 1;
         } elseif ($state === 1) {
             $ret->field = Expression::parse($parser, $list, array('breakOnAlias' => true, 'parseField' => 'column'));
             if ($ret->field === null) {
                 // No field was read. We go back one token so the next
                 // iteration will parse the same token, but in state 2.
                 --$list->idx;
             }
             $state = 2;
         } elseif ($state === 2) {
             if ($token->type === Token::TYPE_OPERATOR) {
                 if ($token->value === '(') {
                     ++$brackets;
                 } elseif ($token->value === ')') {
                     --$brackets;
                 } elseif ($token->value === ',' && $brackets === 0) {
                     break;
                 }
             } elseif (!empty(Parser::$STATEMENT_PARSERS[$token->value])) {
                 // We have reached the end of ALTER operation and suddenly found
                 // a start to new statement, but have not find a delimiter between them
                 if (!($token->value == 'SET' && $list->tokens[$list->idx - 1]->value == 'CHARACTER')) {
                     $parser->error(__('A new statement was found, but no delimiter between it and the previous one.'), $token);
                     break;
                 }
             }
             $ret->unknown[] = $token;
         }
     }
     if ($ret->options->isEmpty()) {
         $parser->error(__('Unrecognized alter operation.'), $list->tokens[$list->idx]);
     }
     --$list->idx;
     return $ret;
 }
Example #12
0
 /**
  * @param DataType $component The component to be built.
  *
  * @return string
  */
 public static function build($component)
 {
     $tmp = '';
     if (!empty($component->parameters)) {
         $tmp = '(' . implode(',', $component->parameters) . ')';
     }
     return trim(strtolower($component->name) . $tmp . ' ' . OptionsArray::build($component->options));
 }
 /**
  * @param Parser     $parser The instance that requests parsing.
  * @param TokensList $list   The list of tokens to be parsed.
  *
  * @return void
  */
 public function parse(Parser $parser, TokensList $list)
 {
     ++$list->idx;
     // Skipping `REPLACE`.
     // parse any options if provided
     $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
     ++$list->idx;
     $token = $list->tokens[$list->idx];
     /**
      * The state of the parser.
      *
      * Below are the states of the parser.
      *
      *      0 ---------------------------------[ INTO ]----------------------------------> 1
      *
      *      1 -------------------------[ VALUES/VALUE/SET/SELECT ]-----------------------> 2
      *
      * @var int $state
      */
     $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_KEYWORD && $token->value !== 'INTO') {
                 $parser->error(__('Unexpected keyword.'), $token);
                 break;
             } else {
                 ++$list->idx;
                 $this->into = IntoKeyword::parse($parser, $list, array('fromReplace' => true));
             }
             $state = 1;
         } elseif ($state === 1) {
             if ($token->type === Token::TYPE_KEYWORD) {
                 if ($token->value === 'VALUE' || $token->value === 'VALUES') {
                     ++$list->idx;
                     // skip VALUES
                     $this->values = Array2d::parse($parser, $list);
                 } elseif ($token->value === 'SET') {
                     ++$list->idx;
                     // skip SET
                     $this->set = SetOperation::parse($parser, $list);
                 } elseif ($token->value === 'SELECT') {
                     $this->select = new SelectStatement($parser, $list);
                 } else {
                     $parser->error(__('Unexpected keyword.'), $token);
                     break;
                 }
                 $state = 2;
             } else {
                 $parser->error(__('Unexpected token.'), $token);
                 break;
             }
         }
     }
     --$list->idx;
 }
Example #14
0
 /**
  * @param Reference $component The component to be built.
  *
  * @return string
  */
 public static function build($component)
 {
     return trim(Context::escape($component->table) . ' (' . implode(', ', Context::escape($component->columns)) . ') ' . OptionsArray::build($component->options));
 }
Example #15
0
 /**
  * Parses the statements defined by the tokens list.
  *
  * @param Parser     $parser The instance that requests parsing.
  * @param TokensList $list   The list of tokens to be parsed.
  *
  * @return void
  */
 public function parse(Parser $parser, TokensList $list)
 {
     /**
      * Array containing all list of clauses parsed.
      * This is used to check for duplicates.
      *
      * @var array $parsedClauses
      */
     $parsedClauses = array();
     // This may be corrected by the parser.
     $this->first = $list->idx;
     /**
      * Whether options were parsed or not.
      * For statements that do not have any options this is set to `true` by
      * default.
      *
      * @var bool $parsedOptions
      */
     $parsedOptions = empty(static::$OPTIONS);
     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;
         }
         // Checking if this closing bracket is the pair for a bracket
         // outside the statement.
         if ($token->value === ')' && $parser->brackets > 0) {
             --$parser->brackets;
             continue;
         }
         // Only keywords are relevant here. Other parts of the query are
         // processed in the functions below.
         if ($token->type !== Token::TYPE_KEYWORD) {
             if ($token->type !== TOKEN::TYPE_COMMENT && $token->type !== Token::TYPE_WHITESPACE) {
                 $parser->error(__('Unexpected token.'), $token);
             }
             continue;
         }
         // Unions are parsed by the parser because they represent more than
         // one statement.
         if ($token->value === 'UNION' || $token->value === 'UNION ALL' || $token->value === 'UNION DISTINCT') {
             break;
         }
         $lastIdx = $list->idx;
         // ON DUPLICATE KEY UPDATE ...
         // has to be parsed in parent statement (INSERT or REPLACE)
         // so look for it and break
         if (get_class($this) === 'SqlParser\\Statements\\SelectStatement' && $token->value === 'ON') {
             ++$list->idx;
             // Skip ON
             // look for ON DUPLICATE KEY UPDATE
             $first = $list->getNextOfType(Token::TYPE_KEYWORD);
             $second = $list->getNextOfType(Token::TYPE_KEYWORD);
             $third = $list->getNextOfType(Token::TYPE_KEYWORD);
             if ($first && $second && $third && $first->value === 'DUPLICATE' && $second->value === 'KEY' && $third->value === 'UPDATE') {
                 $list->idx = $lastIdx;
                 break;
             }
         }
         $list->idx = $lastIdx;
         /**
          * The name of the class that is used for parsing.
          *
          * @var Component $class
          */
         $class = null;
         /**
          * The name of the field where the result of the parsing is stored.
          *
          * @var string $field
          */
         $field = null;
         /**
          * Parser's options.
          *
          * @var array $options
          */
         $options = array();
         // Looking for duplicated clauses.
         if (!empty(Parser::$KEYWORD_PARSERS[$token->value]) || !empty(Parser::$STATEMENT_PARSERS[$token->value])) {
             if (!empty($parsedClauses[$token->value])) {
                 $parser->error(__('This type of clause was previously parsed.'), $token);
                 break;
             }
             $parsedClauses[$token->value] = true;
         }
         // Checking if this is the beginning of a clause.
         if (!empty(Parser::$KEYWORD_PARSERS[$token->value])) {
             $class = Parser::$KEYWORD_PARSERS[$token->value]['class'];
             $field = Parser::$KEYWORD_PARSERS[$token->value]['field'];
             if (!empty(Parser::$KEYWORD_PARSERS[$token->value]['options'])) {
                 $options = Parser::$KEYWORD_PARSERS[$token->value]['options'];
             }
         }
         // Checking if this is the beginning of the statement.
         if (!empty(Parser::$STATEMENT_PARSERS[$token->value])) {
             if (!empty(static::$CLAUSES) && empty(static::$CLAUSES[$token->value])) {
                 // Some keywords (e.g. `SET`) may be the beginning of a
                 // statement and a clause.
                 // If such keyword was found and it cannot be a clause of
                 // this statement it means it is a new statement, but no
                 // delimiter was found between them.
                 $parser->error(__('A new statement was found, but no delimiter between it and the previous one.'), $token);
                 break;
             }
             if (!$parsedOptions) {
                 if (empty(static::$OPTIONS[$token->value])) {
                     // Skipping keyword because if it is not a option.
                     ++$list->idx;
                 }
                 $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
                 $parsedOptions = true;
             }
         } elseif ($class === null) {
             // Handle special end options in Select statement
             // See Statements\SelectStatement::$END_OPTIONS
             if (get_class($this) === 'SqlParser\\Statements\\SelectStatement' && ($token->value === 'FOR UPDATE' || $token->value === 'LOCK IN SHARE MODE')) {
                 $this->end_options = OptionsArray::parse($parser, $list, static::$END_OPTIONS);
             } else {
                 // There is no parser for this keyword and isn't the beginning
                 // of a statement (so no options) either.
                 $parser->error(__('Unrecognized keyword.'), $token);
                 continue;
             }
         }
         $this->before($parser, $list, $token);
         // Parsing this keyword.
         if ($class !== null) {
             ++$list->idx;
             // Skipping keyword or last option.
             $this->{$field} = $class::parse($parser, $list, $options);
         }
         $this->after($parser, $list, $token);
     }
     // This may be corrected by the parser.
     $this->last = --$list->idx;
     // Go back to last used token.
 }
Example #16
0
 /**
  * @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 AlterOperation
  */
 public static function parse(Parser $parser, TokensList $list, array $options = array())
 {
     $ret = new AlterOperation();
     /**
      * Counts brackets.
      *
      * @var int $brackets
      */
     $brackets = 0;
     /**
      * The state of the parser.
      *
      * Below are the states of the parser.
      *
      *      0 ---------------------[ options ]---------------------> 1
      *
      *      1 ----------------------[ field ]----------------------> 2
      *
      *      2 -------------------------[ , ]-----------------------> 0
      *
      * @var int $state
      */
     $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 comments.
         if ($token->type === Token::TYPE_COMMENT) {
             continue;
         }
         // Skipping whitespaces.
         if ($token->type === Token::TYPE_WHITESPACE) {
             if ($state === 2) {
                 // When parsing the unknown part, the whitespaces are
                 // included to not break anything.
                 $ret->unknown[] = $token;
             }
             continue;
         }
         if ($state === 0) {
             $ret->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
             $state = 1;
         } elseif ($state === 1) {
             $ret->field = Expression::parse($parser, $list, array('noAlias' => true, 'noBrackets' => true));
             if ($ret->field === null) {
                 // No field was read. We go back one token so the next
                 // iteration will parse the same token, but in state 2.
                 --$list->idx;
             }
             $state = 2;
         } elseif ($state === 2) {
             if ($token->type === Token::TYPE_OPERATOR) {
                 if ($token->value === '(') {
                     ++$brackets;
                 } elseif ($token->value === ')') {
                     --$brackets;
                 } elseif ($token->value === ',' && $brackets === 0) {
                     break;
                 }
             }
             $ret->unknown[] = $token;
         }
     }
     if ($ret->options->isEmpty()) {
         $parser->error(__('Unrecognized alter operation.'), $list->tokens[$list->idx]);
     }
     --$list->idx;
     return $ret;
 }
 /**
  * Parses the statements defined by the tokens list.
  *
  * @param Parser     $parser The instance that requests parsing.
  * @param TokensList $list   The list of tokens to be parsed.
  *
  * @return void
  */
 public function parse(Parser $parser, TokensList $list)
 {
     /**
      * Array containing all list of clauses parsed.
      * This is used to check for duplicates.
      *
      * @var array $parsedClauses
      */
     $parsedClauses = array();
     // This may be corrected by the parser.
     $this->first = $list->idx;
     /**
      * Whether options were parsed or not.
      * For statements that do not have any options this is set to `true` by
      * default.
      *
      * @var bool $parsedOptions
      */
     $parsedOptions = empty(static::$OPTIONS);
     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;
         }
         // Only keywords are relevant here. Other parts of the query are
         // processed in the functions below.
         if ($token->type !== Token::TYPE_KEYWORD) {
             if ($token->type !== TOKEN::TYPE_COMMENT && $token->type !== Token::TYPE_WHITESPACE) {
                 $parser->error(__('Unexpected token.'), $token);
             }
             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 Component $class
          */
         $class = null;
         /**
          * The name of the field where the result of the parsing is stored.
          *
          * @var string $field
          */
         $field = null;
         /**
          * Parser's options.
          *
          * @var array $options
          */
         $options = array();
         // Looking for duplicated clauses.
         if (!empty(Parser::$KEYWORD_PARSERS[$token->value]) || !empty(Parser::$STATEMENT_PARSERS[$token->value])) {
             if (!empty($parsedClauses[$token->value])) {
                 $parser->error(__('This type of clause was previously parsed.'), $token);
                 break;
             }
             $parsedClauses[$token->value] = true;
         }
         // Checking if this is the beginning of a clause.
         if (!empty(Parser::$KEYWORD_PARSERS[$token->value])) {
             $class = Parser::$KEYWORD_PARSERS[$token->value]['class'];
             $field = Parser::$KEYWORD_PARSERS[$token->value]['field'];
             if (!empty(Parser::$KEYWORD_PARSERS[$token->value]['options'])) {
                 $options = Parser::$KEYWORD_PARSERS[$token->value]['options'];
             }
         }
         // Checking if this is the beginning of the statement.
         if (!empty(Parser::$STATEMENT_PARSERS[$token->value])) {
             if (!empty(static::$CLAUSES) && empty(static::$CLAUSES[$token->value])) {
                 // Some keywords (e.g. `SET`) may be the beginning of a
                 // statement and a clause.
                 // If such keyword was found and it cannot be a clause of
                 // this statement it means it is a new statement, but no
                 // delimiter was found between them.
                 $parser->error(__('A new statement was found, but no delimiter between it and the previous one.'), $token);
                 break;
             }
             if (!$parsedOptions) {
                 if (empty(static::$OPTIONS[$token->value])) {
                     // Skipping keyword because if it is not a option.
                     ++$list->idx;
                 }
                 $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
                 $parsedOptions = true;
             }
         } elseif ($class === null) {
             // There is no parser for this keyword and isn't the beginning
             // of a statement (so no options) either.
             $parser->error(__('Unrecognized keyword.'), $token);
             continue;
         }
         $this->before($parser, $list, $token);
         // Parsing this keyword.
         if ($class !== null) {
             ++$list->idx;
             // Skipping keyword or last option.
             $this->{$field} = $class::parse($parser, $list, $options);
         }
         $this->after($parser, $list, $token);
     }
     // This may be corrected by the parser.
     $this->last = --$list->idx;
     // Go back to last used token.
 }
 /**
  * @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 PartitionDefinition
  */
 public static function parse(Parser $parser, TokensList $list, array $options = array())
 {
     $ret = new PartitionDefinition();
     /**
      * The state of the parser.
      *
      * Below are the states of the parser.
      *
      *      0 -------------[ PARTITION | SUBPARTITION ]------------> 1
      *
      *      1 -----------------------[ name ]----------------------> 2
      *
      *      2 ----------------------[ VALUES ]---------------------> 3
      *
      *      3 ---------------------[ LESS THAN ]-------------------> 4
      *      3 ------------------------[ IN ]-----------------------> 4
      *
      *      4 -----------------------[ expr ]----------------------> 5
      *
      *      5 ----------------------[ options ]--------------------> 6
      *
      *      6 ------------------[ subpartitions ]------------------> (END)
      *
      * @var int $state
      */
     $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) {
             $ret->isSubpartition = $token->type === Token::TYPE_KEYWORD && $token->value === 'SUBPARTITION';
             $state = 1;
         } elseif ($state === 1) {
             $ret->name = $token->value;
             $state = $ret->isSubpartition ? 5 : 2;
         } elseif ($state === 2) {
             $state = 3;
         } elseif ($state === 3) {
             $ret->type = $token->value;
             $state = 4;
         } elseif ($state === 4) {
             if ($token->value === 'MAXVALUE') {
                 $ret->expr = $token->value;
             } else {
                 $ret->expr = Expression::parse($parser, $list, array('bracketsDelimited' => true, 'noAlias' => true));
             }
             $state = 5;
         } elseif ($state === 5) {
             $ret->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
             $state = 6;
         } elseif ($state === 6) {
             if ($token->type === Token::TYPE_OPERATOR && $token->value === '(') {
                 $ret->subpartitions = ArrayObj::parse($parser, $list, array('type' => 'SqlParser\\Components\\PartitionDefinition'));
                 ++$list->idx;
             }
             break;
         }
     }
     --$list->idx;
     return $ret;
 }
 /**
  * @param Parser     $parser The instance that requests parsing.
  * @param TokensList $list   The list of tokens to be parsed.
  *
  * @return void
  */
 public function parse(Parser $parser, TokensList $list)
 {
     ++$list->idx;
     // Skipping `CREATE`.
     // Parsing options.
     $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
     ++$list->idx;
     // Skipping last option.
     // Parsing the field name.
     $this->name = Expression::parse($parser, $list, array('noAlias' => true, 'noBrackets' => true, 'skipColumn' => true));
     ++$list->idx;
     // Skipping field.
     if ($this->options->has('DATABASE')) {
         $this->entityOptions = OptionsArray::parse($parser, $list, static::$DB_OPTIONS);
     } elseif ($this->options->has('TABLE')) {
         $this->fields = FieldDefinition::parse($parser, $list);
         ++$list->idx;
         $this->entityOptions = OptionsArray::parse($parser, $list, static::$TABLE_OPTIONS);
     } elseif ($this->options->has('PROCEDURE') || $this->options->has('FUNCTION')) {
         $this->parameters = ParameterDefinition::parse($parser, $list);
         if ($this->options->has('FUNCTION')) {
             $token = $list->getNextOfType(Token::TYPE_KEYWORD);
             if ($token->value !== 'RETURNS') {
                 $parser->error('\'RETURNS\' keyword was expected.', $token);
             } else {
                 ++$list->idx;
                 $this->return = DataType::parse($parser, $list);
             }
         }
         ++$list->idx;
         $this->entityOptions = OptionsArray::parse($parser, $list, static::$FUNC_OPTIONS);
         ++$list->idx;
         for (; $list->idx < $list->count; ++$list->idx) {
             $token = $list->tokens[$list->idx];
             $this->body[] = $token;
         }
     } else {
         if ($this->options->has('VIEW')) {
             $token = $list->getNext();
             // Skipping whitespaces and comments.
             // Parsing columns list.
             if ($token->type === Token::TYPE_OPERATOR && $token->value === '(') {
                 --$list->idx;
                 // getNext() also goes forward one field.
                 $this->fields = ArrayObj::parse($parser, $list);
                 ++$list->idx;
                 // Skipping last token from the array.
                 $list->getNext();
             }
             // Parsing the `AS` keyword.
             for (; $list->idx < $list->count; ++$list->idx) {
                 $token = $list->tokens[$list->idx];
                 if ($token->type === Token::TYPE_DELIMITER) {
                     break;
                 }
                 $this->body[] = $token;
             }
         } else {
             if ($this->options->has('TRIGGER')) {
                 // Parsing the time and the event.
                 $this->entityOptions = OptionsArray::parse($parser, $list, static::$TRIGGER_OPTIONS);
                 ++$list->idx;
                 $list->getNextOfTypeAndValue(Token::TYPE_KEYWORD, 'ON');
                 ++$list->idx;
                 // Skipping `ON`.
                 // Parsing the name of the table.
                 $this->table = Expression::parse($parser, $list, array('noAlias' => true, 'noBrackets' => true, 'skipColumn' => true));
                 ++$list->idx;
                 $list->getNextOfTypeAndValue(Token::TYPE_KEYWORD, 'FOR EACH ROW');
                 ++$list->idx;
                 // Skipping `FOR EACH ROW`.
                 for (; $list->idx < $list->count; ++$list->idx) {
                     $token = $list->tokens[$list->idx];
                     $this->body[] = $token;
                 }
             }
         }
     }
 }
Example #20
0
 /**
  * Parses the statements defined by the tokens list.
  *
  * @param Parser     $parser The instance that requests parsing.
  * @param TokensList $list   The list of tokens to be parsed.
  *
  * @return void
  */
 public function parse(Parser $parser, TokensList $list)
 {
     // This may be corrected by the parser.
     $this->first = $list->idx;
     /**
      * Whether options were parsed or not.
      * For statements that do not have any options this is set to `true` by
      * default.
      * @var bool $parsedOptions
      */
     $parsedOptions = !empty(static::$OPTIONS) ? false : true;
     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;
         }
         // Only keywords are relevant here. Other parts of the query are
         // processed in the functions below.
         if ($token->type !== Token::TYPE_KEYWORD) {
             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 $class
          */
         $class = null;
         /**
          * The name of the field where the result of the parsing is stored.
          * @var string $field
          */
         $field = null;
         /**
          * Parser's options.
          * @var array $options
          */
         $options = array();
         if (!empty(Parser::$KEYWORD_PARSERS[$token->value])) {
             $class = Parser::$KEYWORD_PARSERS[$token->value]['class'];
             $field = Parser::$KEYWORD_PARSERS[$token->value]['field'];
             if (!empty(Parser::$KEYWORD_PARSERS[$token->value]['options'])) {
                 $options = Parser::$KEYWORD_PARSERS[$token->value]['options'];
             }
         }
         if (!empty(Parser::$STATEMENT_PARSERS[$token->value])) {
             if (!$parsedOptions) {
                 ++$list->idx;
                 // Skipping keyword.
                 $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
                 $parsedOptions = true;
             }
         } elseif ($class === null) {
             // There is no parser for this keyword and isn't the beginning
             // of a statement (so no options) either.
             $parser->error('Unrecognized keyword "' . $token->value . '".', $token);
             continue;
         }
         $this->before($parser, $list, $token);
         // Parsing this keyword.
         if ($class !== null) {
             ++$list->idx;
             // Skipping keyword.
             $this->{$field} = $class::parse($parser, $list, $options);
         }
         $this->after($parser, $list, $token);
     }
     // This may be corrected by the parser.
     $this->last = --$list->idx;
     // Go back to last used token.
 }
 /**
  * @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
      */
     $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;
 }
Example #22
0
 /**
  * @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 DataType
  */
 public static function parse(Parser $parser, TokensList $list, array $options = array())
 {
     $ret = new DataType();
     /**
      * The state of the parser.
      *
      * Below are the states of the parser.
      *
      *      0 -------------------[ data type ]--------------------> 1
      *
      *      1 ----------------[ size and options ]----------------> 2
      *
      * @var int $state
      */
     $state = 0;
     for (; $list->idx < $list->count; ++$list->idx) {
         /**
          * Token parsed at this moment.
          *
          * @var Token $token
          */
         $token = $list->tokens[$list->idx];
         // Skipping whitespaces and comments.
         if ($token->type === Token::TYPE_WHITESPACE || $token->type === Token::TYPE_COMMENT) {
             continue;
         }
         if ($state === 0) {
             $ret->name = strtoupper($token->value);
             if ($token->type !== Token::TYPE_KEYWORD || !($token->flags & Token::FLAG_KEYWORD_DATA_TYPE)) {
                 $parser->error(__('Unrecognized data type.'), $token);
             }
             $state = 1;
         } elseif ($state === 1) {
             if ($token->type === Token::TYPE_OPERATOR && $token->value === '(') {
                 $parameters = ArrayObj::parse($parser, $list);
                 ++$list->idx;
                 $ret->parameters = $ret->name === 'ENUM' || $ret->name === 'SET' ? $parameters->raw : $parameters->values;
             }
             $ret->options = OptionsArray::parse($parser, $list, static::$DATA_TYPE_OPTIONS);
             ++$list->idx;
             break;
         }
     }
     if (empty($ret->name)) {
         return null;
     }
     --$list->idx;
     return $ret;
 }
Example #23
0
 /**
  * @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 Reference
  */
 public static function parse(Parser $parser, TokensList $list, array $options = array())
 {
     $ret = new Reference();
     /**
      * The state of the parser.
      *
      * Below are the states of the parser.
      *
      *      0 ----------------------[ table ]---------------------> 1
      *
      *      1 ---------------------[ columns ]--------------------> 2
      *
      *      2 ---------------------[ options ]--------------------> (END)
      *
      * @var int $state
      */
     $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) {
             $ret->table = $token->value;
             $state = 1;
         } elseif ($state === 1) {
             $ret->columns = ArrayObj::parse($parser, $list)->values;
             $state = 2;
         } elseif ($state === 2) {
             $ret->options = OptionsArray::parse($parser, $list, static::$REFERENCES_OPTIONS);
             ++$list->idx;
             break;
         }
     }
     --$list->idx;
     return $ret;
 }
 /**
  * @return string
  */
 public function build()
 {
     $tmp = array();
     foreach ($this->altered as $altered) {
         $tmp[] = $altered::build($altered);
     }
     return 'ALTER ' . OptionsArray::build($this->options) . ' TABLE ' . Expression::build($this->table) . ' ' . implode(', ', $tmp);
 }
Example #25
0
 /**
  * @param Parser     $parser The instance that requests parsing.
  * @param TokensList $list   The list of tokens to be parsed.
  *
  * @return void
  */
 public function parse(Parser $parser, TokensList $list)
 {
     ++$list->idx;
     // Skipping `DELETE`.
     // parse any options if provided
     $this->options = OptionsArray::parse($parser, $list, static::$OPTIONS);
     ++$list->idx;
     /**
      * The state of the parser.
      *
      * Below are the states of the parser.
      *
      *      0 ---------------------------------[ FROM ]----------------------------------> 2
      *      0 ------------------------------[ table[.*] ]--------------------------------> 1
      *      1 ---------------------------------[ FROM ]----------------------------------> 2
      *      2 --------------------------------[ USING ]----------------------------------> 3
      *      2 --------------------------------[ WHERE ]----------------------------------> 4
      *      2 --------------------------------[ ORDER ]----------------------------------> 5
      *      2 --------------------------------[ LIMIT ]----------------------------------> 6
      *
      * @var int $state
      */
     $state = 0;
     /**
      * If the query is multi-table or not
      *
      * @var bool $multiTable
      */
     $multiTable = false;
     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;
         }
         if ($state === 0) {
             if ($token->type === Token::TYPE_KEYWORD && $token->value !== 'FROM') {
                 $parser->error(__('Unexpected keyword.'), $token);
                 break;
             } elseif ($token->type === Token::TYPE_KEYWORD && $token->value === 'FROM') {
                 ++$list->idx;
                 // Skip 'FROM'
                 $this->from = ExpressionArray::parse($parser, $list);
                 $state = 2;
             } else {
                 $this->columns = ExpressionArray::parse($parser, $list);
                 $state = 1;
             }
         } elseif ($state === 1) {
             if ($token->type === Token::TYPE_KEYWORD && $token->value !== 'FROM') {
                 $parser->error(__('Unexpected keyword.'), $token);
                 break;
             } elseif ($token->type === Token::TYPE_KEYWORD && $token->value === 'FROM') {
                 ++$list->idx;
                 // Skip 'FROM'
                 $this->from = ExpressionArray::parse($parser, $list);
                 $state = 2;
             } else {
                 $parser->error(__('Unexpected token.'), $token);
                 break;
             }
         } elseif ($state === 2) {
             if ($token->type === Token::TYPE_KEYWORD && $token->value === 'USING') {
                 ++$list->idx;
                 // Skip 'USING'
                 $this->using = ExpressionArray::parse($parser, $list);
                 $state = 3;
                 $multiTable = true;
             } elseif ($token->type === Token::TYPE_KEYWORD && $token->value === 'WHERE') {
                 ++$list->idx;
                 // Skip 'WHERE'
                 $this->where = Condition::parse($parser, $list);
                 $state = 4;
             } elseif ($token->type === Token::TYPE_KEYWORD && $token->value === 'ORDER BY') {
                 ++$list->idx;
                 // Skip 'ORDER BY'
                 $this->order = OrderKeyword::parse($parser, $list);
                 $state = 5;
             } elseif ($token->type === Token::TYPE_KEYWORD && $token->value === 'LIMIT') {
                 ++$list->idx;
                 // Skip 'LIMIT'
                 $this->limit = Limit::parse($parser, $list);
                 $state = 6;
             } elseif ($token->type === Token::TYPE_KEYWORD) {
                 $parser->error(__('Unexpected keyword.'), $token);
                 break;
             }
         } elseif ($state === 3) {
             if ($token->type === Token::TYPE_KEYWORD && $token->value === 'WHERE') {
                 ++$list->idx;
                 // Skip 'WHERE'
                 $this->where = Condition::parse($parser, $list);
                 $state = 4;
             } elseif ($token->type === Token::TYPE_KEYWORD) {
                 $parser->error(__('Unexpected keyword.'), $token);
                 break;
             } else {
                 $parser->error(__('Unexpected token.'), $token);
                 break;
             }
         } elseif ($state === 4) {
             if ($multiTable === true && $token->type === Token::TYPE_KEYWORD) {
                 $parser->error(__('This type of clause is not valid in Multi-table queries.'), $token);
                 break;
             }
             if ($token->type === Token::TYPE_KEYWORD && $token->value === 'ORDER BY') {
                 ++$list->idx;
                 // Skip 'ORDER  BY'
                 $this->order = OrderKeyword::parse($parser, $list);
                 $state = 5;
             } elseif ($token->type === Token::TYPE_KEYWORD && $token->value === 'LIMIT') {
                 ++$list->idx;
                 // Skip 'LIMIT'
                 $this->limit = Limit::parse($parser, $list);
                 $state = 6;
             } elseif ($token->type === Token::TYPE_KEYWORD) {
                 $parser->error(__('Unexpected keyword.'), $token);
                 break;
             }
         } elseif ($state === 5) {
             if ($token->type === Token::TYPE_KEYWORD && $token->value === 'LIMIT') {
                 ++$list->idx;
                 // Skip 'LIMIT'
                 $this->limit = Limit::parse($parser, $list);
                 $state = 6;
             } elseif ($token->type === Token::TYPE_KEYWORD) {
                 $parser->error(__('Unexpected keyword.'), $token);
                 break;
             }
         }
     }
     if ($state >= 2) {
         foreach ($this->from as $from_expr) {
             $from_expr->database = $from_expr->table;
             $from_expr->table = $from_expr->column;
             $from_expr->column = null;
         }
     }
     --$list->idx;
 }
Example #26
0
 /**
  * @param AlterOperation $component The component to be built.
  *
  * @return string
  */
 public static function build($component)
 {
     $ret = OptionsArray::build($component->options) . ' ';
     if (!empty($component->field)) {
         $ret .= Expression::build($component->field) . ' ';
     }
     $ret .= TokensList::build($component->unknown);
     return $ret;
 }