Skip to content

Commit 6901c50

Browse files
committed
Enforce termination of queries
1 parent 283f5bd commit 6901c50

10 files changed

+121
-55
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
11
Changelog
22
=========
33

4-
54
dev-master
65
----------
76

7+
### Bug fixes
8+
9+
- [query] Enforce termination of queries with ";": fixes #162
10+
11+
beta2
12+
-----
13+
814
### Features
915

1016
- [profile:show] Added command to display current profile

features/all/phpcr_query_delete.feature

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ Feature: Execute a a raw DELETE query in JCR_SQL2
1919
"""
2020
Examples:
2121
| query | path |
22-
| DELETE FROM [nt:unstructured] AS a WHERE localname() = 'product1' | /cms/products/product1 |
23-
| delete FROM [nt:unstructured] as a where localname() = 'product1' | /cms/products/product1 |
24-
| DELETE FROM nt:unstructured AS a WHERE localname() = 'product1' | /cms/products/product1 |
22+
| DELETE FROM [nt:unstructured] AS a WHERE localname() = 'product1'; | /cms/products/product1 |
23+
| delete FROM [nt:unstructured] as a where localname() = 'product1'; | /cms/products/product1 |
24+
| DELETE FROM nt:unstructured AS a WHERE localname() = 'product1'; | /cms/products/product1 |
25+
26+
Scenario: It should fail if a non terminated query is executed
27+
Given I execute the "DELETE FROM [nt:unstructured] WHERE bar = 'product1'" command
28+
Then the command should fail

features/all/phpcr_query_select.feature

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,12 @@ Feature: Execute a raw query in JCR_SQL2
88
And the "session_data.xml" fixtures are loaded
99

1010
Scenario: Execute query
11-
Given I execute the "SELECT a.[jcr:createdBy], a.[jcr:primaryType] from [nt:folder] AS a WHERE localname() = 'emptyExample'" command
11+
Given I execute the "SELECT a.[jcr:createdBy], a.[jcr:primaryType] from [nt:folder] AS a WHERE localname() = 'emptyExample';" command
1212
Then the command should not fail
1313
And I should see a table containing the following rows:
1414
| a.jcr:createdBy | a.jcr:primaryType |
1515
| admin | nt:folder |
16+
17+
Scenario: It should fail if a non terminated query is executed
18+
Given I execute the "SELECT * FROM [nt:unstructured] WHERE bar = 'product1'" command
19+
Then the command should fail

features/all/phpcr_query_update.feature

Lines changed: 29 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -18,29 +18,29 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
1818
"""
1919
Examples:
2020
| query | path | property | expectedValue |
21-
| UPDATE [nt:unstructured] AS a SET a.title = 'DTL' WHERE localname() = 'article1' | /cms/articles/article1 | title | DTL |
22-
| update [nt:unstructured] as a set a.title = 'dtl' where localname() = 'article1' | /cms/articles/article1 | title | dtl |
23-
| UPDATE nt:unstructured AS a SET a.title = 'DTL' WHERE localname() = 'article1' | /cms/articles/article1 | title | DTL |
24-
| UPDATE nt:unstructured AS a SET title = 'DTL' WHERE localname() = 'article1' | /cms/articles/article1 | title | DTL |
25-
| UPDATE nt:unstructured AS a SET title = 'DTL', foobar='barfoo' WHERE localname() = 'article1' | /cms/articles/article1 | foobar | barfoo |
21+
| UPDATE [nt:unstructured] AS a SET a.title = 'DTL' WHERE localname() = 'article1'; | /cms/articles/article1 | title | DTL |
22+
| update [nt:unstructured] as a set a.title = 'dtl' where localname() = 'article1'; | /cms/articles/article1 | title | dtl |
23+
| UPDATE nt:unstructured AS a SET a.title = 'DTL' WHERE localname() = 'article1'; | /cms/articles/article1 | title | DTL |
24+
| UPDATE nt:unstructured AS a SET title = 'DTL' WHERE localname() = 'article1'; | /cms/articles/article1 | title | DTL |
25+
| UPDATE nt:unstructured AS a SET title = 'DTL', foobar='barfoo' WHERE localname() = 'article1'; | /cms/articles/article1 | foobar | barfoo |
2626

2727
Scenario: Replace a multivalue index by value
28-
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_replace(a.tags, 'Trains', 'Rockets') WHERE a.tags = 'Trains'" command
28+
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_replace(a.tags, 'Trains', 'Rockets') WHERE a.tags = 'Trains';" command
2929
Then the command should not fail
3030
And I save the session
3131
Then the command should not fail
3232
And the node at "/cms/articles/article1" should have the property "tags" with value "Rockets" at index "1"
3333

