List of supported dbms values - liquibase

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

Related

HSQLDB MySQL compatibility is rubbish

With reference to http://hsqldb.org/doc/2.0/guide/compatibility-chapt.html#coc_compatibility_mysql, the compatibility only solves half the problem. THE CAPITALIZED RESULTSETMETADATA (COLUMN NAMES) IS A PROBLEM! This complicates testing with the in-memory database when the MySQL is used in production. I have to sprinkle code in my controllers / verticles to check which database is used (test or non-test) and format the SQL query string by double-quoting the column names in the query.
Related post: Java common JDBC SQL Query strategy for Unit Test using HSQLDB and runtime using MySQL
Question: How to use lower-case column names or how to convert the capitalized RESULTSETMETADATA returned from HSQLDB to lower case?
Solution: Ditch HSQLDB and use H2 with database_to_upper=false option.

setColumnRemarks is not supported on mysql

I use liquibase diff generate the diff between dev mysql and prod mysql, I see there exist some change set like:
When I run the diff file, it shows exception like:
setColumnRemarks is not supported on mysql, db/changelog/V1.1.0_prod_uat.xml::1524893614482-984::davy (generated)
setColumnRemarks is not supported on mysql, db/changelog/V1.1.0_prod_uat.xml::1524893614482-985::davy (generated)
setColumnRemarks is not supported on mysql, db/changelog/V1.1.0_prod_uat.xml::1524893614482-986::davy (generated)
at liquibase.changelog.DatabaseChangeLog.validate(DatabaseChangeLog.java:276)
at liquibase.Liquibase.update(Liquibase.java:198)
at liquibase.Liquibase.update(Liquibase.java:179)
at liquibase.integration.spring.SpringLiquibase.performUpdate(SpringLiquibase.java:317)
at liquibase.integration.spring.SpringLiquibase.afterPropertiesSet(SpringLiquibase.java:269)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1769)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1706)
How to resolve this problem?
Object's comment update (Liquibase's set*Remarks) is not supported for some databases, including MySQL. So immediate fix could be to remove this action from your change log.
In my project we generating change sets by comparing (with liquibase diffChangeLog) 2 schemas, and setColumnRemarks actions are included although they cannot be executed afterwards. So I'm just removing these actions from resulting change sets.
I am afraid a proper solution would be to add appropriate MySQL SQL generator implementation to Liquibase.

Bad changelog from generateChangeLog with MariaDB

I am attempting to generate a change log against a MariaDB server. I am able to successfully generate a change log, however if I do a dropAll and update to validate that it is useful, there are multiple problems with it. I have tried using both the native mariadb and MySQL jdbc connectors and both experience these problems. I am also using liquibase 3.1.1.
The first is that there are deferrable and initiallyDeferred flags which are not supported by MySQL. The update command specifically calls these out as being invalid flags against MySQL.
Once I remove all of those references in the .xml, attempting to update runs into a sql syntax error because a double datatype is defined as DOUBLE(22) (in the xml). This is not a valid syntax for a double in mariadb or MySQL. They accept no parameters, or DOUBLE(m,d); my database is defined as default (no parameters).
Now its trying to create a table with an auto_increment but not specifying that the column is also a key in the create table statement; ie. it's missing the primaryKey constraint.
And I'm sure there are more problems in line as I work my way through the changelog (this is just changeset 116 out of 1500+).
Its almost as if liquibase is creating the changelog based on it thinking the db is a different type (postgres/oracle?).
Am I missing something?
You are right, the problem is that Liquibase is thinking it is an unknown database and doesn't know it is almost mysql. There is an issue open to add mariaDB support (https://liquibase.jira.com/browse/CORE-1411) but it hasn't been implemented quite yet.
The easiest work-around would be to add an extension:
Create a new liquibase.database.ext.MariaDBDatabase class in your codebase that extends liquibase.database.core.MySQLDatabase and override the isCorrectDatabaseImplementation(DatabaseConnection conn) method that returns true if conn.getDatabaseProductName() equals whatever the MariaDB jdbc driver is returning.
You may also want to override the getDefaultDatabaseProductName() to return "mariadb" instead of MySQL so you can differentiate it with contexts

jOOQ MERGE support for PostgreSQL conditional insert

I had understood that jOOQ would simulate SQL MERGE on systems (such as PostgreSQL) that don't support it.
I have a table with a serial (autoincrement) "id" column and a string "uri" column. I want to use numeric IDs instead of URIs in my database, so I have to make sure I have a URI in the ID lookup table. So following the example in the jOOQ manual, I thought this would work:
createDSLContext().mergeInto(tableByName("uris"))
.using(createDSLContext().selectOne())
.on(fieldByName("uri").equal("http://example.com/"))
.whenNotMatchedThenInsert(fieldByName("uri"))
.values("http://example.com/").execute();
This gives me a DataAccessException saying something like:
SQL [merge into "uris" using (select 1) on "uri" = ? when not matched then insert ("uri") values (?)]; ERROR: syntax error at or near "merge"
But then the log says jOOQ goes ahead and tries to execute the query with bind values. But the table is never updated. So I'm guessing the jOOQ doesn't simulate MERGE on PostgreSQL?
So I then try the H2 database syntax:
createDSLContext().mergeInto(tableByName("uris"), fieldByName("uri")).values(uri.toString()).execute();
I get:
The H2-specific MERGE syntax is not supported in dialect : POSTGRES
What!? But the jOOQ documentation says that the H2 syntax "can be fully simulated by jOOQ for all other databases that support the SQL standard." Surely PostgreSQL supports the SQL standard. Does it really mean "...the SQL standard version of MERGE?"
Is there any way to get PostgreSQL support for MERGE via jOOQ, or am I stuck doing the same workarounds I would do anyway?
To be sure if a given SQL feature is supported by jOOQ for your database, please consider the Javadoc's #Support annotation on the relevant DSL method. This is also documented in the manual. In this case, DSLContext.mergeInto(), where you can see that this statement is currently only supported for these SQLDialects:
#Support(value={CUBRID,DB2,HSQLDB,ORACLE,SQLSERVER,SYBASE})
MERGE is a very powerful statement that is not really easy to emulate if your database doesn't natively support it.
"can be fully simulated by jOOQ for all other databases that support the SQL standard." Surely PostgreSQL supports the SQL standard. Does it really mean "...the SQL standard version of MERGE?"
Yes of course, the SQL standard MERGE statement must be supported :-) We'll clarify this in the manual. I have registered issue #3183 for this.
Is there any way to get PostgreSQL support for MERGE via jOOQ, or am I stuck doing the same workarounds I would do anyway?
Right now, unfortunately, we don't have a solution for this in PostgreSQL. Feel free to discuss possible solutions on the jOOQ User Group.
Yes , it can support which database support the merge in SQL stand.
but postgresql unsupport this feature in SQL standard.
Please see
F312 MERGE statement
F313 Enhanced MERGE statement
F314 MERGE statement with DELETE branch
http://www.postgresql.org/docs/9.3/static/unsupported-features-sql-standard.html

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.