diff --git a/Oracle_dataset/online-ecommerce1/README.md b/Oracle_dataset/online-ecommerce1/README.md index 2a6dc54..fdae453 100644 --- a/Oracle_dataset/online-ecommerce1/README.md +++ b/Oracle_dataset/online-ecommerce1/README.md @@ -1,13 +1,20 @@ # Oracle E-commerce and Accounting Workload -This project contains three SQL*Plus/SQLcl scripts for creating and exercising -an Oracle e-commerce and accounting schema. +This project contains SQL*Plus/SQLcl scripts for creating and exercising an +Oracle e-commerce and accounting schema, including background workload jobs. ## Requirements - Oracle Database 12c or later. The schema uses identity columns and daily interval partitioning. - Run the scripts while connected as the schema owner. +- The Scheduler management procedures require the schema owner to have the + `CREATE JOB` system privilege. A DBA can grant it directly: + + ```sql + GRANT CREATE JOB TO your_schema; + ``` + - The activity procedure uses `DBMS_LOCK.SLEEP`. The schema owner may need a direct grant from a DBA: @@ -25,11 +32,13 @@ Run these scripts in order from SQL*Plus or SQLcl: @oracle_ecommerce_schema.sql @oracle_ecommerce_seed_2gb.sql @oracle_ecommerce_activity.sql +@oracle_ecommerce_job_management.sql ``` The schema script creates objects only. The seed script expects the schema to -be empty and should be run once. The activity script creates or replaces the -workload procedure and can be rerun to install procedure changes. +be empty and should be run once. The activity and job-management scripts +create or replace their procedures and can be rerun to install procedure +changes. ## `oracle_ecommerce_schema.sql` @@ -110,3 +119,46 @@ EXEC simulate_commerce_activity(100, 2, 5.5); The procedure prints a one-line summary for each iteration and a final total and realized average. `DBMS_OUTPUT` is buffered, so SQL*Plus/SQLcl may display the output after the procedure completes. + +## `oracle_ecommerce_job_management.sql` + +Creates four procedures for managing one-time Oracle Scheduler jobs that run +`SIMULATE_COMMERCE_ACTIVITY` asynchronously. A created job is enabled +immediately, starts as soon as Scheduler can run it, executes the specified +number of iterations, and remains in the schema's Scheduler job list after +completion (`AUTO_DROP` is disabled). + +```sql +SET SERVEROUTPUT ON + +-- Create a background job: name, iterations, seconds between iterations, +-- average DML rows per iteration. +EXEC create_commerce_activity_job('COMMERCE_LOAD_01', 10000, 3, 5.5); + +-- List Scheduler jobs for SIMULATE_COMMERCE_ACTIVITY. +EXEC list_commerce_activity_jobs; + +-- Stop and disable a pending or running job; it remains listed. +EXEC stop_commerce_activity_job('COMMERCE_LOAD_01'); + +-- Remove the job. FORCE also stops it if it is still running. +EXEC remove_commerce_activity_job('COMMERCE_LOAD_01'); +``` + +The list procedure reports the job state, enabled status, run/failure counts, +and last start time. `STOP` disables the job and force-stops it if running; +it does not resume automatically. `REMOVE` drops the job and force-stops it +if necessary. These operations apply to jobs owned by the connected schema. + +For run history and Scheduler error messages, query the job run details view: + +```sql +SELECT log_date, status, error#, additional_info +FROM user_scheduler_job_run_details +WHERE job_name = 'COMMERCE_LOAD_01' +ORDER BY log_date DESC; +``` + +The activity procedure's `DBMS_OUTPUT` is generated in the Scheduler worker +session and is not normally returned to the session that submitted the job. +Use Scheduler run details to inspect completion status and errors. diff --git a/Oracle_dataset/online-ecommerce1/oracle_ecommerce_job_management.sql b/Oracle_dataset/online-ecommerce1/oracle_ecommerce_job_management.sql new file mode 100644 index 0000000..6250c01 --- /dev/null +++ b/Oracle_dataset/online-ecommerce1/oracle_ecommerce_job_management.sql @@ -0,0 +1,170 @@ +-- Scheduler helpers for running SIMULATE_COMMERCE_ACTIVITY asynchronously. +-- Run as the schema owner after oracle_ecommerce_activity.sql. +-- The schema owner needs the CREATE JOB system privilege. + +WHENEVER SQLERROR EXIT SQL.SQLCODE +SET DEFINE OFF +SET SERVEROUTPUT ON SIZE UNLIMITED + +CREATE OR REPLACE PROCEDURE create_commerce_activity_job ( + p_job_name IN VARCHAR2, + p_iterations IN PLS_INTEGER, + p_seconds_between_iterations IN NUMBER, + p_average_rows_per_iteration IN NUMBER +) AS + l_job_name VARCHAR2(128); +BEGIN + IF p_job_name IS NULL OR TRIM(p_job_name) IS NULL THEN + RAISE_APPLICATION_ERROR(-20010, 'p_job_name must not be empty'); + END IF; + l_job_name := DBMS_ASSERT.SIMPLE_SQL_NAME(UPPER(TRIM(p_job_name))); + + IF p_iterations IS NULL OR p_iterations < 0 THEN + RAISE_APPLICATION_ERROR(-20011, '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(-20012, '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(-20013, 'p_average_rows_per_iteration must be between 0 and 10000'); + END IF; + + DBMS_SCHEDULER.CREATE_JOB( + job_name => l_job_name, + job_type => 'STORED_PROCEDURE', + job_action => 'SIMULATE_COMMERCE_ACTIVITY', + number_of_arguments => 3, + start_date => SYSTIMESTAMP, + enabled => FALSE, + auto_drop => FALSE, + comments => 'Background e-commerce activity simulation' + ); + + DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE( + job_name => l_job_name, + argument_position => 1, + argument_value => TO_CHAR(p_iterations, 'TM9', 'NLS_NUMERIC_CHARACTERS=''.,''') + ); + DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE( + job_name => l_job_name, + argument_position => 2, + argument_value => TO_CHAR( + p_seconds_between_iterations, 'TM9', 'NLS_NUMERIC_CHARACTERS=''.,''' + ) + ); + DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE( + job_name => l_job_name, + argument_position => 3, + argument_value => TO_CHAR( + p_average_rows_per_iteration, 'TM9', 'NLS_NUMERIC_CHARACTERS=''.,''' + ) + ); + + DBMS_SCHEDULER.ENABLE(l_job_name); + DBMS_OUTPUT.PUT_LINE( + 'Enabled Scheduler job ' || l_job_name || + ' to run SIMULATE_COMMERCE_ACTIVITY in the background.' + ); +END; +/ + +CREATE OR REPLACE PROCEDURE list_commerce_activity_jobs AS + l_jobs_found PLS_INTEGER := 0; +BEGIN + DBMS_OUTPUT.PUT_LINE( + RPAD('JOB NAME', 32) || RPAD('STATE', 16) || + RPAD('ENABLED', 10) || RPAD('RUNS', 8) || + RPAD('FAILURES', 10) || 'LAST START' + ); + DBMS_OUTPUT.PUT_LINE(RPAD('-', 100, '-')); + + FOR job_rec IN ( + SELECT job_name, state, enabled, run_count, failure_count, last_start_date + FROM user_scheduler_jobs + WHERE job_type = 'STORED_PROCEDURE' + AND job_action = 'SIMULATE_COMMERCE_ACTIVITY' + ORDER BY job_name + ) LOOP + l_jobs_found := l_jobs_found + 1; + DBMS_OUTPUT.PUT_LINE( + RPAD(job_rec.job_name, 32) || + RPAD(job_rec.state, 16) || + RPAD(CASE WHEN job_rec.enabled = 'TRUE' THEN 'YES' ELSE 'NO' END, 10) || + RPAD(TO_CHAR(job_rec.run_count), 8) || + RPAD(TO_CHAR(job_rec.failure_count), 10) || + NVL( + TO_CHAR(job_rec.last_start_date, 'YYYY-MM-DD HH24:MI:SS TZH:TZM'), + 'never' + ) + ); + END LOOP; + + IF l_jobs_found = 0 THEN + DBMS_OUTPUT.PUT_LINE('No SIMULATE_COMMERCE_ACTIVITY Scheduler jobs found.'); + END IF; +END; +/ + +CREATE OR REPLACE PROCEDURE stop_commerce_activity_job ( + p_job_name IN VARCHAR2 +) AS + l_job_name VARCHAR2(128); + l_job_count PLS_INTEGER; +BEGIN + IF p_job_name IS NULL OR TRIM(p_job_name) IS NULL THEN + RAISE_APPLICATION_ERROR(-20020, 'p_job_name must not be empty'); + END IF; + l_job_name := DBMS_ASSERT.SIMPLE_SQL_NAME(UPPER(TRIM(p_job_name))); + + SELECT COUNT(*) + INTO l_job_count + FROM user_scheduler_jobs + WHERE job_name = l_job_name + AND job_type = 'STORED_PROCEDURE' + AND job_action = 'SIMULATE_COMMERCE_ACTIVITY'; + IF l_job_count = 0 THEN + RAISE_APPLICATION_ERROR(-20021, 'No activity Scheduler job named ' || l_job_name); + END IF; + + DBMS_SCHEDULER.DISABLE( + name => l_job_name, + force => TRUE + ); + DBMS_OUTPUT.PUT_LINE('Stopped and disabled Scheduler job ' || l_job_name || '.'); +END; +/ + +CREATE OR REPLACE PROCEDURE remove_commerce_activity_job ( + p_job_name IN VARCHAR2 +) AS + l_job_name VARCHAR2(128); + l_job_count PLS_INTEGER; +BEGIN + IF p_job_name IS NULL OR TRIM(p_job_name) IS NULL THEN + RAISE_APPLICATION_ERROR(-20030, 'p_job_name must not be empty'); + END IF; + l_job_name := DBMS_ASSERT.SIMPLE_SQL_NAME(UPPER(TRIM(p_job_name))); + + SELECT COUNT(*) + INTO l_job_count + FROM user_scheduler_jobs + WHERE job_name = l_job_name + AND job_type = 'STORED_PROCEDURE' + AND job_action = 'SIMULATE_COMMERCE_ACTIVITY'; + IF l_job_count = 0 THEN + RAISE_APPLICATION_ERROR(-20031, 'No activity Scheduler job named ' || l_job_name); + END IF; + + DBMS_SCHEDULER.DROP_JOB( + job_name => l_job_name, + force => TRUE + ); + DBMS_OUTPUT.PUT_LINE('Removed Scheduler job ' || l_job_name || '.'); +END; +/ + +SHOW ERRORS PROCEDURE create_commerce_activity_job +SHOW ERRORS PROCEDURE list_commerce_activity_jobs +SHOW ERRORS PROCEDURE stop_commerce_activity_job +SHOW ERRORS PROCEDURE remove_commerce_activity_job