Skip to content

Commit 6ab7975

Browse files
committed
Merge pull request #15 from dmaechler/fix_simple_functions
fixing delimiter issuer with simple function case and add a unit test for this case too.
2 parents 1ca5956 + 8c288ee commit 6ab7975

File tree

10 files changed

+333
-19
lines changed

10 files changed

+333
-19
lines changed

src/SQLParser/ExpressionType.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,8 @@ class ExpressionType
4545
const RESERVED = 'reserved';
4646
const CONSTANT = 'const';
4747

48+
const LIMIT_CONST = 'limit_const';
49+
4850
const AGGREGATE_FUNCTION = 'aggregate_function';
4951
const SIMPLE_FUNCTION = 'function';
5052

src/SQLParser/Node/LimitNode.php

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
<?php
2+
3+
/**
4+
* expression-types.php.
5+
*
6+
*
7+
* Copyright (c) 2010-2013, Justin Swanhart
8+
* with contributions by André Rothe <[email protected], [email protected]>
9+
* and David Négrier <[email protected]>
10+
*
11+
* All rights reserved.
12+
*
13+
* Redistribution and use in source and binary forms, with or without modification,
14+
* are permitted provided that the following conditions are met:
15+
*
16+
* * Redistributions of source code must retain the above copyright notice,
17+
* this list of conditions and the following disclaimer.
18+
* * Redistributions in binary form must reproduce the above copyright notice,
19+
* this list of conditions and the following disclaimer in the documentation
20+
* and/or other materials provided with the distribution.
21+
*
22+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
23+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25+
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27+
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28+
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31+
* DAMAGE.
32+
*/
33+
34+
namespace SQLParser\Node;
35+
36+
use Doctrine\DBAL\Connection;
37+
use Mouf\MoufManager;
38+
use Mouf\MoufInstanceDescriptor;
39+
use SQLParser\Node\Traverser\VisitorInterface;
40+
41+
/**
42+
* This class represents a constant of a LIMIT in an SQL expression.
43+
*
44+
* @author David MAECHLER <[email protected]>
45+
*/
46+
class LimitNode implements NodeInterface
47+
{
48+
private $value;
49+
50+
public function getValue()
51+
{
52+
return $this->value;
53+
}
54+
55+
/**
56+
* Sets the value.
57+
*
58+
* @Important
59+
*
60+
* @param string $value
61+
*/
62+
public function setValue($value)
63+
{
64+
$this->value = $value;
65+
}
66+
67+
/**
68+
* Returns a Mouf instance descriptor describing this object.
69+
*
70+
* @param MoufManager $moufManager
71+
*
72+
* @return MoufInstanceDescriptor
73+
*/
74+
public function toInstanceDescriptor(MoufManager $moufManager)
75+
{
76+
$instanceDescriptor = $moufManager->createInstance(get_called_class());
77+
$instanceDescriptor->getProperty('value')->setValue(NodeFactory::nodeToInstanceDescriptor($this->value, $moufManager));
78+
79+
return $instanceDescriptor;
80+
}
81+
82+
/**
83+
* Renders the object as a SQL string.
84+
*
85+
* @param array $parameters
86+
* @param Connection $dbConnection
87+
* @param int|number $indent
88+
* @param int $conditionsMode
89+
* @return string
90+
* @throws \Exception
91+
*/
92+
public function toSql(array $parameters = array(), Connection $dbConnection = null, $indent = 0, $conditionsMode = self::CONDITION_APPLY)
93+
{
94+
if($this->value === null) {
95+
throw new \Exception('A limit parameter must be an integer');
96+
}
97+
98+
if(is_numeric($this->value)) {
99+
return (int) $this->value;
100+
} else if ($dbConnection != null) {
101+
return $dbConnection->quote($this->value);
102+
} else {
103+
return addslashes($this->value);
104+
}
105+
}
106+
107+
/**
108+
* Walks the tree of nodes, calling the visitor passed in parameter.
109+
*
110+
* @param VisitorInterface $visitor
111+
* @return NodeInterface|null|string Can return null if nothing is to be done or a node that should replace this node, or NodeTraverser::REMOVE_NODE to remove the node
112+
*/
113+
public function walk(VisitorInterface $visitor) {
114+
$node = $this;
115+
$result = $visitor->enterNode($node);
116+
if ($result instanceof NodeInterface) {
117+
$node = $result;
118+
}
119+
return $visitor->leaveNode($node);
120+
}
121+
}

src/SQLParser/Node/NodeFactory.php

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,32 @@ public static function toObject(array $desc)
5454
}
5555

5656
switch ($desc['expr_type']) {
57+
case ExpressionType::LIMIT_CONST:
58+
if (substr($desc['base_expr'], 0, 1) == ':') {
59+
$instance = new UnquotedParameter();
60+
$instance->setName(substr($desc['base_expr'], 1));
61+
} else {
62+
$instance = new LimitNode();
63+
$expr = $desc['base_expr'];
64+
if (strpos($expr, "'") === 0) {
65+
$expr = substr($expr, 1);
66+
}
67+
if (strrpos($expr, "'") === strlen($expr) - 1) {
68+
$expr = substr($expr, 0, strlen($expr) - 1);
69+
}
70+
$expr = stripslashes($expr);
71+
72+
$instance->setValue($expr);
73+
}
74+
// Debug:
75+
unset($desc['base_expr']);
76+
unset($desc['expr_type']);
77+
unset($desc['sub_tree']);
78+
if (!empty($desc)) {
79+
throw new \InvalidArgumentException('Unexpected parameters in exception: '.var_export($desc, true));
80+
}
81+
82+
return $instance;
5783
case ExpressionType::CONSTANT:
5884
$const = new ConstNode();
5985
$expr = $desc['base_expr'];
@@ -108,10 +134,10 @@ public static function toObject(array $desc)
108134
if (!empty($desc['alias'])) {
109135
$instance->setAlias($desc['alias']['name']);
110136
}
111-
}
112137

