How to Encrypt A Certain Column automatically with ColumnTransformer? - spring

#ColumnTransformer(forColumn = "description", read = "pgp_sym_decrypt(description, current_setting('encrypt.key'))", write = "pgp_sym_encrypt(?, current_setting('encrypt.key'))")
#Column(name = "description", length=6000)
#Lob
#Type(type = "org.hibernate.type.TextType")
private String description;
I have this column transform where I encrypt the column before saving to the database.
Sometiems it works but most of the time it shows this error. The database not just this, and it works for other columns. Only on this particular column, it wont work. Do you have ideas? Could this be server related issue? As the application works on the test and local machines
column "description" is of type bytea but expression is of type character varying. Hint: You will need to rewrite or cast the expression.

Remove the #Lob annotation, unless the DDL type is oid. Other than that, the mapping looks good to me. Share the stack trace of the error and the failing SQL in case this doesn't help.

Related

Spring boot JPA specification find by #Column name

I'm developing a service that must be able to have a configurable username column in its User field, i.e. different columns can be treated by the service as the "username" (i.e. the actual username column, the ID column etc.). It is a strange requirement to have, but legacy support is a strange thing as you all know by now :)
I've tried to tackle this in a following way, my configuration file contains the name of the column that will be treated as the username, and then that value is used with JPA specifications to find the User (my repository extends JpaSpecificationExecutor).
The code looks something like this:
public UserEntity getUserByUsername(String username) {
String columnName = configuration.getUsernameColumn();
return userRepository.findOne((root, query, builder) ->
builder.and(builder.equal(root.<String>get(columnName), username)));
}
This should work fine... However there is a catch, the column name is specified as the actual column name in the database, and the JPA specification seems to expect field name to be specified, not the database column. My entity is annotated as:
#Column(name = "USER_NAME", length = 100)
private String userName;
So when I try to find the User by searching for "USER_NAME", my code throws an exception because it expected to find a "USER_NAME" field, not column in the database.
I know that the obvious solution is putting "userName" in the configuration instead, however that is not an option. Another way to do this is by using reflection, but that would a last resort approach. Is there a better way to go about this?
One of the another solution can be the criteria query. Pass the column and the searchString and build the criteria query.
Reference : https://eng.zemosolabs.com/dynamic-multi-column-search-with-jpa-criteria-5720fedf13d3

spring-data-cassandra: InvalidQueryException: Cannot execute this query ... use ALLOW FILTERING

I have the following code
#Indexed
#PrimaryKeyColumn(name = "x", ordinal = 1, type = PrimaryKeyType.PARTITIONED)
#Column(value="x")
private String x;
#Indexed
#PrimaryKeyColumn(name = "code", ordinal = 2, type = PrimaryKeyType.PARTITIONED)
#Column(value="code")
private String code;
#Query(value = "select * from customers where code = ?0")
Optional<Customer> findByCode(String code);
When this is executed, I get Caused by: com.datastax.driver.core.exceptions.InvalidQueryException: Cannot execute this query as it might involve data filtering and thus may have unpredictable performance. If you want to execute this query despite the performance unpredictability, use ALLOW FILTERING.
Is there a way to avoid this just from spring-data-cassandra? I do not want to add ALLOW FILTERING in my query. I tried creating a separate index on the code column but this haven't solved the issue. I think it stops in the spring data configuration. If I execute the same query in cqlsh, it works.
You must specify partition key on your query, unless you create index or use ALLOW FILTERING
Executing query with allow filtering might not be a good idea as it can use a lot of your computing resources and Might not return any result because of timeout. Don't use allow filtering in production Read the datastax doc about using ALLOW FILTERING
https://docs.datastax.com/en/cql/3.3/cql/cql_reference/select_r.html?hl=allow,filter
When using a no-sql database, you need to properly design your data to avoid filtering. You can add a secondary index to optimize retrieval by a specific field. More details here: https://docs.datastax.com/en/archived/cql/3.3/cql/cql_using/useSecondaryIndex.html
If you are sure that the query is what you need, you can use the allowFiltering parameter on the #Query annotation to explicitly indicate that ALLOW FILTERING be used.
#Query(value = "select * from customers where code = ?0", allowFiltering = true)
Optional<Customer> findOneByCode(String code);

