Liquibase Different Datatypes H2/Oracle - oracle

So I do have the following changeset in my dbchangelog:
<changeSet id="04_04_2018" author="codeit">
<createTable tableName="BSP_TABELLE">
<column name="name" type="varchar(255)"/>
<column name="datum" type="datetime"/>
<column name="richtigfalsch" type="boolean"/>
<column name="blub" type="blob"/>
<column name="club" type="clob"/>
<column name="ganzzahl" type="int"/>
<column name="grosseganzzahl" type="bigint"/>
<column name="gleitkommazahl" type="decimal(17,5)"/>
</createTable>
</changeSet>
In H2 I do get what I expected like:
CREATE TABLE BSP_TABELLE
(
NAME VARCHAR(255),
DATUM TIMESTAMP,
RICHTIGFALSCH BOOLEAN,
BLUB BLOB,
CLUB CLOB,
GANZZAHL INTEGER,
GROSSEGANZZAHL BIGINT,
GLEITKOMMAZAHL DECIMAL(17, 5)
)
But in Oracle I do get:
CREATE TABLE BSP_TABELLE
(
NAME VARCHAR2(255),
DATUM TIMESTAMP(6),
RICHTIGFALSCH NUMBER(1),
BLUB BLOB,
CLUB CLOB,
GANZZAHL NUMBER,
GROSSEGANZZAHL NUMBER,
GLEITKOMMAZAHL NUMBER(17, 5)
)
And I expected:
CREATE TABLE BSP_TABELLE
(
NAME VARCHAR2(255),
DATUM TIMESTAMP(6),
RICHTIGFALSCH NUMBER(1),
BLUB BLOB,
CLUB CLOB,
GANZZAHL NUMBER(10),
GROSSEGANZZAHL NUMBER(19,0),
GLEITKOMMAZAHL NUMBER(17, 5)
)
How can I achieve it, that the DataType for Oracle will fit, without modifying the datatypes in H2?
I am currently loading the changelog from the java implementation at runtime like:
Connection connection = openDatabaseConnection();
Database database = DatabaseFactory.getInstance().findCorrectDatabaseImplementation(new JdbcConnection(connection));
String[] validatedLiquibaseChangelogs = validateLiquibaseChangelogs();
for (String validatedChangelog : validatedLiquibaseChangelogs) {
Liquibase liquibase = new liquibase.Liquibase(validatedChangelog, new FileSystemResourceAccessor(), database);
//Updaten der Datenbank
liquibase.update(new Contexts(), new LabelExpression());
}

Related

Liquibase with column type numeric(x, y) is creating postgreSQL table with column type number

