Merge remote-tracking branch 'upstream/main' into wip/6.0_merge

This commit is contained in:
Andrea Boriero 2021-10-19 16:23:07 +02:00
commit 7f46f11f3b
6 changed files with 81 additions and 70 deletions

View File

@ -12,10 +12,10 @@ and it allows you to deal with geographic data in a standardized way.
Hibernate Spatial provides a standardized, cross-database interface to geographic data storage and query functions.
It supports most of the functions described by the OGC Simple Feature Specification. Supported databases are Oracle 10g/11g,
PostgreSQL/PostGIS, MySQL, Microsoft SQL Server and H2/GeoDB.
PostgreSQL/PostGIS, MySQL, Microsoft SQL Server, DB2, CockroachDB and H2/GeoDB.
Spatial data types are not part of the Java standard library, and they are absent from the JDBC specification.
Over the years https://tsusiatsoftware.net/jts/main.html[JTS] has emerged the _de facto_ standard to fill this gap. JTS is
Over the years https://tsusiatsoftware.net/jts/main.html[JTS] has emerged as the _de facto_ standard to fill this gap. JTS is
an implementation of the https://portal.opengeospatial.org/files/?artifact_id=829[Simple Feature Specification (SFS)]. Many databases
on the other hand implement the SQL/MM - Part 3: Spatial Data specification - a related, but broader specification. The biggest difference is that
SFS is limited to 2D geometries in the projected plane (although JTS supports 3D coordinates), whereas
@ -26,7 +26,7 @@ https://github.com/GeoLatte/geolatte-geom[geolatte-geom]. As already mentioned,
standard. Geolatte-geom (also written by the lead developer of Hibernate Spatial) is a more recent library that
supports many features specified in SQL/MM but not available in JTS (such as support for 4D geometries, and support for extended WKT/WKB formats).
Geolatte-geom also implements encoders/decoders for the database native types. Geolatte-geom has good interoperability with
JTS. Converting a Geolatte `geometry` to a JTS `geometry, for instance, doesn't require copying of the coordinates.
JTS. Converting a Geolatte `geometry` to a JTS `geometry`, for instance, doesn't require copying of the coordinates.
It also delegates spatial processing to JTS.
Whether you use JTS or Geolatte-geom, Hibernate spatial maps the database spatial types to your geometry model of choice. It will, however,
@ -260,7 +260,7 @@ create transform for db2gse.st_geometry db2_program (
Hibernate Spatial comes with the following types:
jts_geometry::
Handled by `org.hibernate.spatial.JTSGeometryType` it maps a database geometry column type to a `org.locationtech.jts.geom.Geometry` entity property type.
Handled by `org.hibernate.spatial.JTSGeometryType`, it maps a database geometry column type to a `org.locationtech.jts.geom.Geometry` entity property type.
geolatte_geometry::
Handled by `org.hibernate.spatial.GeolatteGeometryType`, it maps a database geometry column type to an `org.geolatte.geom.Geometry` entity property type.

View File

@ -147,6 +147,12 @@ public enum LockMode {
return NONE;
}
for ( LockMode lockMode : LockMode.values() ) {
if ( lockMode.externalForm.equals( externalForm ) ) {
return lockMode;
}
}
for ( LockMode lockMode : LockMode.values() ) {
if ( lockMode.externalForm.equalsIgnoreCase( externalForm ) ) {
return lockMode;

View File

@ -6,117 +6,117 @@
*/
package org.hibernate.internal.util.collections;
import java.util.LinkedList;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
import java.util.function.Consumer;
import java.util.function.Function;
/**
* A general-purpose stack impl.
* A general-purpose stack impl supporting null values.
*
* @param <T> The type of things stored in the stack
*
* @author Steve Ebersole
* @author Sanne Grinovero
*/
public final class StandardStack<T> implements Stack<T> {
@SuppressWarnings("unchecked")
private final T nullMarker = (T) new Object();
private T current;
private final LinkedList<T> internalStack = new LinkedList<>();
private ArrayDeque<T> internalStack;
private static final Object NULL_TOKEN = new Object();
public StandardStack() {
}
public StandardStack(T initial) {
current = initial;
stackInstanceExpected().addFirst( initial );
}
@Override
public void push(T newCurrent) {
Object toStore = newCurrent;
if ( newCurrent == null ) {
newCurrent = nullMarker;
toStore = NULL_TOKEN;
}
stackInstanceExpected().addFirst( toStore );
}
if ( current != null ) {
internalStack.addFirst( current );
private Deque stackInstanceExpected() {
if ( internalStack == null ) {
//"7" picked to use 8, but skipping the odd initialCapacity method
internalStack = new ArrayDeque<>( 7 );
}
current = newCurrent;
return internalStack;
}
@Override
public T pop() {
final T popped = this.current;
if ( internalStack.isEmpty() ) {
this.current = null;
}
else {
this.current = internalStack.removeFirst();
}
return convert( stackInstanceExpected().removeFirst() );
}
return popped == nullMarker ? null : popped;
private T convert(final Object internalStoredObject) {
if ( internalStoredObject == NULL_TOKEN ) {
return null;
}
return (T) internalStoredObject;
}
@Override
public T getCurrent() {
return current == nullMarker ? null : current;
if ( internalStack == null ) {
return null;
}
return convert( internalStack.peek() );
}
@Override
public int depth() {
if ( current == null ) {
if ( internalStack == null ) {
return 0;
}
else if ( internalStack.isEmpty() ) {
return 1;
}
else {
return internalStack.size() + 1;
}
return internalStack.size();
}
@Override
public boolean isEmpty() {
return current == null;
if ( internalStack == null ) {
return true;
}
return internalStack.isEmpty();
}
@Override
public void clear() {
current = null;
internalStack.clear();
if ( internalStack != null ) {
internalStack.clear();
}
}
@Override
public void visitRootFirst(Consumer<T> action) {
final int stackSize = internalStack.size();
for ( int i = stackSize - 1; i >= 0; i-- ) {
action.accept( internalStack.get( i ) );
if ( internalStack == null ) {
return;
}
if ( current != null ) {
action.accept( current );
final Iterator<T> iterator = internalStack.descendingIterator();
while ( iterator.hasNext() ) {
action.accept( iterator.next() );
}
}
@Override
public <X> X findCurrentFirst(Function<T, X> function) {
if ( current != null ) {
{
final X result = function.apply( current );
if ( result != null ) {
return result;
}
}
for ( T t : internalStack ) {
final X result = function.apply( t );
if ( result != null ) {
return result;
}
if ( internalStack == null ) {
return null;
}
final Iterator<T> iterator = internalStack.iterator();
while ( iterator.hasNext() ) {
final X result = function.apply( iterator.next() );
if ( result != null ) {
return result;
}
}
return null;
}
}

View File

@ -39,21 +39,10 @@ public final class LockModeTypeHelper {
return getLockMode( (LockModeType) value );
}
else if ( String.class.isInstance( value ) ) {
// first try LockMode name
LockMode lockMode = LockMode.valueOf( (String) value );
if ( lockMode == null ) {
try {
lockMode = getLockMode( LockModeType.valueOf( (String) value ) );
}
catch ( Exception ignore ) {
}
}
if ( lockMode != null ) {
return lockMode;
}
return LockMode.fromExternalForm( (String) value );
}
throw new IllegalArgumentException( "Unknown lock mode source : " + value );
throw new IllegalArgumentException( "Unknown lock mode source: '" + value + "'; can't convert from value of type " + value.getClass() );
}
}

View File

@ -49,6 +49,7 @@ import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.internal.AbstractSharedSessionContract;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.jpa.internal.util.LockModeTypeHelper;
import org.hibernate.jpa.spi.NativeQueryTupleTransformer;
import org.hibernate.metamodel.model.domain.AllowableParameterType;
import org.hibernate.metamodel.model.domain.BasicDomainType;
@ -77,7 +78,6 @@ import org.hibernate.query.spi.MutableQueryOptions;
import org.hibernate.query.spi.NonSelectQueryPlan;
import org.hibernate.query.spi.ParameterMetadataImplementor;
import org.hibernate.query.spi.QueryEngine;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.spi.QueryInterpretationCache;
import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.spi.QueryParameterImplementor;
@ -94,7 +94,6 @@ import org.hibernate.sql.exec.internal.CallbackImpl;
import org.hibernate.sql.exec.spi.Callback;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
import org.hibernate.sql.results.spi.RowTransformer;
import org.hibernate.transform.ResultTransformer;
import org.hibernate.type.BasicType;
import org.hibernate.type.BasicTypeReference;
@ -1067,6 +1066,9 @@ public class NativeQueryImpl<R>
else if ( value instanceof LockModeType ) {
applyLockModeTypeHint( (LockModeType) value );
}
else if ( String.class.isInstance( value ) ) {
applyHibernateLockModeHint( LockModeTypeHelper.interpretLockMode( value ) );
}
else {
throw new IllegalArgumentException(
String.format(

View File

@ -16,8 +16,10 @@ import jakarta.persistence.NamedQueries;
import jakarta.persistence.NamedQuery;
import jakarta.persistence.Query;
import org.hibernate.LockMode;
import org.hibernate.Session;
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
import org.hibernate.jpa.QueryHints;
import org.hibernate.query.NativeQuery;
import org.hibernate.testing.TestForIssue;
@ -192,6 +194,18 @@ public class NamedQueryTest extends BaseEntityManagerFunctionalTestCase {
} );
}
@Test
@TestForIssue(jiraKey = "HHH-14816")
public void testQueryHintLockMode() {
doInJPA( this::entityManagerFactory, entityManager -> {
Query query = entityManager.createNamedQuery( "NamedNativeQuery" );
query.setHint( QueryHints.HINT_NATIVE_LOCKMODE, "none" );
query.setParameter( 1, GAME_TITLES[0] );
assertEquals( LockMode.NONE, query.getHints().get( QueryHints.HINT_NATIVE_LOCKMODE ) );
}
);
}
@Entity(name = "Game")
@NamedQueries(@NamedQuery(name = "NamedQuery", query = "select g from Game g where title = ?1"))
@NamedNativeQueries(@NamedNativeQuery(name = "NamedNativeQuery", query = "select * from Game g where title = ?"))