Changing the data owned by common users in multiple PDBs

Temos na arquitetura Multitenant a opção de utilizar a cláusula CONTAINERS também em DMLs, permitindo assim que manipulemos dados de múltiplos PDBs. Neste artigo vamos explorar alguns exemplos de uso, onde os objetos pertecem a um Common User.

Coletando informações do ambiente de testes:

[oracle@quiasma ~]$ sqlplus / as sysdba
 
SQL*Plus: Release 18.0.0.0.0 - Production on Thu Jun 17 05:57:14 2021
Version 18.13.0.0.0
 
Copyright (c) 1982, 2018, Oracle.  All rights reserved.
 
 
Connected to:
Oracle Database 18c Enterprise Edition Release 18.0.0.0.0 - Production
Version 18.13.0.0.0
 
SQL> SELECT NAME,OPEN_MODE,CDB FROM V$DATABASE;
 
NAME      OPEN_MODE            CDB
--------- -------------------- ---
ASWAN     READ WRITE           YES
 
SQL> SHOW PDBS;
 
    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 HIPOFISE2                      READ WRITE NO
         4 HIPOFISE1                      READ WRITE NO
SQL> CONN C##LUXOR/oracle
Connected.
SQL> SELECT * FROM CONTAINERS(LOGIN_AUDIT);
 
 RECORD_ID DB    USER_ LOGIN_TIM LOGOFF_TI     CON_ID
---------- ----- ----- --------- --------- ----------
        12 PDB2  USER4 12-JUN-21 12-JUN-21          3
        22 PDB2  USER5 12-JUN-21 12-JUN-21          3
        32 PDB2  USER4 12-JUN-21 12-JUN-21          3
        11 PDB1  USER1 13-JUN-21 13-JUN-21          4
        21 PDB1  USER2 13-JUN-21 13-JUN-21          4
        31 PDB1  USER3 13-JUN-21 13-JUN-21          4
 
6 rows selected.

Conectado com o Common User “C##LUXOR” no CDB$ROOT, vamos realizar um insert na tabela apenas no PDB HIPOFISE1 (CON_ID 4):

SQL> SHOW USER;
USER is "C##LUXOR"
SQL> ALTER SESSION SET NLS_DATE_FORMAT='DD-MM-RR HH24:MI';
 
Session altered.
 
SQL> INSERT INTO CONTAINERS(LOGIN_AUDIT) (CON_ID, RECORD_ID, DB, USER_ID, LOGIN_TIME, LOGOFF_TIME) VALUES (4,41,'PDB1','USER4', SYSDATE-2.5, SYSDATE-2.4);
 
1 row created.
 
SQL> COMMIT;
 
Commit complete.
 
SQL> SELECT * FROM CONTAINERS(LOGIN_AUDIT);
 
 RECORD_ID DB    USER_ LOGIN_TIME     LOGOFF_TIME        CON_ID
---------- ----- ----- -------------- -------------- ----------
        12 PDB2  USER4 12-06-21 16:47 12-06-21 19:11          3
        22 PDB2  USER5 12-06-21 14:23 12-06-21 16:47          3
        32 PDB2  USER4 12-06-21 11:59 12-06-21 16:47          3
        41 PDB1  USER4 14-06-21 18:01 14-06-21 20:25          4
        11 PDB1  USER1 13-06-21 16:46 13-06-21 19:10          4
        21 PDB1  USER2 13-06-21 14:22 13-06-21 16:46          4
        31 PDB1  USER3 13-06-21 11:58 13-06-21 16:46          4
 
7 rows selected.
 
SQL> conn C##LUXOR/oracle
Connected.
SQL> SELECT * FROM CONTAINERS(LOGIN_AUDIT) WHERE CON$NAME IN ('HIPOFISE1') AND RECORD_ID=41;
 
 RECORD_ID DB    USER_ LOGIN_TIM LOGOFF_TI     CON_ID
---------- ----- ----- --------- --------- ----------
        41 PDB1  USER4 14-JUN-21 14-JUN-21          4

Realizando operação de UPDATE também usando o recurso de filtro por PDB:

SQL> UPDATE CONTAINERS(LOGIN_AUDIT) SET USER_ID='TESTE' WHERE CON_ID=4 AND RECORD_ID=41;
 
1 row updated.
 
SQL> COMMIT;
 
Commit complete.
 
SQL> SELECT * FROM CONTAINERS(LOGIN_AUDIT) WHERE CON$NAME IN ('HIPOFISE1') AND RECORD_ID=41;
 
 RECORD_ID DB    USER_ LOGIN_TIM LOGOFF_TI     CON_ID
---------- ----- ----- --------- --------- ----------
        41 PDB1  TESTE 14-JUN-21 14-JUN-21          4

Por fim, realizando o delete desse registro:

SQL> DELETE CONTAINERS(LOGIN_AUDIT) WHERE CON_ID=4 AND RECORD_ID=41;
 
1 row deleted.
 
SQL> COMMIT;
 
Commit complete.
 
SQL> SELECT * FROM CONTAINERS(LOGIN_AUDIT) WHERE CON$NAME IN ('HIPOFISE1') AND RECORD_ID=41;
 
no rows selected

A única coisa interessante é que, na documentação da Oracle, podemos realizar um DML que altere dados de vários PDBs ao mesmo tempo, ou seja, usando o mesmo comando (link AQUI):

Porém, na prática, isso não é possível (aí não é possível saber se é um Bug do RDMS ou da própria documentação):

SQL> UPDATE CONTAINERS(LOGIN_AUDIT) SET USER_ID='TESTE' WHERE CON_ID in (3,4);
UPDATE CONTAINERS(LOGIN_AUDIT) SET USER_ID='TESTE' WHERE CON_ID in (3,4)
                  *
ERROR at line 1:
ORA-65319: DML on CONTAINERS() specified an unsupported CON_ID predicate
 
SQL> DELETE CONTAINERS(LOGIN_AUDIT) WHERE CON_ID in (3,4);
DELETE CONTAINERS(LOGIN_AUDIT) WHERE CON_ID in (3,4)
                  *
ERROR at line 1:
ORA-65319: DML on CONTAINERS() specified an unsupported CON_ID predicate

Obs: Este procedimento foi criado pelo senhor Ahmed Baraka (www.ahmedbaraka.com) e foi apenas reproduzido por mim em um laboratório pessoal para fins de aprendizado.

Leave a Comment

Your email address will not be published.