Ejemplo n.º 1
0
 public function convertSqlToJob(SQLTokenIterator $tokens)
 {
     $tokens->seekTokenNum(SqlToken::T_DROP());
     if ($tokens->getCurrentTokenNumber() !== SqlToken::T_DROP()) {
         throw new ErrorException("Tried to parse sql-drop when token-iterator does not point to T_DROP!");
     }
     $dropJob = new DropStatement();
     if ($tokens->seekTokenNum(SqlToken::T_TEMPORARY())) {
         $dropJob->setIsTemporary(true);
     }
     switch (true) {
         case $tokens->seekTokenNum(SqlToken::T_SCHEMA(), TokenIterator::NEXT):
         case $tokens->seekTokenNum(SqlToken::T_DATABASE()):
             $dropJob->setType(DropStatement::TYPE_DATABASE);
             break;
         case $tokens->seekTokenNum(SqlToken::T_TABLE()):
             $dropJob->setType(DropStatement::TYPE_TABLE);
             break;
         case $tokens->seekTokenNum(SqlToken::T_VIEW()):
             $dropJob->setType(DropStatement::TYPE_VIEW);
             break;
     }
     if ($tokens->seekTokenNum(SqlToken::T_IF())) {
         if (!$tokens->seekTokenNum(SqlToken::T_EXISTS())) {
             throw new MalformedSqlException("Malformed drop-statement (missing T_EXISTS after T_IF)!");
         }
         $dropJob->setOnlyIfExist(true);
     } else {
         $dropJob->setOnlyIfExist(false);
     }
     do {
         if (!$this->valueParser->canParseTokens($tokens)) {
             throw new MalformedSqlException("Missing a subject to drop for T_DROP statement!", $tokens);
         }
         $subject = $this->valueParser->convertSqlToJob($tokens);
         $dropJob->addSubject($subject);
     } while ($tokens->seekTokenText(','));
     if ($tokens->seekTokenNum(SqlToken::T_RESTRICT())) {
         $dropJob->setReferenceOption(ReferenceOption::RESTRICT());
         if ($tokens->seekTokenNum(SqlToken::T_CASCADE())) {
             throw new MalformedSqlException("Conflicting T_RESTRICT with T_CASCADE!", $tokens);
         }
     }
     if ($tokens->seekTokenNum(SqlToken::T_CASCADE())) {
         $dropJob->setReferenceOption(ReferenceOption::CASCADE());
         if ($tokens->seekTokenNum(SqlToken::T_RESTRICT())) {
             throw new MalformedSqlException("Conflicting T_RESTRICT with T_CASCADE!", $tokens);
         }
     }
     return $dropJob;
 }
