Add an Oracle Database 23ai store#102
Merged
Merged
Conversation
RowValues reads a Clob column by pulling its substring instead of assuming a String, so a store can return a java.sql.Clob without breaking hydration. AbstractJobRowMapper coerces a null cron expression back to the empty-string sentinel the engine expects, since Oracle collapses '' to NULL and cannot keep that column NOT NULL. Both keep their existing behaviour for MySQL and PostgreSQL. Signed-off-by: Jonathan Putney <jonathan@putney.io>
Contributor
Qodana for JVM1 new problem were found
☁️ View the detailed Qodana report Contact Qodana teamContact us at qodana-support@jetbrains.com
|
DialectTypeMapper gains two hooks: one to fold identifiers to the case the catalog stores, one to supply the delete-rule lookup query. The conformance contract routes table names and the foreign-key check through them. Oracle has no information_schema and upper-cases unquoted identifiers; the defaults still match MySQL and PostgreSQL. Signed-off-by: Jonathan Putney <jonathan@putney.io>
Adds Oracle to the migrator whitelist and dialect map, a MERGE-based version-ledger upsert, and a CREATE TABLE IF NOT EXISTS ledger. Oracle has no grant-free session lock and its DDL auto-commits, so concurrent migrators serialise through an EXCLUSIVE lock on a dedicated ratchet_schema_lock table held on a second connection, which means the pool needs room for two. The checksum and version-gap guards are unchanged. Signed-off-by: Jonathan Putney <jonathan@putney.io>
A full Oracle 23ai store built against the same store TCK as the others. UUIDs are RAW(16), JSON columns are CLOB with JSON_VALUE virtual columns, enum-like columns are VARCHAR2 with CHECK constraints, and flags use the native BOOLEAN. The claim path is two-phase because Oracle rejects FETCH FIRST combined with FOR UPDATE SKIP LOCKED. The JDBC driver stays test-scoped: its license is not OSI-approved, so deployers supply their own ojdbc at runtime. Signed-off-by: Jonathan Putney <jonathan@putney.io>
Adds an oracle profile to the testsuite and coverage builds, the Oracle container and datasource plumbing for the managed servers, and the WildFly driver module (which needs java.security.jgss because ojdbc reaches for GSS classes). Forces inline LOB prefetch on the server JVMs so CLOB reads through a pooled connection return content rather than a stale locator. Signed-off-by: Jonathan Putney <jonathan@putney.io>
Adds an Oracle deployment page, lists Oracle in the database-setup guide and the migrator dialect table, and adds it to the sidebar next to the other SQL stores. Notes the LOB prefetch setting that keeps CLOB reads reliable through a connection pool. Signed-off-by: Jonathan Putney <jonathan@putney.io>
Several native-query mappers in the Oracle store pulled CLOB-backed columns off the result row with a String cast or toString(). That holds only when the driver inlines the LOB through prefetch and returns a String. Under the pooled, concurrent poller load of the server matrix the driver hands back a java.sql.Clob locator instead, so the cast throws and toString() yields "oracle.sql.CLOB@...", which then reaches JSON-B as a value starting with 'o' and fails to parse. Route the workflow condition expression, the batch progress hook, the signal payload and rejection reason, and the hot-row last_error comparison through RowValues.stringOrNull. It reads the locator's content when the driver returns one and passes a plain String through untouched otherwise, so MySQL and PostgreSQL, which already return these columns as String, are unaffected. Signed-off-by: Jonathan Putney <jonathan@putney.io>
The Oracle store inherited MySQL's isolation self-check verbatim, including the @@SESSION.transaction_isolation query. Oracle rejects that syntax with ORA-00936, and the failure marks the surrounding JTA transaction rollback-only. When the first store write after startup shares that transaction, as the @Recurring master INSERT does, it then fails with STATUS_MARKED_ROLLBACK and the recurring job never registers. Oracle has no privilege-free way to read the session isolation level outside a transaction, and it offers no REPEATABLE READ level to guard against in the first place. Pass no probe query so the shared check degrades to a safe skip. The datasource and hibernate.connection.isolation still pin READ COMMITTED. Signed-off-by: Jonathan Putney <jonathan@putney.io>
The JPA cleanup strategy truncated tables between tests while the poller kept running. On Oracle that races badly. TRUNCATE fails on any table an enabled foreign key references (ORA-02266), and it resets a table's data-object number, so an in-flight poller query against that table dies with ORA-08103. Leftover state then bled into later tests. Send Oracle down the same row-level DELETE path PostgreSQL already uses. DELETE plays well with MVCC, honors the existing child-before-parent table order, and tolerates the live poller. MySQL keeps using TRUNCATE behind its foreign-key-check toggle. Signed-off-by: Jonathan Putney <jonathan@putney.io>
The JPA test data manipulator backdates rows with native UPDATEs keyed on job_id. It pre-converted the UUID to bytes only for MySQL and passed a bare UUID otherwise. PostgreSQL's native uuid column accepts that, but Oracle's job_id is RAW(16): Hibernate coerces a UUID parameter into those bytes for a native query, EclipseLink binds it verbatim, and the predicate then matches nothing. The backdating UPDATE silently affected zero rows under EclipseLink, so the archiving and DLQ-purge tests saw no stale rows to act on. Convert the UUID to its 16 big-endian bytes for Oracle as well, leaving PostgreSQL on the bare UUID. Signed-off-by: Jonathan Putney <jonathan@putney.io>
The Oracle permit acquire locked the resource-limit row, then read the active permit count in a separate statement before inserting. Under EclipseLink that second read can still see the pre-lock statement snapshot even after the FOR UPDATE wait, so concurrent acquirers all read a zero count and over-admit past the configured limit. The same code serialized fine on Hibernate. Move the capacity check inside the insert: lock the limit row, then run a guarded INSERT ... SELECT whose WHERE clause re-counts the live permits in the same statement that writes the new row. The count is evaluated against fresh committed data on the write path, so the limit holds on both Hibernate and EclipseLink. This mirrors what the PostgreSQL store already does for the same reason. Signed-off-by: Jonathan Putney <jonathan@putney.io>
Add the two validated Oracle cells to the integration matrix: WildFly for the Hibernate path and OpenLiberty for EclipseLink. Both run the full suite against a gvenzl Oracle 23ai container, and ojdbc stays test-scoped. The other server profiles can run against Oracle too but are not wired here yet. Signed-off-by: Jonathan Putney <jonathan@putney.io>
Oracle columns are TIMESTAMP(6), so a persisted Instant is floored to microsecond precision. Oracle's JDBC driver binds an Instant or Timestamp parameter at full nanosecond precision and compares it literally, so a cutoff taken from the same Instant as a stored row misses an exclusive (<) or inclusive-lower (>=) boundary by the sub-microsecond remainder. The MySQL and PostgreSQL drivers floor the bind to the column scale, so they pass the shared contracts unchanged; the gap only shows on a nanosecond-resolution clock (Linux), which hid it on macOS and in the store unit tests. Add OracleTimestamps.floorMicros/microTimestamp and route every < and >= comparison cutoff through it: DLQ alert dedup, log purge, DLQ job purge, archive find/count/purge, inactive-node find/delete, orphan-job reset, recurring annotation cancellation, the since/threshold metric windows, and the job-query range filters. The <= and > sites already handle the boundary correctly and are left unchanged. On Linux the wildfly+oracle integration matrix surfaced two of these as failures (DlqAlert exact-cutoff in the store suite, DlqPurgeIT exclusive-cutoff in the testsuite); the rest share the same mechanism and are fixed pre-emptively. Signed-off-by: Jonathan Putney <jonathan@putney.io>
The Oracle store hits the same two Qodana false positives the MySQL and PostgreSQL stores already suppress, but its paths were never added to the exclusion blocks. Every store method reads the container-managed EntityManager through context.em(), which Qodana flags as an AutoCloseable that should be closed (154 hits). Closing an injected @PersistenceContext EntityManager would be wrong, so the warning is a false positive. OracleJobStoreImpl's CDI no-arg constructor and lazy em init produce the same three nullability warnings already excluded on the MySQL and PostgreSQL impls. Add the Oracle paths to the AutoCloseableResource and DataFlowIssue blocks. A local scan with the community linter confirms the 158 Oracle findings drop to zero. Signed-off-by: Jonathan Putney <jonathan@putney.io>
Contributor
There was a problem hiding this comment.
Pull request overview
Adds first-class Oracle Database 23ai support to Ratchet by introducing a new Oracle-backed store module and wiring it into the existing schema migrator, store TCK, integration tests, docs, and CI matrix.
Changes:
- Introduces
ratchet-store-oracle(Oracle 23ai store implementation + schema resources + TCK/IT coverage). - Extends store-core + TCK to support Oracle-specific catalog behavior and CLOB/UUID/timestamp edge cases.
- Wires Oracle into docs, testsuite infrastructure (WildFly/OpenLiberty), and CI server×database matrix.
Reviewed changes
Copilot reviewed 106 out of 106 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| website/docs/getting-started/introduction.md | Mentions Oracle as a supported pluggable store. |
| website/docs/deployment/oracle.md | New Oracle 23ai deployment/configuration guide. |
| website/docs/deployment/database-setup.md | Adds Oracle setup guidance + migrator dialect table entry. |
| website/docs/concepts/persistence.md | Updates SPI docs to include Oracle in shipped stores list. |
| website/docs/advanced/spi-implementation.md | Updates SPI implementation docs to include Oracle store. |
| website/docs/.vitepress/config.ts | Adds Oracle deployment page to docs sidebar. |
| testing/ratchet-testsuite/src/test/resources/wildfly-setup.cli | Registers Oracle JDBC driver in WildFly test setup. |
| testing/ratchet-testsuite/src/test/resources/arquillian.xml | Adds Oracle LOB prefetch JVM arg to managed-server test runs. |
| testing/ratchet-testsuite/src/test/java/run/ratchet/testsuite/util/RatchetArchiveBuilder.java | Extends testsuite deployment builder to support Oracle persistence mappings/properties. |
| testing/ratchet-testsuite/src/test/java/run/ratchet/testsuite/util/DataSourceResourcesTest.java | Adds Oracle datasource/driver coordinate assertions; updates rejection test. |
| testing/ratchet-testsuite/src/test/java/run/ratchet/testsuite/util/DataSourceResources.java | Adds Oracle datasource class name and driver coordinates. |
| testing/ratchet-testsuite/src/test/java/run/ratchet/testsuite/infra/JdbcContainerExtension.java | Adds Oracle Testcontainers support + db-type wiring. |
| testing/ratchet-testsuite/src/main/java/run/ratchet/testsuite/app/JpaTestDataManipulator.java | Adjusts UUID native-binding behavior to handle RAW(16) (Oracle) like BINARY(16) (MySQL). |
| testing/ratchet-testsuite/src/main/java/run/ratchet/testsuite/app/JpaTestCleanupStrategy.java | Switches Oracle cleanup to DELETE (like PostgreSQL) to avoid TRUNCATE issues. |
| testing/ratchet-testsuite/pom.xml | Adds Testcontainers Oracle Free dependency + copies ojdbc into WildFly module + adds oracle profile. |
| testing/ratchet-tck/store/src/main/java/run/ratchet/tck/store/schema/DialectTypeMapper.java | Adds metadata identifier normalization, nullability relaxation hook, and dialect-specific delete rule query hook. |
| testing/ratchet-tck/store/src/main/java/run/ratchet/tck/store/AbstractSchemaConformanceContract.java | Uses new dialect hooks for Oracle (identifier casing, FK delete rule introspection, nullable relaxations). |
| testing/ratchet-coverage/pom.xml | Includes Oracle store module in coverage aggregation. |
| stores/ratchet-store-oracle/src/test/resources/META-INF/persistence.xml | Test persistence unit for Oracle store tests. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleWorkflowConditionStoreContractTest.java | Oracle TCK contract binding for workflow conditions. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleTransientExceptionTranslationTest.java | Tests Oracle transient exception translation behavior. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleTestFixture.java | Shared Oracle Testcontainers + JPA fixture for Oracle store TCK. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleTagStoreContractTest.java | Oracle TCK contract binding for tags. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleSignalStoreContractTest.java | Oracle TCK contract binding for signals. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleSchemaMigratorIT.java | Oracle schema migrator integration tests (including parallel migrator locking). |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleSchemaConformanceContractTest.java | Oracle schema conformance contract test (catalog/type/DDL expectations). |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleResourcePermitStoreContractTest.java | Oracle TCK contract binding for resource permits. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleRecurringJobStoreContractTest.java | Oracle TCK contract binding for recurring jobs. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleRecurringClaimConcurrencyContractTest.java | Oracle recurring claim concurrency contract test. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OraclePayloadEncryptionContractTest.java | Oracle payload encryption contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleNodeStoreContractTest.java | Oracle node store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleNodeLockOperationsTest.java | Unit tests for Oracle node lock operations SQL behavior. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleLockStoreContractTest.java | Oracle lock store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobTerminalStoreContractTest.java | Oracle terminal lifecycle contract + extra CAS invariants. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobStoreImplTransactionTest.java | Ensures transaction boundary annotations are correct for managed servers. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobRowMapperTest.java | Tests Oracle row mapper error-context behavior. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobRetryStoreContractTest.java | Oracle retry store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobQueryStoreContractTest.java | Oracle query store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobPauseStoreContractTest.java | Oracle pause store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobDeleteOperationsTest.java | Unit test ensuring orphan reset query handles NULL picked_by correctly. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobCrudStoreContractTest.java | Oracle CRUD store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobCountOperationsTest.java | Unit tests for Oracle analytics/counting operations. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobClaimStoreContractTest.java | Oracle claim store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobClaimOperationsTest.java | Verifies claim select column ordering/indexing contract. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobBulkStoreContractTest.java | Oracle bulk store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobBatchStatusStoreContractTest.java | Oracle batch status store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobAuditStoreContractTest.java | Oracle audit store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleJobAnalyticsStoreContractTest.java | Oracle analytics store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleExplainPlanCaptureIT.java | Captures/asserts Oracle claim candidate select uses the covering index. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleDualWriteInvariantContractTest.java | Oracle dual-write (hot/cold split) invariant contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleDlqAlertStoreContractTest.java | Oracle DLQ alert store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleDialectMapper.java | Oracle dialect mapper for schema conformance introspection. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleConstraintDetectorTest.java | Unit tests for Oracle constraint/transient detection. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleBusinessKeyReservationsTest.java | Unit tests for Oracle business-key reservation SQL/binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleBatchStoreContractTest.java | Oracle batch store contract + concurrency regression coverage. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleAuxiliaryOperationsTest.java | Unit tests for permit acquisition idempotency/defaults. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleArchiveStoreContractTest.java | Oracle archive store contract binding. |
| stores/ratchet-store-oracle/src/test/java/run/ratchet/store/oracle/OracleActiveBusinessKeyContractTest.java | Oracle active business key contract binding. |
| stores/ratchet-store-oracle/src/main/resources/META-INF/orm-oracle.xml | EclipseLink/non-Hibernate UUID RAW(16) mapping + reserved-word quoting mapping. |
| stores/ratchet-store-oracle/src/main/resources/META-INF/beans.xml | CDI bean discovery descriptor for Oracle store module. |
| stores/ratchet-store-oracle/src/main/resources/ddl/views/vw_jobs.sql | Operator views script (currently MySQL-specific; needs Oracle equivalent). |
| stores/ratchet-store-oracle/src/main/resources/ddl/README.md | DDL readme (currently MySQL-specific; should describe Oracle schema/migrations). |
| stores/ratchet-store-oracle/src/main/resources/ddl/oracle-debug-indexes.sql | Optional debug indexes script (header comments currently MySQL-specific). |
| stores/ratchet-store-oracle/src/main/resources/ddl/EXPLAIN-PLANS.md | EXPLAIN plan notes (currently MySQL-specific; should be Oracle-specific or removed). |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleTimestamps.java | Oracle-specific timestamp binding helpers (microsecond flooring). |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleStoreContext.java | Oracle store context wiring for metrics/dialect label + constraint detection. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleSignalOperations.java | Oracle signal store implementation (WAITING job timeout selection + delivery updates). |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleJobStore.java | Public Oracle store interface advertising capability closure. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleJobStatusTransitions.java | Oracle job status transition operations. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleJobRowMapper.java | Oracle job row mapper + payload/params encryption helpers. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleJobRecurringAndResetOperations.java | Oracle reset + cancel-by-tag operations. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleJobReadOperations.java | Oracle job read/find operations using native SQL hydration. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleJobLifecycleOperations.java | Oracle implementation wiring for pause/retry/terminal/batch status stores. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleJobDeleteOperations.java | Oracle delete + DLQ purge + orphan reset operations. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleJobCrudOperations.java | Oracle CRUD/bulk/analytics facade delegating to operation classes. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleEntityManagerProvider.java | Default CDI EntityManager provider for Oracle store module. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleConstraintDetector.java | Oracle constraint-violation + transient error detector. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleBusinessKeyReservations.java | Oracle business-key reservation DML + batch deletion helpers. |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/OracleArchiveOperations.java | Oracle archive store operations (batch archive + search + purge). |
| stores/ratchet-store-oracle/src/main/java/run/ratchet/store/oracle/converter/UuidRawConverter.java | UUID <-> RAW(16) attribute converter for non-Hibernate JPA providers. |
| stores/ratchet-store-oracle/src/main/java/module-info.java | Java module descriptor for Oracle store module. |
| stores/ratchet-store-oracle/README.md | Store README (currently MySQL-specific; should document Oracle store). |
| stores/ratchet-store-oracle/pom.xml | New Maven module definition for ratchet-store-oracle. |
| stores/ratchet-store-core/src/test/java/run/ratchet/store/migration/SchemaMigratorTest.java | Extends dialect auto-detection tests to include Oracle. |
| stores/ratchet-store-core/src/main/java/run/ratchet/store/util/RowValues.java | Adds CLOB-aware string extraction for Oracle native queries. |
| stores/ratchet-store-core/src/main/java/run/ratchet/store/migration/SchemaMigrationLifecycleHook.java | Updates lifecycle hook docs to include Oracle and its 2-connection lock requirement. |
| stores/ratchet-store-core/src/main/java/run/ratchet/store/context/AbstractJobRowMapper.java | Adds cron_expr NULL→"" normalization for Oracle empty-string semantics. |
| stores/ratchet-store-core/src/main/java/module-info.java | Exports store context package to Oracle module. |
| ratchet-bom/pom.xml | Adds Oracle store to BOM. |
| qodana.yaml | Excludes Oracle store paths from specific inspections (consistent with other stores). |
| pom.xml | Adds Oracle store module + ojdbc version and dependency management entry. |
| .github/workflows/ci.yml | Adds Oracle runs to the server×database integration matrix. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
The Oracle store module was seeded from the MySQL store, and several MySQL references were never converted. The docs pointed at files that do not exist in this module (mysql-schema.sql, orm-mysql.xml), the operator views called BIN_TO_UUID(), which Oracle has no equivalent for, and two comments described an "open InnoDB transaction" that Oracle never has. Three copy-paste bugs rode along with the docs: - RowValues.clobToString cast the CLOB length (a long) to int before getSubString, which truncates any CLOB over ~2 GB. It now streams through the character reader with no cast. - Two "<= ?" cutoff comparisons against TIMESTAMP(6) columns bound a raw Timestamp.from(now) instead of flooring to microseconds via OracleTimestamps.microTimestamp. Oracle's driver compares at nanosecond precision, so the boundary was missed on nanosecond-resolution clocks. The operator views now render RAW(16) with RAWTOHEX plus REGEXP_REPLACE, and the docs describe the Oracle schema, RAW(16) UUID storage, the two-connection migrator lock, and orm-oracle.xml wiring. Signed-off-by: Jonathan Putney <jonathan@putney.io>
testcontainers-oracle-free is already declared as a base test dependency (ungated, so JdbcContainerExtension compiles under every db profile), and the base comment says the oracle profile only needs to add the store and the JDBC driver. The profile's own copy was redundant. Signed-off-by: Jonathan Putney <jonathan@putney.io>
The Oracle store shipped running only two CI cells (WildFly for Hibernate, Open Liberty for EclipseLink) and was absent from most of the documentation that lists the supported stores. This brings it level with the MySQL, PostgreSQL, and MongoDB stores. CI and conformance: - Oracle now runs the full server matrix (WildFly, WildFly EE 11, Payara, Open Liberty, GlassFish) against the gvenzl Oracle 23ai container, with ojdbc kept test-scoped. - The docs.yml conformance generator and the VitePress sidebar now include Oracle, and the conformance index matrices gain an Oracle column. - Adds the Oracle conformance placeholder pages; the next CI run on main fills them with real results. Docs: - Adds Oracle to the supported-store lists across the README and the website (getting-started, deployment, concepts, comparison, troubleshooting, use-cases, SPI reference, homepage trust strip) and CONTRIBUTING. Signed-off-by: Jonathan Putney <jonathan@putney.io>
GlassFish and Payara instantiate the jdbc-connection-pool datasource-classname directly, and DataSourceResources handed them oracle.jdbc.datasource.OracleDataSource, which is an interface. The WAR never deployed -- it failed with "Error instantiating class oracle.jdbc.datasource.OracleDataSource" -- so every Payara/Oracle and GlassFish/Oracle test errored before it ran. Switch to the concrete oracle.jdbc.pool.OracleDataSource, the class Oracle's own GlassFish administration docs specify for an Oracle connection pool (restype javax.sql.DataSource). MySQL and PostgreSQL already used concrete classes. WildFly does not use this value (driver module plus auto-detected datasource), and OpenLiberty tolerated the interface through driver auto-detection; the concrete class is correct there too. Signed-off-by: Jonathan Putney <jonathan@putney.io>
Signed-off-by: Jonathan Putney <jonathan@putney.io>
The Oracle store module was added on this branch while the repo was at 0.1.1-SNAPSHOT. main has since bumped to 0.1.2-SNAPSHOT, but the bump did not touch the not-yet-merged Oracle pom, so after merging main every module was 0.1.2-SNAPSHOT except ratchet-store-oracle. ratchet-coverage (and the license gate) then could not resolve ratchet-store-oracle:0.1.2-SNAPSHOT and the build failed before any test ran. Signed-off-by: Jonathan Putney <jonathan@putney.io>
The shorter oracle.jdbc.pool.OracleDataSource literal fits on one line with its assertEquals argument, so google-java-format collapses it; apply that. Signed-off-by: Jonathan Putney <jonathan@putney.io>
With the datasource fix the Oracle WAR now deploys on Payara and GlassFish and 195-205 tests pass per cell, but ojdbc11 is a much heavier driver than the mysql/pg ones and one deploy OOMs the default 512m domain heap with 'Java heap space' (GlassFish), leaving a stuck app that cascades into 'application name already in use' on the following Payara deploys. Raise the domain heap to 2048m via the existing domain.xml antrun edit; the 16g runner has room alongside the gvenzl Oracle container. Signed-off-by: Jonathan Putney <jonathan@putney.io>
github-merge-queue Bot
pushed a commit
that referenced
this pull request
Jun 26, 2026
Adds `ratchet-store-sqlserver`, a Microsoft SQL Server implementation of the store SPI, alongside the existing MySQL/PostgreSQL/Oracle/MongoDB stores. Branched off the SQL Server port and rebased onto `main` after the Oracle store (#102) and the `0.1.2-SNAPSHOT` bump landed. ## What's here - New `stores/ratchet-store-sqlserver` module: full store + capability operations, `SqlserverConstraintDetector`, `SqlserverJobRowMapper`, T-SQL dialect translations (two-phase claim, `MERGE` upserts, `sp_getapplock` migration lock), and DDL (`V001` + consolidated schema + debug indexes). - Taught `SchemaMigrator` the `sqlserver` dialect (product-name detection, lock acquire/release, version-table DDL, `MERGE` record-version). - Wired into the integration matrix (all 5 servers × `sqlserver`, including GlassFish), TCK schema conformance, and the testsuite Arquillian harness. ## Two SQL Server / GlassFish-specific fixes worth calling out - **UUIDs stored as `BINARY(16)` (canonical big-endian), not `UNIQUEIDENTIFIER`.** EclipseLink 5.0 on GlassFish 8 reads `UNIQUEIDENTIFIER` via `getBytes`, returning `.NET-Guid` mixed-endian storage bytes that no JPA-layer intercept can redirect. Raw `BINARY(16)` is provider-independent, so EclipseLink 4/5/2.7 and Hibernate all decode it identically — same shape as `ratchet-store-mysql`, and time-sortable for UUIDv7. Hibernate paths set `hibernate.type.preferred_uuid_jdbc_type=BINARY`. - **`@Recurring` registration deferred to the managed scheduled executor.** EclipseLink 5.0 + mssql-jdbc on a non-XA pool does not autocommit DML run outside JTA, so registration from the mid-deployment `@Initialized(ApplicationScoped)` observer was rolled back. Registration now runs post-deployment with a real component context and retries idempotently until each master is confirmed; SE/plain-CDI still register inline. ## Validation - `mvn test-compile` green for store-core + sqlserver + full testsuite (`-am`). - `spotless:check` green. - `SchemaMigratorTest` passes (13/13). - Full Arquillian matrix (incl. glassfish+sqlserver) left to CI.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What this adds
An Oracle Database 23ai store (
ratchet-store-oracle), built against the same store TCK as the MySQL, PostgreSQL, and MongoDB stores, plus the migrator, matrix, and docs work to go with it.RAW(16), JSON columns asCLOBwithJSON_VALUEvirtual columns, enum-like columns asVARCHAR2+CHECK, flags as the native 23aiBOOLEAN. The claim path is two-phase (an unlocked candidate select, thenFOR UPDATE SKIP LOCKEDover those ids) because Oracle rejectsFETCH FIRSTcombined withFOR UPDATE SKIP LOCKED.EXCLUSIVElock on a dedicatedratchet_schema_locktable held on a second connection — Oracle has no grant-free session lock, and its DDL auto-commits, so a lock on the migration connection would not survive the firstCREATE TABLE. That design was peer-reviewed before implementation. It needs a pool that can hand out two connections.ojdbc11stays test-scoped. Its license is Oracle's Free Use Terms and Conditions, not OSI-approved, so Ratchet never bundles it and deployers supply their own. The parent POM flags this.What's verified
mvn verify -pl stores/ratchet-store-oracle -amis green on a realgvenzl/oracle-free:slim-faststart(Oracle 23ai) container: 380 store + schema-conformance tests, the restoredOracleSchemaMigratorIT(3/3, including the parallel-migrator convergence test that exercises the lock), andOracleExplainPlanCaptureIT(the captured plan ridesINDEX RANGE SCAN | IDX_CLAIM_EXECUTABLE, no full scan).RowValues, thecron NULL→""coercion, and the twoDialectTypeMapperhooks all keep their existing behaviour for those stores).Server matrix
Both cells run the full integration suite against Oracle and pass, so the matrix is wired into CI: one Hibernate cell (
wildfly-managed) and one EclipseLink cell (openliberty-managed), both 204/204.Getting there took five fixes, all of which surfaced only once the store ran inside a managed server under concurrent load:
last_errorcomparison) read CLOB columns with aStringcast ortoString(). Under a pooled connection the driver hands those back as ajava.sql.Cloblocator instead of aString, so the cast threw ortoString()leaked anoracle.sql.CLOB@...handle into JSON-B. They now go through the Clob-awareRowValues.stringOrNull.@@SESSION.transaction_isolationprobe, which Oracle rejects withORA-00936. The failure marked the startup transaction rollback-only and sank the@Recurringmaster insert. Oracle has no privilege-free way to read the session isolation level and noREPEATABLE READlevel to guard against, so the check now skips on Oracle.INSERT ... SELECT, the same shape the PostgreSQL store already uses.ORA-02266) and invalidates in-flight queries (ORA-08103). Oracle now clears withDELETE, like PostgreSQL.RAW(16)job_id needs the 16 bytes, which Hibernate coerced for free but EclipseLink did not.Follow-ups
wildfly-ee11-managed,payara-managed,glassfish-managed) are wired but not yet exercised in CI.https://claude.ai/code/session_01Q3y1VcGjFU9Q6ceSoKUsfX