Skip to content

Commit 03cfcfd

Browse files
authored
Fixed issue with SQLServerBulkCopy from CSV with setEscapeColumnDelimerts set to true (#2575)
* Fixed issue with SQLServerBulkCopy from CSV for setEscapeColumnDelimitersCSV * Fixed scenario with last line having blank content * Simplied if condition * Changed sb.isEmpty to sb.toString().isEmpty() * Use length instead of toString * Added dropTable in finally block.
1 parent 08cd6fd commit 03cfcfd

File tree

3 files changed

+75
-1
lines changed

3 files changed

+75
-1
lines changed

src/main/java/com/microsoft/sqlserver/jdbc/SQLServerBulkCSVFileRecord.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ private String readLineEscapeDelimiters() throws SQLServerException {
246246
if (c == -1 && quoteCount % 2 != 0) { // stream ended, but we are within quotes -- data problem
247247
throw new SQLServerException(SQLServerException.getErrString("R_InvalidCSVQuotes"), null, 0, null);
248248
}
249-
if (c == -1) { // keep semantics of readLine() by returning a null when there is no more data
249+
if ((c == -1) && (sb.length() == 0)) { // keep semantics of readLine() by returning a null when there is no more data
250250
return null;
251251
}
252252
} catch (IOException e) {

src/test/java/com/microsoft/sqlserver/jdbc/bulkCopy/BulkCopyCSVTest.java

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ public class BulkCopyCSVTest extends AbstractTest {
6666
static String inputFile = "BulkCopyCSVTestInput.csv";
6767
static String inputFileNoColumnName = "BulkCopyCSVTestInputNoColumnName.csv";
6868
static String inputFileDelimiterEscape = "BulkCopyCSVTestInputDelimiterEscape.csv";
69+
static String inputFileDelimiterEscapeNoNewLineAtEnd = "BulkCopyCSVTestInputDelimiterEscapeNoNewLineAtEnd.csv";
6970
static String inputFileMultipleDoubleQuotes = "BulkCopyCSVTestInputMultipleDoubleQuotes.csv";
7071
static String encoding = "UTF-8";
7172
static String delimiter = ",";
@@ -197,12 +198,70 @@ public void testEscapeColumnDelimitersCSV() throws Exception {
197198
assertEquals(expectedEscaped[i][3], rs.getString("c4"));
198199
i++;
199200
}
201+
assertEquals(i, 12, "Expected to load 12 records, but loaded " + i + " records");
200202
}
201203

202204
TestUtils.dropTableIfExists(tableName, stmt);
203205
}
204206
}
205207

208+
@Test
209+
@DisplayName("Test setEscapeColumnDelimitersCSVNoNewLineAtEnd")
210+
public void testEscapeColumnDelimitersCSVNoNewLineAtEnd() throws Exception {
211+
String tableName = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("BulkEscape"));
212+
String fileName = filePath + inputFileDelimiterEscapeNoNewLineAtEnd;
213+
/*
214+
* The list below is the copy of inputFileDelimiterEsc ape with quotes removed.
215+
*/
216+
String[][] expectedEscaped = new String[12][4];
217+
expectedEscaped[0] = new String[] {"test", " test\"", "no@split", " testNoQuote", ""};
218+
expectedEscaped[1] = new String[] {null, null, null, null, ""};
219+
expectedEscaped[2] = new String[] {"\"", "test\"test", "test@\" test", null, ""};
220+
expectedEscaped[3] = new String[] {"testNoQuote ", " testSpaceAround ", " testSpaceInside ",
221+
" testSpaceQuote\" ", ""};
222+
expectedEscaped[4] = new String[] {null, null, null, " testSpaceInside ", ""};
223+
expectedEscaped[5] = new String[] {"1997", "Ford", "E350", "E63", ""};
224+
expectedEscaped[6] = new String[] {"1997", "Ford", "E350", "E63", ""};
225+
expectedEscaped[7] = new String[] {"1997", "Ford", "E350", "Super@ luxurious truck", ""};
226+
expectedEscaped[8] = new String[] {"1997", "Ford", "E350", "Super@ \"luxurious\" truck", ""};
227+
expectedEscaped[9] = new String[] {"1997", "Ford", "E350", "E63", ""};
228+
expectedEscaped[10] = new String[] {"1997", "Ford", "E350", " Super luxurious truck ", ""};
229+
expectedEscaped[11] = new String[] {"1997", "F\r\no\r\nr\r\nd", "E350", "\"Super\" \"luxurious\" \"truck\"",
230+
""};
231+
232+
try (Connection con = getConnection(); Statement stmt = con.createStatement();
233+
SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con);
234+
SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord(fileName, encoding, "@",
235+
false)) {
236+
bulkCopy.setDestinationTableName(tableName);
237+
fileRecord.setEscapeColumnDelimitersCSV(true);
238+
fileRecord.addColumnMetadata(1, null, java.sql.Types.INTEGER, 0, 0);
239+
fileRecord.addColumnMetadata(2, null, java.sql.Types.VARCHAR, 50, 0);
240+
fileRecord.addColumnMetadata(3, null, java.sql.Types.VARCHAR, 50, 0);
241+
fileRecord.addColumnMetadata(4, null, java.sql.Types.VARCHAR, 50, 0);
242+
fileRecord.addColumnMetadata(5, null, java.sql.Types.VARCHAR, 50, 0);
243+
fileRecord.addColumnMetadata(6, null, java.sql.Types.VARCHAR, 50, 0);
244+
stmt.executeUpdate("CREATE TABLE " + tableName
245+
+ " (id INT IDENTITY(1,1), c1 VARCHAR(50), c2 VARCHAR(50), c3 VARCHAR(50), c4 VARCHAR(50), c5 VARCHAR(50))");
246+
bulkCopy.writeToServer(fileRecord);
247+
248+
int i = 0;
249+
try (ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName + " ORDER BY id");
250+
BufferedReader br = new BufferedReader(new FileReader(fileName));) {
251+
while (rs.next()) {
252+
assertEquals(expectedEscaped[i][0], rs.getString("c1"));
253+
assertEquals(expectedEscaped[i][1], rs.getString("c2"));
254+
assertEquals(expectedEscaped[i][2], rs.getString("c3"));
255+
assertEquals(expectedEscaped[i][3], rs.getString("c4"));
256+
i++;
257+
}
258+
assertEquals(i, 12, "Expected to load 12 records, but loaded " + i + " records");
259+
} finally {
260+
TestUtils.dropTableIfExists(tableName, stmt);
261+
}
262+
}
263+
}
264+
206265
/**
207266
* test simple csv file for bulkcopy, for GitHub issue 1391 Tests to ensure that the set returned by
208267
* getColumnOrdinals doesn't have to be ordered
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
1@"test"@ " test"""@ "no@split" @ testNoQuote@
2+
2@""@ ""@ ""@ ""@
3+
3@""""@ "test""test"@ "test@"" test"@ ""@
4+
4@testNoQuote @ testSpaceAround @ " testSpaceInside "@ " testSpaceQuote"" "@
5+
5@""@ ""@ ""@ " testSpaceInside "@
6+
6@1997@Ford@E350@E63@
7+
7@"1997"@"Ford"@"E350"@"E63"@
8+
8@1997@Ford@E350@"Super@ luxurious truck"@
9+
9@1997@Ford@E350@"Super@ ""luxurious"" truck"@
10+
10@1997@ "Ford" @E350@ "E63"@
11+
11@1997@Ford@E350@" Super luxurious truck "@
12+
12@1997@"F
13+
o
14+
r
15+
d"@"E350"@"""Super"" ""luxurious"" ""truck"""@

0 commit comments

Comments
 (0)