Alter/Evolve Type User Defined Constructor Function Signature (PL/SQL) - oracle

How does one evolve a user defined constructor function signature?
Given an Oracle PL/SQL user defined type that has table dependents, instead of replacing them with create/replace statements I need to evolve these types. I found Oracle documentation on how to drop/add attributes, and drop/add member functions via alter statements, but I do not see information on how to evolve a constructor function signature. I need to do this without creating a new table/type and migrating data over to the new updated type. In my case, using FORCE does not work either.
For example, given the type below, how could I update the user defined constructor signature to include a new parameter to use during initialization?
-- Create new type
CREATE OR REPLACE TYPE test_type AS OBJECT (
test_attribute NUMBER(1, 0),
CONSTRUCTOR FUNCTION test_type(
p_test_attribute NUMBER DEFAULT NULL
)
RETURN SELF AS RESULT
);
-- Make this new type have table dependents
CREATE OR REPLACE TYPE test_type_table
AS TABLE OF test_type;
CREATE TYPE test_child_obj AS OBJECT (
test_type_field test_type_table
);
-- Add new attribute via alter statement
ALTER TYPE test_type
ADD ATTRIBUTE (new_attribute NUMBER)
CASCADE NOT INCLUDING TABLE DATA;
I would like to update the constructor signature to the following:
CONSTRUCTOR FUNCTION test_type(
p_test_attribute NUMBER DEFAULT NULL,
p_new_attribute NUMBER DEFAULT NULL
)
RETURN SELF AS RESULT
I was hoping there would be an alter statement like the following, but I cannot find a proper alter statement. Please help.
ALTER TYPE test_type
ADD CONSTRUCTOR FUNCTION test_type(
p_test_attribute NUMBER DEFAULT NULL,
p_new_attribute NUMBER DEFAULT NULL
)
RETURN SELF AS RESULT
CASCADE NOT INCLUDING TABLE DATA;

It turns out that the alter statement is in fact the one stated above and shown below. However, you can run into "too many declarations of 'test_type' match this call". In my real problem, the issue was all my constructor parameters have default NULL values and conflicted with my original constructor that all had default NULL parameters. If I take away the DEFAULT NULL, I can add new constructors.
ALTER TYPE test_type
ADD CONSTRUCTOR FUNCTION test_type(
p_test_attribute NUMBER DEFAULT NULL,
p_new_attribute NUMBER DEFAULT NULL
)
RETURN SELF AS RESULT
CASCADE NOT INCLUDING TABLE DATA;

Related

Accessing table from an object

Is it possible to access an existing table from an object?
Here the simplified snippet:
CREATE OR REPLACE TYPE MYOBJ AS OBJECT(
MEMBER PROCEDURE MYEXPORT( ERRORS.ERRORS_ID%TYPE));
ERRORS is a table. When I write it like above I'm getting error:
PLS-00201 - identifier must be declared.
Any clue? Thanks!
You have three issues:
The syntax is
MEMBER PROCEDURE procedure_name (argument_name data_type)
You have specified the data type but not an argument name which is why you get the error message PLS-00201 - identifier must be declared. as you need to specify an identifier for the argument.
table_name.column_name%TYPE declarations can be used in the PL/SQL scope but not in the SQL scope. Your object declaration is in the SQL scope so you need to fully define the data type rather than referring to a column.
An object must have at least one attribute.
You want:
CREATE OR REPLACE TYPE MYOBJ AS OBJECT(
attr1 NUMBER,
MEMBER PROCEDURE MYEXPORT( v_errors_id NUMBER )
);

record linking to each other in PL/SQL Developer

