skills/oracle/SKILL.md
Use when working with Oracle Database, Oracle SQL, PL/SQL, sqlplus, cx_Oracle, oracledb, ORDS, OCI drivers, Oracle containers, schema migrations, security, vectors, or performance tuning.
npx skillsauth add cofin/flow oracleInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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/:
testing
Use when syncing Beads state to markdown, checking Flow status, refreshing context docs, validating task markers, or reporting ready/blocked Flow work.
testing
Use when initializing Flow in a repo, configuring .agents, installing or checking Beads bd, setting local-only sync policy, or creating first project context files.
data-ai
Use when drafting PRDs, researching, planning, refining, revising, or creating .agents/specs/<flow_id>/spec.md worksheets for Flow.
testing
Use when implementing Flow tasks from Beads or spec.md, claiming ready work, applying TDD, recording task notes, committing, and syncing after task state changes.