Error getting H2 with r2dbc running in Spring boot - spring

for days now I've been trying to get a simple H2 / R2dbc database running in Spring boot with WebFlux. The app starts up just fine but when I call the /todos endpoint to get all the objects in the database I get the following error:
reactor.core.Exceptions$ErrorCallbackNotImplemented: org.springframework.data.r2dbc.BadSqlGrammarException: executeMany; bad SQL grammar [SELECT TODO.* FROM TODO]; nested exception is io.r2dbc.spi.R2dbcBadGrammarException: [42102] [42S02] Table "TODO" not found; SQL statement:
SELECT TODO.* FROM TODO [42102-200]
My understanding is that if I add a schema.sql file on the class path with a create table command it will use that to create the table on startup, but it does not look like that is working. Any ideas on what I may be doing wrong? Any help would be appreciated, what would like to get to is a working mysql/r2dbc example, if someone could point me to one.
All the code is located at: https://gitlab.com/vanfleet/test-r2dbc-h2

It is query issue. Run same query in editor.

Related

Springboot 2.7.2 with Hibernate 5.6 Error ORA 32575 during INSERT

Using Springboot 2.7.2 and Hibernate 5.6 with Oracle 12.2 to write a web application. I use the repository model to do an insert and test with mockmvc. With SQL Debug turned on I get an error ORA 32575 at the point where it executes the insert statement. In the debug log it has INSERT INTO TABLE (COL1, COL2, ID) VALUES ('X','Y',DEFAULT). The Oracle error 32575 follows this. The ID field in question is part of a Hibernate pojo and is a primary key and uses GenerationType.SEQUENCE. It is an Entity that points to a Table.
The DataSource is "thin" driver using the ojdbc8.jar. The Datasource is set up using a #Configuration" annotation in the application during Tomcat startup. If you take all of this by itself I dont get the error above.
However, I have a requirement to connect to each database user through a PROXY USER account because we use Oracle Label Security. It looks something like GRANT CONNECT TO userX THROUGH proxyuser. Using the database driver it would be something like
Properties proxyProps = new Properties()
proxyProps.set(Connection.PROXY_USER_NAME, user)
oraCon.openProxySession(Connection.PROXYTYPE_USER_NAME)
This is being done inside of an application class called ProxyDelegatingDatasourceThin which extends DelegatingDataSource which is a Spring class that I believe gets called when a new connection attempt is made.
Again, queries work fine, updates seem to work, its only the INSERTS. The ID column itself is set to NUMBER and is flagged as a Primary Key. It is not set as any kind of an IDENTITY column.
The error seems to want the ID column to be omitted from the INSERT Statement all together but Hibernate or Spring is generating it with the DEFAULT in the VALUES that is associated to ID.
Im hoping someone can help. Spent days on this.
Set the #ID column to be nullable, insertable, updatable all set to false
Tried using merge and persist from the entity manager (EntityManager) instead of using the Spring Repository save() method.
The implicit caching property is set to true
The error seems to want the ID column to be omitted from the INSERT Statement all together but Hibernate or Spring is generating it with the DEFAULT in the VALUES that is associated to ID.
Adding more info...
When I remove the code above which opens the proxy session, I don't get the error. I also printed some info from the database context while using the proxy session and the PROXY USER is to the PROXY ACCOUNT and the SESSION user is to the user that is connecting through the PROXY ACCOUNT.
Whether I use the Oracle Thin Driver or UCP I get the same result.

Spring JPA H2 and DB2 How to specify table schema to work on both databases