Ejemplo n.º 2
0
 public function convertSqlToJob(SQLTokenIterator $tokens)
 {
     $alterJob = new AlterStatement();
     $tokens->seekTokenNum(SqlToken::T_ALTER());
     if ($tokens->getCurrentTokenNumber() !== SqlToken::T_ALTER()) {
         throw new ErrorException("Tried to parse an ALTER statement when token-iterator does not point to T_ALTER!");
     }
     $alterJob->setDoIgnoreErrors($tokens->seekTokenNum(SqlToken::T_IGNORE()));
     if (!$tokens->seekTokenNum(SqlToken::T_TABLE())) {
         throw new MalformedSqlException("Missing TABLE for ALTER statement!", $tokens);
     }
     if (!$this->tableParser->canParseTokens($tokens)) {
         throw new MalformedSqlException("Missing Table-Specifier for ALTER TABLE statement!");
     }
     $alterJob->setTable($this->tableParser->convertSqlToJob($tokens));
     $dataChange = new AlterTableDataChange();
     do {
         switch (true) {
             case $tokens->seekTokenNum(SqlToken::T_ADD()):
                 $isInParenthesises = $tokens->seekTokenText('(');
                 do {
                     switch (true) {
                         case $tokens->seekTokenNum(SqlToken::T_COLUMN()):
                             if ($tokens->seekTokenText('(')) {
                                 do {
                                     if (!$this->columnDefinitionParser->canParseTokens($tokens)) {
                                         throw new MalformedSqlException("Missing column definition after ALTER TABLE ADD COLUMN!", $tokens);
                                     }
                                     $dataChange->setAttribute(AlterAttributeType::ADD());
                                     $dataChange->setSubjectColumnDefinition($this->columnDefinitionParser->convertSqlToJob($tokens));
                                     $alterJob->addDataChange(clone $dataChange);
                                 } while ($tokens->seekTokenText(','));
                                 if (!$tokens->seekTokenText(')')) {
                                     throw new MalformedSqlException("Missing ending parenthesis after column list", $tokens);
                                 }
                             } else {
                                 if (!$this->columnDefinitionParser->canParseTokens($tokens)) {
                                     throw new MalformedSqlException("Missing column definition after ALTER TABLE ADD COLUMN!", $tokens);
                                 }
                                 $dataChange->setAttribute(AlterAttributeType::ADD());
                                 $dataChange->setSubjectColumnDefinition($this->columnDefinitionParser->convertSqlToJob($tokens));
                                 $alterJob->addDataChange(clone $dataChange);
                             }
                             break;
                         case $this->columnDefinitionParser->canParseTokens($tokens):
                             $dataChange->setAttribute(AlterAttributeType::ADD());
                             $dataChange->setSubjectColumnDefinition($this->columnDefinitionParser->convertSqlToJob($tokens));
                             $alterJob->addDataChange(clone $dataChange);
                             break;
                         case $tokens->seekTokenNum(SqlToken::T_PRIMARY(), TokenIterator::NEXT, [SqlToken::T_CONSTRAINT(), T_STRING]):
                         case $tokens->seekTokenNum(SqlToken::T_UNIQUE(), TokenIterator::NEXT, [SqlToken::T_CONSTRAINT(), T_STRING]):
                         case $tokens->seekTokenNum(SqlToken::T_FOREIGN(), TokenIterator::NEXT, [SqlToken::T_CONSTRAINT(), T_STRING]):
                         case $tokens->seekTokenNum(SqlToken::T_FULLTEXT()):
                         case $tokens->seekTokenNum(SqlToken::T_SPATIAL()):
                         case $tokens->seekTokenNum(SqlToken::T_INDEX()):
                             $indexJob = new IndexJob();
                             if ($tokens->isTokenNum(SqlToken::T_CONSTRAINT(), TokenIterator::PREVIOUS)) {
                                 $beforeIndex = $tokens->getIndex();
                                 if (!$tokens->seekTokenNum(T_STRING, TokenIterator::PREVIOUS)) {
                                     throw new MalformedSqlException("Missing constraing-symbol T_STRING after T_CONSTRAINT!", $tokens);
                                 }
                                 $indexJob->setContraintSymbol($tokens->getCurrentTokenString());
                                 $tokens->seekIndex($beforeIndex);
                             }
                             $needsReferenceDefinition = false;
                             switch ($tokens->getCurrentTokenNumber()) {
                                 case SqlToken::T_PRIMARY():
                                     $indexJob->setIsPrimary(true);
                                     $indexJob->setName("PRIMARY");
                                     if (!$tokens->seekTokenNum(SqlToken::T_KEY())) {
                                         throw new MalformedSqlException("Missing T_KEY after T_FOREIGN!", $tokens);
                                     }
                                     break;
                                 case SqlToken::T_UNIQUE():
                                     $indexJob->setIsUnique(true);
                                     $tokens->seekTokenNum(SqlToken::T_INDEX());
                                     break;
                                 case SqlToken::T_FOREIGN():
                                     if (!$tokens->seekTokenNum(SqlToken::T_KEY())) {
                                         throw new MalformedSqlException("Missing T_KEY after T_FOREIGN!", $tokens);
                                     }
                                     $needsReferenceDefinition = true;
                                     break;
                                 case SqlToken::T_FULLTEXT():
                                     $indexJob->setIsFullText(true);
                                     break;
                                 case SqlToken::T_SPATIAL():
                                     $indexJob->setIsSpatial(true);
                                     break;
                             }
                             if (!$indexJob->getIsPrimary() && $tokens->seekTokenNum(T_STRING)) {
                                 $indexJob->setName($tokens->getCurrentTokenString());
                             }
                             if ($tokens->seekTokenNum(T_STRING)) {
                                 $indexJob->setType(IndexType::factory(strtoupper($tokens->getCurrentTokenString())));
                             }
                             if (!$tokens->seekTokenText('(')) {
                                 throw new MalformedSqlException("Missing beginning parenthesis for defining columns for PRIMARY KEY index!", $tokens);
                             }
                             do {
                                 if (!$this->columnParser->canParseTokens($tokens)) {
                                     throw new MalformedSqlException("Invalid column-specifier in defining columns for PRIMARY KEY index!", $tokens);
                                 }
                                 $indexJob->addColumn($this->columnParser->convertSqlToJob($tokens));
                             } while ($tokens->seekTokenText(','));
                             if (!$tokens->seekTokenText(')')) {
                                 throw new MalformedSqlException("Missing ending parenthesis for defining columns for PRIMARY KEY index!", $tokens);
                             }
                             if ($needsReferenceDefinition) {
                                 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);
                                         $indexJob->addForeignKey(Column::factory("{$fkTable}.{$fkColumn->getColumn()}"));
                                     } 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()):
                                                     $indexJob->setForeignKeyOnDeleteReferenceOption(ReferenceOption::RESTRICT());
                                                     break;
                                                 case $tokens->seekTokenNum(SqlToken::T_CASCADE()):
                                                     $indexJob->setForeignKeyOnDeleteReferenceOption(ReferenceOption::CASCADE());
                                                     break;
                                                 case $tokens->seekTokenNum(SqlToken::T_SET()) && $tokens->seekTokenNum(SqlToken::T_NULL()):
                                                     $indexJob->setForeignKeyOnDeleteReferenceOption(ReferenceOption::SET_NULL());
                                                     break;
                                                 case $tokens->seekTokenNum(SqlToken::T_NO()) && $tokens->seekTokenText('ACTION'):
                                                     $indexJob->setForeignKeyOnDeleteReferenceOption(ReferenceOption::NO_ACTION());
                                                     break;
                                                 default:
                                                     throw new MalformedSqlException("Invalid reference-option for foreign key ON DELETE option!", $tokens);
                                             }
                                             break;
                                         case $tokens->seekTokenNum(SqlToken::T_UPDATE()):
                                             switch (true) {
                                                 case $tokens->seekTokenNum(SqlToken::T_RESTRICT()):
                                                     $indexJob->setForeignKeyOnUpdateReferenceOption(ReferenceOption::RESTRICT());
                                                     break;
                                                 case $tokens->seekTokenNum(SqlToken::T_CASCADE()):
                                                     $indexJob->setForeignKeyOnUpdateReferenceOption(ReferenceOption::CASCADE());
                                                     break;
                                                 case $tokens->seekTokenNum(SqlToken::T_SET()) && $tokens->seekTokenNum(SqlToken::T_NULL()):
                                                     $indexJob->setForeignKeyOnUpdateReferenceOption(ReferenceOption::SET_NULL());
                                                     break;
                                                 case $tokens->seekTokenNum(SqlToken::T_NO()) && $tokens->seekTokenText('ACTION'):
                                                     $indexJob->setForeignKeyOnUpdateReferenceOption(ReferenceOption::NO_ACTION());
                                                     break;
                                                 default:
                                                     throw new MalformedSqlException("Invalid reference-option for foreign key ON UPDATE option!", $tokens);
                                             }
                                             break;
                                         default:
                                             throw new MalformedSqlException("Invalid ON event for foreign key (allowed are UPDATE and DELETE)!", $tokens);
                                     }
                                 }
                             }
                             $dataChange->setAttribute(AlterAttributeType::ADD());
                             $dataChange->setSubjectIndex($indexJob);
                             $alterJob->addDataChange(clone $dataChange);
                             break;
                     }
                 } while ($isInParenthesises && $tokens->seekTokenText(','));
                 if ($isInParenthesises && !$tokens->seekTokenText(')')) {
                     throw new MalformedSqlException("Missing closing parenthesis after ALTER ADD statement!", $tokens);
                 }
                 break;
             case $tokens->seekTokenNum(SqlToken::T_ALTER()):
                 $tokens->seekTokenNum(SqlToken::T_COLUMN());
                 if (!$this->columnParser->canParseTokens($tokens)) {
                     throw new MalformedSqlException("Missing column-specification for ALTER COLUMN statement!", $tokens);
                 }
                 $dataChange->setAttribute(AlterAttributeType::DEFAULT_VALUE());
                 $dataChange->setSubject($this->columnParser->convertSqlToJob($tokens));
                 switch (true) {
                     case $tokens->seekTokenNum(SqlToken::T_SET()):
                         if (!$tokens->seekTokenNum(SqlToken::T_DEFAULT())) {
                             throw new MalformedSqlException("Missing T_DEFAULT for ALTER TABLE ALTER COLUMN SET DEFAULT statement", $tokens);
                         }
                         if (!$this->valueParser->canParseTokens($tokens)) {
                             throw new MalformedSqlException("Missing new valid value for DEFAULT value!");
                         }
                         $dataChange->setValue($this->valueParser->convertSqlToJob($tokens));
                         break;
                     case $tokens->seekTokenNum(SqlToken::T_DROP()):
                         if (!$tokens->seekTokenNum(SqlToken::T_DEFAULT())) {
                             throw new MalformedSqlException("Missing T_DEFAULT for ALTER TABLE ALTER COLUMN SET DEFAULT statement", $tokens);
                         }
                         $dataChange->setValue(null);
                         break;
                     default:
                         throw new MalformedSqlException("Invalid action (SET or DROP) for ALTER TABLE ALTER COLUMN statement!", $tokens);
                 }
                 $alterJob->addDataChange(clone $dataChange);
                 break;
             case $tokens->seekTokenNum(SqlToken::T_CHANGE()):
                 $dataChange->setAttribute(AlterAttributeType::MODIFY());
                 $tokens->seekTokenNum(SqlToken::T_COLUMN());
                 if (!$this->columnParser->canParseTokens($tokens)) {
                     throw new MalformedSqlException("Missing column-specification for ALTER TABLE CHANGE COLUMN statement!", $tokens);
                 }
                 $dataChange->setSubject($this->columnParser->convertSqlToJob($tokens));
                 if (!$this->columnDefinitionParser->canParseTokens($tokens)) {
                     throw new MalformedSqlException("Missing valid column-definiton for ALTER TABLE CHANGE COLUMN statement!", $tokens);
                 }
                 $dataChange->setValue($this->columnDefinitionParser->convertSqlToJob($tokens));
                 switch (true) {
                     case $tokens->seekTokenNum(SqlToken::T_FIRST()):
                         $dataChange->setAttribute(AlterAttributeType::SET_FIRST());
                         break;
                     case $tokens->seekTokenNum(SqlToken::T_AFTER()):
                         $dataChange->setAttribute(AlterAttributeType::SET_AFTER());
                         if (!$this->columnParser->canParseTokens($tokens)) {
                             throw new MalformedSqlException("Missing column specifier for ALTER TABLE CHANGE COLUMN AFTER statement!", $tokens);
                         }
                         $dataChange->setValue($this->columnParser->convertSqlToJob($tokens));
                         break;
                 }
                 $alterJob->addDataChange(clone $dataChange);
                 break;
             case $tokens->seekTokenNum(SqlToken::T_MODIFY()):
                 $dataChange->setAttribute(AlterAttributeType::MODIFY());
                 $tokens->seekTokenNum(SqlToken::T_COLUMN());
                 if (!$this->columnDefinitionParser->canParseTokens($tokens)) {
                     throw new MalformedSqlException("Missing valid column definition for ALTER TABLE MODIFY COLUMN statement!", $tokens);
                 }
                 $dataChange->setSubjectColumnDefinition($this->columnDefinitionParser->convertSqlToJob($tokens));
                 switch (true) {
                     case $tokens->seekTokenNum(SqlToken::T_FIRST()):
                         $dataChange->setAttribute(AlterAttributeType::SET_FIRST());
                         break;
                     case $tokens->seekTokenNum(SqlToken::T_AFTER()):
                         $dataChange->setAttribute(AlterAttributeType::SET_AFTER());
                         if (!$this->columnParser->canParseTokens($tokens)) {
                             throw new MalformedSqlException("Missing column specifier for ALTER TABLE MODIFY COLUMN AFTER statement!", $tokens);
                         }
                         $dataChange->setValue($this->columnParser->convertSqlToJob($tokens));
                         break;
                 }
                 $alterJob->addDataChange(clone $dataChange);
                 break;
             case $tokens->seekTokenNum(SqlToken::T_DROP()):
                 $dataChange->setAttribute(AlterAttributeType::DROP());
                 switch (true) {
                     case $tokens->seekTokenNum(SqlToken::T_COLUMN()):
                         if (!$this->columnParser->canParseTokens($tokens)) {
                             throw new MalformedSqlException("Missing valid column specificator for ALTER TABLE DROP COLUMN statement!", $tokens);
                         }
                         $dataChange->setSubject($this->columnParser->convertSqlToJob($tokens));
                         break;
                     case $this->columnParser->canParseTokens($tokens):
                         $dataChange->setSubject($this->columnParser->convertSqlToJob($tokens));
                         break;
                     case $tokens->seekTokenNum(SqlToken::T_PRIMARY()):
                         if (!$tokens->seekTokenNum(SqlToken::T_KEY())) {
                             throw new MalformedSqlException("Missing T_KEY after T_PRIMARY for ALTER TABLE DROP PRIMARY KEY statement!");
                         }
                         $dataChange->setSubject(Index::factory("PRIMARY"));
                         break;
                     case $tokens->seekTokenNum(SqlToken::T_FOREIGN()):
                         if (!$tokens->seekTokenNum(SqlToken::T_KEY())) {
                             throw new MalformedSqlException("Missing T_KEY after T_FOREIGN for ALTER TABLE DROP FOREIGN KEY statement!", $tokens);
                         }
                     case $tokens->seekTokenNum(SqlToken::T_INDEX()):
                         if (!$tokens->seekTokenNum(T_STRING)) {
                             throw new MalformedSqlException("Missing index name for ALTER TABLE DROP INDEX statement!", $tokens);
                         }
                         $dataChange->setSubject(Index::factory($tokens->getCurrentTokenString()));
                         break;
                 }
                 $alterJob->addDataChange(clone $dataChange);
                 break;
             case $tokens->seekTokenNum(SqlToken::T_DISABLE()):
                 $alterJob->setAction(Action::DISABLE());
                 if (!$tokens->seekTokenText(SqlToken::T_KEYS())) {
                     throw new MalformedSqlException("Missing T_KEYS after T_DISABLE!", $tokens);
                 }
                 break;
             case $tokens->seekTokenNum(SqlToken::T_ENABLE()):
                 $alterJob->setAction(Action::ENABLE());
                 if (!$tokens->seekTokenText(SqlToken::T_KEYS())) {
                     throw new MalformedSqlException("Missing T_KEYS after T_DISABLE!", $tokens);
                 }
                 break;
             case $tokens->seekTokenNum(SqlToken::T_RENAME()):
                 if (!$tokens->seekTokenNum(SqlToken::T_TO())) {
                     throw new MalformedSqlException("Missing T_TO after T_RENAME for ALTER TABLE RENAME TO statement!", $tokens);
                 }
                 if (!$tokens->seekTokenNum(T_STRING)) {
                     throw new MalformedSqlException("Missing new table-name for ALTER TABLE RENAME TO statement!", $tokens);
                 }
                 $dataChange->setAttribute(AlterAttributeType::RENAME());
                 $dataChange->setValue($tokens->getCurrentTokenString());
                 $alterJob->addDataChange(clone $dataChange);
                 break;
             case $tokens->seekTokenNum(SqlToken::T_ORDER()):
                 if (!$tokens->seekTokenNum(SqlToken::T_BY())) {
                     throw new MalformedSqlException("Missing BY after ORDER in ALTER TABLE ORDER BY statement!", $tokens);
                 }
                 if (!$this->columnParser->canParseTokens($tokens)) {
                     throw new MalformedSqlException("Missing column specifier for ALTER TABLE ORDER BY statement!", $tokens);
                 }
                 $dataChange->setSubject($this->columnParser->convertSqlToJob($tokens));
                 switch (true) {
                     case $tokens->seekTokenNum(SqlToken::T_DESC()):
                         $dataChange->setAttribute(AlterAttributeType::ORDER_BY_DESC());
                         break;
                     default:
                     case $tokens->seekTokenNum(SqlToken::T_ASC()):
                         $dataChange->setAttribute(AlterAttributeType::ORDER_BY_ASC());
                         break;
                 }
                 break;
             case $tokens->seekTokenNum(SqlToken::T_CHARACTER(), TokenIterator::NEXT, [SqlToken::T_DEFAULT()]):
             case $tokens->seekTokenNum(SqlToken::T_CHARACTER(), TokenIterator::NEXT, [SqlToken::T_CONVERT(), SqlToken::T_TO()]):
                 if (!$tokens->seekTokenNum(SqlToken::T_SET())) {
                     throw new MalformedSqlException("Missing T_SET after T_CHARACTER for ALTER TABLE CONVERT TO CHARACTER SET statement!", $tokens);
                 }
                 if (!$tokens->seekTokenNum(T_STRING)) {
                     throw new MalformedSqlException("Missing character-set specifier for ALTER TABLE CONVERT TO CHARACTER SET statement!", $tokens);
                 }
                 $dataChange->setAttribute(AlterAttributeType::CHARACTER_SET());
                 $dataChange->setValue($tokens->getCurrentTokenString());
                 $alterJob->addDataChange(clone $dataChange);
                 if ($tokens->seekTokenNum(SqlToken::T_COLLATE())) {
                     if (!$tokens->seekTokenNum(T_STRING)) {
                         throw new MalformedSqlException("Missing collation-specifier for ALTER TABLE CONVERT TO CHARACTER SET COLLATE statement!", $tokens);
                     }
                     $dataChange->setAttribute(AlterAttributeType::COLLATE());
                     $dataChange->setValue($tokens->getCurrentTokenString());
                     $alterJob->addDataChange(clone $dataChange);
                 }
                 break;
             case $tokens->seekTokenNum(SqlToken::T_DISCARD()):
             case $tokens->seekTokenNum(SqlToken::T_IMPORT()):
                 if (!$tokens->seekTokenNum(SqlToken::T_TABLESPACE())) {
                     throw new MalformedSqlException("Missing T_TABLESPACE after T_DISCARD or T_IMPORT!", $tokens);
                 }
                 break;
         }
     } while ($tokens->seekTokenText(','));
     return $alterJob;
 }