public function convertSqlToJob(SQLTokenIterator $tokens, &$checkFlags = 0) { if (!$tokens->seekTokenNum(SqlToken::T_IN(), TokenIterator::NEXT, [SqlToken::T_NOT()])) { throw new ErrorException("Missing IN after string when tried to parse IN-condition! (was 'canParseTokens' not used?)"); } $enumConditionJob = new EnumConditionJob(); $enumConditionJob->setIsNegated($tokens->isTokenNum(SqlToken::T_NOT(), TokenIterator::PREVIOUS)); if (!$tokens->seekTokenText('(')) { throw new MalformedSqlException("Missing beginning parenthesis for IN condition!", $tokens); } do { if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid value in value-listing for IN condition!", $tokens); } $enumConditionJob->addValue($this->valueParser->convertSqlToJob($tokens)); } while ($tokens->seekTokenText(',')); if (!$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing ending parenthesis for IN condition!", $tokens); } return $enumConditionJob; }
public function convertSqlToJob(SQLTokenIterator $tokens) { $parts = array(); do { $tokens->seekIndex($tokens->getExclusiveTokenIndex()); $part = $tokens->getCurrentTokenString(); if ($part[0] === '`' && $part[strlen($part) - 1] === '`') { $part = substr($part, 1, strlen($part) - 2); } $parts[] = $part; } while ($tokens->seekTokenText(".") && !$tokens->isTokenText('*')); return TableSpecifier::factory(implode(".", $parts)); }
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; }
public function convertSqlToJob(SQLTokenIterator $tokens) { $parts = array(); do { if (!$tokens->seekTokenNum(T_STRING)) { throw new ErrorException("Tried to convert sql-database-specifier when token-iterator does not point to T_STRING!"); } $part = $tokens->getCurrentTokenString(); if ($part[0] === '`' && $part[strlen($part) - 1] === '`') { $part = substr($part, 1, strlen($part) - 2); } $parts[] = $part; } while ($tokens->seekTokenText(".")); $specifier = DatabaseSpecifier::factory(implode(".", $parts)); return $specifier; }
public function convertSqlToJob(SQLTokenIterator $tokens) { $tokens->seekTokenNum(SqlToken::T_SET()); if ($tokens->getCurrentTokenNumber() !== SqlToken::T_SET()) { throw new ErrorException("Tried to parse SET statement when token-iterator is not at T_SET!"); } $setJob = new SetStatement(); if (!$tokens->seekTokenNum(T_STRING)) { throw new MalformedSqlException("Missing configuration name for SET statement!", $tokens); } $setJob->setKey($tokens->getCurrentTokenString()); $tokens->seekTokenText('='); if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid value definition for SET statement!", $tokens); } $setJob->setValue($this->valueParser->convertSqlToJob($tokens)); return $setJob; }
public function convertSqlToJob(SQLTokenIterator $tokens) { if (get_class($this) !== __CLASS__) { throw new ErrorException("Class '" . get_class($this) . "' needs to declare an own method '" . __FUNCTION__ . "'!"); } if (!$this->wasInitialized) { $this->initSqlSubParsers(); } /* @var $jobEntity Job */ $jobEntities = array(); # $tokens->seekIndex(-1); do { while ($tokens->seekTokenText(';')) { } $parserFound = false; foreach ($this->sqlParser as $sqlParser) { /* @var $sqlParser SqlParser */ if ($sqlParser->canParseTokens($tokens)) { $parserFound = true; $jobEntity = $sqlParser->convertSqlToJob($tokens); while ($jobEntity instanceof ParenthesisPart) { $jobEntity = $jobEntity->getContain(); } $jobEntities[] = $jobEntity; break; } } if (!$parserFound) { if (is_null($tokens->getExclusiveTokenNumber()) || $tokens->isAtEnd()) { break; } else { $relevantToken = $tokens->getExclusiveTokenString(); throw new MalformedSqlException("Invalid SQL-statement! (Cannot extract command: '{$relevantToken}')", $tokens); } } } while ($tokens->isTokenText(';')); if (!$tokens->isAtEnd() && $tokens->getExclusiveTokenIndex() !== $tokens->getIndex()) { throw new MalformedSqlException("Overlapping unparsed SQL at the end of statement!", $tokens); } foreach ($jobEntities as $job) { $job->checkPlausibility(); } return $jobEntities; }
public function convertSqlToJob(SQLTokenIterator $tokens) { $parts = array(); do { if ($tokens->seekTokenNum(T_VARIABLE)) { $part = Variable::factory($tokens->getCurrentTokenString()); } elseif ($tokens->seekTokens([T_STRING, T_CONSTANT_ENCAPSED_STRING])) { $part = $tokens->getCurrentTokenString(); if ($part[0] === '`' && $part[strlen($part) - 1] === '`') { $part = substr($part, 1, strlen($part) - 2); } elseif ($part[0] === '"' && $part[strlen($part) - 1] === '"') { $part = substr($part, 1, strlen($part) - 2); } elseif ($part[0] === "'" && $part[strlen($part) - 1] === "'") { $part = substr($part, 1, strlen($part) - 2); } } else { throw new ErrorException("Tried to convert sql-column-specifier when token-iterator does not point to T_STRING!"); } $parts[] = $part; } while ($tokens->seekTokenText(".")); $specifier = ColumnSpecifier::factory(implode(".", $parts)); return $specifier; }
public function convertSqlToJob(SQLTokenIterator $tokens) { $columnDefinition = new ColumnDefinitionJob(); $tokens->seekTokens([T_STRING, T_CONSTANT_ENCAPSED_STRING]); if (!$tokens->isTokens([T_STRING, T_CONSTANT_ENCAPSED_STRING], TokenIterator::CURRENT)) { throw new MalformedSqlException("Missing name for column!", $tokens); } $name = $tokens->getCurrentTokenString(); if ($name[0] === '`' && $name[strlen($name) - 1] === '`') { $name = substr($name, 1, strlen($name) - 2); } if ($name[0] === '"' && $name[strlen($name) - 1] === '"') { $name = substr($name, 1, strlen($name) - 2); } if ($name[0] === "'" && $name[strlen($name) - 1] === "'") { $name = substr($name, 1, strlen($name) - 2); } $columnDefinition->setName($name); # this makes sure that the next token is valid data-type $dataTypeString = strtoupper($tokens->getExclusiveTokenString()); $dataType = DataType::factory($dataTypeString); $columnDefinition->setDataType($dataType); $tokens->seekIndex($tokens->getExclusiveTokenIndex()); # data-type-length if ($tokens->seekTokenText('(')) { if ($dataType === DataType::ENUM() || $dataType === DataType::SET()) { do { if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Invalid value in ENUM!", $tokens); } $columnDefinition->addEnumValue($this->valueParser->convertSqlToJob($tokens)); } while ($tokens->seekTokenText(',')); } else { if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing number for length of data-type!", $tokens); } $columnDefinition->setDataTypeLength((int) $tokens->getCurrentTokenString()); if ($tokens->seekTokenText(',')) { if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing second number for length of data-type!", $tokens); } $columnDefinition->setDataTypeSecondLength((int) $tokens->getCurrentTokenString()); } } if (!$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing end-parenthesis for length of data-type!", $tokens); } } while (true) { switch (true) { case $tokens->seekTokenNum(SqlToken::T_NOT()): if (!$tokens->seekTokenNum(SqlToken::T_NULL())) { throw new MalformedSqlException("Missing T_NULL after T_NOT in column-definition!", $tokens); } $columnDefinition->setIsNullable(false); break; case $tokens->seekTokenNum(SqlToken::T_NULL()): $columnDefinition->setIsNullable(true); break; case $tokens->seekTokenNum(SqlToken::T_DEFAULT()): if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid default value for column definition!", $tokens); } $beforeIndex = $tokens->getIndex(); $defaultValue = $this->valueParser->convertSqlToJob($tokens); $afterIndex = $tokens->getIndex(); $defaultSqlRepresentation = ""; for ($index = $beforeIndex + 1; $index <= $afterIndex; $index++) { $defaultSqlRepresentation .= $tokens->getTokenArray()[$index][1]; } $columnDefinition->setDefaultValue($defaultValue); break; case $tokens->seekTokenNum(SqlToken::T_UNIQUE()): $tokens->seekTokenNum(SqlToken::T_KEY()); $columnDefinition->setIsUnique(true); break; case $tokens->seekTokenNum(SqlToken::T_PRIMARY()): $tokens->seekTokenNum(SqlToken::T_KEY()); $columnDefinition->setIsPrimaryKey(true); break; case $tokens->seekTokenNum(SqlToken::T_UNSIGNED()): $columnDefinition->setIsUnsigned(true); break; case $tokens->seekTokenNum(SqlToken::T_COMMENT()): if (!$tokens->seekTokenNum(T_CONSTANT_ENCAPSED_STRING)) { throw new MalformedSqlException("Missing encapsed string for comment-declaration column-definition!", $tokens); } $columnDefinition->setComment($tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_AUTO_INCREMENT()): $columnDefinition->setAutoIncrement(true); 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); } $columnDefinition->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); } $columnDefinition->setCollate($tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(SqlToken::T_ON()): switch (true) { case $tokens->seekTokenNum(SqlToken::T_UPDATE()): switch (true) { case $this->valueParser->canParseTokens($tokens): $columnDefinition->setOnUpdate($this->valueParser->convertSqlToJob($tokens)); break; default: throw new MalformedSqlException("Invalid value for ON UPDATE!", $tokens); } break; case $tokens->seekTokenNum(SqlToken::T_DELETE()): switch (true) { case $this->valueParser->canParseTokens($tokens): $columnDefinition->setOnDelete($this->valueParser->convertSqlToJob($tokens)); break; default: throw new MalformedSqlException("Invalid value for ON UPDATE!", $tokens); } break; default: throw new MalformedSqlException("Only UPDATE and DELETE allowed for ON trigger!", $tokens); } break; case is_int($tokens->isTokenText(')')): case is_int($tokens->isTokenText(',')): break 2; default: break 2; } } return $columnDefinition; }
public function convertSqlToJob(SQLTokenIterator $tokens) { $tokens->seekTokenNum(SqlToken::T_UPDATE()); if ($tokens->getCurrentTokenNumber() !== SqlToken::T_UPDATE()) { throw new ErrorException("Tried to parse update statement when token-iterator does not point to T_UPDATE!"); } $dataChange = new UpdateDataChange(); $updateJob = new UpdateStatement(); if ($tokens->seekTokenNum(SqlToken::T_LOW_PRIORITY())) { $updateJob->setIsLowPriority(true); } if ($tokens->seekTokenNum(SqlToken::T_IGNORE())) { $updateJob->setDoIgnoreErrors(true); } do { if (!$this->tableParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing table specifier in UPDATE statement!", $tokens); } $updateJob->addTable($this->tableParser->convertSqlToJob($tokens)); } while ($tokens->seekTokenText(',')); if (!$tokens->seekTokenNum(SqlToken::T_SET())) { throw new MalformedSqlException("Missing SET after table specifier in UPDATE statement!", $tokens); } do { if (!$this->columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing column specifier for SET part in UPDATE statement!", $tokens); } $dataChange->setColumn($this->columnParser->convertSqlToJob($tokens)); if (!$tokens->seekTokenText('=')) { throw new MalformedSqlException("Missing '=' on SET part in UPDATE statement!", $tokens); } if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("MIssing valid value on SET part in UPDATE statement!", $tokens); } $dataChange->setValue($this->valueParser->convertSqlToJob($tokens)); $updateJob->addDataChange(clone $dataChange); } while ($tokens->seekTokenText(',')); if ($tokens->seekTokenNum(SqlToken::T_WHERE())) { if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing condition for WHERE clause in UPDATE statement!", $tokens); } $updateJob->setCondition($this->valueParser->convertSqlToJob($tokens)); } if ($tokens->seekTokenNum(SqlToken::T_ORDER())) { if (!$tokens->seekTokenNum(SqlToken::T_BY())) { throw new MalformedSqlException("Missing BY after ORDER on UPDATE statement!", $tokens); } if (!$this->columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing column specifier for ORDER BY part on UPDATE statement!", $tokens); } $updateJob->setOrderColumn($this->columnParser->convertSqlToJob($tokens)); if ($tokens->seekTokenNum(SqlToken::T_DESC())) { $updateJob->setOrderDirection(SqlToken::T_DESC()); } elseif ($tokens->seekTokenNum(SqlToken::T_ASC())) { $updateJob->setOrderDirection(SqlToken::T_ASC()); } } if ($tokens->seekTokenNum(SqlToken::T_LIMIT())) { if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing offset number for LIMIT part in UPDATE statement!", $tokens); } $updateJob->setLimitOffset((int) $tokens->getCurrentTokenString()); if ($tokens->seekTokenText(',')) { if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing length number for LIMIT part in UPDATE statement!", $tokens); } $updateJob->setLimitRowCount((int) $tokens->getCurrentTokenString()); } } return $updateJob; }
/** * @param SQLTokenIterator $tokens * @return Operator */ protected function parseCondition(SQLTokenIterator $tokens) { switch (true) { case $tokens->seekTokenText('='): return Operator::OP_EQUAL(); case $tokens->seekTokenText('<=>'): return Operator::OP_EQUAL_NULLSAFE(); case $tokens->seekTokenText('!='): return Operator::OP_NOT_EQUAL(); case $tokens->seekTokenText('<>'): return Operator::OP_LESSERGREATER(); case $tokens->seekTokenText('<='): return Operator::OP_LESSEREQUAL(); case $tokens->seekTokenText('<'): return Operator::OP_LESSER(); case $tokens->seekTokenText('>='): return Operator::OP_GREATEREQUAL(); case $tokens->seekTokenText('>'): return Operator::OP_GREATER(); case $tokens->seekTokenText('+'): return Operator::OP_ADDITION(); case $tokens->seekTokenText('-'): return Operator::OP_SUBTRACTION(); case $tokens->seekTokenText('*'): return Operator::OP_MULTIPLICATION(); case $tokens->seekTokenText('/'): return Operator::OP_DIVISION(); case $tokens->seekTokenNum(SqlToken::T_IS()): if ($tokens->seekTokenNum(SqlToken::T_NOT())) { return Operator::OP_IS_NOT(); } else { return Operator::OP_IS(); } break; case $tokens->seekTokenNum(SqlToken::T_AND()): return Operator::OP_AND(); case $tokens->seekTokenNum(SqlToken::T_OR()): return Operator::OP_OR(); case $tokens->seekTokenNum(SqlToken::T_BETWEEN(), TokenIterator::NEXT, SqlToken::T_NOT()): if ($tokens->isTokenNum(SqlToken::T_NOT(), TokenIterator::PREVIOUS)) { return Operator::OP_NOT_BETWEEN(); } else { return Operator::OP_BETWEEN(); } default: return null; } }
public function convertSqlToJob(SQLTokenIterator $tokens) { $tokens->seekTokenNum(SqlToken::T_DELETE()); if ($tokens->getCurrentTokenNumber() !== SqlToken::T_DELETE()) { throw new ErrorException("Tried to parse DELETE statement when token iterator is not at T_DELETE!"); } $deleteJob = new DeleteStatement(); if ($tokens->seekTokenNum(SqlToken::T_LOW_PRIORITY())) { $deleteJob->setIsLowPriority(true); } if ($tokens->seekTokenNum(SqlToken::T_QUICK())) { $deleteJob->setIsQuick(true); } if ($tokens->seekTokenNum(SqlToken::T_IGNORE())) { $deleteJob->setIsIgnore(true); } if ($tokens->seekTokenNum(SqlToken::T_FROM())) { do { if (!$this->tableParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid table specifier in DELETE statement!", $tokens); } $deleteJob->addDeleteTable($this->tableParser->convertSqlToJob($tokens)); if ($tokens->seekTokenText('.')) { if (!$tokens->seekTokenText('*')) { throw new MalformedSqlException("Only '*' allowed for column specification in DELETE statement!", $tokens); } } } while ($tokens->seekTokenText(',')); if ($tokens->seekTokenNum(SqlToken::T_USING())) { if (!$this->joinParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid JOIN definition after USING in DELETE statement!", $tokens); } $deleteJob->setJoinDefinition($this->joinParser->convertSqlToJob($tokens)); } } else { do { if (!$this->tableParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid table specifier in DELETE statement!", $tokens); } $deleteJob->addDeleteTable($this->tableParser->convertSqlToJob($tokens)); if ($tokens->seekTokenText('.')) { if (!$tokens->seekTokenText('*')) { throw new MalformedSqlException("Only '*' allowed for column specification in DELETE statement!", $tokens); } } } while ($tokens->seekTokenText(',')); if ($tokens->seekTokenNum(SqlToken::T_FROM())) { if (!$this->joinParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid JOIN definition after FROM in DELETE statement!", $tokens); } $deleteJob->setJoinDefinition($this->joinParser->convertSqlToJob($tokens)); } } if ($tokens->seekTokenNum(SqlToken::T_WHERE())) { if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing condition for WHERE clause in UPDATE statement!", $tokens); } $deleteJob->setCondition($this->valueParser->convertSqlToJob($tokens)); } if ($tokens->seekTokenNum(SqlToken::T_ORDER())) { if (!$tokens->seekTokenNum(SqlToken::T_BY())) { throw new MalformedSqlException("Missing BY after ORDER on DELETE statement!", $tokens); } if (!$columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing column specifier for ORDER BY part on DELETE statement!", $tokens); } $deleteJob->setOrderColumn($columnParser->convertSqlToJob($tokens)); if ($tokens->seekTokenNum(SqlToken::T_DESC())) { $deleteJob->setOrderDirection(SqlToken::T_DESC()); } elseif ($tokens->seekTokenNum(SqlToken::T_ASC())) { $deleteJob->setOrderDirection(SqlToken::T_ASC()); } } if ($tokens->seekTokenNum(SqlToken::T_LIMIT())) { if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing offset number for LIMIT part in DELETE statement!", $tokens); } $deleteJob->setLimitOffset((int) $tokens->getCurrentTokenString()); if ($tokens->seekTokenText(',')) { if (!$tokens->seekTokenNum(T_NUM_STRING)) { throw new MalformedSqlException("Missing length number for LIMIT part in DELETE statement!", $tokens); } $deleteJob->setLimitRowCount((int) $tokens->getCurrentTokenString()); } } return $deleteJob; }
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; }
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; }
protected function parseJoinOperator(SQLTokenIterator $tokens) { $joinData = array('isInner' => false, 'isRight' => false); if ($tokens->seekTokenText(',')) { return $joinData; } if (!$tokens->isTokenNum(SqlToken::T_JOIN(), TokenIterator::NEXT, [SqlToken::T_LEFT(), SqlToken::T_RIGHT(), SqlToken::T_INNER(), SqlToken::T_OUTER(), SqlToken::T_CROSS()])) { return null; } while (true) { switch (true) { case $tokens->seekTokenNum(SqlToken::T_RIGHT()): $joinData['isRight'] = true; break; case $tokens->seekTokenNum(SqlToken::T_LEFT()): $joinData['isRight'] = false; break; case $tokens->seekTokenNum(SqlToken::T_INNER()): $joinData['isInner'] = true; break; case $tokens->seekTokenNum(SqlToken::T_CROSS()): case $tokens->seekTokenNum(SqlToken::T_OUTER()): $joinData['isInner'] = false; break; case $tokens->seekTokenNum(SqlToken::T_JOIN()): return $joinData; default: throw new MalformedSqlException("Invalid JOIN definition!"); } } }