I am creating a Springboot app which I am planning to talk to DB2 database for production and to H2 database for development environments which I have setup using spring application.profiles.
My application.properties file also has setting:
spring.jpa.hibernate.naming.physical-strategy=org.hibernate.boot.model.naming.PhysicalNamingStrategyStandardImpl
, which if set, will not replace "." with "_" (as in MY_SCHEMA.CAR with MY_SCHEMA_CAR).
I need this since on DB2, I have to prefix table with schema like SELECT * FROM MY_SCHEMA.CAR. In H2 console, this is not needed and I can just do SELECT * FROM CAR.
However, I am running into following problem:
if my entity is annotated with #Table(name = "MY_SCHEMA.CAR") , I get DB2 error
error com.ibm.db2.jcc.am.SqlSyntaxErrorException: DB2 SQL Error:
SQLCODE=-551, SQLSTATE=42501, SQLERRMC=MY_USER;CREATE TABLE FOR USER
MY_SCHEMA;MY_SCHEMA.CAR, DRIVER=4.29.24. On H2, this creates table MY_SCHEMA.CAR.
if my entity is annotated with #Table(name = "CAR", schema = "MY_SCHEMA"), it works with DB2 but on H2, I get error
org.h2.jdbc.JdbcSQLSyntaxErrorException: Schema "MY_SCHEMA" not
found; SQL statement: create table MY_SCHEMA.CAR (...
How do I address issue in #2 above to get it working on my H2 database as well?
In general I prefer not to hardcode the default schema in the app. If the schema changes for any reason the app doesn't need to be affected.
To do that, remove the schema on the SpringBoot app. You'll need to change the JDBC connection URL, though. Append :currentSchema=MY_SCHEMA; to set the default schema.
For example, when connecting to DB2 in my sandbox I use:
jdbc:db2://192.168.56.218:50000/empusa:currentSchema=ECOS;
H2 offers a similar feature. When I connect to my H2 database I use:
jdbc:h2:tcp://localhost/~/test;SCHEMA=ECOS

can not run springboot junit tests with globally quoted identifiers

I've got an app that runs with spring.jpa.properties.hibernate.globally_quoted_identifiers=true. The database changes are managed through liquibase and the app uses a mysql database.
The problem is that when I try and run my junit tests, which use a hsqldb, I get the following exception when a repository call is made:
Caused by: java.sql.SQLSyntaxErrorException: unexpected token: in statement
I believe this is because we're not currently setting a default schema, so it's running it without a schema but the liquibase created the tables in PUBLIC schema. I tried setting spring.liquibase.default-schema=SCHEMA in my test properties to be the same schema as my prod properties, but then liquibase gets
liquibase.exception.DatabaseException: invalid schema name: SCHEMA in statement [CREATE TABLE SCHEMA.DATABASECHANGELOGLOCK
Because the schema hasn't been created yet in the HSQLDB.
Adding:
spring.jpa.hibernate.ddl-auto=update
spring.datasource.schema=classpath:test-schema.sql
where test-schema.sql is just CREATE SCHEMA IF NOT EXISTS schema; got me a bit further, but now when the tests run it tries to run some of the liquibase which runs a sql insert that is like INSERT INTO table without a schema attached, which fails. Unfortunately this changeset has already run against the actual app, so I can't really change it.
Is there a way to get spring.jpa.properties.hibernate.globally_quoted_identifiers=true along with setting the schema to work without getting rid of those changesets, or are the tests just totally hooped? Is there a way to get liquibase to run sql statements and automatically use the default schema for them?
If it helps, here is what my application-test.properties looks like:
spring.datasource.url=jdbc:hsqldb:mem:testdb;
spring.datasource.driver-class-name=org.hsqldb.jdbcDriver
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.properties.hibernate.globally_quoted_identifiers=true
spring.liquibase.url=${spring.datasource.url}
spring.liquibase.change-log=classpath:db/changelog/db.changelog-test.xml
spring.liquibase.user=sa
spring.liquibase.contexts=test
spring.liquibase.password=
spring.liquibase.default-schema=schema
spring.jpa.hibernate.ddl-auto=update
spring.datasource.schema=classpath:test-schema.sql

Schema not found using Hibernate and Oracle

Right now I am running into an issue where I am getting "MySchema" not found exception:
org.h2.jdbc.JdbcSQLSyntaxErrorException: Schema "MySchema" not found; SQL statement:
select batchstatu0_.batch_key as batch_ke1_0_ from myschema.batch_status batchstatu0_ [90079-199]
at org.h2.message.DbException.getJdbcSQLException(DbException.java:573)
at org.h2.message.DbException.getJdbcSQLException(DbException.java:427)
When I run the generated sql from Oracle SQL Developer using the same credentials, the select statement correctly finds the schema and runs the query.
One of the things I initially tried with success but not the solution I would like to go with was to specify a whole new DataSource for the specified schema. That worked but will be a serious headache when we start adding event more schemas. I would much rather use one Datasource and specify the schema in the Table annotations.
#Table(name="BATCH_STATUS", schema ="MySchema")
public class BatchStatus {
...
}
And the properties:
spring.jpa.hibernate.ddl-auto=create
spring.jpa.show-sql=true
hibernate.show_sql=true
spring.datasource.jdbc-url=jdbc:oracle:thin:xxx
spring.datasource.username=xxx
spring.datasource.password=xxx
hibernate.default_schema=MySchema
I would assume this has to be some sort of config issue but I haven't been able to figure it out.
you need to specify
spring.datasource.driver-class-name=oracle.jdbc.OracleDriver
As per the exception, it is using H2 driver

Is it possible to get the SQL query causing a Spring DataAccessException?

I have an application that uses a JdbcTemplate to perform queries on a MySQL database. If the JdbcTemplate ever throws an org.springframework.dao.DataAccessException, it logs the exception's stack trace. However, I'd also like to include the SQL query that caused the exception to be thrown. Is there an easy way to do this that doesn't involve writing custom error messages for every place JdbcTemplate is used?
If you only intend to log SQL statements during an exception, you might have to write your own custom subclass of JdbcTemplate and alter the logging preconditions as seen in the source code at Github.
If that is not the case, you may consider the following.
From the Spring documentation, All SQL Statements are logged at DEBUG level.
All SQL issued by this class is logged at the DEBUG level under the category corresponding to the fully qualified class name of the template instance (typically JdbcTemplate, but it may be different if you are using a custom subclass of the JdbcTemplate class).
You make also change the Jdbc url by setting profileSQL to true to trace the SQL.
MySQl Connection Reference Documentation

Resources