# [26ai] DBMS_CLOUD — Capitulo Uno

*El artículo también se encuentra publicado en Ingles* [***English version***](https://dbaintheshadow.com/26ai-dbms-cloud-chapter-one)*.*

En el artículo de hoy vamos a ver algunos beneficios que podemos tener en el día a día al utilizar *DBMS\_CLOUD* en 26ai para nuestras tareas diarias, como puede ser tareas de respaldo de un datapump o guardar informes, ya que se conecta a un *Object Storage* de OCI.

Por defecto, no viene configurado en nuestra 26ai, con lo que el primer paso que debemos hacer es configurarlo para un usuario válido de nuestra **tenancy**.

Antes de meternos en faena, debemos asegurarnos que nuestra base de datos tiene *DBMS\_CLOUD* configurado y listo para usarse. Dejo por aquí la nota de Oracle para la instalación en caso que no tengamos configurado ese punto:

[***How To Setup And Use DBMS\_CLOUD Package (Doc ID 2748362.1)***](https://support.oracle.com/support/?anchorId=&kmContentId=2748362&page=sptemplate&sptemplate=km-article)

A nivel de OCI, debemos configurar para nuestro usuario un **token** o **API Key** ya que necesitamos definir una **credencial** porque nuestro *Bucket* es privado. No sería necesario definir la credencial si nuestro *Bucket* es público*.*

### **Token**

El primer paso que vamos a realizar es generar el token de nuestro usuario en OCI. Para ello, tendremos que ir a la parte de configuración de nuestro usuario, justo en la parte superior derecha:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1771410019467/915ef3cc-14f9-41d5-9e8f-feb4566a6036.png align="center")

Una vez dentro, vamos a la pestaña **Tokens and keys**:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1771329298121/73011e3f-f972-434c-9386-e50f55798bf7.png align="center")

Ahí vamos a ver tres secciones: *API Keys*, *Auth Tokens* y *Customer Secrets Keys*.

Bien, la que nos interesa es la de *Auth Tokens*:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1771329519186/02251fb9-d8c1-4ecb-b635-417e614f8d0a.png align="center")

Ahí pulsamos en *Generate token*. Nos pedirá un nombre y pulsamos en *Generate token*:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1771329590592/50419b9d-06d2-476b-b216-4b8fc0a8f0c0.png align="center")

La siguiente ventana **no** la debemos cerrar sin antes copiar el token.

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1771329749038/4ebb4308-6ad9-4092-a766-1e20ff09a5b9.png align="center")

Una vez que hayamos copiado el token, definimos la **credential** en nuestra base de datos usando el token que hemos generado en el punto anterior.

### **Configuración de la Credencial**

Para generarlo, debemos usar **DBMS\_CLOUD.CREATE\_CREDENTIAL**.

Este procedimiento recibe los siguientes parámetros:

*   CREDENTIAL\_NAME: Nombre de la credencial que vamos a crear.
    
*   USERNAME: Nombre del nuestro usuario, siempre debe seguir la estructura de “*<IdentityDomain>/<username>*”.
    
*   Password: Valor del <token> que hemos generado antes
    

```sql
SQL>EXEC  dbms_cloud.create_credential(
    credential_name => 'DBA_IN_THE_SHADOW',
    username        => '<IdentityDomain>/<usuario_tenancy>',
    password        => '<token>');

SQL> R
  1  select credential_name,
  2         username,
  3         enabled
  4  from   DBA_credentials
  5* order by credential_name

CREDENTIAL_NAME           USERNAME                                           ENABLED
------------------------- -------------------------------------------------- --------------------
DBA_IN_THE_SHADOW         <IdentityDomain>/<usuario_tenancy>       TRUE
```

Una manera rápida de verificar que funciona correctamente es listando el contenido que tenemos en nuestra *Bucket*. Para ello nos apoyaremos en la función **DBMS\_CLOUD.LIST\_OBJECTS**.

Esta función recibe dos parámetros, el primero sería el nombre de la credencial que hemos generado en el punto anterior, y el segundo sería la URL para acceder a nuestro *Bucket*.

