Updates to the new parser.
This commit is contained in:
parent
71d1150e3f
commit
394152e763
@ -1,4 +1,37 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An LL(k) parser for the context-free grammar of Doctrine Query Language.
|
||||
* Parses a DQL query, reports any errors in it, and generates the corresponding
|
||||
* SQL.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Parser
|
||||
{
|
||||
/**
|
||||
@ -46,21 +79,41 @@ class Doctrine_Query_Parser
|
||||
protected $_errorDistance = self::MIN_ERROR_DISTANCE;
|
||||
|
||||
/**
|
||||
* A query printer object used to print a parse tree from the input string.
|
||||
* A query printer object used to print a parse tree from the input string
|
||||
* for debugging purposes.
|
||||
*
|
||||
* @var Doctrine_Query_Printer
|
||||
*/
|
||||
protected $_printer;
|
||||
|
||||
/**
|
||||
* The connection object used by this query.
|
||||
*
|
||||
* @var Doctrine_Connection
|
||||
*/
|
||||
protected $_conn;
|
||||
|
||||
/**
|
||||
* Creates a new query parser object.
|
||||
*
|
||||
* @param string $input query string to be parsed
|
||||
* @param Doctrine_Connection The connection object the query will use.
|
||||
*/
|
||||
public function __construct($input)
|
||||
public function __construct($input, Doctrine_Connection $conn = null)
|
||||
{
|
||||
$this->_scanner = new Doctrine_Query_Scanner($input);
|
||||
$this->_printer = new Doctrine_Query_Printer(true);
|
||||
|
||||
if ($conn === null) {
|
||||
$conn = Doctrine_Manager::getInstance()->getCurrentConnection();
|
||||
}
|
||||
|
||||
$this->_conn = $conn;
|
||||
}
|
||||
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->_conn;
|
||||
}
|
||||
|
||||
public function getProduction($name)
|
||||
@ -90,26 +143,20 @@ class Doctrine_Query_Parser
|
||||
}
|
||||
|
||||
if ($isMatch) {
|
||||
//$this->_printer->println($this->lookahead['value']);
|
||||
$this->_printer->println($this->lookahead['value']);
|
||||
$this->lookahead = $this->_scanner->next();
|
||||
$this->_errorDistance++;
|
||||
} else {
|
||||
$this->syntaxError();
|
||||
$this->logError();
|
||||
}
|
||||
}
|
||||
|
||||
public function syntaxError()
|
||||
public function logError($message = '')
|
||||
{
|
||||
$this->_error('Unexpected "' . $this->lookahead['value'] . '"');
|
||||
}
|
||||
if ($message === '') {
|
||||
$message = 'Unexpected "' . $this->lookahead['value'] . '"';
|
||||
}
|
||||
|
||||
public function semanticalError($message)
|
||||
{
|
||||
$this->_error($message);
|
||||
}
|
||||
|
||||
protected function _error($message)
|
||||
{
|
||||
if ($this->_errorDistance >= self::MIN_ERROR_DISTANCE) {
|
||||
$message .= 'at line ' . $this->lookahead['line']
|
||||
. ', column ' . $this->lookahead['column'];
|
||||
|
@ -1,6 +1,35 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An abstract base class that all query parser productions extend.
|
||||
* An abstract base class for the productions of the Doctrine Query Language
|
||||
* context-free grammar.
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
abstract class Doctrine_Query_Production
|
||||
{
|
||||
@ -37,7 +66,6 @@ abstract class Doctrine_Query_Production
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
return $this->_parser->getProduction($method)->execute($args);
|
||||
$this->_parser->getPrinter()->startProduction($name);
|
||||
$retval = $this->_parser->getProduction($method)->execute($args);
|
||||
$this->_parser->getPrinter()->endProduction();
|
||||
@ -53,13 +81,4 @@ abstract class Doctrine_Query_Production
|
||||
* @return mixed
|
||||
*/
|
||||
abstract public function execute(array $params = array());
|
||||
|
||||
protected function _isSubquery()
|
||||
{
|
||||
$lookahead = $this->_parser->lookahead;
|
||||
$next = $this->_parser->getScanner()->peek();
|
||||
|
||||
return $lookahead['value'] === '(' && $next['type'] === Doctrine_Query_Token::T_SELECT;
|
||||
}
|
||||
|
||||
}
|
||||
|
70
draft/Doctrine/Query/Production/AbstractSchemaName.php
Normal file
70
draft/Doctrine/Query/Production/AbstractSchemaName.php
Normal file
@ -0,0 +1,70 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* This class represents the AbstractSchemaName production in DQL grammar.
|
||||
*
|
||||
* <code>
|
||||
* AbstractSchemaName = identifier
|
||||
* </code>
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Production_AbstractSchemaName extends Doctrine_Query_Production
|
||||
{
|
||||
/**
|
||||
* Executes the AbstractSchemaName production.
|
||||
*
|
||||
* <code>
|
||||
* AbstractSchemaName = identifier
|
||||
* </code>
|
||||
*
|
||||
* @param array $params This production does not take any parameters.
|
||||
* @return Doctrine_Table|null the table object corresponding the identifier
|
||||
* name
|
||||
*/
|
||||
public function execute(array $params = array())
|
||||
{
|
||||
$table = null;
|
||||
$token = $this->_parser->lookahead;
|
||||
|
||||
if ($token['type'] === Doctrine_Query_Token::T_IDENTIFIER) {
|
||||
|
||||
$table = $this->_parser->getConnection()->getTable($token['value']);
|
||||
|
||||
if ($table === null) {
|
||||
$this->_parser->logError('Table named "' . $name . '" does not exist.');
|
||||
}
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
} else {
|
||||
$this->_parser->logError('Identifier expected');
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
}
|
19
draft/Doctrine/Query/Production/IdentificationVariable.php
Normal file
19
draft/Doctrine/Query/Production/IdentificationVariable.php
Normal file
@ -0,0 +1,19 @@
|
||||
<?php
|
||||
/**
|
||||
* IdentificationVariable = identifier
|
||||
*/
|
||||
class Doctrine_Query_Production_IdentificationVariable extends Doctrine_Query_Production
|
||||
{
|
||||
public function execute(array $params = array())
|
||||
{
|
||||
$token = $this->_parser->lookahead;
|
||||
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
|
||||
/*
|
||||
if ( ! isValidIdentificationVariable($token['value'])) {
|
||||
$this->error('"' . $name . '" is not a identification variable.');
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
@ -0,0 +1,16 @@
|
||||
<?php
|
||||
/**
|
||||
* PathExpressionEndingWithAsterisk = {identifier "."} "*"
|
||||
*/
|
||||
class Doctrine_Query_Production_PathExpressionEndingWithAsterisk extends Doctrine_Query_Production
|
||||
{
|
||||
public function execute(array $params = array())
|
||||
{
|
||||
while ($this->_isNextToken(Doctrine_Query_Token::T_IDENTIFIER)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
$this->_parser->match('.');
|
||||
}
|
||||
|
||||
$this->_parser->match('*');
|
||||
}
|
||||
}
|
@ -18,7 +18,7 @@ class Doctrine_Query_Production_QueryLanguage extends Doctrine_Query_Production
|
||||
$this->DeleteStatement();
|
||||
break;
|
||||
default:
|
||||
$this->_parser->syntaxError();
|
||||
$this->_parser->logError();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,18 +1,17 @@
|
||||
<?php
|
||||
/**
|
||||
* RangeVariableDeclaration = PathExpression [["AS" ] identifier]
|
||||
* RangeVariableDeclaration = AbstractSchemaName ["AS"] IdentificationVariable
|
||||
*/
|
||||
class Doctrine_Query_Production_RangeVariableDeclaration extends Doctrine_Query_Production
|
||||
{
|
||||
public function execute(array $params = array())
|
||||
{
|
||||
$this->PathExpression();
|
||||
$this->AbstractSchemaName();
|
||||
|
||||
if ($this->_isNextToken(Doctrine_Query_Token::T_AS)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_AS);
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
} elseif ($this->_isNextToken(Doctrine_Query_Token::T_IDENTIFIER)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
}
|
||||
|
||||
$this->IdentificationVariable();
|
||||
}
|
||||
}
|
||||
|
@ -1,12 +1,35 @@
|
||||
<?php
|
||||
/**
|
||||
* SelectExpression = (Expression | "(" Subselect ")" ) [["AS"] identifier]
|
||||
* SelectExpression = (PathExpressionEndingWithAsterisk | Expression | "(" Subselect ")")
|
||||
* [["AS"] IdentificationVariable]
|
||||
*/
|
||||
class Doctrine_Query_Production_SelectExpression extends Doctrine_Query_Production
|
||||
{
|
||||
private function _isPathExpressionEndingWithAsterisk()
|
||||
{
|
||||
$token = $this->_parser->lookahead;
|
||||
$this->_parser->getScanner()->resetPeek();
|
||||
|
||||
while (($token['type'] === Doctrine_Query_Token::T_IDENTIFIER) || ($token['value'] === '.')) {
|
||||
$token = $this->_parser->getScanner()->peek();
|
||||
}
|
||||
|
||||
return $token['value'] === '*';
|
||||
}
|
||||
|
||||
private function _isSubquery()
|
||||
{
|
||||
$lookahead = $this->_parser->lookahead;
|
||||
$next = $this->_parser->getScanner()->peek();
|
||||
|
||||
return $lookahead['value'] === '(' && $next['type'] === Doctrine_Query_Token::T_SELECT;
|
||||
}
|
||||
|
||||
public function execute(array $params = array())
|
||||
{
|
||||
if ($this->_isSubquery()) {
|
||||
if ($this->_isPathExpressionEndingWithAsterisk()) {
|
||||
$this->PathExpressionEndingWithAsterisk();
|
||||
} elseif ($this->_isSubquery()) {
|
||||
$this->_parser->match('(');
|
||||
$this->Subselect();
|
||||
$this->_parser->match(')');
|
||||
@ -18,7 +41,7 @@ class Doctrine_Query_Production_SelectExpression extends Doctrine_Query_Producti
|
||||
$this->_parser->match(Doctrine_Query_Token::T_AS);
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
} elseif ($this->_isNextToken(Doctrine_Query_Token::T_IDENTIFIER)) {
|
||||
$this->_parser->match(Doctrine_Query_Token::T_IDENTIFIER);
|
||||
$this->IdentificationVariable();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,35 @@
|
||||
<?php
|
||||
/*
|
||||
* $Id$
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* This software consists of voluntary contributions made by many individuals
|
||||
* and is licensed under the LGPL. For more information, see
|
||||
* <http://www.phpdoctrine.org>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* ...
|
||||
*
|
||||
* @package Doctrine
|
||||
* @subpackage Query
|
||||
* @author Janne Vanhala <jpvanhal@cc.hut.fi>
|
||||
* @license http://www.opensource.org/licenses/lgpl-license.php LGPL
|
||||
* @link www.phpdoctrine.org
|
||||
* @since 1.0
|
||||
* @version $Revision$
|
||||
*/
|
||||
class Doctrine_Query_Scanner
|
||||
{
|
||||
/**
|
||||
|
@ -50,14 +50,6 @@ final class Doctrine_Query_Token
|
||||
const T_SQRT = 141;
|
||||
const T_MOD = 142;
|
||||
const T_SIZE = 143;
|
||||
const T_CURRENT_DATE = 144;
|
||||
const T_CURRENT_TIMESTAMP = 145;
|
||||
const T_CURRENT_TIME = 146;
|
||||
const T_SUBSTRING = 147;
|
||||
const T_CONCAT = 148;
|
||||
const T_TRIM = 149;
|
||||
const T_LOWER = 150;
|
||||
const T_UPPER = 151;
|
||||
|
||||
private function __construct() {}
|
||||
}
|
||||
|
@ -1,3 +1,16 @@
|
||||
/* Context-free grammar for Doctrine Query Language
|
||||
*
|
||||
* Document syntax:
|
||||
* - non-terminals begin with an upper case character
|
||||
* - terminals begin with a lower case character
|
||||
* - parentheses (...) are used for grouping
|
||||
* - square brackets [...] are used for defining an optional part, eg. zero or
|
||||
* one time time
|
||||
* - curly brackets {...} are used for repetion, eg. zero or more times
|
||||
* - double quotation marks "..." define a terminal string
|
||||
* - a vertical bar represents an alternative
|
||||
*/
|
||||
|
||||
QueryLanguage = SelectStatement | UpdateStatement | DeleteStatement
|
||||
|
||||
SelectStatement = [SelectClause] FromClause [WhereClause] [GroupByClause] [HavingClause] [OrderByClause] [LimitClause]
|
||||
@ -20,11 +33,11 @@ OrderByItem = PathExpression ["ASC" | "DESC"]
|
||||
GroupByItem = PathExpression
|
||||
UpdateItem = PathExpression "=" (Expression | "NULL")
|
||||
|
||||
IdentificationVariableDeclaration = RangeVariableDeclaration {Join}
|
||||
RangeVariableDeclaration = PathExpression [["AS" ] identifier<identification-variable>]
|
||||
IdentificationVariableDeclaration = RangeVariableDeclaration {Join}
|
||||
RangeVariableDeclaration = AbstractSchemaName ["AS"] IdentificationVariable
|
||||
|
||||
Join = ["LEFT" | "INNER"] "JOIN" PathExpression "AS" identifier [["ON" | "WITH"] ConditionalExpression] IndexBy
|
||||
IndexBy = "INDEXBY" identifier
|
||||
Join = ["LEFT" | "INNER"] "JOIN" PathExpression ["AS"] IdentificationVariable [("ON" | "WITH") ConditionalExpression] [IndexBy]
|
||||
IndexBy = "INDEXBY" PathExpression
|
||||
|
||||
ConditionalExpression = ConditionalTerm {"OR" ConditionalTerm}
|
||||
ConditionalTerm = ConditionalFactor {"AND" ConditionalFactor}
|
||||
@ -34,15 +47,16 @@ SimpleConditionalExpression
|
||||
= Expression (ComparisonExpression | BetweenExpression | LikeExpression
|
||||
| InExpression | NullComparisonExpression) | ExistsExpression
|
||||
|
||||
Atom = string-literal | numeric-constant | input-parameter
|
||||
Atom = string_literal | numeric_constant | input_parameter
|
||||
|
||||
Expression = Expression {("+" | "-" | "*" | "/") Expression}
|
||||
Expression = ("+" | "-") Expression
|
||||
Expression = "(" Expression ")"
|
||||
Expression = PathExpression | Atom | | Function | AggregateExpression
|
||||
Expression = Term {("+" | "-") Term}
|
||||
Term = Factor {("*" | "/") Factor}
|
||||
Factor = [("+" | "-")] Primary
|
||||
Primary = PathExpression | Atom | "(" Expression ")" | Function | AggregateExpression
|
||||
|
||||
SelectExpression = (Expression | "(" Subselect ")" ) [["AS"] identifier]
|
||||
SelectExpression = (PathExpressionEndingWithAsterisk | Expression | "(" Subselect ")" ) [["AS"] IdentificationVariable]
|
||||
PathExpression = identifier {"." identifier}
|
||||
PathExpressionEndingWithAsterisk = {identifier "."} "*"
|
||||
|
||||
AggregateExpression = ("AVG" | "MAX" | "MIN" | "SUM") "(" ["DISTINCT"] Expression ")"
|
||||
| "COUNT" "(" ["DISTINCT"] (Expression | "*") ")"
|
||||
@ -51,26 +65,8 @@ QuantifiedExpression = ("ALL" | "ANY" | "SOME") "(" Subselect ")"
|
||||
BetweenExpression = ["NOT"] "BETWEEN" Expression "AND" Expression
|
||||
ComparisonExpression = ComparisonOperator ( QuantifiedExpression | Expression | "(" Subselect ")" )
|
||||
InExpression = ["NOT"] "IN" "(" (Atom {"," Atom} | Subselect) ")"
|
||||
LikeExpression = ["NOT"] "LIKE" Expression ["ESCAPE" escape_character]
|
||||
LikeExpression = ["NOT"] "LIKE" Expression ["ESCAPE" string_literal]
|
||||
NullComparisonExpression = "IS" ["NOT"] "NULL"
|
||||
ExistsExpression = ["NOT"] "EXISTS" "(" Subselect ")"
|
||||
|
||||
|
||||
Function =
|
||||
"CURRENT_DATE" |
|
||||
"CURRENT_TIME" |
|
||||
"CURRENT_TIMESTAMP" |
|
||||
"LENGTH" "(" Expression ")" |
|
||||
"LOCATE" "(" Expression "," Expression ["," Expression] ")" |
|
||||
"ABS" "(" Expression ")" |
|
||||
"SQRT" "(" Expression ")" |
|
||||
"MOD" "(" Expression "," Expression ")" |
|
||||
"SIZE" "(" Expression ")" |
|
||||
"CONCAT" "(" Expression "," Expression ")" |
|
||||
"SUBSTRING" "(" Expression "," Expression "," "Expression" ")" |
|
||||
"TRIM" "(" [[TrimSpecification] [trim_character] "FROM"] string_primary ")" |
|
||||
"LOWER" "(" string_primary ")" |
|
||||
"UPPER" "(" string_primary ")" |
|
||||
identifier "(" [Expression {"," Expression}]")" // Custom function
|
||||
|
||||
TrimSpecification = "LEADING" | "TRAILING" | "BOTH"
|
||||
Function = identifier "(" [Expression {"," Expression}] ")"
|
||||
|
Loading…
x
Reference in New Issue
Block a user