Автор: Dan Ungureanu (udan1107@gmail.com)
Наследование: extends SqlParser\Component
 /**
  * Parses a parameter of a routine.
  *
  * @param string $param Parameter's definition.
  *
  * @return array
  */
 public static function getParameter($param)
 {
     $lexer = new Lexer('(' . $param . ')');
     // A dummy parser is used for error reporting.
     $param = ParameterDefinition::parse(new Parser(), $lexer->list);
     if (empty($param[0])) {
         return array('', '', '', '', '');
     }
     $param = $param[0];
     $options = array();
     foreach ($param->type->options->options as $opt) {
         $options[] = is_string($opt) ? $opt : $opt['value'];
     }
     return array(empty($param->inOut) ? '' : $param->inOut, $param->name, $param->type->name, implode(',', $param->type->parameters), implode(' ', $options));
 }
Пример #2
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 `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;
         }
     }
 }
Пример #3
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 `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;
                 }
             }
         }
     }
 }
 public function testParse()
 {
     $component = ParameterDefinition::parse(new Parser(), $this->getTokensList('(a INT, b INT'));
     $this->assertEquals('a', $component[0]->name);
     $this->assertEquals('b', $component[1]->name);
 }