コード例 #1
0
ファイル: CreateIndexExecutor.php プロジェクト: addiks/phpsql
 public function executeJob(StatementJob $statement, array $parameters = array())
 {
     /* @var $statement CreateIndexStatement */
     /* @var $tableSpecifier TableSpecifier */
     $tableSpecifier = $statement->getTable();
     ### WRITE INDEX PAGE
     /* @var $tableResource TableInterface */
     $tableResource = $this->tableManager->getTable($tableSpecifier->getTable(), $tableSpecifier->getDatabase());
     /* @var $tableSchema TableSchema */
     $tableSchema = $tableResource->getTableSchema();
     $indexPage = new Index();
     $indexPage->setName($statement->getName());
     $indexPage->setEngine(IndexEngine::factory($statement->getIndexType()->getName()));
     $columnIds = array();
     $keyLength = 0;
     foreach ($statement->getColumns() as $columnDataset) {
         $columnSpecifier = $columnDataset['column'];
         /* @var $columnSpecifier Column */
         $columnId = $tableSchema->getColumnIndex($columnSpecifier->getColumn());
         if (is_null($columnId)) {
             throw new InvalidArgumentException("Cannot create index for unknown column '{$columnSpecifier->getColumn()}'!");
         }
         if (!is_null($columnDataset['length'])) {
             $keyLength += (int) $columnDataset['length'];
         } else {
             $keyLength += $tableSchema->getColumn($columnId)->getLength();
         }
         $columnIds[] = $columnId;
     }
     $indexPage->setColumns($columnIds);
     $indexPage->setKeyLength($keyLength);
     if ($statement->getIsPrimary()) {
         $indexPage->setType(Type::PRIMARY());
     } elseif ($statement->getIsUnique()) {
         $indexPage->setType(Type::UNIQUE());
     } else {
         $indexPage->setType(Type::INDEX());
     }
     $tableSchema->addIndexSchema($indexPage);
     ### PHSICALLY BUILD INDEX
     /* @var $tableResource TableInterface */
     $tableResource = $this->tableManager->getIndex($indexPage->getName(), $tableSpecifier->getTable(), $tableSpecifier->getDatabase());
     foreach ($tableResource->getIterator() as $rowId => $row) {
         $indexResource->insert($row, $rowId);
     }
     foreach ($this->tableManager->getTableFactories() as $tableFactory) {
         /* @var $tableFactory TableFactoryInterface */
         if ($tableFactory instanceof InformationSchemaTableFactory) {
             $tableFactory->clearCache();
         }
     }
 }
コード例 #2
0
ファイル: SelectExecutor.php プロジェクト: addiks/phpsql
 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();
 }