La manera más fácil de obtener la url, es ir a un objecto de nuestro *Bucket* e ir a los detalles del mismo:

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1771411079006/0d136145-6a8c-487d-b28a-7edff7d3abda.png align="center")

![](https://cdn.hashnode.com/res/hashnode/image/upload/v1771411298002/5eee5747-6775-4097-9424-7e33298cdd84.png align="center")

Ahí copiamos el valor de “*URL path (URI)*”.

Una vez que lo tenemos copiado, listamos vía SQL el contenido del *Bucket*:

```sql
SQL> 
Select object_name
  From Dbms_cloud.list_objects('DBA_IN_THE_SHADOW','<location_uri>'); 

OBJECT_NAME
--------------------------------------------------------------------------------
XXXXXXXX.zip
XXXXXXXX.zip
XXXXXXXX.zip
```

Perfecto, tenemos acceso.

### **Subida de ficheros**

Generamos un fichero **csv** y lo subimos a nuestro *Bucket*.

Utilizaremos **DBMS\_CLOUD.PUT\_OBJECTS** para subir el fichero generado. Para utilizarlo, definiremos el directory apuntando al path donde se encuentra nuestro fichero.

```sql
SQL> ! cat generate.sql
set heading off
set feedback off
set echo off
set verify off
set termout off
set markup csv on
spool myfile.csv
Select trunc(dbms_random.value(1, 1000)), dbms_random.string('x', 10)     
 From dual  
connect by level <= 10000;
spool off

SQL> @generate.sql
SQL> ! ls -lac *csv
-rw-r--r-- 1 oracle oinstall 168924 Feb 18 12:42 myfile.csv

SQL> CREATE DIRECTORY OCI_HOME as '/home/oracle';
SQL> GRANT READ, WRITE ON DIRECTORY OCI_HOME TO PUBLIC;
SQL> begin
  dbms_cloud.put_object (
    credential_name => 'DBA_IN_THE_SHADOW',
    object_uri      => '<location_uri>/myfile.csv',
    directory_name  => 'OCI_HOME',
    file_name       => 'myfile.csv');
end;
/ 
SQL>
SQL> Select object_name
  From 
   dbms_cloud.list_objects('DBA_IN_THE_SHADOW','<location_uri>');  

OBJECT_NAME
--------------------------------------------------------------------------------
XXXXXXXX.zip
XXXXXXXX.zip
XXXXXXXX.zip
myfile.csv
```

Listo, ya tenemos el fichero en nuestro *Bucket*.

Una vez subido, podemos generar una tabla externa que lee ese fichero. Una manera rápida de definir este punto, es usando **DBMS\_CLOUD.CREATE\_EXTERNAL\_TABLE**, que genera una tabla en nuestro schema que lee el fichero que le pasemos por parámetro.

```sql
SQL> 
BEGIN
  DBMS_CLOUD.CREATE_EXTERNAL_TABLE(
    table_name      => 'EXT_MYFILE_CSV',
    credential_name => 'DBA_IN_THE_SHADOW',
    file_uri_list   => '<location_uri>/myfile.csv',
    format          => JSON_OBJECT(
                         'type' VALUE 'csv',
                         'delimiter' VALUE ',',
                         'quote' VALUE '"',
                         'skipheaders' VALUE '0'
                       ),
    column_list     => '
        id   NUMBER,
        code VARCHAR2(50)
    '
  );
END;
/

SQL> SELECT COUNT(*) FROM EXT_MYFILE_CSV;
1000
SQL>
 SELECT * FROM EXT_MYFILE_CSV FETCH FIRST 25 ROWS ONLY
        ID CODE
---------- --------------------------------------------------
       224 3LU82RWW27
       654 LASYRZWUUE
        17 UW34WB3O4Y
       764 5Z2I01ITAX
       132 V4XCFDS9GA
       131 6PRK6G0VTC
       650 NST09S6RY9
       133 R8IIPLJZ95
       477 WK8Y1XC5XK
       930 O574M5RJK2
       371 P8G6PF91A9
       214 WRUYMY4BWY
       273 YD5NG441MV
       706 DQYEBYNF5H
       699 J3T3RHNHU0
       744 VVXATGVW0N
       945 U55X9EATLH
       371 RHW44MZ1DQ
       595 B1RU6VN33B
       864 P02I2A9Z8S
       218 R02XSI9MLY
       980 M0CSWHE4G7
       396 UZYFEL7UKI
       619 DYKCFI912X
       881 2TZ0GEQ6MM

25 rows selected.
```

También podemos exportar la información de una consulta válida a nuestro *Bucket* usando **DBMS\_CLOUD.EXPORT\_DATA**.

Este procedimiento recibe los siguientes parámetros:

*   CREDENTIAL\_NAME: Nombre de la credencial que vamos a crear.
    
*   URL: “*URL path (URI)*” más el nombre del fichero, no es necesario indicar la extensión, ya que eso lo indicamos en el parámetro Format.
    
*   Format: Formato en que queremos guardar el spool de nuestra consulta, en nuestra caso es **json**.
    
*   Query: SQL válida que queremos exportar.
    

```sql
SQL> 
BEGIN
      DBMS_CLOUD.EXPORT_DATA(  
        credential_name =>'DBA_IN_THE_SHADOW',
        file_uri_list =>'<location_uri>/config_system_parameter',
        format => json_object(  'type' VALUE 'json' ),
        query => 'SELECT NAME, VALUE FROM V$SYSTEM_PARAMETER'
      );
   END;
  / 

SQL> Select object_name
  From 
   dbms_cloud.list_objects('DBA_IN_THE_SHADOW','<location_uri>');  

OBJECT_NAME
--------------------------------------------------------------------------------
XXXXXXXX.zip
XXXXXXXX.zip
XXXXXXXX.zip
config_system_parameter_1_1_1.json
myfile.csv
```

Y si necesitamos descargar ese fichero en una tabla, podríamos usar el procedimiento **DBMS\_CLOUD.COPY\_DATA**.

```sql
SQL> 
  Create table BACK_SYSTEM_PARAMETER ( 
    INFO_PARAMETER CLOB  CONSTRAINT INFO_PARAMETER_JSON CHECK ( INFO_PARAMETER IS JSON )
      );

Table created.

SQL>
begin
  DBMS_CLOUD.COPY_DATA (
    table_name      => 'BACK_SYSTEM_PARAMETER',
    credential_name => 'DBA_IN_THE_SHADOW',
    file_uri_list   => '<location_uri>/config_system_parameter_1_1_1.json'
     );
end;
/
PL/SQL procedure successfully completed.
```

Ahí he definido una tabla *BACK\_SYSTEM\_PARAMETER* con una única columna con el objecto de inyectar ahí el contenido del JSON. Una vez definida, ejecuto el procedimiento para descargar la información.

Si consultamos la tabla, vemos que se ha cargado correctamente la información:

```sql
SQL>
 select 
    JSON_VALUE(INFO_PARAMETER, '$.NAME') AS NAME, 
    JSON_VALUE(INFO_PARAMETER, '$.VALUE') AS VALUE 
   from BACK_SYSTEM_PARAMETER
 Where INSTR(UPPER(JSON_VALUE(INFO_PARAMETER, '$.NAME')),'OPTIMIZER') != 0
  FETCH FIRST 5 ROWS ONLY;

NAME                                     VALUE
---------------------------------------- ----------------------------------------
optimizer_ignore_hints                   FALSE
optimizer_secure_view_merging            TRUE
optimizer_use_pending_statistics         FALSE
optimizer_capture_sql_plan_baselines     FALSE
optimizer_use_sql_plan_baselines         TRUE

10 rows selected.
```

En el próximo artículo abordaremos el uso del *Data Pump* junto con el *DBMS\_CLOUD*

Espero que os guste. ¡Nos vemos en el próximo artículo!
