PLS-00539: subprogram is declared in an object type body and must be defined in the object type specification - plsql

I'm trying to create subclass item_t from base class base_t, but it gives me errors:
PLS-00539: subprogram 'ITEM_T' is declared in an object type body and must be defined in the object type specification
PLS-00538: subprogram or cursor 'ITEM_T' is declared in an object type specification and must be defined in the object type body
Have no idea what is wrong. Could you please help.
-- Open log file.
SPOOL example.txt
DROP TYPE item_t FORCE;
DROP TYPE base_t FORCE;
CREATE OR REPLACE TYPE base_t IS OBJECT
(oname VARCHAR2(30)
, name VARCHAR2(30)
, CONSTRUCTOR FUNCTION base_t RETURN SELF AS RESULT
, CONSTRUCTOR FUNCTION base_t (oname VARCHAR2, name VARCHAR2) RETURN SELF AS RESULT
, MEMBER FUNCTION get_name RETURN VARCHAR2
, MEMBER FUNCTION get_oname RETURN VARCHAR2
, MEMBER PROCEDURE set_oname (oname VARCHAR2)
, MEMBER FUNCTION to_string RETURN VARCHAR2
) INSTANTIABLE NOT FINAL;
/
CREATE OR REPLACE TYPE BODY base_t IS
CONSTRUCTOR FUNCTION base_t RETURN SELF AS RESULT IS
BEGIN
self.oname := 'BASE_T';
RETURN;
END base_t;
CONSTRUCTOR FUNCTION base_t (oname VARCHAR2, name VARCHAR2) RETURN SELF AS RESULT IS
BEGIN
self.oname := oname;
self.name := name;
RETURN;
END base_t;
MEMBER FUNCTION get_name RETURN VARCHAR2 IS
BEGIN
RETURN NVL(self.name, NULL);
END get_name;
MEMBER FUNCTION get_oname RETURN VARCHAR2 IS
BEGIN
RETURN self.oname;
END get_oname;
MEMBER PROCEDURE set_oname (oname VARCHAR2) IS
BEGIN
self.oname := oname;
END set_oname;
MEMBER FUNCTION to_string RETURN VARCHAR2 IS
BEGIN
return '['||self.oname||']';
END to_string;
END;
/
SET PAGESIZE 999
SET SERVEROUTPUT ON
DROP TABLE logger;
/
DROP SEQUENCE logger_s;
/
CREATE SEQUENCE logger_s;
CREATE TABLE logger
(logger_id NUMBER
, log_text base_t);
/
DECLARE
/* Declare a variable of the UDT type. */
lv_base BASE_T;
BEGIN
/* Assign an instance of the variable. */
lv_base := base_t(
oname => 'BASE_T'
, name => 'NEW' );
/* Insert instance of the base_t object type into table. */
INSERT INTO logger
VALUES (logger_s.NEXTVAL, lv_base);
/* Commit the record. */
COMMIT;
END;
/
COLUMN oname FORMAT A20
COLUMN get_name FORMAT A20
COLUMN to_string FORMAT A20
SELECT t.logger_id
, t.log.oname AS oname
, NVL(t.log.get_name(),'Unset') AS get_name
, t.log.to_string() AS to_string
FROM (SELECT l.logger_id
, TREAT(l.log_text AS base_t) AS log
FROM logger l) t
WHERE t.log.oname = 'BASE_T';
CREATE OR REPLACE
TYPE item_t UNDER base_t
( item_id NUMBER
, item_barcode VARCHAR2(20)
, item_type NUMBER
, item_title VARCHAR2(60)
, item_subtitle VARCHAR2(60)
, item_rating VARCHAR2(8)
, item_rating_agency VARCHAR2(4)
, item_release_date DATE
, created_by NUMBER
, creation_date DATE
, last_update_by NUMBER
, last_update_date DATE
, CONSTRUCTOR FUNCTION item_t
( oname VARCHAR2
, name VARCHAR2
, item_id NUMBER
, item_barcode VARCHAR2
, item_type NUMBER
, item_title VARCHAR2
, item_subtitle VARCHAR2
, item_rating VARCHAR2
, itmer_rating_agency VARCHAR2
, item_realease_date DATE
, created_by NUMBER
, creation_date DATE
, last_update_by NUMBER
, last_update_date DATE) RETURN SELF AS RESULT
, OVERRIDING MEMBER FUNCTION get_name RETURN VARCHAR2
, OVERRIDING MEMBER FUNCTION to_string RETURN VARCHAR2)
INSTANTIABLE NOT FINAL;
/
CREATE OR REPLACE
TYPE BODY item_t IS
CONSTRUCTOR FUNCTION item_t
( oname VARCHAR2
, name VARCHAR2
, item_id NUMBER
, item_barcode VARCHAR2
, item_type NUMBER
, item_title VARCHAR2
, item_subtitle VARCHAR2
, item_rating VARCHAR2
, item_rating_agency VARCHAR2
, item_release_date DATE
, created_by NUMBER
, creation_date DATE
, last_update_by NUMBER
, last_update_date DATE)
RETURN SELF AS RESULT IS
BEGIN
self.oname := oname;
self.name := name;
self.item_id := item_id;
self.item_barcode := item_barcode;
self.item_type := item_type;
self.item_title := item_title;
self.item_subtitle := item_subtitle;
self.item_rating := item_rating;
self.item_rating_agency := item_rating_agency;
self.item_release_date := item_release_date;
self.created_by := created_by;
self.creation_date := creation_date;
self.last_update_by := last_update_by;
self.last_update_date := last_update_date;
RETURN;
END item_t;
OVERRIDING MEMBER FUNCTION get_name RETURN VARCHAR2 IS
BEGIN
RETURN NVL(self.name, NULL);
END get_name;
OVERRIDING MEMBER FUNCTION to_string RETURN VARCHAR2 IS
BEGIN
return (self AS base_t).to_string()||'['||self.oname||'].[' || self.name || ']';
END to_string;
END;
/
SPOOL OFF

