2929import java .io .InputStream ;
3030import java .lang .reflect .InvocationTargetException ;
3131import java .math .BigDecimal ;
32+ import java .math .RoundingMode ;
3233import java .nio .ByteBuffer ;
3334import java .sql .Blob ;
3435import java .sql .Clob ;
3738import java .sql .ResultSet ;
3839import java .sql .ResultSetMetaData ;
3940import java .sql .SQLException ;
41+ import java .sql .SQLXML ;
4042import java .sql .Struct ;
4143import java .sql .Timestamp ;
4244import java .sql .Types ;
@@ -124,105 +126,84 @@ protected void setFieldValue(StructuredRecord.Builder recordBuilder, Schema.Fiel
124126 return ;
125127 }
126128
127- Schema fieldSchema = field .getSchema ().isNullable () ? field .getSchema ().getNonNullable () : field .getSchema ();
129+ Schema fieldSchema = field .getSchema ().isNullable () ? field .getSchema ().getNonNullable ()
130+ : field .getSchema ();
128131 String attrClassName = attrValue .getClass ().getName ();
129-
130- // Handle Nested Structs Recursively
131132 if (attrValue instanceof Struct ) {
132- recordBuilder .set (field .getName (), convertStructToRecord ((Struct ) attrValue , fieldSchema , null ));
133+ recordBuilder .set (field .getName (), convertStructToRecord ((Struct ) attrValue , fieldSchema ));
133134 return ;
134135 }
135-
136- // Handle Oracle UDTs (Clobs, Blobs, SQLXML, INTERVALS)
137136 if (attrValue instanceof Clob ) {
138137 Clob clob = (Clob ) attrValue ;
139138 recordBuilder .set (field .getName (), clob .getSubString (1 , (int ) clob .length ()));
140139 return ;
141140 }
142-
143141 if (attrValue instanceof Blob ) {
144142 Blob blob = (Blob ) attrValue ;
145143 recordBuilder .set (field .getName (), blob .getBytes (1 , (int ) blob .length ()));
146144 return ;
147145 }
148-
149- if (attrValue instanceof java .sql .SQLXML ) {
150- recordBuilder .set (field .getName (), ((java .sql .SQLXML ) attrValue ).getString ());
146+ if (attrValue instanceof SQLXML ) {
147+ recordBuilder .set (field .getName (), ((SQLXML ) attrValue ).getString ());
151148 return ;
152149 }
153-
154150 if ("oracle.sql.INTERVALDS" .equals (attrClassName ) || "oracle.sql.INTERVALYM" .equals (attrClassName )) {
155151 recordBuilder .set (field .getName (), attrValue .toString ());
156152 return ;
157153 }
158-
159- // Handle Oracle's lazy BigDecimals and downcast them
154+ if ("oracle.sql.NCLOB" .equals (attrClassName )) {
155+ recordBuilder .set (field .getName (), attrValue .toString ());
156+ return ;
157+ }
160158 if (attrValue instanceof BigDecimal ) {
161159 BigDecimal bigDecimal = (BigDecimal ) attrValue ;
162160 if (Schema .LogicalType .DECIMAL .equals (fieldSchema .getLogicalType ())) {
163- recordBuilder .setDecimal (field .getName (), bigDecimal .setScale (fieldSchema .getScale (),
164- java .math .RoundingMode .HALF_UP ));
165- } else {
166- switch (fieldSchema .getType ()) {
167- case DOUBLE : recordBuilder .set (field .getName (), bigDecimal .doubleValue ()); break ;
168- case FLOAT : recordBuilder .set (field .getName (), bigDecimal .floatValue ()); break ;
169- case INT : recordBuilder .set (field .getName (), bigDecimal .intValue ()); break ;
170- case LONG : recordBuilder .set (field .getName (), bigDecimal .longValue ()); break ;
171- case STRING : recordBuilder .set (field .getName (), bigDecimal .toString ()); break ;
172- default : recordBuilder .set (field .getName (), bigDecimal );
173- }
161+ recordBuilder .setDecimal (field .getName (), bigDecimal .setScale (fieldSchema .getScale (), RoundingMode .HALF_UP ));
162+ return ;
163+ }
164+ switch (fieldSchema .getType ()) {
165+ case DOUBLE : recordBuilder .set (field .getName (), bigDecimal .doubleValue ()); break ;
166+ case FLOAT : recordBuilder .set (field .getName (), bigDecimal .floatValue ()); break ;
167+ case INT : recordBuilder .set (field .getName (), bigDecimal .intValue ()); break ;
168+ case LONG : recordBuilder .set (field .getName (), bigDecimal .longValue ()); break ;
169+ case STRING : recordBuilder .set (field .getName (), bigDecimal .toString ()); break ;
170+ default : recordBuilder .set (field .getName (), bigDecimal );
174171 }
175172 return ;
176173 }
177174
178- // 4. Handle Oracle Timestamps to ensure DATETIME schema compatibility
179175 if (attrValue instanceof Timestamp ) {
180176 Timestamp timestamp = (Timestamp ) attrValue ;
181177 if (Schema .LogicalType .DATETIME .equals (fieldSchema .getLogicalType ())) {
182178 recordBuilder .setDateTime (field .getName (), timestamp .toLocalDateTime ());
183- } else if (Schema .LogicalType .DATE .equals (fieldSchema .getLogicalType ())) {
184- recordBuilder .setDate (field .getName (), timestamp .toLocalDateTime ().toLocalDate ());
185- } else if (fieldSchema .getLogicalType () == null && Schema .Type .STRING .equals (fieldSchema .getType ())) {
186- // Only stringify if the CDAP schema strictly demands a String
187- recordBuilder .set (field .getName (), attrValue .toString ());
188179 } else {
189- // HAND IT BACK TO THE PARENT! This restores the exact behavior of your old build.
190180 super .setFieldValue (recordBuilder , field , attrValue );
191181 }
192182 return ;
193183 }
194-
195- // Handle Timezone shifting
196- if (attrValue instanceof OffsetDateTime || attrValue instanceof ZonedDateTime ) {
197- ZonedDateTime zonedDateTime = (attrValue instanceof OffsetDateTime )
198- ? ((OffsetDateTime ) attrValue ).atZoneSameInstant (ZoneId .of ("UTC" ))
199- : ((ZonedDateTime ) attrValue ).withZoneSameInstant (ZoneId .of ("UTC" ));
184+ if (attrValue instanceof OffsetDateTime ) {
185+ ZonedDateTime zonedDateTime = ((OffsetDateTime ) attrValue ).atZoneSameInstant (ZoneId .of ("UTC" ));
200186
201187 if (fieldSchema .getLogicalType () != null &&
202188 (Schema .LogicalType .TIMESTAMP_MICROS .equals (fieldSchema .getLogicalType ()) ||
203189 Schema .LogicalType .TIMESTAMP_MILLIS .equals (fieldSchema .getLogicalType ()))) {
204190 recordBuilder .setTimestamp (field .getName (), zonedDateTime );
205- } else if (Schema .Type .LONG .equals (fieldSchema .getType ())) {
206- recordBuilder .set (field .getName (), zonedDateTime .toInstant ().toEpochMilli ());
207191 } else {
208192 recordBuilder .set (field .getName (), zonedDateTime .toString ());
209193 }
210194 return ;
211195 }
212196
213- // Handle BFILE
214- try {
215- ClassLoader oracleLoader = attrValue .getClass ().getClassLoader ();
216- if (oracleLoader != null && oracleLoader .loadClass ("oracle.jdbc.OracleBfile" ).isInstance (attrValue )) {
217- recordBuilder .set (field .getName (), getBfileBytes (attrValue , field .getName ()));
218- return ;
197+ ClassLoader oracleLoader = attrValue .getClass ().getClassLoader ();
198+ try {
199+ if (oracleLoader != null && oracleLoader .loadClass ("oracle.jdbc.OracleBfile" ).isInstance (attrValue )) {
200+ recordBuilder .set (field .getName (), getBfileBytes (attrValue , field .getName ()));
201+ return ;
202+ }
203+ } catch (ClassNotFoundException e ) {
204+ throw new RuntimeException (e );
219205 }
220- } catch (Exception e ) {
221- // Not a BFile, let it fall through
222- }
223-
224- // Parent DBRecord handles the standard types
225- super .setFieldValue (recordBuilder , field , attrValue );
206+ super .setFieldValue (recordBuilder , field , attrValue );
226207 }
227208
228209 @ Override
@@ -347,7 +328,7 @@ private byte[] getBfileBytes(ResultSet resultSet, String columnName) throws SQLE
347328 return getBfileBytes (bfile , columnName );
348329 }
349330
350- public static byte [] getBfileBytes (Object bfile , String columnName ) {
331+ public byte [] getBfileBytes (Object bfile , String columnName ) {
351332 if (bfile == null ) {
352333 return null ;
353334 }
@@ -460,7 +441,7 @@ private void handleOracleSpecificType(ResultSet resultSet, StructuredRecord.Buil
460441 case Types .STRUCT :
461442 Struct structValue = (Struct ) resultSet .getObject (columnIndex );
462443 if (structValue != null ) {
463- recordBuilder .set (field .getName (), convertStructToRecord (structValue , nonNullSchema , resultSet ));
444+ recordBuilder .set (field .getName (), convertStructToRecord (structValue , nonNullSchema ));
464445 }
465446 break ;
466447 case Types .DECIMAL :
@@ -493,7 +474,7 @@ private void handleOracleSpecificType(ResultSet resultSet, StructuredRecord.Buil
493474 }
494475 }
495476
496- private StructuredRecord convertStructToRecord (Struct struct , Schema schema , ResultSet resultSet )
477+ protected StructuredRecord convertStructToRecord (Struct struct , Schema schema )
497478 throws SQLException {
498479 Object [] attributes = struct .getAttributes ();
499480 List <Schema .Field > fields = schema .getFields ();
@@ -502,7 +483,6 @@ private StructuredRecord convertStructToRecord(Struct struct, Schema schema, Res
502483 for (int index = 0 ; index < attributes .length ; index ++) {
503484 Schema .Field field = fields .get (index );
504485 Object attrValue = attributes [index ];
505-
506486 setFieldValue (builder , field , attrValue );
507487 }
508488 return builder .build ();
0 commit comments