Understanding SLQ syntax error in Flyway initial migration - spring-boot

I am configuring Flyway for a brand new Spring Boot project. This is the initial migration provided by DBA.
The application works in SQL Server, however I am struggling to make it work on H2 for in-memory testing purposes. The DBA didn't provide (and maybe is not going to provide) a dialect-neutral version of the DDL.
I tried to use H2's SQL Server mode
application.yaml
spring:
datasource:
url: jdbc:h2:mem:almc-be;Mode=MSSQLServer
flyway:
check-location: true
enabled: true
encoding: utf-8
locations: classpath:/flyway/${spring.datasource.platform:sqlserver}
create-schemas: true
default-schema: dbo
schemas: dbo
Beginning of the script
-- Create tables section -------------------------------------------------
-- Table dbo.Users
CREATE TABLE [dbo].[Users]
(
[UserId] Int NOT NULL,
[UserName] Nvarchar(50) NOT NULL,
[UserSurname] Nvarchar(50) NOT NULL,
[UserEmail] Nvarchar(100) NOT NULL
)
go
-- Add keys for table dbo.Users
On startup, I get the following error
2021-07-22 15:48:43.189 WARN 6316 --- [ restartedMain] ConfigServletWebServerApplicationContext : Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.internal.command.DbMigrate$FlywayMigrateException:
Migration V202107221432__DDL.sql failed
---------------------------------------
SQL State : 42000
Error Code : 42000
Message : Syntax error in SQL statement "CREATE TABLE ""dbo"".""Users""
(
""UserId"" INT NOT NULL,
""UserName"" NVARCHAR(50) NOT NULL,
""UserSurname"" NVARCHAR(50) NOT NULL,
""UserEmail"" NVARCHAR(100) NOT NULL
)
GO[*]
ALTER TABLE ""dbo"".""Users"" ADD CONSTRAINT ""PK_Users"" PRIMARY KEY (""UserId"")
GO
Yes, the escape sequence is changed in the logs from the SQL file
What is the cause of the error and how can I fix it without rewriting the script into a dialect-neutral version myself?

Related

Tests fail to run with H2 database on Micronaut project with Flyway migrations