I have a spring application connected to a postgreSQL DB. My issue is that this bit of script:
<column name="utmx" type="numeric(20, 5)">
<constraints nullable="true"/>
</column>
<column name="utmy" type="numeric(20, 5)">
<constraints nullable="true"/>
</column>
Is being executed like this:
CREATE TABLE PUBLIC.table (... utmx NUMBER(20, 5), utmy NUMBER(20, 5)...
As you can see, the column type NUMERIC is being changed to NUMBER on table creation.
Why is that? How can I solve it?
Thanks in advance

Liquibase ignores autoIncrement="true" for Oracle DB

I generated a schema/tables via the DDL that Hibernate generated which was correct:
create table cat_component.organisation (
id number(19,0) generated as identity,
archived number(1,0),
is_in_avaloq_group number(1,0) not null,
mdm_uuid varchar2(255 char),
name varchar2(255 char),
primary key (id)
)
After that, I tried to generate Liquibase changelog which looks like this:
<changeSet author="blabla (generated)" id="1582733383680-5">
<createTable tableName="organisation">
<column autoIncrement="true" name="id" type="NUMBER(19, 0)">
<constraints primaryKey="true" primaryKeyName="organisationPK"/>
</column>
<column name="archived" type="NUMBER(1, 0)"/>
<column name="is_in_avaloq_group" type="NUMBER(1, 0)">
<constraints nullable="false"/>
</column>
<column name="mdm_uuid" type="VARCHAR2(255 CHAR)"/>
<column name="name" type="VARCHAR2(255 CHAR)"/>
</createTable>
</changeSet>
The problem is that if I try to run the liquibase changelog, it translates the XML definition into this:
2020-02-26 16:15:10.779 INFO 8064 --- [main] liquibase.executor.jvm.JdbcExecutor : CREATE TABLE CAT_COMPONENT.organisation (id NUMBER(19, 0) NOT NULL, archived NUMBER(1, 0), is_in_avaloq_group NUMBER(1, 0) NOT NULL, mdm_uuid VARCHAR2(255 CHAR), name VARCHAR2(255 CHAR), CONSTRAINT organisationPK PRIMARY KEY (id))
2020-02-26 16:15:10.787 INFO 8064 --- [main] liquibase.changelog.ChangeSet : Table organisation created
2020-02-26 16:15:10.787 INFO 8064 --- [main] liquibase.changelog.ChangeSet : ChangeSet classpath:/db/changelog/db.changelog-master.xml::1582733383680-5::blabla (generated) ran successfully in 9ms
As you may have noticed, "generated as identity" is missing, which
makes me believe that for whatever reason, the autoIncrement="true"
is ignored.
I use Oracle 12.1.0.2 and org.liquibase:liquibase-core 3.8.2.
The OJDBC driver is version 19.3.0.0.
The gradle properties are:
spring.datasource.url=jdbc:oracle:thin:#//host:1522/SID
spring.datasource.driverClassName=oracle.jdbc.OracleDriver
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
spring.jpa.properties.hibernate.show_sql=true
spring.jpa.properties.hibernate.format_sql=true
spring.datasource.username=user
spring.datasource.password=pass
spring.jpa.database-platform=org.hibernate.dialect.Oracle12cDialect
spring.jpa.show-sql=true
logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type=trace
spring.datasource.continue-on-error=true
spring.datasource.platform=oracle
spring.liquibase.url=${spring.datasource.url}
spring.liquibase.user=${spring.datasource.username}
spring.liquibase.password=${spring.datasource.password}
spring.liquibase.url=${spring.datasource.url}
spring.liquibase.user=${spring.datasource.username}
spring.liquibase.password=${spring.datasource.password}
spring.liquibase.change-log=classpath:/db/changelog/db.changelog-master.xml
spring.liquibase.default-schema=${spring.jpa.properties.hibernate.default_schema}
spring.liquibase.liquibase-schema=${spring.jpa.properties.hibernate.default_schema}
I've read the Internet, and I know that my Oracle version is compatible with this column type and I don't need to create extra oracle Sequences.
Any clue what could be the problem?
It seems to be a bug in Liquibase. I just found it here https://liquibase.jira.com/projects/CORE/issues/CORE-3524?filter=allissues&orderby=updated%20DESC&keyword=Oracle
As it states, there is a work-around to add the
generationType="BY DEFAULT"
at each column definition, where autoIncrement="true" has been used.
Correct the autoIncrement="true" is ignored due to the missing support on Oracle side for auto incremented columns as seen in the docs from liquienter link description here:
Is column an auto-increment column. Ignored on databases that do not
support autoincrement/identity functionality.
You will need to create a sequence for generating the IDs and providing the sequence to the id column when inserting the data i.e. with hibernate:
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "XXX_ID_GEN")
#SequenceGenerator(name = "XXX_ID_GEN", sequenceName = "SEQ_XXX")
long id;

Parsing multiple columns from XMLTYPE

I want to select data from a XML file using Oracle SQL.
Here is my XML file:
<worksheet>
<sheetData>
<row>
<column>
<value>0</value>
</column>
<column>
<value>1</value>
</column>
<column>
<value>2</value>
</column>
</row>
<row>
<column>
<value>3</value>
</column>
<column>
<value>4</value>
</column>
<column>
<value>5</value>
</column>
</row>
<row>
<column>
<value>6</value>
</column>
<column>
<value>7</value>
</column>
<column>
<value>8</value>
</column>
</row>
</sheetData>
</worksheet>
The following code is the SQL I'm using to extract the XML (minified in SQL query):
SELECT
*
FROM
XMLTABLE(
'for $i in worksheet/sheetData/row return $i'
PASSING XMLTYPE('<worksheet><sheetData><row><column><value>0</value></column><column><value>1</value></column><column><value>2</value></column></row><row><column><value>3</value></column><column><value>4</value></column><column><value>5</value></column></row><row><column><value>6</value></column><column><value>7</value></column><column><value>8</value></column></row></sheetData></worksheet>')
COLUMNS
column1 CLOB PATH 'column[1]/value',
column2 CLOB PATH 'column[2]/value'
) xml;
And this is the output:
---------------------
| COLUMN1 | COLUMN2 |
|---------|---------|
| 0 | 1 |
| 3 | 4 |
| 6 | 7 |
---------------------
You can see that the third <column> child of <row> is missing from the output but if I add column3 CLOB PATH 'column[3]/value' to the COLUMNS property, it will appear.
My problem is that the XML can have any number of <column> tags and since I don't know the count from the beginning, I can't define a fixed solution.
Can you help to tell me which modification should make my query to work for multiple <column> tags? Or which query should output a dynamic number of <column>?
Easy ways
Predefined redundant amount of columns.
SELECT
*
FROM
XMLTABLE(
'/worksheet/sheetData/row'
PASSING XMLTYPE('<worksheet><sheetData><row><column><value>0</value></column><column><value>1</value></column><column><value>2</value></column></row><row><column><value>3</value></column><column><value>4</value></column><column><value>5</value></column></row><row><column><value>6</value></column><column><value>7</value></column><column><value>8</value></column></row></sheetData></worksheet>')
COLUMNS
column_cnt number path 'count(column)',
column1 varchar2(4000) PATH 'column[1]/value',
column2 varchar2(4000) PATH 'column[2]/value',
--etc. ...
column10 varchar2(4000) path 'column[10]/value'
) xml;
Pivot the result
SELECT
row_nr,
col_nr,
col_value
FROM
XMLTABLE(
'/worksheet/sheetData/row'
PASSING XMLTYPE('<worksheet><sheetData><row><column><value>0</value></column><column><value>1</value></column><column><value>2</value></column></row><row><column><value>3</value></column><column><value>4</value></column><column><value>5</value></column></row><row><column><value>6</value></column><column><value>7</value></column><column><value>8</value></column></row></sheetData></worksheet>')
COLUMNS
columns_xml xmltype path '.',
row_nr FOR ORDINALITY
) xml
,xmltable('row/column' passing columns_xml
columns
col_nr for ordinality,
col_value varchar2(10) path './value/text()')
Hardcore approach.
Alway you can use pipelined table function.
1) Find max count of columns
2) Generate dynamic type
3) Populate dynamic type
4) Two days later enjoy the most sophisticated code written in pl sql :)
Good example of pipelline function below. This is not exactly what you need but you can build on it
Return dynamic result set from sys_refcursor

