简体   繁体   中英

Oracle JDBC / PL SQL / TYPE / Package Level / Invalid Name Pattern

I have declared package level type this way (using Oracle XE 11):

create or replace PACKAGE RM_TYPES
AS
    TYPE RECPPART_ARR IS TABLE OF RM_RECEPCIONPARTIDAS%ROWTYPE;
END RM_TYPES;

I have SP like this:

create or replace PROCEDURE "RM_TRY_B" (partidas OUT RM_TYPES.RECPPART_ARR) as 
begin
  SELECT * BULK COLLECT INTO partidas FROM rm_recepcionpartidas;
end;

I have java code like this:

CallableStatement cstmt = conn.prepareCall("{call RM_TRY_B(?)}");
cstmt.registerOutParameter(1, OracleTypes.ARRAY, "RM_TYPES.RECPPART_ARR");
cstmt.execute();
Array a = cstmt.getArray(1);

It gives me an excepcion:

Exception in thread "main" java.sql.SQLException: invalid name pattern: RM_TYPES.RECPPART_ARR

I have already granted access to package to my user by issuing this command to oracle:

GRANT EXECUTE ON RM_TYPES TO myuser;

I used this as reference: https://docs.oracle.com/database/121/JJDBC/apxref.htm#JJDBC28913 (section named: Creating Java level objects for each row using %ROWTYPE Attribute

Where did I do wrong?


I've also try passing in this name in my java code: "RECPPART_ARR" or "MYSCHEMA.RM_TYPES.RECPPART_ARR" none of them works.

Then I read someone said this on stackoverflow: java - passing array in oracle stored procedure : "actually the problem is that any type created within a package is not visible by java. If I create the type at schema level then it works. "

Is it true?

Then maybe I should define an alias at schema level?

How? I tried "CREATE SYNONYM":

CREATE PUBLIC SYNONYM RECPPART_ARRAY FOR RM_TYPES.RECPPART_ARR;

And then (tried to modify my SP):

create or replace PROCEDURE "RM_TRY_B" (partidas OUT RECPPART_ARRAY) as 
begin
  SELECT * BULK COLLECT INTO partidas FROM rm_recepcionpartidas;
end;

But this time this SP wouldn't compile, with this error message in my SQLDeveloper: Error(1,36): PLS-00905: object MYSCHEMA.RECPPART_ARRAY is invalid.

Then I tried using the previous definition of my sp:

create or replace PROCEDURE "RM_TRY_B" (partidas OUT RM_TYPES.RECPPART_ARR) as 
begin
  SELECT * BULK COLLECT INTO partidas FROM rm_recepcionpartidas;
end;

And modified my Java code to use the synomim instead:

CallableStatement cstmt = conn.prepareCall("{call RM_TRY_B(?)}");
cstmt.registerOutParameter(1, OracleTypes.ARRAY, "RECPPART_ARRAY");
cstmt.execute();
Array a = cstmt.getArray(1);

Still, exception, with message: Fail to construct descriptor: Unable to resolve type: "MYSCHEMA.RECPPART_ARRAY"


ADDITION

Some other info I just found:

http://oracle.developer-works.com/article/5227493/%22invalid+name+pattern%22++when+trying+to+user+packaged+TYPE

Someone wrote: I had the same issue. Managed to solve it by creating public synonym and giving grants.

As you see, I did that already, but no luck for me.


ADDITION

Or ... maybe something like this in oracle (after reading this: http://docs.oracle.com/javadb/10.10.1.2/ref/rrefsqljgrant.html ):

create or replace PACKAGE RM_TYPES
AS
  TYPE RECPPART_ARR IS TABLE OF RM_RECEPCIONPARTIDAS%ROWTYPE;
END RM_TYPES;

sqlplus (logged in as sys as SYSDBA)> GRANT USAGE ON TYPE RM_TYPES.RECPPART_ARR TO myuser;

CREATE PUBLIC SYNONYM RECPPART_ARRAY FOR RM_TYPES.RECPPART_ARR;

create or replace PROCEDURE "RM_TRY_B" (partidas OUT RM_TYPES.RECPPART_ARR) as 
begin
  SELECT * BULK COLLECT INTO partidas FROM rm_recepcionpartidas;
end;

....

I tried it..., even logged in using user "sys" as SYSDBA .... I got an error when issuing grant:

Error starting at line : 1 in command - GRANT USAGE TYPE ON RM_TYPES.RECP_ARR TO myuser Error report - SQL Error: ORA-00990: missing or invalid privilege 00990. 00000 - "missing or invalid privilege" *Cause:
*Action:

I'm running out of idea now.

JDBC Support for PL/SQL Data Types as Parameters is a new feature of Oracle 12c.

PL/SQL types look and act like regular types; they can be used in SQL and other contexts, they have a TYPE_OID and TYPECODE, and they have a data dictionary view (DBA_PLSQL_TYPES). One odd difference is that PL/SQL types do not show up in DBA_OBJECTS.

In older versions you must create a TYPE as a stand-alone object in order to use it outside of PL/SQL. Code like this can create the objects:

CREATE OR REPLACE TYPE RECPPART_REC IS OBJECT
(
    --list RM_RECEPCIONPARTIDAS columns here.  %ROWTYPE is not available in SQL.
);

CREATE OR REPLACE RECPPART_ARR IS TABLE OF RECPPART_REC;

You could make use of a little-known feature in PL/SQL: PIPELINED functions. An example:

create table tab (
  id number(7)
);
/

insert into tab values (1);
insert into tab values (2);

create or replace package pkg
as
  type typ is table of tab%rowtype;
end pkg;
/

create or replace procedure proc (param out pkg.typ) as 
begin
  select * bulk collect into param from tab;
end;
/

create or replace function func return pkg.typ pipelined as
begin
  for rec in (select * from tab) loop
    pipe row(rec);
  end loop;
end;
/

select * from table(func);

The above will yield:

ID
--
1
2

So you can materialise the table type also easily from JDBC.

The reason for this is the fact that every pipelined function implicitly creates a top-level SQL type that is of the same type as your PL/SQL table type. In the above case something like:

create or replace type SYS_PLSQL_29848_13_1 as object (ID NUMBER(7));
create or replace type SYS_PLSQL_29753_9_1 as table of SYS_PLSQL_29848_13_1;

This is more of a side-note. In general, you should probably prefer the approach suggested by Jon Heller

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM