Skip to content

Commit

Permalink
Fixed issue with SQLServerBulkCopy from CSV with setEscapeColumnDelim…
Browse files Browse the repository at this point in the history
…erts 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.
  • Loading branch information
machavan authored Jan 27, 2025
1 parent 08cd6fd commit 03cfcfd
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -246,7 +246,7 @@ private String readLineEscapeDelimiters() throws SQLServerException {
if (c == -1 && quoteCount % 2 != 0) { // stream ended, but we are within quotes -- data problem
throw new SQLServerException(SQLServerException.getErrString("R_InvalidCSVQuotes"), null, 0, null);
}
if (c == -1) { // keep semantics of readLine() by returning a null when there is no more data
if ((c == -1) && (sb.length() == 0)) { // keep semantics of readLine() by returning a null when there is no more data
return null;
}
} catch (IOException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ public class BulkCopyCSVTest extends AbstractTest {
static String inputFile = "BulkCopyCSVTestInput.csv";
static String inputFileNoColumnName = "BulkCopyCSVTestInputNoColumnName.csv";
static String inputFileDelimiterEscape = "BulkCopyCSVTestInputDelimiterEscape.csv";
static String inputFileDelimiterEscapeNoNewLineAtEnd = "BulkCopyCSVTestInputDelimiterEscapeNoNewLineAtEnd.csv";
static String inputFileMultipleDoubleQuotes = "BulkCopyCSVTestInputMultipleDoubleQuotes.csv";
static String encoding = "UTF-8";
static String delimiter = ",";
Expand Down Expand Up @@ -197,12 +198,70 @@ public void testEscapeColumnDelimitersCSV() throws Exception {
assertEquals(expectedEscaped[i][3], rs.getString("c4"));
i++;
}
assertEquals(i, 12, "Expected to load 12 records, but loaded " + i + " records");
}

TestUtils.dropTableIfExists(tableName, stmt);
}
}

@Test
@DisplayName("Test setEscapeColumnDelimitersCSVNoNewLineAtEnd")
public void testEscapeColumnDelimitersCSVNoNewLineAtEnd() throws Exception {
String tableName = AbstractSQLGenerator.escapeIdentifier(RandomUtil.getIdentifier("BulkEscape"));
String fileName = filePath + inputFileDelimiterEscapeNoNewLineAtEnd;
/*
* The list below is the copy of inputFileDelimiterEsc ape with quotes removed.
*/
String[][] expectedEscaped = new String[12][4];
expectedEscaped[0] = new String[] {"test", " test\"", "no@split", " testNoQuote", ""};
expectedEscaped[1] = new String[] {null, null, null, null, ""};
expectedEscaped[2] = new String[] {"\"", "test\"test", "test@\" test", null, ""};
expectedEscaped[3] = new String[] {"testNoQuote ", " testSpaceAround ", " testSpaceInside ",
" testSpaceQuote\" ", ""};
expectedEscaped[4] = new String[] {null, null, null, " testSpaceInside ", ""};
expectedEscaped[5] = new String[] {"1997", "Ford", "E350", "E63", ""};
expectedEscaped[6] = new String[] {"1997", "Ford", "E350", "E63", ""};
expectedEscaped[7] = new String[] {"1997", "Ford", "E350", "Super@ luxurious truck", ""};
expectedEscaped[8] = new String[] {"1997", "Ford", "E350", "Super@ \"luxurious\" truck", ""};
expectedEscaped[9] = new String[] {"1997", "Ford", "E350", "E63", ""};
expectedEscaped[10] = new String[] {"1997", "Ford", "E350", " Super luxurious truck ", ""};
expectedEscaped[11] = new String[] {"1997", "F\r\no\r\nr\r\nd", "E350", "\"Super\" \"luxurious\" \"truck\"",
""};

try (Connection con = getConnection(); Statement stmt = con.createStatement();
SQLServerBulkCopy bulkCopy = new SQLServerBulkCopy(con);
SQLServerBulkCSVFileRecord fileRecord = new SQLServerBulkCSVFileRecord(fileName, encoding, "@",
false)) {
bulkCopy.setDestinationTableName(tableName);
fileRecord.setEscapeColumnDelimitersCSV(true);
fileRecord.addColumnMetadata(1, null, java.sql.Types.INTEGER, 0, 0);
fileRecord.addColumnMetadata(2, null, java.sql.Types.VARCHAR, 50, 0);
fileRecord.addColumnMetadata(3, null, java.sql.Types.VARCHAR, 50, 0);
fileRecord.addColumnMetadata(4, null, java.sql.Types.VARCHAR, 50, 0);
fileRecord.addColumnMetadata(5, null, java.sql.Types.VARCHAR, 50, 0);
fileRecord.addColumnMetadata(6, null, java.sql.Types.VARCHAR, 50, 0);
stmt.executeUpdate("CREATE TABLE " + tableName
+ " (id INT IDENTITY(1,1), c1 VARCHAR(50), c2 VARCHAR(50), c3 VARCHAR(50), c4 VARCHAR(50), c5 VARCHAR(50))");
bulkCopy.writeToServer(fileRecord);

int i = 0;
try (ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName + " ORDER BY id");
BufferedReader br = new BufferedReader(new FileReader(fileName));) {
while (rs.next()) {
assertEquals(expectedEscaped[i][0], rs.getString("c1"));
assertEquals(expectedEscaped[i][1], rs.getString("c2"));
assertEquals(expectedEscaped[i][2], rs.getString("c3"));
assertEquals(expectedEscaped[i][3], rs.getString("c4"));
i++;
}
assertEquals(i, 12, "Expected to load 12 records, but loaded " + i + " records");
} finally {
TestUtils.dropTableIfExists(tableName, stmt);
}
}
}

/**
* test simple csv file for bulkcopy, for GitHub issue 1391 Tests to ensure that the set returned by
* getColumnOrdinals doesn't have to be ordered
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
1@"test"@ " test"""@ "no@split" @ testNoQuote@
2@""@ ""@ ""@ ""@
3@""""@ "test""test"@ "test@"" test"@ ""@
4@testNoQuote @ testSpaceAround @ " testSpaceInside "@ " testSpaceQuote"" "@
5@""@ ""@ ""@ " testSpaceInside "@
6@1997@Ford@E350@E63@
7@"1997"@"Ford"@"E350"@"E63"@
8@1997@Ford@E350@"Super@ luxurious truck"@
9@1997@Ford@E350@"Super@ ""luxurious"" truck"@
10@1997@ "Ford" @E350@ "E63"@
11@1997@Ford@E350@" Super luxurious truck "@
12@1997@"F
o
r
d"@"E350"@"""Super"" ""luxurious"" ""truck"""@

0 comments on commit 03cfcfd

Please sign in to comment.