Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed issue with SQLServerBulkCopy from CSV with setEscapeColumnDelimerts set to true #2575

Merged
merged 8 commits into from
Jan 27, 2025
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"""@
Loading