From 9e5b82f5b10dc0641f88057d2958b9d45307e9f5 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Mon, 14 Jan 2019 13:59:13 -0800 Subject: [PATCH 1/2] Handle null values in TVP --- .../com/microsoft/sqlserver/jdbc/TVP.java | 68 ++++++++++--------- 1 file changed, 36 insertions(+), 32 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java index abe9fe097e..18c75825cc 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java @@ -89,7 +89,7 @@ void initTVP(TVPType type, String tvpPartName) throws SQLServerException { TVP(String tvpPartName, ResultSet tvpResultSet) throws SQLServerException { initTVP(TVPType.ResultSet, tvpPartName); sourceResultSet = tvpResultSet; - // Populate TVP metdata from ResultSetMetadta. + // Populate TVP metadata from ResultSetMetadta. populateMetadataFromResultSet(); } @@ -97,10 +97,10 @@ void initTVP(TVPType type, String tvpPartName) throws SQLServerException { initTVP(TVPType.ISQLServerDataRecord, tvpPartName); sourceRecord = tvpRecord; columnNames = new HashSet<>(); - // Populate TVP metdata from ISQLServerDataRecord. + // Populate TVP metadata from ISQLServerDataRecord. populateMetadataFromDataRecord(); - // validate sortOrdinal and throw all relavent exceptions before proceeding + // validate sortOrdinal and throw all relevant exceptions before proceeding validateOrderProperty(); } @@ -143,49 +143,53 @@ boolean next() throws SQLServerException { } } else if (TVPType.SQLServerDataTable == tvpType) { return sourceDataTableRowIterator.hasNext(); - } else + } else if (null != sourceRecord) { return sourceRecord.next(); + } + return false; } void populateMetadataFromDataTable() throws SQLServerException { - assert null != sourceDataTable; - - Map dataTableMetaData = sourceDataTable.getColumnMetadata(); - if (null == dataTableMetaData || dataTableMetaData.isEmpty()) { - throw new SQLServerException(SQLServerException.getErrString("R_TVPEmptyMetadata"), null); - } - for (Entry pair : dataTableMetaData.entrySet()) { - // duplicate column names for the dataTable will be checked in the SQLServerDataTable. - columnMetadata.put(pair.getKey(), new SQLServerMetaData(pair.getValue().columnName, - pair.getValue().javaSqlType, pair.getValue().precision, pair.getValue().scale)); + if (null != sourceDataTable) { + Map dataTableMetaData = sourceDataTable.getColumnMetadata(); + if (null == dataTableMetaData || dataTableMetaData.isEmpty()) { + throw new SQLServerException(SQLServerException.getErrString("R_TVPEmptyMetadata"), null); + } + for (Entry pair : dataTableMetaData.entrySet()) { + // duplicate column names for the dataTable will be checked in the SQLServerDataTable. + columnMetadata.put(pair.getKey(), new SQLServerMetaData(pair.getValue().columnName, + pair.getValue().javaSqlType, pair.getValue().precision, pair.getValue().scale)); + } } } void populateMetadataFromResultSet() throws SQLServerException { - assert null != sourceResultSet; - try { - ResultSetMetaData rsmd = sourceResultSet.getMetaData(); - for (int i = 0; i < rsmd.getColumnCount(); i++) { - SQLServerMetaData columnMetaData = new SQLServerMetaData(rsmd.getColumnName(i + 1), - rsmd.getColumnType(i + 1), rsmd.getPrecision(i + 1), rsmd.getScale(i + 1)); - columnMetadata.put(i, columnMetaData); + if (null != sourceResultSet) { + try { + ResultSetMetaData rsmd = sourceResultSet.getMetaData(); + for (int i = 0; i < rsmd.getColumnCount(); i++) { + SQLServerMetaData columnMetaData = new SQLServerMetaData(rsmd.getColumnName(i + 1), + rsmd.getColumnType(i + 1), rsmd.getPrecision(i + 1), rsmd.getScale(i + 1)); + columnMetadata.put(i, columnMetaData); + } + } catch (SQLException e) { + throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveColMeta"), e); } - } catch (SQLException e) { - throw new SQLServerException(SQLServerException.getErrString("R_unableRetrieveColMeta"), e); } } void populateMetadataFromDataRecord() throws SQLServerException { - assert null != sourceRecord; - if (0 >= sourceRecord.getColumnCount()) { - throw new SQLServerException(SQLServerException.getErrString("R_TVPEmptyMetadata"), null); - } - for (int i = 0; i < sourceRecord.getColumnCount(); i++) { - Util.checkDuplicateColumnName(sourceRecord.getColumnMetaData(i + 1).columnName, columnNames); + if (null != sourceRecord) { + if (0 >= sourceRecord.getColumnCount()) { + throw new SQLServerException(SQLServerException.getErrString("R_TVPEmptyMetadata"), null); + } + for (int i = 0; i < sourceRecord.getColumnCount(); i++) { + Util.checkDuplicateColumnName(sourceRecord.getColumnMetaData(i + 1).columnName, columnNames); - // Make a copy here as we do not want to change user's metadata. - SQLServerMetaData metaData = new SQLServerMetaData(sourceRecord.getColumnMetaData(i + 1)); - columnMetadata.put(i, metaData); + // Make a copy here as we do not want to change user's metadata. + SQLServerMetaData metaData = new SQLServerMetaData(sourceRecord.getColumnMetaData(i + 1)); + columnMetadata.put(i, metaData); + } } } From 2198415c4818bce50844d3bd9a41b76b55346886 Mon Sep 17 00:00:00 2001 From: Cheena Malhotra Date: Mon, 14 Jan 2019 15:06:41 -0800 Subject: [PATCH 2/2] More improvements --- .../com/microsoft/sqlserver/jdbc/TVP.java | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java index 18c75825cc..ee6841378d 100644 --- a/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java +++ b/src/main/java/com/microsoft/sqlserver/jdbc/TVP.java @@ -89,7 +89,7 @@ void initTVP(TVPType type, String tvpPartName) throws SQLServerException { TVP(String tvpPartName, ResultSet tvpResultSet) throws SQLServerException { initTVP(TVPType.ResultSet, tvpPartName); sourceResultSet = tvpResultSet; - // Populate TVP metadata from ResultSetMetadta. + // Populate TVP metadata from ResultSetMetadata. populateMetadataFromResultSet(); } @@ -97,6 +97,7 @@ void initTVP(TVPType type, String tvpPartName) throws SQLServerException { initTVP(TVPType.ISQLServerDataRecord, tvpPartName); sourceRecord = tvpRecord; columnNames = new HashSet<>(); + // Populate TVP metadata from ISQLServerDataRecord. populateMetadataFromDataRecord(); @@ -114,9 +115,10 @@ Object[] getRowData() throws SQLServerException { Object[] rowData = new Object[colCount]; for (int i = 0; i < colCount; i++) { try { - // for Time types, getting Timestamp instead of Time, because this value will be converted to String - // later on. If the value is a - // time object, the millisecond would be removed. + /* + * for Time types, getting TimeStamp instead of Time, because this value will be converted to String + * later on. If the value is a time object, the millisecond would be removed. + */ if (java.sql.Types.TIME == sourceResultSet.getMetaData().getColumnType(i + 1)) { rowData[i] = sourceResultSet.getTimestamp(i + 1); } else { @@ -155,11 +157,9 @@ void populateMetadataFromDataTable() throws SQLServerException { if (null == dataTableMetaData || dataTableMetaData.isEmpty()) { throw new SQLServerException(SQLServerException.getErrString("R_TVPEmptyMetadata"), null); } - for (Entry pair : dataTableMetaData.entrySet()) { - // duplicate column names for the dataTable will be checked in the SQLServerDataTable. - columnMetadata.put(pair.getKey(), new SQLServerMetaData(pair.getValue().columnName, - pair.getValue().javaSqlType, pair.getValue().precision, pair.getValue().scale)); - } + dataTableMetaData.entrySet() + .forEach(E -> columnMetadata.put(E.getKey(), new SQLServerMetaData(E.getValue().columnName, + E.getValue().javaSqlType, E.getValue().precision, E.getValue().scale))); } } @@ -258,7 +258,7 @@ void parseTypeName(String name) throws SQLServerException { StringBuilder sb = new StringBuilder(name.length()); - // String buffer to hold white space used when parsing nonquoted strings 'a b . c d' = 'a b' and 'c d' + // String buffer to hold white space used when parsing non-quoted strings 'a b . c d' = 'a b' and 'c d' StringBuilder whitespaceSB = null; // Right quote character to use given the left quote character found. @@ -273,14 +273,13 @@ void parseTypeName(String name) throws SQLServerException { if (Character.isWhitespace(testchar)) // skip the whitespace continue; else if (testchar == separator) { - // If separator was found,but no string was found, initialize the string we are parsing to + // If separator was found, but no string was found, initialize the string we are parsing to // Empty. parsedNames[stringCount] = ""; stringCount++; } else if (-1 != (quoteIndex = leftQuote.indexOf(testchar))) { - // If we are at left quote - rightQuoteChar = rightQuote.charAt(quoteIndex); // record the corresponding right quote for the - // left quote + // If we are at left quote, record the corresponding right quote for the left quote + rightQuoteChar = rightQuote.charAt(quoteIndex); sb.setLength(0); state = MPIState.MPI_ParseQuote; } else if (-1 != rightQuote.indexOf(testchar)) { @@ -331,8 +330,8 @@ else if ((-1 != rightQuote.indexOf(testchar)) || (-1 != leftQuote.indexOf(testch // If its not a separator and not whitespace sb.append(whitespaceSB); sb.append(testchar); - parsedNames[stringCount] = sb.toString(); // Need to set the name here in case the string - // ends here. + // Need to set the name here in case the string ends here. + parsedNames[stringCount] = sb.toString(); state = MPIState.MPI_ParseNonQuote; } } else { @@ -344,7 +343,7 @@ else if ((-1 != rightQuote.indexOf(testchar)) || (-1 != leftQuote.indexOf(testch break; case MPI_ParseQuote: - // if are on a right quote see if we are escapeing the right quote or ending the quoted string + // if are on a right quote see if we are escaping the right quote or ending the quoted string if (testchar == rightQuoteChar) state = MPIState.MPI_RightQuote; else @@ -353,7 +352,7 @@ else if ((-1 != rightQuote.indexOf(testchar)) || (-1 != leftQuote.indexOf(testch case MPI_RightQuote: if (testchar == rightQuoteChar) { - // If the next char is a another right quote then we were escapeing the right quote + // If the next char is a another right quote then we were escaping the right quote sb.append(testchar); state = MPIState.MPI_ParseQuote; } else if (testchar == separator) { @@ -419,7 +418,7 @@ else if ((-1 != rightQuote.indexOf(testchar)) || (-1 != leftQuote.indexOf(testch MessageFormat form = new MessageFormat(SQLServerException.getErrString("R_invalidThreePartName")); throw new SQLServerException(null, form.format(new Object[] {}), null, 0, false); } else { - // Shuffle the parsed name, from left justification to right justification, ie [a][b][null][null] goes to + // Shuffle the parsed name, from left justification to right justification, i.e. [a][b][null][null] goes to // [null][null][a][b] int offset = limit - stringCount - 1; if (offset > 0) { @@ -435,9 +434,9 @@ else if ((-1 != rightQuote.indexOf(testchar)) || (-1 != leftQuote.indexOf(testch } /* - * parsing the multipart identifer string. parameters: name - string to parse leftquote: set of characters which are - * valid quoteing characters to initiate a quote rightquote: set of characters which are valid to stop a quote, - * array index's correspond to the the leftquote array. separator: separator to use limit: number of names to parse + * Parsing the multi-part identifier string. parameters: name - string to parse left-quote: set of characters which + * are valid quoting characters to initiate a quote right-quote: set of characters which are valid to stop a quote, + * array index's correspond to the the left-quote array. separator: separator to use limit: number of names to parse * out removequote:to remove the quotes on the returned string */ private int incrementStringCount(String[] ary, int position) throws SQLServerException {