there are typos in the parameter names in specification for type_t
, itmer_rating_agency VARCHAR2 --> item_rating_agency
, item_realease_date DATE --> item_release_date
And because of those typos oracle sees constructor functions different and errors it out

Related

How to use table functions

I was trying to use tabel functions but after creating this block:
create table tmp_ft
(field VARCHAR2 ( 1000 ));
DECLARE
TYPE names_nt IS TABLE OF VARCHAR2 ( 1000 );
FUNCTION lotsa_names (
base_name_in IN VARCHAR2
, count_in IN INTEGER
)
RETURN names_nt
IS
retval names_nt := names_nt ( );
BEGIN
retval.EXTEND ( count_in );
FOR indx IN 1 .. count_in
LOOP
retval ( indx ) := base_name_in || ' ' || indx;
END LOOP;
RETURN retval;
END lotsa_names;
BEGIN
insert into tmp_ft
SELECT *
FROM TABLE ( lotsa_names ( 'Steven', 5 )) ;
END;
/
I get the following error:
ORA-06550: line 26, column 15:
PLS-00231: function 'LOTSA_NAMES' may not be used in SQL
Why? It seems all is ok but I can't understand why it doesn't work
Thanks!
Because the function and the type you are using are defines locally to the anonymous block. Thus they cannot be used outside of that block. In Oracle there are separate engines for SQL and PLSQL. So any SQL actually runs outside the block. You need to define the type and function at the schema level.
create table tmp_ft
(field VARCHAR2 ( 1000 ));
create type names_nt is table of varchar2 ( 1000 );
create or replace
function lotsa_names (
base_name_in in varchar2
, count_in in integer
)
return names_nt
is
retval names_nt := names_nt ( );
begin
retval.extend ( count_in );
for indx in 1 .. count_in
loop
retval ( indx ) := base_name_in || ' ' || indx;
end loop;
return retval;
end lotsa_names;
--======= Test =========
begin
insert into tmp_ft
select *
from table ( lotsa_names ( 'Steven', 5 )) ;
end;
select * from tmp_ft;

The insertion part is not getting executed

