Modifications:
Script to Re-submit Batch ID 3
Below is a script to reset and re-submit the task for batch_id = 3 in the background, including UPDATE statements and a scheduler job creation.
sql
SET SERVEROUTPUT ON;
-- Step 1: Identify tablespace for batch_id = 3
BEGIN
DBMS_OUTPUT.PUT_LINE('Checking tablespace for batch_id = 3:');
FOR rec IN (
SELECT tablespace_name, initial_size_gb, batch_id, status, retry_count
FROM tablespace_control
WHERE batch_id = 3
) LOOP
DBMS_OUTPUT.PUT_LINE('Tablespace: ' || rec.tablespace_name ||
', Size: ' || rec.initial_size_gb || ' GB, Status: ' || rec.status ||
', Retry Count: ' || rec.retry_count);
END LOOP;
END;
/
-- Step 2: Reset status to PENDING for batch_id = 3
BEGIN
UPDATE tablespace_control
SET status = 'PENDING', retry_count = 0, last_attempt = NULL
WHERE batch_id = 3;
COMMIT;
DBMS_OUTPUT.PUT_LINE(SQL%ROWCOUNT || ' tablespaces reset to PENDING for batch_id = 3.');
END;
/
-- Step 3: Create scheduler job for batch_id = 3
DECLARE
v_job_name VARCHAR2(30);
v_created_count NUMBER := 0;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
-- Drop existing job for batch_id = 3 if it exists
FOR rec IN (
SELECT tablespace_name
FROM tablespace_control
WHERE batch_id = 3
) LOOP
v_job_name := UPPER(USER) || '.CREATE_TS_' || rec.tablespace_name;
BEGIN
DBMS_SCHEDULER.DROP_JOB(job_name => v_job_name, force => TRUE);
DBMS_OUTPUT.PUT_LINE('Dropped existing job: ' || v_job_name);
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -27475 THEN -- Job does not exist
DBMS_OUTPUT.PUT_LINE('Job ' || v_job_name || ' does not exist, proceeding to create.');
ELSE
RAISE;
END IF;
END;
END LOOP;
-- Create new scheduler job for batch_id = 3
FOR rec IN (
SELECT tablespace_name, initial_size_gb, batch_id
FROM tablespace_control
WHERE batch_id = 3
AND status = 'PENDING'
) LOOP
v_job_name := UPPER(USER) || '.CREATE_TS_' || rec.tablespace_name;
DBMS_OUTPUT.PUT_LINE('Creating job for tablespace: ' || rec.tablespace_name);
DBMS_SCHEDULER.CREATE_JOB(
job_name => v_job_name,
job_type => 'STORED_PROCEDURE',
job_action => 'CREATE_SINGLE_TABLESPACE',
number_of_arguments => 3,
start_date => SYSTIMESTAMP,
repeat_interval => NULL,
enabled => FALSE,
auto_drop => FALSE,
comments => 'Retry bigfile tablespace ' || rec.tablespace_name
);
-- Set arguments: p_tablespace_name, p_initial_size_gb, p_batch_id
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => v_job_name,
argument_position => 1,
argument_value => rec.tablespace_name
);
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => v_job_name,
argument_position => 2,
argument_value => TO_CHAR(rec.initial_size_gb)
);
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => v_job_name,
argument_position => 3,
argument_value => TO_CHAR(rec.batch_id)
);
-- Enable the job
DBMS_SCHEDULER.ENABLE(v_job_name);
DBMS_OUTPUT.PUT_LINE('Submitted and enabled job ' || v_job_name || ' for tablespace ' || rec.tablespace_name);
v_created_count := v_created_count + 1;
END LOOP;
IF v_created_count = 0 THEN
DBMS_OUTPUT.PUT_LINE('No jobs created for batch_id = 3; check tablespace_control status.');
ELSE
DBMS_OUTPUT.PUT_LINE(v_created_count || ' job(s) created for batch_id = 3.');
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating job for batch_id = 3: ' || SQLERRM);
RAISE;
END;
/
Monitoring After Retry
Monitor the retry attempt with these queries:
- Check tablespace_log:
sql
SELECT tablespace_name, batch_id, action, status, error_message, start_time, end_time,
ROUND(
EXTRACT(DAY FROM (end_time - start_time)) * 1440 +
EXTRACT(HOUR FROM (end_time - start_time)) * 60 +
EXTRACT(MINUTE FROM (end_time - start_time)) +
EXTRACT(SECOND FROM (end_time - start_time)) / 60,
2
) AS duration_minutes
FROM tablespace_log
WHERE batch_id = 3
AND action = 'CREATE'
ORDER BY start_time DESC;
- Check tablespace_monitor:
sql
SELECT tablespace_name, batch_id, status, log_status, error_message, start_time, end_time
FROM tablespace_monitor
WHERE batch_id = 3
AND action_status IN ('Failed', 'Long Running')
ORDER BY batch_id;
- Check Scheduler Job:
sql
SELECT job_name, state, run_count, failure_count
FROM DBA_SCHEDULER_JOBS
WHERE job_name LIKE UPPER(USER) || '.CREATE_TS_%' AND job_name LIKE '%TS_PROD_03%'; -- Adjust for your tablespace name
SELECT job_name, status, error#, error_msg
FROM DBA_SCHEDULER_JOB_RUN_DETAILS
WHERE job_name LIKE UPPER(USER) || '.CREATE_TS_%' AND job_name LIKE '%TS_PROD_03%';
Notes
- Batch ID 3: The script targets only batch_id = 3, resetting its status to PENDING and creating a scheduler job to retry in the background.
- Tablespace Name: The script uses the tablespace name from tablespace_control for batch_id = 3 (e.g., TS_PROD_03 in v1.0 or a custom name like FTI_DATA_03 if using the modified Step 4). Update the monitoring queries with your exact tablespace name if different.
- Disk Space: Since batch_id = 3 failed due to a disk space issue (addressed in a previous discussion), ensure sufficient disk space (e.g., 50 GB for TS_PROD_03 or your custom size) is available:
sql
SELECT SUM(bytes)/1024/1024/1024 AS free_space_gb FROM dba_free_space;
- Fallback: If the job fails again (e.g., ORA-01031), run manually:
sql
EXEC create_single_tablespace('TS_PROD_03', 50, 3); -- Replace with your tablespace name and size
Run the script to retry batch_id = 3 and monitor the results. If you share the exact tablespace name for batch_id = 3, I can refine the script further!
-- Step 4: Define and populate tablespaces with dynamic names and automatic batch_id
DECLARE
TYPE t_tablespace IS RECORD (
tablespace_name VARCHAR2(30),
initial_size_gb NUMBER
);
TYPE t_tablespace_list IS TABLE OF t_tablespace;
v_tablespaces t_tablespace_list := t_tablespace_list(
t_tablespace('FTI_DATA_01', 10),
t_tablespace('FTO_INDEX_01', 20),
t_tablespace('FL8_APP_01', 50),
t_tablespace('FTI_DATA_02', 15),
t_tablespace('FTO_INDEX_02', 30),
t_tablespace('FL8_APP_02', 25),
t_tablespace('FTI_DATA_03', 40),
t_tablespace('FTO_INDEX_03', 60),
t_tablespace('FL8_APP_03', 12),
t_tablespace('FTI_DATA_04', 18),
t_tablespace('FTO_INDEX_04', 45),
t_tablespace('FL8_APP_04', 55),
t_tablespace('FTI_DATA_05', 10),
t_tablespace('FTO_INDEX_05', 20),
t_tablespace('FL8_APP_05', 50),
t_tablespace('FTI_DATA_06', 15),
t_tablespace('FTO_INDEX_06', 30),
t_tablespace('FL8_APP_06', 25),
t_tablespace('FTI_DATA_07', 40),
t_tablespace('FTO_INDEX_07', 60),
t_tablespace('FL8_APP_07', 12),
t_tablespace('FTI_DATA_08', 18),
t_tablespace('FTO_INDEX_08', 45),
t_tablespace('FL8_APP_08', 55)
);
v_inserted_count NUMBER := 0;
v_max_batch_id NUMBER;
BEGIN
-- Get the maximum batch_id from tablespace_control, default to 0 if none exists
BEGIN
SELECT NVL(MAX(batch_id), 0)
INTO v_max_batch_id
FROM tablespace_control;
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_max_batch_id := 0;
END;
-- Insert tablespaces with incremental batch_id
FOR i IN 1..v_tablespaces.COUNT LOOP
MERGE INTO tablespace_control t
USING (SELECT v_tablespaces(i).tablespace_name AS tablespace_name,
v_tablespaces(i).initial_size_gb AS initial_size_gb,
v_max_batch_id + i AS batch_id
FROM DUAL) s
ON (t.tablespace_name = s.tablespace_name)
WHEN NOT MATCHED THEN
INSERT (tablespace_name, initial_size_gb, batch_id)
VALUES (s.tablespace_name, s.initial_size_gb, s.batch_id);
IF SQL%ROWCOUNT > 0 THEN
v_inserted_count := v_inserted_count + 1;
END IF;
END LOOP;
COMMIT;
DBMS_OUTPUT.PUT_LINE('Populated tablespace_control with ' || v_inserted_count || ' new tablespaces starting from batch_id ' || (v_max_batch_id + 1));
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('Error populating tablespace_control: ' || SQLERRM);
RAISE;
END;
/
-- Step 5: Create scheduler jobs for each tablespace using CREATE_SINGLE_TABLESPACE
DECLARE
v_job_name VARCHAR2(30);
v_created_count NUMBER := 0;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
-- Drop existing scheduler jobs
DBMS_OUTPUT.PUT_LINE('Dropping existing scheduler jobs:');
FOR job_rec IN (
SELECT JOB_NAME
FROM DBA_SCHEDULER_JOBS
WHERE JOB_NAME LIKE UPPER(USER) || '.CREATE_TS_%'
) LOOP
DBMS_SCHEDULER.DROP_JOB(job_name => job_rec.JOB_NAME, force => TRUE);
DBMS_OUTPUT.PUT_LINE('Dropped job: ' || job_rec.JOB_NAME);
v_created_count := v_created_count + 1;
END LOOP;
IF v_created_count = 0 THEN
DBMS_OUTPUT.PUT_LINE('No existing scheduler jobs found.');
ELSE
DBMS_OUTPUT.PUT_LINE(v_created_count || ' existing scheduler jobs dropped.');
END IF;
v_created_count := 0;
-- Create scheduler jobs for each tablespace
DBMS_OUTPUT.PUT_LINE('Creating scheduler jobs for tablespaces:');
FOR rec IN (
SELECT tablespace_name, initial_size_gb, batch_id
FROM tablespace_control
WHERE batch_id IS NOT NULL
ORDER BY batch_id
) LOOP
v_job_name := UPPER(USER) || '.CREATE_TS_' || rec.tablespace_name;
DBMS_OUTPUT.PUT_LINE('Creating job for tablespace: ' || rec.tablespace_name);
DBMS_SCHEDULER.CREATE_JOB(
job_name => v_job_name,
job_type => 'STORED_PROCEDURE',
job_action => 'CREATE_SINGLE_TABLESPACE',
number_of_arguments => 3,
start_date => SYSTIMESTAMP,
repeat_interval => NULL,
enabled => FALSE,
auto_drop => FALSE,
comments => 'Create bigfile tablespace ' || rec.tablespace_name
);
-- Set arguments: p_tablespace_name, p_initial_size_gb, p_batch_id
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => v_job_name,
argument_position => 1,
argument_value => rec.tablespace_name
);
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => v_job_name,
argument_position => 2,
argument_value => TO_CHAR(rec.initial_size_gb)
);
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => v_job_name,
argument_position => 3,
argument_value => TO_CHAR(rec.batch_id)
);
-- Enable the job
DBMS_SCHEDULER.ENABLE(v_job_name);
DBMS_OUTPUT.PUT_LINE('Submitted and enabled job ' || v_job_name || ' for tablespace ' || rec.tablespace_name);
v_created_count := v_created_count + 1;
END LOOP;
IF v_created_count = 0 THEN
DBMS_OUTPUT.PUT_LINE('No new scheduler jobs created; all tablespaces may already have jobs.');
ELSE
DBMS_OUTPUT.PUT_LINE(v_created_count || ' new scheduler jobs submitted and enabled for parallel execution. Monitor with DBA_SCHEDULER_JOBS and tablespace_log.');
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating scheduler jobs: ' || SQLERRM);
RAISE;
END;
/
Changes:
- Removed AND batch_id BETWEEN 1 AND 12 from the query, allowing all non-null batch_id entries to be processed.
- No other changes needed, as the rest of the logic supports dynamic tablespaces.
Integration Instructions
- Backup v1.0:
- Save a copy of TablespaceCreationParallel_v1.0 before modifying.
- Replace Step 4:
- In create_tablespaces_parallel_v1.0.sql, replace the entire Step 4 (from DECLARE to the final /) with the modified Step 4 above.
- Customize the v_tablespaces list with your actual tablespace names (e.g., FTI_DATA_XYZ, FTO_INDEX_ABC, etc.) and sizes.
- Replace Step 5:
- Replace the entire Step 5 (from DECLARE to the final /) with the modified Step 5 above.
- No Changes to Steps 1, 2, 3:
- Steps 1 (drop tables), 2 (create tables), and 3 (drop/create procedures) remain unchanged, as they are identical in v1.0 and v2.2.
Scaling to 48 or More Tablespaces
To add more tablespaces (e.g., 48):
- Update the v_tablespaces list in Step 4 with additional entries:
plsql
v_tablespaces t_tablespace_list := t_tablespace_list(
t_tablespace('FTI_DATA_09', 10),
t_tablespace('FTO_INDEX_09', 20),
...
t_tablespace('FL8_APP_16', 55)
);
- The batch_id will automatically start from the highest existing batch_id in tablespace_control (e.g., 24 + 1 = 25 for the next batch).
========================================================================
WITH latest_log AS (
SELECT tablespace_name, batch_id,
ROW_NUMBER() OVER (PARTITION BY tablespace_name ORDER BY log_id DESC) AS rn
FROM tablespace_log
WHERE tablespace_name IN ('TS_PROD_01', 'TS_PROD_02', 'TS_PROD_03', 'TS_PROD_04', 'TS_PROD_05',
'TS_PROD_06', 'TS_PROD_07', 'TS_PROD_08', 'TS_PROD_09', 'TS_PROD_10',
'TS_PROD_11', 'TS_PROD_12')
)
SELECT
COALESCE(c.tablespace_name, l.tablespace_name) AS tablespace_name,
c.batch_id AS control_batch_id,
l.batch_id AS log_batch_id,
CASE
WHEN c.tablespace_name IS NULL THEN 'Missing in tablespace_control'
WHEN l.tablespace_name IS NULL THEN 'Missing in tablespace_log'
WHEN c.batch_id != l.batch_id THEN 'Batch ID mismatch'
WHEN c.batch_id IS NULL AND l.batch_id IS NOT NULL THEN 'Batch ID missing in control'
WHEN c.batch_id IS NOT NULL AND l.batch_id IS NULL THEN 'Batch ID missing in log'
ELSE 'Match'
END AS validation_result
FROM tablespace_control c
FULL OUTER JOIN latest_log l
ON c.tablespace_name = l.tablespace_name
AND l.rn = 1
WHERE COALESCE(c.tablespace_name, l.tablespace_name) IN (
'TS_PROD_01', 'TS_PROD_02', 'TS_PROD_03', 'TS_PROD_04', 'TS_PROD_05',
'TS_PROD_06', 'TS_PROD_07', 'TS_PROD_08', 'TS_PROD_09', 'TS_PROD_10',
'TS_PROD_11', 'TS_PROD_12'
)
ORDER BY COALESCE(c.batch_id, l.batch_id);
SET SERVEROUTPUT ON;
-- Step 1: Drop tables if they exist
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE tablespace_control PURGE';
DBMS_OUTPUT.PUT_LINE('Dropped tablespace_control');
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -942 THEN -- Table does not exist
DBMS_OUTPUT.PUT_LINE('Table tablespace_control does not exist, skipping drop');
ELSE
RAISE;
END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE tablespace_log PURGE';
DBMS_OUTPUT.PUT_LINE('Dropped tablespace_log');
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -942 THEN -- Table does not exist
DBMS_OUTPUT.PUT_LINE('Table tablespace_log does not exist, skipping drop');
ELSE
RAISE;
END IF;
END;
/
-- Step 2: Create tables
BEGIN
EXECUTE IMMEDIATE q'[
CREATE TABLE tablespace_control (
tablespace_name VARCHAR2(30) PRIMARY KEY,
initial_size_gb NUMBER NOT NULL,
batch_id NUMBER,
status VARCHAR2(10) DEFAULT 'PENDING' CHECK (status IN ('PENDING', 'RUNNING', 'COMPLETED', 'FAILED')),
retry_count NUMBER DEFAULT 0,
last_attempt TIMESTAMP,
created_by VARCHAR2(30) DEFAULT USER,
CONSTRAINT chk_size_positive CHECK (initial_size_gb > 0)
)
]';
DBMS_OUTPUT.PUT_LINE('Created tablespace_control');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating tablespace_control: ' || SQLERRM);
RAISE;
END;
/
BEGIN
EXECUTE IMMEDIATE q'[
CREATE TABLE tablespace_log (
log_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
tablespace_name VARCHAR2(30),
batch_id NUMBER,
action VARCHAR2(20),
status VARCHAR2(10),
error_message VARCHAR2(4000),
start_time TIMESTAMP DEFAULT SYSTIMESTAMP,
end_time TIMESTAMP,
log_time TIMESTAMP DEFAULT SYSTIMESTAMP,
session_user VARCHAR2(30) DEFAULT USER,
session_id NUMBER DEFAULT SYS_CONTEXT('USERENV', 'SID')
)
]';
DBMS_OUTPUT.PUT_LINE('Created tablespace_log');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating tablespace_log: ' || SQLERRM);
RAISE;
END;
/
-- Step 3: Drop existing procedures if they exist
BEGIN
EXECUTE IMMEDIATE 'DROP PROCEDURE create_tablespace_batch';
DBMS_OUTPUT.PUT_LINE('Dropped create_tablespace_batch');
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -4043 THEN -- Procedure does not exist
DBMS_OUTPUT.PUT_LINE('Procedure create_tablespace_batch does not exist, skipping drop');
ELSE
RAISE;
END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP PROCEDURE create_single_tablespace';
DBMS_OUTPUT.PUT_LINE('Dropped create_single_tablespace');
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -4043 THEN -- Procedure does not exist
DBMS_OUTPUT.PUT_LINE('Procedure create_single_tablespace does not exist, skipping drop');
ELSE
RAISE;
END IF;
END;
/
-- Step 3a: Create stored procedure for batch tablespace creation (kept for reference but not used)
BEGIN
EXECUTE IMMEDIATE q'[
CREATE OR REPLACE PROCEDURE create_tablespace_batch (p_batch_id IN NUMBER) AUTHID CURRENT_USER AS
v_sql VARCHAR2(1000);
v_common_clause CONSTANT VARCHAR2(500) := 'AUTOEXTEND ON NEXT 1G MAXSIZE UNLIMITED LOGGING DEFAULT COMPRESS FOR OLTP NO INMEMORY EXTENT MANAGEMENT LOCAL AUTOALLOCATE BLOCKSIZE 8K SEGMENT SPACE MANAGEMENT AUTO FLASHBACK ON';
v_max_retries CONSTANT NUMBER := 3;
v_error_msg VARCHAR2(4000);
v_log_id NUMBER;
v_sqlerr_msg VARCHAR2(4000);
BEGIN
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (NULL, p_batch_id, 'JOB_EXEC', 'RUNNING', SYSTIMESTAMP)
RETURNING log_id INTO v_log_id;
COMMIT;
FOR rec IN (
SELECT tablespace_name, initial_size_gb, retry_count
FROM tablespace_control
WHERE batch_id = p_batch_id AND status IN ('PENDING', 'FAILED')
ORDER BY tablespace_name
) LOOP
IF NOT REGEXP_LIKE(rec.tablespace_name, '^[A-Z][A-Z0-9_]{1,29}$') THEN
v_error_msg := 'Invalid tablespace name: ' || rec.tablespace_name;
UPDATE tablespace_control SET status = 'FAILED', retry_count = retry_count + 1, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = rec.tablespace_name;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message, start_time, end_time)
VALUES (rec.tablespace_name, p_batch_id, 'VALIDATE', 'FAILED', v_error_msg, SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
CONTINUE;
END IF;
DECLARE
v_exists NUMBER;
BEGIN
SELECT COUNT(*) INTO v_exists FROM DBA_TABLESPACES WHERE UPPER(tablespace_name) = UPPER(rec.tablespace_name);
IF v_exists > 0 THEN
UPDATE tablespace_control SET status = 'COMPLETED', last_attempt = SYSTIMESTAMP
WHERE tablespace_name = rec.tablespace_name;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time, end_time)
VALUES (rec.tablespace_name, p_batch_id, 'SKIP_EXISTS', 'COMPLETED', SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
CONTINUE;
END IF;
END;
UPDATE tablespace_control SET status = 'RUNNING', last_attempt = SYSTIMESTAMP
WHERE tablespace_name = rec.tablespace_name;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (rec.tablespace_name, p_batch_id, 'CREATE', 'RUNNING', SYSTIMESTAMP)
RETURNING log_id INTO v_log_id;
COMMIT;
v_sql := 'CREATE BIGFILE TABLESPACE ' || rec.tablespace_name || ' DATAFILE SIZE ' || rec.initial_size_gb || 'G ' || v_common_clause;
BEGIN
EXECUTE IMMEDIATE v_sql;
UPDATE tablespace_control SET status = 'COMPLETED', retry_count = 0, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = rec.tablespace_name;
UPDATE tablespace_log SET status = 'COMPLETED', end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
v_sqlerr_msg := SQLERRM;
UPDATE tablespace_control SET status = 'FAILED', retry_count = retry_count + 1, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = rec.tablespace_name;
UPDATE tablespace_log SET status = 'FAILED', error_message = v_sqlerr_msg, end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
IF rec.retry_count + 1 < v_max_retries THEN
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (rec.tablespace_name, p_batch_id, 'AUTO_RETRY', 'SCHEDULED', SYSTIMESTAMP);
COMMIT;
END IF;
END;
END LOOP;
UPDATE tablespace_log SET status = 'COMPLETED', end_time = SYSTIMESTAMP
WHERE log_id = v_log_id AND status = 'RUNNING';
COMMIT;
EXCEPTION
WHEN OTHERS THEN
v_sqlerr_msg := SQLERRM;
UPDATE tablespace_log SET status = 'FAILED', error_message = v_sqlerr_msg, end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
RAISE;
END;
]';
DBMS_OUTPUT.PUT_LINE('Created stored procedure create_tablespace_batch');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating stored procedure create_tablespace_batch: ' || SQLERRM);
RAISE;
END;
/
-- Step 3b: Create stored procedure for single tablespace creation
BEGIN
EXECUTE IMMEDIATE q'[
CREATE OR REPLACE PROCEDURE create_single_tablespace (
p_tablespace_name IN VARCHAR2,
p_initial_size_gb IN NUMBER
) AUTHID CURRENT_USER AS
v_sql VARCHAR2(1000);
v_common_clause CONSTANT VARCHAR2(500) := 'AUTOEXTEND ON NEXT 1G MAXSIZE UNLIMITED LOGGING DEFAULT COMPRESS FOR OLTP NO INMEMORY EXTENT MANAGEMENT LOCAL AUTOALLOCATE BLOCKSIZE 8K SEGMENT SPACE MANAGEMENT AUTO FLASHBACK ON';
v_max_retries CONSTANT NUMBER := 3;
v_error_msg VARCHAR2(4000);
v_log_id NUMBER;
v_sqlerr_msg VARCHAR2(4000);
v_retry_count NUMBER;
v_exists NUMBER;
BEGIN
IF NOT REGEXP_LIKE(p_tablespace_name, '^[A-Z][A-Z0-9_]{1,29}$') THEN
v_error_msg := 'Invalid tablespace name: ' || p_tablespace_name;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message, start_time, end_time)
VALUES (p_tablespace_name, NULL, 'VALIDATE', 'FAILED', v_error_msg, SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
RAISE_APPLICATION_ERROR(-20001, v_error_msg);
END IF;
SELECT COUNT(*) INTO v_exists
FROM DBA_TABLESPACES
WHERE UPPER(tablespace_name) = UPPER(p_tablespace_name);
IF v_exists > 0 THEN
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time, end_time)
VALUES (p_tablespace_name, NULL, 'SKIP_EXISTS', 'COMPLETED', SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
RETURN;
END IF;
BEGIN
SELECT retry_count INTO v_retry_count
FROM tablespace_control
WHERE tablespace_name = p_tablespace_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_retry_count := 0;
END;
MERGE INTO tablespace_control t
USING (SELECT p_tablespace_name AS tablespace_name, p_initial_size_gb AS initial_size_gb, NULL AS batch_id FROM DUAL) s
ON (t.tablespace_name = s.tablespace_name)
WHEN MATCHED THEN
UPDATE SET status = 'RUNNING', last_attempt = SYSTIMESTAMP
WHEN NOT MATCHED THEN
INSERT (tablespace_name, initial_size_gb, batch_id, status, last_attempt)
VALUES (s.tablespace_name, s.initial_size_gb, s.batch_id, 'RUNNING', SYSTIMESTAMP);
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (p_tablespace_name, NULL, 'CREATE', 'RUNNING', SYSTIMESTAMP)
RETURNING log_id INTO v_log_id;
COMMIT;
v_sql := 'CREATE BIGFILE TABLESPACE ' || p_tablespace_name || ' DATAFILE SIZE ' || p_initial_size_gb || 'G ' || v_common_clause;
BEGIN
EXECUTE IMMEDIATE v_sql;
UPDATE tablespace_control
SET status = 'COMPLETED', retry_count = 0, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = p_tablespace_name;
UPDATE tablespace_log
SET status = 'COMPLETED', end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
v_sqlerr_msg := SQLERRM;
UPDATE tablespace_control
SET status = 'FAILED', retry_count = v_retry_count + 1, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = p_tablespace_name;
UPDATE tablespace_log
SET status = 'FAILED', error_message = v_sqlerr_msg, end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
IF v_retry_count + 1 < v_max_retries THEN
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (p_tablespace_name, NULL, 'AUTO_RETRY', 'SCHEDULED', SYSTIMESTAMP);
COMMIT;
END IF;
RAISE;
END;
EXCEPTION
WHEN OTHERS THEN
v_sqlerr_msg := SQLERRM;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message, start_time, end_time)
VALUES (p_tablespace_name, NULL, 'CREATE', 'FAILED', v_sqlerr_msg, SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
RAISE;
END;
]';
DBMS_OUTPUT.PUT_LINE('Created stored procedure create_single_tablespace');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating stored procedure create_single_tablespace: ' || SQLERRM);
RAISE;
END;
/
-- Step 4: Define and populate tablespaces with unique batch IDs
DECLARE
TYPE t_tablespace IS RECORD (
tablespace_name VARCHAR2(30),
initial_size_gb NUMBER,
batch_id NUMBER
);
TYPE t_tablespace_list IS TABLE OF t_tablespace;
v_tablespaces t_tablespace_list := t_tablespace_list(
t_tablespace('TS_PROD_01', 10, 1),
t_tablespace('TS_PROD_02', 20, 2),
t_tablespace('TS_PROD_03', 50, 3),
t_tablespace('TS_PROD_04', 15, 4),
t_tablespace('TS_PROD_05', 30, 5),
t_tablespace('TS_PROD_06', 25, 6),
t_tablespace('TS_PROD_07', 40, 7),
t_tablespace('TS_PROD_08', 60, 8),
t_tablespace('TS_PROD_09', 12, 9),
t_tablespace('TS_PROD_10', 18, 10),
t_tablespace('TS_PROD_11', 45, 11),
t_tablespace('TS_PROD_12', 55, 12)
);
v_inserted_count NUMBER := 0;
BEGIN
FOR i IN 1..v_tablespaces.COUNT LOOP
MERGE INTO tablespace_control t
USING (SELECT v_tablespaces(i).tablespace_name AS tablespace_name,
v_tablespaces(i).initial_size_gb AS initial_size_gb,
v_tablespaces(i).batch_id AS batch_id
FROM DUAL) s
ON (t.tablespace_name = s.tablespace_name)
WHEN NOT MATCHED THEN
INSERT (tablespace_name, initial_size_gb, batch_id)
VALUES (s.tablespace_name, s.initial_size_gb, s.batch_id);
IF SQL%ROWCOUNT > 0 THEN
v_inserted_count := v_inserted_count + 1;
END IF;
END LOOP;
COMMIT;
DBMS_OUTPUT.PUT_LINE('Populated tablespace_control with ' || v_inserted_count || ' new tablespaces (batch IDs 1-12, skipped existing)');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('Error populating tablespace_control: ' || SQLERRM);
RAISE;
END;
/
-- Step 5: Create scheduler jobs for each tablespace using CREATE_SINGLE_TABLESPACE
DECLARE
v_job_name VARCHAR2(30);
v_created_count NUMBER := 0;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
-- Drop existing scheduler jobs
DBMS_OUTPUT.PUT_LINE('Dropping existing scheduler jobs:');
FOR job_rec IN (
SELECT JOB_NAME
FROM DBA_SCHEDULER_JOBS
WHERE JOB_NAME LIKE UPPER(USER) || '.CREATE_TS_%'
) LOOP
DBMS_SCHEDULER.DROP_JOB(job_name => job_rec.JOB_NAME, force => TRUE);
DBMS_OUTPUT.PUT_LINE('Dropped job: ' || job_rec.JOB_NAME);
v_created_count := v_created_count + 1;
END LOOP;
IF v_created_count = 0 THEN
DBMS_OUTPUT.PUT_LINE('No existing scheduler jobs found.');
ELSE
DBMS_OUTPUT.PUT_LINE(v_created_count || ' existing scheduler jobs dropped.');
END IF;
v_created_count := 0;
-- Create scheduler jobs for each tablespace
DBMS_OUTPUT.PUT_LINE('Creating scheduler jobs for tablespaces:');
FOR rec IN (
SELECT tablespace_name, initial_size_gb
FROM tablespace_control
WHERE batch_id IS NOT NULL
AND batch_id BETWEEN 1 AND 12
ORDER BY batch_id
) LOOP
v_job_name := UPPER(USER) || '.CREATE_TS_' || rec.tablespace_name;
DBMS_OUTPUT.PUT_LINE('Creating job for tablespace: ' || rec.tablespace_name);
DBMS_SCHEDULER.CREATE_JOB(
job_name => v_job_name,
job_type => 'STORED_PROCEDURE',
job_action => 'CREATE_SINGLE_TABLESPACE',
number_of_arguments => 2,
start_date => SYSTIMESTAMP,
repeat_interval => NULL,
enabled => FALSE, -- Initially disabled to set arguments
auto_drop => FALSE,
comments => 'Create bigfile tablespace ' || rec.tablespace_name
);
-- Set arguments: tablespace_name and initial_size_gb
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => v_job_name,
argument_position => 1,
argument_value => rec.tablespace_name
);
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => v_job_name,
argument_position => 2,
argument_value => TO_CHAR(rec.initial_size_gb)
);
-- Enable the job
DBMS_SCHEDULER.ENABLE(v_job_name);
DBMS_OUTPUT.PUT_LINE('Submitted and enabled job ' || v_job_name || ' for tablespace ' || rec.tablespace_name);
v_created_count := v_created_count + 1;
END LOOP;
IF v_created_count = 0 THEN
DBMS_OUTPUT.PUT_LINE('No new scheduler jobs created; all tablespaces may already have jobs.');
ELSE
DBMS_OUTPUT.PUT_LINE(v_created_count || ' new scheduler jobs submitted and enabled for parallel execution. Monitor with DBA_SCHEDULER_JOBS and tablespace_log.');
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating scheduler jobs: ' || SQLERRM);
RAISE;
END;
/
Corrected Query
To fix the ORA-00932 error, you can use one of these methods to convert the interval to a numeric value (e.g., minutes):
- Use EXTRACT: Extract components (days, hours, minutes, seconds) from the interval and compute the total minutes.
- Use NUMTODSINTERVAL or Casting: Convert the interval to a numeric value compatible with multiplication.
Here’s the corrected query using the EXTRACT method, which is straightforward and widely compatible:
sql
SELECT tablespace_name,
batch_id,
action,
status,
error_message,
start_time,
end_time,
ROUND(
EXTRACT(DAY FROM (end_time - start_time)) * 1440 +
EXTRACT(HOUR FROM (end_time - start_time)) * 60 +
EXTRACT(MINUTE FROM (end_time - start_time)) +
EXTRACT(SECOND FROM (end_time - start_time)) / 60,
2
) AS duration_minutes,
CASE
WHEN end_time IS NULL AND start_time < SYSTIMESTAMP - INTERVAL '30' MINUTE THEN 'Long Running'
WHEN status = 'FAILED' THEN 'Failed'
WHEN status = 'COMPLETED' THEN 'Completed'
ELSE 'In Progress'
END AS action_status
FROM tablespace_log
WHERE tablespace_name IN ('TS_PROD_01', 'TS_PROD_02', 'TS_PROD_03', 'TS_PROD_04', 'TS_PROD_05',
'TS_PROD_06', 'TS_PROD_07', 'TS_PROD_08', 'TS_PROD_09', 'TS_PROD_10',
'TS_PROD_11', 'TS_PROD_12')
OR tablespace_name IS NULL
ORDER BY start_time DESC;
Explanation of Fix
- Interval Conversion:
- end_time - start_time produces a DAY TO SECOND INTERVAL.
- EXTRACT retrieves components:
- EXTRACT(DAY FROM ...): Number of days.
- EXTRACT(HOUR FROM ...): Hours (0-23).
- EXTRACT(MINUTE FROM ...): Minutes (0-59).
- EXTRACT(SECOND FROM ...): Seconds (including microseconds).
- Convert to minutes:
- Days to minutes: days * 1440.
- Hours to minutes: hours * 60.
- Minutes: Direct.
- Seconds to minutes: seconds / 60.
- Combine: (days * 1440) + (hours * 60) + minutes + (seconds / 60).
- ROUND: Applies ROUND(..., 2) to the numeric result, giving duration in minutes with two decimal places.
- Null Handling: If end_time is NULL (action still running), duration_minutes will be NULL, which is appropriate.
Alternative Approach
If you prefer a simpler method, you can use NUMTODSINTERVAL or a timestamp difference in seconds:
sql
SELECT tablespace_name,
batch_id,
action,
status,
error_message,
start_time,
end_time,
ROUND(
EXTRACT(DAY FROM (end_time - start_time) * 1440) +
EXTRACT(HOUR FROM (end_time - start_time)) * 60 +
EXTRACT(MINUTE FROM (end_time - start_time)) +
EXTRACT(SECOND FROM (end_time - start_time)) / 60,
2
) AS duration_minutes,
CASE
WHEN end_time IS NULL AND start_time < SYSTIMESTAMP - INTERVAL '30' MINUTE THEN 'Long Running'
WHEN status = 'FAILED' THEN 'Failed'
WHEN status = 'COMPLETED' THEN 'Completed'
ELSE 'In Progress'
END AS action_status
FROM tablespace_log
WHERE tablespace_name IN ('TS_PROD_01', 'TS_PROD_02', 'TS_PROD_03', 'TS_PROD_04', 'TS_PROD_05',
'TS_PROD_06', 'TS_PROD_07', 'TS_PROD_08', 'TS_PROD_09', 'TS_PROD_10',
'TS_PROD_11', 'TS_PROD_12')
OR tablespace_name IS NULL
ORDER BY start_time DESC;
This query avoids direct interval multiplication and should work across Oracle versions (e.g., 19c, 23c).
Monitoring with the Corrected Query
To effectively monitor start_time and end_time for your 12 tablespaces in the context of your script (using CREATE_SINGLE_TABLESPACE in scheduler jobs for parallel background execution):
- Run the Query:
- Execute the corrected query above to monitor all actions for the 12 tablespaces (TS_PROD_01 to TS_PROD_12) and JOB_EXEC entries (tablespace_name IS NULL).
- Example output might look like:
text
TABLESPACE_NAME | BATCH_ID | ACTION | STATUS | ERROR_MESSAGE | START_TIME | END_TIME | DURATION_MINUTES | ACTION_STATUS
TS_PROD_01 | 1 | CREATE | COMPLETED | | 2025-09-06 12:00:00 | 2025-09-06 12:05:00 | 5.00 | Completed
TS_PROD_02 | 2 | CREATE | FAILED | ORA-01031: insufficient priv | 2025-09-06 12:00:00 | 2025-09-06 12:00:10 | 0.17 | Failed
NULL | 1 | JOB_EXEC | COMPLETED | | 2025-09-06 12:00:00 | 2025-09-06 12:05:00 | 5.00 | Completed
- Focus on Failures:
- Filter for failed actions to diagnose issues like ORA-01031:
sql
SELECT tablespace_name, batch_id, action, status, error_message, start_time, end_time,
ROUND(
EXTRACT(DAY FROM (end_time - start_time)) * 1440 +
EXTRACT(HOUR FROM (end_time - start_time)) * 60 +
EXTRACT(MINUTE FROM (end_time - start_time)) +
EXTRACT(SECOND FROM (end_time - start_time)) / 60,
2
) AS duration_minutes
FROM tablespace_log
WHERE status = 'FAILED'
AND (tablespace_name IN ('TS_PROD_01', 'TS_PROD_02', 'TS_PROD_03', 'TS_PROD_04', 'TS_PROD_05',
'TS_PROD_06', 'TS_PROD_07', 'TS_PROD_08', 'TS_PROD_09', 'TS_PROD_10',
'TS_PROD_11', 'TS_PROD_12')
OR tablespace_name IS NULL)
ORDER BY start_time DESC;
- Check Long-Running Tasks:
- Identify actions running longer than 30 minutes:
sql
SELECT tablespace_name, batch_id, action, status, start_time,
ROUND((SYSTIMESTAMP - start_time) * 1440, 2) AS running_minutes
FROM tablespace_log
WHERE end_time IS NULL
AND start_time < SYSTIMESTAMP - INTERVAL '30' MINUTE
AND (tablespace_name IN ('TS_PROD_01', 'TS_PROD_02', 'TS_PROD_03', 'TS_PROD_04', 'TS_PROD_05',
'TS_PROD_06', 'TS_PROD_07', 'TS_PROD_08', 'TS_PROD_09', 'TS_PROD_10',
'TS_PROD_11', 'TS_PROD_12')
OR tablespace_name IS NULL)
ORDER BY start_time DESC;
- Update tablespace_monitor View:
- Update the view to include the corrected duration calculation:
sql
CREATE OR REPLACE VIEW tablespace_monitor AS
SELECT c.tablespace_name,
c.initial_size_gb,
c.batch_id,
c.status,
c.retry_count,
l.action,
l.status AS log_status,
l.error_message,
l.start_time,
l.end_time,
ROUND(
EXTRACT(DAY FROM (l.end_time - l.start_time)) * 1440 +
EXTRACT(HOUR FROM (l.end_time - l.start_time)) * 60 +
EXTRACT(MINUTE FROM (l.end_time - l.start_time)) +
EXTRACT(SECOND FROM (l.end_time - l.start_time)) / 60,
2
) AS duration_minutes,
CASE
WHEN l.end_time IS NULL AND l.start_time < SYSTIMESTAMP - INTERVAL '30' MINUTE THEN 'Long Running'
WHEN l.status = 'FAILED' THEN 'Failed'
WHEN l.status = 'COMPLETED' THEN 'Completed'
ELSE 'In Progress'
END AS action_status
FROM tablespace_control c
LEFT JOIN tablespace_log l
ON c.tablespace_name = l.tablespace_name
AND l.log_id = (
SELECT MAX(log_id)
FROM tablespace_log
WHERE tablespace_name = c.tablespace_name
)
ORDER BY c.batch_id, c.tablespace_name;
- Monitor with View:
sql
SELECT tablespace_name, batch_id, status, log_status, error_message, start_time, end_time, duration_minutes, action_status
FROM tablespace_monitor
WHERE action_status IN ('Failed', 'Long Running')
OR status IN ('PENDING', 'FAILED')
ORDER BY batch_id;
Context with Your Script
- Script Status: Your latest script (from my previous response) uses DBMS_SCHEDULER jobs to call CREATE_SINGLE_TABLESPACE for each of the 12 tablespaces, aiming for parallel background execution. If you’re still seeing ORA-01031 errors in tablespace_log, the RDS scheduler restrictions may still apply.
- Fallback Option: If scheduler jobs fail, use direct execution of CREATE_SINGLE_TABLESPACE (as you tested successfully):
plsql
BEGIN
create_single_tablespace('TS_PROD_01', 10);
create_single_tablespace('TS_PROD_02', 20);
create_single_tablespace('TS_PROD_03', 50);
create_single_tablespace('TS_PROD_04', 15);
create_single_tablespace('TS_PROD_05', 30);
create_single_tablespace('TS_PROD_06', 25);
create_single_tablespace('TS_PROD_07', 40);
create_single_tablespace('TS_PROD_08', 60);
create_single_tablespace('TS_PROD_09', 12);
create_single_tablespace('TS_PROD_10', 18);
create_single_tablespace('TS_PROD_11', 45);
create_single_tablespace('TS_PROD_12', 55);
END;
/
Note: This is sequential and foreground, not parallel or background.
If Scheduler Jobs Fail
If the script’s jobs still fail with ORA-01031:
- Check Job Errors:
sql
SELECT job_name, status, error#, error_msg
FROM DBA_SCHEDULER_JOB_RUN_DETAILS
WHERE job_name LIKE UPPER(USER) || '.CREATE_TS_%';
- Contact AWS Support: Confirm if RDS restricts CREATE TABLESPACE in scheduler jobs, even with AUTHID CURRENT_USER.
- Alternative Parallelism: Use a PL/SQL block with DBMS_PARALLEL_EXECUTE for parallel execution without scheduler jobs, if needed.
Please run the corrected query and check tablespace_log and tablespace_monitor for results. If you see errors (e.g., ORA-01031), share the output, and I’ll provide further fixes. Let me know if you need a modified script with a different approach (e.g., DBMS_PARALLEL_EXECUTE)!
If Failures Persist
If CREATE_TABLESPACE_BATCH still fails:
- Check Errors: Review tablespace_log for new error messages beyond ORA-01031.
- Verify Procedure:
sql
SELECT object_name, status
FROM user_objects
WHERE object_name IN ('CREATE_TABLESPACE_BATCH', 'CREATE_SINGLE_TABLESPACE');
SELECT line, text
FROM user_source
WHERE name = 'CREATE_TABLESPACE_BATCH'
AND text LIKE '%v_common_clause%';
- RDS Support: Contact AWS support to confirm if RDS restricts CREATE TABLESPACE in procedures, even with direct execution.
- Fallback: Use CREATE_SINGLE_TABLESPACE for all 12 tablespaces:
plsql
BEGIN
create_single_tablespace('TS_PROD_01', 10);
create_single_tablespace('TS_PROD_02', 20);
create_single_tablespace('TS_PROD_03', 50);
create_single_tablespace('TS_PROD_04', 15);
create_single_tablespace('TS_PROD_05', 30);
create_single_tablespace('TS_PROD_06', 25);
create_single_tablespace('TS_PROD_07', 40);
create_single_tablespace('TS_PROD_08', 60);
create_single_tablespace('TS_PROD_09', 12);
create_single_tablespace('TS_PROD_10', 18);
create_single_tablespace('TS_PROD_11', 45);
create_single_tablespace('TS_PROD_12', 55);
END;
/
Summary
This script integrates all fixes (ORA-01031, ORA-00904, ORA-25142, procedure version issues) and uses direct execution to create 12 tablespaces in batches, leveraging the success of CREATE_SINGLE_TABLESPACE. The tablespace_monitor view provides comprehensive tracking. If you encounter new errors, share the output from tablespace_log or tablespace_monitor, and I’ll assist further. Let me know if you need additional tweaks (e.g., parallelism, alerts)!
Monitoring Best Practices (Unchanged)
SELECT tablespace_name, batch_id, status, retry_count, last_attempt
FROM tablespace_control
WHERE status IN ('FAILED', 'PENDING')
ORDER BY batch_id;
Detailed Logs:
SELECT tablespace_name, batch_id, action, status, error_message,
ROUND((end_time - start_time) * 1440, 2) AS duration_minutes
FROM tablespace_log
WHERE status = 'FAILED'
ORDER BY start_time DESC;
Scheduler Job Status:
SELECT job_name, state, enabled, run_count, failure_count, last_start_date
FROM DBA_SCHEDULER_JOBS
WHERE job_name LIKE UPPER(USER) || '.CREATE_TS_BATCH_%';
Monitoring View:
CREATE OR REPLACE VIEW tablespace_monitor AS
SELECT c.tablespace_name, c.initial_size_gb, c.batch_id, c.status, c.retry_count,
l.action, l.status AS log_status, l.error_message, l.start_time, l.end_time,
ROUND((end_time - l.start_time) * 1440, 2) AS duration_minutes
FROM tablespace_control c
LEFT JOIN tablespace_log l
ON c.tablespace_name = l.tablespace_name
AND l.log_id = (
SELECT MAX(log_id)
FROM tablespace_log
WHERE tablespace_name = c.tablespace_name
)
ORDER BY c.batch_id, c.tablespace_name;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_01'
AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_02'
AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_03'
AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_04'
AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_05'
AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_06'
AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_07'
AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_08'
AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_09'
AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_10'
AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_11'
AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_12'
AND l.batch_id IS NULL;
COMMIT;
===================================================================
version -2 yet to be tested
batch_id generated - fixed in tablespace_log
```plsql
SET SERVEROUTPUT ON;
-- Step 1: Drop tables if they exist
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE tablespace_control PURGE';
DBMS_OUTPUT.PUT_LINE('Dropped tablespace_control');
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -942 THEN -- Table does not exist
DBMS_OUTPUT.PUT_LINE('Table tablespace_control does not exist, skipping drop');
ELSE
RAISE;
END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP TABLE tablespace_log PURGE';
DBMS_OUTPUT.PUT_LINE('Dropped tablespace_log');
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -942 THEN -- Table does not exist
DBMS_OUTPUT.PUT_LINE('Table tablespace_log does not exist, skipping drop');
ELSE
RAISE;
END IF;
END;
/
-- Step 2: Create tables
BEGIN
EXECUTE IMMEDIATE q'[
CREATE TABLE tablespace_control (
tablespace_name VARCHAR2(30) PRIMARY KEY,
initial_size_gb NUMBER NOT NULL,
batch_id NUMBER,
status VARCHAR2(10) DEFAULT 'PENDING' CHECK (status IN ('PENDING', 'RUNNING', 'COMPLETED', 'FAILED')),
retry_count NUMBER DEFAULT 0,
last_attempt TIMESTAMP,
created_by VARCHAR2(30) DEFAULT USER,
CONSTRAINT chk_size_positive CHECK (initial_size_gb > 0)
)
]';
DBMS_OUTPUT.PUT_LINE('Created tablespace_control');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating tablespace_control: ' || SQLERRM);
RAISE;
END;
/
BEGIN
EXECUTE IMMEDIATE q'[
CREATE TABLE tablespace_log (
log_id NUMBER GENERATED ALWAYS AS IDENTITY PRIMARY KEY,
tablespace_name VARCHAR2(30),
batch_id NUMBER,
action VARCHAR2(20),
status VARCHAR2(10),
error_message VARCHAR2(4000),
start_time TIMESTAMP DEFAULT SYSTIMESTAMP,
end_time TIMESTAMP,
log_time TIMESTAMP DEFAULT SYSTIMESTAMP,
session_user VARCHAR2(30) DEFAULT USER,
session_id NUMBER DEFAULT SYS_CONTEXT('USERENV', 'SID')
)
]';
DBMS_OUTPUT.PUT_LINE('Created tablespace_log');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating tablespace_log: ' || SQLERRM);
RAISE;
END;
/
-- Step 3: Drop existing procedures if they exist
BEGIN
EXECUTE IMMEDIATE 'DROP PROCEDURE create_tablespace_batch';
DBMS_OUTPUT.PUT_LINE('Dropped create_tablespace_batch');
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -4043 THEN -- Procedure does not exist
DBMS_OUTPUT.PUT_LINE('Procedure create_tablespace_batch does not exist, skipping drop');
ELSE
RAISE;
END IF;
END;
/
BEGIN
EXECUTE IMMEDIATE 'DROP PROCEDURE create_single_tablespace';
DBMS_OUTPUT.PUT_LINE('Dropped create_single_tablespace');
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -4043 THEN -- Procedure does not exist
DBMS_OUTPUT.PUT_LINE('Procedure create_single_tablespace does not exist, skipping drop');
ELSE
RAISE;
END IF;
END;
/
-- Step 3a: Create stored procedure for batch tablespace creation (kept for reference)
BEGIN
EXECUTE IMMEDIATE q'[
CREATE OR REPLACE PROCEDURE create_tablespace_batch (p_batch_id IN NUMBER) AUTHID CURRENT_USER AS
v_sql VARCHAR2(1000);
v_common_clause CONSTANT VARCHAR2(500) := 'AUTOEXTEND ON NEXT 1G MAXSIZE UNLIMITED LOGGING DEFAULT COMPRESS FOR OLTP NO INMEMORY EXTENT MANAGEMENT LOCAL AUTOALLOCATE BLOCKSIZE 8K SEGMENT SPACE MANAGEMENT AUTO FLASHBACK ON';
v_max_retries CONSTANT NUMBER := 3;
v_error_msg VARCHAR2(4000);
v_log_id NUMBER;
v_sqlerr_msg VARCHAR2(4000);
BEGIN
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (NULL, p_batch_id, 'JOB_EXEC', 'RUNNING', SYSTIMESTAMP)
RETURNING log_id INTO v_log_id;
COMMIT;
FOR rec IN (
SELECT tablespace_name, initial_size_gb, retry_count
FROM tablespace_control
WHERE batch_id = p_batch_id AND status IN ('PENDING', 'FAILED')
ORDER BY tablespace_name
) LOOP
IF NOT REGEXP_LIKE(rec.tablespace_name, '^[A-Z][A-Z0-9_]{1,29}$') THEN
v_error_msg := 'Invalid tablespace name: ' || rec.tablespace_name;
UPDATE tablespace_control SET status = 'FAILED', retry_count = retry_count + 1, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = rec.tablespace_name;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message, start_time, end_time)
VALUES (rec.tablespace_name, p_batch_id, 'VALIDATE', 'FAILED', v_error_msg, SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
CONTINUE;
END IF;
DECLARE
v_exists NUMBER;
BEGIN
SELECT COUNT(*) INTO v_exists FROM DBA_TABLESPACES WHERE UPPER(tablespace_name) = UPPER(rec.tablespace_name);
IF v_exists > 0 THEN
UPDATE tablespace_control SET status = 'COMPLETED', last_attempt = SYSTIMESTAMP
WHERE tablespace_name = rec.tablespace_name;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time, end_time)
VALUES (rec.tablespace_name, p_batch_id, 'SKIP_EXISTS', 'COMPLETED', SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
CONTINUE;
END IF;
END;
UPDATE tablespace_control SET status = 'RUNNING', last_attempt = SYSTIMESTAMP
WHERE tablespace_name = rec.tablespace_name;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (rec.tablespace_name, p_batch_id, 'CREATE', 'RUNNING', SYSTIMESTAMP)
RETURNING log_id INTO v_log_id;
COMMIT;
v_sql := 'CREATE BIGFILE TABLESPACE ' || rec.tablespace_name || ' DATAFILE SIZE ' || rec.initial_size_gb || 'G ' || v_common_clause;
BEGIN
EXECUTE IMMEDIATE v_sql;
UPDATE tablespace_control SET status = 'COMPLETED', retry_count = 0, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = rec.tablespace_name;
UPDATE tablespace_log SET status = 'COMPLETED', end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
v_sqlerr_msg := SQLERRM;
UPDATE tablespace_control SET status = 'FAILED', retry_count = retry_count + 1, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = rec.tablespace_name;
UPDATE tablespace_log SET status = 'FAILED', error_message = v_sqlerr_msg, end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
IF rec.retry_count + 1 < v_max_retries THEN
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (rec.tablespace_name, p_batch_id, 'AUTO_RETRY', 'SCHEDULED', SYSTIMESTAMP);
COMMIT;
END IF;
END;
END LOOP;
UPDATE tablespace_log SET status = 'COMPLETED', end_time = SYSTIMESTAMP
WHERE log_id = v_log_id AND status = 'RUNNING';
COMMIT;
EXCEPTION
WHEN OTHERS THEN
v_sqlerr_msg := SQLERRM;
UPDATE tablespace_log SET status = 'FAILED', error_message = v_sqlerr_msg, end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
RAISE;
END;
]';
DBMS_OUTPUT.PUT_LINE('Created stored procedure create_tablespace_batch');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating stored procedure create_tablespace_batch: ' || SQLERRM);
RAISE;
END;
/
-- Step 3b: Create stored procedure for single tablespace creation
CREATE OR REPLACE PROCEDURE create_single_tablespace (
p_tablespace_name IN VARCHAR2,
p_initial_size_gb IN NUMBER,
p_batch_id IN NUMBER DEFAULT NULL
) AUTHID CURRENT_USER AS
v_sql VARCHAR2(1000);
v_common_clause CONSTANT VARCHAR2(500) := 'AUTOEXTEND ON NEXT 1G MAXSIZE UNLIMITED LOGGING DEFAULT COMPRESS FOR OLTP NO INMEMORY EXTENT MANAGEMENT LOCAL AUTOALLOCATE BLOCKSIZE 8K SEGMENT SPACE MANAGEMENT AUTO FLASHBACK ON';
v_max_retries CONSTANT NUMBER := 3;
v_error_msg VARCHAR2(4000);
v_log_id NUMBER;
v_sqlerr_msg VARCHAR2(4000);
v_retry_count NUMBER;
v_exists NUMBER;
BEGIN
IF p_tablespace_name IS NULL OR TRIM(p_tablespace_name) IS NULL THEN
v_error_msg := 'Tablespace name cannot be NULL or empty';
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message, start_time, end_time)
VALUES (p_tablespace_name, p_batch_id, 'VALIDATE', 'FAILED', v_error_msg, SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
RAISE_APPLICATION_ERROR(-20001, v_error_msg);
END IF;
IF NOT REGEXP_LIKE(p_tablespace_name, '^[A-Z][A-Z0-9_]{1,29}$') THEN
v_error_msg := 'Invalid tablespace name: ' || p_tablespace_name;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message, start_time, end_time)
VALUES (p_tablespace_name, p_batch_id, 'VALIDATE', 'FAILED', v_error_msg, SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
RAISE_APPLICATION_ERROR(-20001, v_error_msg);
END IF;
SELECT COUNT(*) INTO v_exists
FROM DBA_TABLESPACES
WHERE UPPER(tablespace_name) = UPPER(p_tablespace_name);
IF v_exists > 0 THEN
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time, end_time)
VALUES (p_tablespace_name, p_batch_id, 'SKIP_EXISTS', 'COMPLETED', SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
RETURN;
END IF;
BEGIN
SELECT retry_count INTO v_retry_count
FROM tablespace_control
WHERE tablespace_name = p_tablespace_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_retry_count := 0;
END;
MERGE INTO tablespace_control t
USING (SELECT p_tablespace_name AS tablespace_name, p_initial_size_gb AS initial_size_gb, p_batch_id AS batch_id FROM DUAL) s
ON (t.tablespace_name = s.tablespace_name)
WHEN MATCHED THEN
UPDATE SET status = 'RUNNING', last_attempt = SYSTIMESTAMP, batch_id = s.batch_id
WHEN NOT MATCHED THEN
INSERT (tablespace_name, initial_size_gb, batch_id, status, last_attempt)
VALUES (s.tablespace_name, s.initial_size_gb, s.batch_id, 'RUNNING', SYSTIMESTAMP);
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (p_tablespace_name, p_batch_id, 'CREATE', 'RUNNING', SYSTIMESTAMP)
RETURNING log_id INTO v_log_id;
COMMIT;
v_sql := 'CREATE BIGFILE TABLESPACE ' || p_tablespace_name || ' DATAFILE SIZE ' || p_initial_size_gb || 'G ' || v_common_clause;
BEGIN
EXECUTE IMMEDIATE v_sql;
UPDATE tablespace_control
SET status = 'COMPLETED', retry_count = 0, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = p_tablespace_name;
UPDATE tablespace_log
SET status = 'COMPLETED', end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
v_sqlerr_msg := SQLERRM;
UPDATE tablespace_control
SET status = 'FAILED', retry_count = v_retry_count + 1, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = p_tablespace_name;
UPDATE tablespace_log
SET status = 'FAILED', error_message = v_sqlerr_msg, end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
IF v_retry_count + 1 < v_max_retries THEN
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (p_tablespace_name, p_batch_id, 'AUTO_RETRY', 'SCHEDULED', SYSTIMESTAMP);
COMMIT;
END IF;
RAISE;
END;
EXCEPTION
WHEN OTHERS THEN
v_sqlerr_msg := SQLERRM;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message, start_time, end_time)
VALUES (p_tablespace_name, p_batch_id, 'CREATE', 'FAILED', v_sqlerr_msg, SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
RAISE;
END;
/
BEGIN
DBMS_OUTPUT.PUT_LINE('Created stored procedure create_single_tablespace');
END;
/
-- Step 4: Define and populate tablespaces with unique batch IDs
DECLARE
TYPE t_tablespace IS RECORD (
tablespace_name VARCHAR2(30),
initial_size_gb NUMBER,
batch_id NUMBER
);
TYPE t_tablespace_list IS TABLE OF t_tablespace;
v_tablespaces t_tablespace_list := t_tablespace_list(
t_tablespace('TS_PROD_01', 10, 1),
t_tablespace('TS_PROD_02', 20, 2),
t_tablespace('TS_PROD_03', 50, 3),
t_tablespace('TS_PROD_04', 15, 4),
t_tablespace('TS_PROD_05', 30, 5),
t_tablespace('TS_PROD_06', 25, 6),
t_tablespace('TS_PROD_07', 40, 7),
t_tablespace('TS_PROD_08', 60, 8),
t_tablespace('TS_PROD_09', 12, 9),
t_tablespace('TS_PROD_10', 18, 10),
t_tablespace('TS_PROD_11', 45, 11),
t_tablespace('TS_PROD_12', 55, 12)
);
v_inserted_count NUMBER := 0;
BEGIN
FOR i IN 1..v_tablespaces.COUNT LOOP
MERGE INTO tablespace_control t
USING (SELECT v_tablespaces(i).tablespace_name AS tablespace_name,
v_tablespaces(i).initial_size_gb AS initial_size_gb,
v_tablespaces(i).batch_id AS batch_id
FROM DUAL) s
ON (t.tablespace_name = s.tablespace_name)
WHEN NOT MATCHED THEN
INSERT (tablespace_name, initial_size_gb, batch_id)
VALUES (s.tablespace_name, s.initial_size_gb, s.batch_id);
IF SQL%ROWCOUNT > 0 THEN
v_inserted_count := v_inserted_count + 1;
END IF;
END LOOP;
COMMIT;
DBMS_OUTPUT.PUT_LINE('Populated tablespace_control with ' || v_inserted_count || ' new tablespaces (batch IDs 1-12, skipped existing)');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE('Error populating tablespace_control: ' || SQLERRM);
RAISE;
END;
/
-- Step 5: Create scheduler jobs for each tablespace using CREATE_SINGLE_TABLESPACE
DECLARE
v_job_name VARCHAR2(30);
v_created_count NUMBER := 0;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
-- Drop existing scheduler jobs
DBMS_OUTPUT.PUT_LINE('Dropping existing scheduler jobs:');
FOR job_rec IN (
SELECT JOB_NAME
FROM DBA_SCHEDULER_JOBS
WHERE JOB_NAME LIKE UPPER(USER) || '.CREATE_TS_%'
) LOOP
DBMS_SCHEDULER.DROP_JOB(job_name => job_rec.JOB_NAME, force => TRUE);
DBMS_OUTPUT.PUT_LINE('Dropped job: ' || job_rec.JOB_NAME);
v_created_count := v_created_count + 1;
END LOOP;
IF v_created_count = 0 THEN
DBMS_OUTPUT.PUT_LINE('No existing scheduler jobs found.');
ELSE
DBMS_OUTPUT.PUT_LINE(v_created_count || ' existing scheduler jobs dropped.');
END IF;
v_created_count := 0;
-- Create scheduler jobs for each tablespace
DBMS_OUTPUT.PUT_LINE('Creating scheduler jobs for tablespaces:');
FOR rec IN (
SELECT tablespace_name, initial_size_gb, batch_id
FROM tablespace_control
WHERE batch_id IS NOT NULL
AND batch_id BETWEEN 1 AND 12
ORDER BY batch_id
) LOOP
v_job_name := UPPER(USER) || '.CREATE_TS_' || rec.tablespace_name;
DBMS_OUTPUT.PUT_LINE('Creating job for tablespace: ' || rec.tablespace_name);
DBMS_SCHEDULER.CREATE_JOB(
job_name => v_job_name,
job_type => 'STORED_PROCEDURE',
job_action => 'CREATE_SINGLE_TABLESPACE',
number_of_arguments => 3,
start_date => SYSTIMESTAMP,
repeat_interval => NULL,
enabled => FALSE,
auto_drop => FALSE,
comments => 'Create bigfile tablespace ' || rec.tablespace_name
);
-- Set arguments: p_tablespace_name, p_initial_size_gb, p_batch_id
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => v_job_name,
argument_position => 1,
argument_value => rec.tablespace_name
);
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => v_job_name,
argument_position => 2,
argument_value => TO_CHAR(rec.initial_size_gb)
);
DBMS_SCHEDULER.SET_JOB_ARGUMENT_VALUE(
job_name => v_job_name,
argument_position => 3,
argument_value => TO_CHAR(rec.batch_id)
);
-- Enable the job
DBMS_SCHEDULER.ENABLE(v_job_name);
DBMS_OUTPUT.PUT_LINE('Submitted and enabled job ' || v_job_name || ' for tablespace ' || rec.tablespace_name);
v_created_count := v_created_count + 1;
END LOOP;
IF v_created_count = 0 THEN
DBMS_OUTPUT.PUT_LINE('No new scheduler jobs created; all tablespaces may already have jobs.');
ELSE
DBMS_OUTPUT.PUT_LINE(v_created_count || ' new scheduler jobs submitted and enabled for parallel execution. Monitor with DBA_SCHEDULER_JOBS and tablespace_log.');
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating scheduler jobs: ' || SQLERRM);
RAISE;
END;
/
```
### Execution and Verification
1. **Run the Script**:
- Save as `create_tablespaces_parallel.sql` and run as `rdsadm` in TOAD or SQL*Plus:
```sql
@create_tablespaces_parallel.sql
```
2. **Backfill `batch_id`** (if needed for prior runs):
- Run the `UPDATE` statements to fix existing `tablespace_log` entries:
```sql
BEGIN
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_01' AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_02' AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_03' AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_04' AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_05' AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_06' AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_07' AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_08' AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_09' AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_10' AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_11' AND l.batch_id IS NULL;
UPDATE tablespace_log l
SET l.batch_id = (SELECT c.batch_id FROM tablespace_control c WHERE c.tablespace_name = l.tablespace_name)
WHERE l.tablespace_name = 'TS_PROD_12' AND l.batch_id IS NULL;
COMMIT;
END;
/
```
3. **Monitor Execution**:
- Use the corrected monitoring query (fixes `ORA-00932`):
```sql
SELECT tablespace_name,
batch_id,
action,
status,
error_message,
start_time,
end_time,
ROUND(
EXTRACT(DAY FROM (end_time - start_time)) * 1440 +
EXTRACT(HOUR FROM (end_time - start_time)) * 60 +
EXTRACT(MINUTE FROM (end_time - start_time)) +
EXTRACT(SECOND FROM (end_time - start_time)) / 60,
2
) AS duration_minutes,
CASE
WHEN end_time IS NULL AND start_time < SYSTIMESTAMP - INTERVAL '30' MINUTE THEN 'Long Running'
WHEN status = 'FAILED' THEN 'Failed'
WHEN status = 'COMPLETED' THEN 'Completed'
ELSE 'In Progress'
END AS action_status
FROM tablespace_log
WHERE tablespace_name IN ('TS_PROD_01', 'TS_PROD_02', 'TS_PROD_03', 'TS_PROD_04', 'TS_PROD_05',
'TS_PROD_06', 'TS_PROD_07', 'TS_PROD_08', 'TS_PROD_09', 'TS_PROD_10',
'TS_PROD_11', 'TS_PROD_12')
OR tablespace_name IS NULL
ORDER BY start_time DESC;
```
- Check `tablespace_monitor`:
```sql
SELECT tablespace_name, batch_id, status, log_status, error_message, start_time, end_time, duration_minutes
FROM tablespace_monitor
WHERE action_status IN ('Failed', 'Long Running')
ORDER BY batch_id;
```
4. **Verify Scheduler Jobs**:
```sql
SELECT job_name, state, run_count, failure_count
FROM DBA_SCHEDULER_JOBS
WHERE job_name LIKE UPPER(USER) || '.CREATE_TS_%';
SELECT job_name, status, error#, error_msg
FROM DBA_SCHEDULER_JOB_RUN_DETAILS
WHERE job_name LIKE UPPER(USER) || '.CREATE_TS_%';
```
### If Issues Persist
If `ORA-01031` or other errors occur:
- **Check Job Errors**:
```sql
SELECT job_name, status, error#, error_msg
FROM DBA_SCHEDULER_JOB_RUN_DETAILS
WHERE job_name LIKE UPPER(USER) || '.CREATE_TS_%';
```
- **Fallback to Direct Execution**:
```plsql
BEGIN
create_single_tablespace('TS_PROD_01', 10, 1);
create_single_tablespace('TS_PROD_02', 20, 2);
create_single_tablespace('TS_PROD_03', 50, 3);
create_single_tablespace('TS_PROD_04', 15, 4);
create_single_tablespace('TS_PROD_05', 30, 5);
create_single_tablespace('TS_PROD_06', 25, 6);
create_single_tablespace('TS_PROD_07', 40, 7);
create_single_tablespace('TS_PROD_08', 60, 8);
create_single_tablespace('TS_PROD_09', 12, 9);
create_single_tablespace('TS_PROD_10', 18, 10);
create_single_tablespace('TS_PROD_11', 45, 11);
create_single_tablespace('TS_PROD_12', 55, 12);
END;
/
```
- **Contact AWS Support**: Confirm RDS restrictions on `CREATE TABLESPACE` in scheduler jobs.
Please run the updated script and the `UPDATE` statements for existing logs. If you see new errors, share the output from `tablespace_log` or `DBA_SCHEDULER_JOB_RUN_DETAILS`.
END
==================================================================
BEGIN
EXECUTE IMMEDIATE q'[
CREATE OR REPLACE PROCEDURE create_single_tablespace (
p_tablespace_name IN VARCHAR2,
p_initial_size_gb IN NUMBER
) AUTHID CURRENT_USER AS
v_sql VARCHAR2(1000);
v_common_clause CONSTANT VARCHAR2(500) := 'AUTOEXTEND ON NEXT 1G MAXSIZE UNLIMITED LOGGING DEFAULT COMPRESS FOR OLTP NO INMEMORY EXTENT MANAGEMENT LOCAL AUTOALLOCATE BLOCKSIZE 8K SEGMENT SPACE MANAGEMENT AUTO FLASHBACK ON';
v_max_retries CONSTANT NUMBER := 3;
v_error_msg VARCHAR2(4000);
v_log_id NUMBER;
v_sqlerr_msg VARCHAR2(4000);
v_retry_count NUMBER;
v_exists NUMBER;
BEGIN
-- Validate tablespace name
IF NOT REGEXP_LIKE(p_tablespace_name, '^[A-Z][A-Z0-9_]{1,29}$') THEN
v_error_msg := 'Invalid tablespace name: ' || p_tablespace_name;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message, start_time, end_time)
VALUES (p_tablespace_name, NULL, 'VALIDATE', 'FAILED', v_error_msg, SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
RAISE_APPLICATION_ERROR(-20001, v_error_msg);
END IF;
-- Check if tablespace exists
SELECT COUNT(*) INTO v_exists
FROM DBA_TABLESPACES
WHERE UPPER(tablespace_name) = UPPER(p_tablespace_name);
IF v_exists > 0 THEN
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time, end_time)
VALUES (p_tablespace_name, NULL, 'SKIP_EXISTS', 'COMPLETED', SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
RETURN;
END IF;
-- Get retry count from tablespace_control, if exists
BEGIN
SELECT retry_count INTO v_retry_count
FROM tablespace_control
WHERE tablespace_name = p_tablespace_name;
EXCEPTION
WHEN NO_DATA_FOUND THEN
v_retry_count := 0;
END;
-- Update or insert into tablespace_control
MERGE INTO tablespace_control t
USING (SELECT p_tablespace_name AS tablespace_name, p_initial_size_gb AS initial_size_gb, NULL AS batch_id FROM DUAL) s
ON (t.tablespace_name = s.tablespace_name)
WHEN MATCHED THEN
UPDATE SET status = 'RUNNING', last_attempt = SYSTIMESTAMP
WHEN NOT MATCHED THEN
INSERT (tablespace_name, initial_size_gb, batch_id, status, last_attempt)
VALUES (s.tablespace_name, s.initial_size_gb, s.batch_id, 'RUNNING', SYSTIMESTAMP);
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (p_tablespace_name, NULL, 'CREATE', 'RUNNING', SYSTIMESTAMP)
RETURNING log_id INTO v_log_id;
COMMIT;
-- Create tablespace
v_sql := 'CREATE BIGFILE TABLESPACE ' || p_tablespace_name || ' DATAFILE SIZE ' || p_initial_size_gb || 'G ' || v_common_clause;
BEGIN
EXECUTE IMMEDIATE v_sql;
UPDATE tablespace_control
SET status = 'COMPLETED', retry_count = 0, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = p_tablespace_name;
UPDATE tablespace_log
SET status = 'COMPLETED', end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
v_sqlerr_msg := SQLERRM;
UPDATE tablespace_control
SET status = 'FAILED', retry_count = v_retry_count + 1, last_attempt = SYSTIMESTAMP
WHERE tablespace_name = p_tablespace_name;
UPDATE tablespace_log
SET status = 'FAILED', error_message = v_sqlerr_msg, end_time = SYSTIMESTAMP
WHERE log_id = v_log_id;
COMMIT;
IF v_retry_count + 1 < v_max_retries THEN
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, start_time)
VALUES (p_tablespace_name, NULL, 'AUTO_RETRY', 'SCHEDULED', SYSTIMESTAMP);
COMMIT;
END IF;
RAISE;
END;
EXCEPTION
WHEN OTHERS THEN
v_sqlerr_msg := SQLERRM;
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message, start_time, end_time)
VALUES (p_tablespace_name, NULL, 'CREATE', 'FAILED', v_sqlerr_msg, SYSTIMESTAMP, SYSTIMESTAMP);
COMMIT;
RAISE;
END;
]';
DBMS_OUTPUT.PUT_LINE('Created stored procedure create_single_tablespace');
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error creating stored procedure create_single_tablespace: ' || SQLERRM);
RAISE;
END;
/
EXEC create_single_tablespace('TS_PROD_01', 10);
==================
SET SERVEROUTPUT ON;
-- Step 2: Populate tablespace_control with new batch assignments (dynamic and validated)
DECLARE
-- Define a record type for tablespace details
TYPE t_tablespace IS RECORD (
tablespace_name VARCHAR2(30),
initial_size_gb NUMBER
);
-- Define a collection type for multiple tablespaces
TYPE t_tablespace_list IS TABLE OF t_tablespace;
-- Initialize the collection with tablespaces to insert
v_tablespaces t_tablespace_list := t_tablespace_list(
t_tablespace('TS_REVANTH_6', 6268),
t_tablespace('TS_REVANTH_7', 6268),
t_tablespace('TS_REVANTH_8', 6268)
-- Add more tablespaces here as needed, e.g., t_tablespace('TS_REVANTH_9', 2500)
);
v_next_batch_id NUMBER;
v_error_count NUMBER := 0;
BEGIN
DBMS_OUTPUT.ENABLE(1000000);
-- Get the next available batch_id
SELECT NVL(MAX(batch_id), 0) + 1 INTO v_next_batch_id FROM tablespace_control;
-- Loop through the collection to perform MERGE operations
FOR i IN 1..v_tablespaces.COUNT LOOP
-- Validate tablespace_name
IF NOT REGEXP_LIKE(v_tablespaces(i).tablespace_name, '^[A-Z][A-Z0-9_]{1,29}$') THEN
DBMS_OUTPUT.PUT_LINE('Error: Invalid tablespace name: ' || v_tablespaces(i).tablespace_name);
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message)
VALUES (v_tablespaces(i).tablespace_name, v_next_batch_id, 'VALIDATE', 'FAILED',
'Invalid tablespace name format (must start with letter, followed by letters/numbers/underscores, max 30 chars)');
COMMIT;
v_error_count := v_error_count + 1;
CONTINUE;
END IF;
-- Validate initial_size_gb
IF v_tablespaces(i).initial_size_gb <= 0 THEN
DBMS_OUTPUT.PUT_LINE('Error: Invalid size for ' || v_tablespaces(i).tablespace_name || ': ' || v_tablespaces(i).initial_size_gb || ' GB');
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message)
VALUES (v_tablespaces(i).tablespace_name, v_next_batch_id, 'VALIDATE', 'FAILED',
'Initial size must be positive: ' || v_tablespaces(i).initial_size_gb);
COMMIT;
v_error_count := v_error_count + 1;
CONTINUE;
END IF;
-- Perform MERGE to insert if not exists
BEGIN
MERGE INTO tablespace_control t
USING (SELECT v_tablespaces(i).tablespace_name AS tablespace_name,
v_tablespaces(i).initial_size_gb AS initial_size_gb,
v_next_batch_id AS batch_id FROM DUAL) s
ON (t.tablespace_name = s.tablespace_name)
WHEN NOT MATCHED THEN
INSERT (tablespace_name, initial_size_gb, batch_id, status, created_by)
VALUES (s.tablespace_name, s.initial_size_gb, s.batch_id, 'PENDING', USER);
DBMS_OUTPUT.PUT_LINE('Inserted/Updated ' || v_tablespaces(i).tablespace_name || ' with batch_id ' || v_next_batch_id);
v_next_batch_id := v_next_batch_id + 1; -- Increment batch_id for next tablespace
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Error inserting ' || v_tablespaces(i).tablespace_name || ': ' || SQLERRM);
INSERT INTO tablespace_log (tablespace_name, batch_id, action, status, error_message)
VALUES (v_tablespaces(i).tablespace_name, v_next_batch_id, 'INSERT', 'FAILED', SQLERRM);
v_error_count := v_error_count + 1;
CONTINUE;
END;
COMMIT;
END LOOP;
IF v_error_count = 0 THEN
DBMS_OUTPUT.PUT_LINE('Successfully populated tablespace_control with ' || v_tablespaces.COUNT || ' new batch assignments');
ELSE
DBMS_OUTPUT.PUT_LINE('Populated tablespace_control with ' || (v_tablespaces.COUNT - v_error_count) || ' new batch assignments, ' || v_error_count || ' errors encountered');
END IF;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Unexpected error in Step 2: ' || SQLERRM);
RAISE;
END;
/
No comments:
Post a Comment