summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/Components/CaseExpression.php284
-rw-r--r--src/Components/ExpressionArray.php14
2 files changed, 295 insertions, 3 deletions
diff --git a/src/Components/CaseExpression.php b/src/Components/CaseExpression.php
new file mode 100644
index 0000000..6195cd8
--- /dev/null
+++ b/src/Components/CaseExpression.php
@@ -0,0 +1,284 @@
+<?php
+
+/**
+ * Parses a reference to a CASE expression
+ *
+ * @package SqlParser
+ * @subpackage Components
+ */
+namespace SqlParser\Components;
+
+use SqlParser\Context;
+use SqlParser\Component;
+use SqlParser\Parser;
+use SqlParser\Token;
+use SqlParser\TokensList;
+
+
+
+
+/**
+ * Parses a reference to a CASE expression
+ *
+ * @category Components
+ * @package SqlParser
+ * @subpackage Components
+ * @author Deven Bansod <devenbansod.bits@gmail.com>
+ * @license http://opensource.org/licenses/GPL-2.0 GNU Public License
+ */
+class CaseExpression extends Component
+{
+
+ /**
+ * The value to be compared
+ *
+ * @var Expression
+ */
+ public $value;
+
+ /**
+ * The conditions in WHEN clauses
+ *
+ * @var array
+ */
+ public $conditions;
+
+ /**
+ * The results matching with the WHEN clauses
+ *
+ * @var array
+ */
+ public $results;
+
+ /**
+ * The values to be compared against
+ *
+ * @var array
+ */
+ public $compare_values;
+
+ /**
+ * The result in ELSE section of expr
+ *
+ * @var array
+ */
+ public $else_result;
+
+ /**
+ * Constructor.
+ *
+ */
+ public function __construct()
+ {
+ }
+
+ /**
+ *
+ * @param Parser $parser The parser that serves as context.
+ * @param TokensList $list The list of tokens that are being parsed.
+ *
+ * @return Expression
+ */
+ public static function parse(Parser $parser, TokensList $list)
+ {
+ $ret = new CaseExpression();
+
+ /**
+ * Counts brackets.
+ *
+ * @var int $brackets
+ */
+ $brackets = 0;
+
+ /**
+ * Keeps track of the last two previous tokens.
+ *
+ * @var Token[] $prev
+ */
+ $prev = array(null, null);
+
+ /**
+ * State of parser
+ *
+ * @var int $parser
+ */
+ $state = 0;
+
+ /**
+ * Syntax type (type 0 or type 1)
+ *
+ * @var int $type
+ */
+ $type = 0;
+
+ ++$list->idx; // Skip 'CASE'
+
+ for (; $list->idx < $list->count; ++$list->idx) {
+
+ /**
+ * Token parsed at this moment.
+ *
+ * @var Token $token
+ */
+ $token = $list->tokens[$list->idx];
+
+ // End of statement.
+ if ($token->type === Token::TYPE_DELIMITER) {
+ break;
+ }
+
+ // Skipping whitespaces and comments.
+ if (($token->type === Token::TYPE_WHITESPACE)
+ || ($token->type === Token::TYPE_COMMENT)
+ ) {
+ continue;
+ }
+
+ if ($state === 0) {
+ if ($token->type === Token::TYPE_KEYWORD
+ && $token->value === 'WHEN'
+ ) {
+ ++$list->idx; // Skip 'WHEN'
+ $new_condition = Condition::parse($parser, $list);
+ $type = 1;
+ $state = 1;
+ $ret->conditions[] = $new_condition;
+ } elseif ($token->type === Token::TYPE_KEYWORD
+ && $token->value === 'ELSE'
+ ) {
+ ++$list->idx; // Skip 'ELSE'
+ $ret->else_result = Expression::parse($parser, $list);
+ $state = 0; // last clause of CASE expression
+ } elseif ($token->type === Token::TYPE_KEYWORD
+ && ($token->value === 'END'
+ || $token->value === 'end')
+ ) {
+ $state = 3; // end of CASE expression
+ ++$list->idx;
+ break;
+ } elseif ($token->type === Token::TYPE_KEYWORD) {
+ $parser->error(__('Unexpected keyword'), $token);
+ break;
+ } else {
+ $ret->value = Expression::parse($parser, $list);
+ $type = 0;
+ $state = 1;
+ }
+ } elseif ($state === 1) {
+ if ($type === 0) {
+ if ($token->type === Token::TYPE_KEYWORD
+ && $token->value === 'WHEN'
+ ) {
+ ++$list->idx; // Skip 'WHEN'
+ $new_value = Expression::parse($parser, $list);
+ $state = 2;
+ $ret->compare_values[] = $new_value;
+ } elseif ($token->type === Token::TYPE_KEYWORD
+ && $token->value === 'ELSE'
+ ) {
+ ++$list->idx; // Skip 'ELSE'
+ $ret->else_result = Expression::parse($parser, $list);
+ $state = 0; // last clause of CASE expression
+ } elseif ($token->type === Token::TYPE_KEYWORD
+ && ($token->value === 'END'
+ || $token->value === 'end')
+ ) {
+ $state = 3; // end of CASE expression
+ ++$list->idx;
+ break;
+ } elseif ($token->type === Token::TYPE_KEYWORD) {
+ $parser->error(__('Unexpected keyword'), $token);
+ break;
+ } else {
+ $parser->error(__('Unexpected token'), $token);
+ break;
+ }
+ } else {
+ if ($token->type === Token::TYPE_KEYWORD
+ && $token->value === 'THEN'
+ ) {
+ ++$list->idx; // Skip 'THEN'
+ $new_result = Expression::parse($parser, $list);
+ $state = 0;
+ $ret->results[] = $new_result;
+ } elseif ($token->type === Token::TYPE_KEYWORD) {
+ $parser->error(__('Unexpected keyword'), $token);
+ break;
+ } else {
+ $parser->error(__('Unexpected token'), $token);
+ break;
+ }
+ }
+ } elseif ($state === 2) {
+ if ($type === 0) {
+ if ($token->type === Token::TYPE_KEYWORD
+ && $token->value === 'THEN'
+ ) {
+ ++$list->idx; // Skip 'THEN'
+ $new_result = Expression::parse($parser, $list);
+ $ret->results[] = $new_result;
+ $state = 1;
+ } elseif ($token->type === Token::TYPE_KEYWORD) {
+ $parser->error(__('Unexpected keyword'), $token);
+ break;
+ } else {
+ $parser->error(__('Unexpected token'), $token);
+ break;
+ }
+ } else {
+ $parser->error(__('Unexpected token'), $token);
+ break;
+ }
+ }
+ }
+
+ if ($state !== 3) {
+ $parser->error(
+ __('Unexpected end of CASE expression'),
+ $list->list[$list->idx - 1]
+ );
+ }
+
+ --$list->idx;
+ return $ret;
+ }
+
+ /**
+ * @param Expression $component The component to be built.
+ * @param array $options Parameters for building.
+ *
+ * @return string
+ */
+ public static function build($component, array $options = array())
+ {
+ $ret = 'CASE ';
+ if (isset($component->value)) {
+ // Syntax type 0
+ $ret .= $component->value . ' ';
+ for (
+ $i = 0;
+ $i < count($component->compare_values) && $i < count($component->results);
+ $i++
+ ) {
+ $ret .= 'WHEN ' . $component->compare_values[$i] . ' ';
+ $ret .= 'THEN ' . $component->results[$i] . ' ';
+ }
+ } else {
+ // Syntax type 1
+ for (
+ $i = 0;
+ $i < count($component->conditions) && $i < count($component->results);
+ $i++
+ ) {
+ $ret .= 'WHEN ' . Condition::build($component->conditions[$i]) . ' ';
+ $ret .= 'THEN ' . $component->results[$i] . ' ';
+ }
+ }
+ if (isset($component->else_result)) {
+ $ret .= 'ELSE ' . $component->else_result . ' ';
+ }
+ $ret .= 'END';
+
+ return $ret;
+ }
+}
diff --git a/src/Components/ExpressionArray.php b/src/Components/ExpressionArray.php
index f108ad8..a64f64a 100644
--- a/src/Components/ExpressionArray.php
+++ b/src/Components/ExpressionArray.php
@@ -1,7 +1,7 @@
<?php
/**
- * Parses a a list of expressions delimited by a comma.
+ * Parses a list of expressions delimited by a comma.
*
* @package SqlParser
* @subpackage Components
@@ -14,7 +14,7 @@ use SqlParser\Token;
use SqlParser\TokensList;
/**
- * Parses a a list of expressions delimited by a comma.
+ * Parses a list of expressions delimited by a comma.
*
* @category Keywords
* @package SqlParser
@@ -73,13 +73,21 @@ class ExpressionArray extends Component
&& ((~$token->flags & Token::FLAG_KEYWORD_FUNCTION))
&& ($token->value !== 'DUAL')
&& ($token->value !== 'NULL')
+ && ($token->value !== 'CASE')
) {
// No keyword is expected.
break;
}
if ($state === 0) {
- $expr = Expression::parse($parser, $list, $options);
+ if ($token->type === Token::TYPE_KEYWORD
+ && $token->value === 'CASE'
+ ) {
+ $expr = CaseExpression::parse($parser, $list, $options);
+ } else {
+ $expr = Expression::parse($parser, $list, $options);
+ }
+
if ($expr === null) {
break;
}