Flyway h2 postgressql mode migration not working - java

I have to following migration working in postgres:
ALTER TABLE task_def
DROP COLUMN retry_count,
DROP COLUMN timeout_seconds;
(and running in prod)
but now i want to switch to h2 for my unit test but h2 doesnt seem to accept it
My database config in spring boot:
spring.datasource.url=jdbc:h2:./target/testdb;MODE=PostgreSQL
spring.datasource.username="sa"
spring.datasource.password=""
spring.jpa.hibernate.ddl-auto=none
spring.datasource.driver-class-name=org.postgresql.Driver
spring.flyway.url=jdbc:h2:./target/testdb;MODE=PostgreSQL
spring.flyway.user="sa"
spring.flyway.password=""
spring.flyway.schemas=
The error:
Migration V3__.....sql failed
---------------------------------------
SQL State : 42S22
Error Code : 42122
Message : Column "DROP" not found; SQL statement:
ALTER TABLE task_def
DROP COLUMN retry_count,
DROP COLUMN timeout_seconds [42122-200]
Location : db/migration/V3__.....sql
Line : 1
Statement : ALTER TABLE task_def
DROP COLUMN retry_count,
DROP COLUMN timeout_seconds

I haven't worked with H2 but it looks like it supports the following:
2 Statements instead of one in the same migration (flyway should run them in the same transaction anyway):
ALTER TABLE task_def DROP COLUMN retry_count;
ALTER TABLE task_def DROP COLUMN timeout_seconds;
Use different syntax:
ALTER TABLE task_def DROP COLUMN retry_count, timeout_seconds;
Of course if postgresql allows to do so as well.
All in all, I don't think that H2 will be able to cover all the features offered by postgres with its dialect, so failures like this can't be avoided.
So in my experience the following approach works much better:
Create a "test container" of postgres (see testcontainers project) and configure flyway / data source to run against it in tests. Depending on your tests infrastructure you can even not stop the container, but drop the database and run flyway before each test case. Or alternatively you can do like in spring tests - create an artificial transaction before running the test and "fail" it when the test finishes (even if it finishes successfully) so that the db won't be dirty for the next test.

There is no portable way to drop multiple columns at once, ALTER TABLE … DROP COLUMN is a standard command, but only for one column.
Some databases, however, including PostgreSQL and H2, support such non-standard feature, but their syntax is different. PostgreSQL expects
ALTER TABLE tableName DROP COLUMN columnName1, DROP COLUMN columnName2, …
https://www.postgresql.org/docs/12/sql-altertable.html
H2 expects
ALTER TABLE tableName DROP COLUMN columnName1, columnName2, …
https://h2database.com/html/commands.html#alter_table_drop_column
If you use different databases, you should avoid non-portable commands when possible.

Related

H2 memory DB test can't find table TAB

I use H2 memory DB to do my test integration and my real BD is oracle DB
jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;Mode=Oracle
When I want to use this SQL to check if my table exists
SELECT TNAME FROM TAB WHERE TNAME='myTableName'
But in the execution test, I got the error message "Table "TAB" not found".
What could I do to use this oracle table?
Create the table TAB in integration script sql and simule the fonctionnement Oracle ...

Oracle NUMBER(precision,scale) in HSQLDB

In a unit test I am trying to generate a table in an in-mem HSQLDB, the table contains a column with the definition: #Column(name = "xxx", columnDefinition="NUMBER(10,0) default 0"). NUMBER is not recognized by HSQLDB (version 2.3.3), so I have added a script running this statement first: CREATE TYPE NUMBER AS NUMERIC;. Now it seems to recognize NUMBER, but I get the error unexpected token: ( instead. I cannot edit the column definition, so wow do I correctly map Oracle NUMBER(10,0) to NUMERIC? If I remove the precision and scale from NUMBER it seems to work.
You do not need to define the NUMBER type, as it is supported by HSQLDB.
HSQLDB supports Oracle syntax in one of its compatibility modes. Run this statement to enable it:
SET DATABASE SQL SYNTAX ORA TRUE

Change Table names in derby database using entitymanager

I am using an APACHE DERBY database, and basing my database interactions on EntityManager, and I don't want to use JDBC class to build a query to change my tables' names (i just need to put a prefix to each new user to the application, but have the same structure of tables), such as:
//em stands for EntityManager object
Query tableNamesQuery= em.createNamedQuery("RENAME TABLE SCHEMA.EMP_ACT TO EMPLOYEE_ACT");
em.executeUpdate();
// ... rest of the function's work
// The command works from the database command prompt but i don't know how to use it in a program
//Or as i know you can't change system tables data, but here's the code
Query tableNamesQuery= em.createNamedQuery("UPDATE SYS.SYSTABLES SET TABLENAME='NEW_TABLE_NAME' WHERE TABLETYPE='T'");
em.executeUpdate();
// ... rest of the function's work
My questions are :
This syntax is correct?
Will it work?
Is there any other alternative?
Should I just use the SYS.SYSTABLES and find all the tables that has 'T' as tabletype and alter their name their, will it change the access name ?
I think you're looking for the RENAME TABLE statement: http://db.apache.org/derby/docs/10.10/ref/rrefsqljrenametablestatement.html
Don't just issue update statements against the system catalogs, you will corrupt your database.

