[JIRA] (HHH-15929) Mapping jsonb of different types in a class inheritance hierarchy does not work.
by Gavin King (JIRA)
Gavin King ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... ) *commented* on HHH-15929 ( https://hibernate.atlassian.net/browse/HHH-15929?atlOrigin=eyJpIjoiYWExNT... )
Re: Mapping jsonb of different types in a class inheritance hierarchy does not work. ( https://hibernate.atlassian.net/browse/HHH-15929?atlOrigin=eyJpIjoiYWExNT... )
FTR, here is my test code:
In import.sql :
INSERT INTO table_test(id, type, property) VALUES('1','A','{"propertyA": "valueA"}'::jsonb)
INSERT INTO table_test(id, type, property) VALUES('2','B','{"propertyB": "valueB"}'::jsonb)
In Main.java :
public class Main {
public static void main( String [] args) {
var sessionFactory = new Configuration()
.addAnnotatedClass(CommonEntity.class)
.addAnnotatedClass(EntityA.class)
.addAnnotatedClass(EntityB.class)
// use Postgres
.setProperty(URL, "jdbc:postgresql: //localhost/hreact" )
.setProperty(USER, "hreact" )
.setProperty(PASS, "hreact" )
// display SQL in console
.setProperty(SHOW_SQL, TRUE.toString())
.setProperty(FORMAT_SQL, TRUE.toString())
.setProperty(HIGHLIGHT_SQL, TRUE.toString())
.buildSessionFactory();
// export the inferred database schema
sessionFactory.getSchemaManager().dropMappedObjects( false );
sessionFactory.getSchemaManager().exportMappedObjects( true );
sessionFactory.inSession(session -> {
var ea = session.find(EntityA. class, 1);
var eb = session.find(EntityB. class, 2);
});
}
}
Executed SQL:
[Hibernate]
drop table if exists table_test cascade
[Hibernate]
create table table_test (
type varchar (31) not null ,
id bigint not null ,
property jsonb,
primary key (id)
)
[INFO] HHH000476: Executing script ' file :/Users/gavin/Downloads/test/untitled/build/resources/main/import. sql '
[Hibernate] INSERT INTO table_test(id, type , property) VALUES ( '1' , ' A ' , '{ "propertyA" : "valueA" }' ::jsonb)
[Hibernate] INSERT INTO table_test(id, type , property) VALUES ( '2' , 'B' , '{ "propertyB" : "valueB" }' ::jsonb)
[Hibernate]
select
e1_0.id,
e1_0.property
from
table_test e1_0
where
e1_0. type = ' A '
and e1_0.id=?
[Hibernate]
select
e1_0.id,
e1_0.property
from
table_test e1_0
where
e1_0. type = 'B'
and e1_0.id=?
( https://hibernate.atlassian.net/browse/HHH-15929#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-15929#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100225- sha1:e4eb869 )
2 years, 11 months
[JIRA] (HHH-16591) @org.hibernate.annotations.JdbcType does not override the `hibernate.type.preferred_duration_jdbc_type` type
by Čedomir Igaly (JIRA)
Čedomir Igaly ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=557058%... ) *commented* on HHH-16591 ( https://hibernate.atlassian.net/browse/HHH-16591?atlOrigin=eyJpIjoiYzNmND... )
Re: @org.hibernate.annotations.JdbcType does not override the `hibernate.type.preferred_duration_jdbc_type` type ( https://hibernate.atlassian.net/browse/HHH-16591?atlOrigin=eyJpIjoiYzNmND... )
Please, correct me if I am worng …
In present implementation you first and last assertions are contradictory. If registered JdbcType for SqlTypes.INTERVAL_SECOND is NumericJdbcType (first assertion), then sam JdbcType will be used for property annotated with @JdbcType(SqlTypes.INTERVAL_SECOND) (as is checked with last assertion). My understanding (again, please, correct me if I am wrong) is that JdbcType for INTERVAL_SECOND should not be replaced when preferred duration JDBC type is set to NUMERIC. What should be changed is JavaType used, by default, for java.time.Duration properties.
It seems to me that it your test case line
>
>
>
> final JdbcType intervalType = jdbcTypeRegistry.getDescriptor(
> SqlTypes.INTERVAL_SECOND );
>
>
should be replaced with:
>
>
>
> final JdbcType intervalType =
> mappingMetamodel.getTypeConfiguration().getBasicTypeForJavaType(
> Duration.class ).getJdbcType();
>
>
My understanding is that, whatever is preferred JDBC type for Duration is, JDBC type 3100 (= SqlTypes.INTERVAL_SECOND) should be handled by same JdbcType implementation. In this case this is PostgreSQLIntervalSecondJdbcType. To check that I wil add line:
>
>
>
> assertThat( jdbcTypeRegistry.getDescriptor( SqlTypes.INTERVAL_SECOND ) )
>
>
>
> .isOfAnyClassIn( PostgreSQLIntervalSecondJdbcType.class );
>
>
This assertion is equivalent to last one and it will fail in current implementation.
My guess is that source of the problem is in MetadataBuildingProcess class when JdbcType for INTERVAL_SECOND is replaced with one for NUMERIC. If this is fixed, your (slightly changed) test will pass, but another one will now fail.
Also, my guess is that this is more general problem, not limited only to Duration’s, but for other types where there is preferred JDBC type.
( https://hibernate.atlassian.net/browse/HHH-16591#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-16591#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100225- sha1:e4eb869 )
2 years, 11 months
[JIRA] (HHH-16589) In-Clause Parameter Padding mistreats Dilect.getInExpressionCountLimit which can cause ORA-01795: maximum number of expressions in a list is 1000
by Adrodoc (JIRA)
Adrodoc ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=5b2a4a0... ) *commented* on HHH-16589 ( https://hibernate.atlassian.net/browse/HHH-16589?atlOrigin=eyJpIjoiYWY3NG... )
Re: In-Clause Parameter Padding mistreats Dilect.getInExpressionCountLimit which can cause ORA-01795: maximum number of expressions in a list is 1000 ( https://hibernate.atlassian.net/browse/HHH-16589?atlOrigin=eyJpIjoiYWY3NG... )
While coding a fix I noticed two additional Bugs in this code:
* For a NOT-IN-Clause you would have to use AND instead of OR. Currently Hibernate generates a query like ID not in(?,?,?,?,...) or ID not in }}which is incorrect. It should be {{ID not in(?,?,?,?,...) and ID not in.
* No braces are added around multiple in clauses. For example if you have an additional where clause like ID < ? Hibernate generates ID < ? and id in(?,?,...) or id in. This query ignores the first predicate for all IDs in the second in clause.
( https://hibernate.atlassian.net/browse/HHH-16589#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-16589#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100225- sha1:84d3b45 )
2 years, 11 months
[JIRA] (HHH-16589) In-Clause Parameter Padding mistreats Dilect.getInExpressionCountLimit which can cause ORA-01795: maximum number of expressions in a list is 1000
by Adrodoc (JIRA)
Adrodoc ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=5b2a4a0... ) *commented* on HHH-16589 ( https://hibernate.atlassian.net/browse/HHH-16589?atlOrigin=eyJpIjoiYmQ1Yj... )
Re: In-Clause Parameter Padding mistreats Dilect.getInExpressionCountLimit which can cause ORA-01795: maximum number of expressions in a list is 1000 ( https://hibernate.atlassian.net/browse/HHH-16589?atlOrigin=eyJpIjoiYmQ1Yj... )
I analyzed the code further. It took me a while to figure out exactly what it was trying to do. From my understanding bindValueMaxCount is supposed to be the number of bind variables that should be used in the last IN-Clause. Here is a small program that fixes the calculation of bindValueMaxCount and compares it to the current hibernate implementation. The fix not only makes it so that inExprList is properly respected, but also fixes the calculation for values greater that 1073741824 (probably not that important, but the current implementation fails horribly for such large numbers) and personally I find it much easier to understand:
package de.sanacorp.security.persistence.base.inclause;
import java.util.function.IntBinaryOperator;
import org.hibernate.internal.util.MathHelper;
public class HHH_16589 {
public static void main( String [] args) {
System.out.println( "| bindValueCount | inExprLimit | originalResult | proposalResult |" );
System.out.println( "|----------------|-------------|----------------|----------------|" );
IntBinaryOperator original = HHH_16589::hibernate_6_2_2_Final;
IntBinaryOperator proposal = HHH_16589::calculateLastInClauseSize;
compare(1, 0, original, proposal);
compare(2, 0, original, proposal);
compare(3, 0, original, proposal);
compare(4, 0, original, proposal);
compare(5, 0, original, proposal);
compare(1000, 0, original, proposal);
compare((1 << 30) - 1, 0, original, proposal);
compare(1 << 30, 0, original, proposal);
compare((1 << 30) + 1, 0, original, proposal);
compare( Integer.MAX_VALUE - 1, 0, original, proposal);
compare( Integer.MAX_VALUE, 0, original, proposal);
compare(1, 1000, original, proposal);
compare(7, 1000, original, proposal);
compare(8, 1000, original, proposal);
compare(511, 1000, original, proposal);
compare(512, 1000, original, proposal);
compare(513, 1000, original, proposal);
compare(999, 1000, original, proposal);
compare(1000, 1000, original, proposal);
compare(1001, 1000, original, proposal);
compare(1008, 1000, original, proposal);
compare(1023, 1000, original, proposal);
compare(1024, 1000, original, proposal);
compare(1025, 1000, original, proposal);
compare(1511, 1000, original, proposal);
compare(1512, 1000, original, proposal);
compare(1513, 1000, original, proposal);
compare(1999, 1000, original, proposal);
compare(2000, 1000, original, proposal);
compare(2001, 1000, original, proposal);
compare(2511, 1000, original, proposal);
compare(2512, 1000, original, proposal);
compare(2513, 1000, original, proposal);
compare(2999, 1000, original, proposal);
compare(3000, 1000, original, proposal);
compare(3001, 1000, original, proposal);
compare( Integer.MAX_VALUE - 1, 1000, original, proposal);
compare( Integer.MAX_VALUE, 1000, original, proposal);
}
public static void compare( int bindValueCount, int inExprLimit, IntBinaryOperator original,
IntBinaryOperator proposal) {
int originalResult = original.applyAsInt(bindValueCount, inExprLimit);
int proposalResult = proposal.applyAsInt(bindValueCount, inExprLimit);
System.out
.println( "| " + bindValueCount + " | " + inExprLimit + " | " + originalResult + " | " + proposalResult + " |" );
}
private static int hibernate_6_2_2_Final( int bindValueCount, int inExprLimit) {
int bindValueMaxCount = bindValueCount;
// bindValueCount: 1005
// bindValuePaddingCount: 1024
int bindValuePaddingCount = MathHelper.ceilingPowerOfTwo(bindValueCount);
// inExprLimit: 1000
if (inExprLimit > 0) {
if (bindValuePaddingCount > inExprLimit) {
// bindValueCount % inExprLimit: 5
// bindValuePaddingCount: 8
if (bindValueCount < inExprLimit) {
bindValueMaxCount = inExprLimit;
} else {
bindValueMaxCount = MathHelper.ceilingPowerOfTwo(bindValueCount % inExprLimit);
}
} else if (bindValueCount < bindValuePaddingCount) {
bindValueMaxCount = bindValuePaddingCount;
}
} else if (bindValueCount < bindValuePaddingCount) {
bindValueMaxCount = bindValuePaddingCount;
}
return bindValueMaxCount;
}
private static int calculateLastInClauseSize( int bindValueCount, int inExprLimit) {
if (inExprLimit > 0) {
int lastInClauseSize = bindValueCount % inExprLimit;
int lastInClauseSizeWithPadding = ceilingPowerOfTwoFixed(lastInClauseSize);
return Math.min(inExprLimit, lastInClauseSizeWithPadding);
} else {
return ceilingPowerOfTwoFixed(bindValueCount);
}
}
// This should probably be done in MathHelper already.
// If values above 1073741824 (2^30) are not of a concern we could just use MathHelper directly.
private static int ceilingPowerOfTwoFixed( int value) {
int result = MathHelper.ceilingPowerOfTwo(value);
if (result < value) { // Overflow
return Integer.MAX_VALUE;
}
return result;
}
}
When executed the Program prints this Table (as Markdown):
bindValueCount inExprLimit originalResult proposalResult 1 0 1 1 2 0 2 2 3 0 4 4 4 0 4 4 5 0 8 8 1000 0 1024 1024 1073741823 0 1073741824 1073741824 1073741824 0 1073741824 1073741824 1073741825 0 1073741825 2147483647 2147483646 0 2147483646 2147483647 2147483647 0 2147483647 2147483647 1 1000 1 1 7 1000 8 8 8 1000 8 8 511 1000 512 512 512 1000 512 512 513 1000 1000 1000 999 1000 1000 1000 1000 1000 1 1 1001 1000 1 1 1008 1000 8 8 1023 1000 32 32 1024 1000 32 32 1025 1000 32 32 1511 1000 512 512 1512 1000 512 512 1513 1000 1024 1000 1999 1000 1024 1000 2000 1000 1 1 2001 1000 1 1 2511 1000 512 512 2512 1000 512 512 2513 1000 1024 1000 2999 1000 1024 1000 3000 1000 1 1 3001 1000 1 1 2147483646 1000 2147483646 1000 2147483647 1000 2147483647 1000
( https://hibernate.atlassian.net/browse/HHH-16589#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-16589#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100225- sha1:84d3b45 )
2 years, 11 months