It turns out that the existing code for chunking a table when taking
an incremental snapshot was buggy and did not correctly handle NULL
values when building the chunk query. An example of such a situation
would be when the user has specified "message.key.columns" to reference
a column that is part of a PostgreSQL UNIQUE INDEX that was created with
the NULLS NOT DISTINCT option.
This commit updates the new AbstractChunkQueryBuilder so that it checks
whether a key column is optional. If it is, then additional will
appropriately consider NULL values when generating a chunk query using
"IS [NOT] NULL" clauses.
One complication is that different database engines have different
sorting behavior of ORDER BY. It is apparently not well-defined by the
SQL standard. Some databases consider NULL values to be higher than any
non-NULL values, and others consider them to be lower.
To handle this situation, a new nullsSortLast() function is added to the
JdbcConnection class. By default, it returns an empty value, indicating
that the behavior of the database engine is unknown. When an optional
field is encountered by AbstractChunkQueryBuilder in this situation, we
throw an error because we don't actually know how to correctly chunk the
query: there's no safe assumption that can be made here.
Derived JdbcConnection classes can then override the nullsSortLast
function, and return a value indicating the actual behavior of that
database engine. When this is done, the AbstractChunkQueryBuilder then
knows how to correctly build a chunk query that can handle NULL values.
To help test this, new tests have been added to
AbstractIncrementalSnapshotTest. First, the existing insertsWithoutPks
test has been moved and deduplicated from MySQL and PostgreSQL so that
the test case can be reused on other engines. Second, a new
insertsWithoutPksAndNull test is run, which inserts data with NULL
values in the message key columns. To demonstrate that chunk queries
are being correctly generated for practically every case, the
INCREMENTAL_SNAPSHOT_CHUNK_SIZE is set to 1 so that NULL values are not
returned in the middle of a chunk, which can cause us to skip testing
the code we need to test.
Because OracleConnection uses flashback query (AS OF SCN) to re-select row, it is potentially possible to get "ORA-01555 Snapshot too old" error, which can be solved by performing reselection without flashback to get at least its latest row state.
Each time, Oracle connector creates a new instance of PreparedStatement because value of commit SCN is added directly to SQL query to reselect column values.
* Create oracle-init dir with SQL init scripts
* Create init-db.sh to set default password and run init scripts
* Update test.sh to run init-db.sh for oracle-23
* Introduce new InstantClient version property
Needed because ojdbc8 versions for Oracle 23 have different version semantics
Also adjusted documentation/build pipelines
* Introduce oracle-23 profile
Allows testing Oracle 23 separately from distribution builds
As a part of this work to handle injection in a cleaner way, this commit
adds two new broad concepts called `BeanRegistry` and `ServiceRegistry`.
A BeanRegistry is a glorified registry of different objects that are not
necessarily services but may be desired by a service. This contract will
allow Debezium to integrate in the future with other CDI providers.
A ServiceRegistry is more of an internal concept, where various systems
can be started based on their dependency order and provides a universal
way to split larger parts of the code into smaller, focused modules that
can be accessed using the Service Locator pattern.
The snapshot phase was not setting the unavailable value placeholder when the
user had configured LOB as off, this aligns that behavior to be consistent
with the behavior from streaming.
also makes sure that events are correctly removed in ISPN event processor after transaction is abandoned.
Also fixes scenario with event number based threshold abandonment in ISPN - events comming afterwards would be still processed.
There is a corner case where it's possible the Oracle connector may query
the Oracle metadata tables quicker than the ARC process can generate an
archive log history record in V$ARCHIVED_LOG, and this can lead to a race
condition where we may incorrectly advance the connector forward to start
mining a group of logs when a log sequence gap exists in the log ranges.
For users who use the online_catalog strategy, there are some checks that
LogMiner does automatically which it skips, and one is with log sequence
gaps. This fix enforces that check by Debezium even for users who may use
the faster online_catalog mode so that no logs are omitted and events
could be missed.
There was a possible situation where if a long transaction consisted of
updating and inserting into the same table with identical keys with a
given sequence that the commit handler would merge several events for a
table without LOB columns, resulting in a difference in expected events
in the Kafka topic vs what was seen in LogMiner.
This config will be re-used by possible other implementations of
DebeiumEngine API in the embedded package. As DebeziumEngine API
can have completely different implementations and thus also config,
the class is called `EmbeddedEngineConfig` as it's assumed to be used
only by embedded engine "family" of implementations.
To keep backward compatibility, the config options are extracted into
an interface and `EmbeddedEngine` implements this interface, thus
allowing to use these options in custom classes without any need for the
code changes.
It is recommended by Infinispan that specific calls that return a collection
of elements should be treated as a closable object so that any and all the
potential resources associated with the operation are closed.
Add a new internal `log.mining.schema_changes.username.exclude.list` to allow users
to customize the default behavior for excluding the SYS and SYSTEM usernames from
DDL changes.
In some corner cases, users may have unusually large SQL statements that
need to be buffered due to the number of columns paired with the data in
those columns. Previously we capped this to 4000*10 or 40kb primarily to
address situations with LOB operations that could lead to OOM scenarios.
The new code rather logs a warning when exceeding 100kb and hard faults
ony when the connector sees Integer.MAX_VALUE number of SQL lines for a
single SQL buffer.
Pending transactions with a START_SCN of 0 are considered transactions
that have started before the oldest available archive log and these
will be ignored as the entire transaction cannot be mined.
This returns the age in milliseconds from the poll time for the age of the oldest
transaction's starting system change number in the transaction buffer.
The SCN data types were previously exposed as `String` types, which is not
consumable by Grafana and Prometheus. By using `BigInteger`, we can now
make these accessible on dashboards.
When a user supplies a column visibility clause in an ALTER TABLE statement,
there are no "modify_col_properties" clauses present, and this will lead to
the aforementioned exception. The listener should be tolerant of this case
and should not initialize any column editors.
The shouldCaptureChangesForTransactionsAcrossSnapshotBoundaryWithoutReemittingDDLChanges test
only expects the tables created by the entire test to exist but tables from other tests not,
and it would appear this commonly happens when another test fails to cleanup after itself.
This fix is to guarantee that the Oracle database state is set properly so that tests from
within this class are executed with the right number of tables expected to exist.
We hypothesize that there could be a situation where we may be mining precisely
around the CURRENT_SCN and this may lead to situations where LGWR may not have
flushed all records for the same SCN before being mined by the connector.