-
Notifications
You must be signed in to change notification settings - Fork 1.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Replace common patterns in query object model #7284
Comments
This isn't really related to parsing, but could be done in general. Once we have a better query object model, pattern matching the object model in such ways would be quite common We'll review this in the context of the query object model redesign project. |
- transformPatternsNormaliseAssociativeOps (WIP) - transformPatternsNormaliseFieldCompareValue - transformPatternsOrEqToIn (WIP)
- transformPatternsNormaliseAssociativeOps (complete)
- transformPatternsOrEqToIn (support interleaving unrelated predicates) - transformPatternsAndNeToNotIn - transformPatternsMergeOrComparison
- transformPatternsNormaliseInListSingleElementToComparison - transformPatternsMergeInLists - Support the feature in ParserCLI
- transformPatternsMergeRangePredicates
- transformPatternsMergeAndComparison
- transformPatternsMergeInLists (merge also Eq with InList)
The various edge cases that arose from testing the transformations around hyperbolic functions have shown that it is important to separate canonicalisation/normalisation steps from merging steps. For example
That's the formula on wikipedia, but it is equivalent to these:
Much more thought will need to go into this. We're hardly breaking new grounds here, these symbol transformation algorithms must have been studied well already. |
The status quo will ship in jOOQ 3.17. More work in jOOQ 3.18 here: #13593 |
There are some common expressions that can be simplified by the jOOQ parser into better equivalents, such as:
In the above example, if jOOQ has a
trim()
function in its expression tree, that will perform (and look) better in all dialects that support it, while it still can be transformed back toRTRIM(LTRIM(...))
on the other dialects.This should be an configurable feature. There are some new
Settings
flags that allow for opting in to a set of sub-flags:transformPatterns
allows for removing excessively verbose syntax, replacing some patterns by a shorter, equivalent syntaxtransformPatternsTrim
:RTRIM(LTRIM(x))
=>TRIM(x)
transformPatternsTrim
:LTRIM(RTRIM(x))
=>TRIM(x)
transformPatternsIdempotentFunctionRepetition
:LTRIM(LTRIM(x))
orLTRIM(TRIM(x))
RTRIM(RTRIM(x))
orRTRIM(TRIM(x))
TRIM(TRIM(x))
UPPER(UPPER(x))
LOWER(LOWER(x))
ABS(ABS(x))
SIGN(SIGN(x))
CEIL(CEIL(x))
FLOOR(FLOOR(x))
ROUND(ROUND(x))
TRUNC(TRUNC(x))
CAST(CAST(x AS t) AS t)
transformPatternsArithmeticExpressions
:0 + x
=>x
1 * x
=>x
POWER(x, 1)
=>x
0 - x
=>-x
x + -y
=>x - y
x - -y
=>x + y
-x * -y
=>x * y
-x / -y
=>x / y
-(const)
=>-const
(change the value, don't useNeg
)-1 * x
=>-x
1 / y * x
=>x / y
x * x
=>SQUARE(x)
x <commutative op> const
=>const <commutative op> x
x + const
=>const + x
x * const
=>const * x
=
, the inverse is being donetransformPatternsTrigonometricFunctions
:SIN(x) / COS(x)
=>TAN(x)
1 / COT(x)
=>TAN(x)
COS(x) / SIN(x)
=>COT(x)
1 / TAN(x)
=>COT(x)
transformPatternsHyperbolicFunctions
(from https://en.wikipedia.org/wiki/Hyperbolic_functions, some of these might be derived from other maths transformations):(EXP(x) - EXP(-x)) / 2
=>SINH(x)
(EXP(2 * x) - 1) / (2 * EXP(x))
=>SINH(x)
(1 - EXP(-2 * x)) / (2 * EXP(-x))
=>SINH(x)
(EXP(x) + EXP(-x)) / 2
=>COSH(x)
(EXP(2 * x) + 1) / (2 * EXP(x))
=>COSH(x)
(1 + EXP(-2 * x)) / (2 * EXP(-x))
=>COSH(x)
SINH(x) / COSH(x)
=>TANH(x)
1 / COTH(x)
=>TANH(x)
(EXP(x) - EXP(-x)) / (EXP(x) + EXP(-x))
=>TANH(x)
(EXP(2 * x) - 1) / (EXP(2 * x) + 1)
=>TANH(x)
COSH(x) / SINH(x)
=>COTH(x)
1 / TANH(x)
=>COTH(x)
(EXP(x) + EXP(-x)) / (EXP(x) - EXP(-x))
=>COTH(x)
(EXP(2 * x) + 1) / (EXP(2 * x) - 1)
=>COTH(x)
transformPatternsInverseHyperbolicFunctions
(from https://en.wikipedia.org/wiki/Inverse_hyperbolic_functions)LN(x + SQRT(SQUARE(x) + 1))
=>ASINH(x)
LN(x + SQRT(SQUARE(x) - 1))
=>ACOSH(x)
LN((1 + x) / (1 - x)) / 2)
=>ATANH(x)
LN((x + 1) / (x - 1)) / 2)
=>ACOTH(x)
transformPatternsLogarithmicFunctions
LN(value) / LN(base)
=>LOG(base, value)
EXP(1)
=>e
LOG(e, x)
=>LN(x)
LOG(10, x)
=>LOG10(x)
POWER(e, x)
=>EXP(x)
transformPatternsOrEqToIn
:x = a OR x = b OR x = c OR ...
=>x IN (a, b, c, ...)
x = a OR x IN (b, c, ...)
=>x IN (a, b, c, ...)
x = a
anda = x
. Related (but not dependent on:transformPatternsNormaliseFieldCompareValue
)transformPatternsAndNeToNotIn
:x != a AND x != b AND x != c AND ...
=>x NOT IN (a, b, c, ...)
transformPatternsMergeOrComparison
:x = a OR x > a
=>x >= a
x = a OR x < a
=>x <= a
x > a OR x < a
=>x != a
x > a OR x != a
=>x != a
x < a OR x != a
=>x != a
transformPatternsMergeAndComparison
:x = a AND x >= a
=>x = a
x = a AND x <= a
=>x = a
x > a AND x < a
=>x != x
x > a AND x != a
=>x > a
x < a AND x != a
=>x < a
transformPatternsMergeInPredicates
:x IN (a, b, c) AND x IN (b, c, d)
=>x IN (b, c)
transformPatternsMergeRangePredicates
:x >= a AND x <= b
=>x BETWEEN a AND b
(done as part oftransformPatternsRedundantPredicates
:transformPatternsMergeOrComparison
)a <op> b AND/OR a <op> b
=>a <op> b
a <op> b AND/OR b <inverse op> a
=>a = b
transformPatternsTrivialCaseAbbreviation
:NVL(NULL, a)
=>a
NULLIF(a, a)
=>NULL
NULLIF(NULL, a)
=>NULL
NULLIF(a, NULL)
=>a
transformPatternsTrivialPredicates
:a is not distinct from a
=>TRUE
a is distinct from a
=>FALSE
a >= a
anda <= a
=>a = a
(leave as is, because ofNULL
semantics)a > a
anda < a
=>a != a
(leave as is, because ofNULL
semantics)<const> IS NOT NULL
=>TRUE
<const> IS NULL
=>FALSE
TRUE AND FALSE
=>FALSE
(and the whole truth table)TRUE OR FALSE
=>TRUE
(and the whole truth table)NOT (TRUE)
=>FALSE
andNOT (FALSE)
=>TRUE
SELECT .. WHERE TRUE
=>SELECT ..
SELECT .. HAVING TRUE
=>SELECT ..
SELECT .. QUALIFY TRUE
=>SELECT ..
transformPatternsNotNot
:NOT (NOT (p))
=>p
transformPatternsNotComparison
:NOT (a = b)
=>A != B
NOT (a != b)
=>A = B
NOT (a > b)
=>A <= B
NOT (a >= b)
=>A < B
NOT (a < b)
=>A >= B
NOT (a <= b)
=>A > B
transformPatternsNotNotDistinct
: MySQLNOT(a <=> b)
=>a IS DISTINCT FROM b
transformPatternsNegNeg
:-(-(i))
=>i
transformPatternsBitNotBitNot
:~(~(i))
=>i
transformPatternsBitNotNand
: (both for scalar and aggregate functions)~(bitnand(a, b))
=>bitand(a, b)
~(bitand(a, b))
=>bitnand(a, b)
transformPatternsBitNotNor
:~(bitnor(a, b))
=>bitor(a, b)
~(bitnor(a, b))
=>bitnor(a, b)
transformPatternsBitNotXNor
:~(bitxnor(a, b))
=>bitxor(a, b)
~(bitxor(a, b))
=>bitxnor(a, b)
. It's now a binary operator, so this no longer applies(a + b) + c
=>a + b + c
(works the same way for all associative operations)These are normalisation transformations that transform more esoteric syntaxes to more standardised ones. By normalising things, we can greatly reduce the search space of possible patterns, as not to miss any possible transformations:
transformPatternsNormaliseAssociativeOps
:(a + b) + (c + d)
=>(((a + b) + c) + d)
+
*
AND
OR
transformPatternsNormaliseFieldCompareValue
:1 = a
=>a = 1
transformPatternsNormaliseInListSingleElementToComparison
:x IN (a)
=>x = a
x NOT IN (a)
=>x != a
transformPatternsScalarSubqueryCountAsteriskGtZero
:(SELECT COUNT(*) ..) > 0
=>EXISTS (SELECT 1 ..)
UNION
and other set operationsGROUP BY
andHAVING
COUNT(*)
, not withCOUNT(expr)
(SELECT COUNT(*) ..) >= 1
transformPatternsScalarSubqueryCountExpressionGtZero
:(SELECT COUNT(expr) ..) > 0
=>EXISTS (SELECT 1 .. WHERE expr IS NOT NULL)
transformPatternsEmptyScalarSubquery
:SELECT .. FROM .. WHERE FALSE
=>NULL
A part of this task is to also add support for this functionality (but not each individual flag (yet)):
ParserCLI
Caveats
See follow-up task: #13593
The text was updated successfully, but these errors were encountered: