From 2f694bfe89b088d5a7037298fa35449d91d816c6 Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 24 Jan 2017 16:04:02 +0000 Subject: [PATCH 1/9] Fixed namespacing for creator uniontest --- tests/cases/creator/unionTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/cases/creator/unionTest.php b/tests/cases/creator/unionTest.php index aa3c51a7..cc7c3be8 100644 --- a/tests/cases/creator/unionTest.php +++ b/tests/cases/creator/unionTest.php @@ -37,7 +37,7 @@ * @version SVN: $Id$ * */ -namespace PHPSQLParser\Test\Parser; +namespace PHPSQLParser\Test\Creator; use PHPSQLParser\PHPSQLParser; use PHPSQLParser\PHPSQLCreator; use Analog\Analog; From f3a5333533108e123b21dc6cb13c8effb128ba1e Mon Sep 17 00:00:00 2001 From: dave Date: Tue, 24 Jan 2017 17:32:13 +0000 Subject: [PATCH 2/9] Fixed multi line comment test Test was failing due to an issue with encoding and line endings. Unserialization was failing because amount of characters serialized for the multi line string differs on different environments. Added new test function to deal with data returned directly from a php file instead. --- tests/bootstrap.php | 5 ++ tests/cases/parser/commentsTest.php | 2 +- tests/expected/parser/comment2.php | 69 +++++++++++++++++++++++ tests/expected/parser/comment2.serialized | 4 -- 4 files changed, 75 insertions(+), 5 deletions(-) create mode 100644 tests/expected/parser/comment2.php delete mode 100644 tests/expected/parser/comment2.serialized diff --git a/tests/bootstrap.php b/tests/bootstrap.php index e83363fd..08b402e0 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -14,4 +14,9 @@ function getExpectedValue($path, $filename, $unserialize = true) { $content = file_get_contents(dirname(__FILE__) . "/expected/" . array_pop($path) . "/" . $filename); return ($unserialize ? unserialize($content) : $content); } + +function getExpectedValueFromPhpFile($path, $filename) { + $path = explode(DIRECTORY_SEPARATOR, $path); + return include(dirname(__FILE__) . "/expected/" . array_pop($path) . "/" . $filename); +} ?> diff --git a/tests/cases/parser/commentsTest.php b/tests/cases/parser/commentsTest.php index e6f4a18d..a726b5a1 100644 --- a/tests/cases/parser/commentsTest.php +++ b/tests/cases/parser/commentsTest.php @@ -32,7 +32,7 @@ public function testComments2() { b FROM test'; $p = $this->parser->parse($sql); - $expected = getExpectedValue(dirname(__FILE__), 'comment2.serialized'); + $expected = getExpectedValueFromPhpFile(dirname(__FILE__), 'comment2.php'); $this->assertEquals($expected, $p, 'multi line comment'); } diff --git a/tests/expected/parser/comment2.php b/tests/expected/parser/comment2.php new file mode 100644 index 00000000..5f1c26e4 --- /dev/null +++ b/tests/expected/parser/comment2.php @@ -0,0 +1,69 @@ + + array ( + 0 => + array ( + 'expr_type' => 'colref', + 'alias' => false, + 'base_expr' => 'a', + 'no_quotes' => + array ( + 'delim' => false, + 'parts' => + array ( + 0 => 'a', + ), + ), + 'sub_tree' => false, + 'delim' => ',', + ), + 1 => + array ( + 'expr_type' => 'comment', + 'value' => '/* + multi line + comment + */', + ), + 2 => + array ( + 'expr_type' => 'colref', + 'alias' => false, + 'base_expr' => 'b', + 'no_quotes' => + array ( + 'delim' => false, + 'parts' => + array ( + 0 => 'b', + ), + ), + 'sub_tree' => false, + 'delim' => false, + ), + ), + 'FROM' => + array ( + 0 => + array ( + 'expr_type' => 'table', + 'table' => 'test', + 'no_quotes' => + array ( + 'delim' => false, + 'parts' => + array ( + 0 => 'test', + ), + ), + 'alias' => false, + 'hints' => false, + 'join_type' => 'JOIN', + 'ref_type' => false, + 'ref_clause' => false, + 'base_expr' => 'test', + 'sub_tree' => false, + ), + ), +); \ No newline at end of file diff --git a/tests/expected/parser/comment2.serialized b/tests/expected/parser/comment2.serialized deleted file mode 100644 index 3b769a5c..00000000 --- a/tests/expected/parser/comment2.serialized +++ /dev/null @@ -1,4 +0,0 @@ -a:2:{s:6:"SELECT";a:3:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:8:"sub_tree";b:0;s:5:"delim";s:1:",";}i:1;a:2:{s:9:"expr_type";s:7:"comment";s:5:"value";s:109:"/* - multi line - comment - */";}i:2;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:4:"test";s:8:"sub_tree";b:0;}}} \ No newline at end of file From a787db743ded9c0b6bec858aff8bccceaa9567b5 Mon Sep 17 00:00:00 2001 From: dave Date: Fri, 3 Feb 2017 20:27:23 +0100 Subject: [PATCH 3/9] Fix for ORDER BY not being returned for issue117 Multi bracketed expressions now return the lost clauses, which get passed back to the chunk processor fully parsed. The chunk processor handles the result in a similar way to the returned bracket clause. --- .../processors/BracketProcessor.php | 20 +++++++++++++++++-- .../processors/SQLChunkProcessor.php | 14 ++++++++++++- tests/cases/parser/issue117Test.php | 16 ++++++++------- tests/expected/parser/issue117.serialized | 2 +- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/src/PHPSQLParser/processors/BracketProcessor.php b/src/PHPSQLParser/processors/BracketProcessor.php index 5e6d2a58..d3f7c579 100644 --- a/src/PHPSQLParser/processors/BracketProcessor.php +++ b/src/PHPSQLParser/processors/BracketProcessor.php @@ -57,10 +57,11 @@ protected function processTopLevel($sql) { } public function process($tokens) { - $token = $this->removeParenthesisFromStart($tokens[0]); $subtree = $this->processTopLevel($token); + $remainingExpressions = $this->getRemainingNotBracketExpression($subtree); + if (isset($subtree['BRACKET'])) { // TODO: here we lose some other parts of a statement like ORDER BY $subtree = $subtree['BRACKET']; @@ -73,7 +74,22 @@ public function process($tokens) { return array( array('expr_type' => ExpressionType::BRACKET_EXPRESSION, 'base_expr' => trim($tokens[0]), - 'sub_tree' => $subtree)); + 'sub_tree' => $subtree, 'remaining_expressions' => $remainingExpressions)); + } + + private function getRemainingNotBracketExpression($subtree) + { + $remainingExpressions = array(); + $ignoredKeys = array('BRACKET', 'SELECT', 'FROM'); + $subtreeKeys = array_keys($subtree); + + foreach($subtreeKeys as $key) { + if(!in_array($key, $ignoredKeys)) { + $remainingExpressions[$key] = $subtree[$key]; + } + } + + return $remainingExpressions; } } diff --git a/src/PHPSQLParser/processors/SQLChunkProcessor.php b/src/PHPSQLParser/processors/SQLChunkProcessor.php index 65e72f25..039cf4c8 100644 --- a/src/PHPSQLParser/processors/SQLChunkProcessor.php +++ b/src/PHPSQLParser/processors/SQLChunkProcessor.php @@ -66,7 +66,18 @@ public function process($out) { // TODO: this field should be a global STATEMENT field within the output // we could add all other categories as sub_tree, it could also work with multipe UNIONs $processor = new BracketProcessor($this->options); - $out['BRACKET'] = $processor->process($out['BRACKET']); + $processedBracket = $processor->process($out['BRACKET']); + $remainingExpressions = $processedBracket[0]['remaining_expressions']; + + unset($processedBracket[0]['remaining_expressions']); + + if(!empty($remainingExpressions)) { + foreach($remainingExpressions as $key=>$expression) { + $processedBracket[][$key] = $expression; + } + } + + $out['BRACKET'] = $processedBracket; } if (!empty($out['CREATE'])) { $processor = new CreateProcessor($this->options); @@ -180,6 +191,7 @@ public function process($out) { $processor = new WithProcessor($this->options); $out['WITH'] = $processor->process($out['WITH']); } + return $out; } } diff --git a/tests/cases/parser/issue117Test.php b/tests/cases/parser/issue117Test.php index e982b463..38f65608 100644 --- a/tests/cases/parser/issue117Test.php +++ b/tests/cases/parser/issue117Test.php @@ -39,22 +39,24 @@ * */ namespace PHPSQLParser\Test\Parser; + use PHPSQLParser\PHPSQLParser; -use PHPSQLParser\PHPSQLCreator; use Analog\Analog; +use PHPUnit_Framework_TestCase; -class Issue117Test extends \PHPUnit_Framework_TestCase { - - public function testIssue117() { - +class Issue117Test extends PHPUnit_Framework_TestCase +{ + public function testIssue117() + { // TODO: not solved, ORDER BY has been lost $sql = "(((SELECT x FROM table)) ORDER BY x)"; + //$sql = "(SELECT x FROM table) ORDER BY x"; $parser = new PHPSQLParser($sql, true); $p = $parser->parsed; - Analog::log(print_r($p, true)); + $expected = getExpectedValue(dirname(__FILE__), 'issue117.serialized'); - $this->assertEquals($expected, $p, 'parentheses on the first position of statement'); + $this->assertEquals($expected, $p, 'parentheses on the first position of statement'); } } diff --git a/tests/expected/parser/issue117.serialized b/tests/expected/parser/issue117.serialized index 3319d478..ab670388 100644 --- a/tests/expected/parser/issue117.serialized +++ b/tests/expected/parser/issue117.serialized @@ -1 +1 @@ -a:1:{s:7:"BRACKET";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:36:"(((SELECT x FROM table)) ORDER BY x)";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:23:"((SELECT x FROM table))";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:21:"(SELECT x FROM table)";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:5:"query";s:9:"base_expr";s:19:"SELECT x FROM table";s:8:"sub_tree";a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"x";s:9:"no_quotes";s:1:"x";s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:10;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";s:5:"table";s:5:"alias";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"table";s:8:"sub_tree";b:0;s:8:"position";i:17;}}}s:8:"position";i:3;}}s:8:"position";i:2;}}s:8:"position";i:1;}}s:8:"position";i:0;}}} \ No newline at end of file +a:1:{s:7:"BRACKET";a:2:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:36:"(((SELECT x FROM table)) ORDER BY x)";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:23:"((SELECT x FROM table))";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:18:"bracket_expression";s:9:"base_expr";s:21:"(SELECT x FROM table)";s:8:"sub_tree";a:1:{i:0;a:4:{s:9:"expr_type";s:5:"query";s:9:"base_expr";s:19:"SELECT x FROM table";s:8:"sub_tree";a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:10;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:5:"table";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:5:"table";}}s:5:"alias";b:0;s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:5:"table";s:8:"sub_tree";b:0;s:8:"position";i:17;}}}s:8:"position";i:3;}}s:8:"position";i:2;}}s:8:"position";i:1;}}s:8:"position";i:0;}i:1;a:1:{s:5:"ORDER";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:9:"base_expr";s:1:"x";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"x";}}s:8:"sub_tree";b:0;s:9:"direction";s:3:"ASC";s:8:"position";i:34;}}}}} \ No newline at end of file From 3b627b91e2f533cf2b16e338b29ef7299dfcf32b Mon Sep 17 00:00:00 2001 From: Dave Bould Date: Sun, 19 Feb 2017 14:48:02 +0000 Subject: [PATCH 4/9] Added missing options parameter for new union processor was previously causing tests to error --- src/PHPSQLParser/processors/FromProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/PHPSQLParser/processors/FromProcessor.php b/src/PHPSQLParser/processors/FromProcessor.php index b7717a50..b68229d7 100644 --- a/src/PHPSQLParser/processors/FromProcessor.php +++ b/src/PHPSQLParser/processors/FromProcessor.php @@ -117,7 +117,7 @@ protected function processFromExpression(&$parseInfo) { $res['expr_type'] = ExpressionType::SUBQUERY; } else { $tmp = $this->splitSQLIntoTokens($parseInfo['expression']); - $unionProcessor = new UnionProcessor(); + $unionProcessor = new UnionProcessor($this->options); $unionQueries = $unionProcessor->process($tmp); // If there was no UNION or UNION ALL in the query, then the query is From 12c5f487abb6f8e74de646be61b6b7ae13f60a21 Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 19 Feb 2017 14:50:45 +0000 Subject: [PATCH 5/9] Fixed remaining failing tests in union test --- .../processors/UnionProcessor.php | 42 +++++++++++++++++++ tests/cases/parser/unionTest.php | 18 ++++++++ 2 files changed, 60 insertions(+) diff --git a/src/PHPSQLParser/processors/UnionProcessor.php b/src/PHPSQLParser/processors/UnionProcessor.php index 0ed37c93..6f87e190 100644 --- a/src/PHPSQLParser/processors/UnionProcessor.php +++ b/src/PHPSQLParser/processors/UnionProcessor.php @@ -110,6 +110,48 @@ protected function processMySQLUnion($queries) { return $queries; } + /** + * Moves the final union query into a separate output, so the remainder (such as ORDER BY) can + * be processed separately. + */ + protected function splitUnionRemainder($queries, $unionType, $outputArray) + { + $finalQuery = []; + + //If this token contains a matching pair of brackets at the start and end, use it as the final query + foreach ($outputArray as $key => $token) { + $tokenAsArray = str_split(trim($token)); + $keyCount = max(array_keys($tokenAsArray)); + + if (($tokenAsArray[0] == '(' && $tokenAsArray[$keyCount] == ')')) { + $queries[$unionType][] = $outputArray; + unset($outputArray[$key]); + break; + } elseif (strtoupper($token) == 'ORDER') { + break; + } else { + $finalQuery[] = $token; + unset($outputArray[$key]); + } + } + + $finalQueryString = trim(implode($finalQuery)); + + if (!empty($finalQuery) && $finalQueryString != '') { + $queries[$unionType][] = $finalQuery; + } + + $defaultProcessor = new DefaultProcessor($this->options); + $rePrepareSqlString = trim(implode($outputArray)); + + if (!empty($rePrepareSqlString)) { + $remainingQueries = $defaultProcessor->process($rePrepareSqlString); + $queries[] = $remainingQueries; + } + + return $queries; + } + public function process($inputArray) { $outputArray = array(); diff --git a/tests/cases/parser/unionTest.php b/tests/cases/parser/unionTest.php index a712ab4c..b881350c 100644 --- a/tests/cases/parser/unionTest.php +++ b/tests/cases/parser/unionTest.php @@ -65,6 +65,7 @@ public function testUnion2() { (SELECT colB from test b) order by 1'; $p = $parser->parse($sql, true); $expected = getExpectedValue(dirname(__FILE__), 'union2.serialized'); + $this->assertEquals($expected, $p, 'mysql union with order-by'); } public function testUnion3() { @@ -74,5 +75,22 @@ public function testUnion3() { $expected = getExpectedValue(dirname(__FILE__), 'union3.serialized'); $this->assertEquals($expected, $p, 'complicated mysql union'); } + + public function testUnion4() + { + $parser = new PHPSQLParser(); + + $sql = 'SELECT colA From test a + union + SELECT colB from test + as b order by 1'; + + $p = $parser->parse($sql, true); + Analog::log(serialize($p)); + $expectedSerialized = getExpectedValue(dirname(__FILE__), 'union4.serialized', false); + $expected = unserialize(base64_decode($expectedSerialized)); + + $this->assertEquals($expected, $p, 'simple union with order by and no brackets'); + } } ?> From bd3b18097fac44a30f0252c971cc947791c07248 Mon Sep 17 00:00:00 2001 From: dave Date: Wed, 15 Feb 2017 21:56:20 +0000 Subject: [PATCH 6/9] Added a fix for ORDER statements after bracketed UNION statements Fixed broken tests, added a new test to check UNION level ORDER BYs with no brackets --- .../processors/BracketProcessor.php | 1 - src/PHPSQLParser/processors/UnionProcessor.php | 7 +++---- tests/cases/parser/unionTest.php | 18 ++++++++++++------ tests/expected/parser/union2.serialized | 2 +- tests/expected/parser/union4.serialized | 1 + 5 files changed, 17 insertions(+), 12 deletions(-) create mode 100644 tests/expected/parser/union4.serialized diff --git a/src/PHPSQLParser/processors/BracketProcessor.php b/src/PHPSQLParser/processors/BracketProcessor.php index d3f7c579..a771587d 100644 --- a/src/PHPSQLParser/processors/BracketProcessor.php +++ b/src/PHPSQLParser/processors/BracketProcessor.php @@ -63,7 +63,6 @@ public function process($tokens) { $remainingExpressions = $this->getRemainingNotBracketExpression($subtree); if (isset($subtree['BRACKET'])) { - // TODO: here we lose some other parts of a statement like ORDER BY $subtree = $subtree['BRACKET']; } diff --git a/src/PHPSQLParser/processors/UnionProcessor.php b/src/PHPSQLParser/processors/UnionProcessor.php index 6f87e190..75af5867 100644 --- a/src/PHPSQLParser/processors/UnionProcessor.php +++ b/src/PHPSQLParser/processors/UnionProcessor.php @@ -100,12 +100,12 @@ protected function processMySQLUnion($queries) { $queries[$unionType][$key] = $this->processDefault($this->removeParenthesisFromStart($token)); break; } - $queries[$unionType][$key] = $this->processSQL($queries[$unionType][$key]); break; } } } + // it can be parsed or not return $queries; } @@ -140,7 +140,7 @@ protected function splitUnionRemainder($queries, $unionType, $outputArray) if (!empty($finalQuery) && $finalQueryString != '') { $queries[$unionType][] = $finalQuery; } - + $defaultProcessor = new DefaultProcessor($this->options); $rePrepareSqlString = trim(implode($outputArray)); @@ -211,7 +211,7 @@ public function process($inputArray) { // or we don't have an UNION/UNION ALL if (!empty($outputArray)) { if ($unionType) { - $queries[$unionType][] = $outputArray; + $queries = $this->splitUnionRemainder($queries, $unionType, $outputArray); } else { $queries[] = $outputArray; } @@ -219,6 +219,5 @@ public function process($inputArray) { return $this->processMySQLUnion($queries); } - } ?> diff --git a/tests/cases/parser/unionTest.php b/tests/cases/parser/unionTest.php index b881350c..be8545a9 100644 --- a/tests/cases/parser/unionTest.php +++ b/tests/cases/parser/unionTest.php @@ -39,12 +39,15 @@ * */ namespace PHPSQLParser\Test\Parser; +use PHPUnit_Framework_TestCase; use PHPSQLParser\PHPSQLParser; use PHPSQLParser\PHPSQLCreator; use Analog\Analog; -class UnionTest extends \PHPUnit_Framework_TestCase { - public function testUnion1() { +class UnionTest extends PHPUnit_Framework_TestCase +{ + public function testUnion1() + { $parser = new PHPSQLParser(); $sql = 'SELECT colA From test a @@ -54,13 +57,14 @@ public function testUnion1() { $p = $parser->parse($sql, true); Analog::log(serialize($p)); $expected = getExpectedValue(dirname(__FILE__), 'union1.serialized'); + //var_export($p);die(); $this->assertEquals($expected, $p, 'simple union'); } - public function testUnion2() { - // TODO: the order-by clause has not been parsed + public function testUnion2() + { $parser = new PHPSQLParser(); - $sql = '(SELECT colA From test a) + $sql = '(SELECT colA From test a) union all (SELECT colB from test b) order by 1'; $p = $parser->parse($sql, true); @@ -68,7 +72,9 @@ public function testUnion2() { $this->assertEquals($expected, $p, 'mysql union with order-by'); } - public function testUnion3() { + + public function testUnion3() + { $sql = "SELECT x FROM ((SELECT y FROM z WHERE (y > 2) ) UNION ALL (SELECT a FROM z WHERE (y < 2))) as f "; $parser = new PHPSQLParser(); $p = $parser->parse($sql, true); diff --git a/tests/expected/parser/union2.serialized b/tests/expected/parser/union2.serialized index f9c4b0e4..a689305a 100644 --- a/tests/expected/parser/union2.serialized +++ b/tests/expected/parser/union2.serialized @@ -1 +1 @@ -a:1:{s:9:"UNION ALL";a:2:{i:0;a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"colA";s:9:"no_quotes";s:4:"colA";s:8:"sub_tree";b:0;s:8:"position";i:8;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";s:4:"test";s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"a";s:9:"no_quotes";s:1:"a";s:9:"base_expr";s:1:"a";s:8:"position";i:23;}s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test a";s:8:"sub_tree";b:0;s:8:"position";i:18;}}}i:1;a:2:{s:6:"SELECT";a:1:{i:0;a:6:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"colB";s:9:"no_quotes";s:4:"colB";s:8:"sub_tree";b:0;s:8:"position";i:60;}}s:4:"FROM";a:1:{i:0;a:10:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";s:4:"test";s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"b";s:9:"no_quotes";s:1:"b";s:9:"base_expr";s:1:"b";s:8:"position";i:75;}s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test b";s:8:"sub_tree";b:0;s:8:"position";i:70;}}}}} \ No newline at end of file +a:2:{s:9:"UNION ALL";a:2:{i:0;a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"colA";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colA";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:8;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"a";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"a";}}s:9:"base_expr";s:1:"a";s:8:"position";i:23;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test a";s:8:"sub_tree";b:0;s:8:"position";i:18;}}}i:1;a:2:{s:6:"SELECT";a:1:{i:0;a:7:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:4:"colB";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"colB";}}s:8:"sub_tree";b:0;s:5:"delim";b:0;s:8:"position";i:76;}}s:4:"FROM";a:1:{i:0;a:11:{s:9:"expr_type";s:5:"table";s:5:"table";s:4:"test";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:4:"test";}}s:5:"alias";a:5:{s:2:"as";b:0;s:4:"name";s:1:"b";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:1:"b";}}s:9:"base_expr";s:1:"b";s:8:"position";i:91;}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:6:"test b";s:8:"sub_tree";b:0;s:8:"position";i:86;}}}}i:0;a:1:{s:5:"ORDER";a:1:{i:0;a:4:{s:9:"expr_type";s:3:"pos";s:9:"base_expr";s:1:"1";s:9:"direction";s:3:"ASC";s:8:"position";i:103;}}}} \ No newline at end of file diff --git a/tests/expected/parser/union4.serialized b/tests/expected/parser/union4.serialized new file mode 100644 index 00000000..d8186107 --- /dev/null +++ b/tests/expected/parser/union4.serialized @@ -0,0 +1 @@ +YToyOntzOjU6IlVOSU9OIjthOjI6e2k6MDthOjI6e3M6NjoiU0VMRUNUIjthOjE6e2k6MDthOjc6e3M6OToiZXhwcl90eXBlIjtzOjY6ImNvbHJlZiI7czo1OiJhbGlhcyI7YjowO3M6OToiYmFzZV9leHByIjtzOjQ6ImNvbEEiO3M6OToibm9fcXVvdGVzIjthOjI6e3M6NToiZGVsaW0iO2I6MDtzOjU6InBhcnRzIjthOjE6e2k6MDtzOjQ6ImNvbEEiO319czo4OiJzdWJfdHJlZSI7YjowO3M6NToiZGVsaW0iO2I6MDtzOjg6InBvc2l0aW9uIjtpOjc7fX1zOjQ6IkZST00iO2E6MTp7aTowO2E6MTE6e3M6OToiZXhwcl90eXBlIjtzOjU6InRhYmxlIjtzOjU6InRhYmxlIjtzOjQ6InRlc3QiO3M6OToibm9fcXVvdGVzIjthOjI6e3M6NToiZGVsaW0iO2I6MDtzOjU6InBhcnRzIjthOjE6e2k6MDtzOjQ6InRlc3QiO319czo1OiJhbGlhcyI7YTo1OntzOjI6ImFzIjtiOjA7czo0OiJuYW1lIjtzOjE6ImEiO3M6OToibm9fcXVvdGVzIjthOjI6e3M6NToiZGVsaW0iO2I6MDtzOjU6InBhcnRzIjthOjE6e2k6MDtzOjE6ImEiO319czo5OiJiYXNlX2V4cHIiO3M6MToiYSI7czo4OiJwb3NpdGlvbiI7aToyMjt9czo1OiJoaW50cyI7YjowO3M6OToiam9pbl90eXBlIjtzOjQ6IkpPSU4iO3M6ODoicmVmX3R5cGUiO2I6MDtzOjEwOiJyZWZfY2xhdXNlIjtiOjA7czo5OiJiYXNlX2V4cHIiO3M6NjoidGVzdCBhIjtzOjg6InN1Yl90cmVlIjtiOjA7czo4OiJwb3NpdGlvbiI7aToxNzt9fX1pOjE7YToyOntzOjY6IlNFTEVDVCI7YToxOntpOjA7YTo3OntzOjk6ImV4cHJfdHlwZSI7czo2OiJjb2xyZWYiO3M6NToiYWxpYXMiO2I6MDtzOjk6ImJhc2VfZXhwciI7czo0OiJjb2xCIjtzOjk6Im5vX3F1b3RlcyI7YToyOntzOjU6ImRlbGltIjtiOjA7czo1OiJwYXJ0cyI7YToxOntpOjA7czo0OiJjb2xCIjt9fXM6ODoic3ViX3RyZWUiO2I6MDtzOjU6ImRlbGltIjtiOjA7czo4OiJwb3NpdGlvbiI7aTo1Mzt9fXM6NDoiRlJPTSI7YToxOntpOjA7YToxMTp7czo5OiJleHByX3R5cGUiO3M6NToidGFibGUiO3M6NToidGFibGUiO3M6NDoidGVzdCI7czo5OiJub19xdW90ZXMiO2E6Mjp7czo1OiJkZWxpbSI7YjowO3M6NToicGFydHMiO2E6MTp7aTowO3M6NDoidGVzdCI7fX1zOjU6ImFsaWFzIjthOjU6e3M6MjoiYXMiO2I6MTtzOjQ6Im5hbWUiO3M6MToiYiI7czo5OiJiYXNlX2V4cHIiO3M6NDoiYXMgYiI7czo5OiJub19xdW90ZXMiO2E6Mjp7czo1OiJkZWxpbSI7YjowO3M6NToicGFydHMiO2E6MTp7aTowO3M6MToiYiI7fX1zOjg6InBvc2l0aW9uIjtpOjc3O31zOjU6ImhpbnRzIjtiOjA7czo5OiJqb2luX3R5cGUiO3M6NDoiSk9JTiI7czo4OiJyZWZfdHlwZSI7YjowO3M6MTA6InJlZl9jbGF1c2UiO2I6MDtzOjk6ImJhc2VfZXhwciI7czoxODoidGVzdCAKICAgICAgICBhcyBiIjtzOjg6InN1Yl90cmVlIjtiOjA7czo4OiJwb3NpdGlvbiI7aTo2Mzt9fX19aTowO2E6MTp7czo1OiJPUkRFUiI7YToxOntpOjA7YTo0OntzOjk6ImV4cHJfdHlwZSI7czozOiJwb3MiO3M6OToiYmFzZV9leHByIjtzOjE6IjEiO3M6OToiZGlyZWN0aW9uIjtzOjM6IkFTQyI7czo4OiJwb3NpdGlvbiI7aTo5MTt9fX19 \ No newline at end of file From 80bd2ab3984982867ca90e6aaffdc063f2b61c9e Mon Sep 17 00:00:00 2001 From: dave Date: Wed, 15 Feb 2017 22:20:45 +0000 Subject: [PATCH 7/9] Found a fix for some characters stopping deserialization from working by base64 encoding the seralized data. Switched comments test back to use this. --- tests/bootstrap.php | 6 -- tests/cases/parser/commentsTest.php | 5 +- tests/expected/parser/comment2.php | 69 ----------------------- tests/expected/parser/comment2.serialized | 1 + 4 files changed, 5 insertions(+), 76 deletions(-) delete mode 100644 tests/expected/parser/comment2.php create mode 100644 tests/expected/parser/comment2.serialized diff --git a/tests/bootstrap.php b/tests/bootstrap.php index 08b402e0..735edcfe 100644 --- a/tests/bootstrap.php +++ b/tests/bootstrap.php @@ -14,9 +14,3 @@ function getExpectedValue($path, $filename, $unserialize = true) { $content = file_get_contents(dirname(__FILE__) . "/expected/" . array_pop($path) . "/" . $filename); return ($unserialize ? unserialize($content) : $content); } - -function getExpectedValueFromPhpFile($path, $filename) { - $path = explode(DIRECTORY_SEPARATOR, $path); - return include(dirname(__FILE__) . "/expected/" . array_pop($path) . "/" . $filename); -} -?> diff --git a/tests/cases/parser/commentsTest.php b/tests/cases/parser/commentsTest.php index a726b5a1..4fdb547b 100644 --- a/tests/cases/parser/commentsTest.php +++ b/tests/cases/parser/commentsTest.php @@ -32,7 +32,10 @@ public function testComments2() { b FROM test'; $p = $this->parser->parse($sql); - $expected = getExpectedValueFromPhpFile(dirname(__FILE__), 'comment2.php'); + $expectedEncoded = getExpectedValue(dirname(__FILE__), 'comment2.serialized', false); + $expectedSerialized = base64_decode($expectedEncoded); + $expected = unserialize($expectedSerialized); + $this->assertEquals($expected, $p, 'multi line comment'); } diff --git a/tests/expected/parser/comment2.php b/tests/expected/parser/comment2.php deleted file mode 100644 index 5f1c26e4..00000000 --- a/tests/expected/parser/comment2.php +++ /dev/null @@ -1,69 +0,0 @@ - - array ( - 0 => - array ( - 'expr_type' => 'colref', - 'alias' => false, - 'base_expr' => 'a', - 'no_quotes' => - array ( - 'delim' => false, - 'parts' => - array ( - 0 => 'a', - ), - ), - 'sub_tree' => false, - 'delim' => ',', - ), - 1 => - array ( - 'expr_type' => 'comment', - 'value' => '/* - multi line - comment - */', - ), - 2 => - array ( - 'expr_type' => 'colref', - 'alias' => false, - 'base_expr' => 'b', - 'no_quotes' => - array ( - 'delim' => false, - 'parts' => - array ( - 0 => 'b', - ), - ), - 'sub_tree' => false, - 'delim' => false, - ), - ), - 'FROM' => - array ( - 0 => - array ( - 'expr_type' => 'table', - 'table' => 'test', - 'no_quotes' => - array ( - 'delim' => false, - 'parts' => - array ( - 0 => 'test', - ), - ), - 'alias' => false, - 'hints' => false, - 'join_type' => 'JOIN', - 'ref_type' => false, - 'ref_clause' => false, - 'base_expr' => 'test', - 'sub_tree' => false, - ), - ), -); \ No newline at end of file diff --git a/tests/expected/parser/comment2.serialized b/tests/expected/parser/comment2.serialized new file mode 100644 index 00000000..e5b15c9a --- /dev/null +++ b/tests/expected/parser/comment2.serialized @@ -0,0 +1 @@ +YToyOntzOjY6IlNFTEVDVCI7YTozOntpOjA7YTo2OntzOjk6ImV4cHJfdHlwZSI7czo2OiJjb2xyZWYiO3M6NToiYWxpYXMiO2I6MDtzOjk6ImJhc2VfZXhwciI7czoxOiJhIjtzOjk6Im5vX3F1b3RlcyI7YToyOntzOjU6ImRlbGltIjtiOjA7czo1OiJwYXJ0cyI7YToxOntpOjA7czoxOiJhIjt9fXM6ODoic3ViX3RyZWUiO2I6MDtzOjU6ImRlbGltIjtzOjE6IiwiO31pOjE7YToyOntzOjk6ImV4cHJfdHlwZSI7czo3OiJjb21tZW50IjtzOjU6InZhbHVlIjtzOjEwNjoiLyogCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtdWx0aSBsaW5lIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgY29tbWVudAogICAgICAgICAgICAgICAgICAgICAgICAqLyI7fWk6MjthOjY6e3M6OToiZXhwcl90eXBlIjtzOjY6ImNvbHJlZiI7czo1OiJhbGlhcyI7YjowO3M6OToiYmFzZV9leHByIjtzOjE6ImIiO3M6OToibm9fcXVvdGVzIjthOjI6e3M6NToiZGVsaW0iO2I6MDtzOjU6InBhcnRzIjthOjE6e2k6MDtzOjE6ImIiO319czo4OiJzdWJfdHJlZSI7YjowO3M6NToiZGVsaW0iO2I6MDt9fXM6NDoiRlJPTSI7YToxOntpOjA7YToxMDp7czo5OiJleHByX3R5cGUiO3M6NToidGFibGUiO3M6NToidGFibGUiO3M6NDoidGVzdCI7czo5OiJub19xdW90ZXMiO2E6Mjp7czo1OiJkZWxpbSI7YjowO3M6NToicGFydHMiO2E6MTp7aTowO3M6NDoidGVzdCI7fX1zOjU6ImFsaWFzIjtiOjA7czo1OiJoaW50cyI7YjowO3M6OToiam9pbl90eXBlIjtzOjQ6IkpPSU4iO3M6ODoicmVmX3R5cGUiO2I6MDtzOjEwOiJyZWZfY2xhdXNlIjtiOjA7czo5OiJiYXNlX2V4cHIiO3M6NDoidGVzdCI7czo4OiJzdWJfdHJlZSI7YjowO319fQ== \ No newline at end of file From 194defdd55fca28f69a8d80817ca71ee47d91e8f Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 19 Feb 2017 14:50:45 +0000 Subject: [PATCH 8/9] Fixed remaining failing tests in union test --- src/PHPSQLParser/processors/UnionProcessor.php | 2 +- tests/cases/parser/unionTest.php | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/PHPSQLParser/processors/UnionProcessor.php b/src/PHPSQLParser/processors/UnionProcessor.php index 75af5867..4f2c23f8 100644 --- a/src/PHPSQLParser/processors/UnionProcessor.php +++ b/src/PHPSQLParser/processors/UnionProcessor.php @@ -140,7 +140,7 @@ protected function splitUnionRemainder($queries, $unionType, $outputArray) if (!empty($finalQuery) && $finalQueryString != '') { $queries[$unionType][] = $finalQuery; } - + $defaultProcessor = new DefaultProcessor($this->options); $rePrepareSqlString = trim(implode($outputArray)); diff --git a/tests/cases/parser/unionTest.php b/tests/cases/parser/unionTest.php index be8545a9..e905e95b 100644 --- a/tests/cases/parser/unionTest.php +++ b/tests/cases/parser/unionTest.php @@ -57,7 +57,6 @@ public function testUnion1() $p = $parser->parse($sql, true); Analog::log(serialize($p)); $expected = getExpectedValue(dirname(__FILE__), 'union1.serialized'); - //var_export($p);die(); $this->assertEquals($expected, $p, 'simple union'); } From 4cf0cc98cca72badbc23bd871d388487f7f3375b Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 19 Feb 2017 21:45:49 +0000 Subject: [PATCH 9/9] Added expected result for issue95 test. Looks like it's already working as expected, UNION is showing up under FROM key --- tests/cases/parser/issue95Test.php | 15 +++++++-------- tests/expected/parser/issue95.serialized | 1 + 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/cases/parser/issue95Test.php b/tests/cases/parser/issue95Test.php index 2322e247..b51dd2a5 100644 --- a/tests/cases/parser/issue95Test.php +++ b/tests/cases/parser/issue95Test.php @@ -39,15 +39,14 @@ * */ namespace PHPSQLParser\Test\Parser; -use PHPSQLParser\PHPSQLParser; -use PHPSQLParser\PHPSQLCreator; - -class issue95Test extends \PHPUnit_Framework_TestCase { - - public function testIssue95() { +use PHPUnit_Framework_TestCase; +use PHPSQLParser\PHPSQLParser; - // TODO: not solved, the parser doesn't recognize the UNION +class issue95Test extends PHPUnit_Framework_TestCase +{ + public function testIssue95() + { $sql="SELECT * FROM ((SELECT 1 AS `ID`) UNION (SELECT 2 AS `ID`)) AS `Tmp`"; try { @@ -56,8 +55,8 @@ public function testIssue95() { $p = $parser->parsed; $expected = getExpectedValue(dirname(__FILE__), 'issue95.serialized'); - $this->assertEquals($expected, $p, 'union within the from clause'); + $this->assertEquals($expected, $p, 'union within the from clause'); } } diff --git a/tests/expected/parser/issue95.serialized b/tests/expected/parser/issue95.serialized index e69de29b..0e871e67 100644 --- a/tests/expected/parser/issue95.serialized +++ b/tests/expected/parser/issue95.serialized @@ -0,0 +1 @@ +a:2:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:6:"colref";s:5:"alias";b:0;s:9:"base_expr";s:1:"*";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}s:4:"FROM";a:1:{i:0;a:8:{s:9:"expr_type";s:16:"table_expression";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:5:"`Tmp`";s:9:"base_expr";s:8:"AS `Tmp`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:3:"Tmp";}}}s:5:"hints";b:0;s:9:"join_type";s:4:"JOIN";s:8:"ref_type";b:0;s:10:"ref_clause";b:0;s:9:"base_expr";s:43:"(SELECT 1 AS `ID`) UNION (SELECT 2 AS `ID`)";s:8:"sub_tree";a:1:{s:5:"UNION";a:2:{i:0;a:1:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:5:"const";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:4:"`ID`";s:9:"base_expr";s:7:"AS `ID`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ID";}}}s:9:"base_expr";s:1:"1";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}}i:1;a:1:{s:6:"SELECT";a:1:{i:0;a:5:{s:9:"expr_type";s:5:"const";s:5:"alias";a:4:{s:2:"as";b:1;s:4:"name";s:4:"`ID`";s:9:"base_expr";s:7:"AS `ID`";s:9:"no_quotes";a:2:{s:5:"delim";b:0;s:5:"parts";a:1:{i:0;s:2:"ID";}}}s:9:"base_expr";s:1:"2";s:8:"sub_tree";b:0;s:5:"delim";b:0;}}}}}}}} \ No newline at end of file