Auto-activate for cx_Oracle imports, oracledb imports, Oracle connection strings. Produces Oracle Database SQL, PL/SQL, connection configurations, and ORDS REST API patterns. Use when: working with Oracle databases, writing SQL/PL/SQL, building REST APIs with ORDS, configuring database connections, OCI drivers, Podman/Docker Oracle containers, or Oracle 26ai Free images. Not for PostgreSQL (see postgres), MySQL (see mysql), or cloud-only Oracle services without database access.
From flownpx claudepluginhub cofin/flow --plugin flowThis skill uses the workspace's default tool permissions.
references/admin.mdreferences/agent_patterns.mdreferences/connections.mdreferences/containers.mdreferences/json.mdreferences/oci.mdreferences/oem.mdreferences/ords.mdreferences/performance.mdreferences/plsql.mdreferences/schema_migrations.mdreferences/security.mdreferences/sql_patterns.mdreferences/sqlplus.mdreferences/vectors.mdSearches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Searches prompts.chat for AI prompt templates by keyword or category, retrieves by ID with variable handling, and improves prompts via AI. Use for discovering or enhancing prompts.
Enables AI agents to execute x402 payments with per-task budgets, spending controls, and non-custodial wallets via MCP tools. Use when agents pay for APIs, services, or other agents.
Use this skill when working with Oracle Database in any capacity: OCI-based data paths (connect, execute, fetch, bind, transaction control), Instant Client configuration, or container-based Oracle 26ai workflows for dev/test/CI environments.
import oracledb
# Thin mode -- no Instant Client required
conn = oracledb.connect(
user="app_user",
password="secret",
dsn="host.example.com:1521/FREEPDB1",
)
with conn.cursor() as cur:
# Always use bind variables
cur.execute(
"SELECT order_id, total FROM orders WHERE customer_id = :cid",
{"cid": 42},
)
rows = cur.fetchall()
# Create pool at startup; reuse for process lifetime
pool = oracledb.create_pool(
user="app_user", password="secret",
dsn="host.example.com:1521/FREEPDB1",
min=2, max=10, increment=1,
)
with pool.acquire() as conn:
with conn.cursor() as cur:
cur.execute("SELECT SYSDATE FROM dual")
import oracle.jdbc.pool.OracleDataSource;
OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:@//host.example.com:1521/FREEPDB1");
ods.setUser("app_user");
ods.setPassword("secret");
try (Connection conn = ods.getConnection();
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM orders WHERE customer_id = ?")) {
ps.setInt(1, 42);
try (ResultSet rs = ps.executeQuery()) {
while (rs.next()) {
System.out.println(rs.getInt("order_id"));
}
}
}
-- Package spec: public API contract
CREATE OR REPLACE PACKAGE order_api AS
SUBTYPE order_id_t IS orders.order_id%TYPE;
PROCEDURE place_order(
p_customer_id IN customers.customer_id%TYPE,
p_items IN order_item_tab_t,
p_order_id OUT order_id_t
);
END order_api;
/
-- Exception handling with diagnostic capture
EXCEPTION
WHEN OTHERS THEN
log_pkg.error(
p_message => SQLERRM,
p_backtrace => DBMS_UTILITY.FORMAT_ERROR_BACKTRACE,
p_stack => DBMS_UTILITY.FORMAT_ERROR_STACK
);
RAISE; -- re-raise after logging; never silently swallow
Module: /api/v1/ (base path)
Template: /api/v1/orders/ (collection)
Template: /api/v1/orders/:id (single item)
Handler: GET on /api/v1/orders/ -> SELECT query
Handler: POST on /api/v1/orders/ -> INSERT + RETURNING
-- AutoREST: enable CRUD endpoints for a schema
BEGIN
ORDS.ENABLE_SCHEMA(
p_enabled => TRUE,
p_schema => 'APP_USER',
p_url_mapping_type => 'BASE_PATH',
p_url_mapping_pattern => 'app'
);
END;
/
<workflow>
| Need | Reference | Key Concept |
|---|---|---|
| Connect from Python | connections.md | oracledb thin/thick, pooling |
| Connect from Java | connections.md | JDBC thin, UCP |
| Write PL/SQL | plsql.md | Packages, BULK COLLECT, FORALL |
| SQL patterns | sql_patterns.md | Analytics, CTEs, MERGE, MODEL |
| REST APIs | ords.md | Modules, templates, handlers |
| JSON operations | json.md | JSON_VALUE, Duality Views (23ai+) |
| Container dev/test | containers.md | Podman, 26ai Free |
| Performance tuning | performance.md | EXPLAIN PLAN, AWR, indexes |
| Vector/AI search | vectors.md | VECTOR type, IVF/HNSW indexes |
| Schema migrations | schema_migrations.md | Liquibase, EBR, DBMS_REDEFINITION |
%TYPE / %ROWTYPEFORMAT_ERROR_BACKTRACE + FORMAT_ERROR_STACK, then re-raiseRun through the validation checkpoint below before considering the work complete.
</workflow> <guardrails>:param_name syntax -- never concatenate values into SQL stringscreate_pool() at startup, pool.acquire() per operationWHEN OTHERS%TYPE / %ROWTYPE so DDL changes propagate automaticallyRAISE_APPLICATION_ERROR for custom errors visible to SQL callers (range -20000 to -20999)Before delivering Oracle code, verify:
:param_name) -- no string concatenation for valuesmin/max/increment parameters%TYPE:id) in SQL source, not concatenationTask: "Create a PL/SQL stored procedure for order placement with proper error handling, and call it from Python with connection pooling."
-- PL/SQL: Package for order management
CREATE OR REPLACE PACKAGE order_api AS
SUBTYPE order_id_t IS orders.order_id%TYPE;
gc_max_items CONSTANT PLS_INTEGER := 500;
PROCEDURE place_order(
p_customer_id IN customers.customer_id%TYPE,
p_product_id IN products.product_id%TYPE,
p_quantity IN PLS_INTEGER,
p_order_id OUT order_id_t
);
END order_api;
/
CREATE OR REPLACE PACKAGE BODY order_api AS
PROCEDURE place_order(
p_customer_id IN customers.customer_id%TYPE,
p_product_id IN products.product_id%TYPE,
p_quantity IN PLS_INTEGER,
p_order_id OUT order_id_t
) IS
v_price products.unit_price%TYPE;
BEGIN
IF p_quantity > gc_max_items THEN
RAISE_APPLICATION_ERROR(-20100,
'Quantity ' || p_quantity || ' exceeds limit of ' || gc_max_items);
END IF;
SELECT unit_price INTO v_price
FROM products
WHERE product_id = p_product_id;
INSERT INTO orders (customer_id, product_id, quantity, total)
VALUES (p_customer_id, p_product_id, p_quantity, v_price * p_quantity)
RETURNING order_id INTO p_order_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20101,
'Product ' || p_product_id || ' not found');
WHEN OTHERS THEN
log_pkg.error(
p_message => SQLERRM,
p_backtrace => DBMS_UTILITY.FORMAT_ERROR_BACKTRACE,
p_stack => DBMS_UTILITY.FORMAT_ERROR_STACK
);
RAISE;
END place_order;
END order_api;
/
# Python: Call the procedure with connection pooling
import oracledb
pool = oracledb.create_pool(
user="app_user",
password="secret",
dsn="host.example.com:1521/FREEPDB1",
min=2,
max=10,
increment=1,
)
def place_order(customer_id: int, product_id: int, quantity: int) -> int:
with pool.acquire() as conn:
with conn.cursor() as cur:
order_id = cur.var(oracledb.NUMBER)
cur.callproc("order_api.place_order", [
customer_id, product_id, quantity, order_id,
])
conn.commit()
return int(order_id.getvalue())
# Usage
new_order_id = place_order(customer_id=42, product_id=101, quantity=5)
print(f"Created order: {new_order_id}")
</example>
For detailed guides and code examples, refer to the following documents in references/: