I am usig liquibase for building database. And on startup of war the liquibase initializes Oracle db from application and makes it successfully. But in unit tests H2 db is used and here is a problem. Can't find smth similar in google. this is my changeset:
<changeSet author="Andriyanchik" id="EBS-639">
<sql endDelimiter="/">
CREATE OR REPLACE TRIGGER TR_SET_TYPE_NUMBER
BEFORE INSERT
ON PROVIDER
FOR EACH ROW
DECLARE
v_category_inc NUMBER;
BEGIN
SELECT MAX(TYPENUMBER) INTO v_category_inc FROM PROVIDER WHERE PRODUCTNAME = :NEW.PRODUCTNAME;
IF v_category_inc is null THEN
:NEW.TYPENUMBER := 0;
ELSE
:NEW.TYPENUMBER := v_category_inc + 1;
END IF;
END;
/
</sql>
</changeSet>
In H2 I am getting error:
Syntax error in SQL statement "CREATE OR REPLACE TRIGGER TR_SET_TYPE_NUMBER..."
expected "QUEUE, NOWAIT, AS, CALL"; SQL statement:
Related
We are using Postgres 13.0 version with Spring-Boot .sql file as an initial step.
I need to run an UPDATE script but only if the table itself already exists.
After some effort to understand what is the correct syntax I came with the following script:
ALTER TABLE IF EXISTS ONLY scm_repos ADD COLUMN IF NOT EXISTS token_id BIGINT;
DO '
BEGIN
IF EXISTS
(SELECT 1 FROM scm_repos WHERE id = 1)
THEN
UPDATE scm_repos repos SET token_id=(SELECT token_id FROM scm_orgs orgs WHERE repos.org_id=orgs.id);
END IF ;
END;
' ;
My intention is simple - to run the UPDATE script only if the scm_repos table does exists, but whatever I tried, I'm still getting the following error:
Failed to execute SQL script statement #5 of URL [jar:file:/app/cx-integrations-datastore.jar!/BOOT-INF/classes!/schema.sql]: DO '
BEGIN
IF EXISTS
(SELECT 1 FROM scm_repos WHERE id = 1)
THEN
UPDATE scm_repos repos SET token_id=(SELECT token_id FROM scm_orgs orgs WHERE repos.org_id=orgs.id);
END IF ;
END;
' ; nested exception is org.********ql.util.PSQLException: ERROR: relation "scm_repos" does not exist
Where: PL/pgSQL function inline_code_block line 3 at IF
What am I missing here?
13.0 has known unfixed bugs. 13.4 is the latest release of 13. There is almost never a good reason to run an old minor release version. Not that that seems to be relevant here.
But what you are missing here is that at the top level, EXISTS checks to see if a SELECT returns any rows. It does not check to see if tables mentioned in the FROM list of the SELECT exist or not, it assumes they do.
You could change your query so that it queries the catalog to see if the table exists, something like:
IF EXISTS
(SELECT 1 FROM pg_class where relname=$J$scm_repos$J$)
...
I have a Spring CRUD application, with an Oracle SQL database.
I have several integration tests and use the #Sql annotation to run .sql files which put the database in a desired state before running the test. I have had no problem with any of my .sql scripts so far, although they have all be very simple INSERT and DROP statements.
I am now trying to set up a scenario in which the database holds thousands of records in a particular table. I am not bothered about the content, only the number of records.
In order to replicate this scenario, I have written the following SQL script:
DECLARE
id integer := 1;
BEGIN
WHILE id <= 3000
LOOP
INSERT INTO USER (ID, FIRST_NAME, LAST_NAME, AGE)
VALUES (id, 'John', 'Smith', 32);
id := id + 1;
END LOOP;
END;
I have ran this script using IntelliJ and it works as expected.
However, when I put the script into a #Sql annotation, I run into the following error:
org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of class path resource [sql/setUp.sql]: DECLARE id integer := 1; nested exception is java.sql.SQLException: ORA-06550: line 1, column 23:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
* & = - + ; < / > at in is mod remainder not rem
<an exponent (**)> <> or != or ~= >= <= <> and or like like2
like4 likec between || multiset member submultiset
I am at a loss as to the solution; I have encountered similar issues where the solution was just a missing semi-colon, but that doesn't seem to be the case here.
What's even more mystifying is that I tried running the following script via the #Sql annotation:
BEGIN
INSERT INTO USER (ID, FIRST_NAME, LAST_NAME, AGE)
VALUES (1, 'John', 'Smith', 32);
END;
This produced the following error, which makes even less sense:
org.springframework.jdbc.datasource.init.ScriptStatementFailedException: Failed to execute SQL script statement #1 of class path resource [sql/test.sql]: BEGIN INSERT INTO USER (ID, FIRST_NAME, LAST_NAME, AGE) VALUES (1, 'John', 'Smith', 32); nested exception is java.sql.SQLException: ORA-06550: line 1, column 87:
PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following:
;
Most interesting to note is that removing the BEGIN and END statements (leaving just the INSERT INTO statement) works.
So does Spring JDBC simply not support BEGIN/END blocks? Are there limitations to the pre test #Sql annotation that I'm not aware of? Or have I missed something painfully obvious?
Thanks to #MarkRotteveel for his suggestion, I have discovered the solution to this issue.
JDBC was indeed running each line of the script as if it was a separate statement, which is incompatible with statement blocks. This is because the separator is set to the ; symbol by default, causing JDBC to treat each block of code ended with a ; as if it was a separate script. I set this separator to the EOF symbol, which caused JDBC to treat the whole file as a single script.
My original test code looked something like this:
#Sql(scripts = {"sql/cleanup.sql", "sql/setUp.sql"})
public void testWithThousandsOfRecords() {
// do tests
}
My test code now looks like this:
#Sql(scripts = "sql/cleanup.sql")
#Sql(scripts = "sql/setUp.sql", config = #SqlConfig(separator = ScriptUtils.EOF_STATEMENT_SEPARATOR))
public void testWithThousandsOfRecords() {
// do tests
}
Note that I had to separate my cleanup and setUp scripts, as changing the separator may break some scripts that worked before.
I'm trying to create a stored procedure in a MySQL database using the contents of a text file:
USE myDatabase;
DROP PROCEDURE IF EXISTS myStoredProcedure;
DELIMITER $$
CREATE PROCEDURE myStoredProcedure
(
_description VARCHAR(50),
_value INT
)
BEGIN
INSERT INTO myTable
(
description,
value
) VALUES (
_description,
_value
);
SELECT
id,
description,
value
FROM myTable
WHERE id = LAST_INSERT_ID();
END;
$$
DELIMITER ;
I execute the SQL using a native query:
Query query = entityManager.createNativeQuery(queryText);
...
query.executeUpdate();
But it gets an error on the DROP PROCEDURE
I commented out the DROP PROCEDURE and then it gets an error on the DELIMITER
Basically, it gets an error on any line after the first semicolon.
It seems as if JPA hibernate is parsing my query and telling me there's a problem with it rather than passing the unadulterated text onto MySQL.
The sql runs in MySQL without error.
I can't find anything in Google about creating a stored procedure with JPA, only calling one.
Does anyone have any insight on what I might be doing wrong? Or if this is even possible.
This can be possible if you mention the following property in the url
spring.datasource.url=jdbc:mysql://localhost:3306/test?allowMultiQueries=true
The allowMultiQueries will instruct the driver to sent delimited queries to the database.
Please note that if you are using native queries be-aware of sql injection attack.
You dont need to put the delimiter(DELIMITER) explicitly.The sql statement
The following query works
SET myDatabase;
DROP PROCEDURE IF EXISTS myStoredProcedure;
CREATE PROCEDURE myStoredProcedure ( _description VARCHAR(50), _value INT )
BEGIN
INSERT INTO
myTable ( description, value )
VALUES ( _description, _value );
SELECT id, description, value
FROM myTable
WHERE id = LAST_INSERT_ID();
END;
How can I create a stored procedure using JDBC? I've tried the following code, but it fails with errors.
Contents of the 'sql' variable which is used in jdbc code
CREATE PROCEDURE 'init'()
BEGIN
DECLARE '_rollback' BOOL DEFAULT 0;
DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET '_rollback' = 1;
START TRANSACTION;
DROP TABLE IF EXISTS tst;
CREATE TABLE IF NOT EXISTS tst
(
did INT AUTO_INCREMENT PRIMARY KEY,
stage INT
);
INSERT INTO tst (stage) VALUES (11);
INSERT INTO tst (stage) VALUES (23);
IF '_rollback'
THEN
ROLLBACK;
ELSE
COMMIT;
END IF;
END;
JDBC Code:
Statement statement = connection.createStatement();
statement.executeLargeUpdate(sql);
JDBC Error:
java.sql.SQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near ''create_and_populate_schema'()
BEGIN
DECLARE '_rollback' BOOL DEFAULT 0;
' at line 1
at com.mysql.cj.jdbc.exceptions.SQLError.createSQLException(SQLError.java:536)
I hope DELIMITER should not be set because it only works inside 'mysql' client and it seems that there is no any alternative with sql-String that is supposed to be used with JDBC
Why does this statement work fine in workbench but not in Java.
SET #sqlstmt := IF( #exist <= 0, 'select ''INFO: Key does not exist.''', 'ALTER TABLE `SOMETABLE` DROP FOREIGN KEY `SOMEKEY`');
In Java I get
MySQLSyntaxErrorException: You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'SET #sqlstmt := IF( #exist <= 0, 'select ''INFO: Key does not exist.''', 'ALTER ' at line 1
It turned out to be the fact that multiple statements were being executed (separated by semicolons). In JDBC MYSQL you need allowMultiQueries=true