public function getLastParameter() { if (is_null($this->lastParameter)) { $this->setLastParameter(SqlToken::T_TRUE()); } return $this->lastParameter; }
public function convertSqlToJob(SQLTokenIterator $tokens) { $tokens->seekTokenNum(SqlToken::T_USE()); if ($tokens->getCurrentTokenNumber() !== SqlToken::T_USE()) { throw new MalformedSqlException("Tried to parse USE statement when token-iterator does not point to T_USE!", $tokens); } if ($tokens->seekTokenNum(T_VARIABLE)) { $databaseName = Variable::factory($tokens->getCurrentTokenString()); } elseif ($tokens->seekTokenNum(T_STRING)) { $databaseName = $tokens->getCurrentTokenString(); } elseif ($tokens->seekTokenNum(T_CONSTANT_ENCAPSED_STRING)) { $databaseName = $tokens->getCurrentTokenString(); if (($databaseName[0] === '"' || $databaseName[0] === "'") && $databaseName[0] === $databaseName[strlen($databaseName) - 1]) { // remove quotes if needed $databaseName = substr($databaseName, 1, strlen($databaseName) - 2); } } else { throw new MalformedSqlException("Missing database-specifier for USE statement!", $tokens); } $databaseNameValue = new ValuePart(); $databaseNameValue->addChainValue($databaseName); $useJob = new UseStatement(); $useJob->setDatabase($databaseNameValue); return $useJob; }
public function getOrderDirection() { if (is_null($this->orderDirection)) { $this->orderDirection = SqlToken::T_ASC(); } return $this->orderDirection; }
public function convertSqlToJob(SQLTokenIterator $tokens, &$skipChecks = 0) { $likeCondition = new LikeConditionJob(); $likeCondition->setIsNegated($tokens->seekTokenNum(SqlToken::T_NOT())); if (!$tokens->seekTokenNum(SqlToken::T_LIKE())) { throw new ErrorException("Missing [NOT] LIKE after value when parsing LIKE condition! (not used 'canParseTokens'?)"); } return $likeCondition; }
public function convertSqlToJob(SQLTokenIterator $tokens) { $statement = null; if ($tokens->seekTokenNum(SqlToken::T_COMMIT())) { $statement = new CommitStatement(); } else { throw new MalformedSqlException("Tried to parse COMMIT statement when token-iterator does not point to T_COMMIT!", $tokens); } return $statement; }
public function convertSqlToJob(SQLTokenIterator $tokens) { $statement = null; if ($tokens->seekTokenNum(SqlToken::T_TRANSACTION(), SQLTokenIterator::NEXT, [SqlToken::T_START()])) { $statement = new StartTransactionStatement(); } else { throw new MalformedSqlException("Tried to parse START TRANSACTION statement when token-iterator does not point to T_START!", $tokens); } return $statement; }
public function convertSqlToJob(SQLTokenIterator $tokens) { $statement = null; $tokens->seekTokenNum(SqlToken::T_ROLLBACK()); if ($tokens->getCurrentTokenNumber() === SqlToken::T_ROLLBACK()) { $statement = new RollbackStatement(); } else { throw new MalformedSqlException("Tried to parse ROLLBACK statement when token-iterator does not point to T_ROLLBACK!", $tokens); } return $statement; }
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) { $tokens->seekTokenNum(SqlToken::T_CASE()); if ($tokens->getCurrentTokenNumber() !== SqlToken::T_CASE()) { throw new ErrorException("Tried to parse CASE statement when token-iterator is not at CASE!"); } $caseJob = new CaseJob(); if (!$tokens->isTokenNum(SqlToken::T_WHEN()) && $this->valueParser->canParseTokens($tokens)) { $caseJob->setCaseValue($this->valueParser->convertSqlToJob($tokens)); } do { if (!$tokens->seekTokenNum(SqlToken::T_WHEN())) { throw new MalformedSqlException("Missing WHEN in CASE statement!", $tokens); } if (!$this->valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid when-value in CASE statement!", $tokens); } $whenValue = $this->valueParser->convertSqlToJob($tokens); if (!$tokens->seekTokenNum(SqlToken::T_THEN())) { throw new MalformedSqlException("Missing THEN in CASE statement!", $tokens); } switch (true) { case $this->valueParser->canParseTokens($tokens): $thenExpression = $this->valueParser->convertSqlToJob($tokens); break; default: throw new MalformedSqlException("Missing valid THEN statement for CASE statement!", $tokens); } $caseJob->addWhenThenStatement($whenValue, $thenExpression); } while ($tokens->isTokenNum(SqlToken::T_WHEN())); if ($tokens->seekTokenNum(SqlToken::T_ELSE())) { switch (true) { case $this->valueParser->canParseTokens($tokens): $caseJob->setElseStatement($this->valueParser->convertSqlToJob($tokens)); break; default: throw new MalformedSqlException("Missing valid THEN statement for CASE statement!", $tokens); } } if (!$tokens->seekTokenNum(SqlToken::T_END())) { throw new MalformedSqlException("Missing END at the end of for CASE statement!", $tokens); } $tokens->seekTokenNum(SqlToken::T_CASE()); return $caseJob; }
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) { $tokens->seekTokenNum(SqlToken::T_DESCRIBE()); $tokens->seekTokenNum(SqlToken::T_DESC()); if (!in_array($tokens->getCurrentTokenNumber(), [SqlToken::T_DESCRIBE(), SqlToken::T_DESC()])) { throw new ErrorException("Tried to parse DESCRIBE statement when token-iterator does not point to DESC or DESCRIBE!"); } if (!$this->tableParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing table-specifier for DESCRIBE statement!", $tokens); } $describeJob = new DescribeStatement(); $describeJob->setTable($this->tableParser->convertSqlToJob($tokens)); if ($tokens->seekTokenText('wild')) { $describeJob->setIsWild(true); } elseif ($tokens->seekTokenNum(T_STRING)) { $describeJob->setColumnName($tokens->getCurrentTokenString()); } return $describeJob; }
public function convertSqlToJob(SQLTokenIterator $tokens) { /* @var $valueParser ValueParser */ $valueParser = $this->valueParser; $tokens->seekTokenNum(SqlToken::T_SHOW()); if ($tokens->getCurrentTokenNumber() !== SqlToken::T_SHOW()) { throw new ErrorException("Tried to convert sql-show to job-entity when tokeniterator does not point to T_SHOW!"); } $showJob = new ShowStatement(); if ($tokens->seekTokenNum(SqlToken::T_FULL())) { $showJob->setIsFull(true); } switch (true) { case $tokens->seekTokenNum(SqlToken::T_DATABASES()): $showJob->setType(ShowType::DATABASES()); break; case $tokens->seekTokenNum(SqlToken::T_TABLES()): $showJob->setType(ShowType::TABLES()); break; case $tokens->seekTokenNum(SqlToken::T_VIEWS()): $showJob->setType(ShowType::VIEWS()); break; default: throw new MalformedSqlException("Invalid parameter for show-statement!", $tokens); } if ($tokens->seekTokenNum(SqlToken::T_FROM())) { if (!$tokens->seekTokenNum(T_STRING)) { throw new MalformedSqlException("Missing database name after FROM in SHOW statement!"); } $showJob->setDatabase($tokens->getCurrentTokenString()); } if ($tokens->seekTokenNum(SqlToken::T_WHERE())) { if (!$valueParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid condition-value after WHERE in SHOW statement!"); } /* @var $conditionValue ValuePart */ $conditionValue = $valueParser->convertSqlToJob($tokens); $showJob->setConditionValue($conditionValue); } return $showJob; }
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 getSortIndexByColumns(array $orderColumns) { $insertionSortFile = new FileResourceProxy(fopen("php://memory", "w")); $columnPage = new ColumnSchema(); $columnPages = array(); foreach ($orderColumns as $columnIndex => $columnDataset) { if ($columnDataset instanceof Column) { $direction = 'ASC'; $columnPage = $columnDataset; } else { $direction = $columnDataset['direction'] === SqlToken::T_ASC() ? 'ASC' : 'DESC'; /* @var $value Value */ $value = $columnDataset['value']; $columnPage->setDataType(DataType::VARCHAR()); # TODO: get actual column-page if possible $columnPage->setLength(64); $columnPage->setName("INDEXVALUE_{$columnIndex}"); } $columnPages[] = [clone $columnPage, $direction]; } $sortIndex = new QuickSort($insertionSortFile, $columnPages); return $sortIndex; }
public function convertSqlToJob(SQLTokenIterator $tokens) { $tokens->seekTokenNum(SqlToken::T_INSERT()); if ($tokens->getCurrentTokenNumber() !== SqlToken::T_INSERT()) { throw new ErrorException("Tried to parse INSERT statement when token-iterator is not at INSERT!"); } $dataChange = new InsertDataChange(); $insertJob = new InsertStatement(); switch (true) { case $tokens->seekTokenNum(SqlToken::T_LOW_PRIORITY()): $insertJob->setPriority(Priority::LOW_PRIORITY()); break; case $tokens->seekTokenNum(SqlToken::T_DELAYED()): $insertJob->setPriority(Priority::DELAYED()); break; case $tokens->seekTokenNum(SqlToken::T_HIGH_PRIORITY()): $insertJob->setPriority(Priority::HIGH_PRIORITY()); break; } if ($tokens->seekTokenNum(SqlToken::T_IGNORE())) { $insertJob->setDoIgnoreErrors(true); } if (!$tokens->seekTokenNum(SqlToken::T_INTO())) { throw new MalformedSqlException("Missing INTO after INSERT for INSERT INTO statement!", $tokens); } if (!$this->tableParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing table-specifier for INSERT INTO statement!", $tokens); } $insertJob->setTable($this->tableParser->convertSqlToJob($tokens)); if ($tokens->seekTokenText('(')) { do { if (!$this->columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing valid column name in column selection for INSERT INTO statement!", $tokens); } $insertJob->addColumnSelection($this->columnParser->convertSqlToJob($tokens)); } while ($tokens->seekTokenText(',')); if (!$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing closing parenthesis after column-selection for INSERT INTO statement!"); } if ($tokens->seekTokenNum(SqlToken::T_VALUES())) { do { if (!$tokens->seekTokenText('(')) { throw new MalformedSqlException("Missing begin parenthesis in value definiton for INSERT INTO statement!", $tokens); } $dataRow = array(); do { switch (true) { case $this->valueParser->canParseTokens($tokens): $dataRow[] = $this->valueParser->convertSqlToJob($tokens); break; default: throw new MalformedSqlException("Invalid value in value-defintion for INSERT INTO statement!", $tokens); } } while ($tokens->seekTokenText(',')); if (!$tokens->seekTokenText(')')) { throw new MalformedSqlException("Missing ending parenthesis in value definiton for INSERT INTO statement!", $tokens); } $insertJob->addDataSourceValuesRow($dataRow); } while ($tokens->seekTokenText(',')); } elseif ($this->selectParser->canParseTokens($tokens)) { $insertJob->setDataSourceSelect($this->selectParser->convertSqlToJob($tokens)); } else { throw new MalformedSqlException("Invalid data-source-definiton (VALUES or SELECT) in INSERT INTO statement!", $tokens); } } elseif ($tokens->seekTokenNum(SqlToken::T_SET())) { do { if (!$this->columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing column specifier for INSERT INTO SET statement!", $tokens); } $dataChange->setColumn($this->columnParser->convertSqlToJob($tokens)); if (!$tokens->seekTokenText('=')) { throw new MalformedSqlException("Missing '=' in INSERT INTO SET statement!", $tokens); } switch (true) { case $this->valueParser->canParseTokens($tokens): $dataChange->setValue($this->valueParser->convertSqlToJob($tokens)); break; default: throw new MalformedSqlException("Invalid value for INSERT INTO SET statement!", $tokens); } $insertJob->addColumnSetValue(clone $dataChange); } while ($tokens->seekTokenText(',')); } elseif ($this->selectParser->canParseTokens($tokens)) { $insertJob->setDataSourceSelect($this->selectParser->convertSqlToJob($tokens)); } else { throw new MalformedSqlException("Invalid column-selection for INSERT INTO statement!", $tokens); } if ($tokens->seekTokenNum(SqlToken::T_ON())) { if (!$tokens->seekTokenNum(SqlToken::T_DUPLICATE())) { throw new MalformedSqlException("Missing DUPLICATE in INSERT INTO ON DUPLICATE KEY UPDATE statement!", $tokens); } if (!$tokens->seekTokenNum(SqlToken::T_KEY())) { throw new MalformedSqlException("Missing KEY in INSERT INTO ON DUPLICATE KEY UPDATE statement!", $tokens); } if (!$tokens->seekTokenNum(SqlToken::T_UPDATE())) { throw new MalformedSqlException("Missing UPDATE in INSERT INTO ON DUPLICATE KEY UPDATE statement!", $tokens); } do { if (!$this->columnParser->canParseTokens($tokens)) { throw new MalformedSqlException("Missing column specifier for INSERT INTO ON DUPLICATE KEY UPDATE statement!", $tokens); } $dataChange->setColumn($this->columnParser->convertSqlToJob($tokens)); if (!$tokens->seekTokenText('=')) { throw new MalformedSqlException("Missing '=' in INSERT INTO ON DUPLICATE KEY UPDATE statement!", $tokens); } switch (true) { case $valueParser->canParseTokens($tokens): $dataChange->setValue($valueParser->convertSqlToJob($tokens)); break; default: throw new MalformedSqlException("Invalid value for INSERT INTO ON DUPLICATE KEY UPDATE statement!", $tokens); } $insertJob->addOnDuplicateDataChange(clone $dataChange); } while ($tokens->seekTokenText(',')); } return $insertJob; }
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 executeJob(StatementJob $statement, array $parameters = array()) { /* @var $statement SelectStatement */ $defaultSchema = $this->schemaManager->getSchema(); $executionContext = new ExecutionContext($this->schemaManager, $statement, $parameters); ### COLLECT SOURCE TABLES if (!is_null($statement->getJoinDefinition())) { foreach ($statement->getJoinDefinition()->getTables() as $joinTable) { /* @var $joinTable TableJoin */ /* @var $dataSource ParenthesisPart */ $dataSource = $joinTable->getDataSource(); $tableResource = null; $alias = $dataSource->getAlias(); $dataSource = $dataSource->getContain(); if ($dataSource instanceof TableInterface) { $tableResource = $dataSource; if (is_null($alias)) { $alias = $tableResource->getName(); } } if ($dataSource instanceof SelectStatement) { /* @var $subQueryResult TemporaryResult */ $tableResource = $this->executeJob($dataSource, $parameters); } if ($dataSource instanceof TableSpecifier) { if (!is_null($dataSource->getDatabase())) { if (!$this->schemaManager->schemaExists($dataSource->getDatabase())) { throw new InvalidArgumentException("Database '{$dataSource->getDatabase()}' does not exist!"); } $schema = $this->schemaManager->getSchema($dataSource->getDatabase()); } else { $schema = $defaultSchema; } if (!$schema->tableExists($dataSource->getTable())) { throw new InvalidArgumentException("Table '{$dataSource}' does not exist!"); } if (is_null($alias)) { $alias = $dataSource->getTable(); } $tableResource = $this->tableManager->getTable($dataSource->getTable(), $dataSource->getDatabase()); } $executionContext->setTable($tableResource, (string) $alias); } } ### INIT RESULTSET $resultColumns = array(); foreach ($statement->getColumns() as $column) { if ($column === '*') { foreach ($executionContext->getTables() as $alias => $table) { /* @var $table Table */ /* @var $tableSchema TableSchema */ $tableSchema = $table->getTableSchema(); foreach ($tableSchema->getColumnIterator() as $columnPage) { /* @var $columnPage ColumnSchema */ $columnName = $columnPage->getName(); if (count($executionContext->getTables()) > 1) { $columnName = "{$alias}.{$columnName}"; } $resultColumns[] = $columnName; } } } elseif ($column instanceof ValuePart) { $resultColumns[] = $column->getAlias(); } } $result = new TemporaryResult($resultColumns); $executionContext->setCurrentResultSet(new TemporaryResult($resultColumns)); $executionContext->setCurrentSourceSet(new TemporaryResult()); ### PRE-FILTER SOURCE COLUMNS (currently not implemented) if (!is_null($statement->getCondition())) { /* @var $condition ValuePart */ $condition = $statement->getCondition(); $tableConditions = $this->findFixedConditions($condition); foreach ($executionContext->getTables() as $alias => $table) { /* @var $table TableInterface */ /* @var $tableSchema TableSchema */ $tableSchema = $table->getTableSchema(); $tableIterator = $table; $indexes = $this->findIndexesForTableConditions($tableConditions, $table, $alias); if (!empty($indexes)) { # TODO: actually choose the best index instead of using the first usable index # (We probably need table-statistics to do that.) $index = $indexes[0]; /* @var $indexSchema IndexSchema */ $indexSchema = $index->getIndexSchema(); $indexecColumns = array(); foreach ($indexSchema->getColumns() as $columnId) { $columnName = $tableSchema->getColumn($columnId)->getName(); $indexecColumns[$columnId] = $columnName; } $tableIterator = new FilteredResourceIterator($tableIterator, $condition, $this->valueResolver, $executionContext, $index, $indexecColumns); } if ($tableIterator !== $table) { $executionContext->setTable($tableIterator, $alias); } } } /* @var $joinDefinition Join */ $joinDefinition = $statement->getJoinDefinition(); if (!is_null($joinDefinition)) { ### BUILD JOIN if (count($joinDefinition->getTables()) > 1) { $iterator = new JoinIterator($joinDefinition, $executionContext, $this, $this->valueResolver, $statement, null); } else { /* @var $tableJoin TableJoin */ $tableJoin = $joinDefinition->getTables()[0]; $tableSource = $tableJoin->getDataSource(); $alias = null; while ($tableSource instanceof ParenthesisPart) { if (is_null($alias)) { $alias = $tableSource->getAlias(); } $tableSource = $tableSource->getContain(); } if ($tableSource instanceof TableSpecifier) { if (is_null($alias)) { $alias = $tableSource->getTable(); } $iterator = $executionContext->getTable($alias); } elseif ($tableSource instanceof SelectStatement) { $iterator = $this->executeJob($tableSource); } else { throw new ErrorException("Unexpected object given as source for join!"); } $iterator = new AliasedResourceIterator($iterator, $alias); } ### FILTER RESULT // WHERE condition $condition = $statement->getCondition(); if (!is_null($condition)) { if ($iterator instanceof IteratorAggreagte) { $iterator = $iterator->getIterator(); } $iterator = new FilteredResourceIterator($iterator, $condition, $this->valueResolver, $executionContext); } // ON/USING conditions from joins foreach ($joinDefinition->getTables() as $joinTable) { /* @var $joinTable TableJoin */ $joinCondition = $joinTable->getCondition(); if (!is_null($joinCondition)) { if ($iterator instanceof IteratorAggreagte) { $iterator = $iterator->getIterator(); } $iterator = new FilteredResourceIterator($iterator, $joinCondition, $this->valueResolver, $executionContext); } } ### SET UP SORTING $orderColumns = $statement->getOrderColumns(); if (count($orderColumns) > 0) { $innerIterator = $iterator; $iterator = new SortedResourceIterator($iterator, $this->valueResolver); $iterator->setTemporaryBuildChildIteratorByValue($orderColumns, $innerIterator, $executionContext); } ### WRITE RESULTSET foreach ($iterator as $dataRow) { if ($iterator instanceof UsesBinaryDataInterface && $iterator->usesBinaryData()) { $dataRow = $iterator->convertDataRowToStringRow($dataRow); } $executionContext->getCurrentSourceSet()->addRow($dataRow); $executionContext->setCurrentSourceRow($dataRow); $resolvedRow = $this->valueResolver->resolveSourceRow($statement->getColumns(), $executionContext); $executionContext->getCurrentResultSet()->addRow($resolvedRow); } } else { // no joining (something like "SELECT 5+5 as foo") $resolvedRow = $this->valueResolver->resolveSourceRow($statement->getColumns(), $executionContext); $executionContext->getCurrentResultSet()->addRow($resolvedRow); } ### UNLOCK TABLES foreach ($executionContext->getTables() as $table) { # TODO: unlock tables } ### APPLY GROUPING $groupings = $statement->getGroupings(); if (count($groupings) > 0) { foreach ($groupings as $groupingDefinition) { /* @var $groupingDefinition GroupingDefinition */ /* @var $groupingValue ValuePart */ $groupingValue = $groupingDefinition->getValue(); $beforeSourceRow = $executionContext->getCurrentSourceRow(); $groupedRows = array(); foreach ($executionContext->getCurrentSourceSet() as $row) { $executionContext->setCurrentSourceRow($row); $groupId = $this->valueResolver->resolveValue($groupingValue, $executionContext); if (!isset($groupedRows[$groupId])) { $groupedRows[$groupId] = array(); } $groupedRows[$groupId][] = $row; } $groupedResultSet = new TemporaryResult($resultColumns); foreach ($groupedRows as $groupId => $rows) { if ($groupingDefinition->getDirection() === SqlToken::T_ASC()) { $groupingMainRow = reset($rows); } else { $groupingMainRow = end($rows); } $currentGroupResultSet = new TemporaryResult(); foreach ($rows as $row) { $currentGroupResultSet->addRow($row); } $executionContext->setCurrentSourceRow($groupingMainRow); $executionContext->setCurrentSourceSet($currentGroupResultSet); $resolvedRow = $this->valueResolver->resolveSourceRow($statement->getColumns(), $executionContext); $groupedResultSet->addRow($resolvedRow); } $executionContext->setCurrentSourceRow($beforeSourceRow); $executionContext->setCurrentResultSet($groupedResultSet); } } ### APPLY RESULT-FILTER (HAVING) /* @var $resultFilter ConditionJob */ $resultFilter = $statement->getResultFilter(); if (!is_null($resultFilter)) { $filteredResult = new TemporaryResult($resultColumns); foreach ($executionContext->getCurrentResultSet() as $row) { $executionContext->setCurrentSourceRow($row); $passesFilter = (bool) $this->valueResolver->resolveValue($resultFilter, $executionContext); if ($passesFilter) { $filteredResult->addRow($row); } } $executionContext->setCurrentResultSet($filteredResult); } ### APPEND UNIONED SELECT $unionSelect = $statement->getUnionSelect(); if (!is_null($unionSelect)) { $unionResult = $this->executeJob($unionSelect, $parameters); foreach ($unionResult as $unionRow) { $executionContext->getCurrentResultSet()->addRow($unionRow); } } return $executionContext->getCurrentResultSet(); }
public function parsePlainValue(SQLTokenIterator $tokens, ValueJob $valueJob) { switch (true) { case $tokens->seekTokenNum(T_NUM_STRING): $valueJob->addChainValue((double) $tokens->getCurrentTokenString()); break; case $tokens->seekTokenNum(T_CONSTANT_ENCAPSED_STRING): $string = $tokens->getCurrentTokenString(); if (($string[0] === '"' || $string[0] === "'") && $string[0] === $string[strlen($string) - 1]) { // remove quotes if needed $string = substr($string, 1, strlen($string) - 2); } $valueJob->addChainValue($string); break; case $tokens->seekTokenNum(T_VARIABLE): $variableString = $tokens->getCurrentTokenString(); $variable = Variable::factory($variableString); if ($variableString === '?') { $variable->setIndex($tokens->countTokenOccourences(T_VARIABLE, 0, $tokens->getIndex() - 1)); } $valueJob->addChainValue($variable); break; case $this->parenthesisParser->canParseTokens($tokens): $valueJob->addChainValue($this->parenthesisParser->convertSqlToJob($tokens)); break; case $this->functionParser->canParseTokens($tokens): $valueJob->addChainValue($this->functionParser->convertSqlToJob($tokens)); break; case $this->columnParser->canParseTokens($tokens): $valueJob->addChainValue($this->columnParser->convertSqlToJob($tokens)); break; case $this->caseParser->canParseTokens($tokens): $valueJob->addChainValue($this->caseParser->convertSqlToJob($tokens)); break; case $tokens->seekTokenNum(SqlToken::T_DEFAULT()): case $tokens->seekTokenNum(SqlToken::T_NULL()): case $tokens->seekTokenNum(SqlToken::T_FALSE()): case $tokens->seekTokenNum(SqlToken::T_TRUE()): case $tokens->seekTokenNum(SqlToken::T_CURRENT_TIMESTAMP()): case $tokens->seekTokenNum(SqlToken::T_CURRENT_DATE()): case $tokens->seekTokenNum(SqlToken::T_CURRENT_TIME()): case $tokens->seekTokenNum(SqlToken::T_CURRENT_USER()): $valueJob->addChainValue($tokens->getCurrentTokenNumber()); break; default: return false; } return true; }
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; }
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 setDirection() { $this->direction = SqlToken::T_ASC() ? $direction : SqlToken::T_DESC(); }
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 setOrderDirection(SqlToken $direction) { $this->orderDirection = $direction === SqlToken::T_ASC() ? $direction : SqlToken::T_DESC(); }
public function addColumn(ColumnSpecifier $column, $length = null, $direction = null) { $direction = $direction === SqlToken::T_DESC() ? SqlToken::T_DESC() : SqlToken::T_ASC(); $this->columns[] = ['column' => $column, 'length' => $length, 'direction' => $direction]; }
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; }
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; }
/** * @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 resolveSqlToken(SqlToken $token) { switch ($token) { case SqlToken::T_DEFAULT(): return $this->getCurrentColumnSchema()->getDefaultValue(); case SqlToken::T_FALSE(): return 0; case SqlToken::T_TRUE(): return 1; case SqlToken::T_NULL(): return null; case SqlToken::T_CURRENT_TIMESTAMP(): return date("Y-m-d H:i:s", time()); case SqlToken::T_CURRENT_DATE(): return date("Y-m-d", time()); case SqlToken::T_CURRENT_TIME(): return time(); case SqlToken::T_CURRENT_USER(): // There is simply no user management, so what to do here? return "NoUserManagementImplemented"; default: throw new ErrorException("Unknown or unimplemented SqlToken '{$token->getName()}' to resolve to scalar value!"); } }
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; }
public function addOrderColumn($value, $direction) { $this->orderColumns[] = ['value' => $value, 'direction' => SqlToken::T_ASC() ? $direction : SqlToken::T_DESC()]; }