Skip to Main Content

SQL & PL/SQL

Before insert TRIGGER to create partitions problem

676821Jan 14 2009 — edited Jan 14 2009
Hi there,

I´m having a problem with the following situation in Oracle 8i:

I have a table TEST_TABLE, which is partitioned by range using a DATE column. The idea is to have one partition for each month, so the HIGH_VALUE of the partitions is always the first day of the of the following month that the partition represents.

I created a BEFORE INSERT TRIGGER on the table TEST_TABLE, which tests if the partition for the month of the record that is being inserted exists and, in case it doesn´t, an AUTONOMOUS_TRANSACTION PROC is called to create the TRIGGER.

Running the code below one can see that although the partitions are being created as expected, when you try to insert a record with a date higher than that of the last partition for the first time, this error is returned:
ORA-14400: inserted partition key is beyond highest legal partition key.

Notice that if you run the same insert statement again, it´s inserted correctly on the partition that was created on the first try.

I´ll appreciate any help with this matter.

code
----------------
CREATE TABLE TEST_TABLE (
ID NUMBER,
DT DATE
)
TABLESPACE USERS
PARTITION BY RANGE (DT)
(
PARTITION PART_B42009 VALUES LESS THAN (TO_DATE('2009-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS', 'NLS_CALENDAR=GREGORIAN'))
LOGGING
TABLESPACE USERS
);
/

CREATE OR REPLACE PROCEDURE SP_ADD_PARTITION(P_DATE TEST_TABLE.DT%TYPE)
IS
PRAGMA AUTONOMOUS_TRANSACTION;
V_STR VARCHAR2(500);
BEGIN

V_STR := 'ALTER TABLE TEST_TABLE ADD'
|| ' PARTITION PART_' || TO_CHAR(P_DATE, 'YYYYMM')
|| ' VALUES LESS THAN ( TO_DATE ( '''
|| TO_CHAR(ADD_MONTHS(P_DATE, 1), 'YYYY-MM') || '-01 00:00:00'', '
|| '''SYYYY-MM-DD HH24:MI:SS'', ''NLS_CALENDAR=GREGORIAN''))';

EXECUTE IMMEDIATE(V_STR);

END SP_ADD_PARTITION;
/

CREATE OR REPLACE TRIGGER TR_B_I_R_TEST_TABLE
BEFORE INSERT
ON TEST_TABLE FOR EACH ROW
DECLARE
V_PARTITION_EXISTS NUMBER;
BEGIN

IF :NEW.DT >= TO_DATE('2009-01-01 00:00:00', 'YYYY-MM-DD HH24:MI:SS') THEN

EXECUTE IMMEDIATE ('SELECT COUNT(1)'
|| ' FROM all_tab_partitions atp'
|| ' WHERE atp.table_name = ''TEST_TABLE'' '
|| ' AND atp.PARTITION_NAME = :v1 ')
INTO V_PARTITION_EXISTS
USING 'PART_' || TO_CHAR(:NEW.DT, 'YYYYMM');

IF V_PARTITION_EXISTS = 0 THEN

DBMS_OUTPUT.PUT_LINE ('Partition [' || 'PART_' || TO_CHAR(:NEW.DT, 'YYYYMM') || '] does not exist!');
DBMS_OUTPUT.PUT_LINE ('Creating..');
SP_ADD_PARTITION ( :NEW.DT );
DBMS_OUTPUT.PUT_LINE ('Success.');

EXECUTE IMMEDIATE ('SELECT COUNT(1)'
|| ' FROM all_tab_partitions atp'
|| ' WHERE atp.table_name = ''TEST_TABLE'' '
|| ' AND atp.PARTITION_NAME = :v1 ')
INTO V_PARTITION_EXISTS
USING 'PART_' || TO_CHAR(:NEW.DT, 'YYYYMM');

IF V_PARTITION_EXISTS = 1 THEN
DBMS_OUTPUT.PUT_LINE ('it´s visible at this stage..');
ELSE
DBMS_OUTPUT.PUT_LINE ('it´s not visible at this stage..');
END IF;

ELSE

DBMS_OUTPUT.PUT_LINE ('Partition [' || 'PART_' || TO_CHAR(:NEW.DT, 'YYYYMM')
|| '] already exists!');

END IF;

END IF;

DBMS_OUTPUT.PUT_LINE ('Continuing with insertion..');

END TR_B_I_R_TEST_TABLE;
/

-- Goes to the lower partition
INSERT INTO TEST_TABLE VALUES (1, TO_DATE('2008-12-31 23:59:59','YYYY-MM-DD HH24:MI:SS'));

-- Returns error on the first try
INSERT INTO TEST_TABLE VALUES (2, TO_DATE('2009-01-01 00:00:01','YYYY-MM-DD HH24:MI:SS'));

----------------
This post has been answered by APC on Jan 14 2009
Jump to Answer
Comments
Locked Post
New comments cannot be posted to this locked post.
Post Details
Locked on Feb 11 2009
Added on Jan 14 2009
5 comments
887 views