ORA-01741 for DBMS_REDEFINITION with invisible fields and implicit constraints - oracle

I recently noticed an odd failure pattern recently in one database (12cR1) when using DBMS_REDEFINITION. CAN_REDEF_TABLE completes fine, as does START_REDEF_TABLE, but COPY_TABLE_DEPENDENTS fails with a bewildering:
ORA-01741: illegal zero-length identifier
After some debugging, the exception appears to be related to the ORIG_TABLE carrying both INVISIBLE column(s) and implicit system-named constraints. I'll include an example below to demonstrate the problem, but I hoped to gain some understanding of the behavior, and didn't see anything notable about INVISIBLE called out in the docs.
It seems there is some nuance to the creation of system-generated constraints I'd like to understand better. Apologies for the "why" question, but, Why do implicit system constraints behave any differently than explicitly-defined constraints during redefinition? I had thought that after being assigned a system-generated name, a constraint was just a constraint. Are system-generated objects different in other ways from client-named constraints beyond their names?
I also hoped to see if anyone has another workaround to recommend beyond just renaming implicit constraints or un-hiding the columns before the redifinition.
Thanks
Example:
Below are three versions of the same ORIG_TABLE for redefinition. The first two both undergo the far-below redefinition ok with the given INT_TABLE, but the third throws the ORA-01741 during COPY_TABLE_DEPENDENTS.
Version 1: All columns visible, implicit system-generated constraints:
CREATE TABLE REDEF_TARGET (
THE_KEY INTEGER NOT NULL PRIMARY KEY ,
THE_DATE DATE NOT NULL
);
Version 2: INVISIBLE column present, explicit constraint (given an absurd name here to poke at if DBMS_REDEFINITION is instrumenting existing names)
CREATE TABLE REDEF_TARGET (
THE_KEY INTEGER NOT NULL PRIMARY KEY ,
THE_DATE DATE INVISIBLE ,
CONSTRAINT SYS_C02583271 CHECK (THE_DATE IS NOT NULL)
);
Version 3: INVISIBLE column and implicit constraint both present
CREATE TABLE REDEF_TARGET (
THE_KEY INTEGER NOT NULL PRIMARY KEY ,
THE_DATE DATE INVISIBLE NOT NULL
);
Running either of the first against the below will work, while the third will fail during copy-deps.
CREATE TABLE REDEFINER (
THE_KEY INTEGER ,
THE_DATE DATE
);
DECLARE
V_NUM INTEGER;
BEGIN
DBMS_REDEFINITION.CAN_REDEF_TABLE(UNAME => USER , TNAME => 'REDEF_TARGET');
DBMS_REDEFINITION.START_REDEF_TABLE(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER');
DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER' , NUM_ERRORS => V_NUM);
DBMS_REDEFINITION.FINISH_REDEF_TABLE(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER');
END;
/

First of all you do not need to use NOT NULL with PRIMARY KEY clause. Get rid of such NOT NULLs.
Let's run your statement for version 3 on DB version 12cR1 as in your case :
Connected to Oracle Database 12c Enterprise Edition Release 12.1.0.2.0
Connected as hr
SQL> CREATE TABLE REDEF_TARGET (
2 THE_KEY INTEGER PRIMARY KEY ,
3 THE_DATE DATE INVISIBLE NOT NULL
4 );
Table created
SQL> CREATE TABLE REDEFINER(
2 THE_KEY INTEGER,
3 THE_DATE DATE
4 );
Table created
SQL> DECLARE
2 V_NUM INTEGER;
3 BEGIN
4 DBMS_REDEFINITION.CAN_REDEF_TABLE(UNAME => USER , TNAME => 'REDEF_TARGET');
5 DBMS_REDEFINITION.START_REDEF_TABLE(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER');
6 DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER' , NUM_ERRORS => V_NUM);
7 DBMS_REDEFINITION.FINISH_REDEF_TABLE(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER');
8 END;
9 /
ORA-01741: illegal zero-length identifier
ORA-06512: at "SYS.DBMS_REDEFINITION", line 1646
ORA-06512: at "SYS.DBMS_REDEFINITION", line 2502
ORA-06512: at "SYS.DBMS_REDEFINITION", line 3803
ORA-06512: at line 7
SQL> DROP TABLE REDEF_TARGET;
Table dropped
SQL> DROP TABLE REDEFINER;
DROP TABLE REDEFINER
ORA-12083: must use DROP MATERIALIZED VIEW to drop "HR"."REDEFINER"
SQL> DROP MATERIALIZED VIEW REDEFINER;
Materialized view dropped
SQL> DROP TABLE REDEFINER;
Table dropped
SQL> CREATE TABLE REDEF_TARGET (
2 THE_KEY INTEGER PRIMARY KEY ,
3 THE_DATE DATE INVISIBLE NOT NULL
4 );
Table created
SQL> CREATE TABLE REDEFINER(
2 THE_KEY INTEGER,
3 THE_DATE DATE INVISIBLE
4 );
Table created
SQL> DECLARE
2 V_NUM INTEGER;
3 BEGIN
4 DBMS_REDEFINITION.CAN_REDEF_TABLE(UNAME => USER , TNAME => 'REDEF_TARGET');
5 DBMS_REDEFINITION.START_REDEF_TABLE(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER');
6 DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER' , NUM_ERRORS => V_NUM);
7 DBMS_REDEFINITION.FINISH_REDEF_TABLE(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER');
8 END;
9 /
ORA-01741: illegal zero-length identifier
ORA-06512: at "SYS.DBMS_REDEFINITION", line 1646
ORA-06512: at "SYS.DBMS_REDEFINITION", line 2502
ORA-06512: at "SYS.DBMS_REDEFINITION", line 3803
ORA-06512: at line 7
and DB version 12cR2 :
Connected to Oracle Database 12c Enterprise Edition Release 12.2.0.1.0
Connected as hr
SQL> CREATE TABLE REDEF_TARGET (
2 THE_KEY INTEGER PRIMARY KEY ,
3 THE_DATE DATE INVISIBLE NOT NULL
4 );
Table created
SQL> CREATE TABLE REDEFINER(
2 THE_KEY INTEGER,
3 THE_DATE DATE
4 );
Table created
SQL> DECLARE
2 V_NUM INTEGER;
3 BEGIN
4 DBMS_REDEFINITION.CAN_REDEF_TABLE(UNAME => USER , TNAME => 'REDEF_TARGET');
5 DBMS_REDEFINITION.START_REDEF_TABLE(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER');
6 DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER' , NUM_ERRORS => V_NUM);
7 DBMS_REDEFINITION.FINISH_REDEF_TABLE(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER');
8 END;
9 /
ORA-042067: invalid column mapping with invisible columns on original or interim table
ORA-06512: at "SYS.DBMS_REDEFINITION", line 109
ORA-06512: at "SYS.DBMS_REDEFINITION", line 3887
ORA-06512: at "SYS.DBMS_REDEFINITION", line 5208
ORA-06512: at line 5
SQL> DROP TABLE REDEF_TARGET;
Table dropped
SQL> DROP TABLE REDEFINER;
Table dropped
SQL> CREATE TABLE REDEF_TARGET (
2 THE_KEY INTEGER PRIMARY KEY ,
3 THE_DATE DATE INVISIBLE NOT NULL
4 );
Table created
SQL> CREATE TABLE REDEFINER(
2 THE_KEY INTEGER,
3 THE_DATE DATE INVISIBLE
4 );
Table created
SQL> DECLARE
2 V_NUM INTEGER;
3 BEGIN
4 DBMS_REDEFINITION.CAN_REDEF_TABLE(UNAME => USER , TNAME => 'REDEF_TARGET');
5 DBMS_REDEFINITION.START_REDEF_TABLE(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER');
6 DBMS_REDEFINITION.COPY_TABLE_DEPENDENTS(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER' , NUM_ERRORS => V_NUM);
7 DBMS_REDEFINITION.FINISH_REDEF_TABLE(UNAME => USER , ORIG_TABLE => 'REDEF_TARGET' , INT_TABLE => 'REDEFINER');
8 END;
9 /
PL/SQL procedure successfully completed.
So, Results follow :
Version 12c Release 1 suppresses the main problem of being
ORA-042067 instead of ORA-01741. So, INVISIBLE option needed to be added for THE_DATE (DATE) column of REDEFINER table for true column mappings between original and interim tables.
Even if INVISIBLE option added for above mentioned column, you'll
get still the same error code ( ORA-01741 ) for version R1, while
you'll be successful for version R2. So, upgrade seems to be
necessary.
By the way every time we try to drop REDEFINER table, materialized
view needed to be dropped for R1, but no for R2. Interesting, might be a bug ...

it seems due to oracle bug.the bug is fixed on oracle 12.2.
the following is some key information:
Bug 17871192 : ILM POLICY FAILS WITH ORA-01741 ON TABLE WITH INVISIBLE COLUMN
PROBLEM:
An ADO Policy on a table with added invisible not null default column fails
with the following message:
ORA-12012: error on auto execute of job "SYS"."ILMJOB2628"
ORA-1741: illegal zero-length identifier
ORA-6512: at "SYS.DBMS_REDEFINITION", line 2525
DIAGNOSTIC ANALYSIS:
To reproduce, you need a table which had a column with the following command
added:
alter table "ILMT3" add "C4" varchar2 (10) invisible default ' ' not null;
All three attributes are needed to reproduce.
WORKAROUND:
Dont use one of the attributes
RELEASE NOTES:
]] INVISIBLE COLUMN metadata is missing.
REDISCOVERY INFORMATION:
In INVISIBLE COLUMN column name is missing then you are hitting this issue.

Related

ORA-30657 when creating an interval (or auto list) external partition table

When trying to create an Interval (or auto list) external partitioned table with DBMS_CLOUD, I am getting ORA-30657: operation not supported on external organized table.
What am I missing?
SQL> BEGIN
2 DBMS_CLOUD.CREATE_EXTERNAL_PART_TABLE(
3 table_name =>'PETX',
4 credential_name =>'MY_CRED',
5 format => json_object('delimiter' value '#'),
6 column_list => 'deptno number,dname char(14),loc char(13)',
7 partitioning_clause => 'partition by range (deptno) interval (15)
8 (
9 partition xp1 values less than (15) location(''https://swiftobjectstorage.XXXX/xp1_15.txt'') ,
10 partition xp2 values less than (30) location (''https://swiftobjectstorage.XXXX/xp2_30.txt'')
11 )'
12 );
13 END;
14 /
Error starting at line : 5 in command -
BEGIN
DBMS_CLOUD.CREATE_EXTERNAL_PART_TABLE(
table_name =>'PETX',
credential_name =>'MY_CRED',
format => json_object('delimiter' value '#'),
column_list => 'deptno number,dname char(14),loc char(13)',
partitioning_clause => 'partition by range (deptno) interval (15)
(
partition xp1 values less than (15) location(''https://swiftobjectstorage.XXXX/xp1_15.txt'') ,
partition xp2 values less than (30) location (''https://swiftobjectstorage.XXXX/xp2_30.txt'')
)'
);
END;
Error report -
ORA-20000: ORA-30657: operation not supported on external organized table
ORA-06512: at "C##CLOUD$SERVICE.DBMS_CLOUD", line 1289
ORA-06512: at "C##CLOUD$SERVICE.DBMS_CLOUD", line 4115
Interval and auto-list partitioning is functionality that creates new partitions as-needed, based on new data inserted into the database where the partition key(s) of the new data do not map to any existing partition. With external tables the database does not control the data (or insertion of it), thus the concept of auto-generation of a partition at insertion is not applying to external tables.
Adding a new partition to a partitioned external table is equivalent to having new data files that the table has to point at. You have to tell the database about this, which you are doing by adding a new partition to a table (manually or programmatically).
Short example of how to make the above-example work and how to add a new partition (pointing to additional data files):
SQL>
SQL> BEGIN
2 DBMS_CLOUD.CREATE_EXTERNAL_PART_TABLE(
3 table_name =>'PETX',
4 credential_name =>'MY_CRED',
5 format => json_object('delimiter' value '#'),
6 column_list => 'deptno number,dname char(14),loc char(13)',
7 partitioning_clause => 'partition by range (deptno)
8 (
9 partition xp1 values less than (15) location(''https://swiftobjectstorage.XXXX/xp1_15.txt'') ,
10 partition xp2 values less than (30) location (''https://swiftobjectstorage.XXXX/xp2_30.txt'')
11 )'
12 );
13 END;
14 /
PL/SQL procedure successfully completed.
SQL>
SQL> alter table petx add partition xp3 values less than (50) location ('https://swiftobjectstorage.XXXX/xp3_45.txt');
Table PETX altered.
SQL> select count(*) from petx partition (xp3);
COUNT(*)
----------
49999999
PS: The exact same behavior applies to standard Oracle Database.

how to make distinct type with condition in oracle

create or replace TYPE PDV AS OBJECT
( percentage NUMBER(4,2),
MEMBER FUNCTION get_percentage RETURN NUMBER
) INSTANTIABLE NOT FINAL;
create or replace TYPE BODY PDV AS
MEMBER FUNCTION get_percentage RETURN NUMBER AS
BEGIN
return SELF.percentage;
END get_percentage;
END;
I have table Product (productID, name, description, percentage)
When I insert this in the database, it should be saved in the table Product:
insert into Product VALUES (1, 'Table', 'Brown table for six people.Made of oak', PDV(20.00));
When I insert this into the database, an error should occur:
insert into Product VALUES (1, 'Table', 'Brown table for six people.Made of oak', PDV(130.20));
I want to make distinct type with condition - percentage must be between 0 and 100. Where to put that condition?
percentage must be between 0 and 100. Where to put that condition?
Nowhere, I'd say. PERCENTAGE's data type, a numeric having precision 4 and scale 2 will take care about it.
As you didn't provide whole code you use, here's an example.
SQL> create or replace type pdv as object
2 (productid number,
3 name varchar2(30),
4 description varchar2(100),
5 percentage number(4, 2),
6 member function get_percentage return number
7 ) instantiable not final;
8 /
Type created.
SQL> create or replace type body pdv as
2 member function get_percentage return number as
3 begin
4 return self.percentage;
5 end get_percentage;
6 end;
7 /
Type body created.
SQL> create table product (prod pdv);
Table created.
SQL> insert into product values (pdv(1, 'Table', 'Made of oak', 20));
1 row created.
SQL> insert into product values (pdv(1, 'Table', 'Made of oak', 130));
insert into product values (pdv(1, 'Table', 'Made of oak', 130))
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
SQL> insert into product values (pdv(1, 'Table', 'Made of oak', 55.567));
1 row created.
SQL>
[EDIT, written after reading OP's comment]
I'm not sure I understood what you mean. If it means that you want to create an inline CHECK constraint, well, that won't work:
SQL> create or replace type pdv_typ as object
2 (
3 producid number,
4 name varchar2 (30),
5 description varchar2 (100),
6 percentage number (4, 2) constraint ch_perc check (percentage between 0 and 100),
7 member function get_percentage
8 return number
9 );
10 /
create or replace type pdv_typ as object
*
ERROR at line 1:
ORA-06545: PL/SQL: compilation error - compilation aborted
ORA-06550: line 6, column 29:
PLS-00103: Encountered the symbol "CONSTRAINT" when expecting one of the
following:
:= ) , not null default external character
ORA-06550: line 0, column 0:
PLS-00565: PDV_TYP must be completed as a potential REF target (object type)
SQL>
What you could do is to create a table whose column data type is of a previously created type, such as this:
SQL> create or replace type pdv_typ as object
2 (
3 producid number,
4 name varchar2 (30),
5 description varchar2 (100),
6 percentage number (4, 2),
7 member function get_percentage
8 return number
9 );
10 /
Type created.
SQL> create or replace type body pdv_typ
2 as
3 member function get_percentage
4 return number
5 as
6 begin
7 return self.percentage;
8 end get_percentage;
9 end;
10 /
Type body created.
SQL> create table pdv_tab
2 (
3 id number primary key,
4 pdv pdv_typ constraint ch_perc check (pdv.percentage between 0 and 100)
5 );
Table created.
SQL>
SQL> insert into pdv_tab values (1, pdv_typ (1, 'Table', 'Made of oak', 20));
1 row created.
SQL> insert into pdv_tab values (2, pdv_typ (2, 'Chair', 'Made of steel', 120));
insert into pdv_tab values (2, pdv_typ (2, 'Chair', 'Made of steel', 120))
*
ERROR at line 1:
ORA-01438: value larger than specified precision allowed for this column
SQL> insert into pdv_tab values (3, pdv_typ (3, 'Window', 'Made of glass', -5));
insert into pdv_tab values (3, pdv_typ (3, 'Window', 'Made of glass', -5))
*
ERROR at line 1:
ORA-02290: check constraint (SCOTT.CH_PERC) violated
SQL>
Personally, I really, really don't like object side of Oracle. For me, it is a relational DBMS. Object support came as if they wanted to say hey, look, we can do that too!. I can't remember whether I ever used that functionality, except for educational purposes. Drawbacks? Plenty. Benefits? None. Once again, from my point of view.
So, what are you, really, doing? This is not a real-life problem, is it? That suggests your comment, saying that it has to be done that way. Says who? If it is a client, tell him to mind his own business. If it is a professor, then do what he says, regardless.
The straightforward way to do this would be a CHECK constraint on the table. That could be as simple as:
create table Product (
productID number primary key
, name varchar2(30) not null
, description varchar2(128) not null
, percentage number check (percentage between 0 and 100)
);
Demo in SQL Fiddle.

ORA-20010: DBMS_STATS INTERNAL ERROR in fill_cstats : both dmin/dmax and nmin/nmax are null for table SOA , column KEY , ssize 29892

ORA-20010: DBMS_STATS INTERNAL ERROR in fill_cstats : both dmin/dmax and nmin/nmax are null for table SOA, column KEY , ssize 29892
ORA-06512: at "MOSTI", line 165
ORA-06512: at line 1
The above error occurred in production, can someone please explain why it has occurred and solution?
It seems due to an oracle internal bug.
ORA-20010: DBMS_STATS INTERNAL ERROR In Fill_cstat During Analyze A
Table (文档 ID 2247315.1)
Getting following error when gathering the table statistics:
EXEC DBMS_STATS.gather_table_stats(ownname => 'S', tabname => 'TEST',
estimate_percent => 100, cascade => TRUE, granularity=> 'ALL', degree
=> 2, no_invalidate=>FALSE);
* ERROR at line 1: ORA-20010: DBMS_STATS INTERNAL ERROR in fill_cstats : both dmin/dmax and nmin/nmax are null for table S.TEST , column
FIRST_NAME , ssize 430241 ORA-06512: at "SYS.DBMS_STATS", line 34757
ORA-06512: at line 1
The bug is fixed in 12.2
Workaround for the bug is to delete statistics and re-gather statistics
If the above workaround does not work, another potential workaround is using parallel degree of 1:
SYS#EXEC DBMS_STATS.gather_table_stats(ownname => 'SCOTT', tabname => 'TEST', estimate_percent => 100, cascade => TRUE, degree => 1);
but it matches oracle 12.1

ORA-04088: error during execution of trigger

I am facing following problem. I created a table with following sql in Oracle 11g release 2:
create table loc_aud
(
username varchar2(20),
audittime date,
IP VARCHAR2(30),
locno number(4),
old_city number(4),
new_city number(4)
);
This table is in sys schema. Then I created a trigger for value base auditing using following command in sys schema
CREATE OR REPLACE TRIGGER location_audit
AFTER UPDATE OF city
ON hr.locations
REFERENCING NEW AS NEW OLD AS OLD
FOR EACH ROW
BEGIN
IF :old.city != :new.city THEN
INSERT INTO loc_aud
VALUES (user, sysdate, UTL_INADDR.get_host_address,
:new.location_id,:old.city,:new.city);
END IF;
END;
After that I connected with hr schema and tried to update the city column with following command:
update locations set city = 'Dhaka' where location_id = 2100;
But it is giving me following errors
update locations set city = 'Dubai' where location_id = 2100
*
ERROR at line 1:
ORA-01722: invalid number
ORA-06512: at "SYS.LOCATION_AUDIT", line 3
ORA-04088: error during execution of trigger 'SYS.LOCATION_AUDIT'
What am I doing wrong?
The table I created named loc_aud had a wrong datatype. The column city was varchar2 and what I tried to save in it was a number datatype. I altered the table and it worked.

varrays oracle ORA-02330

I'm develop a simple app for learn about oracle and database object-relational with objects and varrays... I did the next code:
this is my varrays
SQL> create or replace type software_va as varray(3) of varchar2(30);
2 /
here is an object that I created:
SQL> create or replace type cargo1 as object(
2 id_cargo number,
3 nom_cargo varchar2(20),
4 suc ref sucursal);
5 /
when I try to create the table at this way:
SQL> create table cargos of cargo1(
2  primary key(id_cargo),
3  manejosoft software_va);
I got this error:
ERROR en line 3:
ORA-02330: datatype specification not allowed
I don't understand why I got this error and don't know if I have something wrong
If you want a relational table with both object and varray columns, this should work, and still has a primary key based on the object's ID:
create table cargos
(
cargo cargo1,
manejosoft software_va,
constraint cargos_pk primary key (cargo.id_cargo)
);
Table created.
insert into cargos values (cargo1(1, 'test'), software_va('a', 'b', 'c'));
1 row created.
insert into cargos values (cargo1(1, 'dup test'), software_va('d', 'e', 'f'));
insert into cargos values (cargo1(1, 'dup test'), software_va('d', 'e', 'f'))
*
ERROR at line 1:
ORA-00001: unique constraint (SCOTT.CARGOS_PK) violated
select * from cargos;
CARGO(ID_CARGO, NOM_CARGO)
--------------------------------------------------------------------------------
MANEJOSOFT
--------------------------------------------------------------------------------
CARGO1(1, 'test')
SOFTWARE_VA('a', 'b', 'c')
select c.cargo.nom_cargo
from cargos c
where c.cargo.id_cargo = 1;
CARGO.NOM_CARGO
--------------------
test
If you wanted an object table then you couldn't have the varray column as mentioned in comments:
create table cargos of cargo1
(
primary key(id_cargo)
);

Resources