diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index 1e61e56a9..2bcdc0fef 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -172,8 +172,11 @@ final class TDS { // Vector support static final byte TDS_FEATURE_EXT_VECTORSUPPORT = 0x0E; - static final byte VECTORSUPPORT_NOT_SUPPORTED = 0x00; - static final byte MAX_VECTORSUPPORT_VERSION = 0x01; + static final byte VECTORSUPPORT_NOT_SUPPORTED = 0x00; // vector not supported; will return json formatted string + static final byte VECTORSUPPORT_VERSION_1 = 0x01; // supports float32 vector type + static final byte VECTORSUPPORT_VERSION_2 = 0x02; // supports float32 and float16 vector types + static final byte MAX_VECTORSUPPORT_VERSION = 0x02; + // JSON support static final byte TDS_FEATURE_EXT_JSONSUPPORT = 0x0D; static final byte JSONSUPPORT_NOT_SUPPORTED = 0x00; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java index 541869c53..ea4103792 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerConnection.java @@ -658,7 +658,10 @@ CallableStatement prepareCall(String sql, int nType, int nConcur, int nHold, * * @param vectorTypeSupport * A string that indicates the vector type support during connection initialization. - * Valid values are "off" (vector types are returned as strings) and "v1" (vectors of type FLOAT32 are returned as vectors). + * Valid values are : + * - "off" (vector types are returned as strings) + * - "v1" (supports float32 vector type) + * - "v2" (supports float32 and float16 vector types) * Default is "v1". */ void setVectorTypeSupport(String vectorTypeSupport); @@ -667,7 +670,7 @@ CallableStatement prepareCall(String sql, int nType, int nConcur, int nHold, * Returns the value of the vectorTypeSupport connection property. * * @return vectorTypeSupport - * The current vector type support setting ("off" or "v1"). + * The current vector type support setting ("off"|"v1"|"v2"). */ String getVectorTypeSupport(); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java index e0ed8cadf..197d900d2 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/ISQLServerDataSource.java @@ -1090,7 +1090,10 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * * @param vectorTypeSupport * A string that indicates the vector type support during connection initialization. - * Valid values are "off" (vector types are returned as strings) and "v1" (vectors of type FLOAT32 are returned as vectors). + * Valid values are : + * - "off" (vector types are returned as strings) + * - "v1" (supports float32 vector type) + * - "v2" (supports float32 and float16 vector types) * Default is "v1". */ void setVectorTypeSupport(String vectorTypeSupport); @@ -1099,7 +1102,7 @@ public interface ISQLServerDataSource extends javax.sql.CommonDataSource { * Returns the value of the vectorTypeSupport connection property. * * @return vectorTypeSupport - * The current vector type support setting ("off" or "v1"). + * The current vector type support setting ("off"|"v1"|"v2"). */ String getVectorTypeSupport(); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java index a6cbb5dca..bf1fde91f 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnection.java @@ -760,8 +760,9 @@ private ActiveDirectoryAuthentication() { } } - private static final String VECTOR_SUPPORT_OFF = "off"; - private static final String VECTOR_SUPPORT_V1 = "v1"; + private static final String VECTOR_SUPPORT_OFF = "off"; // vector not supported; will return json formatted string + private static final String VECTOR_SUPPORT_V1 = "v1"; // supports float32 vector type + private static final String VECTOR_SUPPORT_V2 = "v2"; // supports float32 and float16 vector types final static int TNIR_FIRST_ATTEMPT_TIMEOUT_MS = 500; // fraction of timeout to use for fast failover connections @@ -1103,16 +1104,24 @@ public void setBulkCopyForBatchInsertAllowEncryptedValueModifications( /** * A string that indicates the vector type support during connection initialization. - * Valid values are "off" (vector types are returned as strings) and "v1" (vectors of type FLOAT32 are returned as vectors). + * Valid values are : + * - "off" (vector types are returned as strings) + * - "v1" (supports float32 vector type) + * - "v2" (supports float32 and float16 vector types) * Default is "v1". */ - private String vectorTypeSupport = VECTOR_SUPPORT_V1; + private String vectorTypeSupport = SQLServerDriverStringProperty.VECTOR_TYPE_SUPPORT.getDefaultValue(); + + /** + * Negotiated vector version between client and server + */ + private byte negotiatedVectorVersion = TDS.VECTORSUPPORT_NOT_SUPPORTED; /** * Returns the value of the vectorTypeSupport connection property. * * @return vectorTypeSupport - * The current vector type support setting ("off" or "v1"). + * The current vector type support setting ("off"|"v1"|"v2"). */ @Override public String getVectorTypeSupport() { @@ -1124,7 +1133,10 @@ public String getVectorTypeSupport() { * * @param vectorTypeSupport * A string that indicates the vector type support during connection initialization. - * Valid values are "off" (vector types are returned as strings) and "v1" (vectors of type FLOAT32 are returned as vectors). + * Valid values are : + * - "off" (vector types are returned as strings) + * - "v1" (supports float32 vector type) + * - "v2" (supports float32 and float16 vector types) * Default is "v1". */ @Override @@ -1137,6 +1149,7 @@ public void setVectorTypeSupport(String vectorTypeSupport) { switch (vectorTypeSupport.trim().toLowerCase()) { case VECTOR_SUPPORT_OFF: case VECTOR_SUPPORT_V1: + case VECTOR_SUPPORT_V2: this.vectorTypeSupport = vectorTypeSupport.toLowerCase(); break; default: @@ -5904,7 +5917,22 @@ int writeVectorSupportFeatureRequest(boolean write, if (write) { tdsWriter.writeByte(TDS.TDS_FEATURE_EXT_VECTORSUPPORT); tdsWriter.writeInt(1); - tdsWriter.writeByte(TDS.MAX_VECTORSUPPORT_VERSION); + + byte clientVectorSupportVersion; + switch (vectorTypeSupport) { + case VECTOR_SUPPORT_V2: + clientVectorSupportVersion = TDS.VECTORSUPPORT_VERSION_2; + break; + case VECTOR_SUPPORT_V1: + clientVectorSupportVersion = TDS.VECTORSUPPORT_VERSION_1; + break; + case VECTOR_SUPPORT_OFF: + default: + // Should not reach here due to prior validation. + clientVectorSupportVersion = TDS.VECTORSUPPORT_VERSION_1; + break; + } + tdsWriter.writeByte(clientVectorSupportVersion); } return len; } @@ -7116,7 +7144,20 @@ private void onFeatureExtAck(byte featureId, byte[] data) throws SQLServerExcept if (0 == serverSupportedVectorVersion || serverSupportedVectorVersion > TDS.MAX_VECTORSUPPORT_VERSION) { throw new SQLServerException(SQLServerException.getErrString("R_InvalidVectorVersionNumber"), null); } - serverSupportsVector = true; + // Negotiate the vector version between client and server + negotiatedVectorVersion = negotiateVectorVersion(vectorTypeSupport, serverSupportedVectorVersion); + + if (negotiatedVectorVersion > TDS.VECTORSUPPORT_NOT_SUPPORTED) { + serverSupportsVector = true; + + if (connectionlogger.isLoggable(Level.FINE)) { + connectionlogger.fine(toString() + " Vector support negotiated. Client: " + vectorTypeSupport + + ", Server: " + serverSupportedVectorVersion + + ", Negotiated: " + negotiatedVectorVersion); + } + } else { + serverSupportsVector = false; + } break; } @@ -7152,6 +7193,57 @@ private void onFeatureExtAck(byte featureId, byte[] data) throws SQLServerExcept } } + /** + * Negotiates the vector version between client and server based on the + * following rules: + * - If either client or server is "off", negotiated version is "off" + * - If both support v2, negotiated version is v2 + * - If both support v1, negotiated version is v1 + * - Otherwise, use the minimum supported version + * + * @param clientVectorSupport The client's vector type support setting + * @param serverVersion The server's supported vector version + * @return The negotiated vector version + */ + private byte negotiateVectorVersion(String clientVectorSupport, byte serverVersion) { + + // If server doesn't support vectors, negotiation is off + if (serverVersion == TDS.VECTORSUPPORT_NOT_SUPPORTED) { + return TDS.VECTORSUPPORT_NOT_SUPPORTED; + } + + byte clientMaxVersion; + + switch (clientVectorSupport.toLowerCase()) { + case VECTOR_SUPPORT_OFF: + return TDS.VECTORSUPPORT_NOT_SUPPORTED; + + case VECTOR_SUPPORT_V2: + clientMaxVersion = TDS.VECTORSUPPORT_VERSION_2; + break; + + case VECTOR_SUPPORT_V1: + clientMaxVersion = TDS.VECTORSUPPORT_VERSION_1; + break; + + default: + // Invalid client setting + return TDS.VECTORSUPPORT_NOT_SUPPORTED; + } + + // Negotiate using the minimum supported version + return (byte) Math.min(clientMaxVersion, serverVersion); + } + + /** + * Returns the negotiated vector version between client and server. + * + * @return The negotiated vector version (0 = off, 1 = v1, 2 = v2) + */ + public byte getNegotiatedVectorVersion() { + return negotiatedVectorVersion; + } + /* * Executes a DTC command */ @@ -7450,6 +7542,7 @@ final boolean complete(LogonCommand logonCommand, TDSReader tdsReader) throws SQ // request vector support len += writeVectorSupportFeatureRequest(false, tdsWriter); + // request JSON support len += writeJSONSupportFeatureRequest(false, tdsWriter); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java index bcb8a4529..6249bb1a8 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerConnectionPoolProxy.java @@ -893,19 +893,25 @@ public void setBulkCopyForBatchInsertAllowEncryptedValueModifications(boolean bu } /** - * Returns the vectorTypeSupport value. + * Returns the value of the vectorTypeSupport connection property. * - * @return the vectorTypeSupport value. + * @return vectorTypeSupport + * The current vector type support setting ("off"|"v1"|"v2"). */ public String getVectorTypeSupport() { return wrappedConnection.getVectorTypeSupport(); } /** - * Sets the vectorTypeSupport value. + * Sets the value of the vectorTypeSupport connection property. * * @param vectorTypeSupport - * the vectorTypeSupport value to set ("off" or "v1"). + * A string that indicates the vector type support during connection initialization. + * Valid values are : + * - "off" (vector types are returned as strings) + * - "v1" (supports float32 vector type) + * - "v2" (supports float32 and float16 vector types) + * Default is "v1". */ public void setVectorTypeSupport(String vectorTypeSupport) { wrappedConnection.setVectorTypeSupport(vectorTypeSupport); diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java index ca8e9cecb..47a692a32 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerDriver.java @@ -501,6 +501,48 @@ static DatetimeType valueOfString(String value) throws SQLServerException { } } +enum VectorTypeSupport { + OFF("off"), + V1("v1"), //float32 support + V2("v2"); //float32 and float16 support + + private final String type; + + VectorTypeSupport(String type) { + this.type = type; + } + + @Override + public String toString() { + return type; + } + + static VectorTypeSupport valueOfString(String value) throws SQLServerException { + if (value == null) { + throwInvalid(value); + } + + switch (value.toLowerCase()) { + case "off": + return VectorTypeSupport.OFF; + case "v1": + return VectorTypeSupport.V1; + case "v2": + return VectorTypeSupport.V2; + default: + throwInvalid(value); + return VectorTypeSupport.OFF; + } + } + + private static void throwInvalid(String value) throws SQLServerException { + MessageFormat form = + new MessageFormat(SQLServerException.getErrString("R_invalidVectorTypeSupport")); + Object[] msgArgs = {"vectorTypeSupport", value}; + throw new SQLServerException(null, form.format(msgArgs), null, 0, false); + } +} + enum SQLServerDriverObjectProperty { GSS_CREDENTIAL("gsscredential", null), @@ -615,7 +657,7 @@ enum SQLServerDriverStringProperty { RETRY_CONN("retryConn", ""), QUOTED_IDENTIFIER("quotedIdentifier", OnOffOption.ON.toString()), CONCAT_NULL_YIELDS_NULL("concatNullYieldsNull", OnOffOption.ON.toString()), - VECTOR_TYPE_SUPPORT("vectorTypeSupport", "v1"); + VECTOR_TYPE_SUPPORT("vectorTypeSupport", VectorTypeSupport.V1.toString()); private final String name; private final String defaultValue; @@ -1014,7 +1056,8 @@ public final class SQLServerDriver implements java.sql.Driver { new SQLServerDriverPropertyInfo(SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.toString(), Boolean.toString(SQLServerDriverBooleanProperty.ENABLE_BULK_COPY_CACHE.getDefaultValue()),false, TRUE_FALSE), new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.VECTOR_TYPE_SUPPORT.toString(), - SQLServerDriverStringProperty.VECTOR_TYPE_SUPPORT.getDefaultValue(), false, new String[] {"off", "v1"}), + SQLServerDriverStringProperty.VECTOR_TYPE_SUPPORT.getDefaultValue(), false, + new String[] {VectorTypeSupport.OFF.toString(), VectorTypeSupport.V1.toString(), VectorTypeSupport.V2.toString()}), new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.MSI_CLIENT_ID.toString(), SQLServerDriverStringProperty.MSI_CLIENT_ID.getDefaultValue(), false, null), new SQLServerDriverPropertyInfo(SQLServerDriverStringProperty.KEY_VAULT_PROVIDER_CLIENT_ID.toString(), diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java index 79bea5073..69aa3f1f5 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerResource.java @@ -341,8 +341,8 @@ protected Object[][] getContents() { {"R_unsupportedStmtColEncSetting", "SQLServerStatementColumnEncryptionSetting cannot be null."}, {"R_unsupportedConversionAE", "The conversion from {0} to {1} is unsupported for encrypted column."}, {"R_InvalidDataForAE", "The given value of type {0} from the data source cannot be converted to type {1} of the specified target column {2}."}, - {"R_vectorTypeSupportPropertyDescription", "Determines the vector support feature negotiation during connection initialization. Valid values are \"off\" or \"v1\". Default is \"v1\"."}, - {"R_invalidVectorTypeSupport", "Invalid value for vectorTypeSupport: {0}. Valid values are \"off\" or \"v1\"."}, + {"R_vectorTypeSupportPropertyDescription", "Determines the vector support feature negotiation during connection initialization. Valid values are \"off\" ,\"v1\" or \"v2\". Default is \"v1\"."}, + {"R_invalidVectorTypeSupport", "Invalid value for vectorTypeSupport: {0}. Valid values are \"off\" ,\"v1\" or \"v2\"."}, {"R_VectorDimensionCountMismatch", "Mismatch between vector dimension count and provided data."}, {"R_InvalidVectorDimensionCount", "Invalid vector dimension count."}, {"R_VectorDimensionTypeCannotBeNull", "Vector dimension type cannot be null."},