#Column(name="open")
Using sqlserver dialect with hibernate.
[SchemaUpdate] Unsuccessful: create table auth_session (id numeric(19,0) identity not null, active tinyint null, creation_date datetime not null, last_modified datetime not null, maxidle int null, maxlive int null, open tinyint null, sessionid varchar(255) not null, user_id numeric(19,0) not null, primary key (id), unique (sessionid))
[SchemaUpdate] Incorrect syntax near the keyword 'open'.
I would have expected hibernate to use quoted identifier when creating the table.
Any ideas on how to handle this... other than renaming the field?
With Hibernate as JPA 1.0 provider, you can escape a reserved keyword by enclosing it within backticks:
#Column(name="`open`")
This is the syntax inherited from Hiberate Core:
5.4. 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.
<class name="LineItem" table="`Line Item`">
<id name="id" column="`Item Id`"/><generator class="assigned"/></id>
<property name="itemNumber" column="`Item #`"/>
...
</class>
In JPA 2.0, the syntax is standardized and becomes:
#Column(name="\"open\"")
References
Hibernate reference guide
5.4. SQL quoted identifiers
JPA 2.0 specification
2.13 Naming of Database Objects
Related questions
Hibernate, MySQL and table named “Repeat” - strange behaviour
Automatic reserved word escaping for Hibernate tables and columns
Had the same problem, but with a tablename called Transaction. If you set
hibernate.globally_quoted_identifiers=true
Then all database identifiers will be quoted.
Found my answer here
Special character in table name hibernate giving error
And found all available settings here
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/appendices/Configurations.html
Could not find better docs for this though.
In my case the setting was in my Spring properties file. As mentioned in the comments, it could also be in other, hibernate related, configuration files.
Manually escaping the reserved keywords
If you are using JPA, you can escape with double quotes:
#Column(name = "\"open\"")
If you're using Hibernate native API, then you can escape them using backticks:
#Column(name = "`open`")
Automatically escaping reserved keywords
If you want to automatically escape reserved keywords, you can set to true the Hibernate-specific hibernate.globally_quoted_identifiers configuration property:
<property
name="hibernate.globally_quoted_identifiers"
value="true"
/>
Yaml format
spring:
jpa:
properties:
hibernate:
globally_quoted_identifiers: true
If you use as shown below it should work
#Column(name="[order]")
private int order;
#Column(name="\"open\"")
This will work for sure, Same problem happened with me, when I was learning hibernate.
There is also another option: hibernate.auto_quote_keyword
which
Specifies whether to automatically quote any names that are deemed keywords.
<property name="hibernate.auto_quote_keyword" value="true" />
Yaml
spring:
jpa:
properties:
hibernate:
auto_quote_keyword: true
No - change the column name.
This is database-specific, and you just can't create such a column. After all hibernate finally sends DDL to the database. If you can't create a valid DDL with this column name, this means hibernate can't as well. I don't think quoting would solve the issue even if you are writing the DDL.
Even if you somehow succeed to escape the name - change it. It will work with this database, but won't work with another.
Some JPA implementations (e.g the one I use, DataNucleus) automatically quote the identifier for you, so you never get this.
Related
I'm exporting a Oracle schema, and I want to have a script that I can use for in-memory tests with H2.
I export the schema with maven, mvn liquibase:generateChangeLog.
I have noticed that when I specify an outputChangeLogFile of type sql, the Oracle and H2 formats produce different output (e.g. generatedChangelog.h2.sql vs generatedChangelog.oracle.sql).
With type xml they produce the same ( generatedChangelog.h2.xml vs generatedChangelog.oracle.xml).
In particular, with the sql type I get
NAME VARCHAR(255) NOT NULL for H2
NAME VARCHAR2(255 BYTE) NOT NULL for Oracle
with the xml format I get
<column name="NAME" type="VARCHAR2(255 BYTE)"> for both H2 and Oracle
this particular syntax is not valid with H2, so this seems a bug to me. Liquibase can clearly understands this as you can see from the sql example, but it doesn't produce a valid changeSet for the xml format.
Is there anything I can do to produce the correct output in xml format?
Thanks
There is quite a lot of differences between different databases. What you can do (manually or by some regex) is to create changeLog variables and do following:
change column definition
<column name="NAME" type="VARCHAR2(255${byteType})">
add variable for different db vendors
<property name="byteType" dbms="oracle" value="BYTE"/>
<property name="byteType" dbms="h2" value=""/>
with changes above you'll be able to run changeSets against both (or almost any) databases.
This question already has an answer here:
jpa namedquery with literals changed to prepared statement
(1 answer)
Closed 7 years ago.
I seem to have a problem with a query on a CHAR field that is incorrectly filtered when OpenJPA replaces my constant value with an SQL parameter.
Example
Given this table in Oracle
create table PERSON (
id char(10) not null,
type char(3) not null,
primary key (id)
)
with three different values for type: WTW, WAI, V
and the corresponding entity
#Entity
public class Person {
String id;
String type;
}
I use the following query from an orm.xml file:
<named-query name="person.v">
<query>
select p
from Person p
where p.type = 'V'
</query>
</named-query>
Problem
When I run this through an EntityManager provided by OpenJPA, the query changes to
select p.id, p.type
from PERSON p
where p.type = ?
and OpenJPA passes the value "V" as parameter. The previously "constant" value for type is now an SQL parameter. The problem lies in the fact that for the char(3) type column, Oracle will store
"V "
and this is not equal to the value passed by OpenJPA as a parameter. Again: without parameters, i.e. just using the string in SQL that I use in JPQL, everything works just fine.
I assume OpenJPA performs this replacement in order to minimize the query cache by normalizing all queries, and I understand that this makes a big difference for a lot of people, but I think this is a problem in my case.
My question is now: how can I prevent OpenJPA from doing this replacement? I know that I won't have different permutations of this query at runtime. Is there a configuration property or a query hint that I can use?
Besides just changing the column to a VARCHAR, I have two workarounds that are not very nice:
Adapt the JPQL to where p.type = 'V ' ("V" followed by two spaces).
Use a native query which won't be optimized by OpenJPA.
In (1), I know about the underlying char(3) and the idea of JPQL is to abstract this away, so this goes a little bit against the idea of using JPA.
With (2) I have to rewrite this simple query just a little bit, but it just does not seem right to use a native query just to avoid problems created by good intentions of my persistence provider.
I'm currently porting a Code Igniter based application from MySQL to Oracle (11g) for a specific client. Both the MySQL and Oracle back-ends have to work in conjunction (i.e. we cannot drop the one or the other).
The MySQL DB uses around 100 tables of which ALL identifiers are in lowercase. When I migrate this DB to Oracle, using Oracle's SQL Developer tool, I end up with a 'properly' converted DB, but... with all uppercase identifiers.
Now, for normal usage this isn't really a problem, but the issue arises when using the CI Active Record class. It generates queries to the effect of:
SELECT "somecolumn" FROM "sometable" WHERE "someothercolumn" = somevalue
The issue is that when the " quotes are used for these identifiers, Oracle forces these identifiers to be interpreted in a case sensitive way, which in this case is wreaking havoc.
Patching the core code of CI and/or the application to either make all queries use case insensitive identifiers (i.e. by dropping the usage of the " quotes around the identifiers) or to convert all identifiers to uppercase ones on the fly, is IMO not desired, as a potential future framework upgrade is then compromised. Renaming ALL MySQL identifiers to become in uppercase is also a very unattractive scenario and has an even bigger impact on the application itself -- not an option for sure.
Instead, what I would like to achieve, is to have the migration process (i.e. using SQL Developer) simply respecting the case of the source DB and to perform the conversion exactly as it does up to now, with the exception that the identifiers do not get changed to their uppercase version.
I have searched a fair deal online to find a way to achieve this, and so far it has been to no avail.
Does anyone know if this can be done, and if so: how?
Is the conversion to all uppercase identifiers by any chance a global DB setting, perhaps?
I would have assumed this to be a trivial thing, but I haven't been able to figure it out so far and what little related references that I did come across do not sound very promising...
If you can acquire a schema script created by the database migration all you need to do is change the identifiers ( tablenames, view names, column names etc ) to be surrounded with double quotation marks. (I'm not sure if SQL Developer migrations actually has the option to preserve the case).
Without the quote marks Oracle will assume all identifiers are case-insensitive. However this is stored internally as upper case strings in the data dictionary. By using quote marks will force Oracle to use the exact case for the schema objects.
eg.
create table Customers
(
Name varchar2(100),
CreationDate date not null
);
will create CUSTOMERS internally in the data-dictionar and you can write queries like:
select name, creationdate from customers;
alternatively:
create table "Customers"
(
"Name" varchar2(100),
"CreationDate" date not null
);
will create "Customers" internally. You can only write queries using quotes and exact case:
select "Name", "CreationDate" from "Customers";
I have hit this before and simply edited oci8_driver.php (../system/database/oci) as follows:
// The character used for excaping
var $_escape_char = '"';
to
// The character used for excaping
var $_escape_char = '';
Stewart
I have just started using ORMLite and was using at home to experiment on MySQL. Now I have decided to try using it on Oracle, but have noticed an issue with case sensitivity of column names.
When using the TableUtils.createTableIfNotExists() it appears to generate CREATE statements that wrap the table and column names in double quotes. For example:
CREATE TABLE "T_SUBURB" ("id" NUMERIC , "description" VARCHAR2(255)
NOT NULL , "gnaf" VARCHAR2(255) , PRIMARY KEY ("id") )
This means that when I am attempting to query the database in Oracle SQL Developer I have to use the double quotes to specify the table and column names. This doesn't seem to happen when using MySQL.
I must admit I am a SQL novice, however it doesn't seem natural to wrap every table or column name in double quotes when attempting to query them. Looking at the OracleDatabaseType implementation it would seem that the entity name is intentionally double quoted in this example.
Does anybody know of a way to turn this behaviour off?
I am currently running version 4.43 from maven-central and Oracle 11g. Cheers.
When using the TableUtils.createTableIfNotExists() it appears to generate CREATE statements that wrap the table and column names in double quotes.
That's correct. The challenge for ORMLite is that it has to protect against special characters or reserved-words as field and table names. Words like "index" or "create" might make fine field names but will cause invalid SQL.
However, according to my reading of the OracleDatabaseType is should be generating uppercase field names:
#Override
public boolean isEntityNamesMustBeUpCase() {
return true;
}
If your field is created as "description" then something is wrong. Does DESCRIPTION work instead? Is ORMLite generating your schema and using an Oracle JDBC URI? Something like:
jdbc:oracle:...
If you are not using a JDBC URI like that then ORMLite may not be using the Oracle database type to create your tables. If you need to force it to use Oracle, you can create your
ConnectionSource connectionSource =
new JdbcConnectionSource(databaseUrl, new OracleDatabaseType());
Hope this helps.
More info:
http://www.h2database.com/javadoc/org/h2/constant/DbSettings.html#DATABASE_TO_UPPER
https://groups.google.com/forum/?fromgroups=#!topic/h2-database/B1zEC0V6m34
It looks like all upper case is the default for H2.
The schema_version table name is case-sensitive due to the quotes in the creation script. This allows for characters not supported in identifiers otherwise. You can configure flyway.table to an uppercase value if you wish.
The columns inside the table are internal to Flyway and not meant as a public API. They are private and therefore can change from one Flyway version to the next. Flyway will always ensure these changes are automatic with no manual effort for you.
You enclose the table name in "double quotes" to ensure the actual table created does not suffer from an toUpperCase translation - a feature that is supported in some dbs by configuration.
Enclosing the "table" in quotes ensures the table created is exactly as requested.