Skip to content

Enforce termination of queries #166

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 4, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
Changelog
=========


dev-master
----------

### Bug fixes

- [query] Enforce termination of queries with ";": fixes #162

beta2
-----

### Features

- [profile:show] Added command to display current profile
Expand Down
10 changes: 7 additions & 3 deletions features/all/phpcr_query_delete.feature
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ Feature: Execute a a raw DELETE query in JCR_SQL2
"""
Examples:
| query | path |
| DELETE FROM [nt:unstructured] AS a WHERE localname() = 'product1' | /cms/products/product1 |
| delete FROM [nt:unstructured] as a where localname() = 'product1' | /cms/products/product1 |
| DELETE FROM nt:unstructured AS a WHERE localname() = 'product1' | /cms/products/product1 |
| DELETE FROM [nt:unstructured] AS a WHERE localname() = 'product1'; | /cms/products/product1 |
| delete FROM [nt:unstructured] as a where localname() = 'product1'; | /cms/products/product1 |
| DELETE FROM nt:unstructured AS a WHERE localname() = 'product1'; | /cms/products/product1 |

Scenario: It should fail if a non terminated query is executed
Given I execute the "DELETE FROM [nt:unstructured] WHERE bar = 'product1'" command
Then the command should fail
6 changes: 5 additions & 1 deletion features/all/phpcr_query_select.feature
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,12 @@ Feature: Execute a raw query in JCR_SQL2
And the "session_data.xml" fixtures are loaded

Scenario: Execute query
Given I execute the "SELECT a.[jcr:createdBy], a.[jcr:primaryType] from [nt:folder] AS a WHERE localname() = 'emptyExample'" command
Given I execute the "SELECT a.[jcr:createdBy], a.[jcr:primaryType] from [nt:folder] AS a WHERE localname() = 'emptyExample';" command
Then the command should not fail
And I should see a table containing the following rows:
| a.jcr:createdBy | a.jcr:primaryType |
| admin | nt:folder |

Scenario: It should fail if a non terminated query is executed
Given I execute the "SELECT * FROM [nt:unstructured] WHERE bar = 'product1'" command
Then the command should fail
54 changes: 29 additions & 25 deletions features/all/phpcr_query_update.feature
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,29 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
"""
Examples:
| query | path | property | expectedValue |
| UPDATE [nt:unstructured] AS a SET a.title = 'DTL' WHERE localname() = 'article1' | /cms/articles/article1 | title | DTL |
| update [nt:unstructured] as a set a.title = 'dtl' where localname() = 'article1' | /cms/articles/article1 | title | dtl |
| UPDATE nt:unstructured AS a SET a.title = 'DTL' WHERE localname() = 'article1' | /cms/articles/article1 | title | DTL |
| UPDATE nt:unstructured AS a SET title = 'DTL' WHERE localname() = 'article1' | /cms/articles/article1 | title | DTL |
| UPDATE nt:unstructured AS a SET title = 'DTL', foobar='barfoo' WHERE localname() = 'article1' | /cms/articles/article1 | foobar | barfoo |
| UPDATE [nt:unstructured] AS a SET a.title = 'DTL' WHERE localname() = 'article1'; | /cms/articles/article1 | title | DTL |
| update [nt:unstructured] as a set a.title = 'dtl' where localname() = 'article1'; | /cms/articles/article1 | title | dtl |
| UPDATE nt:unstructured AS a SET a.title = 'DTL' WHERE localname() = 'article1'; | /cms/articles/article1 | title | DTL |
| UPDATE nt:unstructured AS a SET title = 'DTL' WHERE localname() = 'article1'; | /cms/articles/article1 | title | DTL |
| UPDATE nt:unstructured AS a SET title = 'DTL', foobar='barfoo' WHERE localname() = 'article1'; | /cms/articles/article1 | foobar | barfoo |

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

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

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

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

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

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

Scenario: Replace a multivalue property by index
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
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
And I save the session
Then the command should not fail
And I should see the following:
Expand All @@ -98,43 +98,43 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
And the node at "/cms/articles/article1" should have the property "tags" with value "foobar" at index "2"

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

Scenario: Attempt to update a numerically named property (must use a selector)
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
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
Then the command should fail
And I should see the following:
"""
[PHPCR\PathNotFoundException] Property 10
"""

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

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

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

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

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