I've got a unit test suite in a Micronaut 2.0.3 project that's supposed to run on an H2 DB. Since I started using Flyway for my DB migrations, I'm getting an error coming from H2 being unable to run the migrations.
The error is
Bean definition [javax.sql.DataSource] could not be loaded: Migration V1__schema.sql failed
-------------------------------
SQL State : 42001
Error Code : 42001
Message : Syntax error in SQL statement "CREATE DATABASE[*] IF NOT EXISTS MY_DB"; expected "OR, FORCE, VIEW, ALIAS, SEQUENCE, USER, TRIGGER, ROLE, SCHEMA, CONSTANT, DOMAIN, TYPE, DATATYPE, AGGREGATE, LINKED, MEMORY, CACHED, LOCAL, GLOBAL, TEMP, TEMPORARY, TABLE, SYNONYM, PRIMARY, UNIQUE, HASH, SPATIAL, INDEX"; SQL statement:
CREATE DATABASE if not exists my_db [42001-200]
Location : db/migration/V1__schema.sql (/somelocation/build/resources/main/db/migration/V1__schema.sql)
Line : 1
Statement : CREATE DATABASE if not exists my_db
io.micronaut.context.exceptions.BeanInstantiationException: Bean definition [javax.sql.DataSource] could not be loaded: Migration V1__schema.sql failed
-------------------------------
My application.yml is configured to point at a MariaDB instance in Azure like so:
micronaut:
application:
name: myapp
server:
context-path: /myapp/api
cors:
enabled: true
endpoints:
all:
enabled: true
sensitive: false
datasources:
default:
url: jdbc:mariadb://${ENV_DB_HOST_PORT:myurl.mariadb.database.azure.com}:${ENV_DB_PORT:3306}/${ENV_DB_SCHEMA:my_db}?useSSL=${ENV_DB_USE_SSL:true}&useUnicode=true&serverTimezone=Europe/London&autoReconnect=true
driverClassName: org.mariadb.jdbc.Driver
username: myusername
password: mypassword
dialect: MYSQL
allow-pool-suspension: false
connection-test-query: SELECT 1
connection-timeout: 30000
max-lifetime: 60000
maximum-pool-size: 10
minimum-idle: 1
flyway:
datasources:
default:
enabled: true
But my application-test.yml points at the H2 DB for testing purposes:
datasources:
default:
url: jdbc:h2:mem:devDb;LOCK_TIMEOUT=10000;DB_CLOSE_ON_EXIT=FALSE
driverClassName: org.h2.Driver
username: sa
password: ''
jpa:
default:
properties:
hibernate:
hbm2ddl:
auto: update
And my migration file V1__schema.sql looks like the following:
CREATE DATABASE if not exists my_db;
use my_db;
DROP TABLE IF EXISTS `preset`;
CREATE TABLE `preset` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`preset_name` varchar(30) NOT NULL,
`preset_value` varchar(4000) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
DROP TABLE IF EXISTS `note`;
CREATE TABLE `note` (
`ID` int(11) NOT NULL AUTO_INCREMENT,
`code` varchar(30) NOT NULL,
`text` varchar(4000) DEFAULT NULL,
PRIMARY KEY (`ID`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
The error is pretty much self explanatory
Message : Syntax error in SQL statement "CREATE DATABASE[*] IF NOT EXISTS MY_DB";
CREATE DATABASE if not exists my_db;
According to H2 commands, CREATE DATABASE is not a valid command for H2. You probably need the command CREATE SCHEMA if not exists my_db;

Oracle and H2 number data type incompatibility

I am using Flyway for my Spring boot app (working with Oracle DB). I have a new script which will create a table with a number field, something like:
CREATE TABLE ENGINEER (
...
SALARY NUMBER(*, 2),
...
);
I want to debug the app with H2 database and it will run the script. H2 documentation says that NUMBER(precision, scale) is a valid data type but seems that it does not support * for precision as Oracle. So that I cannot debug it with H2, when I run the script cannot be run successfully:
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2020-08-21 18:19:47.026 ERROR 25932 --- [ main] o.s.boot.SpringApplication : Application run failed
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'flywayInitializer' defined in class path resource [org/springframework/boot/autoconfigure/flyway/FlywayAutoConfiguration$FlywayConfiguration.class]: Invocation of init method failed; nested exception is org.flywaydb.core.internal.command.DbMigrate$FlywayMigrateException:
Migration <file-name>.sql failed
-------------------------------------------
SQL State : 42001
Error Code : 42001
Message : Syntax error in SQL statement "
CREATE TABLE ENGINEER(
...
SALARY NUMBER(*, 2),
...
)"; expected "long"; SQL statement:
CREATE TABLE ENGINEER(
...
SALARY NUMBER(*, 2),
...
) [42001-200]
Location : sql/db/migration/v04/<file-name>.sql
Line : 1
Is there any way to do so that I can keep the migration script like above but still able to debug with H2 anytime I want?
Thanks

Spring H2 created table not found after successful creation

I am using Spring Boot's schema.sql magic to create an in memory H2 database. The script contains the following statements:
create table PERSON
(
ID BIGINT not null primary key,
NAME VARCHAR(255) not null
);
create index IDX_PERSON_NAME on PERSON (NAME);
Upon launch Spring Boo fails with the following exception:
Caused by: org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #2 of URL [file:/D:/git/.../build/resources/main/schema.sql]: create index IDX_PERSON_NAME on PERSON (NAME); nested exception is org.h2.jdbc.JdbcSQLSyntaxErrorException: Table "PERSON" not found; SQL statement:
create index IDX_PERSON_NAME on PERSON (NAME) [42102-200]
How can the statement fail to find the table that was created in the preceding statement?
Simply because NAME is not mentioned as Unique constraint, you have only specified it as NOT NULL constraint
create table PERSON
(
ID BIGINT not null primary key,
NAME VARCHAR(255) not null,
CONSTRAINT Person_Name_Unique UNIQUE (NAME)
);
create index IDX_PERSON_NAME on PERSON (NAME);
Here are the possible reasons,
The schema needs to be mentioned on while referring to table like test_schema.person
Your syntax for creating the index might be wrong. Refer to this link for H2 Syntax,https://www.baeldung.com/spring-yaml

PostgreSQL 9.4 create table if not exists

I created tables on heroku using the following DDL.
CREATE TABLE IF NOT EXISTS "Team"(
"id" SERIAL,
"name" varchar(50) NOT NULL,
"description" varchar(255)
);
CREATE TABLE IF NOT EXISTS "Member"(
"id" SERIAL,
"name" varchar(50) NOT NULL,
"emp_number" integer NOT NULL,
"position" varchar(100) NOT NULL,
"team_id" integer references "Team"("id")
);
I got the following error:
play.api.UnexpectedException: Unexpected exception[ProvisionException: Unable to provision, see the following errors:
1) Error injecting constructor, javax.persistence.PersistenceException: Unable to execute JPA schema generation create command [CREATE TABLE IF NOT EXISTS "Team"(]
at play.db.jpa.DefaultJPAApi$JPAApiProvider.<init>(DefaultJPAApi.java:35)
at play.db.jpa.DefaultJPAApi$JPAApiProvider.class(DefaultJPAApi.java:30)
...
1 error]
at play.api.http.DefaultHttpErrorHandler.onServerError(HttpErrorHandler.scala:191) ~[com.typesafe.play.play_2.11-2.4.2.jar:2.4.2]
at play.api.http.HttpErrorHandlerExceptions$.throwableToUsefulException(HttpErrorHandler.scala:261) ~[com.typesafe.play.play_2.11-2.4.2.jar:2.4.2]
at play.api.GlobalSettings$class.onError(GlobalSettings.scala:179) [com.typesafe.play.play_2.11-2.4.2.jar:2.4.2]
...
Caused by: com.google.inject.ProvisionException: Unable to provision, see the following errors:
1) Error injecting constructor, javax.persistence.PersistenceException: Unable to execute JPA schema generation create command [CREATE TABLE IF NOT EXISTS "Team"(]
at play.db.jpa.DefaultJPAApi$JPAApiProvider.<init>(DefaultJPAApi.java:35)
...
1 error
at com.google.inject.internal.InjectorImpl$2.get(InjectorImpl.java:1025) ~[com.google.inject.guice-4.0.jar:na]
at com.google.inject.internal.InjectorImpl.getInstance(InjectorImpl.java:1051) ~[com.google.inject.guice-4.0.jar:na]
...
Caused by: javax.persistence.PersistenceException: Unable to execute JPA schema generation create command [CREATE TABLE IF NOT EXISTS "Team"(]
at org.hibernate.jpa.internal.schemagen.GenerationTargetToDatabase.acceptCreateCommands(GenerationTargetToDatabase.java:64) ~[org.hibernate.hibernate-entitymanager-4.3.9.Final.jar:4.3.9.Final]
...
Caused by: org.postgresql.util.PSQLException: ERROR: syntax error at end of input
at org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl$4.perform(EntityManagerFactoryBuilderImpl.java:850) ~[org.hibernate.hibernate-entitymanager-4.3.9.Final.jar:4.3.9.Final]
...
Position: 35
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2270) ~[org.postgresql.postgresql-9.4-1201-jdbc41.jar:9.4]
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1998) ~[org.postgresql.postgresql-9.4-1201-jdbc41.jar:9.4]
...
The error is quite obvious. The SQL contains errors. I am quite new to postgres sql. At least I know the current version used by heroku supports if not exists syntax but I am not sure where I went wrong.
Is anybody good at PostgreSQL here?
If you had run this query directly, you would have gotten the error:
ERROR: there is no unique constraint matching given keys for referenced table "Team"
This gives you a clue that there's something missing to identify the columns in the "Team" table uniquely. You have declared that the ids of the tables are serials, but forgot to add primary key constraints. Adding this, will let you execute the query:
CREATE TABLE IF NOT EXISTS "Team"(
"id" SERIAL primary key,
...
);
CREATE TABLE IF NOT EXISTS "Member"(
"id" SERIAL primary key,
...
);

Can't use HSQL sequences in JUnit

I'm trying to run a JUnit test class for my Spring-Batch application. I had to create the following tables: http://static.springsource.org/spring-batch/reference/html/metaDataSchema.html. I create them in my initialization database script, including the following:
CREATE SEQUENCE BATCH_STEP_EXECUTION_SEQ;
CREATE SEQUENCE BATCH_JOB_EXECUTION;
CREATE SEQUENCE BATCH_JOB_SEQ;
The creation of all sequences and tables didn't generate any errors. But while executing my JUnit test, I get the following error:
org.springframework.dao.DataAccessResourceFailureException: Could not obtain identity(); nested exception is java.sql.SQLSyntaxErrorException: user lacks privilege or object not found: BATCH_JOB_SEQ
at org.springframework.jdbc.support.incrementer.HsqlMaxValueIncrementer.getNextKey(HsqlMaxValueIncrementer.java:119)
That is caused when the class HsqlMaxValueIncrementer runs:
stmt.executeUpdate("insert into " + getIncrementerName() + " values(null)");
What am I doing wrong?
Thanks!!
For HSQLDB the 3 tables need the ID field.
CREATE TABLE BATCH_STEP_EXECUTION_SEQ (
ID BIGINT IDENTITY
);
CREATE TABLE BATCH_JOB_EXECUTION_SEQ (
ID BIGINT IDENTITY
);
CREATE TABLE BATCH_JOB_SEQ (
ID BIGINT IDENTITY
);
Reference: https://github.com/SpringSource/spring-batch/blob/master/spring-batch-core/src/main/resources/org/springframework/batch/core/schema-hsqldb.sql

Resources