@@ -311,13 +311,60 @@ protected function parseDescendantNodeJoinCondition()
311311 }
312312
313313 /**
314- * 6.7.12 Constraint
315314 * 6.7.13 And
316315 * 6.7.14 Or
317316 *
318317 * @return \PHPCR\Query\QOM\ConstraintInterface
319318 */
320- protected function parseConstraint ()
319+ protected function parseConstraint ($ lhs = null , $ minprec = 0 )
320+ {
321+ if ($ lhs === null ) {
322+ $ lhs = $ this ->parsePrimaryConstraint ();
323+ }
324+
325+ $ opprec = array (
326+ 'OR ' => 1 ,
327+ 'AND ' => 2 ,
328+ );
329+
330+ $ op = strtoupper ($ this ->scanner ->lookupNextToken ());
331+ while (isset ($ opprec [$ op ]) && $ opprec [$ op ] >= $ minprec ) {
332+ $ this ->scanner ->fetchNextToken ();
333+
334+ $ rhs = $ this ->parsePrimaryConstraint ();
335+
336+ $ nextop = strtoupper ($ this ->scanner ->lookupNextToken ());
337+
338+ while (isset ($ opprec [$ nextop ]) && $ opprec [$ nextop ] > $ opprec [$ op ]) {
339+ $ rhs = $ this ->parseConstraint ($ rhs , $ opprec [$ nextop ]);
340+ $ nextop = strtoupper ($ this ->scanner ->lookupNextToken ());
341+ }
342+
343+ if ($ op == 'AND ' ) {
344+ $ lhs = $ this ->factory ->andConstraint ($ lhs , $ rhs );
345+ } elseif ($ op == 'OR ' ) {
346+ $ lhs = $ this ->factory ->orConstraint ($ lhs , $ rhs );
347+ } else {
348+ // this only happens if the operator is
349+ // in the $opprec-array but there is no
350+ // "elseif"-branch here for this operator.
351+ throw new \Exception (
352+ "Internal error: No action is defined for operator ' $ op' "
353+ );
354+ }
355+
356+ $ op = strtoupper ($ this ->scanner ->lookupNextToken ());
357+ }
358+
359+ return $ lhs ;
360+ }
361+
362+ /**
363+ * 6.7.12 Constraint
364+ *
365+ * @return \PHPCR\Query\QOM\ConstraintInterface
366+ */
367+ protected function parsePrimaryConstraint ()
321368 {
322369 $ constraint = null ;
323370 $ token = $ this ->scanner ->lookupNextToken ();
@@ -365,18 +412,6 @@ protected function parseConstraint()
365412 throw new \Exception ("Syntax error: constraint expected in ' {$ this ->sql2 }' " );
366413 }
367414
368- // Is it a composed contraint?
369- $ token = $ this ->scanner ->lookupNextToken ();
370- if (in_array (strtoupper ($ token ), array ('AND ' , 'OR ' ))) {
371- $ this ->scanner ->fetchNextToken ();
372- $ constraint2 = $ this ->parseConstraint ();
373- if ($ this ->scanner ->tokenIs ($ token , 'AND ' )) {
374- return $ this ->factory ->andConstraint ($ constraint , $ constraint2 );
375- }
376-
377- return $ this ->factory ->orConstraint ($ constraint , $ constraint2 );
378- }
379-
380415 return $ constraint ;
381416 }
382417
@@ -389,7 +424,7 @@ protected function parseNot()
389424 {
390425 $ this ->scanner ->expectToken ('NOT ' );
391426
392- return $ this ->factory ->notConstraint ($ this ->parseConstraint ());
427+ return $ this ->factory ->notConstraint ($ this ->parsePrimaryConstraint ());
393428 }
394429
395430 /**
0 commit comments