Scenario: Execute an update with a quoted expression (can't do this in Examples above)
When I execute the following command:
"""
UPDATE [nt:unstructured] AS a SET a.weight = expr('row.getNode().getPropertyValue("weight") * 2') WHERE a.name = 'Product One'
UPDATE [nt:unstructured] AS a SET a.weight = expr('row.getNode().getPropertyValue("weight") * 2') WHERE a.name = 'Product One';
"""
Then the command should not fail
And I save the session
Expand All @@ -180,3 +180,7 @@ Feature: Execute a a raw UPDATE query in JCR_SQL2
"""
1 row(s) affected
"""

Scenario: It should fail if a non terminated query is executed
Given I execute the "UPDATE [nt:unstructured] SET foo = 'bar'" command
Then the command should fail
2 changes: 1 addition & 1 deletion features/shell/shell_alias.feature
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Feature: Command aliases

Examples:
| command |
| select * from [nt:unstructured] |
| select * from [nt:unstructured]; |
| cd cms |
| rm cms |
| mv cms smc |
Expand Down
33 changes: 33 additions & 0 deletions src/PHPCR/Shell/Console/Command/Phpcr/BaseQueryCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

/*
* This file is part of the PHPCR Shell package
*
* (c) Daniel Leech <daniel@dantleech.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace PHPCR\Shell\Console\Command\Phpcr;

use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use PHPCR\Util\QOM\Sql2ToQomQueryConverter;

class BaseQueryCommand extends BasePhpcrCommand
{
public function getQuery(InputInterface $input)
{
$sql = $input->getRawCommand();

if (substr($sql, -1) !== ';') {
throw new \InvalidArgumentException(
'Queries must be terminated with ";"'
);
}

return substr($sql, 0, -1);
}
}
15 changes: 5 additions & 10 deletions src/PHPCR/Shell/Console/Command/Phpcr/QueryDeleteCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
use Symfony\Component\Console\Output\OutputInterface;
use PHPCR\Util\QOM\Sql2ToQomQueryConverter;

class QueryDeleteCommand extends BasePhpcrCommand
class QueryDeleteCommand extends BaseQueryCommand
{
protected function configure()
{
Expand All @@ -38,22 +38,17 @@ protected function configure()

public function execute(InputInterface $input, OutputInterface $output)
{
$sql = $input->getRawCommand();

// trim ";" for people used to MysQL
if (substr($sql, -1) == ';') {
$sql = substr($sql, 0, -1);
}

$session = $this->get('phpcr.session');
$qm = $session->getWorkspace()->getQueryManager();
$sql = $this->getQuery($input);

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

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

$sql = 'SELECT * FROM' . substr($sql, 11);

$selectParser = new Sql2ToQomQueryConverter($qm->getQOMFactory());
Expand Down
10 changes: 3 additions & 7 deletions src/PHPCR/Shell/Console/Command/Phpcr/QuerySelectCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class QuerySelectCommand extends BasePhpcrCommand
class QuerySelectCommand extends BaseQueryCommand
{
protected function configure()
{
Expand All @@ -34,12 +34,8 @@ protected function configure()

public function execute(InputInterface $input, OutputInterface $output)
{
$sql = $input->getRawCommand();

// trim ";" for people used to MysQL
if (substr($sql, -1) == ';') {
$sql = substr($sql, 0, -1);
}
$sql = $this->getQuery($input);
$input = $this->getQuery($input);

$session = $this->get('phpcr.session');
$qm = $session->getWorkspace()->getQueryManager();
Expand Down
9 changes: 2 additions & 7 deletions src/PHPCR/Shell/Console/Command/Phpcr/QueryUpdateCommand.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
use PHPCR\Shell\Query\UpdateParser;
use PHPCR\Shell\Query\UpdateProcessor;

class QueryUpdateCommand extends BasePhpcrCommand
class QueryUpdateCommand extends BaseQueryCommand
{
/**
* @var OutputInterface
Expand Down Expand Up @@ -69,12 +69,7 @@ protected function configure()
public function execute(InputInterface $input, OutputInterface $output)
{
$this->output = $output;
$sql = $input->getRawCommand();

// trim ";" for people used to MysQL
if (substr($sql, -1) == ';') {
$sql = substr($sql, 0, -1);
}
$sql = $this->getQuery($input);

$session = $this->get('phpcr.session');
$qm = $session->getWorkspace()->getQueryManager();
Expand Down
29 changes: 29 additions & 0 deletions src/PHPCR/Shell/Query/Validator.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

/*
* This file is part of the PHPCR Shell package
*
* (c) Daniel Leech <daniel@dantleech.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

namespace \PHPCR\Shell\Query;

class Validator
{
/**
* Assert that queries are terminated with ";"
*
* @param string $sql2
*/
public static function validateQuery($sql2)
{
if (substr($sql2, -1) !== ';') {
throw new \InvalidArgumentException(
'Queries must be terminated with ";"'
);
}
}
}