Skip to content

Commit 75795a8

Browse files
committed
Merge pull request #99 from phpcr/parse_cast
implement parsing of CAST(), automatically parse dates inside literals
2 parents 988c131 + 38d2906 commit 75795a8

File tree

1 file changed

+63
-1
lines changed

1 file changed

+63
-1
lines changed

src/PHPCR/Util/QOM/Sql2ToQomQueryConverter.php

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace PHPCR\Util\QOM;
44

5+
use PHPCR\PropertyType;
56
use PHPCR\Query\InvalidQueryException;
67
use PHPCR\Query\QOM\ChildNodeJoinConditionInterface;
78
use PHPCR\Query\QOM\ColumnInterface;
@@ -22,6 +23,7 @@
2223
use PHPCR\Query\QOM\SameNodeJoinConditionInterface;
2324
use PHPCR\Query\QOM\SourceInterface;
2425
use PHPCR\Query\QOM\StaticOperandInterface;
26+
use PHPCR\Util\ValueConverter;
2527

2628
/**
2729
* Parse SQL2 statements and output a corresponding QOM objects tree.
@@ -67,9 +69,10 @@ class Sql2ToQomQueryConverter
6769
*
6870
* @param QueryObjectModelFactoryInterface $factory
6971
*/
70-
public function __construct(QueryObjectModelFactoryInterface $factory)
72+
public function __construct(QueryObjectModelFactoryInterface $factory, ValueConverter $valueConverter = null)
7173
{
7274
$this->factory = $factory;
75+
$this->valueConverter = $valueConverter ?: new ValueConverter();
7376
}
7477

7578
/**
@@ -723,6 +726,56 @@ protected function parsePropertyValue()
723726
return $this->factory->propertyValue($selectorName, $prop);
724727
}
725728

729+
protected function parseCastLiteral($token)
730+
{
731+
if ($this->scanner->tokenIs($token, 'CAST')) {
732+
$this->scanner->expectToken('(');
733+
$token = $this->scanner->fetchNextToken();
734+
735+
$quoteString = false;
736+
if (substr($token, 0, 1) === '\'') {
737+
$quoteString = "'";
738+
} elseif (substr($token, 0, 1) === '"') {
739+
$quoteString = '"';
740+
}
741+
742+
if ($quoteString) {
743+
while (substr($token, -1) !== $quoteString) {
744+
$nextToken = $this->scanner->fetchNextToken();
745+
if ('' === $nextToken) {
746+
break;
747+
}
748+
$token .= $nextToken;
749+
}
750+
751+
if (substr($token, -1) !== $quoteString) {
752+
throw new InvalidQueryException("Syntax error: unterminated quoted string $token in '{$this->sql2}'");
753+
}
754+
$token = substr($token, 1, -1);
755+
$token = str_replace('\\'.$quoteString, $quoteString, $token);
756+
}
757+
758+
$this->scanner->expectToken('AS');
759+
760+
$type = $this->scanner->fetchNextToken();
761+
try {
762+
$typeValue = PropertyType::valueFromName($type);
763+
} catch (\InvalidArgumentException $e) {
764+
throw new InvalidQueryException("Syntax error: attempting to cast to an invalid type '$type'");
765+
}
766+
767+
$this->scanner->expectToken(')');
768+
769+
try {
770+
$token = $this->valueConverter->convertType($token, $typeValue, PropertyType::STRING);
771+
} catch (\Exception $e) {
772+
throw new InvalidQueryException("Syntax error: attempting to cast string '$token' to type '$type'");
773+
}
774+
775+
return $this->factory->literal($token);
776+
}
777+
}
778+
726779
/**
727780
* 6.7.34 Literal
728781
* Parse an SQL2 literal value
@@ -732,6 +785,9 @@ protected function parsePropertyValue()
732785
protected function parseLiteral()
733786
{
734787
$token = $this->scanner->fetchNextToken();
788+
if ($this->scanner->tokenIs($token, 'CAST')) {
789+
return $this->parseCastLiteral($token);
790+
}
735791

736792
$quoteString = false;
737793
if (substr($token, 0, 1) === '\'') {
@@ -755,6 +811,12 @@ protected function parseLiteral()
755811
}
756812
$token = substr($token, 1, -1);
757813
$token = str_replace('\\'.$quoteString, $quoteString, $token);
814+
if (preg_match('/^\d{4}-\d{2}-\d{2}( \d{2}:\d{2}:\d+)?$/', $token)) {
815+
if (preg_match('/^\d{4}-\d{2}-\d{2}$/', $token)) {
816+
$token.= ' 00:00:00';
817+
}
818+
$token = \DateTime::createFromFormat('Y-m-d H:i:s', $token);
819+
}
758820
} elseif (is_numeric($token)) {
759821
$token = strpos($token, '.') === false ? (int) $token : (float) $token;
760822
} elseif ($token == 'true') {

0 commit comments

Comments
 (0)