2026-09-30 15:59:45

This commit is contained in:
support committed 2026-09-30 17:59:45 +02:00
1 parent d1dc3376bd
commit 4f6a34cfcc
4 files changed
+1216

No files matched your search

@@ -0,0 +1,431 @@
-- Creates a workload procedure for the e-commerce schema.
-- Run as the schema owner after oracle_ecommerce_schema.sql. The workload
-- commits after each iteration so other sessions can observe the activity.
-- DBMS_LOCK.SLEEP may require EXECUTE on SYS.DBMS_LOCK for the schema owner.
-- The average is realized by randomly rounding its fractional part per iteration;
-- each successful insert, update, or delete affects one row. Example:
-- EXEC simulate_commerce_activity(100, 2, 5.5);
WHENEVER SQLERROR EXIT SQL.SQLCODE
SET DEFINE OFF
CREATE OR REPLACE PROCEDURE simulate_commerce_activity (
p_iterations IN PLS_INTEGER,
p_seconds_between_iterations IN NUMBER,
p_average_rows_per_iteration IN NUMBER
) AS
TYPE t_varchar_array IS TABLE OF VARCHAR2(1000) INDEX BY PLS_INTEGER;
l_tables t_varchar_array;
l_update_sets t_varchar_array;
l_delete_tests t_varchar_array;
l_table_index PLS_INTEGER;
l_action PLS_INTEGER;
l_target_rows PLS_INTEGER;
l_rows_done PLS_INTEGER;
l_rows_total NUMBER := 0;
l_rows_this PLS_INTEGER;
l_attempts PLS_INTEGER;
l_rowid UROWID;
l_id1 NUMBER;
l_id2 NUMBER;
l_id3 NUMBER;
l_id4 NUMBER;
l_id5 NUMBER;
l_line_number NUMBER;
l_amount NUMBER(14,2);
FUNCTION random_number(p_table IN VARCHAR2, p_column IN VARCHAR2)
RETURN NUMBER
IS
l_result NUMBER;
BEGIN
EXECUTE IMMEDIATE
'SELECT chosen_value FROM (' ||
' SELECT ' || p_column || ' AS chosen_value FROM ' || p_table ||
' ORDER BY DBMS_RANDOM.VALUE) WHERE ROWNUM = 1'
INTO l_result;
RETURN l_result;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END random_number;
FUNCTION random_rowid(p_table IN VARCHAR2, p_filter IN VARCHAR2)
RETURN UROWID
IS
l_result UROWID;
l_sql VARCHAR2(2000);
BEGIN
l_sql :=
'SELECT chosen_rowid FROM (' ||
' SELECT ROWID AS chosen_rowid FROM ' || p_table ||
' WHERE ' || NVL(p_filter, '1 = 1') ||
' ORDER BY DBMS_RANDOM.VALUE) WHERE ROWNUM = 1';
EXECUTE IMMEDIATE l_sql INTO l_result;
RETURN l_result;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RETURN NULL;
END random_rowid;
PROCEDURE do_one_activity (
p_table_index IN PLS_INTEGER,
p_action IN PLS_INTEGER,
p_row_count OUT PLS_INTEGER
) IS
BEGIN
p_row_count := 0;
l_id1 := NULL;
l_id2 := NULL;
l_id3 := NULL;
l_id4 := NULL;
l_id5 := NULL;
IF p_action = 1 THEN
CASE p_table_index
WHEN 1 THEN
l_id1 := random_number('sales_order_lines', 'order_line_id');
l_id2 := random_number('customers', 'customer_id');
IF l_id1 IS NOT NULL AND l_id2 IS NOT NULL THEN
INSERT INTO returns (
returned_at, order_line_id, customer_id, return_status,
quantity, reason_code
) VALUES (
SYSDATE, l_id1, l_id2, 'REQUESTED', 1, 'SIMULATED'
);
p_row_count := SQL%ROWCOUNT;
END IF;
WHEN 2 THEN
l_id1 := random_number('suppliers', 'supplier_id');
l_id2 := random_number('warehouses', 'warehouse_id');
l_id3 := random_number('currencies', 'currency_id');
IF l_id1 IS NOT NULL AND l_id2 IS NOT NULL AND l_id3 IS NOT NULL THEN
INSERT INTO purchase_orders (
ordered_at, supplier_id, warehouse_id, currency_id, purchase_status
) VALUES (
SYSDATE, l_id1, l_id2, l_id3, 'DRAFT'
);
p_row_count := SQL%ROWCOUNT;
END IF;
WHEN 3 THEN
l_id1 := random_number('purchase_orders', 'purchase_order_id');
l_id2 := random_number('products', 'product_id');
IF l_id1 IS NOT NULL AND l_id2 IS NOT NULL THEN
SELECT NVL(MAX(line_number), 0) + 1
INTO l_line_number
FROM purchase_order_lines
WHERE purchase_order_id = l_id1;
IF l_line_number <= 9999 THEN
INSERT INTO purchase_order_lines (
purchase_order_id, product_id, line_number, quantity, unit_cost
) VALUES (
l_id1, l_id2, l_line_number, 1, ROUND(DBMS_RANDOM.VALUE(1, 300), 2)
);
p_row_count := SQL%ROWCOUNT;
END IF;
END IF;
WHEN 4 THEN
l_id1 := random_number('product_categories', 'category_id');
l_id2 := random_number('suppliers', 'supplier_id');
IF l_id1 IS NOT NULL AND l_id2 IS NOT NULL THEN
INSERT INTO products (
category_id, supplier_id, sku, product_name, unit_price, product_status
) VALUES (
l_id1, l_id2, 'SIM-' || RAWTOHEX(SYS_GUID()),
'Simulated product', ROUND(DBMS_RANDOM.VALUE(1, 500), 2), 'ACTIVE'
);
p_row_count := SQL%ROWCOUNT;
END IF;
WHEN 5 THEN
l_id1 := random_number('customers', 'customer_id');
IF l_id1 IS NOT NULL THEN
INSERT INTO customer_addresses (
customer_id, address_type, address_line1, city, country_code, is_default
) VALUES (
l_id1, 'BOTH', '1 Simulation Way', 'Simulated City', 'US', 'N'
);
p_row_count := SQL%ROWCOUNT;
END IF;
WHEN 6 THEN
l_id1 := random_number('sales_orders', 'order_id');
l_id2 := random_number('warehouses', 'warehouse_id');
IF l_id1 IS NOT NULL AND l_id2 IS NOT NULL THEN
INSERT INTO shipments (
shipped_at, order_id, warehouse_id, tracking_number,
carrier_name, shipment_status
) VALUES (
SYSDATE, l_id1, l_id2, 'SIM-' || RAWTOHEX(SYS_GUID()),
'Simulation Carrier', 'CREATED'
);
p_row_count := SQL%ROWCOUNT;
END IF;
WHEN 7 THEN
l_id1 := random_number('sales_orders', 'order_id');
l_id2 := random_number('currencies', 'currency_id');
IF l_id1 IS NOT NULL AND l_id2 IS NOT NULL THEN
INSERT INTO payments (
payment_date, order_id, currency_id, payment_method,
payment_status, amount, provider_reference
) VALUES (
SYSDATE, l_id1, l_id2, 'CARD', 'AUTHORIZED',
ROUND(DBMS_RANDOM.VALUE(1, 1000), 2), 'SIM-' || RAWTOHEX(SYS_GUID())
);
p_row_count := SQL%ROWCOUNT;
END IF;
WHEN 8 THEN
INSERT INTO customers (
email, first_name, last_name, customer_since, customer_status
) VALUES (
'sim-' || RAWTOHEX(SYS_GUID()) || '@example.test',
'Simulated', 'Customer', SYSDATE, 'ACTIVE'
);
p_row_count := SQL%ROWCOUNT;
WHEN 9 THEN
l_id1 := random_number('currencies', 'currency_id');
IF l_id1 IS NOT NULL THEN
INSERT INTO journal_entries (
posted_at, currency_id, source_type, source_id, entry_status, memo
) VALUES (
SYSDATE, l_id1, 'SIMULATION', NULL, 'DRAFT', 'Simulated journal entry'
);
p_row_count := SQL%ROWCOUNT;
END IF;
WHEN 10 THEN
l_id1 := random_number('customers', 'customer_id');
l_id2 := random_number('sales_channels', 'channel_id');
l_id3 := random_number('currencies', 'currency_id');
l_id4 := random_number('customer_addresses', 'address_id');
l_id5 := random_number('customer_addresses', 'address_id');
IF l_id1 IS NOT NULL AND l_id2 IS NOT NULL AND l_id3 IS NOT NULL
AND l_id4 IS NOT NULL AND l_id5 IS NOT NULL THEN
INSERT INTO sales_orders (
order_date, customer_id, channel_id, currency_id,
billing_address_id, shipping_address_id, order_status,
subtotal, tax_amount, shipping_amount
) VALUES (
SYSDATE, l_id1, l_id2, l_id3, l_id4, l_id5,
'PENDING', 0, 0, 0
);
p_row_count := SQL%ROWCOUNT;
END IF;
WHEN 11 THEN
l_id1 := random_number('products', 'product_id');
l_id2 := random_number('warehouses', 'warehouse_id');
IF l_id1 IS NOT NULL AND l_id2 IS NOT NULL THEN
INSERT INTO inventory_movements (
movement_at, product_id, warehouse_id, movement_type,
quantity_delta, reference_note
) VALUES (
SYSDATE, l_id1, l_id2, 'RECEIPT', 1, 'Simulated stock receipt'
);
p_row_count := SQL%ROWCOUNT;
END IF;
WHEN 12 THEN
l_id1 := random_number('shipments', 'shipment_id');
l_id2 := random_number('sales_order_lines', 'order_line_id');
IF l_id1 IS NOT NULL AND l_id2 IS NOT NULL THEN
INSERT INTO shipment_items (shipment_id, order_line_id, quantity)
VALUES (l_id1, l_id2, 1);
p_row_count := SQL%ROWCOUNT;
END IF;
WHEN 13 THEN
l_id1 := random_number('sales_orders', 'order_id');
l_id2 := random_number('products', 'product_id');
IF l_id1 IS NOT NULL AND l_id2 IS NOT NULL THEN
SELECT NVL(MAX(line_number), 0) + 1
INTO l_line_number
FROM sales_order_lines
WHERE order_id = l_id1;
IF l_line_number <= 9999 THEN
INSERT INTO sales_order_lines (
order_id, product_id, line_number, quantity,
unit_price, discount_amount
) VALUES (
l_id1, l_id2, l_line_number, 1,
ROUND(DBMS_RANDOM.VALUE(1, 500), 2), 0
);
p_row_count := SQL%ROWCOUNT;
END IF;
END IF;
WHEN 14 THEN
l_id1 := random_number('journal_entries', 'journal_entry_id');
l_id2 := random_number('gl_accounts', 'account_id');
IF l_id1 IS NOT NULL AND l_id2 IS NOT NULL THEN
SELECT NVL(MAX(line_number), 0) + 1
INTO l_line_number
FROM journal_lines
WHERE journal_entry_id = l_id1;
IF l_line_number <= 9999 THEN
l_amount := ROUND(DBMS_RANDOM.VALUE(1, 1000), 2);
INSERT INTO journal_lines (
journal_entry_id, account_id, line_number,
debit_amount, credit_amount, line_memo
) VALUES (
l_id1, l_id2, l_line_number, l_amount, 0, 'Simulated debit'
);
p_row_count := SQL%ROWCOUNT;
END IF;
END IF;
WHEN 15 THEN
BEGIN
SELECT product_id, warehouse_id
INTO l_id1, l_id2
FROM (
SELECT p.product_id, w.warehouse_id
FROM products p
CROSS JOIN warehouses w
WHERE NOT EXISTS (
SELECT 1
FROM inventory_balances b
WHERE b.product_id = p.product_id
AND b.warehouse_id = w.warehouse_id
)
ORDER BY DBMS_RANDOM.VALUE
)
WHERE ROWNUM = 1;
INSERT INTO inventory_balances (
product_id, warehouse_id, quantity_on_hand,
quantity_reserved, last_counted_at
) VALUES (
l_id1, l_id2, 1, 0, SYSDATE
);
p_row_count := SQL%ROWCOUNT;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
END;
WHEN 16 THEN
l_id1 := random_number('customers', 'customer_id');
INSERT INTO audit_events (
event_at, actor_customer_id, event_type, source_ip, details
) VALUES (
SYSDATE, l_id1, 'SIMULATED_ACTIVITY', '192.0.2.1',
'Generated by SIMULATE_COMMERCE_ACTIVITY'
);
p_row_count := SQL%ROWCOUNT;
END CASE;
ELSIF p_action = 2 THEN
l_rowid := random_rowid(l_tables(p_table_index), NULL);
IF l_rowid IS NOT NULL THEN
EXECUTE IMMEDIATE
'UPDATE ' || l_tables(p_table_index) ||
' SET ' || l_update_sets(p_table_index) ||
' WHERE ROWID = :selected_rowid'
USING l_rowid;
p_row_count := SQL%ROWCOUNT;
END IF;
ELSE
l_rowid := random_rowid(
l_tables(p_table_index), l_delete_tests(p_table_index)
);
IF l_rowid IS NOT NULL THEN
EXECUTE IMMEDIATE
'DELETE FROM ' || l_tables(p_table_index) ||
' WHERE ROWID = :selected_rowid'
USING l_rowid;
p_row_count := SQL%ROWCOUNT;
END IF;
END IF;
END do_one_activity;
BEGIN
IF p_iterations IS NULL OR p_iterations < 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'p_iterations must be a non-negative integer');
END IF;
IF p_seconds_between_iterations IS NULL OR p_seconds_between_iterations < 0 THEN
RAISE_APPLICATION_ERROR(-20002, 'p_seconds_between_iterations must be non-negative');
END IF;
IF p_average_rows_per_iteration IS NULL OR p_average_rows_per_iteration < 0
OR p_average_rows_per_iteration > 10000 THEN
RAISE_APPLICATION_ERROR(-20003, 'p_average_rows_per_iteration must be between 0 and 10000');
END IF;
l_tables(1) := 'RETURNS';
l_tables(2) := 'PURCHASE_ORDERS';
l_tables(3) := 'PURCHASE_ORDER_LINES';
l_tables(4) := 'PRODUCTS';
l_tables(5) := 'CUSTOMER_ADDRESSES';
l_tables(6) := 'SHIPMENTS';
l_tables(7) := 'PAYMENTS';
l_tables(8) := 'CUSTOMERS';
l_tables(9) := 'JOURNAL_ENTRIES';
l_tables(10) := 'SALES_ORDERS';
l_tables(11) := 'INVENTORY_MOVEMENTS';
l_tables(12) := 'SHIPMENT_ITEMS';
l_tables(13) := 'SALES_ORDER_LINES';
l_tables(14) := 'JOURNAL_LINES';
l_tables(15) := 'INVENTORY_BALANCES';
l_tables(16) := 'AUDIT_EVENTS';
l_update_sets(1) := 'return_status = CASE return_status WHEN ''REQUESTED'' THEN ''APPROVED'' ELSE ''REQUESTED'' END';
l_update_sets(2) := 'purchase_status = CASE purchase_status WHEN ''DRAFT'' THEN ''ORDERED'' WHEN ''ORDERED'' THEN ''RECEIVED'' ELSE ''DRAFT'' END';
l_update_sets(3) := 'quantity = quantity + 1';
l_update_sets(4) := 'unit_price = unit_price + 1, product_status = CASE product_status WHEN ''ACTIVE'' THEN ''DISCONTINUED'' ELSE ''ACTIVE'' END';
l_update_sets(5) := 'city = SUBSTR(city || ''X'', 1, 80)';
l_update_sets(6) := 'shipment_status = CASE shipment_status WHEN ''CREATED'' THEN ''IN_TRANSIT'' WHEN ''IN_TRANSIT'' THEN ''DELIVERED'' ELSE ''CREATED'' END';
l_update_sets(7) := 'payment_status = CASE payment_status WHEN ''AUTHORIZED'' THEN ''CAPTURED'' WHEN ''CAPTURED'' THEN ''REFUNDED'' ELSE ''AUTHORIZED'' END';
l_update_sets(8) := 'phone_number = ''SIM-'' || TO_CHAR(TRUNC(DBMS_RANDOM.VALUE(100000, 999999))), customer_status = CASE customer_status WHEN ''ACTIVE'' THEN ''INACTIVE'' ELSE ''ACTIVE'' END';
l_update_sets(9) := 'entry_status = CASE entry_status WHEN ''DRAFT'' THEN ''POSTED'' WHEN ''POSTED'' THEN ''VOID'' ELSE ''DRAFT'' END, memo = SUBSTR(memo || '' *'', 1, 240)';
l_update_sets(10) := 'order_status = CASE order_status WHEN ''PENDING'' THEN ''PAID'' WHEN ''PAID'' THEN ''FULFILLED'' ELSE ''PENDING'' END, subtotal = subtotal + 1';
l_update_sets(11) := 'quantity_delta = -quantity_delta, reference_note = ''Simulated movement update''';
l_update_sets(12) := 'quantity = quantity + 1';
l_update_sets(13) := 'quantity = quantity + 1';
l_update_sets(14) := 'debit_amount = CASE WHEN debit_amount > 0 THEN debit_amount + 1 ELSE 0 END, credit_amount = CASE WHEN credit_amount > 0 THEN credit_amount + 1 ELSE 0 END';
l_update_sets(15) := 'quantity_on_hand = quantity_on_hand + 1, last_counted_at = SYSDATE';
l_update_sets(16) := 'details = SUBSTR(details || ''x'', 1, 2000)';
l_delete_tests(1) := '1 = 1';
l_delete_tests(2) := 'NOT EXISTS (SELECT 1 FROM purchase_order_lines x WHERE x.purchase_order_id = purchase_orders.purchase_order_id)';
l_delete_tests(3) := '1 = 1';
l_delete_tests(4) := 'NOT EXISTS (SELECT 1 FROM sales_order_lines x WHERE x.product_id = products.product_id) AND NOT EXISTS (SELECT 1 FROM inventory_balances x WHERE x.product_id = products.product_id) AND NOT EXISTS (SELECT 1 FROM inventory_movements x WHERE x.product_id = products.product_id) AND NOT EXISTS (SELECT 1 FROM purchase_order_lines x WHERE x.product_id = products.product_id)';
l_delete_tests(5) := 'NOT EXISTS (SELECT 1 FROM sales_orders x WHERE x.billing_address_id = customer_addresses.address_id OR x.shipping_address_id = customer_addresses.address_id)';
l_delete_tests(6) := 'NOT EXISTS (SELECT 1 FROM shipment_items x WHERE x.shipment_id = shipments.shipment_id)';
l_delete_tests(7) := '1 = 1';
l_delete_tests(8) := 'NOT EXISTS (SELECT 1 FROM customer_addresses x WHERE x.customer_id = customers.customer_id) AND NOT EXISTS (SELECT 1 FROM sales_orders x WHERE x.customer_id = customers.customer_id) AND NOT EXISTS (SELECT 1 FROM returns x WHERE x.customer_id = customers.customer_id) AND NOT EXISTS (SELECT 1 FROM audit_events x WHERE x.actor_customer_id = customers.customer_id)';
l_delete_tests(9) := 'NOT EXISTS (SELECT 1 FROM journal_lines x WHERE x.journal_entry_id = journal_entries.journal_entry_id)';
l_delete_tests(10) := 'NOT EXISTS (SELECT 1 FROM sales_order_lines x WHERE x.order_id = sales_orders.order_id) AND NOT EXISTS (SELECT 1 FROM payments x WHERE x.order_id = sales_orders.order_id) AND NOT EXISTS (SELECT 1 FROM shipments x WHERE x.order_id = sales_orders.order_id)';
l_delete_tests(11) := '1 = 1';
l_delete_tests(12) := '1 = 1';
l_delete_tests(13) := 'NOT EXISTS (SELECT 1 FROM shipment_items x WHERE x.order_line_id = sales_order_lines.order_line_id) AND NOT EXISTS (SELECT 1 FROM inventory_movements x WHERE x.order_line_id = sales_order_lines.order_line_id) AND NOT EXISTS (SELECT 1 FROM returns x WHERE x.order_line_id = sales_order_lines.order_line_id)';
l_delete_tests(14) := '1 = 1';
l_delete_tests(15) := '1 = 1';
l_delete_tests(16) := '1 = 1';
FOR iteration_no IN 1 .. p_iterations LOOP
l_target_rows := TRUNC(p_average_rows_per_iteration);
IF DBMS_RANDOM.VALUE(0, 1) <
p_average_rows_per_iteration - TRUNC(p_average_rows_per_iteration) THEN
l_target_rows := l_target_rows + 1;
END IF;
l_rows_done := 0;
l_attempts := 0;
WHILE l_rows_done < l_target_rows AND l_attempts < (l_target_rows * 20 + 100) LOOP
l_table_index := TRUNC(DBMS_RANDOM.VALUE(1, 17));
l_action := TRUNC(DBMS_RANDOM.VALUE(1, 4));
do_one_activity(l_table_index, l_action, l_rows_this);
l_rows_done := l_rows_done + l_rows_this;
l_attempts := l_attempts + 1;
END LOOP;
COMMIT;
l_rows_total := l_rows_total + l_rows_done;
DBMS_OUTPUT.PUT_LINE(
'Iteration ' || iteration_no || ': ' || l_rows_done ||
' row(s) affected (target ' || l_target_rows || ')'
);
IF iteration_no < p_iterations AND p_seconds_between_iterations > 0 THEN
DBMS_LOCK.SLEEP(p_seconds_between_iterations);
END IF;
END LOOP;
IF p_iterations > 0 THEN
DBMS_OUTPUT.PUT_LINE(
'Total rows affected: ' || l_rows_total ||
'; actual average per iteration: ' || ROUND(l_rows_total / p_iterations, 2)
);
END IF;
END;
/
SHOW ERRORS PROCEDURE simulate_commerce_activity