Hibernate Spatial PostGis PSQLException column is of type point but expression is of type bytea

In a Spring Boot project, Java8, with hibernate-spatial and PostgresDB 9.4
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-spatial</artifactId>
<version>5.2.10.Final</version>
</dependency>
application.properties
spring.datasource.driver-class-name=org.postgresql.Driver
spring.jpa.database-platform=org.hibernate.spatial.dialect.postgis.PostgisPG94Dialect
spring.jpa.properties.hibernate.dialect=org.hibernate.spatial.dialect.postgis.PostgisPG94Dialect
(I tried also PostgisPG9Dialect)
My Entity has a property
...
import com.vividsolutions.jts.geom.Point;
....
#Column(columnDefinition = "Point")
private Point cityLocation;
If I save with null value it's ok, but if I put a value
setCityLocation(new GeometryFactory().createPoint(new Coordinate(lng, lat));
I have:
PSQLException: ERROR: column "city_location" is of type point but expression is of type bytea You will need to rewrite or cast the expression.
In my db I can see the column definition as
type: point
column size: 2147483647
data type: 1111
num prec radix: 10
char octet length: 2147483647
I'M GOING CRAZY... Why It doesn't work?
UPDATE (It still don't work, I'm collecting new informations)
1) I'm thinking the problem could be the creation of the db.
In my application.properties I also have :
spring.jpa.properties.hibernate.hbm2ddl.auto=update
so the schema will update 'automatically' by hibernate.
2) I can run with success a query directly on the db (I use "Squirrel SQL" as client)
update my_table set city_location = POINT(-13,23) where id = 1
and if I
select city_location from my_table where id = 1
the answer is
<Other>
I can't see the value... I got the same answer for the record with null value inside the point type...
3) After set a value to the 'point' column with a query, I'm no more able to read from the table, I receive the exception:
org.geolatte.geom.codec.WktDecodeException : Wrong symbol at position: 1 in Wkt: (-13.0,23.0)
4) I look inside the hibernate-spatial-5.2.10.Final.jar and I found two "geolatte" named classes in the package org.hibernate.spatial :
GeolatteGeometryJavaTypeDescriptor.class
GeolatteGeometryType.class
5) And also (specific for Squirrel SQL client experts):
if I try to change a value of a column in "my_table" (not the 'point' city_location but anyone of the other columns) I recive an error similar to the one I recive in java when I try to insert a point value:
Exception seen during check on DB. Exception was:
ERROR: operator does not exist: point = character varying
Hint: No operator matches the given name and argument type(s). You might need to add explicit type casts.
Squirrel is made with java.. so I can accept this strange thing, may be it compose the query in a 'wrong' way, maybe it is connected to the value I see when I make a select...
Any ideas?
I found the solution!!
A fix to the code was needed and a magic trick I read in another stackoverflow question saved my life.
The problem was that the db column was created in a wrong way:
in the db the column type should be geometry NOT point
I removed the columnDefinition = "Point" from the #Column annotation and I ran the query
CREATE EXTENSION postgis;
on my db following these instructions:
Postgis installation: type "geometry" does not exist
Krishna Sapkota you are my new super hero!
Just remove columnDefinition = "POINT", from #Column annotation, and just use the Point object. (i.e. Use default column definition)

Insensitive on compounds name with uppercase

