Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Issue with executing procedure in spring boot schema.sql file

I am using schema.sql file to CREATE/DROP tables in my Spring Boot application and it works fine.

But when I have added procedure for altering table:

DELIMITER $$
CREATE PROCEDURE Alter_Table()
BEGIN
 IF NOT EXISTS( SELECT NULL
            FROM INFORMATION_SCHEMA.COLUMNS
           WHERE table_name = 'test_table'
             AND table_schema = 'test'
             AND column_name = 'cc_test_id')  THEN

  alter table test_table add cc_test_id VARCHAR(128) NOT NULL;

END IF;
END $$

call Alter_Table;

I received:

com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException exception.

However, execution of this procedure in MySQL workbench finishes with successful results.

So, should anyone know what is the reason for this issue, let me know?

like image 741
I. Domshchikov Avatar asked Oct 02 '15 08:10

I. Domshchikov


People also ask

What is DDL Auto in Spring boot?

ddl-auto explicitly and the standard Hibernate property values are none , validate , update , create , and create-drop . Spring Boot chooses a default value for you based on whether it thinks your database is embedded. It defaults to create-drop if no schema manager has been detected or none in all other cases.

How does spring boot project connect to database?

To access the Relational Database by using JdbcTemplate in Spring Boot application, we need to add the Spring Boot Starter JDBC dependency in our build configuration file. Then, if you @Autowired the JdbcTemplate class, Spring Boot automatically connects the Database and sets the Datasource for the JdbcTemplate object.


2 Answers

Here is the solution I found that works well enough, though it is not ideal as you have to change your SQL script.

In your application.properties file change the DataSource separator property:

spring.datasource.separator=^;

Then update your schema.sql file to look as follows:

CREATE PROCEDURE Alter_Table()
BEGIN
 IF NOT EXISTS( SELECT NULL
            FROM INFORMATION_SCHEMA.COLUMNS
           WHERE table_name = 'test_table'
             AND table_schema = 'test'
             AND column_name = 'cc_test_id')  THEN

  alter table test_table add cc_test_id VARCHAR(128) NOT NULL;

END IF;
END ^;

call Alter_Table ^;

The DELIMITER command only works with the MySQL CLI client and Workbench and will not work for Spring Boot database initialization. Once you have removed the DELIMITER commands, Spring Boot will still throw an exception as it will not understand the ; characters in the stored procedures are not separate statements, so you have to change the datasource separator property as a workaround.

like image 64
Andrew Avatar answered Sep 24 '22 02:09

Andrew


Here's the fix:

Set your spring.datasource.separator property to ^^^ END OF SCRIPT ^^^, and Spring Boot will execute your entire schema.sql script as a single statement.

Here's why:

Spring Boot splits your schema.sql script into statements, then sends each statement to the database individually for execution. By default, the script is split on semicolons, as that is the default value of the spring.datasource.separator property (per the documentation). This causes your schema.sql to be split, and the first statement executed is the following:

DELIMITER $$
CREATE PROCEDURE Alter_Table()
BEGIN
 IF NOT EXISTS( SELECT NULL
            FROM INFORMATION_SCHEMA.COLUMNS
           WHERE table_name = 'test_table'
             AND table_schema = 'test'
             AND column_name = 'cc_test_id')  THEN

  alter table test_table add cc_test_id VARCHAR(128) NOT NULL

This is invalid SQL because the dollar-quote is never terminated in the statement.

The javadoc for org.springframework.jdbc.datasource.init.ScriptUtils.EOF_STATEMENT_SEPARATOR provides a good explanation of how my suggested solution works:

End of file (EOF) SQL statement separator: "^^^ END OF SCRIPT ^^^".

This value may be supplied as the separator to executeSqlScript(Connection, EncodedResource, boolean, boolean, String, String, String, String) to denote that an SQL script contains a single statement (potentially spanning multiple lines) with no explicit statement separator. Note that such a script should not actually contain this value; it is merely a virtual statement separator.

like image 21
Aaron Avatar answered Sep 23 '22 02:09

Aaron