AgentStack
Browse Sign in
Browse Why AgentStack Sell Docs
Sign in
SKILL verified MIT Self-run

Migrate Oracle Aq To Scalardb

skill-wfukatsu-nexus-architect-migrate-oracle-aq-to-scalardb · by wfukatsu

Generates Oracle AQ setup SQL (payload types, queues, enqueue triggers/SPs) and Java consumer files that dequeue messages and process them using the ScalarDB Java Transaction API.

— No reviews yet
0 installs
34 views
0.0% view→install

Install

$ agentstack add skill-wfukatsu-nexus-architect-migrate-oracle-aq-to-scalardb

✓ scanned · ✓ verified, works with Claude Code, Cursor, and more.

Security review

✓ Passed

No issues found. Passed automated security review. · v0.1.0 How review works →

  • ✓ Prompt-injection patterns
  • ✓ Secret / credential exfiltration
  • ✓ Dangerous shell & filesystem operations
  • ✓ Untrusted network calls
  • ✓ Known-malicious package signatures

What it can access

  • ✓ Network access No
  • ✓ Filesystem access No
  • ✓ Shell / process execution No
  • ✓ Environment & secrets No
  • ✓ Dynamic code execution No

From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.

View the full security report →

Verified badge

Passed review? Show it. Paste this badge into your README, it links to the public security report.

