diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index d9cfd9d53bfa..2402d43b9f8d 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,3 +1,7 @@ # Initial commits that enabled spotless automatic formatting 59731c089e9d649a663c81d9622b54557d6aba37 4d63ffd98cdead513ab0be0fa23f9787423092d3 +# Envers removal/restore +9c7dd3bf34dfbb2f4fa9eb79a0294c2cc759c836 +b2a528f2945cee26667b22b867ccef143b7c430c +4273f1cde06f3622f50c2846078398c1977a49c4 diff --git a/.github/workflows/ci-report.yml b/.github/workflows/ci-report.yml index 566c6b5e0c77..e0a6e1add3e6 100644 --- a/.github/workflows/ci-report.yml +++ b/.github/workflows/ci-report.yml @@ -21,11 +21,11 @@ jobs: with: persist-credentials: false ref: ${{ github.ref }} - - name: Set up Java 17 + - name: Set up JDK uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 with: distribution: 'temurin' - java-version: '17' + java-version: '21' - name: Generate cache key id: cache-key diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5efd639265dc..1aaf7b380605 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -25,7 +25,7 @@ jobs: build: permissions: contents: read - name: OpenJDK 17 - ${{matrix.rdbms}} + name: OpenJDK 21 - ${{matrix.rdbms}} runs-on: ubuntu-latest strategy: fail-fast: false @@ -55,11 +55,11 @@ jobs: env: RDBMS: ${{ matrix.rdbms }} run: ci/database-start.sh - - name: Set up Java 17 + - name: Set up Java 21 uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 with: distribution: 'temurin' - java-version: '17' + java-version: '21' - name: Generate cache key id: cache-key @@ -146,7 +146,7 @@ jobs: fail-fast: false matrix: include: - - rdbms: oracle_atps_tls + - rdbms: oracle_atps - rdbms: oracle_db19c - rdbms: oracle_db21c - rdbms: oracle_db23c @@ -253,11 +253,11 @@ jobs: persist-credentials: false - name: Reclaim disk space and sanitize user home run: .github/ci-prerequisites-atlas.sh - - name: Set up Java 17 + - name: Set up Java 21 uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 with: distribution: 'temurin' - java-version: '17' + java-version: '21' - name: Generate cache key id: cache-key diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 964aeafe7eeb..c4dcfaa09b23 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -40,7 +40,7 @@ jobs: uses: actions/setup-java@3a4f6e1af504cf6a31855fa899c6aa5355ba6c12 # v4.7.0 with: distribution: 'temurin' - java-version: '17' + java-version: '21' - name: Checkout repository uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 diff --git a/.gitignore b/.gitignore index 8d0d975bf5bc..38f13ef5aa12 100644 --- a/.gitignore +++ b/.gitignore @@ -50,4 +50,4 @@ ObjectStore *.swo # SDKman, used by some module maintainers -.sdkmanrc \ No newline at end of file +.sdkmanrc diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml index 46d3b56a67a2..c8bd7f0a2413 100644 --- a/.idea/codeStyles/Project.xml +++ b/.idea/codeStyles/Project.xml @@ -2,8 +2,8 @@ @@ -37,4 +37,4 @@ - \ No newline at end of file + diff --git a/AUTHORS.txt b/AUTHORS.txt new file mode 100644 index 000000000000..234330ef0bf7 --- /dev/null +++ b/AUTHORS.txt @@ -0,0 +1,295 @@ +# This file lists copyright owners of the project. +# The list is not exhaustive: other copyright owners exist. +# See CONTRIBUTING.md for instructions regarding how to be added to this list. + +# Corporate contributors + +Red Hat, Inc. +Oracle, Corporation. + +# Individual contributors + +A Garcia +Adam Warski +Adar Lieber-Dembo +Adrodoc +ageery +Aleksander Blomskøld +Ales Justin +Alex Kalashnikov +Alex Snaps +Alex Soto +Alexey Loubyansky +Alexey Nesterov +Alvaro Esteban Pedraza +amaeda +Amit Mendapara +amkad +Anders Wallgren +Andrea Boriero +Andreas Asplund +Andreas Knees +Andrei Ivanov +Andrei Solntsev +Andrew Clemons +Andrew Guibert +Andrew Judson +Andrew Lee Rubinger +Andrig Miller +András Eisenberger +Andy2003 +Anilabha Baral +Anthony Patricio +Antoine Reilles +Anton Marsden +Archie L. Cobbs +Arnold Galovics +bananan +Barnaby Court +Barnaby Court +Barney +Barry LaFond +Bas van Schaik +Batbileg Dorj +Bato-Bair +Bawany Satgunanathan +bb7133 +Becca Gaspard +Benedikt Waldvogel +Benjamin Hartmann +benoit +Bogdan Stirbat +Boris Korogvich +boris-unckel +Brad Koehn +Bradley Hess +Brett Meyer +Brian Stansberry +Bryan Varner +Burkhard Graves +Cash Costello +Cedomir Igaly +Chris Bredesen +Chris Cranford +Chris Dennis +Christian Bauer +Christian Beikov +Christoph Dreis +clement +Cody Lerum +Craig K +cristhiank +Csaba Varga +Cédric Tabin +Damien Hollis +Daniel Black +Daniel Gredler +Daniel Mensinger +Daniel Shuy +Dave Stephan +David Avenante +David Ellingsworth +David M. Lloyd +Davide D'Alto +dcebotarenco +dewarder +Dgray16 +Diego Plentz +dkublik +Dmitrii Bocharov +Dmitrii Karmanov +Dmitry Kryukov +Dmytro Bondar +Dominique Toupin +Edward.Wilson +Emmanuel Bernard +Emmanuel Duchastenier +Emond Papegaaij +Eric Dalquist +Erik-Berndt Scheper +Erin Schnabel +Etienne Miret +Ettavolt +Fabio Massimo Ercoli +Fabricio Gregorio +Falko Modler +Farah Juma +Felix +Felix Feisst +Fernando Guardiola +Filipe Roque +Florian Heck +fmusolino +Francesco Nigro +Frank Doherty +Fábio Ueno +Gabriel Belingueres +Gail Badner +Galder Zamarreño +Gary Gregory +Gary LosHuertos +Gavin King +Georg Echterling +George Gastaldi +Georgios Andrianakis +graemerocher +Gregorio Palamà +Guenther Demetz +Guillaume Smet +Gunnar Morling +H.Lo +Hardy Ferentschik +HARPER Jon +Harsh Panchal +Hassan AL Meftah +Hendrik Schreiber +Henri Tremblay +hugothomas +Hynek Svabek +Igor Vaynberg +Ivan Munic +Ivan Straka +Ivaylo Mitrev +Jaikiran Pai +James R. Perkins +Jan Martiska +Jan Schatteman +Jan-Willem Gmelig Meyling +Janario Oliveira +Jarkko Hyöty +Jason Pyeron +Jason T. Greene +jcibik +Jere Penttinen +Jeremy Whiting +Jerome Prinet +Jocki Hendry +John Lin +John O'Hara +John Verhaeg +johnniang +Jonathan Bregler +Joseph B. Ottinger +João Carlos Heringer Moreira +Juraci Krohling +k abram +Kabir Khan +Kai Suchomel +Kamil Szymanski +Karel Maesen +KARGET +Ken Schosinsky +Koen Aers +Kristoffer Lundberg +kubo +Ladislav Thon +Lars Storm +Laurent Almeras +Laurent RICHARD +ldelima +Leandro Taveras +Legohuman +Leonard Siu +Louis Jacomet +Loïc Lefevre +lpradel +Luca Molteni +Luis Barreiro +Lukasz Antoniak +Luke Chen +Madhumita Sadhukhan +magdalena +Manik Surtani +Manuel Bernhardt +Marcel Overdijk +marcgiffing +Marco Belladelli +Marcus +Mark Rotteveel +Marko Bekhta +Markus Heiden +Martijn Blankestijn +Martin Simka +Masafumi Miura +Matej Pucihar +Matt Drees +Matthew Vance +Matthias Kurz +Michael Rudolf +Michal Skowronek +MilovanderZee +Misty Stanley-Jones +Moritz Becker +mrizzi +msvticket +Mustafa Ulu +Nathan Xu +Nguyen Nhu Phuc +Nikolay Shestakov +Norbert Wirges +Oliver Breidenbach +Oliver Saggau +Owen Farrell +Panagiotis Sotiropoulos +Paul Ferraro +Petteri Pitkänen +Philippe Marschall +Pierrick Rouxel +qinxi +Radim Vansa +Rafael Winterhalter +Rafi Shamim +Randy May +Ratul sharker +rgarcia +rhart +Richard Barnes +Richard Wilding +rmartinc +Rob Worsnop +Roland Kurucz +Rune Steinseth +Russ Tennant +Réda Housni Alaoui +Sam De Block +Samuel Andersson +Sande Gilda +Sanne Grinovero +Scott Marlow +Sebastian Nohn +seregamorph +Sergey Chernolyas +Sergey Morgunov +Shawn Clowater +Simeon +Simon StJohn-Green +skis +Staffan Hörke +Stephanie Miller +Steve Ebersole +Strong Liu +Stuart Douglas +Ståle W. Pedersen +Stéphane Épardaud +Sven Strickroth +Sylvain Dusart +The Geeky Asian +The-Huginn +Thomas Heigl +Timo Verhoeven +Tomas Lamr +Torsten Schöne +Vasily Kochnev +Vedran Prišćan +Vincent Bouthinon +Vincent Stradiot +Vlad Kuznetsov +Vlad Mihalcea +Vladimír Kuruc +William Burns +xhuang +Yanming Zhou +yjpark +Yoann Rodière +Zbyněk Roubalík +Zhenlei Huang diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c1ae3ab03064..144d0e3e2213 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,17 +5,24 @@ project really) strong and successful. # Legal -All original contributions to Hibernate are licensed under the -[GNU Lesser General Public License (LGPL)](https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt), -version 2.1 or later, or, if another license is specified as governing the file or directory being -modified, such other license. +All original contributions to Hibernate are licensed under the +[Apache License version 2.0 (Apache-2.0)](https://www.apache.org/licenses/LICENSE-2.0.txt), +or, if another license is specified as governing the file or directory being modified, such other license. +The Apache-2.0 license text is included verbatim in the [`LICENSE.txt`](LICENSE.txt) file -The LGPL text is included verbatim in the [lgpl.txt](lgpl.txt) file in the root directory of the ORM repository. - -All contributions are subject to the [Developer Certificate of Origin (DCO)](https://developercertificate.org/). +Note that Hibernate ORM 7.0.0.Beta4 and earlier are distributed under +[a different license](https://github.com/hibernate/hibernate-orm/blob/6.6/CONTRIBUTING.md#legal). +To allow for potential backporting, the Hibernate team asks contributors to dual-license their contribution. +A Pull Request template already applies the proper wording to make it easy. +All contributions are subject to the [Developer Certificate of Origin (DCO)](https://developercertificate.org/). The DCO text is available verbatim in the [dco.txt](dco.txt) file in the root directory of the ORM repository. +Copyright owners are listed in [AUTHORS.txt](AUTHORS.txt). +Contributors with a valid copyright claim can request to be added to that list +by sending a pull request to the project's GitHub repository, +listing at least one relevant contribution in the pull request description. +Note: one-liner or repetitive patches may not be sufficient to claim copyright. ## Guidelines @@ -105,3 +112,11 @@ It is important that this topic branch of your fork: # Notes (1) Gradle `eclipse` plugin is no longer supported, so the recommended way to import the project in your IDE is with the proper IDE tools/plugins. Don't try to run `./gradlew clean eclipse --refresh-dependencies` from the command line as you'll get an error because `eclipse` no longer exists + +## Continuous integration + +See [MAINTAINERS.md](MAINTAINERS.md#ci) for information about CI. + +## Releasing + +See [MAINTAINERS.md](MAINTAINERS.md#ci) for information about releasing. diff --git a/Jenkinsfile b/Jenkinsfile index 94f09b358130..9fce1f93a078 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,8 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ import groovy.transform.Field @@ -16,7 +14,7 @@ import org.jenkinsci.plugins.workflow.support.steps.build.RunWrapper @Library('hibernate-jenkins-pipeline-helpers') _ import org.hibernate.jenkins.pipeline.helpers.job.JobHelper -@Field final String DEFAULT_JDK_VERSION = '17' +@Field final String DEFAULT_JDK_VERSION = '21' @Field final String DEFAULT_JDK_TOOL = "OpenJDK ${DEFAULT_JDK_VERSION} Latest" @Field final String NODE_PATTERN_BASE = 'Worker&&Containers' @Field List environments @@ -42,19 +40,20 @@ stage('Configure') { // Don't build with HANA by default, but only do it nightly until we receive a 3rd instance // new BuildEnvironment( dbName: 'hana_cloud', dbLockableResource: 'hana-cloud', dbLockResourceAsHost: true ), new BuildEnvironment( node: 's390x' ), - new BuildEnvironment( dbName: 'tidb', node: 'tidb', - notificationRecipients: 'tidb_hibernate@pingcap.com' ), + // We generally build with JDK 21, but our baseline is Java 17, so we test with JDK 17, to be sure everything works. + // Here we even compile the main code with JDK 17, to be sure no JDK 18+ classes are depended on. + new BuildEnvironment( mainJdkVersion: '17', testJdkVersion: '17' ), // We want to enable preview features when testing newer builds of OpenJDK: // even if we don't use these features, just enabling them can cause side effects // and it's useful to test that. - new BuildEnvironment( testJdkVersion: '21', testJdkLauncherArgs: '--enable-preview' ), - new BuildEnvironment( testJdkVersion: '23', testJdkLauncherArgs: '--enable-preview' ), - new BuildEnvironment( testJdkVersion: '24', testJdkLauncherArgs: '--enable-preview' ), + new BuildEnvironment( testJdkVersion: '23', testJdkLauncherArgs: '--enable-preview', additionalOptions: '-PskipJacoco=true' ), + new BuildEnvironment( testJdkVersion: '24', testJdkLauncherArgs: '--enable-preview', additionalOptions: '-PskipJacoco=true' ), + new BuildEnvironment( testJdkVersion: '25', testJdkLauncherArgs: '--enable-preview', additionalOptions: '-PskipJacoco=true' ), // The following JDKs aren't supported by Hibernate ORM out-of-the box yet: // they require the use of -Dnet.bytebuddy.experimental=true. // Make sure to remove that argument as soon as possible // -- generally that requires upgrading bytebuddy after the JDK goes GA. - new BuildEnvironment( testJdkVersion: '25', testJdkLauncherArgs: '--enable-preview -Dnet.bytebuddy.experimental=true' ) + new BuildEnvironment( testJdkVersion: '26', testJdkLauncherArgs: '--enable-preview -Dnet.bytebuddy.experimental=true', additionalOptions: '-PskipJacoco=true' ) ]; if ( env.CHANGE_ID ) { @@ -67,6 +66,9 @@ stage('Configure') { if ( pullRequest.labels.contains( 'sybase' ) ) { this.environments.add( new BuildEnvironment( dbName: 'sybase_jconn' ) ) } + if ( pullRequest.labels.contains( 'tidb' ) ) { + this.environments.add( new BuildEnvironment( dbName: 'tidb', node: 'tidb', notificationRecipients: 'tidb_hibernate@pingcap.com' ) ) + } } helper.configure { @@ -101,13 +103,19 @@ stage('Build') { Map executions = [:] Map> state = [:] environments.each { BuildEnvironment buildEnv -> - // Don't build environments for newer JDKs when this is a PR - if ( helper.scmSource.pullRequest && buildEnv.testJdkVersion ) { + // Don't build environments for newer JDKs when this is a PR, unless the PR is labelled with 'jdk' or 'jdk-' + if ( helper.scmSource.pullRequest && + buildEnv.testJdkVersion && buildEnv.testJdkVersion.toInteger() > DEFAULT_JDK_VERSION.toInteger() && + !pullRequest.labels.contains( 'jdk' ) && !pullRequest.labels.contains( "jdk-${buildEnv.testJdkVersion}" ) ) { return } state[buildEnv.tag] = [:] executions.put(buildEnv.tag, { runBuildOnNode(buildEnv.node ?: NODE_PATTERN_BASE) { + def mainJavaHome + if ( buildEnv.mainJdkVersion ) { + mainJavaHome = tool(name: "OpenJDK ${buildEnv.mainJdkVersion} Latest", type: 'jdk') + } def testJavaHome if ( buildEnv.testJdkVersion ) { testJavaHome = tool(name: "OpenJDK ${buildEnv.testJdkVersion} Latest", type: 'jdk') @@ -117,9 +125,17 @@ stage('Build') { // See https://github.com/jenkinsci/pipeline-plugin/blob/master/TUTORIAL.md withEnv(["JAVA_HOME=${javaHome}", "PATH+JAVA=${javaHome}/bin"]) { state[buildEnv.tag]['additionalOptions'] = '-PmavenMirror=nexus-load-balancer-c4cf05fd92f43ef8.elb.us-east-1.amazonaws.com' - if ( testJavaHome ) { + if ( buildEnv.mainJdkVersion ) { + state[buildEnv.tag]['additionalOptions'] = state[buildEnv.tag]['additionalOptions'] + + " -Pmain.jdk.version=${buildEnv.mainJdkVersion}" + } + if ( buildEnv.testJdkVersion ) { + state[buildEnv.tag]['additionalOptions'] = state[buildEnv.tag]['additionalOptions'] + + " -Ptest.jdk.version=${buildEnv.testJdkVersion}" + } + if ( buildEnv.mainJdkVersion || buildEnv.testJdkVersion ) { state[buildEnv.tag]['additionalOptions'] = state[buildEnv.tag]['additionalOptions'] + - " -Ptest.jdk.version=${buildEnv.testJdkVersion} -Porg.gradle.java.installations.paths=${javaHome},${testJavaHome}" + " -Porg.gradle.java.installations.paths=${[javaHome, mainJavaHome, testJavaHome].findAll { it != null }.join(',')}" } if ( buildEnv.testJdkLauncherArgs ) { state[buildEnv.tag]['additionalOptions'] = state[buildEnv.tag]['additionalOptions'] + @@ -205,6 +221,7 @@ stage('Build') { // Job-specific helpers class BuildEnvironment { + String mainJdkVersion String testJdkVersion String testJdkLauncherArgs String dbName = 'h2' @@ -240,7 +257,7 @@ void ciBuild(buildEnv, String args) { // On untrusted nodes, we use the same access key as for PRs: // it has limited access, essentially it can only push build scans. - def develocityCredentialsId = buildEnv.node ? 'ge.hibernate.org-access-key-pr' : 'ge.hibernate.org-access-key' + def develocityCredentialsId = buildEnv.node ? 'develocity.commonhaus.dev-access-key-pr' : 'develocity.commonhaus.dev-access-key' withCredentials([string(credentialsId: develocityCredentialsId, variable: 'DEVELOCITY_ACCESS_KEY')]) { @@ -255,7 +272,7 @@ void ciBuild(buildEnv, String args) { tryFinally({ sh "./ci/build.sh $args" }, { // Finally - withCredentials([string(credentialsId: 'ge.hibernate.org-access-key-pr', + withCredentials([string(credentialsId: 'develocity.commonhaus.dev-access-key-pr', variable: 'DEVELOCITY_ACCESS_KEY')]) { withGradle { // withDevelocity, actually: https://plugins.jenkins.io/gradle/#plugin-content-capturing-build-scans-from-jenkins-pipeline // Don't fail a build if publishing fails diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000000..261eeb9e9f8b --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/MAINTAINERS.md b/MAINTAINERS.md index dd4b34e38e20..aebd87f99601 100644 --- a/MAINTAINERS.md +++ b/MAINTAINERS.md @@ -8,7 +8,7 @@ i.e. anybody with direct push access to the git repository. See [CONTRIBUTING.md](CONTRIBUTING.md). -## Continuous integration +## Continuous integration Continuous integration is split across two platforms: @@ -46,12 +46,20 @@ See [Releasing](#releasing) for more information. ## Releasing +### Where is the information + +If you're looking for information about how releases are implemented technically, see [release/README.adoc](release/README.adoc). + +If you're looking for information about how to release Hibernate ORM, read on. + ### Automated releases -On select maintenance branches (`6.2`, `6.4`, ...), -micro releases (`x.y.1`, `x.y.2`, ...) are performed as soon as you push to that branch. +On select maintenance branches (`6.2`, `6.4`, `7.0`, ...), +micro releases (`x.y.1`, `x.y.2`, ...) are performed on weekends +if, since the last release, commits were pushed with a message starting with `[HHH-` or `HHH-` -- +which is taken as "someone fixed something worthy of a Jira issue". -Make sure to assign fix versions properly before merging pull requests. +Make sure to assign fix versions properly in Jira when merging pull requests. No announcements are expected for such releases: neither through X, blog posts, or email. @@ -71,12 +79,14 @@ In any case, before the release: * Check that the [CI jobs](#continuous-integration) for the branch you want to release are green. * Check Jira [Releases](https://hibernate.atlassian.net/projects/HHH?selectedItem=com.atlassian.jira.jira-projects-plugin%3Arelease-page): * Check that the release you are about to publish exists in Jira. - * Check there are no outstanding issues assigned to that release. + * Remove the fix version for anything rejected, etc. + * Move unresolved issues to another version * Check there are no resolved/closed issues in the corresponding "work-in-progress version" (e.g. `6.6`, `6.6-next`, ... naming convention may vary); if there are, you might want to assign them to your release. +* Pull all upstream changes and perform `./gradlew preVerifyRelease` locally. -**If it is a new major or minor release**, before the release: +**If it's the first `Alpha`/`Beta` of a new major or minor release**, before the release: * Reset the migration guide to include only information relevant to the new major or minor. @@ -93,7 +103,7 @@ Once you trigger the CI job, it automatically pushes artifacts to the and the documentation to [docs.jboss.org](https://docs.jboss.org/hibernate/orm/). * Do *not* mark the Jira Release as "released" or close issues, - the release job does it for you. + the release job triggers Jira automation that does it for you. * Do *not* update the repository (in particular changelog.txt and README.md), the release job does it for you. * Trigger the release on CI: @@ -106,10 +116,27 @@ and the documentation to [docs.jboss.org](https://docs.jboss.org/hibernate/orm/) After the job succeeds: -* Update [hibernate.org](https://github.com/hibernate/hibernate.org) if necessary: - * If it is a new major or minor release, add a `_data/projects/orm/releases/series.yml` file - and a `orm/releases//index.adoc` file. - * Adjust the release file in `_data/projects/orm/releases`: use a meaningful summary and set `announcement_url` to the blog post, if any. +* Release the artifacts on the [OSSRH repository manager](https://oss.sonatype.org/#stagingRepositories). + * Log into Nexus. The credentials can be found on Bitwarden; ask a teammate if you don't have access. + * Click "staging repositories" to the left. + * Examine your staging repository: check that all expected artifacts are there. + * If necessary (that's very rare), test the release in the staging repository. + You can drop the staging repo if there is a problem, + but you'll need to revert the commits pushed during the release. + * If everything is ok, select the staging repository and click the "Release" button. + * For branches with automated releases (e.g. 6.6) the "release repository" will happen automatically. + to enable/disable the automatic release of the staging repository update the [jreleaser.yml](jreleaser.yml) file, + in particular change the `deploy.maven.nexus2.maven-central.releaseRepository` to `true`/`false`. + +* Update [hibernate.org](https://github.com/hibernate/hibernate.org) as necessary: + * If it is a new major or minor release (new "series"): + * Add a `_data/projects/orm/releases//series.yml` file, + a `orm/releases//index.adoc` file, and a `orm/documentation//index.adoc` file. + Generally these files can be copied from previous series. + * If this new series is to support a new JPA release, also be sure to update `orm/releases/index.adoc` + * Adjust the release file in `_data/projects/orm/releases` that was created automatically by the release job: + use a meaningful summary, if relevant, and set `announcement_url` to the blog post, if any. + * None of the above is necessary for maintenance (micro) releases. * Depending on which series you want to have displayed, make sure to adjust the `status`/`displayed` attributes of the `series.yml` file of the old series. * Push to the production branch. @@ -121,8 +148,13 @@ After the job succeeds: #### Announcing the release +If it is an `Alpha`, `Beta`, `CR` or first `Final` (`x.y.0.Final`) release, announce it: + +* Blog about release on [in.relation.to](https://github.com/hibernate/in.relation.to). + Make sure to use the tags "Hibernate ORM" and "Releases" for the blog entry. * Send an email to `hibernate-announce@lists.jboss.org` and CC `hibernate-dev@lists.jboss.org`. * Tweet about the release via the `@Hibernate` account. +* Announce it anywhere else you wish (BlueSky, etc). #### Updating depending projects diff --git a/README.adoc b/README.adoc index 9392eca52045..f37bcf0249bc 100644 --- a/README.adoc +++ b/README.adoc @@ -1,23 +1,23 @@ +== Hibernate ORM + +image:https://img.shields.io/maven-central/v/org.hibernate.orm/hibernate-core.svg?label=Maven%20Central&style=for-the-badge[Maven Central,link=https://central.sonatype.com/search?namespace=org.hibernate.orm&sort=name] +image:https://img.shields.io/jenkins/build?jobUrl=https%3A%2F%2Fci.hibernate.org%2Fjob%2Fhibernate-orm-pipeline%2Fjob%2Fmain%2F&style=for-the-badge[Build Status,link=https://ci.hibernate.org/job/hibernate-orm-pipeline/job/main/] +image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?style=for-the-badge&logo=gradle[Develocity,link=https://develocity.commonhaus.dev/scans?search.rootProjectNames=Hibernate%20ORM] +image:https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/jvm-repo-rebuild/reproducible-central/master/content/org/hibernate/orm/hibernate-core/badge.json&style=for-the-badge[Reproducible Builds,link=https://github.com/jvm-repo-rebuild/reproducible-central/blob/master/content/org/hibernate/orm/hibernate-core/README.md] + Hibernate ORM is a powerful object/relational mapping solution for Java, and makes it easy to develop persistence logic for applications, libraries, and frameworks. Hibernate implements JPA, the standard API for object/relational persistence in Java, but also offers an extensive set of features and APIs which go beyond the specification. See https://hibernate.org/orm/[Hibernate.org] for more information. -image:https://ci.hibernate.org/job/hibernate-orm-pipeline/job/main/badge/icon[Build Status,link=https://ci.hibernate.org/job/hibernate-orm-pipeline/job/main/] -image:https://img.shields.io/badge/Revved%20up%20by-Develocity-06A0CE?logo=Gradle&labelColor=02303A[link=https://ge.hibernate.org/scans] - == Continuous Integration -Hibernate uses both https://jenkins-ci.org[Jenkins] and https://github.com/features/actions[GitHub Actions] -for its CI needs. See - -* https://ci.hibernate.org/view/ORM/[Jenkins Jobs] -* https://github.com/hibernate/hibernate-orm/actions[GitHub Actions Jobs] +See link:MAINTAINERS.md#ci[MAINTAINERS.md] for information about CI. == Building from sources -The build requires at least Java 11 and at most Java 17. +The build requires at least JDK 21, and produces Java 17 bytecode. Hibernate uses https://gradle.org[Gradle] as its build tool. See the _Gradle Primer_ section below if you are new to Gradle. diff --git a/annotation-descriptor-generator/annotation-descriptor-generator.gradle b/annotation-descriptor-generator/annotation-descriptor-generator.gradle deleted file mode 100644 index 33cf9bb3be0e..000000000000 --- a/annotation-descriptor-generator/annotation-descriptor-generator.gradle +++ /dev/null @@ -1,4 +0,0 @@ -plugins { - id "local.java-module" - id "org.hibernate.build.version-injection" -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/AbstractClassWriter.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/AbstractClassWriter.java deleted file mode 100644 index 3224cbdf8f59..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/AbstractClassWriter.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations; - -import java.io.IOException; -import java.io.Writer; -import java.util.Locale; - -/** - * @author Steve Ebersole - */ -public abstract class AbstractClassWriter { - protected final Writer writer; - - protected AbstractClassWriter(Writer writer) { - this.writer = writer; - } - - protected void writeLine() throws IOException { - writer.write( '\n' ); - } - - protected void writeLine(String line, Object... args) throws IOException { - writer.write( String.format( Locale.ROOT, line, args ) ); - writeLine(); - } - - protected void writeLine(int indentation, String line, Object... args) throws IOException { - writer.write( " " .repeat( indentation * 4 ) ); - writeLine( line, args ); - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/ClassFileHelper.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/ClassFileHelper.java deleted file mode 100644 index b9dbddf60ff1..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/ClassFileHelper.java +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations; - -import java.lang.reflect.Method; -import java.util.Locale; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.lang.model.element.TypeElement; - -/** - * @author Steve Ebersole - */ -public class ClassFileHelper { - public static final String GENERATION_PACKAGE = "org.hibernate.boot.models.annotations.spi"; - static final Pattern CAMEL_CASE_SPLITTER = Pattern.compile( "(([A-Z]?[a-z]+)|([A-Z]))" ); - - static String determineConstantName(TypeElement annotationClass) { - final StringBuilder nameBuffer = new StringBuilder(); - final Matcher matcher = CAMEL_CASE_SPLITTER.matcher( annotationClass.getSimpleName().toString() ); - boolean firstPass = true; - while ( matcher.find() ) { - if ( !firstPass ) { - nameBuffer.append( '_' ); - } - else { - firstPass = false; - } - nameBuffer.append( matcher.group(0).toUpperCase( Locale.ROOT ) ); - } - return nameBuffer.toString(); - } - - public static Object defaultValueValue(Method declaredMethod) { - // should not get in here if there is no default - assert declaredMethod.getDefaultValue() != null; - - if ( declaredMethod.getReturnType().isAnnotation() ) { - return String.format( - Locale.ROOT, - "modelContext.getAnnotationDescriptorRegistry().getDescriptor(%s.class).createUsage(modelContext)", - declaredMethod.getReturnType().getName() - ); - } - - if ( String.class.equals( declaredMethod.getReturnType() ) ) { - return "\"" + declaredMethod.getDefaultValue() + "\""; - } - - if ( long.class.equals( declaredMethod.getReturnType() ) ) { - return declaredMethod.getDefaultValue() + "L"; - } - - if ( declaredMethod.getReturnType().isArray() ) { - final Class componentType = declaredMethod.getReturnType().getComponentType(); - return "new " + componentType.getName() + "[0]"; - } - - return declaredMethod.getDefaultValue(); - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/ClassGeneratorProcessor.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/ClassGeneratorProcessor.java deleted file mode 100644 index a9335499b86c..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/ClassGeneratorProcessor.java +++ /dev/null @@ -1,230 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations; - -import java.util.ArrayList; -import java.util.Comparator; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TreeMap; -import javax.annotation.processing.AbstractProcessor; -import javax.annotation.processing.RoundEnvironment; -import javax.annotation.processing.SupportedAnnotationTypes; -import javax.lang.model.element.Element; -import javax.lang.model.element.ElementKind; -import javax.lang.model.element.ExecutableElement; -import javax.lang.model.element.PackageElement; -import javax.lang.model.element.TypeElement; -import javax.lang.model.type.ArrayType; -import javax.lang.model.type.DeclaredType; -import javax.lang.model.type.ExecutableType; -import javax.lang.model.type.TypeMirror; - -import org.hibernate.orm.build.annotations.structure.AnnotationDescriptor; -import org.hibernate.orm.build.annotations.structure.AnnotationType; -import org.hibernate.orm.build.annotations.structure.AttributeDescriptor; -import org.hibernate.orm.build.annotations.structure.BooleanType; -import org.hibernate.orm.build.annotations.structure.EnumType; -import org.hibernate.orm.build.annotations.structure.IntType; -import org.hibernate.orm.build.annotations.structure.LongType; -import org.hibernate.orm.build.annotations.structure.ShortType; -import org.hibernate.orm.build.annotations.structure.Type; - -import static org.hibernate.orm.build.annotations.structure.StringType.STRING_TYPE; - -/** - * @author Steve Ebersole - */ -@SupportedAnnotationTypes( "java.lang.annotation.Retention" ) -public class ClassGeneratorProcessor extends AbstractProcessor { - public static final String JPA_PACKAGE = "jakarta.persistence"; - public static final String HIBERNATE_PACKAGE = "org.hibernate.annotations"; - public static final String HIBERNATE_PACKAGE2 = "org.hibernate.boot.internal"; - public static final String DIALECT_OVERRIDES = "org.hibernate.annotations.DialectOverride"; - - private final Map annotationDescriptorMap = new TreeMap<>( Comparator.comparing( typeElement -> typeElement.getSimpleName().toString() ) ); - - @Override - public boolean process(Set annotations, RoundEnvironment roundEnv) { - if ( roundEnv.processingOver() ) { - finishUp(); - } - else { - processAnnotations( roundEnv ); - } - - return false; - } - - private void processAnnotations(RoundEnvironment roundEnv) { - processAnnotations( - processingEnv.getElementUtils().getPackageElement( JPA_PACKAGE ), - "%sJpaAnnotation", - "org.hibernate.boot.models.JpaAnnotations" - ); - - processAnnotations( - processingEnv.getElementUtils().getPackageElement( HIBERNATE_PACKAGE ), - "%sAnnotation", - "org.hibernate.boot.models.HibernateAnnotations" - ); - - processAnnotations( - processingEnv.getElementUtils().getPackageElement( HIBERNATE_PACKAGE2 ), - "%sXmlAnnotation", - "org.hibernate.boot.models.XmlAnnotations" - ); - - processAnnotations( - processingEnv.getElementUtils().getTypeElement( DIALECT_OVERRIDES ), - "%sAnnotation", - "org.hibernate.boot.models.DialectOverrideAnnotations" - ); - } - - private void processAnnotations(PackageElement packageElement, String concreteNamePattern, String constantsClassName) { - for ( Element enclosedElement : packageElement.getEnclosedElements() ) { - if ( enclosedElement instanceof TypeElement typeElement ) { - if ( typeElement.getKind() == ElementKind.ANNOTATION_TYPE ) { - processAnnotation( typeElement, concreteNamePattern, constantsClassName, annotationDescriptorMap ); - } - } - } - } - - private void processAnnotations(TypeElement typeElement, String concreteNamePattern, String constantsClassName) { - for ( Element enclosedElement : typeElement.getEnclosedElements() ) { - if ( enclosedElement instanceof TypeElement nestedTypeElement ) { - if ( nestedTypeElement.getKind() == ElementKind.ANNOTATION_TYPE ) { - processAnnotation( nestedTypeElement, concreteNamePattern, constantsClassName, annotationDescriptorMap ); - } - } - } - } - - private void processAnnotation( - TypeElement annotationClass, - String concreteNamePattern, - String constantsClassName, - Map descriptorMap) { - if ( descriptorMap.containsKey( annotationClass ) ) { - // we've already processed it - return; - } - - final String concreteClassName = String.format( concreteNamePattern, annotationClass.getSimpleName().toString() ); - final String constantName = ClassFileHelper.determineConstantName( annotationClass ); - final String repeatableContainerConstantName = resolveRepeatableContainer( annotationClass ); - - final AnnotationDescriptor annotationDescriptor = new AnnotationDescriptor( - annotationClass, - concreteClassName, - constantsClassName, - constantName, - repeatableContainerConstantName, - extractAttributes( annotationClass ) - ); - descriptorMap.put( annotationClass, annotationDescriptor ); - - ConcreteClassWriter.writeClass( annotationDescriptor, processingEnv ); - } - - private List extractAttributes(TypeElement annotationType) { - final List allMembers = processingEnv.getElementUtils().getAllMembers( annotationType ); - final List attributeDescriptors = new ArrayList<>( allMembers.size() ); - - for ( Element member : allMembers ) { - if ( member.getKind() != ElementKind.METHOD ) { - // should only ever be methods anyway, but... - continue; - } - - if ( !member.getEnclosingElement().equals( annotationType ) ) { - // we only want members declared on the annotation (as opposed to Object e.g.) - continue; - } - - ExecutableElement memberAsExecutableElement = (ExecutableElement) member; - - attributeDescriptors.add( new AttributeDescriptor( - member.getSimpleName().toString(), - determineType( member ), - memberAsExecutableElement.getDefaultValue() - ) ); - } - - return attributeDescriptors; - } - - private Type determineType(Element member) { - // member should be an ExecutableElement... - - final ExecutableType memberAsExecutableType = (ExecutableType) member.asType(); - - return interpretType( memberAsExecutableType.getReturnType() ); - } - - private Type interpretType(TypeMirror type) { - return switch ( type.getKind() ) { - case BOOLEAN -> BooleanType.BOOLEAN_TYPE; - case SHORT -> ShortType.SHORT_TYPE; - case INT -> IntType.INT_TYPE; - case LONG -> LongType.LONG_TYPE; - case DECLARED -> interpretDeclaredType( type ); - case ARRAY -> interpretArrayType( type ); - default -> throw new IllegalStateException(); - }; - } - - private Type interpretDeclaredType(TypeMirror type) { - final DeclaredType declaredType = (DeclaredType) type; - final Element declaredTypeAsElement = declaredType.asElement(); - - if ( String.class.getName().equals( declaredTypeAsElement.toString() ) ) { - return STRING_TYPE; - } - - if ( declaredTypeAsElement.getKind() == ElementKind.ANNOTATION_TYPE ) { - return new AnnotationType( declaredType ); - } - - if ( declaredTypeAsElement.getKind() == ElementKind.ENUM ) { - return new EnumType( declaredType ); - } - return new org.hibernate.orm.build.annotations.structure.DeclaredType( declaredType ); - } - - private Type interpretArrayType(TypeMirror type) { - final ArrayType arrayType = (ArrayType) type; - final TypeMirror componentType = arrayType.getComponentType(); - return new org.hibernate.orm.build.annotations.structure.ArrayType( interpretType( componentType ) ); - } - - private String resolveRepeatableContainer(TypeElement annotationClass) { - // todo : need to resolve this... - return null; - } - - private void finishUp() { -// jpaAnnotationDescriptorMap.forEach( (typeElement, annotationDescriptor) -> { -// ConcreteClassWriter.writeClass( annotationDescriptor, JPA_CONSTANTS_CLASS, processingEnv ); -// } ); -// ConstantsClassWriter.writeClass( -// JPA_CONSTANTS_CLASS, -// jpaAnnotationDescriptorMap, -// processingEnv -// ); -// -// hibernateAnnotationDescriptorMap.forEach( (typeElement, annotationDescriptor) -> { -// ConcreteClassWriter.writeClass( annotationDescriptor, HIBERNATE_CONSTANTS_CLASS, processingEnv ); -// } ); -// ConstantsClassWriter.writeClass( -// HIBERNATE_CONSTANTS_CLASS, -// hibernateAnnotationDescriptorMap, -// processingEnv -// ); - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/ConcreteClassWriter.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/ConcreteClassWriter.java deleted file mode 100644 index 552a953a78ba..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/ConcreteClassWriter.java +++ /dev/null @@ -1,258 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations; - -import java.io.IOException; -import java.io.Writer; -import javax.annotation.processing.Filer; -import javax.annotation.processing.ProcessingEnvironment; -import javax.tools.JavaFileObject; - -import org.hibernate.orm.build.annotations.structure.AnnotationDescriptor; -import org.hibernate.orm.build.annotations.structure.AttributeDescriptor; - -import static org.hibernate.orm.build.annotations.ClassFileHelper.GENERATION_PACKAGE; - -/** - * Writes the concrete annotation class to file - * - * @author Steve Ebersole - */ -public class ConcreteClassWriter extends AbstractClassWriter { - - public static void writeClass( - AnnotationDescriptor annotationDescriptor, - ProcessingEnvironment processingEnv) { - final String sourceFileName = GENERATION_PACKAGE + "." + annotationDescriptor.concreteTypeName(); - - final Filer filer = processingEnv.getFiler(); - try { - final JavaFileObject sourceFile = filer.createSourceFile( sourceFileName, annotationDescriptor.annotationType() ); - try (Writer writer = sourceFile.openWriter()) { - final ConcreteClassWriter classWriter = new ConcreteClassWriter( annotationDescriptor, writer, processingEnv ); - classWriter.write(); - } - } - catch (IOException e) { - throw new RuntimeException( "Unable to create concrete Annotation class source file : " + sourceFileName, e ); - } - } - - private final AnnotationDescriptor annotationDescriptor; - private final ProcessingEnvironment processingEnv; - - public ConcreteClassWriter( - AnnotationDescriptor annotationDescriptor, - Writer writer, - ProcessingEnvironment processingEnv) { - super( writer ); - this.annotationDescriptor = annotationDescriptor; - this.processingEnv = processingEnv; - } - - private void write() throws IOException { - writeLine( "package %s;", GENERATION_PACKAGE ); - - writer.write( '\n' ); - - writeLine( "import java.lang.annotation.Annotation;" ); - writeLine(); - writeLine( "import org.hibernate.models.spi.SourceModelBuildingContext;" ); - writeLine(); - writeLine( "import org.jboss.jandex.AnnotationInstance;" ); - writeLine(); - writeLine( "import %s;", annotationDescriptor.annotationType().getQualifiedName().toString() ); - writeLine(); - writeLine( "import static org.hibernate.boot.models.internal.OrmAnnotationHelper.extractJdkValue;" ); - writeLine( "import static org.hibernate.boot.models.internal.OrmAnnotationHelper.extractJandexValue;" ); - - writer.write( '\n' ); - - writeLine( "@SuppressWarnings({ \"ClassExplicitlyAnnotation\", \"unused\" })" ); - writeLine( "@jakarta.annotation.Generated(\"org.hibernate.orm.build.annotations.ClassGeneratorProcessor\")" ); - writeLine( "public class %s implements %s {", annotationDescriptor.concreteTypeName(), annotationDescriptor.annotationType().getSimpleName().toString() ); - - writeDescriptorConstant(); - writeFields(); - writeConstructors(); - writeMethods(); - - writeLine( "}" ); - } - - private void writeDescriptorConstant() throws IOException { -// writeLine( -// 1, -// "public static final %s<%s,%> %s = new %s(%s.class, %s.class, %s);", -// "OrmAnnotationDescriptor", -// annotationDescriptor.annotationType().getSimpleName(), -// annotationDescriptor.concreteTypeName(), -// annotationDescriptor.constantName(), -// "OrmAnnotationDescriptor", -// annotationDescriptor.annotationType().getSimpleName(), -// annotationDescriptor.concreteTypeName(), -// annotationDescriptor.repeatableContainerConstantName() -// ); - writeLine( - 1, - "public static final %s<%s,%s> %s = null;", - "OrmAnnotationDescriptor", - annotationDescriptor.annotationType().getSimpleName(), - annotationDescriptor.concreteTypeName(), - annotationDescriptor.constantName() - ); - writeLine(); - } - - private void writeFields() throws IOException { - for ( AttributeDescriptor attribute : annotationDescriptor.attributes() ) { - writeLine( 1, "private %s %s;", attribute.getType().getTypeDeclarationString(), attribute.getName() ); - } - writeLine(); - } - - private void writeConstructors() throws IOException { - writeDefaultInitialization(); - writeJdkInitialization(); - writeJandexInitialization(); - } - - private void writeDefaultInitialization() throws IOException { - writeLine( 1, "/**" ); - writeLine( 1, " * Used in creating dynamic annotation instances (e.g. from XML)" ); - writeLine( 1, " */" ); - writeLine( 1, "public %s(SourceModelBuildingContext modelContext) {", annotationDescriptor.concreteTypeName() ); - - for ( AttributeDescriptor attribute : annotationDescriptor.attributes() ) { - writeDefaultValueInitialization( attribute ); - } - - writeLine( 1, "}" ); - writeLine(); - } - - private void writeDefaultValueInitialization(AttributeDescriptor attribute) throws IOException { - if ( attribute.getDefaultValue() == null || attribute.getDefaultValue().getValue() == null ) { - return; - } - - writeLine( 2, "this.%s = %s;", attribute.getName(),attribute.getType().getInitializerValue( attribute.getDefaultValue() ) ); - } - - private void writeJdkInitialization() throws IOException { - writeLine( 1, "/**" ); - writeLine( 1, " * Used in creating annotation instances from JDK variant" ); - writeLine( 1, " */" ); - writeLine( 1, "public %s(%s annotation, SourceModelBuildingContext modelContext) {", annotationDescriptor.concreteTypeName(), annotationDescriptor.annotationType().getSimpleName().toString() ); - - for ( AttributeDescriptor attributeDescriptor : annotationDescriptor.attributes() ) { - writeJdkValueInitialization( attributeDescriptor ); - } - - writeLine( 1, "}" ); - writeLine(); - } - - private void writeJdkValueInitialization(AttributeDescriptor attribute) throws IOException { - writeLine( - 2, - "this.%s = extractJdkValue( annotation, %s, \"%s\", modelContext );", - attribute.getName(), - annotationDescriptor.getConstantFqn(), - attribute.getName() - ); - } - - private void writeJandexInitialization() throws IOException { - writeLine( 1, "/**" ); - writeLine( 1, " * Used in creating annotation instances from Jandex variant" ); - writeLine( 1, " */" ); - writeLine( 1, "public %s(AnnotationInstance annotation, SourceModelBuildingContext modelContext) {", annotationDescriptor.concreteTypeName() ); - - for ( AttributeDescriptor attributeDescriptor : annotationDescriptor.attributes() ) { - writeJandexValueInitialization( attributeDescriptor ); - } - - writeLine( 1, "}" ); - writeLine(); - } - - private void writeJandexValueInitialization(AttributeDescriptor attributeDescriptor) throws IOException { - final String attrName = attributeDescriptor.getName(); - - writeLine( - 2, - "this.%s = extractJandexValue( annotation, %s, \"%s\", modelContext );", - attrName, - annotationDescriptor.getConstantFqn(), - attrName - ); - } - - private void writeMethods() throws IOException { - writeAnnotationTypeMethod(); - writeGettersAndSetters(); - writeHelperMethods(); - } - - private void writeAnnotationTypeMethod() throws IOException { - writeLine( 1, "@Override" ); - writeLine( 1, "public Class annotationType() {" ); - writeLine( 2, "return %s.class;", annotationDescriptor.annotationType().getSimpleName() ); - writeLine( 1, "}" ); - writeLine(); - } - - private void writeGettersAndSetters() throws IOException { - for ( AttributeDescriptor attribute : annotationDescriptor.attributes() ) { - writeGetterAndSetter( attribute ); - writeLine(); - } - } - - private void writeGetterAndSetter(AttributeDescriptor attribute) throws IOException { - // "getter" - writeLine( - 1, - "@Override public %s %s() { return %s; }", - attribute.getType().getTypeDeclarationString(), - attribute.getName(), - attribute.getName() - ); - - // "setter" - writeLine( - 1, - "public void %s(%s value) { this.%s = value; }", - attribute.getName(), - attribute.getType().getTypeDeclarationString(), - attribute.getName() - ); - - writeLine(); - } - - private void writeHelperMethods() throws IOException { -// writeLine( 1, "public static V extractJdkValue(A jdkAnnotation, AttributeDescriptor attributeDescriptor, SourceModelBuildingContext modelContext) {" ); -// writeLine( 2, "return attributeDescriptor.getTypeDescriptor().createJdkValueExtractor( modelContext ).extractValue( jdkAnnotation, attributeDescriptor, modelContext );" ); -// writeLine( 1, "}" ); -// writeLine(); -// writeLine( 1, "public static V extractJdkValue(A jdkAnnotation, AnnotationDescriptor annotationDescriptor, String attributeName, SourceModelBuildingContext modelContext) {" ); -// writeLine( 2, "final AttributeDescriptor attributeDescriptor = annotationDescriptor.getAttribute( attributeName );" ); -// writeLine( 2, "return extractJdkValue( jdkAnnotation, attributeDescriptor, modelContext );" ); -// writeLine( 1, "}" ); -// writeLine(); -// writeLine( 1, "public static V extractJandexValue(AnnotationInstance jandexAnnotation, AttributeDescriptor attributeDescriptor, SourceModelBuildingContext modelContext) {" ); -// writeLine( 2, "final AnnotationValue value = jandexAnnotation.value( attributeDescriptor.getName() );" ); -// writeLine( 2, "return attributeDescriptor.getTypeDescriptor().createJandexValueConverter( modelContext ).convert( value, modelContext );" ); -// writeLine( 1, "}" ); -// writeLine(); -// writeLine( 1, "public static V extractJandexValue(AnnotationInstance jandexAnnotation, AnnotationDescriptor annotationDescriptor, String attributeName, SourceModelBuildingContext modelContext) {" ); -// writeLine( 2, "final AttributeDescriptor attributeDescriptor = %s.getAttribute( attributeName );" ); -// writeLine( 2, "return extractJandexValue( jandexAnnotation, attributeDescriptor, modelContext );" ); -// writeLine( 1, "}" ); - } - -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/AnnotationDescriptor.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/AnnotationDescriptor.java deleted file mode 100644 index 70ea10f293f7..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/AnnotationDescriptor.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - -import java.util.List; -import javax.lang.model.element.TypeElement; - -/** - * @author Steve Ebersole - */ -public record AnnotationDescriptor( - TypeElement annotationType, - String concreteTypeName, - String constantsClassName, - String constantName, - String repeatableContainerConstantName, - List attributes) { - public String getConstantFqn() { - return constantsClassName() + "." + constantName(); - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/AnnotationType.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/AnnotationType.java deleted file mode 100644 index 7c469014f6ae..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/AnnotationType.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - -import java.util.Locale; -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.type.DeclaredType; - -/** - * @author Steve Ebersole - */ -public class AnnotationType implements Type { - private final javax.lang.model.type.DeclaredType underlyingType; - - public AnnotationType(DeclaredType underlyingType) { - this.underlyingType = underlyingType; - } - - @Override - public String getTypeDeclarationString() { - return underlyingType.toString(); - } - - @Override - public String getInitializerValue(AnnotationValue defaultValue) { - return String.format( - Locale.ROOT, - "modelContext.getAnnotationDescriptorRegistry().getDescriptor(%s.class).createUsage(modelContext)", - underlyingType.toString() - ); - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/ArrayType.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/ArrayType.java deleted file mode 100644 index 0fbd4dc91d56..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/ArrayType.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - -import java.util.Locale; -import javax.lang.model.element.AnnotationValue; - -/** - * @author Steve Ebersole - */ -public class ArrayType implements Type { - private final Type componentType; - - public ArrayType(Type componentType) { - this.componentType = componentType; - } - - @Override - public String getTypeDeclarationString() { - return componentType.getTypeDeclarationString() + "[]"; - } - - @Override - public String getInitializerValue(AnnotationValue defaultValue) { - return String.format( Locale.ROOT, "new %s[0]", componentType.getTypeDeclarationString() ); - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/AttributeDescriptor.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/AttributeDescriptor.java deleted file mode 100644 index c46b971e6d5b..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/AttributeDescriptor.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - -import javax.lang.model.element.AnnotationValue; - -/** - * @author Steve Ebersole - */ -public class AttributeDescriptor { - private final String name; - private final Type type; - private final AnnotationValue defaultValue; - - public AttributeDescriptor(String name, Type type, AnnotationValue defaultValue) { - this.name = name; - this.type = type; - this.defaultValue = defaultValue; - } - - public String getName() { - return name; - } - - public Type getType() { - return type; - } - - public AnnotationValue getDefaultValue() { - return defaultValue; - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/BooleanType.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/BooleanType.java deleted file mode 100644 index dd9977ccd19c..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/BooleanType.java +++ /dev/null @@ -1,17 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - -/** - * @author Steve Ebersole - */ -public class BooleanType implements Type { - public static final BooleanType BOOLEAN_TYPE = new BooleanType(); - - @Override - public String getTypeDeclarationString() { - return "boolean"; - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/DeclaredType.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/DeclaredType.java deleted file mode 100644 index 12a5c3d0bbad..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/DeclaredType.java +++ /dev/null @@ -1,21 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - -/** - * @author Steve Ebersole - */ -public class DeclaredType implements Type { - private final javax.lang.model.type.DeclaredType underlyingType; - - public DeclaredType(javax.lang.model.type.DeclaredType underlyingType) { - this.underlyingType = underlyingType; - } - - @Override - public String getTypeDeclarationString() { - return underlyingType.toString(); - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/EnumType.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/EnumType.java deleted file mode 100644 index aabe606c677d..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/EnumType.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - -import javax.lang.model.element.AnnotationValue; -import javax.lang.model.type.DeclaredType; - -/** - * @author Steve Ebersole - */ -public class EnumType implements Type { - private final DeclaredType underlyingType; - - public EnumType(DeclaredType underlyingType) { - this.underlyingType = underlyingType; - } - - @Override - public String getTypeDeclarationString() { - return underlyingType.toString(); - } - - @Override - public String getInitializerValue(AnnotationValue defaultValue) { - return underlyingType.toString() + "." + defaultValue.toString(); - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/IntType.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/IntType.java deleted file mode 100644 index 2862a0aabd96..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/IntType.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - -import javax.lang.model.element.AnnotationValue; - -/** - * @author Steve Ebersole - */ -public class IntType implements Type { - public static final IntType INT_TYPE = new IntType(); - - @Override - public String getTypeDeclarationString() { - return "int"; - } - - @Override - public String getInitializerValue(AnnotationValue defaultValue) { - return defaultValue.toString(); - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/LongType.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/LongType.java deleted file mode 100644 index 99f42e257e5c..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/LongType.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - -import javax.lang.model.element.AnnotationValue; - -/** - * @author Steve Ebersole - */ -public class LongType implements Type { - public static final LongType LONG_TYPE = new LongType(); - - @Override - public String getTypeDeclarationString() { - return "long"; - } - - @Override - public String getInitializerValue(AnnotationValue defaultValue) { - return Type.super.getInitializerValue( defaultValue ) + "L"; - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/ShortType.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/ShortType.java deleted file mode 100644 index 5b2d730a06d4..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/ShortType.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - - -/** - * @author Steve Ebersole - */ -public class ShortType implements Type { - public static final ShortType SHORT_TYPE = new ShortType(); - - @Override - public String getTypeDeclarationString() { - return "short"; - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/StringType.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/StringType.java deleted file mode 100644 index a7b0b198f2b9..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/StringType.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - - -/** - * Type implementation Strings - * - * @author Steve Ebersole - */ -public class StringType implements Type { - public static final StringType STRING_TYPE = new StringType(); - - public StringType() { - } - - @Override - public String getTypeDeclarationString() { - return "String"; - } -} diff --git a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/Type.java b/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/Type.java deleted file mode 100644 index 8049539b9cd2..000000000000 --- a/annotation-descriptor-generator/src/main/java/org/hibernate/orm/build/annotations/structure/Type.java +++ /dev/null @@ -1,18 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.build.annotations.structure; - -import javax.lang.model.element.AnnotationValue; - -/** - * @author Steve Ebersole - */ -public interface Type { - String getTypeDeclarationString(); - - default String getInitializerValue(AnnotationValue defaultValue) { - return defaultValue.toString(); - } -} diff --git a/annotation-descriptor-generator/src/main/resources/META-INF/services/javax.annotation.processing.Processor b/annotation-descriptor-generator/src/main/resources/META-INF/services/javax.annotation.processing.Processor deleted file mode 100644 index e71374d7d09a..000000000000 --- a/annotation-descriptor-generator/src/main/resources/META-INF/services/javax.annotation.processing.Processor +++ /dev/null @@ -1 +0,0 @@ -org.hibernate.orm.build.annotations.ClassGeneratorProcessor \ No newline at end of file diff --git a/build.gradle b/build.gradle index 2efc7939dcd3..604cc09b4cbc 100644 --- a/build.gradle +++ b/build.gradle @@ -1,8 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ buildscript { @@ -25,7 +23,7 @@ plugins { id 'org.hibernate.orm.database-service' apply false id 'biz.aQute.bnd' version '7.0.0' apply false - id 'com.diffplug.spotless' version '6.25.0' + id "com.diffplug.spotless" version "7.0.2" id 'org.checkerframework' version '0.6.40' id 'org.hibernate.orm.build.jdks' @@ -57,14 +55,6 @@ tasks.register( 'releasePerform' ) { // See `:release:releasePerform` which does a lot of heavy lifting here } - -nexusPublishing { - repositories { - sonatype() - } -} - - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // CI Build Task diff --git a/changelog.txt b/changelog.txt index 96a85ccf06ec..b47823ee7033 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,8 +1,182 @@ -Hibernate 6 Changelog +Hibernate 7 Changelog ======================= Note: Please refer to JIRA to learn more about each issue. +Changes in 7.0.0.Final (May 19, 2025) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/33439 + +** Task + * [HHH-19474] - Release 7.0 + + +Changes in 7.0.0.CR2 (May 14, 2025) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/33340 + +** Bug + * [HHH-19425] - incorrect class literals in Processor-generated code + * [HHH-19389] - use of @Struct on databases without UDTs + * [HHH-19386] - MutationSepectification#getResultType should return null + +** Deprecation + * [HHH-19440] - Deprecate exposing of LockOptions + +** Improvement + * [HHH-19460] - mis-named leads to NPE + * [HHH-19456] - Upgrade to hibernate-models 1.0.0.CR3 + * [HHH-19449] - how does client obtain a BindableType + * [HHH-19448] - API/SPI split for BindableType/BindingContext + * [HHH-19447] - org.hibernate.query.procedure + * [HHH-19445] - methods of ProcedureCall accept BasicTypeReference + * [HHH-19444] - [SQLiteDialect] Fix ViolatedConstraintNameExtractor + * [HHH-19442] - ProcedureCall should not extend NameableQuery + * [HHH-19438] - move OutputableType + * [HHH-19428] - Support @ListIndexBase in mapping.xml + * [HHH-19422] - Introduce @CollectionIdJavaClass + * [HHH-19420] - Support batch-size for collections in mapping.xml + * [HHH-19399] - setting to enable logging of SQLExceptions + * [HHH-19397] - LIMIT clause does not work without ORDER BY clause + * [HHH-19324] - Switch tests using hbm.xml to use mapping.xml + * [HHH-19310] - Simplified declaration of type for basic mappings in XML + * [HHH-19299] - with LIST classification interpreted as BAG + * [HHH-19209] - Verify and fix ID class generation for inner classes + +** New Feature + * [HHH-19450] - Have processor generate EnabledFetchProfile for all discovered profiles + + +Changes in 7.0.0.CR1 (April 24, 2025) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/33078 + +** Bug + * [HHH-19375] - fix check for presence of Quarkus in reactive case + * [HHH-19374] - repositories should always be @Dependent + * [HHH-19345] - EntityManager#remove checks for entity state are too strict + * [HHH-19334] - CCE arising from tuple passed to HQL position() function + * [HHH-19330] - Error in lockstring generation in PostgreSQL + * [HHH-19320] - Assigned id value is not passed into BeforeExecutionGenerator#generate() method when allowAssignedIdentifiers() is true and id has been assigned + * [HHH-19318] - follow-on locking and StatelessSession + * [HHH-19314] - StackOverflowException when using onConflict with createCriteriaInsertValues and createCriteriaInsertSelect + * [HHH-19306] - Composite generator may not respect the event types of generators it consits of + * [HHH-19301] - Must import FQCN when generating metamodel class for inner Jakarta Data repository interface + * [HHH-19291] - Expressions.nullExpresion() in querydsl result in NPE in SqmExpressible with named parameters + * [HHH-19280] - ResourceRegistryStandardImpl#close(java.sql.Statement) is called on already closed statements + * [HHH-19279] - @Basic not implicit optional + * [HHH-19248] - Return of deleted entities doesn't work with naturalid multiloading + * [HHH-19208] - Javadoc of org.hibernate.cfg.QuerySettings.QUERY_PLAN_CACHE_ENABLED mentions that the query plan cache is disabled by default, but it is enabled by default + * [HHH-19207] - JPA OrderBy annotated relation not ordered when using entity graph with criteria api + * [HHH-19059] - Bytecode enhancement fails when inherited fields are mapped using property access in subclass + * [HHH-18991] - Restrictions should use JDBC parameters + * [HHH-18920] - Enum parameters in Jakarta Data repository method return type constructor are not properly matched + * [HHH-18745] - Unnecessary joins when use TREAT operator + * [HHH-14694] - Use stable proxy names to avoid managing proxy state and memory leaks + * [HHH-9127] - L2 cache stores stale data when an entity is locked with OPTIMISTIC_FORCE_INCREMENT lock type + +** Deprecation + * [HHH-19357] - deprecate hibernate.discard_pc_on_close + +** Improvement + * [HHH-19378] - find by multiple ids with EntityGraph + * [HHH-19364] - Introduce QuerySpecification + * [HHH-19358] - Add a "What's New" document for series + * [HHH-19352] - move legacy LimitHandlers to community dialects module + * [HHH-19350] - SessionBuilder exposes SPI types + * [HHH-19349] - rework ImmutableEntityUpdateQueryHandlingMode and immutable_entity_update_query_handling_mode + * [HHH-19340] - Make TypedParameterValue a record + * [HHH-19325] - Upgrade to Jandex 3.3.0 + * [HHH-19317] - Mark org.hibernate.boot.models as incubating + * [HHH-19300] - more ConstraintKinds + * [HHH-19286] - Ignoring auto-applied conversions on special mappings + * [HHH-19284] - Extract Duplicated Vector Function Registration Logic + * [HHH-19278] - fixes to logic in MultiIdEntityLoaders + * [HHH-19096] - Adjust `SelectionQuery#setEntityGraph(..)` to accept entity graphs of supertypes + * [HHH-19001] - Map ConstraintType to UNIQUE on ConstraintViolationException + * [HHH-18896] - Use binary_float/binary_double on Oracle for Java float/double + * [HHH-18008] - Ability to clear persistence context for a specific type + * [HHH-17002] - Query plan caching for CriteriaQuery based on query structure + * [HHH-16972] - Reorganize parts of org.hibernate.query.sqm + +** New Feature + * [HHH-19327] - overload SF.addNamedQuery() to take TypedQuery and return TypedQueryReference + * [HHH-19319] - StatelessSession.findMultiple() accepting a LockMode + * [HHH-19303] - validate @Id fields against @IdClass in Processor + * [HHH-19298] - add convenience overloads of StatelessSession.get() which default GraphSemantic.LOAD + * [HHH-19296] - overload createSelectionQuery() to accept an EntityGraph instead of a result class + * [HHH-19115] - Implement support for ordered loading by multiple natural-id values + * [HHH-18563] - Add foreign key target tables to affected tables (update query set-clause) + * [HHH-16643] - @NamedFetchGraph annotation + + +Changes in 7.0.0.Beta5 (March 21, 2025) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/32581 + +** Bug + * [HHH-19266] - inconsistencies in ScrollableResults + * [HHH-19259] - Static metamodel for id/timestamp not set (and triggers warnings) for DefaultRevisionEntity and similar + * [HHH-19258] - Remove @Entity annotation from default revision entities contributed internally by Envers + * [HHH-19254] - The return value of st_envelope() is not recognised as a geometry type on MariaDB + * [HHH-19246] - Fetch join makes partially covered EntityGraph ineffective + * [HHH-19232] - BeanValidationEventListener not called if only associated collection is updated via getter + * [HHH-19227] - errors in class OracleSDOFunctionDescriptors + * [HHH-19220] - ClassCastException: class org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer$1 cannot be cast to class java.lang.String + * [HHH-19206] - Bytecode-enhanced dirty checking ineffective if entity's embedded ID set manually (to same value) + * [HHH-19195] - Embeddable inheritance: discriminator values are not hierarchically ordered + * [HHH-19173] - PostgreSQLLegacySqlAstTranslator does not implement visitInArrayPredicates + * [HHH-19143] - javadoc for 7 links to JPA 3.1 javadoc instead of 3.2 + * [HHH-19140] - Enhanced entities with AccessType.PROPERTY does not work well with inheritance + * [HHH-19134] - Hibernate processor - find by id fails for entity with composite identifier with @IdClass + * [HHH-19126] - Plural valued paths should be collection-typed instead of element typed + * [HHH-19118] - The columnDefinition field of joinColumn does not take effect + * [HHH-19116] - Error when using fk() function on left joined many-to-one association and is null predicate + * [HHH-19110] - Flush operation fails with "UnsupportedOperationException: compare() not implemented for EntityType" + * [HHH-19109] - Hibernate Data Repositories are @RequestScoped + * [HHH-19097] - CoercionException for empty CHAR(1) from MySQL when used with MySQLLegacyDialect + * [HHH-19091] - Nested entity classes not properly handled by jpamodelgen + * [HHH-19005] - High memory usage for JSON string literals in BasicFormatterImpl + * [HHH-18946] - Startup issues with HANA in failover situations + * [HHH-18780] - Performance regression on Postgres with polymorphic query due to incorrect casts of null columns + * [HHH-17151] - NPE when binding null parameter in native query with explicit TemporalType + * [HHH-11801] - AbstractPersistentCollection.SetProxy does not implement equals() + +** Deprecation + * [HHH-19274] - Deprecate MetadataBuilder#applyIndexView and friends + * [HHH-19265] - deprecate hibernate.jdbc.use_scrollable_resultset + * [HHH-19253] - deprecate use of lifecycle callbacks on embeddables + * [HHH-19063] - Drop forms of SchemaNameResolver performing reflection + +** Improvement + * [HHH-19271] - support HINT_FETCH_PROFILE in SelectionQuery + * [HHH-19260] - Move feature supports methods from the SqlAstTranslator base impl to Dialect + * [HHH-19252] - overriding @Id generation declared by @MappedSuperclass + * [HHH-19223] - Upgrade JBoss Logging Tools (processor) to 3.0.4.Final + * [HHH-19219] - Informix Catalog and schema support + * [HHH-19210] - Propagate exceptions from building a ValidatorFactory + * [HHH-19205] - Do not recreate the validator on each BeanValidationEventListener#validate call + * [HHH-19196] - Upgrade to JUnit 5.12.0 + * [HHH-19145] - Relicense Hibernate ORM under ASL + * [HHH-19142] - StatelessSession.findMultiple() and second-level cache + * [HHH-19089] - Lower collection pre-sizing limit to avoid excessive memory usage + * [HHH-18724] - Support Hibernate Validator @ConstraintComposition(OR) for 'not null' DDL generation + * [HHH-18723] - Support @SQLRestriction in class marked as @MappedSuperclass + * [HHH-18482] - Provide access to a mutable ClassDetailsRegistry from the Integrator + * [HHH-17325] - @SoftDelete with timestamp + * [HHH-15271] - Don't initialize lazy associations via merge + * [HHH-4396] - Ability to patternize embedded column names + +** New Feature + * [HHH-19237] - Expand graph language to optionally specify entity + * [HHH-19217] - Expose GraphParser#parse on SessionFactory + * [HHH-19216] - NamedEntityGraph annotation supporting Hibernate parseable format + + Changes in 7.0.0.Beta4 (February 12, 2025) ------------------------------------------------------------------------------------------------------------------------ diff --git a/ci/jpa-3.2-tck.Jenkinsfile b/ci/jpa-3.2-tck.Jenkinsfile index ac125925a11b..789b11ce3fea 100644 --- a/ci/jpa-3.2-tck.Jenkinsfile +++ b/ci/jpa-3.2-tck.Jenkinsfile @@ -22,7 +22,7 @@ else { pipeline { agent none tools { - jdk 'OpenJDK 17 Latest' + jdk 'OpenJDK 21 Latest' } options { rateLimitBuilds(throttle: [count: throttleCount, durationName: 'day', userBoost: true]) @@ -151,7 +151,7 @@ pipeline { } archiveArtifacts artifacts: 'results/**' script { - failures = sh ( + def failures = sh ( script: """ \ while read line; do if [[ "\$line" = *'-error" style="display:none;">' ]]; then diff --git a/ci/release/Jenkinsfile b/ci/release/Jenkinsfile index 7b819f569291..a6c8f6f7aa14 100644 --- a/ci/release/Jenkinsfile +++ b/ci/release/Jenkinsfile @@ -1,9 +1,7 @@ #! /usr/bin/groovy /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ /* @@ -72,7 +70,7 @@ pipeline { cron('0 0 * * 0') } tools { - jdk 'OpenJDK 17 Latest' + jdk 'OpenJDK 21 Latest' } options { buildDiscarder logRotator(daysToKeepStr: '30', numToKeepStr: '10') @@ -99,7 +97,7 @@ pipeline { ) } stages { - stage('Release check') { + stage('Check') { steps { script { print "INFO: params.RELEASE_VERSION = ${params.RELEASE_VERSION}" @@ -134,11 +132,13 @@ pipeline { else { echo "Release was triggered automatically" - // Avoid doing an automatic release for commits from a release - def lastCommitter = sh(script: 'git show -s --format=\'%an\'', returnStdout: true) - def secondLastCommitter = sh(script: 'git show -s --format=\'%an\' HEAD~1', returnStdout: true) - if (lastCommitter == 'Hibernate-CI' && secondLastCommitter == 'Hibernate-CI') { - print "INFO: Automatic release skipped because last commits were for the previous release" + // Avoid doing an automatic release if there are no "releasable" commits since the last release (see release scripts for determination) + def releasableCommitCount = sh( + script: ".release/scripts/count-releasable-commits.sh ${env.PROJECT}", + returnStdout: true + ).trim().toInteger() + if ( releasableCommitCount <= 0 ) { + print "INFO: Automatic release skipped because no releasable commits were pushed since the previous release" currentBuild.getRawBuild().getExecutor().interrupt(Result.NOT_BUILT) sleep(1) // Interrupt is not blocking and does not take effect immediately. return @@ -165,13 +165,14 @@ pipeline { env.RELEASE_VERSION = releaseVersion.toString() env.DEVELOPMENT_VERSION = developmentVersion.toString() env.SCRIPT_OPTIONS = params.RELEASE_DRY_RUN ? "-d" : "" + env.JRELEASER_DRY_RUN = params.RELEASE_DRY_RUN // Determine version id to check if Jira version exists sh ".release/scripts/determine-jira-version-id.sh ${env.JIRA_KEY} ${releaseVersion.withoutFinalQualifier}" } } } - stage('Release prepare') { + stage('Prepare') { steps { script { checkoutReleaseScripts() @@ -186,19 +187,18 @@ pipeline { // tags the version // changes the version to the provided development version withEnv([ - "BRANCH=${env.GIT_BRANCH}", "DISABLE_REMOTE_GRADLE_CACHE=true", // Increase the amount of memory for this part since asciidoctor doc rendering consumes a lot of metaspace "GRADLE_OPTS=-Dorg.gradle.jvmargs='-Dlog4j2.disableJmx -Xmx4g -XX:MaxMetaspaceSize=768m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8'" ]) { - sh ".release/scripts/prepare-release.sh ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION}" + sh ".release/scripts/prepare-release.sh -j -b ${env.GIT_BRANCH} -v ${env.DEVELOPMENT_VERSION} ${env.PROJECT} ${env.RELEASE_VERSION}" } } } } } } - stage('Publish release') { + stage('Publish') { steps { script { checkoutReleaseScripts() @@ -208,13 +208,13 @@ pipeline { configFile(fileId: 'release.config.ssh.knownhosts', targetLocation: "${env.HOME}/.ssh/known_hosts") ]) { withCredentials([ - // https://github.com/gradle-nexus/publish-plugin#publishing-to-maven-central-via-sonatype-ossrh - usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'ORG_GRADLE_PROJECT_sonatypePassword', usernameVariable: 'ORG_GRADLE_PROJECT_sonatypeUsername'), + usernamePassword(credentialsId: 'central.sonatype.com', passwordVariable: 'JRELEASER_MAVENCENTRAL_TOKEN', usernameVariable: 'JRELEASER_MAVENCENTRAL_USERNAME'), // https://docs.gradle.org/current/userguide/publishing_gradle_plugins.html#account_setup usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'GRADLE_PUBLISH_SECRET', usernameVariable: 'GRADLE_PUBLISH_KEY'), - file(credentialsId: 'release.gpg.private-key', variable: 'SIGNING_GPG_PRIVATE_KEY_PATH'), - string(credentialsId: 'release.gpg.passphrase', variable: 'SIGNING_GPG_PASSPHRASE'), - gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default') + gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default'), + file(credentialsId: 'release.gpg.private-key', variable: 'RELEASE_GPG_PRIVATE_KEY_PATH'), + string(credentialsId: 'release.gpg.passphrase', variable: 'JRELEASER_GPG_PASSPHRASE'), + string(credentialsId: 'Hibernate-CI.github.com', variable: 'JRELEASER_GITHUB_TOKEN') ]) { sshagent(['ed25519.Hibernate-CI.github.com', 'hibernate.filemgmt.jboss.org', 'hibernate-ci.frs.sourceforge.net']) { // performs documentation upload and Sonatype release @@ -222,7 +222,7 @@ pipeline { withEnv([ "DISABLE_REMOTE_GRADLE_CACHE=true" ]) { - sh ".release/scripts/publish.sh ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}" + sh ".release/scripts/publish.sh -j ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION} ${env.GIT_BRANCH}" } } } @@ -230,7 +230,18 @@ pipeline { } } } - stage('Website release') { + stage('Release on Jira') { + steps { + script { + checkoutReleaseScripts() + + withCredentials([string(credentialsId: 'release-webhook.hibernate.atlassian.net', variable: 'JIRA_WEBHOOK_SECRET')]) { + sh ".release/scripts/jira-release.sh ${env.SCRIPT_OPTIONS} ${env.PROJECT} ${env.RELEASE_VERSION} ${env.DEVELOPMENT_VERSION}" + } + } + } + } + stage('Update website') { steps { script { checkoutReleaseScripts() @@ -257,7 +268,7 @@ pipeline { } } } - stage('GitHub release') { + stage('Create GitHub release') { steps { script { checkoutReleaseScripts() diff --git a/ci/snapshot-publish.Jenkinsfile b/ci/snapshot-publish.Jenkinsfile index 178e2d83aebc..8b54b31e858c 100644 --- a/ci/snapshot-publish.Jenkinsfile +++ b/ci/snapshot-publish.Jenkinsfile @@ -10,12 +10,20 @@ if (currentBuild.getBuildCauses().toString().contains('BranchIndexingCause')) { return } +def checkoutReleaseScripts() { + dir('.release/scripts') { + checkout scmGit(branches: [[name: '*/main']], extensions: [], + userRemoteConfigs: [[credentialsId: 'ed25519.Hibernate-CI.github.com', + url: 'https://github.com/hibernate/hibernate-release-scripts.git']]) + } +} + pipeline { agent { label 'Release' } tools { - jdk 'OpenJDK 17 Latest' + jdk 'OpenJDK 21 Latest' } options { rateLimitBuilds(throttle: [count: 1, durationName: 'hour', userBoost: true]) @@ -30,21 +38,29 @@ pipeline { } stage('Publish') { steps { - withCredentials([ - // https://github.com/gradle-nexus/publish-plugin#publishing-to-maven-central-via-sonatype-ossrh - usernamePassword(credentialsId: 'ossrh.sonatype.org', passwordVariable: 'ORG_GRADLE_PROJECT_sonatypePassword', usernameVariable: 'ORG_GRADLE_PROJECT_sonatypeUsername'), - // https://docs.gradle.org/current/userguide/publishing_gradle_plugins.html#account_setup - usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'GRADLE_PUBLISH_SECRET', usernameVariable: 'GRADLE_PUBLISH_KEY'), - file(credentialsId: 'release.gpg.private-key', variable: 'SIGNING_GPG_PRIVATE_KEY_PATH'), - string(credentialsId: 'release.gpg.passphrase', variable: 'SIGNING_GPG_PASSPHRASE'), - gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default') - ]) { - withEnv([ - "DISABLE_REMOTE_GRADLE_CACHE=true" - ]) { - sh './gradlew clean publish -x test --no-scan --no-daemon --no-build-cache --stacktrace -PmavenMirror=nexus-load-balancer-c4cf05fd92f43ef8.elb.us-east-1.amazonaws.com' - } - } + script { + withCredentials([ + // https://github.com/gradle-nexus/publish-plugin#publishing-to-maven-central-via-sonatype-ossrh + // https://docs.gradle.org/current/samples/sample_publishing_credentials.html#:~:text=via%20environment%20variables + usernamePassword(credentialsId: 'central.sonatype.com', passwordVariable: 'ORG_GRADLE_PROJECT_snapshotsPassword', usernameVariable: 'ORG_GRADLE_PROJECT_snapshotsUsername'), + string(credentialsId: 'Hibernate-CI.github.com', variable: 'JRELEASER_GITHUB_TOKEN'), + // https://docs.gradle.org/current/userguide/publishing_gradle_plugins.html#account_setup + usernamePassword(credentialsId: 'gradle-plugin-portal-api-key', passwordVariable: 'GRADLE_PUBLISH_SECRET', usernameVariable: 'GRADLE_PUBLISH_KEY'), + gitUsernamePassword(credentialsId: 'username-and-token.Hibernate-CI.github.com', gitToolName: 'Default') + ]) { + withEnv([ + "DISABLE_REMOTE_GRADLE_CACHE=true" + ]) { + checkoutReleaseScripts() + def version = sh( + script: ".release/scripts/determine-current-version.sh orm", + returnStdout: true + ).trim() + echo "Current version: '${version}'" + sh "bash -xe .release/scripts/snapshot-deploy.sh orm ${version}" + } + } + } } } } @@ -55,4 +71,4 @@ pipeline { } } } -} \ No newline at end of file +} diff --git a/design/sqm.adoc b/design/sqm.adoc index 3c0af9f93798..d33a3bd661a4 100644 --- a/design/sqm.adoc +++ b/design/sqm.adoc @@ -6,7 +6,7 @@ represents an atomic piece of the query. E.g. `SqmSelectClause` represents the `SqmSelectClause` is ultimately a collection of one or more `SqmSelection` references representing the individual selections to be returned from the query (called the domain results). Etc -All of these details are handled by the `QuerySqmImpl` implementation of `Query`. This is what Hibernate +All of these details are handled by the `SqmQueryImpl` implementation of `Query`. This is what Hibernate uses for both HQL and Criteria queries. diff --git a/docker_db.sh b/docker_db.sh index 8c3cca558fb0..e280694fb29f 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -16,7 +16,7 @@ else fi mysql() { - mysql_8_2 + mysql_9_2 } mysql_8_0() { @@ -34,7 +34,7 @@ mysql_8_0() { fi n=$((n+1)) echo "Waiting for MySQL to start..." - sleep 3 + sleep 5 done if [ "$n" -ge 5 ]; then echo "MySQL failed to start and configure after 15 seconds" @@ -58,7 +58,7 @@ mysql_8_1() { fi n=$((n+1)) echo "Waiting for MySQL to start..." - sleep 3 + sleep 5 done if [ "$n" -ge 5 ]; then echo "MySQL failed to start and configure after 15 seconds" @@ -74,6 +74,30 @@ mysql_8_2() { OUTPUT= n=0 until [ "$n" -ge 5 ] + do + # Need to access STDERR. Thanks for the snippet https://stackoverflow.com/a/56577569/412446 + { OUTPUT="$( { $CONTAINER_CLI logs mysql; } 2>&1 1>&3 3>&- )"; } 3>&1; + if [[ $OUTPUT == *"ready for connections"* ]]; then + break; + fi + n=$((n+1)) + echo "Waiting for MySQL to start..." + sleep 5 + done + if [ "$n" -ge 5 ]; then + echo "MySQL failed to start and configure after 15 seconds" + else + echo "MySQL successfully started" + fi +} + +mysql_9_2() { + $CONTAINER_CLI rm -f mysql || true + $CONTAINER_CLI run --name mysql -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=hibernate_orm_test -p3306:3306 -d ${DB_IMAGE_MYSQL_9_2:-docker.io/mysql:9.2.0} --character-set-server=utf8mb4 --collation-server=utf8mb4_0900_as_cs --init-connect="SET character_set_client= 'utf8mb4';SET character_set_results = 'utf8mb4'; SET character_set_connection= 'utf8mb4'; SET collation_connection = 'utf8mb4_0900_as_cs';" --log-bin-trust-function-creators=1 --lower_case_table_names=2 + # Give the container some time to start + OUTPUT= + n=0 + until [ "$n" -ge 5 ] do # Need to access STDERR. Thanks for the snippet https://stackoverflow.com/a/56577569/412446 { OUTPUT="$( { $CONTAINER_CLI logs mysql; } 2>&1 1>&3 3>&- )"; } 3>&1; @@ -691,7 +715,7 @@ oracle_atps() { export SERVICE=$(echo $INFO | jq -r '.database' | jq -r '.service') export PASSWORD=$(echo $INFO | jq -r '.database' | jq -r '.password') - curl -k -s -X POST "https://${HOST}.oraclecloudapps.com/ords/admin/_/sql" -H 'content-type: application/sql' -H 'accept: application/json' -basic -u admin:${PASSWORD} --data-ascii "create user hibernate_orm_test_$RUNID identified by \"Oracle_19_Password\" DEFAULT TABLESPACE DATA TEMPORARY TABLESPACE TEMP;alter user hibernate_orm_test_$RUNID quota unlimited on data;grant CREATE SESSION, RESOURCE, CREATE VIEW, CREATE SYNONYM, CREATE ANY INDEX, EXECUTE ANY TYPE to hibernate_orm_test_$RUNID;" + curl -k -s -X POST "https://${HOST}.oraclevcn.com:8443/ords/admin/_/sql" -H 'content-type: application/sql' -H 'accept: application/json' -basic -u admin:${PASSWORD} --data-ascii "create user hibernate_orm_test_$RUNID identified by \"Oracle_19_Password\" DEFAULT TABLESPACE DATA TEMPORARY TABLESPACE TEMP;alter user hibernate_orm_test_$RUNID quota unlimited on data;grant CREATE SESSION, RESOURCE, CREATE VIEW, CREATE SYNONYM, CREATE ANY INDEX, EXECUTE ANY TYPE to hibernate_orm_test_$RUNID;" } oracle_atps_tls() { @@ -1058,6 +1082,7 @@ if [ -z ${1} ]; then echo -e "\tmssql_2022" echo -e "\tmssql_2017" echo -e "\tmysql" + echo -e "\tmysql_9_2" echo -e "\tmysql_8_2" echo -e "\tmysql_8_1" echo -e "\tmysql_8_0" diff --git a/documentation/documentation.gradle b/documentation/documentation.gradle index e1f7a825d752..19b3daf882f5 100644 --- a/documentation/documentation.gradle +++ b/documentation/documentation.gradle @@ -1,8 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ import java.util.function.Function @@ -59,7 +57,7 @@ configurations { javadocClasspath { description = 'Class files for the javadoc to be built' - resolutionStrategy.capabilitiesResolution.withCapability('org.junit.jupiter:junit-jupiter-params:5.7.1') { details -> + resolutionStrategy.capabilitiesResolution.withCapability('org.junit.jupiter:junit-jupiter-params:'+testLibs.versions.junit5.get()) { details -> details.select( details.candidates.first() ).because( 'first' ) } @@ -127,6 +125,7 @@ dependencies { reportAggregation project( ':hibernate-agroal' ) reportAggregation project( ':hibernate-c3p0' ) reportAggregation project( ':hibernate-core' ) + reportAggregation project(':hibernate-envers') reportAggregation project(':hibernate-graalvm') reportAggregation project(':hibernate-hikaricp') reportAggregation project(':hibernate-jcache') @@ -141,6 +140,9 @@ dependencies { core project( ':hibernate-core' ) javadocSources project( path: ':hibernate-core', configuration: 'javadocSources' ) + envers project( ':hibernate-envers' ) + javadocSources project( path: ':hibernate-envers', configuration: 'javadocSources' ) + testing project( ':hibernate-testing' ) spatial project( ':hibernate-spatial' ) @@ -735,6 +737,45 @@ def renderIntegrationGuidesTask = tasks.register( "renderIntegrationGuides" ) { } +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +// What's New Guide + +def whatsNewGuideSourceStagingDir = layout.buildDirectory.dir( "tmp/asciidoc/whats-new" ) + +def copyWhatsNewTask = tasks.register( "copyWhatsNew", Copy ) {task -> + group = "Documentation" + description = "Copies whats-new.adoc in preparation for rendering." + + inputs.property "hibernate-version", hibernateVersion + + from rootProject.layout.projectDirectory.file( "whats-new.adoc" ) + into whatsNewGuideSourceStagingDir +} + +def renderWhatsNewTask = tasks.register( "renderWhatsNew", AsciidoctorTask ) { + group = "Documentation" + description = "Renders the What's New guide in HTML format using Asciidoctor." + + dependsOn copyWhatsNewTask + inputs.property "hibernate-version", hibernateVersion + + sourceDir = whatsNewGuideSourceStagingDir + + outputDir = project.layout.buildDirectory.dir( 'asciidoc/whats-new' ) + + attributes linkcss: true, + stylesheet: "css/hibernate.css" + + resources { + from( 'src/main/style/asciidoctor' ) { + include 'images/**' + } + from( 'src/main/style/asciidoctor' ) { + include 'css/**' + } + } +} + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Migration Guide @@ -851,6 +892,7 @@ def buildDocsTask = tasks.register( 'buildDocs' ) { task -> task.dependsOn renderTopicalGuidesTask task.dependsOn generateReportsTask task.dependsOn renderMigrationGuideTask + task.dependsOn renderWhatsNewTask } //noinspection GroovyUnusedAssignment diff --git a/documentation/src/main/asciidoc/introduction/Advanced.adoc b/documentation/src/main/asciidoc/introduction/Advanced.adoc index 8bc5921f026c..26c74a8e658b 100644 --- a/documentation/src/main/asciidoc/introduction/Advanced.adoc +++ b/documentation/src/main/asciidoc/introduction/Advanced.adoc @@ -316,8 +316,8 @@ To make use of multi-tenancy, we'll usually need to set at least one of these co |=== | Configuration property name | Purpose -| `hibernate.tenant_identifier_resolver` | Specifies the `CurrentTenantIdentifierResolver` -| `hibernate.multi_tenant_connection_provider` | Specifies the `MultiTenantConnectionProvider` +| link:{doc-javadoc-url}org/hibernate/cfg/MultiTenancySettings.html#MULTI_TENANT_IDENTIFIER_RESOLVER[`hibernate.tenant_identifier_resolver`] | Specifies the `CurrentTenantIdentifierResolver` +| link:{doc-javadoc-url}org/hibernate/cfg/MultiTenancySettings.html#MULTI_TENANT_CONNECTION_PROVIDER[`hibernate.multi_tenant_connection_provider`] | Specifies the `MultiTenantConnectionProvider` |=== Do not configure those properties if you would like the configured `BeanContainer` provide the implementation. @@ -467,7 +467,7 @@ Furthermore, the link:{doc-javadoc-url}org/hibernate/annotations/ValueGeneration // .The older APIs are still available in Hibernate 6 ==== These APIs were new in Hibernate 6, and supersede the classic `IdentifierGenerator` interface and `@GenericGenerator` annotation from older versions of Hibernate. -However, the older APIs are still available and custom ``IdentifierGenerator``s written for older versions of Hibernate continue to work in Hibernate 6. +However, the older APIs are still available and custom ``IdentifierGenerator``s written for older versions of Hibernate continue to work in Hibernate 7. ==== Hibernate has a range of built-in generators which are defined in terms of this new framework. @@ -477,12 +477,12 @@ Hibernate has a range of built-in generators which are defined in terms of this |=== | Annotation | Implementation | Purpose -| `@Generated` | `GeneratedGeneration` | Generically handles database-generated values -| `@GeneratedColumn` | `GeneratedAlwaysGeneration` | Handles values generated using `generated always` -| `@CurrentTimestamp` | `CurrentTimestampGeneration` | Generic support for database or in-memory generation of creation or update timestamps -| `@CreationTimestamp` | `CurrentTimestampGeneration` | A timestamp generated when an entity is first made persistent -| `@UpdateTimestamp` | `CurrentTimestampGeneration` | A timestamp generated when an entity is made persistent, and regenerated every time the entity is modified -| `@UuidGenerator` | `UuidGenerator` | A more flexible generator for RFC 4122 UUIDs +| link:{doc-javadoc-url}org/hibernate/annotations/Generated.html[`@Generated`] | `GeneratedGeneration` | Generically handles database-generated values +| link:{doc-javadoc-url}org/hibernate/annotations/GeneratedColumn.html[`@GeneratedColumn`] | `GeneratedAlwaysGeneration` | Handles values generated using `generated always` +| link:{doc-javadoc-url}org/hibernate/annotations/CurrentTimestamp.html[`@CurrentTimestamp`] | `CurrentTimestampGeneration` | Generic support for database or in-memory generation of creation or update timestamps +| link:{doc-javadoc-url}org/hibernate/annotations/CreationTimestamp.html[`@CreationTimestamp`] | `CurrentTimestampGeneration` | A timestamp generated when an entity is first made persistent +| link:{doc-javadoc-url}org/hibernate/annotations/UpdateTimestamp.html[`@UpdateTimestamp`] | `CurrentTimestampGeneration` | A timestamp generated when an entity is made persistent, and regenerated every time the entity is modified +| link:{doc-javadoc-url}org/hibernate/annotations/UuidGenerator.html[`@UuidGenerator`] | `UuidGenerator` | A more flexible generator for RFC 4122 UUIDs |=== Furthermore, support for JPA's standard id generation strategies is also defined in terms of this framework. @@ -595,8 +595,8 @@ Custom naming strategies may be enabled using the configuration properties we al |=== | Configuration property name | Purpose -| `hibernate.implicit_naming_strategy` | Specifies the `ImplicitNamingStrategy` -| `hibernate.physical_naming_strategy` | Specifies the `PhysicalNamingStrategy` +| link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#IMPLICIT_NAMING_STRATEGY[`hibernate.implicit_naming_strategy`] | Specifies the `ImplicitNamingStrategy` +| link:{doc-javadoc-url}org/hibernate/cfg/MappingSettings.html#PHYSICAL_NAMING_STRATEGY[`hibernate.physical_naming_strategy`] | Specifies the `PhysicalNamingStrategy` |=== [[spatial]] @@ -1140,7 +1140,7 @@ We may define as many different fetch profiles as we like. | `@FetchProfileOverride` | Specifies the fetch strategy for the annotated association, in a given fetch profile |=== -A fetch profile must be explicitly enabled for a given session by calling link:{doc-javadoc-url}org/hibernate/Session.html#enableFetchProfile(java.lang.String)[`enableFetchProfile()`]: +A fetch profile must be explicitly enabled for a given session by passing the name of the profile to link:{doc-javadoc-url}org/hibernate/Session.html#enableFetchProfile(java.lang.String)[`enableFetchProfile()`]: [source,java] ---- @@ -1148,6 +1148,21 @@ session.enableFetchProfile(Book_.PROFILE_EAGER_BOOK); Book eagerBook = session.find(Book.class, bookId); ---- +Alternatively, an instance of link:{doc-javadoc-url}org/hibernate/EnabledFetchProfile.html[`EnabledFetchProfile`] may be obtained in a type safe way from the static metamodel, and applied to the session: + +[source,java] +---- +Book_._EagerBook.enable(session); +Book eagerBook = session.find(Book.class, bookId); +---- + +Even better, the `EnabledFetchProfile` may be passed as a `FindOption`: + +[source,java] +---- +Book eagerBook = entityManager.find(Book.class, bookId, Book_._EagerBook); +---- + So why or when might we prefer named fetch profiles to entity graphs? Well, it's really hard to say. It's nice that this feature _exists_, and if you love it, that's great. diff --git a/documentation/src/main/asciidoc/introduction/Configuration.adoc b/documentation/src/main/asciidoc/introduction/Configuration.adoc index ec699ac35549..d1a5e1acf627 100644 --- a/documentation/src/main/asciidoc/introduction/Configuration.adoc +++ b/documentation/src/main/asciidoc/introduction/Configuration.adoc @@ -109,7 +109,7 @@ and `io.agroal:agroal-pool` | The {query-validator}[Query Validator], for compile-time checking of HQL | `org.hibernate:query-validator` | {validator}[Hibernate Validator], an implementation of {bean-validation}[Bean Validation] | `org.hibernate.validator:hibernate-validator` + -and `org.glassfish:jakarta.el` +and `org.glassfish.expressly:expressly` | Local second-level cache support via JCache and {ehcache}[EHCache] | `org.hibernate.orm:hibernate-jcache` + and `org.ehcache:ehcache` | Local second-level cache support via JCache and {caffeine}[Caffeine]| `org.hibernate.orm:hibernate-jcache` + @@ -122,6 +122,7 @@ or `org.eclipse:yasson` | <> | `org.hibernate.orm:hibernate-spatial` | <>, for auditing historical data | `org.hibernate.orm:hibernate-envers` | <>, for monitoring via Java Flight Recorder | `org.hibernate.orm:hibernate-jfr` +| Hibernate Jandex integration, for <> | `org.hibernate.orm:hibernate-scan-jandex` |=== You might also add the Hibernate {enhancer}[bytecode enhancer] to your @@ -264,6 +265,35 @@ This API is useful if you have very advanced requirements, for example, if you'r You'll find more information in the {native-bootstrap}[User Guide], and in the {boot}[package-level documentation] of `org.hibernate.boot`. **** +[[entity-discovery]] +=== Entity discovery + +In a Jakarta EE container environment, we don't usually need to list entity and embeddable classes explicitly in `persistence.xml`. +Instead, the container scans the persistence unit `jar` file and automatically discovers classes annotated `@Entity`, `@Embeddable`, or `@MappedSuperclass`. + +`HibernatePersistenceConfiguration` offers the same functionality if the <> `hibernate-scan-jandex` is available at runtime. + +In the following code, entity classes available on the class loader which loaded `Main.class` are automatically discovered. + +[source,java] +---- +SessionFactory sessionFactory = + // entities discovered on ClassLoader of Main.class + new HibernatePersistenceConfiguration("Bookshop", Main.class) + // PostgreSQL + .jdbcUrl("jdbc:postgresql://localhost/example") + // Credentials + .jdbcCredentials(user, password) + // Automatic schema export + .schemaToolingAction(Action.SPEC_ACTION_DROP_AND_CREATE) + // SQL statement logging + .showSql(true, true, true) + // Create a new SessionFactory + .createEntityManagerFactory(); +---- + +Notice that we were able to remove the calls to `managedClass()`. + [[configuration-properties]] === Configuration using Hibernate properties file @@ -397,13 +427,14 @@ properties: | Configuration property name | Purpose | `jakarta.persistence.schema-generation.database.action` -a| * If `drop-and-create`, first drop the schema and then export tables, sequences, and constraints -* If `create`, export tables, sequences, and constraints, without attempting to drop them first -* If `create-drop`, drop the schema and recreate it on `SessionFactory` startup -Additionally, drop the schema on `SessionFactory` shutdown +a| * If `drop-and-create`, first drop the schema, then export tables, sequences, and constraints, and then populate initial data +* If `create`, export tables, sequences, and constraints, without attempting to drop them first, and then populate initial data +* If `create-drop`, drop the schema and recreate it on `SessionFactory` startup; +additionally, drop the schema on `SessionFactory` shutdown * If `drop`, drop the schema on `SessionFactory` shutdown * If `validate`, validate the database schema without changing it -* If `update`, only export what's missing in the schema +* If `update`, only export what's missing in the schema, and alter incorrect column types +* If `populate`, only populate initial data | `jakarta.persistence.create-database-schemas` | (Optional) If `true`, automatically create schemas and catalogs @@ -478,7 +509,7 @@ logger.jdbc-extract.level=trace ---- -But with this approach we miss out on the pretty highlighting. +SQL logging respects the settings `hibernate.format_sql` and `hibernate.highlight_sql`, so we don't miss out on the pretty formatting and highlighting. [[minimizing]] === Minimizing repetitive mapping information diff --git a/documentation/src/main/asciidoc/introduction/Entities.adoc b/documentation/src/main/asciidoc/introduction/Entities.adoc index dd9b9d84ed63..a4be5745b09d 100644 --- a/documentation/src/main/asciidoc/introduction/Entities.adoc +++ b/documentation/src/main/asciidoc/introduction/Entities.adoc @@ -71,7 +71,7 @@ When XML-based mappings are used, the `` element is used to declare an e Since the `orm.xml` mapping file format defined by the JPA specification was modelled closely on the annotation-based mappings, it's usually easy to go back and forth between the two options. **** -We won't have much more to say about XML-based mappings in this Introduction, since it's not our preferred way to do things. +We won't have much more to say about XML-based mappings in this Short Guide, since it's not our preferred way to do things. ."Dynamic" models **** @@ -534,11 +534,12 @@ The JPA specification defines a quite limited set of basic types: | Primitive wrappers | `java.lang` | `Boolean`, `Integer`, `Double`, etc | Strings | `java.lang` | `String` | Arbitrary-precision numeric types | `java.math` | `BigInteger`, `BigDecimal` +| UUIDs | `java.util` | `UUID` | Date/time types | `java.time` | `LocalDate`, `LocalTime`, `LocalDateTime`, `OffsetDateTime`, `Instant`, `Year` | Deprecated date/time types 💀 | `java.util` | `Date`, `Calendar` | Deprecated JDBC date/time types 💀 | `java.sql` | `Date`, `Time`, `Timestamp` | Binary and character arrays | | `byte[]`, `char[]` -| UUIDs | `java.util` | `UUID` +| Binary and character wrapper arrays 💀 | `java.lang` | `Byte[]`, `Character[]` | Enumerated types | | Any `enum` | Serializable types | | Any type which implements `java.io.Serializable` |==== @@ -549,6 +550,13 @@ The JPA specification defines a quite limited set of basic types: We're begging you to use types from the `java.time` package instead of anything which inherits `java.util.Date`. ==== +[WARNING] +==== +The use of `Byte[]` and `Character[]` as basic types was deprecated by Jakarta Persistence 3.2. +Hibernate does not allow `null` elements in such arrays. +Use `byte[]` or `char[]` instead. +==== + [CAUTION] // .Serialization is usually a bad idea ==== @@ -1082,7 +1090,8 @@ That said, it's possible to take this idea way to far. **** It's come to our attention that a vocal group of people advocate that Java entity classes should be broken up into tiny disconnected islands they call "aggregates". An aggregate--at least as a first approximation--corresponds roughly to what we would usually call a parent/child relationship. Simple examples of aggregates might be `Order`/`Item`, or `Product`/`Part`. -According to this way of thinking, there should be no associations _between_ aggregates, that is, that the `Item.product` association should be replaced with `productId`, that `Part.manufacturer` should be replaced with `manufacturerId`, and so on. +According to this way of thinking, there should be no associations _between_ aggregates. +So the `Item.product` association should be replaced with `productId`, `Part.manufacturer` should be replaced with `manufacturerId`, and so on. (Of course, the word "aggregate" may also be employed in other senses, but this is the sense we're discussing right now.) In the example we've been using, `Book` would not be permitted to have a collection of entity type `Author`, and should instead hold only the ids of the authors, or perhaps instances of some `BookAuthor` type which duplicates some state of `Author` and is disconnected from the rest of the model. @@ -1188,7 +1197,7 @@ bit more type safe: @OneToMany(mappedBy=Book_.PUBLISHER) // get used to doing it this way! Set books; ---- -We're going to use this approach for the rest of the Introduction. +We're going to use this approach for the rest of the Short Guide. To modify a bidirectional association, we must change the _owning side_. @@ -1262,7 +1271,7 @@ class Author { Long id; @OneToOne(optional=false, fetch=LAZY) - Person author; + Person person; ... } @@ -1333,7 +1342,7 @@ class Author { @OneToOne(optional=false, fetch=LAZY) @MapsId - Person author; + Person person; ... } diff --git a/documentation/src/main/asciidoc/introduction/Hibernate_Introduction.adoc b/documentation/src/main/asciidoc/introduction/Hibernate_Introduction.adoc index 64bcba3cd17c..da784ed26c08 100644 --- a/documentation/src/main/asciidoc/introduction/Hibernate_Introduction.adoc +++ b/documentation/src/main/asciidoc/introduction/Hibernate_Introduction.adoc @@ -20,6 +20,7 @@ include::Configuration.adoc[] include::Entities.adoc[] include::Mapping.adoc[] include::Interacting.adoc[] +include::Querying.adoc[] include::Processor.adoc[] include::Tuning.adoc[] include::Advanced.adoc[] diff --git a/documentation/src/main/asciidoc/introduction/Interacting.adoc b/documentation/src/main/asciidoc/introduction/Interacting.adoc index f3286caa5d4c..7f3cd40ef8e1 100644 --- a/documentation/src/main/asciidoc/introduction/Interacting.adoc +++ b/documentation/src/main/asciidoc/introduction/Interacting.adoc @@ -233,6 +233,14 @@ entityManager.getTransaction().setRollbackOnly(); A transaction in rollback-only mode will be rolled back when it completes. +[[after-tx-rollback]] +[IMPORTANT] +==== +Hibernate is not a software transactional memory. +When a transaction rolls back, Hibernate makes no attempt to roll back the state of objects held in memory to their state at the beginning of the transaction. +After a transaction rollback, the persistence context must be discarded, and the state of its entities must be assumed inconsistent with the state held by the database. +==== + [[persistence-operations]] === Operations on the persistence context @@ -294,6 +302,7 @@ Now, if an exception occurs while interacting with the database, there's no good Therefore, a session is considered to be unusable after any of its methods throws an exception. +[[fragile-persistence-context]] [IMPORTANT] // .The persistence context is fragile ==== @@ -346,6 +355,8 @@ Finally, the Hibernate `Session` offers the following method, which is capable o | `findMultiple(Class,List,FindOption...)` | Obtain a list of persistent objects given their type and their ids, using the specified options +| `findMultiple(EntityGraph,List,FindOption...)` +| Obtain a list of persistent objects given their ids and an `EntityGraph` specifying their type and associations which should be eagerly fetched, using the specified options |=== The following code results in a single SQL `select` statement: @@ -393,7 +404,7 @@ _Orphan removal_ indicates that an `Item` should be automatically deleted if it Our data model is a set of interconnected entities, and in Java our whole dataset would be represented as an enormous interconnected graph of objects. It's possible that this graph is disconnected, but more likely it's connected, or composed of a relatively small number of connected subgraphs. -Therefore, when we retrieve on object belonging to this graph from the database and instantiate it in memory, we simply can't recursively retrieve and instantiate all its associated entities. +Therefore, when we retrieve an object belonging to this graph from the database and instantiate it in memory, we simply can't recursively retrieve and instantiate all its associated entities. Quite aside from the waste of memory on the VM side, this process would involve a huge number of round trips to the database server, or a massive multidimensional cartesian product of tables, or both. Instead, we're forced to cut the graph somewhere. @@ -559,6 +570,74 @@ JPA even specifies a way to define named entity graphs using annotations. But the annotation-based API is so verbose that it's just not worth using. ==== +[[load-access]] +=== Controlling lookup by id + +As we will soon see in the <>, we can do almost anything via <>, <>, or <> queries. +But when we already know the identifier of the entity we need, a query can feel like overkill. +And queries don't make efficient use of the <>. + +We met the `find()` and `findMultiple()` methods <>. +These are the most basic ways to perform a _lookup_ by id. +But they can't quite do everything. +Therefore, Hibernate has some APIs that streamline certain more complicated lookups: + +.Operations for lookup by id +[%breakable,cols="30,~"] +|=== +| Method name | Purpose + +| `byId()` | Lets us specify association fetching via an `EntityGraph`, as we saw; also lets us specify some additional options, including how the lookup <>, and whether the entity should be loaded in read-only mode +| `byMultipleIds()` | Lets us load a _batch_ of ids at the same time +|=== + +[NOTE] +==== +Since the introduction of `FindOption` in JPA 3.2, `byId()` is now much less useful. +==== + +Batch loading is very useful when we need to retrieve multiple instances of the same entity class by id: + +[source,java] +---- +var graph = session.createEntityGraph(Book.class); +graph.addSubgraph(Book_.publisher); + +List books = + session.byMultipleIds(Book.class) + .withFetchGraph(graph) // control association fetching + .withBatchSize(20) // specify an explicit batch size + .with(CacheMode.GET) // control interaction with the cache + .multiLoad(bookIds); +---- + +The given list of `bookIds` will be broken into batches, and each batch will be fetched from the database in a single `select`. +If we don't specify the batch size explicitly, a batch size will be chosen automatically. + +We also have some operations for working with lookups by <>: + +[%breakable,cols="30,~"] +|=== +| Method name | Purpose + +| `bySimpleNaturalId()` | For an entity with just one attribute is annotated `@NaturalId` +| `byNaturalId()` | For an entity with multiple attributes are annotated `@NaturalId` +| `byMultipleNaturalId()` | Lets us load a _batch_ of natural ids at the same time +|=== + +Here's how we can retrieve an entity by its composite natural id: + +[source,java] +---- +Book book = + session.byNaturalId(Book.class) + .using(Book_.isbn, isbn) + .using(Book_.printing, printing) + .load(); +---- + +Notice that this code fragment is completely typesafe, again thanks to <>. + [[flush]] === Flushing the session @@ -679,755 +758,89 @@ var book = entityManager.find(Book.class, isbn, ReadOnlyMode.READ_ONLY); It's not necessary to dirty-check an entity instance in read-only mode. -[[queries]] -=== Queries - -:hql: {doc-user-guide-url}#query-language - -Hibernate features three complementary ways to write queries: - -- the _Hibernate Query Language_, an extremely powerful superset of JPQL, which abstracts most of the features of modern dialects of SQL, -- the JPA _criteria query_ API, along with extensions, allowing almost any HQL query to be constructed programmatically via a typesafe API, and, of course -- for when all else fails, _native SQL_ queries. - -[[hql-queries]] -=== HQL queries - -:hql: {doc-user-guide-url}#query-language - -A full discussion of the query language would require almost as much text as the rest of this Introduction. -Fortunately, HQL is already described in exhaustive (and exhausting) detail in {doc-query-language-url}[_A Guide to Hibernate Query Language_]. -It doesn't make sense to repeat that information here. -// The query language is discussed in great detail below in <>. - -Here we want to see how to execute a query via the `Session` or `EntityManager` API. -The method we call depends on what kind of query it is: - -- _selection queries_ return a result list, but do not modify the data, but -- _mutation queries_ modify data, and return the number of modified rows. - -Selection queries usually start with the keyword `select` or `from`, whereas mutation queries begin with the keyword `insert`, `update`, or `delete`. - -.Executing HQL -[%breakable,cols="10,36,32,22"] -|=== -| Kind | `Session` method | `EntityManager` method | `Query` execution method - -| Selection | `createSelectionQuery(String,Class)` | `createQuery(String,Class)` | `getResultList()`, `getSingleResult()`, or `getSingleResultOrNull()` -| Mutation | `createMutationQuery(String)` | `createQuery(String)` | `executeUpdate()` -|=== - -So for the `Session` API we would write: - -[source,java] ----- -List matchingBooks = - session.createSelectionQuery("from Book where title like :titleSearchPattern", Book.class) - .setParameter("titleSearchPattern", titleSearchPattern) - .getResultList(); ----- - -Or, if we're sticking to the JPA-standard APIs: - -[source,java] ----- -List matchingBooks = - entityManager.createQuery("select b from Book b where b.title like :titleSearchPattern", Book.class) - .setParameter("titleSearchPattern", titleSearchPattern) - .getResultList(); ----- - -The only difference between `createSelectionQuery()` and `createQuery()` is that `createSelectionQuery()` throws an exception if passed an `insert`, `delete`, or `update`. - -In the query above, `:titleSearchPattern` is called a _named parameter_. -We may also identify parameters by a number. -These are called _ordinal parameters_. - -[source,java] ----- -List matchingBooks = - session.createSelectionQuery("from Book where title like ?1", Book.class) - .setParameter(1, titleSearchPattern) - .getResultList(); ----- - -When a query has multiple parameters, named parameters tend to be easier to read, even if slightly more verbose. - -[WARNING] -// .Using parameters to avoid injection attacks -==== -_Never_ concatenate user input with HQL and pass the concatenated string to `createSelectionQuery()`. -This would open up the possibility for an attacker to execute arbitrary code on your database server. -==== - -If we're expecting a query to return a single result, we can use `getSingleResult()`. - -[source,java] ----- -Book book = - session.createSelectionQuery("from Book where isbn = ?1", Book.class) - .setParameter(1, isbn) - .getSingleResult(); ----- - -Or, if we're expecting it to return at most one result, we can use `getSingleResultOrNull()`. - -[source,java] ----- -Book bookOrNull = - session.createSelectionQuery("from Book where isbn = ?1", Book.class) - .setParameter(1, isbn) - .getSingleResultOrNull(); ----- - -The difference, of course, is that `getSingleResult()` throws an exception if there's no matching row in the database, whereas `getSingleResultOrNull()` just returns `null`. - -By default, Hibernate dirty checks entities in the persistence context before executing a query, in order to determine if the session should be flushed. -If there are many entities association with the persistence context, then this can be an expensive operation. - -To disable this behavior, set the flush mode to `COMMIT` or `MANUAL`: - -[source,java] ----- -Book bookOrNull = - session.createSelectionQuery("from Book where isbn = ?1", Book.class) - .setParameter(1, isbn) - .setHibernateFlushMode(MANUAL) - .getSingleResult(); ----- - -[CAUTION] -==== -Setting the flush mode to `COMMIT` or `MANUAL` might cause the query to return stale results. -==== - -Occasionally we need to build a query at runtime, from a set of optional conditions. -For this, JPA offers an API which allows programmatic construction of a query. - -[[criteria-queries]] -=== Criteria queries - -Imagine we're implementing some sort of search screen, where the user of our system is offered several different ways to constrain the query result set. -For example, we might let them search for books by title and/or the author name. -Of course, we could construct a HQL query by string concatenation, but this is a bit fragile, so it's quite nice to have an alternative. - -.HQL is implemented in terms of criteria objects -**** -Actually, since Hibernate 6, every HQL query is compiled to a criteria query before being translated to SQL. -This ensures that the semantics of HQL and criteria queries are identical. -**** - -First we need an object for building criteria queries. -Using the JPA-standard APIs, this would be a `CriteriaBuilder`, and we get it from the `EntityManagerFactory`: - -[source,java] ----- -CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder(); ----- - -But if we have a `SessionFactory`, we get something much better, a link:{doc-javadoc-url}org/hibernate/query/criteria/HibernateCriteriaBuilder.html[`HibernateCriteriaBuilder`]: - -[source,java] ----- -HibernateCriteriaBuilder builder = sessionFactory.getCriteriaBuilder(); ----- - -The `HibernateCriteriaBuilder` extends `CriteriaBuilder` and adds many operations that JPQL doesn't have. - -[TIP] -// .Getting a `HibernateCriteriaBuilder` in JPA -==== -If you're using `EntityManagerFactory`, don't despair, you have two perfectly good ways to obtain the `HibernateCriteriaBuilder` associated with that factory. -Either: - -[source,java] ----- -HibernateCriteriaBuilder builder = - entityManagerFactory.unwrap(SessionFactory.class).getCriteriaBuilder(); ----- - -Or simply: - -[source,java] ----- -HibernateCriteriaBuilder builder = - (HibernateCriteriaBuilder) entityManagerFactory.getCriteriaBuilder(); ----- -==== - -We're ready to create a criteria query. - -[source,java] ----- -CriteriaQuery query = builder.createQuery(Book.class); -Root book = query.from(Book.class); -Predicate where = builder.conjunction(); -if (titlePattern != null) { - where = builder.and(where, builder.like(book.get(Book_.title), titlePattern)); -} -if (namePattern != null) { - Join author = book.join(Book_.author); - where = builder.and(where, builder.like(author.get(Author_.name), namePattern)); -} -query.select(book).where(where) - .orderBy(builder.asc(book.get(Book_.title))); ----- - -Here, as before, the classes `Book_` and `Author_` are generated by <>. - -[NOTE] -// .Injection attacks and criteria queries -==== -Notice that we didn't bother treating `titlePattern` and `namePattern` as parameters. -That's safe because, by default, Hibernate automatically and transparently treats strings passed to the `CriteriaBuilder` as JDBC parameters. -==== - -Execution of a criteria query works almost exactly like execution of HQL. - -.Executing criteria queries -[%breakable,cols="10,36,32,22"] -|=== -| Kind | `Session` method | `EntityManager` method | `Query` execution method - -| Selection | `createSelectionQuery(CriteriaQuery)` | `createQuery(CriteriaQuery)` | `getResultList()`, `getSingleResult()`, or `getSingleResultOrNull()` -| Mutation | `createMutationQuery(CriteriaUpdate)` or `createMutationQuery(CriteriaDelete)` | `createQuery(CriteriaUpdate)` or `createQuery(CriteriaDelte)` | `executeUpdate()` -|=== +[[callbacks]] +=== Lifecycle callbacks and entity listeners +The annotations `@PrePersist`, `@PreRemove`, `@PreUpdate`, `@PostPersist`, `@PostRemove`, `@PostUpdate`, and `@PostLoad` allow an entity to respond to persistence lifecycle operations and maintain its transient internal state. For example: [source,java] ---- -List matchingBooks = - session.createSelectionQuery(query) - .getResultList(); ----- - -Update, insert, and delete queries work similarly: - -[source,java] ----- -CriteriaDelete delete = builder.createCriteriaDelete(Book.class); -Root book = delete.from(Book.class); -delete.where(builder.lt(builder.year(book.get(Book_.publicationDate)), 2000)); -session.createMutationQuery(delete).executeUpdate(); ----- - -[TIP] -==== -It's even possible to transform a HQL query string to a criteria query, and modify the query programmatically before execution: -[source,java] ----- -HibernateCriteriaBuilder builder = sessionFactory.getCriteriaBuilder(); -var query = builder.createQuery("from Book where year(publicationDate) > 2000", Book.class); -var root = query.getRoot(0, Book.class); -query.where(builder.like(root.get(Book_.title), builder.literal("Hibernate%"))); -query.orderBy(builder.asc(root.get(Book_.title)), builder.desc(root.get(Book_.isbn))); -List matchingBooks = session.createSelectionQuery(query).getResultList(); ----- -This is starting to get a bit messy. -In Hibernate 7, we can often use <> instead. -==== - -Do you find some of the code above a bit too verbose? -We do. - -[[criteria-definition]] -=== A more comfortable way to write criteria queries - -Actually, what makes the JPA criteria API less ergonomic than it should be is the need to call all operations of the `CriteriaBuilder` as instance methods, instead of having them as `static` functions. -The reason it works this way is that each JPA provider has its own implementation of `CriteriaBuilder`. - -// [%unbreakable] -// [TIP] -// ==== -Hibernate 6.3 introduces the helper class link:{doc-javadoc-url}org/hibernate/query/criteria/CriteriaDefinition.html[`CriteriaDefinition`] to reduce the verbosity of criteria queries. -Our example looks like this: - -[source,java] ----- -CriteriaQuery query = - new CriteriaDefinition(entityManagerFactory, Book.class) {{ - select(book); - if (titlePattern != null) { - restrict(like(book.get(Book_.title), titlePattern)); - } - if (namePattern != null) { - var author = book.join(Book_.author); - restrict(like(author.get(Author_.name), namePattern)); - } - orderBy(asc(book.get(Book_.title))); - }}; ----- -// ==== - -When all else fails, and sometimes even before that, we're left with the option of writing a query in SQL. - -[[native-queries]] -=== Native SQL queries - -HQL is a powerful language which helps reduce the verbosity of SQL, and significantly increases portability of queries between databases. -But ultimately, the true value of ORM is not in avoiding SQL, but in alleviating the pain involved in dealing with SQL result sets once we get them back to our Java program. -As we said <>, Hibernate's generated SQL is meant to be used in conjunction with handwritten SQL, and native SQL queries are one of the facilities we provide to make that easy. - -.Executing SQL -[%breakable,cols="10,36,32,22"] -|=== -| Kind | `Session` method | `EntityManager` method | `Query` execution method - -| Selection | `createNativeQuery(String,Class)` | `createNativeQuery(String,Class)` | `getResultList()`, `getSingleResult()`, or `getSingleResultOrNull()` -| Mutation | `createNativeMutationQuery(String)` | `createNativeQuery(String)` | `executeUpdate()` -| Stored procedure | `createStoredProcedureCall(String)` | `createStoredProcedureQuery(String)` | `execute()` -|=== - -For the most simple cases, Hibernate can infer the shape of the result set: - -[source, java] ----- -Book book = - session.createNativeQuery("select * from Books where isbn = ?1", Book.class) - .setParameter(1, isbn) - .getSingleResult(); - -String title = - session.createNativeQuery("select title from Books where isbn = ?1", String.class) - .setParameter(1, isbn) - .getSingleResult(); ----- - -However, in general, there isn't enough information in the JDBC `ResultSetMetaData` to infer the mapping of columns to entity objects. -So for more complicated cases, you'll need to use the `@SqlResultSetMapping` annotation to define a named mapping, and pass the name to `createNativeQuery()`. This gets fairly messy, so we don't want to hurt your eyes by showing you an example of it. - -By default, Hibernate doesn't flush the session before execution of a native query. -That's because the session is unaware of which modifications held in memory would affect the results of the query. - -So if there are any unflushed changes to ``Book``s, this query might return stale data: - -[source,java] ----- -List books = - session.createNativeQuery("select * from Books", Book.class) - .getResultList(); ----- - -There's two ways to ensure the persistence context is flushed before this query is executed. - -Either, we could simply force a flush by calling `flush()` or by setting the flush mode to `ALWAYS`: - -[source,java] ----- -List books = - session.createNativeQuery("select * from Books", Book.class) - .setHibernateFlushMode(ALWAYS) - .getResultList(); ----- - -Or, alternatively, we could tell Hibernate which modified state affects the results of the query: - -[source,java] ----- -List books = - session.createNativeQuery("select * from Books", Book.class) - .addSynchronizedEntityClass(Book.class) - .getResultList(); ----- - -[TIP] -==== -You can call stored procedures using `createStoredProcedureQuery()` or `createStoredProcedureCall()`. -==== - -[[restrictions-and-ordering]] -=== Restrictions and ordering - -We've already seen how the JPA <> can be used to construct a query completely programmatically. -The Criteria API is powerful, but for the most common scenarios it's at least arguably overkill. -The <> class helps a bit, but it doesn't completely eliminate the verbosity of programmatic query definition. - -In Hibernate 7, there's a new option, a very ergonomic API for programmatically adding restrictions or ordering to an existing query before executing it. -(Actually, the ordering part of this was introduced in Hibernate 6.5.) -This new API: - -- isn't part of the Criteria Query API, and so we don't need a `CriteriaQuery` object to make use of it, -- works with both HQL and Criteria queries, and even with <>, and -- is optimized for the case of a query which returns its single root entity. - -[source,java] ----- -var query = session.createSelectionQuery("from Book where year(publicationDate) > 2000", Book.class); -if (titlePattern != null) { - query.addRestriction(Restriction.like(Book_.title, namePattern)); -} -if (isbns != null && !isbns.isEmpty()) { - query.addRestriction(Restriction.in(Book_.isbn, isbns)) -} -query.setOrder(List.of(Order.asc(Book_.title), Order.asc(Book_.isbn))); -List matchingBooks = query.getResultList(); - ----- - -Notice that: - -- The link:{doc-javadoc-url}org/hibernate/query/restriction/Restriction.html[`Restriction`] interface has static methods for constructing a variety of different kinds of restriction in a completely typesafe way. -- Similarly, the link:{doc-javadoc-url}org/hibernate/query/Order.html[`Order`] class has a variety of static methods for constructing different kinds of ordering criteria. - -We need the following methods of `SelectionQuery`: - -.Methods for query restriction and ordering -[%breakable,cols="30,~,^15"] -|=== -| Method name | Purpose | JPA-standard - -| `addRestriction()` | Add a restriction on the query results | ✖ -| `setOrder()` | Specify how the query results should be ordered | ✖ -|=== - -Unfortunately, `Restriction` and `Order` can't be used with JPA's `TypedQuery` interface, and JPA has no built-in alternative, so if we're using `EntityManager`, we need to call `unwrap()` to obtain a `SelectionQuery`. - -Alternatively, `Restriction` and `Order` can be used with <>, and even with link:{doc-data-repositories-url}[Jakarta Data repositories]. - -The interface link:{doc-javadoc-url}org/hibernate/query/restriction/Path.html[`Path`] may be used to express restrictions on fields of an embedded or associated entity class. - -[source,java] ----- -List booksForPublisher = - session.createSelectionQuery("from Book", Book.class) - .addRestriction(Path.from(Book.class).to(Book_.publisher).to(Publisher_.name) - .equalTo(publisherName)) - .getResultList(); ----- - -Programmatic restrictions, and especially programmatic ordering, are often used together with pagination. - -[[pagination]] -=== Limits and pagination - -If a query might return more results than we can handle at one time, we may specify: - -- a _limit_ on the maximum number of rows returned, and, -- optionally, an _offset_, the first row of an ordered result set to return. - -[TIP] -==== -The offset is used to paginate query results. -==== - -There's two ways to add a limit or offset to a HQL or native SQL query: - -- using the syntax of the query language itself, for example, `offset 10 rows fetch next 20 rows only`, or -- using the methods `setFirstResult()` and `setMaxResults()` of the `SelectionQuery` interface. - -If the limit or offset is parameterized, the second option is simpler. -For example, this: - -[source,java] ----- -List books = - session.createSelectionQuery("from Book where title like ?1 order by title", Book.class) - .setParameter(1, titlePattern) - .setMaxResults(MAX_RESULTS) - .getResultList(); ----- - -is simpler than: - -[source,java] ----- -// a worse way to do pagination -List books = - session.createSelectionQuery("from Book where title like ?1 order by title fetch first ?2 rows only", Book.class) - .setParameter(1, titlePattern) - .setParameter(2, MAX_RESULTS) - .getResultList(); ----- - -Hibernate's `SelectionQuery` has a slightly different way to paginate the query results: - -[source,java] ----- -List books = - session.createSelectionQuery("from Book where title like ?1 order by title", Book.class) - .setParameter(1, titlePattern) - .setPage(Page.first(MAX_RESULTS)) - .getResultList(); ----- - -The `getResultCount()` method is useful for displaying the number of pages of results: - -[source,java] ----- -SelectionQuery query = - session.createSelectionQuery("from Book where title like ?1 order by title", Book.class) - .setParameter(1, titlePattern); -long results = query.getResultCount(); -long pages = results / MAX_RESULTS + (results % MAX_RESULTS == 0 ? 0 : 1); -List books = query.setMaxResults(MAX_RESULTS).getResultList(); ----- - -.Methods for query limits, pagination, and ordering -[%breakable,cols="30,~,^15"] -|=== -| Method name | Purpose | JPA-standard - -| `setMaxResults()` | Set a limit on the number of results returned by a query | ✔ -| `setFirstResult()` | Set an offset on the results returned by a query | ✔ -| `setPage()` | Set the limit and offset by specifying a `Page` object | ✖ -| `getResultCount()` | Determine how many results the query would return in the absence of any limit or offset | ✖ -|=== - -It's quite common for pagination to be combined with the need to order query results by a field that's determined at runtime. -The `Order` class we just met <> provides the ability to specify that the query results should be ordered by one or more fields of the entity type returned by the query: - -[[query-order-example]] -[source,java] ----- -List books = - session.createSelectionQuery("from Book where title like ?1", Book.class) - .setParameter(1, titlePattern) - .setOrder(List.of(Order.asc(Book_.title), Order.asc(Book_.isbn))) - .setMaxResults(MAX_RESULTS) - .getResultList(); ----- - -The approach to pagination we've just seen is sometimes called _offset-based pagination_. -Since Hibernate 6.5, there's an alternative approach, which offers some advantages, though it's a little more difficult to use. - -[[key-based-pagination]] -=== Key-based pagination - -_Key-based pagination_ aims to reduce the likelihood of missed or duplicate results when data is modified between page requests. -It's most easily illustrated with an example: - -[source,java] ----- -String QUERY = "from Book where publicationDate > :minDate"; - -// obtain the first page of results -KeyedResultList first = - session.createSelectionQuery(QUERY, Book.class) - .setParameter("minDate", minDate) - .getKeyedResultList(Page.first(25) - .keyedBy(Order.asc(Book_.isbn))); -List firstPage = first.getResultList(); -... - -if (!firstPage.isLastPage()) { - // obtain the second page of results - KeyedResultList second = - session.createSelectionQuery(QUERY, Book.class) - .setParameter("minDate", minDate)) - .getKeyedResultList(firstPage.getNextPage()); - List secondPage = second.getResultList(); - ... -} ----- - -The "key" in key-based pagination refers to a unique key of the result set which determines a total order on the query results. -In this example, `Book.isbn` is the key. - -Since this code is a little bit fiddly, key-based pagination works best with <>. - -[[projection-lists]] -=== Representing projection lists - -A _projection list_ is the list of things that a query returns, that is, the list of expressions in the `select` clause. -Since Java has no tuple types, representing query projection lists in Java has always been a problem for JPA and Hibernate. -Traditionally, we've just used `Object[]` most of the time: - -[source,java] ----- -var results = - session.createSelectionQuery("select isbn, title from Book", Object[].class) - .getResultList(); - -for (var result : results) { - var isbn = (String) result[0]; - var title = (String) result[1]; - ... -} ----- - -This is really a bit ugly. -Java's `record` types now offer an interesting alternative: - -[source,java] ----- -record IsbnTitle(String isbn, String title) {} - -var results = - session.createSelectionQuery("select isbn, title from Book", IsbnTitle.class) - .getResultList(); - -for (var result : results) { - var isbn = result.isbn(); - var title = result.title(); +@Entity +class Order { ... -} ----- -Notice that we're able to declare the `record` right before the line which executes the query. - -Now, this is only _superficially_ more typesafe, since the query itself is not checked statically, and so we can't say it's objectively better. -But perhaps you find it more aesthetically pleasing. -And if we're going to be passing query results around the system, the use of a `record` type is _much_ better. + transient double total; -The criteria query API offers a much more satisfying solution to the problem. -Consider the following code: + @PostLoad + void computeTotal() { + total = items.stream().mapToDouble(i -> i.price * i.quantity).sum(); + } -[source,java] ----- -var builder = sessionFactory.getCriteriaBuilder(); -var query = builder.createTupleQuery(); -var book = query.from(Book.class); -var bookTitle = book.get(Book_.title); -var bookIsbn = book.get(Book_.isbn); -var bookPrice = book.get(Book_.price); -query.select(builder.tuple(bookTitle, bookIsbn, bookPrice)); -var resultList = session.createSelectionQuery(query).getResultList(); -for (var result : resultList) { - String title = result.get(bookTitle); - String isbn = result.get(bookIsbn); - BigDecimal price = result.get(bookPrice); ... } ---- -This code is manifestly completely typesafe, and much better than we can hope to do with HQL. - -[[named-queries]] -=== Named queries - -The `@NamedQuery` annotation lets us define a HQL query that is compiled and checked as part of the bootstrap process. -This means we find out about errors in our queries earlier, instead of waiting until the query is actually executed. -We can place the `@NamedQuery` annotation on any class, even on an entity class. +If we need to interact with technical objects, we can place the lifecycle callback on a separate class, called an _entity listener_. +The `@EntityListeners` annotation specifies the listeners for a given entity class: [source,java] ---- -@NamedQuery(name = "10BooksByTitle", - query = "from Book where title like :titlePattern order by title fetch first 10 rows only") -class BookQueries {} +@Entity +@EntityListeners(OrderEvents.class) +class Order { ... } ---- -We have to make sure that the class with the `@NamedQuery` annotation will be scanned by Hibernate, either: - -- by adding `org.hibernate.example.BookQueries` to `persistence.xml`, or -- by calling `configuration.addClass(BookQueries.class)`. +An entity listener may inject CDI beans: -[TIP] -==== -Unfortunately, JPA's `@NamedQuery` annotation can't be placed on a package descriptor. -Therefore, Hibernate provides a very similar annotation, `@org.hibernate.annotations.NamedQuery` which _can_ be specified at the package level. -If we declare a named query at the package level, we must call: [source,java] ---- -configuration.addPackage("org.hibernate.example") ----- -so that Hibernate knows where to find it. -==== - -The `@NamedNativeQuery` annotation lets us do the same for native SQL queries. -There's much less advantage to using `@NamedNativeQuery`, because there is very little that Hibernate can do to validate the correctness of a query written in the native SQL dialect of your database. - -.Executing named queries -[%breakable,cols="10,36,32,22"] -|=== -| Kind | `Session` method | `EntityManager` method | `Query` execution method - -| Selection | `createNamedSelectionQuery(String,Class)` | `createNamedQuery(TypedQueryReference)`, `createNamedQuery(String,Class)` | `getResultList()`, `getSingleResult()`, `getSingleResultOrNull()` -| Mutation | `createNamedMutationQuery(String)` | `createNamedQuery(TypedQueryReference)`, `createNamedQuery(String)` | `executeUpdate()` -|=== - -We execute our named query like this: +// entity listener class +class OrderEvents { + @Inject + Event newOrderEvent; -[source,java] ----- -List books = - entityManager.createQuery(BookQueries_._10BooksByTitle_) - .setParameter("titlePattern", titlePattern) - .getResultList() + @PostPersist + void newOrder(Order order) { + // send a CDI event + newOrderEvent.fire(new NewOrder(order)); + } +} ---- - -Here, `BookQueries_.\_10BooksByTitle_` is an element of the JPA static metamodel of type `TypedQueryReference`, generated by Hibernate Processor. - -Note that the code which executes the named query is not aware of whether the query was written in HQL or in native SQL, making it slightly easier to change and optimize the query later. +A single entity listener class may even be a generic listener that receives lifecycle callbacks for multiple different entity classes. [TIP] -==== -:query-validator: https://github.com/hibernate/query-validator/ +The venerable link:{doc-javadoc-url}org/hibernate/Interceptor.html[`Interceptor`] interface is a more powerful alternative to entity listeners. +`Interceptor` and its friend link:{doc-javadoc-url}org/hibernate/CustomEntityDirtinessStrategy.html[`CustomEntityDirtinessStrategy`] allow advanced users to augment the built-in handling of managed entities with custom behavior. +These interfaces are very useful if you're building your own persistence framework with Hibernate as the foundation. -It's nice to have our queries checked at startup time. -It's even better to have them checked at compile time. -In <>, we mentioned that the Hibernate Processor can do that for us, with the help of the `@CheckHQL` annotation, and we presented that as a reason to use `@NamedQuery`. +We're about to see one way `Interceptor` can be used. -But actually, Hibernate has a separate <> capable of performing compile-time validation of HQL query strings that occur as arguments to `createQuery()` and friends. -If we use the Query Validator, there's not much advantage to the use of named queries. -==== +[[transient-vs-detached]] +=== Transient vs detached -[[load-access]] -=== Controlling lookup by id +Sometimes, Hibernate needs to be able to distinguish whether an entity instance is: -We can do almost anything via HQL, criteria, or native SQL queries. -But when we already know the identifier of the entity we need, a query can feel like overkill. -And queries don't make efficient use of the <>. +- a brand-new transient object the client just instantiated using `new`, or +- a detached object, which previously belonged to a persistence context. -We met the `find()` and `findMultiple()` methods <>. -These are the most basic ways to perform a _lookup_ by id. -But they can't quite do everything. -Therefore, Hibernate has some APIs that streamline certain more complicated lookups: +This is a bit of a problem, since there's no good and efficient way for Hibernate to just tag an entity with a Post-it saying "I've seen you before". -.Operations for lookup by id -[%breakable,cols="30,~"] -|=== -| Method name | Purpose +Therefore, Hibernate uses heuristics. +The two most useful heuristics are: -| `byId()` | Lets us specify association fetching via an `EntityGraph`, as we saw; also lets us specify some additional options, including how the lookup <>, and whether the entity should be loaded in read-only mode -| `byMultipleIds()` | Lets us load a _batch_ of ids at the same time -|=== +1. If the entity has a <>, the value of the id field is inspected: if the value currently assigned to the id field is the default value for the type of the field, then the object is transient; otherwise, the object is detached. +2. If the entity has a <>, the value of the version field is inspected: if the value currently assigned to the version field is the default value, or a negative number, then the object is transient; otherwise, the object is detached. -[NOTE] -==== -Since the introduction of `FindOption` in JPA 3.2, `byId()` is now much less useful. -==== +If the entity has neither a generated id, nor a version, Hibernate usually falls back to just doing something reasonable. +In extreme cases a `SELECT` query will be issued to determine whether a matching row exists in the database. -Batch loading is very useful when we need to retrieve multiple instances of the same entity class by id: - -[source,java] ----- -var graph = session.createEntityGraph(Book.class); -graph.addSubgraph(Book_.publisher); - -List books = - session.byMultipleIds(Book.class) - .withFetchGraph(graph) // control association fetching - .withBatchSize(20) // specify an explicit batch size - .with(CacheMode.GET) // control interaction with the cache - .multiLoad(bookIds); ----- - -The given list of `bookIds` will be broken into batches, and each batch will be fetched from the database in a single `select`. -If we don't specify the batch size explicitly, a batch size will be chosen automatically. - -We also have some operations for working with lookups by <>: - -[%breakable,cols="30,~"] -|=== -| Method name | Purpose - -| `bySimpleNaturalId()` | For an entity with just one attribute is annotated `@NaturalId` -| `byNaturalId()` | For an entity with multiple attributes are annotated `@NaturalId` -| `byMultipleNaturalId()` | Lets us load a _batch_ of natural ids at the same time -|=== - -Here's how we can retrieve an entity by its composite natural id: +[WARNING] +These heuristics aren't perfect. +It's quite easy to confuse Hibernate by assigning a value to the id field or version field, making a new transient instance look like it's detached. +We therefore strongly discourage assigning values to fields annotated `@GeneratedValue` or `@Version` before passing an entity to Hibernate. -[source,java] ----- -Book book = - session.byNaturalId(Book.class) - .using(Book_.isbn, isbn) - .using(Book_.printing, printing) - .load(); ----- +If the heuristics ever happen cause a real problem, you may implement your own Post-it tagging via link:{doc-javadoc-url}org/hibernate/Interceptor.html#isTransient(java.lang.Object)[`Interceptor.isTransient()`]. -Notice that this code fragment is completely typesafe, again thanks to <>. [[jdbc]] === Interacting directly with JDBC @@ -1468,57 +881,6 @@ The `Connection` passed to the work is the same connection being used by the ses In a container environment where transactions and database connections are managed by the container, this might not be the easiest way to obtain the JDBC connection. ==== -[[callbacks]] -=== Lifecycle callbacks and entity listeners - -The annotations `@PrePersist`, `@PreRemove`, `@PreUpdate`, `@PostPersist`, `@PostRemove`, `@PostUpdate`, and `@PostLoad` allow an entity to respond to persistence lifecycle operations and maintain its transient internal state. -For example: - -[source,java] ----- -@Entity -class Order { - ... - transient double total; - - @PostLoad - void computeTotal() { - total = items.stream().mapToDouble(i -> i.price * i.quantity).sum(); - } - - ... -} ----- - -If we need to interact with technical objects, we can place the lifecycle callback on a separate class, called an _entity listener_. -The `@EntityListeners` annotation specifies the listeners for a given entity class: - -[source,java] ----- -@Entity -@EntityListeners(OrderEvents.class) -class Order { ... } ----- - -An entity listener may inject CDI beans: - -[source,java] ----- -// entity listener class -class OrderEvents { - @Inject - Event newOrderEvent; - - @PostPersist - void newOrder(Order order) { - // send a CDI event - newOrderEvent.fire(new NewOrder(order)); - } -} ----- -A single entity listener class may even be a generic listener that receives lifecycle callbacks for multiple different entity classes. - - [[advice]] === What to do when things go wrong @@ -1542,7 +904,7 @@ In this section we'll quickly sketch some general strategies for avoiding "quagm Even when everything seems to be "working", there might be a lurking <>. - Be careful when <>. In principle, you should update _both ends_ of the association. - But Hibernate doesn't strictly enforce that, since there are some situations where such a rule would be too heavy-handed. + But Hibernate doesn't strictly enforce that, since there are situations where such a rule would be too heavy-handed. Whatever the case, it's up to you to maintain consistency across your model. - Never <> across threads or concurrent transactions. Have a strategy or framework to guarantee this never happens. @@ -1558,11 +920,13 @@ In this section we'll quickly sketch some general strategies for avoiding "quagm Isolate the problem. Find the absolute minimum test case which reproduces the behavior, _before_ asking for help online. Most of the time, the mere act of isolating the problem will suggest an obvious solution. -- Avoid frameworks and libraries that "wrap" JPA. +- If you're new to Hibernate, avoid frameworks and libraries that "wrap" JPA. + You need an excellent understanding of Hibernate and JPA _first_, before introducing unnecessary additional moving parts. If there's any one criticism of Hibernate and ORM that sometimes _does_ ring true, it's that it takes you too far from direct control over JDBC. An additional layer just takes you even further. + If you insist you really do need this extra layer, we beg you to consider https://hibernate.org/repositories/[Hibernate Data Repositories] instead of older third-party solutions. - Avoid copy/pasting code from random bloggers or stackoverflow reply guys. - Many of the suggestions you'll find online just aren't the simplest solution, and many aren't correct for Hibernate 6. + Many of the suggestions you'll find online just aren't the simplest solution, and many aren't correct for Hibernate 6 and 7. Instead, _understand_ what you're doing; study the Javadoc of the APIs you're using; read the JPA specification; follow the advice we give in this document; go direct to the Hibernate team on Zulip. (Sure, we can be a bit cantankerous at times, but we _do_ always want you to be successful.) - Always consider other options. diff --git a/documentation/src/main/asciidoc/introduction/Introduction.adoc b/documentation/src/main/asciidoc/introduction/Introduction.adoc index 220bc62be97d..f317c6886bdb 100644 --- a/documentation/src/main/asciidoc/introduction/Introduction.adoc +++ b/documentation/src/main/asciidoc/introduction/Introduction.adoc @@ -1,6 +1,10 @@ [[introduction]] == Introduction +:persistence: https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2 +:data: https://jakarta.ee/specifications/data/1.0/jakarta-data-1.0 + + Hibernate is usually described as a library that makes it easy to map Java classes to relational database tables. But this formulation does no justice to the central role played by the relational data itself. So a better description might be: @@ -30,12 +34,27 @@ But if Hibernate is making things more difficult, for some particularly tricky p Just because you're using Hibernate for persistence doesn't mean you have to use it for _everything_. ==== +Let's underline the important point here: the goal of ORM is _not_ to hide SQL or the relational model. +After all, Hibernate's query language is link:{doc-query-language-url}[nothing more than an object-oriented dialect of ANSI SQL]. + +.Is Hibernate a "leaky abstraction"? +**** +Hibernate--and ORM in general--has been accused of being a _leaky abstraction_, that is, of failing to completely hide the underlying relational database. +Is this true? +Well, as you can guess from what we've already said, the short answer is: yes, _and that's a good thing._ +Of course, whether you consider an abstraction "leaky" depends on what you think it's trying to abstract. +Hibernate successfully abstracts many things: variations between dialects of SQL, messy interactions with JDBC, SQL object naming conventions, and so on. +But it doesn't even attempt to pretend there's anything other than a relational data model underlying all this. +The simple reason is performance. It's just not possible to <> in data access without acknowledging the nature of the underlying persistent representation. +We're old enough to have seen multiple generations of developer relearn this lesson by experience. +**** + Developers often ask about the relationship between Hibernate and JPA, so let's take a short detour into some history. [[hibernate-and-jpa]] === Hibernate and JPA -Hibernate was the inspiration behind the _Java_ (now _Jakarta_) _Persistence API_, or JPA, and includes a complete implementation of the latest revision of this specification. +Hibernate was the inspiration behind the _Java_ (now _Jakarta_) _Persistence API_, or JPA, and includes a complete implementation of the latest revision of link:{persistence}[this specification]. .The early history of Hibernate and JPA **** @@ -116,28 +135,6 @@ Take your time with this code, and try to produce a Java model that's as close a When in the slightest doubt, map a foreign key relationship using `@ManyToOne` with `@OneToMany(mappedBy=...)` in preference to more complicated association mappings. ==== -.What sort of logic belongs in an entity? -**** -There exists an extensive online literature which posits that there are _rich domain models_, where entities have methods implementing interesting business logic, and _anemic domain models_, where the entities are pure data holders, and that a developer should hold an opinion that one or the other of these sorts of domain model is "better". - -We do not hold any such opinion, and if you ask us for one, we will most likely suddenly discover somewhere else we need to be. - -A more interesting question is not _how much_ logic belongs in the entity class, but _what sort_ of logic belongs there. -We think the answer is that an entity should never implement technical concerns, and should never obtain references to framework objects. -Nor should it hold extra mutable state which is not very directly related to its role in representing persistent state. -For example: - -- an entity may compute totals and averages, even caching them if necessary, enforce its invariants, interact with and construct other entities, and so on, -- but the entity should never call the `EntityManager` or a Jakarta Data repository, build a criteria query, send a JMS message, start a transaction, publish events to the CDI event bus, maintain a stateful queue of events to be published later, or anything of a similar nature. - -One way to summarize this is: - -> Entities do business logic; but they don't do orchestration. - -Later, we'll discuss various ways to <>, <>, and <>. -Such code will always be external to the entity itself. -**** - The second part of the code is much trickier to get right. This code must: - manage transactions and sessions, @@ -158,14 +155,13 @@ Responsibility for transaction and session management, and for recovery from cer // ==== We're going to <> to the thorny question of how this persistence logic should be organized, and how it should fit into the rest of the system. -// First we want to make the ideas above concrete by seeing a simple example program that uses Hibernate in isolation. [[hello-hibernate]] === Hello, Hibernate Before we get deeper into the weeds, we'll quickly present a basic example program that will help you get started if you don't already have Hibernate integrated into your project. -We begin with a simple gradle build file: +We begin with a simple https://gradle.org[Gradle] build file: [[build-gradle]] [source,groovy,subs="attributes+"] @@ -190,8 +186,8 @@ dependencies { annotationProcessor 'org.hibernate.orm:hibernate-processor:{fullVersion}' // Hibernate Validator - implementation 'org.hibernate.validator:hibernate-validator:8.0.1.Final' - implementation 'org.glassfish:jakarta.el:4.0.2' + implementation 'org.hibernate.validator:hibernate-validator:9.0.0.Final' + implementation 'org.glassfish.expressly:expressly:6.0.0' // Agroal connection pool runtimeOnly 'org.hibernate.orm:hibernate-agroal:{fullVersion}' @@ -207,7 +203,7 @@ dependencies { Only the first of these dependencies is absolutely _required_ to run Hibernate. -Next, we'll add a logging configuration file for log4j: +Next, we'll add a logging configuration file for https://logging.apache.org/log4j/[log4j]: [source,properties] .`log4j2.properties` @@ -216,9 +212,20 @@ rootLogger.level = info rootLogger.appenderRefs = console rootLogger.appenderRef.console.ref = console +# SQL statements (set level=debug to enable) logger.hibernate.name = org.hibernate.SQL logger.hibernate.level = info - +# JDBC parameter binding (set level=trace to enable) +logger.jdbc-bind.name=org.hibernate.orm.jdbc.bind +logger.jdbc-bind.level=info +# JDBC result set extraction (set level=trace to enable) +logger.jdbc-extract.name=org.hibernate.orm.jdbc.extract +logger.jdbc-extract.level=info +# JDBC batching (set level=trace to enable) +logger.batch.name=org.hibernate.orm.jdbc.batch +logger.batch.level=info + +# direct log output to the console appender.console.name = console appender.console.type = Console appender.console.layout.type = PatternLayout @@ -226,7 +233,7 @@ appender.console.layout.pattern = %highlight{[%p]} %m%n ---- Now we need some Java code. -We begin with our _entity class_: +We begin with our <>: [[book]] [source,java] @@ -255,9 +262,9 @@ class Book { } ---- -Finally, let's see code which configures and instantiates Hibernate and asks it to persist and query the entity. +Finally, let's see code which <> and instantiates Hibernate and asks it to <> the entity. Don't worry if this makes no sense at all right now. -It's the job of this Introduction to make all this crystal clear. +It's the job of the rest of this Short Guide to make all this crystal clear. [[main-hibernate]] [source,java] @@ -431,6 +438,106 @@ So now let's talk about how to organize persistence logic in a real system. The rest of this chapter is not compulsory. If you're itching for more details about Hibernate itself, you're quite welcome to skip straight to the <>, and come back later. +[[domain-model]] +=== Entities + +A class in the domain model which directly represents a relational database table is called an <>. +Entity classes are central to object persistence and to object/relational mapping. +They're also, typically, central players in the business logic of our application program. +Entities represent the _things_ in our business domain. +This makes them very important objects indeed! + +Given how much weight an entity already bears due to its very nature, we need to think carefully before weighing it down with too many additional responsibilities. + +[[entity-logic]] +.What sort of logic belongs in an entity? +**** +There exists an extensive online literature which posits that there are _rich domain models_, where entities have methods implementing interesting business logic, and _anemic domain models_, where the entities are pure data holders, and that a developer should hold an opinion that one or the other of these sorts of domain model is "better". + +We do not hold any such opinion, and if you ask us for one, we will most likely suddenly discover somewhere else we need to be. + +A more interesting question is not _how much_ logic belongs in the entity class, but _what sort_ of logic belongs there. +We think the answer is that an entity should never implement technical concerns, and should never obtain references to framework objects. +Nor should it hold extra mutable state which is not very directly related to its role in representing persistent state. +For example: + +- an entity may compute totals and averages, even caching them if necessary, enforce its invariants, interact with and construct other entities, and so on, and its annotations express how it maps to database tables, +- but the entity should not call the `EntityManager` or a Jakarta Data repository, build a criteria query, send a JMS message, start a transaction, publish events to the CDI event bus, maintain a stateful queue of events to be published later, or anything of a similar nature. + +One way to summarize this is: + +> Entities do business logic; but they don't do orchestration. + +Later, we'll discuss various ways to <>, <>, and <>. +Such code will always be external to the entity itself. +**** + +In keeping with our commitment to anti-dogmatism, we would like to add the following important caveat to the discussion in the previous callout. + +[[active-record]] +.Active Record +**** +The discussion <> expresses our "traditional" approach--which lay behind the design of Hibernate, of JPA, and of Jakarta Data--where entity classes are plain Java objects without dependence on framework code. +An alternative approach is the Active Record pattern, as exemplified by link:https://quarkus.io/guides/hibernate-orm-panache[Panache]. +In Active Record, entity types inherit framework objects, and persistence operations are located directly on the entities. +You can think of this as merging the roles of entity and DAO/Repository into a single object. + +Active Record comes with both upsides and downsides, but we don't mean to exclude it from consideration. +We must therefore slightly modify the prescription we've given above: in an Active Record, it's obviously OK to access the `EntityManager` and perform other persistence-related operations, and we therefore expect our Active Record class to look somewhat more "technical" than a trad entity. + +But the basic principle remains intact: an entity does not do orchestration, it does not manage transactions, it does not obtain references to _other_ sorts of framework object, and it does not hold mutable state unrelated to its persistent state. +**** + +For now, we're going to assume that entities are implemented as plain Java classes. + +[[stateful-and-stateless-sessions]] +=== Stateful and stateless sessions + +It should be very clear from the example code <>, that the session is also a very important object. +It exposes basic operations like `persist()` and `createQuery()`, and so it's our first port of call when we want to <> via Hibernate. +In the code we just saw, we've used a _stateful session_. + +Later, we'll learn about the idea of a <>. +Oversimplifying for now, you can think of it as a cache of data which has been read in the current transaction. +Thus, in the architecture of Hibernate, it's sometimes called the _first-level cache_. +Each stateful session -- that is, every Hibernate `Session`, and every JPA <> -- has its own persistence context. + +But stateful sessions have never been the only possibility. +The <> interface offers a way to interact with Hibernate _without_ going through a persistence context. +However, the programming model is somewhat different. + +.Stateless sessions +**** +Among our biggest regrets is that we didn't give enough love to `StatelessSession` twenty years ago. +Sure, a stateful session is in some sense more powerful, or at least more magical. +But with that magic comes a loss of direct control over persistence operations, and some traps for inexperienced users. +A significant minority of developers find working with a persistence context frustrating, and they would surely be better served by a stateless session. + +- We used to view `StatelessSession` as an API directed toward very specific usage patterns, in particular, batch processing of large numbers of entities. +As a result, we left out certain functionality -- for example, use of the <> -- which didn't seem relevant to those use cases. +This left `StatelessSession` lacking feature parity with `Session`, and it was a mistake. +In Hibernate 7, we've fixed this mistake. +A `StatelessSession` now offers essentially all the functionality of Hibernate except, naturally, the first-level cache. + +- Compounding our error, we left `StatelessSession` out of JPA. +This meant that a large number of Hibernate users _didn't even realize this option existed._ +We promise to make sure there are stateless sessions in Jakarta Persistence 4. + +So, finally, let us state for the record: we messed up here. +Hibernate is all about _object/relational mapping;_ persistence contexts are something extra on top. +You don't have to use stateful sessions, and you're not doing anything wrong if you decide to use stateless sessions instead. +**** + +As of Hibernate 7, a key decision for any new project is which of these programming models to take as a baseline. +Fortunately, the two models aren't mutually exclusive. +This is a friendly competition, where the two APIs are designed to complement each other. +Even if we decide to use stateful ``Session``s most of the time, we can still use a `StatelessSession` wherever it's more convenient. + +NOTE: On the other hand, if you decide to adopt Jakarta Data, the decision is made for you: repositories in Jakarta Data 1.0 are always stateless, and in https://hibernate.org/repositories/[Hibernate Data Repositories] a repository is backed by a `StatelessSession`. + +But now we've got just a little bit ahead of ourselves. +In the next section taking we're taking a journey which _might_ -- but definitely doesn't _necessarily_ -- end at the idea of a "repository". + [[organizing-persistence]] === Organizing persistence logic @@ -669,7 +776,7 @@ Alternatively, if CDI isn't available, we may directly instantiate the generated [TIP] ==== -The Jakarta Data specification now formalizes this approach using standard annotations, and our implementation of this specification, Hibernate Data Repositories, is built into <>. +The link:{data}[Jakarta Data specification] now formalizes this approach using standard annotations, and our implementation of this specification, Hibernate Data Repositories, is built into <>. You probably already have it available in your program. Unlike other repository frameworks, Hibernate Data Repositories offers something that plain JPA simply doesn’t have: full compile-time type safety for your queries. To learn more, please refer to link:{doc-data-repositories-url}[Introducing Hibernate Data Repositories]. @@ -681,7 +788,7 @@ At the time we wrote _An Introduction to Hibernate 6_, we were especially frustr In our considered opinion, such frameworks typically made JPA harder to use, sometimes misleading users into misuse of the technology. The birth of the Jakarta Data specification has obsoleted our arguments against repositories, along with the older frameworks which were the source of our frustration. -Jakarta Data--as realized by Hibernate Data Repositories--offers a clean but very flexible way to organize code, along with much better compile-time type safety, without getting in the way of direct use of the `StatelessSession`. +Jakarta Data--as realized by Hibernate Data Repositories--offers a clean but very flexible way to organize code, along with much better compile-time type safety, without getting in the way of direct use of the <>. **** Now that we have a rough picture of what our persistence logic might look like, it's natural to ask how we should test our code. diff --git a/documentation/src/main/asciidoc/introduction/Mapping.adoc b/documentation/src/main/asciidoc/introduction/Mapping.adoc index cad2cc0c61d4..c638dd0e049b 100644 --- a/documentation/src/main/asciidoc/introduction/Mapping.adoc +++ b/documentation/src/main/asciidoc/introduction/Mapping.adoc @@ -470,6 +470,7 @@ Note that the `foreignKey` member is completely optional and only affects DDL ge If you don't supply an explicit name using `@ForeignKey`, Hibernate will generate a quite ugly name. The reason for this is that the maximum length of foreign key names on some databases is extremely constrained, and we need to avoid collisions. To be fair, this is perfectly fine if you're only using the generated DDL for testing. +You can customize the generated constraint names by writing your own <>. ==== For composite foreign keys we might have multiple `@JoinColumn` annotations: diff --git a/documentation/src/main/asciidoc/introduction/Preface.adoc b/documentation/src/main/asciidoc/introduction/Preface.adoc index 18733ed83e16..b10cd7287555 100644 --- a/documentation/src/main/asciidoc/introduction/Preface.adoc +++ b/documentation/src/main/asciidoc/introduction/Preface.adoc @@ -1,19 +1,21 @@ [[preface]] == Preface +:persistence: https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2 +:data: https://jakarta.ee/specifications/data/1.0/jakarta-data-1.0 + Hibernate 6 was a major redesign of the world's most popular and feature-rich ORM solution. The redesign touched almost every subsystem of Hibernate, including the APIs, mapping annotations, and the query language. This new Hibernate was suddenly more powerful, more robust, more portable, and more type safe. -Hibernate 7 builds on this foundation, adds support for JPA 3.2, and introduces Hibernate Data Repositories, an implementation of the Jakarta Data specification. +Hibernate 7 builds on this foundation, adds support for link:{persistence}[JPA 3.2], and introduces https://hibernate.org/repositories/[Hibernate Data Repositories], an implementation of the link:{data}[Jakarta Data specification]. Taken together, these enhancements yield a level of compile-time type safety--and resulting developer productivity--which was previously impossible. Hibernate Data Repositories offers truly seamless integration of the ORM solution with the persistence layer, obsoleting older add-on repository frameworks. -Hibernate and Hibernate Reactive are core components of Quarkus 3, the most exciting new environment for cloud-native development in Java, and Hibernate remains the persistence solution of choice for almost every major Java framework or server. +Hibernate ORM and https://hibernate.org/reactive/[Hibernate Reactive] are core components of https://quarkus.io[Quarkus 3], the most exciting new environment for cloud-native development in Java, and Hibernate remains the persistence solution of choice for almost every major Java framework or server. Unfortunately, the changes in Hibernate 6 also obsoleted much of the information about Hibernate that's available in books, in blog posts, and on stackoverflow. - This guide is an up-to-date, high-level discussion of the current feature set and recommended usage. It does not attempt to cover every feature and should be used in conjunction with other documentation: diff --git a/documentation/src/main/asciidoc/introduction/Processor.adoc b/documentation/src/main/asciidoc/introduction/Processor.adoc index 21f85a465a4f..0c50487a29bb 100644 --- a/documentation/src/main/asciidoc/introduction/Processor.adoc +++ b/documentation/src/main/asciidoc/introduction/Processor.adoc @@ -5,14 +5,22 @@ The _static metamodel generator_ is a standard part of JPA. // It's an annotation processor that produces a statically-typed metamodel of the entity classes in a Java program. We've actually already seen its handiwork in the code examples <>: it's the author of the class `Book_`, which contains the static metamodel of the <> `Book`. +Hibernate comes with an annotation processor which does much more than just this. +It's capable of automatically generating: + +- <> classes, as we've already seen, +- link:{doc-data-repositories-url}#data-static-metamodel[Jakarta Data metamodel] classes, +- static <> and <>, and +- implementations of <>, including link:{doc-data-repositories-url}#repository-interfaces[Jakarta Data repositories]. + [[metamodel-generator]] .Hibernate Processor **** -:generator: https://hibernate.org/orm/tooling/ +:generator: https://hibernate.org/orm/processor/ :generator-guide: {doc-user-guide-url}#tooling-modelgen -{generator}[Hibernate Processor], the annotation processor formerly known as the Metamodel Generator, began its life as a code generator for what JPA calls a _static metamodel_. +{generator}[Hibernate Processor], the annotation processor formerly known as the Metamodel Generator, began its life as a code generator for what JPA calls a https://jakarta.ee/specifications/persistence/3.2/jakarta-persistence-spec-3.2#a6072[_static metamodel_]. That is, it produces a typed model of the persistent classes in our program, giving us a type safe way to refer to their attributes in Java code. In particular, it lets us specify <> and <> in a completely type-safe way. @@ -31,7 +39,7 @@ The static metamodel itself is undeniably useful and elegant. And it turns out that there was quite a lot of unlocked potential there. Since Hibernate 6.3 the Processor has started taking on a much bigger role. -Today, it even contains a complete implementation of the Jakarta Data specification. +Today, it even contains a link:{doc-data-repositories-url}[complete implementation of the Jakarta Data specification]. Now, you still don't have to use the Hibernate Processor with Hibernate—the APIs we just mentioned still also accept plain strings—but we find that it works well with Gradle and integrates smoothly with our IDE, and the advantage in type-safety is compelling. **** @@ -42,6 +50,17 @@ We've already seen how to set up the annotation processor in the <>, +- eager fetching via an <>, +- dynamic <>, and +- references to named <> and named entity graphs. + Here's an example of the sort of code that's generated for an entity class, as mandated by the JPA specification: [source,java] @@ -169,17 +188,10 @@ Actually, Hibernate Processor doesn't require that such annotations be applied t We've already been using metamodel references like `Book_.authors` and `Book.AUTHORS` in the previous chapters. So now let's see what else Hibernate Processor can do for us. -[NOTE] -==== -The functionality we're about to describe was developed before Jakarta Data took on its current shape, and directly triggered the apocalypse which lead to the final form of the specification. -Therefore, there's massive overlap between the functionality described in this chapter, and the functionality available via the Jakarta Data annotations. -On the other hand, Jakarta Data can't do _everything_ described below, and in particular it doesn't yet come with built-in support for stateful persistence contexts or reactive sessions. - -We've therefore opted _not_ to rewrite this chapter in a Jakarta Data-centric way, and instead refer you to link:{doc-data-repositories-url}[Introducing Hibernate Data Repositories]. -==== +[[finders-queries-repositories]] +=== Finder methods, query methods, and repositories -Automatic generation of _finder methods_ and _query methods_ is a relatively new feature of Hibernate Processor, and an extension to the functionality defined by the JPA specification. -In this chapter, we're going to explore these features. +Automatic generation of _finder methods_ and _query methods_ is a relatively new feature of Hibernate Processor--originally introduced as an experiment--which ultimately grew into a whole new way to use Hibernate. We're going to meet three different kinds of generated method: @@ -192,7 +204,25 @@ We're also going to see two ways that these methods can be called: - as static methods of a generated abstract class, or - as <> with a generated implementation which may even be <>. -To whet our appetites, let's see how this works for a `@NamedQuery`. +Back in <>, we walked you through a few different ways to organize your code with the help of Hibernate Processor. +That journey terminated at the idea of a repository, but we emphasized that you aren't required to stay all the way to the end of the line. +Repositories are a sweet spot for many users, but they might not be your sweet spot, and that's OK. +Hibernate Processor is perfectly happy to generate `static` implementations of `@HQL`, `@SQL`, and `@Find` methods, eliminating the need to inject or instantiate a repository object. + +.Hibernate Processor and Jakarta Data +**** +// For many years we've followed a three-step process: implement, learn from experience, and then standardize. +// +The functionality we're about to describe was developed before Jakarta Data took on its current shape, and directly triggered the apocalypse which lead to the final form of the specification. +Therefore, there's massive overlap between the functionality described in this chapter, and the functionality available via the Jakarta Data annotations. +On the other hand, Jakarta Data can't do _everything_ described below, and in particular it doesn't yet come with built-in support for stateful persistence contexts or reactive sessions. +// We are currently working hard to standardize these capabilities, but writing great specifications takes time. + +We've therefore opted _not_ to rewrite this chapter in a Jakarta Data-centric way, and instead refer you to link:{doc-data-repositories-url}[Introducing Hibernate Data Repositories] for information about the standard Jakarta Data APIs. + +As Jakarta Data matures, even more of this functionality might be made obsolete, at least in the form described here. +We're working hard to make that happen. +**** [CAUTION] ==== @@ -201,6 +231,8 @@ Hibernate Processor is not currently able to generate finder methods and query m (On the other hand, the <> may be specified in XML, since they're not needed by the Processor.) ==== +To whet our appetites, let's see how it works for a `@NamedQuery`. + [[generated-named-queries]] === Named queries and Hibernate Processor @@ -304,7 +336,7 @@ Hibernate Processor defaults to using `EntityManager` as the session type, but o - `Session`, - `StatelessSession`, or -- `Mutiny.Session` from Hibernate Reactive. +- `Mutiny.Session` or `Mutiny.StatelessSession` from Hibernate Reactive. The real value of all this is in the checks which can now be done at compile time. Hibernate Processor verifies that the parameters of our abstract method declaration match the parameters of the HQL query, for example: diff --git a/documentation/src/main/asciidoc/introduction/Querying.adoc b/documentation/src/main/asciidoc/introduction/Querying.adoc new file mode 100644 index 000000000000..5ca2eddc2b45 --- /dev/null +++ b/documentation/src/main/asciidoc/introduction/Querying.adoc @@ -0,0 +1,818 @@ +[[queries]] +== Executing queries + +:hql: {doc-user-guide-url}#query-language + +Hibernate features three complementary ways to write queries: + +- the _Hibernate Query Language_, an extremely powerful superset of JPQL, which abstracts most of the features of modern dialects of SQL, +- the JPA _criteria query_ API, along with extensions, allowing almost any HQL query to be constructed programmatically via a typesafe API, and, of course +- for when all else fails, _native SQL_ queries. + +In addition, Hibernate 7 provides a convenient new way to <> a query before executing it. + +[[hql-queries]] +=== HQL queries + +:hql: {doc-user-guide-url}#query-language + +A full discussion of the query language would require almost as much text as the rest of this Short Guide. +Fortunately, HQL is already described in exhaustive (and exhausting) detail in {doc-query-language-url}[_A Guide to Hibernate Query Language_]. +It doesn't make sense to repeat that information here. +// The query language is discussed in great detail below in <>. + +Here we want to see how to execute a query via the `Session` or `EntityManager` API. +The method we call depends on what kind of query it is: + +- _selection queries_ return a result list, but do not modify the data, but +- _mutation queries_ modify data, and return the number of modified rows. + +Selection queries usually start with the keyword `select` or `from`, whereas mutation queries begin with the keyword `insert`, `update`, or `delete`. + +.Executing HQL +[%breakable,cols="10,36,32,22"] +|=== +| Kind | `Session` method | `EntityManager` method | `Query` execution method + +| Selection | link:{doc-javadoc-url}org/hibernate/query/QueryProducer.html#createSelectionQuery(java.lang.String,java.lang.Class)[`createSelectionQuery(String,Class)`] | `createQuery(String,Class)` | `getResultList()`, `getSingleResult()`, or `getSingleResultOrNull()` +| Mutation | link:{doc-javadoc-url}org/hibernate/query/QueryProducer.html#createMutationQuery(java.lang.String)[`createMutationQuery(String)`] | `createQuery(String)` | `executeUpdate()` +|=== + +So for the `Session` API we would write: + +[source,java] +---- +List matchingBooks = + session.createSelectionQuery("from Book where title like :titleSearchPattern", Book.class) + .setParameter("titleSearchPattern", titleSearchPattern) + .getResultList(); +---- + +Or, if we're sticking to the JPA-standard APIs: + +[source,java] +---- +List matchingBooks = + entityManager.createQuery("select b from Book b where b.title like :titleSearchPattern", Book.class) + .setParameter("titleSearchPattern", titleSearchPattern) + .getResultList(); +---- + +The main difference between `createSelectionQuery()` and `createQuery()` is that `createSelectionQuery()` throws an exception if passed a query string that begins with `insert`, `delete`, or `update`. + +We've been using link:{doc-javadoc-url}org/hibernate/query/SelectionQuery.html#getResultList()[`getResultList()`] because we've been expecting our queries to return multiple results. +If we're expecting a query to return a single result, we can use link:{doc-javadoc-url}org/hibernate/query/SelectionQuery.html#getSingleResult()[`getSingleResult()`]. + +[source,java] +---- +Book book = + session.createSelectionQuery("from Book where isbn = ?1", Book.class) + .setParameter(1, isbn) + .getSingleResult(); +---- + +Or, if we're expecting it to return at most one result, we can use link:{doc-javadoc-url}org/hibernate/query/SelectionQuery.html#getSingleResultOrNull()[`getSingleResultOrNull()`]. + +[source,java] +---- +Book bookOrNull = + session.createSelectionQuery("from Book where isbn = ?1", Book.class) + .setParameter(1, isbn) + .getSingleResultOrNull(); +---- + +The difference, of course, is that `getSingleResult()` throws an exception if there's no matching row in the database, whereas `getSingleResultOrNull()` just returns `null`. + +To execute a `MutationQuery`, we use link:{doc-javadoc-url}org/hibernate/query/MutationQuery.html#executeUpdate()[`executeUpdate()`], which returns the number of entities affected by the `insert`, `update`, or `delete`. + +[[query-parameters]] +=== Query parameters + +Queries are often parameterized. + +- In the query above, `:titleSearchPattern` is called a _named parameter_. +- Alternatively, we may label a parameter by a number. Such a parameter is called an _ordinal parameter_. + +We may easily rewrite our query to use an ordinal parameter: + +[source,java] +---- +List matchingBooks = + session.createSelectionQuery("from Book where title like ?1", Book.class) + .setParameter(1, titleSearchPattern) + .getResultList(); +---- + +When a query has multiple parameters, named parameters tend to be easier to read, even if slightly more verbose. + +[WARNING] +// .Using parameters to avoid injection attacks +==== +_Never_ concatenate user input with HQL and pass the concatenated string to `createSelectionQuery()`. +This would open up the possibility for an attacker to execute arbitrary code on your database server. +==== + +The link:{doc-javadoc-url}org/hibernate/query/CommonQueryContract.html#setParameter(java.lang.String,java.lang.Object)[`setParameter()`] methods specify arguments to query parameters. + +[TIP] +==== +The two-argument forms of `setParameter()` are perfect for most purposes, but _very occasionally_ it's necessary to resolve an ambiguity in the interpretation of the argument value by explicitly specifying the <> of the argument. +The best way to identify the type is via a reference to a JPA metamodel `Type`. +There are two ways to do this: + +// - by passing a Java `Class` as a third argument to link:{doc-javadoc-url}org/hibernate/query/CommonQueryContract.html#setParameter(java.lang.String,java.lang.Object,java.lang.Class)[`setParameter()`] (this doesn't usually help very much), +- by passing the `Type` as a third argument to link:{doc-javadoc-url}org/hibernate/query/CommonQueryContract.html#setParameter(java.lang.String,java.lang.Object,jakarta.persistence.metamodel.Type)[`setParameter()`], or +- by packaging the argument and its `Type` in a link:{doc-javadoc-url}org/hibernate/query/TypedParameterValue.html[`TypedParameterValue`]. + +For example, we may pass a <> reference to `setParameter()`. + +[source,java] +---- +session.createSelectionQuery("from Person where address = :address") + .setParameter("address" address, Person_.address.getType()) + .getResultList(); +---- +==== + +[[auto-flush]] +=== Auto-flush + +By default, Hibernate dirty checks entities in the persistence context before executing a query, in order to determine if there are changes which have not yet been flushed to the database, but which might affect the results of the query. +If there are unflushed changes, then Hibernate goes ahead and executes an automatic <> before executing the query. +That way, the query won't return stale results which fail to reflect changes made to data within the current unit of work. +But if there are many entities association with the persistence context, then this can be an expensive operation. + +To disable this behavior, set the link:{doc-javadoc-url}org/hibernate/query/QueryFlushMode.html[query flush mode] to `NO_FLUSH`: + +[source,java] +---- +Book bookOrNull = + session.createSelectionQuery("from Book where isbn = ?1", Book.class) + .setParameter(1, isbn) + .setQueryFlushMode(QueryFlushMode.NO_FLUSH) + .getSingleResult(); +---- + +Or, especially if you're using JPA-standard APIs, use `FlushModeType.COMMIT`: + +[source,java] +---- +Book bookOrNull = + session.createSelectionQuery("from Book where isbn = ?1", Book.class) + .setParameter(1, isbn) + .setFlushMode(FlushModeType.COMMIT) + .getSingleResult(); +---- + +[CAUTION] +==== +Setting the flush mode to `NO_FLUSH`, `COMMIT`, or `MANUAL` might cause the query to return stale results. +==== + +Occasionally we need to build a query at runtime, from a set of optional conditions. +For this, JPA offers an API which allows programmatic construction of a query. + +[[criteria-queries]] +=== Criteria queries + +Imagine we're implementing some sort of search screen, where the user of our system is offered several different ways to constrain the query result set. +For example, we might let them search for books by title and/or the author name. +Of course, we could construct a HQL query by string concatenation, but this is a bit fragile, so it's quite nice to have an alternative. + +.HQL is implemented in terms of criteria objects +**** +Actually, since Hibernate 6, every HQL query is compiled to a criteria query before being translated to SQL. +This ensures that the semantics of HQL and criteria queries are identical. +**** + +First we need an object for building criteria queries. +Using the JPA-standard APIs, this would be a `CriteriaBuilder`, and we get it from the `EntityManagerFactory`: + +[source,java] +---- +CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder(); +---- + +But if we have a `SessionFactory`, we get something much better, a link:{doc-javadoc-url}org/hibernate/query/criteria/HibernateCriteriaBuilder.html[`HibernateCriteriaBuilder`]: + +[source,java] +---- +HibernateCriteriaBuilder builder = sessionFactory.getCriteriaBuilder(); +---- + +The `HibernateCriteriaBuilder` extends `CriteriaBuilder` and adds many operations that JPQL doesn't have. + +[TIP] +// .Getting a `HibernateCriteriaBuilder` in JPA +==== +If you're using `EntityManagerFactory`, don't despair, you have two perfectly good ways to obtain the `HibernateCriteriaBuilder` associated with that factory. +Either: + +[source,java] +---- +HibernateCriteriaBuilder builder = + entityManagerFactory.unwrap(SessionFactory.class).getCriteriaBuilder(); +---- + +Or simply: + +[source,java] +---- +HibernateCriteriaBuilder builder = + (HibernateCriteriaBuilder) entityManagerFactory.getCriteriaBuilder(); +---- +==== + +We're ready to create a criteria query. + +[[criteria-query-example]] +[source,java] +---- +CriteriaQuery query = builder.createQuery(Book.class); +Root book = query.from(Book.class); +Predicate where = builder.conjunction(); +if (titlePattern != null) { + where = builder.and(where, builder.like(book.get(Book_.title), titlePattern)); +} +if (namePattern != null) { + Join author = book.join(Book_.author); + where = builder.and(where, builder.like(author.get(Author_.name), namePattern)); +} +query.select(book).where(where) + .orderBy(builder.asc(book.get(Book_.title))); +---- + +Here, as before, the classes `Book_` and `Author_` are generated by <>. + +[NOTE] +// .Injection attacks and criteria queries +==== +Notice that we didn't bother treating `titlePattern` and `namePattern` as parameters. +That's safe because, by default, Hibernate automatically and transparently treats strings passed to the `CriteriaBuilder` as JDBC parameters. +==== + +Execution of a criteria query works almost exactly like execution of HQL. + +.Executing criteria queries +[%breakable,cols="10,36,32,22"] +|=== +| Kind | `Session` method | `EntityManager` method | `Query` execution method + +| Selection | link:{doc-javadoc-url}org/hibernate/query/QueryProducer.html#createSelectionQuery(jakarta.persistence.criteria.CriteriaQuery)[`createSelectionQuery(CriteriaQuery)`] | `createQuery(CriteriaQuery)` | `getResultList()`, `getSingleResult()`, or `getSingleResultOrNull()` +| Mutation | link:{doc-javadoc-url}org/hibernate/query/QueryProducer.html#createMutationQuery(jakarta.persistence.criteria.CriteriaUpdate)[`createMutationQuery(CriteriaUpdate)`] or link:{doc-javadoc-url}org/hibernate/query/QueryProducer.html#createMutationQuery(jakarta.persistence.criteria.CriteriaDelete)[`createMutationQuery(CriteriaDelete)`] |`createQuery(CriteriaUpdate)` or `createQuery(CriteriaDelete)` | `executeUpdate()` +|=== + +For example: + +[source,java] +---- +List matchingBooks = + session.createSelectionQuery(query) + .getResultList(); +---- + +Update, insert, and delete queries work similarly: + +[source,java] +---- +CriteriaDelete delete = builder.createCriteriaDelete(Book.class); +Root book = delete.from(Book.class); +delete.where(builder.lt(builder.year(book.get(Book_.publicationDate)), 2000)); +session.createMutationQuery(delete).executeUpdate(); +---- + +[TIP] +==== +It's even possible to transform a HQL query string to a criteria query, and modify the query programmatically before execution: +[source,java] +---- +HibernateCriteriaBuilder builder = sessionFactory.getCriteriaBuilder(); +var query = builder.createQuery("from Book where year(publicationDate) > 2000", Book.class); +var root = query.getRoot(0, Book.class); +query.where(builder.like(root.get(Book_.title), builder.literal("Hibernate%"))); +query.orderBy(builder.asc(root.get(Book_.title)), builder.desc(root.get(Book_.isbn))); +List matchingBooks = session.createSelectionQuery(query).getResultList(); +---- +This is starting to get a bit messy. +In Hibernate 7, we can often use <> instead. +==== + +Do you find some of the code above a bit too verbose? +We do. + +[[criteria-definition]] +=== A more comfortable way to write criteria queries + +Actually, what makes the JPA criteria API less ergonomic than it should be is the need to call all operations of the `CriteriaBuilder` as instance methods, instead of having them as `static` functions. +The reason it works this way is that each JPA provider has its own implementation of `CriteriaBuilder`. + +// [%unbreakable] +// [TIP] +// ==== +The helper class link:{doc-javadoc-url}org/hibernate/query/criteria/CriteriaDefinition.html[`CriteriaDefinition`] can reduce the verbosity of criteria queries by eliminating the need to explicitly qualify calls to the methods of `CriteriaBuilder`. +Our <> would look like this: + +[source,java] +---- +CriteriaQuery query = + new CriteriaDefinition(entityManagerFactory, Book.class) {{ + select(book); + if (titlePattern != null) { + restrict(like(book.get(Book_.title), titlePattern)); + } + if (namePattern != null) { + var author = book.join(Book_.author); + restrict(like(author.get(Author_.name), namePattern)); + } + orderBy(asc(book.get(Book_.title))); + }}; +---- +// ==== + +When all else fails, and sometimes even before that, we're left with the option of writing a query in SQL. + +[[native-queries]] +=== Native SQL queries + +HQL is a powerful language which helps reduce the verbosity of SQL, and significantly increases portability of queries between databases. +But ultimately, the true value of ORM is not in avoiding SQL, but in alleviating the pain involved in dealing with SQL result sets once we get them back to our Java program. +As we said <>, Hibernate's generated SQL is meant to be used in conjunction with handwritten SQL, and native SQL queries are one of the facilities we provide to make that easy. + +.Executing SQL +[%breakable,cols="10,36,32,22"] +|=== +| Kind | `Session` method | `EntityManager` method | `Query` execution method + +| Selection | link:{doc-javadoc-url}org/hibernate/query/QueryProducer.html#createNativeQuery(java.lang.String,java.lang.Class)[`createNativeQuery(String,Class)`] | `createNativeQuery(String,Class)` | `getResultList()`, `getSingleResult()`, or `getSingleResultOrNull()` +| Mutation | link:{doc-javadoc-url}org/hibernate/query/QueryProducer.html#createNativeMutationQuery(java.lang.String)[`createNativeMutationQuery(String)`] | `createNativeQuery(String)` | `executeUpdate()` +| Stored procedure | link:{doc-javadoc-url}org/hibernate/SharedSessionContract.html#createStoredProcedureCall(java.lang.String)[`createStoredProcedureCall(String)`] | `createStoredProcedureQuery(String)` | `execute()` +|=== + +For the most simple cases, Hibernate can infer the shape of the result set: + +[source, java] +---- +Book book = + session.createNativeQuery("select * from Books where isbn = ?1", Book.class) + .setParameter(1, isbn) + .getSingleResult(); + +String title = + session.createNativeQuery("select title from Books where isbn = ?1", String.class) + .setParameter(1, isbn) + .getSingleResult(); +---- + +However, in general, there isn't enough information in the JDBC `ResultSetMetaData` to infer the mapping of columns to entity objects. +So for more complicated cases, you'll need to use the `@SqlResultSetMapping` annotation to define a named mapping, and pass the name to `createNativeQuery()`. This gets fairly messy, so we don't want to hurt your eyes by showing you an example of it. + +By default, Hibernate doesn't flush the session before execution of a native query. +That's because the session is unaware of which modifications held in memory would affect the results of the query. + +So if there are any unflushed changes to ``Book``s, this query might return stale data: + +[source,java] +---- +List books = + session.createNativeQuery("select * from Books", Book.class) + .getResultList(); +---- + +There's two ways to ensure the persistence context is flushed before this query is executed. + +Either, we could simply force a flush by calling `flush()` or by setting the flush mode to `ALWAYS`: + +[source,java] +---- +List books = + session.createNativeQuery("select * from Books", Book.class) + .setHibernateFlushMode(ALWAYS) + .getResultList(); +---- + +Or, alternatively, we could tell Hibernate which modified state affects the results of the query: + +[source,java] +---- +List books = + session.createNativeQuery("select * from Books", Book.class) + .addSynchronizedEntityClass(Book.class) + .getResultList(); +---- + +[TIP] +==== +You can call stored procedures using `createStoredProcedureQuery()` or `createStoredProcedureCall()`. +==== + +[[restrictions-and-ordering]] +=== Restrictions and ordering + +We've already seen how the JPA <> can be used to construct a query completely programmatically. +The Criteria API is powerful, but for the most common scenarios it's at least arguably overkill. +The <> class helps a bit, but it doesn't completely eliminate the verbosity of programmatic query definition. + +In Hibernate 7, there's a new option, a very ergonomic API for programmatically adding restrictions or ordering to an existing query before executing it. +(Actually, the ordering part of this was introduced in Hibernate 6.5.) +This new API: + +- isn't part of the Criteria Query API, and so we don't need a `CriteriaQuery` object to make use of it, +- _does_ make use of the JPA <> for type safety, +- works with both HQL and Criteria queries, and +- is optimized for the case of a query which returns its single root entity. + +[source,java] +---- +var selection = + SelectionSpecification.create(Book.class, + // an optional base query, written in HQL: + "from Book where year(publicationDate) > 2000"); + +// add programmatic restrictions: +if (titlePattern != null) + selection.restrict(Restriction.like(Book_.title, namePattern)); +if (isbns != null && !isbns.isEmpty()) + selection.restrict(Restriction.in(Book_.isbn, isbns)); + +// add programmatic ordering: +if (orderByTitle) selection.sort(Order.asc(Book_.title)); +if (orderByIsbn) selection.sort(Order.asc(Book_.isbn)); + +// add programmatic association fetching: +if (fetchPublisher) selection.fetch(Path.from(Book.class).to(Book_.publisher)); + +// execute the query in the given session: +List matchingBooks = selection.createQuery(session).getResultList(); +---- + +Notice that: + +- The link:{doc-javadoc-url}org/hibernate/query/restriction/Restriction.html[`Restriction`] interface has static methods for constructing a variety of different kinds of restriction in a completely typesafe way. +- Similarly, the link:{doc-javadoc-url}org/hibernate/query/Order.html[`Order`] interface has a variety of static methods for constructing different kinds of sorting criteria. + +We need the following methods of link:{doc-javadoc-url}org/hibernate/query/programmatic/SelectionSpecification.html[`SelectionSpecification`]: + +.Methods for query restriction and ordering +[%breakable,cols="20,~] +|=== +| Method name | Purpose + +| `restrict()` | Add a `Restriction` on the query results +| `sort()`, `resort()` | Specify how the query results should be ordered +| `fetch()` | Add a fetched association `Path` +| `augment()` | Add a custom function which directly manipulates the select query +|=== + +Two of these operations are also available for a link:{doc-javadoc-url}org/hibernate/query/programmatic/MutationSpecification.html[`MutationSpecification`]: + +.Methods for mutation restriction +[%breakable,cols="20,~] +|=== +| Method name | Purpose + +| `restrict()` | Add a `Restriction` on the records to be updated +| `augment()` | Add a custom function which directly manipulates the update or delete query +|=== + +Alternatively, `Restriction` and `Order` can be used with <>, and even with link:{doc-data-repositories-url}[Jakarta Data repositories]. + +The interface link:{doc-javadoc-url}org/hibernate/query/restriction/Path.html[`Path`] may be used to express restrictions on fields of an embedded or associated entity class. +It may even be used for association fetching. + +[source,java] +---- +List booksForPublisher = + SelectionSpecification.create(Book.class) + .restrict(Path.from(Book.class).to(Book_.publisher).to(Publisher_.name) + .equalTo(publisherName)) + .fetch(Path.from(Book.class).to(Book_.publisher)) + .createQuery(session) + .getResultList(); +---- + +Specifications aren't for everything, however. + +[NOTE] +==== +`SelectionSpecification` (similar to its friend `MutationSpecification`) may be used in cases where a query returns a single "root" entity, possibly with some fetched associations. +It's not useful in cases where a query should return multiple entities, a projection of entity fields, or an aggregation. +For such cases, the full Criteria API is appropriate. +==== + +Finally, the `augment()` method deserves its own subsection. + +[[augmentation]] +=== Augmentation + +When `Restriction`, `Path`, and `Order` aren't expressive enough, we can _augment_ the query by manipulating its representation as a criteria: + +[source,java] +---- +var books = + SelectionSpecification.create(Book.class) + .augment((builder, query, book) -> + // augment the query via JPA Criteria API + query.where(builder.like(book.get(Book_.title), titlePattern))) + .orderBy(builder.asc(book.get(Book_.isbn))) + .createQuery(session) + .getResultList(); +---- + +For really advanced cases, `augment()` works quite nicely with <>. + +[source,java] +---- +var books = + SelectionSpecification.create(Book.class) + .augment((builder, query, book) -> + // eliminate explicit references to 'builder' + new CriteriaDefinition<>(query) {{ + where(like(entity.get(BasicEntity_.title), titlePattern), + greaterThan(book.get(Book_.pages), minPages)); + orderBy(asc(book.get(Book_.isbn))); + }} + ) + .createQuery(session) + .getResultList(); +---- + +However, we emphasize that this API shines in cases where complex manipulations are _not_ required. +For complicated queries involving multiple entities, or with aggregation and projection, you're best off heading straight to the `CriteriaBuilder`. + +Programmatic restrictions, and especially programmatic ordering, are often used together with pagination. + +[[pagination]] +=== Limits and pagination + +If a query might return more results than we can handle at one time, we may specify: + +- a _limit_ on the maximum number of rows returned, and, +- optionally, an _offset_, the first row of an ordered result set to return. + +[TIP] +==== +The offset is used to paginate query results. +==== + +There's two ways to add a limit or offset to a HQL or native SQL query: + +- using the syntax of the query language itself, for example, `offset 10 rows fetch next 20 rows only`, or +- using the methods `setFirstResult()` and `setMaxResults()` of the `SelectionQuery` interface. + +If the limit or offset is parameterized, the second option is simpler. +For example, this: + +[source,java] +---- +List books = + session.createSelectionQuery("from Book where title like ?1 order by title", Book.class) + .setParameter(1, titlePattern) + .setMaxResults(MAX_RESULTS) + .getResultList(); +---- + +is simpler than: + +[source,java] +---- +// a worse way to do pagination +List books = + session.createSelectionQuery("from Book where title like ?1 order by title fetch first ?2 rows only", Book.class) + .setParameter(1, titlePattern) + .setParameter(2, MAX_RESULTS) + .getResultList(); +---- + +Hibernate's `SelectionQuery` has a slightly different way to paginate the query results: + +[source,java] +---- +List books = + session.createSelectionQuery("from Book where title like ?1 order by title", Book.class) + .setParameter(1, titlePattern) + .setPage(Page.first(MAX_RESULTS)) + .getResultList(); +---- + +The `getResultCount()` method is useful for displaying the number of pages of results: + +[source,java] +---- +SelectionQuery query = + session.createSelectionQuery("from Book where title like ?1 order by title", Book.class) + .setParameter(1, titlePattern); +long results = query.getResultCount(); +long pages = results / MAX_RESULTS + (results % MAX_RESULTS == 0 ? 0 : 1); +List books = query.setMaxResults(MAX_RESULTS).getResultList(); +---- + +.Methods for query limits, pagination, and ordering +[%breakable,cols="30,~,^15"] +|=== +| Method name | Purpose | JPA-standard + +| `setMaxResults()` | Set a limit on the number of results returned by a query | ✔ +| `setFirstResult()` | Set an offset on the results returned by a query | ✔ +| `setPage()` | Set the limit and offset by specifying a `Page` object | ✖ +| `getResultCount()` | Determine how many results the query would return in the absence of any limit or offset | ✖ +|=== + +It's quite common for pagination to be combined with the need to order query results by a field that's determined at runtime. +The `Order` class we just met <> provides the ability to specify that the query results should be ordered by one or more fields of the entity type returned by the query: + +[[query-order-example]] +[source,java] +---- +List books = + session.createSelectionQuery("from Book where title like ?1", Book.class) + .setParameter(1, titlePattern) + .setOrder(List.of(Order.asc(Book_.title), Order.asc(Book_.isbn))) + .setMaxResults(MAX_RESULTS) + .getResultList(); +---- + +The approach to pagination we've just seen is sometimes called _offset-based pagination_. +Since Hibernate 6.5, there's an alternative approach, which offers some advantages, though it's a little more difficult to use. + +[[key-based-pagination]] +=== Key-based pagination + +_Key-based pagination_ aims to reduce the likelihood of missed or duplicate results when data is modified between page requests. +It's most easily illustrated with an example: + +[source,java] +---- +String QUERY = "from Book where publicationDate > :minDate"; + +// obtain the first page of results +KeyedResultList first = + session.createSelectionQuery(QUERY, Book.class) + .setParameter("minDate", minDate) + .getKeyedResultList(Page.first(25) + .keyedBy(Order.asc(Book_.isbn))); +List firstPage = first.getResultList(); +... + +if (!firstPage.isLastPage()) { + // obtain the second page of results + KeyedResultList second = + session.createSelectionQuery(QUERY, Book.class) + .setParameter("minDate", minDate)) + .getKeyedResultList(firstPage.getNextPage()); + List secondPage = second.getResultList(); + ... +} +---- + +The "key" in key-based pagination refers to a unique key of the result set which determines a total order on the query results. +In this example, `Book.isbn` is the key. + +Since this code is a little bit fiddly, key-based pagination works best with <>. + +[[projection-lists]] +=== Representing projection lists + +A _projection list_ is the list of things that a query returns, that is, the list of expressions in the `select` clause. +Since Java has no tuple types, representing query projection lists in Java has always been a problem for JPA and Hibernate. +Traditionally, we've just used `Object[]` most of the time: + +[source,java] +---- +var results = + session.createSelectionQuery("select isbn, title from Book", Object[].class) + .getResultList(); + +for (var result : results) { + var isbn = (String) result[0]; + var title = (String) result[1]; + ... +} +---- + +This is really a bit ugly. +Java's `record` types now offer an interesting alternative: + +[source,java] +---- +record IsbnTitle(String isbn, String title) {} + +var results = + session.createSelectionQuery("select isbn, title from Book", IsbnTitle.class) + .getResultList(); + +for (var result : results) { + var isbn = result.isbn(); + var title = result.title(); + ... +} +---- +Notice that we're able to declare the `record` right before the line which executes the query. + +This works just as well with queries written in SQL: + +[source,java] +---- +record BookInfo(String isbn, String title, int pages) {} + +List resultList = + session.createNativeQuery("select title, isbn, pages from Book", BookInfo.class) + .getResultList(); +---- + +Now, this approach is only _superficially_ more typesafe, since the query itself is not checked statically, and so we can't say it's objectively better. +But perhaps you find it more aesthetically pleasing. +And if we're going to be passing query results around the system, the use of a `record` type is _much_ better. + +The criteria query API offers a much more satisfying solution to the problem. +Consider the following code: + +[source,java] +---- +var builder = sessionFactory.getCriteriaBuilder(); +var query = builder.createTupleQuery(); +var book = query.from(Book.class); +var bookTitle = book.get(Book_.title); +var bookIsbn = book.get(Book_.isbn); +var bookPrice = book.get(Book_.price); +query.select(builder.tuple(bookTitle, bookIsbn, bookPrice)); +var resultList = session.createSelectionQuery(query).getResultList(); +for (var result : resultList) { + String title = result.get(bookTitle); + String isbn = result.get(bookIsbn); + BigDecimal price = result.get(bookPrice); + ... +} +---- + +This code is manifestly completely typesafe, and much better than we can hope to do with HQL. + +[[named-queries]] +=== Named queries + +The `@NamedQuery` annotation lets us define a HQL query that is compiled and checked as part of the bootstrap process. +This means we find out about errors in our queries earlier, instead of waiting until the query is actually executed. +We can place the `@NamedQuery` annotation on any class, even on an entity class. + +[source,java] +---- +@NamedQuery(name = "10BooksByTitle", + query = "from Book where title like :titlePattern order by title fetch first 10 rows only") +class BookQueries {} +---- + +We have to make sure that the class with the `@NamedQuery` annotation will be scanned by Hibernate, either: + +- by adding `org.hibernate.example.BookQueries` to `persistence.xml`, or +- by calling `persistenceConfiguration.managedClass(BookQueries.class)`. + +[TIP] +==== +Unfortunately, JPA's `@NamedQuery` annotation can't be placed on a package descriptor. +Therefore, Hibernate provides a very similar annotation, `@org.hibernate.annotations.NamedQuery` which _can_ be specified at the package level. +If we declare a named query at the package level, we must call: +[source,java] +---- +configuration.addPackage("org.hibernate.example") +---- +so that Hibernate knows where to find it. +==== + +The `@NamedNativeQuery` annotation lets us do the same for native SQL queries. +There's much less advantage to using `@NamedNativeQuery`, because there is very little that Hibernate can do to validate the correctness of a query written in the native SQL dialect of your database. + +.Executing named queries +[%breakable,cols="10,36,32,22"] +|=== +| Kind | `Session` method | `EntityManager` method | `Query` execution method + +| Selection | `createNamedSelectionQuery(String,Class)` | `createNamedQuery(TypedQueryReference)`, `createNamedQuery(String,Class)` | `getResultList()`, `getSingleResult()`, `getSingleResultOrNull()` +| Mutation | `createNamedMutationQuery(String)` | `createNamedQuery(TypedQueryReference)`, `createNamedQuery(String)` | `executeUpdate()` +|=== + +We execute our named query like this: + +[source,java] +---- +List books = + entityManager.createQuery(BookQueries_._10BooksByTitle_) + .setParameter("titlePattern", titlePattern) + .getResultList() +---- + +Here, `BookQueries_.\_10BooksByTitle_` is an element of the JPA static metamodel of type `TypedQueryReference`, generated by Hibernate Processor. + +Note that the code which executes the named query is not aware of whether the query was written in HQL or in native SQL, making it slightly easier to change and optimize the query later. + +It's nice to have our queries checked at startup time. +It's even better to have them checked at compile time. +In <>, we mentioned that the Hibernate Processor can do that for us, with the help of the `@CheckHQL` annotation, and we presented that as a reason to use `@NamedQuery`. + +[TIP] +==== +:query-validator: https://github.com/hibernate/query-validator/ + +Actually, Hibernate even has a separate <> capable of performing compile-time validation of HQL query strings that occur as arguments to `createQuery()` and friends. +If we use the Query Validator, there's not much advantage to the use of named queries. +==== + +We're going to learn more about Hibernate Processor in the next chapter. diff --git a/documentation/src/main/asciidoc/introduction/Tuning.adoc b/documentation/src/main/asciidoc/introduction/Tuning.adoc index 190bfd037d84..6e5f7144b743 100644 --- a/documentation/src/main/asciidoc/introduction/Tuning.adoc +++ b/documentation/src/main/asciidoc/introduction/Tuning.adoc @@ -45,7 +45,7 @@ Perhaps it's better to set this configuration property: |=== | Configuration property name | Purpose -| link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#CONNECTION_PROVIDER[`hibernate.connection.provider_class`] | Explicitly specify a link:{doc-javadoc-url}/org/hibernate/engine/jdbc/connections/spi/ConnectionProvider.html[connection pool], for example, `agroal`, `hikaricp`, `c3p0`, or `oracleucp`. +| link:{doc-javadoc-url}/org/hibernate/cfg/JdbcSettings.html#CONNECTION_PROVIDER[`hibernate.connection.provider_class`] | Explicitly specify a link:{doc-javadoc-url}/org/hibernate/engine/jdbc/connections/spi/ConnectionProvider.html[connection pool], for example, `agroal`, `hikaricp` or `c3p0`. |=== TIP: You can set `hibernate.connection.provider_class` to `agroal` so that Hibernate fails at startup if Agroal is missing. @@ -934,12 +934,34 @@ NOTE: There's no `flush()` operation, and so `update()` is always explicit. In certain circumstances, this makes stateless sessions easier to work with and simpler to reason about, but with the caveat that a stateless session is much more vulnerable to data aliasing effects, since it's easy to get two non-identical Java objects which both represent the same row of a database table. +Consider the following fragments: + +[source,java] +---- +var b1 = statelessSession.get(Book.class, isbn); +var b2 = statelessSession.get(Book.class, isbn); +assert b1 == b2; // fails +---- +[source,java] +---- +var b1 = statelessSession.get(Book.class, isbn); +var b2 = statelessSession.get(Book.class, isbn); +statelessSession.fetch(b1.publisher); +statelessSession.fetch(b2.publisher); +assert b1.publisher == b2.publisher; // fails +---- + +In a stateful session, entity instances are canonicalized by primary key, and so we don't usually have two different objects representing a single row. +No such canonicalization exists across invocations of a stateless session. +In a stateless session, both the assertions fail. + [%unbreakable] [CAUTION] ==== If we use `fetch()` in a stateless session, we can very easily obtain two objects representing the same database row! ==== +But there are also some advantages to this model. In particular, the absence of a persistence context means that we can safely perform bulk-processing tasks without allocating huge quantities of memory. Use of a `StatelessSession` alleviates the need to call: @@ -1153,7 +1175,7 @@ It's much more typesafe to use one of the first two options. === Reactive programming with Hibernate :hr: https://hibernate.org/reactive/ -:hr-guide: https://hibernate.org/reactive/documentation/2.0/reference/html_single/ +:hr-guide: https://hibernate.org/reactive/documentation/3.0/reference/html_single/ Finally, many systems which require high scalability now make use of reactive programming and reactive streams. {hr}[Hibernate Reactive] brings O/R mapping to the world of reactive programming. diff --git a/documentation/src/main/asciidoc/querylanguage/Expressions.adoc b/documentation/src/main/asciidoc/querylanguage/Expressions.adoc index eac1d68adde6..a4c28ec7a7cc 100644 --- a/documentation/src/main/asciidoc/querylanguage/Expressions.adoc +++ b/documentation/src/main/asciidoc/querylanguage/Expressions.adoc @@ -96,45 +96,73 @@ Similarly, the Java-style postfix is case-insensitive. [[datetime-literals]] ==== Date and time literals -According to the JPQL specification, date and time literals may be specified using the JDBC escape syntax. -Since this syntax is rather unpleasant to look at, HQL provides not one, but two alternatives. +According to the JPQL specification, literal dates and times may be specified using the JDBC escape syntax. +[cols="~,~,~,^15"] |=== -| Date/time type | Recommended Java type | JDBC escape syntax 💀| Braced literal syntax | Explicitly typed literal syntax - -| Date | `LocalDate` | `{d 'yyyy-mm-dd'}` | `{yyyy-mm-dd}` | `date yyyy-mm-dd` -| Time | `LocalTime` | `{t 'hh:mm'}` | `{hh:mm}` | `time hh:mm` -| Time with seconds | `LocalTime` | `{t 'hh:mm:ss'}` | `{hh:mm:ss}` | `time hh:mm:ss` -| Datetime | `LocalDateTime` | `{ts 'yyyy-mm-ddThh:mm:ss'}` | `{yyyy-mm-dd hh:mm:ss}` | `datetime yyyy-mm-dd hh:mm:ss` -| Datetime with milliseconds | `LocalDateTime` | `{ts 'yyyy-mm-ddThh:mm:ss.millis'}` | `{yyyy-mm-dd hh:mm:ss.millis}` | `datetime yyyy-mm-dd hh:mm:ss.millis` -| Datetime with an offset | `OffsetDateTime` | `{ts 'yyyy-mm-ddThh:mm:ss+hh:mm'}` | `{yyyy-mm-dd hh:mm:ss +hh:mm}` | `datetime yyyy-mm-dd hh:mm:ss +hh:mm` -| Datetime with a time zone | `OffsetDateTime` | `{ts 'yyyy-mm-ddThh:mm:ss GMT'}` | `{yyyy-mm-dd hh:mm:ss GMT}` | `datetime yyyy-mm-dd hh:mm:ss GMT` +| Date/time type | Java type | JDBC escape syntax | JPA standard + +| Date | `java.sql.Date` 💀 | `{d 'yyyy-mm-dd'}` | ✔ +| Time | `java.sql.Time` 💀 | `{t 'hh:mm'}` | ✔ +| Time with seconds | `java.sql.Time` 💀 | `{t 'hh:mm:ss'}` | ✔ +| Timestamp | `java.sql.Timestamp` 💀 | `{ts 'yyyy-mm-ddThh:mm:ss'}` | ✔ +| Timestamp with milliseconds | `java.sql.Timestamp` 💀 | `{ts 'yyyy-mm-ddThh:mm:ss.millis'}` | ✔ +| Timestamp with an offset | `java.sql.Timestamp` 💀 | `{ts 'yyyy-mm-ddThh:mm:ss+hh:mm'}` | ✔ +| Timestamp with a time zone | `java.sql.Timestamp` 💀 | `{ts 'yyyy-mm-ddThh:mm:ss GMT'}` | ✔ |=== -Literals referring to the current date and time are also provided. -Again there is some flexibility. +There's two problems here: -|=== -| Date/time type | Java type | Underscored syntax | Spaced syntax - -| Date | `java.time.LocalDate` | `local_date` | `local date` -| Time | `java.time.LocalTime` | `local_time` | `local time` -| Datetime | `java.time.LocalDateTime` | `local_datetime` | `local datetime` -| Offset datetime | `java.time.OffsetDateTime`| `offset_datetime` | `offset datetime` -| Instant | `java.time.Instant` | `instant` | `instant` -| Date | `java.sql.Date` 💀| `current_date` | `current date` -| Time | `java.sql.Time` 💀| `current_time` | `current time` -| Datetime | `java.sql.Timestamp` 💀| `current_timestamp` | `current timestamp` -|=== - -Of these, only `local date`, `local time`, `local datetime`, `current_date`, `current_time`, and `current_timestamp` are defined by the JPQL specification. +1. this syntax is rather unpleasant to look at, and +2. these literals are assigned types defined by JDBC, instead of date/time types defined in `java.time`. [IMPORTANT] ==== The use of date and time types from the `java.sql` package is strongly discouraged! +Jakarta Persistence 3.2 deprecates support for these types. Always use `java.time` types in new code. ==== +HQL provides not one, but two alternatives. + +[cols="~,~,~,~,^15"] +|=== +| Date/time type | Java type| Braced literal syntax | Explicitly-typed literal syntax | JPA standard + +| Date | `LocalDate` | `{yyyy-mm-dd}` | `date yyyy-mm-dd` | ✖ +| Time | `LocalTime` | `{hh:mm}` | `time hh:mm` | ✖ +| Time with seconds | `LocalTime` | `{hh:mm:ss}` | `time hh:mm:ss` | ✖ +| Datetime | `LocalDateTime` | `{yyyy-mm-dd hh:mm:ss}` | `datetime yyyy-mm-dd hh:mm:ss` | ✖ +| Datetime with milliseconds | `LocalDateTime` | `{yyyy-mm-dd hh:mm:ss.millis}` | `datetime yyyy-mm-dd hh:mm:ss.millis` | ✖ +| Datetime with an offset | `OffsetDateTime` | `{yyyy-mm-dd hh:mm:ss +hh:mm}` | `datetime yyyy-mm-dd hh:mm:ss +hh:mm` | ✖ +| Datetime with a time zone | `OffsetDateTime` | `{yyyy-mm-dd hh:mm:ss GMT}` | `datetime yyyy-mm-dd hh:mm:ss GMT` | ✖ +|=== + +Literals referring to the current date and time are also available. + +[cols="~,~,~,^15"] +|=== +| Date/time type | Java type | Syntax | JPA standard + +| Date | `java.time.LocalDate` | `local date` | ✔ +| Time | `java.time.LocalTime` | `local time` | ✔ +| Datetime | `java.time.LocalDateTime` | `local datetime` | ✔ +| Offset datetime | `java.time.OffsetDateTime` | `offset datetime` | ✖ +| Instant | `java.time.Instant` | `instant` | ✖ +|=== + +The following are deprecated in JPA 3.2. +We include them here only for completeness: + +[cols="~,~,~,~,^15"] +|=== +| Date/time type | Java type | JPA syntax ✔ | HQL syntax ✖ | JPA standard + +| JDBC date | `java.sql.Date` 💀| `current_date` | `current date` | 💀 +| JDBC time | `java.sql.Time` 💀| `current_time` | `current time` | 💀 +| JDBC timestamp | `java.sql.Timestamp` 💀| `current_timestamp` | `current timestamp` | 💀 +|=== + [[duration-literals]] ==== Duration literals @@ -548,6 +576,7 @@ The following special functions make it possible to discover or narrow expressio | `cast()` | Narrow a basic type | `cast(x as Type)` | ✔ | `str()` | Cast to a string | `str(x)` | ✖ | `ordinal()` | Get the ordinal value of an enum | `ordinal(x)` | ✖ +| `string()` | Get the string-valued name of an enum | `string(x)` | ✖ |=== Let's see what these functions do. @@ -619,16 +648,17 @@ select str(id) from Order [[function-ordinal]] [discrete] -===== Extracting the ordinal value of an enum +===== Extracting the ordinal value or name of an enum -The function `ordinal(x)` extracts the ordinal value of an enum. -It supports both enum fields mapped as `ORDINAL` and `STRING`. +The function `ordinal(x)` extracts the ordinal value of an enum, and the function `string(x)` extracts the name of the enum value as a string. [source, hql] ---- -select ordinal(p.type) from Phone p +select ordinal(p.type), string(p.type) from Phone p ---- +Both functions work with enum fields mapped as `ORDINAL` and with enum fields mapped as `STRING`. + [[functions-null]] ==== Functions for working with null values diff --git a/documentation/src/main/asciidoc/quickstart/guides/obtaining.adoc b/documentation/src/main/asciidoc/quickstart/guides/obtaining.adoc index 495610c54ab4..1534a4267523 100644 --- a/documentation/src/main/asciidoc/quickstart/guides/obtaining.adoc +++ b/documentation/src/main/asciidoc/quickstart/guides/obtaining.adoc @@ -52,7 +52,6 @@ transitive dependencies based on the features being used or not. |hibernate-agroal| Support for https://agroal.github.io/[Agroal] connection pooling |hibernate-c3p0| Support for https://www.mchange.com/projects/c3p0/[C3P0] connection pooling |hibernate-hikaricp| Support for https://github.com/brettwooldridge/HikariCP/[HikariCP] connection pooling -|hibernate-ucp| Support for https://docs.oracle.com/en/database/oracle/oracle-database/23/jjucp/intro.html[Universal Connection Pool] connection pooling |hibernate-jcache| Integration with https://jcp.org/en/jsr/detail?id=107$$[JCache], allowing any compliant implementation as a second-level cache provider |hibernate-graalvm| Experimental extension to make it easier to compile applications as a https://www.graalvm.org/[GraalVM] native image |hibernate-micrometer| Integration with https://micrometer.io[Micrometer] metrics diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/annotations/pom.xml b/documentation/src/main/asciidoc/quickstart/tutorials/annotations/pom.xml index 9e0c3bc4819d..258ce73164d9 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/annotations/pom.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/annotations/pom.xml @@ -1,9 +1,7 @@ diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/annotations/src/test/java/org/hibernate/tutorial/annotations/Event.java b/documentation/src/main/asciidoc/quickstart/tutorials/annotations/src/test/java/org/hibernate/tutorial/annotations/Event.java index d609935d4bb0..5db4abea7a84 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/annotations/src/test/java/org/hibernate/tutorial/annotations/Event.java +++ b/documentation/src/main/asciidoc/quickstart/tutorials/annotations/src/test/java/org/hibernate/tutorial/annotations/Event.java @@ -1,25 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2010, Red Hat Inc. or third-party contributors as - * indicated by the @author tags or express copyright attribution - * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Inc. - * - * This copyrighted material is made available to anyone wishing to use, modify, - * copy, or redistribute it subject to the terms and conditions of the GNU - * Lesser General Public License, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this distribution; if not, write to: - * Free Software Foundation, Inc. - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301 USA + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.tutorial.annotations; diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/annotations/src/test/java/org/hibernate/tutorial/annotations/HibernateIllustrationTest.java b/documentation/src/main/asciidoc/quickstart/tutorials/annotations/src/test/java/org/hibernate/tutorial/annotations/HibernateIllustrationTest.java index 958606a7d55e..f815fd95310c 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/annotations/src/test/java/org/hibernate/tutorial/annotations/HibernateIllustrationTest.java +++ b/documentation/src/main/asciidoc/quickstart/tutorials/annotations/src/test/java/org/hibernate/tutorial/annotations/HibernateIllustrationTest.java @@ -1,25 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2010, Red Hat Inc. or third-party contributors as - * indicated by the @author tags or express copyright attribution - * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Inc. - * - * This copyrighted material is made available to anyone wishing to use, modify, - * copy, or redistribute it subject to the terms and conditions of the GNU - * Lesser General Public License, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this distribution; if not, write to: - * Free Software Foundation, Inc. - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301 USA + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.tutorial.annotations; diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/pom.xml b/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/pom.xml index b441a70ca5c4..61198316b17a 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/pom.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/pom.xml @@ -1,9 +1,7 @@ diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/java/org/hibernate/tutorial/em/Event.java b/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/java/org/hibernate/tutorial/em/Event.java index dc5a9257fc56..fe876db9b897 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/java/org/hibernate/tutorial/em/Event.java +++ b/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/java/org/hibernate/tutorial/em/Event.java @@ -1,25 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2010, Red Hat Inc. or third-party contributors as - * indicated by the @author tags or express copyright attribution - * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Inc. - * - * This copyrighted material is made available to anyone wishing to use, modify, - * copy, or redistribute it subject to the terms and conditions of the GNU - * Lesser General Public License, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this distribution; if not, write to: - * Free Software Foundation, Inc. - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301 USA + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.tutorial.em; diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/java/org/hibernate/tutorial/em/JPAIllustrationTest.java b/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/java/org/hibernate/tutorial/em/JPAIllustrationTest.java index 0f7adc680320..dfc28264ef38 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/java/org/hibernate/tutorial/em/JPAIllustrationTest.java +++ b/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/java/org/hibernate/tutorial/em/JPAIllustrationTest.java @@ -1,25 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2010, Red Hat Inc. or third-party contributors as - * indicated by the @author tags or express copyright attribution - * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Inc. - * - * This copyrighted material is made available to anyone wishing to use, modify, - * copy, or redistribute it subject to the terms and conditions of the GNU - * Lesser General Public License, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this distribution; if not, write to: - * Free Software Foundation, Inc. - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301 USA + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.tutorial.em; diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/resources/META-INF/persistence.xml b/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/resources/META-INF/persistence.xml index db0787396dd9..3c1e77324b26 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/resources/META-INF/persistence.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/entitymanager/src/test/resources/META-INF/persistence.xml @@ -1,8 +1,6 @@ diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/java/org/hibernate/tutorial/envers/EnversIllustrationTest.java b/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/java/org/hibernate/tutorial/envers/EnversIllustrationTest.java index 808ca2db7b0e..81eb6196488a 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/java/org/hibernate/tutorial/envers/EnversIllustrationTest.java +++ b/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/java/org/hibernate/tutorial/envers/EnversIllustrationTest.java @@ -1,25 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2010, Red Hat Inc. or third-party contributors as - * indicated by the @author tags or express copyright attribution - * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Inc. - * - * This copyrighted material is made available to anyone wishing to use, modify, - * copy, or redistribute it subject to the terms and conditions of the GNU - * Lesser General Public License, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this distribution; if not, write to: - * Free Software Foundation, Inc. - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301 USA + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.tutorial.envers; diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/java/org/hibernate/tutorial/envers/Event.java b/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/java/org/hibernate/tutorial/envers/Event.java index 9cb5dd661b69..e91303acdecf 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/java/org/hibernate/tutorial/envers/Event.java +++ b/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/java/org/hibernate/tutorial/envers/Event.java @@ -1,25 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * Copyright (c) 2010, Red Hat Inc. or third-party contributors as - * indicated by the @author tags or express copyright attribution - * statements applied by the authors. All third-party contributions are - * distributed under license by Red Hat Inc. - * - * This copyrighted material is made available to anyone wishing to use, modify, - * copy, or redistribute it subject to the terms and conditions of the GNU - * Lesser General Public License, as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY - * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License - * for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this distribution; if not, write to: - * Free Software Foundation, Inc. - * 51 Franklin Street, Fifth Floor - * Boston, MA 02110-1301 USA + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.tutorial.envers; diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/resources/META-INF/persistence.xml b/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/resources/META-INF/persistence.xml index e84f11cc2a8b..dd3bf26fd2ea 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/resources/META-INF/persistence.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/envers/src/test/resources/META-INF/persistence.xml @@ -1,8 +1,6 @@ diff --git a/documentation/src/main/asciidoc/repositories/Configuration.adoc b/documentation/src/main/asciidoc/repositories/Configuration.adoc index f9dcd23ae913..72161c9a5965 100644 --- a/documentation/src/main/asciidoc/repositories/Configuration.adoc +++ b/documentation/src/main/asciidoc/repositories/Configuration.adoc @@ -45,7 +45,7 @@ In addition, we might add some of the following to the mix. | Optional dependency | Explanation | `org.hibernate.validator:hibernate-validator` + -and `org.glassfish:jakarta.el` | Hibernate Validator +and `org.glassfish.expressly:expressly` | Hibernate Validator | `org.apache.logging.log4j:log4j-core` | log4j | `org.jboss.weld:weld-core-impl` | Weld CDI |=== @@ -55,7 +55,7 @@ In Gradle, for example, you'll need to use `annotationProcessor`. [source,groovy] ---- -annotationProcessor 'org.hibernate.orm:hibernate-processor:7.0.0' +annotationProcessor 'org.hibernate.orm:hibernate-processor:7.0.0.Final' ---- === Excluding classes from processing diff --git a/documentation/src/main/asciidoc/repositories/Pagination.adoc b/documentation/src/main/asciidoc/repositories/Pagination.adoc index 33555767110c..c6be16c2ee20 100644 --- a/documentation/src/main/asciidoc/repositories/Pagination.adoc +++ b/documentation/src/main/asciidoc/repositories/Pagination.adoc @@ -65,8 +65,8 @@ But since Hibernate Data Repositories already validates the content of the `@Ord Dynamic sorting criteria are expressed using the types `Sort` and `Order`: -- an instance of `Sort` represents a single criterion for sorting query results, and -- an instance of `Order` packages multiple ``Sort``s together. +- an instance of https://jakarta.ee/specifications/data/1.0/apidocs/jakarta.data/jakarta/data/sort[`Sort`] represents a single criterion for sorting query results, and +- an instance of https://jakarta.ee/specifications/data/1.0/apidocs/jakarta.data/jakarta/data/order[`Order`] packages multiple ``Sort``ing criteria together. A query method may accept an instance of `Sort`. @@ -107,6 +107,18 @@ var books = Dynamic sorting criteria may be combined with static criteria. +[TIP] +==== +If the entity has entity supertypes, use a lower bounded wildcard in the repository method declaration, for example: +[source,java] +---- +@Find +List books(@Pattern String title, Year yearPublished, + Order order); +---- +This lets the caller sort by fields of the supertype. +==== + [source,java] ---- @Find @@ -120,13 +132,13 @@ We're not convinced this is very useful in practice. [[limits]] === Limits -A `Limit` is the simplest way to express a subrange of query results. +A https://jakarta.ee/specifications/data/1.0/apidocs/jakarta.data/jakarta/data/limit[`Limit`] is the simplest way to express a subrange of query results. It specifies: - `maxResults`, the maximum number of results to be returned from the database server to the client, and, -- optionally, `startAt`, an offset from the very first result. +- optionally, `startAt`, the position of the first result to be returned to the client. -These values map directly the familiar `setMaxResults()` and `setFirstResults()` of the Jakarta Persistence `Query` interface. +These values map directly to the familiar `setMaxResults()` and `setFirstResult()` of the Jakarta Persistence `Query` interface. [source,java] ---- @@ -142,12 +154,15 @@ var books = Limit.of(MAX_RESULTS)); ---- +[CAUTION] +Whereas `Query.setFirstResult()` is an _offset_ of the first result to be returned, with `setFirstResult(0)` meaning "no offset", `Limit.startAt` numbers results from one, with `Limit.range(1, n)` meaning "at most _n_ results, starting from the first result". + A more sophisticated approach is provided by `PageRequest`. [[offset-based-pagination]] === Offset-based pagination -A `PageRequest` is superficially similar to a `Limit`, except that it's specified in terms of: +A https://jakarta.ee/specifications/data/1.0/apidocs/jakarta.data/jakarta/data/page/pagerequest[`PageRequest`] is superficially similar to a `Limit`, except that it's specified in terms of: - a page `size`, and - a numbered `page`. @@ -176,7 +191,7 @@ The easiest way to be sure that you have a well-defined total order is to specif For this reason, we specified `@OrderBy("isbn")` in the previous example. ==== -However, a repository method which accepts a `PageRequest` may return a `Page` instead of a `List`, making it easier to implement pagination. +However, a repository method which accepts a `PageRequest` may return a https://jakarta.ee/specifications/data/1.0/apidocs/jakarta.data/jakarta/data/page/page[`Page`] of results instead of a `List`, making it easier to implement pagination. [source,java] ---- @@ -238,7 +253,7 @@ For key-based pagination, it's _essential_ that the query has a total order. ==== From our point of view as users of Jakarta Data, key-based pagination works almost exactly like offset-based pagination. -The difference is that we must declare our repository method to return `CursoredPage`. +The difference is that we must declare our repository method to return https://jakarta.ee/specifications/data/1.0/apidocs/jakarta.data/jakarta/data/page/cursoredpage[`CursoredPage`]. [source,java] ---- diff --git a/documentation/src/main/asciidoc/repositories/Preface.adoc b/documentation/src/main/asciidoc/repositories/Preface.adoc index 0c2ee6d8b9f9..c47d97e4bfd5 100644 --- a/documentation/src/main/asciidoc/repositories/Preface.adoc +++ b/documentation/src/main/asciidoc/repositories/Preface.adoc @@ -16,7 +16,7 @@ On the other hand, the programming model for interacting with the database is qu Therefore, this document will show you a different way to use Hibernate. The coverage of Jakarta Data is intentionally inexhaustive. -If exhaustion is sought, this document should be read in conjunction with the specification, which we've worked hard to keep readable. +If exhaustion is sought, this document should be read in conjunction with https://jakarta.ee/specifications/data/1.0/jakarta-data-1.0[the specification], which we've worked hard to keep readable. If you are unfamiliar with Hibernate, this document should be read in conjunction with: diff --git a/documentation/src/main/asciidoc/repositories/Reactive.adoc b/documentation/src/main/asciidoc/repositories/Reactive.adoc index 2bd2c6ad4eb7..687ceeda4c92 100644 --- a/documentation/src/main/asciidoc/repositories/Reactive.adoc +++ b/documentation/src/main/asciidoc/repositories/Reactive.adoc @@ -3,22 +3,27 @@ Hibernate Data Repositories provides repositories backed by https://hibernate.org/reactive/[Hibernate Reactive] for use in reactive programming. The methods of a reactive repository are non-blocking, and so every operation returns a reactive stream. -This is an extension to the programming model defined by Jakarta Data. [NOTE] ==== -The Jakarta Data specification has not yet defined a way to write repositories for use in reactive programming, but the spec was written to accommodate such extensions, and this capability might be standardized in a future release. +Jakarta Data 1.0 does not define a way to write repositories for use in reactive programming, but the spec was written to accommodate such extensions. +This capability is being written into Data 1.1 under the more general category of _asynchronous repositories_. ==== In Hibernate Data Repositories we use https://smallrye.io/smallrye-mutiny/[Mutiny] to work with reactive streams. -[WARNING] +[CAUTION] ==== -If and when Jakarta Data _does_ provide standard support for reactive repositories, the functionality will almost certainly be based on Java's `CompletionStage`, and not on Mutiny. +A future version of Hibernate Data Repositories will also allow the use of `CompletionStage` from `java.util.concurrent`. +Asynchronous repositories based on Mutiny are unlikely to ever be portable to other implementations of Jakarta Data. ==== In our opinion, Mutiny is a _much_ more comfortable API than `CompletionStage`. +[TIP] +The documentation for Hibernate Reactive contains a https://hibernate.org/reactive/documentation/3.0/reference/html_single/#_apis_for_chaining_reactive_operations[comparison table] that's useful if you're more familiar with `CompletionStage`. + + === Defining a reactive repository In the following code example we notice the two requirements for a reactive repository in Hibernate Data Repositories: @@ -49,6 +54,8 @@ interface Library { It's _not_ possible to mix blocking and non-blocking operations in the same repository interface. +IMPORTANT: Depending on how you're managing the stateless session, you might need to declare the resource accessor method with the type `Uni`. + === Obtaining a reactive repository To make use of our reactive repository, we'll need to bootstrap Hibernate Reactive and obtain a `Mutiny.SessionFactory`. @@ -61,7 +68,9 @@ Mutiny.SessionFactory factory = .unwrap(Mutiny.SessionFactory.class); ---- -Please refer to the documentation for Hibernate Reactive for more information on this topic. +Please refer to the https://hibernate.org/reactive/documentation/[documentation for Hibernate Reactive] for more information on this topic. + +TIP: In Quarkus, this step is unnecessary, and you can let Quarkus manage and inject the reactive `SessionFactory`. Once we have the `SessionFactory`, we can easily obtain a `Mutiny.StatelessSession`, and use it to instantiate our repository: @@ -73,7 +82,11 @@ factory.withStatelessTransaction(session -> { }) ---- -TIP: In Quarkus, all this is unnecessary, and you can directly inject the `Library`. +TIP: An even better approach is to make a `@RequestScoped` instance of `Mutiny.StatelessSession` or `Uni` available for injection by CDI. +Then the `Library` repository itself may be directly injected, and you won't have to worry about managing the stateless session in application program code. +This is a little bit tricky to get working perfectly, so hopefully by the time you're reading this, there will already be a built-in implementation in Quarkus. + +// TIP: In Quarkus, all this is unnecessary, and you can directly inject the `Library`. === Calling a reactive repository diff --git a/documentation/src/main/asciidoc/repositories/Repositories.adoc b/documentation/src/main/asciidoc/repositories/Repositories.adoc index b1b90acfd783..d6d58cc8c4ba 100644 --- a/documentation/src/main/asciidoc/repositories/Repositories.adoc +++ b/documentation/src/main/asciidoc/repositories/Repositories.adoc @@ -49,7 +49,7 @@ public class Author { } ---- -For more information about mapping entities, see the link:{doc-introduction-url}#entities[Introduction to Hibernate 6]. +For more information about mapping entities, see the link:{doc-introduction-url}#entities[Short Guide to Hibernate 7]. [NOTE] ==== @@ -138,7 +138,7 @@ A _repository interface_ is an interface written by you, the application program The implementation of the repository interface is provided by a Jakarta Data provider, in our case, by Hibernate Data Repositories. The Jakarta Data specification does not say how this should work, but in Hibernate Data Repositories, the implementation is generated by an annotation processor. -In fact, you might already be using this annotation processor: it's just `HibernateProcessor` from the module which used to be called `hibernate-jpamodelgen`, and has now been renamed `hibernate-processor` in Hibernate 7. +In fact, you might already be using https://hibernate.org/orm/processor/[this annotation processor]: it's just `HibernateProcessor` from the module which used to be called `hibernate-jpamodelgen`, and has now been renamed `hibernate-processor` in Hibernate 7. [TIP] ==== @@ -147,7 +147,7 @@ If you're already using the JPA static metamodel in your project, you already ha If you don't, we'll see how to set it up in the <>. ==== -Of course, a Jakarta Data provider can't generate an implementation of any arbitrary method. +Unlike a language model, a Jakarta Data provider can't generate an implementation of any arbitrary method based only on vibes. Therefore, the methods of a repository interface must fall into one of the following categories: - <>, @@ -204,7 +204,7 @@ interface AuthorRepository } ---- -We won't see `BasicRepository` and `CrudRepository` again in this document, because they're not necessary, and because they implement the older, less-flexible way of doing things. +We won't see `BasicRepository` and `CrudRepository` again in this document, because they're not necessary, and because they implement the older, completely uncool way of doing things. Instead, our repositories will often group together operations dealing with several related entities, even when the entities don't have a single "root". This situation is _extremely_ common in relational data models. @@ -259,7 +259,11 @@ For that, we'll need to add a resource accessor method. === Resource accessor methods A resource accessor method is one which exposes access to an underlying implementation type. -Currently, Hibernate Data Repositories only supports one such type: `StatelessSession`. +Currently, Hibernate Data Repositories supports two such implementation types: + +1. `StatelessSession`, for the ordinary sort of repository we're talking about now, and +2. `Mutiny.StatelessSession`, for <>. + So a resource accessor method is just any abstract method which returns `StatelessSession`. The name of the method doesn't matter. @@ -498,7 +502,7 @@ The JPQL specification provides the `select new` construct for this. @Query("select new AuthorBookSummary(b.isbn, a.ssn, a.name, b.title " + "from Author a join books b " + "where title like :pattern") -List summariesForTitle(@Pattern String pattern); +List summariesForTitle(String pattern); ---- Note that the `from` clause is required here, since it's impossible to infer the queried entity type from the return type of the repository method. @@ -511,7 +515,7 @@ Since this is quite verbose, Hibernate doesn't require the use of `select new`, @Query("select isbn, ssn, name, title " + "from Author join books " + "where title like :pattern") -List summariesForTitle(@Pattern String pattern); +List summariesForTitle(String pattern); ---- ==== diff --git a/documentation/src/main/asciidoc/userguide/Hibernate_User_Guide.adoc b/documentation/src/main/asciidoc/userguide/Hibernate_User_Guide.adoc index 01e738fc3f8a..e3f87461dd47 100644 --- a/documentation/src/main/asciidoc/userguide/Hibernate_User_Guide.adoc +++ b/documentation/src/main/asciidoc/userguide/Hibernate_User_Guide.adoc @@ -31,6 +31,7 @@ include::chapters/caching/Caching.adoc[] include::chapters/events/Events.adoc[] include::chapters/query/hql/Query.adoc[] include::chapters/query/hql/QueryLanguage.adoc[] +include::chapters/query/programmatic/QuerySpecification.adoc[] include::chapters/query/criteria/Criteria.adoc[] include::chapters/query/criteria/CriteriaExtensions.adoc[] include::chapters/query/native/Native.adoc[] diff --git a/documentation/src/main/asciidoc/userguide/appendices/extras/timestamp_version.xml b/documentation/src/main/asciidoc/userguide/appendices/extras/timestamp_version.xml index 9100ddfe3a6d..b1afffeb3f82 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/extras/timestamp_version.xml +++ b/documentation/src/main/asciidoc/userguide/appendices/extras/timestamp_version.xml @@ -1,8 +1,6 @@ . + ~ SPDX-License-Identifier: Apache-2.0 + ~ Copyright Red Hat Inc. and Hibernate Authors --> >. +==== + +Considering we have a `Customer` entity, when annotating it with the `Audited` annotation, +Hibernate is going to generate the following tables using the `hibernate.hbm2ddl.auto` schema tool: + +[[envers-audited-mapping-example]] +.Basic Envers entity mapping +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/DefaultAuditTest.java[tags=envers-audited-mapping-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-audited-mapping-example.sql[] +---- +==== + +Instead of annotating the whole class and auditing all properties, you can annotate only some persistent properties with `@Audited`. +This will cause only these properties to be audited. + +Now, considering the previous `Customer` entity, +let's see how Envers auditing works when inserting, updating, and deleting the entity in question. + +[[envers-audited-insert-example]] +.Auditing the entity `INSERT` operation +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/DefaultAuditTest.java[tags=envers-audited-insert-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-audited-insert-example.sql[] +---- +==== + +[[envers-audited-update-example]] +.Auditing the entity `UPDATE` operation +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/DefaultAuditTest.java[tags=envers-audited-update-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-audited-update-example.sql[] +---- +==== + +[[envers-audited-delete-example]] +.Auditing the entity `DELETE` operation +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/DefaultAuditTest.java[tags=envers-audited-delete-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-audited-delete-example.sql[] +---- +==== + +The `REVTYPE` column value is taken from the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/envers/RevisionType.html[`RevisionType`] Enum. + +[[envers-revtype-column]] +.`REVTYPE` column values +[width="100%",cols="20%,20%,60%",] +|================================= +|Database column value |Associated `RevisionType` Enum value |Description +|0 | `ADD` |A database table row was inserted. +|1 | `MOD` |A database table row was updated. +|2 | `DEL` |A database table row was deleted. +|================================= + +The audit (history) of an entity can be accessed using the `AuditReader` interface, which can be obtained by having an open `EntityManager` or `Session` via the `AuditReaderFactory`. + +[[envers-audited-revisions-example]] +.Getting a list of revisions for the `Customer` entity +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/DefaultAuditTest.java[tags=envers-audited-revisions-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-audited-revisions-example.sql[] +---- +==== + +Using the previously fetched revisions, we can now inspect the state of the `Customer` entity at that particular revision: + +[[envers-audited-rev1-example]] +.Getting the first revision for the `Customer` entity +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/DefaultAuditTest.java[tags=envers-audited-rev1-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-audited-rev1-example.sql[] +---- +==== + +When executing the aforementioned SQL query, there are two parameters: + +revision_number:: +The first parameter marks the revision number we are interested in or the latest one that exists up to this particular revision. +revision_type:: +The second parameter specifies that we are not interested in `DEL` `RevisionType` so that deleted entries are filtered out. + +The same goes for the second revision associated with the `UPDATE` statement. + +[[envers-audited-rev2-example]] +.Getting the second revision for the `Customer` entity +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/DefaultAuditTest.java[tags=envers-audited-rev2-example] +---- +==== + +For the deleted entity revision, Envers throws a `NoResultException` since the entity was no longer valid at that revision. + +[[envers-audited-rev3-example]] +.Getting the third revision for the `Customer` entity +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/DefaultAuditTest.java[tags=envers-audited-rev3-example] +---- +==== + +You can use the +https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/envers/query/AuditQueryCreator.html#forEntitiesAtRevision-java.lang.Class-java.lang.String-java.lang.Number-boolean-[`forEntitiesAtRevision(Class cls, String entityName, Number revision, boolean includeDeletions)`] +method to get the deleted entity revision so that, instead of a `NoResultException`, +all attributes, except for the entity identifier, are going to be `null`. + +[[envers-audited-rev4-example]] +.Getting the third revision for the `Customer` entity without getting a `NoResultException` +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/DefaultAuditTest.java[tags=envers-audited-rev4-example] +---- +==== + +See the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/envers/AuditReader.html[Javadocs] for details on other functionality offered. + +[[envers-configuration]] +=== Configuration Properties + +It is possible to configure various aspects of Hibernate Envers behavior, such as table names, etc. + +`*org.hibernate.envers.audit_table_prefix*`:: +String that will be prepended to the name of an audited entity to create the name of the entity and that will hold audit information. + +`*org.hibernate.envers.audit_table_suffix`* (default: `_AUD`):: +String that will be appended to the name of an audited entity to create the name of the entity and that will hold audit information. ++ +If you audit an entity with a table name Person, in the default setting Envers will generate a `Person_AUD` table to store historical data. + +`*org.hibernate.envers.revision_field_name*` (default: `REV`):: +Name of a field in the audit entity that will hold the revision number. + +`*org.hibernate.envers.revision_type_field_name*` (default: `REVTYPE` ):: +Name of a field in the audit entity that will hold the type of the revision (currently, this can be: `add`, `mod`, `del`). + +`*org.hibernate.envers.revision_on_collection_change*` (default: `true` ):: +Should a revision be generated when a not-owned relation field changes (this can be either a collection in a one-to-many relation or the field using `mappedBy` attribute in a one-to-one relation). + +`*org.hibernate.envers.do_not_audit_optimistic_locking_field*` (default: `true` ):: +When true, properties to be used for optimistic locking, annotated with `@Version`, will not be automatically audited (their history won't be stored; it normally doesn't make sense to store it). + +`*org.hibernate.envers.store_data_at_delete*` (default: `false` ):: +Should the entity data be stored in the revision when the entity is deleted (instead of only storing the id and all other properties as null). ++ +This is not normally needed, as the data is present in the last-but-one revision. +Sometimes, however, it is easier and more efficient to access it in the last revision (then the data that the entity contained before deletion is stored twice). + +`*org.hibernate.envers.default_schema*` (default: `null` - same schema as the table being audited):: +The default schema name that should be used for audit tables. ++ +Can be overridden using the `@AuditTable( schema = "..." )` annotation. ++ +If not present, the schema will be the same as the schema of the table being audited. + +`*org.hibernate.envers.default_catalog*` (default: `null` - same catalog as the table being audited):: +The default catalog name that should be used for audit tables. ++ +Can be overridden using the `@AuditTable( catalog = "..." )` annotation. ++ +If not present, the catalog will be the same as the catalog of the normal tables. + +`*org.hibernate.envers.audit_strategy*`(default: `org.hibernate.envers.strategy.DefaultAuditStrategy` ):: +The audit strategy that should be used when persisting audit data. +The default stores only the revision, at which an entity was modified. ++ +An alternative, the `org.hibernate.envers.strategy.ValidityAuditStrategy` stores both the start revision and the end revision. +Together these define when an audit row was valid, hence the name ValidityAuditStrategy. + +`*org.hibernate.envers.audit_strategy_validity_end_rev_field_name*` (default: `REVEND`):: +The column name that will hold the end revision number in audit entities. +This property is only valid if the validity audit strategy is used. + +`*org.hibernate.envers.audit_strategy_validity_store_revend_timestamp*`(default: `false` ):: +Should the timestamp of the end revision be stored, until which the data was valid, in addition to the end revision itself. +This is useful to be able to purge old Audit records out of a relational database by using table partitioning. ++ +Partitioning requires a column that exists within the table. +This property is only evaluated if the `ValidityAuditStrategy` is used. + +`*org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name*`(default: `REVEND_TSTMP` ):: +Column name of the timestamp of the end revision until which the data was valid. +Only used if the `ValidityAuditStrategy` is used, and `org.hibernate.envers.audit_strategy_validity_store_revend_timestamp` evaluates to true. + +`*org.hibernate.envers.audit_strategy_validity_revend_timestamp_numeric*`(default: `false` ):: +Boolean flag that controls whether the revision end timestamp field is treated as a `Long` data type. +Only used if the `ValidityAuditStrategy` is used, and `org.hibernate.envers.audit_strategy_validity_store_revend_timestamp` evaluates to true. + +`*org.hibernate.envers.audit_strategy_validity_revend_timestamp_legacy_placement*`(default: `true` ):: +Boolean flag that controls whether the revision end timestamp field is propagated to the joined subclass audit tables. +Only used if the `ValidityAuditStrategy` is used, and `org.hibernate.envers.audit_strategy_validity_store_revend_timestamp` evaluates to true. ++ +When set to `true`, the legacy mapping behavior is used such that the revision end timestamp is only maintained in the root entity audit table. +When set to `false`, the revision end timestamp is maintained in both the root entity and joined subclass audit tables; allowing the potential to apply database partitioning to the joined subclass tables just like the root entity audit tables. + +[[envers-config-native-id]] +`*org.hibernate.envers.use_revision_entity_with_native_id*` (default: `true` ):: +Boolean flag that determines the strategy of revision number generation. +Default implementation of revision entity uses native identifier generator. ++ +If the current database engine does not support identity columns, users are advised to set this property to false. ++ +In this case revision numbers are created by a preconfigured `org.hibernate.id.enhanced.SequenceStyleGenerator`. + +[[envers-config-track-entities]] +`*org.hibernate.envers.track_entities_changed_in_revision*` (default: `false` ):: +Should entity types, that have been modified during each revision, be tracked. +The default implementation creates `REVCHANGES` table that stores entity names of modified persistent objects. +Single record encapsulates the revision identifier (foreign key to `REVINFO` table) and a string value. +For more information, refer to <> and <>. + +`*org.hibernate.envers.global_with_modified_flag*` (default: `false`, can be individually overridden with `@Audited( withModifiedFlag = true )` ):: +Should property modification flags be stored for all audited entities and all properties. ++ +When set to true, for all properties an additional boolean column in the audit tables will be created, filled with information if the given property changed in the given revision. ++ +When set to false, such column can be added to selected entities or properties using the `@Audited` annotation. ++ +For more information, refer to <> and <>. + +`*org.hibernate.envers.modified_flag_suffix*` (default: `_MOD` ):: +The suffix for columns storing "Modified Flags". ++ +For example, a property called "age", will by default get modified flag with column name "age_MOD". + +`*org.hibernate.envers.modified_column_naming_strategy*` (default: `org.hibernate.envers.boot.internal.LegacyModifiedColumnNamingStrategy` ):: +The naming strategy to be used for modified flag columns in the audit metadata. + +`*org.hibernate.envers.embeddable_set_ordinal_field_name*` (default: `SETORDINAL` ):: +Name of column used for storing ordinal of the change in sets of embeddable elements. + +`*org.hibernate.envers.cascade_delete_revision*` (default: `false` ):: +While deleting revision entry, remove data of associated audited entities. Requires database support for cascade row removal. + +`*org.hibernate.envers.allow_identifier_reuse*` (default: `false` ):: +Guarantees proper validity audit strategy behavior when application reuses identifiers of deleted entities. Exactly one row with `null` end date exists for each identifier. + +`*org.hibernate.envers.original_id_prop_name*` (default: `originalId` ):: +Specifies the composite-id key property name used by the audit table mappings. + +`*org.hibernate.envers.find_by_revision_exact_match*` (default: `false` ):: +Specifies whether or not `AuditReader#find` methods which accept a revision-number argument are to find results based on fuzzy-match or exact-match behavior. ++ +The old (legacy) behavior has always been to perform a fuzzy-match where these methods would return a match if any revision existed for the primary-key with a revision-number less-than or equal-to the revision method argument. +This behavior is great when you want to find the snapshot of a non-related entity based on another entity's revision number. ++ +The new (optional) behavior when this option is enabled forces the query to perform an exact-match instead. +In order for these methods to return a non-`null` value, a revision entry must exist for the entity with the specified primary key and revision number; otherwise the result will be `null`. + +`*org.hibernate.envers.global_relation_not_found_legacy_flag*` (default: `true` ):: +Globally defines whether legacy relation not-found behavior should be used or not. ++ +By specifying `true`, any `EntityNotFoundException` errors will be thrown unless the `Audited` annotation explicitly specifies to _ignore_ not-found relations. +By specifying `false`, any `EntityNotFoundException` will be be ignored unless the `Audited` annotation explicitly specifies to _raise the error_ rather than silently ignore not-found relations. + +[IMPORTANT] +==== +The following configuration options have been added recently and should be regarded as experimental: + +. `org.hibernate.envers.track_entities_changed_in_revision` +. `org.hibernate.envers.modified_flag_suffix` +. `org.hibernate.envers.modified_column_naming_strategy` +. `org.hibernate.envers.original_id_prop_name` +. `org.hibernate.envers.find_by_revision_exact_match` +. `org.hibernate.envers.audit_strategy_validity_revend_timestamp_numeric` +. `org.hibernate.envers.global_relation_not_found_legacy_flag` +==== + +[[envers-additional-mappings]] +=== Additional mapping annotations + +The name of the audit table can be set on a per-entity basis, using the `@AuditTable` annotation. +It may be tedious to add this annotation to every audited entity, so if possible, it's better to use a prefix/suffix. + +If you have a mapping with secondary tables, audit tables for them will be generated in the same way (by adding the prefix and suffix). +If you wish to overwrite this behavior, you can use the `@SecondaryAuditTable` and `@SecondaryAuditTables` annotations. + +If you have a mapping with collection tables, the audit table for them will be generated in the same way (by using the prefix and suffix). +If you wish to overwrite this behavior, you can use the `@CollectionAuditTable` annotations. + +If you'd like to override auditing behavior of some fields/properties inherited from `@MappedSuperclass` or in an embedded component, +you can apply the `@AuditOverride` annotation on the subtype or usage site of the component. + +If you want to audit a relation mapped with `@OneToMany` and `@JoinColumn`, +please see <> for a description of the additional `@AuditJoinTable` annotation that you'll probably want to use. + +If you want to audit a relation, where the target entity is not audited (that is the case for example with dictionary-like entities, which don't change and don't have to be audited), +just annotate it with `@Audited( targetAuditMode = RelationTargetAuditMode.NOT_AUDITED )`. +Then, while reading historic versions of your entity, the relation will always point to the "current" related entity. +By default Envers throws `jakarta.persistence.EntityNotFoundException` when "current" entity does not exist in the database. +Apply `@NotFound( action = NotFoundAction.IGNORE )` annotation to silence the exception and assign null value instead. +The hereby solution causes implicit eager loading of to-one relations. + +If you'd like to audit properties of a superclass of an entity, which are not explicitly audited (they don't have the `@Audited` annotation on any properties or on the class), +you can set the `@AuditOverride( forClass = SomeEntity.class, isAudited = true/false )` annotation. + +[NOTE] +==== +The `@Audited` annotation also features an `auditParents` attribute but it's now deprecated in favor of `@AuditOverride`. +==== + +[[envers-audit-strategy]] +=== Choosing an audit strategy + +After the basic configuration, it is important to choose the audit strategy that will be used to persist and retrieve audit information. +There is a trade-off between the performance of persisting and the performance of querying the audit information. +Currently, there are two audit strategies. + +. The default audit strategy persists the audit data together with a start revision. +For each row inserted, updated or deleted in an audited table, one or more rows are inserted in the audit tables, together with the start revision of its validity. +Rows in the audit tables are never updated after insertion. +Queries of audit information use subqueries to select the applicable rows in the audit tables. ++ +IMPORTANT: These subqueries are notoriously slow and difficult to index. + +. The alternative is a validity audit strategy. +This strategy stores the start-revision and the end-revision of audit information. +For each row inserted, updated or deleted in an audited table, one or more rows are inserted in the audit tables, together with the start revision of its validity. +But at the same time, the end-revision field of the previous audit rows (if available) is set to this revision. +Queries on the audit information can then use 'between start and end revision' instead of subqueries as used by the default audit strategy. ++ +The consequence of this strategy is that persisting audit information will be a bit slower because of the extra updates involved, +but retrieving audit information will be a lot faster. ++ +IMPORTANT: This can be improved even further by adding extra indexes. + +[[envers-audit-ValidityAuditStrategy]] +==== Configuring the `ValidityAuditStrategy` + +To better visualize how the `ValidityAuditStrategy` works, consider the following exercise where +we replay the previous audit logging example for the `Customer` entity. + +First, you need to configure the `ValidityAuditStrategy`: + +[[envers-audited-validity-configuration-example]] +.Configuring the `ValidityAuditStrategy` +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/ValidityStrategyAuditTest.java[tags=envers-audited-validity-configuration-example] +---- +==== + +If, you're using the `persistence.xml` configuration file, +then the mapping will look as follows: + +[source, XML, indent=0] +---- + +---- + +Once you configured the `ValidityAuditStrategy`, the following schema is going to be automatically generated: + +[[envers-audited-validity-mapping-example]] +.Envers schema for the `ValidityAuditStrategy` +==== +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-audited-validity-mapping-example.sql[] +---- +==== + +As you can see, the `REVEND` column is added as well as its foreign key to the `REVINFO` table. + +When rerunning the previous `Customer` audit log queries against the `ValidityAuditStrategy`, +we get the following results: + +[[envers-audited-validity-rev1-example]] +.Getting the first revision for the `Customer` entity +==== +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-audited-validity-rev1-example.sql[] +---- +==== + +[NOTE] +==== +Compared to the default strategy, the `ValidityAuditStrategy` generates simpler queries that can render better SQL execution plans. +==== + +[[envers-revisionlog]] +=== Revision Log + +When Envers starts a new revision, it creates a new revision entity which stores information about the revision. + +By default, that includes just: + +revision number:: +An integral value (`int/Integer` or `long/Long`). Essentially, the primary key of the revision. ++ +[WARNING] +==== +A revision number value should **always** be increasing and never overflows. + +The default implementations provided by Envers use an `int` data type which has an upper bounds of `Integer.MAX_VALUE`. +It is critical that users consider whether this upper bounds is feasible for your application. If a large range is needed, consider using a custom revision entity mapping using a `long` data type. + +In the event that the revision number reaches its upper bounds wrapping around becoming negative, an `AuditException` will be thrown causing the current transaction to be rolled back. +This guarantees that the audit history remains in a valid state that can be queried by the Envers Query API. +==== + +revision timestamp:: +Either a `long/Long` or `java.util.Date` value representing the instant at which the revision was made. +When using a `java.util.Date`, instead of a `long/Long` for the revision timestamp, take care not to store it to a column data type which will lose precision. + +Envers handles this information as an entity. + +[[envers-default-revision-entity]] +==== Default Revision Entity + +By default, Envers uses its own internal class to act as the entity, mapped to the `REVINFO` table. +The entity type that's used depends on a couple configuration properties: <> and <>. Here is a table showing the entity type used based on the configuration values: +[cols="1,1,1"] +|=== +| +| native-id `false` +| native-id `true` + +| track-entities `false` +| `org.hibernate.envers.DefaultRevisionEntity` +| `org.hibernate.envers.enhanced.SequenceIdRevisionEntity` + +| track-entities `true` +| `org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity` +| `org.hibernate.envers.enhanced.SequenceIdTrackingModifiedEntitiesRevisionEntity` +|=== + +[[envers-custom-revision-entity]] +==== Custom Revision Entity + +You can also supply your own approach to collecting this information which might be useful to capture additional details such as who made a change +or the IP address from which the request came. +There are two things you need to make this work: + +. First, you will need to tell Envers about the entity you wish to use. +Your entity must use the `@org.hibernate.envers.RevisionEntity` annotation. +It must define the two attributes described above annotated with `@org.hibernate.envers.RevisionNumber` and `@org.hibernate.envers.RevisionTimestamp`, respectively. +You can extend from any of the revision mapped superclass types, if you wish, to inherit all these required behaviors: + + org.hibernate.envers.RevisionMapping + org.hibernate.envers.TrackingModifiedEntitiesRevisionMapping + org.hibernate.envers.enhanced.SequenceIdRevisionMapping + org.hibernate.envers.enhanced.SequenceIdTrackingModifiedEntitiesRevisionMapping + ++ +Simply add the custom revision entity as you do your normal entities and Envers will *find it*. ++ +To understand which mapping you should extend based on configuration see the <> paragraph. ++ +NOTE: It is an error for there to be multiple entities marked as `@org.hibernate.envers.RevisionEntity`. + +. Second, you need to tell Envers how to create instances of your revision entity which is handled by the +https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/envers/RevisionListener.html#newRevision-java.lang.Object-[`newRevision( Object revisionEntity )`] +method of the `org.hibernate.envers.RevisionListener` interface. ++ +You tell Envers your custom `org.hibernate.envers.RevisionListener` implementation to use by specifying it on the `@org.hibernate.envers.RevisionEntity` annotation, using the value attribute. +If your `RevisionListener` class is inaccessible from `@RevisionEntity` (e.g. it exists in a different module), +set `org.hibernate.envers.revision_listener` property to its fully qualified class name. +Class name defined by the configuration parameter overrides the revision entity's value attribute. + +Considering we have a `CurrentUser` utility which stores the currently logged user: + +[[envers-revisionlog-CurrentUser-example]] +.`CurrentUser` utility +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/CustomRevisionEntityTest.java[tags=envers-revisionlog-CurrentUser-example] +---- +==== + +Now, we need to provide a custom `@RevisionEntity` to store the currently logged user + +[[envers-revisionlog-RevisionEntity-example]] +.Custom `@RevisionEntity` example +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/CustomRevisionEntityTest.java[tags=envers-revisionlog-RevisionEntity-example] +---- +==== + +With the custom `RevisionEntity` implementation in place, +we only need to provide the `RevisionEntity` implementation which acts as a factory +of `RevisionEntity` instances. + +[[envers-revisionlog-RevisionListener-example]] +.Custom `@RevisionListener` example +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/CustomRevisionEntityTest.java[tags=envers-revisionlog-RevisionListener-example] +---- +==== + +When generating the database schema, Envers creates the following `RevisionEntity` table: + +[[envers-revisionlog-custom-revision-entity-table-example]] +.Auto-generated `RevisionEntity` Envers table +==== +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-revisionlog-custom-revision-entity-table-example.sql[] +---- +==== + +You can see the `username` column in place. + +Now, when inserting a `Customer` entity, Envers generates the following statements: + +[[envers-revisionlog-RevisionEntity-persist-example]] +.Auditing using the custom `@RevisionEntity` instance +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/CustomRevisionEntityTest.java[tags=envers-revisionlog-RevisionEntity-persist-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-revisionlog-RevisionEntity-persist-example.sql[] +---- +==== + +As demonstrated by the example above, the username is properly set and propagated to the `CUSTOM_REV_INFO` table. + +[WARNING] +==== +**This strategy is deprecated since version 5.2. The alternative is to use dependency injection offered as of version 5.3.** + +An alternative method to using the `org.hibernate.envers.RevisionListener` is to instead call the +[line-through]#https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/envers/AuditReader.html#getCurrentRevision-java.lang.Class-boolean-[`getCurrentRevision( Class revisionEntityClass, boolean persist )`]# +method of the `org.hibernate.envers.AuditReader` interface to obtain the current revision, +and fill it with desired information. + +The method accepts a `persist` parameter indicating whether the revision entity should be persisted prior to returning from this method: + +`true`:: ensures that the returned entity has access to its identifier value (revision number), but the revision entity will be persisted regardless of whether there are any audited entities changed. +`false`:: means that the revision number will be `null`, but the revision entity will be persisted only if some audited entities have changed. +==== + +[NOTE] +==== +As of Hibernate Envers 5.3, dependency injection is now supported for a `RevisionListener`. + +This feature is up to the various dependency frameworks, such as CDI and Spring, to supply the +necessary implementation during Hibernate ORM bootstrap to support injection. If no qualifying +implementation is supplied, the `RevisionListener` will be constructed without injection. +==== + +[[envers-tracking-modified-entities-revchanges]] +=== Tracking entity names modified during revisions + +By default, entity types that have been changed in each revision are not being tracked. +This implies the necessity to query all tables storing audited data in order to retrieve changes made during the specified revision. +Envers provides a simple mechanism that creates `REVCHANGES` table which stores entity names of modified persistent objects. +Single record encapsulates the revision identifier (foreign key to `REVINFO` table) and a string value. + +Tracking of modified entity names can be enabled in three different ways: + +. Set `org.hibernate.envers.track_entities_changed_in_revision` parameter to `true`. + In this case `org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity` will be implicitly used as the revision log entity. +. Create a custom revision entity that extends `org.hibernate.envers.DefaultTrackingModifiedEntitiesRevisionEntity` class. ++ +[source, java, indent=0] +---- +include::{example-dir-envers}/EntityTypeChangeAuditDefaultTrackingTest.java[tags=envers-tracking-modified-entities-revchanges-example] +---- ++ +. Mark an appropriate field of a custom revision entity with `@org.hibernate.envers.ModifiedEntityNames` annotation. + The property is required to be of `Set` type. ++ +[source, java, indent=0] +---- +include::{example-dir-envers}/EntityTypeChangeAuditTest.java[tags=envers-tracking-modified-entities-revchanges-example] +---- + +Considering we have a `Customer` entity illustrated by the following example: + +[[envers-tracking-modified-entities-revchanges-before-rename-example]] +.`Customer` entity before renaming +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/EntityTypeChangeAuditTest.java[tags=envers-tracking-modified-entities-revchanges-before-rename-example] +---- +==== + +If the `Customer` entity class name is changed to `ApplicationCustomer`, +Envers is going to insert a new record in the `REVCHANGES` table with the previous entity class name: + +[[envers-tracking-modified-entities-revchanges-after-rename-example]] +.`Customer` entity after renaming +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/EntityTypeChangeAuditTest.java[tags=envers-tracking-modified-entities-revchanges-after-rename-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-tracking-modified-entities-revchanges-after-rename-example.sql[] +---- +==== + +Users, that have chosen one of the approaches listed above, +can retrieve all entities modified in a specified revision by utilizing API described in <>. + +Users are also allowed to implement custom mechanisms of tracking modified entity types. +In this case, they shall pass their own implementation of `org.hibernate.envers.EntityTrackingRevisionListener` +interface as the value of `@org.hibernate.envers.RevisionEntity` annotation. + +`EntityTrackingRevisionListener` interface exposes one method that notifies whenever audited entity instance has been +added, modified or removed within current revision boundaries. + +[[envers-tracking-modified-entities-revchanges-EntityTrackingRevisionListener-example]] +.The `EntityTrackingRevisionListener` implementation +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/EntityTypeChangeAuditTrackingRevisionListenerTest.java[tags=envers-tracking-modified-entities-revchanges-EntityTrackingRevisionListener-example] +---- +==== + +The `CustomTrackingRevisionListener` adds the fully-qualified class name to the `modifiedEntityTypes` attribute of the `CustomTrackingRevisionEntity`. + +[[envers-tracking-modified-entities-revchanges-RevisionEntity-example]] +.The `RevisionEntity` using the custom `EntityTrackingRevisionListener` +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/EntityTypeChangeAuditTrackingRevisionListenerTest.java[tags=envers-tracking-modified-entities-revchanges-RevisionEntity-example] +---- +==== + +The `CustomTrackingRevisionEntity` contains a `@OneToMany` list of `ModifiedTypeRevisionEntity` + +[[envers-tracking-modified-entities-revchanges-EntityType-example]] +.The `EntityType` encapsulates the entity type name before a class name modification +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/EntityTypeChangeAuditTrackingRevisionListenerTest.java[tags=envers-tracking-modified-entities-revchanges-EntityType-example] +---- +==== + +Now, when fetching the `CustomTrackingRevisionEntity`, you can get access to the previous entity class name. + +[[envers-tracking-modified-entities-revchanges-query-example]] +.Getting the `EntityType` through the `CustomTrackingRevisionEntity` +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/EntityTypeChangeAuditTrackingRevisionListenerTest.java[tags=envers-tracking-modified-entities-revchanges-query-example] +---- +==== + +[[envers-tracking-properties-changes]] +=== Tracking entity changes at the property level + +By default, the only information stored by Envers are revisions of modified entities. +This approach lets users create audit queries based on historical values of entity properties. +Sometimes it is useful to store additional metadata for each revision, when you are interested also in the type of changes, not only about the resulting values. + +The feature described in <> makes it possible to tell which entities were modified in a given revision. + +The feature described here takes it one step further. +_Modification Flags_ enable Envers to track which properties of audited entities were modified in a given revision. + +Tracking entity changes at the property level can be enabled by: + +. setting `org.hibernate.envers.global_with_modified_flag` configuration property to `true`. + This global switch will cause adding modification flags to be stored for all audited properties of all audited entities. + +. using `@Audited( withModifiedFlag = true )` on a property or on an entity. + +The trade-off coming with this functionality is an increased size of audit tables and a very little, almost negligible, performance drop during audit writes. +This is due to the fact that every tracked property has to have an accompanying boolean column in the schema that stores information about the property modifications. +Of course, it is Enver's job to fill these columns accordingly - no additional work by the developer is required. +Because of costs mentioned, it is recommended to enable the feature selectively, when needed with use of the granular configuration means described above. + +[[envers-tracking-properties-changes-mapping-example]] +.Mapping for tracking entity changes at the property level +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/ModifiedFlagsAuditTest.java[tags=envers-tracking-properties-changes-mapping-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-tracking-properties-changes-mapping-example.sql[] +---- +==== + +As you can see, every property features a `_MOD` column (e.g. `createdOn_MOD`) in the audit log. + +[[envers-tracking-properties-changes-example]] +.Tracking entity changes at the property level example +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/ModifiedFlagsAuditTest.java[tags=envers-tracking-properties-changes-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-tracking-properties-changes-example.sql[] +---- +==== + +To see how "Modified Flags" can be utilized, check out the very simple query API that uses them: <>. + +[[envers-tracking-properties-changes-strategy]] +=== Selecting strategy for tracking property level changes + +By default, Envers uses the `legacy` modified column naming strategy. +This strategy is designed to add columns based on the following rule-set: + +. If property is annotated with `@Audited` and the _modifiedColumnName_ attribute is specified, the column will directly be based on the supplied name. +. If property is not annotated with `@Audited` or if no _modifiedColumnName_ attribute is given, the column will be named after the java class property, appended with the configured suffix, the default being `_MOD`. + +While this strategy has no performance drawbacks, it does present concerns for users who prefer consistency without verbosity. +Lets take the following entity mapping as an example. + +``` +@Audited(withModifiedFlags = true) +@Entity +public class Customer { + @Id + private Integer id; + @Column(name = "customer_name") + private String name; +} +``` + +This mapping will actually lead to some inconsistent naming between columns, see below for how the model's name will be stored in `customer_name` but the modified column that tracks whether this column changes between revisions is named `name_MOD`. + +``` +CREATE TABLE Customer_AUD ( + id bigint not null, + REV integer not null, + REVTYPE tinyint not null, + customer_name varchar(255), + name_MOD boolean, + primary key(id, REV) +) +``` + +An additional strategy called `improved`, aims to address these inconsistent column naming concerns. +This strategy uses the following rule-set: + +. Property is a Basic type (Single Column valued property) +.. Use the _modifiedColumnName_ directly if one is supplied on the property mapping +.. Otherwise use the resolved ORM column name appended with the modified flag suffix configured value +. Property is an Association (to-one mapping) with a Foreign Key using a single column +.. Use the _modifiedColumnName_ directly if one is supplied on the property mapping +.. Otherwise use the resolved ORM column name appended with the modified flag suffix configured value +. Property is an Association (to-one mapping) with a Foreign Key using multiple columns +.. Use the _modifiedColumnName_ directly if one is supplied on the property mapping +.. Otherwise use the property name appended with the modified flag suffix configured value +. Property is an Embeddable +.. Use the _modifiedColumnName_ directly if one is supplied on the property mapping +.. Otherwise use the property name appended with the modified flag suffix configured value + +While using this strategy, the same `Customer` mapping will generate the following table schema: + +``` +CREATE TABLE Customer_AUD ( + id bigint not null, + REV integer not null, + REVTYPE tinyint not null, + customer_name varchar(255), + customer_name_MOD boolean, + primary key(id, REV) +) +``` + +When already using Envers in conjunction with the modified columns flag feature, it is advised not to enable the new strategy immediately as schema changes would be required. +You will need to either migrate your existing schema manually to adhere to the rules above or use the explicit _modifiedColumnName_ attribute on the `@Audited` annotation for existing columns that use the feature. + +To configure a custom strategy implementation or use the improved strategy, the configuration option `org.hibernate.envers.modified_column_naming_strategy` will need to be set. +This option can be the fully qualified class name of a `ModifiedColumnNameStrategy` implementation or `legacy` or `improved` for either of the two provided implementations. + +[[envers-queries]] +=== Queries + +You can think of historic data as having two dimensions: + +horizontal:: The state of the database at a given revision. Thus, you can query for entities as they were at revision N. +vertical:: The revisions, at which entities changed. Hence, you can query for revisions, in which a given entity changed. + +The queries in Envers are similar to Hibernate Criteria queries, so if you are familiar with them, using Envers queries will be much easier. + +The main limitation of the current queries implementation is that you cannot traverse relations. +You can only specify constraints on the ids of the related entities, and only on the "owning" side of the relation. +This, however, will be changed in future releases. + +[NOTE] +==== +The queries on the audited data will be in many cases much slower than corresponding queries on "live" data, +as, especially for the default audit strategy, they involve correlated subselects. + +Queries are improved both in terms of speed and possibilities when using the validity audit strategy, +which stores both start and end revisions for entities. See <> for a more detailed discussion. +==== + +[[entities-at-revision]] +=== Querying for entities of a class at a given revision + +The entry point for this type of queries is: + +[[entities-at-revision-example]] +.Getting the `Customer` entity at a given revision +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=entities-at-revision-example] +---- +==== + +[[entities-filtering]] +=== Querying for entities using filtering criteria + +You can then specify constraints, which should be met by the entities returned, by adding restrictions, +which can be obtained using the `AuditEntity` factory class. + +For example, to select only entities where the `firstName` property is equal to "John": + +[[entities-filtering-example]] +.Getting the `Customer` audit log with a given `firstName` attribute value +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=entities-filtering-example] +---- +==== + +And, to select only entities whose relationships are related to a given entity, +you can use either the target entity or its identifier. + +[[entities-filtering-by-entity-example]] +.Getting the `Customer` entities whose `address` attribute matches the given entity reference +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=entities-filtering-by-entity-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/entities-filtering-by-entity-example.sql[] +---- +==== + +The same SQL is generated even if we provide the identifier instead of the target entity reference. + +[[entities-filtering-by-entity-identifier-example]] +.Getting the `Customer` entities whose `address` identifier matches the given entity identifier +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=entities-filtering-by-entity-identifier-example] +---- +==== + +Apart from strict equality matching, you can also use an `IN` clause to provide multiple entity identifiers: + +[[entities-in-clause-filtering-by-entity-identifier-example]] +.Getting the `Customer` entities whose `address` identifier matches one of the given entity identifiers +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=entities-in-clause-filtering-by-entity-identifier-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/entities-in-clause-filtering-by-entity-identifier-example.sql[] +---- +==== + +You can limit the number of results, order them, and set aggregations and projections (except grouping) in the usual way. +When your query is complete, you can obtain the results by calling the `getSingleResult()` or `getResultList()` methods. + +A full query, can look for example like this: + +[[entities-filtering-and-pagination]] +.Getting the `Customer` entities using filtering and pagination +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=entities-filtering-and-pagination] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/entities-filtering-and-pagination.sql[] +---- +==== + +[[revisions-of-entity]] +=== Querying for revisions, at which entities of a given class changed + +The entry point for this type of queries is: + +[[revisions-of-entity-query-example]] +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=revisions-of-entity-query-example] +---- + +You can add constraints to this query in the same way as to the previous one. + +There are some additional possibilities: + +. using `AuditEntity.revisionNumber()` you can specify constraints, projections and order on the revision number, in which the audited entity was modified. + +. similarly, using `AuditEntity.revisionProperty( propertyName )` you can specify constraints, projections and order on a property of the revision entity, + corresponding to the revision in which the audited entity was modified. + +. `AuditEntity.revisionType()` gives you access as above to the type of the revision (`ADD`, `MOD`, `DEL`). + +Using these methods, you can order the query results by revision number, set projection or constraint the revision number to be greater or less than a specified value, etc. +For example, the following query will select the smallest revision number, at which entity of class `MyEntity` with id `entityId` has changed, after revision number 2: + +[[revisions-of-entity-query-by-revision-number-example]] +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=revisions-of-entity-query-by-revision-number-example] +---- + +The second additional feature you can use in queries for revisions is the ability to _maximize_/_minimize_ a property. + +For example, if you want to select the smallest possible revision at which the value of the `createdOn` +attribute was larger than a given value, +you can run the following query: + +[[revisions-of-entity-query-minimize-example]] +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=revisions-of-entity-query-minimize-example] +---- + +The `minimize()` and `maximize()` methods return a criterion, to which you can add constraints, +which must be met by the entities with the _maximized_/_minimized_ properties. + +You probably also noticed that there are two boolean parameters, passed when creating the query. + +`selectEntitiesOnly`:: The first parameter is only valid when you don't set an explicit projection. ++ +If true, the result of the query will be a list of entities (which changed at revisions satisfying the specified constraints). ++ +If false, the result will be a list of three element arrays: + +* the first element will be the changed entity instance. +* the second will be an entity containing revision data (if no custom entity is used, this will be an instance of the <>). +* the third will be the type of the revision (one of the values of the `RevisionType` enumeration: `ADD`, `MOD`, `DEL`). + +`selectDeletedEntities`:: The second parameter specifies if revisions, +in which the entity was deleted should be included in the results. ++ +If yes, such entities will have the revision type `DEL` and all attributes, except the `id`, will be set to `null`. + +Another useful feature is `AggregatedAuditExpression#computeAggregationInInstanceContext()`. This can be used to create +an aggregate query based on the entity instance primary key. + +For example, if you wanted to locate all customers but only wanted to retrieve the instances with the +maximum revision number, you would use the following query: + +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=aggregate-max-revision-with-entity-example] +---- + +In other words, the result set would contain a list of `Customer` instances, one per primary key. Each instance would +hold the audited property data at the _maximum_ revision number for each `Customer` primary key. + +[[envers-tracking-properties-changes-queries]] +=== Querying for entity revisions that modified a given property + +For the two types of queries described above it's possible to use special `Audit` criteria called `hasChanged()` and `hasNotChanged()` +that make use of the functionality described in <>. + +Let's have a look at various queries that can benefit from these two criteria. + +First, you must make sure that your entity can track _modification flags_: + +[[envers-tracking-properties-changes-queries-entity-example]] +.Valid only when audit logging tracks entity attribute modification flags +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditWithModifiedFlagTest.java[tags=envers-tracking-properties-changes-queries-entity-example] +---- +==== + +The following query will return all revisions of the `Customer` entity with the given `id`, +for which the `lastName` property has changed. + +[[envers-tracking-properties-changes-queries-hasChanged-example]] +.Getting all `Customer` revisions for which the `lastName` attribute has changed +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditWithModifiedFlagTest.java[tags=envers-tracking-properties-changes-queries-hasChanged-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-tracking-properties-changes-queries-hasChanged-example.sql[] +---- +==== + +Using this query we won't get all other revisions in which `lastName` wasn't touched. +From the SQL query you can see that the `lastName_MOD` column is being used in the WHERE clause, +hence the aforementioned requirement for tracking modification flags. + +Of course, nothing prevents users from combining `hasChanged` condition with some additional criteria. + +[[envers-tracking-properties-changes-queries-hasChanged-and-hasNotChanged-example]] +.Getting all `Customer` revisions for which the `lastName` attribute has changed and the `firstName` attribute has not changed +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditWithModifiedFlagTest.java[tags=envers-tracking-properties-changes-queries-hasChanged-and-hasNotChanged-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-tracking-properties-changes-queries-hasChanged-and-hasNotChanged-example.sql[] +---- +==== + +To get the `Customer` entities changed at a given `revisionNumber` with `lastName` modified and `firstName` untouched, +we have to use the `forEntitiesModifiedAtRevision` query: + +[[envers-tracking-properties-changes-queries-at-revision-example]] +.Getting the `Customer` entity for a given revision if the `lastName` attribute has changed and the `firstName` attribute has not changed +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditWithModifiedFlagTest.java[tags=envers-tracking-properties-changes-queries-at-revision-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-tracking-properties-changes-queries-at-revision-example.sql[] +---- +==== + +[[envers-tracking-obtain-properties-changed-queries]] +=== Querying for revisions of entity including property names that were modified + +[NOTE] +==== +This feature described here is still considered experimental. +It is subject to change in future releases based on user feedback to improve its usefulness. +==== + +Sometimes it may be useful to query entity revisions and also determine all the properties of that revision which +were modified without having to issue multiple queries using `hasChanged()` and `hasNotChanged()` criteria. + +You can now obtain this information easily by using the following query: + +.Querying entity revisions including property names modified. +==== +[source, java, indent=0] +---- +List results = AuditReaderFactory.get( entityManager ) + .createQuery() + .forRevisionsOfEntityWithChanges( Customer.class, false ) + .add( AuditEntity.id().eq( 1L ) ) + .getResultList(); + +for ( Object entry : results ) { + final Object[] array = (Object[]) entry; + final Set propertiesChanged = (Set) array[3]; + for ( String propertyName : propertiesChanged ) { + /* Do something useful with the modified property `propertyName` */ + } +} +---- +==== + +[[envers-tracking-modified-entities-queries]] +=== Querying for entity types modified in a given revision + +[NOTE] +==== +The methods described below can be used only when the default mechanism of tracking changed entity types is enabled (see <>). +==== + +This basic query allows retrieving entity names and corresponding Java classes changed in a specified revision: + +[[envers-tracking-modified-entities-queries-example]] +.Retrieving entity names and corresponding Java classes changed in a specified revision +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/EntityTypeChangeAuditTest.java[tags=envers-tracking-modified-entities-queries-example1] +---- + +[source, java, indent=0] +---- +include::{example-dir-envers}/EntityTypeChangeAuditTest.java[tags=envers-tracking-modified-entities-queries-example2] +---- +==== + +Other queries (also accessible from `org.hibernate.envers.CrossTypeRevisionChangesReader`): + +`List findEntities(Number)`:: + Returns snapshots of all audited entities changed (added, updated and removed) in a given revision. + Executes `N + 1` SQL queries, where `N` is a number of different entity classes modified within specified revision. + +`List findEntities(Number, RevisionType)`:: + Returns snapshots of all audited entities changed (added, updated or removed) in a given revision filtered by modification type. + Executes `N + 1` SQL queries, where `N` is a number of different entity classes modified within specified revision. + +`Map> findEntitiesGroupByRevisionType(Number)`:: + Returns a map containing lists of entity snapshots grouped by modification operation (e.g. addition, update and removal). + Executes `3N + 1` SQL queries, where `N` is a number of different entity classes modified within specified revision. + +[[envers-querying-entity-relation-joins]] +=== Querying for entities using entity relation joins + +[WARNING] +==== +Relation join queries are considered experimental and may change in future releases. +==== + +Audit queries support the ability to apply constraints, projections, and sort operations based on entity relations. In order +to traverse entity relations through an audit query, you must use the relation traversal API with a join type. + +[NOTE] +==== +Relation joins can be applied to `many-to-one` and `one-to-one` mappings only when using `JoinType.LEFT` or `JoinType.INNER`. +==== + +The basis for creating an entity relation join query is as follows: + +[[envers-querying-entity-relation-inner-join]] +.INNER JOIN entity audit query +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=envers-querying-entity-relation-inner-join] +---- +==== + +[[envers-querying-entity-relation-left-join]] +.LEFT JOIN entity audit query +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=envers-querying-entity-relation-left-join] +---- +==== + +Like any other query, constraints may be added to restrict the results. + +For example, to find all `Customer` entities at a given revision whose addresses are in `România`, +you can use the following query: + +[[envers-querying-entity-relation-join-restriction]] +.Filtering the join relation with a WHERE clause predicate +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditTest.java[tags=envers-querying-entity-relation-join-restriction] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-querying-entity-relation-join-restriction.sql[] +---- +==== + +It is also possible to traverse beyond the first relation in an entity graph. + +For example, to find all `Customer` entities at a given revision +with the country attribute of the address property being `România`: + +[[envers-querying-entity-relation-nested-join-restriction]] +.Filtering a nested join relation with a WHERE clause predicate +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditAdressCountryTest.java[tags=envers-querying-entity-relation-nested-join-restriction] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-querying-entity-relation-nested-join-restriction.sql[] +---- +==== + +Constraints may also be added to the properties of nested joined relations, such as testing for `null`. + +For example, the following query illustrates how to find all `Customer` entities at a given revision +having the `address` in `Cluj-Napoca` or the `address` does _not_ have any country entity reference: + +[[envers-querying-entity-relation-join-multiple-restrictions]] +.Filtering a join relation using multiple predicates +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditAdressCountryTest.java[tags=envers-querying-entity-relation-join-multiple-restrictions] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-querying-entity-relation-join-multiple-restrictions.sql[] +---- +==== + +[NOTE] +==== +Queries can use the `up` method to navigate back up the entity graph. +==== + +Disjunction criterion may also be applied to relation join queries. + +For example, the following query will find all `Customer` entities at a given revision +where the country name is `România` or that the `Customer` lives in `Cluj-Napoca`: + +[[envers-querying-entity-relation-nested-join-multiple-restrictions]] +.Filtering a nested join relation using multiple predicates +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditAdressCountryTest.java[tags=envers-querying-entity-relation-nested-join-multiple-restrictions] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-querying-entity-relation-nested-join-multiple-restrictions.sql[] +---- +==== + +Lastly, this example illustrates how related entity properties can be compared in a single constraint. + +Assuming the `Customer` and the `Address` were previously changed as follows: + +[[envers-querying-entity-relation-nested-join-multiple-restrictions-combined-entities]] +.Changing the `Address` to match the `Country` name +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditAdressCountryTest.java[tags=envers-querying-entity-relation-nested-join-multiple-restrictions-combined-entities] +---- +==== + +The following query shows how to find the `Customer` entities +where the `city` property of the `address` attribute equals the `name` of the associated `country` attribute. + +[[envers-querying-entity-relation-nested-join-multiple-restrictions-combined]] +.Filtering a nested join relation using multiple predicates +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditAdressCountryTest.java[tags=envers-querying-entity-relation-nested-join-multiple-restrictions-combined] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-querying-entity-relation-nested-join-multiple-restrictions-combined.sql[] +---- +==== + +[[envers-querying-revision-entities]] +=== Querying for revision information without loading entities + +Sometimes, it may be useful to load information about revisions to find out who performed specific revisions or +to know what entity names were modified but the change log about the related audited entities isn't needed. +This API allows an efficient way to get the revision information entity log without instantiating the actual +entities themselves. + +Here is a simple example: + +[source,java] +---- +AuditQuery query = getAuditReader().createQuery() + .forRevisionsOfEntity( Customer.class, true ) + .add( AuditEntity.revisionNumber().between( 1, 25 ) ); +---- + +This query will return all information for revisions between 1 and 25 including those which are +related to deletions. If deletions are not of interest, you would pass `false` as the second argument. + +Note that this query produces `@RevisionEntity` instances. The obtained instance type will vary depending on the +configuration properties used to configure Envers, like showed in <>, +or if you supply your own revision entity. + +[[envers-querying-revision-info]] +=== Directly querying revision information + +You can also directly query all revision information available on the database by writing HQL or Criteria queries +which select from the revision entity used by your application. For example: + +[source,java] +---- +List resultList = session.createQuery( "from DefaultRevisionEntity where id = 1", DefaultRevisionEntity.class ).getResultList(); +---- + +This query will return all revision entity information for revision numbers equal to 1 (the first revision of each entity). +Often, users who will take advantage of this functionality will be providing a custom revision entity implementation to +obtain additional information being maintained per revision. + +[[envers-conditional-auditing]] +=== Conditional auditing + +Envers persists audit data in reaction to various Hibernate events (e.g. `post update`, `post insert`, and so on), +using a series of event listeners from the `org.hibernate.envers.event.spi` package. +By default, if the Envers jar is in the classpath, the event listeners are auto-registered with Hibernate. + +Conditional auditing can be implemented by overriding some of the Envers event listeners. +To use customized Envers event listeners, the following steps are needed: + +. Turn off automatic Envers event listeners registration by setting the `hibernate.envers.autoRegisterListeners` Hibernate property to `false`. + +. Create subclasses for appropriate event listeners. + For example, if you want to conditionally audit entity insertions, extend the `org.hibernate.envers.event.spi.EnversPostInsertEventListenerImpl` class. + Place the conditional-auditing logic in the subclasses, call the super method if auditing should be performed. + +. Create your own implementation of `org.hibernate.integrator.spi.Integrator`, similar to `org.hibernate.envers.boot.internal.EnversIntegrator`. + Use your event listener classes instead of the default ones. + +. For the integrator to be automatically used when Hibernate starts up, you will need to add a `META-INF/services/org.hibernate.integrator.spi.Integrator` file to your jar. + The file should contain the fully qualified name of the class implementing the interface. + +[NOTE] +==== +The use of `hibernate.listeners.envers.autoRegister` has been deprecated. +The new `hibernate.envers.autoRegisterListeners` configuration setting should be used instead. +==== + +[[envers-schema]] +=== Understanding the Envers Schema + +For each audited entity (that is, for each entity containing at least one audited field), an audit table is created. +By default, the audit table's name is created by adding an "_AUD" suffix to the original table name, +but this can be overridden by specifying a different suffix/prefix in the configuration properties or per-entity using the `@org.hibernate.envers.AuditTable` annotation. + +The audit table contains the following columns: + +id:: `id` of the original entity (this can be more then one column in the case of composite primary keys). +revision number:: an integer, which matches to the revision number in the revision entity table. +revision type:: The `org.hibernate.envers.RevisionType` enumeration ordinal stating if the change represents an INSERT, UPDATE or DELETE. +audited fields:: properties from the original entity being audited. + +The primary key of the audit table is the combination of the original id of the entity and the revision number, +so there can be at most one historic entry for a given entity instance at a given revision. + +The current entity data is stored in the original table and in the audit table. +This is a duplication of data, however, as this solution makes the query system much more powerful, and as memory is cheap, hopefully, this won't be a major drawback for the users. + +A row in the audit table with entity id `ID`, revision `N`, and data `D` means: entity with id `ID` has data `D` from revision `N` upwards. +Hence, if we want to find an entity at revision `M`, we have to search for a row in the audit table, which has the revision number smaller or equal to `M`, but as large as possible. +If no such row is found, or a row with a "deleted" marker is found, it means that the entity didn't exist at that revision. + +The "revision type" field can currently have three values: `0`, `1` and `2`, which means `ADD`, `MOD`, and `DEL`, respectively. +A row with a revision of type `DEL` will only contain the id of the entity and no data (all fields `NULL`), as it only serves as a marker saying "this entity was deleted at that revision". + +Additionally, there is a revision entity table which contains the information about the global revision. +By default, the generated table is named `REVINFO` and contains just two columns: `ID` and `TIMESTAMP`. +A row is inserted into this table on each new revision, that is, on each commit of a transaction, which changes audited data. +The name of this table can be configured, the name of its columns as well as adding additional columns can be achieved as discussed in <>. + +[NOTE] +==== +While global revisions are a good way to provide correct auditing of relations, some people have pointed out that this may be a bottleneck in systems where data is very often modified. + +One viable solution is to introduce an option to have an entity "locally revisioned", that is revisions would be created for it independently. +This would not enable correct versioning of relations, but it would work without the `REVINFO` table. + +Another possibility is to introduce a notion of "revisioning groups", which would group entities sharing the same revision numbering. +Each such group would have to consist of one or more strongly connected components belonging to the entity graph induced by relations between entities. + +Your opinions on the subject are very welcome on the forum. +==== + +[[envers-generateschema]] +=== Generating Envers schema with Hibernate hbm2ddl tool + +If you would like to generate the database schema file with Hibernate, +you simply need to use the hbm2ddl tool. + +This task will generate the definitions of all entities, both of those which are audited by Envers and those which are not. + +See the <> chapter for more info. + +For the following entities, Hibernate is going to generate the following database schema: + +[[envers-generateschema-example]] +.Filtering a nested join relation using multiple predicates +==== +[source, java, indent=0] +---- +include::{example-dir-envers}/QueryAuditAdressCountryTest.java[tags=envers-generateschema-example] +---- + +[source, SQL, indent=0] +---- +include::{extrasdir}/envers-generateschema-example.sql[] +---- +==== + +[[envers-mappingexceptions]] +=== Mapping exceptions + +==== What isn't and will not be supported + +Bags are not supported because they can contain non-unique elements. +Persisting a bag of `String`s violates the relational database principle that each table is a set of tuples. + +In case of bags, however (which require a join table), if there is a duplicate element, the two tuples corresponding to the elements will be the same. +Although Hibernate allows this, Envers (or more precisely the database connector) will throw an exception when trying to persist two identical elements because of a unique constraint violation. + +There are at least two ways out if you need bag semantics: + +. use an indexed collection, with the `@jakarta.persistence.OrderColumn` annotation. +. provide a unique id for your elements with the `@CollectionId` annotation. + +==== What isn't and _will_ be supported + +* Bag style collections with a `@CollectionId` identifier column (see https://hibernate.atlassian.net/browse/HHH-3950[HHH-3950]). + +=== `@OneToMany` with `@JoinColumn` + +When a collection is mapped using these two annotations, Hibernate doesn't generate a join table. +Envers, however, has to do this so that when you read the revisions in which the related entity has changed, you don't get false results. + +To be able to name the additional join table, there is a special annotation: `@AuditJoinTable`, which has similar semantics to Jakarta Persistence `@JoinTable`. + +One special case is to have relations mapped with `@OneToMany` with `@JoinColumn` on the one side, and `@ManyToOne` and `@JoinColumn( insertable = false, updatable = false`) on the many side. +Such relations are, in fact, bidirectional, but the owning side is the collection. + +To properly audit such relations with Envers, you can use the `@AuditMappedBy` annotation. +It enables you to specify the reverse property (using the `mappedBy` element). +In case of indexed collections, the index column must also be mapped in the referenced entity (using `@Column( insertable = false, updatable = false )`, and specified using `positionMappedBy`. +This annotation will affect only the way Envers works. +Please note that the annotation is experimental and may change in the future. + +[[envers-partitioning]] +=== Advanced: Audit table partitioning + +[[envers-partitioning-benefits]] +=== Benefits of audit table partitioning + +Because audit tables tend to grow indefinitely, they can quickly become really large. +When the audit tables have grown to a certain limit (varying per RDBMS and/or operating system) it makes sense to start using table partitioning. +SQL table partitioning offers a lot of advantages including, but certainly not limited to: + +. Improved query performance by selectively moving rows to various partitions (or even purging old rows). +. Faster data loads, index creation, etc. + +[[envers-partitioning-columns]] +=== Suitable columns for audit table partitioning + +Generally, SQL tables must be partitioned on a column that exists within the table. +As a rule, it makes sense to use either the _end revision_ or the _end revision timestamp_ column for partitioning of audit tables. + +[NOTE] +==== +End revision information is not available for the default `AuditStrategy`. + +Therefore the following Envers configuration options are required: + +`org.hibernate.envers.audit_strategy` = `org.hibernate.envers.strategy.ValidityAuditStrategy` + +`org.hibernate.envers.audit_strategy_validity_store_revend_timestamp` = `true` + +Optionally, you can also override the default values using following properties: + +`org.hibernate.envers.audit_strategy_validity_end_rev_field_name` + +`org.hibernate.envers.audit_strategy_validity_revend_timestamp_field_name` + +`org.hibernate.envers.audit_strategy_validity_revend_timestamp_numeric` + +For more information, see <>. +==== + +The reason why the end revision information should be used for audit table partitioning is based on the assumption that audit tables should be partitioned on an 'increasing level of relevancy', like so: + +. A couple of partitions with audit data that is not very (or no longer) relevant. + This can be stored on slow media, and perhaps even be purged eventually. +. Some partitions for audit data that is potentially relevant. +. One partition for audit data that is most likely to be relevant. + This should be stored on the fastest media, both for reading and writing. + +[[envers-partitioning-example]] +=== Audit table partitioning example + +In order to determine a suitable column for the 'increasing level of relevancy', +consider a simplified example of a salary registration for an unnamed agency. + +Currently, the salary table contains the following rows for a certain person X: + +.Salaries table +[width="100%",cols="50%,50%",options="header",] +|================== +|Year |Salary (USD) +|2006 |3300 +|2007 |3500 +|2008 |4000 +|2009 |4500 +|================== + +The salary for the current fiscal year (2010) is unknown. +The agency requires that all changes in registered salaries for a fiscal year are recorded (i.e., an audit trail). +The rationale behind this is that decisions made at a certain date are based on the registered salary at that time. +And at any time it must be possible to reproduce the reason why a certain decision was made at a certain date. + +The following audit information is available, sorted in order of occurrence: + +.Salaries - audit table +[width="100%",cols="20%,20%,20%,20%,20%",options="header",] +|======================================================================= +|Year |Revision type |Revision timestamp |Salary (USD) |End revision timestamp +|2006 |ADD |2007-04-01 |3300 |null +|2007 |ADD |2008-04-01 |35 |2008-04-02 +|2007 |MOD |2008-04-02 |3500 |null +|2008 |ADD |2009-04-01 |3700 |2009-07-01 +|2008 |MOD |2009-07-01 |4100 |2010-02-01 +|2008 |MOD |2010-02-01 |4000 |null +|2009 |ADD |2010-04-01 |4500 |null +|======================================================================= + +[[envers-partitioning-example-column]] +=== Determining a suitable partitioning column + +To partition this data, the _level of relevancy_ must be defined. Consider the following: + +. For the fiscal year 2006, there is only one revision. +It has the oldest _revision timestamp_ of all audit rows, +but should still be regarded as relevant because it's the latest modification for this fiscal year in the salary table (its _end revision timestamp_ is null). ++ +Also, note that it would be very unfortunate if in 2011 there would be an update of the salary for the fiscal year 2006 (which is possible until at least 10 years after the fiscal year), +and the audit information would have been moved to a slow disk (based on the age of the __revision timestamp__). +Remember that, in this case, Envers will have to update the _end revision timestamp_ of the most recent audit row. +. There are two revisions in the salary of the fiscal year 2007 which both have nearly the same _revision timestamp_ and a different __end revision timestamp__. + +On first sight, it is evident that the first revision was a mistake and probably not relevant. +The only relevant revision for 2007 is the one with _end revision timestamp_ value of null. + +Based on the above, it is evident that only the _end revision timestamp_ is suitable for audit table partitioning. +The _revision timestamp_ is not suitable. + +[[envers-partitioning-example-scheme]] +=== Determining a suitable partitioning scheme + +A possible partitioning scheme for the salary table would be as follows: + +_end revision timestamp_ year = 2008:: This partition contains audit data that is not very (or no longer) relevant. +_end revision timestamp_ year = 2009:: This partition contains audit data that is potentially relevant. +_end revision timestamp_ year >= 2010 or null:: This partition contains the most relevant audit data. + +This partitioning scheme also covers the potential problem of the update of the __end revision timestamp__, +which occurs if a row in the audited table is modified. +Even though Envers will update the _end revision timestamp_ of the audit row to the system date at the instant of modification, +the audit row will remain in the same partition (the 'extension bucket'). + +And sometime in 2011, the last partition (or 'extension bucket') is split into two new partitions: + +. _end revision timestamp_ year = 2010: This partition contains audit data that is potentially relevant (in 2011). +. _end revision timestamp_ year >= 2011 or null: This partition contains the most interesting audit data and is the new 'extension bucket'. + +[[envers-links]] +=== Envers links + +. https://hibernate.org[Hibernate main page] +. https://hibernate.org/community/[Forum] +. https://hibernate.atlassian.net/[JIRA issue tracker] (when adding issues concerning Envers, be sure to select the "envers" component!) +. https://hibernate.zulipchat.com/#narrow/stream/132096-hibernate-user[Zulip channel] +. https://community.jboss.org/wiki/EnversFAQ[FAQ] + diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/entities-filtering-and-pagination.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/entities-filtering-and-pagination.sql new file mode 100644 index 000000000000..a54249260754 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/entities-filtering-and-pagination.sql @@ -0,0 +1,17 @@ +select + c.id as id1_3_, + c.REV as REV2_3_, + c.REVTYPE as REVTYPE3_3_, + c.REVEND as REVEND4_3_, + c.created_on as created_5_3_, + c.firstName as firstNam6_3_, + c.lastName as lastName7_3_, + c.address_id as address_8_3_ +from + Customer_AUD c +where + c.address_id = ? +order by + c.lastName desc +limit ? +offset ? \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/entities-filtering-by-entity-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/entities-filtering-by-entity-example.sql new file mode 100644 index 000000000000..b005434eb4fa --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/entities-filtering-by-entity-example.sql @@ -0,0 +1,17 @@ +select + c.id as id1_3_, + c.REV as REV2_3_, + c.REVTYPE as REVTYPE3_3_, + c.REVEND as REVEND4_3_, + c.created_on as created_5_3_, + c.firstName as firstNam6_3_, + c.lastName as lastName7_3_, + c.address_id as address_8_3_ +from + Customer_AUD c +where + c.address_id = ? +order by + c.REV asc + +-- binding parameter [1] as [BIGINT] - [1] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/entities-in-clause-filtering-by-entity-identifier-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/entities-in-clause-filtering-by-entity-identifier-example.sql new file mode 100644 index 000000000000..05d3b85f9c58 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/entities-in-clause-filtering-by-entity-identifier-example.sql @@ -0,0 +1,20 @@ +select + c.id as id1_3_, + c.REV as REV2_3_, + c.REVTYPE as REVTYPE3_3_, + c.REVEND as REVEND4_3_, + c.created_on as created_5_3_, + c.firstName as firstNam6_3_, + c.lastName as lastName7_3_, + c.address_id as address_8_3_ +from + Customer_AUD c +where + c.address_id in ( + ? , ? + ) +order by + c.REV asc + +-- binding parameter [1] as [BIGINT] - [1] +-- binding parameter [2] as [BIGINT] - [2] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-delete-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-delete-example.sql new file mode 100644 index 000000000000..ce40f7aaa64c --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-delete-example.sql @@ -0,0 +1,31 @@ +delete +from + Customer +where + id = ? + +-- binding parameter [1] as [BIGINT] - [1] + +insert +into + REVINFO + (REV, REVTSTMP) +values + (?, ?) + +-- binding parameter [1] as [BIGINT] - [3] +-- binding parameter [2] as [BIGINT] - [1500906092876] + +insert +into + Customer_AUD + (REVTYPE, created_on, firstName, lastName, id, REV) +values + (?, ?, ?, ?, ?, ?) + +-- binding parameter [1] as [INTEGER] - [2] +-- binding parameter [2] as [TIMESTAMP] - [null] +-- binding parameter [3] as [VARCHAR] - [null] +-- binding parameter [4] as [VARCHAR] - [null] +-- binding parameter [5] as [BIGINT] - [1] +-- binding parameter [6] as [INTEGER] - [3] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-insert-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-insert-example.sql new file mode 100644 index 000000000000..e81e86b44b9d --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-insert-example.sql @@ -0,0 +1,35 @@ +insert +into + Customer + (created_on, firstName, lastName, id) +values + (?, ?, ?, ?) + +-- binding parameter [1] as [TIMESTAMP] - [Mon Jul 24 17:21:32 EEST 2017] +-- binding parameter [2] as [VARCHAR] - [John] +-- binding parameter [3] as [VARCHAR] - [Doe] +-- binding parameter [4] as [BIGINT] - [1] + +insert +into + REVINFO + (REV, REVTSTMP) +values + (?, ?) + +-- binding parameter [1] as [BIGINT] - [1] +-- binding parameter [2] as [BIGINT] - [1500906092803] + +insert +into + Customer_AUD + (REVTYPE, created_on, firstName, lastName, id, REV) +values + (?, ?, ?, ?, ?, ?) + +-- binding parameter [1] as [INTEGER] - [0] +-- binding parameter [2] as [TIMESTAMP] - [Mon Jul 24 17:21:32 EEST 2017] +-- binding parameter [3] as [VARCHAR] - [John] +-- binding parameter [4] as [VARCHAR] - [Doe] +-- binding parameter [5] as [BIGINT] - [1] +-- binding parameter [6] as [INTEGER] - [1] diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-mapping-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-mapping-example.sql new file mode 100644 index 000000000000..6444cfa64b18 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-mapping-example.sql @@ -0,0 +1,28 @@ +create table Customer ( + id bigint not null, + created_on timestamp, + firstName varchar(255), + lastName varchar(255), + primary key (id) +) + +create table Customer_AUD ( + id bigint not null, + REV integer not null, + REVTYPE tinyint, + created_on timestamp, + firstName varchar(255), + lastName varchar(255), + primary key (id, REV) +) + +create table REVINFO ( + REV integer generated by default as identity, + REVTSTMP bigint, + primary key (REV) +) + +alter table Customer_AUD + add constraint FK5ecvi1a0ykunrriib7j28vpdj + foreign key (REV) + references REVINFO \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-rev1-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-rev1-example.sql new file mode 100644 index 000000000000..654b798f09f2 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-rev1-example.sql @@ -0,0 +1,23 @@ +select + c.id as id1_1_, + c.REV as REV2_1_, + c.REVTYPE as REVTYPE3_1_, + c.created_on as created_4_1_, + c.firstName as firstNam5_1_, + c.lastName as lastName6_1_ +from + Customer_AUD c +where + c.REV = ( + select + max( c_max.REV ) + from + Customer_AUD c_max + where + c_max.REV <= ? + and c.id = c_max.id + ) + and c.REVTYPE <> ? + +-- binding parameter [1] as [INTEGER] - [1] +-- binding parameter [2] as [INTEGER] - [2] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-revisions-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-revisions-example.sql new file mode 100644 index 000000000000..69f0f6d93933 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-revisions-example.sql @@ -0,0 +1,13 @@ +select + c.REV as col_0_0_ +from + Customer_AUD c +cross join + REVINFO r +where + c.id = ? + and c.REV = r.REV +order by + c.REV asc + +-- binding parameter [1] as [BIGINT] - [1] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-update-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-update-example.sql new file mode 100644 index 000000000000..57bb75402f41 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-update-example.sql @@ -0,0 +1,37 @@ +update + Customer +set + created_on=?, + firstName=?, + lastName=? +where + id=? + +-- binding parameter [1] as [TIMESTAMP] - [2017-07-24 17:21:32.757] +-- binding parameter [2] as [VARCHAR] - [John] +-- binding parameter [3] as [VARCHAR] - [Doe Jr.] +-- binding parameter [4] as [BIGINT] - [1] + +insert +into + REVINFO + (REV, REVTSTMP) +values + (?, ?) + +-- binding parameter [1] as [BIGINT] - [2] +-- binding parameter [2] as [BIGINT] - [1500906092853] + +insert +into + Customer_AUD + (REVTYPE, created_on, firstName, lastName, id, REV) +values + (?, ?, ?, ?, ?, ?) + +-- binding parameter [1] as [INTEGER] - [1] +-- binding parameter [2] as [TIMESTAMP] - [2017-07-24 17:21:32.757] +-- binding parameter [3] as [VARCHAR] - [John] +-- binding parameter [4] as [VARCHAR] - [Doe Jr.] +-- binding parameter [5] as [BIGINT] - [1] +-- binding parameter [6] as [INTEGER] - [2] diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-validity-mapping-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-validity-mapping-example.sql new file mode 100644 index 000000000000..3e8088a10a39 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-validity-mapping-example.sql @@ -0,0 +1,34 @@ +create table Customer ( + id bigint not null, + created_on timestamp, + firstName varchar(255), + lastName varchar(255), + primary key (id) +) + +create table Customer_AUD ( + id bigint not null, + REV integer not null, + REVTYPE tinyint, + REVEND integer, + created_on timestamp, + firstName varchar(255), + lastName varchar(255), + primary key (id, REV) +) + +create table REVINFO ( + REV integer generated by default as identity, + REVTSTMP bigint, + primary key (REV) +) + +alter table Customer_AUD + add constraint FK5ecvi1a0ykunrriib7j28vpdj + foreign key (REV) + references REVINFO + +alter table Customer_AUD + add constraint FKqd4fy7ww1yy95wi4wtaonre3f + foreign key (REVEND) + references REVINFO \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-validity-rev1-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-validity-rev1-example.sql new file mode 100644 index 000000000000..4d5a7cb9003e --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-audited-validity-rev1-example.sql @@ -0,0 +1,21 @@ +select + c.id as id1_1_, + c.REV as REV2_1_, + c.REVTYPE as REVTYPE3_1_, + c.REVEND as REVEND4_1_, + c.created_on as created_5_1_, + c.firstName as firstNam6_1_, + c.lastName as lastName7_1_ +from + Customer_AUD c +where + c.REV <= ? + and c.REVTYPE <> ? + and ( + c.REVEND > ? + or c.REVEND is null + ) + +-- binding parameter [1] as [INTEGER] - [1] +-- binding parameter [2] as [INTEGER] - [2] +-- binding parameter [3] as [INTEGER] - [1] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-generateschema-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-generateschema-example.sql new file mode 100644 index 000000000000..494777730858 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-generateschema-example.sql @@ -0,0 +1,102 @@ +create table Address ( + id bigint not null, + city varchar(255), + street varchar(255), + streetNumber varchar(255), + country_id bigint, + primary key (id) +) + +create table Address_AUD ( + id bigint not null, + REV integer not null, + REVTYPE tinyint, + REVEND integer, + city varchar(255), + street varchar(255), + streetNumber varchar(255), + country_id bigint, + primary key (id, REV) +) + +create table Country ( + id bigint not null, + name varchar(255), + primary key (id) +) + +create table Country_AUD ( + id bigint not null, + REV integer not null, + REVTYPE tinyint, + REVEND integer, + name varchar(255), + primary key (id, REV) +) + +create table Customer ( + id bigint not null, + created_on timestamp, + firstName varchar(255), + lastName varchar(255), + address_id bigint, + primary key (id) +) + +create table Customer_AUD ( + id bigint not null, + REV integer not null, + REVTYPE tinyint, + REVEND integer, + created_on timestamp, + firstName varchar(255), + lastName varchar(255), + address_id bigint, + primary key (id, REV) +) + +create table REVINFO ( + REV integer generated by default as identity, + REVTSTMP bigint, + primary key (REV) +) + +alter table Address +add constraint FKpr4rl83u5fv832kdihl6w3kii +foreign key (country_id) +references Country + +alter table Address_AUD +add constraint FKgwp5sek4pjb4awy66sp184hrv +foreign key (REV) +references REVINFO + +alter table Address_AUD +add constraint FK52pqkpismfxg2b9tmwtncnk0d +foreign key (REVEND) +references REVINFO + +alter table Country_AUD +add constraint FKrix4g8hm9ui6sut5sy86ujggr +foreign key (REV) +references REVINFO + +alter table Country_AUD +add constraint FKpjeqmdccv22y1lbtswjb84ghi +foreign key (REVEND) +references REVINFO + +alter table Customer +add constraint FKfok4ytcqy7lovuiilldbebpd9 +foreign key (address_id) +references Address + +alter table Customer_AUD +add constraint FK5ecvi1a0ykunrriib7j28vpdj +foreign key (REV) +references REVINFO + +alter table Customer_AUD +add constraint FKqd4fy7ww1yy95wi4wtaonre3f +foreign key (REVEND) +references REVINFO \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-join-multiple-restrictions.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-join-multiple-restrictions.sql new file mode 100644 index 000000000000..b52fb72caf0f --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-join-multiple-restrictions.sql @@ -0,0 +1,48 @@ +select + c.id as id1_5_, + c.REV as REV2_5_, + c.REVTYPE as REVTYPE3_5_, + c.REVEND as REVEND4_5_, + c.created_on as created_5_5_, + c.firstName as firstNam6_5_, + c.lastName as lastName7_5_, + c.address_id as address_8_5_ +from + Customer_AUD c +left outer join + Address_AUD a + on ( + c.address_id=a.id + or ( + c.address_id is null + ) + and ( + a.id is null + ) + ) +where + c.REV<=? + and c.REVTYPE<>? + and ( + c.REVEND>? + or c.REVEND is null + ) + and ( + a.REV is null + or a.REV<=? + and ( + a.REVEND>? + or a.REVEND is null + ) + ) + and ( + a.city=? + or a.country_id is null + ) + +-- binding parameter [1] as [INTEGER] - [1] +-- binding parameter [2] as [INTEGER] - [2] +-- binding parameter [3] as [INTEGER] - [1] +-- binding parameter [4] as [INTEGER] - [1] +-- binding parameter [5] as [INTEGER] - [1] +-- binding parameter [6] as [VARCHAR] - [Cluj-Napoca] diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-join-restriction.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-join-restriction.sql new file mode 100644 index 000000000000..865858d31001 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-join-restriction.sql @@ -0,0 +1,42 @@ +select + c.id as id1_3_, + c.REV as REV2_3_, + c.REVTYPE as REVTYPE3_3_, + c.REVEND as REVEND4_3_, + c.created_on as created_5_3_, + c.firstName as firstNam6_3_, + c.lastName as lastName7_3_, + c.address_id as address_8_3_ +from + Customer_AUD c +inner join + Address_AUD a + on ( + c.address_id=a.id + or ( + c.address_id is null + ) + and ( + a.id is null + ) + ) +where + c.REV<=? + and c.REVTYPE<>? + and ( + c.REVEND>? + or c.REVEND is null + ) + and a.REV<=? + and a.country=? + and ( + a.REVEND>? + or a.REVEND is null + ) + +-- binding parameter [1] as [INTEGER] - [1] +-- binding parameter [2] as [INTEGER] - [2] +-- binding parameter [3] as [INTEGER] - [1] +-- binding parameter [4] as [INTEGER] - [1] +-- binding parameter [5] as [VARCHAR] - [România] +-- binding parameter [6] as [INTEGER] - [1] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-nested-join-multiple-restrictions-combined.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-nested-join-multiple-restrictions-combined.sql new file mode 100644 index 000000000000..a41067211b3d --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-nested-join-multiple-restrictions-combined.sql @@ -0,0 +1,59 @@ +select + cu.id as id1_5_, + cu.REV as REV2_5_, + cu.REVTYPE as REVTYPE3_5_, + cu.REVEND as REVEND4_5_, + cu.created_on as created_5_5_, + cu.firstName as firstNam6_5_, + cu.lastName as lastName7_5_, + cu.address_id as address_8_5_ +from + Customer_AUD cu +inner join + Address_AUD a + on ( + cu.address_id=a.id + or ( + cu.address_id is null + ) + and ( + a.id is null + ) + ) +inner join + Country_AUD cr + on ( + a.country_id=cr.id + or ( + a.country_id is null + ) + and ( + cr.id is null + ) + ) +where + cu.REV<=? + and cu.REVTYPE<>? + and a.city=cr.name + and ( + cu.REVEND>? + or cu.REVEND is null + ) + and a.REV<=? + and ( + a.REVEND>? + or a.REVEND is null + ) + and cr.REV<=? + and ( + cr.REVEND>? + or cr.REVEND is null + ) + +-- binding parameter [1] as [INTEGER] - [2] +-- binding parameter [2] as [INTEGER] - [2] +-- binding parameter [3] as [INTEGER] - [2] +-- binding parameter [4] as [INTEGER] - [2] +-- binding parameter [5] as [INTEGER] - [2] +-- binding parameter [6] as [INTEGER] - [2] +-- binding parameter [7] as [INTEGER] - [2] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-nested-join-multiple-restrictions.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-nested-join-multiple-restrictions.sql new file mode 100644 index 000000000000..e21eba04abfd --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-nested-join-multiple-restrictions.sql @@ -0,0 +1,66 @@ +select + cu.id as id1_5_, + cu.REV as REV2_5_, + cu.REVTYPE as REVTYPE3_5_, + cu.REVEND as REVEND4_5_, + cu.created_on as created_5_5_, + cu.firstName as firstNam6_5_, + cu.lastName as lastName7_5_, + cu.address_id as address_8_5_ +from + Customer_AUD cu +inner join + Address_AUD a + on ( + cu.address_id=a.id + or ( + cu.address_id is null + ) + and ( + a.id is null + ) + ) +inner join + Country_AUD co + on ( + a.country_id=co.id + or ( + a.country_id is null + ) + and ( + co.id is null + ) + ) +where + cu.REV<=? + and cu.REVTYPE<>? + and ( + cu.REVEND>? + or cu.REVEND is null + ) + and ( + a.city=? + or co.name=? + ) + and a.REV<=? + and ( + a.REVEND>? + or a.REVEND is null + ) + and co.REV<=? + and ( + co.REVEND>? + or co.REVEND is null + ) +order by + cu.created_on asc + +-- binding parameter [1] as [INTEGER] - [1] +-- binding parameter [2] as [INTEGER] - [2] +-- binding parameter [3] as [INTEGER] - [1] +-- binding parameter [4] as [VARCHAR] - [Cluj-Napoca] +-- binding parameter [5] as [VARCHAR] - [România] +-- binding parameter [6] as [INTEGER] - [1] +-- binding parameter [7] as [INTEGER] - [1] +-- binding parameter [8] as [INTEGER] - [1] +-- binding parameter [9] as [INTEGER] - [1] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-nested-join-restriction.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-nested-join-restriction.sql new file mode 100644 index 000000000000..4ca5a8f788d3 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-querying-entity-relation-nested-join-restriction.sql @@ -0,0 +1,60 @@ +select + cu.id as id1_5_, + cu.REV as REV2_5_, + cu.REVTYPE as REVTYPE3_5_, + cu.REVEND as REVEND4_5_, + cu.created_on as created_5_5_, + cu.firstName as firstNam6_5_, + cu.lastName as lastName7_5_, + cu.address_id as address_8_5_ +from + Customer_AUD cu +inner join + Address_AUD a + on ( + cu.address_id=a.id + or ( + cu.address_id is null + ) + and ( + a.id is null + ) + ) +inner join + Country_AUD co + on ( + a.country_id=co.id + or ( + a.country_id is null + ) + and ( + co.id is null + ) + ) +where + cu.REV<=? + and cu.REVTYPE<>? + and ( + cu.REVEND>? + or cu.REVEND is null + ) + and a.REV<=? + and ( + a.REVEND>? + or a.REVEND is null + ) + and co.REV<=? + and co.name=? + and ( + co.REVEND>? + or co.REVEND is null + ) + +-- binding parameter [1] as [INTEGER] - [1] +-- binding parameter [2] as [INTEGER] - [2] +-- binding parameter [3] as [INTEGER] - [1] +-- binding parameter [4] as [INTEGER] - [1] +-- binding parameter [5] as [INTEGER] - [1] +-- binding parameter [6] as [INTEGER] - [1] +-- binding parameter [7] as [VARCHAR] - [România] +-- binding parameter [8] as [INTEGER] - [1] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-revisionlog-RevisionEntity-persist-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-revisionlog-RevisionEntity-persist-example.sql new file mode 100644 index 000000000000..7a3e12ae59be --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-revisionlog-RevisionEntity-persist-example.sql @@ -0,0 +1,36 @@ +insert +into + Customer + (created_on, firstName, lastName, id) +values + (?, ?, ?, ?) + +-- binding parameter [1] as [TIMESTAMP] - [Thu Jul 27 15:45:00 EEST 2017] +-- binding parameter [2] as [VARCHAR] - [John] +-- binding parameter [3] as [VARCHAR] - [Doe] +-- binding parameter [4] as [BIGINT] - [1] + +insert +into + CUSTOM_REV_INFO + (timestamp, username, id) +values + (?, ?, ?) + +-- binding parameter [1] as [BIGINT] - [1501159500888] +-- binding parameter [2] as [VARCHAR] - [Vlad Mihalcea] +-- binding parameter [3] as [INTEGER] - [1] + +insert +into + Customer_AUD + (REVTYPE, created_on, firstName, lastName, id, REV) +values + (?, ?, ?, ?, ?, ?) + +-- binding parameter [1] as [INTEGER] - [0] +-- binding parameter [2] as [TIMESTAMP] - [Thu Jul 27 15:45:00 EEST 2017] +-- binding parameter [3] as [VARCHAR] - [John] +-- binding parameter [4] as [VARCHAR] - [Doe] +-- binding parameter [5] as [BIGINT] - [1] +-- binding parameter [6] as [INTEGER] - [1] diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-revisionlog-custom-revision-entity-table-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-revisionlog-custom-revision-entity-table-example.sql new file mode 100644 index 000000000000..5e2884009090 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-revisionlog-custom-revision-entity-table-example.sql @@ -0,0 +1,6 @@ +create table CUSTOM_REV_INFO ( + id integer not null, + timestamp bigint not null, + username varchar(255), + primary key (id) +) \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-modified-entities-revchanges-after-rename-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-modified-entities-revchanges-after-rename-example.sql new file mode 100644 index 000000000000..b66b68764d95 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-modified-entities-revchanges-after-rename-example.sql @@ -0,0 +1,9 @@ +insert +into + REVCHANGES + (REV, ENTITYNAME) +values + (?, ?) + +-- binding parameter [1] as [INTEGER] - [1] +-- binding parameter [2] as [VARCHAR] - [org.hibernate.userguide.envers.EntityTypeChangeAuditTest$Customer] diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-example.sql new file mode 100644 index 000000000000..9be648011932 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-example.sql @@ -0,0 +1,39 @@ +update + Customer +set + created_on = ?, + firstName = ?, + lastName = ? +where + id = ? + +-- binding parameter [1] as [TIMESTAMP] - [2017-07-31 15:58:20.342] +-- binding parameter [2] as [VARCHAR] - [John] +-- binding parameter [3] as [VARCHAR] - [Doe Jr.] +-- binding parameter [4] as [BIGINT] - [1] + +insert +into + REVINFO + (REV, REVTSTMP) +values + (null, ?) + +-- binding parameter [1] as [BIGINT] - [1501505900439] + +insert +into + Customer_AUD + (REVTYPE, created_on, createdOn_MOD, firstName, firstName_MOD, lastName, lastName_MOD, id, REV) +values + (?, ?, ?, ?, ?, ?, ?, ?, ?) + +-- binding parameter [1] as [INTEGER] - [1] +-- binding parameter [2] as [TIMESTAMP] - [2017-07-31 15:58:20.342] +-- binding parameter [3] as [BOOLEAN] - [false] +-- binding parameter [4] as [VARCHAR] - [John] +-- binding parameter [5] as [BOOLEAN] - [false] +-- binding parameter [6] as [VARCHAR] - [Doe Jr.] +-- binding parameter [7] as [BOOLEAN] - [true] +-- binding parameter [8] as [BIGINT] - [1] +-- binding parameter [9] as [INTEGER] - [2] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-mapping-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-mapping-example.sql new file mode 100644 index 000000000000..8cf1c2896eb3 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-mapping-example.sql @@ -0,0 +1,12 @@ +create table Customer_AUD ( + id bigint not null, + REV integer not null, + REVTYPE tinyint, + created_on timestamp, + createdOn_MOD boolean, + firstName varchar(255), + firstName_MOD boolean, + lastName varchar(255), + lastName_MOD boolean, + primary key (id, REV) +) \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-queries-at-revision-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-queries-at-revision-example.sql new file mode 100644 index 000000000000..33ca9a67aa1e --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-queries-at-revision-example.sql @@ -0,0 +1,25 @@ +select + c.id as id1_3_, + c.REV as REV2_3_, + c.REVTYPE as REVTYPE3_3_, + c.REVEND as REVEND4_3_, + c.created_on as created_5_3_, + c.createdOn_MOD as createdO6_3_, + c.firstName as firstNam7_3_, + c.firstName_MOD as firstNam8_3_, + c.lastName as lastName9_3_, + c.lastName_MOD as lastNam10_3_, + c.address_id as address11_3_, + c.address_MOD as address12_3_ +from + Customer_AUD c +where + c.REV=? + and c.id=? + and c.lastName_MOD=? + and c.firstName_MOD=? + +-- binding parameter [1] as [INTEGER] - [2] +-- binding parameter [2] as [BIGINT] - [1] +-- binding parameter [3] as [BOOLEAN] - [true] +-- binding parameter [4] as [BOOLEAN] - [false] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-queries-hasChanged-and-hasNotChanged-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-queries-hasChanged-and-hasNotChanged-example.sql new file mode 100644 index 000000000000..f3579a041672 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-queries-hasChanged-and-hasNotChanged-example.sql @@ -0,0 +1,30 @@ +select + c.id as id1_3_0_, + c.REV as REV2_3_0_, + defaultrev1_.REV as REV1_4_1_, + c.REVTYPE as REVTYPE3_3_0_, + c.REVEND as REVEND4_3_0_, + c.created_on as created_5_3_0_, + c.createdOn_MOD as createdO6_3_0_, + c.firstName as firstNam7_3_0_, + c.firstName_MOD as firstNam8_3_0_, + c.lastName as lastName9_3_0_, + c.lastName_MOD as lastNam10_3_0_, + c.address_id as address11_3_0_, + c.address_MOD as address12_3_0_, + defaultrev1_.REVTSTMP as REVTSTMP2_4_1_ +from + Customer_AUD c cross +join + REVINFO defaultrev1_ +where + c.id=? + and c.lastName_MOD=? + and c.firstName_MOD=? + and c.REV=defaultrev1_.REV +order by + c.REV asc + +-- binding parameter [1] as [BIGINT] - [1] +-- binding parameter [2] as [BOOLEAN] - [true] +-- binding parameter [3] as [BOOLEAN] - [false] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-queries-hasChanged-example.sql b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-queries-hasChanged-example.sql new file mode 100644 index 000000000000..a466fb8f3ec8 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/extras/envers-tracking-properties-changes-queries-hasChanged-example.sql @@ -0,0 +1,28 @@ +select + c.id as id1_3_0_, + c.REV as REV2_3_0_, + defaultrev1_.REV as REV1_4_1_, + c.REVTYPE as REVTYPE3_3_0_, + c.REVEND as REVEND4_3_0_, + c.created_on as created_5_3_0_, + c.createdOn_MOD as createdO6_3_0_, + c.firstName as firstNam7_3_0_, + c.firstName_MOD as firstNam8_3_0_, + c.lastName as lastName9_3_0_, + c.lastName_MOD as lastNam10_3_0_, + c.address_id as address11_3_0_, + c.address_MOD as address12_3_0_, + defaultrev1_.REVTSTMP as REVTSTMP2_4_1_ +from + Customer_AUD c cross +join + REVINFO defaultrev1_ +where + c.id = ? + and c.lastName_MOD = ? + and c.REV=defaultrev1_.REV +order by + c.REV asc + +-- binding parameter [1] as [BIGINT] - [1] +-- binding parameter [2] as [BOOLEAN] - [true] \ No newline at end of file diff --git a/documentation/src/main/asciidoc/userguide/chapters/jdbc/Database_Access.adoc b/documentation/src/main/asciidoc/userguide/chapters/jdbc/Database_Access.adoc index b4498fed7fde..387e2e33509a 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/jdbc/Database_Access.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/jdbc/Database_Access.adoc @@ -18,9 +18,8 @@ Hibernate will internally determine which `ConnectionProvider` to use based on t 3. else if any setting prefixed by `hibernate.c3p0.` is set -> <> 4. else if any setting prefixed by `hibernate.hikari.` is set -> <> 5. else if any setting prefixed by `hibernate.agroal.` is set -> <> -6. else if any setting prefixed by `hibernate.oracleucp.` is set -> <> -7. else if `hibernate.connection.url` is set -> <> -9. else -> <> +6. else if `hibernate.connection.url` is set -> <> +7. else -> <> [[database-connectionprovider-datasource]] === Using DataSources @@ -111,38 +110,6 @@ Additionally, this `ConnectionProvider` will pick up the following Hibernate-spe `hibernate.connection.isolation`:: Mapped to Agroal's `jdbcTransactionIsolation` setting. See <>. `hibernate.connection.autocommit`:: Mapped to Agroal's `autoCommit` setting -[[database-connectionprovider-ucp]] -=== Using Oracle Universal Connection Pool - -[IMPORTANT] -==== -To use the Universal Connection Pool (aka UCP) integration, the application must include the `hibernate-ucp` module jar (as well as its dependencies) on the classpath. -==== - -Hibernate also provides support for applications to use https://docs.oracle.com/en/database/oracle/oracle-database/23/jjucp/intro.html[Oracle Universal Connection Pool]. - -Set all of your UCP settings in Hibernate prefixed by `hibernate.oracleucp.` and this `ConnectionProvider` will pick them up and pass them along to UCP. -Additionally, this `ConnectionProvider` will pick up the following Hibernate-specific properties and map them to the corresponding UCP ones (any `hibernate.oracleucp.` prefixed ones have precedence): - -`hibernate.connection.url`:: Mapped to UCP's `URL` setting -`hibernate.connection.username`:: Mapped to UCP's `user` setting -`hibernate.connection.password`:: Mapped to UCP's `password` setting -`hibernate.connection.isolation`:: Used to initialize `Connection` retrieved from UCP. See <>. -`hibernate.connection.autocommit`:: Used to initialize `Connection` retrieved from UCP. -Any other settings prefixed with `hibernate.oracleucp.`:: Will have the `hibernate.oracleucp.` portion stripped and be passed to UCP. - -[IMPORTANT] -==== -You can pass further settings to the `Connection` provided by UCP by using the `hibernate.oracleucp.connectionProperties` property in the following manner: - -`hibernate.oracleucp.connectionProperties=oracle.jdbc.thinForceDNSLoadBalancing=true,oracle.jdbc.fanEnabled=true,oracle.jdbc.defaultConnectionValidation=SOCKET,oracle.jdbc.implicitStatementCacheSize=50,oracle.jdbc.loginTimeout=5000` -==== - -The Hibernate property `hibernate.oracleucp.connectionFactoryClassName` can be used to choose between: - -. a standard connection pool: `oracle.jdbc.pool.OracleDataSource` -. a _replay_ connection pool: `oracle.jdbc.replay.OracleDataSourceImpl` which allows using [Transparent] Application Continuity capabilities to mask planned and unplanned downtime - [[database-connectionprovider-drivermanager]] === Using Hibernate's built-in (and unsupported) pooling diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/programmatic/QuerySpecification.adoc b/documentation/src/main/asciidoc/userguide/chapters/query/programmatic/QuerySpecification.adoc new file mode 100644 index 000000000000..b2d2ce1dfc9f --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/query/programmatic/QuerySpecification.adoc @@ -0,0 +1,125 @@ +[[QuerySpecification]] +== Programmatic Query Specification +:root-project-dir: ../../../../../../../.. + +Hibernate offers an API for creating a representation of a query, adjusting that representation programmatically, and then creating an executable form of the query. The idea is similar in concept to <>, but focused on ease-of-use and less verbosity. + +There is support for both <> and <> queries via the `SelectionSpecification` and `MutationSpecification` contracts, respectively. These can be obtained from both `Session` and `StatelessSession`. + +[NOTE] +==== +These APIs are new in 7.0 and considered incubating. +==== + +[[SelectionSpecification]] +=== SelectionSpecification + +A `SelectionSpecification` allows to iteratively build a query from a "base", adjust the query by adding sorting and restrictions and finally creating an executable <>. We can use HQL as the base - + +.SelectionSpecification from HQL +==== +[source, java, indent=0] +---- +SelectionSpecification spec = SelectionSpecification.create( + Book.class, + "from Book" +); +---- +==== + +or a root entity as the base - + +.SelectionSpecification from root entity +==== +[source, java, indent=0] +---- +SelectionSpecification spec = SelectionSpecification.create(Book.class); +---- +==== + +Once we have the `SelectionSpecification` we can adjust the query adding restrictions and sorting - + +.Adjusting the SelectionSpecification +==== +[source, java, indent=0] +---- +// from here we can augment the base query "from Book", +// with either restrictions +spec.restrict( + Restriction.restrict( + Book_.suggestedCost, + Range.closed(10.00, 19.99) + ) +); + +// or here with some sorting +spec.sort( + Order.asc(Book_.suggestedCost) +) +---- +==== + +[NOTE] +==== +Notice that generally the JPA static metamodel is a convenient and type-safe way to help build these sorting and restriction references. +==== + +After adjusting the query, we can obtain the executable `SelectionQuery`: + +.Using the SelectionSpecification +==== +[source, java, indent=0] +---- +SelectionQuery qry = ds.createQuery(session); +List books = qry.getResultList(); +---- +==== + +These calls can even be chained, e.g. + +.Example of chained calls +==== +[source, java, indent=0] +---- +SelectionQuery qry = SelectionSpecification.create( + Book.class, + "from Book" +).restrict( + Restriction.restrict( + Book_.suggestedCost, + Range.closed(10.00, 19.99) + ) +).sort( + Order.asc(Book_.suggestedCost) +).createQuery(session); +---- +==== + +[NOTE] +==== +We expect, in future releases, to add the ability to handle pagination. + +We also expect to add the ability to use <> references as the base. Possibly even `TypedQueryReference` references. +==== + +[[MutationSpecification]] +=== MutationSpecification + +There is also support for mutation queries through `MutationSpecification`. +At the moment, only update and delete queries are supported. E.g. + +.MutationQuery example +==== +[source, java, indent=0] +---- +MutationQuery qry = MutationSpecification.create( + Book.class, + "delete Book" +).restrict( + Restriction.restrict( + Book_.suggestedCost, + Range.closed(10.00, 19.99) + ) +).createQuery(session); +---- +==== diff --git a/etc/ehcache.xml b/etc/ehcache.xml deleted file mode 100644 index 63a35aedf76a..000000000000 --- a/etc/ehcache.xml +++ /dev/null @@ -1,94 +0,0 @@ - - - - - - - - - - - - - - - - - --> - - - - diff --git a/etc/hibernate-service.xml b/etc/hibernate-service.xml deleted file mode 100644 index 657c74a8427d..000000000000 --- a/etc/hibernate-service.xml +++ /dev/null @@ -1,101 +0,0 @@ - - - - - - - - - - - - - - - - - - - - jca/test - - - - - - - - ConnectionURL - java.lang.String - jdbc:mysql:///test - - - DriverClass - java.lang.String - com.mysql.jdbc.Driver - - - Password - java.lang.String - - - - UserName - java.lang.String - dbradby - - - Dialect - java.lang.String - org.hibernate.dialect.MySQLDialect - - - MapResources - java.lang.String - Simple.hbm.xml - - - - - - - jboss.jca:service=RARDeployment,name=Hibernate Resource Adapter - - - - - - - - 0 - 50 - 5000 - 15 - - ByContainer - - - - jboss.jca:service=CachedConnectionManager - - jboss.security:service=JaasSecurityManager - - - jboss.jca:service=RARDeployer - java:/TransactionManager - - - - diff --git a/etc/hibernate.cfg.xml b/etc/hibernate.cfg.xml deleted file mode 100644 index 3471f87137f9..000000000000 --- a/etc/hibernate.cfg.xml +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - true - - - - \ No newline at end of file diff --git a/etc/hibernate.properties b/etc/hibernate.properties deleted file mode 100644 index fcad56cba16f..000000000000 --- a/etc/hibernate.properties +++ /dev/null @@ -1,440 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# - -################# -### Platforms ### -################# - -## JNDI Datasource - -#hibernate.connection.datasource jdbc/test -#hibernate.connection.username db2 -#hibernate.connection.password db2 - - -## HypersonicSQL - -hibernate.dialect org.hibernate.dialect.HSQLDialect -hibernate.connection.driver_class org.hsqldb.jdbcDriver -hibernate.connection.username sa -hibernate.connection.password -hibernate.connection.url jdbc:hsqldb:./build/db/hsqldb/hibernate -#hibernate.connection.url jdbc:hsqldb:hsql://localhost -#hibernate.connection.url jdbc:hsqldb:test - -## H2 (www.h2database.com) -#hibernate.dialect org.hibernate.dialect.H2Dialect -#hibernate.connection.driver_class org.h2.Driver -#hibernate.connection.username sa -#hibernate.connection.password -#hibernate.connection.url jdbc:h2:mem:./build/db/h2/hibernate -#hibernate.connection.url jdbc:h2:testdb/h2test -#hibernate.connection.url jdbc:h2:mem:imdb1 -#hibernate.connection.url jdbc:h2:tcp://dbserv:8084/sample; -#hibernate.connection.url jdbc:h2:ssl://secureserv:8085/sample; -#hibernate.connection.url jdbc:h2:ssl://secureserv/testdb;cipher=AES - -## MySQL - -#hibernate.dialect org.hibernate.dialect.MySQLDialect -#hibernate.dialect org.hibernate.dialect.MySQLInnoDBDialect -#hibernate.dialect org.hibernate.dialect.MySQLMyISAMDialect -#hibernate.connection.driver_class com.mysql.jdbc.Driver -#hibernate.connection.url jdbc:mysql:///test -#hibernate.connection.username gavin -#hibernate.connection.password - - -## Oracle - -#hibernate.dialect org.hibernate.dialect.OracleDialect -#hibernate.connection.driver_class oracle.jdbc.OracleDriver -#hibernate.connection.username ora -#hibernate.connection.password ora -#hibernate.connection.url jdbc:oracle:thin:@localhost:1521:orcl -#hibernate.connection.url jdbc:oracle:thin:@localhost:1522:XE - - -## PostgreSQL - -#hibernate.dialect org.hibernate.dialect.PostgreSQLDialect -#hibernate.connection.driver_class org.postgresql.Driver -#hibernate.connection.url jdbc:postgresql:template1 -#hibernate.connection.username pg -#hibernate.connection.password - - -## DB2 - -#hibernate.dialect org.hibernate.dialect.DB2Dialect -#hibernate.connection.driver_class com.ibm.db2.jcc.DB2Driver -#hibernate.connection.driver_class COM.ibm.db2.jdbc.app.DB2Driver -#hibernate.connection.url jdbc:db2://localhost:50000/somename -#hibernate.connection.url jdbc:db2:somename -#hibernate.connection.username db2 -#hibernate.connection.password db2 - -## TimesTen - -#hibernate.dialect org.hibernate.community.dialect.TimesTenDialect -#hibernate.connection.driver_class com.timesten.jdbc.TimesTenDriver -#hibernate.connection.url jdbc:timesten:direct:test -#hibernate.connection.username -#hibernate.connection.password - -## DB2/400 - -#hibernate.dialect org.hibernate.dialect.DB2iDialect -#hibernate.connection.username user -#hibernate.connection.password password - -## Native driver -#hibernate.connection.driver_class COM.ibm.db2.jdbc.app.DB2Driver -#hibernate.connection.url jdbc:db2://systemname - -## Toolbox driver -#hibernate.connection.driver_class com.ibm.as400.access.AS400JDBCDriver -#hibernate.connection.url jdbc:as400://systemname - - -## Derby (not supported!) - -#hibernate.dialect org.hibernate.community.dialect.DerbyDialect -#hibernate.connection.driver_class org.apache.derby.jdbc.EmbeddedDriver -#hibernate.connection.username -#hibernate.connection.password -#hibernate.connection.url jdbc:derby:build/db/derby/hibernate;create=true - - -## Sybase - -#hibernate.dialect org.hibernate.dialect.SybaseDialect -#hibernate.connection.driver_class com.sybase.jdbc2.jdbc.SybDriver -#hibernate.connection.username sa -#hibernate.connection.password sasasa -#hibernate.connection.url jdbc:sybase:Tds:co3061835-a:5000/tempdb - - -## SAP MaxDB - -#hibernate.dialect org.hibernate.community.dialect.MaxDBDialect -#hibernate.connection.driver_class com.sap.dbtech.jdbc.DriverSapDB -#hibernate.connection.url jdbc:sapdb://localhost/TST -#hibernate.connection.username TEST -#hibernate.connection.password TEST - - -## MS SQL Server - -#hibernate.dialect org.hibernate.dialect.SQLServerDialect -#hibernate.connection.username sa -#hibernate.connection.password sa - -## JSQL Driver -#hibernate.connection.driver_class com.jnetdirect.jsql.JSQLDriver -#hibernate.connection.url jdbc:JSQLConnect://1E1/test - -## JTURBO Driver -#hibernate.connection.driver_class com.newatlanta.jturbo.driver.Driver -#hibernate.connection.url jdbc:JTurbo://1E1:1433/test - -## WebLogic Driver -#hibernate.connection.driver_class weblogic.jdbc.mssqlserver4.Driver -#hibernate.connection.url jdbc:weblogic:mssqlserver4:1E1:1433 - -## Microsoft Driver (not recommended!) -#hibernate.connection.driver_class com.microsoft.jdbc.sqlserver.SQLServerDriver -#hibernate.connection.url jdbc:microsoft:sqlserver://1E1;DatabaseName=test;SelectMethod=cursor - -## The New Microsoft Driver -#hibernate.connection.driver_class com.microsoft.sqlserver.jdbc.SQLServerDriver -#hibernate.connection.url jdbc:sqlserver://localhost - -## jTDS (since version 0.9) -#hibernate.connection.driver_class net.sourceforge.jtds.jdbc.Driver -#hibernate.connection.url jdbc:jtds:sqlserver://1E1/test - - -## Ingres - -## older versions (before Ingress 2006) - -#hibernate.dialect org.hibernate.community.dialect.IngresDialect -#hibernate.connection.driver_class ca.edbc.jdbc.EdbcDriver -#hibernate.connection.url jdbc:edbc://localhost:II7/database -#hibernate.connection.username user -#hibernate.connection.password password - -## Ingres 2006 or later - -#hibernate.dialect org.hibernate.community.dialect.IngresDialect -#hibernate.connection.driver_class com.ingres.jdbc.IngresDriver -#hibernate.connection.url jdbc:ingres://localhost:II7/database;CURSOR=READONLY;auto=multi -#hibernate.connection.username user -#hibernate.connection.password password - -## Mimer SQL - -#hibernate.dialect org.hibernate.community.dialect.MimerSQLDialect -#hibernate.connection.driver_class com.mimer.jdbc.Driver -#hibernate.connection.url jdbc:mimer:multi1 -#hibernate.connection.username hibernate -#hibernate.connection.password hibernate - - -## InterSystems Cache - -#hibernate.dialect org.hibernate.community.dialect.Cache71Dialect -#hibernate.connection.driver_class com.intersys.jdbc.CacheDriver -#hibernate.connection.username _SYSTEM -#hibernate.connection.password SYS -#hibernate.connection.url jdbc:Cache://127.0.0.1:1972/HIBERNATE - - -################################# -### Hibernate Connection Pool ### -################################# - -hibernate.connection.pool_size 1 - - - -########################### -### C3P0 Connection Pool### -########################### - -#hibernate.c3p0.max_size 2 -#hibernate.c3p0.min_size 2 -#hibernate.c3p0.timeout 5000 -#hibernate.c3p0.max_statements 100 -#hibernate.c3p0.idle_test_period 3000 -#hibernate.c3p0.acquire_increment 2 -#hibernate.c3p0.validate false - - - -################################# -### Plugin ConnectionProvider ### -################################# - -## use a custom ConnectionProvider (if not set, Hibernate will choose a built-in ConnectionProvider using hueristics) - -#hibernate.connection.provider_class org.hibernate.connection.DriverManagerConnectionProvider -#hibernate.connection.provider_class org.hibernate.connection.DatasourceConnectionProvider -#hibernate.connection.provider_class org.hibernate.connection.C3P0ConnectionProvider - - - -####################### -### Transaction API ### -####################### - -## Enable automatic flush during the JTA beforeCompletion() callback -## (This setting is relevant with or without the Transaction API) - -#hibernate.transaction.flush_before_completion - - -## Enable automatic session close at the end of transaction -## (This setting is relevant with or without the Transaction API) - -#hibernate.transaction.auto_close_session - - -## the Transaction API abstracts application code from the underlying JTA or JDBC transactions - -#hibernate.transaction.factory_class org.hibernate.transaction.JTATransactionFactory -#hibernate.transaction.factory_class org.hibernate.transaction.JDBCTransactionFactory - - -## to use JTATransactionFactory, Hibernate must be able to locate the UserTransaction in JNDI -## default is java:comp/UserTransaction -## you do NOT need this setting if you specify hibernate.transaction.manager_lookup_class - -#jta.UserTransaction jta/usertransaction -#jta.UserTransaction javax.transaction.UserTransaction -#jta.UserTransaction UserTransaction - - -## to use the second-level cache with JTA, Hibernate must be able to obtain the JTA TransactionManager - -#hibernate.transaction.manager_lookup_class org.hibernate.transaction.JBossTransactionManagerLookup -#hibernate.transaction.manager_lookup_class org.hibernate.transaction.WeblogicTransactionManagerLookup -#hibernate.transaction.manager_lookup_class org.hibernate.transaction.WebSphereTransactionManagerLookup -#hibernate.transaction.manager_lookup_class org.hibernate.transaction.OrionTransactionManagerLookup -#hibernate.transaction.manager_lookup_class org.hibernate.transaction.ResinTransactionManagerLookup - - - -############################## -### Miscellaneous Settings ### -############################## - -## print all generated SQL to the console - -#hibernate.show_sql true - - -## format SQL in log and console - -hibernate.format_sql true - - -## add comments to the generated SQL - -#hibernate.use_sql_comments true - - -## generate statistics - -#hibernate.generate_statistics true - - -## auto schema export - -#hibernate.hbm2ddl.auto create-drop -#hibernate.hbm2ddl.auto create -#hibernate.hbm2ddl.auto update -#hibernate.hbm2ddl.auto validate - - -## specify a default schema and catalog for unqualified tablenames - -#hibernate.default_schema test -#hibernate.default_catalog test - - -## enable ordering of SQL UPDATEs by primary key - -#hibernate.order_updates true - - -## set the maximum depth of the outer join fetch tree - -hibernate.max_fetch_depth 1 - - -## set the default batch size for batch fetching - -#hibernate.default_batch_fetch_size 8 - - -## rollback generated identifier values of deleted entities to default values - -#hibernate.use_identifier_rollback true - - - -##################### -### JDBC Settings ### -##################### - -## specify a JDBC isolation level - -#hibernate.connection.isolation 4 - - -## enable JDBC autocommit (not recommended!) - -#hibernate.connection.autocommit true - - -## set the JDBC fetch size - -#hibernate.jdbc.fetch_size 25 - - -## set the maximum JDBC 2 batch size (a nonzero value enables batching) - -#hibernate.jdbc.batch_size 5 -#hibernate.jdbc.batch_size 0 - - -## enable use of JDBC 2 scrollable ResultSets (specifying a Dialect will cause Hibernate to use a sensible default) - -#hibernate.jdbc.use_scrollable_resultset true - - -## use JDBC 3 PreparedStatement.getGeneratedKeys() to get the identifier of an inserted row - -#hibernate.jdbc.use_get_generated_keys false - - -## choose a custom JDBC batcher - -# hibernate.jdbc.factory_class - - -## enable JDBC result set column alias caching -## (minor performance enhancement for broken JDBC drivers) - - - -########################## -### Second-level Cache ### -########################## - -## optimize cache for minimal "puts" instead of minimal "gets" (good for clustered cache) - -#hibernate.cache.use_minimal_puts true - - -## set a prefix for cache region names - -hibernate.cache.region_prefix hibernate.test - - -## disable the second-level cache - -#hibernate.cache.use_second_level_cache false - - -## enable the query cache - -#hibernate.cache.use_query_cache true - - -## store the second-level cache entries in a more human-friendly format - -#hibernate.cache.use_structured_entries true - - -## choose a cache implementation - -#hibernate.cache.region.factory_class org.hibernate.cache.infinispan.InfinispanRegionFactory -#hibernate.cache.region.factory_class org.hibernate.cache.infinispan.JndiInfinispanRegionFactory -#hibernate.cache.region.factory_class org.hibernate.cache.internal.EhCacheRegionFactory -#hibernate.cache.region.factory_class org.hibernate.cache.internal.SingletonEhCacheRegionFactory -hibernate.cache.region.factory_class org.hibernate.cache.internal.NoCachingRegionFactory - -## choose a custom query cache implementation - -#hibernate.cache.query_cache_factory - - - -############ -### JNDI ### -############ - -## specify a JNDI name for the SessionFactory - -#hibernate.session_factory_name hibernate/session_factory - - -## Hibernate uses JNDI to bind a name to a SessionFactory and to look up the JTA UserTransaction; -## if hibernate.jndi.* are not specified, Hibernate will use the default InitialContext() which -## is the best approach in an application server - -#file system -#hibernate.jndi.class com.sun.jndi.fscontext.RefFSContextFactory -#hibernate.jndi.url file:/ - -#WebSphere -#hibernate.jndi.class com.ibm.websphere.naming.WsnInitialContextFactory -#hibernate.jndi.url iiop://localhost:900/ - diff --git a/etc/hibernate.properties.template b/etc/hibernate.properties.template deleted file mode 100644 index 03fea63d75e5..000000000000 --- a/etc/hibernate.properties.template +++ /dev/null @@ -1,404 +0,0 @@ -################# -### Platforms ### -################# - -hibernate.dialect @HIBERNATE_DIALECT@ -hibernate.connection.driver_class @DRIVER_CLASS@ -hibernate.connection.username @DB_USERNAME@ -hibernate.connection.password @DB_PASSWORD@ -hibernate.connection.url @DB_URL@ - -## JNDI Datasource - -#hibernate.connection.datasource jdbc/test -#hibernate.connection.username db2 -#hibernate.connection.password db2 - - -## HypersonicSQL - -#hibernate.dialect org.hibernate.dialect.HSQLDialect -#hibernate.connection.driver_class org.hsqldb.jdbcDriver -#hibernate.connection.username sa -#hibernate.connection.password -#hibernate.connection.url jdbc:hsqldb:hsql://localhost -#hibernate.connection.url jdbc:hsqldb:test -#hibernate.connection.url jdbc:hsqldb:. - - -## MySQL - - -#hibernate.dialect org.hibernate.dialect.MySQLDialect -#hibernate.connection.driver_class org.gjt.mm.mysql.Driver -#hibernate.connection.driver_class com.mysql.jdbc.Driver -#hibernate.connection.url jdbc:mysql:///test -#hibernate.connection.username gavin -#hibernate.connection.password - - -## Oracle - -#hibernate.dialect org.hibernate.dialect.OracleDialect -#hibernate.dialect org.hibernate.dialect.Oracle9Dialect -#hibernate.connection.driver_class oracle.jdbc.OracleDriver -#hibernate.connection.username ora -#hibernate.connection.password ora -#hibernate.connection.url jdbc:oracle:thin:@localhost:1521:test - - -## PostgreSQL - -#hibernate.dialect org.hibernate.dialect.PostgreSQLDialect -#hibernate.connection.driver_class org.postgresql.Driver -#hibernate.connection.url jdbc:postgresql:template1 -#hibernate.connection.username pg -#hibernate.connection.password - - -## DB2 - -#hibernate.dialect org.hibernate.dialect.DB2Dialect -#hibernate.connection.driver_class COM.ibm.db2.jdbc.app.DB2Driver -#hibernate.connection.url jdbc:db2:test -#hibernate.connection.username db2 -#hibernate.connection.password db2 - -## TimesTen (not supported yet) - -#hibernate.dialect org.hibernate.community.dialect.TimesTenDialect -#hibernate.connection.driver_class com.timesten.jdbc.TimesTenDriver -#hibernate.connection.url jdbc:timesten:direct:test -#hibernate.connection.username -#hibernate.connection.password - -## DB2/400 - -#hibernate.dialect org.hibernate.dialect.DB2iDialect -#hibernate.connection.username user -#hibernate.connection.password password - -## Native driver -#hibernate.connection.driver_class COM.ibm.db2.jdbc.app.DB2Driver -#hibernate.connection.url jdbc:db2://systemname - -## Toolbox driver -#hibernate.connection.driver_class com.ibm.as400.access.AS400JDBCDriver -#hibernate.connection.url jdbc:as400://systemname - - -## Derby (Not supported!) - -#hibernate.dialect org.hibernate.community.dialect.DerbyDialect -#hibernate.connection.driver_class org.apache.derby.jdbc.EmbeddedDriver -#hibernate.connection.username -#hibernate.connection.password -#hibernate.connection.url jdbc:derby:/test;create=true - - -## Sybase - -#hibernate.dialect org.hibernate.dialect.SybaseDialect -#hibernate.connection.driver_class com.sybase.jdbc2.jdbc.SybDriver -#hibernate.connection.username sa -#hibernate.connection.password sasasa -#hibernate.connection.url jdbc:sybase:Tds:co3061835-a:5000/tempdb - - -## SAP MaxDB - -#hibernate.dialect org.hibernate.community.dialect.MaxDBDialect -#hibernate.connection.driver_class com.sap.dbtech.jdbc.DriverSapDB -#hibernate.connection.url jdbc:sapdb://localhost/TST -#hibernate.connection.username TEST -#hibernate.connection.password TEST - - -## MS SQL Server - -#hibernate.dialect org.hibernate.dialect.SQLServerDialect -#hibernate.connection.username sa -#hibernate.connection.password sa - -## JSQL Driver -#hibernate.connection.driver_class com.jnetdirect.jsql.JSQLDriver -#hibernate.connection.url jdbc:JSQLConnect://1E1/test - -## JTURBO Driver -#hibernate.connection.driver_class com.newatlanta.jturbo.driver.Driver -#hibernate.connection.url jdbc:JTurbo://1E1:1433/test - -## WebLogic Driver -#hibernate.connection.driver_class weblogic.jdbc.mssqlserver4.Driver -#hibernate.connection.url jdbc:weblogic:mssqlserver4:1E1:1433 - -## Microsoft Driver (not recommended!) -#hibernate.connection.driver_class com.microsoft.jdbc.sqlserver.SQLServerDriver -#hibernate.connection.url jdbc:microsoft:sqlserver://1E1;DatabaseName=test;SelectMethod=cursor - -## jTDS (since version 0.9) -#hibernate.connection.driver_class net.sourceforge.jtds.jdbc.Driver -#hibernate.connection.url jdbc:jtds:sqlserver://1E1/test - - -## Ingres - -#hibernate.dialect org.hibernate.community.dialect.IngresDialect -#hibernate.connection.driver_class ca.edbc.jdbc.EdbcDriver -#hibernate.connection.url jdbc:edbc://localhost:II7/database -#hibernate.connection.username user -#hibernate.connection.password password - - -## Mimer SQL - -#hibernate.dialect org.hibernate.community.dialect.MimerSQLDialect -#hibernate.connection.driver_class com.mimer.jdbc.Driver -#hibernate.connection.url jdbc:mimer:multi1 -#hibernate.connection.username hibernate -#hibernate.connection.password hibernate - - -## HANA - -#hibernate.dialect org.hibernate.dialect.HANADialect -#hibernate.connection.driver_class com.sap.db.jdbc.Driver -#hibernate.connection.url jdbc:sap://localhost:30015 -#hibernate.connection.username HIBERNATE_TEST -#hibernate.connection.password H1bernate_test - - - -################################# -### Hibernate Connection Pool ### -################################# - -hibernate.connection.pool_size 1 - - - -########################### -### C3P0 Connection Pool### -########################### - -#hibernate.c3p0.max_size 2 -#hibernate.c3p0.min_size 2 -#hibernate.c3p0.timeout 5000 -#hibernate.c3p0.max_statements 100 -#hibernate.c3p0.idle_test_period 3000 -#hibernate.c3p0.acquire_increment 2 -#hibernate.c3p0.validate false - - - -################################# -### Plugin ConnectionProvider ### -################################# - -## use a custom ConnectionProvider (if not set, Hibernate will choose a built-in ConnectionProvider using hueristics) - -#hibernate.connection.provider_class org.hibernate.connection.DriverManagerConnectionProvider -#hibernate.connection.provider_class org.hibernate.connection.DatasourceConnectionProvider -#hibernate.connection.provider_class org.hibernate.connection.C3P0ConnectionProvider -#hibernate.connection.provider_class org.hibernate.connection.DBCPConnectionProvider - - - -####################### -### Transaction API ### -####################### - -## Enable automatic flush during the JTA beforeCompletion() callback -## (This setting is relevant with or without the Transaction API) - -#hibernate.transaction.flush_before_completion - - -## Enable automatic session close at the end of transaction -## (This setting is relevant with or without the Transaction API) - -#hibernate.transaction.auto_close_session - - -## the Transaction API abstracts application code from the underlying JTA or JDBC transactions - -#hibernate.transaction.factory_class org.hibernate.transaction.JTATransactionFactory -#hibernate.transaction.factory_class org.hibernate.transaction.JDBCTransactionFactory - - -## to use JTATransactionFactory, Hibernate must be able to locate the UserTransaction in JNDI -## default is java:comp/UserTransaction -## you do NOT need this setting if you specify hibernate.transaction.manager_lookup_class - -#jta.UserTransaction jta/usertransaction -#jta.UserTransaction javax.transaction.UserTransaction -#jta.UserTransaction UserTransaction - - -## to use the second-level cache with JTA, Hibernate must be able to obtain the JTA TransactionManager - -#hibernate.transaction.manager_lookup_class org.hibernate.transaction.JBossTransactionManagerLookup -#hibernate.transaction.manager_lookup_class org.hibernate.transaction.WeblogicTransactionManagerLookup -#hibernate.transaction.manager_lookup_class org.hibernate.transaction.WebSphereTransactionManagerLookup -#hibernate.transaction.manager_lookup_class org.hibernate.transaction.OrionTransactionManagerLookup -#hibernate.transaction.manager_lookup_class org.hibernate.transaction.ResinTransactionManagerLookup - - - -############################## -### Miscellaneous Settings ### -############################## - -## print all generated SQL to the console - -#hibernate.show_sql true - - -## add comments to the generated SQL - -#hibernate.use_sql_comments true - - -## generate statistics - -#hibernate.generate_statistics true - - -## auto schema export - -#hibernate.hbm2ddl.auto create-drop -#hibernate.hbm2ddl.auto create -#hibernate.hbm2ddl.auto update - - -## specify a default schema and catalog for unqualified tablenames - -#hibernate.default_schema test -#hibernate.default_catalog test - - -## enable ordering of SQL UPDATEs by primary key - -hibernate.order_updates true - - -## set the maximum depth of the outer join fetch tree - -hibernate.max_fetch_depth 1 - - -## set the default batch size for batch fetching - -hibernate.default_batch_fetch_size 8 - - -## rollback generated identifier values of deleted entities to default values - -#hibernate.use_identifier_rollback true - - - -##################### -### JDBC Settings ### -##################### - -## specify a JDBC isolation level - -#hibernate.connection.isolation 4 - - -## enable JDBC autocommit (not recommended!) - -#hibernate.connection.autocommit true - - -## set the JDBC fetch size - -#hibernate.jdbc.fetch_size 25 - - -## set the maximum JDBC 2 batch size (a nonzero value enables batching) - -#hibernate.jdbc.batch_size 5 - -## enable use of JDBC 2 scrollable ResultSets (specifying a Dialect will cause Hibernate to use a sensible default) - -#hibernate.jdbc.use_scrollable_resultset true - - -## use JDBC 3 PreparedStatement.getGeneratedKeys() to get the identifier of an inserted row - -#hibernate.jdbc.use_get_generated_keys false - - -## choose a custom JDBC batcher - -# hibernate.jdbc.factory_class - - - -########################## -### Second-level Cache ### -########################## - -## optimize cache for minimal "puts" instead of minimal "gets" (good for clustered cache) - -#hibernate.cache.use_minimal_puts true - - -## set a prefix for cache region names - -hibernate.cache.region_prefix hibernate.test - - -## disable the second-level cache - -#hibernate.cache.use_second_level_cache false - - -## enable the query cache - -#hibernate.cache.use_query_cache true - - -## store the second-level cache entries in a more human-friendly format - -#hibernate.cache.use_structured_entries true - - -## choose a cache implementation - -#hibernate.cache.region.factory_class org.hibernate.cache.infinispan.InfinispanRegionFactory -#hibernate.cache.region.factory_class org.hibernate.cache.infinispan.JndiInfinispanRegionFactory -#hibernate.cache.region.factory_class org.hibernate.cache.internal.EhCacheRegionFactory -#hibernate.cache.region.factory_class org.hibernate.cache.internal.SingletonEhCacheRegionFactory -#hibernate.cache.region.factory_class org.hibernate.cache.internal.NoCachingRegionFactory - - -## choose a custom query cache implementation - -#hibernate.cache.query_cache_factory - - - -############ -### JNDI ### -############ - -## specify a JNDI name for the SessionFactory - -#hibernate.session_factory_name hibernate/session_factory - - -## Hibernate uses JNDI to bind a name to a SessionFactory and to look up the JTA UserTransaction; -## if hibernate.jndi.* are not specified, Hibernate will use the default InitialContext() which -## is the best approach in an application server - -#file system -#hibernate.jndi.class com.sun.jndi.fscontext.RefFSContextFactory -#hibernate.jndi.url file:/ - -#WebSphere -#hibernate.jndi.class com.ibm.websphere.naming.WsnInitialContextFactory -#hibernate.jndi.url iiop://localhost:900/ - diff --git a/etc/log4j2.properties b/etc/log4j2.properties deleted file mode 100644 index e12215cd7299..000000000000 --- a/etc/log4j2.properties +++ /dev/null @@ -1,66 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# - -### direct log messages to stdout ### -appender.stdout.type=Console -appender.stdout.name=STDOUT -appender.stdout.layout.type=PatternLayout -appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -### direct messages to file hibernate.log ### -#appender.file.type=File -#appender.file.name=file -#appender.file.fileName=hibernate.log -#appender.file.layout.type=PatternLayout -#appender.file.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -### set log levels - for more verbose logging change 'info' to 'debug' ### - -rootLogger.level=warn -rootLogger.appenderRef.stdout.ref=STDOUT - -logger.hibernate.name=org.hibernate -#logger.hibernate.level=info -logger.hibernate.level=debug - -### log HQL query parser activity -logger.hql-ast.name=org.hibernate.hql.ast.AST -#logger.hql-ast.level=debug - -### log just the SQL -logger.sql.name=org.hibernate.SQL -#logger.sql.level=debug - -### log JDBC bind parameters ### -logger.hibernate-type.name=org.hibernate.type -logger.hibernate-type.level=info -#logger.hibernate-type.level=debug - -### log schema export/update ### -logger.hbm2ddl.name=org.hibernate.tool.hbm2ddl -logger.hbm2ddl.level=debug - -### log HQL parse trees -logger.hql.name=org.hibernate.hql -#logger.hql.level=debug - -### log cache activity ### -logger.cache.name=org.hibernate.cache -#logger.cache.level=debug - -### log transaction activity -logger.hibernate-transaction.name=org.hibernate.transaction -#logger.hibernate-transaction.level=debug - -### log JDBC resource acquisition -logger.hibernate-jdbc.name=org.hibernate.jdbc -#logger.hibernate-jdbc.level=debug - -### enable the following line if you want to track down connection ### -### leakages when using DriverManagerConnectionProvider ### -logger.driver-manager-connection-provider.name=org.hibernate.connection.DriverManagerConnectionProvider -#logger.driver-manager-connection-provider.level=trace diff --git a/gradle.properties b/gradle.properties index 70ee1d9a77bb..bf09b28cd3f1 100644 --- a/gradle.properties +++ b/gradle.properties @@ -27,4 +27,6 @@ org.gradle.java.installations.auto-download=false # externalized definition of JDK versions so that they are available in both Project (build.gradle) and Settings (settings.gradle) orm.jdk.base=17 +orm.jdk.min=21 +# See gradlew/wrapper/gradle-wrapper.properties, https://docs.gradle.org/current/userguide/compatibility.html#java_runtime orm.jdk.max=22 \ No newline at end of file diff --git a/gradle/gradle-develocity.gradle b/gradle/gradle-develocity.gradle index 5e835cd6f263..5c7416f3aaf3 100644 --- a/gradle/gradle-develocity.gradle +++ b/gradle/gradle-develocity.gradle @@ -1,12 +1,10 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -// Applies details for `https://ge.hibernate.org` +// Applies details for `https://develocity.commonhaus.dev` // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ext { @@ -46,7 +44,7 @@ static boolean isEnabled(String setting) { } develocity { - server = 'https://ge.hibernate.org' + server = 'https://develocity.commonhaus.dev' buildScan { capture { diff --git a/gradle/version.properties b/gradle/version.properties index 17618fcbb236..14628370e1f7 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=7.0.0-SNAPSHOT \ No newline at end of file +hibernateVersion=7.1.0-SNAPSHOT \ No newline at end of file diff --git a/hibernate-agroal/hibernate-agroal.gradle b/hibernate-agroal/hibernate-agroal.gradle index 1a2730e44535..d19d28475c8a 100644 --- a/hibernate-agroal/hibernate-agroal.gradle +++ b/hibernate-agroal/hibernate-agroal.gradle @@ -1,8 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ plugins { diff --git a/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/AgroalConnectionProvider.java b/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/AgroalConnectionProvider.java index f568266400d1..887b91c81b1d 100644 --- a/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/AgroalConnectionProvider.java +++ b/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/AgroalConnectionProvider.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.agroal.internal; diff --git a/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/StrategyRegistrationProviderImpl.java b/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/StrategyRegistrationProviderImpl.java index 531315cae267..30455fb7ba62 100644 --- a/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/StrategyRegistrationProviderImpl.java +++ b/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/StrategyRegistrationProviderImpl.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.agroal.internal; diff --git a/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/package-info.java b/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/package-info.java index dcd7eb663070..11da5a9014c3 100644 --- a/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/package-info.java +++ b/hibernate-agroal/src/main/java/org/hibernate/agroal/internal/package-info.java @@ -1,8 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ /** diff --git a/hibernate-agroal/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider b/hibernate-agroal/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider index cd58cd1a2002..9edd7fab2d8a 100644 --- a/hibernate-agroal/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider +++ b/hibernate-agroal/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider @@ -1,13 +1,3 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# +# SPDX-License-Identifier: Apache-2.0 +# Copyright Red Hat Inc. and Hibernate Authors org.hibernate.agroal.internal.StrategyRegistrationProviderImpl diff --git a/hibernate-agroal/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/hibernate-agroal/src/main/resources/OSGI-INF/blueprint/blueprint.xml index 71b48a990a68..d4a7b25fa62b 100644 --- a/hibernate-agroal/src/main/resources/OSGI-INF/blueprint/blueprint.xml +++ b/hibernate-agroal/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -1,10 +1,8 @@ . +# SPDX-License-Identifier: Apache-2.0 +# Copyright Red Hat Inc. and Hibernate Authors # hibernate.dialect @db.dialect@ hibernate.connection.driver_class @jdbc.driver@ diff --git a/hibernate-agroal/src/test/resources/log4j2.properties b/hibernate-agroal/src/test/resources/log4j2.properties index 621e6a3dbf81..7a171f173762 100644 --- a/hibernate-agroal/src/test/resources/log4j2.properties +++ b/hibernate-agroal/src/test/resources/log4j2.properties @@ -1,8 +1,6 @@ # -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . +# SPDX-License-Identifier: Apache-2.0 +# Copyright Red Hat Inc. and Hibernate Authors # appender.stdout.type=Console appender.stdout.name=STDOUT diff --git a/hibernate-c3p0/hibernate-c3p0.gradle b/hibernate-c3p0/hibernate-c3p0.gradle index 64e39e191def..c7ac3cba0ced 100644 --- a/hibernate-c3p0/hibernate-c3p0.gradle +++ b/hibernate-c3p0/hibernate-c3p0.gradle @@ -1,8 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ plugins { diff --git a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java index df3a54284c8f..3677142246e2 100644 --- a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java +++ b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0ConnectionProvider.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.c3p0.internal; diff --git a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0MessageLogger.java b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0MessageLogger.java index 2d0b80dd0f3c..fde5cf50a2db 100644 --- a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0MessageLogger.java +++ b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/C3P0MessageLogger.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.c3p0.internal; diff --git a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/StrategyRegistrationProviderImpl.java b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/StrategyRegistrationProviderImpl.java index f2a83e067ee7..c6247952779d 100644 --- a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/StrategyRegistrationProviderImpl.java +++ b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/StrategyRegistrationProviderImpl.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.c3p0.internal; diff --git a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/package-info.java b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/package-info.java index c8665cd110a6..fc6473f008ce 100644 --- a/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/package-info.java +++ b/hibernate-c3p0/src/main/java/org/hibernate/c3p0/internal/package-info.java @@ -1,8 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ /** diff --git a/hibernate-c3p0/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider b/hibernate-c3p0/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider index 4bf0e1ef5b52..b4d9b0e9d689 100644 --- a/hibernate-c3p0/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider +++ b/hibernate-c3p0/src/main/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider @@ -1,13 +1,4 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . +# SPDX-License-Identifier: Apache-2.0 +# Copyright Red Hat Inc. and Hibernate Authors # org.hibernate.c3p0.internal.StrategyRegistrationProviderImpl diff --git a/hibernate-c3p0/src/main/resources/OSGI-INF/blueprint/blueprint.xml b/hibernate-c3p0/src/main/resources/OSGI-INF/blueprint/blueprint.xml index 7c4dd76d1bd9..19cd7c596f3d 100644 --- a/hibernate-c3p0/src/main/resources/OSGI-INF/blueprint/blueprint.xml +++ b/hibernate-c3p0/src/main/resources/OSGI-INF/blueprint/blueprint.xml @@ -1,10 +1,8 @@ diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ConnectionProviderTest.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ConnectionProviderTest.java index 48c2a8f0ca4f..96a4d92a38f0 100644 --- a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ConnectionProviderTest.java +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ConnectionProviderTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.test.c3p0; diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DefaultIsolationLevelTest.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DefaultIsolationLevelTest.java index cbcce75971c6..d23f95e714a4 100644 --- a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DefaultIsolationLevelTest.java +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DefaultIsolationLevelTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.test.c3p0; diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DifferentIsolationLevelTest.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DifferentIsolationLevelTest.java index 7d077bb8fe8a..4121026650cb 100644 --- a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DifferentIsolationLevelTest.java +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0DifferentIsolationLevelTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.test.c3p0; diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java index 49b91fcd9192..e954b3122036 100644 --- a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3P0ProxyConnectionProvider.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.test.c3p0; diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3p0TransactionIsolationConfigTest.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3p0TransactionIsolationConfigTest.java index a7e23c5da70a..7e002cc81ca5 100644 --- a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3p0TransactionIsolationConfigTest.java +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/C3p0TransactionIsolationConfigTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.test.c3p0; @@ -9,7 +9,7 @@ import org.hibernate.c3p0.internal.C3P0ConnectionProvider; import org.hibernate.community.dialect.AltibaseDialect; import org.hibernate.dialect.SybaseASEDialect; -import org.hibernate.dialect.TiDBDialect; +import org.hibernate.community.dialect.TiDBDialect; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.service.spi.ServiceRegistryImplementor; diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/IrrelevantEntity.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/IrrelevantEntity.java index 86070b7989c9..4735e78e4e88 100644 --- a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/IrrelevantEntity.java +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/IrrelevantEntity.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.test.c3p0; diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/JdbcCompatibilityTest.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/JdbcCompatibilityTest.java index be705daf97f5..09c1aceb20cb 100644 --- a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/JdbcCompatibilityTest.java +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/JdbcCompatibilityTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.test.c3p0; diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/OracleSQLCallableStatementProxyTest.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/OracleSQLCallableStatementProxyTest.java index 846cf80edf28..cd0f30f165f4 100644 --- a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/OracleSQLCallableStatementProxyTest.java +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/OracleSQLCallableStatementProxyTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.test.c3p0; diff --git a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/StatementCacheTest.java b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/StatementCacheTest.java index 75e287d132d5..d63a74ee90b1 100644 --- a/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/StatementCacheTest.java +++ b/hibernate-c3p0/src/test/java/org/hibernate/test/c3p0/StatementCacheTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.test.c3p0; diff --git a/hibernate-c3p0/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener b/hibernate-c3p0/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener index 8f96f0a8e1b0..ef95df5d6c74 100644 --- a/hibernate-c3p0/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener +++ b/hibernate-c3p0/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener @@ -1 +1,5 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# Copyright Red Hat Inc. and Hibernate Authors +# org.hibernate.testing.schema.CheckClearSchemaListener diff --git a/hibernate-c3p0/src/test/resources/META-INF/validation.xml b/hibernate-c3p0/src/test/resources/META-INF/validation.xml index 04cc24117fdd..e4a501404f82 100644 --- a/hibernate-c3p0/src/test/resources/META-INF/validation.xml +++ b/hibernate-c3p0/src/test/resources/META-INF/validation.xml @@ -1,8 +1,6 @@ . +# SPDX-License-Identifier: Apache-2.0 +# Copyright Red Hat Inc. and Hibernate Authors # hibernate.dialect @db.dialect@ hibernate.connection.driver_class @jdbc.driver@ diff --git a/hibernate-c3p0/src/test/resources/log4j2.properties b/hibernate-c3p0/src/test/resources/log4j2.properties index d4da0b21a5e8..0b179695ce92 100644 --- a/hibernate-c3p0/src/test/resources/log4j2.properties +++ b/hibernate-c3p0/src/test/resources/log4j2.properties @@ -1,8 +1,6 @@ # -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . +# SPDX-License-Identifier: Apache-2.0 +# Copyright Red Hat Inc. and Hibernate Authors # appender.stdout.type=Console appender.stdout.name=STDOUT diff --git a/hibernate-community-dialects/hibernate-community-dialects.gradle b/hibernate-community-dialects/hibernate-community-dialects.gradle index 0ed79a16a4e4..c2089b483917 100644 --- a/hibernate-community-dialects/hibernate-community-dialects.gradle +++ b/hibernate-community-dialects/hibernate-community-dialects.gradle @@ -1,8 +1,6 @@ /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ plugins { diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java index a609ae0e8d7e..7b5671f5e17c 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -515,13 +515,13 @@ public int getMaxIdentifierLength() { @Override public IdentifierHelper buildIdentifierHelper( IdentifierHelperBuilder builder, - DatabaseMetaData dbMetaData) throws SQLException { + DatabaseMetaData metadata) throws SQLException { // Any use of keywords as identifiers will result in syntax error, so enable auto quote always builder.setAutoQuoteKeywords( true ); builder.setAutoQuoteInitialUnderscore( false ); - builder.applyReservedWords( dbMetaData ); + builder.applyReservedWords( metadata ); - return super.buildIdentifierHelper( builder, dbMetaData ); + return super.buildIdentifierHelper( builder, metadata ); } @Override @@ -718,4 +718,24 @@ public String getFromDualForSelectOnly() { return " from " + getDual(); } + @Override + public boolean supportsJoinsInDelete() { + return true; + } + + @Override + public boolean supportsSimpleQueryGrouping() { + return false; + } + + @Override + public boolean supportsWithClauseInSubquery() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseSqlAstTranslator.java index 616ea6f5bcf2..be1f10cf42fe 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/AltibaseSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -64,7 +64,8 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp @Override public void visitOver(Over over) { final Expression expression = over.getExpression(); - if ( expression instanceof FunctionExpression && "row_number".equals( ( (FunctionExpression) expression ).getFunctionName() ) ) { + if ( expression instanceof FunctionExpression functionExpression + && "row_number".equals( functionExpression.getFunctionName() ) ) { if ( over.getPartitions().isEmpty() && over.getOrderList().isEmpty() && over.getStartKind() == FrameKind.UNBOUNDED_PRECEDING && over.getEndKind() == FrameKind.CURRENT_ROW @@ -223,24 +224,4 @@ protected boolean needsRecursiveKeywordInWithClause() { return false; } - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - - @Override - protected boolean supportsWithClauseInSubquery() { - return false; - } - - @Override - protected boolean supportsJoinsInDelete() { - return true; - } - - @Override - protected boolean supportsSimpleQueryGrouping() { - return false; - } - } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java index bf425eefe2f3..e82b226971d6 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -527,4 +527,19 @@ public String getFromDualForSelectOnly() { return " from " + getDual(); } + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDSqlAstTranslator.java index 12590f845d6a..e9daf6fd3ac4 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CUBRIDSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -62,19 +62,4 @@ else if ( expression instanceof Summarization ) { expression.accept( this ); } } - - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java index 02e45053c9ed..551c737b194a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -435,4 +435,19 @@ public void appendDatetimeFormat(SqlAppender appender, String format) { appender.appendSql( OracleDialect.datetimeFormat( format, false, false ).result() ); } + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheSqlAstTranslator.java index fa707b760712..6650ce08c9b0 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -105,19 +105,4 @@ else if ( expression instanceof Summarization ) { expression.accept( this ); } } - - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java index f59c66fca7a5..c31d2712b985 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java @@ -1,31 +1,32 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; -import java.lang.invoke.MethodHandles; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; -import java.time.temporal.ChronoField; -import java.time.temporal.TemporalAccessor; -import java.util.Calendar; -import java.util.Date; -import java.util.Map; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - +import jakarta.persistence.GenerationType; +import jakarta.persistence.TemporalType; +import jakarta.persistence.Timeout; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.PessimisticLockException; import org.hibernate.QueryTimeoutException; +import org.hibernate.Timeouts; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; -import org.hibernate.dialect.*; +import org.hibernate.dialect.DatabaseVersion; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.DmlTargetColumnQualifierSupport; +import org.hibernate.dialect.FunctionalDependencyAnalysisSupport; +import org.hibernate.dialect.FunctionalDependencyAnalysisSupportImpl; +import org.hibernate.dialect.NationalizationSupport; +import org.hibernate.dialect.NullOrdering; +import org.hibernate.dialect.PostgreSQLDriverKind; +import org.hibernate.dialect.RowLockStrategy; +import org.hibernate.dialect.SimpleDatabaseVersion; +import org.hibernate.dialect.SpannerDialect; +import org.hibernate.dialect.TimeZoneSupport; import org.hibernate.dialect.aggregate.AggregateSupport; import org.hibernate.dialect.aggregate.CockroachDBAggregateSupport; import org.hibernate.dialect.function.CommonFunctionFactory; @@ -37,6 +38,15 @@ import org.hibernate.dialect.pagination.OffsetFetchLimitHandler; import org.hibernate.dialect.sequence.PostgreSQLSequenceSupport; import org.hibernate.dialect.sequence.SequenceSupport; +import org.hibernate.dialect.type.PgJdbcHelper; +import org.hibernate.dialect.type.PostgreSQLArrayJdbcTypeConstructor; +import org.hibernate.dialect.type.PostgreSQLCastingInetJdbcType; +import org.hibernate.dialect.type.PostgreSQLCastingIntervalSecondJdbcType; +import org.hibernate.dialect.type.PostgreSQLCastingJsonArrayJdbcTypeConstructor; +import org.hibernate.dialect.type.PostgreSQLCastingJsonJdbcType; +import org.hibernate.dialect.type.PostgreSQLEnumJdbcType; +import org.hibernate.dialect.type.PostgreSQLOrdinalEnumJdbcType; +import org.hibernate.dialect.type.PostgreSQLUUIDJdbcType; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; @@ -47,13 +57,11 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor; import org.hibernate.exception.spi.ViolatedConstraintNameExtractor; -import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.internal.util.StringHelper; import org.hibernate.query.SemanticException; -import org.hibernate.query.sqm.IntervalType; -import org.hibernate.dialect.NullOrdering; import org.hibernate.query.common.TemporalUnit; +import org.hibernate.query.sqm.IntervalType; import org.hibernate.query.sqm.produce.function.StandardFunctionArgumentTypeResolvers; import org.hibernate.service.ServiceRegistry; import org.hibernate.sql.ast.SqlAstTranslator; @@ -76,10 +84,18 @@ import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; import org.hibernate.type.spi.TypeConfiguration; -import org.jboss.logging.Logger; - -import jakarta.persistence.GenerationType; -import jakarta.persistence.TemporalType; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.time.temporal.ChronoField; +import java.time.temporal.TemporalAccessor; +import java.util.Calendar; +import java.util.Date; +import java.util.Map; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate; import static org.hibernate.query.common.TemporalUnit.DAY; @@ -124,7 +140,6 @@ */ public class CockroachLegacyDialect extends Dialect { - private static final CoreMessageLogger LOG = Logger.getMessageLogger( MethodHandles.lookup(), CoreMessageLogger.class, CockroachLegacyDialect.class.getName() ); // KNOWN LIMITATIONS: // * no support for java.sql.Clob @@ -188,11 +203,6 @@ protected static DatabaseVersion parseVersion(String versionString ) { } if ( databaseVersion == null ) { // Recur to the default version of the no-args constructor - LOG.unableToDetermineCockroachDatabaseVersion( - DEFAULT_VERSION.getDatabaseMajorVersion() + "." + - DEFAULT_VERSION.getDatabaseMinorVersion() + "." + - DEFAULT_VERSION.getDatabaseMicroVersion() - ); databaseVersion = DEFAULT_VERSION; } return databaseVersion; @@ -1000,38 +1010,45 @@ public String getForUpdateString(String aliases, LockOptions lockOptions) { if (lockMode == null ) { lockMode = lockOptions.getLockMode(); } - switch ( lockMode ) { - case PESSIMISTIC_READ: { - return getReadLockString( aliases, lockOptions.getTimeOut() ); - } - case PESSIMISTIC_WRITE: { - return getWriteLockString( aliases, lockOptions.getTimeOut() ); - } - case UPGRADE_NOWAIT: - case PESSIMISTIC_FORCE_INCREMENT: { - return getForUpdateNowaitString(aliases); - } - case UPGRADE_SKIPLOCKED: { - return getForUpdateSkipLockedString(aliases); - } - default: { - return ""; - } - } + return switch ( lockMode ) { + case PESSIMISTIC_READ -> getReadLockString( aliases, lockOptions.getTimeOut() ); + case PESSIMISTIC_WRITE -> getWriteLockString( aliases, lockOptions.getTimeOut() ); + case UPGRADE_NOWAIT, PESSIMISTIC_FORCE_INCREMENT -> getForUpdateNowaitString( aliases ); + case UPGRADE_SKIPLOCKED -> getForUpdateSkipLockedString( aliases ); + default -> ""; + }; + } + + private String withTimeout(String lockString, Timeout timeout) { + return withTimeout( lockString, timeout.milliseconds() ); } private String withTimeout(String lockString, int timeout) { - switch (timeout) { - case LockOptions.NO_WAIT: { - return supportsNoWait() ? lockString + " nowait" : lockString; - } - case LockOptions.SKIP_LOCKED: { - return supportsSkipLocked() ? lockString + " skip locked" : lockString; - } - default: { - return lockString; - } - } + return switch ( timeout ) { + case Timeouts.NO_WAIT_MILLI -> supportsNoWait() ? lockString + " nowait" : lockString; + case Timeouts.SKIP_LOCKED_MILLI -> supportsSkipLocked() ? lockString + " skip locked" : lockString; + default -> lockString; + }; + } + + @Override + public String getWriteLockString(Timeout timeout) { + return withTimeout( getForUpdateString(), timeout ); + } + + @Override + public String getWriteLockString(String aliases, Timeout timeout) { + return withTimeout( getForUpdateString( aliases ), timeout ); + } + + @Override + public String getReadLockString(Timeout timeout) { + return withTimeout(" for share", timeout ); + } + + @Override + public String getReadLockString(String aliases, Timeout timeout) { + return withTimeout(" for share of " + aliases, timeout ); } @Override @@ -1146,15 +1163,15 @@ public NameQualifierSupport getNameQualifierSupport() { } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { - if ( dbMetaData == null ) { + if ( metadata == null ) { builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.LOWER ); builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); } - return super.buildIdentifierHelper( builder, dbMetaData ); + return super.buildIdentifierHelper( builder, metadata ); } @Override @@ -1248,4 +1265,20 @@ public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { public boolean supportsFromClauseInUpdate() { return true; } + + @Override + public boolean supportsRowConstructor() { + return true; + } + + @Override + public boolean supportsArrayConstructor() { + return true; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacySqlAstTranslator.java index 63a75fcd7ada..c49aaf4554ff 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -129,16 +129,6 @@ protected void renderMaterializationHint(CteMaterialization materialization) { } } - @Override - protected boolean supportsRowConstructor() { - return true; - } - - @Override - protected boolean supportsArrayConstructor() { - return true; - } - @Override protected String getForShare(int timeoutMillis) { return " for share"; @@ -244,11 +234,6 @@ public void visitLikePredicate(LikePredicate likePredicate) { } } - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - @Override public void visitInArrayPredicate(InArrayPredicate inArrayPredicate) { inArrayPredicate.getTestExpression().accept( this ); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDatabase.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDatabase.java index b7b0f58c846a..73011693dbd7 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDatabase.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDatabase.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDialectResolver.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDialectResolver.java index f9d4dc341166..bc0eddf72671 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDialectResolver.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDialectResolver.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDialectSelector.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDialectSelector.java index 4ad491e2dc21..a14a8b495e90 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDialectSelector.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CommunityDialectSelector.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java index b49e1397de7c..da0bea1227ff 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacyDialect.java @@ -1,34 +1,17 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; -import java.sql.CallableStatement; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; -import java.time.Instant; -import java.time.LocalDate; -import java.time.LocalDateTime; -import java.time.LocalTime; -import java.time.OffsetDateTime; -import java.time.OffsetTime; -import java.time.ZonedDateTime; -import java.time.temporal.TemporalAccessor; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.TimeZone; - -import org.hibernate.LockOptions; +import jakarta.persistence.TemporalType; +import jakarta.persistence.Timeout; +import org.hibernate.Timeouts; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; import org.hibernate.community.dialect.sequence.LegacyDB2SequenceSupport; import org.hibernate.dialect.DB2Dialect; import org.hibernate.dialect.DB2GetObjectExtractor; -import org.hibernate.dialect.DB2StructJdbcType; import org.hibernate.dialect.DatabaseVersion; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.DmlTargetColumnQualifierSupport; @@ -49,6 +32,7 @@ import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.sequence.DB2SequenceSupport; import org.hibernate.dialect.sequence.SequenceSupport; +import org.hibernate.dialect.type.DB2StructJdbcType; import org.hibernate.dialect.unique.AlterTableUniqueIndexDelegate; import org.hibernate.dialect.unique.SkipNullableUniqueDelegate; import org.hibernate.dialect.unique.UniqueDelegate; @@ -70,9 +54,9 @@ import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.procedure.internal.DB2CallableStatementSupport; import org.hibernate.procedure.spi.CallableStatementSupport; +import org.hibernate.query.common.TemporalUnit; import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.IntervalType; -import org.hibernate.query.common.TemporalUnit; import org.hibernate.query.sqm.mutation.internal.cte.CteInsertStrategy; import org.hibernate.query.sqm.mutation.internal.cte.CteMutationStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy; @@ -118,7 +102,23 @@ import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; import org.hibernate.type.spi.TypeConfiguration; -import jakarta.persistence.TemporalType; +import java.sql.CallableStatement; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; +import java.time.Instant; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.OffsetDateTime; +import java.time.OffsetTime; +import java.time.ZonedDateTime; +import java.time.temporal.TemporalAccessor; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate; import static org.hibernate.type.SqlTypes.BINARY; @@ -781,16 +781,30 @@ public String getForUpdateSkipLockedString(String aliases) { return getForUpdateSkipLockedString(); } + @Override + public String getWriteLockString(Timeout timeout) { + return timeout.milliseconds() == Timeouts.SKIP_LOCKED_MILLI && supportsSkipLocked() + ? FOR_UPDATE_SKIP_LOCKED_SQL + : FOR_UPDATE_SQL; + } + + @Override + public String getReadLockString(Timeout timeout) { + return timeout.milliseconds() == Timeouts.SKIP_LOCKED_MILLI && supportsSkipLocked() + ? FOR_SHARE_SKIP_LOCKED_SQL + : FOR_SHARE_SQL; + } + @Override public String getWriteLockString(int timeout) { - return timeout == LockOptions.SKIP_LOCKED && supportsSkipLocked() + return timeout == Timeouts.SKIP_LOCKED_MILLI && supportsSkipLocked() ? FOR_UPDATE_SKIP_LOCKED_SQL : FOR_UPDATE_SQL; } @Override public String getReadLockString(int timeout) { - return timeout == LockOptions.SKIP_LOCKED && supportsSkipLocked() + return timeout == Timeouts.SKIP_LOCKED_MILLI && supportsSkipLocked() ? FOR_SHARE_SKIP_LOCKED_SQL : FOR_SHARE_SQL; } @@ -1240,10 +1254,10 @@ public String generatedAs(String generatedAs) { } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { builder.setAutoQuoteInitialUnderscore(true); - return super.buildIdentifierHelper(builder, dbMetaData); + return super.buildIdentifierHelper(builder, metadata ); } @Override @@ -1306,4 +1320,25 @@ public String getDual() { public String getFromDualForSelectOnly() { return " from " + getDual(); } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsWithClauseInSubquery() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java index 4bfd9aafb01f..ee3176a74cee 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -74,11 +74,6 @@ protected boolean needsRecursiveKeywordInWithClause() { return false; } - @Override - protected boolean supportsWithClauseInSubquery() { - return false; - } - @Override protected void renderTableReferenceJoins(TableGroup tableGroup, int swappedJoinIndex, boolean forceLeftJoin) { // When we are in a recursive CTE, we can't render joins on DB2... @@ -623,21 +618,6 @@ else if ( expression instanceof Summarization ) { } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - @Override protected void visitReturningColumns(List returningColumns) { // For DB2 we use #renderReturningClause to render a wrapper around the DML statement diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2iLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2iLegacyDialect.java index 134d3b710b40..94d2c3aed20a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2iLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2iLegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2iLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2iLegacySqlAstTranslator.java index 605742b95cc9..23403b587513 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2iLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2iLegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2zLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2zLegacyDialect.java index c1bbbd2a3a46..a1f25cd4429c 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2zLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2zLegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2zLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2zLegacySqlAstTranslator.java index 54f7b3386736..7bbd45a1cc84 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2zLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2zLegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyDialect.java index f336f52ffb8c..ca2ba74b9533 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -9,6 +9,7 @@ import java.sql.Types; import java.util.Locale; +import jakarta.persistence.Timeout; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; import org.hibernate.dialect.DB2Dialect; @@ -577,6 +578,16 @@ public String getForUpdateString() { return " for update with rs"; } + @Override + public String getWriteLockString(Timeout timeout) { + return " for update with rs"; + } + + @Override + public String getReadLockString(Timeout timeout) { + return " for read only with rs"; + } + @Override public String getWriteLockString(int timeout) { return " for update with rs"; @@ -1046,10 +1057,10 @@ public boolean supportsValuesList() { } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { builder.setAutoQuoteInitialUnderscore(true); - return super.buildIdentifierHelper(builder, dbMetaData); + return super.buildIdentifierHelper(builder, metadata ); } @Override @@ -1072,4 +1083,29 @@ public String getFromDualForSelectOnly() { return " from " + getDual() + " dual"; } + @Override + public boolean supportsJoinInMutationStatementSubquery() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsWithClause() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacyDialect.java index 6b660f8bceac..9d6e824702ab 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -8,6 +8,7 @@ import java.sql.SQLException; import java.sql.Types; +import jakarta.persistence.Timeout; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; import org.hibernate.dialect.DB2Dialect; @@ -593,6 +594,16 @@ public String getForUpdateString() { return " for update with rs"; } + @Override + public String getWriteLockString(Timeout timeout) { + return " for update with rs"; + } + + @Override + public String getReadLockString(Timeout timeout) { + return " for read only with rs"; + } + @Override public String getWriteLockString(int timeout) { return " for update with rs"; @@ -1057,10 +1068,10 @@ public boolean supportsValuesList() { } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { builder.setAutoQuoteInitialUnderscore(true); - return super.buildIdentifierHelper(builder, dbMetaData); + return super.buildIdentifierHelper(builder, metadata ); } @Override @@ -1077,4 +1088,30 @@ public String getDual() { public String getFromDualForSelectOnly() { return " from " + getDual() + " dual"; } + + @Override + public boolean supportsJoinInMutationStatementSubquery() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsWithClause() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacySqlAstTranslator.java index 8988e01b84de..36195423f296 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -105,11 +105,6 @@ protected void renderDmlTargetTableExpression(NamedTableReference tableReference } } - @Override - protected boolean supportsWithClause() { - return false; - } - @Override protected void renderExpressionAsClauseItem(Expression expression) { expression.accept( this ); @@ -283,21 +278,6 @@ public void visitInListPredicate(InListPredicate inListPredicate) { } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - @Override protected boolean needsRowsToSkip() { return !supportsOffsetFetchClause(); @@ -317,11 +297,6 @@ private boolean supportsOffsetFetchClause() { return getDialect().getVersion().isSameOrAfter( 10, 5 ); } - @Override - protected boolean supportsJoinInMutationStatementSubquery() { - return false; - } - @Override protected void visitArithmeticOperand(Expression expression) { render( expression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbySqlAstTranslator.java index 2a03d4f7dea3..5f886c46b51b 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -105,11 +105,6 @@ protected void renderDmlTargetTableExpression(NamedTableReference tableReference } } - @Override - protected boolean supportsWithClause() { - return false; - } - @Override protected void renderExpressionAsClauseItem(Expression expression) { expression.accept( this ); @@ -283,21 +278,6 @@ public void visitInListPredicate(InListPredicate inListPredicate) { } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - @Override protected boolean needsRowsToSkip() { return !supportsOffsetFetchClause(); @@ -317,11 +297,6 @@ private boolean supportsOffsetFetchClause() { return true; } - @Override - protected boolean supportsJoinInMutationStatementSubquery() { - return false; - } - @Override protected void visitArithmeticOperand(Expression expression) { render( expression, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java index 5a2b7a89c088..7bece930e33c 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -33,9 +33,11 @@ import org.hibernate.dialect.BooleanDecoder; import org.hibernate.dialect.DatabaseVersion; import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.DmlTargetColumnQualifierSupport; import org.hibernate.dialect.NationalizationSupport; import org.hibernate.dialect.TimeZoneSupport; import org.hibernate.dialect.function.CommonFunctionFactory; +import org.hibernate.dialect.function.HypotheticalSetWindowEmulation; import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.OffsetFetchLimitHandler; @@ -88,6 +90,7 @@ import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; import jakarta.persistence.TemporalType; +import org.hibernate.type.spi.TypeConfiguration; import static org.hibernate.query.sqm.produce.function.FunctionParameterType.INTEGER; import static org.hibernate.query.sqm.produce.function.FunctionParameterType.STRING; @@ -96,6 +99,7 @@ import static org.hibernate.type.SqlTypes.BOOLEAN; import static org.hibernate.type.SqlTypes.CLOB; import static org.hibernate.type.SqlTypes.NCLOB; +import static org.hibernate.type.SqlTypes.TIME; import static org.hibernate.type.SqlTypes.TIMESTAMP; import static org.hibernate.type.SqlTypes.TIMESTAMP_WITH_TIMEZONE; import static org.hibernate.type.SqlTypes.TIME_WITH_TIMEZONE; @@ -114,7 +118,7 @@ */ public class FirebirdDialect extends Dialect { - private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 2, 5 ); + private static final DatabaseVersion DEFAULT_VERSION = DatabaseVersion.make( 3 ); @SuppressWarnings("unused") public FirebirdDialect() { @@ -140,31 +144,24 @@ public FirebirdDialect(DatabaseVersion version) { @Override protected String columnType(int sqlTypeCode) { - switch ( sqlTypeCode ) { + return switch ( sqlTypeCode ) { //'boolean' type introduced in 3.0 - case BOOLEAN: - return getVersion().isBefore( 3, 0 ) ? "smallint" : super.columnType( sqlTypeCode ); - case TINYINT: - return "smallint"; + case BOOLEAN -> getVersion().isBefore( 3 ) ? "smallint" : "boolean"; + case TINYINT -> "smallint"; //no precision for 'timestamp' type - case TIMESTAMP: - return "timestamp"; - case TIME_WITH_TIMEZONE: - return getVersion().isBefore( 4, 0 ) ? "time" : "time with time zone"; - case TIMESTAMP_WITH_TIMEZONE: - return getVersion().isBefore( 4, 0 ) ? "timestamp" : "timestamp with time zone"; - case BINARY: - return getVersion().isBefore( 4, 0 ) ? "char($l) character set octets" : super.columnType( sqlTypeCode ); - case VARBINARY: - return getVersion().isBefore( 4, 0 ) ? "varchar($l) character set octets" : super.columnType( sqlTypeCode ); - case BLOB: - return "blob sub_type binary"; - case CLOB: - case NCLOB: - return "blob sub_type text"; - default: - return super.columnType( sqlTypeCode ); - } + case TIMESTAMP -> "timestamp"; + //no precision for 'time' type + case TIME -> "time"; + //no precision for 'time with time zone' type + case TIME_WITH_TIMEZONE -> getVersion().isBefore( 4 ) ? "time" : "time with time zone"; + //no precision for 'timestamp with time zone' type + case TIMESTAMP_WITH_TIMEZONE -> getVersion().isBefore( 4 ) ? "timestamp" : "timestamp with time zone"; + case BINARY -> getVersion().isBefore( 4 ) ? "char($l) character set octets" : "binary($l)"; + case VARBINARY -> getVersion().isBefore( 4 ) ? "varchar($l) character set octets" : "varbinary($l)"; + case BLOB -> "blob sub_type binary"; + case CLOB, NCLOB -> "blob sub_type text"; + default -> super.columnType( sqlTypeCode ); + }; } @Override @@ -209,6 +206,21 @@ public TimeZoneSupport getTimeZoneSupport() { return getVersion().isSameOrAfter( 4, 0 ) ? TimeZoneSupport.NATIVE : TimeZoneSupport.NONE; } + @Override + public String currentTime() { + return getVersion().isSameOrAfter( 4 ) ? "localtime" : "current_time"; + } + + @Override + public String currentTimestamp() { + return getVersion().isSameOrAfter( 4 ) ? "localtimestamp" : "current_timestamp"; + } + + @Override + public String currentTimestampWithTimeZone() { + return "current_timestamp"; + } + @Override public JdbcType resolveSqlTypeDescriptor( String columnTypeName, @@ -249,6 +261,20 @@ public int getDefaultTimestampPrecision() { return 3; } + @Override + public long getFractionalSecondPrecisionInNanos() { + // Formally, Firebird can store values with 100 microsecond precision (100_000 nanoseconds). + // However, some functions (e.g. CURRENT_TIMESTAMP) will only return values with millisecond precision + // So, we report millisecond precision + return 1_000_000; //milliseconds + } + + @Override + public boolean doesRoundTemporalOnOverflow() { + // Driver truncates parameter values with a higher precision to 100 microseconds (precision of 4) + return false; + } + @Override public void initializeFunctionRegistry(FunctionContributions functionContributions) { super.initializeFunctionRegistry(functionContributions); @@ -256,11 +282,13 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio final BasicTypeRegistry basicTypeRegistry = functionContributions.getTypeConfiguration().getBasicTypeRegistry(); final BasicType byteArrayType = basicTypeRegistry.resolve( StandardBasicTypes.BINARY ); final BasicType integerType = basicTypeRegistry.resolve( StandardBasicTypes.INTEGER ); - final BasicType shortType = basicTypeRegistry.resolve( StandardBasicTypes.SHORT ); final BasicType doubleType = basicTypeRegistry.resolve( StandardBasicTypes.DOUBLE ); final BasicType characterType = basicTypeRegistry.resolve( StandardBasicTypes.CHARACTER ); + final DatabaseVersion version = getVersion(); + CommonFunctionFactory functionFactory = new CommonFunctionFactory(functionContributions); + TypeConfiguration typeConfiguration = functionContributions.getTypeConfiguration(); // Firebird needs an actual argument type for aggregates like SUM, AVG, MIN, MAX to determine the result type functionFactory.aggregates( this, SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER ); @@ -272,7 +300,7 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio functionFactory.cosh(); functionFactory.sinh(); functionFactory.tanh(); - if ( getVersion().isSameOrAfter( 3, 0 ) ) { + if ( version.isSameOrAfter( 3 ) ) { functionFactory.moreHyperbolic(); functionFactory.stddevPopSamp(); functionFactory.varPopSamp(); @@ -292,23 +320,28 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio functionFactory.bitLength(); functionFactory.substringFromFor(); functionFactory.overlay(); - functionFactory.position(); + functionFactory.insert_overlay(); functionFactory.reverse(); functionFactory.bitandorxornot_binAndOrXorNot(); functionFactory.leastGreatest_minMaxValue(); + if ( version.isSameOrAfter( 3, 0, 4 ) + || version.isBefore( 3 ) && version.isSameOrAfter( 2, 5, 9 ) ) { + functionFactory.localtimeLocaltimestamp(); + } SqmFunctionRegistry functionRegistry = functionContributions.getFunctionRegistry(); functionRegistry.registerBinaryTernaryPattern( - "locate", + "position", integerType, "position(?1 in ?2)", "position(?1,?2,?3)", STRING, STRING, INTEGER, - functionContributions.getTypeConfiguration() - ).setArgumentListSignature( "(pattern, string[, start])" ); + typeConfiguration + ).setArgumentListSignature( "(STRING pattern, STRING string[, INTEGER start])" ); + functionRegistry.registerAlternateKey( "locate", "position" ); functionRegistry.namedDescriptorBuilder( "ascii_val" ) .setExactArgumentCount( 1 ) - .setInvariantType( shortType ) + .setInvariantType( integerType ) .register(); functionRegistry.registerAlternateKey( "ascii", "ascii_val" ); functionRegistry.namedDescriptorBuilder( "ascii_char" ) @@ -327,46 +360,54 @@ public void initializeFunctionRegistry(FunctionContributions functionContributio "((?1)*180e0/pi())", doubleType ); + functionFactory.repeat_rpad( "char_length" ); - if ( getVersion().isSameOrAfter( 3 ) ) { + if ( version.isSameOrAfter( 3 ) ) { functionFactory.windowFunctions(); - if ( getVersion().isSameOrAfter( 4, 0 ) ) { - Arrays.asList( "md5", "sha1", "sha256", "sha512" ) + functionFactory.hypotheticalOrderedSetAggregates(); + if ( version.isBefore( 4 )) { + // percent_rank and cume_dist introduced in Firebird 4.0, emulate + // see hypotheticalOrderedSetAggregates_windowEmulation + functionRegistry.register( + "percent_rank", + new HypotheticalSetWindowEmulation( "percent_rank", StandardBasicTypes.DOUBLE, typeConfiguration ) + ); + functionRegistry.register( + "cume_dist", + new HypotheticalSetWindowEmulation( "cume_dist", StandardBasicTypes.DOUBLE, typeConfiguration ) + ); + } + if ( version.isSameOrAfter( 4 ) ) { + functionFactory.sha( "crypt_hash(?1 using sha256)" ); + functionFactory.md5( "crypt_hash(?1 using md5)" ); + Arrays.asList( "sha1", "sha256", "sha512" ) .forEach( hash -> functionRegistry.registerPattern( hash, "crypt_hash(?1 using " + hash + ")", byteArrayType ) ); - functionRegistry.registerAlternateKey( "sha", "sha1" ); functionRegistry.registerPattern( "crc32", "hash(?1 using crc32)", integerType ); + functionFactory.hex( "hex_encode(?1)" ); } } functionFactory.listagg_list( "varchar" ); - } - @Override - public String currentLocalTime() { - if ( getTimeZoneSupport() == TimeZoneSupport.NATIVE ) { - return "localtime"; - } - else { - return super.currentLocalTime(); - } + functionFactory.generateSeries_recursive( getMaximumSeriesSize(), false, false ); } - @Override - public String currentLocalTimestamp() { - if ( getTimeZoneSupport() == TimeZoneSupport.NATIVE ) { - return "localtimestamp"; - } - else { - return super.currentLocalTimestamp(); - } + /** + * Firebird doesn't support the {@code generate_series} function or {@code lateral} recursive CTEs, + * so it has to be emulated with a top level recursive CTE which requires an upper bound on the amount + * of elements that the series can return. + */ + protected int getMaximumSeriesSize() { + // The maximum recursion depth of Firebird + return 1024; } @Override @@ -443,14 +484,6 @@ public String castPattern(CastType from, CastType to) { return super.castPattern( from, to ); } - @Override - public long getFractionalSecondPrecisionInNanos() { - // Formally, Firebird can store values with 100 microsecond precision (100_000 nanoseconds). - // However, some functions (e.g. CURRENT_TIMESTAMP) will only return values with millisecond precision - // So, we report millisecond precision - return 1_000_000; //milliseconds - } - /** * Firebird extract() function returns {@link TemporalUnit#DAY_OF_WEEK} * numbered from 0 to 6, and {@link TemporalUnit#DAY_OF_YEAR} numbered @@ -459,47 +492,34 @@ public long getFractionalSecondPrecisionInNanos() { */ @Override public String extractPattern(TemporalUnit unit) { - switch ( unit ) { - case DAY_OF_WEEK: - case DAY_OF_YEAR: - return "(" + super.extractPattern( unit ) + "+1)"; - case QUARTER: - return "((extract(month from ?2)+2)/3)"; - default: - return super.extractPattern( unit ); - } + return switch ( unit ) { + case DAY_OF_WEEK, DAY_OF_YEAR -> "(" + super.extractPattern( unit ) + "+1)"; + case QUARTER -> "((extract(month from ?2)+2)/3)"; + case EPOCH -> "datediff(second from timestamp '1970-01-01 00:00:00' to ?2)"; + default -> super.extractPattern( unit ); + }; } @Override public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) { - switch ( unit ) { - case NATIVE: - return "dateadd((?2) millisecond to ?3)"; - case NANOSECOND: - return "dateadd((?2)/1e6 millisecond to ?3)"; - case WEEK: - return "dateadd((?2)*7 day to ?3)"; - case QUARTER: - return "dateadd((?2)*3 month to ?3)"; - default: - return "dateadd(?2 ?1 to ?3)"; - } + return switch ( unit ) { + case NATIVE -> "dateadd((?2) millisecond to ?3)"; + case NANOSECOND -> "dateadd((?2)/1e6 millisecond to ?3)"; + case WEEK -> "dateadd((?2)*7 day to ?3)"; + case QUARTER -> "dateadd((?2)*3 month to ?3)"; + default -> "dateadd(?2 ?1 to ?3)"; + }; } @Override public String timestampdiffPattern(TemporalUnit unit, TemporalType fromTemporalType, TemporalType toTemporalType) { - switch ( unit ) { - case NATIVE: - return "datediff(millisecond from ?2 to ?3)"; - case NANOSECOND: - return "datediff(millisecond from ?2 to ?3)*1e6"; - case WEEK: - return "datediff(day from ?2 to ?3)/7"; - case QUARTER: - return "datediff(month from ?2 to ?3)/3"; - default: - return "datediff(?1 from ?2 to ?3)"; - } + return switch ( unit ) { + case NATIVE -> "datediff(millisecond from ?2 to ?3)"; + case NANOSECOND -> "datediff(millisecond from ?2 to ?3)*1e6"; + case WEEK -> "datediff(day from ?2 to ?3)/7"; + case QUARTER -> "datediff(month from ?2 to ?3)/3"; + default -> "datediff(?1 from ?2 to ?3)"; + }; } @Override @@ -534,7 +554,7 @@ public int getMaxIdentifierLength() { public IdentifierHelper buildIdentifierHelper( IdentifierHelperBuilder builder, - DatabaseMetaData dbMetaData) throws SQLException { + DatabaseMetaData metadata) throws SQLException { // Any use of keywords as identifiers will result in token unknown error, so enable auto quote always builder.setAutoQuoteKeywords( true ); builder.setAutoQuoteInitialUnderscore( true ); @@ -556,7 +576,7 @@ public IdentifierHelper buildIdentifierHelper( "POSITION", "SUM", "TRIM", "UPPER" ); } - return super.buildIdentifierHelper( builder, dbMetaData ); + return super.buildIdentifierHelper( builder, metadata ); } @Override @@ -604,8 +624,9 @@ public boolean supportsTupleDistinctCounts() { @Override public int getInExpressionCountLimit() { - // see https://www.firebirdsql.org/file/documentation/html/en/refdocs/fblangref25/firebird-25-language-reference.html#fblangref25-commons-in - return 1500; + // see https://firebirdsql.org/file/documentation/html/en/refdocs/fblangref25/firebird-25-language-reference.html#fblangref25-commons-in + // and https://firebirdsql.org/file/documentation/html/en/refdocs/fblangref50/firebird-50-language-reference.html#fblangref50-commons-in + return getVersion().isBefore( 5 ) ? 1500 : 65535; } @Override @@ -676,6 +697,16 @@ public String getForUpdateString() { return " with lock"; } + @Override + public String getForUpdateSkipLockedString() { + return getVersion().isSameOrAfter( 5 ) ? " with lock skip locked" : " with lock"; + } + + @Override + public String getForUpdateSkipLockedString(String aliases) { + return getForUpdateSkipLockedString(); + } + @Override public LimitHandler getLimitHandler() { return getVersion().isBefore( 3, 0 ) @@ -787,14 +818,15 @@ public boolean hasDataTypeBeforeGeneratedAs() { @Override public String translateExtractField(TemporalUnit unit) { - switch ( unit ) { - case DAY_OF_MONTH: return "day"; - case DAY_OF_YEAR: return "yearday"; - case DAY_OF_WEEK: return "weekday"; - default: return super.translateExtractField( unit ); - } + return switch ( unit ) { + case DAY_OF_MONTH -> "day"; + case DAY_OF_YEAR -> "yearday"; + case DAY_OF_WEEK -> "weekday"; + default -> super.translateExtractField( unit ); + }; } + @Override public void appendDateTimeLiteral( SqlAppender appender, TemporalAccessor temporalAccessor, @@ -938,17 +970,44 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { return new LockAcquisitionException( message, sqlException, sql ); case 335544466: // isc_foreign_key (violation of FOREIGN KEY constraint "{0}" on table "{1}") - case 336396758: + case 336396758: { // *no error name* (violation of FOREIGN KEY constraint "{0}") - case 335544558: + final String constraintName = getViolatedConstraintNameExtractor().extractConstraintName( + sqlException ); + return new ConstraintViolationException( + message, + sqlException, + sql, + ConstraintViolationException.ConstraintKind.FOREIGN_KEY, + constraintName + ); + } + case 335544558: { // isc_check_constraint (Operation violates CHECK constraint {0} on view or table {1}) + final String constraintName = getViolatedConstraintNameExtractor().extractConstraintName( + sqlException ); + return new ConstraintViolationException( + message, + sqlException, + sql, + ConstraintViolationException.ConstraintKind.CHECK, + constraintName + ); + } case 336396991: // *no error name* (Operation violates CHECK constraint {0} on view or table) - case 335544665: + case 335544665: { // isc_unique_key_violation (violation of PRIMARY or UNIQUE KEY constraint "{0}" on table "{1}") final String constraintName = getViolatedConstraintNameExtractor().extractConstraintName( sqlException ); - return new ConstraintViolationException( message, sqlException, sql, constraintName ); + return new ConstraintViolationException( + message, + sqlException, + sql, + ConstraintViolationException.ConstraintKind.UNIQUE, + constraintName + ); + } } // Apply heuristics based on exception message @@ -1112,4 +1171,48 @@ public String getDual() { public String getFromDualForSelectOnly() { return " from " + getDual(); } + + @Override + public boolean supportsIntersect() { + return false; + } + + @Override + public boolean supportsSimpleQueryGrouping() { + // Firebird 4 and earlier are quite strict i.e. it requires `select ... union all select * from (select ...)` + // rather than `select ... union all (select ...)` + return getVersion().isSameOrAfter( 5 ); + } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsNestedWithClause() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + + @Override + public String getTruncateTableStatement(String tableName) { + // Firebird doesn't have truncate table; https://github.com/FirebirdSQL/firebird/issues/2892 + return "delete from " + tableName; + } + + @Override + public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { + return DmlTargetColumnQualifierSupport.TABLE_ALIAS; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java index 31882f1df88d..a682295e495c 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -16,6 +16,7 @@ import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.Statement; +import org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression; import org.hibernate.sql.ast.tree.expression.CaseSearchedExpression; import org.hibernate.sql.ast.tree.expression.CaseSimpleExpression; import org.hibernate.sql.ast.tree.expression.Expression; @@ -27,13 +28,18 @@ import org.hibernate.sql.ast.tree.expression.SelfRenderingExpression; import org.hibernate.sql.ast.tree.expression.SqlTuple; import org.hibernate.sql.ast.tree.expression.Summarization; +import org.hibernate.sql.ast.tree.from.NamedTableReference; +import org.hibernate.sql.ast.tree.from.ValuesTableReference; +import org.hibernate.sql.ast.tree.insert.InsertSelectStatement; import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate; +import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate; import org.hibernate.sql.ast.tree.predicate.InListPredicate; import org.hibernate.sql.ast.tree.predicate.SelfRenderingPredicate; import org.hibernate.sql.ast.tree.select.QueryGroup; import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.SelectClause; +import org.hibernate.sql.ast.tree.update.UpdateStatement; import org.hibernate.sql.exec.spi.JdbcOperation; /** @@ -49,6 +55,27 @@ public FirebirdSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statem super( sessionFactory, statement ); } + @Override + protected void visitInsertStatementOnly(InsertSelectStatement statement) { + if ( statement.getConflictClause() == null || statement.getConflictClause().isDoNothing() ) { + // Render plain insert statement and possibly run into unique constraint violation + super.visitInsertStatementOnly( statement ); + } + else { + visitInsertStatementEmulateMerge( statement ); + } + } + + @Override + protected void visitUpdateStatementOnly(UpdateStatement statement) { + if ( hasNonTrivialFromClause( statement.getFromClause() ) ) { + visitUpdateStatementEmulateMerge( statement ); + } + else { + super.visitUpdateStatementOnly( statement ); + } + } + @Override public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanExpressionPredicate) { if ( getDialect().getVersion().isSameOrAfter( 3 ) ) { @@ -123,6 +150,11 @@ protected String getForUpdate() { return " with lock"; } + @Override + protected String getForShare(int timeoutMillis) { + return getForUpdate(); + } + protected boolean shouldEmulateFetchClause(QueryPart queryPart) { // Percent fetches or ties fetches aren't supported in Firebird // Before 3.0 there was also no support for window functions @@ -151,6 +183,7 @@ public void visitQuerySpec(QuerySpec querySpec) { } } + // overridden due to visitSqlSelections @Override public void visitSelectClause(SelectClause selectClause) { Stack clauseStack = getClauseStack(); @@ -187,13 +220,6 @@ public void visitOffsetFetchClause(QueryPart queryPart) { } } - @Override - protected boolean supportsSimpleQueryGrouping() { - // Firebird 4 and earlier are quite strict i.e. it requires `select .. union all select * from (select ...)` - // rather than `select .. union all (select ...)` - return getDialect().getVersion().isSameOrAfter( 5 ); - } - @Override protected void renderSelectExpression(Expression expression) { renderSelectExpressionWithCastedOrInlinedPlainParameters( expression ); @@ -246,34 +272,14 @@ public void visitInListPredicate(InListPredicate inListPredicate) { } @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; + public void visitValuesTableReference(ValuesTableReference tableReference) { + emulateValuesTableReferenceColumnAliasing( tableReference ); } private boolean supportsOffsetFetchClause() { return getDialect().getVersion().isSameOrAfter( 3 ); } - @Override - protected boolean supportsIntersect() { - return false; - } - - @Override - protected boolean supportsNestedWithClause() { - return false; - } - @Override public void visitSelfRenderingPredicate(SelfRenderingPredicate selfRenderingPredicate) { // see comments in visitParameter @@ -291,7 +297,7 @@ public void visitSelfRenderingPredicate(SelfRenderingPredicate selfRenderingPred public void visitSelfRenderingExpression(SelfRenderingExpression expression) { // see comments in visitParameter boolean inFunction = this.inFunction; - this.inFunction = !( expression instanceof FunctionExpression ) || !"cast".equals( ( (FunctionExpression) expression ).getFunctionName() ); + this.inFunction = isFunctionOrCastWithArithmeticExpression( expression ); try { super.visitSelfRenderingExpression( expression ); } @@ -300,6 +306,14 @@ public void visitSelfRenderingExpression(SelfRenderingExpression expression) { } } + private boolean isFunctionOrCastWithArithmeticExpression(SelfRenderingExpression expression) { + // see comments in visitParameter + return expression instanceof FunctionExpression fe + && ( !"cast".equals( fe.getFunctionName() ) + // types of parameters in an arithmetic expression inside a cast are not (always?) inferred + || fe.getArguments().get( 0 ) instanceof BinaryArithmeticExpression ); + } + @Override public void visitParameter(JdbcParameter jdbcParameter) { if ( inFunction ) { @@ -340,4 +354,38 @@ private void visitLiteral(Literal literal) { renderLiteral( literal, inFunction ); } } + + @Override + public void visitRelationalPredicate(ComparisonPredicate comparisonPredicate) { + if ( isParameterOrContainsParameter( comparisonPredicate.getLeftHandExpression() ) + && isParameterOrContainsParameter( comparisonPredicate.getRightHandExpression() ) ) { + // Firebird cannot compare two parameters with each other as they will be untyped, and in some cases + // comparisons involving arithmetic expression with parameters also fails to infer the type + withParameterRenderingMode( + SqlAstNodeRenderingMode.NO_PLAIN_PARAMETER, + () -> super.visitRelationalPredicate( comparisonPredicate ) + ); + } + else { + super.visitRelationalPredicate( comparisonPredicate ); + } + } + + private static boolean isParameterOrContainsParameter( Expression expression ) { + if ( expression instanceof BinaryArithmeticExpression arithmeticExpression ) { + // Recursive search for parameter + return isParameterOrContainsParameter( arithmeticExpression.getLeftHandOperand() ) + || isParameterOrContainsParameter( arithmeticExpression.getRightHandOperand() ); + } + return isParameter( expression ); + } + + @Override + protected void renderDmlTargetTableExpression(NamedTableReference tableReference) { + super.renderDmlTargetTableExpression( tableReference ); + if ( getClauseStack().getCurrent() != Clause.INSERT ) { + renderTableReferenceIdentificationVariable( tableReference ); + } + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java index 7bf87bd651e1..eb7df8592267 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -34,6 +34,9 @@ import org.hibernate.dialect.sequence.SequenceSupport; import org.hibernate.dialect.temptable.TemporaryTable; import org.hibernate.dialect.temptable.TemporaryTableKind; +import org.hibernate.dialect.type.H2DurationIntervalSecondJdbcType; +import org.hibernate.dialect.type.H2JsonArrayJdbcTypeConstructor; +import org.hibernate.dialect.type.H2JsonJdbcType; import org.hibernate.dialect.unique.CreateTableUniqueDelegate; import org.hibernate.dialect.unique.UniqueDelegate; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; @@ -1057,4 +1060,60 @@ public boolean supportsValuesList() { public String getDual() { return "dual"; } + + @Override + public boolean supportsFilterClause() { + return getVersion().isSameOrAfter( 1, 4, 197 ); + } + + @Override + public boolean supportsRowConstructor() { + return getVersion().isSameOrAfter( 2 ); + } + + @Override + public boolean supportsArrayConstructor() { + return getVersion().isSameOrAfter( 2 ); + } + + @Override + public boolean supportsJoinInMutationStatementSubquery() { + return false; + } + + @Override + public boolean supportsNullPrecedence() { + // Support for nulls clause in listagg was added in 2.0 + return getVersion().isSameOrAfter( 2 ); + } + + @Override + public boolean supportsRowValueConstructorSyntax() { + // Just a guess + return getVersion().isSameOrAfter( 1, 4, 197 ); + } + + @Override + public boolean supportsRowValueConstructorDistinctFromSyntax() { + // Seems that before, this was buggy + return getVersion().isSameOrAfter( 1, 4, 200 ); + } + + @Override + public boolean supportsWithClauseInSubquery() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + // Just a guess + return getVersion().isSameOrAfter( 1, 4, 197 ); + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + // Just a guess + return getVersion().isSameOrAfter( 1, 4, 197 ); + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacySqlAstTranslator.java index 308048f8e3ef..4e823e8ace8a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/H2LegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -202,21 +202,6 @@ protected boolean shouldInlineCte(TableGroup tableGroup) { && !getCteStatement( tableGroup.getPrimaryTableReference().getTableId() ).isRecursive(); } - @Override - protected boolean supportsWithClauseInSubquery() { - return false; - } - - @Override - protected boolean supportsRowConstructor() { - return getDialect().getVersion().isSameOrAfter( 2 ); - } - - @Override - protected boolean supportsArrayConstructor() { - return getDialect().getVersion().isSameOrAfter( 2 ); - } - @Override protected String getArrayContainsFunction() { return "array_contains"; @@ -356,34 +341,8 @@ public void visitLikePredicate(LikePredicate likePredicate) { } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - // Just a guess - return getDialect().getVersion().isSameOrAfter( 1, 4, 197 ); - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - // Just a guess - return getDialect().getVersion().isSameOrAfter( 1, 4, 197 ); - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - // Just a guess - return getDialect().getVersion().isSameOrAfter( 1, 4, 197 ); - } - - @Override - protected boolean supportsRowValueConstructorDistinctFromSyntax() { - // Seems that before, this was buggy - return getDialect().getVersion().isSameOrAfter( 1, 4, 200 ); - } - - @Override - protected boolean supportsNullPrecedence() { - // Support for nulls clause in listagg was added in 2.0 - return getClauseStack().getCurrent() != Clause.WITHIN_GROUP || getDialect().getVersion().isSameOrAfter( 2 ); + protected boolean allowsNullPrecedence() { + return getClauseStack().getCurrent() != Clause.WITHIN_GROUP || getDialect().supportsNullPrecedence(); } private boolean supportsOffsetFetchClause() { @@ -395,14 +354,4 @@ private boolean supportsOffsetFetchClausePercentWithTies() { // Introduction of PERCENT support https://github.com/h2database/h2database/commit/f45913302e5f6ad149155a73763c0c59d8205849 return getDialect().getVersion().isSameOrAfter( 1, 4, 198 ); } - - @Override - protected boolean supportsJoinInMutationStatementSubquery() { - return false; - } - - @Override - public boolean supportsFilterClause() { - return getDialect().getVersion().isSameOrAfter( 1, 4, 197 ); - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacyDialect.java index e564c9d7e342..6e1ad5fb906a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacyDialect.java @@ -1,44 +1,15 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.FilterInputStream; -import java.io.FilterReader; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.io.Reader; -import java.io.StringReader; -import java.io.Writer; -import java.nio.charset.StandardCharsets; -import java.sql.Blob; -import java.sql.CallableStatement; -import java.sql.Clob; -import java.sql.DatabaseMetaData; -import java.sql.NClob; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.SQLFeatureNotSupportedException; -import java.sql.Types; -import java.time.temporal.TemporalAccessor; -import java.util.Arrays; -import java.util.Date; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.TimeZone; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - +import jakarta.persistence.TemporalType; +import jakarta.persistence.Timeout; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.ScrollMode; +import org.hibernate.Timeouts; import org.hibernate.boot.Metadata; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; @@ -48,7 +19,6 @@ import org.hibernate.dialect.Dialect; import org.hibernate.dialect.DmlTargetColumnQualifierSupport; import org.hibernate.dialect.HANAServerConfiguration; -import org.hibernate.dialect.HANASqlAstTranslator; import org.hibernate.dialect.NullOrdering; import org.hibernate.dialect.OracleDialect; import org.hibernate.dialect.RowLockStrategy; @@ -62,6 +32,7 @@ import org.hibernate.dialect.pagination.LimitOffsetLimitHandler; import org.hibernate.dialect.sequence.HANASequenceSupport; import org.hibernate.dialect.sequence.SequenceSupport; +import org.hibernate.dialect.sql.ast.HANASqlAstTranslator; import org.hibernate.dialect.temptable.TemporaryTable; import org.hibernate.dialect.temptable.TemporaryTableKind; import org.hibernate.engine.config.spi.ConfigurationService; @@ -131,7 +102,37 @@ import org.hibernate.type.internal.BasicTypeImpl; import org.hibernate.type.spi.TypeConfiguration; -import jakarta.persistence.TemporalType; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FilterInputStream; +import java.io.FilterReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.io.Reader; +import java.io.StringReader; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.sql.Blob; +import java.sql.CallableStatement; +import java.sql.Clob; +import java.sql.DatabaseMetaData; +import java.sql.NClob; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.SQLFeatureNotSupportedException; +import java.sql.Types; +import java.time.temporal.TemporalAccessor; +import java.util.Arrays; +import java.util.Date; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TimeZone; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.hibernate.dialect.HANAServerConfiguration.MAX_LOB_PREFETCH_SIZE_DEFAULT_VALUE; import static org.hibernate.query.sqm.produce.function.FunctionParameterType.ANY; @@ -684,26 +685,14 @@ public String getForUpdateString(final String aliases, final LockOptions lockOpt return getForUpdateString( aliases, lockMode, lockOptions.getTimeOut() ); } - @SuppressWarnings({ "deprecation" }) private String getForUpdateString(String aliases, LockMode lockMode, int timeout) { - switch ( lockMode ) { - case PESSIMISTIC_READ: { - return getReadLockString( aliases, timeout ); - } - case PESSIMISTIC_WRITE: { - return getWriteLockString( aliases, timeout ); - } - case UPGRADE_NOWAIT: - case PESSIMISTIC_FORCE_INCREMENT: { - return getForUpdateNowaitString( aliases ); - } - case UPGRADE_SKIPLOCKED: { - return getForUpdateSkipLockedString( aliases ); - } - default: { - return ""; - } - } + return switch ( lockMode ) { + case PESSIMISTIC_READ -> getReadLockString( aliases, timeout ); + case PESSIMISTIC_WRITE -> getWriteLockString( aliases, timeout ); + case UPGRADE_NOWAIT, PESSIMISTIC_FORCE_INCREMENT -> getForUpdateNowaitString( aliases ); + case UPGRADE_SKIPLOCKED -> getForUpdateSkipLockedString( aliases ); + default -> ""; + }; } @Override @@ -927,7 +916,7 @@ public NameQualifierSupport getNameQualifierSupport() { } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { /* * HANA-specific extensions @@ -935,7 +924,7 @@ public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, D builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.UPPER ); - final IdentifierHelper identifierHelper = super.buildIdentifierHelper( builder, dbMetaData ); + final IdentifierHelper identifierHelper = super.buildIdentifierHelper( builder, metadata ); return new IdentifierHelper() { @@ -976,7 +965,7 @@ public Identifier normalizeQuoting(Identifier identifier) { // need to quote names containing special characters like ':' if ( !normalizedIdentifier.isQuoted() && !normalizedIdentifier.getText().matches( "\\w+" ) ) { - normalizedIdentifier = Identifier.quote( normalizedIdentifier ); + normalizedIdentifier = normalizedIdentifier.quoted(); } return normalizedIdentifier; @@ -1004,6 +993,42 @@ public String getForUpdateNowaitString(String aliases) { return getForUpdateString( aliases ) + " nowait"; } + @Override + public String getReadLockString(Timeout timeout) { + return getWriteLockString( timeout ); + } + + @Override + public String getReadLockString(String aliases, Timeout timeout) { + return getWriteLockString( aliases, timeout ); + } + + @Override + public String getWriteLockString(Timeout timeout) { + if ( Timeouts.isRealTimeout( timeout ) ) { + return getForUpdateString() + " wait " + getTimeoutInSeconds( timeout.milliseconds() ); + } + else if ( timeout.milliseconds() == Timeouts.NO_WAIT_MILLI ) { + return getForUpdateNowaitString(); + } + else { + return getForUpdateString(); + } + } + + @Override + public String getWriteLockString(String aliases, Timeout timeout) { + if ( Timeouts.isRealTimeout( timeout ) ) { + return getForUpdateString( aliases ) + " wait " + getTimeoutInSeconds( timeout.milliseconds() ); + } + else if ( timeout.milliseconds() == Timeouts.NO_WAIT_MILLI ) { + return getForUpdateNowaitString( aliases ); + } + else { + return getForUpdateString( aliases ); + } + } + @Override public String getReadLockString(int timeout) { return getWriteLockString( timeout ); @@ -1016,10 +1041,10 @@ public String getReadLockString(String aliases, int timeout) { @Override public String getWriteLockString(int timeout) { - if ( timeout > 0 ) { - return getForUpdateString() + " wait " + getTimeoutInSeconds( timeout ); + if ( Timeouts.isRealTimeout( timeout ) ) { + return getForUpdateString() + " wait " + Timeouts.getTimeoutInSeconds( timeout ); } - else if ( timeout == 0 ) { + else if ( timeout == Timeouts.NO_WAIT_MILLI ) { return getForUpdateNowaitString(); } else { @@ -2018,4 +2043,21 @@ public String getDual() { public String getFromDualForSelectOnly() { return " from " + getDual(); } + + @Override + public boolean supportsRowValueConstructorGtLtSyntax() { + return false; + } + + @Override + public boolean supportsWithClauseInSubquery() { + // HANA doesn't seem to support correlation, so we just report false here for simplicity + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacyServerConfiguration.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacyServerConfiguration.java index f2ea26c53394..1d8b711c93e5 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacyServerConfiguration.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacyServerConfiguration.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacySqlAstTranslator.java index cad55fa233db..256bf08bdc1b 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -39,7 +39,7 @@ import org.hibernate.sql.exec.spi.JdbcOperation; import org.hibernate.sql.model.internal.TableInsertStandard; -import static org.hibernate.dialect.SybaseASESqlAstTranslator.isLob; +import static org.hibernate.dialect.sql.ast.SybaseASESqlAstTranslator.isLob; /** * An SQL AST translator for the Legacy HANA dialect. @@ -154,12 +154,6 @@ protected boolean shouldEmulateFetchClause(QueryPart queryPart) { && !isRowsOnlyFetchClauseType( queryPart ); } - @Override - protected boolean supportsWithClauseInSubquery() { - // HANA doesn't seem to support correlation, so we just report false here for simplicity - return false; - } - @Override protected boolean isCorrelated(CteStatement cteStatement) { // Report false here, because apparently HANA does not need the "lateral" keyword to correlate a from clause subquery in a subquery @@ -312,16 +306,6 @@ else if ( expression instanceof Summarization ) { } } - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorGtLtSyntax() { - return false; - } - @Override protected void renderInsertIntoNoColumns(TableInsertStandard tableInsert) { throw new MappingException( diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java index d512134a2cb1..68305ff00755 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -26,7 +26,7 @@ import org.hibernate.dialect.lock.PessimisticReadSelectLockingStrategy; import org.hibernate.dialect.lock.PessimisticWriteSelectLockingStrategy; import org.hibernate.dialect.lock.SelectLockingStrategy; -import org.hibernate.dialect.pagination.LegacyHSQLLimitHandler; +import org.hibernate.community.dialect.pagination.LegacyHSQLLimitHandler; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.LimitOffsetLimitHandler; import org.hibernate.dialect.pagination.OffsetFetchLimitHandler; @@ -41,7 +41,7 @@ import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.event.spi.EventSource; +import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.exception.ConstraintViolationException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor; @@ -797,7 +797,7 @@ private ReadUncommittedLockingStrategy(EntityPersister lockable, LockMode lockMo } @Override - public void lock(Object id, Object version, Object object, int timeout, EventSource session) + public void lock(Object id, Object version, Object object, int timeout, SharedSessionContractImplementor session) throws StaleObjectStateException, JDBCException { if ( getLockMode().greaterThan( LockMode.READ ) ) { LOG.hsqldbSupportsOnlyReadCommittedIsolation(); @@ -924,11 +924,11 @@ public String translateExtractField(TemporalUnit unit) { } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { builder.setAutoQuoteInitialUnderscore(true); builder.setAutoQuoteDollar(true); - return super.buildIdentifierHelper(builder, dbMetaData); + return super.buildIdentifierHelper(builder, metadata ); } @Override @@ -945,4 +945,36 @@ public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { public String getFromDualForSelectOnly() { return " from " + getDual(); } + + @Override + public boolean supportsFilterClause() { + return true; + } + + @Override + public boolean supportsArrayConstructor() { + return true; + } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsWithClauseInSubquery() { + // Doesn't support correlations in the WITH clause + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacySqlAstTranslator.java index 2e8d776cd853..ba8a30fc4aff 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -111,17 +111,6 @@ public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanEx } } - @Override - protected boolean supportsArrayConstructor() { - return true; - } - - @Override - protected boolean supportsWithClauseInSubquery() { - // Doesn't support correlations in the WITH clause - return false; - } - @Override protected boolean supportsRecursiveClauseArrayAndRowEmulation() { // Even though HSQL supports the array constructor, it's illegal to use arrays in CTEs @@ -245,11 +234,6 @@ private boolean isStringLiteral( Expression expression ) { return false; } - @Override - public boolean supportsFilterClause() { - return true; - } - @Override protected LockStrategy determineLockingStrategy( QuerySpec querySpec, @@ -337,21 +321,6 @@ else if ( expression instanceof Summarization ) { } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - private boolean supportsOffsetFetchClause() { return getDialect().getVersion().isSameOrAfter( 2, 5 ); } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java index 99775342ae5c..26d34aa016f3 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -24,7 +24,7 @@ import org.hibernate.dialect.NullOrdering; import org.hibernate.dialect.Replacer; import org.hibernate.dialect.SelectItemReferenceStrategy; -import org.hibernate.dialect.VarcharUUIDJdbcType; +import org.hibernate.type.descriptor.jdbc.VarcharUUIDJdbcType; import org.hibernate.dialect.function.CaseLeastGreatestEmulation; import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.identity.IdentityColumnSupport; @@ -910,4 +910,20 @@ public String getDual() { public String getFromDualForSelectOnly() { return " from " + getDual() + " dual"; } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java index 79f6504be00b..1e8f701a8376 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -136,21 +136,6 @@ else if ( expression instanceof Summarization ) { } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - @Override protected void renderNull(Literal literal) { if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.NO_UNTYPED ) { diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqmToSqlAstConverter.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqmToSqlAstConverter.java index 387732544b0a..cd43927c51a8 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqmToSqlAstConverter.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/InformixSqmToSqlAstConverter.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java index 29480c21fd38..82a9b2a72525 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -568,4 +568,20 @@ public String getFromDualForSelectOnly() { //this is only necessary if the query has a where clause return " from " + getDual() + " dual"; } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java index 47cadd977041..2619a3aa85ed 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -120,21 +120,6 @@ else if ( expression instanceof Summarization ) { } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - @Override protected boolean needsRowsToSkip() { return !supportsOffsetFetchClause(); diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqmToSqlAstConverter.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqmToSqlAstConverter.java index 7a83ee805455..c5fcf39b6dc8 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqmToSqlAstConverter.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/IngresSqmToSqlAstConverter.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacyDialect.java index ded2daa3f29e..587dd5ffb5a6 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -16,6 +16,8 @@ import org.hibernate.dialect.function.CommonFunctionFactory; import org.hibernate.dialect.sequence.MariaDBSequenceSupport; import org.hibernate.dialect.sequence.SequenceSupport; +import org.hibernate.dialect.type.MariaDBCastingJsonArrayJdbcTypeConstructor; +import org.hibernate.dialect.type.MariaDBCastingJsonJdbcType; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; @@ -33,6 +35,7 @@ import org.hibernate.type.SqlTypes; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.jdbc.JdbcType; +import org.hibernate.type.descriptor.jdbc.VarcharUUIDJdbcType; import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry; import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl; import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; @@ -181,7 +184,7 @@ public SqlAstTranslatorFactory getSqlAstTranslatorFactory() { @Override protected SqlAstTranslator buildTranslator( SessionFactoryImplementor sessionFactory, Statement statement) { - return new MariaDBLegacySqlAstTranslator<>( sessionFactory, statement ); + return new MariaDBLegacySqlAstTranslator<>( sessionFactory, statement, MariaDBLegacyDialect.this ); } }; } @@ -283,14 +286,14 @@ public FunctionalDependencyAnalysisSupport getFunctionalDependencyAnalysisSuppor } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { // some MariaDB drivers does not return case strategy info builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); - return super.buildIdentifierHelper( builder, dbMetaData ); + return super.buildIdentifierHelper( builder, metadata ); } @Override @@ -302,4 +305,25 @@ public String getDual() { public String getFromDualForSelectOnly() { return getVersion().isBefore( 10, 4 ) ? ( " from " + getDual() ) : ""; } + + @Override + public boolean supportsIntersect() { + return getVersion().isSameOrAfter( 10, 3 ); + } + + @Override + public boolean supportsSimpleQueryGrouping() { + return getVersion().isSameOrAfter( 10, 4 ); + } + + @Override + public boolean supportsWithClause() { + return getVersion().isSameOrAfter( 10, 2 ); + } + + @Override + public boolean supportsWithClauseInSubquery() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacySqlAstTranslator.java index 06c10143b303..60f4d0562e58 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MariaDBLegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -8,7 +8,7 @@ import java.util.List; import org.hibernate.dialect.DmlTargetColumnQualifierSupport; -import org.hibernate.dialect.MySQLSqlAstTranslator; +import org.hibernate.dialect.sql.ast.MySQLSqlAstTranslator; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.collections.Stack; import org.hibernate.metamodel.mapping.JdbcMappingContainer; @@ -46,11 +46,11 @@ */ public class MariaDBLegacySqlAstTranslator extends AbstractSqlAstTranslator { - private MariaDBLegacyDialect dialect; + private final MariaDBLegacyDialect dialect; - public MariaDBLegacySqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) { + public MariaDBLegacySqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement, MariaDBLegacyDialect dialect) { super( sessionFactory, statement ); - this.dialect = (MariaDBLegacyDialect)super.getDialect(); + this.dialect = dialect; } @Override @@ -137,11 +137,6 @@ protected void renderDmlTargetTableExpression(NamedTableReference tableReference } } - @Override - protected boolean supportsJoinsInDelete() { - return true; - } - @Override protected JdbcOperationQueryInsert translateInsert(InsertSelectStatement sqlAst) { visitInsertStatement( sqlAst ); @@ -182,16 +177,6 @@ else if ( qualifierSupport != DmlTargetColumnQualifierSupport.NONE || !getQueryP } } - @Override - protected boolean supportsWithClause() { - return dialect.getVersion().isSameOrAfter( 10, 2 ); - } - - @Override - protected boolean supportsWithClauseInSubquery() { - return false; - } - @Override protected void renderExpressionAsClauseItem(Expression expression) { expression.accept( this ); @@ -235,23 +220,12 @@ protected boolean shouldEmulateFetchClause(QueryPart queryPart) { return useOffsetFetchClause( queryPart ) && getQueryPartForRowNumbering() != queryPart && supportsWindowFunctions() && !isRowsOnlyFetchClauseType( queryPart ); } - @Override - protected boolean supportsSimpleQueryGrouping() { - return dialect.getVersion().isSameOrAfter( 10, 4 ); - } - @Override protected boolean shouldEmulateLateralWithIntersect(QueryPart queryPart) { // Intersect emulation requires nested correlation when no simple query grouping is possible // and the query has an offset/fetch clause, so we have to disable the emulation in this case, // because nested correlation is not supported though - return supportsSimpleQueryGrouping() || !queryPart.hasOffsetOrFetchClause(); - } - - @Override - protected boolean supportsNestedSubqueryCorrelation() { - // It seems it doesn't support it - return false; + return getDialect().supportsSimpleQueryGrouping() || !queryPart.hasOffsetOrFetchClause(); } @Override @@ -397,30 +371,9 @@ public void visitLikePredicate(LikePredicate likePredicate) { } } - @Override - public boolean supportsRowValueConstructorSyntaxInSet() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - - @Override - protected boolean supportsIntersect() { - return dialect.getVersion().isSameOrAfter( 10, 3 ); - } - - @Override - protected boolean supportsDistinctFromPredicate() { - // It supports a proprietary operator - return true; - } - @Override public MariaDBLegacyDialect getDialect() { - return this.dialect; + return dialect; } private boolean supportsWindowFunctions() { diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java index 6952e6299e81..63aa5fa15283 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -338,4 +338,20 @@ public String getDual() { public String getFromDualForSelectOnly() { return " from " + getDual(); } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java index eb94eabf3576..ba9db385bce3 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MaxDBSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -75,18 +75,4 @@ else if ( expression instanceof Summarization ) { } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java index 597ad5775db9..6fea3a851ab6 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -346,4 +346,20 @@ public IdentityColumnSupport getIdentityColumnSupport() { public String getFromDualForSelectOnly() { return " from " + getDual(); } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLSqlAstTranslator.java index c23d0f47f339..90853fa54b07 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MimerSQLSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -64,18 +64,4 @@ else if ( expression instanceof Summarization ) { } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java index 29b79d191c0c..6ec5d9d6406f 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacyDialect.java @@ -1,21 +1,29 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; -import java.sql.CallableStatement; -import java.sql.DatabaseMetaData; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; - -import org.hibernate.LockOptions; +import jakarta.persistence.TemporalType; +import jakarta.persistence.Timeout; import org.hibernate.PessimisticLockException; +import org.hibernate.Timeouts; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; import org.hibernate.cfg.Environment; -import org.hibernate.dialect.*; +import org.hibernate.dialect.DatabaseVersion; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.DmlTargetColumnQualifierSupport; +import org.hibernate.dialect.FunctionalDependencyAnalysisSupport; +import org.hibernate.dialect.FunctionalDependencyAnalysisSupportImpl; +import org.hibernate.dialect.InnoDBStorageEngine; +import org.hibernate.dialect.MyISAMStorageEngine; +import org.hibernate.dialect.MySQLServerConfiguration; +import org.hibernate.dialect.MySQLStorageEngine; +import org.hibernate.dialect.NullOrdering; +import org.hibernate.dialect.Replacer; +import org.hibernate.dialect.RowLockStrategy; +import org.hibernate.dialect.SelectItemReferenceStrategy; import org.hibernate.dialect.aggregate.AggregateSupport; import org.hibernate.dialect.aggregate.MySQLAggregateSupport; import org.hibernate.dialect.function.CommonFunctionFactory; @@ -27,6 +35,8 @@ import org.hibernate.dialect.sequence.SequenceSupport; import org.hibernate.dialect.temptable.TemporaryTable; import org.hibernate.dialect.temptable.TemporaryTableKind; +import org.hibernate.dialect.type.MySQLCastingJsonArrayJdbcTypeConstructor; +import org.hibernate.dialect.type.MySQLCastingJsonJdbcType; import org.hibernate.engine.jdbc.Size; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; @@ -44,15 +54,14 @@ import org.hibernate.mapping.CheckConstraint; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; +import org.hibernate.query.common.TemporalUnit; import org.hibernate.query.sqm.CastType; import org.hibernate.query.sqm.IntervalType; -import org.hibernate.dialect.NullOrdering; -import org.hibernate.query.common.TemporalUnit; import org.hibernate.query.sqm.function.SqmFunctionRegistry; -import org.hibernate.query.sqm.mutation.spi.AfterUseAction; -import org.hibernate.query.sqm.mutation.spi.BeforeUseAction; import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableInsertStrategy; import org.hibernate.query.sqm.mutation.internal.temptable.LocalTemporaryTableMutationStrategy; +import org.hibernate.query.sqm.mutation.spi.AfterUseAction; +import org.hibernate.query.sqm.mutation.spi.BeforeUseAction; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableInsertStrategy; import org.hibernate.query.sqm.mutation.spi.SqmMultiTableMutationStrategy; import org.hibernate.query.sqm.produce.function.FunctionParameterType; @@ -77,7 +86,11 @@ import org.hibernate.type.descriptor.sql.internal.NativeOrdinalEnumDdlTypeImpl; import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; -import jakarta.persistence.TemporalType; +import java.sql.CallableStatement; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate; import static org.hibernate.type.SqlTypes.BIGINT; @@ -740,7 +753,7 @@ public SqlAstTranslatorFactory getSqlAstTranslatorFactory() { @Override protected SqlAstTranslator buildTranslator( SessionFactoryImplementor sessionFactory, Statement statement) { - return new MySQLLegacySqlAstTranslator<>( sessionFactory, statement ); + return new MySQLLegacySqlAstTranslator<>( sessionFactory, statement, MySQLLegacyDialect.this ); } }; } @@ -1186,15 +1199,15 @@ public NameQualifierSupport getNameQualifierSupport() { } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { - if ( dbMetaData == null ) { + if ( metadata == null ) { builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); } - return super.buildIdentifierHelper( builder, dbMetaData ); + return super.buildIdentifierHelper( builder, metadata ); } @Override @@ -1324,19 +1337,50 @@ public static Replacer datetimeFormat(String format) { .replace("S", "%f"); } - private String withTimeout(String lockString, int timeout) { - switch (timeout) { - case LockOptions.NO_WAIT: - return supportsNoWait() ? lockString + " nowait" : lockString; - case LockOptions.SKIP_LOCKED: - return supportsSkipLocked() ? lockString + " skip locked" : lockString; - case LockOptions.WAIT_FOREVER: - return lockString; - default: - return supportsWait() ? lockString + " wait " + getTimeoutInSeconds( timeout ) : lockString; + private String withTimeout(String lockString, Timeout timeout) { + return switch ( timeout.milliseconds() ) { + case Timeouts.NO_WAIT_MILLI -> supportsNoWait() ? lockString + " nowait" : lockString; + case Timeouts.SKIP_LOCKED_MILLI -> supportsSkipLocked() ? lockString + " skip locked" : lockString; + case Timeouts.WAIT_FOREVER_MILLI -> lockString; + default -> supportsWait() ? lockString + " wait " + Timeouts.getTimeoutInSeconds( timeout ) : lockString; + }; + } + + @Override + public String getWriteLockString(Timeout timeout) { + return withTimeout( getForUpdateString(), timeout ); + } + + @Override + public String getWriteLockString(String aliases, Timeout timeout) { + return withTimeout( getForUpdateString( aliases ), timeout ); + } + + @Override + public String getReadLockString(Timeout timeout) { + return withTimeout( supportsForShare() ? " for share" : " lock in share mode", timeout ); + } + + @Override + public String getReadLockString(String aliases, Timeout timeout) { + if ( supportsAliasLocks() && supportsForShare() ) { + return withTimeout( " for share of " + aliases, timeout ); + } + else { + // fall back to locking all aliases + return getReadLockString( timeout ); } } + private String withTimeout(String lockString, int timeout) { + return switch ( timeout ) { + case Timeouts.NO_WAIT_MILLI -> supportsNoWait() ? lockString + " nowait" : lockString; + case Timeouts.SKIP_LOCKED_MILLI -> supportsSkipLocked() ? lockString + " skip locked" : lockString; + case Timeouts.WAIT_FOREVER_MILLI -> lockString; + default -> supportsWait() ? lockString + " wait " + Timeouts.getTimeoutInSeconds( timeout ) : lockString; + }; + } + @Override public String getWriteLockString(int timeout) { return withTimeout( getForUpdateString(), timeout ); @@ -1503,4 +1547,45 @@ public String getFromDualForSelectOnly() { return getVersion().isSameOrAfter( 8 ) ? "" : ( " from " + getDual() ); } + @Override + public boolean supportsDistinctFromPredicate() { + // It supports a proprietary operator + return true; + } + + @Override + public boolean supportsIntersect() { + return false; + } + + @Override + public boolean supportsJoinsInDelete() { + return true; + } + + @Override + public boolean supportsNestedSubqueryCorrelation() { + return false; + } + + @Override + public boolean supportsSimpleQueryGrouping() { + return getVersion().isSameOrAfter( 8 ); + } + + @Override + public boolean supportsWithClause() { + return getVersion().isSameOrAfter( 8 ); + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return getVersion().isSameOrAfter( 5, 7 ); + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacySqlAstTranslator.java index 9d143da50a4c..abcd4115a117 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/MySQLLegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -7,9 +7,8 @@ import java.util.ArrayList; import java.util.List; -import org.hibernate.dialect.DialectDelegateWrapper; import org.hibernate.dialect.DmlTargetColumnQualifierSupport; -import org.hibernate.dialect.MySQLSqlAstTranslator; +import org.hibernate.dialect.sql.ast.MySQLSqlAstTranslator; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.collections.Stack; import org.hibernate.query.sqm.ComparisonOperator; @@ -48,8 +47,11 @@ */ public class MySQLLegacySqlAstTranslator extends AbstractSqlAstTranslator { - public MySQLLegacySqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) { + private final MySQLLegacyDialect dialect; + + public MySQLLegacySqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement, MySQLLegacyDialect dialect) { super( sessionFactory, statement ); + this.dialect = dialect; } @Override @@ -147,11 +149,6 @@ protected void renderDmlTargetTableExpression(NamedTableReference tableReference } } - @Override - protected boolean supportsJoinsInDelete() { - return true; - } - @Override protected JdbcOperationQueryInsert translateInsert(InsertSelectStatement sqlAst) { visitInsertStatement( sqlAst ); @@ -369,50 +366,9 @@ public void visitLikePredicate(LikePredicate likePredicate) { } } - @Override - public boolean supportsRowValueConstructorSyntaxInSet() { - return false; - } - - @Override - public boolean supportsRowValueConstructorSyntaxInInList() { - return getDialect().getVersion().isSameOrAfter( 5, 7 ); - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - - @Override - protected boolean supportsIntersect() { - return false; - } - - @Override - protected boolean supportsDistinctFromPredicate() { - // It supports a proprietary operator - return true; - } - - @Override - protected boolean supportsSimpleQueryGrouping() { - return getDialect().getVersion().isSameOrAfter( 8 ); - } - - @Override - protected boolean supportsNestedSubqueryCorrelation() { - return false; - } - - @Override - protected boolean supportsWithClause() { - return getDialect().getVersion().isSameOrAfter( 8 ); - } - @Override public MySQLLegacyDialect getDialect() { - return (MySQLLegacyDialect) DialectDelegateWrapper.extractRealDialect( super.getDialect() ); + return dialect; } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java index 740cc6cdddf8..07e85788a6fa 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -16,22 +16,23 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.hibernate.LockOptions; +import jakarta.persistence.Timeout; import org.hibernate.QueryTimeoutException; +import org.hibernate.Timeouts; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; import org.hibernate.dialect.BooleanDecoder; import org.hibernate.dialect.DatabaseVersion; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.DmlTargetColumnQualifierSupport; -import org.hibernate.dialect.OracleBooleanJdbcType; -import org.hibernate.dialect.OracleJdbcHelper; -import org.hibernate.dialect.OracleJsonArrayJdbcTypeConstructor; -import org.hibernate.dialect.OracleJsonJdbcType; -import org.hibernate.dialect.OracleReflectionStructJdbcType; +import org.hibernate.dialect.type.OracleBooleanJdbcType; +import org.hibernate.dialect.type.OracleJdbcHelper; +import org.hibernate.dialect.type.OracleJsonArrayJdbcTypeConstructor; +import org.hibernate.dialect.type.OracleJsonJdbcType; +import org.hibernate.dialect.type.OracleReflectionStructJdbcType; import org.hibernate.dialect.OracleTypes; -import org.hibernate.dialect.OracleUserDefinedTypeExporter; -import org.hibernate.dialect.OracleXmlJdbcType; +import org.hibernate.dialect.type.OracleUserDefinedTypeExporter; +import org.hibernate.dialect.type.OracleXmlJdbcType; import org.hibernate.dialect.Replacer; import org.hibernate.dialect.RowLockStrategy; import org.hibernate.dialect.TimeZoneSupport; @@ -43,7 +44,7 @@ import org.hibernate.dialect.function.OracleTruncFunction; import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.identity.Oracle12cIdentityColumnSupport; -import org.hibernate.dialect.pagination.LegacyOracleLimitHandler; +import org.hibernate.community.dialect.pagination.LegacyOracleLimitHandler; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.Oracle12LimitHandler; import org.hibernate.dialect.sequence.OracleSequenceSupport; @@ -1410,17 +1411,37 @@ public String getForUpdateSkipLockedString(String aliases) { return " for update of " + aliases + " skip locked"; } + private String withTimeout(String lockString, Timeout timeout) { + return withTimeout( lockString, timeout.milliseconds() ); + } + + @Override + public String getWriteLockString(Timeout timeout) { + return withTimeout( getForUpdateString(), timeout ); + } + + @Override + public String getWriteLockString(String aliases, Timeout timeout) { + return withTimeout( getForUpdateString(aliases), timeout ); + } + + @Override + public String getReadLockString(Timeout timeout) { + return getWriteLockString( timeout ); + } + + @Override + public String getReadLockString(String aliases, Timeout timeout) { + return getWriteLockString( aliases, timeout ); + } + private String withTimeout(String lockString, int timeout) { - switch (timeout) { - case LockOptions.NO_WAIT: - return supportsNoWait() ? lockString + " nowait" : lockString; - case LockOptions.SKIP_LOCKED: - return supportsSkipLocked() ? lockString + " skip locked" : lockString; - case LockOptions.WAIT_FOREVER: - return lockString; - default: - return supportsWait() ? lockString + " wait " + getTimeoutInSeconds( timeout ) : lockString; - } + return switch ( timeout ) { + case Timeouts.NO_WAIT_MILLI -> supportsNoWait() ? lockString + " nowait" : lockString; + case Timeouts.SKIP_LOCKED_MILLI -> supportsSkipLocked() ? lockString + " skip locked" : lockString; + case Timeouts.WAIT_FOREVER_MILLI -> lockString; + default -> supportsWait() ? lockString + " wait " + Timeouts.getTimeoutInSeconds( timeout ) : lockString; + }; } @Override @@ -1589,10 +1610,10 @@ public String generatedAs(String generatedAs) { } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { builder.setAutoQuoteInitialUnderscore(true); - return super.buildIdentifierHelper(builder, dbMetaData); + return super.buildIdentifierHelper(builder, metadata ); } @Override @@ -1659,4 +1680,51 @@ public String getFromDualForSelectOnly() { return " from " + getDual(); } + @Override + public boolean supportsDuplicateSelectItemsInQueryGroup() { + return false; + } + + @Override + public boolean supportsNestedSubqueryCorrelation() { + // It seems it doesn't support it, at least on version 11 + return false; + } + + @Override + public boolean supportsRecursiveCycleClause() { + return true; + } + + @Override + public boolean supportsRecursiveSearchClause() { + return true; + } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsWithClauseInSubquery() { + // Oracle has some limitations, see ORA-32034, so we just report false here for simplicity + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return getVersion().isSameOrAfter( 8, 2 ); + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInSubQuery() { + return getVersion().isSameOrAfter( 9 ); + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacySqlAstTranslator.java index 25348d756960..062dd6c16bfc 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -7,7 +7,7 @@ import java.util.ArrayList; import java.util.List; -import org.hibernate.dialect.OracleArrayJdbcType; +import org.hibernate.dialect.type.OracleArrayJdbcType; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.collections.Stack; import org.hibernate.metamodel.mapping.CollectionPart; @@ -22,6 +22,7 @@ import org.hibernate.query.common.FetchClauseType; import org.hibernate.query.common.FrameExclusion; import org.hibernate.query.common.FrameKind; +import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation; import org.hibernate.sql.ast.Clause; import org.hibernate.sql.ast.SqlAstNodeRenderingMode; import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; @@ -55,7 +56,9 @@ import org.hibernate.sql.ast.tree.select.QueryPart; import org.hibernate.sql.ast.tree.select.QuerySpec; import org.hibernate.sql.ast.tree.select.SelectClause; +import org.hibernate.sql.ast.tree.select.SelectStatement; import org.hibernate.sql.ast.tree.select.SortSpecification; +import org.hibernate.sql.ast.tree.update.Assignable; import org.hibernate.sql.ast.tree.update.Assignment; import org.hibernate.sql.ast.tree.update.UpdateStatement; import org.hibernate.sql.exec.spi.JdbcOperation; @@ -127,22 +130,6 @@ protected boolean needsRecursiveKeywordInWithClause() { return false; } - @Override - protected boolean supportsWithClauseInSubquery() { - // Oracle has some limitations, see ORA-32034, so we just report false here for simplicity - return false; - } - - @Override - protected boolean supportsRecursiveSearchClause() { - return true; - } - - @Override - protected boolean supportsRecursiveCycleClause() { - return true; - } - @Override public void visitSqlSelection(SqlSelection sqlSelection) { if ( getCurrentCteStatement() != null ) { @@ -198,12 +185,6 @@ protected boolean shouldEmulateLateralWithIntersect(QueryPart queryPart) { return !queryPart.hasOffsetOrFetchClause(); } - @Override - protected boolean supportsNestedSubqueryCorrelation() { - // It seems it doesn't support it, at least on version 11 - return false; - } - protected boolean shouldEmulateFetchClause(QueryPart queryPart) { // Check if current query part is already row numbering to avoid infinite recursion if ( getQueryPartForRowNumbering() == queryPart ) { @@ -686,42 +667,47 @@ else if ( expression instanceof Summarization ) { } } - @Override - protected boolean supportsDuplicateSelectItemsInQueryGroup() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return getDialect().getVersion().isSameOrAfter( 8, 2 ); - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; + private boolean supportsOffsetFetchClause() { + return getDialect().supportsFetchClause( FetchClauseType.ROWS_ONLY ); } @Override - protected boolean supportsRowValueConstructorSyntaxInInSubQuery() { - return getDialect().getVersion().isSameOrAfter( 9 ); - } - - private boolean supportsOffsetFetchClause() { - return getDialect().supportsFetchClause( FetchClauseType.ROWS_ONLY ); + protected void renderNull(Literal literal) { + if ( getParameterRenderingMode() == SqlAstNodeRenderingMode.NO_UNTYPED ) { + switch ( literal.getJdbcMapping().getJdbcType().getDdlTypeCode() ) { + case SqlTypes.BLOB: + appendSql( "to_blob(null)" ); + break; + case SqlTypes.CLOB: + appendSql( "to_clob(null)" ); + break; + case SqlTypes.NCLOB: + appendSql( "to_nclob(null)" ); + break; + default: + super.renderNull( literal ); + break; + } + } + else { + super.renderNull( literal ); + } } @Override protected void visitSetAssignment(Assignment assignment) { + final Assignable assignable = assignment.getAssignable(); + if ( assignable instanceof SqmPathInterpretation ) { + final String affectedTableName = ( (SqmPathInterpretation) assignable ).getAffectedTableName(); + if ( affectedTableName != null ) { + addAffectedTableName( affectedTableName ); + } + } final List columnReferences = assignment.getAssignable().getColumnReferences(); + final Expression assignedValue = assignment.getAssignedValue(); if ( columnReferences.size() == 1 ) { columnReferences.get( 0 ).appendColumnForWrite( this ); appendSql( '=' ); - final Expression assignedValue = assignment.getAssignedValue(); final SqlTuple sqlTuple = SqlTupleContainer.getSqlTuple( assignedValue ); if ( sqlTuple != null ) { assert sqlTuple.getExpressions().size() == 1; @@ -731,7 +717,7 @@ protected void visitSetAssignment(Assignment assignment) { assignedValue.accept( this ); } } - else { + else if ( assignedValue instanceof SelectStatement ) { char separator = OPEN_PARENTHESIS; for ( ColumnReference columnReference : columnReferences ) { appendSql( separator ); @@ -741,5 +727,18 @@ protected void visitSetAssignment(Assignment assignment) { appendSql( ")=" ); assignment.getAssignedValue().accept( this ); } + else { + assert assignedValue instanceof SqlTupleContainer; + final List expressions = ( (SqlTupleContainer) assignedValue ).getSqlTuple().getExpressions(); + columnReferences.get( 0 ).appendColumnForWrite( this, null ); + appendSql( '=' ); + expressions.get( 0 ).accept( this ); + for ( int i = 1; i < columnReferences.size(); i++ ) { + appendSql( ',' ); + columnReferences.get( i ).appendColumnForWrite( this, null ); + appendSql( '=' ); + expressions.get( i ).accept( this ); + } + } } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java index 5047e2430b94..ebe39ec04936 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -17,12 +17,14 @@ import java.util.Map; import java.util.TimeZone; +import jakarta.persistence.Timeout; import org.checkerframework.checker.nullness.qual.Nullable; import org.hibernate.Length; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.PessimisticLockException; import org.hibernate.QueryTimeoutException; +import org.hibernate.Timeouts; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; import org.hibernate.community.dialect.sequence.PostgreSQLLegacySequenceSupport; @@ -40,6 +42,16 @@ import org.hibernate.dialect.pagination.OffsetFetchLimitHandler; import org.hibernate.dialect.sequence.PostgreSQLSequenceSupport; import org.hibernate.dialect.sequence.SequenceSupport; +import org.hibernate.dialect.type.PgJdbcHelper; +import org.hibernate.dialect.type.PostgreSQLArrayJdbcTypeConstructor; +import org.hibernate.dialect.type.PostgreSQLCastingInetJdbcType; +import org.hibernate.dialect.type.PostgreSQLCastingIntervalSecondJdbcType; +import org.hibernate.dialect.type.PostgreSQLCastingJsonArrayJdbcTypeConstructor; +import org.hibernate.dialect.type.PostgreSQLCastingJsonJdbcType; +import org.hibernate.dialect.type.PostgreSQLEnumJdbcType; +import org.hibernate.dialect.type.PostgreSQLOrdinalEnumJdbcType; +import org.hibernate.dialect.type.PostgreSQLStructCastingJdbcType; +import org.hibernate.dialect.type.PostgreSQLUUIDJdbcType; import org.hibernate.dialect.unique.CreateTableUniqueDelegate; import org.hibernate.dialect.unique.UniqueDelegate; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; @@ -886,24 +898,13 @@ public String getForUpdateString(String aliases, LockOptions lockOptions) { if (lockMode == null ) { lockMode = lockOptions.getLockMode(); } - switch ( lockMode ) { - case PESSIMISTIC_READ: { - return getReadLockString( aliases, lockOptions.getTimeOut() ); - } - case PESSIMISTIC_WRITE: { - return getWriteLockString( aliases, lockOptions.getTimeOut() ); - } - case UPGRADE_NOWAIT: - case PESSIMISTIC_FORCE_INCREMENT: { - return getForUpdateNowaitString(aliases); - } - case UPGRADE_SKIPLOCKED: { - return getForUpdateSkipLockedString(aliases); - } - default: { - return ""; - } - } + return switch ( lockMode ) { + case PESSIMISTIC_READ -> getReadLockString( aliases, lockOptions.getTimeOut() ); + case PESSIMISTIC_WRITE -> getWriteLockString( aliases, lockOptions.getTimeOut() ); + case UPGRADE_NOWAIT, PESSIMISTIC_FORCE_INCREMENT -> getForUpdateNowaitString( aliases ); + case UPGRADE_SKIPLOCKED -> getForUpdateSkipLockedString( aliases ); + default -> ""; + }; } @Override @@ -991,15 +992,15 @@ public void appendBooleanValueString(SqlAppender appender, boolean bool) { } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { - if ( dbMetaData == null ) { + if ( metadata == null ) { builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.LOWER ); builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); } - return super.buildIdentifierHelper( builder, dbMetaData ); + return super.buildIdentifierHelper( builder, metadata ); } @Override @@ -1318,15 +1319,40 @@ public void appendDateTimeLiteral( } } + private String withTimeout(String lockString, Timeout timeout) { + return switch (timeout.milliseconds()) { + case Timeouts.NO_WAIT_MILLI -> supportsNoWait() ? lockString + " nowait" : lockString; + case Timeouts.SKIP_LOCKED_MILLI -> supportsSkipLocked() ? lockString + " skip locked" : lockString; + default -> lockString; + }; + } + + @Override + public String getWriteLockString(Timeout timeout) { + return withTimeout( getForUpdateString(), timeout ); + } + + @Override + public String getWriteLockString(String aliases, Timeout timeout) { + return withTimeout( getForUpdateString( aliases ), timeout ); + } + + @Override + public String getReadLockString(Timeout timeout) { + return withTimeout(" for share", timeout ); + } + + @Override + public String getReadLockString(String aliases, Timeout timeout) { + return withTimeout(" for share of " + aliases, timeout ); + } + private String withTimeout(String lockString, int timeout) { - switch (timeout) { - case LockOptions.NO_WAIT: - return supportsNoWait() ? lockString + " nowait" : lockString; - case LockOptions.SKIP_LOCKED: - return supportsSkipLocked() ? lockString + " skip locked" : lockString; - default: - return lockString; - } + return switch ( timeout ) { + case Timeouts.NO_WAIT_MILLI -> supportsNoWait() ? lockString + " nowait" : lockString; + case Timeouts.SKIP_LOCKED_MILLI -> supportsSkipLocked() ? lockString + " skip locked" : lockString; + default -> lockString; + }; } @Override @@ -1615,4 +1641,35 @@ public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { public boolean supportsFromClauseInUpdate() { return true; } + + @Override + public boolean supportsFilterClause() { + return getVersion().isSameOrAfter( 9, 4 ); + } + + @Override + public boolean supportsRowConstructor() { + return true; + } + + @Override + public boolean supportsArrayConstructor() { + return true; + } + + @Override + public boolean supportsRecursiveCycleClause() { + return getVersion().isSameOrAfter( 14 ); + } + + @Override + public boolean supportsRecursiveCycleUsingClause() { + return getVersion().isSameOrAfter( 14 ); + } + + @Override + public boolean supportsRecursiveSearchClause() { + return getVersion().isSameOrAfter( 14 ); + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacySqlAstTranslator.java index f75f784102a9..79362a43477a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -184,21 +184,6 @@ protected void renderMaterializationHint(CteMaterialization materialization) { } } - @Override - protected boolean supportsRowConstructor() { - return true; - } - - @Override - protected boolean supportsArrayConstructor() { - return true; - } - - @Override - public boolean supportsFilterClause() { - return getDialect().getVersion().isSameOrAfter( 9, 4 ); - } - @Override protected String getForUpdate() { return getDialect().getVersion().isSameOrAfter( 9, 3 ) ? " for no key update" : " for update"; @@ -250,25 +235,10 @@ public void visitOffsetFetchClause(QueryPart queryPart) { } } - @Override - protected boolean supportsRecursiveSearchClause() { - return getDialect().getVersion().isSameOrAfter( 14 ); - } - - @Override - protected boolean supportsRecursiveCycleClause() { - return getDialect().getVersion().isSameOrAfter( 14 ); - } - - @Override - protected boolean supportsRecursiveCycleUsingClause() { - return getDialect().getVersion().isSameOrAfter( 14 ); - } - @Override protected void renderStandardCycleClause(CteStatement cte) { super.renderStandardCycleClause( cte ); - if ( cte.getCycleMarkColumn() != null && cte.getCyclePathColumn() == null && supportsRecursiveCycleUsingClause() ) { + if ( cte.getCycleMarkColumn() != null && cte.getCyclePathColumn() == null && getDialect().supportsRecursiveCycleUsingClause() ) { appendSql( " using " ); appendSql( determineCyclePathColumnName( cte ) ); } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgresPlusLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgresPlusLegacyDialect.java index f4e8e38f79c7..e1c3870663b6 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgresPlusLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgresPlusLegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java index 8b5ea3a0d2db..d0dfbe7c8188 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200Dialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -442,4 +442,20 @@ public String getDual() { public String getFromDualForSelectOnly() { return " from " + getDual() + " where key_col=1"; } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java index 393037a7965e..5fb371d63dad 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/RDMSOS2200SqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -108,18 +108,4 @@ else if ( expression instanceof Summarization ) { } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java index 73911217fbd5..a9ed9ca58bb5 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -16,8 +16,8 @@ import org.hibernate.dialect.Dialect; import org.hibernate.dialect.DmlTargetColumnQualifierSupport; import org.hibernate.dialect.Replacer; -import org.hibernate.dialect.SQLServerCastingXmlArrayJdbcTypeConstructor; -import org.hibernate.dialect.SQLServerCastingXmlJdbcType; +import org.hibernate.dialect.type.SQLServerCastingXmlArrayJdbcTypeConstructor; +import org.hibernate.dialect.type.SQLServerCastingXmlJdbcType; import org.hibernate.dialect.TimeZoneSupport; import org.hibernate.dialect.aggregate.AggregateSupport; import org.hibernate.dialect.aggregate.SQLServerAggregateSupport; @@ -28,7 +28,7 @@ import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.identity.SQLServerIdentityColumnSupport; import org.hibernate.dialect.pagination.LimitHandler; -import org.hibernate.dialect.pagination.SQLServer2005LimitHandler; +import org.hibernate.community.dialect.pagination.SQLServer2005LimitHandler; import org.hibernate.dialect.pagination.SQLServer2012LimitHandler; import org.hibernate.dialect.pagination.TopLimitHandler; import org.hibernate.dialect.sequence.NoSequenceSupport; @@ -553,16 +553,16 @@ public String currentTimestamp() { @Override public IdentifierHelper buildIdentifierHelper( - IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException { + IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { - if ( dbMetaData == null ) { + if ( metadata == null ) { // TODO: if DatabaseMetaData != null, unquoted case strategy is set to IdentifierCaseStrategy.UPPER // Check to see if this setting is correct. builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); } - return super.buildIdentifierHelper( builder, dbMetaData ); + return super.buildIdentifierHelper( builder, metadata ); } @Override @@ -649,39 +649,31 @@ public String appendLockHint(LockOptions lockOptions, String tableName) { lockMode = lockOptions.getLockMode(); } - final String writeLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "updlock,holdlock"; - final String readLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? "updlock" : "holdlock"; - - final String noWaitStr = lockOptions.getTimeOut() == LockOptions.NO_WAIT ? ",nowait" : ""; - final String skipLockStr = lockOptions.getTimeOut() == LockOptions.SKIP_LOCKED ? ",readpast" : ""; - - switch ( lockMode ) { - case PESSIMISTIC_WRITE: - case WRITE: - return tableName + " with (" + writeLockStr + ",rowlock" + noWaitStr + skipLockStr + ")"; - case PESSIMISTIC_READ: - return tableName + " with (" + readLockStr + ",rowlock" + noWaitStr + skipLockStr + ")"; - case UPGRADE_SKIPLOCKED: - return tableName + " with (updlock,rowlock,readpast" + noWaitStr + ")"; - case UPGRADE_NOWAIT: - return tableName + " with (updlock,holdlock,rowlock,nowait)"; - default: - return tableName; - } + final int timeOut = lockOptions.getTimeOut(); + + final String writeLockStr = timeOut == LockOptions.SKIP_LOCKED ? "updlock" : "updlock,holdlock"; + final String readLockStr = timeOut == LockOptions.SKIP_LOCKED ? "updlock" : "holdlock"; + + final String noWaitStr = timeOut == LockOptions.NO_WAIT ? ",nowait" : ""; + final String skipLockStr = timeOut == LockOptions.SKIP_LOCKED ? ",readpast" : ""; + + return switch ( lockMode ) { + case PESSIMISTIC_WRITE, WRITE -> + tableName + " with (" + writeLockStr + ",rowlock" + noWaitStr + skipLockStr + ")"; + case PESSIMISTIC_READ -> + tableName + " with (" + readLockStr + ",rowlock" + noWaitStr + skipLockStr + ")"; + case UPGRADE_SKIPLOCKED -> tableName + " with (updlock,rowlock,readpast" + noWaitStr + ")"; + case UPGRADE_NOWAIT -> tableName + " with (updlock,holdlock,rowlock,nowait)"; + default -> tableName; + }; } else { - switch ( lockOptions.getLockMode() ) { - case UPGRADE_NOWAIT: - case PESSIMISTIC_WRITE: - case WRITE: - return tableName + " with (updlock,rowlock)"; - case PESSIMISTIC_READ: - return tableName + " with (holdlock,rowlock)"; - case UPGRADE_SKIPLOCKED: - return tableName + " with (updlock,rowlock,readpast)"; - default: - return tableName; - } + return switch ( lockOptions.getLockMode() ) { + case UPGRADE_NOWAIT, PESSIMISTIC_WRITE, WRITE -> tableName + " with (updlock,rowlock)"; + case PESSIMISTIC_READ -> tableName + " with (holdlock,rowlock)"; + case UPGRADE_SKIPLOCKED -> tableName + " with (updlock,rowlock,readpast)"; + default -> tableName; + }; } } @@ -1256,4 +1248,38 @@ private String getCheckConstraintOptions(CheckConstraint checkConstraint) { } return ""; } + + @Override + public boolean supportsJoinsInDelete() { + return true; + } + + @Override + public boolean supportsSimpleQueryGrouping() { + // SQL Server is quite strict i.e. it requires `select ... union all select * from (select ...)` + // rather than `select ... union all (select ...)` because parenthesis followed by select + // is always treated as a subquery, which is not supported in a set operation + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsWithClauseInSubquery() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacySqlAstTranslator.java index ca0bb4b74428..690c8279944a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLServerLegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -115,11 +115,6 @@ protected void renderDmlTargetTableExpression(NamedTableReference tableReference } } - @Override - protected boolean supportsJoinsInDelete() { - return true; - } - @Override protected void renderFromClauseAfterUpdateSet(UpdateStatement statement) { if ( statement.getFromClause().getRoots().isEmpty() ) { @@ -145,11 +140,6 @@ protected boolean needsRecursiveKeywordInWithClause() { return false; } - @Override - protected boolean supportsWithClauseInSubquery() { - return false; - } - @Override protected void renderTableGroupJoin(TableGroupJoin tableGroupJoin, List tableGroupJoinCollector) { appendSql( WHITESPACE ); @@ -356,14 +346,6 @@ else if ( !queryPart.hasSortSpecifications() && ((QuerySpec) queryPart).getSelec } } - @Override - protected boolean supportsSimpleQueryGrouping() { - // SQL Server is quite strict i.e. it requires `select .. union all select * from (select ...)` - // rather than `select .. union all (select ...)` because parenthesis followed by select - // is always treated as a subquery, which is not supported in a set operation - return false; - } - protected boolean shouldEmulateFetchClause(QueryPart queryPart) { // Check if current query part is already row numbering to avoid infinite recursion return getQueryPartForRowNumbering() != queryPart && getOffsetFetchClauseMode( queryPart ) == OffsetFetchClauseMode.EMULATED; @@ -493,11 +475,11 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp // In SQL Server, XMLTYPE is not "comparable", so we have to cast the two parts to varchar for this purpose switch ( operator ) { case DISTINCT_FROM: - if ( !supportsDistinctFromPredicate() ) { + if ( !getDialect().supportsDistinctFromPredicate() ) { appendSql( "not " ); } case NOT_DISTINCT_FROM: { - if ( !supportsDistinctFromPredicate() ) { + if ( !getDialect().supportsDistinctFromPredicate() ) { appendSql( "exists (select cast(" ); getClauseStack().push( Clause.SELECT ); visitSqlSelectExpression( lhs ); @@ -527,7 +509,7 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp break; } } - if ( supportsDistinctFromPredicate() ) { + if ( getDialect().supportsDistinctFromPredicate() ) { renderComparisonStandard( lhs, operator, rhs ); } else { @@ -535,11 +517,6 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp } } - @Override - protected boolean supportsDistinctFromPredicate() { - return getDialect().getVersion().isSameOrAfter( 16 ); - } - @Override protected void renderSelectTupleComparison( List lhsExpressions, @@ -573,21 +550,6 @@ public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeti appendSql( CLOSE_PARENTHESIS ); } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - enum OffsetFetchClauseMode { STANDARD, TOP_ONLY, diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java index 496dc0fc7e71..67c565bf73c2 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -457,9 +457,9 @@ public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() { private static final ViolatedConstraintNameExtractor EXTRACTOR = new TemplatedViolatedConstraintNameExtractor( sqle -> { - final int errorCode = JdbcExceptionHelper.extractErrorCode( sqle ); + final int errorCode = JdbcExceptionHelper.extractErrorCode( sqle ) & 0xFF; if (errorCode == SQLITE_CONSTRAINT) { - return extractUsingTemplate( "constraint ", " failed", sqle.getMessage() ); + return extractUsingTemplate( "constraint failed: ", "\n", sqle.getMessage() ); } return null; } ); @@ -745,4 +745,9 @@ public void appendDateTimeLiteral( } } + @Override + public boolean supportsFilterClause() { + return getVersion().isSameOrAfter( 3, 3 ); + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteSqlAstTranslator.java index f53ae5719a0a..1423bea3edb3 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SQLiteSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -54,16 +54,6 @@ protected void renderMaterializationHint(CteMaterialization materialization) { } } - @Override - public boolean supportsFilterClause() { - return getDialect().getVersion().isSameOrAfter( 3, 3 ); - } - - @Override - protected boolean supportsQuantifiedPredicates() { - return false; - } - protected boolean shouldEmulateFetchClause(QueryPart queryPart) { // Check if current query part is already row numbering to avoid infinite recursion // We also have to emulate this if a fetch clause type other than rows only is used diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreDialect.java index 7db3bc338070..9714b4728dfb 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -16,6 +16,7 @@ import java.util.Date; import java.util.TimeZone; +import jakarta.persistence.Timeout; import org.hibernate.Length; import org.hibernate.PessimisticLockException; import org.hibernate.boot.Metadata; @@ -772,7 +773,7 @@ public SqlAstTranslatorFactory getSqlAstTranslatorFactory() { @Override protected SqlAstTranslator buildTranslator( SessionFactoryImplementor sessionFactory, Statement statement) { - return new SingleStoreSqlAstTranslator<>( sessionFactory, statement ); + return new SingleStoreSqlAstTranslator<>( sessionFactory, statement, SingleStoreDialect.this ); } }; } @@ -1196,11 +1197,11 @@ public NameQualifierSupport getNameQualifierSupport() { } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); - return super.buildIdentifierHelper( builder, dbMetaData ); + return super.buildIdentifierHelper( builder, metadata ); } @Override @@ -1224,6 +1225,11 @@ public String getAddPrimaryKeyConstraintString(String constraintName) { throw new UnsupportedOperationException( "SingleStore does not support altering primary key." ); } + @Override + public String getWriteLockString(String aliases, Timeout timeout) { + return getForUpdateString( aliases ); + } + @Override public String getWriteLockString(String aliases, int timeout) { return getForUpdateString( aliases ); @@ -1414,4 +1420,35 @@ public boolean isForUpdateLockingEnabled() { public String getDual() { return "dual"; } + + @Override + public boolean supportsJoinsInDelete() { + return true; + } + + @Override + public boolean supportsNestedSubqueryCorrelation() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsWithClauseInSubquery() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreSqlAstTranslator.java index fb6129e66c4d..14264326aab9 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SingleStoreSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -7,9 +7,8 @@ import java.util.ArrayList; import java.util.List; -import org.hibernate.dialect.DialectDelegateWrapper; import org.hibernate.dialect.DmlTargetColumnQualifierSupport; -import org.hibernate.dialect.MySQLSqlAstTranslator; +import org.hibernate.dialect.sql.ast.MySQLSqlAstTranslator; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.collections.Stack; import org.hibernate.query.sqm.ComparisonOperator; @@ -52,9 +51,9 @@ public class SingleStoreSqlAstTranslator extends Abstra private final SingleStoreDialect dialect; - public SingleStoreSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) { + public SingleStoreSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement, SingleStoreDialect dialect) { super( sessionFactory, statement ); - this.dialect = (SingleStoreDialect) DialectDelegateWrapper.extractRealDialect( super.getDialect() ); + this.dialect = dialect; } @Override @@ -71,21 +70,6 @@ public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeti } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - @Override protected void renderSelectTupleComparison( List lhsExpressions, SqlTuple tuple, ComparisonOperator operator) { @@ -172,11 +156,6 @@ protected void renderDmlTargetTableExpression(NamedTableReference tableReference } } - @Override - protected boolean supportsJoinsInDelete() { - return true; - } - @Override protected void visitConflictClause(ConflictClause conflictClause) { visitOnDuplicateKeyConflictClause( conflictClause ); @@ -203,11 +182,6 @@ else if ( qualifierSupport != DmlTargetColumnQualifierSupport.NONE || !getQueryP } } - @Override - protected boolean supportsWithClauseInSubquery() { - return false; - } - @Override protected void renderExpressionAsClauseItem(Expression expression) { expression.accept( this ); @@ -234,7 +208,7 @@ protected boolean shouldEmulateFetchClause(QueryPart queryPart) { @Override protected boolean shouldEmulateLateralWithIntersect(QueryPart queryPart) { - return supportsSimpleQueryGrouping() || !queryPart.hasOffsetOrFetchClause(); + return getDialect().supportsSimpleQueryGrouping() || !queryPart.hasOffsetOrFetchClause(); } //SingleStore doesn't support 'FOR UPDATE' clause with distributed joins @@ -253,11 +227,6 @@ public void visitEvery(Every every) { throw new UnsupportedOperationException( "SingleStore doesn't support ALL clause" ); } - @Override - protected boolean supportsNestedSubqueryCorrelation() { - return false; - } - @Override public void visitQueryGroup(QueryGroup queryGroup) { if ( shouldEmulateFetchClause( queryGroup ) ) { @@ -425,19 +394,9 @@ protected void renderBackslashEscapedLikePattern( } } - @Override - public boolean supportsRowValueConstructorSyntaxInSet() { - return false; - } - - @Override - protected boolean supportsDistinctFromPredicate() { - return false; - } - @Override public SingleStoreDialect getDialect() { - return this.dialect; + return dialect; } private boolean supportsWindowFunctions() { diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java index 824d96067891..9a5731621d6b 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -30,7 +30,6 @@ import org.hibernate.exception.spi.SQLExceptionConversionDelegate; import org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor; import org.hibernate.exception.spi.ViolatedConstraintNameExtractor; -import org.hibernate.internal.util.JdbcExceptionHelper; import org.hibernate.query.sqm.IntervalType; import org.hibernate.query.common.TemporalUnit; import org.hibernate.service.ServiceRegistry; @@ -50,6 +49,8 @@ import jakarta.persistence.TemporalType; import static org.hibernate.exception.spi.TemplatedViolatedConstraintNameExtractor.extractUsingTemplate; +import static org.hibernate.internal.util.JdbcExceptionHelper.extractErrorCode; +import static org.hibernate.internal.util.JdbcExceptionHelper.extractSqlState; import static org.hibernate.type.SqlTypes.BIGINT; import static org.hibernate.type.SqlTypes.BOOLEAN; import static org.hibernate.type.SqlTypes.DATE; @@ -257,10 +258,7 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry final JdbcTypeRegistry jdbcTypeRegistry = typeContributions.getTypeConfiguration() .getJdbcTypeRegistry(); jdbcTypeRegistry.addDescriptor( Types.BOOLEAN, TinyIntJdbcType.INSTANCE ); - // At least the jTDS driver does not support this type code - if ( getDriverKind() == SybaseDriverKind.JTDS ) { - jdbcTypeRegistry.addDescriptor( Types.TIMESTAMP_WITH_TIMEZONE, TimestampJdbcType.INSTANCE ); - } + jdbcTypeRegistry.addDescriptor( Types.TIMESTAMP_WITH_TIMEZONE, TimestampJdbcType.INSTANCE ); } @Override @@ -634,8 +632,8 @@ public ViolatedConstraintNameExtractor getViolatedConstraintNameExtractor() { */ private static final ViolatedConstraintNameExtractor EXTRACTOR = new TemplatedViolatedConstraintNameExtractor( sqle -> { - final String sqlState = JdbcExceptionHelper.extractSqlState( sqle ); - final int errorCode = JdbcExceptionHelper.extractErrorCode( sqle ); + final String sqlState = extractSqlState( sqle ); + final int errorCode = extractErrorCode( sqle ); if ( sqlState != null ) { switch ( sqlState ) { case "S1000": @@ -660,8 +658,8 @@ public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() { return null; } return (sqlException, message, sql) -> { - final String sqlState = JdbcExceptionHelper.extractSqlState( sqlException ); - final int errorCode = JdbcExceptionHelper.extractErrorCode( sqlException ); + final String sqlState = extractSqlState( sqlException ); + final int errorCode = extractErrorCode( sqlException ); if ( sqlState != null ) { switch ( sqlState ) { case "HY008": @@ -729,4 +727,16 @@ public LimitHandler getLimitHandler() { public String getDual() { return "(select 1 c1)"; } + + @Override + public boolean supportsIntersect() { + // At least the version that + return false; + } + + @Override + public boolean supportsJoinsInDelete() { + return true; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacySqlAstTranslator.java index f73bd2b35125..d61d0a4b4244 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseASELegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -48,7 +48,7 @@ import org.hibernate.sql.ast.tree.update.UpdateStatement; import org.hibernate.sql.exec.spi.JdbcOperation; -import static org.hibernate.dialect.SybaseASESqlAstTranslator.isLob; +import static org.hibernate.dialect.sql.ast.SybaseASESqlAstTranslator.isLob; /** * A SQL AST translator for Sybase ASE. @@ -108,11 +108,6 @@ protected void renderUpdateClause(UpdateStatement updateStatement) { } } - @Override - protected boolean supportsJoinsInDelete() { - return true; - } - @Override protected void renderFromClauseAfterUpdateSet(UpdateStatement statement) { if ( statement.getFromClause().getRoots().isEmpty() ) { @@ -134,11 +129,6 @@ protected void visitConflictClause(ConflictClause conflictClause) { } } - @Override - protected boolean supportsWithClause() { - return false; - } - // Sybase ASE does not allow CASE expressions where all result arms contain plain parameters. // At least one result arm must provide some type context for inference, // so we cast the first result arm if we encounter this condition @@ -423,7 +413,7 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp break; } } - if ( supportsDistinctFromPredicate() ) { + if ( getDialect().supportsDistinctFromPredicate() ) { renderComparisonEmulateIntersect( lhs, operator, rhs ); } else { @@ -482,7 +472,7 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp } } else { - if ( supportsDistinctFromPredicate() ) { + if ( getDialect().supportsDistinctFromPredicate() ) { renderComparisonEmulateIntersect( lhs, operator, rhs ); } else { @@ -492,12 +482,6 @@ protected void renderComparison(Expression lhs, ComparisonOperator operator, Exp } } - @Override - protected boolean supportsIntersect() { - // At least the version that - return false; - } - @Override protected void renderSelectTupleComparison( List lhsExpressions, @@ -572,21 +556,6 @@ protected boolean needsMaxRows() { return !supportsTopClause(); } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - private boolean supportsTopClause() { return getDialect().getVersion().isSameOrAfter( 12, 5 ); } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereDialect.java index 71879f917e17..c5528d537acf 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java index 869c688d83da..4154ed000534 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseAnywhereSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -222,18 +222,4 @@ public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeti appendSql( CLOSE_PARENTHESIS ); } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacyDialect.java index e2e924a790ce..6936884c9e06 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacyDialect.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -487,14 +487,14 @@ public boolean supportsStandardCurrentTimestampFunction() { } @Override - public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData metadata) throws SQLException { - if ( dbMetaData == null ) { + if ( metadata == null ) { builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); } - return super.buildIdentifierHelper( builder, dbMetaData ); + return super.buildIdentifierHelper( builder, metadata ); } @Override @@ -529,4 +529,25 @@ public DmlTargetColumnQualifierSupport getDmlTargetColumnQualifierSupport() { public boolean supportsFromClauseInUpdate() { return true; } + + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsWithClause() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacySqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacySqlAstTranslator.java index 0bf55746fb77..c2206b78f46e 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacySqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacySqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -89,11 +89,6 @@ protected void visitConflictClause(ConflictClause conflictClause) { } } - @Override - protected boolean supportsWithClause() { - return false; - } - // Sybase does not allow CASE expressions where all result arms contain plain parameters. // At least one result arm must provide some type context for inference, // so we cast the first result arm if we encounter this condition @@ -254,21 +249,6 @@ public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeti appendSql( CLOSE_PARENTHESIS ); } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - @Override protected boolean needsRowsToSkip() { return true; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacySqmToSqlAstConverter.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacySqmToSqlAstConverter.java index 31ac69046c85..02998e071d04 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacySqmToSqlAstConverter.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/SybaseLegacySqmToSqlAstConverter.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TeradataSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TeradataSqlAstTranslator.java deleted file mode 100644 index ffaeb8ef6639..000000000000 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TeradataSqlAstTranslator.java +++ /dev/null @@ -1,142 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.community.dialect; - -import java.util.List; - -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.query.sqm.ComparisonOperator; -import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator; -import org.hibernate.sql.ast.spi.SqlSelection; -import org.hibernate.sql.ast.tree.Statement; -import org.hibernate.sql.ast.tree.expression.Expression; -import org.hibernate.sql.ast.tree.expression.Literal; -import org.hibernate.sql.ast.tree.expression.SqlTuple; -import org.hibernate.sql.ast.tree.expression.Summarization; -import org.hibernate.sql.ast.tree.select.QueryPart; -import org.hibernate.sql.ast.tree.select.QuerySpec; -import org.hibernate.sql.ast.tree.select.SelectClause; -import org.hibernate.sql.exec.spi.JdbcOperation; - -/** - * A SQL AST translator for Teradata. - * - * @author Christian Beikov - */ -public class TeradataSqlAstTranslator extends AbstractSqlAstTranslator { - - public TeradataSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) { - super( sessionFactory, statement ); - } - - @Override - public void visitQuerySpec(QuerySpec querySpec) { - if ( querySpec.isRoot() && getDialect().getVersion().isSameOrAfter( 14 ) ) { - final ForUpdateClause forUpdateClause = new ForUpdateClause(); - forUpdateClause.merge( getLockOptions() ); - super.renderForUpdateClause( querySpec, forUpdateClause ); - } - super.visitQuerySpec( querySpec ); - } - - @Override - protected String getForUpdate() { - return "locking row for write "; - } - - @Override - protected String getForShare(int timeoutMillis) { - return "locking row for read "; - } - - @Override - protected String getNoWait() { - return "nowait "; - } - - @Override - protected LockStrategy determineLockingStrategy( - QuerySpec querySpec, - ForUpdateClause forUpdateClause, - Boolean followOnLocking) { - return LockStrategy.NONE; - } - - @Override - protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) { - // Teradata does not support the FOR UPDATE clause but has a proprietary LOCKING clause - } - - @Override - protected boolean needsRowsToSkip() { - return true; - } - - @Override - protected void renderFetchPlusOffsetExpression( - Expression fetchClauseExpression, - Expression offsetClauseExpression, - int offset) { - renderFetchPlusOffsetExpressionAsSingleParameter( fetchClauseExpression, offsetClauseExpression, offset ); - } - - @Override - protected void visitSqlSelections(SelectClause selectClause) { - renderTopClause( (QuerySpec) getQueryPartStack().getCurrent(), true, true ); - super.visitSqlSelections( selectClause ); - } - - @Override - public void visitOffsetFetchClause(QueryPart queryPart) { - // Teradata only supports the TOP clause - if ( !queryPart.isRoot() && queryPart.getOffsetClauseExpression() != null ) { - throw new IllegalArgumentException( "Can't emulate offset clause in subquery" ); - } - } - - @Override - protected void renderComparison(Expression lhs, ComparisonOperator operator, Expression rhs) { - renderComparisonEmulateIntersect( lhs, operator, rhs ); - } - - @Override - protected void renderSelectTupleComparison( - List lhsExpressions, - SqlTuple tuple, - ComparisonOperator operator) { - emulateSelectTupleComparison( lhsExpressions, tuple.getExpressions(), operator, true ); - } - - @Override - protected void renderPartitionItem(Expression expression) { - if ( expression instanceof Literal ) { - appendSql( "()" ); - } - else if ( expression instanceof Summarization ) { - // This could theoretically be emulated by rendering all grouping variations of the query and - // connect them via union all but that's probably pretty inefficient and would have to happen - // on the query spec level - throw new UnsupportedOperationException( "Summarization is not supported by DBMS!" ); - } - else { - expression.accept( this ); - } - } - - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } -} diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TiDBDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TiDBDialect.java new file mode 100644 index 000000000000..28363d72e7f8 --- /dev/null +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TiDBDialect.java @@ -0,0 +1,243 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.community.dialect; + +import jakarta.persistence.TemporalType; +import jakarta.persistence.Timeout; +import org.hibernate.Timeouts; +import org.hibernate.community.dialect.sequence.SequenceInformationExtractorTiDBDatabaseImpl; +import org.hibernate.community.dialect.sequence.TiDBSequenceSupport; +import org.hibernate.dialect.DatabaseVersion; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.FunctionalDependencyAnalysisSupport; +import org.hibernate.dialect.FunctionalDependencyAnalysisSupportImpl; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.MySQLServerConfiguration; +import org.hibernate.dialect.aggregate.AggregateSupport; +import org.hibernate.dialect.aggregate.MySQLAggregateSupport; +import org.hibernate.dialect.sequence.SequenceSupport; +import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.query.common.TemporalUnit; +import org.hibernate.query.sqm.IntervalType; +import org.hibernate.sql.ast.SqlAstTranslator; +import org.hibernate.sql.ast.SqlAstTranslatorFactory; +import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory; +import org.hibernate.sql.ast.tree.Statement; +import org.hibernate.sql.exec.spi.JdbcOperation; +import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; + +/** + * A {@linkplain Dialect SQL dialect} for TiDB. + * + * @author Cong Wang + */ +public class TiDBDialect extends MySQLDialect { + + private static final DatabaseVersion VERSION57 = DatabaseVersion.make( 5, 7 ); + + private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 5, 4 ); + + public TiDBDialect() { + this( MINIMUM_VERSION ); + } + + public TiDBDialect(DatabaseVersion version) { + super( version ); + } + + public TiDBDialect(DialectResolutionInfo info) { + super( createVersion( info, MINIMUM_VERSION ), MySQLServerConfiguration.fromDialectResolutionInfo( info ) ); + registerKeywords( info ); + } + + @Override + public DatabaseVersion getMySQLVersion() { + // For simplicity’s sake, configure MySQL 5.7 compatibility + return VERSION57; + } + + @Override + protected DatabaseVersion getMinimumSupportedVersion() { + return MINIMUM_VERSION; + } + + @Override + protected void registerDefaultKeywords() { + super.registerDefaultKeywords(); + // TiDB implemented 'Window Functions' of MySQL 8, so the following keywords are reserved. + registerKeyword( "CUME_DIST" ); + registerKeyword( "DENSE_RANK" ); + registerKeyword( "EXCEPT" ); + registerKeyword( "FIRST_VALUE" ); + registerKeyword( "GROUPS" ); + registerKeyword( "LAG" ); + registerKeyword( "LAST_VALUE" ); + registerKeyword( "LEAD" ); + registerKeyword( "NTH_VALUE" ); + registerKeyword( "NTILE" ); + registerKeyword( "PERCENT_RANK" ); + registerKeyword( "RANK" ); + registerKeyword( "ROW_NUMBER" ); + } + + @Override + public boolean supportsCascadeDelete() { + return false; + } + + @Override + public String getQuerySequencesString() { + return "SELECT sequence_name FROM information_schema.sequences WHERE sequence_schema = database()"; + } + + @Override + public SequenceSupport getSequenceSupport() { + return TiDBSequenceSupport.INSTANCE; + } + + @Override + public AggregateSupport getAggregateSupport() { + return MySQLAggregateSupport.forTiDB( this ); + } + + @Override + public SequenceInformationExtractor getSequenceInformationExtractor() { + return SequenceInformationExtractorTiDBDatabaseImpl.INSTANCE; + } + + @Override + public SqlAstTranslatorFactory getSqlAstTranslatorFactory() { + return new StandardSqlAstTranslatorFactory() { + @Override + protected SqlAstTranslator buildTranslator( + SessionFactoryImplementor sessionFactory, Statement statement) { + return new TiDBSqlAstTranslator<>( sessionFactory, statement, TiDBDialect.this ); + } + }; + } + + @Override + public boolean supportsRecursiveCTE() { + return true; + } + + @Override + public boolean supportsSkipLocked() { + return false; + } + + @Override + public boolean supportsNoWait() { + return true; + } + + @Override + public boolean supportsWait() { + return true; + } + + @Override + protected boolean supportsForShare() { + return false; + } + + @Override + protected boolean supportsAliasLocks() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return getVersion().isSameOrAfter( 5, 7 ); + } + + @Override + public String getReadLockString(Timeout timeout) { + if ( timeout.milliseconds() == Timeouts.NO_WAIT_MILLI ) { + return getForUpdateNowaitString(); + } + return super.getReadLockString( timeout ); + } + + @Override + public String getReadLockString(String aliases, Timeout timeout) { + if ( timeout.milliseconds() == Timeouts.NO_WAIT_MILLI ) { + return getForUpdateNowaitString( aliases ); + } + return super.getReadLockString( aliases, timeout ); + } + + @Override + public String getWriteLockString(Timeout timeout) { + if ( timeout.milliseconds() == Timeouts.NO_WAIT_MILLI ) { + return getForUpdateNowaitString(); + } + + if ( Timeouts.isRealTimeout( timeout ) ) { + return getForUpdateString() + " wait " + Timeouts.getTimeoutInSeconds( timeout ); + } + + return getForUpdateString(); + } + + @Override + public String getReadLockString(int timeout) { + if ( timeout == Timeouts.NO_WAIT_MILLI ) { + return getForUpdateNowaitString(); + } + return super.getReadLockString( timeout ); + } + + @Override + public String getReadLockString(String aliases, int timeout) { + if ( timeout == Timeouts.NO_WAIT_MILLI ) { + return getForUpdateNowaitString( aliases ); + } + return super.getReadLockString( aliases, timeout ); + } + + @Override + public String getWriteLockString(int timeout) { + if ( timeout == Timeouts.NO_WAIT_MILLI ) { + return getForUpdateNowaitString(); + } + + if ( Timeouts.isRealTimeout( timeout ) ) { + return getForUpdateString() + " wait " + Timeouts.getTimeoutInSeconds( timeout ); + } + + return getForUpdateString(); + } + + @Override + public String getForUpdateNowaitString() { + return getForUpdateString() + " nowait"; + } + + @Override + public String getForUpdateNowaitString(String aliases) { + return getForUpdateString( aliases ) + " nowait"; + } + + @Override + public FunctionalDependencyAnalysisSupport getFunctionalDependencyAnalysisSupport() { + return FunctionalDependencyAnalysisSupportImpl.TABLE_REFERENCE; + } + + @Override + @SuppressWarnings("deprecation") + public String timestampaddPattern(TemporalUnit unit, TemporalType temporalType, IntervalType intervalType) { + // TiDB doesn't natively support adding fractional seconds + return unit == TemporalUnit.SECOND && intervalType == null + ? "timestampadd(microsecond,?2*1e6,?3)" + : super.timestampaddPattern( unit, temporalType, intervalType ); + } + + @Override + public String getDual() { + return "dual"; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TiDBSqlAstTranslator.java similarity index 95% rename from hibernate-core/src/main/java/org/hibernate/dialect/TiDBSqlAstTranslator.java rename to hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TiDBSqlAstTranslator.java index e9943f85da87..d19c638a99ac 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/TiDBSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TiDBSqlAstTranslator.java @@ -1,13 +1,15 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.dialect; +package org.hibernate.community.dialect; import java.util.ArrayList; import java.util.List; import org.hibernate.LockOptions; +import org.hibernate.dialect.DmlTargetColumnQualifierSupport; +import org.hibernate.dialect.sql.ast.MySQLSqlAstTranslator; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.util.collections.Stack; import org.hibernate.query.sqm.ComparisonOperator; @@ -49,9 +51,9 @@ public class TiDBSqlAstTranslator extends AbstractSqlAs private final TiDBDialect dialect; - public TiDBSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement) { + public TiDBSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement statement, TiDBDialect dialect) { super( sessionFactory, statement ); - this.dialect = (TiDBDialect) super.getDialect(); + this.dialect = dialect; } @Override @@ -152,11 +154,6 @@ protected void renderDmlTargetTableExpression(NamedTableReference tableReference } } - @Override - protected boolean supportsJoinsInDelete() { - return true; - } - @Override protected JdbcOperationQueryInsert translateInsert(InsertSelectStatement sqlAst) { visitInsertStatement( sqlAst ); @@ -320,21 +317,6 @@ public void visitLikePredicate(LikePredicate likePredicate) { } } - @Override - public boolean supportsRowValueConstructorSyntaxInSet() { - return false; - } - - @Override - public boolean supportsRowValueConstructorSyntaxInInList() { - return dialect.getVersion().isSameOrAfter( 5, 7 ); - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } - @Override protected String getForShare(int timeoutMillis) { if ( timeoutMillis == LockOptions.NO_WAIT ) { @@ -345,7 +327,7 @@ protected String getForShare(int timeoutMillis) { @Override public TiDBDialect getDialect() { - return this.dialect; + return dialect; } @Override diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java index 80a27666c872..47bf46cb80c0 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenDialect.java @@ -1,13 +1,14 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; import java.sql.Types; +import jakarta.persistence.Timeout; import org.hibernate.LockMode; -import org.hibernate.LockOptions; +import org.hibernate.Timeouts; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.community.dialect.pagination.TimesTenLimitHandler; import org.hibernate.community.dialect.sequence.SequenceInformationExtractorTimesTenDatabaseImpl; @@ -259,6 +260,35 @@ public String getForUpdateNowaitString() { return " for update nowait"; } + @Override + public String getWriteLockString(Timeout timeout) { + return withTimeout( getForUpdateString(), timeout ); + } + + @Override + public String getWriteLockString(String aliases, Timeout timeout) { + return withTimeout( getForUpdateString(aliases), timeout ); + } + + @Override + public String getReadLockString(Timeout timeout) { + return getWriteLockString( timeout ); + } + + @Override + public String getReadLockString(String aliases, Timeout timeout) { + return getWriteLockString( aliases, timeout ); + } + + + private String withTimeout(String lockString, Timeout timeout) { + return switch ( timeout.milliseconds() ) { + case Timeouts.NO_WAIT_MILLI -> supportsNoWait() ? lockString + " nowait" : lockString; + case Timeouts.SKIP_LOCKED_MILLI, Timeouts.WAIT_FOREVER_MILLI -> lockString; + default -> supportsWait() ? lockString + " wait " + Timeouts.getTimeoutInSeconds( timeout ) : lockString; + }; + } + @Override public String getWriteLockString(int timeout) { return withTimeout( getForUpdateString(), timeout ); @@ -281,15 +311,11 @@ public String getReadLockString(String aliases, int timeout) { private String withTimeout(String lockString, int timeout) { - switch (timeout) { - case LockOptions.NO_WAIT: - return supportsNoWait() ? lockString + " nowait" : lockString; - case LockOptions.SKIP_LOCKED: - case LockOptions.WAIT_FOREVER: - return lockString; - default: - return supportsWait() ? lockString + " wait " + getTimeoutInSeconds( timeout ) : lockString; - } + return switch ( timeout ) { + case Timeouts.NO_WAIT_MILLI -> supportsNoWait() ? lockString + " nowait" : lockString; + case Timeouts.SKIP_LOCKED_MILLI, Timeouts.WAIT_FOREVER_MILLI -> lockString; + default -> supportsWait() ? lockString + " wait " + getTimeoutInSeconds( timeout ) : lockString; + }; } @Override @@ -424,4 +450,19 @@ public String getSelectClauseNullString(int sqlType, TypeConfiguration typeConfi } } + @Override + public boolean supportsRowValueConstructorSyntax() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { + return false; + } + + @Override + public boolean supportsRowValueConstructorSyntaxInInList() { + return false; + } + } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenSqlAstTranslator.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenSqlAstTranslator.java index 493f16d98f09..2fb793c59830 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenSqlAstTranslator.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/TimesTenSqlAstTranslator.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -127,18 +127,4 @@ else if ( expression instanceof Summarization ) { } } - @Override - protected boolean supportsRowValueConstructorSyntax() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInInList() { - return false; - } - - @Override - protected boolean supportsRowValueConstructorSyntaxInQuantifiedPredicates() { - return false; - } } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/function/DerbyLpadEmulation.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/function/DerbyLpadEmulation.java index 144620da69be..7744faeeced9 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/function/DerbyLpadEmulation.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/function/DerbyLpadEmulation.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.function; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/function/DerbyRpadEmulation.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/function/DerbyRpadEmulation.java index 981c0130d7f2..fed51b08a59e 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/function/DerbyRpadEmulation.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/function/DerbyRpadEmulation.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.function; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/CUBRIDIdentityColumnSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/CUBRIDIdentityColumnSupport.java index af34e16ae967..d8b74e20c5b8 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/CUBRIDIdentityColumnSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/CUBRIDIdentityColumnSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.identity; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/CacheIdentityColumnSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/CacheIdentityColumnSupport.java index 29dec0d32a45..502959cccba2 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/CacheIdentityColumnSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/CacheIdentityColumnSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.identity; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/FirebirdIdentityColumnSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/FirebirdIdentityColumnSupport.java index d7572a63a88b..b4f16c3b55ed 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/FirebirdIdentityColumnSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/FirebirdIdentityColumnSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.identity; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/InformixIdentityColumnSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/InformixIdentityColumnSupport.java index d040aef5a44d..6b52e346a825 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/InformixIdentityColumnSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/InformixIdentityColumnSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.identity; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/Ingres10IdentityColumnSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/Ingres10IdentityColumnSupport.java index 2f6298ffb463..e1ff20542713 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/Ingres10IdentityColumnSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/Ingres10IdentityColumnSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.identity; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/Ingres9IdentityColumnSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/Ingres9IdentityColumnSupport.java index 818567d3269a..f5773eaeaa8b 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/Ingres9IdentityColumnSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/Ingres9IdentityColumnSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.identity; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/MimerSQLIdentityColumnSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/MimerSQLIdentityColumnSupport.java index 61acd99cade9..3249aa4f9824 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/MimerSQLIdentityColumnSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/MimerSQLIdentityColumnSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.identity; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/SQLiteIdentityColumnSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/SQLiteIdentityColumnSupport.java index 4444a3f56667..7be3f3a65e36 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/SQLiteIdentityColumnSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/SQLiteIdentityColumnSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.identity; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/SybaseAnywhereIdentityColumnSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/SybaseAnywhereIdentityColumnSupport.java index 0e90b018a551..c7953d7d2604 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/SybaseAnywhereIdentityColumnSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/SybaseAnywhereIdentityColumnSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.identity; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/Teradata14IdentityColumnSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/Teradata14IdentityColumnSupport.java deleted file mode 100644 index de5932953b96..000000000000 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/identity/Teradata14IdentityColumnSupport.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SPDX-License-Identifier: LGPL-2.1-or-later - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.community.dialect.identity; - -import org.hibernate.dialect.identity.IdentityColumnSupportImpl; - -/** - * @author Andrea Boriero - */ -public class Teradata14IdentityColumnSupport extends IdentityColumnSupportImpl { - - public static Teradata14IdentityColumnSupport INSTANCE = new Teradata14IdentityColumnSupport(); - - @Override - public boolean supportsIdentityColumns() { - return true; - } - - @Override - public String getIdentityColumnString(int type) { - return "generated by default as identity not null"; - } - - @Override - public String getIdentityInsertString() { - return "null"; - } -} diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/AltibaseLimitHandler.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/AltibaseLimitHandler.java index 3829eda8947c..a95be7931045 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/AltibaseLimitHandler.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/AltibaseLimitHandler.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.pagination; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/DerbyLimitHandler.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/DerbyLimitHandler.java index ff8b9948cfd2..c307790f223b 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/DerbyLimitHandler.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/DerbyLimitHandler.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.pagination; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/FirstLimitHandler.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/FirstLimitHandler.java index 9fcad91bf17c..3dd03b74ca14 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/FirstLimitHandler.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/FirstLimitHandler.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.pagination; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/FirstSkipLimitHandler.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/FirstSkipLimitHandler.java index c13612efb1a6..d8d4adf69d5b 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/FirstSkipLimitHandler.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/FirstSkipLimitHandler.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.pagination; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/IngresLimitHandler.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/IngresLimitHandler.java index 73c7dc33f283..5d70b31af673 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/IngresLimitHandler.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/IngresLimitHandler.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.pagination; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/LegacyHSQLLimitHandler.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/LegacyHSQLLimitHandler.java new file mode 100644 index 000000000000..63ec85a897e5 --- /dev/null +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/LegacyHSQLLimitHandler.java @@ -0,0 +1,31 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.community.dialect.pagination; + +import org.hibernate.dialect.pagination.AbstractSimpleLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; + +/** + * A {@link LimitHandler} for HSQL prior to 2.0. + */ +public class LegacyHSQLLimitHandler extends AbstractSimpleLimitHandler { + + public static LegacyHSQLLimitHandler INSTANCE = new LegacyHSQLLimitHandler(); + + @Override + protected String limitClause(boolean hasFirstRow) { + return hasFirstRow ? " limit ? ?" : " top ?"; + } + + @Override + protected String insert(String limitOrTop, String sql) { + return insertAfterSelect( limitOrTop, sql ); + } + + @Override + public final boolean bindLimitParametersFirst() { + return true; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LegacyOracleLimitHandler.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/LegacyOracleLimitHandler.java similarity index 90% rename from hibernate-core/src/main/java/org/hibernate/dialect/pagination/LegacyOracleLimitHandler.java rename to hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/LegacyOracleLimitHandler.java index 43c2e75fe79d..2000e8401f45 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LegacyOracleLimitHandler.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/LegacyOracleLimitHandler.java @@ -1,10 +1,12 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.dialect.pagination; +package org.hibernate.community.dialect.pagination; import org.hibernate.dialect.DatabaseVersion; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.query.spi.Limit; import java.util.regex.Matcher; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/RowsLimitHandler.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/RowsLimitHandler.java index 0ad62fed1251..e666d9184094 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/RowsLimitHandler.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/RowsLimitHandler.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.pagination; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQLServer2005LimitHandler.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/SQLServer2005LimitHandler.java similarity index 98% rename from hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQLServer2005LimitHandler.java rename to hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/SQLServer2005LimitHandler.java index d328f23d92e2..e48e94e60204 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQLServer2005LimitHandler.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/SQLServer2005LimitHandler.java @@ -1,8 +1,8 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.dialect.pagination; +package org.hibernate.community.dialect.pagination; import java.sql.PreparedStatement; import java.sql.SQLException; @@ -11,6 +11,8 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.internal.util.StringHelper; import org.hibernate.query.spi.Limit; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/SkipFirstLimitHandler.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/SkipFirstLimitHandler.java index f7fe65d8fa46..56e3fcc5a62a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/SkipFirstLimitHandler.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/SkipFirstLimitHandler.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.pagination; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/TimesTenLimitHandler.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/TimesTenLimitHandler.java index 7357779f6d37..a42aa619c409 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/TimesTenLimitHandler.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/pagination/TimesTenLimitHandler.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.pagination; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/AltibaseSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/AltibaseSequenceSupport.java index e2016e06aeb1..f8f1e393857d 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/AltibaseSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/AltibaseSequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/CUBRIDSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/CUBRIDSequenceSupport.java index 76745376a5f6..47a5c66dfde6 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/CUBRIDSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/CUBRIDSequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/CacheSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/CacheSequenceSupport.java index ec39a9d5f7e4..ff369048fbbb 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/CacheSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/CacheSequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/DerbySequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/DerbySequenceSupport.java index 16e666a00f87..773b366d50ec 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/DerbySequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/DerbySequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/FirebirdSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/FirebirdSequenceSupport.java index 91880044baab..8231eac65f41 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/FirebirdSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/FirebirdSequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/InformixSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/InformixSequenceSupport.java index e59ed475dd9a..4da255db7a1b 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/InformixSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/InformixSequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/IngresLegacySequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/IngresLegacySequenceSupport.java index 8d377b0e207f..e9a35b009f66 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/IngresLegacySequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/IngresLegacySequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/InterbaseSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/InterbaseSequenceSupport.java index 229a5844bba7..ca8d84c4d185 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/InterbaseSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/InterbaseSequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/LegacyDB2SequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/LegacyDB2SequenceSupport.java index 1d85ea828e03..99db6d5c6d7a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/LegacyDB2SequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/LegacyDB2SequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/MaxDBSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/MaxDBSequenceSupport.java index e39081d40e07..dfbcff54d30a 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/MaxDBSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/MaxDBSequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/MimerSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/MimerSequenceSupport.java index 8d8688a2f842..e41b907fcc99 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/MimerSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/MimerSequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/PostgreSQLLegacySequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/PostgreSQLLegacySequenceSupport.java index 8ef804948bc5..e687c66094b8 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/PostgreSQLLegacySequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/PostgreSQLLegacySequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/RDMSSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/RDMSSequenceSupport.java index dcf06cd7451d..ffbfb76f171b 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/RDMSSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/RDMSSequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorAltibaseDatabaseImpl.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorAltibaseDatabaseImpl.java index d57c8cad67d6..3f20803dc89c 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorAltibaseDatabaseImpl.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorAltibaseDatabaseImpl.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorCUBRIDDatabaseImpl.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorCUBRIDDatabaseImpl.java index 843d68cd26dc..359f6fa0935f 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorCUBRIDDatabaseImpl.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorCUBRIDDatabaseImpl.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorDerbyDatabaseImpl.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorDerbyDatabaseImpl.java index b9fbcd534b25..0af6f854da7c 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorDerbyDatabaseImpl.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorDerbyDatabaseImpl.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorFirebirdDatabaseImpl.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorFirebirdDatabaseImpl.java index 16ea355efbf1..b4605375f288 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorFirebirdDatabaseImpl.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorFirebirdDatabaseImpl.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorInformixDatabaseImpl.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorInformixDatabaseImpl.java index 5428ce548a39..cd3c76b60809 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorInformixDatabaseImpl.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorInformixDatabaseImpl.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorIngresDatabaseImpl.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorIngresDatabaseImpl.java index e4fd6d7408ad..4ea3d4546bba 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorIngresDatabaseImpl.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorIngresDatabaseImpl.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorMimerSQLDatabaseImpl.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorMimerSQLDatabaseImpl.java index 7811192e1f64..8288a86e013c 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorMimerSQLDatabaseImpl.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorMimerSQLDatabaseImpl.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorSAPDBDatabaseImpl.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorSAPDBDatabaseImpl.java index a29353332d61..792e78a2198d 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorSAPDBDatabaseImpl.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorSAPDBDatabaseImpl.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorTiDBDatabaseImpl.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorTiDBDatabaseImpl.java similarity index 91% rename from hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorTiDBDatabaseImpl.java rename to hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorTiDBDatabaseImpl.java index 4b1e8232e442..dff958dcbf24 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorTiDBDatabaseImpl.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorTiDBDatabaseImpl.java @@ -1,11 +1,14 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.tool.schema.extract.internal; +package org.hibernate.community.dialect.sequence; import org.hibernate.boot.model.relational.QualifiedSequenceName; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorLegacyImpl; +import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl; +import org.hibernate.tool.schema.extract.internal.SequenceInformationImpl; import org.hibernate.tool.schema.extract.spi.ExtractionContext; import org.hibernate.tool.schema.extract.spi.SequenceInformation; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorTimesTenDatabaseImpl.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorTimesTenDatabaseImpl.java index 1f2194f72615..82dce3e04ce8 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorTimesTenDatabaseImpl.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/SequenceInformationExtractorTimesTenDatabaseImpl.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/sequence/TiDBSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/TiDBSequenceSupport.java similarity index 81% rename from hibernate-core/src/main/java/org/hibernate/dialect/sequence/TiDBSequenceSupport.java rename to hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/TiDBSequenceSupport.java index 9b194854c6cc..3119bfdedc14 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/sequence/TiDBSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/TiDBSequenceSupport.java @@ -1,13 +1,15 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.dialect.sequence; +package org.hibernate.community.dialect.sequence; import org.hibernate.MappingException; +import org.hibernate.community.dialect.TiDBDialect; +import org.hibernate.dialect.sequence.SequenceSupport; /** - * Sequence support for {@link org.hibernate.dialect.TiDBDialect}. + * Sequence support for {@link TiDBDialect}. * * @author Cong Wang */ diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/TimesTenSequenceSupport.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/TimesTenSequenceSupport.java index 04b9266dfee2..13afbf3080a6 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/TimesTenSequenceSupport.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/sequence/TimesTenSequenceSupport.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.sequence; diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/unique/InformixUniqueDelegate.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/unique/InformixUniqueDelegate.java index ba61fdd6ad4a..c05fabbc5ce1 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/unique/InformixUniqueDelegate.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/unique/InformixUniqueDelegate.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.unique; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/AltibaseDialectTestCase.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/AltibaseDialectTestCase.java index 5b4dbac8825b..105ece4e5270 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/AltibaseDialectTestCase.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/AltibaseDialectTestCase.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/AltibaseFunctionsTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/AltibaseFunctionsTest.java index 37ecb0688dfe..b5f6d6edc3e7 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/AltibaseFunctionsTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/AltibaseFunctionsTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; @@ -23,10 +23,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.jupiter.api.Assertions.assertNotNull; -@DomainModel( - annotatedClasses = { Person.class }, - xmlMappings = "org/hibernate/community/dialect/Person.hbm.xml" -) +@DomainModel(annotatedClasses = Person.class) @RequiresDialect(AltibaseDialect.class) @SessionFactory public class AltibaseFunctionsTest { diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/CommunityDialectFactoryTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/CommunityDialectFactoryTest.java index 423cd51c863b..b5fcc2508230 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/CommunityDialectFactoryTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/CommunityDialectFactoryTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/CommunityDialectSelectorTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/CommunityDialectSelectorTest.java index f473f7c67530..a5898270b69a 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/CommunityDialectSelectorTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/CommunityDialectSelectorTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DB2LegacyDialectTestCase.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DB2LegacyDialectTestCase.java index 09350761a703..e38f5a34505c 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DB2LegacyDialectTestCase.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DB2LegacyDialectTestCase.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyCustomSQLTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyCustomSQLTest.java index a1cffc37e441..f42f36526beb 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyCustomSQLTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyCustomSQLTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyDateTimeParameterTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyDateTimeParameterTest.java index 8f1c15c968cf..ebd927b8453f 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyDateTimeParameterTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyDateTimeParameterTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyDialectTestCase.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyDialectTestCase.java index 6184c199d089..27cefd4c8d8b 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyDialectTestCase.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyDialectTestCase.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyJpaTckUsageTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyJpaTckUsageTest.java index aa83b092b230..1aa41aa1b25d 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyJpaTckUsageTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyJpaTckUsageTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyLegacyDialectTestCase.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyLegacyDialectTestCase.java index 912780982f20..6eb127580196 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyLegacyDialectTestCase.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyLegacyDialectTestCase.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyLimitHandlerTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyLimitHandlerTest.java index ad36cd586ca5..0746308ae159 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyLimitHandlerTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyLimitHandlerTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyStoreProcedures.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyStoreProcedures.java index 7f61aa76298d..2561d3b37921 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyStoreProcedures.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyStoreProcedures.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyStoredProcedureTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyStoredProcedureTest.java index fdc70307f63c..99ef1528ce2c 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyStoredProcedureTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyStoredProcedureTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyTransactionTimeoutTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyTransactionTimeoutTest.java index da7cfb4c9e10..bfdf634a5a90 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyTransactionTimeoutTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/DerbyTransactionTimeoutTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/FirebirdDialectTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/FirebirdDialectTest.java index d2b0d572d40e..f8439b52d2da 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/FirebirdDialectTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/FirebirdDialectTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixFunctionTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixFunctionTest.java index ec1c686aa55f..2cb69ca19e4b 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixFunctionTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/InformixFunctionTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/IngresLimitHandlerTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/IngresLimitHandlerTest.java index a5e6d68a5cdb..f5bf1d79ec17 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/IngresLimitHandlerTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/IngresLimitHandlerTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/Person.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/Person.java index 3489048d1e35..de3629a69140 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/Person.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/Person.java @@ -1,12 +1,23 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; -import java.sql.*; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.SequenceGenerator; +import java.sql.Date; +import java.sql.Blob; +import java.sql.Clob; + +@Entity public class Person { + @Id + @GeneratedValue + @SequenceGenerator(sequenceName = "PERSON_SEQ") private int id; private String name; private Date birthDate; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/RowsLimitHandlerTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/RowsLimitHandlerTest.java index 59ae2166f4a1..51a76a4f9b16 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/RowsLimitHandlerTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/RowsLimitHandlerTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SQLServer2005DialectTestCase.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SQLServer2005DialectTestCase.java index e20d113c4847..a661c99f36fd 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SQLServer2005DialectTestCase.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SQLServer2005DialectTestCase.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SQLServer2008DialectTestCase.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SQLServer2008DialectTestCase.java index 0eb9908276a5..bf2eefa8f2d8 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SQLServer2008DialectTestCase.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SQLServer2008DialectTestCase.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/SQLServer2012DialectTestCase.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SQLServer2012DialectTestCase.java similarity index 88% rename from hibernate-core/src/test/java/org/hibernate/orm/test/dialect/SQLServer2012DialectTestCase.java rename to hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SQLServer2012DialectTestCase.java index 5856b9a3d67a..521218a63bdc 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/dialect/SQLServer2012DialectTestCase.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SQLServer2012DialectTestCase.java @@ -1,13 +1,13 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.orm.test.dialect; +package org.hibernate.community.dialect; import java.util.Locale; import org.hibernate.dialect.DatabaseVersion; -import org.hibernate.dialect.SQLServerDialect; +import org.hibernate.dialect.Dialect; import org.hibernate.query.spi.Limit; import org.junit.After; @@ -20,16 +20,16 @@ import static org.junit.Assert.assertEquals; /** - * Tests the Limit/Offset handler for {@link SQLServerDialect, v11}. + * Tests the Limit/Offset handler for SQLServerDialect. * * @author Chris Cranford */ public class SQLServer2012DialectTestCase extends BaseUnitTestCase { - private SQLServerDialect dialect; + private Dialect dialect; @Before public void setup() { - dialect = new SQLServerDialect( DatabaseVersion.make( 11 ) ); + dialect = new SQLServerLegacyDialect( DatabaseVersion.make( 11 ) ); } @After diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SingleStoreDialectTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SingleStoreDialectTest.java index bc2fc6e8ece3..a6f8797d8903 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SingleStoreDialectTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/SingleStoreDialectTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/functional/cache/SQLFunctionsInterSystemsTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/functional/cache/SQLFunctionsInterSystemsTest.java index 6c9648990111..ea84e4cac83e 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/functional/cache/SQLFunctionsInterSystemsTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/functional/cache/SQLFunctionsInterSystemsTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.functional.cache; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/functional/cache/TestInterSystemsFunctionsClass.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/functional/cache/TestInterSystemsFunctionsClass.java index b477eeac8ebc..e9ddefc7ea68 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/functional/cache/TestInterSystemsFunctionsClass.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/functional/cache/TestInterSystemsFunctionsClass.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.functional.cache; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/lockhint/SQLServer2005LockHintsTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/lockhint/SQLServer2005LockHintsTest.java index f746dc43d730..5ca8b9dc15db 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/lockhint/SQLServer2005LockHintsTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/lockhint/SQLServer2005LockHintsTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.unit.lockhint; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/lockhint/SybaseASE15LockHintsTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/lockhint/SybaseASE15LockHintsTest.java index 25dcbbc46f1f..0a6c71bd61ae 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/lockhint/SybaseASE15LockHintsTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/lockhint/SybaseASE15LockHintsTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.unit.lockhint; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DB2390SequenceInformationExtractorTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DB2390SequenceInformationExtractorTest.java index 50fe6f668c2f..aef225fb3d1e 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DB2390SequenceInformationExtractorTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DB2390SequenceInformationExtractorTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.unit.sequence; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DB2400SequenceInformationExtractorTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DB2400SequenceInformationExtractorTest.java index 9f9de27fddaa..062c5835efcc 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DB2400SequenceInformationExtractorTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DB2400SequenceInformationExtractorTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.unit.sequence; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenFiveDialectSequenceInformationExtractorTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenFiveDialectSequenceInformationExtractorTest.java index 02d533e9a42b..d963d672f397 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenFiveDialectSequenceInformationExtractorTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenFiveDialectSequenceInformationExtractorTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.unit.sequence; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java index 61989317fe03..26006aacbd8e 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenSevenDialectSequenceInformationExtractorTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.unit.sequence; diff --git a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java index 4dafdb0b8a12..48b3f342bf6f 100644 --- a/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java +++ b/hibernate-community-dialects/src/test/java/org/hibernate/community/dialect/unit/sequence/DerbyTenSixDialectSequenceInformationExtractorTest.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.community.dialect.unit.sequence; diff --git a/hibernate-community-dialects/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener b/hibernate-community-dialects/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener index 8f96f0a8e1b0..ef95df5d6c74 100644 --- a/hibernate-community-dialects/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener +++ b/hibernate-community-dialects/src/test/resources/META-INF/services/org.junit.platform.launcher.LauncherSessionListener @@ -1 +1,5 @@ +# +# SPDX-License-Identifier: Apache-2.0 +# Copyright Red Hat Inc. and Hibernate Authors +# org.hibernate.testing.schema.CheckClearSchemaListener diff --git a/hibernate-community-dialects/src/test/resources/org/hibernate/community/dialect/Person.hbm.xml b/hibernate-community-dialects/src/test/resources/org/hibernate/community/dialect/Person.hbm.xml deleted file mode 100644 index 784e939b145a..000000000000 --- a/hibernate-community-dialects/src/test/resources/org/hibernate/community/dialect/Person.hbm.xml +++ /dev/null @@ -1,27 +0,0 @@ - - - - - - - - - PERSON_SEQ - - - - - - - - - - - diff --git a/hibernate-community-dialects/src/test/resources/org/hibernate/community/dialect/derby/Mappings.hbm.xml b/hibernate-community-dialects/src/test/resources/org/hibernate/community/dialect/derby/Mappings.hbm.xml index 40c040f033ae..7d84cd279417 100644 --- a/hibernate-community-dialects/src/test/resources/org/hibernate/community/dialect/derby/Mappings.hbm.xml +++ b/hibernate-community-dialects/src/test/resources/org/hibernate/community/dialect/derby/Mappings.hbm.xml @@ -1,9 +1,7 @@ . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ import org.apache.tools.ant.filters.ReplaceTokens @@ -45,8 +43,6 @@ dependencies { compileOnly libs.jacksonXml compileOnly jdbcLibs.postgresql - compileOnly project( ":annotation-descriptor-generator" ) - testImplementation project(':hibernate-testing') testImplementation project(':hibernate-ant') testImplementation project(':hibernate-scan-jandex') @@ -268,6 +264,7 @@ tasks.withType( Test.class ).each { test -> tasks.named( "javadoc", Javadoc ) { configure(options) { overview = rootProject.file( "shared/javadoc/overview.html" ) + exclude( "**/internal/**", "org/hibernate/boot/jaxb/**", "org/hibernate/tuple/**" ) } } diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/graph/GraphLanguageLexer.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/graph/GraphLanguageLexer.g4 index c96cb4b04081..59bc9723cc5f 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/graph/GraphLanguageLexer.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/graph/GraphLanguageLexer.g4 @@ -2,10 +2,8 @@ lexer grammar GraphLanguageLexer; @header { /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.grammars.graph; } diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/graph/GraphLanguageParser.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/graph/GraphLanguageParser.g4 index b8036c9e1c81..a0e6c33b9974 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/graph/GraphLanguageParser.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/graph/GraphLanguageParser.g4 @@ -6,10 +6,8 @@ options { @header { /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.grammars.graph; } diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 index d2669e6b7fa0..a0e1d938b254 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlLexer.g4 @@ -3,10 +3,8 @@ lexer grammar HqlLexer; @header { /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.grammars.hql; } diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 index 87a53174b009..5db8339e9a72 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/hql/HqlParser.g4 @@ -6,10 +6,8 @@ options { @header { /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.grammars.hql; } @@ -161,9 +159,9 @@ queryExpression * A query with an optional 'order by' clause */ orderedQuery - : query queryOrder? # QuerySpecExpression - | LEFT_PAREN queryExpression RIGHT_PAREN queryOrder? # NestedQueryExpression - | queryOrder # QueryOrderExpression + : query orderByClause? limitOffset # QuerySpecExpression + | LEFT_PAREN queryExpression RIGHT_PAREN orderByClause? limitOffset # NestedQueryExpression + | orderByClause limitOffset # QueryOrderExpression ; /** @@ -176,10 +174,10 @@ setOperator ; /** - * The 'order by' clause and optional subclauses for limiting and pagination + * Optional subclauses for limiting and pagination */ -queryOrder - : orderByClause limitClause? offsetClause? fetchClause? +limitOffset + : limitClause? offsetClause? fetchClause? ; /** @@ -187,11 +185,14 @@ queryOrder * * - The 'select' clause may come first, in which case 'from' is optional * - The 'from' clause may come first, in which case 'select' is optional, and comes last + * - If both 'select' and 'from' are missing, a 'where' clause on its own is allowed + * + * Note that 'having' is only allowed with 'group by', but we don't enforce + * that in the grammar. */ query -// TODO: add with clause - : selectClause fromClause? whereClause? (groupByClause havingClause?)? - | fromClause whereClause? (groupByClause havingClause?)? selectClause? + : selectClause fromClause? whereClause? groupByClause? havingClause? + | fromClause whereClause? groupByClause? havingClause? selectClause? | whereClause ; diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/importsql/SqlScriptLexer.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/importsql/SqlScriptLexer.g4 index 33725f642a92..24c8839e405b 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/importsql/SqlScriptLexer.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/importsql/SqlScriptLexer.g4 @@ -2,10 +2,8 @@ lexer grammar SqlScriptLexer; @header { /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.grammars.importsql; } diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/importsql/SqlScriptParser.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/importsql/SqlScriptParser.g4 index a996dfa07eaf..3fc9a540679f 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/importsql/SqlScriptParser.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/importsql/SqlScriptParser.g4 @@ -6,10 +6,8 @@ options { @header { /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.grammars.importsql; } diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/ordering/OrderingLexer.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/ordering/OrderingLexer.g4 index b288be9db6c0..e25975f6d6de 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/ordering/OrderingLexer.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/ordering/OrderingLexer.g4 @@ -3,10 +3,8 @@ lexer grammar OrderingLexer; @header { /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.grammars.ordering; } diff --git a/hibernate-core/src/main/antlr/org/hibernate/grammars/ordering/OrderingParser.g4 b/hibernate-core/src/main/antlr/org/hibernate/grammars/ordering/OrderingParser.g4 index d5f3e7fe7422..3e57b1cf7dc9 100644 --- a/hibernate-core/src/main/antlr/org/hibernate/grammars/ordering/OrderingParser.g4 +++ b/hibernate-core/src/main/antlr/org/hibernate/grammars/ordering/OrderingParser.g4 @@ -6,10 +6,8 @@ options { @header { /* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.grammars.ordering; diff --git a/hibernate-core/src/main/java/org/hibernate/AnnotationException.java b/hibernate-core/src/main/java/org/hibernate/AnnotationException.java index dcc5bcac42e9..3a011343b672 100644 --- a/hibernate-core/src/main/java/org/hibernate/AnnotationException.java +++ b/hibernate-core/src/main/java/org/hibernate/AnnotationException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/AssertionFailure.java b/hibernate-core/src/main/java/org/hibernate/AssertionFailure.java index 7bc6eaa8460a..fecf27dc1349 100644 --- a/hibernate-core/src/main/java/org/hibernate/AssertionFailure.java +++ b/hibernate-core/src/main/java/org/hibernate/AssertionFailure.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -13,7 +13,6 @@ * @author Gavin King */ public class AssertionFailure extends RuntimeException { - private static final long serialVersionUID = 1L; private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AssertionFailure.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/BaseSessionEventListener.java b/hibernate-core/src/main/java/org/hibernate/BaseSessionEventListener.java index 6d0222d6094e..da7f16b924f9 100644 --- a/hibernate-core/src/main/java/org/hibernate/BaseSessionEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/BaseSessionEventListener.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/BatchSize.java b/hibernate-core/src/main/java/org/hibernate/BatchSize.java index 1c848dc59d13..15b98e7eade7 100644 --- a/hibernate-core/src/main/java/org/hibernate/BatchSize.java +++ b/hibernate-core/src/main/java/org/hibernate/BatchSize.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/Cache.java b/hibernate-core/src/main/java/org/hibernate/Cache.java index e57f6214d836..b257917c44ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/Cache.java +++ b/hibernate-core/src/main/java/org/hibernate/Cache.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/CacheMode.java b/hibernate-core/src/main/java/org/hibernate/CacheMode.java index c7ec5a38eaf8..828b86f9f5d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/CacheMode.java +++ b/hibernate-core/src/main/java/org/hibernate/CacheMode.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/CallbackException.java b/hibernate-core/src/main/java/org/hibernate/CallbackException.java index 02f4814be212..11452f950e9b 100644 --- a/hibernate-core/src/main/java/org/hibernate/CallbackException.java +++ b/hibernate-core/src/main/java/org/hibernate/CallbackException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -8,10 +8,13 @@ * Intended to be thrown from {@link Interceptor} callbacks. * * @implNote This is a legacy exception type from back in the day before - * Hibernate moved to an unchecked exception strategy. + * Hibernate moved to an unchecked exception strategy. + * @deprecated Methods of {@link Interceptor} are no longer required to + * throw this exception type. * * @author Gavin King */ +@Deprecated(since = "7") public class CallbackException extends HibernateException { /** * Creates a CallbackException using the given underlying cause. diff --git a/hibernate-core/src/main/java/org/hibernate/ConnectionAcquisitionMode.java b/hibernate-core/src/main/java/org/hibernate/ConnectionAcquisitionMode.java index 0364eb46daf6..c11a368479d2 100644 --- a/hibernate-core/src/main/java/org/hibernate/ConnectionAcquisitionMode.java +++ b/hibernate-core/src/main/java/org/hibernate/ConnectionAcquisitionMode.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -18,14 +18,15 @@ public enum ConnectionAcquisitionMode { /** * The {@code Connection} will be acquired as soon as a session is opened. *

- * This circumvents the {@link ConnectionReleaseMode}, as the {@code Connection} - * will then be held until the session is closed. + * In this acquisition mode, {@link ConnectionReleaseMode#ON_CLOSE} must be used. */ IMMEDIATELY, /** * A {@code Connection} is acquired only when (and if) it's actually needed. *

* This is the default (and legacy) behavior. + *

+ * In this acquisition mode, any {@link ConnectionReleaseMode} must be used. */ AS_NEEDED; @@ -39,16 +40,13 @@ public static ConnectionAcquisitionMode interpret(Object setting) { if ( setting == null ) { return null; } - - if ( setting instanceof ConnectionAcquisitionMode mode ) { + else if ( setting instanceof ConnectionAcquisitionMode mode ) { return mode; } - - final String value = setting.toString(); - if ( isEmpty( value ) ) { - return null; + else { + final String value = setting.toString(); + return isEmpty( value ) ? null : interpret( value ); } - return interpret( value ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/ConnectionReleaseMode.java b/hibernate-core/src/main/java/org/hibernate/ConnectionReleaseMode.java index fcece90242b9..85bdd3b6beef 100644 --- a/hibernate-core/src/main/java/org/hibernate/ConnectionReleaseMode.java +++ b/hibernate-core/src/main/java/org/hibernate/ConnectionReleaseMode.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -71,21 +71,21 @@ public static ConnectionReleaseMode interpret(Object setting) { if ( setting == null ) { return null; } - - if ( setting instanceof ConnectionReleaseMode mode ) { + else if ( setting instanceof ConnectionReleaseMode mode ) { return mode; } - - final String value = setting.toString(); - if ( isEmpty( value ) ) { - return null; + else { + final String value = setting.toString(); + if ( isEmpty( value ) ) { + return null; + } + // here we disregard "auto" + else if ( value.equalsIgnoreCase( "auto" ) ) { + return null; + } + else { + return parse( value ); + } } - - // here we disregard "auto" - if ( value.equalsIgnoreCase( "auto" ) ) { - return null; - } - - return parse( value ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/CustomEntityDirtinessStrategy.java b/hibernate-core/src/main/java/org/hibernate/CustomEntityDirtinessStrategy.java index c94e8e90f6a1..124e8b06bdf4 100644 --- a/hibernate-core/src/main/java/org/hibernate/CustomEntityDirtinessStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/CustomEntityDirtinessStrategy.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -15,6 +15,40 @@ * since, by default, Hibernate must check each of the entity's attribute values one by one. Sometimes, an * application already has knowledge of an entity's dirtiness and making use of that information would save some * work. This contract allows the application to take over the task of determining if an entity is dirty. + *

+ * For example, the application program might define an interface implemented by entities which keep track of + * their own modified fields: + *

+ * public interface DirtyTracker {
+ *     Set<String> changes();
+ * }
+ * 
+ * Then the following implementation of {@code CustomEntityDirtinessStrategy} would be used: + *
+ * public class DirtyTrackerDirtinessStrategy implements CustomEntityDirtinessStrategy {
+ *     @Override
+ *     public boolean canDirtyCheck(Object entity, EntityPersister persister, Session session) {
+ *         return entity instanceof DirtyTracker;
+ *     }
+ *
+ *     @Override
+ *     public boolean isDirty(Object entity, EntityPersister persister, Session session) {
+ *         return !((DirtyTracker) entity).changes().isEmpty();
+ *     }
+ *
+ *     @Override
+ *     public void resetDirty(Object entity, EntityPersister persister, Session session) {
+ *         ((DirtyTracker) entity).changes().clear();
+ *     }
+ *
+ *     @Override
+ *     public void findDirty(Object entity, EntityPersister persister, Session session, DirtyCheckContext dirtyCheckContext) {
+ *         dirtyCheckContext.doDirtyChecking( attributeInformation ->
+ *                ((DirtyTracker) entity).changes().contains( attributeInformation.getName() ) );
+ *     }
+ * }
+ * 
+ * * * @see org.hibernate.cfg.AvailableSettings#CUSTOM_ENTITY_DIRTINESS_STRATEGY * @see org.hibernate.cfg.Configuration#setCustomEntityDirtinessStrategy(CustomEntityDirtinessStrategy) diff --git a/hibernate-core/src/main/java/org/hibernate/DuplicateMappingException.java b/hibernate-core/src/main/java/org/hibernate/DuplicateMappingException.java index 172eb39408dd..7dbbc3093f57 100644 --- a/hibernate-core/src/main/java/org/hibernate/DuplicateMappingException.java +++ b/hibernate-core/src/main/java/org/hibernate/DuplicateMappingException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/EnabledFetchProfile.java b/hibernate-core/src/main/java/org/hibernate/EnabledFetchProfile.java index a9d7cd21417d..b26ed6b4c48f 100644 --- a/hibernate-core/src/main/java/org/hibernate/EnabledFetchProfile.java +++ b/hibernate-core/src/main/java/org/hibernate/EnabledFetchProfile.java @@ -1,16 +1,57 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; import jakarta.persistence.FindOption; +import org.hibernate.query.SelectionQuery; /** * A {@link jakarta.persistence.FindOption} which requests a named * {@linkplain org.hibernate.annotations.FetchProfile fetch profile}. + *

+ * An instance of this class may be obtained in a type safe way + * from the static metamodel for the class annotated + * {@link org.hibernate.annotations.FetchProfile @FetchProfile}. + *

+ * For example, this class defines a fetch profile: + *

+ * @Entity
+ * @FetchProfile(name = "WithAuthors")
+ * class Book {
+ *     ...
  *
- * @param profileName the {@link org.hibernate.annotations.FetchProfile#name()}
+ *     @ManyToMany
+ *     @FetchProfileOverride(profile = Book_.PROFILE_WITH_AUTHORS)
+ *     Set<Author> authors;
+ * }
+ * 
+ *

+ * An {@code EnabledFetchProfile} may be obtained from the static + * metamodel for the entity {@code Book} and passed as an option to + * {@link Session#find(Class, Object, FindOption...) find()}. + *

+ * Book bookWithAuthors =
+ *         session.find(Book.class, isbn, Book_._WithAuthors)
+ * 
+ * Alternatively, it may be {@linkplain #enable(Session) applied} + * to a {@code Session} or {@code Query}. + *
+ * Book_._WithAuthors.enable(session);
+ * Book bookWithAuthors = session.find(Book.class, isbn);
+ * 
+ *

+ * When the static metamodel is not used, an {@code EnabledFetchProfile} + * may be instantiated directly, passing the name of the fetch profile + * as a string. + *

+ * Book bookWithAuthors =
+ *         session.find(Book.class, isbn,
+ *                      new EnabledFetchProfile("WithAuthors"))
+ * 
+ * + * @param profileName the {@linkplain org.hibernate.annotations.FetchProfile#name profile name} * * @since 7.0 * @@ -21,4 +62,20 @@ */ public record EnabledFetchProfile(String profileName) implements FindOption { + + /** + * Enable the fetch profile represented by this + * object in the given session. + */ + public void enable(Session session) { + session.enableFetchProfile(profileName); + } + + /** + * Enable the fetch profile represented by this + * object during execution of the given query. + */ + public void enable(SelectionQuery query) { + query.enableFetchProfile(profileName); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/EntityFilterException.java b/hibernate-core/src/main/java/org/hibernate/EntityFilterException.java index 0cb30d18f119..a3328c6eb3ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/EntityFilterException.java +++ b/hibernate-core/src/main/java/org/hibernate/EntityFilterException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/EntityNameResolver.java b/hibernate-core/src/main/java/org/hibernate/EntityNameResolver.java index a5a10a66bc0c..91bdb87349f3 100644 --- a/hibernate-core/src/main/java/org/hibernate/EntityNameResolver.java +++ b/hibernate-core/src/main/java/org/hibernate/EntityNameResolver.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/FetchMode.java b/hibernate-core/src/main/java/org/hibernate/FetchMode.java index 64aa7d2f4242..4068c50fa6ff 100644 --- a/hibernate-core/src/main/java/org/hibernate/FetchMode.java +++ b/hibernate-core/src/main/java/org/hibernate/FetchMode.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/FetchNotFoundException.java b/hibernate-core/src/main/java/org/hibernate/FetchNotFoundException.java index af0ca114118d..45b465b39bec 100644 --- a/hibernate-core/src/main/java/org/hibernate/FetchNotFoundException.java +++ b/hibernate-core/src/main/java/org/hibernate/FetchNotFoundException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/Filter.java b/hibernate-core/src/main/java/org/hibernate/Filter.java index a5cdab84b8c6..28d908ba011c 100644 --- a/hibernate-core/src/main/java/org/hibernate/Filter.java +++ b/hibernate-core/src/main/java/org/hibernate/Filter.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/FlushMode.java b/hibernate-core/src/main/java/org/hibernate/FlushMode.java index ad5ba2118079..ead3fc8104a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/FlushMode.java +++ b/hibernate-core/src/main/java/org/hibernate/FlushMode.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/Hibernate.java b/hibernate-core/src/main/java/org/hibernate/Hibernate.java index 7eca767ac5ca..3a641aa739d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/Hibernate.java +++ b/hibernate-core/src/main/java/org/hibernate/Hibernate.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -65,7 +65,7 @@ * delegate. *
  • The proxy does not have the same concrete type as the proxied delegate, and so * {@link #getClass(Object)} must be used in place of {@link Object#getClass()}, - * and this method fetches the entity by side-effect. + * and this method fetches the entity by side effect. *
  • For a polymorphic association, the concrete type of the associated entity is * not known until the delegate is fetched from the database, and so * {@link #unproxy(Object, Class)}} must be used to perform typecasts, and diff --git a/hibernate-core/src/main/java/org/hibernate/HibernateError.java b/hibernate-core/src/main/java/org/hibernate/HibernateError.java index 6bb44c1ab150..9e8c3406ad71 100644 --- a/hibernate-core/src/main/java/org/hibernate/HibernateError.java +++ b/hibernate-core/src/main/java/org/hibernate/HibernateError.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/HibernateException.java b/hibernate-core/src/main/java/org/hibernate/HibernateException.java index 5b3714638a62..33a00f053e1f 100644 --- a/hibernate-core/src/main/java/org/hibernate/HibernateException.java +++ b/hibernate-core/src/main/java/org/hibernate/HibernateException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java index 844bafd4ae28..20c66cf468bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/IdentifierLoadAccess.java @@ -1,13 +1,16 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; import java.util.Optional; +import jakarta.persistence.EntityGraph; + +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; /** * Loads an entity by its primary identifier. @@ -43,6 +46,38 @@ * @see Session#byId(Class) */ public interface IdentifierLoadAccess { + + /** + * Specify the {@linkplain LockMode lock mode} to use when + * querying the database. + * + * @param lockMode The lock mode to apply + * @return {@code this}, for method chaining + */ + default IdentifierLoadAccess with(LockMode lockMode) { + return with( lockMode, PessimisticLockScope.NORMAL ); + } + + /** + * Specify the {@linkplain LockMode lock mode} to use when + * querying the database. + * + * @param lockMode The lock mode to apply + * + * @return {@code this}, for method chaining + */ + IdentifierLoadAccess with(LockMode lockMode, PessimisticLockScope lockScope); + + /** + * Specify the {@linkplain Timeout timeout} to use when + * querying the database. + * + * @param timeout The timeout to apply to the database operation + * + * @return {@code this}, for method chaining + */ + IdentifierLoadAccess with(Timeout timeout); + /** * Specify the {@linkplain LockOptions lock options} to use when * querying the database. @@ -50,7 +85,12 @@ public interface IdentifierLoadAccess { * @param lockOptions The lock options to use * * @return {@code this}, for method chaining + * + * @deprecated Use one of {@linkplain #with(LockMode)}, + * {@linkplain #with(LockMode, PessimisticLockScope)} + * and/or {@linkplain #with(Timeout)} instead. */ + @Deprecated(since = "7.0", forRemoval = true) IdentifierLoadAccess with(LockOptions lockOptions); /** @@ -76,7 +116,7 @@ public interface IdentifierLoadAccess { * * @since 6.3 */ - default IdentifierLoadAccess withFetchGraph(RootGraph graph) { + default IdentifierLoadAccess withFetchGraph(EntityGraph graph) { return with( graph, GraphSemantic.FETCH ); } @@ -87,7 +127,7 @@ default IdentifierLoadAccess withFetchGraph(RootGraph graph) { * * @since 6.3 */ - default IdentifierLoadAccess withLoadGraph(RootGraph graph) { + default IdentifierLoadAccess withLoadGraph(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -95,7 +135,7 @@ default IdentifierLoadAccess withLoadGraph(RootGraph graph) { * @deprecated use {@link #withLoadGraph} */ @Deprecated(since = "6.3") - default IdentifierLoadAccess with(RootGraph graph) { + default IdentifierLoadAccess with(EntityGraph graph) { return withLoadGraph( graph ); } @@ -104,7 +144,7 @@ default IdentifierLoadAccess with(RootGraph graph) { * {@linkplain jakarta.persistence.EntityGraph entity graph}, * and how it should be {@linkplain GraphSemantic interpreted}. */ - IdentifierLoadAccess with(RootGraph graph, GraphSemantic semantic); + IdentifierLoadAccess with(EntityGraph graph, GraphSemantic semantic); /** * Customize the associations fetched by specifying a diff --git a/hibernate-core/src/main/java/org/hibernate/Incubating.java b/hibernate-core/src/main/java/org/hibernate/Incubating.java index 270c4803ca6a..fcb7c731a180 100644 --- a/hibernate-core/src/main/java/org/hibernate/Incubating.java +++ b/hibernate-core/src/main/java/org/hibernate/Incubating.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/InstantiationException.java b/hibernate-core/src/main/java/org/hibernate/InstantiationException.java index d56b58cf15b7..71bba7333425 100644 --- a/hibernate-core/src/main/java/org/hibernate/InstantiationException.java +++ b/hibernate-core/src/main/java/org/hibernate/InstantiationException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/Interceptor.java b/hibernate-core/src/main/java/org/hibernate/Interceptor.java index e40854b2f330..098f0b830e38 100644 --- a/hibernate-core/src/main/java/org/hibernate/Interceptor.java +++ b/hibernate-core/src/main/java/org/hibernate/Interceptor.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -39,11 +39,18 @@ * Whichever approach is used, the interceptor must be serializable for the * {@code Session} to be serializable. This means that {@code SessionFactory}-scoped * interceptors should implement {@code readResolve()}. - *

    - * This venerable callback interface, dating to the very earliest days of Hibernate, - * competes with JPA entity listener callbacks: {@link jakarta.persistence.PostLoad}, - * {@link jakarta.persistence.PrePersist} {@link jakarta.persistence.PreUpdate}, and - * {@link jakarta.persistence.PreRemove}. + * + * @apiNote This venerable callback interface, dating from the very earliest days of + * Hibernate, competes with standard JPA entity listener callbacks: + * {@link jakarta.persistence.PostLoad}, {@link jakarta.persistence.PrePersist}, + * {@link jakarta.persistence.PreUpdate}, and {@link jakarta.persistence.PreRemove}. + * However, JPA callbacks do not provide the ability to access the previous + * value of an updated property in a {@code @PreUpdate} callback, and do not + * provide a well-defined way to intercept changes to collections. + *

    + * Note that this API exposes the interface {@link Type}, which in modern + * versions of Hibernate is considered an SPI. This is unfortunate, and might + * change in the future, but is bearable for now. * * @see SessionBuilder#interceptor(Interceptor) * @see SharedSessionBuilder#interceptor() @@ -69,11 +76,8 @@ public interface Interceptor { * @param types The types of the entity properties, corresponding to the {@code state}. * * @return {@code true} if the user modified the {@code state} in any way. - * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. */ - default boolean onLoad(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) - throws CallbackException { + default boolean onLoad(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) { return false; } @@ -91,13 +95,10 @@ default boolean onLoad(Object entity, Object id, Object[] state, String[] proper * * @return {@code true} if the user modified the {@code state} in any way. * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. - * * @see Session#persist(Object) * @see Session#merge(Object) */ - default boolean onPersist(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) - throws CallbackException { + default boolean onPersist(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) { return onSave(entity, id, state, propertyNames, types); } @@ -112,12 +113,9 @@ default boolean onPersist(Object entity, Object id, Object[] state, String[] pro * @param propertyNames The names of the entity properties. * @param types The types of the entity properties * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. - * * @see Session#remove(Object) */ - default void onRemove(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) - throws CallbackException { + default void onRemove(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) { onDelete(entity, id, state, propertyNames, types); } @@ -140,8 +138,6 @@ default void onRemove(Object entity, Object id, Object[] state, String[] propert * * @return {@code true} if the user modified the {@code currentState} in any way. * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. - * * @see Session#flush() */ default boolean onFlushDirty( @@ -150,7 +146,7 @@ default boolean onFlushDirty( Object[] currentState, Object[] previousState, String[] propertyNames, - Type[] types) throws CallbackException { + Type[] types) { return false; } @@ -168,16 +164,13 @@ default boolean onFlushDirty( * * @return {@code true} if the user modified the {@code state} in any way. * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. - * * @see Session#persist(Object) * @see Session#merge(Object) * * @deprecated Use {@link #onPersist(Object, Object, Object[], String[], Type[])} */ @Deprecated(since = "6.6") - default boolean onSave(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) - throws CallbackException { + default boolean onSave(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) { return false; } @@ -192,15 +185,12 @@ default boolean onSave(Object entity, Object id, Object[] state, String[] proper * @param propertyNames The names of the entity properties. * @param types The types of the entity properties * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. - * * @see Session#remove(Object) * * @deprecated Use {@link #onRemove(Object, Object, Object[], String[], Type[])} */ @Deprecated(since = "6.6") - default void onDelete(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) - throws CallbackException { + default void onDelete(Object entity, Object id, Object[] state, String[] propertyNames, Type[] types) { } /** @@ -208,10 +198,8 @@ default void onDelete(Object entity, Object id, Object[] state, String[] propert * * @param collection The collection instance. * @param key The collection key value. - * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. */ - default void onCollectionRecreate(Object collection, Object key) throws CallbackException { + default void onCollectionRecreate(Object collection, Object key) { } /** @@ -219,10 +207,8 @@ default void onCollectionRecreate(Object collection, Object key) throws Callback * * @param collection The collection instance. * @param key The collection key value. - * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. */ - default void onCollectionRemove(Object collection, Object key) throws CallbackException { + default void onCollectionRemove(Object collection, Object key) { } /** @@ -230,49 +216,49 @@ default void onCollectionRemove(Object collection, Object key) throws CallbackEx * * @param collection The collection instance. * @param key The collection key value. - * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. */ - default void onCollectionUpdate(Object collection, Object key) throws CallbackException { + default void onCollectionUpdate(Object collection, Object key) { } + /** * Called before a flush. * * @param entities The entities to be flushed. - * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. */ - default void preFlush(Iterator entities) throws CallbackException {} + default void preFlush(Iterator entities) {} /** - * Called after a flush that actually ends in execution of the SQL statements required to synchronize - * in-memory state with the database. + * Called after a flush that actually ends in execution of the SQL statements + * required to synchronize in-memory state with the database. * * @param entities The entities that were flushed. - * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. */ - default void postFlush(Iterator entities) throws CallbackException {} + default void postFlush(Iterator entities) {} /** - * Called to distinguish between transient and detached entities. The return value determines the - * state of the entity with respect to the current session. + * Called to distinguish between transient and detached entities. The return + * value determines the state of the entity with respect to the current session. + * This method should return: *
      - *
    • {@code Boolean.TRUE} - the entity is transient - *
    • {@code Boolean.FALSE} - the entity is detached - *
    • {@code null} - Hibernate uses the {@code unsaved-value} mapping and other heuristics to - * determine if the object is unsaved + *
    • {@code Boolean.TRUE} if the entity is transient, + *
    • {@code Boolean.FALSE} if the entity is detached, or + *
    • {@code null} to signal that the usual heuristics should be used to determine + * if the instance is transient *
    + * Heuristics used when this method returns null are based on the value of the + * {@linkplain jakarta.persistence.GeneratedValue generated} id field, or the + * {@linkplain jakarta.persistence.Version version} field, if any. * * @param entity a transient or detached entity - * @return Boolean or {@code null} to choose default behaviour + * @return {@link Boolean} or {@code null} to choose default behaviour */ default Boolean isTransient(Object entity) { return null; } /** - * Called from {@code flush()}. The return value determines whether the entity is updated + * Called from {@code flush()}. The return value determines whether the entity + * is updated *
      *
    • an array of property indices - the entity is dirty *
    • an empty array - the entity is not dirty @@ -282,13 +268,13 @@ default Boolean isTransient(Object entity) { * @param entity The entity for which to find dirty properties. * @param id The identifier of the entity * @param currentState The current entity state as taken from the entity instance - * @param previousState The state of the entity when it was last synchronized (generally when it was loaded) + * @param previousState The state of the entity when it was last synchronized + * (generally when it was loaded) * @param propertyNames The names of the entity properties. * @param types The types of the entity properties * - * @return array of dirty property indices or {@code null} to indicate Hibernate should perform default behaviour - * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. + * @return array of dirty property indices or {@code null} to indicate Hibernate + * should perform default behaviour */ default int[] findDirty( Object entity, @@ -301,26 +287,26 @@ default int[] findDirty( } /** - * Instantiate the entity. Return {@code null} to indicate that Hibernate should use - * the default constructor of the class. The identifier property of the returned instance - * should be initialized with the given identifier. + * Instantiate the entity. Return {@code null} to indicate that Hibernate should + * use the default constructor of the class. The identifier property of the + * returned instance should be initialized with the given identifier. */ default Object instantiate( String entityName, EntityRepresentationStrategy representationStrategy, - Object id) throws CallbackException { + Object id) { return instantiate( entityName, representationStrategy.getMode(), id ); } /** - * Instantiate the entity. Return {@code null} to indicate that Hibernate should use - * the default constructor of the class. The identifier property of the returned instance - * should be initialized with the given identifier. + * Instantiate the entity. Return {@code null} to indicate that Hibernate should + * use the default constructor of the class. The identifier property of the + * returned instance should be initialized with the given identifier. */ default Object instantiate( String entityName, RepresentationMode representationMode, - Object id) throws CallbackException { + Object id) { return null; } @@ -331,11 +317,9 @@ default Object instantiate( * * @return the name of the entity * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. - * * @see EntityNameResolver */ - default String getEntityName(Object object) throws CallbackException { + default String getEntityName(Object object) { return null; } @@ -346,17 +330,16 @@ default String getEntityName(Object object) throws CallbackException { * @param id the instance identifier * * @return a fully initialized entity - * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. */ - default Object getEntity(String entityName, Object id) throws CallbackException { + default Object getEntity(String entityName, Object id) { return null; } /** - * Called when a Hibernate transaction is begun via the Hibernate {@code Transaction} - * API. Will not be called if transactions are being controlled via some other - * mechanism (CMT, for example). + * Called when a Hibernate transaction is begun via the JPA-standard + * {@link jakarta.persistence.EntityTransaction} API, or via {@link Transaction}. + * This method is not be called if transactions are being controlled via some + * other mechanism, for example, if transactions are managed by a container. * * @param tx The Hibernate transaction facade object */ @@ -385,8 +368,6 @@ default void afterTransactionCompletion(Transaction tx) {} * @param propertyNames The names of the entity properties. * @param propertyTypes The types of the entity properties * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. - * * @see StatelessSession#insert(Object) */ default void onInsert(Object entity, Object id, Object[] state, String[] propertyNames, Type[] propertyTypes) {} @@ -397,11 +378,9 @@ default void onInsert(Object entity, Object id, Object[] state, String[] propert * @param entity The entity instance being deleted * @param id The identifier of the entity * @param state The entity state - * @param propertyNames The names of the entity properties. + * @param propertyNames The names of the entity properties * @param propertyTypes The types of the entity properties * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. - * * @see StatelessSession#update(Object) */ default void onUpdate(Object entity, Object id, Object[] state, String[] propertyNames, Type[] propertyTypes) {} @@ -412,11 +391,9 @@ default void onUpdate(Object entity, Object id, Object[] state, String[] propert * @param entity The entity instance being deleted * @param id The identifier of the entity * @param state The entity state - * @param propertyNames The names of the entity properties. + * @param propertyNames The names of the entity properties * @param propertyTypes The types of the entity properties * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. - * * @see StatelessSession#upsert(String, Object) */ default void onUpsert(Object entity, Object id, Object[] state, String[] propertyNames, Type[] propertyTypes) {} @@ -426,12 +403,49 @@ default void onUpsert(Object entity, Object id, Object[] state, String[] propert * * @param entity The entity instance being deleted * @param id The identifier of the entity - * @param propertyNames The names of the entity properties. + * @param propertyNames The names of the entity properties * @param propertyTypes The types of the entity properties * - * @throws CallbackException Thrown if the interceptor encounters any problems handling the callback. - * * @see StatelessSession#delete(Object) */ default void onDelete(Object entity, Object id, String[] propertyNames, Type[] propertyTypes) {} + + /** + * Called before copying the state of a merged entity to a managed entity + * belonging to the persistence context of a stateful {@link Session}. + *

      + * The interceptor may modify the {@code state}. + * + * @param entity The entity passed to {@code merge()} + * @param state The state of the entity passed to {@code merge()} + * @param propertyNames The names of the entity properties + * @param propertyTypes The types of the entity properties + * + * @since 7.1 + */ + @Incubating + default void preMerge(Object entity, Object[] state, String[] propertyNames, Type[] propertyTypes) {} + + /** + * Called after copying the state of a merged entity to a managed entity + * belonging to the persistence context of a stateful {@link Session}. + *

      + * Modification of the {@code sourceState} or {@code targetState} has no effect. + * + * @param source The entity passed to {@code merge()} + * @param target The target managed entity + * @param id The identifier of the managed entity + * @param targetState The copied state already assigned to the target managed entity + * @param originalState The original state of the target managed entity before assignment of the copied state, + * or {@code null} if the target entity is a new instance + * @param propertyNames The names of the entity properties + * @param propertyTypes The types of the entity properties + * + * @since 7.1 + */ + @Incubating + default void postMerge( + Object source, Object target, Object id, + Object[] targetState, Object[] originalState, + String[] propertyNames, Type[] propertyTypes) {} } diff --git a/hibernate-core/src/main/java/org/hibernate/Internal.java b/hibernate-core/src/main/java/org/hibernate/Internal.java index a53e4ff17b54..ffe1dea3d64a 100644 --- a/hibernate-core/src/main/java/org/hibernate/Internal.java +++ b/hibernate-core/src/main/java/org/hibernate/Internal.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java b/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java index eddb54ea6f02..5076db8fd457 100644 --- a/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java +++ b/hibernate-core/src/main/java/org/hibernate/InvalidMappingException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/JDBCException.java b/hibernate-core/src/main/java/org/hibernate/JDBCException.java index 0f6448a62719..b98cc90b9661 100644 --- a/hibernate-core/src/main/java/org/hibernate/JDBCException.java +++ b/hibernate-core/src/main/java/org/hibernate/JDBCException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/LazyInitializationException.java b/hibernate-core/src/main/java/org/hibernate/LazyInitializationException.java index afdf2abc1882..775761898d45 100644 --- a/hibernate-core/src/main/java/org/hibernate/LazyInitializationException.java +++ b/hibernate-core/src/main/java/org/hibernate/LazyInitializationException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -19,6 +19,8 @@ * * @see Hibernate#initialize(Object) * @see Hibernate#isInitialized(Object) + * @see StatelessSession#fetch(Object) + * * @author Gavin King */ public class LazyInitializationException extends HibernateException { diff --git a/hibernate-core/src/main/java/org/hibernate/Length.java b/hibernate-core/src/main/java/org/hibernate/Length.java index 71724ba37732..9de8cb04653b 100644 --- a/hibernate-core/src/main/java/org/hibernate/Length.java +++ b/hibernate-core/src/main/java/org/hibernate/Length.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/LobHelper.java b/hibernate-core/src/main/java/org/hibernate/LobHelper.java index 6ee3da32488f..f311a8fa80ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/LobHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/LobHelper.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/LockMode.java b/hibernate-core/src/main/java/org/hibernate/LockMode.java index 16a565fa6581..7e103adad675 100644 --- a/hibernate-core/src/main/java/org/hibernate/LockMode.java +++ b/hibernate-core/src/main/java/org/hibernate/LockMode.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -38,8 +38,10 @@ * @author Gavin King * * @see Session#lock(Object, LockMode) + * @see Session#lock(Object, LockMode, jakarta.persistence.LockOption...) + * @see Session#find(Class, Object, FindOption...) + * @see Session#refresh(Object, RefreshOption...) * @see LockModeType - * @see LockOptions * @see org.hibernate.annotations.OptimisticLocking */ public enum LockMode implements FindOption, RefreshOption { @@ -50,7 +52,7 @@ public enum LockMode implements FindOption, RefreshOption { * rather than pull it from a cache. *

      * This is the "default" lock mode, the mode requested by calling - * {@link Session#get(Class, Object)} without passing an explicit + * {@link Session#find(Class, Object)} without passing an explicit * mode. It permits the state of an object to be retrieved from * the cache without the cost of database access. * @@ -103,7 +105,7 @@ public enum LockMode implements FindOption, RefreshOption { *

      * This lock mode is for internal use only and is not a legal * argument to {@link Session#get(Class, Object, LockMode)}, - * {@link Session#refresh(Object, LockMode)}, or + * {@link Session#refresh(Object, RefreshOption...)}, or * {@link Session#lock(Object, LockMode)}. These methods throw * an exception if {@code WRITE} is given as an argument. *

      @@ -113,25 +115,6 @@ public enum LockMode implements FindOption, RefreshOption { @Internal WRITE, - /** - * A pessimistic upgrade lock, obtained using an Oracle-style - * {@code select for update nowait}. The semantics of this - * lock mode, if the lock is successfully obtained, are the same - * as {@link #PESSIMISTIC_WRITE}. If the lock is not immediately - * available, an exception occurs. - */ - UPGRADE_NOWAIT, - - /** - * A pessimistic upgrade lock, obtained using an Oracle-style - * {@code select for update skip locked}. The semantics of this - * lock mode, if the lock is successfully obtained, are the same - * as {@link #PESSIMISTIC_WRITE}. But if the lock is not - * immediately available, no exception occurs, but the locked - * row is not returned from the database. - */ - UPGRADE_SKIPLOCKED, - /** * A pessimistic shared lock, which prevents concurrent * transactions from writing the locked object. Obtained via @@ -164,7 +147,34 @@ public enum LockMode implements FindOption, RefreshOption { * * @see LockModeType#PESSIMISTIC_FORCE_INCREMENT */ - PESSIMISTIC_FORCE_INCREMENT; + PESSIMISTIC_FORCE_INCREMENT, + + /** + * A pessimistic upgrade lock, obtained using an Oracle-style + * {@code select for update nowait}. The semantics of this + * lock mode, if the lock is successfully obtained, are the same + * as {@link #PESSIMISTIC_WRITE}. If the lock is not immediately + * available, an exception occurs. + * + * @apiNote To be removed in a future version. A different approach to + * specifying handling for locked rows will be introduced. + */ + @Remove + UPGRADE_NOWAIT, + + /** + * A pessimistic upgrade lock, obtained using an Oracle-style + * {@code select for update skip locked}. The semantics of this + * lock mode, if the lock is successfully obtained, are the same + * as {@link #PESSIMISTIC_WRITE}. But if the lock is not + * immediately available, no exception occurs, but the locked + * row is not returned from the database. + * + * @apiNote To be removed in a future version. A different approach to + * specifying handling for locked rows will be introduced. + */ + @Remove + UPGRADE_SKIPLOCKED; /** * @return an instance with the same semantics as the given JPA @@ -273,9 +283,11 @@ public static LockMode fromExternalForm(String externalForm) { } /** - * @return an instance of {@link LockOptions} with this lock mode, and - * all other settings defaulted. + * @return an instance of {@link LockOptions} with this lock mode, and all other settings defaulted. + * + * @deprecated As LockOptions will become an SPI, this method will be removed with no replacement */ + @Deprecated(since = "7", forRemoval = true) public LockOptions toLockOptions() { return switch (this) { case NONE -> LockOptions.NONE; diff --git a/hibernate-core/src/main/java/org/hibernate/LockOptions.java b/hibernate-core/src/main/java/org/hibernate/LockOptions.java index c90feab563fd..c428773a52be 100644 --- a/hibernate-core/src/main/java/org/hibernate/LockOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/LockOptions.java @@ -1,9 +1,12 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; + import java.io.Serializable; import java.util.HashMap; import java.util.Iterator; @@ -12,11 +15,6 @@ import java.util.Objects; import java.util.Set; -import jakarta.persistence.FindOption; -import jakarta.persistence.PessimisticLockScope; -import jakarta.persistence.RefreshOption; -import org.hibernate.query.Query; - import static jakarta.persistence.PessimisticLockScope.NORMAL; import static java.util.Collections.emptySet; import static java.util.Collections.unmodifiableSet; @@ -29,9 +27,9 @@ * {@link Session#refresh(Object, LockOptions)}, the relevant options * are: *

        - *
      • the {@linkplain #getLockMode() lock mode}, - *
      • the {@linkplain #getTimeOut() pessimistic lock timeout}, and - *
      • the {@linkplain #getLockScope() lock scope}, that is, whether + *
      • the {@linkplain #getLockMode lock mode}, + *
      • the {@linkplain #getTimeOut pessimistic lock timeout}, and + *
      • the {@linkplain #getLockScope lock scope}, that is, whether * the lock extends to rows of owned collections. *
      *

      @@ -49,120 +47,72 @@ * default behavior of the SQL dialect} by passing a non-null argument * to {@link #setFollowOnLocking(Boolean)}. * + * @deprecated + * Since JPA 3.2 and Hibernate 7, a {@link LockMode}, {@link Timeout}, + * or {@link PessimisticLockScope} may be passed directly as an option + * to {@code find()}, {@code refresh()}, or {@code lock()}. Therefore, + * this class is obsolete as an API and will be moved to an SPI package. + *

      + * For HQL/JPQL queries, locking should be controlled via operations of + * the {@link org.hibernate.query.SelectionQuery} interface: + *

        + *
      • A timeout may be set via + * {@link org.hibernate.query.CommonQueryContract#setTimeout(Timeout)} + *
      • The {@code PessimisticLockScope} may be set using + * {@link org.hibernate.query.SelectionQuery#setLockScope(PessimisticLockScope)} + *
      • Alias-specific lock modes may be specified using + * {@link org.hibernate.query.SelectionQuery#setLockMode(String, LockMode)} + *
      • Use of follow-on locking may be enabled via + * {@link org.hibernate.query.SelectionQuery#setFollowOnLocking(boolean)} + *
      + * The interface {@link Timeouts} provides several operations to simplify + * migration. + * + * @see Timeout + * @see Timeouts + * @see LockMode + * @see jakarta.persistence.LockModeType + * @see PessimisticLockScope + * * @author Scott Marlow */ -public class LockOptions implements FindOption, RefreshOption, Serializable { - /** - * Represents {@link LockMode#NONE}, to which timeout and scope are - * not applicable. - */ - public static final LockOptions NONE = new LockOptions( true, LockMode.NONE ); - - /** - * Represents {@link LockMode#READ}, to which timeout and scope are - * not applicable. - */ - public static final LockOptions READ = new LockOptions( true, LockMode.READ ); - - /** - * Represents {@link LockMode#OPTIMISTIC}. - */ - static final LockOptions OPTIMISTIC = new LockOptions( true, LockMode.OPTIMISTIC ); - - /** - * Represents {@link LockMode#OPTIMISTIC_FORCE_INCREMENT}, to which - * timeout and scope are not applicable. - */ - static final LockOptions OPTIMISTIC_FORCE_INCREMENT = new LockOptions( true, LockMode.OPTIMISTIC_FORCE_INCREMENT ); - - /** - * Represents {@link LockMode#PESSIMISTIC_READ}. - */ - static final LockOptions PESSIMISTIC_READ = new LockOptions( true, LockMode.PESSIMISTIC_READ ); - - /** - * Represents {@link LockMode#PESSIMISTIC_WRITE}. - */ - static final LockOptions PESSIMISTIC_WRITE = new LockOptions( true, LockMode.PESSIMISTIC_WRITE ); - - /** - * Represents {@link LockMode#PESSIMISTIC_FORCE_INCREMENT}. - */ - static final LockOptions PESSIMISTIC_FORCE_INCREMENT = new LockOptions( true, LockMode.PESSIMISTIC_FORCE_INCREMENT ); - - /** - * Represents {@link LockMode#UPGRADE_NOWAIT}. - */ - static final LockOptions UPGRADE_NOWAIT = new LockOptions( true, LockMode.UPGRADE_NOWAIT ); - - /** - * Represents {@link LockMode#UPGRADE_SKIPLOCKED}. - */ - static final LockOptions UPGRADE_SKIPLOCKED = new LockOptions( true, LockMode.UPGRADE_SKIPLOCKED ); - - /** - * Represents {@link LockMode#PESSIMISTIC_WRITE} with - * {@linkplain #WAIT_FOREVER no timeout}, and - * {@linkplain PessimisticLockScope#NORMAL no extension of the - * lock to owned collections}. - */ - public static final LockOptions UPGRADE = PESSIMISTIC_WRITE; - - /** - * Indicates that the database should not wait at all to acquire - * a pessimistic lock which is not immediately available. This - * has the same effect as {@link LockMode#UPGRADE_NOWAIT}. - * - * @see #getTimeOut - */ - public static final int NO_WAIT = 0; - - /** - * Indicates that there is no timeout for the lock acquisition, - * that is, that the database should in principle wait forever - * to obtain the lock. - * - * @see #getTimeOut - */ - public static final int WAIT_FOREVER = -1; - - /** - * Indicates that rows which are already locked should be skipped. - * - * @see #getTimeOut() - * @deprecated use {@link LockMode#UPGRADE_SKIPLOCKED} - */ - @Deprecated - public static final int SKIP_LOCKED = -2; +@Deprecated(since = "7", forRemoval = true) // moving to an SPI package +public class LockOptions implements Serializable { private final boolean immutable; private LockMode lockMode; - private int timeout; + private Timeout timeout; private PessimisticLockScope pessimisticLockScope; private Boolean followOnLocking; + private Map aliasSpecificLockModes; /** * Construct an instance with mode {@link LockMode#NONE} and - * timeout {@link #WAIT_FOREVER}. + * no timeout. + * + * @see LockMode#NONE + * @see Timeouts#WAIT_FOREVER */ public LockOptions() { immutable = false; lockMode = LockMode.NONE; - timeout = WAIT_FOREVER; + timeout = Timeouts.WAIT_FOREVER; pessimisticLockScope = NORMAL; } /** * Construct an instance with the given {@linkplain LockMode mode} - * and {@link #WAIT_FOREVER}. + * and no timeout. * * @param lockMode The initial lock mode + * + * @see Timeouts#WAIT_FOREVER */ public LockOptions(LockMode lockMode) { immutable = false; this.lockMode = lockMode; - timeout = WAIT_FOREVER; + timeout = Timeouts.WAIT_FOREVER; pessimisticLockScope = NORMAL; } @@ -171,9 +121,9 @@ public LockOptions(LockMode lockMode) { * and timeout. * * @param lockMode The initial lock mode - * @param timeout The initial timeout + * @param timeout The initial timeout, in milliseconds */ - public LockOptions(LockMode lockMode, int timeout) { + public LockOptions(LockMode lockMode, Timeout timeout) { immutable = false; this.lockMode = lockMode; this.timeout = timeout; @@ -182,13 +132,13 @@ public LockOptions(LockMode lockMode, int timeout) { /** * Construct an instance with the given {@linkplain LockMode mode}, - * timeout, and {@link PessimisticLockScope scope}. + * timeout, and {@linkplain PessimisticLockScope scope}. * * @param lockMode The initial lock mode * @param timeout The initial timeout * @param scope The initial lock scope */ - public LockOptions(LockMode lockMode, int timeout, PessimisticLockScope scope) { + public LockOptions(LockMode lockMode, Timeout timeout, PessimisticLockScope scope) { immutable = false; this.lockMode = lockMode; this.timeout = timeout; @@ -198,21 +148,54 @@ public LockOptions(LockMode lockMode, int timeout, PessimisticLockScope scope) { /** * Internal operation used to create immutable global instances. */ - private LockOptions(boolean immutable, LockMode lockMode) { + protected LockOptions(boolean immutable, LockMode lockMode) { this.immutable = immutable; this.lockMode = lockMode; - timeout = WAIT_FOREVER; + timeout = Timeouts.WAIT_FOREVER; pessimisticLockScope = NORMAL; } + + + /** + * Construct an instance with the given {@linkplain LockMode mode} + * and timeout. + * + * @param lockMode The initial lock mode + * @param timeout The initial timeout, in milliseconds + * + * @deprecated Use {@linkplain #LockOptions(LockMode, Timeout)} instead + */ + @Deprecated(since = "7.0") + public LockOptions(LockMode lockMode, int timeout) { + this( lockMode, Timeouts.interpretMilliSeconds( timeout ) ); + } + + + /** + * Construct an instance with the given {@linkplain LockMode mode}, + * timeout, and {@linkplain PessimisticLockScope scope}. + * + * @param lockMode The initial lock mode + * @param timeout The initial timeout, in milliseconds + * @param scope The initial lock scope + * + * @deprecated Use {@linkplain #LockOptions(LockMode, Timeout, PessimisticLockScope)} instead + */ + @Deprecated(since = "7.0") + public LockOptions(LockMode lockMode, int timeout, PessimisticLockScope scope) { + this( lockMode, Timeouts.interpretMilliSeconds( timeout ), scope ); + } + /** - * Determine of the lock options are empty. + * Whether this {@code LockOptions} instance is "empty", meaning + * it has any non-default values set (which is the same as * * @return {@code true} if the lock options are equivalent to - * {@link LockOptions#NONE}. + * {@link org.hibernate.LockOptions#NONE}. */ public boolean isEmpty() { return lockMode == LockMode.NONE - && timeout == WAIT_FOREVER + && timeout == Timeouts.WAIT_FOREVER && followOnLocking == null && pessimisticLockScope == NORMAL && !hasAliasSpecificLockModes(); @@ -243,137 +226,33 @@ public LockOptions setLockMode(LockMode lockMode) { } /** - * Specify the {@link LockMode} to be used for the given query alias. - * - * @param alias the query alias to which the lock mode applies - * @param lockMode the lock mode to apply to the given alias - * @return {@code this} for method chaining - * - * @see Query#setLockMode(String, LockMode) - */ - public LockOptions setAliasSpecificLockMode(String alias, LockMode lockMode) { - if ( immutable ) { - throw new UnsupportedOperationException("immutable global instance of LockOptions"); - } - if ( aliasSpecificLockModes == null ) { - aliasSpecificLockModes = new LinkedHashMap<>(); - } - if ( lockMode == null ) { - aliasSpecificLockModes.remove( alias ); - } - else { - aliasSpecificLockModes.put( alias, lockMode ); - } - return this; - } - - /** - * Get the {@link LockMode} explicitly specified for the given alias - * via {@link #setAliasSpecificLockMode(String, LockMode)}. - *

      - * Differs from {@link #getEffectiveLockMode(String)} in that here we - * only return an explicitly specified alias-specific lock mode. - * - * @param alias The alias for which to locate the explicit lock mode. - * @return The explicit lock mode for that alias. - */ - public LockMode getAliasSpecificLockMode(String alias) { - return aliasSpecificLockModes == null ? null : aliasSpecificLockModes.get( alias ); - } - - /** - * Determine the {@link LockMode} to apply to the given alias. If no - * mode was {@linkplain #setAliasSpecificLockMode(String, LockMode)} - * explicitly set}, the {@linkplain #getLockMode()} overall mode} is - * returned. If the overall lock mode is also {@code null}, - * {@link LockMode#NONE} is returned. - *

      - * Differs from {@link #getAliasSpecificLockMode(String)} in that here - * we fall back to only returning the overall lock mode. - * - * @param alias The alias for which to locate the effective lock mode. - * @return The effective lock mode. + * The timeout associated with {@code this} options, defining a maximum + * amount of time that the database should wait to obtain a pessimistic + * lock before returning an error to the client. */ - public LockMode getEffectiveLockMode(String alias) { - LockMode lockMode = getAliasSpecificLockMode( alias ); - if ( lockMode == null ) { - lockMode = this.lockMode; - } - return lockMode == null ? LockMode.NONE : lockMode; - } - - /** - * Does this {@code LockOptions} instance define alias-specific lock - * modes? - * - * @return {@code true} if this object defines alias-specific lock modes; - * {@code false} otherwise. - */ - public boolean hasAliasSpecificLockModes() { - return aliasSpecificLockModes != null && !aliasSpecificLockModes.isEmpty(); - } - - /** - * The number of aliases that have alias-specific lock modes specified. - * - * @return the number of explicitly defined alias lock modes. - */ - public int getAliasLockCount() { - return aliasSpecificLockModes == null ? 0 : aliasSpecificLockModes.size(); - } - - /** - * Iterator over {@link Map.Entry}s, each containing an alias and its - * {@link LockMode}. - * - * @return an iterator over the {@link Map.Entry}s - * @deprecated use {@link #getAliasSpecificLocks()} - */ - @Deprecated - public Iterator> getAliasLockIterator() { - return getAliasSpecificLocks().iterator(); + public Timeout getTimeout() { + return timeout; } /** - * Set of {@link Map.Entry}s, each associating an alias with its - * specified {@linkplain #setAliasSpecificLockMode alias-specific} - * {@link LockMode}. + * Set the {@linkplain #getTimeout() timeout} associated with {@code this} options. * - * @return an iterable with the {@link Map.Entry}s - */ - public Set> getAliasSpecificLocks() { - return aliasSpecificLockModes == null ? emptySet() : unmodifiableSet( aliasSpecificLockModes.entrySet() ); - } - - /** - * Currently needed for follow-on locking. + * @return {@code this} for method chaining * - * @return The greatest of all requested lock modes. + * @see #getTimeout() */ - public LockMode findGreatestLockMode() { - LockMode lockModeToUse = getLockMode(); - if ( lockModeToUse == null ) { - lockModeToUse = LockMode.NONE; - } - - if ( aliasSpecificLockModes == null ) { - return lockModeToUse; - } - - for ( LockMode lockMode : aliasSpecificLockModes.values() ) { - if ( lockMode.greaterThan( lockModeToUse ) ) { - lockModeToUse = lockMode; - } + public LockOptions setTimeout(Timeout timeout) { + if ( immutable ) { + throw new UnsupportedOperationException("immutable global instance of LockMode"); } - - return lockModeToUse; + this.timeout = timeout; + return this; } /** - * The current timeout, a maximum amount of time in milliseconds - * that the database should wait to obtain a pessimistic lock before - * returning an error to the client. - *

      + * The {@linkplain #getTimeout() timeout}, in milliseconds, associated + * with {@code this} options. + *

      * {@link #NO_WAIT}, {@link #WAIT_FOREVER}, or {@link #SKIP_LOCKED} * represent 3 "magic" values. * @@ -381,28 +260,22 @@ public LockMode findGreatestLockMode() { * {@link #WAIT_FOREVER}, or {@link #SKIP_LOCKED} */ public int getTimeOut() { - return timeout; + return getTimeout().milliseconds(); } /** - * Set the timeout, that is, the maximum amount of time in milliseconds - * that the database should wait to obtain a pessimistic lock before - * returning an error to the client. - *

      + * Set the {@linkplain #getTimeout() timeout}, in milliseconds, associated + * with {@code this} options. + *

      * {@link #NO_WAIT}, {@link #WAIT_FOREVER}, or {@link #SKIP_LOCKED} * represent 3 "magic" values. * - * @param timeout the new timeout setting, in milliseconds * @return {@code this} for method chaining * * @see #getTimeOut */ public LockOptions setTimeOut(int timeout) { - if ( immutable ) { - throw new UnsupportedOperationException("immutable global instance of LockMode"); - } - this.timeout = timeout; - return this; + return setTimeout( Timeouts.interpretMilliSeconds( timeout ) ); } /** @@ -557,4 +430,275 @@ else if ( !(object instanceof LockOptions that) ) { public int hashCode() { return Objects.hash( lockMode, timeout, aliasSpecificLockModes, followOnLocking, pessimisticLockScope ); } + + /** + * Set of {@link Map.Entry}s, each associating an alias with its + * specified {@linkplain #setAliasSpecificLockMode alias-specific} + * {@link LockMode}. + * + * @return an iterable with the {@link Map.Entry}s + * + * @apiNote This will be removed in 7.1 and replaced with an extension + * to JPA's {@linkplain PessimisticLockScope} + */ + @Remove + public Set> getAliasSpecificLocks() { + return aliasSpecificLockModes == null ? emptySet() : unmodifiableSet( aliasSpecificLockModes.entrySet() ); + } + + /** + * Specify the {@link LockMode} to be used for the given query alias. + * + * @param alias the query alias to which the lock mode applies + * @param lockMode the lock mode to apply to the given alias + * @return {@code this} for method chaining + * + * @see org.hibernate.query.Query#setLockMode(String, LockMode) + * + * @apiNote This will be removed in 7.1 and replaced with an extension + * to JPA's {@linkplain PessimisticLockScope} + */ + @Remove + public LockOptions setAliasSpecificLockMode(String alias, LockMode lockMode) { + if ( immutable ) { + throw new UnsupportedOperationException("immutable global instance of LockOptions"); + } + if ( aliasSpecificLockModes == null ) { + aliasSpecificLockModes = new LinkedHashMap<>(); + } + if ( lockMode == null ) { + aliasSpecificLockModes.remove( alias ); + } + else { + aliasSpecificLockModes.put( alias, lockMode ); + } + return this; + } + + /** + * The number of aliases that have alias-specific lock modes specified. + * + * @return the number of explicitly defined alias lock modes. + * + * @apiNote This will be removed in 7.1 and replaced with an extension + * to JPA's {@linkplain PessimisticLockScope} + */ + @Remove + public int getAliasLockCount() { + return aliasSpecificLockModes == null ? 0 : aliasSpecificLockModes.size(); + } + + /** + * Whether this {@code LockOptions} instance defines alias-specific lock-modes + * + * @return {@code true} if this object defines alias-specific lock modes; + * {@code false} otherwise. + * + * @apiNote This will be removed in 7.1 and replaced with an extension + * to JPA's {@linkplain PessimisticLockScope} + */ + @Remove + public boolean hasAliasSpecificLockModes() { + return aliasSpecificLockModes != null && !aliasSpecificLockModes.isEmpty(); + } + + /** + * Get the {@link LockMode} explicitly specified for the given alias + * via {@link #setAliasSpecificLockMode(String, LockMode)}. + *

      + * Differs from {@link #getEffectiveLockMode(String)} in that here we + * only return an explicitly specified alias-specific lock mode. + * + * @param alias The alias for which to locate the explicit lock mode. + * @return The explicit lock mode for that alias. + * + * @apiNote This will be removed in 7.1 and replaced with an extension + * to JPA's {@linkplain PessimisticLockScope} + */ + @Remove + public LockMode getAliasSpecificLockMode(String alias) { + return aliasSpecificLockModes == null ? null : aliasSpecificLockModes.get( alias ); + } + + /** + * Iterator over {@link Map.Entry}s, each containing an alias and its + * {@link LockMode}. + * + * @return an iterator over the {@link Map.Entry}s + * @deprecated use {@link #getAliasSpecificLocks()} + */ + @Deprecated + public Iterator> getAliasLockIterator() { + return getAliasSpecificLocks().iterator(); + } + + /** + * Determine the {@link LockMode} to apply to the given alias. If no + * mode was {@linkplain #setAliasSpecificLockMode(String, LockMode) + * explicitly set}, the {@linkplain #getLockMode() overall mode} is + * returned. If the overall lock mode is also {@code null}, + * {@link LockMode#NONE} is returned. + *

      + * Differs from {@link #getAliasSpecificLockMode(String)} in that here + * we fall back to only returning the overall lock mode. + * + * @param alias The alias for which to locate the effective lock mode. + * @return The effective lock mode. + * + * @apiNote This will be removed in 7.1 and replaced with an extension + * to JPA's {@linkplain PessimisticLockScope} + */ + @Remove + public LockMode getEffectiveLockMode(String alias) { + LockMode lockMode = getAliasSpecificLockMode( alias ); + if ( lockMode == null ) { + lockMode = this.lockMode; + } + return lockMode == null ? LockMode.NONE : lockMode; + } + + /** + * Currently needed for follow-on locking. + * + * @return The greatest of all requested lock modes. + * + * @apiNote This will be removed in 7.1 and replaced with an extension + * to JPA's {@linkplain PessimisticLockScope}. See {@linkplain #getLockMode()} + */ + @Remove + public LockMode findGreatestLockMode() { + LockMode lockModeToUse = getLockMode(); + if ( lockModeToUse == null ) { + lockModeToUse = LockMode.NONE; + } + + if ( aliasSpecificLockModes == null ) { + return lockModeToUse; + } + + for ( LockMode lockMode : aliasSpecificLockModes.values() ) { + if ( lockMode.greaterThan( lockModeToUse ) ) { + lockModeToUse = lockMode; + } + } + + return lockModeToUse; + } + + + /** + * Represents {@link LockMode#NONE}, to which timeout and scope are + * not applicable. + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + public static final LockOptions NONE = new LockOptions( true, LockMode.NONE ); + + /** + * Represents {@link LockMode#READ}, to which timeout and scope are + * not applicable. + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + public static final LockOptions READ = new LockOptions( true, LockMode.READ ); + + /** + * Represents {@link LockMode#OPTIMISTIC}. + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + static final LockOptions OPTIMISTIC = new LockOptions( true, LockMode.OPTIMISTIC ); + + /** + * Represents {@link LockMode#OPTIMISTIC_FORCE_INCREMENT}, to which + * timeout and scope are not applicable. + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + static final LockOptions OPTIMISTIC_FORCE_INCREMENT = new LockOptions( true, LockMode.OPTIMISTIC_FORCE_INCREMENT ); + + /** + * Represents {@link LockMode#PESSIMISTIC_READ}. + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + static final LockOptions PESSIMISTIC_READ = new LockOptions( true, LockMode.PESSIMISTIC_READ ); + + /** + * Represents {@link LockMode#PESSIMISTIC_WRITE}. + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + static final LockOptions PESSIMISTIC_WRITE = new LockOptions( true, LockMode.PESSIMISTIC_WRITE ); + + /** + * Represents {@link LockMode#PESSIMISTIC_FORCE_INCREMENT}. + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + static final LockOptions PESSIMISTIC_FORCE_INCREMENT = new LockOptions( true, LockMode.PESSIMISTIC_FORCE_INCREMENT ); + + /** + * Represents {@link LockMode#UPGRADE_NOWAIT}. + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + static final LockOptions UPGRADE_NOWAIT = new LockOptions( true, LockMode.UPGRADE_NOWAIT ); + + /** + * Represents {@link LockMode#UPGRADE_SKIPLOCKED}. + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + static final LockOptions UPGRADE_SKIPLOCKED = new LockOptions( true, LockMode.UPGRADE_SKIPLOCKED ); + + /** + * Represents {@link LockMode#PESSIMISTIC_WRITE} with + * {@linkplain #WAIT_FOREVER no timeout}, and + * {@linkplain PessimisticLockScope#NORMAL no extension of the + * lock to owned collections}. + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + public static final LockOptions UPGRADE = PESSIMISTIC_WRITE; + + /** + * @see Timeouts#NO_WAIT_MILLI + * @see Timeouts#NO_WAIT + * @see #getTimeOut + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + public static final int NO_WAIT = Timeouts.NO_WAIT_MILLI; + + /** + * @see Timeouts#WAIT_FOREVER_MILLI + * @see Timeouts#WAIT_FOREVER + * @see #getTimeOut + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "7", forRemoval = true) + public static final int WAIT_FOREVER = Timeouts.WAIT_FOREVER_MILLI; + + /** + * @see Timeouts#SKIP_LOCKED_MILLI + * @see Timeouts#SKIP_LOCKED + * @see #getTimeOut() + * + * @deprecated This, and the other constants on this class, will be removed. + */ + @Deprecated(since = "6.2", forRemoval = true) + public static final int SKIP_LOCKED = -2; } diff --git a/hibernate-core/src/main/java/org/hibernate/MappingException.java b/hibernate-core/src/main/java/org/hibernate/MappingException.java index a1cd9bf38439..3bed9ef50019 100644 --- a/hibernate-core/src/main/java/org/hibernate/MappingException.java +++ b/hibernate-core/src/main/java/org/hibernate/MappingException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java index d574ada8f7d3..0d33cbff22db 100644 --- a/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/MultiIdentifierLoadAccess.java @@ -1,13 +1,16 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; import java.util.List; +import jakarta.persistence.EntityGraph; + +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; /** * Loads multiple instances of a given entity type at once, by @@ -30,6 +33,38 @@ * @author Steve Ebersole */ public interface MultiIdentifierLoadAccess { + + /** + * Specify the {@linkplain LockMode lock mode} to use when + * querying the database. + * + * @param lockMode The lock mode to apply + * @return {@code this}, for method chaining + */ + default MultiIdentifierLoadAccess with(LockMode lockMode) { + return with( lockMode, PessimisticLockScope.NORMAL ); + } + + /** + * Specify the {@linkplain LockMode lock mode} to use when + * querying the database. + * + * @param lockMode The lock mode to apply + * + * @return {@code this}, for method chaining + */ + MultiIdentifierLoadAccess with(LockMode lockMode, PessimisticLockScope lockScope); + + /** + * Specify the {@linkplain Timeout timeout} to use when + * querying the database. + * + * @param timeout The timeout to apply to the database operation + * + * @return {@code this}, for method chaining + */ + MultiIdentifierLoadAccess with(Timeout timeout); + /** * Specify the {@linkplain LockOptions lock options} to use when * querying the database. @@ -37,7 +72,12 @@ public interface MultiIdentifierLoadAccess { * @param lockOptions The lock options to use * * @return {@code this}, for method chaining + * + * @deprecated Use one of {@linkplain #with(LockMode)}, + * {@linkplain #with(LockMode, PessimisticLockScope)} + * and/or {@linkplain #with(Timeout)} instead. */ + @Deprecated(since = "7.0", forRemoval = true) MultiIdentifierLoadAccess with(LockOptions lockOptions); /** @@ -65,7 +105,7 @@ public interface MultiIdentifierLoadAccess { * * @since 6.3 */ - default MultiIdentifierLoadAccess withFetchGraph(RootGraph graph) { + default MultiIdentifierLoadAccess withFetchGraph(EntityGraph graph) { return with( graph, GraphSemantic.FETCH ); } @@ -76,7 +116,7 @@ default MultiIdentifierLoadAccess withFetchGraph(RootGraph graph) { * * @since 6.3 */ - default MultiIdentifierLoadAccess withLoadGraph(RootGraph graph) { + default MultiIdentifierLoadAccess withLoadGraph(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -84,7 +124,7 @@ default MultiIdentifierLoadAccess withLoadGraph(RootGraph graph) { * @deprecated use {@link #withLoadGraph} */ @Deprecated(since = "6.3") - default MultiIdentifierLoadAccess with(RootGraph graph) { + default MultiIdentifierLoadAccess with(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -93,7 +133,7 @@ default MultiIdentifierLoadAccess with(RootGraph graph) { * {@linkplain jakarta.persistence.EntityGraph entity graph}, * and how it should be {@linkplain GraphSemantic interpreted}. */ - MultiIdentifierLoadAccess with(RootGraph graph, GraphSemantic semantic); + MultiIdentifierLoadAccess with(EntityGraph graph, GraphSemantic semantic); /** * Customize the associations fetched by specifying a diff --git a/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java index 1d0e27121b48..d60e404cfc9b 100644 --- a/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/NaturalIdLoadAccess.java @@ -1,12 +1,15 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; +import jakarta.persistence.EntityGraph; + +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; import jakarta.persistence.metamodel.SingularAttribute; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; import java.util.Map; import java.util.Optional; @@ -34,6 +37,38 @@ * @see SimpleNaturalIdLoadAccess */ public interface NaturalIdLoadAccess { + + /** + * Specify the {@linkplain LockMode lock mode} to use when + * querying the database. + * + * @param lockMode The lock mode to apply + * @return {@code this}, for method chaining + */ + default NaturalIdLoadAccess with(LockMode lockMode) { + return with( lockMode, PessimisticLockScope.NORMAL ); + } + + /** + * Specify the {@linkplain LockMode lock mode} to use when + * querying the database. + * + * @param lockMode The lock mode to apply + * + * @return {@code this}, for method chaining + */ + NaturalIdLoadAccess with(LockMode lockMode, PessimisticLockScope lockScope); + + /** + * Specify the {@linkplain Timeout timeout} to use when + * querying the database. + * + * @param timeout The timeout to apply to the database operation + * + * @return {@code this}, for method chaining + */ + NaturalIdLoadAccess with(Timeout timeout); + /** * Specify the {@linkplain LockOptions lock options} to use when * querying the database. @@ -41,7 +76,12 @@ public interface NaturalIdLoadAccess { * @param lockOptions The lock options to use. * * @return {@code this}, for method chaining + * + * @deprecated Use one of {@linkplain #with(LockMode)}, + * {@linkplain #with(LockMode, PessimisticLockScope)} + * and/or {@linkplain #with(Timeout)} instead. */ + @Deprecated(since = "7.0", forRemoval = true) NaturalIdLoadAccess with(LockOptions lockOptions); /** @@ -51,7 +91,7 @@ public interface NaturalIdLoadAccess { * * @since 6.3 */ - default NaturalIdLoadAccess withFetchGraph(RootGraph graph) { + default NaturalIdLoadAccess withFetchGraph(EntityGraph graph) { return with( graph, GraphSemantic.FETCH ); } @@ -62,7 +102,7 @@ default NaturalIdLoadAccess withFetchGraph(RootGraph graph) { * * @since 6.3 */ - default NaturalIdLoadAccess withLoadGraph(RootGraph graph) { + default NaturalIdLoadAccess withLoadGraph(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -73,7 +113,7 @@ default NaturalIdLoadAccess withLoadGraph(RootGraph graph) { * * @since 6.3 */ - NaturalIdLoadAccess with(RootGraph graph, GraphSemantic semantic); + NaturalIdLoadAccess with(EntityGraph graph, GraphSemantic semantic); /** * Customize the associations fetched by specifying a diff --git a/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java b/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java index c21a0c7a163c..29c21475af44 100644 --- a/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/NaturalIdMultiLoadAccess.java @@ -1,11 +1,14 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; +import jakarta.persistence.EntityGraph; + +import jakarta.persistence.PessimisticLockScope; +import jakarta.persistence.Timeout; import org.hibernate.graph.GraphSemantic; -import org.hibernate.graph.RootGraph; import java.util.List; @@ -35,6 +38,38 @@ * @see org.hibernate.annotations.NaturalId */ public interface NaturalIdMultiLoadAccess { + + /** + * Specify the {@linkplain LockMode lock mode} to use when + * querying the database. + * + * @param lockMode The lock mode to apply + * @return {@code this}, for method chaining + */ + default NaturalIdMultiLoadAccess with(LockMode lockMode) { + return with( lockMode, PessimisticLockScope.NORMAL ); + } + + /** + * Specify the {@linkplain LockMode lock mode} to use when + * querying the database. + * + * @param lockMode The lock mode to apply + * + * @return {@code this}, for method chaining + */ + NaturalIdMultiLoadAccess with(LockMode lockMode, PessimisticLockScope lockScope); + + /** + * Specify the {@linkplain Timeout timeout} to use when + * querying the database. + * + * @param timeout The timeout to apply to the database operation + * + * @return {@code this}, for method chaining + */ + NaturalIdMultiLoadAccess with(Timeout timeout); + /** * Specify the {@linkplain LockOptions lock options} to use when * querying the database. @@ -42,7 +77,12 @@ public interface NaturalIdMultiLoadAccess { * @param lockOptions The lock options to use * * @return {@code this}, for method chaining + * + * @deprecated Use one of {@linkplain #with(LockMode)}, + * {@linkplain #with(LockMode, PessimisticLockScope)} + * and/or {@linkplain #with(Timeout)} instead. */ + @Deprecated(since = "7.0", forRemoval = true) NaturalIdMultiLoadAccess with(LockOptions lockOptions); /** @@ -61,7 +101,7 @@ public interface NaturalIdMultiLoadAccess { * * @since 6.3 */ - default NaturalIdMultiLoadAccess withFetchGraph(RootGraph graph) { + default NaturalIdMultiLoadAccess withFetchGraph(EntityGraph graph) { return with( graph, GraphSemantic.FETCH ); } @@ -72,7 +112,7 @@ default NaturalIdMultiLoadAccess withFetchGraph(RootGraph graph) { * * @since 6.3 */ - default NaturalIdMultiLoadAccess withLoadGraph(RootGraph graph) { + default NaturalIdMultiLoadAccess withLoadGraph(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -80,7 +120,7 @@ default NaturalIdMultiLoadAccess withLoadGraph(RootGraph graph) { * @deprecated use {@link #withLoadGraph} */ @Deprecated(since = "6.3") - default NaturalIdMultiLoadAccess with(RootGraph graph) { + default NaturalIdMultiLoadAccess with(EntityGraph graph) { return with( graph, GraphSemantic.LOAD ); } @@ -89,7 +129,7 @@ default NaturalIdMultiLoadAccess with(RootGraph graph) { * {@linkplain jakarta.persistence.EntityGraph entity graph}, * and how it should be {@linkplain GraphSemantic interpreted}. */ - NaturalIdMultiLoadAccess with(RootGraph graph, GraphSemantic semantic); + NaturalIdMultiLoadAccess with(EntityGraph graph, GraphSemantic semantic); /** * Specify a batch size, that is, how many entities should be diff --git a/hibernate-core/src/main/java/org/hibernate/NonUniqueObjectException.java b/hibernate-core/src/main/java/org/hibernate/NonUniqueObjectException.java index ef3e6728ba67..68492bef2cd7 100644 --- a/hibernate-core/src/main/java/org/hibernate/NonUniqueObjectException.java +++ b/hibernate-core/src/main/java/org/hibernate/NonUniqueObjectException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/NonUniqueResultException.java b/hibernate-core/src/main/java/org/hibernate/NonUniqueResultException.java index 443180679bdc..f021e3589560 100644 --- a/hibernate-core/src/main/java/org/hibernate/NonUniqueResultException.java +++ b/hibernate-core/src/main/java/org/hibernate/NonUniqueResultException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -13,6 +13,10 @@ * this one is recoverable! * * @author Gavin King + * + * @see jakarta.persistence.Query#getSingleResult + * @see org.hibernate.query.SelectionQuery#getSingleResult + * @see jakarta.persistence.NonUniqueResultException */ public class NonUniqueResultException extends HibernateException { diff --git a/hibernate-core/src/main/java/org/hibernate/ObjectDeletedException.java b/hibernate-core/src/main/java/org/hibernate/ObjectDeletedException.java index 628f493b59a3..0ade030edd2f 100644 --- a/hibernate-core/src/main/java/org/hibernate/ObjectDeletedException.java +++ b/hibernate-core/src/main/java/org/hibernate/ObjectDeletedException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/ObjectNotFoundException.java b/hibernate-core/src/main/java/org/hibernate/ObjectNotFoundException.java index 11350f9059c9..3d157245eba8 100644 --- a/hibernate-core/src/main/java/org/hibernate/ObjectNotFoundException.java +++ b/hibernate-core/src/main/java/org/hibernate/ObjectNotFoundException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/PersistentObjectException.java b/hibernate-core/src/main/java/org/hibernate/PersistentObjectException.java index a1af82b4452f..c930dd298048 100644 --- a/hibernate-core/src/main/java/org/hibernate/PersistentObjectException.java +++ b/hibernate-core/src/main/java/org/hibernate/PersistentObjectException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/PessimisticLockException.java b/hibernate-core/src/main/java/org/hibernate/PessimisticLockException.java index 5d52a18daa40..d6ab0542a6ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/PessimisticLockException.java +++ b/hibernate-core/src/main/java/org/hibernate/PessimisticLockException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -9,7 +9,13 @@ /** * Thrown when a pessimistic locking conflict occurs. * + * @apiNote When a conflict is detected while acquiring a database-level lock, + * {@link org.hibernate.exception.LockAcquisitionException} is preferred. + * * @author Scott Marlow + * + * @see jakarta.persistence.PessimisticLockException + * @see org.hibernate.exception.LockAcquisitionException */ public class PessimisticLockException extends JDBCException { /** @@ -22,4 +28,14 @@ public class PessimisticLockException extends JDBCException { public PessimisticLockException(String message, SQLException sqlException, String sql) { super( message, sqlException, sql ); } + /** + * Constructs a {@code PessimisticLockException} using the specified information. + * + * @param message A message explaining the exception condition + * @param sqlException The underlying SQL exception + */ + public PessimisticLockException(String message, SQLException sqlException) { + super( message, sqlException ); + + } } diff --git a/hibernate-core/src/main/java/org/hibernate/PropertyAccessException.java b/hibernate-core/src/main/java/org/hibernate/PropertyAccessException.java index 2403c5510d6d..27f17283f402 100644 --- a/hibernate-core/src/main/java/org/hibernate/PropertyAccessException.java +++ b/hibernate-core/src/main/java/org/hibernate/PropertyAccessException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/PropertyNotFoundException.java b/hibernate-core/src/main/java/org/hibernate/PropertyNotFoundException.java index 68686414389b..0f95a425075c 100644 --- a/hibernate-core/src/main/java/org/hibernate/PropertyNotFoundException.java +++ b/hibernate-core/src/main/java/org/hibernate/PropertyNotFoundException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/PropertySetterAccessException.java b/hibernate-core/src/main/java/org/hibernate/PropertySetterAccessException.java index e9092007fa1d..b490c47de78c 100644 --- a/hibernate-core/src/main/java/org/hibernate/PropertySetterAccessException.java +++ b/hibernate-core/src/main/java/org/hibernate/PropertySetterAccessException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -11,6 +11,8 @@ import org.checkerframework.checker.nullness.qual.Nullable; /** + * Thrown when an {@link IllegalArgumentException} occurs calling a property setter method. + * * @author Steve Ebersole */ public class PropertySetterAccessException extends PropertyAccessException { @@ -49,10 +51,9 @@ public PropertySetterAccessException( } public static String loggablePropertyValueString(Object value) { - if ( value instanceof Collection || value instanceof HibernateProxy ) { - return value.getClass().getSimpleName(); - } - return value.toString(); + return value instanceof Collection || value instanceof HibernateProxy + ? value.getClass().getSimpleName() + : value.toString(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/PropertyValueException.java b/hibernate-core/src/main/java/org/hibernate/PropertyValueException.java index 1cc36966d81d..1c5d978d8686 100644 --- a/hibernate-core/src/main/java/org/hibernate/PropertyValueException.java +++ b/hibernate-core/src/main/java/org/hibernate/PropertyValueException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/QueryException.java b/hibernate-core/src/main/java/org/hibernate/QueryException.java index aad15570ee88..c7c9ba6a3ab4 100644 --- a/hibernate-core/src/main/java/org/hibernate/QueryException.java +++ b/hibernate-core/src/main/java/org/hibernate/QueryException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/QueryParameterException.java b/hibernate-core/src/main/java/org/hibernate/QueryParameterException.java index 083978a34bbe..ec4628c5e803 100644 --- a/hibernate-core/src/main/java/org/hibernate/QueryParameterException.java +++ b/hibernate-core/src/main/java/org/hibernate/QueryParameterException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/QueryTimeoutException.java b/hibernate-core/src/main/java/org/hibernate/QueryTimeoutException.java index b2830aa2e9a1..431badc12eca 100644 --- a/hibernate-core/src/main/java/org/hibernate/QueryTimeoutException.java +++ b/hibernate-core/src/main/java/org/hibernate/QueryTimeoutException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -7,9 +7,14 @@ import java.sql.SQLException; /** - * Thrown when a database query timeout occurs. + * A {@link JDBCException} indicating that a database query timed + * out on the database. * * @author Scott Marlow + * + * @see jakarta.persistence.Query#setTimeout + * @see org.hibernate.query.CommonQueryContract#setTimeout + * @see jakarta.persistence.QueryTimeoutException */ public class QueryTimeoutException extends JDBCException { /** diff --git a/hibernate-core/src/main/java/org/hibernate/ReadOnlyMode.java b/hibernate-core/src/main/java/org/hibernate/ReadOnlyMode.java index 2dea698be3e9..4097952b4fdd 100644 --- a/hibernate-core/src/main/java/org/hibernate/ReadOnlyMode.java +++ b/hibernate-core/src/main/java/org/hibernate/ReadOnlyMode.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/Remove.java b/hibernate-core/src/main/java/org/hibernate/Remove.java index c7a5b763f5d9..12dc58769a4a 100644 --- a/hibernate-core/src/main/java/org/hibernate/Remove.java +++ b/hibernate-core/src/main/java/org/hibernate/Remove.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/ReplicationMode.java b/hibernate-core/src/main/java/org/hibernate/ReplicationMode.java index 74f1d5bd2382..5b402a49ca6d 100644 --- a/hibernate-core/src/main/java/org/hibernate/ReplicationMode.java +++ b/hibernate-core/src/main/java/org/hibernate/ReplicationMode.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/ResourceClosedException.java b/hibernate-core/src/main/java/org/hibernate/ResourceClosedException.java index 403ac67f0441..29f1853dc544 100644 --- a/hibernate-core/src/main/java/org/hibernate/ResourceClosedException.java +++ b/hibernate-core/src/main/java/org/hibernate/ResourceClosedException.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; diff --git a/hibernate-core/src/main/java/org/hibernate/ScrollMode.java b/hibernate-core/src/main/java/org/hibernate/ScrollMode.java index ac9703fdbc8b..352aaca69881 100644 --- a/hibernate-core/src/main/java/org/hibernate/ScrollMode.java +++ b/hibernate-core/src/main/java/org/hibernate/ScrollMode.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -11,6 +11,8 @@ * to use underneath a {@link ScrollableResults}. * * @author Gavin King + * + * @see org.hibernate.query.SelectionQuery#scroll(ScrollMode) */ public enum ScrollMode { /** diff --git a/hibernate-core/src/main/java/org/hibernate/ScrollableResults.java b/hibernate-core/src/main/java/org/hibernate/ScrollableResults.java index 06f35d6dba86..56d46f256dd2 100644 --- a/hibernate-core/src/main/java/org/hibernate/ScrollableResults.java +++ b/hibernate-core/src/main/java/org/hibernate/ScrollableResults.java @@ -1,5 +1,5 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; @@ -8,15 +8,15 @@ /** * A result iterator that allows moving around within the results by - * arbitrary increments. The {@link Query} / {@link ScrollableResults} - * pattern is very similar to the JDBC {@link java.sql.PreparedStatement}/ + * arbitrary increments. + * + * @apiNote The {@link Query} / {@link ScrollableResults} pattern is + * very similar to the JDBC {@link java.sql.PreparedStatement} / * {@link java.sql.ResultSet} pattern and so the semantics of methods * of this interface are similar to the similarly-named methods of * {@code ResultSet}. - *

      - * Contrary to JDBC, columns of results are numbered from zero. * - * @see Query#scroll() + * @see org.hibernate.query.SelectionQuery#scroll() * * @author Gavin King */ @@ -57,19 +57,41 @@ public interface ScrollableResults extends AutoCloseable { * position. * * @param positions a positive (forward) or negative (backward) - * number of rows + * number of positions * * @return {@code true} if there is a result at the new location */ boolean scroll(int positions); /** - * Moves the result cursor to the specified position. + * Moves the result cursor to the specified position. The index + * may be a positive value, and the position may be reached by + * counting forward from the first result at position {@code 1}, + * or it may be a negative value, so that the position may be + * reached by counting backward from the last result at position + * {@code -1}. + * + * @param position an absolute positive (from the start) or + * negative (from the end) position within the + * query results * * @return {@code true} if there is a result at the new location */ boolean position(int position); + /** + * The current position within the query results. The first + * query result, if any, is at position {@code 1}. An empty + * or newly-created instance has position {@code 0}. + * + * @return the current position, a positive integer index + * starting at {@code 1}, or {@code 0} if this + * instance is empty or newly-created + * + * @since 7.0 + */ + int getPosition(); + /** * Go to the last result. * @@ -113,20 +135,24 @@ public interface ScrollableResults extends AutoCloseable { boolean isLast(); /** - * Get the current position in the results. - *

      - * The first position is number 0 (unlike JDBC). + * Get the current position in the results, with the first + * position labelled as row number {@code 0}. That is, this + * operation returns {@link #getPosition() position-1}. + * + * @return The current position number, numbered from {@code 0}; + * {@code -1} indicates that there is no current row * - * @return The current position number, numbered from 0; - * -1 indicates that there is no current row + * @deprecated Use {@link #getPosition()} */ + @Deprecated(since = "7", forRemoval = true) int getRowNumber(); /** - * Set the current position in the result set. - *

      - * Can be numbered from the first result (positive number) - * or backward from the last result (negative number). + * Set the current position in the result set, with the first + * position labelled as row number {@code 1}, and the last + * position labelled as row number {@code -1}. Results may be + * numbered from the first result (using a positive position) + * or backward from the last result (using a negative position). * * @param rowNumber the row number. A positive number indicates * a value numbered from the first row; a @@ -134,7 +160,10 @@ public interface ScrollableResults extends AutoCloseable { * from the last row. * * @return true if there is a row at that row number + * + * @deprecated Use {@link #position(int)} */ + @Deprecated(since = "7", forRemoval = true) boolean setRowNumber(int rowNumber); /** diff --git a/hibernate-core/src/main/java/org/hibernate/Session.java b/hibernate-core/src/main/java/org/hibernate/Session.java index 7da28ac938b3..e9e81f5076fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/Session.java +++ b/hibernate-core/src/main/java/org/hibernate/Session.java @@ -1,13 +1,17 @@ /* - * SPDX-License-Identifier: LGPL-2.1-or-later + * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate; +import java.util.Collection; import java.util.List; import java.util.function.Consumer; import jakarta.persistence.FindOption; +import jakarta.persistence.LockOption; +import jakarta.persistence.RefreshOption; +import jakarta.persistence.metamodel.EntityType; import org.hibernate.graph.RootGraph; import org.hibernate.jdbc.Work; import org.hibernate.query.Query; @@ -42,7 +46,14 @@ * {@code Session}. *

    *

    - * At any given time, an instance may be associated with at most one open session. + * Each persistent instance has a persistent identity determined by its type + * and identifier value. There may be at most one persistent instance with a given + * persistent identity associated with a given session. A persistent identity is + * assigned when an {@linkplain #persist(Object) instance is made persistent}. + *

    + * An instance of an entity class may be associated with at most one open session. + * Distinct sessions represent state with the same persistent identity using distinct + * persistent instances of the mapped entity class. *

    * Any instance returned by {@link #get(Class, Object)}, {@link #find(Class, Object)}, * or by a query is persistent. A persistent instance might hold references to other @@ -57,8 +68,8 @@ *

    * A transient instance may be made persistent by calling {@link #persist(Object)}. * A persistent instance may be made detached by calling {@link #detach(Object)}. - * A persistent instance may be marked for removal, and eventually made transient, by - * calling {@link #remove(Object)}. + * A persistent instance may be marked for removal, and eventually made transient, + * by calling {@link #remove(Object)}. *

    * Persistent instances are held in a managed state by the persistence context. Any * change to the state of a persistent instance is automatically detected and eventually @@ -91,9 +102,9 @@ * behavior is appropriate for programs which use optimistic locking. *