How to use HSQLDB in Oracle query syntax mode? - hsqldb

I am trying to use HSQLDB as an embedded database in a spring application (for testing). As the target production database is Oracle, I would like to use HSQLDBs Oracle syntax mode feature.
In the Spring config I use
<jdbc:embedded-database type="HSQL" id="dataSource">
</jdbc:embedded-database>
<jdbc:initialize-database data-source="dataSource" enabled="true">
<jdbc:script location="classpath:schema.sql"/>
</jdbc:initialize-database>
And in schema.sql at the top I wrote:
SET DATABASE SQL SYNTAX ORA TRUE;
However, when running my test, I get the following error:
java.sql.SQLException: Unexpected token: DATABASE in statement [SET DATABASE SQL SYNTAX ORA TRUE]
Is this a syntax error or a permissions error or something entirely different?
Thanks - also for any pointers that might lead to the answer.
Given that HSQL is the Spring default for jdbc:embedded-database and given the target is Oracle, this scenario should actually be very common. However, I found nothing on the Web even touching the issue.
Update:
The issue above is resolved thanks to answer #1.
However, I now get another exception:
org.springframework.dao.DataAccessResourceFailureException: Failed to populate database; nested exception is java.sql.SQLException: java.lang.RuntimeException: unsupported internal operation: StatementCommand unsupported internal operation: StatementCommand
Any idea what this is caused by?

This option was introduced with HSQLDB 2.0.
Are you sure you are using the correct version?
Maybe you have 1.8 still in the classpath somewhere.
But that won't get you far in terms of testing anyway, because this only turns on some basic syntax "replacing", there is no real behaviour change involved here (and I'm not even talking about more advanced Oracle features like analytical functions, CONNECT BY or something similar).
It is very seldom a good idea to test your application with a DBMS that will not be used in production. It is simply not a valid test.

Even if it only change some basic syntax here is an example of how you can do it:
<bean class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close" id="dataSource">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:PUBLIC;sql.syntax_ora=true" />
<property name="username" value="sa" />
<property name="password" value="" />
</bean>

The sql.syntax_ora=true URL property enables syntax compatibility, including the NUMBER type and the DUAL table. Additional properties can be used for more behavior compatibility. These are documented in the HSQLDB Guide:
http://hsqldb.org/doc/2.0/guide/compatibility-chapt.html#coc_compatibility_oracle

Related

List of supported dbms values

In Liquibase I can set properties based on what DBMS I'm using, as mentioned here: Liquibase changeset by dbms type
For example:
<property name="val" dbms="postgresql" value="x"/>
<property name="val" dbms="h2" value="y"/>
My question is - where can I find a list of all valid/possible dbms values? In the Liquibase docs it just points to a page saying what databases are supported, but it does not give a corresponding dbms value. I know MYSQL is 'mysql', oracle is 'oracle', and so on, but where is the canonical list of values?
I searched the github repo for liquibase core, but can't find the magic class or enum that defines all these values.
Does anyone know where they are?
I don't think there is a canonical list of what values are accepted. From what I can tell, it takes the value you provide for dbms and compares it to the short name for the connected database, so it isn't a list that it is being compared to.
If you are not connected to the database, you can usually find the dbms short name via the connection url or by looking for the getShortName() function in the database files. For example, to connect to AWS redshift, the url is jdbc:redshift://endpoint:port/database and the dbms value you'd set is just redshift. This can also be confirmed by looking at the Redshift extension for Liquibase. The function getShortName() returns redshift
If you are connected to the database, you can easily find out what the value is by running liquibase status and have a precondition with dbms set to some value in a changelog. For example (in XML),
<preConditions>
<dbms type="mongo"/>
</preConditions>
results in Unexpected error running Liquibase: Validation Failed: 1 preconditions failed changelog_mongo.xml : DBMS Precondition failed: expected mongo, got mongodb
The expected value is the value you provide for dbms, and the got value is the connected database short name.
But to have a "list", I looked around and found the following ones listed at some point:
cockroachdb, db2, derby, edb, firebird, h2, hsqldb, informix, ingres, mariadb, mock, mssql, mysql, postgresql, sqlite, sybase

Jooq text array generated as object array

