From f3dc54d8a7556b1ea2d5668b9d5562a20a308c3f Mon Sep 17 00:00:00 2001 From: Rophy Tsai Date: Fri, 20 Mar 2026 00:49:14 +0000 Subject: [PATCH] feat: add ROWID column type (type# 69) decoding MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ROWID columns were unsupported — values were silently dropped. Add decoding from the 10-byte big-endian redo format (dataObj + DBA + slot) and output as Oracle's standard base64 ROWID string. UROWID (type 208) is unchanged — it keeps the existing hex format since UROWID can store variable-length logical ROWIDs from IOTs. --- src/builder/Builder.cpp | 26 ++++++++++++++++++++++++++ src/builder/BuilderJson.h | 6 ++++++ src/builder/BuilderProtobuf.h | 6 ++++++ src/common/table/SysCol.h | 1 + 4 files changed, 39 insertions(+) diff --git a/src/builder/Builder.cpp b/src/builder/Builder.cpp index 16ab66ba..bb962f36 100644 --- a/src/builder/Builder.cpp +++ b/src/builder/Builder.cpp @@ -598,6 +598,32 @@ namespace OpenLogReplicator { } break; + case SysCol::COLTYPE::ROWID: + // ROWID (type 69) in redo: 10 bytes big-endian + // dataObj(4) + DBA(4, afn<<22|block) + slot(2) + // Output as Oracle base64 ROWID string (e.g. AAASnuAAMAAAAKtAAA) + if (size == 10) { + const typeDataObj rDataObj = (static_cast(data[0]) << 24) | + (static_cast(data[1]) << 16) | + (static_cast(data[2]) << 8) | + static_cast(data[3]); + const typeDba rDba = (static_cast(data[4]) << 24) | + (static_cast(data[5]) << 16) | + (static_cast(data[6]) << 8) | + static_cast(data[7]); + const typeSlot rSlot = (static_cast(data[8]) << 8) | + static_cast(data[9]); + RowId rowId(rDataObj, rDba, rSlot); + // Output as base64 string (Oracle's standard ROWID display format) + // Not using columnRowId — that uses toHex for UROWID compatibility + rowId.toString(reinterpret_cast(valueBuffer)); + valueSize = RowId::SIZE; + columnString(column->name); + } else { + columnUnknown(column->name, data, size); + } + break; + case SysCol::COLTYPE::UROWID: if (size == 13 && data[0] == 0x01) { RowId rowId; diff --git a/src/builder/BuilderJson.h b/src/builder/BuilderJson.h index 797df782..26680981 100644 --- a/src/builder/BuilderJson.h +++ b/src/builder/BuilderJson.h @@ -69,6 +69,7 @@ namespace OpenLogReplicator { && typeNo != SysCol::COLTYPE::TIMESTAMP && typeNo != SysCol::COLTYPE::INTERVAL_YEAR_TO_MONTH && typeNo != SysCol::COLTYPE::INTERVAL_DAY_TO_SECOND + && typeNo != SysCol::COLTYPE::ROWID && typeNo != SysCol::COLTYPE::UROWID && typeNo != SysCol::COLTYPE::TIMESTAMP_WITH_LOCAL_TZ) return; @@ -501,6 +502,11 @@ namespace OpenLogReplicator { appendDec(table->columns[column]->length); break; + case SysCol::COLTYPE::ROWID: + append(std::string_view(R"("rowid","length":)")); + appendDec(table->columns[column]->length); + break; + case SysCol::COLTYPE::UROWID: append(std::string_view(R"("urowid","length":)")); appendDec(table->columns[column]->length); diff --git a/src/builder/BuilderProtobuf.h b/src/builder/BuilderProtobuf.h index e6469b1a..3013c33d 100644 --- a/src/builder/BuilderProtobuf.h +++ b/src/builder/BuilderProtobuf.h @@ -64,6 +64,7 @@ namespace OpenLogReplicator { && typeNo != SysCol::COLTYPE::TIMESTAMP && typeNo != SysCol::COLTYPE::INTERVAL_YEAR_TO_MONTH && typeNo != SysCol::COLTYPE::INTERVAL_DAY_TO_SECOND + && typeNo != SysCol::COLTYPE::ROWID && typeNo != SysCol::COLTYPE::UROWID && typeNo != SysCol::COLTYPE::TIMESTAMP_WITH_LOCAL_TZ) return; @@ -302,6 +303,11 @@ namespace OpenLogReplicator { columnPB->set_length(static_cast(table->columns[column]->length)); break; + case SysCol::COLTYPE::ROWID: + columnPB->set_type(pb::UROWID); + columnPB->set_length(static_cast(table->columns[column]->length)); + break; + case SysCol::COLTYPE::UROWID: columnPB->set_type(pb::UROWID); columnPB->set_length(static_cast(table->columns[column]->length)); diff --git a/src/common/table/SysCol.h b/src/common/table/SysCol.h index a5e6c70a..ddcde0e4 100644 --- a/src/common/table/SysCol.h +++ b/src/common/table/SysCol.h @@ -75,6 +75,7 @@ namespace OpenLogReplicator { RAW = 23, LONG_RAW = 24, XMLTYPE = 58, + ROWID = 69, CHAR = 96, FLOAT = 100, DOUBLE = 101,