tags:

views:

332

answers:

2

Suppose I have schemas A and B.

In schema A I would like to call package X in schema B. However, there exists a package B in schema A.

A:
    package B
B:
    package X

When I call from schema A:

begin b.x.foo(); end

it looks for procedure X in package B, i.e. A.B.X(), and gets an error.

How can I fully qualify the call to force B to be considered a schema name?

update:

  • It does seem there's no way to scope the reference to refer to b.x.foo.
  • CREATE SYNONYM B_X for B.X works. B_X.foo() calls the procedure in schema B.
+5  A: 

I don't think you can. From the PL/SQL User's Guide:

"The name resolution rules for PL/SQL and SQL are similar. You can avoid the few differences if you follow the capture avoidance rules. For compatibility, the SQL rules are more permissive than the PL/SQL rules. SQL rules, which are mostly context sensitive, recognize as legal more situations and DML statements than the PL/SQL rules.

  • PL/SQL uses the same name-resolution rules as SQL when the PL/SQL compiler processes a SQL statement, such as a DML statement. For example, for a name such as HR.JOBS, SQL matches objects in the HR schema first, then packages, types, tables, and views in the current schema.
  • PL/SQL uses a different order to resolve names in PL/SQL statements such as assignments and procedure calls. In the case of a name HR.JOBS, PL/SQL searches first for packages, types, tables, and views named HR in the current schema, then for objects in the HR schema."

The second bullet above applies. Since the object "B" exists in schema A, that's what the reference resolves to.

DCookie
+2  A: 

Hi Mark,

I agree with DCookie, this is a normal scoping problem. If you're in this situation though, one way to solve the issue would be to change the CURRENT_SCHEMA:

SQL> exec b.x.foo;

begin b.x.foo; end;

ORA-06550: line 2, column 9:
PLS-00302: component 'X' must be declared
ORA-06550: line 2, column 7:
PL/SQL: Statement ignored

SQL> alter session set current_schema=b;

Session altered

SQL> exec b.x.foo;

PL/SQL procedure successfully completed
Vincent Malgrat
+1 nice workaround
skaffman
This only works if you set the current schema before you run the PL/SQL block, and thus is effective for the entire block. You can't run the alter session inside the PL/SQL block. If that's not a problem, then this works.
DCookie
@DCookie: This is only a simple workaround -- the true solution would be to design a naming scheme that prevents this type of name collision
Vincent Malgrat
@Vincent, I agree completely. I was simply pointing out that this might not solve OP's full problem, even if it does make the example work. Certainly not inteneded as a criticism of the answer given. I tried making the current_schema thing work inside the PL/SQL block and couldn't get there.
DCookie