Problems creating tables for Oracle on H2 in memory DB

I can't seem to figure out the right combination to get this to work. I have generated DDL from Oracle QL developer with the Quick DDL and the get_ddl functions as well as written my own SQL. All work fine in SQL Plus and SQL Developer, but I can't figure out how to get H2 to accept the SQL.
Ive tried different variations, left off the schema name, etc. Nothing seems to work.
SQL:
CREATE TABLE TEST_SCHEMA.SAVED_SEARCHES(
SEARCHID INT GENERATED ALWAYS AS IDENTITY AUTO_INCREMENT BY 1 START WITH 1 NOT NULL,
NAME VARCHAR2(30) NOT NULL,
USERID VARCHAR2(32 BYTE),
WORKGROUPID VARCHAR2(50 BYTE),
ONECLICK VARCHAR2(1 BYTE) NOT NULL
)
Connection properties:
<Context reloadable="true" crossContext="true">
<Resource
name="jdbc/cts"
auth="Container"
type="javax.sql.DataSource"
removeAbandoned="true"
removeAbandonedTimeout="30"
maxActive="100"
maxIdle="30"
maxWait="10000"
username="test_schema"
password="oracle"
driverClassName="com.test.h2.H2Driver"
url="jdbc:testh2:mem:testdb;MODE=Oracle;DB_CLOSE_DELAY=-1;INIT=CREATE SCHEMA IF NOT EXISTS TEST_SCHEMA\;SET SCHEMA TEST_SCHEMA"
validationQuery="SELECT 1 FROM DUAL"
/>
</Context>
Error:
Syntax error in SQL statement: expected "(, NOT, NULL_TO_DEFAULT, SEQUENCE, SELECTIVITY, COMMENT, CONSTRAINT, PRIMARY, UNIQUE, NOT, NULL, CHECK, REFERENCES, ,, )"; SQL statement:
Start from studying a syntax of CREATE TABLE statement in H2 database:
http://www.h2database.com/html/grammar.html#create_table
A simplified syntax is:
CREATE TABLE name (
columnDefinition,
columnDefinition,
....
);
where columnDefinition is:
http://www.h2database.com/html/grammar.html#column_definition
columnName dataType [ AUTO_INCREMENT | IDENTITY [ (startInt [,incrementInt ] ) ]]
where elements withins [] brackets are optional
As you see Oracle's syntax:
columnName dataType GENERATED ALWAYS AS IDENTITY AUTO_INCREMENT BY 1 START WITH 1
is completely different than H2's syntax:
columnName dataType IDENTITY (1,1)
You need to rewrite the CREATE TABLE statement by hand to adapt it to H2 database.
Also H2 doesn't alows for VARCHAR2 and (50 BYTE) length
you need to use just VARCHAR( 50 ) or more than 50, see this link:
http://www.h2database.com/html/datatypes.html#varchar_type

How to get Oracle next sequence value in liqiibase 1.9.5 for insert

How to get Oracle next sequence value in liqiibase 1.9.5 for insert
<changeSet author="MIGRATE" id="070214010049877">
<insert tableName="MYTABLE">
<column name="ID" valueNumeric=" nextval( 'MYTABLE_SEQ' ) "/>
<column name="NUMBER" value="5"/>
</insert>
</changeSet>
it is trying to put the value of ID " nextval( 'MYTABLE_SEQ' )" in table so it gives error
With Liquibase 1.9.5, there is no support for finding the next sequence value with the <insert> tag. You will have to either drop back to using <sql> or use <modifySql> assuming that existed in 1.9.5.

Resources