By Franck Pachot

Multitenant architecture is not such a big change and this is why I recommend it when you start a project in 12c or if you upgrade to 12.2 – of course after thoroughly testing your application. However, there is a point where you may encounter problems on dictionary queries, because it is really a big change internally. The dictionary separation has several side effects. You should test carefully the queries you do on the dictionary views to get metadata. Here is an example of a bug I recently encountered.

This happened with a combination of things you should not do very often, and not in a critical use case: query dictionary for constraints owned by your current schema, when different than the user you connect with.

I create two users: USER1 and USER2

SQL> connect sys/[email protected]//localhost/PDB1 as sysdba
SQL> grant dba to USER1 identified by USER1 container=current;
Grant succeeded.
SQL> grant dba to USER2 identified by USER2 container=current;
Grant succeeded.

USER1 owns a table which has a constraint:

SQL> connect USER1/[email protected]//localhost/PDB1
SQL> create table DEMO(dummy constraint pk primary key) as select * from dual;
Table DEMO created.

USER2 can access to the table either by prefixing it with USER1 or by setting the current_schema to USER1

SQL> connect USER2/[email protected]//localhost/PDB1
SQL> alter session set current_schema=USER1;
Session altered.


Ok, now imagine you want to read constraint metadata for the current schema you have set:

SQL> select sys_context('USERENV','CURRENT_SCHEMA'), a.*
  2  from sys.dba_constraints a
  3       where owner = sys_context('USERENV','CURRENT_SCHEMA')
  4  /
no rows selected

No rows selected is a wrong result here because my current_schema is USER1 and USER1 has constraints:

SQL> select owner,constraint_name
  2  from sys.dba_constraints a
  3       where owner = 'USER1'
  4  /
-----  ---------------

So, where’s the problem? Let’s have a look at the execution plan:

SQL_ID  2fghqwz1cktyf, child number 0
select sys_context('USERENV','CURRENT_SCHEMA'), a.*  from
sys.dba_constraints a      where owner =
Plan hash value: 1258862619
| Id  | Operation                | Name                    | Starts | E-Rows | A-Rows |   A-Time   | Buffers |
|   0 | SELECT STATEMENT         |                         |      1 |        |      0 |00:00:00.32 |    2656 |
|   1 |  PARTITION LIST ALL      |                         |      1 |      2 |      0 |00:00:00.32 |    2656 |
|*  2 |   EXTENDED DATA LINK FULL| INT$INT$DBA_CONSTRAINTS |      2 |      2 |      0 |00:00:00.32 |    2656 |
Predicate Information (identified by operation id):

I am in 12.2 and DBA_CONSTRAINTS reads from INT$DBA_CONSTRAINTS which reads from INT$INT$DBA_CONSTRAINTS and in multitenant this view being an extended data view will read from CDB$ROOT and from the current container. This is why we see EXTENDED DATA LINK FULL in the execution plan and up to this point the predicates are correct: “OWNER”=SYS_CONTEXT(‘USERENV’,’CURRENT_SCHEMA’)

The execution through data link is run on each container with parallel processes: they switch to the container and run the underlying query on the view. But when I look at the sql trace of the parallel process running the query on my PDB I can see that the predicate on OWNER has replaced the SYS_CONTEXT(‘USERENV’,’CURRENT_SCHEMA’) with the hardcoded value:


And unfortunately, this value is not the right one: USER2 is my connected user, but not the CURRENT_SCHEMA that I have set. In the same trace, I can see where this value comes from:

select 'q''"' || SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') || '"''' from sys.dual

but it seems that the current_schema was lost through the call to the parallel process and the PDB switch to my container.


The problem is easy to workaround. This works:

SQL> select owner,constraint_name
  2  from sys.dba_constraints a
  3       where owner = ( select sys_context('USERENV','CURRENT_SCHEMA') from dual )
  4  /
-----  ---------------

And anyway, better to get the current schema before and pass it as a bind variable. The bind variables are passed correctly through data link queries:

SQL> variable v varchar2(30)
SQL> exec select sys_context('USERENV','CURRENT_SCHEMA') into :v from dual;
PL/SQL procedure successfully completed.
SQL> select sys_context('USERENV','CURRENT_SCHEMA'), a.*
  2  from sys.dba_constraints a
  3       --where owner = sys_context('USERENV','CURRENT_SCHEMA')
  4       where owner = :v
  5  /

So what?

The multitenant architecture is a real challenge for dictionary views. The dictionary is separated: system metadata in CDB$ROOT and user metadata in PDB. But, because of compatibility with non-CDB architecture, the dictionary views must show both of them, and this is where it becomes complex: what was separated on purpose has now to be merged. And complexity is subject to bugs. If you want to get an idea, have a look at dcore.sql in ORACLE_HOME/rdbms/admin and compare 11g version with 12c ones, with all the evolution in, and

Added OCT-17

I’ve opened a SR and the following bug is logged: Bug 26986472 – WRONG RESULT WHILE USING SYS_CONTEXT(‘USERENV’,’CURRENT_SCHEMA’) IN PDB

Thumbnail [60x60]
Oracle Team