Why is Hibernate generating this SQL query?

I'm using Hibernate and a MySql server. I use multiple databases as "namespaces" (e.g. users, transactions, logging etc.).
So, I configued Hibernate to NOT connect to a particular database :
url = jdbc:mysql://127.0.0.1/
The databases where tables are located are defined in the hbm files through the catalog attribute :
<class name="com.myApp.entities.User" table="user" schema="" catalog="users"> ...
When I want to load some data, everything works fine and Hibernate seems to generate the expected SQL queries (by using the catalog prefix in the table names) e.g. :
select id from users.user
However, when I try to add a new record, Hibernate don't use the from [catalog].[table_name] syntax anymore. So I get a MySQL error 'No database selected'.
select max(id) from user
Hibernate is trying the get the future id to create a new record, but it doesn't specify in which database is located the table, it should be :
select max(id) from users.user
Why is Hibernate generating this invalid query ? Have someone ever experienced this problem ?
You need to specify the schema for the generator. See this question on SO for a more detailed answer.

Spring's JdbcDaoSupport (using MySQL Connector/J) fails after executing sql that adds FK

I am using Spring's JdbcDaoSupport class with a DriverManagerDataSource using the MySQL Connector/J 5.0 driver (driverClassName=com.mysql.jdbc.driver). allowMultiQueries is set to true in the url.
My application is an in-house tool we recently developed that executes sql scripts in a directory one-by-one (allows us to re-create our schema and reference table data for a given date, etc, but I digress). The sql scripts sometime contain multiple statements (hence allowMultiQueries), so one script can create a table, add indexes for that table, etc.
The problem happens when including a statement to add a foreign key constraint in one of these files. If I have a file that looks like...
--(column/constraint names are examples)
CREATE TABLE myTable (
fk1 BIGINT(19) NOT NULL,
fk2 BIGINT(19) NOT NULL,
PRIMARY KEY (fk1, fk2)
);
ALTER TABLE myTable ADD CONSTRAINT myTable_fk1
FOREIGN KEY (fk1)
REFERENCES myOtherTable (id)
;
ALTER TABLE myTable ADD CONSTRAINT myTable_fk2
FOREIGN KEY (fk2)
REFERENCES myOtherOtherTable (id)
;
then JdbcTemplate.execute throws an UncategorizedSqlException with the following error message and stack trace:
Exception in thread "main" org.springframework.jdbc.UncategorizedSQLException: StatementCallback; uncategorized SQLException for SQL [ THE SQL YOU SEE ABOVE LISTED HERE ];
SQL state [HY000]; error code [1005]; Can't create table 'myDatabase.myTable' (errno: 150); nested exception is java.sql.SQLException: Can't create table 'myDatabase.myTable' (errno: 150)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:83)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:80)
and the table and foreign keys are not inserted.
Also, especially weird: if I take the foreign key statements out of the script I showed above and then place them in their own script that executes after (so I now have 1 script with just the create table statement, and 1 script with the add foreign key statements that executes after that) then what happens is:
tool executes create table script, works fine, table is created
tool executes add fk script, throws the same exception as seen above (except errno=121 this time), but the FKs actually get added (!!!)
In other words, when the create table/FK statements are in the same script then the exception is thrown and nothing is created, but when they are different scripts a nearly identical exception is thrown but both things get created.
Any help on this would be greatly appreciated. Please let me know if you'd like me to clarify anything more.
Some more info:
1) This only happens on my box. My coworker does not get the same problem.
2) The script that forces the tool to error works fine when executed from the mysql command line using the "script" command
My God.
http://bugs.mysql.com/bug.php?id=41635
and
[2nd link removed because spam filter isn't letting me add 2 links. Search Google for "mysql connector / j errno 150" and it's the 3rd result]
...
Looks like mySql5.1 has a bug with its jdbc connector where it bombs where an alter statement to add a FK is in a script with any other statement.
When I broke out my 3 statements into 3 scripts, it worked (the way I was trying before with the 2 fk statements in their own script still bombed because they were sharing a script!!). Also, my coworker is using MySql5.0, so it didn't affect him.
Holy Cow, that was a fun 5 hours.

Categories