AgentStack Verified badge Links to your public security report.
[![AgentStack Verified](https://agentstack.voostack.com/badges/verified.svg)](https://agentstack.voostack.com/security/report/skill-wfukatsu-nexus-architect-migrate-oracle-aq-to-scalardb)

Reliability & compatibility

✓ Security review passed
0 installs to date
— no reviews yet
● 2mo ago

Declared compatibility

Claude CodeClaude Desktop

Compatibility is declared by the source manifest. End-to-end runtime verification is coming, see below.

Preview Execution monitoring

We're building live execution health for every listing: tool-call success rate, median latency, uptime, and last-checked timestamps, measured, not self-reported. It isn't live yet, so we don't show numbers we can't stand behind.

How agent discovery & health will work →
Are you the author of Migrate Oracle Aq To Scalardb? Claim this listing to set pricing, connect Stripe payouts, and keep 70% of every sale.
Sign up to claim

About

Migrate Oracle Stored Procedures & Triggers to AQ + ScalarDB Consumer Skill

Purpose

Convert Oracle triggers and stored procedures into an event-driven architecture using Oracle Advanced Queuing (AQ) as the messaging layer and ScalarDB Java Transaction API as the consumer layer.

Producer side (Oracle SQL): Triggers and stored procedures are replaced with AQ enqueue operations — triggers contain no business logic and simply call enqueue SPs.

Consumer side (Java): Message consumer classes dequeue from AQ using JMS and write to ScalarDB-managed tables using the Java Transaction API.

This skill produces:

  1. A complete SQL file (aq_setup.sql) for the Oracle producer side
  2. Java consumer files for the ScalarDB consumer side
  3. An AQ migration report documenting all conversions

Skill Responsibility

This skill is responsible for:

  • Analyzing triggers and stored procedures from extracted schema JSON
  • Determining which triggers/SPs should be converted to AQ enqueue patterns
  • Generating SQL for payload types, queue tables, queues, modified triggers, and enqueue SPs
  • Generating Java consumer service classes (dequeue + ScalarDB Transaction API)
  • Generating message POJO classes and helper utilities
  • Producing an AQ migration report

This skill is NOT responsible for:

  • Orchestration or command handling (handled by /oracle-to-scalardb command)
  • Schema extraction (handled by Subagent 1)
  • Schema report generation (handled by Subagent 2)
  • General migration analysis (handled by Subagent 3)
  • Direct SP/trigger to Java conversion without AQ (handled by Subagent 5)
  • Creating a full consumer application (build files, main class, deployment config)

Input Contract

| Input | Type | Required | Description | |-------|------|----------|-------------| | raw_schema_data.json | File | YES | Extracted Oracle schema data (specifically the plsql section) | | oracle_schema_report.md | File | YES | Schema report (for table/column context needed for accurate Key builders) | | aq-migration-strategy-guide.md | File | YES | Reference doc with AQ conversion patterns and code examples | | aq-exception-handling-strategy.md | File | YES | Exception classification and retry/commit strategy for consumer error handling | | output_directory | Directory | YES | Where to write generated files |


Output Contract

| Output | Location | Description | |--------|----------|-------------| | AQ Setup SQL | /aq_setup.sql | Complete SQL file: payload types, queues, triggers, enqueue SPs | | Java Consumer Classes | /generated-java/Consumer.java | One consumer per queue/message-type | | Java Message POJOs | /generated-java/Message.java | One POJO per payload type | | Java Helper Utility | /generated-java/AqStructHolder.java | Reusable Oracle STRUCT wrapper for ojdbc11 | | Exception Classifier | /generated-java/ExceptionClassifier.java | Classifies exceptions into RETRIABLE / NONRETRIABLE / UNKNOWNTX_STATE for AQ session handling | | AQ Migration Report | /scalardb_aq_migration_report.md | Report documenting all conversions |


How to Parse the JSON

Read raw_schema_data.json and extract these sections from plsql:

| JSON Path | Contains | |-----------|----------| | plsql.procedures | Procedure metadata (name, deterministic, parallel, authid) | | plsql.functions | Function metadata (name, return_type, deterministic) | | plsql.packages | Package metadata (name, authid, spec/body status) | | plsql.triggers | Trigger metadata (name, table, timing, event, status) | | plsql.arguments | Parameters for procedures/functions | | plsql.source | PL/SQL source code (grouped by NAME, TYPE, ordered by LINE) | | plsql.trigger_source | Trigger body source code | | plsql.procedure_ddl | Full DDL for procedures | | plsql.function_ddl | Full DDL for functions | | plsql.trigger_ddl | Full DDL for triggers |

Also read oracle_schema_report.md to extract:

  • Table names and their columns with data types
  • Primary key definitions (needed to build correct Key.of*() calls)
  • Foreign key relationships (needed for multi-table operations)

Conversion Decision Logic

Which triggers/SPs get converted to AQ?

Analyze each trigger and stored procedure to determine if it should be converted to AQ:

| Object | Convert to AQ? | Rationale | |--------|---------------|-----------| | Trigger with DML (INSERT/UPDATE/DELETE on another table) | YES | The DML becomes a consumer-side ScalarDB operation | | Trigger that calls an SP doing DML | YES | Both trigger and SP are converted | | Trigger with only validation/defaults (no cross-table DML) | NO | Keep as application-layer validation | | SP that INSERTs/UPDATEs/DELETEs records | YES | The DML moves to the consumer | | SP with only SELECT/computation | NO | Convert to direct Java (Subagent 5 handles) | | SP called by a trigger | YES | Becomes the enqueue SP; trigger just calls it |

Trigger conversion rules

  1. If a trigger has NO business logic (just calls an SP): The trigger calls the enqueue SP with appropriate parameters. The business logic lives in the consumer.
  2. If a trigger HAS business logic: Extract the logic. The trigger calls an enqueue SP passing all needed data (OLD/NEW values). The consumer Java code implements the business logic.
  3. Original triggers are DISABLED — new triggers replace them.
  4. Preserve the original trigger structure — do NOT split a single trigger into multiple triggers. If the original trigger fires on multiple events (e.g., UPDATE OF job_id, department_id), the AQ replacement MUST be a single trigger with the same event specification. The replacement trigger should call the enqueue SP once, passing all relevant OLD/NEW values.

Stored procedure conversion rules

  1. SPs that do DML: Converted to enqueue SPs (DBMS_AQ.ENQUEUE with ON_COMMIT visibility). The actual DML moves to the consumer.
  2. SPs called by triggers: Become enqueue SPs. The trigger just calls the enqueue SP.
  3. SPs with only SELECT/computation: Not converted to AQ (handled by Subagent 5 as direct Java).

SQL Generation Rules

1. Payload Type

Create one Oracle Object Type per distinct message schema. Include all data the consumer needs:

CREATE OR REPLACE TYPE . AS OBJECT (
    -- Include all columns the consumer needs to write
    -- Include operation_type VARCHAR2(20) as a routing key
        ,
    ...
    operation_type   VARCHAR2(20)   -- routing key: identifies what the consumer should do
);

Naming convention: _change_t (e.g., job_history_change_t)

2. Queue Table

BEGIN
    DBMS_AQADM.CREATE_QUEUE_TABLE(
        queue_table        => '.',
        queue_payload_type => '.'
    );
END;
/

Naming convention: _qt (e.g., job_history_qt)

3. Queue

BEGIN
    DBMS_AQADM.CREATE_QUEUE(
        queue_name  => '.',
        queue_table => '.',
        max_retries => 5,
        retry_delay => 0
    );
END;
/

BEGIN
    DBMS_AQADM.START_QUEUE('.');
END;
/

BEGIN
    DBMS_AQADM.GRANT_QUEUE_PRIVILEGE(
        privilege  => 'ALL',
        queue_name => '.',
        grantee    => ''
    );
END;
/

Naming convention: _queue (e.g., job_history_queue)

4. Enqueue Stored Procedures

CREATE OR REPLACE PROCEDURE .SP_ENQUEUE_ (
    
) AS
    l_enq_opts    DBMS_AQ.ENQUEUE_OPTIONS_T;
    l_msg_props   DBMS_AQ.MESSAGE_PROPERTIES_T;
    l_payload     ;
    l_msgid       RAW(16);
BEGIN
    l_payload := (
         => ,
        ...
        operation_type => ''   -- routing key
    );
    l_enq_opts.visibility := DBMS_AQ.ON_COMMIT;
    DBMS_AQ.ENQUEUE(
        queue_name         => '.',
        enqueue_options    => l_enq_opts,
        message_properties => l_msg_props,
        payload            => l_payload,
        msgid              => l_msgid
    );
END SP_ENQUEUE_;
/

5. Modified Triggers

IMPORTANT: Preserve the original trigger structure. Do NOT split a single trigger into multiple triggers. If the original trigger fires on UPDATE OF col1, col2, the replacement trigger MUST use the same event specification as a single trigger.

-- Disable original trigger
ALTER TRIGGER . DISABLE;

-- New trigger: no business logic, just calls the enqueue SP
-- Preserve the SAME event specification as the original trigger
CREATE OR REPLACE TRIGGER .TRG_AQ_
      ON .
    FOR EACH ROW
BEGIN
    SP_ENQUEUE_(
        p_col1 => :OLD.col1,   -- or :NEW.col1 depending on timing
        p_col2 => :NEW.col2,
        ...
    );
END TRG_AQ_;
/

SQL File Structure

The generated aq_setup.sql MUST be organized in this order:

-- =============================================================================
-- Oracle AQ Setup for  Schema
-- Generated: 
-- =============================================================================

-- Section 1: Payload Type Definitions
-- Section 2: Queue Table Creation
-- Section 3: Queue Creation & Configuration
-- Section 4: Disable Original Triggers
-- Section 5: Enqueue Stored Procedures
-- Section 6: New AQ Triggers
-- Section 7: Verification Queries

Note: Keep the AQ setup SQL minimal — only create the necessary payload types, queues, triggers, and enqueue SPs. Avoid unnecessary idempotent cleanup blocks unless the script is designed to be re-runnable.


Java Consumer Generation Rules

Target Java Version: 17

All generated Java files MUST target Java 17. Use Java 17 features where appropriate: var, records, instanceof pattern matching, switch expressions, text blocks, List.of(), String.formatted().

Do NOT use preview features or anything requiring Java 21+.

Required Dependencies (document in report)

The following JAR files are required for AQ consumer functionality:

| Dependency | Source | Notes | |------------|--------|-------| | aqapi.jar | Oracle DB ($ORACLE_HOME/rdbms/jlib/aqapi.jar) | Must be extracted from Oracle DB installation or container | | javax.jms-api-2.0.1.jar | Maven Central or Oracle DB | JMS 2.0 API | | ojdbc11-23.x.jar | Maven Central (com.oracle.database.jdbc:ojdbc11) | Oracle JDBC driver | | scalardb-3.17.x.jar | Maven Central (com.scalar-labs:scalardb) | ScalarDB Core (Transaction API) |

Note: ScalarDB Core is the default component (open source/community edition). Only add ScalarDB Cluster dependencies if the SQL interface is needed. For the Java Transaction API used by these consumers, ScalarDB Core is sufficient.

Note: aqapi.jar is NOT available in Maven Central for most versions. It must be obtained from inside the Oracle DB installation directory and added to the project's libs/ folder.

File Naming

  • Consumer classes: Consumer.java (PascalCase)
  • Example: job_history_queue → JobHistoryQueueConsumer.java
  • Message POJOs: Message.java (PascalCase)
  • Example: job_history_change_t → JobHistoryChangeMessage.java
  • Helper: AqStructHolder.java (always this name)

IMPORTANT: ALL files listed in the Output Contract MUST actually be written to disk. The Generated File Index in the report MUST match the actual files in generated-java/. Do not reference files that were not written.

AqStructHolder (generate once)

package com.example.scalardb.aq;

import oracle.sql.Datum;
import oracle.sql.ORAData;
import oracle.sql.STRUCT;

/**
 * Wraps Oracle STRUCT for ojdbc11 compatibility.
 * Required because oracle.sql.STRUCT no longer implements ORAData directly in ojdbc11.
 *
 * Java version: 17
 * Generated by ScalarDB AQ Migration Skill
 */
public class AqStructHolder implements ORAData {
    private final Datum datum;

    public AqStructHolder(Datum datum) {
        this.datum = datum;
    }

    public STRUCT asStruct() {
        return (STRUCT) datum;
    }

    @Override
    public Datum toDatum(java.sql.Connection conn) {
        return datum;
    }
}

Message POJO (one per payload type)

package com.example.scalardb.aq;

/**
 * Message POJO for Oracle AQ payload type: 
 * Maps to Oracle Object Type attributes by positional index.
 *
 * Java version: 17
 * Generated by ScalarDB AQ Migration Skill
 */
public class Message {
    private  ;     // [0] 
    ...
    private String operationType;  // [N] operation_type (routing key)

    // Getters and setters for all fields
}

Consumer Service Class (one per queue)

package com.example.scalardb.aq;

import com.scalar.db.api.*;
import com.scalar.db.io.Key;
import com.scalar.db.exception.transaction.*;
import oracle.jms.*;
import oracle.sql.STRUCT;
import javax.jms.*;
import java.math.BigDecimal;
import java.util.*;

/**
 * AQ Consumer for queue: 
 * Dequeues messages and processes them using ScalarDB Java Transaction API.
 *
 * Original triggers/SPs converted:
 *   - 
 *
 * Java version: 17
 * Generated by ScalarDB AQ Migration Skill
 */
public class Consumer {

    private static final String NAMESPACE = "";
    private static final String QUEUE_OWNER = "";
    private static final String QUEUE_NAME = "";
    private static final long RECEIVE_TIMEOUT_MS = 10_000;

    private final DistributedTransactionManager txManager;

    public Consumer(DistributedTransactionManager txManager) {
        this.txManager = txManager;
    }

    /**
     * Processes a single dequeued message using ScalarDB Transaction API.
     * Routes to the appropriate handler based on operation_type.
     *
     * @param message the parsed message POJO
     * @throws TransactionException if ScalarDB transaction fails
     */
    public void processMessage(Message message) throws TransactionException {
        switch (message.getOperationType()) {
            case "" -> handle(message);
            case "" -> handle(message);
            default -> throw new IllegalArgumentException(
                "Unknown operation type: " + message.getOperationType());
        }
    }

    // --- Handler methods (one per operation_type) ---

    private void handle(Message msg) throws TransactionException {
        DistributedTransaction tx = txManager.begin();
        try {
            // ScalarDB write logic — Upsert recommended for idempotency
            var upsert = Upsert.newBuilder()
                .namespace(NAMESPACE)
                .table("")
                .partitionKey(Key.of("", msg.get()))
                // .clusteringKey(...) if applicable
                // .xxxValue("", msg.get()) for each column
                .build();
            tx.upsert(upsert);
            tx.commit();
        } catch (Exception e) {
            tx.abort();
            throw e;
        }
    }

    // --- AQ JMS message parsing ---

    /**
     * Parses an Oracle ADT message (STRUCT) into a message POJO.
     * Attribute positions match the Oracle Object Type definition order.
     */
    public static Message parseMessage(Message jmsMessage) throws Exception {
        var adtMsg = (AQjmsAdtMessage) jmsMessage;
        var holder = (AqStructHolder) adtMsg.getAdtPayload();
        Object[] attrs = holder.asStruct().getAttributes();

        var msg = new Message();
        // Map each positional attribute to the POJO field
        // msg.setField(() attrs[index]);
        return msg;
    }
}

ScalarDB Write Patterns

Upsert (recommended for idempotency):

var upsert = Upsert.newBuilder()
    .namespace(NAMESPACE)
    .table("")
    .partitionKey(Key.of("", value))
    .clusteringKey(Key.of("", value))
    .Value("", value)
    .build();
tx.upsert(upsert);

Using Upsert is recommended because it provides idempotency during message redelivery: if the consumer crashes after the ScalarDB commit but before the AQ session commit, AQ redelivers the message and the Upsert simply overwrites with identical data. However, Upsert is not mandatory — Insert can be used if duplicate handling is managed differently.

Insert (alternative):

var insert =

…

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [wfukatsu](https://github.com/wfukatsu)
- **Source:** [wfukatsu/nexus-architect](https://github.com/wfukatsu/nexus-architect)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

Reviews

No reviews yet, be the first.

Versions

  • v0.1.0 Imported from the upstream source.