3434
Scenario: Set a multivalue value
35-
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array('Rockets', 'Dragons')" command
35+
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array('Rockets', 'Dragons');" command
3636
Then the command should not fail
3737
And I save the session
3838
Then the command should not fail
3939
And the node at "/cms/articles/article1" should have the property "tags" with value "Rockets" at index "0"
4040
And the node at "/cms/articles/article1" should have the property "tags" with value "Dragons" at index "1"
4141

4242
Scenario: Update single multivalue without selector
43-
Given I execute the "UPDATE [nt:unstructured] SET tags = array_replace(tags, 'Planes', 'Rockets') WHERE tags = 'Planes'" command
43+
Given I execute the "UPDATE [nt:unstructured] SET tags = array_replace(tags, 'Planes', 'Rockets') WHERE tags = 'Planes';" command
4444
Then the command should not fail
4545
And I save the session
4646
Then the command should not fail
@@ -52,7 +52,7 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
5252
And the node at "/cms/articles/article1" should have the property "tags" with value "Automobiles" at index "2"
5353

5454
Scenario: Remove single multivalue
55-
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_remove(a.tags, 'Planes') WHERE a.tags = 'Planes'" command
55+
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_remove(a.tags, 'Planes') WHERE a.tags = 'Planes';" command
5656
And I save the session
5757
Then the command should not fail
5858
And I should see the following:
@@ -63,7 +63,7 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
6363
And the node at "/cms/articles/article1" should have the property "tags" with value "Automobiles" at index "1"
6464

6565
Scenario: Remove single multivalue by index
66-
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_replace_at(a.tags, 0, NULL) WHERE a.tags = 'Planes'" command
66+
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_replace_at(a.tags, 0, NULL) WHERE a.tags = 'Planes';" command
6767
And I save the session
6868
Then the command should not fail
6969
And I should see the following:
@@ -74,7 +74,7 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
7474
And the node at "/cms/articles/article1" should have the property "tags" with value "Automobiles" at index "1"
7575

7676
Scenario: Add a multivalue property
77-
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_append(a.tags, 'Kite') WHERE a.tags = 'Planes'" command
77+
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_append(a.tags, 'Kite') WHERE a.tags = 'Planes';" command
7878
And I save the session
7979
Then the command should not fail
8080
And I should see the following:
@@ -86,7 +86,7 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
8686
And the node at "/cms/articles/article1" should have the property "tags" with value "Kite" at index "3"
8787

8888
Scenario: Replace a multivalue property by index
89-
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_replace_at(a.tags, 1, 'Kite'), a.tags = array_replace_at(a.tags, 2, 'foobar') WHERE a.tags = 'Planes'" command
89+
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_replace_at(a.tags, 1, 'Kite'), a.tags = array_replace_at(a.tags, 2, 'foobar') WHERE a.tags = 'Planes';" command
9090
And I save the session
9191
Then the command should not fail
9292
And I should see the following:
@@ -98,43 +98,43 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
9898
And the node at "/cms/articles/article1" should have the property "tags" with value "foobar" at index "2"
9999

100100
Scenario: Replace a multivalue property by invalid index
101-
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_replace_at(a.tags, 10, 'Kite') WHERE a.tags = 'Planes'" command
101+
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_replace_at(a.tags, 10, 'Kite') WHERE a.tags = 'Planes';" command
102102
Then the command should fail
103103
And I should see the following:
104104
"""
105105
Multivalue index "10" does not exist
106106
"""
107107

108108
Scenario: Attempt to update a numerically named property (must use a selector)
109-
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_replace_at(a.tags, a.10, 'Kite') WHERE a.tags = 'Planes'" command
109+
Given I execute the "UPDATE [nt:unstructured] AS a SET a.tags = array_replace_at(a.tags, a.10, 'Kite') WHERE a.tags = 'Planes';" command
110110
Then the command should fail
111111
And I should see the following:
112112
"""
113113
[PHPCR\PathNotFoundException] Property 10
114114
"""
115115

116116
Scenario: Apply mixin_remove
117-
Given I execute the "UPDATE [nt:unstructured] AS a APPLY mixin_remove('mix:title') WHERE a.name = 'Product Two'" command
117+
Given I execute the "UPDATE [nt:unstructured] AS a APPLY mixin_remove('mix:title') WHERE a.name = 'Product Two';" command
118118
Then the command should not fail
119119
And I save the session
120120
Then the command should not fail
121121
Then the node at "/cms/products/product2" should not have the mixin "mix:title"
122122

