diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java b/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java index c2fea6822..0688792a3 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/DataTypes.java @@ -150,7 +150,7 @@ enum SSType { TIMESTAMP(Category.TIMESTAMP, "timestamp", JDBCType.BINARY), GEOMETRY(Category.UDT, "geometry", JDBCType.GEOMETRY), GEOGRAPHY(Category.UDT, "geography", JDBCType.GEOGRAPHY), - JSON(Category.JSON, "json", JDBCType.LONGNVARCHAR); + JSON(Category.JSON, "json", JDBCType.JSON); final Category category; private final String name; @@ -458,10 +458,11 @@ JDBCType getJDBCType(SSType ssType, JDBCType jdbcTypeFromApp) { case NVARCHAR: case NVARCHARMAX: case NTEXT: - case JSON: jdbcType = JDBCType.LONGVARCHAR; break; - + case JSON: + jdbcType = JDBCType.JSON; + break; case XML: default: jdbcType = JDBCType.LONGVARBINARY; diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java index c2c7720a9..aa774e31f 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/IOBuffer.java @@ -4864,6 +4864,12 @@ void writeRPCStringUnicode(String sValue) throws SQLServerException { writeRPCStringUnicode(null, sValue, false, null); } + void writeRPCJson(String sName, String sValue, boolean bOut, + SQLCollation collation) throws SQLServerException { + writeRPCNameValType(sName, bOut, TDSType.JSON); + writeLong(0xFFFFFFFFFFFFFFFFL); + } + /** * Writes a string value as Unicode for RPC * diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCSVFileRecord.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCSVFileRecord.java index 2db4339fa..bb334f79d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCSVFileRecord.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCSVFileRecord.java @@ -545,6 +545,10 @@ else if ((null != columnNames) && (columnNames.length >= positionInSource)) columnMetadata.put(positionInSource, new ColumnMetadata(colName, java.sql.Types.LONGNVARCHAR, precision, scale, dateTimeFormatter)); break; + case microsoft.sql.Types.JSON: + columnMetadata.put(positionInSource, + new ColumnMetadata(colName, microsoft.sql.Types.JSON, precision, scale, dateTimeFormatter)); + break; /* * Redirecting Float as Double based on data type mapping * https://msdn.microsoft.com/library/ms378878%28v=sql.110%29.aspx diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java index 35f239608..93f7e738d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCopy.java @@ -1025,7 +1025,14 @@ private void writeTypeInfo(TDSWriter tdsWriter, int srcJdbcType, int srcScale, i } collation.writeCollation(tdsWriter); break; - + case microsoft.sql.Types.JSON: // 0x62 + tdsWriter.writeByte(TDSType.JSON.byteValue()); + if (isStreaming) { + tdsWriter.writeShort((short) 0xFFFF); + } else { + tdsWriter.writeShort(isBaseType ? (short) (srcPrecision) : (short) (2 * srcPrecision)); + } + break; case java.sql.Types.BINARY: // 0xAD tdsWriter.writeByte(TDSType.BIGBINARY.byteValue()); tdsWriter.writeShort((short) (srcPrecision)); @@ -1127,7 +1134,7 @@ private void writeTypeInfo(TDSWriter tdsWriter, int srcJdbcType, int srcScale, i case microsoft.sql.Types.SQL_VARIANT: // 0x62 tdsWriter.writeByte(TDSType.SQL_VARIANT.byteValue()); tdsWriter.writeInt(TDS.SQL_VARIANT_LENGTH); - break; + break; default: MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported")); String unsupportedDataType = JDBCType.of(srcJdbcType).toString().toLowerCase(Locale.ENGLISH); @@ -1470,6 +1477,8 @@ private String getDestTypeFromSrcType(int srcColIndx, int destColIndx, } case microsoft.sql.Types.SQL_VARIANT: return SSType.SQL_VARIANT.toString(); + case microsoft.sql.Types.JSON: + return SSType.JSON.toString(); default: { MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_BulkTypeNotSupported")); Object[] msgArgs = {JDBCType.of(bulkJdbcType).toString().toLowerCase(Locale.ENGLISH)}; @@ -2090,6 +2099,7 @@ private void writeNullToTdsWriter(TDSWriter tdsWriter, int srcJdbcType, case java.sql.Types.LONGVARCHAR: case java.sql.Types.LONGNVARCHAR: case java.sql.Types.LONGVARBINARY: + case microsoft.sql.Types.JSON: if (isStreaming) { tdsWriter.writeLong(PLPInputStream.PLP_NULL); } else { @@ -2161,6 +2171,7 @@ else if (null != sourceCryptoMeta) { case java.sql.Types.TIME: case java.sql.Types.TIMESTAMP: case microsoft.sql.Types.DATETIMEOFFSET: + case microsoft.sql.Types.JSON: bulkJdbcType = java.sql.Types.VARCHAR; break; default: @@ -2419,6 +2430,7 @@ else if (null != sourceCryptoMeta) { case java.sql.Types.LONGNVARCHAR: case java.sql.Types.NCHAR: case java.sql.Types.NVARCHAR: + case microsoft.sql.Types.JSON: if (isStreaming) { // PLP_BODY rule in TDS // Use ResultSet.getString for non-streaming data and ResultSet.getNCharacterStream() for @@ -2986,6 +2998,7 @@ private Object readColumnFromResultSet(int srcColOrdinal, int srcJdbcType, boole case java.sql.Types.LONGNVARCHAR: case java.sql.Types.NCHAR: case java.sql.Types.NVARCHAR: + case microsoft.sql.Types.JSON: // PLP if stream type and both the source and destination are not encrypted // This is because AE does not support streaming types. // Therefore an encrypted source or destination means the data must not actually be streaming data @@ -3060,7 +3073,8 @@ private void writeColumn(TDSWriter tdsWriter, int srcColOrdinal, int destColOrdi destPrecision = destColumnMetadata.get(destColOrdinal).precision; if ((java.sql.Types.NCHAR == srcJdbcType) || (java.sql.Types.NVARCHAR == srcJdbcType) - || (java.sql.Types.LONGNVARCHAR == srcJdbcType)) { + || (java.sql.Types.LONGNVARCHAR == srcJdbcType) + || (microsoft.sql.Types.JSON == srcJdbcType)) { isStreaming = (DataTypes.SHORT_VARTYPE_MAX_CHARS < srcPrecision) || (DataTypes.SHORT_VARTYPE_MAX_CHARS < destPrecision); } else { @@ -3771,6 +3785,7 @@ void setDestinationTableMetadata(SQLServerResultSet rs) { private boolean unicodeConversionRequired(int jdbcType, SSType ssType) { return ((java.sql.Types.CHAR == jdbcType || java.sql.Types.VARCHAR == jdbcType || java.sql.Types.LONGNVARCHAR == jdbcType) - && (SSType.NCHAR == ssType || SSType.NVARCHAR == ssType || SSType.NVARCHARMAX == ssType)); + && (SSType.NCHAR == ssType || SSType.NVARCHAR == ssType || SSType.NVARCHARMAX == ssType + || SSType.JSON == ssType)); } } diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/dtv.java b/src/main/java/com/microsoft/sqlserver/jdbc/dtv.java index bc0f6fb62..0616220ac 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/dtv.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/dtv.java @@ -295,7 +295,10 @@ final class SendByRPCOp extends DTVExecuteOp { void execute(DTV dtv, String strValue) throws SQLServerException { if (dtv.getJdbcType() == JDBCType.GUID) { tdsWriter.writeRPCUUID(name, UUID.fromString(strValue), isOutParam); - } else { + } else if (dtv.getJdbcType() == JDBCType.JSON) { + tdsWriter.writeRPCJson(name, strValue, isOutParam, collation); + } + else { tdsWriter.writeRPCStringUnicode(name, strValue, isOutParam, collation); } }