summaryrefslogtreecommitdiffstats
path: root/src/Fragments/FieldFragment.php
diff options
context:
space:
mode:
Diffstat (limited to 'src/Fragments/FieldFragment.php')
-rw-r--r--src/Fragments/FieldFragment.php61
1 files changed, 61 insertions, 0 deletions
diff --git a/src/Fragments/FieldFragment.php b/src/Fragments/FieldFragment.php
index 4adbba5..a45c0fe 100644
--- a/src/Fragments/FieldFragment.php
+++ b/src/Fragments/FieldFragment.php
@@ -55,6 +55,20 @@ class FieldFragment extends Fragment
public $alias;
/**
+ * The name of the function.
+ *
+ * @var string
+ */
+ public $function;
+
+ /**
+ * The type of subquery.
+ *
+ * @var string
+ */
+ public $subquery;
+
+ /**
* @param Parser $parser The parser that serves as context.
* @param TokensList $list The list of tokens that are being parsed.
* @param array $options Parameters for parsing.
@@ -89,6 +103,16 @@ class FieldFragment extends Fragment
*/
$brackets = 0;
+ /**
+ * Keeps track of the previous token.
+ * Possible values:
+ * string, if function was previously found;
+ * true, if open bracket was previously found;
+ * null, in any other case.
+ * @var string|bool
+ */
+ $prev = null;
+
for (; $list->idx < $list->count; ++$list->idx) {
/**
@@ -121,12 +145,26 @@ class FieldFragment extends Fragment
continue;
}
break;
+ } else if ($prev === true) {
+ if ((empty($ret->subquery) && (!empty(Parser::$STATEMENT_PARSERS[$token->value])))) {
+ // A `(` was previously found and this keyword is the
+ // beginning of a statement, so this is a subquery.
+ $ret->subquery = $token->value;
+ }
}
}
if ($token->type === Token::TYPE_OPERATOR) {
if ($token->value === '(') {
++$brackets;
+ // We don't check to see if `$prev` is `true` (open bracke
+ // was found before) because the brackets count is one (the
+ // only bracket we found is this one).
+ if (($brackets === 1) && (empty($ret->function)) && ($prev !== null) && ($prev !== true)) {
+ // A function name was previously found and now an open
+ // bracket, so this is a function call.
+ $ret->function = $prev;
+ }
$isExpr = true;
} elseif ($token->value === ')') {
--$brackets;
@@ -150,15 +188,24 @@ class FieldFragment extends Fragment
}
if ($alias) {
+ // An alias is expected (the keyword `AS` was previously found).
$ret->alias = $token->value;
$alias = 0;
} else {
if (!$isExpr) {
if (($token->type === Token::TYPE_OPERATOR) && ($token->value === '.')) {
+ // Found a `.` which means we expect a column name and
+ // the column name we parsed is actually the table name
+ // and the table name is actually a database name.
+ if ((!empty($ret->database)) || ($period)) {
+ $parser->error('Unexpected dot.', $token);
+ }
$ret->database = $ret->table;
$ret->table = $ret->column;
$period = true;
} else {
+ // We found the name of a column (or table if column
+ // field should be skipped; used to parse table names).
if (!empty($options['skipColumn'])) {
$ret->table = $token->value;
} else {
@@ -167,6 +214,8 @@ class FieldFragment extends Fragment
$period = false;
}
} else {
+ // Parsing aliases without `AS` keyword.
+ // Example: SELECT 'foo' `bar`
if ($brackets === 0) {
if (($token->type === Token::TYPE_NONE) || ($token->type === Token::TYPE_STRING)
|| (($token->type === Token::TYPE_SYMBOL) && ($token->flags & Token::FLAG_SYMBOL_BACKTICK))
@@ -178,12 +227,24 @@ class FieldFragment extends Fragment
$ret->expr .= $token->token;
}
+
+ if (($token->type === Token::TYPE_KEYWORD) && ($token->flags & Token::FLAG_KEYWORD_FUNCTION)) {
+ $prev = strtoupper($token->value);
+ } else if (($token->type === Token::TYPE_OPERATOR) || ($token->value === '(')) {
+ $prev = true;
+ } else {
+ $prev = null;
+ }
+
}
if ($alias === 2) {
$parser->error('Alias was expected.');
}
+ // Whitespaces might be added at the end.
+ $ret->expr = trim($ret->expr);
+
if (empty($ret->expr)) {
return null;
}