123123
Scenario: Apply mixin_add
124-
Given I execute the "UPDATE [nt:unstructured] AS a APPLY mixin_add('mix:mimeType') WHERE a.tags = 'Planes'" command
124+
Given I execute the "UPDATE [nt:unstructured] AS a APPLY mixin_add('mix:mimeType') WHERE a.tags = 'Planes';" command
125125
Then the command should not fail
126126
And I save the session
127127
And the node at "/cms/articles/article1" should have the mixin "mix:mimeType"
128128

129129
Scenario: Apply mixin_add existing
130-
Given I execute the "UPDATE [nt:unstructured] AS a APPLY mixin_add('mix:title') WHERE a.name = 'Product Two'" command
130+
Given I execute the "UPDATE [nt:unstructured] AS a APPLY mixin_add('mix:title') WHERE a.name = 'Product Two';" command
131131
Then the command should not fail
132132
And I save the session
133133
Then the command should not fail
134134
Then the node at "/cms/products/product2" should have the mixin "mix:title"
135135

136136
Scenario: Apply multiple functions
137-
Given I execute the "UPDATE [nt:unstructured] AS a APPLY mixin_add('mix:mimeType'), mixin_add('mix:lockable') WHERE a.tags = 'Planes'" command
137+
Given I execute the "UPDATE [nt:unstructured] AS a APPLY mixin_add('mix:mimeType'), mixin_add('mix:lockable') WHERE a.tags = 'Planes';" command
138138
Then the command should not fail
139139
And I save the session
140140
And the node at "/cms/articles/article1" should have the mixin "mix:mimeType"
@@ -149,10 +149,10 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
149149
"""
150150
Examples:
151151
| query |
152-
| UPDATE foo FOR fi |
153-
| UPDATE [nt:unstructured] mixin_foo('bar') |
154-
| UPDATE [nt:unstructured] APPLY mixin_foo('bar') |
155-
| UPDATE [nt:unstructured] mixin_foo'bar') |
152+
| UPDATE foo FOR fi; |
153+
| UPDATE [nt:unstructured] mixin_foo('bar'); |
154+
| UPDATE [nt:unstructured] APPLY mixin_foo('bar'); |
155+
| UPDATE [nt:unstructured] mixin_foo'bar'); |
156156

157157
Scenario Outline: Execute update query with expressions
158158
When I execute the "<query>" command
@@ -165,13 +165,13 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
165165
"""
166166
Examples:
167167
| query | path | property | expectedValue |
168-
| UPDATE [nt:unstructured] AS a SET a.title = expr('row.getNode().getName()') WHERE localname() = 'article1' | /cms/articles/article1 | title | article1 |
169-
| UPDATE [nt:unstructured] AS a SET a.title = expr('row.getPath()') WHERE localname() = 'article1' | /cms/articles/article1 | title | /cms/articles/article1 |
168+
| UPDATE [nt:unstructured] AS a SET a.title = expr('row.getNode().getName()') WHERE localname() = 'article1'; | /cms/articles/article1 | title | article1 |
169+
| UPDATE [nt:unstructured] AS a SET a.title = expr('row.getPath()') WHERE localname() = 'article1'; | /cms/articles/article1 | title | /cms/articles/article1 |
170170

