DBZ-4994 Fix LOB locator event parsing with escaped single quotes

This commit is contained in:
Chris Cranford 2022-04-14 12:29:35 -04:00 committed by Jiri Pechanec
parent f667402fe0
commit f24be1f533
3 changed files with 63 additions and 11 deletions

View File

@ -150,7 +150,7 @@ else if (c == ')' && !inSingleQuotes) {
else if (c == '\'') {
// skip over double single quote
if (inSingleQuotes && lookAhead == '\'') {
i += 2;
i += 1;
continue;
}
if (inSingleQuotes) {

View File

@ -1908,13 +1908,14 @@ public void shouldStreamClobsWrittenInChunkedMode() throws Exception {
}
@Test
@FixFor({ "DBZ-4891", "DBZ-4862" })
@FixFor({ "DBZ-4891", "DBZ-4862", "DBZ-4994" })
public void shouldStreamClobValueWithEscapedSingleQuoteValue() throws Exception {
String ddl = "CREATE TABLE CLOB_TEST ("
+ "ID numeric(9,0), "
+ "VAL_CLOB clob, "
+ "VAL_NCLOB nclob, "
+ "VAL_USERNAME varchar2(100),"
+ "VAL_DATA varchar2(100), "
+ "primary key(id))";
connection.execute(ddl);
@ -1929,15 +1930,10 @@ public void shouldStreamClobValueWithEscapedSingleQuoteValue() throws Exception
assertConnectorIsRunning();
waitForSnapshotToBeCompleted(TestHelper.CONNECTOR_NAME, TestHelper.SERVER_NAME);
// Insert record
Clob clob1 = createClob(part(JSON_DATA, 0, 25000));
NClob nclob1 = createNClob(part(JSON_DATA2, 0, 25000));
connection.prepareQuery("INSERT INTO clob_test VALUES (1, ?, ?, ?)", ps -> {
ps.setClob(1, clob1);
ps.setNClob(2, nclob1);
ps.setString(3, "This will be fixed soon so please don't worry, she wrote.");
}, null);
connection.commit();
// Create simple insert, will be used for updates later
final String simpleQuote = "This will be fixed soon so please don''t worry, she wrote.";
final String complexQuote = "2\"''\" sd f\"\"\" '''''''' ''''";
connection.execute("INSERT INTO clob_test (id,val_username,val_data) values (1,'" + simpleQuote + "','" + complexQuote + "')");
SourceRecords records = consumeRecordsByTopic(1);
assertThat(records.recordsForTopic(topicName("CLOB_TEST"))).hasSize(1);
@ -1945,11 +1941,29 @@ public void shouldStreamClobValueWithEscapedSingleQuoteValue() throws Exception
SourceRecord record = records.recordsForTopic(topicName("CLOB_TEST")).get(0);
VerifyRecord.isValidInsert(record, "ID", 1);
// Update the record this way to enforce that both varchar fields are present in the SELECT_LOB_LOCATOR
// event that will need to be parsed by the SelectLobParser component.
Clob clob1 = createClob(part(JSON_DATA, 0, 25000));
NClob nclob1 = createNClob(part(JSON_DATA2, 0, 25000));
connection.prepareQuery("update clob_test set val_clob=?, val_nclob=? where id=1", ps -> {
ps.setClob(1, clob1);
ps.setClob(2, nclob1);
}, null);
connection.commit();
records = consumeRecordsByTopic(1);
assertThat(records.recordsForTopic(topicName("CLOB_TEST"))).hasSize(1);
record = records.recordsForTopic(topicName("CLOB_TEST")).get(0);
VerifyRecord.isValidUpdate(record, "ID", 1);
// Validate update data
Struct after = after(record);
assertThat(after.get("ID")).isEqualTo(1);
assertThat(after.get("VAL_CLOB")).isEqualTo(getClobString(clob1));
assertThat(after.get("VAL_NCLOB")).isEqualTo(getClobString(nclob1));
assertThat(after.get("VAL_USERNAME")).isEqualTo("This will be fixed soon so please don't worry, she wrote.");
assertThat(after.get("VAL_DATA")).isEqualTo("2\"'\" sd f\"\"\" '''' ''");
}
private Clob createClob(String data) throws SQLException {

View File

@ -206,4 +206,42 @@ public void shouldParseComplexBlobBasedLobSelect() throws Exception {
assertThat(entry.getNewValues()[5]).isNull();
}
@Test
@FixFor("DBZ-4994")
public void shouldParseColumnWithEscapedSingleQuoteColumnValues() throws Exception {
final Table table = Table.editor()
.tableId(TableId.parse("DEBEZIUM.QUOTE_TABLE"))
.addColumn(Column.editor().name("ID").create())
.addColumn(Column.editor().name("NAME").create())
.addColumn(Column.editor().name("CLOB_COL").create())
.create();
String redoSql = "DECLARE \n" +
" loc_c CLOB; \n" +
" buf_c VARCHAR2(6426); \n" +
" loc_b BLOB; \n" +
" buf_b RAW(6426); \n" +
" loc_nc NCLOB; \n" +
" buf_nc NVARCHAR2(6426); \n" +
"BEGIN\n" +
" select \"CLOB_COL\" into loc_c from \"DEBEZIUM\".\"QUOTE_TABLE\" where \"ID\" = '1' and \"NAME\" = " +
"'2\"''\" sd f\"\"\" '''''''' ''''' for update;";
LogMinerDmlEntry entry = parser.parse(redoSql, table);
assertThat(parser.isBinary()).isFalse();
assertThat(parser.getColumnName()).isEqualTo("CLOB_COL");
assertThat(entry.getObjectOwner()).isEqualTo("DEBEZIUM");
assertThat(entry.getObjectName()).isEqualTo("QUOTE_TABLE");
assertThat(entry.getEventType()).isEqualTo(EventType.SELECT_LOB_LOCATOR);
assertThat(entry.getOldValues()).hasSize(3);
assertThat(entry.getOldValues()[0]).isEqualTo("1");
assertThat(entry.getOldValues()[1]).isEqualTo("2\"''\" sd f\"\"\" '''''''' ''''");
assertThat(entry.getOldValues()[2]).isNull();
assertThat(entry.getNewValues()).hasSize(3);
assertThat(entry.getNewValues()[0]).isEqualTo("1");
assertThat(entry.getNewValues()[1]).isEqualTo("2\"''\" sd f\"\"\" '''''''' ''''");
assertThat(entry.getNewValues()[2]).isNull();
}
}