5

Description

I am working as a new member on a Spring Boot Project that utilizes 2 different properties files for 2 different configurations related to DB settings:

  • production mode: postgres SQL DB
  • development mode: h2 in memory DB

Since I'm trying to minimize differences in the two scripts, I have started writing functions that will take case of differences related to date/time handling.

One example is adding hours since postgres uses intervals and h2 uses the oracle similar date_add function.

Unfortunately I am getting an exception for function creation statements that work in the console.

Existing Files

Config/Properties

spring.profiles.active=pre-prod

spring.datasource.url=jdbc:postgresql://localhost:5432/db
spring.datasource.username=postgres
spring.datasource.password=root
spring.datasource.driver-class-name=org.postgresql.Driver

spring.datasource.data=classpath:db/migration/postgres/db_functions.sql,classpath:db/migration/postgres/data.sql
spring.jpa.hibernate.ddl-auto=create

db_functions.sql

--Adds a cast to date to the specific statement
--for h2 simply make a wrapper
CREATE OR REPLACE FUNCTION db_pgres_cast_varchar_to_date(d VARCHAR ) RETURNS date AS $$
        BEGIN
                RETURN d::date;
        END;
$$ LANGUAGE plpgsql;

--Common function for h2 and vct to add hours
--References: http://stackoverflow.com/questions/9376350/postgresql-how-to-concat-interval-value-2-days
CREATE OR REPLACE FUNCTION db_add_hours(d timestamp, hours int) RETURNS timestamp AS $$
        BEGIN
                RETURN d +  (hours || ' hours')::interval;
        END;
$$ LANGUAGE plpgsql;

Exception

NFO] org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor Shutting down ExecutorService 'createTaskExecutor'
Exception in thread "main" org.springframework.jdbc.datasource.init.UncategorizedScriptException: Failed to execute database script from resource [class path resource [db/migration/postgres/vct_functions.sql]]; nested exception is java.lang.ArrayIndexOutOfBoundsException
    at org.springframework.jdbc.datasource.init.ScriptUtils.executeSqlScript(ScriptUtils.java:509)

Update

I started debugging and see that instead of the split/parser code creating 2 statements, my scripts are being interpreted as 6 SQL commands:

enter image description here

Update 2

The problem seems to be with the implementation of splitSqlScript, definition:

public static void splitSqlScript(EncodedResource resource, String script, String separator, String commentPrefix,
            String blockCommentStartDelimiter, String blockCommentEndDelimiter, List<String> statements)
            throws ScriptException

https://www.codatlas.com/github.com/spring-projects/spring-framework/HEAD/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ScriptUtils.java?line=166

Update 3

Since Spring Utils of Spring seems to be the problem I am trying a different syntax to create my functions:

--Adds a cast to date to the specific statement
--for h2 simply a wrapper
CREATE OR REPLACE FUNCTION vct_pgres_cast_varchar_to_date(VARCHAR ) RETURNS date
    AS 'select $1::date;'
    LANGUAGE SQL
    RETURNS NULL ON NULL INPUT;


--Common function for h2 and vct to add hours
--References: http://stackoverflow.com/questions/9376350/postgresql-how-to-concat-interval-value-2-days

CREATE OR REPLACE FUNCTION vct_add_hours(timestamp, integer) RETURNS timestamp
    AS 'select $1 +  ($2 || '' hours'')::interval'
    LANGUAGE SQL
    RETURNS NULL ON NULL INPUT;
Menelaos
  • 23,508
  • 18
  • 90
  • 155
  • 1
    Make sure you're using the latest PgJDBC, older versions IIRC had issues with `$$` quoting. Are you sure that's the bottom exception on the stack? – Craig Ringer Oct 15 '15 at 09:00
  • @Craig Ringer Please see update... it seems the parser is even interpreting ';' as a delimiter. I will also check if `$$` is the problem. – Menelaos Oct 15 '15 at 09:06
  • The exception reports `vct_functions.sql` instead of `db_functions.sql`. A typing mistake? – Tom-db Oct 15 '15 at 09:17
  • @Tommaso Di Bucchianico No, I generally change the names of stuff in my code excepts on stackoverflow. The name of the SQL file is not the issue, thanks. – Menelaos Oct 15 '15 at 09:18
  • @Craig Ringer Does `9.4-1200-jdbc4` have this issue? – Menelaos Oct 15 '15 at 09:24

2 Answers2

2

The problem is SplitSqlScript of spring: https://www.codatlas.com/github.com/spring-projects/spring-framework/HEAD/spring-jdbc/src/main/java/org/springframework/jdbc/datasource/init/ScriptUtils.java?line=166

I worked through this by changing the syntax of my create function statement to avoid $$ and enclose the SQL statement within quotes.

E.g.

CREATE OR REPLACE FUNCTION vct_pgres_cast_varchar_to_date(VARCHAR ) RETURNS date
    AS 'select $1::date;'
    LANGUAGE SQL
    RETURNS NULL ON NULL INPUT;
Menelaos
  • 23,508
  • 18
  • 90
  • 155
0

I had this issue today, trying to load a PostGreSQL dump file containing a stored procedure. The SP had ; within the block, and there is no way to "escape" this. I got the ScriptUtils.executeSqlScript call to work by changing the delimiter from ; to this:

https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/jdbc/datasource/init/ScriptUtils.html#EOF_STATEMENT_SEPARATOR

ScriptUtils.executeSqlScript(dataSource.getConnection(), new EncodedResource(resourceLoader.getResource(String.format("file:%s%s", getCwd(), SCHEMA_SQL_FILE))), false, false, DEFAULT_COMMENT_PREFIX, EOF_STATEMENT_SEPARATOR, DEFAULT_BLOCK_COMMENT_START_DELIMITER, DEFAULT_BLOCK_COMMENT_END_DELIMITER);

The constants I'm using in the parameters can be imported via:

import static org.springframework.jdbc.datasource.init.ScriptUtils.*;
Mike Melusky
  • 515
  • 2
  • 7
  • 19