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 )
);
Related
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;
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.
In oracle database I have created type
CREATE OR REPLACE TYPE DOSSIER_RESULT AS OBJECT
(
id number,
user_id number
)
Then I created the collection of this type
CREATE OR REPLACE TYPE DOSSIER_RESULTS_ARRAY AS TABLE OF DOSSIER_RESULT
Then I added one more attribute in first type definition like this
CREATE OR REPLACE TYPE DOSSIER_RESULT AS OBJECT
(
id number,
user_id number,
child DOSSIER_RESULTS_ARRAY
)
But it compiled with error
Error: PLS-00201: identifier 'DOSSIER_RESULTS_ARRAY' must be declared
The question is: How can I create an Object type with collection of objects of this type in it?
I am trying to create a type with the rowid data type, but I am getting this error because of the type I am trying to use:
SQL> CREATE TYPE join_t IS OBJECT (inn rowid, out rowid );
/
Warning: Type created with compilation errors.
Even though I can create a table with rowid data type:
SQL> create table test_rowid (inn rowid,out rowid);
Table created.
Is it possible to create this type join_t above, with rowid-type attributes?
No, you can't create an object type with rowid fields. If you looks at the actual error raised, via the user_errors view or with the SQL*Plus command show errors, you will see:
LINE/COL ERROR
-------- ------------------------------------------------------------------------------
1/28 PLS-00530: Illegal type used for object type attribute: 'ROWID'.
1/39 PLS-00530: Illegal type used for object type attribute: 'ROWID'.
The documenation says:
Restrictions on datatype
You cannot impose the NOT NULL constraint on an attribute.
You cannot specify attributes of type ROWID, LONG, or LONG RAW.
You cannot specify a data type of UROWID for an ADT.
...
As a workaround, you could potentially use a string type in your object, and convert the values when setting to getting the field values, via the rowidtochar and chartorowid functions:
CREATE TYPE join_t IS OBJECT (inn varchar2(18), out varchar2(18) );
/
Type JOIN_T compiled
SELECT join_t(rowidtochar(rowid), rowidtochar(rowid)) FROM DUAL;
JOIN_T(ROWIDTOCHAR(ROWID),ROWIDTOCHAR(ROWID))(INN, OUT)
-------------------------------------------------------
JOIN_T('AAAAB0AABAAAAOhAAA', 'AAAAB0AABAAAAOhAAA')
Storing rowids in an object doesn't seem particularly useful though, as they can change.
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.