Fix tests and implement handling callable function hint for stored procedures
This commit is contained in:
parent
131b7bb4e0
commit
96931d8094
|
@ -300,22 +300,26 @@ public class ProcedureCallImpl<R>
|
||||||
if ( memento.getHints() != null ) {
|
if ( memento.getHints() != null ) {
|
||||||
final Object callableFunction = memento.getHints().get( HINT_CALLABLE_FUNCTION );
|
final Object callableFunction = memento.getHints().get( HINT_CALLABLE_FUNCTION );
|
||||||
if ( callableFunction != null && Boolean.parseBoolean( callableFunction.toString() ) ) {
|
if ( callableFunction != null && Boolean.parseBoolean( callableFunction.toString() ) ) {
|
||||||
final List<Class<?>> resultTypes = new ArrayList<>();
|
applyCallableFunctionHint();
|
||||||
resultSetMapping.visitResultBuilders(
|
|
||||||
(index, resultBuilder) -> resultTypes.add( resultBuilder.getJavaType() )
|
|
||||||
);
|
|
||||||
final TypeConfiguration typeConfiguration = getSessionFactory().getTypeConfiguration();
|
|
||||||
final BasicType<?> type;
|
|
||||||
if ( resultTypes.size() != 1 || ( type = typeConfiguration.getBasicTypeForJavaType( resultTypes.get( 0 ) ) ) == null ) {
|
|
||||||
markAsFunctionCall( Types.REF_CURSOR );
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
markAsFunctionCall( type.getJdbcType().getJdbcTypeCode() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void applyCallableFunctionHint() {
|
||||||
|
final List<Class<?>> resultTypes = new ArrayList<>();
|
||||||
|
resultSetMapping.visitResultBuilders(
|
||||||
|
(index, resultBuilder) -> resultTypes.add( resultBuilder.getJavaType() )
|
||||||
|
);
|
||||||
|
final TypeConfiguration typeConfiguration = getSessionFactory().getTypeConfiguration();
|
||||||
|
final BasicType<?> type;
|
||||||
|
if ( resultTypes.size() != 1 || ( type = typeConfiguration.getBasicTypeForJavaType( resultTypes.get( 0 ) ) ) == null ) {
|
||||||
|
markAsFunctionCall( Types.REF_CURSOR );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
markAsFunctionCall( type.getJdbcType().getJdbcTypeCode() );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getProcedureName() {
|
public String getProcedureName() {
|
||||||
return procedureName;
|
return procedureName;
|
||||||
|
@ -1062,7 +1066,14 @@ public class ProcedureCallImpl<R>
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ProcedureCallImplementor<R> setHint(String hintName, Object value) {
|
public ProcedureCallImplementor<R> setHint(String hintName, Object value) {
|
||||||
super.setHint( hintName, value );
|
if ( HINT_CALLABLE_FUNCTION.equals( hintName ) ) {
|
||||||
|
if ( value != null && Boolean.parseBoolean( value.toString() ) ) {
|
||||||
|
applyCallableFunctionHint();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
super.setHint( hintName, value );
|
||||||
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.procedure.internal;
|
||||||
|
|
||||||
import java.sql.CallableStatement;
|
import java.sql.CallableStatement;
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
import org.hibernate.procedure.ParameterMisuseException;
|
import org.hibernate.procedure.ParameterMisuseException;
|
||||||
|
@ -27,7 +28,7 @@ import jakarta.persistence.ParameterMode;
|
||||||
* @author Steve Ebersole
|
* @author Steve Ebersole
|
||||||
*/
|
*/
|
||||||
public class ProcedureOutputsImpl extends OutputsImpl implements ProcedureOutputs {
|
public class ProcedureOutputsImpl extends OutputsImpl implements ProcedureOutputs {
|
||||||
private final ProcedureCallImpl procedureCall;
|
private final ProcedureCallImpl<?> procedureCall;
|
||||||
private final CallableStatement callableStatement;
|
private final CallableStatement callableStatement;
|
||||||
|
|
||||||
private final Map<ProcedureParameter<?>, JdbcCallParameterRegistration> parameterRegistrations;
|
private final Map<ProcedureParameter<?>, JdbcCallParameterRegistration> parameterRegistrations;
|
||||||
|
@ -35,7 +36,7 @@ public class ProcedureOutputsImpl extends OutputsImpl implements ProcedureOutput
|
||||||
private int refCursorParamIndex;
|
private int refCursorParamIndex;
|
||||||
|
|
||||||
ProcedureOutputsImpl(
|
ProcedureOutputsImpl(
|
||||||
ProcedureCallImpl procedureCall,
|
ProcedureCallImpl<?> procedureCall,
|
||||||
Map<ProcedureParameter<?>, JdbcCallParameterRegistration> parameterRegistrations,
|
Map<ProcedureParameter<?>, JdbcCallParameterRegistration> parameterRegistrations,
|
||||||
JdbcCallRefCursorExtractor[] refCursorParameters,
|
JdbcCallRefCursorExtractor[] refCursorParameters,
|
||||||
CallableStatement callableStatement) {
|
CallableStatement callableStatement) {
|
||||||
|
@ -44,6 +45,11 @@ public class ProcedureOutputsImpl extends OutputsImpl implements ProcedureOutput
|
||||||
this.callableStatement = callableStatement;
|
this.callableStatement = callableStatement;
|
||||||
this.parameterRegistrations = parameterRegistrations;
|
this.parameterRegistrations = parameterRegistrations;
|
||||||
this.refCursorParameters = refCursorParameters;
|
this.refCursorParameters = refCursorParameters;
|
||||||
|
if ( procedureCall.getFunctionReturn() != null && procedureCall.getFunctionReturn().getMode() != ParameterMode.REF_CURSOR ) {
|
||||||
|
// Set to -1, so we can handle the function return as out parameter separately
|
||||||
|
this.refCursorParamIndex = -1;
|
||||||
|
}
|
||||||
|
executeStatement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -116,9 +122,19 @@ public class ProcedureOutputsImpl extends OutputsImpl implements ProcedureOutput
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Output buildExtendedReturn() {
|
protected Output buildExtendedReturn() {
|
||||||
final JdbcCallRefCursorExtractor refCursorParam = refCursorParameters[ProcedureOutputsImpl.this.refCursorParamIndex++];
|
if ( ProcedureOutputsImpl.this.refCursorParamIndex == -1 ) {
|
||||||
final ResultSet resultSet = refCursorParam.extractResultSet( callableStatement, procedureCall.getSession() );
|
// Handle the function return
|
||||||
return buildResultSetOutput( () -> extractResults( resultSet ) );
|
ProcedureOutputsImpl.this.refCursorParamIndex = 0;
|
||||||
|
return buildResultSetOutput( () -> List.of( getOutputParameterValue( procedureCall.getFunctionReturn() ) ) );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
final JdbcCallRefCursorExtractor refCursorParam = refCursorParameters[ProcedureOutputsImpl.this.refCursorParamIndex++];
|
||||||
|
final ResultSet resultSet = refCursorParam.extractResultSet(
|
||||||
|
callableStatement,
|
||||||
|
procedureCall.getSession()
|
||||||
|
);
|
||||||
|
return buildResultSetOutput( () -> extractResults( resultSet ) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -65,6 +65,9 @@ public class OutputsImpl implements Outputs {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
this.jdbcStatement = jdbcStatement;
|
this.jdbcStatement = jdbcStatement;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void executeStatement() {
|
||||||
try {
|
try {
|
||||||
final boolean isResultSet = jdbcStatement.execute();
|
final boolean isResultSet = jdbcStatement.execute();
|
||||||
currentReturnState = buildCurrentReturnState( isResultSet );
|
currentReturnState = buildCurrentReturnState( isResultSet );
|
||||||
|
@ -343,6 +346,7 @@ public class OutputsImpl implements Outputs {
|
||||||
else if ( hasExtendedReturns() ) {
|
else if ( hasExtendedReturns() ) {
|
||||||
return buildExtendedReturn();
|
return buildExtendedReturn();
|
||||||
}
|
}
|
||||||
|
// else if ( procedureCall)
|
||||||
|
|
||||||
throw new NoMoreOutputsException();
|
throw new NoMoreOutputsException();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class JdbcCallFunctionReturnImpl extends JdbcCallParameterRegistrationImp
|
||||||
super(
|
super(
|
||||||
null,
|
null,
|
||||||
1,
|
1,
|
||||||
ParameterMode.REF_CURSOR,
|
refCursorExtractor == null ? ParameterMode.OUT : ParameterMode.REF_CURSOR,
|
||||||
ormType,
|
ormType,
|
||||||
null,
|
null,
|
||||||
parameterExtractor,
|
parameterExtractor,
|
||||||
|
|
|
@ -18,12 +18,22 @@ import org.hibernate.annotations.Filter;
|
||||||
import org.hibernate.annotations.FilterDef;
|
import org.hibernate.annotations.FilterDef;
|
||||||
import org.hibernate.annotations.JdbcTypeCode;
|
import org.hibernate.annotations.JdbcTypeCode;
|
||||||
import org.hibernate.annotations.ParamDef;
|
import org.hibernate.annotations.ParamDef;
|
||||||
|
import org.hibernate.dialect.DB2Dialect;
|
||||||
|
import org.hibernate.dialect.DerbyDialect;
|
||||||
|
import org.hibernate.dialect.H2Dialect;
|
||||||
|
import org.hibernate.dialect.HSQLDialect;
|
||||||
|
import org.hibernate.dialect.MariaDBDialect;
|
||||||
|
import org.hibernate.dialect.MySQLDialect;
|
||||||
|
import org.hibernate.dialect.OracleDialect;
|
||||||
|
import org.hibernate.dialect.SQLServerDialect;
|
||||||
|
import org.hibernate.dialect.SybaseDialect;
|
||||||
import org.hibernate.type.NumericBooleanConverter;
|
import org.hibernate.type.NumericBooleanConverter;
|
||||||
import org.hibernate.type.YesNoConverter;
|
import org.hibernate.type.YesNoConverter;
|
||||||
|
|
||||||
import org.hibernate.testing.orm.junit.DomainModel;
|
import org.hibernate.testing.orm.junit.DomainModel;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactory;
|
import org.hibernate.testing.orm.junit.SessionFactory;
|
||||||
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
import org.hibernate.testing.orm.junit.SessionFactoryScope;
|
||||||
|
import org.hibernate.testing.orm.junit.SkipForDialect;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -55,12 +65,32 @@ public class FilterParameterTests {
|
||||||
final EntityOne loaded = session.byId( EntityOne.class ).load( 1 );
|
final EntityOne loaded = session.byId( EntityOne.class ).load( 1 );
|
||||||
assertThat( loaded ).isNull();
|
assertThat( loaded ).isNull();
|
||||||
} );
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SkipForDialect(dialectClass = H2Dialect.class, reason = "H2 silently converts a boolean to string types")
|
||||||
|
@SkipForDialect(dialectClass = HSQLDialect.class, reason = "HSQL silently converts a boolean to string types")
|
||||||
|
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby silently converts a boolean to string types")
|
||||||
|
@SkipForDialect(dialectClass = DB2Dialect.class, reason = "DB2 silently converts a boolean to string types")
|
||||||
|
@SkipForDialect(dialectClass = MySQLDialect.class, reason = "MySQL silently converts a boolean to string types")
|
||||||
|
@SkipForDialect(dialectClass = MariaDBDialect.class, reason = "MariaDB silently converts a boolean to string types")
|
||||||
|
@SkipForDialect(dialectClass = SybaseDialect.class, matchSubTypes = true, reason = "Sybase silently converts a boolean to string types")
|
||||||
|
public void testYesNoMismatch(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
final EntityOne loaded = session.byId( EntityOne.class ).load( 1 );
|
||||||
|
assertThat( loaded ).isNotNull();
|
||||||
|
} );
|
||||||
|
|
||||||
scope.inTransaction( (session) -> {
|
scope.inTransaction( (session) -> {
|
||||||
session.enableFilter( "filterYesNoBoolean" ).setParameter( "yesNo", Boolean.FALSE );
|
session.enableFilter( "filterYesNoBoolean" ).setParameter( "yesNo", Boolean.FALSE );
|
||||||
|
|
||||||
final EntityOne loaded = session.byId( EntityOne.class ).load( 1 );
|
try {
|
||||||
assertThat( loaded ).isNull();
|
session.byId( EntityOne.class ).load( 1 );
|
||||||
|
fail( "Expecting an exception" );
|
||||||
|
}
|
||||||
|
catch (Exception expected) {
|
||||||
|
System.out.println(expected.getMessage());
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,16 +107,40 @@ public class FilterParameterTests {
|
||||||
final EntityTwo loaded = session.byId( EntityTwo.class ).load( 1 );
|
final EntityTwo loaded = session.byId( EntityTwo.class ).load( 1 );
|
||||||
assertThat( loaded ).isNull();
|
assertThat( loaded ).isNull();
|
||||||
} );
|
} );
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@SkipForDialect(dialectClass = H2Dialect.class, reason = "H2 silently converts a boolean to integral types")
|
||||||
|
@SkipForDialect(dialectClass = OracleDialect.class, reason = "Oracle silently converts a boolean to integral types")
|
||||||
|
@SkipForDialect(dialectClass = HSQLDialect.class, reason = "HSQL silently converts a boolean to integral types")
|
||||||
|
@SkipForDialect(dialectClass = DerbyDialect.class, reason = "Derby silently converts a boolean to integral types")
|
||||||
|
@SkipForDialect(dialectClass = DB2Dialect.class, reason = "DB2 silently converts a boolean to integral types")
|
||||||
|
@SkipForDialect(dialectClass = MySQLDialect.class, reason = "MySQL silently converts a boolean to integral types")
|
||||||
|
@SkipForDialect(dialectClass = MariaDBDialect.class, reason = "MariaDB silently converts a boolean to integral types")
|
||||||
|
@SkipForDialect(dialectClass = SQLServerDialect.class, reason = "SQL Server silently converts a boolean to integral types")
|
||||||
|
@SkipForDialect(dialectClass = SybaseDialect.class, matchSubTypes = true, reason = "Sybase silently converts a boolean to integral types")
|
||||||
|
public void testNumericMismatch(SessionFactoryScope scope) {
|
||||||
|
scope.inTransaction( (session) -> {
|
||||||
|
final EntityTwo loaded = session.byId( EntityTwo.class ).load( 1 );
|
||||||
|
assertThat( loaded ).isNotNull();
|
||||||
|
} );
|
||||||
|
|
||||||
scope.inTransaction( (session) -> {
|
scope.inTransaction( (session) -> {
|
||||||
session.enableFilter( "filterNumberBoolean" ).setParameter( "zeroOne", Boolean.FALSE );
|
session.enableFilter( "filterNumberBoolean" ).setParameter( "zeroOne", Boolean.FALSE );
|
||||||
|
|
||||||
final EntityTwo loaded = session.byId( EntityTwo.class ).load( 1 );
|
try {
|
||||||
assertThat( loaded ).isNull();
|
session.byId( EntityTwo.class ).load( 1 );
|
||||||
|
fail( "Expecting an exception" );
|
||||||
|
}
|
||||||
|
catch (Exception expected) {
|
||||||
|
System.out.println(expected.getMessage());
|
||||||
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@SkipForDialect(dialectClass = MySQLDialect.class, reason = "MySQL silently converts strings to integral types")
|
||||||
|
@SkipForDialect(dialectClass = MariaDBDialect.class, reason = "MariaDB silently converts strings to integral types")
|
||||||
public void testMismatch(SessionFactoryScope scope) {
|
public void testMismatch(SessionFactoryScope scope) {
|
||||||
scope.inTransaction( (session) -> {
|
scope.inTransaction( (session) -> {
|
||||||
final EntityThree loaded = session.byId( EntityThree.class ).load( 1 );
|
final EntityThree loaded = session.byId( EntityThree.class ).load( 1 );
|
||||||
|
@ -101,6 +155,7 @@ public class FilterParameterTests {
|
||||||
fail( "Expecting an exception" );
|
fail( "Expecting an exception" );
|
||||||
}
|
}
|
||||||
catch (Exception expected) {
|
catch (Exception expected) {
|
||||||
|
System.out.println(expected.getMessage());
|
||||||
}
|
}
|
||||||
} );
|
} );
|
||||||
}
|
}
|
||||||
|
|
|
@ -69,6 +69,8 @@ import static org.junit.jupiter.api.Assertions.fail;
|
||||||
@RequiresDialect(value = OracleDialect.class)
|
@RequiresDialect(value = OracleDialect.class)
|
||||||
public class OracleStoredProcedureTest {
|
public class OracleStoredProcedureTest {
|
||||||
|
|
||||||
|
private Person person1;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUnRegisteredParameter(EntityManagerFactoryScope scope) {
|
public void testUnRegisteredParameter(EntityManagerFactoryScope scope) {
|
||||||
scope.inTransaction( (em) -> {
|
scope.inTransaction( (em) -> {
|
||||||
|
@ -97,7 +99,7 @@ public class OracleStoredProcedureTest {
|
||||||
query.registerStoredProcedureParameter( 1, Long.class, ParameterMode.IN );
|
query.registerStoredProcedureParameter( 1, Long.class, ParameterMode.IN );
|
||||||
query.registerStoredProcedureParameter( 2, Long.class, ParameterMode.OUT );
|
query.registerStoredProcedureParameter( 2, Long.class, ParameterMode.OUT );
|
||||||
|
|
||||||
query.setParameter( 1, 1L );
|
query.setParameter( 1, person1.getId() );
|
||||||
|
|
||||||
query.execute();
|
query.execute();
|
||||||
Long phoneCount = (Long) query.getOutputParameterValue( 2 );
|
Long phoneCount = (Long) query.getOutputParameterValue( 2 );
|
||||||
|
@ -113,7 +115,7 @@ public class OracleStoredProcedureTest {
|
||||||
StoredProcedureQuery query = entityManager.createStoredProcedureQuery( "sp_person_phones" );
|
StoredProcedureQuery query = entityManager.createStoredProcedureQuery( "sp_person_phones" );
|
||||||
query.registerStoredProcedureParameter( 1, Long.class, ParameterMode.IN );
|
query.registerStoredProcedureParameter( 1, Long.class, ParameterMode.IN );
|
||||||
query.registerStoredProcedureParameter( 2, Class.class, ParameterMode.REF_CURSOR );
|
query.registerStoredProcedureParameter( 2, Class.class, ParameterMode.REF_CURSOR );
|
||||||
query.setParameter( 1, 1L );
|
query.setParameter( 1, person1.getId() );
|
||||||
|
|
||||||
query.execute();
|
query.execute();
|
||||||
List<Object[]> postComments = query.getResultList();
|
List<Object[]> postComments = query.getResultList();
|
||||||
|
@ -134,7 +136,7 @@ public class OracleStoredProcedureTest {
|
||||||
Long.class,
|
Long.class,
|
||||||
ParameterMode.IN
|
ParameterMode.IN
|
||||||
);
|
);
|
||||||
call.setParameter( inParam, 1L );
|
call.setParameter( inParam, person1.getId() );
|
||||||
call.registerParameter( 2, Class.class, ParameterMode.REF_CURSOR );
|
call.registerParameter( 2, Class.class, ParameterMode.REF_CURSOR );
|
||||||
|
|
||||||
Output output = call.getOutputs().getCurrent();
|
Output output = call.getOutputs().getCurrent();
|
||||||
|
@ -150,7 +152,7 @@ public class OracleStoredProcedureTest {
|
||||||
entityManager -> {
|
entityManager -> {
|
||||||
BigDecimal phoneCount = (BigDecimal) entityManager
|
BigDecimal phoneCount = (BigDecimal) entityManager
|
||||||
.createNativeQuery( "SELECT fn_count_phones(:personId) FROM DUAL" )
|
.createNativeQuery( "SELECT fn_count_phones(:personId) FROM DUAL" )
|
||||||
.setParameter( "personId", 1 )
|
.setParameter( "personId", person1.getId() )
|
||||||
.getSingleResult();
|
.getSingleResult();
|
||||||
assertEquals( BigDecimal.valueOf( 2 ), phoneCount );
|
assertEquals( BigDecimal.valueOf( 2 ), phoneCount );
|
||||||
}
|
}
|
||||||
|
@ -163,7 +165,7 @@ public class OracleStoredProcedureTest {
|
||||||
entityManager -> {
|
entityManager -> {
|
||||||
List<Object[]> postAndComments = entityManager
|
List<Object[]> postAndComments = entityManager
|
||||||
.createNamedStoredProcedureQuery( "personAndPhonesFunction" )
|
.createNamedStoredProcedureQuery( "personAndPhonesFunction" )
|
||||||
.setParameter( 1, 1L )
|
.setParameter( 1, person1.getId() )
|
||||||
.getResultList();
|
.getResultList();
|
||||||
Object[] postAndComment = postAndComments.get( 0 );
|
Object[] postAndComment = postAndComments.get( 0 );
|
||||||
Person person = (Person) postAndComment[0];
|
Person person = (Person) postAndComment[0];
|
||||||
|
@ -188,7 +190,7 @@ public class OracleStoredProcedureTest {
|
||||||
//OracleTypes.CURSOR
|
//OracleTypes.CURSOR
|
||||||
function.registerOutParameter( 1, -10 );
|
function.registerOutParameter( 1, -10 );
|
||||||
}
|
}
|
||||||
function.setInt( 2, 1 );
|
function.setLong( 2, person1.getId() );
|
||||||
function.execute();
|
function.execute();
|
||||||
try (ResultSet resultSet = (ResultSet) function.getObject( 1 );) {
|
try (ResultSet resultSet = (ResultSet) function.getObject( 1 );) {
|
||||||
while ( resultSet.next() ) {
|
while ( resultSet.next() ) {
|
||||||
|
@ -411,18 +413,18 @@ public class OracleStoredProcedureTest {
|
||||||
);
|
);
|
||||||
|
|
||||||
statement.execute(
|
statement.execute(
|
||||||
"create or replace function find_char(" +
|
"CREATE OR REPLACE FUNCTION find_char(" +
|
||||||
" search in char, " +
|
" search_char IN CHAR, " +
|
||||||
" string in varchar," +
|
" string IN VARCHAR," +
|
||||||
" start in integer default 0) " +
|
" start_idx IN NUMBER DEFAULT 1) " +
|
||||||
"return integer " +
|
"RETURN NUMBER " +
|
||||||
"as " +
|
"IS " +
|
||||||
" position integer; " +
|
" pos NUMBER; " +
|
||||||
"begin " +
|
"BEGIN " +
|
||||||
" select instr( search, string, start ) into position " +
|
" SELECT INSTR( string, search_char, start_idx ) INTO pos " +
|
||||||
" from dual; " +
|
" FROM dual; " +
|
||||||
" return position; " +
|
" RETURN pos; " +
|
||||||
"end;"
|
"END;"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
catch (SQLException e) {
|
catch (SQLException e) {
|
||||||
|
@ -432,7 +434,7 @@ public class OracleStoredProcedureTest {
|
||||||
} ) );
|
} ) );
|
||||||
|
|
||||||
scope.inTransaction( (entityManager) -> {
|
scope.inTransaction( (entityManager) -> {
|
||||||
Person person1 = new Person( "John Doe" );
|
person1 = new Person( "John Doe" );
|
||||||
person1.setNickName( "JD" );
|
person1.setNickName( "JD" );
|
||||||
person1.setAddress( "Earth" );
|
person1.setAddress( "Earth" );
|
||||||
person1.setCreatedOn( Timestamp.from( LocalDateTime.of( 2000, 1, 1, 0, 0, 0 )
|
person1.setCreatedOn( Timestamp.from( LocalDateTime.of( 2000, 1, 1, 0, 0, 0 )
|
||||||
|
|
Loading…
Reference in New Issue