Configuração do Oracle :
CREATE OR REPLACE TYPE BD_TB_STRUCT AS OBJECT(
start_ts TIMESTAMP(3),
end_ts TIMESTAMP(3),
time_type NUMBER(19),
duration NUMBER(12)
) FINAL;
/
CREATE OR REPLACE PROCEDURE merge_time_bounds(
s1_bd_t IN bd_tb_struct,
s2_bd_t IN bd_tb_struct,
r_bd_t OUT bd_tb_struct
)
IS
p_start TIMESTAMP(3) := LEAST( s1_bd_t.start_ts, s2_bd_t.start_ts );
p_end TIMESTAMP(3) := GREATEST( s1_bd_t.end_ts, s2_bd_t.end_ts );
BEGIN
r_bd_t := new BD_TB_STRUCT(
p_start,
p_end,
COALESCE( s1_bd_t.time_type, s2_bd_t.time_type ),
( CAST( p_end AS DATE ) - CAST( p_start AS DATE ) ) * 24 * 60 * 60
);
END;
/
Classe Java SQLData :
import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.SQLData;
import java.sql.SQLException;
import java.sql.SQLInput;
import java.sql.SQLOutput;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
public class BoundsSQL implements SQLData
{
public static final String SQL_TYPE = "BD_TB_STRUCT";
public java.sql.Timestamp start;
public java.sql.Timestamp end;
public BigInteger type;
public BigInteger duration;
public BoundsSQL()
{
}
public BoundsSQL(
final int year,
final int month,
final int dayOfMonth,
final int hour,
final int minute,
final int seconds,
final long duration,
final long type )
{
final long epochSeconds = LocalDateTime.of(
year,
month,
dayOfMonth,
hour,
minute,
seconds
).toEpochSecond( ZoneOffset.UTC );
this.start = new Timestamp( epochSeconds * 1000 );
this.end = new Timestamp( (epochSeconds + duration) * 1000 );
this.duration = BigInteger.valueOf( duration );
this.type = BigInteger.valueOf( type );
}
@Override
public String getSQLTypeName() throws SQLException
{
return SQL_TYPE;
}
@Override
public void readSQL( SQLInput stream,
String typeName ) throws SQLException
{
start = stream.readTimestamp();
end = stream.readTimestamp();
type = stream.readBigDecimal().toBigInteger();
duration = stream.readBigDecimal().toBigInteger();
}
@Override
public void writeSQL( SQLOutput stream ) throws SQLException
{
stream.writeTimestamp( start );
stream.writeTimestamp( end );
stream.writeBigDecimal( new BigDecimal( type ) );
stream.writeBigDecimal( new BigDecimal( duration ) );
}
@Override
public String toString()
{
return String.format(
"Start: %s\nEnd: %s\nDuration: %s\nType: %s",
start,
end,
duration,
type
);
}
}
Chamada de procedimento armazenado de Java :
Chame o procedimento armazenado usando
OracleCallableStatement#setObject( int, Object )
para passar parâmetros e colocar a classe em um mapa de tipos e usar OracleCallableStatement#registerOutParameter( int, int, string )
e OracleCallableStatement#getObject( int )
para recuperar os parâmetros. import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Map;
import oracle.jdbc.OracleCallableStatement;
import oracle.jdbc.OracleConnection;
import oracle.jdbc.OracleTypes;
public class PassStructToProcedure
{
public static void main( final String[] args ){
OracleConnection con = null;
try{
Class.forName( "oracle.jdbc.OracleDriver" );
con = (OracleConnection) DriverManager.getConnection(
"jdbc:oracle:thin:@localhost:1521:orcl",
"USERNAME",
"PASSWORD"
);
BoundsSQL bound1 = new BoundsSQL( 2019, 1, 1, 0, 0, 0, 10, 1 );
BoundsSQL bound2 = new BoundsSQL( 2019, 1, 1, 0, 0, 5, 10, 2 );
OracleCallableStatement st = (OracleCallableStatement) con.prepareCall(
"{ call MERGE_TIME_BOUNDS( ?, ?, ? ) }"
);
st.setObject( 1, bound1 );
st.setObject( 2, bound2 );
st.registerOutParameter( 3, OracleTypes.STRUCT, BoundsSQL.SQL_TYPE );
st.execute();
Map<String,Class<?>> typeMap = con.getTypeMap();
typeMap.put( BoundsSQL.SQL_TYPE, BoundsSQL.class );
BoundsSQL out = (BoundsSQL) st.getObject( 3 );
System.out.println( out.toString() );
st.close();
} catch (ClassNotFoundException | SQLException ex) {
System.out.println( ex.getMessage() );
ex.printStackTrace();
} finally {
try{
if ( con != null )
con.close();
}
catch( SQLException e )
{
}
}
}
}
Saída :
Start: 2019-01-01 00:00:00.0
End: 2019-01-01 00:00:15.0
Duration: 15
Type: 1