summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Context.php2
-rw-r--r--src/Fragments/DataTypeFragment.php39
-rw-r--r--src/Fragments/OptionsFragment.php4
-rw-r--r--src/Fragments/ParamDefFragment.php5
-rw-r--r--src/Lexer.php75
-rw-r--r--src/Parser.php13
-rw-r--r--src/Statements/CreateStatement.php1
-rw-r--r--src/Token.php16
-rw-r--r--src/Utils/Routine.php46
9 files changed, 146 insertions, 55 deletions
diff --git a/src/Context.php b/src/Context.php
index 8c2ac14..3d7f4ab 100644
--- a/src/Context.php
+++ b/src/Context.php
@@ -116,7 +116,7 @@ abstract class Context
'END' => 2,
'INDEX' => 2, 'VALUE' => 2,
'ENGINE' => 2,
- 'COMMENT' => 2, 'RETURNS' => 2, 'STORAGE' => 2,
+ 'CHARSET' => 2, 'COMMENT' => 2, 'RETURNS' => 2, 'STORAGE' => 2,
'CHECKSUM' => 2, 'MAX_ROWS' => 2, 'MIN_ROWS' => 2, 'NOT NULL' => 2,
'PASSWORD' => 2,
'INDEX KEY' => 2, 'PACK_KEYS' => 2,
diff --git a/src/Fragments/DataTypeFragment.php b/src/Fragments/DataTypeFragment.php
index acf3933..a5c8eca 100644
--- a/src/Fragments/DataTypeFragment.php
+++ b/src/Fragments/DataTypeFragment.php
@@ -10,24 +10,40 @@ use SqlParser\Token;
use SqlParser\TokensList;
/**
- * `RETURN` keyword parser.
+ * Parses a data type.
*/
class DataTypeFragment extends Fragment
{
+ public static $OPTIONS = array(
+ 'BINARY' => 1,
+ 'CHARACTER SET' => array(2, 'var'),
+ 'CHARSET' => array(3, 'var'),
+ 'COLLATE' => 4,
+ 'UNSIGNED' => 5,
+ 'ZEROFILL' => 6,
+ );
+
/**
- * The data type returned.
+ * The name of the data type.
*
* @var string
*/
- public $type;
+ public $name;
/**
- * The size of this variable.
+ * The size of this data type.
*
* @var array
*/
- public $size;
+ public $size = array();
+
+ /**
+ * The options of this data type.
+ *
+ * @var OptionsFragment
+ */
+ public $options = array();
/**
* @param Parser $parser
@@ -47,8 +63,7 @@ class DataTypeFragment extends Fragment
*
* 0 -------------------[ data type ]--------------------> 1
*
- * 1 ------------------[ size (array) ]------------------> 4
- * 1 ----------------------[ else ]----------------------> -1
+ * 1 ----------------[ size and options ]----------------> 2
*
* @var int
*/
@@ -64,7 +79,7 @@ class DataTypeFragment extends Fragment
}
if ($state === 0) {
- $ret->type = $token->value;
+ $ret->name = $token->value;
$ret->tokens[] = $token;
if (!isset(Context::$DATA_TYPES[$token->value])) {
$parser->error('Unrecognized data type.', $token);
@@ -75,18 +90,20 @@ class DataTypeFragment extends Fragment
$size = ArrayFragment::parse($parser, $list);
$ret->size = $size->array;
$ret->tokens = array_merge($ret->tokens, $size->tokens);
- } else {
- --$list->idx;
+ ++$list->idx;
}
+ $ret->options = OptionsFragment::parse($parser, $list, static::$OPTIONS);
+ ++$list->idx;
break;
}
}
- if (empty($ret->type)) {
+ if (empty($ret->name)) {
return null;
}
+ --$list->idx;
return $ret;
}
}
diff --git a/src/Fragments/OptionsFragment.php b/src/Fragments/OptionsFragment.php
index ce52135..22661eb 100644
--- a/src/Fragments/OptionsFragment.php
+++ b/src/Fragments/OptionsFragment.php
@@ -19,7 +19,7 @@ class OptionsFragment extends Fragment
*
* @var array
*/
- public $options;
+ public $options = array();
/**
* @param Parser $parser
@@ -109,6 +109,8 @@ class OptionsFragment extends Fragment
}
+ ksort($ret->options);
+
--$list->idx;
return $ret;
}
diff --git a/src/Fragments/ParamDefFragment.php b/src/Fragments/ParamDefFragment.php
index e6ecea9..05bad6e 100644
--- a/src/Fragments/ParamDefFragment.php
+++ b/src/Fragments/ParamDefFragment.php
@@ -23,7 +23,7 @@ class ParamDefFragment extends Fragment
public $name;
/**
- * Parameter's type (IN, OUT or INOUT).
+ * Parameter's direction (IN, OUT or INOUT).
*
* @var string
*/
@@ -91,6 +91,9 @@ class ParamDefFragment extends Fragment
if (($token->value === 'IN') || ($token->value === 'OUT') || ($token->value === 'INOUT')) {
$expr->inOut = $token->value;
++$list->idx;
+ } else if ($token->value === ')') {
+ ++$list->idx;
+ break;
} else {
$expr->name = $token->value;
$state = 2;
diff --git a/src/Lexer.php b/src/Lexer.php
index 416122c..238d63b 100644
--- a/src/Lexer.php
+++ b/src/Lexer.php
@@ -115,6 +115,7 @@ class Lexer
$this->len = ($str instanceof UtfString) ?
$str->length() : strlen($str);
$this->strict = $strict;
+ $this->lex();
}
/**
@@ -134,6 +135,7 @@ class Lexer
// Another example is `parseComment`.
$tokens = new TokensList();
+ $lastToken = NULL;
for ($this->last = 0, $lastIdx = 0; $this->last < $this->len; $lastIdx = ++$this->last) {
/** @var Token The new token. */
@@ -151,6 +153,17 @@ class Lexer
if ($this->delimiter !== $this->str[$this->last]) {
$this->error('Unexpected character.', $this->str[$this->last], $this->last);
}
+ } else if (($token->type === Token::TYPE_SYMBOL) && ($token->flags & Token::FLAG_SYMBOL_VARIABLE) &&
+ ($lastToken !== NULL)) {
+ // Handles ```... FROM 'user'@'%' ...```.
+ if ((($lastToken->type === Token::TYPE_SYMBOL) && ($lastToken->flags & Token::FLAG_SYMBOL_BACKTICK)) ||
+ ($lastToken->type === Token::TYPE_STRING)) {
+ $lastToken->token .= $token->token;
+ $lastToken->type = Token::TYPE_SYMBOL;
+ $lastToken->flags = Token::FLAG_SYMBOL_USER;
+ $lastToken->value .= '@' . $token->value;
+ continue;
+ }
}
$token->position = $lastIdx;
@@ -172,6 +185,8 @@ class Lexer
$token->type = Token::TYPE_DELIMITER;
$token->flags = 0;
}
+
+ $lastToken = $token;
}
// Adding a final delimite at the end to mark the ending.
@@ -479,20 +494,31 @@ class Lexer
/**
* Parses a string.
*
+ * @param string $quote Additional start symbol.
+ *
* @return Token
*/
- public function parseString()
+ public function parseString($quote = '')
{
- $quote = $token = $this->str[$this->last];
- if (!($flags = Context::isString($token))) {
+ $token = $this->str[$this->last];
+ if ((!($flags = Context::isString($token))) && ($token !== $quote)) {
return null;
}
- while ((++$this->last < $this->len) && ($this->str[$this->last] !== $quote)) {
- $token .= $this->str[$this->last];
- if (($this->str[$this->last] === '\\') && (++$this->last < $this->len)) {
+ $quote = $token;
+
+ while (++$this->last < $this->len) {
+ if (($this->last + 1 < $this->len) &&
+ ((($this->str[$this->last] === $quote) && ($this->str[$this->last + 1] === $quote)) ||
+ (($this->str[$this->last] === '\\') && ($quote !== '`')))) {
+ $token .= $this->str[$this->last] . $this->str[++$this->last];
+ } else {
+ if ($this->str[$this->last] === $quote) {
+ break;
+ }
$token .= $this->str[$this->last];
}
}
+
if (($this->last >= $this->len) || ($this->str[$this->last] !== $quote)) {
$this->error('Ending quote ' . $quote . ' was expected.', '', $this->last);
} else {
@@ -508,36 +534,27 @@ class Lexer
*/
public function parseSymbol()
{
- // TODO: `@` can be used in queries like ```... FROM 'user'@'%' ...```.
$token = $this->str[$this->last];
if (!($flags = Context::isSymbol($token))) {
return null;
}
- if ($flags === Token::FLAG_SYMBOL_VARIABLE) {
+
+ if ($flags & Token::FLAG_SYMBOL_VARIABLE) {
++$this->last;
- if (($name = static::parseString($this->str, $this->last, $this->len))) {
- $token .= $name->token;
- } elseif (($name = static::parseSymbol($this->str, $this->last, $this->len))) {
- $token .= $name->token;
- } else {
- $name = static::parseUnknown($this->str, $this->last, $this->len);
- if ($name === null) {
- $this->error('Variable name was expected.', $this->str[$this->last], $this->last);
- return null;
- }
- $token .= $name->token;
- }
- } elseif ($flags === Token::FLAG_SYMBOL_BACKTICK) {
- $token = $this->str[$this->last];
- while ((++$this->last < $this->len) && ($this->str[$this->last] !== '`')) {
- $token .= $this->str[$this->last];
- }
- if ($this->last >= $this->len) {
- $this->error('Ending backtick ` was expected.', '', $this->last);
- } else {
- $token .= $this->str[$this->last];
+ } else {
+ $token = '';
+ }
+
+ if (($str = $this->parseString('`')) === null) {
+ if (($str = static::parseUnknown()) === null) {
+ $this->error('Variable name was expected.', $this->str[$this->last], $this->last);
}
}
+
+ if ($str !== null) {
+ $token .= $str->token;
+ }
+
return new Token($token, Token::TYPE_SYMBOL, $flags);
}
diff --git a/src/Parser.php b/src/Parser.php
index 9fab5ac..c2f4ae2 100644
--- a/src/Parser.php
+++ b/src/Parser.php
@@ -115,14 +115,19 @@ class Parser
/**
* Constructor.
*
- * @param Parser $parser
- * @param TokensList $list
+ * @param mixed $list
* @param bool $strict
*/
- public function __construct(TokensList $list, $strict = false)
+ public function __construct($list, $strict = false)
{
- $this->list = $list;
+ if ((is_string($list)) || ($list instanceof UtfString)) {
+ $lexer = new Lexer($list, $strict);
+ $this->list = $lexer->tokens;
+ } elseif ($list instanceof TokensList) {
+ $this->list = $list;
+ }
$this->strict = $strict;
+ $this->parse();
}
/**
diff --git a/src/Statements/CreateStatement.php b/src/Statements/CreateStatement.php
index edf0dbd..25b4a8f 100644
--- a/src/Statements/CreateStatement.php
+++ b/src/Statements/CreateStatement.php
@@ -30,6 +30,7 @@ class CreateStatement extends Statement
'TEMPORARY' => 2,
'IF NOT EXISTS' => 3,
+ 'DEFINER' => array(4, 'var'),
);
/**
diff --git a/src/Token.php b/src/Token.php
index e597713..61fb16b 100644
--- a/src/Token.php
+++ b/src/Token.php
@@ -136,6 +136,7 @@ class Token
// Symbols related flags.
const FLAG_SYMBOL_VARIABLE = 1;
const FLAG_SYMBOL_BACKTICK = 2;
+ const FLAG_SYMBOL_USER = 4;
/**
* The token it its raw string representation.
@@ -224,15 +225,14 @@ class Token
case Token::TYPE_STRING:
return mb_substr($this->token, 1, -1); // trims quotes
case Token::TYPE_SYMBOL:
- if ($this->flags & Token::FLAG_SYMBOL_VARIABLE) {
- if ($this->token[1] === '`') {
- return mb_substr($this->token, 2, -1); // trims @` and `
- } else {
- return mb_substr($this->token, 1); // trims @
- }
- } elseif ($this->flags & Token::FLAG_SYMBOL_BACKTICK) {
- return mb_substr($this->token, 1, -1); // trims backticks
+ $str = $this->token;
+ if ((isset($str[0])) && ($str[0] === '@')) {
+ $str = mb_substr($str, 1);
+ }
+ if ((isset($str[0])) && (($str[0] === '`') || ($str[0] === '"') || ($str[0] === '\''))) {
+ $str = mb_substr($str, 1, -1);
}
+ return $str;
}
return $this->token;
}
diff --git a/src/Utils/Routine.php b/src/Utils/Routine.php
new file mode 100644
index 0000000..3015a3f
--- /dev/null
+++ b/src/Utils/Routine.php
@@ -0,0 +1,46 @@
+<?php
+
+namespace SqlParser\Utils;
+
+class Routine
+{
+
+ /**
+ * Gets the parameters of a routine from the parse tree.
+ *
+ * @param array $tree
+ *
+ * @return array
+ */
+ public static function getParameters($tree)
+ {
+ $retval = array(
+ 'num' => 0,
+ 'dir' => array(),
+ 'name' => array(),
+ 'type' => array(),
+ 'length' => array(),
+ 'opts' => array(),
+ );
+
+ $idx = 0;
+ foreach ($tree->parameters as $param) {
+ $retval['dir'][$idx] = $param->inOut;
+ $retval['name'][$idx] = $param->name;
+ $retval['type'][$idx] = $param->type->name;
+ $retval['length'][$idx] = implode(',', $param->type->size);
+ $retval['opts'][$idx] = array();
+ foreach ($param->type->options->options as $opt) {
+ $retval['opts'][$idx][] = is_string($opt) ?
+ $opt : $opt['value'];
+ }
+ $retval['opts'][$idx] = implode(' ', $retval['opts'][$idx]);
+ ++$idx;
+ }
+
+ $retval['num'] = $idx;
+
+ return $retval;
+ }
+
+}