From f3726d01da4b6df6ff8bdb4b4a3e0b189d40cbe0 Mon Sep 17 00:00:00 2001 From: Gerrit Addiks Date: Sun, 24 Jul 2016 23:36:03 +0200 Subject: [PATCH 1/4] fix for show sql parser --- .../PHPSQL/Job/Statement/ShowStatement.php | 46 ++++++++++++-- src/Addiks/PHPSQL/SqlParser/ShowSqlParser.php | 61 +++++++++++++++---- src/Addiks/PHPSQL/SqlParser/SqlParser.php | 1 + src/Addiks/PHPSQL/Value/Enum/Sql/SqlToken.php | 7 ++- 4 files changed, 93 insertions(+), 22 deletions(-) diff --git a/src/Addiks/PHPSQL/Job/Statement/ShowStatement.php b/src/Addiks/PHPSQL/Job/Statement/ShowStatement.php index 71ec9be..73c5fab 100644 --- a/src/Addiks/PHPSQL/Job/Statement/ShowStatement.php +++ b/src/Addiks/PHPSQL/Job/Statement/ShowStatement.php @@ -14,6 +14,7 @@ use Addiks\PHPSQL\Value\Enum\Sql\Show\ShowType; use Addiks\PHPSQL\Job\StatementJob; use Addiks\PHPSQL\Executor\ShowExecutor; +use Addiks\PHPSQL\Job\Part\ValuePart; /** * @@ -24,30 +25,63 @@ class ShowStatement extends StatementJob const EXECUTOR_CLASS = ShowExecutor::class; private $type; - + public function setType(ShowType $type) { $this->type = $type; } - + public function getType() { return $this->type; } - + private $database; - + public function setDatabase($database) { $this->database = (string)$database; } - + public function getDatabase() { return $this->database; } - + public function getResultSpecifier() { } + + protected $isFull = false; + + public function setIsFull($isFull) + { + $this->isFull = (bool)$isFull; + } + + public function isFull() + { + return $this->isFull; + } + + /** + * @var ValuePart + */ + protected $conditionValue; + + public function setConditionValue(ValuePart $conditionValue) + { + if (is_null($conditionValue)) { + $this->conditionValue = null; + + } else { + $this->conditionValue = $conditionValue; + } + } + + public function getConditionValue() + { + return $this->conditionValue; + } + } diff --git a/src/Addiks/PHPSQL/SqlParser/ShowSqlParser.php b/src/Addiks/PHPSQL/SqlParser/ShowSqlParser.php index 56b4ee5..250e066 100644 --- a/src/Addiks/PHPSQL/SqlParser/ShowSqlParser.php +++ b/src/Addiks/PHPSQL/SqlParser/ShowSqlParser.php @@ -11,60 +11,95 @@ namespace Addiks\PHPSQL\SqlParser; +use ErrorException; use Addiks\PHPSQL\Value\Enum\Sql\Show\ShowType; use Addiks\PHPSQL\Job\Statement\ShowStatement; use Addiks\PHPSQL\Value\Enum\Sql\SqlToken; use Addiks\PHPSQL\Iterators\SQLTokenIterator; use Addiks\PHPSQL\SqlParser\SqlParser; - use Addiks\PHPSQL\Iterators\TokenIterator; +use Addiks\PHPSQL\Exception\MalformedSqlException; +use Addiks\PHPSQL\SqlParser\Part\ValueParser; +use Addiks\PHPSQL\Job\Part\ValuePart; class ShowSqlParser extends SqlParser { - + + /** + * @var ValueParser + */ + protected $valueParser; + + public function setValueParser(ValueParser $valueParser) + { + $this->valueParser = $valueParser; + } + + public function getValueParser() + { + return $this->valueParser; + } + public function canParseTokens(SQLTokenIterator $tokens) { return is_int($tokens->isTokenNum(SqlToken::T_SHOW(), TokenIterator::CURRENT)) || is_int($tokens->isTokenNum(SqlToken::T_SHOW(), TokenIterator::NEXT)); } - + 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; } } diff --git a/src/Addiks/PHPSQL/SqlParser/SqlParser.php b/src/Addiks/PHPSQL/SqlParser/SqlParser.php index d76409e..b2bb748 100644 --- a/src/Addiks/PHPSQL/SqlParser/SqlParser.php +++ b/src/Addiks/PHPSQL/SqlParser/SqlParser.php @@ -198,6 +198,7 @@ public function initSqlSubParsers() $selectParser->setJoinParser($joinParser); $selectParser->setFunctionParser($functionParser); $selectParser->setParenthesisParser($parenthesisParser); + $showParser->setValueParser($valueParser); $setParser->setValueParser($valueParser); $updateParser->setTableParser($tableParser); $updateParser->setColumnParser($columnParser); diff --git a/src/Addiks/PHPSQL/Value/Enum/Sql/SqlToken.php b/src/Addiks/PHPSQL/Value/Enum/Sql/SqlToken.php index b2e3070..304361c 100644 --- a/src/Addiks/PHPSQL/Value/Enum/Sql/SqlToken.php +++ b/src/Addiks/PHPSQL/Value/Enum/Sql/SqlToken.php @@ -15,8 +15,8 @@ class SqlToken extends Enum { - -/* + +/* # PostgreSql keywords: const T_ABORT = 1; const T_ABS = 2; @@ -538,7 +538,7 @@ class SqlToken extends Enum const T_YEAR = 521; const T_ZONE = 522; */ - + # FOR (MYSQL) SELECT # const T_DISTINCTROW = 523; # const T_HIGH_PRIORITY = 524; @@ -554,6 +554,7 @@ class SqlToken extends Enum # const T_DATABASES = 532; const T_TABLES = 533; const T_VIEWS = 534; + const T_FULL = 585; # FOR DROP # const T_IF = 535; From 8c3af5f8906c351a26c7e9f7c3c6a6a2b773d31a Mon Sep 17 00:00:00 2001 From: Gerrit Addiks Date: Mon, 25 Jul 2016 09:44:05 +0200 Subject: [PATCH 2/4] added alias-iterator to be able to access table-columns by alias in source-result-set --- .../StatementExecutor/SelectExecutor.php | 3 + src/Addiks/PHPSQL/Table/TableSchema.php | 66 +++++++++---------- .../PHPSQL/ValueResolver/ValueResolver.php | 8 +-- 3 files changed, 40 insertions(+), 37 deletions(-) diff --git a/src/Addiks/PHPSQL/StatementExecutor/SelectExecutor.php b/src/Addiks/PHPSQL/StatementExecutor/SelectExecutor.php index 79eae3f..5143081 100644 --- a/src/Addiks/PHPSQL/StatementExecutor/SelectExecutor.php +++ b/src/Addiks/PHPSQL/StatementExecutor/SelectExecutor.php @@ -46,6 +46,7 @@ use Addiks\PHPSQL\Value\Specifier\ColumnSpecifier; use Addiks\PHPSQL\Index\IndexSchema; use Addiks\PHPSQL\Iterators\UsesBinaryDataInterface; +use Addiks\PHPSQL\Iterators\AliasedResourceIterator; class SelectExecutor implements StatementExecutorInterface { @@ -266,6 +267,8 @@ public function executeJob(StatementJob $statement, array $parameters = array()) } else { throw new ErrorException("Unexpected object given as source for join!"); } + + $iterator = new AliasedResourceIterator($iterator, $alias); } ### FILTER RESULT diff --git a/src/Addiks/PHPSQL/Table/TableSchema.php b/src/Addiks/PHPSQL/Table/TableSchema.php index ec3a230..d4b9090 100644 --- a/src/Addiks/PHPSQL/Table/TableSchema.php +++ b/src/Addiks/PHPSQL/Table/TableSchema.php @@ -104,37 +104,37 @@ public function getIndexIterator() } ]); } - + public function getIndexIdByColumns($columnIds) { $indexId = null; - + foreach ($this->getIndexIterator() as $currentIndexId => $indexSchema) { /* @var $indexSchema IndexSchema */ - + if (count($indexSchema->getColumns()) !== count($columnIds)) { continue; } - + foreach ($indexSchema->getColumns() as $columnId) { if (!in_array($columnId, $columnIds)) { continue 2; } } - + $indexId = $currentIndexId; } - + return $indexId; } public function getIndexIdByName($name) { $indexId = null; - + foreach ($this->getIndexIterator() as $currentIndexId => $indexSchema) { /* @var $indexSchema IndexSchema */ - + if ($indexSchema->getName() === $name) { $indexId = $currentIndexId; } @@ -142,18 +142,18 @@ public function getIndexIdByName($name) return $indexId; } - + public function indexExist($name) { - + foreach ($this->getIndexIterator() as $indexId => $indexSchema) { /* @var $indexSchema IndexSchema */ - + if ($indexSchema->getName()) { return true; } } - + return false; } @@ -166,11 +166,11 @@ public function addColumnSchema(ColumnSchema $column) } else { $writeIndex = $this->getLastIndex()+1; } - + $column->setIndex($writeIndex); $this->writeColumn($writeIndex, $column); - + return $writeIndex; } @@ -294,7 +294,7 @@ public function listColumns() $columns[$index] = clone $columnPage; assert(is_int($index) && $index >= 0); - + $this->columnCache[$index] = $columns[$index]; } @@ -332,45 +332,45 @@ public function hasColumn($column) } private $columnCache = array(); - + public function getColumnCache() { return $this->columnCache; } - + public function dropColumnCache() { $this->columnCache = array(); } - + public function getColumn($index) { if (!is_numeric($index)) { $index = $this->getColumnIndex($index); } - + assert(is_numeric($index) && $index >= 0); $index = (int)$index; if (!isset($this->columnCache[$index])) { $file = $this->getColumnFile(); - + $position = $index * ColumnSchema::PAGE_SIZE; - + $file->seek($position, SEEK_SET); $data = $file->read(ColumnSchema::PAGE_SIZE); - + if (strlen($data) !== ColumnSchema::PAGE_SIZE) { return null; } - + $column = new ColumnSchema(); $column->setData($data); $column->setId($index); - + $this->columnCache[$index] = $column; } - + return $this->columnCache[$index]; } @@ -389,7 +389,7 @@ public function getColumnIndex($columnName) return $index; } } - + foreach ($this->getColumnIterator() as $index => $columnPage) { /* @var $columnPage ColumnSchema */ @@ -415,11 +415,11 @@ public function writeColumn($index = null, ColumnSchema $column) $columnId = $this->getColumnIndex($column->getName()); assert(is_null($columnId) || ($columnId === $index)); } - + assert(is_int($index) && $index >= 0); $this->columnCache[$index] = $column; - + $file = $this->getColumnFile(); $file->lock(LOCK_EX); @@ -431,17 +431,17 @@ public function writeColumn($index = null, ColumnSchema $column) return $index; } - + public function removeColumn($index) { - + $file = $this->getColumnFile(); - + $file->lock(LOCK_EX); $file->seek(ColumnSchema::PAGE_SIZE * $index, SEEK_SET); - + $file->write(str_pad("", ColumnSchema::PAGE_SIZE, "\0")); - + $file->lock(LOCK_UN); } diff --git a/src/Addiks/PHPSQL/ValueResolver/ValueResolver.php b/src/Addiks/PHPSQL/ValueResolver/ValueResolver.php index e5a3cef..8fc5be8 100644 --- a/src/Addiks/PHPSQL/ValueResolver/ValueResolver.php +++ b/src/Addiks/PHPSQL/ValueResolver/ValueResolver.php @@ -292,11 +292,11 @@ public function resolveValueJob(ValuePart $valueJob, ExecutionContext $context) public function resolveCondition(ConditionJob $conditionJob, ExecutionContext $context) { - $firstValue = $conditionJob->getFirstParameter(); - $lastValue = $conditionJob->getLastParameter(); + $firstValueUnresolved = $conditionJob->getFirstParameter(); + $lastValueUnresolved = $conditionJob->getLastParameter(); - $firstValue = $this->resolveValue($firstValue, $context); - $lastValue = $this->resolveValue($lastValue, $context); + $firstValue = $this->resolveValue($firstValueUnresolved, $context); + $lastValue = $this->resolveValue($lastValueUnresolved, $context); switch($conditionJob->getOperator()){ case Operator::OP_ADDITION(): From 0d67be08fdeee2dd8741bfda0c99c6c98bbf0c00 Mon Sep 17 00:00:00 2001 From: Gerrit Addiks Date: Mon, 25 Jul 2016 09:44:39 +0200 Subject: [PATCH 3/4] actually added the aliased-iterator... --- .../Iterators/AliasedResourceIterator.php | 237 ++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 src/Addiks/PHPSQL/Iterators/AliasedResourceIterator.php diff --git a/src/Addiks/PHPSQL/Iterators/AliasedResourceIterator.php b/src/Addiks/PHPSQL/Iterators/AliasedResourceIterator.php new file mode 100644 index 0000000..34853c2 --- /dev/null +++ b/src/Addiks/PHPSQL/Iterators/AliasedResourceIterator.php @@ -0,0 +1,237 @@ + or send me a mail so i can send you a copy. + * @license GPL-3.0 + * @author Gerrit Addiks + */ + +namespace Addiks\PHPSQL\Iterators; + +use Iterator; +use Addiks\PHPSQL\Iterators\DataProviderInterface; +use Addiks\PHPSQL\Iterators\UsesBinaryDataInterface; +use IteratorAggregate; + +class AliasedResourceIterator implements Iterator, DataProviderInterface, UsesBinaryDataInterface +{ + + public function __construct( + DataProviderInterface $dataProvider, + $alias + ) { + $this->dataProvider = $dataProvider; + $this->alias = $alias; + } + + /** + * @var DataProviderInterface + */ + protected $dataProvider; + + /** + * @var string + */ + protected $alias; + + /** + * + * @return TableSchema + */ + public function getTableSchema() + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + return $dataProvider->getTableSchema(); + } + + public function doesRowExists($rowId = null) + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + return $dataProvider->doesRowExists($rowId); + } + + public function getRowData($rowId = null) + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + return $dataProvider->getRowData($rowId); + } + + public function getCellData($rowId, $columnId) + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + return $dataProvider->getCellData($rowId, $columnId); + } + + public function tell() + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + return $dataProvider->tell(); + } + + public function seek($rowId) + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + return $dataProvider->seek($rowId); + } + + public function count() + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + return $dataProvider->count(); + } + + public function usesBinaryData() + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + /* @var $usesBinaryData boolean */ + $usesBinaryData = false; + + if ($dataProvider instanceof UsesBinaryDataInterface) { + $usesBinaryData = $dataProvider->usesBinaryData(); + } + + return $usesBinaryData; + } + + public function convertDataRowToStringRow(array $row) + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + /* @var $convertedRow array */ + $convertedRow = $row; + + #if ($dataProvider instanceof UsesBinaryDataInterface && $dataProvider->usesBinaryData()) { + # $convertedRow = $dataProvider->convertDataRowToStringRow($row); + #} + + return $convertedRow; + } + + public function convertStringRowToDataRow(array $row) + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + /* @var $convertedRow array */ + $convertedRow = $row; + + if ($dataProvider instanceof UsesBinaryDataInterface && $dataProvider->usesBinaryData()) { + $convertedRow = $dataProvider->convertStringRowToDataRow($row); + } + + return $convertedRow; + } + + public function rewind() + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + if ($dataProvider instanceof IteratorAggregate) { + $dataProvider = $dataProvider->getIterator(); + } + + if ($dataProvider instanceof Iterator) { + $dataProvider->rewind(); + } + } + + public function valid() + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + if ($dataProvider instanceof IteratorAggregate) { + $dataProvider = $dataProvider->getIterator(); + } + + if ($dataProvider instanceof Iterator) { + return $dataProvider->valid(); + } + } + + public function key() + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + if ($dataProvider instanceof IteratorAggregate) { + $dataProvider = $dataProvider->getIterator(); + } + + if ($dataProvider instanceof Iterator) { + return $dataProvider->key(); + } + } + + public function current() + { + /* @var $row array */ + $row = null; + + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + /* @var $alias string */ + $alias = $this->alias; + + /* @var $iterator Iterator */ + $iterator = $dataProvider; + + if ($iterator instanceof IteratorAggregate) { + $iterator = $iterator->getIterator(); + } + + if ($dataProvider instanceof Iterator) { + $row = $dataProvider->current(); + + if ($dataProvider instanceof UsesBinaryDataInterface && $dataProvider->usesBinaryData()) { + $row = $dataProvider->convertDataRowToStringRow($row); + } + + /* @var $newRow array */ + $newRow = $row; + + foreach ($row as $key => $value) { + $newRow["{$alias}.{$key}"] = $value; + } + + $row = $newRow; + } + + return $row; + } + + public function next() + { + /* @var $dataProvider DataProviderInterface */ + $dataProvider = $this->dataProvider; + + if ($dataProvider instanceof IteratorAggregate) { + $dataProvider = $dataProvider->getIterator(); + } + + if ($dataProvider instanceof Iterator) { + $dataProvider->next(); + } + } +} From 24a74e6e968ae66f093d80c7d24a49d25c8ae9bf Mon Sep 17 00:00:00 2001 From: Gerrit Addiks Date: Mon, 25 Jul 2016 10:37:16 +0200 Subject: [PATCH 4/4] fixes --- src/Addiks/PHPSQL/SqlParser/CreateSqlParser.php | 6 +++--- .../PHPSQL/StatementExecutor/CreateTableExecutor.php | 1 + src/Addiks/PHPSQL/Value/Enum/Page/Column/DataType.php | 9 +++++---- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/Addiks/PHPSQL/SqlParser/CreateSqlParser.php b/src/Addiks/PHPSQL/SqlParser/CreateSqlParser.php index a277816..f5b7474 100644 --- a/src/Addiks/PHPSQL/SqlParser/CreateSqlParser.php +++ b/src/Addiks/PHPSQL/SqlParser/CreateSqlParser.php @@ -335,8 +335,8 @@ protected function parseCreateTable(SQLTokenIterator $tokens) case $tokens->seekTokenNum(SqlToken::T_FULLTEXT(), TokenIterator::NEXT, [SqlToken::T_CONSTRAINT(), T_STRING]): case $tokens->seekTokenNum(SqlToken::T_SPATIAL(), TokenIterator::NEXT, [SqlToken::T_CONSTRAINT(), T_STRING]): - /* @var $indexJob Index */ - $indexJob = new Index(); + /* @var $indexJob IndexPart */ + $indexJob = new IndexPart(); switch($tokens->getCurrentTokenNumber()){ case SqlToken::T_UNIQUE(): @@ -881,6 +881,6 @@ protected function parseCreateIndex(SQLTokenIterator $tokens) protected function parseCreateView(SQLTokenIterator $tokens) { - + } } diff --git a/src/Addiks/PHPSQL/StatementExecutor/CreateTableExecutor.php b/src/Addiks/PHPSQL/StatementExecutor/CreateTableExecutor.php index 9e967e5..7e74df3 100644 --- a/src/Addiks/PHPSQL/StatementExecutor/CreateTableExecutor.php +++ b/src/Addiks/PHPSQL/StatementExecutor/CreateTableExecutor.php @@ -147,6 +147,7 @@ public function executeJob(StatementJob $statement, array $parameters = array()) $columnPage->setExtraFlags($flags); + /* @var $dataType DataType */ $dataType = $column->getDataType(); $columnPage->setLength($dataType->getByteLength()); diff --git a/src/Addiks/PHPSQL/Value/Enum/Page/Column/DataType.php b/src/Addiks/PHPSQL/Value/Enum/Page/Column/DataType.php index b0506a3..842dd55 100644 --- a/src/Addiks/PHPSQL/Value/Enum/Page/Column/DataType.php +++ b/src/Addiks/PHPSQL/Value/Enum/Page/Column/DataType.php @@ -15,9 +15,9 @@ class DataType extends Enum { - + ### NUMBERS - + const BIT = 0x01; const BOOL = 0x02; const BOOLEAN = 0x02; @@ -32,7 +32,7 @@ class DataType extends Enum const FLOAT = 0x09; const DOUBLE = 0x0A; const DOUBLE_PRECISION = 0x0A; - + ### DATE / TIME const DATE = 0x0B; @@ -40,7 +40,7 @@ class DataType extends Enum const TIMESTAMP = 0x0D; const TIME = 0x0E; const YEAR = 0x0F; - + ### STRING const CHAR = 0x10; @@ -118,6 +118,7 @@ public function getByteLength() self::MEDIUMBLOB => 4294967296, self::MEDIUMTEXT => 4294967296, self::LONGBLOB => 4294967296, + self::LONGTEXT => 4294967296, ); $flag = $this->getValue();