171171
Scenario: Execute an update with a quoted expression (can't do this in Examples above)
172172
When I execute the following command:
173173
"""
174-
UPDATE [nt:unstructured] AS a SET a.weight = expr('row.getNode().getPropertyValue("weight") * 2') WHERE a.name = 'Product One'
174+
UPDATE [nt:unstructured] AS a SET a.weight = expr('row.getNode().getPropertyValue("weight") * 2') WHERE a.name = 'Product One';
175175
"""
176176
Then the command should not fail
177177
And I save the session
@@ -180,3 +180,7 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
180180
"""
181181
1 row(s) affected
182182
"""
183+
184+
Scenario: It should fail if a non terminated query is executed
185+
Given I execute the "UPDATE [nt:unstructured] SET foo = 'bar'" command
186+
Then the command should fail

features/shell/shell_alias.feature

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Feature: Command aliases
1818

1919
Examples:
2020
| command |
21-
| select * from [nt:unstructured] |
21+
| select * from [nt:unstructured]; |
2222
| cd cms |
2323
| rm cms |
2424
| mv cms smc |
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the PHPCR Shell package
5+
*
6+
* (c) Daniel Leech <daniel@dantleech.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace PHPCR\Shell\Console\Command\Phpcr;
13+
14+
use Symfony\Component\Console\Command\Command;
15+
use Symfony\Component\Console\Input\InputInterface;
16+
use Symfony\Component\Console\Output\OutputInterface;
17+
use PHPCR\Util\QOM\Sql2ToQomQueryConverter;
18+
19+
class BaseQueryCommand extends BasePhpcrCommand
20+
{
21+
public function getQuery(InputInterface $input)
22+
{
23+
$sql = $input->getRawCommand();
24+
25+
if (substr($sql, -1) !== ';') {
26+
throw new \InvalidArgumentException(
27+
'Queries must be terminated with ";"'
28+
);
29+
}
30+
31+
return substr($sql, 0, -1);
32+
}
33+
}

src/PHPCR/Shell/Console/Command/Phpcr/QueryDeleteCommand.php

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
use Symfony\Component\Console\Output\OutputInterface;
1717
use PHPCR\Util\QOM\Sql2ToQomQueryConverter;
1818

19-
class QueryDeleteCommand extends BasePhpcrCommand
19+
class QueryDeleteCommand extends BaseQueryCommand
2020
{
2121
protected function configure()
2222
{
@@ -38,22 +38,17 @@ protected function configure()
3838

3939
public function execute(InputInterface $input, OutputInterface $output)
4040
{
41-
$sql = $input->getRawCommand();
42-
43-
// trim ";" for people used to MysQL
44-
if (substr($sql, -1) == ';') {
45-
$sql = substr($sql, 0, -1);
46-
}
47-
48-
$session = $this->get('phpcr.session');
49-
$qm = $session->getWorkspace()->getQueryManager();
41+
$sql = $this->getQuery($input);
5042

5143
if (!preg_match('{^delete from}', strtolower($sql))) {
5244
throw new \PHPCR\Query\InvalidQueryException(sprintf(
5345
'"FROM" not specified in DELETE query: "%s"', $sql
5446
));
5547
}
5648

49+
$session = $this->get('phpcr.session');
50+
$qm = $session->getWorkspace()->getQueryManager();
51+
5752
$sql = 'SELECT * FROM' . substr($sql, 11);
5853

5954
$selectParser = new Sql2ToQomQueryConverter($qm->getQOMFactory());

src/PHPCR/Shell/Console/Command/Phpcr/QuerySelectCommand.php

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
use Symfony\Component\Console\Input\InputInterface;
1616
use Symfony\Component\Console\Output\OutputInterface;
1717

18-
class QuerySelectCommand extends BasePhpcrCommand
18+
class QuerySelectCommand extends BaseQueryCommand
1919
{
2020
protected function configure()
2121
{
@@ -34,12 +34,8 @@ protected function configure()
3434

3535
public function execute(InputInterface $input, OutputInterface $output)
3636
{
37-
$sql = $input->getRawCommand();
38-
39-
// trim ";" for people used to MysQL
40-
if (substr($sql, -1) == ';') {
41-
$sql = substr($sql, 0, -1);
42-
}
37+
$sql = $this->getQuery($input);
38+
$input = $this->getQuery($input);
4339

4440
$session = $this->get('phpcr.session');
4541
$qm = $session->getWorkspace()->getQueryManager();

src/PHPCR/Shell/Console/Command/Phpcr/QueryUpdateCommand.php

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
use PHPCR\Shell\Query\UpdateParser;
1818
use PHPCR\Shell\Query\UpdateProcessor;
1919

20-
class QueryUpdateCommand extends BasePhpcrCommand
20+
class QueryUpdateCommand extends BaseQueryCommand
2121
{
2222
/**
2323
* @var OutputInterface
@@ -69,12 +69,7 @@ protected function configure()
6969
public function execute(InputInterface $input, OutputInterface $output)
7070
{
7171
$this->output = $output;
72-
$sql = $input->getRawCommand();
73-
74-
// trim ";" for people used to MysQL
75-
if (substr($sql, -1) == ';') {
76-
$sql = substr($sql, 0, -1);
77-
}
72+
$sql = $this->getQuery($input);
7873

7974
$session = $this->get('phpcr.session');
8075
$qm = $session->getWorkspace()->getQueryManager();

src/PHPCR/Shell/Query/Validator.php

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the PHPCR Shell package
5+
*
6+
* (c) Daniel Leech <daniel@dantleech.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace \PHPCR\Shell\Query;
13+
14+
class Validator
15+
{
16+
/**
17+
* Assert that queries are terminated with ";"
18+
*
19+
* @param string $sql2
20+
*/
21+
public static function validateQuery($sql2)
22+
{
23+
if (substr($sql2, -1) !== ';') {
24+
throw new \InvalidArgumentException(
25+
'Queries must be terminated with ";"'
26+
);
27+
}
28+
}
29+
}

0 commit comments

Comments
 (0)