I got some problems with a request with Doctrine.
I do a findOneByFieldName on my entity which is supposed to retrieves me an object.
I want to findOneByNameSurname (NameSurname is a string) with a parameter which contains for example 'BEART Jean-Francois'.
What I want is that doctrine retrieves me the user BEART Jean-Francois, if only BEART Jean-Francois exists in the table. Nevertheless, if I give to doctrine 'BEART Jean-francois' with an f lowercase, doctrine still retrieves me the user holding the 'BEART Jean-Francois' field with the F uppercase.
What I want is that doctrine should be sensitive with the whole string, I mean that it should not squizze the duplicate name, even if, for real its not a duplicate name as it is written differently (upper case on the f letter).
I tried to run an SQL request directly in SqlDeveloper to test if Oracle makes the difference with and without the f lower or uppercase in 'Jean-Francois', and it DOES.
So what am I missing ? How can I say to doctrine, if you got an f lowercase in the string parameter I give you, and you only find a F uppercase in DB, please don't retrieve me anything, its not a match ...
Thanks anyway for your help.
Solved my problems in my oracle Listener ....
I had that :
private static $_SQL_SET_SORT = "ALTER SESSION SET NLS_SORT=Latin_AI";
private static $_SQL_SET_COMP = "ALTER SESSION SET NLS_COMP=LINGUISTIC";
Changed it to that and now doctrine is sensitive :
private static $_SQL_SET_SORT = "ALTER SESSION SET NLS_SORT=BINARY_CI";
private static $_SQL_SET_COMP = "ALTER SESSION SET NLS_COMP=BINARY";
See this post for more info :
Case insensitive searching in Oracle

Oracle "TIMESTAMP WITH TIMEZONE" Java type mapping issue with raw sql query

I am using an Oracle 11.2 database with column types "TIMESTAMP WITH TIMEZONE" to store time relevant information. I can't change it because it is used by an existing system.
The Java application uses ojdbc7 (v12.1.0.2) + hibernate as JPA provider.
I simplified the following example for easer understanding!
There is an entity "Product" which maps "TIMESTAMP WITH TIMEZONE" columns to java.util.Calendar
#Entity
#Table(name = "PRODUCT")
public class Product {
#Id
#Column(name = "ID")
private String id;
#Column(name = "START_DATE", columnDefinition = "TIMESTAMP WITH TIME ZONE")
private Calendar startDate;
....
}
If I load it through a HQL query it works fine.
1. Issue
If I use a raw sql query:
SELECT * FROM PRODUCT where id='123456';
I get the following exception:
org.hibernate.MappingException: No Dialect mapping for JDBC type: -101
The sql query is a lot more complex I just used a very simple example here. So I can not simply convert it to an HQL query.
2. Issue
If I persist a new product with a start date having a time zone like AEDT. E.g.
2014-01-01 12:00:00 AEDT
it get saved in the database as
01-JAN-14 01.00.00.000000000 UTC
If I query it again from the Java application the Calendar object has the time in UTC as shown above and not the time in AEDT. It is not just a display issue.
The conversion from AEDT to UTC is correct, but the problem is that the information is lost that it was inserted with timezone AEDT.
Is there a way to prevent this? Why is this happening anyway? I searched a lot today, but could not find a good hint.
You can solve the first issue the following way:
First, you need to unwrap the Query implementation. You said that you were using JPA + Hibernate, so:
Query jpaQuery = entityManager.createNativeQuery("select, t.int_c, t.str_c, t.timestamp_c from table t");
SQLQuery hibernateQuery = jpaQuery.unwrap(SQLQuery.class);
(org.hibernate.SQLQuery.class is the wrapped class)
Second, you have to set the type for ALL the columns that you want to retrieve:
hibernateQuery.addScalar("int_c", IntegerType.INSTANCE);
hibernateQuery.addScalar("str_c", StringType.INSTANCE);
hibernateQuery.addScalar("timestamp_c", TimestampType.INSTANCE);
Third, just make the query using the original JPA Query instance
List<Object[]> results = jpaQuery.getResultList();

Resources