1+ /*
2+ ** Semantic Kernel Oracle connector version 1.0.
3+ **
4+ ** Copyright (c) 2025 Oracle and/or its affiliates.
5+ ** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
6+ */
17package com .microsoft .semantickernel .data .jdbc .oracle ;
28
39import com .microsoft .semantickernel .data .jdbc .oracle .OracleVectorStoreQueryProvider .StringTypeMapping ;
410import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordDataField ;
11+ import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordField ;
512import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordKeyField ;
613import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordVectorField ;
714import oracle .jdbc .OracleTypes ;
1623import java .util .stream .Collectors ;
1724
1825/**
19- * Helper class for field operations.
26+ * Helper class for field operations. Handles mapping between field java types to DB types and
27+ * generating SQL statement to create field indexes.
2028 */
21- public class OracleVectorStoreFieldHelper {
22- private static final Logger LOGGER = Logger .getLogger (OracleVectorStoreQueryProvider .class .getName ());
29+ class OracleVectorStoreFieldHelper {
30+
31+ /**
32+ * The logger
33+ */
34+ private static final Logger LOGGER = Logger .getLogger (OracleVectorStoreFieldHelper .class .getName ());
2335
2436 /**
2537 * Maps supported key java classes to Oracle database types
2638 */
2739 private static final HashMap <Class <?>, String > supportedKeyTypes = new HashMap () {
2840 {
2941 put (String .class , String .format (OracleDataTypesMapping .STRING_VARCHAR , 255 ));
30- put (short .class , OracleDataTypesMapping .SHORT );
31- put (Short .class , OracleDataTypesMapping .SHORT );
32- put (int .class , OracleDataTypesMapping .INTEGER );
33- put (Integer .class , OracleDataTypesMapping .INTEGER );
34- put (long .class , OracleDataTypesMapping .LONG );
35- put (Long .class , OracleDataTypesMapping .LONG );
36- put (UUID .class , OracleDataTypesMapping .UUID );
3742 }
3843 };
3944
@@ -47,14 +52,6 @@ public class OracleVectorStoreFieldHelper {
4752 put (Collection .class , OracleDataTypesMapping .VECTOR_FLOAT );
4853 put (float [].class , OracleDataTypesMapping .VECTOR_FLOAT );
4954 put (Float [].class , OracleDataTypesMapping .VECTOR_FLOAT );
50- /*
51- put(byte[].class,"VECTOR(%s, INT8)");
52- put(Byte[].class,"VECTOR(%s, INT8)");
53- put(double[].class,"VECTOR(%s, FLOAT64)");
54- put(Double[].class,"VECTOR(%s, FLOAT64)");
55- put(boolean[].class,"VECTOR(%s, BINARY)");
56- put(Boolean[].class,"VECTOR(%s, BINARY)");
57- */
5855 }
5956 };
6057
@@ -83,26 +80,12 @@ public class OracleVectorStoreFieldHelper {
8380 put (byte [].class , OracleDataTypesMapping .BYTE_ARRAY );
8481 put (List .class , OracleDataTypesMapping .JSON );
8582 }
86-
8783 };
8884
8985 /**
90- * Maps vector type to OracleTypes. Only needed if types other than FLOAT_32 are supported .
86+ * Suffix added to the effective column name to generate the index name for a vector column .
9187 */
92- private static final Map <Class <?>, Integer > mapOracleTypeToVector = new HashMap () {
93- {
94- put (float [].class , OracleTypes .VECTOR_FLOAT32 );
95- put (Float [].class , OracleTypes .VECTOR_FLOAT32 );
96- /*
97- put(byte[].class, OracleTypes.VECTOR_INT8);
98- put(Byte[].class, OracleTypes.VECTOR_INT8);
99- put(Double[].class, OracleTypes.VECTOR_FLOAT64);
100- put(double[].class, OracleTypes.VECTOR_FLOAT64);
101- put(Boolean[].class, OracleTypes.VECTOR_BINARY);
102- put(boolean[].class, OracleTypes.VECTOR_BINARY);
103- */
104- }
105- };
88+ public static final String VECTOR_INDEX_SUFFIX = "_VECTOR_INDEX" ;
10689
10790 /**
10891 * Gets the mapping between the supported Java key types and the Oracle database type.
@@ -120,12 +103,11 @@ public static HashMap<Class<?>, String> getSupportedKeyTypes() {
120103 */
121104 public static Map <Class <?>, String > getSupportedDataTypes (
122105 StringTypeMapping stringTypeMapping , int defaultVarCharLength ) {
123-
124- if (stringTypeMapping .equals (StringTypeMapping .USE_VARCHAR )) {
125- supportedDataTypes .put (String .class , String .format (OracleDataTypesMapping .STRING_VARCHAR , defaultVarCharLength ));
126- } else {
127- supportedDataTypes .put (String .class , OracleDataTypesMapping .STRING_CLOB );
128- }
106+ String stringType = stringTypeMapping .equals (StringTypeMapping .USE_VARCHAR )
107+ ? String .format (OracleDataTypesMapping .STRING_VARCHAR , defaultVarCharLength )
108+ : OracleDataTypesMapping .STRING_CLOB ;
109+ supportedDataTypes .put (String .class , stringType );
110+ LOGGER .finest ("Mapping String columns to " + stringType );
129111 return supportedDataTypes ;
130112 }
131113
@@ -176,14 +158,14 @@ public static String getCreateVectorIndexStatement(VectorStoreRecordVectorField
176158 */
177159 public static String createIndexForDataField (String collectionTableName , VectorStoreRecordDataField dataField , Map <Class <?>, String > supportedDataTypes ) {
178160 if (supportedDataTypes .get (dataField .getFieldType ()) == "JSON" ) {
179- String dataFieldIndex = "CREATE MULTIVALUE INDEX %s ON %s t (t.%s.%s)" ;
161+ String dataFieldIndex = "CREATE MULTIVALUE INDEX IF NOT EXISTS %s ON %s t (t.%s.%s)" ;
180162 return String .format (dataFieldIndex ,
181163 collectionTableName + "_" + dataField .getEffectiveStorageName (),
182164 collectionTableName ,
183165 dataField .getEffectiveStorageName (),
184166 getFunctionForType (supportedDataTypes .get (dataField .getFieldSubType ())));
185167 } else {
186- String dataFieldIndex = "CREATE INDEX %s ON %s (%s ASC)" ;
168+ String dataFieldIndex = "CREATE INDEX IF NOT EXISTS %s ON %s (%s ASC)" ;
187169 return String .format (dataFieldIndex ,
188170 collectionTableName + "_" + dataField .getEffectiveStorageName (),
189171 collectionTableName ,
@@ -192,6 +174,50 @@ public static String createIndexForDataField(String collectionTableName, VectorS
192174 }
193175 }
194176
177+ /**
178+ * Returns vector columns names and types for CREATE TABLE statement
179+ * @param fields list of vector record fields.
180+ * @return comma separated list of columns and types for CREATE TABLE statement.
181+ */
182+ public static String getVectorColumnNamesAndTypes (List <VectorStoreRecordVectorField > fields ) {
183+ List <String > columns = fields .stream ()
184+ .map (field -> field .getEffectiveStorageName () + " " +
185+ OracleVectorStoreFieldHelper .getTypeForVectorField (field )
186+ ).collect (Collectors .toList ());
187+
188+ return String .join (", " , columns );
189+ }
190+
191+ /**
192+ * Returns key column names and type for key column for CREATE TABLE statement
193+ * @param field the key field.
194+ * @return column name and type of the key field for CREATE TABLE statement.
195+ */
196+ public static String getKeyColumnNameAndType (VectorStoreRecordKeyField field ) {
197+ return field .getEffectiveStorageName () + " " + supportedKeyTypes .get (field .getFieldType ());
198+ }
199+
200+
201+ /**
202+ * Generates the index name given the field name. by suffixing "_VECTOR_INDEX" to the field name.
203+ * @param effectiveStorageName the field name.
204+ * @return the index name.
205+ */
206+ private static String getIndexName (String effectiveStorageName ) {
207+ return effectiveStorageName + VECTOR_INDEX_SUFFIX ;
208+ }
209+
210+ /**
211+ * Gets the type of the vector given the field definition. This method is not needed if only
212+ *
213+ * @param field the vector field definition.
214+ * @return returns the type of vector for the given field type.
215+ */
216+ private static String getTypeForVectorField (VectorStoreRecordVectorField field ) {
217+ String dimension = field .getDimensions () > 0 ? String .valueOf (field .getDimensions ()) : "*" ;
218+ return String .format (supportedVectorTypes .get (field .getFieldType ()), dimension );
219+ }
220+
195221 /**
196222 * Gets the function that allows to return the function that converts the JSON value to the
197223 * data type.
@@ -218,90 +244,4 @@ private static String getFunctionForType(String jdbcType) {
218244 }
219245 }
220246
221- /**
222- * Gets the type of the vector given the field definition. This method is not needed if only
223- *
224- * @param field the vector field definition.
225- * @return returns the type of vector for the given field type.
226- */
227- public static String getTypeForVectorField (VectorStoreRecordVectorField field ) {
228- String dimension = field .getDimensions () > 0 ? String .valueOf (field .getDimensions ()) : "*" ;
229- return String .format (supportedVectorTypes .get (field .getFieldType ()), dimension );
230- /* Not needed since all types are FLOAT32
231- if (field.getFieldSubType() != null) {
232- String vectorType;
233- switch (field.getFieldSubType().getName()) {
234- case "java.lang.Double":
235- vectorType = "FLOAT64";
236- break;
237- case "java.lang.Byte":
238- vectorType = "INT8";
239- break;
240- case "java.lang.Boolean":
241- vectorType = "BINARY";
242- break;
243- default:
244- vectorType = "FLOAT32";
245- }
246- return String.format(supportedVectorTypes.get(field.getFieldType()), dimension, vectorType);
247- } else {
248- return String.format(supportedVectorTypes.get(field.getFieldType()), dimension);
249- }
250- */
251- }
252-
253- /**
254- * Gets the JDBC oracle of the vector field definition.
255- * @param field the vector field definition.
256- * @return the JDBC oracle type.
257- */
258- public static int getOracleTypeForField (VectorStoreRecordVectorField field ) {
259- if (field .getFieldSubType () == null ) {
260- return mapOracleTypeToVector .get (field .getFieldType ()).intValue ();
261- } else {
262- switch (field .getFieldSubType ().getName ()) {
263- case "java.lang.Double" :
264- return OracleTypes .VECTOR_FLOAT64 ;
265- case "java.lang.Byte" :
266- return OracleTypes .VECTOR_INT8 ;
267- case "java.lang.Boolean" :
268- return OracleTypes .VECTOR_BINARY ;
269- default :
270- return OracleTypes .VECTOR_FLOAT32 ;
271- }
272- }
273- }
274-
275- /**
276- * Generates the index name given the field name. by suffixing "_VECTOR_INDEX" to the field name.
277- * @param effectiveStorageName the field name.
278- * @return the index name.
279- */
280- private static String getIndexName (String effectiveStorageName ) {
281- return effectiveStorageName + "_VECTOR_INDEX" ;
282- }
283-
284- /**
285- * Returns vector columns names and types for CREATE TABLE statement
286- * @param fields list of vector record fields.
287- * @return comma separated list of columns and types for CREATE TABLE statement.
288- */
289- public static String getVectorColumnNamesAndTypes (List <VectorStoreRecordVectorField > fields ) {
290- List <String > columns = fields .stream ()
291- .map (field -> field .getEffectiveStorageName () + " " +
292- OracleVectorStoreFieldHelper .getTypeForVectorField (field )
293- ).collect (Collectors .toList ());
294-
295- return String .join (", " , columns );
296- }
297-
298- /**
299- * Returns key column names and type for key column for CREATE TABLE statement
300- * @param field the key field.
301- * @return column name and type of the key field for CREATE TABLE statement.
302- */
303- public static String getKeyColumnNameAndType (VectorStoreRecordKeyField field ) {
304- return field .getEffectiveStorageName () + " " + supportedKeyTypes .get (field .getFieldType ());
305- }
306-
307247}
0 commit comments