diff --git a/.gitignore b/.gitignore index fe8fcf49..3c0d23a8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ vendor/ composer.lock -clover.xml \ No newline at end of file +clover.xml +composer.phar diff --git a/src/PHPSQLParser/PHPSQLCreator.php b/src/PHPSQLParser/PHPSQLCreator.php index 54a4e689..954790b3 100644 --- a/src/PHPSQLParser/PHPSQLCreator.php +++ b/src/PHPSQLParser/PHPSQLCreator.php @@ -43,11 +43,13 @@ use PHPSQLParser\exceptions\UnsupportedFeatureException; use PHPSQLParser\builders\SelectStatementBuilder; use PHPSQLParser\builders\DeleteStatementBuilder; +use PHPSQLParser\builders\TruncateStatementBuilder; use PHPSQLParser\builders\UpdateStatementBuilder; use PHPSQLParser\builders\InsertStatementBuilder; use PHPSQLParser\builders\CreateStatementBuilder; use PHPSQLParser\builders\DropStatementBuilder; use PHPSQLParser\builders\RenameStatementBuilder; +use PHPSQLParser\builders\ReplaceStatementBuilder; use PHPSQLParser\builders\ShowStatementBuilder; use PHPSQLParser\builders\BracketStatementBuilder; use PHPSQLParser\builders\UnionStatementBuilder; @@ -88,10 +90,18 @@ public function create($parsed) { $builder = new InsertStatementBuilder(); $this->created = $builder->build($parsed); break; + case 'REPLACE': + $builder = new ReplaceStatementBuilder(); + $this->created = $builder->build($parsed); + break; case 'DELETE': $builder = new DeleteStatementBuilder(); $this->created = $builder->build($parsed); break; + case 'TRUNCATE': + $builder = new TruncateStatementBuilder(); + $this->created = $builder->build($parsed); + break; case 'UPDATE': $builder = new UpdateStatementBuilder(); $this->created = $builder->build($parsed); diff --git a/src/PHPSQLParser/builders/FunctionBuilder.php b/src/PHPSQLParser/builders/FunctionBuilder.php index bd5d0bac..ee22a0dc 100644 --- a/src/PHPSQLParser/builders/FunctionBuilder.php +++ b/src/PHPSQLParser/builders/FunctionBuilder.php @@ -87,7 +87,12 @@ protected function buildSelectBracketExpression($parsed) { $builder = new SelectBracketExpressionBuilder(); return $builder->build($parsed); } - + + protected function buildSubQuery($parsed) { + $builder = new SubQueryBuilder(); + return $builder->build($parsed); + } + public function build(array $parsed) { if (($parsed['expr_type'] !== ExpressionType::AGGREGATE_FUNCTION) && ($parsed['expr_type'] !== ExpressionType::SIMPLE_FUNCTION) @@ -104,6 +109,7 @@ public function build(array $parsed) { $len = strlen($sql); $sql .= $this->build($v); $sql .= $this->buildConstant($v); + $sql .= $this->buildSubQuery($v); $sql .= $this->buildColRef($v); $sql .= $this->buildReserved($v); $sql .= $this->buildSelectBracketExpression($v); diff --git a/src/PHPSQLParser/builders/InsertStatementBuilder.php b/src/PHPSQLParser/builders/InsertStatementBuilder.php index 0a079a2f..fb0cdb8e 100644 --- a/src/PHPSQLParser/builders/InsertStatementBuilder.php +++ b/src/PHPSQLParser/builders/InsertStatementBuilder.php @@ -65,13 +65,21 @@ protected function buildSELECT($parsed) { $builder = new SelectStatementBuilder(); return $builder->build($parsed); } - + + protected function buildSET($parsed) { + $builder = new SetBuilder(); + return $builder->build($parsed); + } + public function build(array $parsed) { // TODO: are there more than one tables possible (like [INSERT][1]) $sql = $this->buildINSERT($parsed['INSERT']); if (isset($parsed['VALUES'])) { $sql .= ' ' . $this->buildVALUES($parsed['VALUES']); } + if (isset($parsed['SET'])) { + $sql .= ' ' . $this->buildSET($parsed['SET']); + } if (isset($parsed['SELECT'])) { $sql .= ' ' . $this->buildSELECT($parsed); } diff --git a/src/PHPSQLParser/builders/ReplaceBuilder.php b/src/PHPSQLParser/builders/ReplaceBuilder.php new file mode 100644 index 00000000..b4e7caff --- /dev/null +++ b/src/PHPSQLParser/builders/ReplaceBuilder.php @@ -0,0 +1,100 @@ + + * @copyright 2010-2014 Justin Swanhart and André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * @version SVN: $Id$ + * + */ + +namespace PHPSQLParser\builders; +use PHPSQLParser\exceptions\UnableToCreateSQLException; + +/** + * This class implements the builder for the [REPLACE] statement parts. + * You can overwrite all functions to achieve another handling. + * + * @author André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * + */ +class ReplaceBuilder implements Builder { + + protected function buildTable($parsed) { + $builder = new TableBuilder(); + return $builder->build($parsed, 0); + } + + protected function buildSubQuery($parsed) { + $builder = new SubQueryBuilder(); + return $builder->build($parsed, 0); + } + + protected function buildReserved($parsed) { + $builder = new ReservedBuilder(); + return $builder->build($parsed); + } + + protected function buildBracketExpression($parsed) { + $builder = new SelectBracketExpressionBuilder(); + return $builder->build($parsed); + } + + protected function buildColumnList($parsed) { + $builder = new ReplaceColumnListBuilder(); + return $builder->build($parsed, 0); + } + + public function build(array $parsed) { + $sql = ''; + foreach ($parsed as $k => $v) { + $len = strlen($sql); + $sql .= $this->buildTable($v); + $sql .= $this->buildSubQuery($v); + $sql .= $this->buildColumnList($v); + $sql .= $this->buildReserved($v); + $sql .= $this->buildBracketExpression($v); + + if ($len == strlen($sql)) { + throw new UnableToCreateSQLException('REPLACE', $k, $v, 'expr_type'); + } + + $sql .= " "; + } + return 'REPLACE ' . substr($sql, 0, -1); + } + +} +?> diff --git a/src/PHPSQLParser/builders/ReplaceColumnListBuilder.php b/src/PHPSQLParser/builders/ReplaceColumnListBuilder.php new file mode 100644 index 00000000..45066964 --- /dev/null +++ b/src/PHPSQLParser/builders/ReplaceColumnListBuilder.php @@ -0,0 +1,80 @@ + + * @copyright 2010-2014 Justin Swanhart and André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * @version SVN: $Id$ + * + */ + +namespace PHPSQLParser\builders; +use PHPSQLParser\exceptions\UnableToCreateSQLException; +use PHPSQLParser\utils\ExpressionType; + +/** + * This class implements the builder for column-list parts of REPLACE statements. + * You can overwrite all functions to achieve another handling. + * + * @author André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * + */ +class ReplaceColumnListBuilder implements Builder { + + protected function buildColumn($parsed) { + $builder = new ColumnReferenceBuilder(); + return $builder->build($parsed); + } + + public function build(array $parsed) { + if ($parsed['expr_type'] !== ExpressionType::COLUMN_LIST) { + return ""; + } + $sql = ""; + foreach ($parsed['sub_tree'] as $k => $v) { + $len = strlen($sql); + $sql .= $this->buildColumn($v); + + if ($len == strlen($sql)) { + throw new UnableToCreateSQLException('REPLACE column-list subtree', $k, $v, 'expr_type'); + } + + $sql .= ", "; + } + return "(" . substr($sql, 0, -2) . ")"; + } + +} +?> diff --git a/src/PHPSQLParser/builders/ReplaceStatementBuilder.php b/src/PHPSQLParser/builders/ReplaceStatementBuilder.php new file mode 100644 index 00000000..5a30e05c --- /dev/null +++ b/src/PHPSQLParser/builders/ReplaceStatementBuilder.php @@ -0,0 +1,89 @@ + + * @copyright 2010-2014 Justin Swanhart and André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * @version SVN: $Id$ + * + */ + +namespace PHPSQLParser\builders; + +/** + * This class implements the builder for the whole Replace statement. You can overwrite + * all functions to achieve another handling. + * + * @author André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * + */ +class ReplaceStatementBuilder implements Builder { + + protected function buildVALUES($parsed) { + $builder = new ValuesBuilder(); + return $builder->build($parsed); + } + + protected function buildREPLACE($parsed) { + $builder = new ReplaceBuilder(); + return $builder->build($parsed); + } + + protected function buildSELECT($parsed) { + $builder = new SelectStatementBuilder(); + return $builder->build($parsed); + } + + protected function buildSET($parsed) { + $builder = new SetBuilder(); + return $builder->build($parsed); + } + + public function build(array $parsed) { + // TODO: are there more than one tables possible (like [REPLACE][1]) + $sql = $this->buildREPLACE($parsed['REPLACE']); + if (isset($parsed['VALUES'])) { + $sql .= ' ' . $this->buildVALUES($parsed['VALUES']); + } + if (isset($parsed['SET'])) { + $sql .= ' ' . $this->buildSET($parsed['SET']); + } + if (isset($parsed['SELECT'])) { + $sql .= ' ' . $this->buildSELECT($parsed); + } + return $sql; + } +} +?> diff --git a/src/PHPSQLParser/builders/SelectStatementBuilder.php b/src/PHPSQLParser/builders/SelectStatementBuilder.php index c7553249..5fc8b125 100644 --- a/src/PHPSQLParser/builders/SelectStatementBuilder.php +++ b/src/PHPSQLParser/builders/SelectStatementBuilder.php @@ -85,6 +85,16 @@ protected function buildLIMIT($parsed) { $builder = new LimitBuilder(); return $builder->build($parsed); } + + protected function buildUNION($parsed) { + $builder = new UnionStatementBuilder(); + return $builder->build($parsed); + } + + protected function buildUNIONALL($parsed) { + $builder = new UnionAllStatementBuilder(); + return $builder->build($parsed); + } public function build(array $parsed) { $sql = ""; @@ -108,6 +118,12 @@ public function build(array $parsed) { } if (isset($parsed['LIMIT'])) { $sql .= " " . $this->buildLIMIT($parsed['LIMIT']); + } + if (isset($parsed['UNION'])) { + $sql .= " " . $this->buildUNION($parsed); + } + if (isset($parsed['UNION ALL'])) { + $sql .= " " . $this->buildUNIONALL($parsed); } return $sql; } diff --git a/src/PHPSQLParser/builders/TruncateBuilder.php b/src/PHPSQLParser/builders/TruncateBuilder.php new file mode 100644 index 00000000..1caffea9 --- /dev/null +++ b/src/PHPSQLParser/builders/TruncateBuilder.php @@ -0,0 +1,71 @@ + + * @copyright 2010-2014 Justin Swanhart and André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * @version SVN: $Id$ + * + */ + +namespace PHPSQLParser\builders; + +/** + * This class implements the builder for the [TRUNCATE] part. You can overwrite + * all functions to achieve another handling. + * + * @author André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * + */ +class TruncateBuilder implements Builder { + + public function build(array $parsed) { + $sql = "TRUNCATE TABLE "; + $right = -1; + + // works for one table only + $parsed['tables'] = array($parsed['TABLE']['base_expr']); + + if ($parsed['tables'] !== false) { + foreach ($parsed['tables'] as $k => $v) { + $sql .= $v . ", "; + $right = -2; + } + } + + return substr($sql, 0, $right); + } +} +?> diff --git a/src/PHPSQLParser/builders/TruncateStatementBuilder.php b/src/PHPSQLParser/builders/TruncateStatementBuilder.php new file mode 100644 index 00000000..1fcea20c --- /dev/null +++ b/src/PHPSQLParser/builders/TruncateStatementBuilder.php @@ -0,0 +1,72 @@ + + * @copyright 2010-2014 Justin Swanhart and André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * @version SVN: $Id$ + * + */ + +namespace PHPSQLParser\builders; + +/** + * This class implements the builder for the whole Truncate statement. You can overwrite + * all functions to achieve another handling. + * + * @author André Rothe + * @license http://www.debian.org/misc/bsd.license BSD License (3 Clause) + * + */ +class TruncateStatementBuilder implements Builder { + + protected function buildTRUNCATE($parsed) { + $builder = new TruncateBuilder(); + return $builder->build($parsed); + } + + protected function buildFROM($parsed) { + $builder = new FromBuilder(); + return $builder->build($parsed); + } + + public function build(array $parsed) { + $sql = $this->buildTRUNCATE($parsed); + // $sql .= " " . $this->buildTRUNCATE($parsed) // Uncomment when parser fills in expr_type=table + + return $sql; + } + +} +?> diff --git a/src/PHPSQLParser/positions/PositionCalculator.php b/src/PHPSQLParser/positions/PositionCalculator.php index 570dc7cd..9eb90d63 100644 --- a/src/PHPSQLParser/positions/PositionCalculator.php +++ b/src/PHPSQLParser/positions/PositionCalculator.php @@ -133,6 +133,8 @@ protected function findPositionWithinString($sql, $value, $expr_type) { while (true) { $pos = strpos($sql, $value, $offset); + // error_log("pos:$pos value:$value sql:$sql"); + if ($pos === false) { break; } diff --git a/src/PHPSQLParser/processors/SQLProcessor.php b/src/PHPSQLParser/processors/SQLProcessor.php index a39731b5..f8732879 100644 --- a/src/PHPSQLParser/processors/SQLProcessor.php +++ b/src/PHPSQLParser/processors/SQLProcessor.php @@ -309,6 +309,10 @@ public function process($tokens) { $out[$prev_category][] = $trim; $token_category = $upper; } + if ($prev_category === 'TRUNCATE') { + $out[$prev_category][] = $trim; + $token_category = $upper; + } break; case 'TEMPORARY':