66 */
77package com .microsoft .semantickernel .data .jdbc .oracle ;
88
9+ import com .fasterxml .jackson .core .JsonFactory ;
910import com .fasterxml .jackson .core .JsonProcessingException ;
11+ import com .fasterxml .jackson .core .JsonGenerator ;
1012import com .fasterxml .jackson .databind .JsonNode ;
1113import com .fasterxml .jackson .databind .MapperFeature ;
1214import com .fasterxml .jackson .databind .ObjectMapper ;
3335import oracle .jdbc .OracleStatement ;
3436import oracle .jdbc .OracleTypes ;
3537import oracle .sql .TIMESTAMPTZ ;
38+ import oracle .jdbc .provider .oson .OsonFactory ;
3639
3740import javax .annotation .Nonnull ;
3841import javax .annotation .concurrent .GuardedBy ;
3942import javax .sql .DataSource ;
43+ import java .io .ByteArrayOutputStream ;
44+ import java .io .IOException ;
4045import java .math .BigDecimal ;
4146import java .sql .Connection ;
4247import java .sql .PreparedStatement ;
4853import java .util .Arrays ;
4954import java .util .Collections ;
5055import java .util .List ;
51- import java .util .Map ;
5256import java .util .UUID ;
5357import java .util .concurrent .locks .ReentrantLock ;
5458import java .util .logging .Logger ;
5559import java .util .stream .Collectors ;
56- import java .util .stream .StreamSupport ;
5760
5861/**
5962 * JDBC Vector Store for the Oracle Database
@@ -329,57 +332,48 @@ private void setUpsertStatementValues(PreparedStatement upsertStatement, Object
329332 // Some field types require special treatment to convert the java type to the
330333 // DB type
331334 if (field instanceof VectorStoreRecordVectorField ) {
332-
333- // Convert the vector field to a string
334- if (field .getFieldType ().equals (String .class )) {
335- String json = (valueNode == null || valueNode .isNull ())
336- ? null
337- : valueNode .asText ();
338- double [] values = (json == null )
339- ? null
340- : objectMapper .readValue (json , double [].class );
341-
342- int dim = ((VectorStoreRecordVectorField ) field ).getDimensions ();
343- if (values != null && values .length != dim ) {
344- throw new SKException ("Vector dimension mismatch: expected " + dim );
345- }
346-
347- upsertStatement .setObject (i + 1 , values , OracleTypes .VECTOR_FLOAT32 );
348- continue ;
349- }
350-
351- // If the vector field is not set as a string convert to an array of doubles
335+ // If the vector field is not set as a string convert to an array of floats
352336 // and set the value
353337 if (!field .getFieldType ().equals (String .class )) {
354- double [] values = (valueNode == null || valueNode .isNull ())
355- ? null
356- : StreamSupport .stream ((
357- (ArrayNode )valueNode ).spliterator (), false )
358- .mapToDouble (d -> d .asDouble ()).toArray ();
359-
360- upsertStatement .setObject (i + 1 , values , OracleTypes .VECTOR_FLOAT32 );
338+ if (valueNode != null && !valueNode .isNull () && valueNode .isArray ()) {
339+ final float [] values = new float [valueNode .size ()];
340+ for (int j = 0 ; j < ((ArrayNode )valueNode ).size (); j ++) {
341+ values [j ] = ((ArrayNode )valueNode ).get (j ).floatValue ();
342+ }
343+ upsertStatement .setObject (i + 1 , values , OracleTypes .VECTOR_FLOAT32 );
344+ } else {
345+ upsertStatement .setNull (i + 1 , OracleTypes .VECTOR_FLOAT32 );
346+ }
361347 continue ;
362348 }
363349 } else if (field instanceof VectorStoreRecordDataField ) {
364- // Lists are stored as JSON objects, write the list as a JSON string representation
365- // of the list .
350+ // Lists are stored as JSON objects, write the list using the JDBC OSON
351+ // extensions .
366352 if (field .getFieldType ().equals (List .class )) {
367- upsertStatement .setObject (i + 1 , objectMapper .writeValueAsString (valueNode ));
353+ JsonFactory osonFactory = new OsonFactory ();
354+ try (ByteArrayOutputStream out = new ByteArrayOutputStream ()) {
355+ try (JsonGenerator osonGen = osonFactory .createGenerator (out )) {
356+ objectMapper .writeValue (osonGen , valueNode );
357+ }
358+ upsertStatement .setBytes (i + 1 , out .toByteArray ());
359+ } catch (IOException ioEx ) {
360+ throw new SKException ("Failed to convert list to JSON value" , ioEx );
361+ }
368362 continue ;
369363 }
370364 // Convert UUID to string before setting the value.
371365 if (field .getFieldType ().equals (UUID .class )) {
372366 upsertStatement .setObject (i + 1 , valueNode .isNull () ? null : valueNode .asText ());
373367 continue ;
374368 }
375- // Convert OffsetDateTime to TIMESTAMPTZ before setting the value.
369+ // Convert value node (its representations depends on Jackson JSON features)
370+ // to OffsetDateTime before setting the value.
376371 if (field .getFieldType ().equals (OffsetDateTime .class )) {
377372 if (valueNode == null || valueNode .isNull ()) {
378373 upsertStatement .setNull (i + 1 , OracleTypes .TIMESTAMPTZ );
379374 } else {
380375 OffsetDateTime offsetDateTime = (OffsetDateTime ) objectMapper .convertValue (valueNode , field .getFieldType ());
381- ((OraclePreparedStatement ) upsertStatement ).setTIMESTAMPTZ (i + 1 ,
382- TIMESTAMPTZ .of (offsetDateTime ));
376+ upsertStatement .setObject (i + 1 , offsetDateTime );
383377 }
384378 continue ;
385379 }
@@ -388,8 +382,8 @@ private void setUpsertStatementValues(PreparedStatement upsertStatement, Object
388382 // For all other field type use setObject with the field value
389383 upsertStatement .setObject (i + 1 ,
390384 objectMapper .convertValue (valueNode ,field .getFieldType ()));
391- } catch (SQLException | JsonProcessingException e ) {
392- throw new RuntimeException (e );
385+ } catch (SQLException e ) {
386+ throw new SKException (e );
393387 }
394388 }
395389 }
0 commit comments