From 80770ab13b022a539093e62752fb0870d7caf884 Mon Sep 17 00:00:00 2001 From: Vlad Mihalcea Date: Wed, 10 Aug 2016 11:02:59 +0300 Subject: [PATCH] HHH-10523 - 2.3.20. SQL quoted identifiers in User Guide should discuss explicit enclosure in double-quotes (JPA) --- .../chapters/domain/basic_types.adoc | 59 +++++++++++- ...basic-auto-quoting-persistence-example.sql | 2 + .../mapping/basic/AutoQuotingTest.java | 95 +++++++++++++++++++ .../mapping/basic/JpaQuotingTest.java | 89 +++++++++++++++++ 4 files changed, 242 insertions(+), 3 deletions(-) create mode 100644 documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/basic-auto-quoting-persistence-example.sql create mode 100644 documentation/src/test/java/org/hibernate/userguide/mapping/basic/AutoQuotingTest.java create mode 100644 documentation/src/test/java/org/hibernate/userguide/mapping/basic/JpaQuotingTest.java diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc index 9a635fe6a7..8849b2a5f7 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc @@ -1012,11 +1012,13 @@ include::{extrasdir}/basic/basic-jpa-convert-period-string-converter-sql-example ==== SQL quoted identifiers You can force Hibernate to quote an identifier in the generated SQL by enclosing the table or column name in backticks in the mapping document. -Hibernate will use the correct quotation style for the SQL `Dialect`. -This is usually double quotes, but the SQL Server uses brackets and MySQL uses backticks. +While traditionally, Hibernate used backticks for escaping SQL reserved keywords, JPA uses double quotes instead. + +Once the reserved keywords are escaped, Hibernate will use the correct quotation style for the SQL `Dialect`. +This is usually double quotes, but SQL Server uses brackets and MySQL uses backticks. [[basic-quoting-example]] -.Quoting column names +.Hibernate legacy quoting ==== [source, JAVA, indent=0] ---- @@ -1024,6 +1026,15 @@ include::{sourcedir}/basic/QuotingTest.java[tags=basic-quoting-example] ---- ==== +[[basic-jpa-quoting-example]] +.JPA quoting +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/basic/JpaQuotingTest.java[tags=basic-jpa-quoting-example] +---- +==== + Because `name` and `number` are reserved words, the `Product` entity mapping uses backtricks to quote these column names. When saving teh following `Product entity`, Hibernate generates the following SQL insert statement: @@ -1034,11 +1045,53 @@ When saving teh following `Product entity`, Hibernate generates the following SQ [source, JAVA, indent=0] ---- include::{sourcedir}/basic/QuotingTest.java[tags=basic-quoting-persistence-example, indent=0] +---- +[source, SQL, indent=0] +---- include::{extrasdir}/basic/basic-quoting-persistence-example.sql[indent=0] ---- ==== +[[mapping-global-quoted-identifiers]] +===== Global quoting + +Hibernate can also quote all identifiers (e.g. table, columns) using the following configuration property: + +==== +[source,xml] +---- + +---- +==== + +This way, we don't need to manually quote any identifier: + +[[basic-auto-quoting-example]] +.JPA quoting +==== +[source, JAVA, indent=0] +---- +include::{sourcedir}/basic/AutoQuotingTest.java[tags=basic-auto-quoting-example] +---- +==== + +When persisting a `Product` entity, Hibernate is going to quote all identifiers as in the following example: + +==== +[source, SQL, indent=0] +---- +include::{extrasdir}/basic/basic-auto-quoting-persistence-example.sql[indent=0] +---- +==== + +As you can see, both the table name and all the column have been quoted. + +For more about quoting-related configuration properties, checkout the <> section as well. + [[mapping-generated]] ==== Generated properties diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/basic-auto-quoting-persistence-example.sql b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/basic-auto-quoting-persistence-example.sql new file mode 100644 index 0000000000..f59d435082 --- /dev/null +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/extras/basic/basic-auto-quoting-persistence-example.sql @@ -0,0 +1,2 @@ +INSERT INTO "Product" ("name", "number", "id") +VALUES ('Mobile phone', '123-456-7890', 1) \ No newline at end of file diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/AutoQuotingTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/AutoQuotingTest.java new file mode 100644 index 0000000000..2585601233 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/AutoQuotingTest.java @@ -0,0 +1,95 @@ +/* + * 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 . + */ +package org.hibernate.userguide.mapping.basic; + +import java.util.Map; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import static org.hibernate.userguide.util.TransactionUtil.doInJPA; + +/** + * @author Vlad Mihalcea + */ +public class AutoQuotingTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Product.class + }; + } + + @Override + protected Map buildSettings() { + Map settings = super.buildSettings(); + settings.put( AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, true ); + return settings; + } + + @Test + public void test() { + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::basic-auto-quoting-persistence-example[] + Product product = new Product(); + product.setId( 1L ); + product.setName( "Mobile phone" ); + product.setNumber( "123-456-7890" ); + entityManager.persist( product ); + //end::basic-auto-quoting-persistence-example[] + } ); + } + + //tag::basic-auto-quoting-example[] + @Entity(name = "Product") + public static class Product { + + @Id + private Long id; + + private String name; + + private String number; + + //Getters and setters are omitted for brevity + + //end::basic-auto-quoting-example[] + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + + //tag::basic-auto-quoting-example[] + } + //end::basic-auto-quoting-example[] +} diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/JpaQuotingTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/JpaQuotingTest.java new file mode 100644 index 0000000000..d0e0cc0901 --- /dev/null +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/JpaQuotingTest.java @@ -0,0 +1,89 @@ +/* + * 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 . + */ +package org.hibernate.userguide.mapping.basic; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.junit.Test; + +import static org.hibernate.userguide.util.TransactionUtil.doInJPA; + +/** + * @author Vlad Mihalcea + */ +public class JpaQuotingTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Product.class + }; + } + + @Test + public void test() { + doInJPA( this::entityManagerFactory, entityManager -> { + //tag::basic-jpa-quoting-persistence-example[] + Product product = new Product(); + product.setId( 1L ); + product.setName( "Mobile phone" ); + product.setNumber( "123-456-7890" ); + entityManager.persist( product ); + //end::basic-jpa-quoting-persistence-example[] + } ); + } + + //tag::basic-jpa-quoting-example[] + @Entity(name = "Product") + public static class Product { + + @Id + private Long id; + + @Column(name = "\"name\"") + private String name; + + @Column(name = "\"number\"") + private String number; + + //Getters and setters are omitted for brevity + + //end::basic-jpa-quoting-example[] + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getNumber() { + return number; + } + + public void setNumber(String number) { + this.number = number; + } + + + //tag::basic-jpa-quoting-example[] + } + //end::basic-jpa-quoting-example[] +}