procedure pod_tag_name (p_TAG_NAME in varchar2,
p_status out varchar2,
p_status_dtl out varchar2)
is
v_tag_name varchar2(100);
begin
v_tag_name := get_tag_name(p_TAG_NAME);
if v_tag_name = '' THEN
insert into pod_tagmaster (TAG_ID,TAG_NAME_NEW , CREATEDBY,
CREATEDDATE,UPDATED_BY, UPDATED_DATE,TAG_NAME_OLD)
values (POD_UNIQUE_VAL_SEQ.NEXTVAL,p_TAG_NAME , null ,
sysdate,null, sysdate, v_tag_name);
v_rec_cnt := sql%rowcount;
commit;
p_status_dtl := v_rec_cnt||' Record Inserted Successfully';
else
update pod_tagmaster
set TAG_NAME_NEW = p_TAG_NAME,
TAG_NAME_OLD = v_tag_name,
UPDATED_BY = null,
UPDATED_DATE = sysdate
where TAG_NAME_NEW = p_TAG_NAME;
v_rec_cnt := sql%rowcount;
commit;
p_status_dtl := v_rec_cnt||' Record Updated Successfully';
end if;
p_status := 'SUCCESS';
end;
function get_tag_name(p_TAG_NAME varchar2) return varchar2
is
v_tag_name varchar2(200);
begin
select TAG_NAME_NEW
into v_tag_name
from pod_tagmaster
where TAG_NAME_NEW = p_TAG_NAME ;
return v_tag_name;
exception
when others then
return '';
end;
end POD_PKG_TAG_MASTER;
Change
if v_tag_name = '' THEN
to
if v_tag_name IS NULL THEN
Also, change
return '';
to
RETURN NULL;
In Oracle a zero-length string is the same as NULL; thus, the equality comparison fails. You must use IS NULL in this case.
Share and enjoy.

i have a function which returns multiple o/p i need to call this function to insert in a table

create or replace type branch_warehouse as object (wh_id number,wh_name varchar2(100));
create or replace type id_warehouse_list as table of branch_warehouse;
function get_ware_house_branch(p_BRANCH_IDS in out varchar2)
return id_warehouse_list is
l_warehouse_list id_warehouse_list := id_warehouse_list();
str varchar2(300);
begin
str := 'SELECT BRANCH_WAREHOUSE(w.wh_id, w.wh_name)
FROM POD_WAREHOUSE_MASTER W
where ( W.BRANCH_ID IN (' || p_BRANCH_IDS || '))';
execute immediate str bulk collect into l_warehouse_list;
for i in l_warehouse_list.first..l_warehouse_list.last loop
dbms_output.put_line(l_warehouse_list(i).wh_id || ', ' || l_warehouse_list(i).wh_name);
end loop;
return l_warehouse_list;
end;
procedure insert_place_warehouse_map(p_PLACE_NAME in varchar2,
p_BRANCH_IDS in number,
p_status out varchar2,
p_status_dtl out varchar2) is
v_ID number;
l_warehouse_list id_warehouse_list := id_warehouse_list();
begin
v_ID := get_place_id (p_PLACE_NAME);
l_warehouse_list := get_ware_house_branch(p_BRANCH_IDS);
for i in l_warehouse_list.first..l_warehouse_list.last loop
insert into pod_place_warehouse_map(
id,
place_id,
wh_id,
wh_name)
values(
pod_unique_val_seq.nextval,
v_ID,
l_warehouse_list(i).wh_id,
l_warehouse_list(i).wh_name);
v_rec_cnt := sql%rowcount;
end loop;
commit;
p_status := 'SUCESS';
p_status_dtl := v_rec_cnt||' Record Inserted Successfully';
exception
when others then
rollback;
p_status_dtl := sqlcode||' - '||substr(sqlerrm,1,100);
p_status := 'ERROR';
end;
i am getting error p_BRANCH_IDS cannot be used as assignment operator in the 2nd code
first code is working,
please help
This is because the parameter is declared as in out in first code, but as in in second.

SYS.DBMS_DDL.WRAP not allowing pragma and intctx

