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; }
protected function parseTableSource(SQLTokenIterator $tokens) { $parenthesis = new ParenthesisPart(); switch (true) { case $this->tableParser->canParseTokens($tokens): $parenthesis->setContain($this->tableParser->convertSqlToJob($tokens)); if ($tokens->seekTokenNum(T_STRING, TokenIterator::NEXT, [SqlToken::T_AS()])) { $parenthesis->setAlias($tokens->getCurrentTokenString()); } break; case $this->parenthesisParser->canParseTokens($tokens): $parenthesisJob = $this->parenthesisParser->convertSqlToJob($tokens); if ($tokens->seekTokenNum(T_STRING, TokenIterator::NEXT, [SqlToken::T_AS()])) { $parenthesis->setAlias($tokens->getCurrentTokenString()); } // resolve cascaded parenthesis $extractParenthesis = $parenthesisJob; while ($extractParenthesis->getContain() instanceof Parenthesis) { $extractParenthesis = $extractParenthesis->getContain(); } if ($extractParenthesis->getContain() instanceof SelectStatement) { $parenthesis = $parenthesisJob; // return original parenthesis for correct alias } else { throw new MalformedSqlException("Parenthesis in JOIN condition has to contain SELECT statement!", $tokens); } break; default: throw new MalformedSqlException("Missing valid table-source in JOIN defintion!", $tokens); } return $parenthesis; }