‪TYPO3CMS  ‪main
Parser.php
Go to the documentation of this file.
1 <?php
2 
3 declare(strict_types=1);
4 
5 /*
6  * This file is part of the TYPO3 CMS project.
7  *
8  * It is free software; you can redistribute it and/or modify it under
9  * the terms of the GNU General Public License, either version 2
10  * of the License, or any later version.
11  *
12  * For the full copyright and license information, please read the
13  * LICENSE.txt file that was distributed with this source code.
14  *
15  * The TYPO3 project - inspiring people to share!
16  */
17 
19 
20 use Doctrine\Common\Lexer\Token;
21 use Doctrine\DBAL\Schema\SchemaException;
22 use Doctrine\DBAL\Schema\Table;
67 
74 final class ‪Parser
75 {
77  private string ‪$statement;
78 
79  public function ‪__construct(
80  private readonly ‪Lexer $lexer,
81  ) {}
82 
92  public function ‪parse(string ‪$statement): array
93  {
94  $ast = $this->‪getAST($statement);
95  if (!$ast instanceof ‪CreateTableStatement) {
96  return [];
97  }
98  $tableBuilder = new ‪TableBuilder();
99  $table = $tableBuilder->create($ast);
100  return [$table];
101  }
102 
110  {
111  // Parse & build AST
112  $this->statement = ‪$statement;
113  $this->lexer->setInput(‪$statement);
114  $this->lexer->moveNext();
115  if (($this->lexer->lookahead?->type ?? null) !== ‪Lexer::T_CREATE) {
116  $this->‪syntaxError('CREATE');
117  }
118  $createStatement = $this->‪createStatement();
119  // Check for end of string
120  if ($this->lexer->lookahead !== null) {
121  $this->‪syntaxError('end of string');
122  }
123  return $createStatement;
124  }
125 
135  private function ‪match(int $token): void
136  {
137  $lookaheadType = $this->lexer->lookahead->type;
138  // Short-circuit on first condition, usually types match
139  if ($lookaheadType !== $token) {
140  // If parameter is not identifier (1-99) must be exact match
141  if ($token < ‪Lexer::T_IDENTIFIER) {
142  $this->‪syntaxError((string)$this->lexer->getLiteral($token));
143  }
144  // If parameter is keyword (200+) must be exact match
145  if ($token > ‪Lexer::T_IDENTIFIER) {
146  $this->‪syntaxError((string)$this->lexer->getLiteral($token));
147  }
148  // If parameter is MATCH then FULL, PARTIAL or SIMPLE must follow
149  if ($token === ‪Lexer::T_MATCH
150  && $lookaheadType !== ‪Lexer::T_FULL
151  && $lookaheadType !== ‪Lexer::T_PARTIAL
152  && $lookaheadType !== ‪Lexer::T_SIMPLE
153  ) {
154  $this->‪syntaxError((string)$this->lexer->getLiteral($token));
155  }
156  if ($token === ‪Lexer::T_ON && $lookaheadType !== ‪Lexer::T_DELETE && $lookaheadType !== ‪Lexer::T_UPDATE) {
157  $this->‪syntaxError((string)$this->lexer->getLiteral($token));
158  }
159  }
160  $this->lexer->moveNext();
161  }
162 
170  private function ‪syntaxError(string $expected = '', ?Token $token = null): void
171  {
172  if ($token === null) {
173  $token = $this->lexer->lookahead;
174  }
175  $tokenPos = $token->position;
176 
177  $message = "line 0, col {$tokenPos}: Error: ";
178  $message .= ($expected !== '') ? "Expected {$expected}, got " : 'Unexpected ';
179  $message .= ($this->lexer->lookahead === null) ? 'end of string.' : "'{$token->value}'";
180 
181  throw ‪StatementException::syntaxError($message, ‪StatementException::sqlError($this->statement));
182  }
183 
190  private function ‪semanticError(string $message = ''): void
191  {
192  $token = $this->lexer->lookahead ?? [];
193  $tokenPos = $token->position;
194 
195  // Minimum exposed chars ahead of token
196  $distance = 12;
197 
198  // Find a position of a final word to display in error string
199  $createTableStatement = ‪$this->statement;
200  $length = strlen($createTableStatement);
201  $pos = $tokenPos + $distance;
202  $pos = strpos($createTableStatement, ' ', ($length > $pos) ? $pos : $length);
203  $length = ($pos !== false) ? $pos - $tokenPos : $distance;
204 
205  $tokenStr = substr($createTableStatement, $tokenPos, $length);
206 
207  // Building informative message
208  $message = 'line 0, col ' . $tokenPos . " near '" . $tokenStr . "': Error: " . $message;
209 
211  }
212 
220  {
222  $statement = ‪match ($this->lexer->lookahead->type) {
224  default => $this->‪syntaxError('TEMPORARY or TABLE'),
225  };
227  return ‪$statement;
228  }
229 
236  {
237  $createTableStatement = new ‪CreateTableStatement($this->‪createTableClause(), $this->‪createDefinition());
238  if (!$this->lexer->isNextToken(‪Lexer::T_SEMICOLON)) {
239  $createTableStatement->tableOptions = $this->‪tableOptions();
240  }
241  return $createTableStatement;
242  }
243 
250  {
251  $isTemporary = false;
252  // Check for TEMPORARY
253  if ($this->lexer->isNextToken(‪Lexer::T_TEMPORARY)) {
255  $isTemporary = true;
256  }
257 
258  $this->‪match(‪Lexer::T_TABLE);
259 
260  // Check for IF NOT EXISTS
261  if ($this->lexer->isNextToken(‪Lexer::T_IF)) {
262  $this->‪match(‪Lexer::T_IF);
263  $this->‪match(‪Lexer::T_NOT);
265  }
266 
267  // Process schema object name (table name)
268  $tableName = $this->‪schemaObjectName();
269 
270  return new ‪CreateTableClause($tableName, $isTemporary);
271  }
272 
289  {
290  $createDefinitions = [];
291 
292  // Process opening parenthesis
294 
295  if ($this->lexer->lookahead->type === ‪Lexer::T_CLOSE_PARENTHESIS) {
296  // No columns defined in this table for now. This is invalid in most DBMS, but core may
297  // auto add fields later. Swallow ")" and return empty CreateDefinition for "no columns".
299  return new ‪CreateDefinition([]);
300  }
301 
302  $createDefinitions[] = $this->‪createDefinitionItem();
303 
304  while ($this->lexer->isNextToken(‪Lexer::T_COMMA)) {
305  $this->‪match(‪Lexer::T_COMMA);
306 
307  // TYPO3 previously accepted invalid SQL files where a "create" definition
308  // item terminated with a comma before the final closing parenthesis.
309  // Silently swallow the extra comma and stop the "create" definition parsing.
310  if ($this->lexer->isNextToken(‪Lexer::T_CLOSE_PARENTHESIS)) {
311  break;
312  }
313 
314  $createDefinitions[] = $this->‪createDefinitionItem();
315  }
316 
317  // Process closing parenthesis
319 
320  return new ‪CreateDefinition($createDefinitions);
321  }
322 
329  {
330  $definitionItem = null;
331 
332  switch ($this->lexer->lookahead->type) {
334  // Intentional fall-through
335  case ‪Lexer::T_SPATIAL:
336  // Intentional fall-through
337  case ‪Lexer::T_PRIMARY:
338  // Intentional fall-through
339  case ‪Lexer::T_UNIQUE:
340  // Intentional fall-through
341  case ‪Lexer::T_KEY:
342  // Intentional fall-through
343  case ‪Lexer::T_INDEX:
344  $definitionItem = $this->‪createIndexDefinitionItem();
345  break;
346  case ‪Lexer::T_FOREIGN:
347  $definitionItem = $this->‪createForeignKeyDefinitionItem();
348  break;
350  $this->‪semanticError('CONSTRAINT [symbol] index definition part not supported');
351  break;
352  case ‪Lexer::T_CHECK:
353  $this->‪semanticError('CHECK (expr) create definition not supported');
354  break;
355  default:
356  $definitionItem = $this->‪createColumnDefinitionItem();
357  }
358 
359  return $definitionItem;
360  }
361 
368  {
369  $indexName = null;
370  $isPrimary = false;
371  $isFulltext = false;
372  $isSpatial = false;
373  $isUnique = false;
374  $indexDefinition = new ‪CreateIndexDefinitionItem();
375 
376  switch ($this->lexer->lookahead->type) {
377  case ‪Lexer::T_PRIMARY:
379  // KEY is a required keyword for PRIMARY index
380  $this->‪match(‪Lexer::T_KEY);
381  $isPrimary = true;
382  break;
383  case ‪Lexer::T_KEY:
384  // Plain index, no special configuration
385  $this->‪match(‪Lexer::T_KEY);
386  break;
387  case ‪Lexer::T_INDEX:
388  // Plain index, no special configuration
389  $this->‪match(‪Lexer::T_INDEX);
390  break;
391  case ‪Lexer::T_UNIQUE:
393  // INDEX|KEY are optional keywords for UNIQUE index
394  if ($this->lexer->isNextTokenAny([‪Lexer::T_INDEX, ‪Lexer::T_KEY])) {
395  $this->lexer->moveNext();
396  }
397  $isUnique = true;
398  break;
401  // INDEX|KEY are optional keywords for FULLTEXT index
402  if ($this->lexer->isNextTokenAny([‪Lexer::T_INDEX, ‪Lexer::T_KEY])) {
403  $this->lexer->moveNext();
404  }
405  $isFulltext = true;
406  break;
407  case ‪Lexer::T_SPATIAL:
409  // INDEX|KEY are optional keywords for SPATIAL index
410  if ($this->lexer->isNextTokenAny([‪Lexer::T_INDEX, ‪Lexer::T_KEY])) {
411  $this->lexer->moveNext();
412  }
413  $isSpatial = true;
414  break;
415  default:
416  $this->‪syntaxError('PRIMARY, KEY, INDEX, UNIQUE, FULLTEXT or SPATIAL');
417  }
418 
419  // PRIMARY KEY has no name in MySQL
420  if (!$indexDefinition->isPrimary) {
421  $indexName = $this->‪indexName();
422  }
423 
424  $indexDefinition = new ‪CreateIndexDefinitionItem(
425  $indexName,
426  $isPrimary,
427  $isUnique,
428  $isSpatial,
429  $isFulltext
430  );
431 
432  // FULLTEXT and SPATIAL indexes can not have a type definition
433  if (!$isFulltext && !$isSpatial) {
434  $indexDefinition->indexType = $this->‪indexType();
435  }
436 
438 
439  $indexDefinition->columnNames[] = $this->‪indexColumnName();
440 
441  while ($this->lexer->isNextToken(‪Lexer::T_COMMA)) {
442  $this->‪match(‪Lexer::T_COMMA);
443  $indexDefinition->columnNames[] = $this->‪indexColumnName();
444  }
445 
447 
448  $indexDefinition->options = $this->‪indexOptions();
449 
450  return $indexDefinition;
451  }
452 
459  {
461  $this->‪match(‪Lexer::T_KEY);
462 
463  $indexName = $this->‪indexName();
464 
466 
467  $indexColumns = [];
468  $indexColumns[] = $this->‪indexColumnName();
469 
470  while ($this->lexer->isNextToken(‪Lexer::T_COMMA)) {
471  $this->‪match(‪Lexer::T_COMMA);
472  $indexColumns[] = $this->‪indexColumnName();
473  }
474 
476 
478  $indexName,
479  $indexColumns,
480  $this->‪referenceDefinition()
481  );
482  }
483 
490  private function ‪indexName(): ‪Identifier
491  {
492  $indexName = new ‪Identifier('');
493  if (!$this->lexer->isNextTokenAny([‪Lexer::T_USING, ‪Lexer::T_OPEN_PARENTHESIS])) {
494  $indexName = $this->‪schemaObjectName();
495  }
496  return $indexName;
497  }
498 
504  private function ‪indexType(): string
505  {
506  $indexType = '';
507  if (!$this->lexer->isNextToken(‪Lexer::T_USING)) {
508  return $indexType;
509  }
510 
511  $this->‪match(‪Lexer::T_USING);
512 
513  switch ($this->lexer->lookahead->type) {
514  case ‪Lexer::T_BTREE:
515  $this->‪match(‪Lexer::T_BTREE);
516  $indexType = 'BTREE';
517  break;
518  case ‪Lexer::T_HASH:
519  $this->‪match(‪Lexer::T_HASH);
520  $indexType = 'HASH';
521  break;
522  default:
523  $this->‪syntaxError('BTREE or HASH');
524  }
525 
526  return $indexType;
527  }
528 
537  private function ‪indexOptions(): array
538  {
539  $options = [];
540 
541  while ($this->lexer->lookahead && !$this->lexer->isNextTokenAny([‪Lexer::T_COMMA, ‪Lexer::T_CLOSE_PARENTHESIS])) {
542  switch ($this->lexer->lookahead->type) {
545  if ($this->lexer->isNextToken(‪Lexer::T_EQUALS)) {
547  }
548  $this->lexer->moveNext();
549  $options['key_block_size'] = (int)$this->lexer->token->value;
550  break;
551  case ‪Lexer::T_USING:
552  $options['index_type'] = $this->indexType();
553  break;
554  case ‪Lexer::T_WITH:
555  $this->‪match(‪Lexer::T_WITH);
557  $options['parser'] = $this->‪schemaObjectName();
558  break;
559  case ‪Lexer::T_COMMENT:
562  $options['comment'] = $this->lexer->token->value;
563  break;
564  default:
565  $this->‪syntaxError('KEY_BLOCK_SIZE, USING, WITH PARSER or COMMENT');
566  }
567  }
568 
569  return $options;
570  }
571 
586  {
587  $columnName = $this->‪schemaObjectName();
588  $dataType = $this->‪columnDataType();
589 
590  $columnDefinitionItem = new ‪CreateColumnDefinitionItem($columnName, $dataType);
591 
592  while ($this->lexer->lookahead && !$this->lexer->isNextTokenAny([‪Lexer::T_COMMA, ‪Lexer::T_CLOSE_PARENTHESIS])) {
593  switch ($this->lexer->lookahead->type) {
594  case ‪Lexer::T_NOT:
595  $columnDefinitionItem->allowNull = false;
596  $this->‪match(‪Lexer::T_NOT);
597  $this->‪match(‪Lexer::T_NULL);
598  break;
599  case ‪Lexer::T_NULL:
600  $columnDefinitionItem->allowNull = true;
601  $this->‪match(‪Lexer::T_NULL);
602  break;
603  case ‪Lexer::T_DEFAULT:
604  $columnDefinitionItem->hasDefaultValue = true;
605  $columnDefinitionItem->defaultValue = $this->‪columnDefaultValue();
606  break;
608  $columnDefinitionItem->autoIncrement = true;
610  break;
611  case ‪Lexer::T_UNIQUE:
612  $columnDefinitionItem->unique = true;
614  if ($this->lexer->isNextToken(‪Lexer::T_KEY)) {
615  $this->‪match(‪Lexer::T_KEY);
616  }
617  break;
618  case ‪Lexer::T_PRIMARY:
619  $columnDefinitionItem->primary = true;
621  if ($this->lexer->isNextToken(‪Lexer::T_KEY)) {
622  $this->‪match(‪Lexer::T_KEY);
623  }
624  break;
625  case ‪Lexer::T_KEY:
626  $columnDefinitionItem->index = true;
627  $this->‪match(‪Lexer::T_KEY);
628  break;
629  case ‪Lexer::T_COMMENT:
631  if ($this->lexer->isNextToken(‪Lexer::T_STRING)) {
632  $columnDefinitionItem->comment = $this->lexer->lookahead->value;
634  }
635  break;
638  if ($this->lexer->isNextToken(‪Lexer::T_FIXED)) {
639  $columnDefinitionItem->columnFormat = 'fixed';
640  $this->‪match(‪Lexer::T_FIXED);
641  } elseif ($this->lexer->isNextToken(‪Lexer::T_DYNAMIC)) {
642  $columnDefinitionItem->columnFormat = 'dynamic';
644  } else {
646  }
647  break;
648  case ‪Lexer::T_STORAGE:
650  if ($this->lexer->isNextToken(‪Lexer::T_MEMORY)) {
651  $columnDefinitionItem->storage = 'memory';
653  } elseif ($this->lexer->isNextToken(‪Lexer::T_DISK)) {
654  $columnDefinitionItem->storage = 'disk';
655  $this->‪match(‪Lexer::T_DISK);
656  } else {
658  }
659  break;
661  $columnDefinitionItem->reference = $this->‪referenceDefinition();
662  break;
663  default:
664  $this->‪syntaxError(
665  'NOT, NULL, DEFAULT, AUTO_INCREMENT, UNIQUE, ' .
666  'PRIMARY, COMMENT, COLUMN_FORMAT, STORAGE or REFERENCES'
667  );
668  }
669  }
670 
671  return $columnDefinitionItem;
672  }
673 
711  {
712  $dataType = null;
713 
714  switch ($this->lexer->lookahead->type) {
715  case ‪Lexer::T_BIT:
716  $this->‪match(‪Lexer::T_BIT);
717  $dataType = new ‪BitDataType(
718  $this->‪dataTypeLength()
719  );
720  break;
721  case ‪Lexer::T_TINYINT:
723  $dataType = new ‪TinyIntDataType(
724  $this->‪dataTypeLength(),
726  );
727  break;
730  $dataType = new ‪SmallIntDataType(
731  $this->‪dataTypeLength(),
733  );
734  break;
737  $dataType = new ‪MediumIntDataType(
738  $this->‪dataTypeLength(),
740  );
741  break;
742  case ‪Lexer::T_INT:
743  $this->‪match(‪Lexer::T_INT);
744  $dataType = new ‪IntegerDataType(
745  $this->‪dataTypeLength(),
747  );
748  break;
749  case ‪Lexer::T_INTEGER:
751  $dataType = new ‪IntegerDataType(
752  $this->‪dataTypeLength(),
754  );
755  break;
756  case ‪Lexer::T_BIGINT:
758  $dataType = new ‪BigIntDataType(
759  $this->‪dataTypeLength(),
761  );
762  break;
763  case ‪Lexer::T_REAL:
764  $this->‪match(‪Lexer::T_REAL);
765  $dataType = new ‪RealDataType(
766  $this->‪dataTypeDecimals(),
768  );
769  break;
770  case ‪Lexer::T_DOUBLE:
772  if ($this->lexer->isNextToken(‪Lexer::T_PRECISION)) {
774  }
775  $dataType = new ‪DoubleDataType(
776  $this->‪dataTypeDecimals(),
778  );
779  break;
780  case ‪Lexer::T_FLOAT:
781  $this->‪match(‪Lexer::T_FLOAT);
782  $dataType = new ‪FloatDataType(
783  $this->‪dataTypeDecimals(),
785  );
786 
787  break;
788  case ‪Lexer::T_DECIMAL:
790  $dataType = new ‪DecimalDataType(
791  $this->‪dataTypeDecimals(),
793  );
794  break;
795  case ‪Lexer::T_NUMERIC:
797  $dataType = new ‪NumericDataType(
798  $this->‪dataTypeDecimals(),
800  );
801  break;
802  case ‪Lexer::T_DATE:
803  $this->‪match(‪Lexer::T_DATE);
804  $dataType = new ‪DateDataType();
805  break;
806  case ‪Lexer::T_TIME:
807  $this->‪match(‪Lexer::T_TIME);
808  $dataType = new ‪TimeDataType($this->‪fractionalSecondsPart());
809  break;
812  $dataType = new ‪TimestampDataType($this->‪fractionalSecondsPart());
813  break;
816  $dataType = new ‪DateTimeDataType($this->‪fractionalSecondsPart());
817  break;
818  case ‪Lexer::T_YEAR:
819  $this->‪match(‪Lexer::T_YEAR);
820  $dataType = new ‪YearDataType();
821  break;
822  case ‪Lexer::T_CHAR:
823  $this->‪match(‪Lexer::T_CHAR);
824  $dataType = new ‪CharDataType(
825  $this->‪dataTypeLength(),
827  );
828  break;
829  case ‪Lexer::T_VARCHAR:
831  $dataType = new ‪VarCharDataType(
832  $this->‪dataTypeLength(true),
834  );
835  break;
836  case ‪Lexer::T_BINARY:
838  $dataType = new ‪BinaryDataType($this->‪dataTypeLength());
839  break;
842  $dataType = new ‪VarBinaryDataType($this->‪dataTypeLength(true));
843  break;
846  $dataType = new ‪TinyBlobDataType();
847  break;
848  case ‪Lexer::T_BLOB:
849  $this->‪match(‪Lexer::T_BLOB);
850  $dataType = new ‪BlobDataType();
851  break;
854  $dataType = new ‪MediumBlobDataType();
855  break;
858  $dataType = new ‪LongBlobDataType();
859  break;
862  $dataType = new ‪TinyTextDataType($this->‪characterDataTypeOptions());
863  break;
864  case ‪Lexer::T_TEXT:
865  $this->‪match(‪Lexer::T_TEXT);
866  $dataType = new ‪TextDataType($this->‪characterDataTypeOptions());
867  break;
870  $dataType = new ‪MediumTextDataType($this->‪characterDataTypeOptions());
871  break;
874  $dataType = new ‪LongTextDataType($this->‪characterDataTypeOptions());
875  break;
876  case ‪Lexer::T_ENUM:
877  $this->‪match(‪Lexer::T_ENUM);
878  $dataType = new ‪EnumDataType($this->‪valueList(), $this->‪enumerationDataTypeOptions());
879  break;
880  case ‪Lexer::T_SET:
881  $this->‪match(‪Lexer::T_SET);
882  $dataType = new ‪SetDataType($this->‪valueList(), $this->‪enumerationDataTypeOptions());
883  break;
884  case ‪Lexer::T_JSON:
885  $this->‪match(‪Lexer::T_JSON);
886  $dataType = new ‪JsonDataType();
887  break;
888  default:
889  $this->‪syntaxError(
890  'BIT, TINYINT, SMALLINT, MEDIUMINT, INT, INTEGER, BIGINT, REAL, DOUBLE, FLOAT, DECIMAL, NUMERIC, ' .
891  'DATE, TIME, TIMESTAMP, DATETIME, YEAR, CHAR, VARCHAR, BINARY, VARBINARY, TINYBLOB, BLOB, ' .
892  'MEDIUMBLOB, LONGBLOB, TINYTEXT, TEXT, MEDIUMTEXT, LONGTEXT, ENUM, SET, or JSON'
893  );
894  }
895 
896  return $dataType;
897  }
898 
904  private function ‪columnDefaultValue(): string|int|float|null
905  {
907  $value = ‪match ($this->lexer->lookahead->type) {
908  ‪Lexer::T_INTEGER => (int)$this->lexer->lookahead->value,
909  ‪Lexer::T_FLOAT => (float)$this->lexer->lookahead->value,
910  ‪Lexer::T_STRING => (string)$this->lexer->lookahead->value,
911  ‪Lexer::T_CURRENT_TIMESTAMP => 'CURRENT_TIMESTAMP',
912  ‪Lexer::T_NULL => null,
913  default => $this->syntaxError('String, Integer, Float, NULL or CURRENT_TIMESTAMP'),
914  };
915  $this->lexer->moveNext();
916  return $value;
917  }
918 
924  private function ‪dataTypeLength(bool $required = false): int
925  {
926  $length = 0;
927  if (!$this->lexer->isNextToken(‪Lexer::T_OPEN_PARENTHESIS)) {
928  if ($required) {
929  $this->‪semanticError('The current data type requires a field length definition.');
930  }
931  return $length;
932  }
933 
935  $length = (int)$this->lexer->lookahead->value;
936  $this->match(‪Lexer::T_INTEGER);
938 
939  return $length;
940  }
941 
947  private function ‪dataTypeDecimals(): array
948  {
949  $options = [];
950  if (!$this->lexer->isNextToken(‪Lexer::T_OPEN_PARENTHESIS)) {
951  return $options;
952  }
953 
955  $options['length'] = (int)$this->lexer->lookahead->value;
956  $this->match(‪Lexer::T_INTEGER);
957 
958  if ($this->lexer->isNextToken(‪Lexer::T_COMMA)) {
959  $this->‪match(‪Lexer::T_COMMA);
960  $options['decimals'] = (int)$this->lexer->lookahead->value;
961  $this->match(‪Lexer::T_INTEGER);
962  }
963 
965 
966  return $options;
967  }
968 
974  private function ‪numericDataTypeOptions(): array
975  {
976  $options = ['unsigned' => false, 'zerofill' => false];
977 
978  if (!$this->lexer->isNextTokenAny([‪Lexer::T_UNSIGNED, ‪Lexer::T_ZEROFILL])) {
979  return $options;
980  }
981 
982  while ($this->lexer->isNextTokenAny([‪Lexer::T_UNSIGNED, ‪Lexer::T_ZEROFILL])) {
983  switch ($this->lexer->lookahead->type) {
986  $options['unsigned'] = true;
987  break;
990  $options['zerofill'] = true;
991  break;
992  default:
993  $this->‪syntaxError('USIGNED or ZEROFILL');
994  }
995  }
996 
997  return $options;
998  }
999 
1005  private function ‪fractionalSecondsPart(): int
1006  {
1007  $fractionalSecondsPart = $this->‪dataTypeLength();
1008  if ($fractionalSecondsPart < 0) {
1009  $this->‪semanticError('the fractional seconds part for TIME, DATETIME or TIMESTAMP columns must >= 0');
1010  }
1011  if ($fractionalSecondsPart > 6) {
1012  $this->‪semanticError('the fractional seconds part for TIME, DATETIME or TIMESTAMP columns must <= 6');
1013  }
1014  return $fractionalSecondsPart;
1015  }
1016 
1022  private function ‪characterDataTypeOptions(): array
1023  {
1024  $options = ['binary' => false, 'charset' => null, 'collation' => null];
1025 
1026  if (!$this->lexer->isNextTokenAny([‪Lexer::T_CHARACTER, ‪Lexer::T_COLLATE, ‪Lexer::T_BINARY])) {
1027  return $options;
1028  }
1029 
1030  while ($this->lexer->isNextTokenAny([‪Lexer::T_CHARACTER, ‪Lexer::T_COLLATE, ‪Lexer::T_BINARY])) {
1031  switch ($this->lexer->lookahead->type) {
1032  case ‪Lexer::T_BINARY:
1033  $this->‪match(‪Lexer::T_BINARY);
1034  $options['binary'] = true;
1035  break;
1036  case ‪Lexer::T_CHARACTER:
1038  $this->‪match(‪Lexer::T_SET);
1039  $this->‪match(‪Lexer::T_STRING);
1040  $options['charset'] = $this->lexer->token->value;
1041  break;
1042  case ‪Lexer::T_COLLATE:
1043  $this->‪match(‪Lexer::T_COLLATE);
1044  $this->‪match(‪Lexer::T_STRING);
1045  $options['collation'] = $this->lexer->token->value;
1046  break;
1047  default:
1048  $this->‪syntaxError('BINARY, CHARACTER SET or COLLATE');
1049  }
1050  }
1051 
1052  return $options;
1053  }
1054 
1060  private function ‪enumerationDataTypeOptions(): array
1061  {
1062  $options = ['charset' => null, 'collation' => null];
1063 
1064  if (!$this->lexer->isNextTokenAny([‪Lexer::T_CHARACTER, ‪Lexer::T_COLLATE])) {
1065  return $options;
1066  }
1067 
1068  while ($this->lexer->isNextTokenAny([‪Lexer::T_CHARACTER, ‪Lexer::T_COLLATE])) {
1069  switch ($this->lexer->lookahead->type) {
1070  case ‪Lexer::T_CHARACTER:
1072  $this->‪match(‪Lexer::T_SET);
1073  $this->‪match(‪Lexer::T_STRING);
1074  $options['charset'] = $this->lexer->token->value;
1075  break;
1076  case ‪Lexer::T_COLLATE:
1077  $this->‪match(‪Lexer::T_COLLATE);
1078  $this->‪match(‪Lexer::T_STRING);
1079  $options['collation'] = $this->lexer->token->value;
1080  break;
1081  default:
1082  $this->‪syntaxError('CHARACTER SET or COLLATE');
1083  }
1084  }
1085 
1086  return $options;
1087  }
1088 
1094  private function ‪valueList(): array
1095  {
1097 
1098  $values = [];
1099  $values[] = $this->‪valueListItem();
1100 
1101  while ($this->lexer->isNextToken(‪Lexer::T_COMMA)) {
1102  $this->‪match(‪Lexer::T_COMMA);
1103  $values[] = $this->‪valueListItem();
1104  }
1105 
1107 
1108  return $values;
1109  }
1110 
1116  private function ‪valueListItem(): string
1117  {
1118  $this->‪match(‪Lexer::T_STRING);
1119 
1120  return (string)$this->lexer->token->value;
1121  }
1122 
1132  {
1134  $tableName = $this->‪schemaObjectName();
1136 
1137  $referenceColumns = [];
1138  $referenceColumns[] = $this->‪indexColumnName();
1139 
1140  while ($this->lexer->isNextToken(‪Lexer::T_COMMA)) {
1141  $this->‪match(‪Lexer::T_COMMA);
1142  $referenceColumns[] = $this->‪indexColumnName();
1143  }
1144 
1146 
1147  $referenceDefinition = new ‪ReferenceDefinition($tableName, $referenceColumns);
1148 
1149  while (!$this->lexer->isNextTokenAny([‪Lexer::T_COMMA, ‪Lexer::T_CLOSE_PARENTHESIS])) {
1150  switch ($this->lexer->lookahead->type) {
1151  case ‪Lexer::T_MATCH:
1152  $this->‪match(‪Lexer::T_MATCH);
1153  $referenceDefinition->match = $this->lexer->lookahead->value;
1154  $this->lexer->moveNext();
1155  break;
1156  case ‪Lexer::T_ON:
1157  $this->‪match(‪Lexer::T_ON);
1158  if ($this->lexer->isNextToken(‪Lexer::T_DELETE)) {
1159  $this->‪match(‪Lexer::T_DELETE);
1160  $referenceDefinition->onDelete = $this->‪referenceOption();
1161  } else {
1162  $this->‪match(‪Lexer::T_UPDATE);
1163  $referenceDefinition->onUpdate = $this->‪referenceOption();
1164  }
1165  break;
1166  default:
1167  $this->‪syntaxError('MATCH, ON DELETE or ON UPDATE');
1168  }
1169  }
1170 
1171  return $referenceDefinition;
1172  }
1173 
1180  {
1181  $columnName = $this->‪schemaObjectName();
1182  $length = $this->‪dataTypeLength();
1183  $direction = null;
1184 
1185  if ($this->lexer->isNextToken(‪Lexer::T_ASC)) {
1186  $this->‪match(‪Lexer::T_ASC);
1187  $direction = 'ASC';
1188  } elseif ($this->lexer->isNextToken(‪Lexer::T_DESC)) {
1189  $this->‪match(‪Lexer::T_DESC);
1190  $direction = 'DESC';
1191  }
1192 
1193  return new ‪IndexColumnName($columnName, $length, $direction);
1194  }
1195 
1201  private function ‪referenceOption(): string
1202  {
1203  $action = null;
1204 
1205  switch ($this->lexer->lookahead->type) {
1206  case ‪Lexer::T_RESTRICT:
1208  $action = 'RESTRICT';
1209  break;
1210  case ‪Lexer::T_CASCADE:
1211  $this->‪match(‪Lexer::T_CASCADE);
1212  $action = 'CASCADE';
1213  break;
1214  case ‪Lexer::T_SET:
1215  $this->‪match(‪Lexer::T_SET);
1216  $this->‪match(‪Lexer::T_NULL);
1217  $action = 'SET NULL';
1218  break;
1219  case ‪Lexer::T_NO:
1220  $this->‪match(‪Lexer::T_NO);
1221  $this->‪match(‪Lexer::T_ACTION);
1222  $action = 'NO ACTION';
1223  break;
1224  default:
1225  $this->‪syntaxError('RESTRICT, CASCADE, SET NULL or NO ACTION');
1226  }
1227 
1228  return $action;
1229  }
1230 
1262  private function ‪tableOptions(): array
1263  {
1264  $options = [];
1265 
1266  while ($this->lexer->lookahead && !$this->lexer->isNextToken(‪Lexer::T_SEMICOLON)) {
1267  switch ($this->lexer->lookahead->type) {
1268  case ‪Lexer::T_DEFAULT:
1269  // DEFAULT prefix is optional for COLLATE/CHARACTER SET, do nothing
1270  $this->‪match(‪Lexer::T_DEFAULT);
1271  break;
1272  case ‪Lexer::T_ENGINE:
1273  $this->‪match(‪Lexer::T_ENGINE);
1274  $options['engine'] = (string)$this->‪tableOptionValue();
1275  break;
1278  $options['auto_increment'] = (int)$this->‪tableOptionValue();
1279  break;
1282  $options['average_row_length'] = (int)$this->‪tableOptionValue();
1283  break;
1284  case ‪Lexer::T_CHARACTER:
1286  $this->‪match(‪Lexer::T_SET);
1287  $options['character_set'] = (string)$this->‪tableOptionValue();
1288  break;
1289  case ‪Lexer::T_CHECKSUM:
1291  $options['checksum'] = (int)$this->‪tableOptionValue();
1292  break;
1293  case ‪Lexer::T_COLLATE:
1294  $this->‪match(‪Lexer::T_COLLATE);
1295  $options['collation'] = (string)$this->‪tableOptionValue();
1296  break;
1297  case ‪Lexer::T_COMMENT:
1298  $this->‪match(‪Lexer::T_COMMENT);
1299  $options['comment'] = (string)$this->‪tableOptionValue();
1300  break;
1303  $options['compression'] = strtoupper((string)$this->‪tableOptionValue());
1304  if (!in_array($options['compression'], ['ZLIB', 'LZ4', 'NONE'], true)) {
1305  $this->‪syntaxError('ZLIB, LZ4 or NONE', $this->lexer->token);
1306  }
1307  break;
1310  $options['connection'] = (string)$this->‪tableOptionValue();
1311  break;
1312  case ‪Lexer::T_DATA:
1313  $this->‪match(‪Lexer::T_DATA);
1315  $options['data_directory'] = (string)$this->‪tableOptionValue();
1316  break;
1319  $options['delay_key_write'] = (int)$this->‪tableOptionValue();
1320  break;
1323  $options['encryption'] = strtoupper((string)$this->‪tableOptionValue());
1324  if (!in_array($options['encryption'], ['Y', 'N'], true)) {
1325  $this->‪syntaxError('Y or N', $this->lexer->token);
1326  }
1327  break;
1328  case ‪Lexer::T_INDEX:
1329  $this->‪match(‪Lexer::T_INDEX);
1331  $options['index_directory'] = (string)$this->‪tableOptionValue();
1332  break;
1335  $options['insert_method'] = strtoupper((string)$this->‪tableOptionValue());
1336  if (!in_array($options['insert_method'], ['NO', 'FIRST', 'LAST'], true)) {
1337  $this->‪syntaxError('NO, FIRST or LAST', $this->lexer->token);
1338  }
1339  break;
1342  $options['key_block_size'] = (int)$this->‪tableOptionValue();
1343  break;
1344  case ‪Lexer::T_MAX_ROWS:
1346  $options['max_rows'] = (int)$this->‪tableOptionValue();
1347  break;
1348  case ‪Lexer::T_MIN_ROWS:
1350  $options['min_rows'] = (int)$this->‪tableOptionValue();
1351  break;
1352  case ‪Lexer::T_PACK_KEYS:
1354  $options['pack_keys'] = strtoupper((string)$this->‪tableOptionValue());
1355  if (!in_array($options['pack_keys'], ['0', '1', 'DEFAULT'], true)) {
1356  $this->‪syntaxError('0, 1 or DEFAULT', $this->lexer->token);
1357  }
1358  break;
1359  case ‪Lexer::T_PASSWORD:
1361  $options['password'] = (string)$this->‪tableOptionValue();
1362  break;
1365  $options['row_format'] = (string)$this->‪tableOptionValue();
1366  $validRowFormats = ['DEFAULT', 'DYNAMIC', 'FIXED', 'COMPRESSED', 'REDUNDANT', 'COMPACT'];
1367  if (!in_array($options['row_format'], $validRowFormats, true)) {
1368  $this->‪syntaxError(
1369  'DEFAULT, DYNAMIC, FIXED, COMPRESSED, REDUNDANT, COMPACT',
1370  $this->lexer->token
1371  );
1372  }
1373  break;
1376  $options['stats_auto_recalc'] = strtoupper((string)$this->‪tableOptionValue());
1377  if (!in_array($options['stats_auto_recalc'], ['0', '1', 'DEFAULT'], true)) {
1378  $this->‪syntaxError('0, 1 or DEFAULT', $this->lexer->token);
1379  }
1380  break;
1383  $options['stats_persistent'] = strtoupper((string)$this->‪tableOptionValue());
1384  if (!in_array($options['stats_persistent'], ['0', '1', 'DEFAULT'], true)) {
1385  $this->‪syntaxError('0, 1 or DEFAULT', $this->lexer->token);
1386  }
1387  break;
1390  $options['stats_sample_pages'] = strtoupper((string)$this->‪tableOptionValue());
1391  if (!in_array($options['stats_sample_pages'], ['0', '1', 'DEFAULT'], true)) {
1392  $this->‪syntaxError('0, 1 or DEFAULT', $this->lexer->token);
1393  }
1394  break;
1397  $options['tablespace'] = (string)$this->‪tableOptionValue();
1398  break;
1399  default:
1400  $this->‪syntaxError(
1401  'DEFAULT, ENGINE, AUTO_INCREMENT, AVG_ROW_LENGTH, CHARACTER SET, ' .
1402  'CHECKSUM, COLLATE, COMMENT, COMPRESSION, CONNECTION, DATA DIRECTORY, ' .
1403  'DELAY_KEY_WRITE, ENCRYPTION, INDEX DIRECTORY, INSERT_METHOD, KEY_BLOCK_SIZE, ' .
1404  'MAX_ROWS, MIN_ROWS, PACK_KEYS, PASSWORD, ROW_FORMAT, STATS_AUTO_RECALC, ' .
1405  'STATS_PERSISTENT, STATS_SAMPLE_PAGES or TABLESPACE'
1406  );
1407  }
1408  }
1409 
1410  return $options;
1411  }
1412 
1418  private function ‪tableOptionValue(): mixed
1419  {
1420  // Skip the optional equals sign
1421  if ($this->lexer->isNextToken(‪Lexer::T_EQUALS)) {
1422  $this->‪match(‪Lexer::T_EQUALS);
1423  }
1424  $this->lexer->moveNext();
1425  return $this->lexer->token->value;
1426  }
1427 
1433  {
1434  $schemaObjectName = $this->lexer->lookahead->value;
1435  $this->lexer->moveNext();
1436  return new ‪Identifier((string)$schemaObjectName);
1437  }
1438 }
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\CreateTableClause
Definition: CreateTableClause.php:28
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\dataTypeDecimals
‪dataTypeDecimals()
Definition: Parser.php:947
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\BigIntDataType
Definition: BigIntDataType.php:25
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TimeDataType
Definition: TimeDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\Identifier
Definition: Identifier.php:27
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\VarCharDataType
Definition: VarCharDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_NO
‪const T_NO
Definition: Lexer.php:126
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_CREATE
‪const T_CREATE
Definition: Lexer.php:85
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_KEY
‪const T_KEY
Definition: Lexer.php:93
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_SPATIAL
‪const T_SPATIAL
Definition: Lexer.php:95
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\DateTimeDataType
Definition: DateTimeDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\numericDataTypeOptions
‪numericDataTypeOptions()
Definition: Parser.php:974
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_PASSWORD
‪const T_PASSWORD
Definition: Lexer.php:148
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_FOREIGN
‪const T_FOREIGN
Definition: Lexer.php:134
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_BTREE
‪const T_BTREE
Definition: Lexer.php:129
‪TYPO3\CMS\Core\Database\Schema\Exception\StatementException
Definition: StatementException.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_USING
‪const T_USING
Definition: Lexer.php:128
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_ENUM
‪const T_ENUM
Definition: Lexer.php:80
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\BitDataType
Definition: BitDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Exception\StatementException\syntaxError
‪static syntaxError(string $message, \Exception $previous=null)
Definition: StatementException.php:36
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\JsonDataType
Definition: JsonDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_HASH
‪const T_HASH
Definition: Lexer.php:130
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DYNAMIC
‪const T_DYNAMIC
Definition: Lexer.php:107
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_SIMPLE
‪const T_SIMPLE
Definition: Lexer.php:120
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_NULL
‪const T_NULL
Definition: Lexer.php:105
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_CONNECTION
‪const T_CONNECTION
Definition: Lexer.php:139
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_INT
‪const T_INT
Definition: Lexer.php:55
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_TEMPORARY
‪const T_TEMPORARY
Definition: Lexer.php:86
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_STRING
‪const T_STRING
Definition: Lexer.php:29
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\CreateTableStatement
Definition: CreateTableStatement.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_ON
‪const T_ON
Definition: Lexer.php:121
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_INTEGER
‪const T_INTEGER
Definition: Lexer.php:56
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_TIME
‪const T_TIME
Definition: Lexer.php:64
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\createColumnDefinitionItem
‪createColumnDefinitionItem()
Definition: Parser.php:585
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\CreateColumnDefinitionItem
Definition: CreateColumnDefinitionItem.php:29
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_TIMESTAMP
‪const T_TIMESTAMP
Definition: Lexer.php:65
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\CreateIndexDefinitionItem
Definition: CreateIndexDefinitionItem.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\VarBinaryDataType
Definition: VarBinaryDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\indexName
‪indexName()
Definition: Parser.php:490
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_TABLE
‪const T_TABLE
Definition: Lexer.php:87
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_REAL
‪const T_REAL
Definition: Lexer.php:58
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\RealDataType
Definition: RealDataType.php:25
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_BINARY
‪const T_BINARY
Definition: Lexer.php:70
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_MEMORY
‪const T_MEMORY
Definition: Lexer.php:108
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\tableOptionValue
‪tableOptionValue()
Definition: Parser.php:1418
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_MIN_ROWS
‪const T_MIN_ROWS
Definition: Lexer.php:146
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\CreateDefinition
Definition: CreateDefinition.php:27
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_CHARACTER
‪const T_CHARACTER
Definition: Lexer.php:113
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TinyTextDataType
Definition: TinyTextDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\__construct
‪__construct(private readonly Lexer $lexer,)
Definition: Parser.php:79
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_VARCHAR
‪const T_VARCHAR
Definition: Lexer.php:69
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_REFERENCES
‪const T_REFERENCES
Definition: Lexer.php:104
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_PRECISION
‪const T_PRECISION
Definition: Lexer.php:155
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_TINYTEXT
‪const T_TINYTEXT
Definition: Lexer.php:76
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_STATS_SAMPLE_PAGES
‪const T_STATS_SAMPLE_PAGES
Definition: Lexer.php:152
‪TYPO3\CMS\Core\Database\Schema\Parser\TableBuilder
Definition: TableBuilder.php:73
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_FLOAT
‪const T_FLOAT
Definition: Lexer.php:60
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_SMALLINT
‪const T_SMALLINT
Definition: Lexer.php:53
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\CreateForeignKeyDefinitionItem
Definition: CreateForeignKeyDefinitionItem.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_ENGINE
‪const T_ENGINE
Definition: Lexer.php:135
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_SEMICOLON
‪const T_SEMICOLON
Definition: Lexer.php:45
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_UNIQUE
‪const T_UNIQUE
Definition: Lexer.php:97
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\dataTypeLength
‪dataTypeLength(bool $required=false)
Definition: Parser.php:924
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_CHAR
‪const T_CHAR
Definition: Lexer.php:68
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_FIXED
‪const T_FIXED
Definition: Lexer.php:106
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_PACK_KEYS
‪const T_PACK_KEYS
Definition: Lexer.php:147
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_COMMENT
‪const T_COMMENT
Definition: Lexer.php:101
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_JSON
‪const T_JSON
Definition: Lexer.php:82
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_COMMA
‪const T_COMMA
Definition: Lexer.php:33
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser
Definition: Parser.php:75
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\characterDataTypeOptions
‪characterDataTypeOptions()
Definition: Parser.php:1022
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_TINYINT
‪const T_TINYINT
Definition: Lexer.php:52
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\indexOptions
‪indexOptions()
Definition: Parser.php:537
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_CHECKSUM
‪const T_CHECKSUM
Definition: Lexer.php:137
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\indexType
‪indexType()
Definition: Parser.php:504
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TextDataType
Definition: TextDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_BIT
‪const T_BIT
Definition: Lexer.php:51
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\MediumTextDataType
Definition: MediumTextDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\schemaObjectName
‪schemaObjectName()
Definition: Parser.php:1432
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_FULL
‪const T_FULL
Definition: Lexer.php:118
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\columnDefaultValue
‪columnDefaultValue()
Definition: Parser.php:904
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_ZEROFILL
‪const T_ZEROFILL
Definition: Lexer.php:111
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_RESTRICT
‪const T_RESTRICT
Definition: Lexer.php:124
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_TINYBLOB
‪const T_TINYBLOB
Definition: Lexer.php:72
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TinyBlobDataType
Definition: TinyBlobDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_KEY_BLOCK_SIZE
‪const T_KEY_BLOCK_SIZE
Definition: Lexer.php:131
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DOUBLE
‪const T_DOUBLE
Definition: Lexer.php:59
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_TEXT
‪const T_TEXT
Definition: Lexer.php:77
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\getAST
‪getAST(string $statement)
Definition: Parser.php:109
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_OPEN_PARENTHESIS
‪const T_OPEN_PARENTHESIS
Definition: Lexer.php:32
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\CharDataType
Definition: CharDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_CLOSE_PARENTHESIS
‪const T_CLOSE_PARENTHESIS
Definition: Lexer.php:31
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DATA
‪const T_DATA
Definition: Lexer.php:140
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\SetDataType
Definition: SetDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_IF
‪const T_IF
Definition: Lexer.php:88
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_WITH
‪const T_WITH
Definition: Lexer.php:132
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\createDefinition
‪createDefinition()
Definition: Parser.php:288
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\IntegerDataType
Definition: IntegerDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DIRECTORY
‪const T_DIRECTORY
Definition: Lexer.php:141
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DECIMAL
‪const T_DECIMAL
Definition: Lexer.php:61
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_COLUMN_FORMAT
‪const T_COLUMN_FORMAT
Definition: Lexer.php:102
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_INDEX
‪const T_INDEX
Definition: Lexer.php:92
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\AbstractDataType
Definition: AbstractDataType.php:27
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_COMPRESSION
‪const T_COMPRESSION
Definition: Lexer.php:138
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DESC
‪const T_DESC
Definition: Lexer.php:116
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\LongTextDataType
Definition: LongTextDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DATE
‪const T_DATE
Definition: Lexer.php:63
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\$statement
‪string $statement
Definition: Parser.php:77
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\indexColumnName
‪indexColumnName()
Definition: Parser.php:1179
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\MediumIntDataType
Definition: MediumIntDataType.php:25
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\FloatDataType
Definition: FloatDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\AbstractCreateStatement
Definition: AbstractCreateStatement.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DELETE
‪const T_DELETE
Definition: Lexer.php:123
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\DoubleDataType
Definition: DoubleDataType.php:25
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\parse
‪list< Table > parse(string $statement)
Definition: Parser.php:92
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\MediumBlobDataType
Definition: MediumBlobDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\valueList
‪valueList()
Definition: Parser.php:1094
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TinyIntDataType
Definition: TinyIntDataType.php:25
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_PRIMARY
‪const T_PRIMARY
Definition: Lexer.php:96
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_MATCH
‪const T_MATCH
Definition: Lexer.php:117
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_BLOB
‪const T_BLOB
Definition: Lexer.php:73
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\BinaryDataType
Definition: BinaryDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\DecimalDataType
Definition: DecimalDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_LONGTEXT
‪const T_LONGTEXT
Definition: Lexer.php:79
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_MEDIUMBLOB
‪const T_MEDIUMBLOB
Definition: Lexer.php:74
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\IndexColumnName
Definition: IndexColumnName.php:28
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_PARTIAL
‪const T_PARTIAL
Definition: Lexer.php:119
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_ASC
‪const T_ASC
Definition: Lexer.php:115
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\valueListItem
‪valueListItem()
Definition: Parser.php:1116
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_NOT
‪const T_NOT
Definition: Lexer.php:89
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\AbstractCreateDefinitionItem
Definition: AbstractCreateDefinitionItem.php:24
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\BlobDataType
Definition: BlobDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DATETIME
‪const T_DATETIME
Definition: Lexer.php:66
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_SET
‪const T_SET
Definition: Lexer.php:81
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_IDENTIFIER
‪const T_IDENTIFIER
Definition: Lexer.php:48
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_ROW_FORMAT
‪const T_ROW_FORMAT
Definition: Lexer.php:149
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_COLLATE
‪const T_COLLATE
Definition: Lexer.php:114
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\createIndexDefinitionItem
‪createIndexDefinitionItem()
Definition: Parser.php:367
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_CHECK
‪const T_CHECK
Definition: Lexer.php:98
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\LongBlobDataType
Definition: LongBlobDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\referenceOption
‪referenceOption()
Definition: Parser.php:1201
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DEFAULT
‪const T_DEFAULT
Definition: Lexer.php:99
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\columnDataType
‪columnDataType()
Definition: Parser.php:710
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_YEAR
‪const T_YEAR
Definition: Lexer.php:67
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\DateDataType
Definition: DateDataType.php:25
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DISK
‪const T_DISK
Definition: Lexer.php:109
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_MEDIUMTEXT
‪const T_MEDIUMTEXT
Definition: Lexer.php:78
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_STATS_PERSISTENT
‪const T_STATS_PERSISTENT
Definition: Lexer.php:151
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_MEDIUMINT
‪const T_MEDIUMINT
Definition: Lexer.php:54
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_UPDATE
‪const T_UPDATE
Definition: Lexer.php:122
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\NumericDataType
Definition: NumericDataType.php:25
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\fractionalSecondsPart
‪fractionalSecondsPart()
Definition: Parser.php:1005
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\SmallIntDataType
Definition: SmallIntDataType.php:25
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_STATS_AUTO_RECALC
‪const T_STATS_AUTO_RECALC
Definition: Lexer.php:150
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\createForeignKeyDefinitionItem
‪createForeignKeyDefinitionItem()
Definition: Parser.php:458
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_STORAGE
‪const T_STORAGE
Definition: Lexer.php:103
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_ENCRYPTION
‪const T_ENCRYPTION
Definition: Lexer.php:143
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\createTableClause
‪createTableClause()
Definition: Parser.php:249
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_VARBINARY
‪const T_VARBINARY
Definition: Lexer.php:71
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\createDefinitionItem
‪createDefinitionItem()
Definition: Parser.php:328
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\tableOptions
‪tableOptions()
Definition: Parser.php:1262
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_CASCADE
‪const T_CASCADE
Definition: Lexer.php:125
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\EnumDataType
Definition: EnumDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\ReferenceDefinition
Definition: ReferenceDefinition.php:28
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_DELAY_KEY_WRITE
‪const T_DELAY_KEY_WRITE
Definition: Lexer.php:142
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_TABLESPACE
‪const T_TABLESPACE
Definition: Lexer.php:153
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_NUMERIC
‪const T_NUMERIC
Definition: Lexer.php:62
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_AVG_ROW_LENGTH
‪const T_AVG_ROW_LENGTH
Definition: Lexer.php:136
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\YearDataType
Definition: YearDataType.php:25
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_ACTION
‪const T_ACTION
Definition: Lexer.php:127
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\enumerationDataTypeOptions
‪enumerationDataTypeOptions()
Definition: Parser.php:1060
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_UNSIGNED
‪const T_UNSIGNED
Definition: Lexer.php:110
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\semanticError
‪semanticError(string $message='')
Definition: Parser.php:190
‪TYPO3\CMS\Core\Database\Schema\Exception\StatementException\sqlError
‪static sqlError(string $sql)
Definition: StatementException.php:28
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_EQUALS
‪const T_EQUALS
Definition: Lexer.php:36
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_INSERT_METHOD
‪const T_INSERT_METHOD
Definition: Lexer.php:144
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_FULLTEXT
‪const T_FULLTEXT
Definition: Lexer.php:94
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\createStatement
‪createStatement()
Definition: Parser.php:219
‪TYPO3\CMS\Core\Database\Schema\Parser\AST\DataType\TimestampDataType
Definition: TimestampDataType.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_AUTO_INCREMENT
‪const T_AUTO_INCREMENT
Definition: Lexer.php:100
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_BIGINT
‪const T_BIGINT
Definition: Lexer.php:57
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_MAX_ROWS
‪const T_MAX_ROWS
Definition: Lexer.php:145
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\syntaxError
‪syntaxError(string $expected='', ?Token $token=null)
Definition: Parser.php:170
‪TYPO3\CMS\Core\Database\Schema\Exception\StatementException\semanticError
‪static semanticError(string $message, \Exception $previous=null)
Definition: StatementException.php:44
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_EXISTS
‪const T_EXISTS
Definition: Lexer.php:90
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_CURRENT_TIMESTAMP
‪const T_CURRENT_TIMESTAMP
Definition: Lexer.php:112
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\referenceDefinition
‪referenceDefinition()
Definition: Parser.php:1131
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer
Definition: Lexer.php:26
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\createTableStatement
‪createTableStatement()
Definition: Parser.php:235
‪TYPO3\CMS\Core\Database\Schema\Parser\Parser\match
‪match(int $token)
Definition: Parser.php:135
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_PARSER
‪const T_PARSER
Definition: Lexer.php:133
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_LONGBLOB
‪const T_LONGBLOB
Definition: Lexer.php:75
‪TYPO3\CMS\Core\Database\Schema\Parser\Lexer\T_CONSTRAINT
‪const T_CONSTRAINT
Definition: Lexer.php:91