22
33namespace PHPCR \Util \QOM ;
44
5+ use PHPCR \PropertyType ;
56use PHPCR \Query \InvalidQueryException ;
67use PHPCR \Query \QOM \ChildNodeJoinConditionInterface ;
78use PHPCR \Query \QOM \ColumnInterface ;
2223use PHPCR \Query \QOM \SameNodeJoinConditionInterface ;
2324use PHPCR \Query \QOM \SourceInterface ;
2425use 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