I am using the below procedure to wrap the PL/SQL Code.
declare
l_source DBMS_SQL.VARCHAR2A;
l_wrap DBMS_SQL.VARCHAR2A;
l_wrap1 clob;
typ_ibt utl_file.file_type;
cnt number := 0;
v_directory varchar2(400) := 'd:\ftpedi\eqpm\eqpm_hold\';
cursor cur_name_get is
select distinct name object_name,type object_type
from user_source
where type = 'PROCEDURE'
and name = 'PROCESS_TIME_INSERT';
cursor cut_text_get ( p_type in varchar2 , p_name in varchar2 ) is
select replace(text,chr(10),'') text
from user_source
where type = p_type
and name = p_name;
begin
for i in cur_name_get
loop
l_source.delete;l_wrap.delete;
open cut_text_get ( i.object_type,i.object_name );
fetch cut_text_get bulk collect into l_source;
close cut_text_get;
l_source (1) := 'CREATE OR REPLACE ' || l_source (1);
l_wrap := SYS.DBMS_DDL.WRAP(ddl => l_source,
lb => 1,
ub => l_source.count);
for i in 1..l_wrap.count
loop
if i = 1
then
l_wrap1 := l_wrap(i);
else
l_wrap1 := l_wrap1 || l_wrap(i);
end if;
insert into ibt_global_inter_transfer ( git_process_id,git_c_1)
values ( 3004, l_wrap1 );
end loop;
end loop;
exception when others
then
dbms_output.put_line('sqlerrm '||sqlerrm||dbms_utility.format_error_backtrace);
end;
The above procedures warps the normal procedure, but not allowing the special character like 'PRAGMA'.
The below is the sample procedure, which is not wrapping.
CREATE OR REPLACE
PROCEDURE xml_insert ( p_in_xml in xmltype ,p_status out varchar2,p_message out varchar2) is
intctx DBMS_XMLSTORE.ctxtype;
rows number;
begin
p_status := 'S';
p_message := 'Success';
intctx := Dbms_xmlstore.newcontext('IBT_GLOBAL_INTER_TRANSFER');
dbms_xmlstore.clearupdatecolumnlist(intctx);
dbms_xmlstore.setupdatecolumn(intCtx,'GIT_PROCESS_ID');
dbms_xmlstore.setupdatecolumn(intCtx,'GIT_SESSION_ID');
rows := Dbms_xmlstore.insertxml(intctx,p_in_xml);
dbms_xmlstore.closecontext(intctx);
exception when others
then
p_status := 'R';
p_message := sqlerrm||dbms_utility.format_error_backtrace;
return;
end;
Could anyone help?
Update
(I misunderstood the problem. I thought you meant the wrapped code wasn't created, now I understand the real problem is that the wrapped output does not compile.)
Remove the replace, there needs to be white space between some of the lines.
Replace:
--select replace(text,chr(10),'') text
with:
select text
Procedure:
CREATE OR REPLACE
PROCEDURE xml_insert ( p_in_xml in xmltype ,p_status out varchar2,p_message out varchar2) is
intctx DBMS_XMLSTORE.ctxtype;
rows number;
pragma autonomous_transaction; --ADDED
begin
p_status := 'S';
p_message := 'Success';
intctx := Dbms_xmlstore.newcontext('IBT_GLOBAL_INTER_TRANSFER');
dbms_xmlstore.clearupdatecolumnlist(intctx);
dbms_xmlstore.setupdatecolumn(intCtx,'GIT_PROCESS_ID');
dbms_xmlstore.setupdatecolumn(intCtx,'GIT_SESSION_ID');
rows := Dbms_xmlstore.insertxml(intctx,p_in_xml);
dbms_xmlstore.closecontext(intctx);
exception when others
then
p_status := 'R';
p_message := sqlerrm||dbms_utility.format_error_backtrace;
return;
end;
/
PL/SQL Block wrapping code:
declare
l_source DBMS_SQL.VARCHAR2A;
l_wrap DBMS_SQL.VARCHAR2A;
l_wrap1 clob;
typ_ibt utl_file.file_type;
cnt number := 0;
v_directory varchar2(400) := 'd:\ftpedi\eqpm\eqpm_hold\';
cursor cur_name_get is
select distinct name object_name,type object_type
from user_source
where type = 'PROCEDURE'
and name = 'XML_INSERT'; --CHANGED
cursor cut_text_get ( p_type in varchar2 , p_name in varchar2 ) is
--select replace(text,chr(10),'') text --WOOPS!
select text
from user_source
where type = p_type
and name = p_name;
begin
for i in cur_name_get
loop
l_source.delete;l_wrap.delete;
open cut_text_get ( i.object_type,i.object_name );
fetch cut_text_get bulk collect into l_source;
close cut_text_get;
l_source (1) := 'CREATE OR REPLACE ' || l_source (1);
l_wrap := SYS.DBMS_DDL.WRAP(ddl => l_source,
lb => 1,
ub => l_source.count);
for i in 1..l_wrap.count
loop
if i = 1
then
l_wrap1 := l_wrap(i);
else
l_wrap1 := l_wrap1 || l_wrap(i);
end if;
--insert into ibt_global_inter_transfer ( git_process_id,git_c_1)
--values ( 3004, l_wrap1 );
dbms_output.put_line(l_wrap1);
end loop;
end loop;
exception when others
then
dbms_output.put_line('sqlerrm '||sqlerrm||dbms_utility.format_error_backtrace);
end;
/

Dynamic String contcatination in Cursor

I have a function which concatinates the value for a cursor. Its now only concatinates 4 columns and that column name should be hardcoded. Is there a way to have a generic solution for this, such that if i pass a cursor it will automatically concatinate data regardless of column name and number of columns in 11g.
FUNCTION generateData(p_dataCursor IN SYS_REFCURSOR)
RETURN VARCHAR2 AS
-- ---------------------------------------------------------------------
crlf VARCHAR2(2) := chr(13)||chr(10);
lv_message VARCHAR2(32000);
BEGIN
FOR rec IN p_dataCursor
LOOP
lv_message := lv_message || rec.a||','||rec.b||','||rec.c||','||rec.d || crlf;
END LOOP;
RETURN lv_message;
END;
Since 11g Oracle built-in package DBMS_SQL provides function TO_CURSOR_NUMBER - "This function takes an OPENed strongly or weakly-typed ref cursor and transforms it into a DBMS_SQL cursor number."
Example code:
DECLARE
l_cursor SYS_REFCURSOR;
FUNCTION generateData(p_dataCursor IN SYS_REFCURSOR)
RETURN VARCHAR2 AS
curs SYS_REFCURSOR := p_dataCursor;
l_cursorid NUMBER;
l_column_count INTEGER;
l_describe_table DBMS_SQL.DESC_TAB;
l_numvar NUMBER;
l_ignore INTEGER;
l_value VARCHAR2(2000);
l_coma VARCHAR2(10);
crlf VARCHAR2(2) := chr(13)||chr(10);
lv_message VARCHAR2(32000);
BEGIN
l_cursorid := dbms_sql.to_cursor_number( curs );
dbms_sql.describe_columns( l_cursorid, l_column_count, l_describe_table );
FOR i IN 1..l_column_count LOOP
dbms_sql.define_column(l_cursorid, i, l_value, 2000);
END LOOP;
LOOP
IF DBMS_SQL.FETCH_ROWS(l_cursorid)>0 THEN
l_coma := '';
FOR i IN 1..l_column_count LOOP
dbms_sql.column_value(l_cursorid, i, l_value);
lv_message := lv_message || l_coma || l_value;
l_coma := ',';
END LOOP;
lv_message := lv_message || crlf;
ELSE
EXIT;
END IF;
END LOOP;
dbms_sql.close_cursor( l_cursorid );
RETURN lv_message;
END;
BEGIN
open l_cursor FOR 'SELECT 1 as A, 2 AS B, 3 AS C, 4 AS D FROM DUAL UNION ALL SELECT 1 as A, 2 AS B, 3 AS C, 4 AS D FROM DUAL';
dbms_Output.put_Line(generateData(l_cursor));
END;
/

Resources