[ ANNOUNCEMENT ] 3.17.0 Release with Computed Columns, Audit Columns, Pattern Matching, Reactive Transactions and Kotlin Coroutine Support and much more

538 views
Skip to first unread message

Lukas Eder

unread,
Jun 22, 2022, 11:14:25 AM6/22/22
to jOOQ User Group
Version 3.17.0 - June 22, 2022
================================================================================

This release contiues the work from previous releases around more
sophisticated SQL transformation capabilities, including:

- Client side computed columns for both read and write operations
- Audit columns
- Pattern matching SQL transformations
- More implicit JOIN capabilities

Client side computed columns
----------------------------

A ground breaking new core feature available in all commercial distributions is
the new client side computed columns feature, building on top of jOOQ 3.16's
commercial support for readonly columns and server side computed columns.

Not all RDBMS support computed columns (e.g. using the standard SQL syntax
GENERATED ALWAYS AS), and if they do, they might not support them in both STORED
(computed on write) and VIRTUAL (computed on read) variants. jOOQ can now
emulate both features at the client side, by transforming your SQL queries:

- STORED affects INSERT, UPDATE,
  DELETE, and MERGE
- VIRTUAL affects SELECT and the
  RETURNING clause of DML statements. To make use of these,
  combine them with the new synthetic column generation feature.

Unlike their server side counterparts, these client side features can produce
arbitrary expressions, including:

- Implicit joins
- Scalar subqueries
- MULTISET subqueries
- Much more

Think of this as "views" written in jOOQ, on a per-column basis. An expecially
useful feature combination is to combine these computed columns with the new
visibility modifier that allows for keeping computed columns (or the underlying
base columns) private and thus invisible to user code.

More about this feature here:

- https://www.jooq.org/doc/3.17/manual/code-generation/codegen-advanced/codegen-config-database/codegen-database-forced-types/codegen-database-forced-types-computed/


Audit columns
-------------

A special case of STORED client side computed columns are audit
columns, whose most basic implementation comes in the form of:

- CREATED_AT
- CREATED_BY
- MODIFIED_AT
- MODIFIED_BY

Other approaches to auditing exist, including soft deletion, additional meta
data, (bi)temporal versioning, but these columns are among the most popular
approaches, making this commercial only convenience feature very useful to a lot
of customers.

More about this feature here:

- https://www.jooq.org/doc/3.17/manual/code-generation/codegen-advanced/codegen-config-database/codegen-database-forced-types/codegen-database-forced-types-audit/


Java 17 baseline for the jOOQ Open Source Edition
-------------------------------------------------

Java 17 has been the latest LTS, and it includes a lot of really cool features,
including:

- sealed types (essential for pattern matching)
- records
- instanceof pattern matching
- text blocks
- switch expressions

jOOQ 3.16's experimental new Query Object Model (QOM) API experiments with
sealed types, which will be adopted more generally once the QOM API is
finalized.

To get broader user feedback on these improvements, as well as to embrace Java's
new LTS update cadence, we've decided to make Java 17 the baseline for the jOOQ
3.17 Open Source Edition, continuing our Java 8 and 11 support in the commercial
jOOQ distributions.

The following older jOOQ releases will continue to receive upgrades for a while:

- jOOQ 3.14: The last release with Java 8 support in the jOOQ Open Source
  Edition and Java 6 support in the jOOQ Enterprise Edition
- jOOQ 3.15 and 3.16: The last releases with Java 11 support in the jOOQ Open
  Source Edition and Java 8 support in the commercial editions.


PostgreSQL data type support
----------------------------

The jooq-postgres-extensions module, which contained support for the
HSTORE type, now has a lot more support for PostgreSQL specific
data types, including array types of each of:

- CIDR
- CITEXT
- LTREE
- HSTORE
- INET
- RANGE (including all the specialisations for INT4, INT8, etc.)

In order to profit from these data types, just add the
org.jooq:jooq-postgres-extensions module to your code generation
and runtime dependencies, and the types are generated automatically.


Implicit JOIN improvements
--------------------------

In this release, we experimented with a few new implicit JOIN features,
including support for implicit JOIN in DML statements. The current
implementation produces correlated subqueries where JOIN isn't supported in DML
statements.

We've also experimented with creating a "convenience syntax" for other commonly
used correlated subqueries, such as EXISTS(...) subqueries or
MULTISET(...) subqueries. The experiment has been very interesting.
The prototype, however, was rejected. See the discussions here:

- https://github.com/jOOQ/jOOQ/issues/13063
- https://github.com/jOOQ/jOOQ/issues/13069

Future jOOQ versions will implement the desired convenience in the form of more
implicit JOIN functionality, offering the feature also as an implicit to-many
JOIN.

A leftover from the prototype is the fact that you can now more easily project
expressions other than classic Field<T> in your SELECT
clause, namely:

- Table<R> now extends SelectField<R>
- Condition now extends Field<Boolean>

This means you can write a query like this:


Result<Record3<CustomerRecord, AddressRecord, Boolean>> result =
ctx.select(
        // Project a CustomerRecord directly
        CUSTOMER,
        // Project an AddressRecord from an implicit JOIN
        CUSTOMER.address(),
        // Project a boolean expression, instead of wrapping it with DSL.field()
        exists(
            selectOne()
            .from(PAYMENT)
            .where(PAYMENT.CUSTOMER_ID.eq(CUSTOMER.CUSTOMER_ID))
        )
   .from(CUSTOMER)
   .fetch();


Pattern matching SQL Transformations
------------------------------------

SQL transformations have been a strategic feature set to recent jOOQ releases,
offering additional compatibility between SQL dialects to commercial customers,
such as, for example:

- Transforming Oracle's ROWNUM into equivalent window functions or
  LIMIT clauses.
- Turning table lists including Oracle's (+) operator into ANSI
  JOIN syntax.

This release ships with a new commercial only feature that directly transforms
the new Query Object Model (QOM)'s expression tree prior to rendering. It does
so by applying pattern matching to the expression tree. Some assorted examples
include:

- LTRIM(RTRIM(x)) into TRIM(x)
- x != a AND x != b into x NOT IN (a, b)
- x IN (a, b, c) AND x IN (b, c, d) into x IN (b, c)
- NOT (NOT (x = 1)) into x = 1
- NOT (x = 1) into x != 1

And much more. The primary use-cases for this functionality are:

- SQL linting, e.g. as part of an ExecuteListener
- SQL auto cleanup, including in a ParsingConnection
- Dialect migration, when upgrading database versions, or moving between
  dialects
- Patching specific SQL features

For more information about the feature, see:

- https://www.jooq.org/doc/3.17/manual/sql-building/queryparts/sql-transformation/transform-patterns/

Note that this feature is also available for free online:

- https://www.jooq.org/translate


Reactive and kotlin coroutine support
-------------------------------------

A lot of minor improvements have been implemented. A few more significant ones
include:

- R2DBC 0.9.1.RELEASE is now supported
- A new reactive transaction API has been added, which offers the same nested
  transaction semantics as the existing blocking transaction API, see also:
  https://blog.jooq.org/nested-transactions-in-jooq/
- jOOQ's reactive streams bindings via the Publisher SPI are now
  bridged automatically to kotlin coroutines in the new
  org.jooq:jooq-kotlin-coroutines module using the usual utilites
  org.jetbrains.kotlinx:kotlinx-coroutines-core and
  org.jetbrains.kotlinx:kotlinx-coroutines-reactor
- The org.jooq:jooq-kotlin extensions module now has additional
  extension functions for more MULTISET and other nesting related
  convenience.
- The entire blocking execution API is now annotated with
  org.jetbrains.annotations.Blocking to help reactive jOOQ users
  avoid accidentally blocking on a query, when using IntelliJ. In addition, we
  now annotate experimental and internal API with the ApiStatus
  annotation from the same package.


API Diff:
---------

See what's changed in terms of an API diff here:
https://www.jooq.org/api-diff/3.16-3.17


For a complete list other, minor improvements, see the below change notes.


Features and Improvements
-------------------------
#1592 - Add formal support for "audit" fields, such as CREATED_AT, CREATED_BY, MODIFIED_AT, MODIFIED_BY
#2092 - Add support for the Postgres INET data type (java.net.InetAddress)
#2333 - Add DSL.noField() for "conditional" LIMIT, OFFSET, GROUP BY, ORDER BY support when creating dynamic SQL
#2968 - Add support for PostgreSQL RANGE types
#3497 - Add methods to Context to distinguish between derived tables and other types of subqueries
#4727 - Let Table<R> extend SelectField<R>
#5214 - Add support for PostgreSQL's EXCLUDED table
#5641 - Support overriding code generation <target/> configuration via system properties
#5695 - Allow for expressions to be put in LIMIT / OFFSET
#5934 - Add support for the Postgres CITEXT type
#5970 - Add Setting to auto-inline all bind variables that participate in predicates on certain fields
#6454 - Support converting from java.sql.Array to Object[] types
#6489 - Code generator should support SQL-generated "dynamic regular expressions"
#7284 - Replace common patterns in query object model
#7508 - Add support for path expressions ("implicit joins") in DML
#7803 - Let ArrayRecord extend Formattable
#7912 - Add InsertOnDuplicateSetStep::setAllToExcluded to auto-set all insert column list columns to their EXCLUDED value
#8653 - Add support for parsing VALUES <row value special case>, ...
#8997 - Remove jOOQ-spring-example and documentation
#9335 - Add a jooq-kotlin-coroutines module to support transactional coroutines based on reactive streams Publishers
#9347 - DataType#getCastTypeName() does not respect rendering settings
#9425 - Add Meta.migrateTo(Meta):Queries to generate a migration script between two Meta versions
#9768 - Support MySQL inline INDEX specifications in DDLDatabase
#9817 - Add support for text blocks in generated code
#9879 - Add support for VIRTUAL and STORED client side computed columns
#10120 - Add some more aliasing examples to the manual
#10132 - Cast NULL literal to known type in Derby
#10407 - Add support for FIREBIRD 4 RETURNING * syntax
#10521 - Push down derived column list aliases to derived table's SELECT clause instead of using UNION ALL emulation, if possible
#10523 - Emulate UPDATE .. SET row = (SELECT ...) for dialects with no native support
#10537 - Split manual section about forcedTypes into different subsections
#10677 - Add <onUnused/> to code generation configuration to specify behaviour when encountering unused objects
#10756 - Generate @Transactional on DAOImpl and generated DAOs query-methods
#10763 - Official jOOQ-postgres-extensions bindings should register themselves as low priority bindings if found on the code generation classpath
#10832 - Review our Nullable and NotNull annotation usage
#11232 - Parser should parse all Names.* values at least once
#11331 - Support SQLDataType.XML in DDL
#11467 - LoggerListener should log batch sizes for BatchSingle and BatchMultiple
#11575 - Replace internal dialect switches by Set<SQLDialect>
#11717 - Known limitations of the R2DBC integration
#11731 - Emulate Oracle INSERT .. SELECT.. RETURNING
#11770 - UpdatableRecord::merge should use new EXCLUDED semantics to avoid repeating bind values
#11823 - Investigate whether read-only converters really require the Class<U> reference
#11969 - Let Condition extend Field<Boolean>
#12481 - ParsingConnection's PreparedStatement.getMetaData should be able to produce ResultSetMetaData prior to execution
#12515 - Support for RowN.mapping(Function<? super Object[], ? extends U>)
#12533 - Use org.jetbrains.annotations.ApiStatus
#12608 - Support referencing the same embeddable type multiple times per table
#12688 - Add support for H2's BIT_NAND_AGG, BIT_NOR_AGG, BIT_XNOR_AGG aggregate functions
#12721 - Add more startup tips to be logged with the jOOQ logo
#12734 - Address known limitations of MULTISET support
#12779 - Add support for MySQL COMMENT syntax in DDLDatabase's CREATE TABLE statements
#12782 - Add DiagnosticsContext.message(): String to give access to a text message
#12785 - Add DiagnosticsListener::exception to handle exceptions encountered while running diagnostics
#12807 - Parse and ignore Teradata's COMPRESS DDL clauses
#12829 - Support parsing H2's undocumented DROP TABLE .. CASCADE CONSTRAINTS syntax
#12830 - Support DROP TABLE .. CASCADE in Oracle
#12832 - Improve parser error message when encountering unterminated quoted identifier
#12834 - Support parsing empty column lists in INSERT statements
#12836 - Parser should support VALUES constructor in FROM clause without parentheses
#12838 - Support parsing DATABASE() as synonym for CURRENT_CATALOG() or CURRENT_DATABASE()
#12840 - Parser improvements thanks to the sqlancer team related test cases
#12843 - Support parsing LOG(n) without explicit base, based on input dialect
#12846 - Support parsing alternative H2 and HSQLDB DROP CONSTRAINT c IF EXISTS clause
#12848 - Support parsing HSQLDB's inline FOREIGN KEY syntax
#12862 - Upgrade all relevant R2DBC dependencies to 0.9.0.RELEASE
#12874 - Upgrade org.jetbrains:annotations dependency to 23.0.0
#12875 - Annotate all blocking execution methods with org.jetbrains.annotations.Blocking
#12877 - Improve blocking call error message when trying to run Query.execute(), etc. with R2DBC
#12883 - Add DSL.nullCondition(), a condition that correctly represents the NULL / UNKNOWN predicate value
#12893 - Add an Replacers.listening(Replacer, BiConsumer<QueryPart, QueryPart>) to allow for listening to QueryPart.$replace() events
#12894 - Add accessors for Select::$limit, ::$limitPercent, $limitWithTies, ::$offset
#12896 - Add Settings.renderOptionalAssociativityParentheses
#12905 - Emulate expressions in LIMIT .. OFFSET where not natively supported
#12906 - Add a QOM.UCommutativeOperator utility with methods like $swap()
#12911 - QOM type accessors should accept Collection when they return UnmodifiableList
#12912 - Add missing Select.$groupBy(), $orderBy(),  setter accessors
#12914 - Document QOM API outside of the QOM type, and annotate it as @Experimental
#12920 - Add Traversers.recursing()
#12921 - Replace internal org.jooq.impl.Finder utility by Traverser API usage
#12945 - Add Field<Result<Record[N]>>.mapping(Function[N]<T[N], E>): Field<List<E>> kotlin extension functions
#12959 - Gradle examples should list the usual commercial groupIds
#12973 - Add Traversers.containing(Predicate<? super QueryPart>)
#12989 - Update R2DBC dependency to 0.9.1.RELEASE
#13000 - Add Replacers.decomposing(): Replacer to decompose a compound statement into equivalent individual statements
#13001 - Refine Replacer Javadoc
#13004 - Add a TableElement type, a super type of Field<?> | Constraint | Index
#13014 - Add support for providing a --schema to the ParserCLI
#13031 - Add a rootPath property to the LiquibaseDatabase configuration for the FileSystemResourceAccessor
#13037 - Add documentation for the new FormattingProvider
#13070 - Change Function[N] to be non-experimental
#13072 - Remove experimental status on Row[N].mapping(Function[N])
#13077 - Bump postgresql from 42.3.2 to 42.3.3
#13078 - Add internal Tools.CONFIG as a convenience for Tools.CTX.configuration()
#13093 - Remove a few redundant null checks in jOOQ's internals
#13097 - Add Converters.forArrayComponents(Converter<T[], U[]>): Converter<T, U>
#13104 - Reimplement SQL Server RETURNING emulation using QueryPart.$replace instead of SchemaMapping
#13109 - Add Settings.parseIgnoreCommercialOnlyFeatures
#13118 - Pull up Field::convert, ::convertFrom, ::convertTo methods to SelectField
#13129 - Add Context::predicandSubquery
#13131 - Add sections to the manual about using Table references as GroupField, SelectField
#13132 - DSLContext.fetchValue(SelectField<T>) should work with Table<R>
#13135 - Generate mapping() deconstruction convenience methods on generated Tables if <recordsImplementingRecordN/> is set
#13137 - Change default for <pojosEqualsAndHashCode/> code generation option to true
#13142 - Add JSONFormat.mutable(), XMLFormat.mutable()
#13143 - Add code generation flags to turn off the recognition of jOOQ-specific types
#13157 - Remove Oracle work around for JSON_ARRAYAGG causing ORA-40590: invalid format in Oracle 21c
#13161 - Add support for array bindings for the PostgreSQL HSTORE, INET, and CIDR types
#13162 - SchemaVersionProvider etc should be looked up using context classloader, too
#13183 - Add Javadoc warnings to UpdatableRecord::fetchChildren, and TableRecord::fetchParent about the N+1 problem
#13188 - Add support for the LTREE data type in the jooq-postgres-extensions module
#13192 - Add SQLDialect.MARIADB_10_7
#13194 - Various third party dependency updates
#13195 - Add a SQLDialect.SQLITE_3_38 dialect
#13201 - Add SQL Server JSON_ARRAY support via JSON_MODIFY
#13223 - Emulate inline indexes in CockroachDB
#13224 - Document declaration vs reference rendering mode of Field, Table, WindowDefinition, Parameter, CommonTableExpression
#13244 - Upgrade kotlin dependency to 1.6
#13246 - Add more examples to manual section "codegen-database-version-providers"
#13248 - Amend manual sections about data types (XML, Spatial, JSON)
#13255 - Support casting VARCHAR to XML / XMLTYPE in Oracle
#13260 - Add DAO.deleteById(T) overload
#13264 - Manual anchors should be generated from text, not from XSL generated ID
#13267 - Make QOM::unmodifiable public, internal
#13271 - Add support for SQLite 3.33 UPDATE .. FROM
#13272 - Add support for SQLite 3.35 ALTER TABLE DROP COLUMN
#13275 - Add SQLite 3.35 support for CTE MATERIALIZED hint
#13277 - Add support for SQLite 3.35's built-in math functions
#13278 - Add support for inverse hyperbolic functions ASINH, ACOSH, ATANH, ACOTH
#13281 - Add more explicit links to Record::from and RecordUnmapper wherever this applies
#13284 - Add support for T-SQL FOR XML EXPLICIT clause
#13286 - Emulate SQL/XML XMLELEMENT and XMLATTRIBUTES in SQL Server using FOR XML EXPLICIT
#13287 - Emulate SQL/XML XMLCOMMENT in T-SQL
#13288 - Emluate SQL/XML XMLCONCAT in T-SQL
#13289 - Support XMLQUERY() and XMLEXISTS() also in SQL Server
#13306 - Separate QOM.Ln (natural logarithm) from QOM.Log (logarithm with base)
#13324 - Code generation output shouldn't print table mapping output, if it's the same as the input
#13325 - Refactor internal FieldMapForUpdate to support the row assignments, too
#13326 - Emulate UPDATE .. FROM with MERGE, where available
#13329 - Add a FieldOrRowOrSelect nominal union type
#13334 - Add native support for MySQL's derived column lists starting from SQLDialect.MYSQL8_0_19
#13335 - Add Table::as and TableLike::asTable overloads accepting Collection<? extends X> for derived column lists
#13336 - Generate covariant overrides for Table.rename(Table) and Table.as(Table) methods
#13342 - Refactor Multiset::jsonxArrayaggEmulation
#13391 - Add support for the FOR XML BINARY BASE64 clause
#13393 - Replace internal usage of DatatypeConverter::parseBase64Binary by java.util.Base64
#13399 - jOOQ-checker should system property defaults that apply to the entire checked code
#13400 - Add native Informix MULTISET and nested ROW support
#13410 - Add a "Don't Do This" page to the manual
#13417 - Add native EXASOL ROWNUM support
#13432 - Add <visibilityModifier/> code generation option to <forcedType/>
#13434 - Add <columns/> to <syntheticObjects/> to generate synthetic columns
#13437 - Add Definition.isSynthetic() to indicate that a jOOQ-meta object has been created synthetically
#13446 - Add H2_2_0_202 support for UPDATE .. RETURNING and DELETE .. RETURNING
#13457 - New configuration to generate implicit join definitions ALWAYS from foreign key name
#13458 - PI() emulation should be ACOS(-1) rather than ASIN(1) * 2
#13461 - ResultQueryTrait::getFields should accept Supplier<ResultSetMetaData> instead of ResultSetMetaData
#13467 - KotlinGenerator should generate open properties in generated records
#13471 - Add Scope.creationTime() and make it available through GeneratorContext.renderTime()
#13482 - Upgrade H2 dependency to 2.1.212
#13485 - Add a QOM.UOpaque marker interface for non-traversable QueryPart types
#13486 - Replace internal ConstantSortField by noField()
#13496 - Specify the various Scope subtype's lifecycle in their Javadoc
#13497 - Add BindingScope, a common super type of the various BindingXYZContext types
#13502 - Add a reactive transaction API
#13508 - Add MySQL support for INSERT .. ON DUPLICATE KEY UPDATE .. WHERE
#13516 - KotlinGenerator should generate implicit joins path accessors as properties
#13523 - Add support for parsing ! (bang) as equivalent to . (dot) in MS Access identifiers
#13525 - Improve Documentation for DSLContext.fetchStream() and related methods
#13528 - Document <implicitJoinPathsToOne/> flag
#13534 - Avoid rendering PostgreSQL native cast operator :: which cannot be used in Hibernate native queries
#13538 - Add a <T, E> Field<Result<R>>.collecting(Collector<R, ?, E>) kotlin extension function, and similar
#13540 - Remove "inline" and "reified" keywords from jOOQ-kotlin extensions where unnecessary
#13544 - Remove EXPERIMENTAL remark from ad-hoc converter and MULTISET construction API
#13546 - Stop aligning generated POJO members and constructor arguments in columns
#13552 - Change DSL.multiset(Select<R>) into DSL.multiset(TableLike<R>)
#13553 - Add TableLike<R>.asMultiset(): Field<Result<R>>
#13556 - Consistently use org.jooq Maven groupId across the manual
#13558 - Add a PrefixSuffixGeneratorStrategy to jOOQ-codegen
#13571 - Emulate the PostgreSQL ON CONFLICT .. EXCLUDED pseudo table in MERGE emulation
#13572 - Add SQLDialect.MYSQL_8_0_20
#13573 - Add parser support for the PostgreSQL EXCLUDED pseudo table and MySQL VALUES() syntax
#13578 - Add native support for BITXNOR in H2
#13579 - Add documentation to the manual for bitwise aggregate functions
#13582 - DefaultRecordMapper should check whether user is attempting to map into an inner class
#13591 - Add a new ColumnElement type
#13594 - Change the Java 17 distribution to --release 17
#13599 - Let Context extends ExecuteScope
#13605 - Add JSONtoJacksonConverter, JSONBtoJacksonConverter, XMLtoJAXBConverter implementations
#13607 - Add JSONtoJacksonConverter, JSONBtoJacksonConverter, XMLtoJAXBConverter forcedType configuration convenience
#13616 - Scala extensions should have some multiset convenience
#13618 - Document EnumType::lookupLiteral's nullable result
#13631 - Add Context.topLevel() and Context.topLevelForLanguageContext() to give access to the top level QueryPart type that is being rendered
#13632 - DDLDatabase should have a sql property, as an alternative to scripts
#13634 - Add Field<Record[N]>.mapping(Function[N]<T[N], E>): Field<E> kotlin extension functions, and the Scala equivalent
#13642 - Add a section about security to the manual's reference section
#13650 - Settings.emulateMultiset should have NestedCollectionEmulation.JSON as default in PostgreSQL
#13657 - Ability to download OSS edition snapshot
#13666 - Support Oracle JSON data type in DDL
#13670 - Add support for Oracle SYS.XMLTYPE in plain SQL templates
#13679 - Upgrade HSQLDB to 2.6.1
#13693 - JPA code examples should produce a jakarta.persistence.* import


Breaking changes
----------------
#12430 - Make Java 17 the baseline for the jOOQ Open Source Edition
#12772 - Continue work on public query object model API
#12781 - Remove pre 3.7 deprecated API and pre 3.7 documentation
#12895 - Rename QOM.UOperator[N]::constructor to ::$constructor
#12904 - Remove redundant limit(int) and offset(int) overloads
#12910 - Add DSL.emptyGroupingSet(): GroupField for explicit empty grouping sets
#13028 - Generated DAOs should use an embeddable's referencingName, not name for the fetchByXYZ() and fetchRangeOfXYZ() methods
#13053 - java.lang.NoClassDefFoundError: org/postgresql/util/PGInterval when rendering SQL without the pgjdbc dependency
#13068 - Change selectFrom(Table<R>) methods to selectFrom(TableLike<R>)
#13080 - Standard SQL MULTISET emulation using XML produces a null Result
#13082 - SQL Server MULTISET as JSON emulation of empty subquery produces NULL instead of empty Result
#13094 - Throw an exception when calling ConvertedDataType.getArrayDataType() when the type has a custom Binding
#13114 - SelectField.as() should return SelectField<T>, not Field<T>
#13115 - Change Table::getType to Table::getTableType
#13116 - Rename QOM.RowField to QOM.RowAsField
#13149 - Let Query.keepStatement() return CloseableQuery and ResultQuery.keepStatement() return CloseableResultQuery
#13181 - MULTISET emulation using SQL/XML doesn't correctly distinguish between NULL and ''
#13208 - SQL Server JSON_OBJECT should implement NULL ON NULL semantics by default
#13307 - Change $number() arguments in experimental QOM function types to $value()
#13426 - DSLContext::fetchFromJSON and ::fetchFromXML wrongly assume dialect specific data types in header


Deprecations
----------------
#13005 - Deprecate FieldOrConstraint
#13071 - Deprecate the org.jooq.Internal annotation
#13542 - Replace SPI default implementation class (e.g. DefaultExecuteListener) by default methods in interface


Bug Fixes
---------
#1049 - Better GREATEST() and LEAST() emulations for SQL Server using MAX() or MIN() with VALUES() correlated derived table
#5612 - Inline enum values should be cast to their enum type just like inline bind variables
#6133 - Cannot combine CREATE TEMPORARY TABLE .. AS .. with ON COMMIT ..
#7362 - Excess parentheses generated in NOT operator
#7783 - Nested row value expressions produce String column types when concrete type information should be available
#8614 - Passing arrays of generated tableRecords to a stored procedure generates SQL that won't parse due to cast ::any[]
#8681 - Wrong SQL generated for connectByRoot(minus(one()))
#9981 - Some BooleanDataKey values should be reset when entering a new scope
#10277 - CAST to PostgreSQL enum type lacks type qualification
#10304 - Unnecessary parentheses generated in ConditionAsField
#11114 - CAST should generate qualified type when casting to Table::getDataType or UDT::getDataType
#11424 - Improve the alignment of GenerationTool INFO log
#11441 - Inlining PostgreSQL CHAR(len)[] types produces VARCHAR[] instead
#11509 - batchStore(), batchInsert(), etc. with StatementType.STATIC_STATEMENT throws java.sql.BatchUpdateException
#11552 - UpdatableRecord::merge doesn't work in the presence of a unique constraint and in the absence of a primary key value
#11637 - FilePattern cannot load classpath resource from within jar file
#11722 - Code generator cannot handle tables from other schemas than PUBLIC referencing H2 enum domain types
#12036 - Timestamp Arithmetic fails with ConvertedDataType
#12134 - Support deserialising binary data in MULTISET emulations
#12269 - Records detached when converting nested multiset
#12287 - Replace calls to System.currentTimeMillis() by Clock usage
#12428 - DDL export no longer exports INDEX WHERE clause
#12525 - Nesting of converters causes unexpected Exception
#12783 - Feature Comparison on website is different from docs
#12788 - Support SQLite columns having no data type declaration
#12794 - Parser and code generator does not recognise H2 2.0's BINARY VARYING and other standard SQL data type synonyms
#12795 - Upgrade H2 dependency to 2.0.206
#12801 - GroupConcat renders string_agg separator argument within wrong parentheses
#12804 - Add parser support for Teradata's { UPDATE | DELETE } .. ALL syntax
#12811 - DAOImpl.findOptionalById shouldn't be final
#12818 - GROUP_CONCAT doesn't work as window function
#12820 - Parser doesn't support Derby's FOR BIT DATA data type modifier
#12824 - Parser cannot handle 1. decimal syntax in SELECT
#12825 - Parser shouldn't parse Teradata cast syntax based on Settings.parseAppendMissingTableReferences, but only based on the parseDialect()
#12852 - Parser can't handle TRIM (FROM <value>) syntax
#12854 - jOOQ Open Source Edition code generation doesn't work PostgreSQL 11 or less because of ERROR: column pg_attribute.attgenerated does not exist
#12855 - Bump spring-core from 5.3.13 to 5.3.14
#12858 - Computed column related support annotations claim SQLDialect.POSTGRES instead of SQLDialect.POSTGRES_12
#12864 - OSS Edition H2 INSERT .. RETURNING no longer works if columns are qualified with a schema
#12868 - The DATA_RENDERING_DATA_CHANGE_DELTA_TABLE qualification omission doesn't work correctly in the presence of scalar subqueries
#12884 - Upgrade jOOQ-checker's error_prone_core's transitive protobuf dependency to mitigate CVE-2021-22569
#12888 - Parser should treat AS optional in CREATE TABLE AS SELECT
#12890 - Parser fails to parse SET SCHEMA 'string-literal'
#12908 - Select::$replace loses GROUP BY clause
#12916 - Select.$where(), $having, $qualify(), $connectBy(), $connectByStartWith() don't actually return null in the absence of a predicate
#12917 - Wrong SQL generated when InlineDerivedTable is transformed using $replace()
#12922 - Bump h2 from 2.0.206 to 2.1.210
#12923 - Upgrade H2 to 2.1.210
#12925 - Work around H2 issue 3398 which hangs the process when using FINAL TABLE (MERGE ...)
#12929 - NullPointerException when mapping NULL nested ROW from scalar subquery
#12930 - Nested ROW projection emulation doesn't work in scalar subqueries
#12931 - DAOImpl#deleteById(Collection<T>) ignores Converter
#12938 - Outdated implementation examples in manual's MULTISET section
#12939 - maven-deploy.sh should have same description in --repository flag as maven-deploy.bat
#12944 - Consider improving invalid JDBC URL error messages in class generation
#12951 - GenerationTool should handle JDBC driver returning null Connection on Driver::connect
#12954 - Typo in manual section "codegen-ddl"
#12955 - Wrong code generated for identity columns in H2 1.4
#12956 - Can no longer store/retrieve blob data exceeding 1M in H2 2.0
#12966 - NullPointerException in MetaDataFieldProvider when reading plain SQL column without a name in MySQL
#12970 - jOOQ Open Source Edition does not generate routine with long name
#12976 - Bump postgresql from 42.3.0 to 42.3.2
#12977 - Jooq holds onto connections when using r2dbc
#12979 - Upgrade the pgjdbc dependency to 42.3.2 due to CVE-2022-21724
#12982 - Bump postgresql from 42.2.8 to 42.2.25 in /jOOQ-examples/jOOQ-spark-chart-example
#12983 - Outdated JAXB dependency in manual tutorial
#12991 - Typo in manual section "codegen-tables"
#12992 - Code generation <indexes/> flag should turn on <tables/> as a dependency
#12993 - [jOOQ/jOOQ#12992] Automatically enable table generation if indexes are enabled
#12994 - Typo in manual section "fetching"
#13008 - Compilation error in KotlinGenerator output when implicit join path cache conflicts with keyword
#13010 - [#13008] Unquote keyword when mapping one to many relation
#13013 - Interpreter does not correctly interpret CREATE INDEX .. WHERE
#13023 - Record.formatJSON(Writer) and Record.formatXML(Writer) should flush the writer
#13029 - SQLDataType.XYZ.getArrayDataType().getTypeName() and getCastTypeName() should produce standard SQL XYZ ARRAY type
#13033 - DSL.function not replacing schema for function call in generated SQL
#13034 - SchemaMapping should apply Settings.defaultCatalog even if Settings.defaultSchema doesn't apply
#13035 - SchemaMapping should cache result of Settings.defaultCatalog or Settings.defaultSchema application
#13040 - AbstractRecord.from(String[], TableField[]) no longer works as expected
#13043 - Avoid generating H2 NUMBER type alias for NUMERIC types
#13048 - Settings.parseRetainCommentsBetweenQueries doesn't work for the last comment
#13054 - java.lang.IllegalArgumentException: Cannot create a VALUES() constructor with an empty set of rows when using JSON_ARRAY(ABSENT ON NULL) in PostgreSQL
#13058 - NullPointerException when using CAST(x AS user-defined-type) with SQLDialect.JAVA
#13060 - Typo in Records.intoArray(Class) Javadoc
#13073 - Order of calling DataType.asConvertedDataType(Converter) and DataType.getArrayDataType() should not matter
#13076 - Bump postgresql from 42.2.25 to 42.3.3 in /jOOQ-examples/jOOQ-spark-chart-example
#13081 - Cannot use H2 enum values in JSON documents
#13085 - Field.sortAsc() should not hard wire NULLS FIRST behaviour
#13089 - MySQL's BIT(1) type doesn't map correctly in MULTISET subqueries
#13107 - Register array types of built-in types in internal static type registry
#13113 - Manual dialects translations for nested records emulations is wrong
#13117 - Bad deserialisation of UDT TIMESTAMP value in the presence of a Converter in PostgreSQL
#13119 - Nested record projection should generate ROW constructor keyword for rows of degree 1 in PostgreSQL's RETURNING clauses
#13120 - Cannot use RETURNING with 2-level nested ROW expressions in SQL Server
#13124 - Sequence.nextvals() doesn't work with DSLContext.selectFrom()
#13138 - Bad JSONFormat rendering of nested records
#13144 - ClobBinding shouldn't call Clob.length() in Firebird
#13147 - Context::scopeMapping should return @NotNull QueryPart
#13148 - Prevent Context::scopeMapping to apply when wrapperFor(X) is equal to X
#13156 - Work around Oracle / ojdbc bug where JSON_ARRAY() can't combine bind parameter marker with FORMAT JSON
#13163 - Compilation error when PostgreSQL stored function has an ANY[] data type reference
#13169 - Incorrect parsing of (NULL) row literal in PostgreSQL for nested records, UDTs, etc.
#13170 - NPE in INSERT .. ON DUPLICATE KEY emulation when defaulted PRIMARY KEY value isn't supplied in Oracle
#13174 - ERROR: could not determine data type of parameter when projecting PostgreSQL UDT bind value
#13184 - UNNEST table expression does not maintain derived column list
#13189 - Feedback about manual section "codegen-ddl"
#13196 - Db2 RowAsField emulation using JSON_OBJECT is lacking RETURNING BLOB when using the JSONB emulation
#13200 - MULTISET nested record as JSON_OBJECT() emulation (Db2, SQL Server) doesn't work for records with more than 10 fields
#13202 - SQL Server CREATE TABLE statement should generate VARBINARY(MAX) for BLOB
#13204 - Boolean values aren't serialised correctly in SQL Server JSON documents
#13211 - KotlinGenerator cannot read existing catalog/schema version
#13212 - [#13211] Use square brackets for KotlinGenerator
#13216 - Change Sakila database such that all ID types are INTEGER
#13217 - Work around xerial SQLite driver's Clob behaviour when data is null
#13220 - SQLite's JSON operators don't retain boolean three-valued logic
#13226 - Wrong escaping of string literals in doubly nested EXECUTE IMMEDIATE blocks for DDL emulations
#13230 - UNNEST with array argument doesn't work in Oracle when used with derived column list
#13237 - ORA-03001: unimplemented feature when nested row emulation produces double quotes in Oracle identifiers
#13240 - Code generation fails with H2 2.1.210 when using MySQL execution mode
#13245 - Bump liquibase-core from 4.4.3 to 4.8.0
#13251 - Error when nesting ROW() expressions with values instead of with fields, with degree > 22
#13252 - Cannot insert data into PostgreSQL XML column due to missing cast
#13273 - INSERT .. ON DUPLICATE KEY { IGNORE | UPDATE } emulation should consider all UNIQUE keys on SQLite
#13276 - Wrong code generated for SQLite table with unnamed primary key and unique constraints
#13290 - NullPointerException in Result.formatJSON(), formatXML(), formatCSV(), formatHTML() when a Record is null
#13302 - H2TableDefinition with H2 2.0+ produces wrong code generation output when the run mode is Oracle
#13311 - QOM API mutators on Select type don't copy OFFSET .. LIMIT and a few other clauses
#13315 - Compilation error in generated UDTRecord's POJO constructor if the UDT contains arrays of table records
#13319 - Generated records shouldn't have a @ConstructorProperties annotation on their POJO constructor
#13340 - Wrong precision documented in forceIntegerTypesOnZeroScaleDecimals manual section
#13341 - jOOQ internals shouldn't create unnamed derived tables
#13348 - Internal deprecation note on FieldsTrait::field leaks into generated code
#13349 - Select.asTable() should delay slow call to Tools::autoAlias
#13355 - Invalid code generated when pojosEqualsAndHashCode option is enabled and column name is 'other'
#13364 - Result::formatXML does not escape type names
#13379 - Generated SQL Server code uses `sp_executeSQL`, which fails for binary (case sensitive) collations
#13383 - Invalid SQL generated in Oracle 11g when query has LIMIT clause and scalar subqueries without explicit aliases
#13392 - Generated column name for binary bind values shouldn't use Java's byte[].toString()
#13395 - Bump spring-core from 5.3.16 to 5.3.18
#13396 - Update spring-core dependency to 5.3.18 to mitigate CVE-2022-22965
#13403 - MULTISET and ROW generated nested records should not have their changed flags set to true
#13415 - GroupConcat renders string_agg separator argument within wrong parentheses in EXASOL
#13422 - Dead links in manual for nested class Javadocs
#13424 - Duplicate headers in manual where there exist redirects
#13429 - DSL.noCondition() isn't applied correctly to aggregate FILTER WHERE clause
#13439 - No warning is logged when readonly columns or rowids are not used
#13447 - Upgrade to org.postgresql:postgresql:42.3.3 to mitigate CVE-2022-26520
#13454 - ARRAY_AGG cannot aggregate array columns in H2
#13465 - Expressions based on computed columns must not retain computation reference
#13468 - Work around SQLite INSERT .. SELECT .. ON CONFLICT bug
#13473 - SQLException when calling oracle.jdbc.driver.ArrayDataResultSet.getMetaData()
#13479 - Bump spring-core from 5.3.18 to 5.3.19
#13488 - org.jooq.SQL and manual should document plain SQL templating's capability of recognising :named parameters
#13489 - ArrayIndexOutOfBoundsException when rendering PostgreSQL plain SQL template containing ?@
#13499 - Improve implementation of QualifiedName.hashCode()
#13503 - Parser meta lookups don't work for INSERT .. SELECT .. RETURNING
#13509 - MariaDB, MySQL, Oracle, SQL Server may ignore MULTISET subquery ORDER BY clause
#13513 - LoaderLoadStep.execute() shouldn't have @CheckReturnValue annotation
#13536 - Wrong documentation for <printMarginForBlockComment/>
#13543 - NullPointerException when rendering CTE without a top level context
#13545 - DSL.quotedName(String[]) should produce QualifiedName only if argument array length != 1
#13555 - Field::likeIgnoreCase should cast lhs operand just like Field::like and Field::similarTo
#13557 - MySQL / MariaDB generated columns with enum type are not generated as readonly
#13560 - Invalid SQL generated for Oracle when selecting multiple unaliased rows
#13563 - INSERT .. RETURNING emulations shouldn't acquire multiple connections from ConnectionProvider when using ThreadLocalTransactionProvider
#13574 - UpdatableRecord::merge might produce wrong update count if generated keys can't be fetched
#13581 - Excess parentheses generated in unary ~ (QOM.BitNot) or - (QOM.Neg) operators
#13600 - Bump spring-core from 5.3.19 to 5.3.20
#13601 - Derby boolean expressions have to be wrapped in parentheses when passed to COALESCE
#13608 - Distribute jOOQ-postgres-extensions also with the commercial distributions
#13611 - UnsupportedOperationException when selecting single nested row with JSON column
#13624 - Manual documents wrong artifactId for
#13625 - Wrong code generated for Oracle package procedure SYS.DBMS_STATS.GATHER_DATABASE_STATS
#13635 - Test container does not close in example
#13636 - Close testcontainer in example
#13643 - Wrong result column type for requested conversion when reading JSONB_ARRAY and JSONB_OBJECT nested in ROW in DB2
#13647 - DefaultRecordUnmapper should cache AbstractRow and record type
#13660 - PostgreSQL ON CONFLICT .. WHERE .. DO NOTHING generates not valid SQL
#13663 - Remove the "modern IDEs" section from the manual
#13664 - Avoid ambiguous reference when using Table<R> as SelectField<R> for table conflicting with column
#13667 - Link.$schema() is Nullable
#13671 - Oracle doesn't support ORDER BY in UPDATE .. SET correlated subquery
#13673 - Settings.returnAllOnUpdatableRecord doesn't work for UPDATE queries in HSQLDB
#13676 - Improve <inputCatalog/> warning message in code generator
#13681 - Cannot use scalar subquery originating from MULTISET in JSON_OBJECT() VALUE clause in Db2
#13691 - Manual should link JDBC types to Javadoc

Per Lundberg

unread,
Jun 23, 2022, 5:21:44 AM6/23/22
to jOOQ User Group
Hi Lukas,

Thank you for this, greatly appreciated. One thing I wonder about though:

- jOOQ 3.15 and 3.16: The last releases with Java 11 support in the jOOQ Open
  Source Edition and Java 8 support in the commercial editions.

(also present in the release notes on the web, https://www.jooq.org/notes/?version=3.17)

Is this really correct? I interpret this as "jOOQ commercial does not support Java 8" in 3.17, but when I go the download page and enter our commercial credentials, 3.17 for Java 8 is still available. Which I am very happy about for the record, since we are still on Java 8 for at least 3-6 months (my guess, can be longer). 🙂

Would be great to see this clarified.

Best regards,
Per

From: jooq...@googlegroups.com <jooq...@googlegroups.com> on behalf of Lukas Eder <lukas...@gmail.com>
Sent: Wednesday, June 22, 2022 18:14
To: jOOQ User Group <jooq...@googlegroups.com>
Subject: [ ANNOUNCEMENT ] 3.17.0 Release with Computed Columns, Audit Columns, Pattern Matching, Reactive Transactions and Kotlin Coroutine Support and much more
 
--
You received this message because you are subscribed to the Google Groups "jOOQ User Group" group.
To unsubscribe from this group and stop receiving emails from it, send an email to jooq-user+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/jooq-user/fffe78b4-3f4a-4304-ab36-5e56686d43b2n%40googlegroups.com.

Lukas Eder

unread,
Jun 23, 2022, 5:33:42 AM6/23/22
to jOOQ User Group
Thanks Per, that's ill worded, indeed. I'll fix it right away. There are no plans of deprecating Java 8 support in commercial distributions, for now.

Per Lundberg

unread,
Jun 23, 2022, 6:34:46 AM6/23/22
to jOOQ User Group
Hi Lukas,

Sounds good. If (or rather, "when") you decide to deprecate/drop Java 8 support for new commercial jOOQ releases, it would be great if it could be pre-announced a good while in advance, just to avoid unpleasant surprises. Something like "this is the last (major) jOOQ release expected to support Java 8" (whenever that happens) would be awesome.

Best regards,
Per

Sent: Thursday, June 23, 2022 12:33

To: jOOQ User Group <jooq...@googlegroups.com>
Subject: Re: [ ANNOUNCEMENT ] 3.17.0 Release with Computed Columns, Audit Columns, Pattern Matching, Reactive Transactions and Kotlin Coroutine Support and much more
 

Lukas Eder

unread,
Jun 23, 2022, 7:53:13 AM6/23/22
to jOOQ User Group
It was announced a while ago in the issue tracker...?

Anyway. How this worked with Java 6: First off, the Java 6 support was moved from the jOOQ Express Edition and jOOQ Professional Edition to the jOOQ Enterprise Edition. I offered a grace period of an additional 1 year to access the Java 6 distribution from the jOOQ Express Edition and jOOQ Professional Edition for no additional charge to existing customers. New customers needed the jOOQ Enterprise Edition to get latest version access to the Java 6 distribution.

The complete removal from all editions happened only when there were no more paying customers left who were using that version. I cannot guarantee the last bit, but I'm positive that only very very few customers will really be affected by the removal of JDK 8 version support in the far future. I currently don't see any good reason to do that. All new Java language features from Java 9 - Java 19 can be either avoided (e.g. switch expressions), or backported (e.g. text blocks, records, instanceof pattern matching to some extent), or ignored (e.g. sealed types, modularity). This was very different with lambdas. The introduction of lambdas in jOOQ's internals has greatly improved the codebase, so getting rid of Java 6 has been to the benefit of everyone.

I don't see that yet with Java 8, and by the time there will be significant benefit, most people will have moved on, because that long-term Java 8 baseline we as an industry all mysteriously agreed upon will have gone. See e.g. Spring's take on this (Spring Boot 3 will have a Java 17 baseline, this year!):

I hope this helps


Per Lundberg

unread,
Jun 23, 2022, 8:49:37 AM6/23/22
to jOOQ User Group
Hi,

Thanks for that detailed explanation on the process of removing Java 6 support and why it made a lot of sense, appreciated.

Re. the issue tracker - I gave it a look now and couldn't find anything about the (upcoming, far-future) removal of JDK 8 support in jOOQ Express Edition and jOOQ Enterprise Edition. Do you have a link? I could only find things like https://github.com/jOOQ/jOOQ/issues/7789 and https://github.com/jOOQ/jOOQ/issues/12430 - all of which is fine, of course. 🙂

Best regards,
Per
Java 17 has introduced lots of exciting language features which we can start using in jOOQ&#39;s internals and the API, most importantly: Sealed types: https://openjdk.java.net/jeps/409 Records: ht...

The jOOQ 3.12 Open Source Edition will continue to support Java 8. The only things we gain from the JDK 11 dependency is: - Updated logic for reflection when mapping into proxied default methods (that stuff has changed completely in JDK 9).


Sent: Thursday, June 23, 2022 14:52

Lukas Eder

unread,
Jun 23, 2022, 9:08:04 AM6/23/22
to jOOQ User Group
I referred to the Java 17 OSS baseline task, which was on the issue tracker for a while.

There's no task for removing Java 8 support, which means it's not planned yet.

Per Lundberg

unread,
Jun 23, 2022, 9:11:38 AM6/23/22
to jOOQ User Group
Got it. I specifically was referring to the Java 8 support: "If (or rather, "when") you decide to deprecate/drop Java 8 support for new commercial jOOQ releases, it would be great if it could be pre-announced a good while in advance, just to avoid unpleasant surprises."

...which you are making clear will happen well before it gets done. All is well.

Best regards,
Per

Sent: Thursday, June 23, 2022 16:07
Reply all
Reply to author
Forward
0 new messages