I have been racking my brain for some time but I am unable to find a way to retrieve the Operator definition in either Toad or SQL Developer.
We have a user defined operator in our support Application Database and I can see it in all_objects dictionary but I am not able to retrieve its definition.
Is there a way to do that?
I have already been through the oracle documentation but I can't seem to find anything about operators, except how to create one.
Oracle Link 1
Oracle Link 2
Simply use dbms_metadata package and specifically get_ddl() function to extract DDL for an operator as you would use it to extract DDL for tables, views, and other database objects:
Here is an example:
create or replace function multf(
arg1 in number,
arg2 in number
) return number
is
begin
return arg1 * arg2;
end;
/
create or replace operator mult
binding (number, number)
return number
using multf;
/
select dbms_metadata.get_ddl('OPERATOR', 'MULT')
from dual
Result of the query:
OP_DDL
--------------------------------------------------------
CREATE OR REPLACE OPERATOR "NK"."MULT" BINDING
(NUMBER, NUMBER) RETURN NUMBER
USING "MULTF"
Related
I have a requirement to return a subset of rows from a table using FOR UPDATE SKIP LOCKED. Based on application parameters this subset may or may not be ordered by a column. I can't use ROWNUM since the numbers are assigned before SKIP LOCKED happens, so using cursors and FETCH ... LIMIT seems to be the way to go.
That works using an anonymous PL/SQL block, but I need to expose the data back to the java application. The most straightforward way would be to use a table function, so I can just do SELECT * FROM table(my_function(<params>)).
I tried a standard table function returning a collection first, but I got the error [902] ORA-00902: invalid datatype. This is roughly what I had in place:
Package specification:
CREATE OR REPLACE PACKAGE ACTIVITY_UTILS AS
TYPE ActivityList IS TABLE OF ACTIVITY_TABLE%ROWTYPE;
FUNCTION activity_batch(batch_size IN INTEGER, order_by_source IN VARCHAR2)
RETURN ActivityList;
END ACTIVITY_UTILS;
Package body:
CREATE OR REPLACE PACKAGE BODY ACTIVITY_UTILS AS
FUNCTION activity_batch(batch_size IN INTEGER, order_by_source IN VARCHAR2)
RETURN ActivityList
IS
batch ActivityList := ActivityList();
selectStatement VARCHAR2(200);
TYPE CursorType IS REF CURSOR;
activitiesCursor CursorType;
BEGIN
IF UPPER(order_by_source) = 'TRUE' THEN
selectStatement := 'SELECT * FROM ACTIVITY_TABLE ORDER BY source FOR UPDATE SKIP LOCKED';
ELSE
selectStatement := 'SELECT * FROM ACTIVITY_TABLE FOR UPDATE SKIP LOCKED';
OPEN activitiesCursor FOR selectStatement;
FETCH activitiesCursor BULK COLLECT INTO batch LIMIT batch_size;
CLOSE activitiesCursor;
RETURN batch;
END activity_batch;
While debugging the ORA-00902 error I ran into this question:
Return collection from packaged function for use in select
My (limited) understanding was I was trying to use a PL/SQL type on plain SQL, which is not allowed. I tried using a pipelined table function, as mentioned in the answer, but then I got the error ORA-14551: cannot perform a DML operation inside a query.
This seemed odd, is SELECT ... FOR UPDATE considered DML? At any rate, I noticed I could workaround this by using pragma autonomous_transaction, but that defeats the purpose of having FOR UPDATE SKIP LOCKED.
My question is, is this requirement achievable at all using functions, or would I have to use a procedure with an OUT parameter?
Option 1: create a function (or procedure) that returns a cursor and let your java application fetch it normally.
Option 2: Use Implicit statement results: in this case your java application can run something like call proc() where proc returns implicit statement results.
PS. It's not a good idea to hide DML under SQL select...
I'm making a procedure inside an Oracle Form that calls a backtracking which inserts in a table (the solution table). That backtracking is fed by a varray (ítem_array) of ítems (beans). Problem is the compiler says that there is no function name ítem.
existing objects in the database:
CREATE TYPE item IS object( NUM_OPERACIO NUMBER, TITULS NUMBER);
CREATE TYPE item_array IS VARRAY(1000) OF item;
create table my_table (NUM_OPERACIO NUMBER, TITULS NUMBER);
insert into my_table ( NUM_OPERACIO,TITULS ) values (1,10);
insert into my_table ( NUM_OPERACIO,TITULS ) values (2,20)
insert into my_table ( NUM_OPERACIO,TITULS ) values (3,30)
procedure
PROCEDURE solver
IS
arr item_array;
BEGIN
SELECT item( NUM_OPERACIO,TITULS )
BULK COLLECT INTO arr
FROM my_table;
delete from solucion ;
backtra(arr,1,0,30);
END;
What can I do to solve this?
That is a PLS error number. From the documentation:
"PLS-00591: this feature is not supported in client-side programs
Cause: One of the following features was used in a wrong context: pragma AUTONOMOUS_TRANSACTION, dynamic SQL statements, (e.g. EXECUTE IMMEDIATE), and bulk binds. These listed features can only be used in server-side programs but not client-side programs."
Your code uses a bulk-bind, so the error fits. Forms PL/SQL and database PL/SQL are similar but they use different engines, and features supported in both is only a sub-set of all features in either. The solution is to pass the array population into a database procedure and call it from Forms as needed.
Without knowing precisely what problem you're trying to solve, it's harder to give a better answer.
I was trying to explore Oracle Collection and Record type. How do they work ? I wrote below script, but unable to compile them. What is wrong here ?
create or replace package pkg is
type ty_rec is record(empno emp.empno%type,ename emp.ename%type,sal emp.sal%type);
end pkg;
/
create or replace package body pkg is
end pkg;
/
create or replace type ty_varray is varray(5) of pkg.ty_rec;
/
create or replace type ty_table is table of pkg.ty_rec;
/
create table tab1(
id number,
col_arr ty_varray,
col_tab ty_table
) nested table col_tab store as tab1_col_tab;
/
Also, anyone could explain the Nested Table vs Varray when we are using them in table column. How do they stores data and which one is faster ?
Note: I'm using scott schema, which has default emp table
Records are a PL/SQL construct. This means they cannot be used in pure SQL statements. So you need to create the "record" type as a pure SQL object:
create or replace type ty_emp_rec as object
(empno number
,ename varchar2(20)
,sal number);
/
create or replace type ty_emp_varray is varray(5) of ty_emp_rec;
/
create or replace type ty_emp_table is table of ty_emp_rec;
/
I agree it would be highly neat if your code worked, not least because the ability to define attributes using the %TYPE syntax would be extremely useful. But alas that's restricted to the PL/SQL engine too.
This limitation is down to the ability to declare heap table columns with user-defined types, as your last example shows. Oracle requires its columns to be strongly-typed. The %TYPE syntax would create all sorts of problems here: consider what would happen if emp.empno changed from NUMBER to VARCHAR2, or vice versa.
It is my understanding that you cannot use a collection in a where clause unless it is defined at the DB level. I have a distinct dislike for random type definitions laying about a schema. It's a religious thing so don't try to dissuade me.
Types contained within a package are cool, because they are easily found and are related to the work at hand. So having said that I have a package that defines a structure (currently a table type collection) that looks like;
TYPE WORD_LIST_ROW IS RECORD(
WORD VARCHAR(255));
TYPE WORD_LIST IS TABLE OF WORD_LIST_ROW;
There is a routine in the package that instantiates and populates an instance of this. It would be useful to be able to use the instantiated object, or some analog therof in a where clause.
So being the clever (or so I thought) programmer, I said why don't I just create a pipelined function to make a table from the collection which I did, and it looks like;
FUNCTION WORD_LIST_TABLE(IN_WORD_LIST WORD_LIST) RETURN WORD_LIST PIPELINED
AS
OUT_WORD_LIST WORD_LIST := WORD_LIST();
BEGIN
FOR I IN 1 .. IN_WORD_LIST.COUNT
LOOP
PIPE ROW(IN_WORD_LIST(I));
END LOOP;
RETURN;
END WORD_LIST_TABLE;
Then in another routine I call the function that builds the collection, finally I use a pipelined function that uses the collection as input in a cursor's where clause.
sort of like this;
cursor xyz
is
select * from x-stuff where fieldA in (select word from table(word_list_table(temp_word_list));
In the loop for the cursor I get an oracle error ora-21700 object does not exist or is marked for delete.
Is there any easy way to build an oracle object that can be used in an Oracle where clause? Basically what I would like to do is;
select * from whatever where fielda in myobject;
The solution is simple - declare the type at schema level using CREATE TYPE statement and you will be able to use your collections in your SQL statements in PL/SQL blocks.
If you have declared your TYPE inside a PL/SQL package you cannot use it in your queries inside PL/SQL blocks.
Also, you must keep in mind that only varray and nested table type collections can be used in queries as of Oracle 11.2 and you cannot use associative arrays in queries.. In 12c you don't have these restrictions.
For further reference go to Oracle Docs.
I see Oracle procedures sometimes written with "AS", and sometimes with "IS" keyword.
CREATE OR REPLACE Procedure TESTUSER.KILLINSTANCE (INSTANCEID integer) **AS**
...
vs.
CREATE OR REPLACE Procedure TESTUSER.KILLINSTANCE (INSTANCEID integer) **IS**
...
Is there any difference between the two?
Edit: Apparently, there is no functional difference between the two, but some people follow a convention to use "AS" when the SP is part of a package and "IS" when it is not. Or the other way 'round. Meh.
None whatsover. They are synonyms supplied to make your code more readable:
FUNCTION f IS ...
CREATE VIEW v AS SELECT ...
One minor difference...
They are synonyms for packages and procedures, but not for cursors:
This works...
cursor test_cursor
is
select * from emp;
... but this doesn't:
cursor test_cursor
as
select * from emp;
"IS" and "AS" act as a synonym while creating procedures and packages but not for a cursor, table or view.
Here's another difference (in 10g, at any rate)
Given a loose object type:
CREATE TYPE someRecordType AS OBJECT
(
SomeCol VARCHAR2(12 BYTE)
);
You can create a loose Table type of this object type with either AS or IS
CREATE OR REPLACE TYPE someTableType
IS {or AS} TABLE OF someRecordType;
However, if you create this same table type within a package, you must use IS:
CREATE OR REPLACE PACKAGE SomePackage IS
TYPE packageTableType IS TABLE OF someRecordType;
END SomePackage;
Use of AS in the package yields the following error:
Error(2,30): PLS-00103: Encountered the symbol "TABLE" when expecting one of the following: object opaque
According to TutorialsPoint
The AS keyword is used instead of the IS keyword for creating a
standalone procedure.
and considering previous answers,
I guess
AS is for stand alone (outside of any block, subprogram, package) entities
and
IS is for embedded (within a block, subprogram or package) entities.
.
The AS keyword is used instead of the IS keyword for creating a standalone function.
[ A standalone stored function is a function (a subprogram that returns a single value) that is stored in the database.
Note: A standalone stored function that you create with the CREATE FUNCTION statement is different from a function that you declare and define in a PL/SQL block or package. ]
For more explanation, read this...