public function convertSqlToJob(SQLTokenIterator $tokens) { // catch both cases when select is current AND when its next token. $tokens->seekTokenNum(SqlToken::T_SELECT()); if ($tokens->getCurrentTokenNumber() !== SqlToken::T_SELECT()) { throw new ErrorException("Tried to convert select-sql to job when sql-token-iterator does not point to T_SELECT!"); } $entitySelect = new SelectStatement(); ### SPECIAL FLAGS foreach ([[SpecialFlags::FLAG_ALL(), SqlToken::T_ALL()], [SpecialFlags::FLAG_DISTINCT(), SqlToken::T_DISTINCT()], [SpecialFlags::FLAG_DISTINCTROW(), SqlToken::T_DISTINCTROW()], [SpecialFlags::FLAG_HIGH_PRIORITY(), SqlToken::T_HIGH_PRIORITY()], [SpecialFlags::FLAG_STRAIGHT_JOIN(), SqlToken::T_STRAIGHT_JOIN()], [SpecialFlags::FLAG_SQL_SMALL_RESULT(), SqlToken::T_SQL_SMALL_RESULT()], [SpecialFlags::FLAG_SQL_BIG_RESULT(), SqlToken::T_SQL_BIG_RESULT()], [SpecialFlags::FLAG_SQL_BUFFER_RESULT(), SqlToken::T_SQL_BUFFER_RESULT()], [SpecialFlags::FLAG_SQL_CACHE(), SqlToken::T_SQL_CACHE()], [SpecialFlags::FLAG_SQL_NO_CACHE(), SqlToken::T_SQL_NO_CACHE()], [SpecialFlags::FLAG_SQL_CALC_FOUND_ROWS(), SqlToken::T_SQL_CALC_FOUND_ROWS()]] as $pair) { list($flagValue, $tokenNum) = $pair; if ($tokens->seekTokenNum($tokenNum)) { $entitySelect->addFlag($flagValue); } } ### COLLECT COLUMNS do { try { switch (true) { # parse jokers like: fooTable.* case is_int($tokens->isTokenText('*', TokenIterator::NEXT, [T_STRING, '.'])): if ($this->tableParser->canParseTokens($tokens)) { $tableFilter = $this->tableParser->convertSqlToJob($tokens); } else { $tableFilter = null; } $tokens->seekTokenText('*', TokenIterator::NEXT, [T_STRING, '.']); $entitySelect->addColumnAllTable($tableFilter); break; case $this->valueParser->canParseTokens($tokens): $value = $this->valueParser->convertSqlToJob($tokens); if ($tokens->seekTokenNum(T_STRING, TokenIterator::NEXT, [SqlToken::T_AS()])) { $entitySelect->addColumnValue($value, $tokens->getCurrentTokenString()); } else { $entitySelect->addColumnValue($value); } break; default: throw new MalformedSqlException("Non-column-sql found in column-part of select!", $tokens); } } catch (MalformedSqlException $exception) { throw new MalformedSqlException($exception->getMessage(), $tokens); } } while ($tokens->seekTokenText(',')); ### COLLECT TABLES if ($tokens->seekTokenNum(SqlToken::T_FROM())) { if (!$this->joinParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid join definition after FROM in SELECT statement!", $tokens); } $entitySelect->setJoinDefinition($this->joinParser->convertSqlToJob($tokens)); } ### PREPENDED CONDITION (WHERE) if ($tokens->seekTokenNum(SqlToken::T_WHERE())) { if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing condition for WHERE clause in SELECT statement!", $tokens); } $entitySelect->setCondition($this->valueParser->convertSqlToJob($tokens)); } ### GROUP if ($tokens->seekTokenNum(SqlToken::T_GROUP())) { if (!$tokens->seekTokenNum(SqlToken::T_BY())) { throw new MalformedSqlException("Missing BY after GROUP in SELECT statement!", $tokens); } do { $groupingDefinition = new GroupingDefinition(); if (!$this->columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Invalid grouping value in SELECT statement!!", $tokens); } $groupingDefinition->setValue($this->columnParser->convertSqlToJob($tokens)); if ($tokens->seekTokenNum(SqlToken::T_DESC())) { $groupingDefinition->setDirection(SqlToken::T_DESC()); } elseif ($tokens->seekTokenNum(SqlToken::T_ASC())) { $groupingDefinition->setDirection(SqlToken::T_ASC()); } $entitySelect->addGrouping($groupingDefinition); } while ($tokens->seekTokenText(',')); } ### APPENDED CONDITION (HAVING) if ($tokens->seekTokenNum(SqlToken::T_HAVING())) { if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing condition for WHERE clause in SELECT statement!", $tokens); } $condition = new ConditionJob(); $condition->setFirstParameter($this->valueParser->convertSqlToJob($tokens)); $entitySelect->setResultFilter($condition); } ### ORDER if ($tokens->seekTokenNum(SqlToken::T_ORDER())) { if (!$tokens->seekTokenNum(SqlToken::T_BY())) { throw new MalformedSqlException("Missing BY after ORDER on SELECT statement!", $tokens); } do { if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing value for ORDER BY part on SELECT statement!", $tokens); } $orderValue = $this->valueParser->convertSqlToJob($tokens); if ($tokens->seekTokenNum(SqlToken::T_DESC())) { $entitySelect->addOrderColumn($orderValue, SqlToken::T_DESC()); } else { $tokens->seekTokenNum(SqlToken::T_ASC()); $entitySelect->addOrderColumn($orderValue, SqlToken::T_ASC()); } } while ($tokens->seekTokenText(',')); } ### LIMIT if ($tokens->seekTokenNum(SqlToken::T_LIMIT())) { if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing offset number for LIMIT part in SELECT statement!", $tokens); } $entitySelect->setLimitOffset((int) $tokens->getCurrentTokenString()); if ($tokens->seekTokenText(',')) { if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing length number for LIMIT part in SELECT statement!", $tokens); } $entitySelect->setLimitRowCount((int) $tokens->getCurrentTokenString()); } } ### PROCEDURE if ($tokens->seekTokenNum(SqlToken::T_PROCEDURE())) { if (!$functionParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid procedure specifier after PROCEDURE!", $tokens); } $entitySelect->setProcedure($functionParser->convertSqlToJob($tokens)); } ### INTO OUTFILE|DUMPFILE if ($tokens->seekTokenNum(SqlToken::T_INTO())) { if (!$tokens->seekTokenNum(SqlToken::T_OUTFILE()) && !$tokens->seekTokenNum(SqlToken::T_DUMPFILE())) { throw new MalformedSqlException("Missing OUTFILE or DUMPFILE after INTO!", $tokens); } if (!$tokens->seekTokenNum(T_CONSTANT_ENCAPSED_STRING)) { throw new MalformedSqlException("Missing escaped string after INTO OUTFILE!"); } $entitySelect->setIntoOutFile($tokens->seekTokenText($searchToken)); } ### FOR UPDATE if ($tokens->seekTokenNum(SqlToken::T_FOR())) { if (!$tokens->seekTokenNum(SqlToken::T_UPDATE())) { throw new MalformedSqlException("Missing UPDATE after FOR on FOR UPDATE parameter in SELECT statement!", $tokens); } $entitySelect->setIsForUpdate(true); } ### LOCK IN SHARE MODE if ($tokens->seekTokenNum(SqlToken::T_LOCK())) { if (!$tokens->seekTokenNum(SqlToken::T_IN())) { throw new MalformedSqlException("Missing UPDATE after FOR on FOR UPDATE parameter in SELECT statement!", $tokens); } if (!$tokens->seekTokenNum(SqlToken::T_SHARE())) { throw new MalformedSqlException("Missing UPDATE after FOR on FOR UPDATE parameter in SELECT statement!", $tokens); } if (!$tokens->seekTokenNum(SqlToken::T_MODE())) { throw new MalformedSqlException("Missing UPDATE after FOR on FOR UPDATE parameter in SELECT statement!", $tokens); } $entitySelect->setIsLockInShareMode(true); } ### UNION if ($tokens->seekTokenNum(SqlToken::T_UNION())) { $isUnionAll = $tokens->seekTokenNum(SqlToken::T_ALL()); $isUnionDistinct = $tokens->seekTokenNum(SqlToken::T_DISTINCT()); $isUnionAll = $isUnionAll || $tokens->seekTokenNum(SqlToken::T_ALL()); if ($isUnionAll && $isUnionDistinct) { throw new MalformedSqlException("UNION cannot be ALL and DISTINCT at the same time!", $tokens); } $isUnionInParenthesis = $tokens->seekTokenText('('); if (!$this->canParseTokens($tokens)) { throw new MalformedSqlException("Missing following SELECT statement after UNION in SELECT statement!", $tokens); } $entitySelect->setUnionSelect($this->convertSqlToJob($tokens), $isUnionDistinct); if ($isUnionInParenthesis && !$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing ending parenthesis after UNION in SELECT statement!", $tokens); } } return $entitySelect; }
public function convertSqlToJob(SQLTokenIterator $tokens, $from = TokenIterator::NEXT) { if (!$tokens->seekTokenText('(', $from)) { throw new ErrorException("Tried to parse sql-parenthesis when token-iterator does not point to paranthesis ('(' sign)!"); } /* @var $parenthesis ParenthesisPart */ $parenthesis = new ParenthesisPart(); switch (true) { case $this->selectParser->canParseTokens($tokens): $parenthesis->setContain($this->selectParser->convertSqlToJob($tokens)); break; case $this->valueParser->canParseTokens($tokens): $parenthesis->setContain($this->valueParser->convertSqlToJob($tokens)); break; } if (!$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing ')' at the end of a parenthesis!", $tokens); } if ($tokens->seekTokenNum(T_STRING, TokenIterator::NEXT, [SqlToken::T_AS()])) { $parenthesis->setAlias($tokens->getCurrentTokenString()); } if ($parenthesis->getContain() instanceof Select && $tokens->isTokenNum(SqlToken::T_UNION())) { $unionSelect = new Select(); while ($tokens->seekTokenNum(SqlToken::T_UNION())) { /* @var $lastUnionedSelect Select */ $lastUnionedSelect = $parenthesis->getContain(); while (!is_null($lastUnionedSelect->getUnionSelect())) { $lastUnionedSelect = $lastUnionedSelect->getUnionSelect(); } $isUnionAll = $tokens->seekTokenNum(SqlToken::T_ALL()); $isUnionDistinct = $tokens->seekTokenNum(SqlToken::T_DISTINCT()); $isUnionAll = $isUnionAll || $tokens->seekTokenNum(SqlToken::T_ALL()); if ($isUnionAll && $isUnionDistinct) { throw new MalformedSqlException("UNION cannot be ALL and DISTINCT at the same time!", $tokens); } $isUnionInParenthesis = $tokens->seekTokenText('('); if (!$this->selectParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing following SELECT statement after UNION in SELECT statement!", $tokens); } $lastUnionedSelect->setUnionSelect($this->selectParser->convertSqlToJob($tokens), $isUnionDistinct); if ($isUnionInParenthesis && !$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing ending parenthesis after UNION in SELECT statement!", $tokens); } } $unionSelect->setUnionSelect($parenthesis->getContain()); ### APPENDED CONDITION (HAVING) if ($tokens->seekTokenNum(SqlToken::T_HAVING())) { if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing condition for WHERE clause in SELECT statement!", $tokens); } $condition = new Condition(); $condition->setFirstParameter($this->valueParser->convertSqlToJob($tokens)); $unionSelect->setResultFilter($condition); } ### ORDER if ($tokens->seekTokenNum(SqlToken::T_ORDER())) { if (!$tokens->seekTokenNum(SqlToken::T_BY())) { throw new MalformedSqlException("Missing BY after ORDER on SELECT statement!", $tokens); } do { if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing value for ORDER BY part on SELECT statement!", $tokens); } $orderValue = $this->valueParser->convertSqlToJob($tokens); if ($tokens->seekTokenNum(SqlToken::T_DESC())) { $unionSelect->addOrderColumn($orderValue, SqlToken::T_DESC()); } else { $tokens->seekTokenNum(SqlToken::T_ASC()); $unionSelect->addOrderColumn($orderValue, SqlToken::T_ASC()); } } while ($tokens->seekTokenText(',')); } ### LIMIT if ($tokens->seekTokenNum(SqlToken::T_LIMIT())) { if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing offset number for LIMIT part in SELECT statement!", $tokens); } $unionSelect->setLimitOffset((int) $tokens->getCurrentTokenString()); if ($tokens->seekTokenText(',')) { if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing length number for LIMIT part in SELECT statement!", $tokens); } $unionSelect->setLimitRowCount((int) $tokens->getCurrentTokenString()); } } $parenthesis->setContain($unionSelect); } return $parenthesis; }
/** * This parses a CREATE TABLE statement. * * @param SQLTokenIterator $tokens * @throws MalformedSql */ protected function parseCreateTable(SQLTokenIterator $tokens) { $createTableJob = new CreateTableStatement(); $createTableJob->setIsTemporaryTable(is_int($tokens->isTokenNum(SqlToken::T_TEMPORARY(), TokenIterator::PREVIOUS))); # [IF NOT EXISTS]: if ($tokens->seekTokenNum(SqlToken::T_IF())) { if (!$tokens->seekTokenNum(SqlToken::T_NOT()) || !$tokens->seekTokenNum(SqlToken::T_EXISTS())) { throw new MalformedSqlException("Invalid create-database statement (invalid 'IF NOT EXISTS')!", $tokens); } $createTableJob->setIfNotExists(true); } else { $createTableJob->setIfNotExists(false); } # NAME if ($tokens->seekTokenNum(T_STRING)) { $createTableJob->setName($tokens->getCurrentTokenString()); } elseif ($this->valueParser->canParseTokens($tokens)) { $createTableJob->setName($this->valueParser->convertSqlToJob($tokens)); } else { throw new MalformedSqlException("Missing name of table to create!", $tokens); } # COLUMN DEFINITION $checkEndParenthesis = $tokens->seekTokenText('('); # LIKE other table? if ($tokens->seekTokenNum(SqlToken::T_LIKE())) { if (!$this->tableParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid table-specifier for 'CREATE TABLE LIKE' statement!", $tokens); } $createTableJob->setLikeTable($this->tableParser->convertSqlToJob($tokens)); } elseif ($this->selectParser->canParseTokens($tokens)) { $createTableJob->setFromSelectStatement($this->selectParser->convertSqlToJob($tokens)); # normal column definition } else { do { switch (true) { # normal column definition case $this->columnDefinitonParser->canParseTokens($tokens): $createTableJob->addColumnDefinition($this->columnDefinitonParser->convertSqlToJob($tokens)); break; # [CONSTRAINT [$keyName]] PRIMARY KEY [$keyType] ($column[, $column, ...]) # [CONSTRAINT [$keyName]] PRIMARY KEY [$keyType] ($column[, $column, ...]) case $tokens->seekTokenNum(SqlToken::T_PRIMARY(), TokenIterator::NEXT, [T_STRING, SqlToken::T_CONSTRAINT()]): $indexJob = new IndexPart(); $indexJob->setIsPrimary(true); if ($tokens->isTokenNum(SqlToken::T_CONSTRAINT(), TokenIterator::PREVIOUS, [T_STRING]) && $tokens->seekTokenNum(T_STRING, TokenIterator::PREVIOUS)) { $indexJob->setContraintSymbol($tokens->getPreviousTokenString()); $tokens->seekTokenNum(SqlToken::T_PRIMARY()); } $indexJob->setName("PRIMARY"); if (!$tokens->seekTokenNum(SqlToken::T_KEY())) { throw new MalformedSqlException("Missing T_KEY for PRIMARY KEY constraint in create-table statement!", $tokens); } # define index type (BTREE, HASH, ...) if ($tokens->seekTokenNum(T_STRING)) { $indexJob->setType(IndexType::factory($tokens->getCurrentTokenString())); } else { $indexJob->setType(IndexType::BTREE()); } # columns in index if ($tokens->seekTokenText('(')) { do { if (!$this->columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Invalid column in column-list for defining index!", $tokens); } $indexJob->addColumn($this->columnParser->convertSqlToJob($tokens)); } while ($tokens->seekTokenText(',')); if (!$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing closing parenthesis at column-list for index!", $tokens); } } $createTableJob->addIndex($indexJob); break; # KEY|INDEX [index_name] [index_type] (index_col_name,...) # KEY|INDEX [index_name] [index_type] (index_col_name,...) case $tokens->seekTokenNum(SqlToken::T_INDEX()): case $tokens->seekTokenNUm(SqlToken::T_KEY()): /* @var $indexJob IndexPart */ $indexJob = new IndexPart(); if ($tokens->seekTokenNum(T_STRING)) { $indexJob->setName($tokens->getCurrentTokenString()); } else { $indexJob->setName(null); # first column name is used } # define index type (BTREE, HASH, ...) if ($tokens->seekTokenNum(T_STRING)) { $indexJob->setType(IndexType::factory($tokens->getCurrentTokenString())); } else { $indexJob->setType(IndexType::BTREE()); } # columns in index if ($tokens->seekTokenText('(')) { do { if (!$this->columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Invalid column in column-list for defining index!", $tokens); } $indexJob->addColumn($this->columnParser->convertSqlToJob($tokens)); } while ($tokens->seekTokenText(',')); if (!$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing closing parenthesis at column-list for index!", $tokens); } } $createTableJob->addIndex($indexJob); break; # [CONSTRAINT [symbol]] UNIQUE|FULLTEXT|SPATIAL [INDEX] [index_name] [index_type] (index_col_name,...) # [CONSTRAINT [symbol]] UNIQUE|FULLTEXT|SPATIAL [INDEX] [index_name] [index_type] (index_col_name,...) case $tokens->seekTokenNum(SqlToken::T_UNIQUE(), TokenIterator::NEXT, [SqlToken::T_CONSTRAINT(), T_STRING]): case $tokens->seekTokenNum(SqlToken::T_FULLTEXT(), TokenIterator::NEXT, [SqlToken::T_CONSTRAINT(), T_STRING]): case $tokens->seekTokenNum(SqlToken::T_SPATIAL(), TokenIterator::NEXT, [SqlToken::T_CONSTRAINT(), T_STRING]): /* @var $indexJob IndexPart */ $indexJob = new IndexPart(); switch ($tokens->getCurrentTokenNumber()) { case SqlToken::T_UNIQUE(): $indexJob->setIsUnique(true); break; case SqlToken::T_FULLTEXT(): $indexJob->setIsFullText(true); break; case SqlToken::T_SPATIAL(): $indexJob->setIsSpatial(true); break; } if ($tokens->isTokenNum(SqlToken::T_CONSTRAINT(), TokenIterator::PREVIOUS, [T_STRING]) && $tokens->seekTokenNum(T_STRING, TokenIterator::PREVIOUS)) { $indexJob->setContraintSymbol($tokens->getPreviousTokenString()); $tokens->seekTokenNum(SqlToken::T_PRIMARY()); } $tokens->seekTokenNum(SqlToken::T_KEY()); $tokens->seekTokenNum(SqlToken::T_INDEX()); if ($tokens->seekTokenNum(T_STRING)) { $indexJob->setName($tokens->getCurrentTokenString()); } else { $indexJob->setName(null); # first column name is used } # define index type (BTREE, HASH, ...) if ($tokens->seekTokenNum(T_STRING)) { $indexJob->setType(IndexType::factory($tokens->getCurrentTokenString())); } else { $indexJob->setType(IndexType::BTREE()); } # columns in index if ($tokens->seekTokenText('(')) { do { if (!$this->columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Invalid column in column-list for defining index!", $tokens); } $indexJob->addColumn($this->columnParser->convertSqlToJob($tokens)); } while ($tokens->seekTokenText(',')); if (!$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing closing parenthesis at column-list for index!", $tokens); } } $createTableJob->addIndex($indexJob); break; # [CONSTRAINT [$symbol]] FOREIGN KEY [$name] ($column[, $column, ...]) [$reference] # [CONSTRAINT [$symbol]] FOREIGN KEY [$name] ($column[, $column, ...]) [$reference] case $tokens->seekTokenNum(SqlToken::T_FOREIGN(), TokenIterator::NEXT, [T_STRING, SqlToken::T_CONSTRAINT()]): /* @var $indexJob IndexPart */ $indexJob = new IndexPart(); if ($tokens->isTokenNum(SqlToken::T_CONSTRAINT(), TokenIterator::PREVIOUS, [T_STRING]) && $tokens->seekTokenNum(T_STRING, TokenIterator::PREVIOUS)) { $indexJob->setContraintSymbol($tokens->getCurrentTokenString()); $tokens->seekTokenNum(SqlToken::T_FOREIGN()); } if (!$tokens->seekTokenNum(SqlToken::T_KEY())) { throw new MalformedSqlException("Missing T_KEY after T_FOREIGN in constraint-definition!", $tokens); } if ($tokens->seekTokenNum(T_STRING)) { $indexJob->setName($tokens->getCurrentTokenString()); } else { $indexJob->setName(null); # first column name is used } # columns in index if ($tokens->seekTokenText('(')) { do { if (!$this->columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Invalid column in column-list for defining index!", $tokens); } $indexJob->addColumn($this->columnParser->convertSqlToJob($tokens)); } while ($tokens->seekTokenText(',')); if (!$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing closing parenthesis at column-list for index!", $tokens); } } if (!$tokens->seekTokenNum(SqlToken::T_REFERENCES())) { throw new MalformedSqlException("Missing reference-definition in foreign-constraint-definition!", $tokens); } if (!$this->tableParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing table-definition in foreign-constraint-definition!", $tokens); } $fkTable = $this->tableParser->convertSqlToJob($tokens); # columns in index if ($tokens->seekTokenText('(')) { do { if (!$this->columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Invalid column in column-list for defining index!", $tokens); } $fkColumn = $this->columnParser->convertSqlToJob($tokens); $fkColumn = ColumnSpecifier::factory($fkTable . '.' . $fkColumn->getColumn()); $indexJob->addForeignKey($fkColumn); } while ($tokens->seekTokenText(',')); if (!$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing closing parenthesis at column-list for index!", $tokens); } } if ($tokens->seekTokenNum(SqlToken::T_MATCH())) { switch (true) { case $tokens->seekTokenNum(SqlToken::T_FULL()): $indexJob->setForeignKeyMatchType(MatchType::FULL()); break; case $tokens->seekTokenNum(SqlToken::T_PARTIAL()): $indexJob->setForeignKeyMatchType(MatchType::PARTIAL()); break; case $tokens->seekTokenNum(SqlToken::T_SIMPLE()): $indexJob->setForeignKeyMatchType(MatchType::SIMPLE()); break; default: throw new MalformedSqlException("Invalid match parameter for foreign key!", $tokens); } } while ($tokens->seekTokenNum(SqlToken::T_ON())) { switch (true) { case $tokens->seekTokenNum(SqlToken::T_DELETE()): switch (true) { case $tokens->seekTokenNum(SqlToken::T_RESTRICT()): $option = ReferenceOption::RESTRICT(); break; case $tokens->seekTokenNum(SqlToken::T_CASCADE()): $option = ReferenceOption::CASCADE(); break; case $tokens->seekTokenNum(SqlToken::T_SET()) && $tokens->seekTokenNum(SqlToken::T_NULL()): $option = ReferenceOption::SET_NULL(); break; case $tokens->seekTokenNum(SqlToken::T_NO()) && $tokens->seekTokenText("ACTION"): $option = ReferenceOption::NO_ACTION(); break; default: throw new MalformedSqlException("Invalid reference-option for foreign key ON DELETE option!", $tokens); } $indexJob->setForeignKeyOnDeleteReferenceOption($option); break; case $tokens->seekTokenNum(SqlToken::T_UPDATE()): switch (true) { case $tokens->seekTokenNum(SqlToken::T_RESTRICT()): $option = ReferenceOption::RESTRICT(); break; case $tokens->seekTokenNum(SqlToken::T_CASCADE()): $option = ReferenceOption::CASCADE(); break; case $tokens->seekTokenNum(SqlToken::T_SET()) && $tokens->seekTokenNum(SqlToken::T_NULL()): $option = ReferenceOption::SET_NULL(); break; case $tokens->seekTokenNum(SqlToken::T_NO()) && $tokens->seekTokenText("ACTION"): $option = ReferenceOption::NO_ACTION(); break; default: throw new MalformedSqlException("Invalid reference-option for foreign key ON UPDATE option!", $tokens); } $indexJob->setForeignKeyOnUpdateReferenceOption($option); break; default: throw new MalformedSqlException("Invalid ON event for foreign key (allowed are UPDATE and DELETE)!", $tokens); } } $createTableJob->addIndex($indexJob); break; # CHECK (expression) # CHECK (expression) case $tokens->seekTokenNum(SqlToken::T_CHECK()): if (!$this->conditionParser->canParseTokens($tokens)) { throw new MalformedSqlException("Invalid CHECK condition statement!", $tokens); } $createTableJob->addCheck($this->conditionParser->convertSqlToJob($tokens)); break; default: throw new MalformedSqlException("Invalid definition in CREATE TABLE statement!", $tokens); } } while ($tokens->seekTokenText(',')); } if ($checkEndParenthesis && !$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing closing parenthesis at end of table-definition!", $tokens); } ### TABLE OPTIONS while (true) { switch (true) { case $tokens->seekTokenNum(SqlToken::T_ENGINE()): case $tokens->seekTokenNum(SqlToken::T_TYPE()): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(T_STRING)) { throw new MalformedSqlException("Missing T_STRING after T_ENGINE!", $tokens); } $createTableJob->setEngine(Engine::factory($tokens->getCurrentTokenString())); break; case $tokens->seekTokenNum(SqlToken::T_AUTO_INCREMENT()): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing number-string for T_AUTO_INCREMENT!", $tokens); } $createTableJob->setAutoIncrement((int) $tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_AVG_ROW_LENGTH()): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing number-string for T_AVG_ROW_LENGTH!", $tokens); } $createTableJob->setAverageRowLength((int) $tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_CHARACTER(), TokenIterator::NEXT, [SqlToken::T_DEFAULT()]): if (!$tokens->seekTokenNum(SqlToken::T_SET())) { throw new MalformedSqlException("Missing SET after CHARACTER keyword!", $tokens); } case $tokens->seekTokenNum(SqlToken::T_CHARSET(), TokenIterator::NEXT, [SqlToken::T_DEFAULT()]): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(T_CONSTANT_ENCAPSED_STRING) && !$tokens->seekTokenNum(T_STRING)) { throw new MalformedSqlException("Missing string for CHARACTER SET!", $tokens); } $createTableJob->setCharacterSet($tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_COLLATE()): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(T_CONSTANT_ENCAPSED_STRING) && !$tokens->seekTokenNum(T_STRING)) { throw new MalformedSqlException("Missing string for COLLATE!", $tokens); } $createTableJob->setCollate($tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_CHECKSUM()): $tokens->seekTokenText('='); switch (true) { case $tokens->seekTokenText('0'): $createTableJob->setUseChecksum(false); break; case $tokens->seekTokenText('1'): $createTableJob->setUseChecksum(true); break; default: throw new MalformedSqlException("Invalid value for CHECKSUM! (only 0 or 1 allowed!)", $tokens); } break; case $tokens->seekTokenNum(SqlToken::T_COMMENT()): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(T_CONSTANT_ENCAPSED_STRING)) { throw new MalformedSqlException("Missing encapsed string for comment!", $tokens); } $createTableJob->setComment($tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_CONNECTION()): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(T_CONSTANT_ENCAPSED_STRING)) { throw new MalformedSqlException("Missing encapsed string for connection-string!", $tokens); } $createTableJob->setConnectString($tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_MAX_ROWS()): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing number-string for MAX_ROWS!", $tokens); } $createTableJob->setMaximumRows((int) $tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_MIN_ROWS()): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing number-string for MIN_ROWS!", $tokens); } $createTableJob->setMinimumRows((int) $tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_PACK_KEYS()): $tokens->seekTokenText('='); switch (true) { case $tokens->seekTokenText('DEFAULT'): case $tokens->seekTokenText('0'): $createTableJob->setDelayKeyWrite(false); break; case $tokens->seekTokenText('1'): $createTableJob->setDelayKeyWrite(true); break; default: throw new MalformedSqlException("Invalid value for PACK_KEYS! (only DEFAULT, 0 or 1 allowed!)", $tokens); } break; case $tokens->seekTokenNum(SqlToken::T_PASSWORD()): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(T_CONSTANT_ENCAPSED_STRING)) { throw new MalformedSqlException("Missing encapsed string for password!", $tokens); } $createTableJob->setPassword($tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_DELAY_KEY_WRITE()): $tokens->seekTokenText('='); switch (true) { case $tokens->seekTokenText('0'): $createTableJob->setDelayKeyWrite(false); break; case $tokens->seekTokenText('1'): $createTableJob->setDelayKeyWrite(true); break; default: throw new MalformedSqlException("Invalid value for DELAY_KEY_WRITE! (only 0 or 1 allowed!)", $tokens); } break; case $tokens->seekTokenNum(SqlToken::T_ROW_FORMAT()): $tokens->seekTokenText('='); $keyword = $tokens->getExclusiveTokenString(); $rowFormat = RowFormat::factory($keyword); $tokens->seekIndex($tokens->getExclusiveTokenIndex()); $createTableJob->setRowFormat($rowFormat); break; case $tokens->seekTokenNum(SqlToken::T_UNION()): $tokens->seekTokenText('='); if (!$tokens->seekTokenText('(')) { throw new MalformedSqlException("Missing opening parenthesis for union-table-definition!", $tokens); } do { if (!$this->tableParser->canParseTokens($tokens)) { throw new MalformedSqlException("Invalid table in table-list for defining union tables!", $tokens); } $createTableJob->addUnionTable($this->tableParser->convertSqlToJob($tokens)); } while ($tokens->seekTokenText(',')); if (!$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing closing parenthesis at union-table-list!", $tokens); } break; case $tokens->seekTokenNum(SqlToken::T_INSERT_METHOD()): $tokens->seekTokenText('='); switch (true) { case $tokens->seekTokenNum(SqlToken::T_NO()): $createTableJob->setInsertMethod(InsertMethod::NO()); break; case $tokens->seekTokenNum(SqlToken::T_FIRST()): $createTableJob->setInsertMethod(InsertMethod::FIRST()); break; case $tokens->seekTokenNum(SqlToken::T_LAST()): $createTableJob->setInsertMethod(InsertMethod::LAST()); break; default: throw new MalformedSqlException("Invalid value given for insert-method (allowed are NO, FIRST and LAST)!"); } break; case $tokens->seekTokenNum(SqlToken::T_DATA()): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(SqlToken::T_DIRECTORY())) { throw new MalformedSqlException("Missing T_DIRECTORY after T_DATA for data-directory!", $tokens); } if (!$tokens->seekTokenNum(T_CONSTANT_ENCAPSED_STRING)) { throw new MalformedSqlException("Missing encapsed string for comment!", $tokens); } $createTableJob->setDataDirectory($tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_INDEX()): $tokens->seekTokenText('='); if (!$tokens->seekTokenNum(SqlToken::T_DIRECTORY())) { throw new MalformedSqlException("Missing T_DIRECTORY after T_INDEX for index-directory!", $tokens); } if (!$tokens->seekTokenNum(T_CONSTANT_ENCAPSED_STRING)) { throw new MalformedSqlException("Missing encapsed string for comment!", $tokens); } $createTableJob->setIndexDirectory($tokens->getCurrentTokenString()); break; default: break 2; } } return $createTableJob; }