113-
if (!empty($desc['direction'])) {
114-
$instance->setDirection($desc['direction']);
138+
if (!empty($desc['direction'])) {
139+
$instance->setDirection($desc['direction']);
140+
}
115141
}
116142

117143
// Debug:
@@ -687,12 +713,12 @@ public static function toSql($nodes, Connection $dbConnection = null, array $par
687713
$item = $nodes;
688714
if ($item instanceof SqlRenderInterface) {
689715
$itemSql = $item->toSql($parameters, $dbConnection, $indent, $conditionsMode);
690-
if ($itemSql == null) {
716+
if ($itemSql === null || $itemSql === '') {
691717
return;
692718
}
693719
$sql = str_repeat(' ', $indent).$itemSql;
694720
} else {
695-
if ($item == null) {
721+
if ($item === null || $item === '') {
696722
return;
697723
}
698724
$sql = str_repeat(' ', $indent).$item;

src/SQLParser/Node/Parameter.php

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,8 @@
4545
*/
4646
class Parameter implements NodeInterface
4747
{
48-
private $name;
49-
private $discardedOnNull = true;
48+
protected $name;
49+
protected $discardedOnNull = true;
5050

5151
/**
5252
* Returns the name.
@@ -80,12 +80,12 @@ public function setName($name)
8080
/**
8181
* @var string
8282
*/
83-
private $autoPrepend;
83+
protected $autoPrepend;
8484

8585
/**
8686
* @var string
8787
*/
88-
private $autoAppend;
88+
protected $autoAppend;
8989

9090
/**
9191
* @return string
@@ -180,9 +180,8 @@ public function toSql(array $parameters = array(), Connection $dbConnection = nu
180180
return "'".addslashes($this->autoPrepend.$item.$this->autoAppend)."'";
181181
}, $parameters[$this->name])).')';
182182
} else{
183-
return "'".addslashes($this->autoPrepend.$parameters[$this->name].$this->autoAppend)."'";
183+
return "'".addslashes($this->autoPrepend.$parameters[$this->name].$this->autoAppend)."'";
184184
}
185-
186185
}
187186
}
188187
} elseif (!$this->isDiscardedOnNull()) {

src/SQLParser/Node/SimpleFunction.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -172,7 +172,7 @@ public function toSql(array $parameters = array(), Connection $dbConnection = nu
172172
if (!empty($this->baseExpression)) {
173173
$sql .= $this->baseExpression.'(';
174174
}
175-
$sql .= NodeFactory::toSql($this->subTree, $dbConnection, $parameters, ' ', false, $indent, $conditionsMode);
175+
$sql .= NodeFactory::toSql($this->subTree, $dbConnection, $parameters, ',', false, $indent, $conditionsMode);
176176
if (!empty($this->baseExpression)) {
177177
$sql .= ')';
178178
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
/**
4+
* expression-types.php.
5+
*
6+
*
7+
* Copyright (c) 2010-2013, Justin Swanhart
8+
* with contributions by André Rothe <[email protected], [email protected]>
9+
* and David Négrier <[email protected]>
10+
*
11+
* All rights reserved.
12+
*
13+
* Redistribution and use in source and binary forms, with or without modification,
14+
* are permitted provided that the following conditions are met:
15+
*
16+
* * Redistributions of source code must retain the above copyright notice,
17+
* this list of conditions and the following disclaimer.
18+
* * Redistributions in binary form must reproduce the above copyright notice,
19+
* this list of conditions and the following disclaimer in the documentation
20+
* and/or other materials provided with the distribution.
21+
*
22+
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
23+
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
24+
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
25+
* SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26+
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
27+
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
28+
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29+
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30+
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31+
* DAMAGE.
32+
*/
33+
34+
namespace SQLParser\Node;
35+
36+
use Doctrine\DBAL\Connection;
37+
use Mouf\MoufInstanceDescriptor;
38+
use Mouf\MoufManager;
39+
use SQLParser\Node\Traverser\VisitorInterface;
40+
41+
/**
42+
* This class represents a parameter (as in parameterized query).
43+
*
44+
* @author David MAECHLER <[email protected]>
45+
*/
46+
class UnquotedParameter extends Parameter
47+
{
48+
/**
49+
* Renders the object as a SQL string without quote if its a numeric
50+
*
51+
* @param array $parameters
52+
* @param Connection $dbConnection
53+
* @param int|number $indent
54+
* @param int $conditionsMode
55+
* @return string
56+
*/
57+
public function toSql(array $parameters = array(), Connection $dbConnection = null, $indent = 0, $conditionsMode = self::CONDITION_APPLY)
58+
{
59+
$name = parent::toSql($parameters, $dbConnection, $indent, $conditionsMode);
60+
$name = str_replace("'", "", $name);
61+
return $name;
62+
}
63+
}

0 commit comments

Comments
 (0)