Skip to content

Commit 7895b26

Browse files
committed
Validate order of clauses in the parsing of statements
Fix #22 Signed-off-by: Deven Bansod <devenbansod.bits@gmail.com>
1 parent 94e550e commit 7895b26

File tree

3 files changed

+114
-0
lines changed

3 files changed

+114
-0
lines changed

src/Parser.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,9 @@ public function parse()
531531
$lastStatement->last = $statement->last;
532532

533533
$unionType = false;
534+
535+
// Validate clause order
536+
$statement->validateClauseOrder($this, $list);
534537
continue;
535538
}
536539

@@ -556,9 +559,15 @@ public function parse()
556559
}
557560
$lastTransaction = null;
558561
}
562+
563+
// Validate clause order
564+
$statement->validateClauseOrder($this, $list);
559565
continue;
560566
}
561567

568+
// Validate clause order
569+
$statement->validateClauseOrder($this, $list);
570+
562571
// Finally, storing the statement.
563572
if ($lastTransaction !== null) {
564573
$lastTransaction->statements[] = $statement;

src/Statement.php

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,4 +422,47 @@ public function __toString()
422422
{
423423
return $this->build();
424424
}
425+
426+
/**
427+
* Validates the order of the clauses in parsed statement
428+
* Ideally this should be called after successfully
429+
* completing the parsing of each statement
430+
*
431+
* @param Parser $parser The instance that requests parsing.
432+
* @param TokensList $list The list of tokens to be parsed.
433+
*
434+
* @return boolean
435+
*/
436+
public function validateClauseOrder($parser, $list)
437+
{
438+
$clauses = array_flip(array_keys($this->getClauses()));
439+
440+
if (empty($clauses)
441+
|| count($clauses) == 0
442+
) {
443+
return true;
444+
}
445+
446+
$minIdx = -1;
447+
foreach ($clauses as $clauseType => $index) {
448+
$clauseStartIdx = Utils\Query::getClauseStartOffset(
449+
$this,
450+
$list,
451+
$clauseType
452+
);
453+
454+
if ($clauseStartIdx != -1 && $clauseStartIdx < $minIdx) {
455+
$token = $list->tokens[$clauseStartIdx];
456+
$parser->error(
457+
__('Unexpected ordering of clauses.'),
458+
$token
459+
);
460+
return false;
461+
} elseif ($clauseStartIdx != -1) {
462+
$minIdx = $clauseStartIdx;
463+
}
464+
}
465+
466+
return true;
467+
}
425468
}

src/Utils/Query.php

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -783,4 +783,66 @@ public static function getFirstStatement($query, $delimiter = null)
783783

784784
return array(trim($statement), $query, $delimiter);
785785
}
786+
787+
/**
788+
* Gets a starting offset of a specific clause.
789+
*
790+
* @param Statement $statement The parsed query that has to be modified.
791+
* @param TokensList $list The list of tokens.
792+
* @param string $clause The clause to be returned.
793+
*
794+
* @return int
795+
*/
796+
public static function getClauseStartOffset($statement, $list, $clause)
797+
{
798+
799+
/**
800+
* The index of the current clause.
801+
*
802+
* @var int $currIdx
803+
*/
804+
$currIdx = 0;
805+
806+
/**
807+
* The count of brackets.
808+
* We keep track of them so we won't insert the clause in a subquery.
809+
*
810+
* @var int $brackets
811+
*/
812+
$brackets = 0;
813+
814+
/**
815+
* The clauses of this type of statement and their index.
816+
*
817+
* @var array $clauses
818+
*/
819+
$clauses = array_flip(array_keys($statement->getClauses()));
820+
821+
for ($i = $statement->first; $i <= $statement->last; ++$i) {
822+
$token = $list->tokens[$i];
823+
824+
if ($token->type === Token::TYPE_COMMENT) {
825+
continue;
826+
}
827+
828+
if ($token->type === Token::TYPE_OPERATOR) {
829+
if ($token->value === '(') {
830+
++$brackets;
831+
} elseif ($token->value === ')') {
832+
--$brackets;
833+
}
834+
}
835+
836+
if ($brackets == 0) {
837+
if (($token->type === Token::TYPE_KEYWORD)
838+
&& (isset($clauses[$token->value]))
839+
&& ($clause === $token->value)
840+
) {
841+
return $i;
842+
}
843+
}
844+
}
845+
846+
return -1;
847+
}
786848
}

0 commit comments

Comments
 (0)