given the following sql
create table something(
id BIGSERIAL,
something TEXT[] NOT NULL DEFAULT '{}',
PRIMARY KEY (id)
);
and instructing the code generator to use DDLDatabase
the generated item is in the form of
public final TableField<JSomethingRecord, Object[]> SOMETHING_
Looking around in the documentation I cannot find how can this be mapped in a String[].
same applies for varchar and varchar(255).
I shouldn't have to use an enforced type here as at least on of the three should be a valid datatype
and not fallback to OTHER as it happens with the UUID (for which I saw there is an example for enforced types)
Am I doing / understanding something wrong or this is an expected behaviour?
The database I am using is PostGres and the generator configuration is the following
<generator>
<database>
<name>org.jooq.meta.extensions.ddl.DDLDatabase</name>
<inputCatalog/>
<inputSchema>PUBLIC</inputSchema>
<properties>
<property>
<key>use-attribute-converters</key>
<value>true</value>
</property>
<property>
<key>scripts</key>
<value>src/main/resources/db/migration/*</value>
</property>
</properties>
</database>
<target>
<clean>true</clean>
<packageName>my.other.package</packageName>
<directory>target/generated-sources/jooq</directory>
</target>
</generator>
Thank you in advance
As of jOOQ 3.13, PostgreSQL's typed arrays are not yet supported by the DDLDatabase, because the current implementation of the DDLDatabase translates your DDL to H2 behind the scenes, and H2 1.4.200's ARRAY type does not support any other type of array than Object[].
This will change in the future, as:
H2 1.4.201 will support typed arrays like PostgreSQL: https://github.com/h2database/h2database/issues/1390
jOOQ will support running your DDL on an actual PostgreSQL database in test containers: https://github.com/jOOQ/jOOQ/issues/6551
jOOQ will support interpreting the DDL instead of running it on a third party database product: https://github.com/jOOQ/jOOQ/issues/7034
Until then, in order to use such PostgreSQL-specific features, I recommend using the classic approach of connecting to an actual PostgreSQL database instance.

Liquibase Single Precondition for multiple Changesets

I have a number of changesets that I would like to run if a specific condition exists. For example run changesets 1, 2, and 3 only if sqlCheck executed with the excepted results.
I can copy the precondition into each changeset. However it feels like there should be a more efficient way of doing this. As the number of changesets grows, the files have a lot of these duplicates.
The preConditions element directly under databaseChangeLog seems to only configure dbms and runAs.
Is there a way to define a single preCondition that will be used by multiple change sets?
Any help is appreciated.
Unfortunately this is not possible but sometimes you can avoid using preconditions when you declare a property tag instead. For example when you have preconditions for different databases like Oracle and SQL Server which have different data types like
number in Oracle and float in SQL Server, you can instead of using a precondition for each database use a propertytag:
<property dbms="oracle" name="DECIMALTYPE" value="NUMBER" />
<property dbms="mssql" name="DECIMALTYPE" value="FLOAT" />

How do I differentiate between databases when using e.g. sequence

I just started using Liquibase and stumpled upon the problem to differentiate between the capabilities of different databases.
We would like to support multiple databases (Oracle, MySQL, Derby - to name three).
The all have different capabilities. In specific Oracle supports sequences whereas MySQL and Derby do not.
When I let hibernate generate the DDL I can choose different dialects and it will consider these different capabilities and generate a Sequencer when using Oracle and use a plain table (for ID-generation) when using Derby or MySQL.
Now, I know I can constraint changesets by specifying 'oracle' in the dbms attribute. But then how can I do the plain table solution for the other databases? There does not seem to be a 'not oracle' attribute for dbms.
How does anyone else handle this? (I could not find anything about it on the liquibase pages nor on the forum.)
Try using a precondition on the changset. Boolean operations are supported.
For example
<preConditions onFail="CONTINUE">
<or>
<dbms type="oracle" />
<dbms type="mysql" />
</or>
</preConditions>
An alternative approach is to put all your sequences in a changlog file which you include in your main changelog, and then do something like this:
<changeSet
dbms="oracle,db2,db2i"
author="mccallim (generated)"
id="1419011907193-1"
>
<createSequence
schemaName="${main.schema}"
...
That changeset only gets executed for the DBMSs listed.

nHibernate default schema unused in formula

Hey Guys,
I'm using nhibernate 2.2 and ran into a problem that I can't seem to find an answer to. My program is using a default schema assigned in the hibernate.cfg.xml file like this:
<property name="default_schema">MY_SCHEMA</property>
which works as advertised for all generated SQL statements, however I have statements in a formula that need to be assigned the default schema as well:
<property name="Count" type="int" formula="SELECT COUNT(*) FROM DETAILS WHERE DETAILS.ID = ID" />
MY_SCHEMA changes relatively often, so I need the SQL to be interpreted as <property name="Count" type="int" formula="SELECT COUNT(*) FROM MY_SCHEMA.DETAILS WHERE DETAILS.ID = ID" />
Is this possible without resorting to hardcoded schemas? Thanks!
Kevin
You can change your mappings on the fly when building the session factory.
Of course that's easier to do if you use a code-based mapping solution, like Fluent or ConfORM.