There was a need to create records in PL / SQL Developer, which refer to each other. I started to understand all this recently, therefore there were doubts about the achievement of this goal, but also the thought was spinning in my head that I was not the first to ask this question. Therefore, if you know how to do it or have ideas for implementation, I will be very glad of your help, but for now I will continue to google.
Example:
TYPE rtype1 IS RECORD
(
/*some code*/
r_type2 rtype2;
);
TYPE rtype2 IS RECORD
(
/*some code*/
r_type1 rtype1;
);
Additional Information:
The fact is that, on the basis of xsd schemes, you need to generate records and collections, but because In the xsd scheme this is not prohibited, such a need has arisen. And it is necessary to create types, and not to use the tools for working with xml.
You can use forward declaration to declare the existence of a type in PL/SQL before you fully specify it. Like this:
DECLARE
TYPE rtype2; -- Forward declaration
TYPE rtype1 IS RECORD( r_type2 rtype2 );
TYPE rtype2 IS RECORD( r_type1 INTEGER );
BEGIN
NULL;
END;
/
However, you cannot use this to declare a non-REF mutually recursive type; if you try this:
DECLARE
TYPE rtype2;
TYPE rtype1 IS RECORD( r_type2 rtype2 );
TYPE rtype2 IS RECORD( r_type1 rtype1 );
BEGIN
NULL;
END;
/
Then you get the error:
ORA-06550: line 4, column 18:
PLS-00318: type "RTYPE2" is malformed because it is a non-REF mutually recursive type
ORA-06550: line 4, column 3:
PL/SQL: Item ignored
You can do it using object data types and a REF in the SQL scope:
CREATE TYPE otype1; -- Forward declaration
CREATE TYPE otype2 IS OBJECT( o_type1 REF otype1 );
CREATE OR REPLACE TYPE otype1 IS OBJECT( o_type2 otype2 );
But, again, if you try to use a non-REF mutually recursive type:
CREATE TYPE otype1;
CREATE TYPE otype2 IS OBJECT( o_type1 otype1 );
/* ORA-24344: success with compilation error */
CREATE TYPE otype1 IS OBJECT( o_type2 otype2 );
/* ORA-04055: Aborted: "OTYPE1" formed a non-REF mutually-dependent cycle with "OTYPE2". */
Then it doesn't work.
db<>fiddle here
Yes, you can define a type and then reference it in another type, which you define later in the code or on the system. However, as Alex asked, what are you trying to accomplish? -- Also contrary to what mathguy posted you can create and use types whose definitions are co-dependent. I do not recommend doing so, but ...
From the documentation:
An incomplete type is a type created by a forward type definition. It is called incomplete because it has a name but no attributes or methods. It can be referenced by other types, allowing you define types that refer to each other. However, you must fully specify the type before you can use it to create a table or an object column or a column of a nested table type.

Create Type based on an exiting Table

As the title said : I want to create a type in oracle based on an existing Table.
I did as follow :
create or replace type MY_NEW_TYPE as object( one_row EXISTING_TABLE%rowtype);
The Aim is to be able to use this into a function which will return a table containing sample row of the table EXISTING_TABLE :
create or replace function OUTPUT_FCT() return MY_NEW_TYPE AS
...
If you only need to create a function that returns a row from your table, you could try something like the following, without creating types.
setup:
create table EXISTING_TABLE( a number, b varchar2(100));
insert into EXISTING_TABLE values (1, 'one');
function:
create or replace function OUTPUT_FCT return EXISTING_TABLE%rowtype AS
retVal EXISTING_TABLE%rowType;
begin
select *
into retVal
from EXISTING_TABLE
where rownum = 1;
--
return retVal;
end;
function call
SQL> begin
2 dbms_output.put_line(OUTPUT_FCT().a);
3 dbms_output.put_line(OUTPUT_FCT().b);
4 end;
5 /
1
one
However, I would not recommend such an approach, because things like select * can be really dangerous; I would much prefer defining a type with the fields I need, and then explicitly query my table for the needed columns.
No, you can't do that, you'll get a compilation error:
create or replace type my_new_type as object(one_row t42%rowtype);
/
Type MY_NEW_TYPE compiled
Errors: check compiler log
show errors
Errors for TYPE STACKOVERFLOW.MY_NEW_TYPE:
LINE/COL ERROR
-------- -----------------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
1/36 PLS-00329: schema-level type has illegal reference to MYSCHEMA.T42
You will need to specify each field in the object type, and you will have to specify the data types manually too - you can't use table.column%type either.
You could create the type dynamically based on column and data type information from the data dictionary, but as this will (hopefully) be a one-off task and not something you'd do at runtime, that doesn't really seem worth it.
You can create a PL/SQL table type based on your table's rowtype, but you would only be able to call a function returning that from PL/SQL, not from plain SQL - so you couldn't use it in a table collection expression for example. If you were only returning a single sample row you could return a record rather than a table, but the same applies. You can also have a function that returns a ref cursor which could match the table's structure, but you wouldn't be able to treat that as a table either.
Read more about object type creation in the documentation. Specifically the attribute and datatype sections.

Type without body in Oracle PL/SQL