コード例 #3
0
ファイル: InsertExecutor.php プロジェクト: addiks/phpsql
 public function executeJob(StatementJob $statement, array $parameters = array())
 {
     /* @var $statement InsertStatement */
     $result = new TemporaryResult();
     $context = new ExecutionContext($this->schemaManager, $statement, $parameters);
     $tableName = (string) $statement->getTable();
     /* @var $table TableInterface */
     $table = $this->tableManager->getTable($tableName);
     /* @var $tableSchema TableSchema */
     $tableSchema = $table->getTableSchema();
     ### BUILD COLUMN MAP
     $columnNameToIdMap = array();
     foreach ($tableSchema->getColumnIterator() as $columnId => $columnPage) {
         /* @var $columnPage Column */
         $columnName = $columnPage->getName();
         $columnNameToIdMap[$columnName] = $columnId;
     }
     ### GET INDICES
     $indices = array();
     foreach ($tableSchema->getIndexIterator() as $indexId => $indexPage) {
         /* @var $indexPage Index */
         /* @var $index Index */
         $index = $table->getIndex($indexId);
         $indices[$indexId] = $index;
     }
     ### BUILD ROW DATA
     $rowDatas = array();
     switch (true) {
         case $statement->getDataSource() instanceof Select:
             $subResult = $this->selectExecutor->executeJob($statement->getDataSource(), $parameters);
             foreach ($subResult as $subResultRow) {
                 $rowData = array();
                 foreach ($subResultRow as $columnName => $value) {
                     $columnId = $columnNameToIdMap[$columnName];
                     $rowData[$columnId] = $value;
                 }
                 $rowDatas[] = $rowData;
             }
             break;
         case is_array($statement->getDataSource()):
             foreach ($statement->getDataSource() as $row) {
                 $sourceRow = array();
                 foreach ($statement->getColumns() as $sourceColumnId => $sourceColumn) {
                     /* @var $sourceColumn Column */
                     $sourceColumnName = (string) $sourceColumn;
                     $sourceRow[$sourceColumnName] = $row[$sourceColumnId];
                 }
                 $rowData = array();
                 foreach ($statement->getColumns() as $sourceColumnId => $sourceColumn) {
                     /* @var $sourceColumn Column */
                     $columnName = (string) $sourceColumn;
                     if (!isset($columnNameToIdMap[$columnName])) {
                         throw new ErrorException("Unknown column '{$columnName}' in statement!");
                     }
                     $columnId = $columnNameToIdMap[$columnName];
                     if (isset($sourceRow[$columnName])) {
                         $value = $sourceRow[$columnName];
                         $value = $this->valueResolver->resolveValue($value, $context);
                     } else {
                         $value = null;
                     }
                     /* @var $columnPage Column */
                     $columnPage = $tableSchema->getColumn($columnId);
                     if (is_null($value) && $columnPage->isAutoIncrement()) {
                         $value = $table->getAutoIncrementId();
                         $table->incrementAutoIncrementId();
                     }
                     if ($columnPage->isNotNull() && is_null($value)) {
                         $columnName = $tableSchema->getColumn($columnId)->getName();
                         throw new ErrorException("Column '{$columnName}' cannot be NULL!");
                     }
                     $rowData[$columnId] = $value;
                 }
                 $primaryKey = array();
                 // fill up missing columns
                 foreach ($columnNameToIdMap as $columnName => $columnId) {
                     /* @var $columnPage Column */
                     $columnPage = $tableSchema->getColumn($columnId);
                     if (!isset($rowData[$columnId])) {
                         if ($columnPage->isNotNull()) {
                             if ($columnPage->isAutoIncrement()) {
                                 $rowData[$columnId] = $table->getAutoIncrementId();
                                 $table->incrementAutoIncrementId();
                             } elseif ($columnPage->hasDefaultValue()) {
                                 if ($columnPage->isDefaultValueInFile()) {
                                     $defaultValueReference = $columnPage->getDefaultValue();
                                     $defaultValueFilePath = sprintf(FilePathes::FILEPATH_DEFAULT_VALUE, $schemaId, $tableName, $columnId);
                                 } else {
                                     $rowData[$columnId] = $columnPage->getDefaultValue();
                                 }
                             } else {
                                 throw new ErrorException("Column '{$columnName}' cannot be NULL!");
                             }
                         }
                     }
                     if ($columnPage->isPrimaryKey()) {
                         $primaryKey[$columnName] = $rowData[$columnId];
                     }
                 }
                 $result->setLastInsertId($primaryKey);
                 $rowData = $table->convertStringRowToDataRow($rowData);
                 foreach ($indices as $indexId => $index) {
                     /* @var $index Index */
                     if (!$index->getIndexSchema()->isUnique()) {
                         continue;
                     }
                     if (count($index->searchRow($rowData)) > 0) {
                         $rowDataString = implode(", ", $rowData);
                         throw new ErrorException("Cannot insert because row '{$rowDataString}' collides " . "with unique key '{$index->getIndexSchema()->getName()}'!");
                     }
                 }
                 $rowDatas[] = $rowData;
             }
             break;
     }
     ### INSERT DATA
     $insertedRowIds = array();
     $success = false;
     try {
         foreach ($rowDatas as $rowData) {
             // check unique keys
             foreach ($indices as $indexId => $index) {
                 if (!$index->getIndexSchema()->isUnique()) {
                     continue;
                 }
                 if (count($index->searchRow($rowData)) > 0) {
                     throw new ErrorException("Cannot insert because of unique key '{$index->getIndexSchema()->getName()}'!");
                 }
             }
             $rowId = $table->addRowData($rowData);
             $insertedRowIds[] = $rowId;
             // insert into indicies
             foreach ($indices as $indexId => $index) {
                 $index->insertRow($rowData, $this->decstr($rowId));
             }
         }
         $success = true;
     } catch (Exception $exception) {
         ### ROLLBACK
         foreach ($insertedRowIds as $rowId) {
             $table->removeRow($rowId);
             // remove from indicies
             foreach ($indices as $indexId => $index) {
                 $index->removeRow($row, $this->decstr($rowId));
             }
         }
         throw new ErrorException("Exception in INSERT statement, rollback executed.", null, null, null, 0, $exception);
     }
     ### RESULT
     $result->setIsSuccess((bool) $success);
     return $result;
 }