2
2
3
3
namespace PHPCR \Util \QOM ;
4
4
5
+ use PHPCR \PropertyType ;
5
6
use PHPCR \Query \InvalidQueryException ;
6
7
use PHPCR \Query \QOM \ChildNodeJoinConditionInterface ;
7
8
use PHPCR \Query \QOM \ColumnInterface ;
22
23
use PHPCR \Query \QOM \SameNodeJoinConditionInterface ;
23
24
use PHPCR \Query \QOM \SourceInterface ;
24
25
use PHPCR \Query \QOM \StaticOperandInterface ;
26
+ use PHPCR \Util \ValueConverter ;
25
27
26
28
/**
27
29
* Parse SQL2 statements and output a corresponding QOM objects tree.
@@ -67,9 +69,10 @@ class Sql2ToQomQueryConverter
67
69
*
68
70
* @param QueryObjectModelFactoryInterface $factory
69
71
*/
70
- public function __construct (QueryObjectModelFactoryInterface $ factory )
72
+ public function __construct (QueryObjectModelFactoryInterface $ factory, ValueConverter $ valueConverter = null )
71
73
{
72
74
$ this ->factory = $ factory ;
75
+ $ this ->valueConverter = $ valueConverter ?: new ValueConverter ();
73
76
}
74
77
75
78
/**
@@ -723,6 +726,56 @@ protected function parsePropertyValue()
723
726
return $ this ->factory ->propertyValue ($ selectorName , $ prop );
724
727
}
725
728
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
+
726
779
/**
727
780
* 6.7.34 Literal
728
781
* Parse an SQL2 literal value
@@ -732,6 +785,9 @@ protected function parsePropertyValue()
732
785
protected function parseLiteral ()
733
786
{
734
787
$ token = $ this ->scanner ->fetchNextToken ();
788
+ if ($ this ->scanner ->tokenIs ($ token , 'CAST ' )) {
789
+ return $ this ->parseCastLiteral ($ token );
790
+ }
735
791
736
792
$ quoteString = false ;
737
793
if (substr ($ token , 0 , 1 ) === '\'' ) {
@@ -755,6 +811,12 @@ protected function parseLiteral()
755
811
}
756
812
$ token = substr ($ token , 1 , -1 );
757
813
$ 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
+ }
758
820
} elseif (is_numeric ($ token )) {
759
821
$ token = strpos ($ token , '. ' ) === false ? (int ) $ token : (float ) $ token ;
760
822
} elseif ($ token == 'true ' ) {
0 commit comments