I'm having problems tracking an array initialized to an empty Type (table of varchar2) object. It's inside a loop and outputs indexes from what I think is coming from the database. I've done my research with the "as table of varchar2" and I think it just simply means a column of a table with varchar as a type.
From what I understood, the "invArry" declared as the type "item_val" in the "item_inv" header just basically means invArry is a varchar, since item_val is a varchar right? But I got confused when in the item_inv body, the invArry is initialized to item_val again. Was it initialized to a varchar again? Or does the type item_val already pointing out to a column in the database? If it's the latter, I'm not sure how it got pointed to the database.
create or replace TYPE "item_inv" AS OBJECT
(invArry item_val, --invArry declared as item_val
CONSTRUCTOR FUNCTION item_inv
RETURN SELF AS RESULT,
CONSTRUCTOR FUNCTION item_inv( recrd VARCHAR2 )
RETURN SELF AS RESULT,
) FINAL;
=========
create or replace TYPE BODY "item_inv" AS
CONSTRUCTOR FUNCTION item_inv
RETURN SELF AS RESULT
IS
BEGIN
invArry := item_val --invArry initialized to item_val. Whut
RETURN;
END;
=========
create or replace TYPE "item_val" AS TABLE OF VARCHAR2( 240 );
--item_val object, does this points already to the database or just an empty object
You've defined item_val as a nested table collection.
In your object type invArry is of that type, so it is a nested table - that is, an unordered collection of strings, each of which is up to 240 characters.
In your object type body you're initialising the invArry to an empty collection:
invArry := item_val();
It is not initialised to a varchar, it's initialised to an empty nested table of varchars. It isn't pointing to any data, table or column in the database. It's a collection which has no elements in it. You can now write code to add elements to that collection. The values could come from elsewhere in the database but there is no automatic link.

Error in creating nested table involving inheritence

I have a somewhat complex structure as follows :
create or replace type user_typ as object(
user_id number(19,0),
username nvarchar2(40 char)
);
I inherit an applicant_typ from this :
create or replace type applicant_typ under user_typ (
resume_text nclob
);
My design involves jobs to which applicants can apply. To this end, I create an application_typ as follows :
create or replace TYPE Application_typ AS OBJECT (
application_id NUMBER,
candidate applicant_typ,
time_of_app DATE
);
CREATE TYPE Application_tab IS TABLE OF Application_typ;
And now I want to create an object type called Job_typ, and a table containing those objects, wherein there will be a nested table for applications :
CREATE OR REPLACE TYPE Job_typ AS OBJECT (
job_ID NUMBER,
company_ID NUMBER,
description NVARCHAR2(1000),
name NVARCHAR2(200),
application Application_tab,
MAP MEMBER FUNCTION job_no RETURN NUMBER,
MEMBER PROCEDURE no_of_applicants
);
All of this works fine. The issue is when I try to create a table of type Job_typ :
CREATE TABLE Job_tab OF Job_typ
NESTED TABLE application STORE AS application_nt;
This doesn't work, giving the error :
SQL Error: ORA-02320: failure in creating storage table for nested table column APPLICATION
ORA-22913: must specify table name for nested table column or attribute
02320. 00000 - "failure in creating storage table for nested table column %s"
*Cause: An error occurred while creating the storage table for the
specified nested table column.
What am I doing wrong?
EDIT : I tried some different things. If I change application_typ as follows :
CREATE OR REPLACE TYPE Application_typ AS OBJECT (
application_id NUMBER,
candidate User_Typ, -- NOTE: This attribute is now of type User_typ instead of the inherited type
time_of_app DATE,
);
CREATE TYPE Application_tab IS TABLE OF Application_typ;
Then everything else works, and I am able to create the Job table. Why do I get the error on using the inherited type?
I tried the following in Oracle 11.2.0.1 and didn't get any error. I made a slight change though:
CREATE OR REPLACE TYPE user_typ AS OBJECT
(
user_id NUMBER (19, 0),
username NVARCHAR2 (40 CHAR)
) NOT FINAL; -- << Notice the NOT FINAL keyword
create or replace type applicant_typ under user_typ (
resume_text nclob
);
CREATE OR REPLACE TYPE Application_typ AS OBJECT
(
application_id NUMBER,
candidate applicant_typ,
time_of_app DATE
);
CREATE TYPE Application_tab IS TABLE OF Application_typ;
CREATE OR REPLACE TYPE Job_typ AS OBJECT
(
job_ID NUMBER,
company_ID NUMBER,
description NVARCHAR2 (1000),
name NVARCHAR2 (200),
application Application_tab,
MAP MEMBER FUNCTION job_no
RETURN NUMBER,
MEMBER PROCEDURE no_of_applicants
);
CREATE TABLE Job_tab OF Job_typ
NESTED TABLE application
STORE AS application_nt;
While trying to create all your types and keywords, I got the error:
[Error] PLS-00590 (10.1): PLS-00590: attempting to create a subtype UNDER a FINAL type
This is because Oracle doesn't allow creation of a subtype on a FINAL type. If you don't define any finalizing clause for the base type, the default is FINAL.
Read more on Oracle Docs.
If you are coding for the real world (read industry), I'd advise against using nested tables as column types. You end up spending your entire life trying to nest and un-nest these. I'd suggest you normalize your schema as much as you can or need and leave nested tables for operations in PL/SQL code blocks.

Resources