2929import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordDataField ;
3030import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordKeyField ;
3131import com .microsoft .semantickernel .data .vectorstorage .definition .VectorStoreRecordVectorField ;
32+ import com .microsoft .semantickernel .exceptions .SKException ;
3233import java .math .BigDecimal ;
3334import java .time .OffsetDateTime ;
3435import java .util .Collection ;
36+ import java .util .Collections ;
3537import java .util .HashMap ;
3638import java .util .List ;
3739import java .util .Map ;
4547 */
4648class OracleVectorStoreFieldHelper {
4749
50+ /**
51+ * Object naming regular expression
52+ */
53+ private static final String OBJECT_NAMING_REGEXP = "[a-zA-Z_][a-zA-Z0-9_]{1,128}" ;
4854 /**
4955 * The logger
5056 */
@@ -109,32 +115,34 @@ class OracleVectorStoreFieldHelper {
109115 *
110116 * @return the mapping between the supported Java key types and the Oracle database type.
111117 */
112- public static HashMap <Class <?>, String > getSupportedKeyTypes () {
113- return supportedKeyTypes ;
118+ static Map <Class <?>, String > getSupportedKeyTypes () {
119+
120+ return Collections .unmodifiableMap (supportedKeyTypes );
114121 }
115122
116123 /**
117124 * Gets the mapping between the supported Java data types and the Oracle database type.
118125 *
119126 * @return the mapping between the supported Java data types and the Oracle database type.
120127 */
121- public static Map <Class <?>, String > getSupportedDataTypes (
128+ static Map <Class <?>, String > getSupportedDataTypes (
122129 StringTypeMapping stringTypeMapping , int defaultVarCharLength ) {
123130 String stringType = stringTypeMapping .equals (StringTypeMapping .USE_VARCHAR )
124131 ? String .format (OracleDataTypesMapping .STRING_VARCHAR , defaultVarCharLength )
125132 : OracleDataTypesMapping .STRING_CLOB ;
126133 supportedDataTypes .put (String .class , stringType );
127134 LOGGER .finest ("Mapping String columns to " + stringType );
128- return supportedDataTypes ;
135+ return Collections . unmodifiableMap ( supportedDataTypes ) ;
129136 }
130137
131138 /**
132139 * Gets the mapping between the supported Java data types and the Oracle database type.
133140 *
134141 * @return the mapping between the supported Java data types and the Oracle database type.
135142 */
136- public static Map <Class <?>, String > getSupportedVectorTypes () {
137- return supportedVectorTypes ;
143+ static Map <Class <?>, String > getSupportedVectorTypes () {
144+
145+ return Collections .unmodifiableMap (supportedVectorTypes );
138146 }
139147
140148 /**
@@ -143,20 +151,23 @@ public static Map<Class<?>, String> getSupportedVectorTypes() {
143151 * @return the CREATE VECTOR INDEX statement to create the index according to the vector
144152 * field definition.
145153 */
146- public static String getCreateVectorIndexStatement (VectorStoreRecordVectorField field , String collectionTableName ) {
154+ static String getCreateVectorIndexStatement (VectorStoreRecordVectorField field , String collectionTableName ) {
147155 switch (field .getIndexKind ()) {
148156 case IVFFLAT :
149157 return "CREATE VECTOR INDEX IF NOT EXISTS "
150- + getIndexName (field .getEffectiveStorageName ())
158+ + validateObjectNaming ( getIndexName (field .getEffectiveStorageName () ))
151159 + " ON "
152- + collectionTableName + "( " + field .getEffectiveStorageName () + " ) "
160+ + validateObjectNaming (collectionTableName )
161+ + "( " + validateObjectNaming (field .getEffectiveStorageName ()) + " ) "
153162 + " ORGANIZATION NEIGHBOR PARTITIONS "
154163 + " WITH DISTANCE COSINE "
155164 + "PARAMETERS ( TYPE IVF )" ;
156165 case HNSW :
157- return "CREATE VECTOR INDEX IF NOT EXISTS " + getIndexName (field .getEffectiveStorageName ())
166+ return "CREATE VECTOR INDEX IF NOT EXISTS "
167+ + validateObjectNaming (getIndexName (field .getEffectiveStorageName ()))
158168 + " ON "
159- + collectionTableName + "( " + field .getEffectiveStorageName () + " ) "
169+ + validateObjectNaming (collectionTableName )
170+ + "( " + validateObjectNaming (field .getEffectiveStorageName ()) + " ) "
160171 + "ORGANIZATION INMEMORY GRAPH "
161172 + "WITH DISTANCE COSINE "
162173 + "PARAMETERS (TYPE HNSW)" ;
@@ -173,20 +184,20 @@ public static String getCreateVectorIndexStatement(VectorStoreRecordVectorField
173184 *
174185 * @return the CREATE INDEX statement to create the index according to the field definition.
175186 */
176- public static String createIndexForDataField (String collectionTableName , VectorStoreRecordDataField dataField , Map <Class <?>, String > supportedDataTypes ) {
187+ static String createIndexForDataField (String collectionTableName , VectorStoreRecordDataField dataField , Map <Class <?>, String > supportedDataTypes ) {
177188 if (supportedDataTypes .get (dataField .getFieldType ()) == "JSON" ) {
178189 String dataFieldIndex = "CREATE MULTIVALUE INDEX IF NOT EXISTS %s ON %s t (t.%s.%s)" ;
179190 return String .format (dataFieldIndex ,
180- collectionTableName + "_" + dataField .getEffectiveStorageName (),
181- collectionTableName ,
182- dataField .getEffectiveStorageName (),
191+ validateObjectNaming ( collectionTableName + "_" + dataField .getEffectiveStorageName () ),
192+ validateObjectNaming ( collectionTableName ) ,
193+ validateObjectNaming ( dataField .getEffectiveStorageName () ),
183194 getFunctionForType (supportedDataTypes .get (dataField .getFieldSubType ())));
184195 } else {
185196 String dataFieldIndex = "CREATE INDEX IF NOT EXISTS %s ON %s (%s ASC)" ;
186197 return String .format (dataFieldIndex ,
187- collectionTableName + "_" + dataField .getEffectiveStorageName (),
188- collectionTableName ,
189- dataField .getEffectiveStorageName ()
198+ validateObjectNaming ( collectionTableName + "_" + dataField .getEffectiveStorageName () ),
199+ validateObjectNaming ( collectionTableName ) ,
200+ validateObjectNaming ( dataField .getEffectiveStorageName () )
190201 );
191202 }
192203 }
@@ -196,9 +207,9 @@ public static String createIndexForDataField(String collectionTableName, VectorS
196207 * @param fields list of vector record fields.
197208 * @return comma separated list of columns and types for CREATE TABLE statement.
198209 */
199- public static String getVectorColumnNamesAndTypes (List <VectorStoreRecordVectorField > fields ) {
210+ static String getVectorColumnNamesAndTypes (List <VectorStoreRecordVectorField > fields ) {
200211 List <String > columns = fields .stream ()
201- .map (field -> field .getEffectiveStorageName () + " " +
212+ .map (field -> validateObjectNaming ( field .getEffectiveStorageName () ) + " " +
202213 OracleVectorStoreFieldHelper .getTypeForVectorField (field )
203214 ).collect (Collectors .toList ());
204215
@@ -210,8 +221,8 @@ public static String getVectorColumnNamesAndTypes(List<VectorStoreRecordVectorFi
210221 * @param field the key field.
211222 * @return column name and type of the key field for CREATE TABLE statement.
212223 */
213- public static String getKeyColumnNameAndType (VectorStoreRecordKeyField field ) {
214- return field .getEffectiveStorageName () + " " + supportedKeyTypes .get (field .getFieldType ());
224+ static String getKeyColumnNameAndType (VectorStoreRecordKeyField field ) {
225+ return validateObjectNaming ( field .getEffectiveStorageName () ) + " " + supportedKeyTypes .get (field .getFieldType ());
215226 }
216227
217228
@@ -220,7 +231,7 @@ public static String getKeyColumnNameAndType(VectorStoreRecordKeyField field) {
220231 * @param effectiveStorageName the field name.
221232 * @return the index name.
222233 */
223- private static String getIndexName (String effectiveStorageName ) {
234+ static String getIndexName (String effectiveStorageName ) {
224235 return effectiveStorageName + VECTOR_INDEX_SUFFIX ;
225236 }
226237
@@ -261,4 +272,19 @@ private static String getFunctionForType(String jdbcType) {
261272 }
262273 }
263274
275+
276+ /**
277+ * Validates an SQL identifier.
278+ *
279+ * @param identifier the identifier
280+ * @return the identifier if it is valid
281+ * @throws SKException if the identifier is invalid
282+ */
283+ static String validateObjectNaming (String identifier ) {
284+ if (identifier .matches (OBJECT_NAMING_REGEXP )) {
285+ return identifier ;
286+ }
287+ throw new SKException ("Invalid SQL identifier: " + identifier );
288+ }
289+
264290}
0 commit comments