public function setUp() { $forkRate = 16; $file = new FileResourceProxy(fopen("php://memory", "w")); $doublesFile = new FileResourceProxy(fopen("php://memory", "w")); $tableSchemaFile = new FileResourceProxy(fopen("php://memory", "w")); $indexSchemaFile = new FileResourceProxy(fopen("php://memory", "w")); $tableSchema = new TableSchema($tableSchemaFile, $indexSchemaFile); $columnPageA = new ColumnSchema(); $columnPageA->setName("columnB"); $columnPageA->setIndex(0); $columnPageA->setDataType(DataType::INT()); $columnPageA->setLength(4); $tableSchema->addColumnSchema($columnPageA); $columnPageB = new ColumnSchema(); $columnPageB->setName("columnC"); $columnPageB->setIndex(1); $columnPageB->setDataType(DataType::VARCHAR()); $columnPageB->setLength(4); $tableSchema->addColumnSchema($columnPageB); $indexPage = new IndexSchema(); $indexPage->setName("test-index"); $indexPage->setColumns([0, 1]); $indexPage->setType(Type::INDEX()); $indexPage->setEngine(IndexEngine::BTREE()); $this->btree = new BTree($file, $tableSchema, $indexPage, $forkRate); $this->btree->setDoublesFile($doublesFile); $this->btree->setIsDevelopmentMode(true); }
public function setUp() { $file = new FileResourceProxy(fopen("php://memory", "w")); $columnSchema = new ColumnSchema(); $columnSchema->setName("test_column"); $columnSchema->setIndex(0); $columnSchema->setDataType(DataType::VARCHAR()); $columnSchema->setLength(10); $this->columnData = new ColumnData($file, $columnSchema); }
public function setUp() { $file = new FileResourceProxy(fopen("php://memory", "w")); $column1 = new ColumnSchema(); $column1->setName("foo"); $column1->setDataType(DataType::INTEGER()); $column1->setLength(4); $column2 = new ColumnSchema(); $column2->setName("bar"); $column2->setDataType(DataType::VARCHAR()); $column2->setLength(12); $columns = [[$column1, 'ASC'], [$column2, 'DESC']]; $this->index = new QuickSort($file, $columns); }
public function createTableSchema($tableSchemaFile, $indexSchemaFile, $tableName) { $tableSchema = new TableSchema(new FileResourceProxy(fopen("php://memory", "w")), new FileResourceProxy(fopen("php://memory", "w"))); $columns = array(); if (isset($this->columnsMap[$tableName])) { $columns = $this->columnsMap[$tableName]; } foreach ($columns as $index => list($name, $type, $length)) { $columnSchema = new ColumnSchema(); $columnSchema->setName($name); $columnSchema->setIndex($index); $columnSchema->setDataType(DataType::getByValue($type)); $columnSchema->setLength($length); $tableSchema->addColumnSchema($columnSchema); } return $tableSchema; }
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; }
/** * * @return TableSchema */ public function getTableSchema() { if (is_null($this->tableSchema)) { $columnFile = new FileResourceProxy(fopen("php://memory", "w")); $indexFile = new FileResourceProxy(fopen("php://memory", "w")); $this->tableSchema = new TableSchema($columnFile, $indexFile); foreach ($this->columnNames as $columnName) { $columnPage = new ColumnSchema(); $columnPage->setName($columnName); $columnPage->setDataType(DataType::VARCHAR()); $columnPage->setLength(1024); $this->tableSchema->addColumnSchema($columnPage); } } return $this->tableSchema; }
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 executeJob(StatementJob $statement, array $parameters = array()) { /* @var $statement CreateTableStatement */ $context = new ExecutionContext($this->schemaManager, $statement, $parameters); /* @var $databaseSchema Schema */ $databaseSchema = $this->schemaManager->getSchema(); $schemaId = $this->schemaManager->getCurrentlyUsedDatabaseId(); $tableName = $this->valueResolver->resolveValue($statement->getName(), $context); $schemaPage = new DatabaseSchemaPage(); $schemaPage->setName($tableName); $schemaPage->setType(Type::TABLE()); $schemaPage->setEngine(Engine::factory($statement->getEngine()->getName())); $schemaPage->setCollation(strtoupper($statement->getCollate())); $schemaPage->setUseChecksum($statement->getUseChecksum()); $schemaPage->setMaxRows($statement->getMaximumRows()); $schemaPage->setMinRows($statement->getMinimumRows()); $schemaPage->setPackKeys($statement->getPackKeys()); $schemaPage->setDelayKeyWrite($statement->getDelayKeyWrite()); $schemaPage->setRowFormat(RowFormat::factory($statement->getRowFormat())); $schemaPage->setInsertMethod(InsertMethod::factory($statement->getInsertMethod())); $databaseSchema->registerTableSchema($schemaPage); /* @var $tableSchema TableSchema */ $tableSchema = $this->schemaManager->getTableSchema($tableName); assert($tableSchema instanceof TableSchema); ### WRITE COLUMNS switch (true) { case is_array($statement->getColumnDefinition()): foreach ($statement->getColumnDefinition() as $name => $column) { /* @var $column ColumnDefinition */ $columnPage = new ColumnSchema(); $columnPage->setName($name); $columnPage->setDataType(DataType::factory($column->getDataType()->getName())); /* @var $dataType DataType */ $dataType = $columnPage->getDataType(); $flags = 0; if ($column->getIsPrimaryKey()) { $flags = $flags ^ ColumnSchema::EXTRA_PRIMARY_KEY; } if ($column->getIsUnique()) { $flags = $flags ^ ColumnSchema::EXTRA_UNIQUE_KEY; } if (!$column->getIsNullable()) { $flags = $flags ^ ColumnSchema::EXTRA_NOT_NULL; } if ($column->getIsAutoIncrement()) { $flags = $flags ^ ColumnSchema::EXTRA_AUTO_INCREMENT; } $columnPage->setExtraFlags($flags); /* @var $dataType DataType */ $dataType = $column->getDataType(); $columnPage->setLength($dataType->getByteLength()); $columnPage->setSecondLength($dataType->getSecondByteLength()); if (!is_null($column->getDataTypeLength())) { $columnPage->setLength($column->getDataTypeLength()); } if (!is_null($column->getDataTypeSecondLength())) { $columnPage->setSecondLength($column->getDataTypeSecondLength()); } if (!is_null($column->getDefaultValue()) && !$columnPage->isDefaultValueInFile()) { $columnPage->setDefaultValue($column->getDefaultValue()); } $columnIndex = $tableSchema->addColumnSchema($columnPage); if (!is_null($column->getDefaultValue()) && $columnPage->isDefaultValueInFile()) { $defaultValueFilepath = sprintf(FilePathes::FILEPATH_DEFAULT_VALUE, $schemaId, $tableName, $columnIndex); $this->tableManager->getFilesystem()->putFileContents($defaultValueFilepath, $column->getDefaultValue()); } } break; case $statement->getColumnDefinition() instanceof Select: break; case $statement->getColumnDefinition() instanceof TableInterface: break; } foreach ($statement->getIndexes() as $indexName => $index) { /* @var $index Index */ $indexSchemaPage = new IndexSchema(); $indexSchemaPage->setName($indexName); $indexSchemaPage->setEngine(IndexEngine::BTREE()); switch (true) { case $index->getIsPrimary(): $indexSchemaPage->setType(IndexType::PRIMARY()); break; case $index->getIsUnique(): $indexSchemaPage->setType(IndexType::UNIQUE()); break; default: $indexSchemaPage->setType(IndexType::INDEX()); break; } $method = ForeignKeyMethod::factory($index->getForeignKeyOnDeleteReferenceOption()->getName()); $indexSchemaPage->setForeignKeyOnDeleteMethod($method); $method = ForeignKeyMethod::factory($index->getForeignKeyOnUpdateReferenceOption()->getName()); $indexSchemaPage->setForeignKeyOnUpdateMethod($method); $keyLength = 0; $columns = array(); foreach ($index->getColumns() as $indexColumnName) { $indexColumnId = $tableSchema->getColumnIndex((string) $indexColumnName); if (strlen($indexColumnId) <= 0) { throw new ErrorException("Could not find index column '{$indexColumnName}' in table-schema!"); } $columns[] = $indexColumnId; $keyLength += $statement->getColumnDefinition()[(string) $indexColumnName]->getDataSize(); } $indexSchemaPage->setColumns($columns); $indexSchemaPage->setKeyLength($keyLength); $tableSchema->addIndexSchema($indexSchemaPage); } foreach ($this->tableManager->getTableFactories() as $tableFactory) { /* @var $tableFactory TableFactoryInterface */ if ($tableFactory instanceof InformationSchemaTableFactory) { $tableFactory->clearCache(); } } ### RESULT $result = new TemporaryResult(); $result->setIsSuccess(true); return $result; }
public function convertBinaryToString($binary, DataType $dataType) { switch ($dataType) { case DataType::BIT(): return $binary; case DataType::BOOL(): break; ### NUMERIC ### NUMERIC case DataType::TINYINT(): return (int) ord($binary); case DataType::SMALLINT(): case DataType::MEDIUMINT(): case DataType::INT(): case DataType::BIGINT(): return $this->strdec($binary); case DataType::DEC(): case DataType::FLOAT(): case DataType::DOUBLE(): return $binary; ### TIME / DATE ### TIME / DATE case DataType::DATE(): return date("Y-m-d", $this->strdec($binary)); case DataType::DATETIME(): return date("Y-m-d H:i:s", $this->strdec($binary)); case DataType::TIMESTAMP(): return date("Y-m-d H:i:s", $this->strdec($binary)); case DataType::TIME(): return date("H:i:s", $this->strdec($binary)); case DataType::YEAR(): return (string) $this->strdec($binary); ### TEXT ### TEXT case DataType::CHAR(): case DataType::VARCHAR(): case DataType::BINARY(): case DataType::VARBINARY(): case DataType::TINYBLOB(): case DataType::TINYTEXT(): case DataType::BLOB(): case DataType::TEXT(): case DataType::MEDIUMBLOB(): case DataType::MEDIUMTEXT(): case DataType::LONGBLOB(): case DataType::LONGTEXT(): case DataType::ENUM(): case DataType::SET(): return $binary; } }
public function dataProviderModifyColumn() { $columnSchema = new ColumnSchema(); $columnSchema->setName("baz"); $columnSchema->setDataType(DataType::VARCHAR()); $columnSchema->setLength(5); return array([[[123, "Lorem ipsum", null], [456, "dolor sit", "2015-06-07 12:34:56"]], $columnSchema, [[789, "amet", "1990-10-02 10:20:30"], [234, "", null]], [['123', "Lorem", null], ['456', "dolor", "2015-06-07 12:34:56"], ['789', "amet", "1990-10-02 10:20:30"], ['234', "", null]]]); }
public function setData($data) { if (strlen($data) !== self::PAGE_SIZE) { throw new \InvalidArgumentException("Invalid data-block given to column-page! (length " . strlen($data) . " != " . self::PAGE_SIZE . ")"); } $rawName = substr($data, 0, 128); $rawIndex = substr($data, 128, 2); $rawDataType = substr($data, 130, 2); $rawLength = substr($data, 132, 16); $rawSecondLength = substr($data, 148, 16); $hasDefaultValue = substr($data, 164, 1); $rawDefaultValue = substr($data, 165, 63); $rawExtra = substr($data, 228, 2); $rawFkTable = substr($data, 230, 8); $rawFkColumn = substr($data, 238, 4); $name = rtrim($rawName, ""); $length = ltrim($rawLength, ""); $secondLength = ltrim($rawSecondLength, ""); $defaultValue = rtrim($rawDefaultValue, ""); $fkTable = ltrim($rawFkTable, ""); $fkColumn = ltrim($rawFkColumn, ""); $dataType = unpack("n", $rawDataType)[1]; $index = unpack("n", $rawIndex)[1]; $length = $this->strdec($length); $secondLength = $this->strdec($secondLength); $extra = unpack("n", $rawExtra)[1]; $fkTable = $this->strdec($fkTable); $fkColumn = $this->strdec($fkColumn); $hasDefaultValue = (bool) ord($hasDefaultValue); if (!$hasDefaultValue) { $defaultValue = null; } $this->setName($name); $this->setIndex($index); $this->setDataType(DataType::getByValue($dataType)); $this->setLength($length); $this->setSecondLength($secondLength); $this->setDefaultValue($defaultValue); $this->setExtraFlags($extra); $this->setFKTableIndex($fkTable); $this->setFKColumnIndex($fkColumn); }