Available in versions: Dev (3.20) | Latest (3.19) | 3.18 | 3.17

This is experimental functionality, and as such subject to change. Use at your own risk!

Pattern based transformation

Applies to ❌ Open Source Edition   ✅ Express Edition   ✅ Professional Edition   ✅ Enterprise Edition

Starting with jOOQ 3.16, a new Query Object Model (QOM) API has been added, which features traversal and replacement SPIs. One out of the box application of replacement are pattern transformations, where we recognise common patterns in a query's expressions and allow for replacing them by a better expression.

For example, the following transformations are possible:

-- With Settings.transformPatternsTrim active, this:

-- ... is transformed into the equivalent expression:

The whole feature set is deactivated by default using the Settings.transformPatterns flag as the traversal overhead does not warrant activation by default. Common use-cases for the activation of this feature include:

  • SQL linting, including as part of an ExecuteListener, where the effort can be controlled in a utility run only during integration testing, for example.
  • SQL cleanup, including as part of a ParsingConnection, where inputs/outputs are cached by default.
  • Dialect migration, when moving from a less powerful dialect to a more powerful one, or to a new version, manually written emulations may become obsolete.
  • Patching specific SQL features only

Individual features can either be turned on in bulk and opted out of individually, or each feature is turned on individually, depending on the use case.

Repetition of pattern replacement

As any replacement SPI implementation, the algorithm iterates over the jOOQ expression tree until it can no longer replace anything, i.e. until the transformations stabilise. For example, the following sequence of transformations is possible:

-- Original SQL
SELECT NOT(1 = 0) AND 1 = 1;

-- Step 1: Settings.transformPatternsNotComparison
SELECT 1 != 0 AND 1 = 1;

-- Step 2: Settings.transformPatternsTrivialPredicates

-- Step 3: Settings.transformPatternsTrivialPredicates

Dialect specific result

The following sections will make claims like 1 / TAN(x) or COS(x) / SIN(x) being replaced by COT(x), see e.g. Trigonometric functions. Some dialects may not have native support for COT(), so this is going to be emulated on those dialects, making the transformation effectively redundant. But these things happen at different times:

  • This pattern transformation feature can either be invoked explicitly by users, or it is enabled by configuration and then happens before all the rendering takes place, only once for the top level org.jooq.QueryPart
  • The rendering of SQL invokes emulations as the above, after the SQL has been transformed.

In other words, the two operations do not know about each other.

Table of contents
AND to NOT IN (new)
Arithmetic expressions (new)
COUNT(*) scalar subquery comparison (new)
COUNT(expr) scalar subquery comparison (new)
Empty scalar subquery (new)
Hyperbolic functions (new)
Idempotent function repetition (new)
Inverse hyperbolic functions (new)
Logarithmic functions (new)
Merge AND predicates (new)
Merge BIT_NOT with BIT_NAND (new)
Merge BIT_NOT with BIT_NOR (new)
Merge BIT_NOT with BIT_XNOR (new)
Merge IN predicates (new)
Merge NOT with comparison predicates (new)
Merge NOT with DISTINCT predicate (new)
Merge OR predicates (new)
Merge range predicates (new)
Normalise associative operations (new)
Normalise fields compared to values (new)
Normalise IN list with single element to comparison (new)
OR to IN (new)
Repeated arithmetic negation (new)
Repeated bitwise negation (new)
Repeated NOT (new)
Trigonometric functions (new)
Trim (new)
Trivial case abbreviations (new)
Trivial predicates (new)

previous : next


Do you have any feedback about this page? We'd love to hear it!

The jOOQ Logo