Skip to content

Commit 7860548

Browse files
committed
Merge pull request #78 from vstm/sql2-operator-precedence
Fix SQL2 operator precedence
2 parents 4c304fd + 47c4685 commit 7860548

File tree

1 file changed

+50
-15
lines changed

1 file changed

+50
-15
lines changed

src/PHPCR/Util/QOM/Sql2ToQomQueryConverter.php

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)