<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[DBA en la SOMBRA]]></title><description><![CDATA[Tutoriales, scripts y casos prácticos que hacemos los DBA de desarrollos.
Únase a mí en mi viaje para optimizar y aprender.]]></description><link>https://dbaenlasombra.com</link><generator>RSS for Node</generator><lastBuildDate>Fri, 11 Sep 2026 13:28:10 GMT</lastBuildDate><atom:link href="https://dbaenlasombra.com/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[[OCI] Upgrade 19c a 26ai]]></title><description><![CDATA[Continuando con nuestros artículos previos:

[OCI] Oracle Grid Infrastructure 19c (Oracle Restart + ASM).

[OCI] 19c DBCA - Silent mode.


Hoy toca subir la base de datos de 19c a 26ai. Para lograr di]]></description><link>https://dbaenlasombra.com/oci-upgrade-19c-a-26ai</link><guid isPermaLink="true">https://dbaenlasombra.com/oci-upgrade-19c-a-26ai</guid><category><![CDATA[Oracle]]></category><category><![CDATA[autoupgrade]]></category><category><![CDATA[Oracle 26ai]]></category><category><![CDATA[Oracle Database 19c]]></category><category><![CDATA[Deploy ]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Thu, 10 Sep 2026 18:28:16 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/a3c1b3a1-9152-47c4-8209-11bffce67e8e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Continuando con nuestros artículos previos:</p>
<ul>
<li><p><a href="https://dbaenlasombra.com/oci-oracle-grid-infrastructure-19c-oracle-restart-asm">[OCI] Oracle Grid Infrastructure 19c (Oracle Restart + ASM)</a>.</p>
</li>
<li><p><a href="https://dbaenlasombra.com/oci-19c-dbca-silent-mode">[OCI] 19c DBCA - Silent mode</a>.</p>
</li>
</ul>
<p>Hoy toca subir la base de datos de <strong>19c</strong> a <strong>26ai</strong>. Para lograr dicho objetivo, vamos a utilizar <strong>autoupgrade</strong>, el uso del mismo, está maravillosamente explicado por <strong>Daniel Overby</strong> en su blog <strong>dohdatabase</strong>.</p>
<p><a href="https://dohdatabase.com/2025/12/18/upgrade-oracle-database-19c-cdb-to-oracle-ai-database-26ai/?utm_source=chatgpt.com">Upgrade Oracle Database 19c CDB to Oracle AI Database 26ai</a></p>
<p>Debo reconocer que tenía muchas ganas de usarlo, así, que sin más, vamos a ello.</p>
<p>Primer paso, descargar el <strong>autoupgrade.jar</strong> desde la página oficial de <strong>Oracle</strong>.</p>
<pre><code class="language-shell">[oracle@]$ wget https://download.oracle.com/otn-pub/otn_software/autoupgrade.jar
</code></pre>
<p>En este punto, podemos verificar si el jar tiene errores con <em><strong>java -jar autoupgrade.jar -version</strong></em>.</p>
<p>El proceso de <strong>autoupgrade</strong> puede hacerse:</p>
<ul>
<li><p><strong>Source</strong> y <strong>target</strong> en el mismo <strong>server</strong></p>
</li>
<li><p><strong>Source</strong> y <strong>target</strong> en diferente <strong>server</strong>.</p>
</li>
</ul>
<p>En este laboratorio, tanto el <strong>source</strong> como el <strong>target</strong>, estarán en el mismo <strong>server</strong>.</p>
<h2>Config Files</h2>
<p>Definir el fichero de configuración es un paso obligatorio para realizar con éxito nuestro <strong>autoupgrade</strong>.</p>
<p>Este fichero, contiene toda la configuración necesaria para realizar el <em><strong>upgrade</strong></em> de nuestra base de datos. Así que este será nuestro primer paso.</p>
<p>Aquí voy a definir las siguientes variables, no van a ser las mismas cuando realice el <strong>analyze</strong> respecto al <strong>display</strong>. En el <strong>analyze</strong>, voy a indicar <strong>target_version</strong> para que el proceso de <strong>autoupgrade</strong> sepa contra que versión se debe hacer los <strong>pre-checks</strong>. Pero para la fase de display debo indicar <strong>target_home</strong>.</p>
<ul>
<li><p><strong>global.autoupg_log_dir</strong>: directorio log.</p>
</li>
<li><p><strong>dba.source_home</strong>: nuestro actual $ORACLE_HOME</p>
</li>
<li><p><strong>dba.target_version</strong>: especificamos la versión a la que queremos realizar el upgrade.</p>
</li>
<li><p><strong>dba.target_home</strong>: $ORACLE_HOME para el target. Ahí deben estar los binarios de nuestra 26ai.</p>
</li>
<li><p><strong>dba.sid</strong>: sid de nuestra base de datos.</p>
</li>
</ul>
<p>Mi prefijo para el proceso es <strong>dba</strong>, pero podemos usar el que queramos.</p>
<pre><code class="language-shell">[oracle@~]$ cat &gt; upgrade19to26.cfg &lt;&lt;EOF
global.autoupg_log_dir=${HOME}/logs
dba.source_home=${ORACLE_HOME}
dba.target_version=23.0.0
dba.sid=${ORACLE_SID}
EOF
</code></pre>
<h2>Analyze</h2>
<p>Ejecutamos la primera fase.</p>
<p>¿Que hace el <strong>analyze</strong>? Verifica si nuestra base de datos está lista para el <strong>upgrade</strong>, haciendo un checkeo y generando un informe. Este informe nos indica posibles errores para corregir antes de la siguiente fase o advertencias que deberíamos prestar atención.</p>
<p>La ejecución de esta fase sería <em>java -jar autoupgrade.jar -config &lt;name_cfg&gt;.cfg -mode analyze</em>.</p>
<pre><code class="language-shell">[oracle@~]$ java -jar autoupgrade.jar -config upgrade19to26.cfg -mode analyze

AutoUpgrade 26.5.260807 launched with default internal options
Processing config file ...
+--------------------------------+
| Starting AutoUpgrade execution |
+--------------------------------+
1 CDB(s) plus 1 PDB(s) will be analyzed
Type 'help' to list console commands
upg&gt; Job 102 completed
------------------- Final Summary --------------------
Number of databases            [ 1 ]

Jobs finished                  [1]
Jobs failed                    [0]

Please check the summary report at:
/home/oracle/logs/cfgtoollogs/upgrade/auto/status/status.html
/home/oracle/logs/cfgtoollogs/upgrade/auto/status/status.log
</code></pre>
<p>Revisamos el informe generado para ver si ha encontrado errores o advertencias antes de continuar.</p>
<p>Adjunto el informe generado:</p>
<p><a href="https://github.com/dbaenlasombra/OCI/blob/main/cdb1_preupgrade.html"><em>cdb1_preupgrade.html</em></a></p>
<p>Leyendo el informe, no indica errores ni componentes inválidos. Solo voy a solucionar la advertencia del <strong>sga_target</strong> antes de pasar a la siguiente fase. El resto de advertencias, como el <strong>unified auditing</strong>, <strong>ordim</strong> o las indicaciones a nivel de <strong>tablespaces</strong>, etc. las revisaremos al finalizar el <strong>upgrade</strong>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/8604d081-14e6-495a-9414-4998473139d7.png" alt="" style="display:block;margin:0 auto" />

<p>Ejecuto la siguiente sentencia desde <strong>CDB$Root</strong> para solucionar la advertencia del <strong>sga_target</strong>.</p>
<pre><code class="language-sql">SQL&gt; ALTER SYSTEM SET sga_target=4672M SCOPE=BOTH;
</code></pre>
<p>Lanzamos de nuevo el <strong>analyze</strong> para verificar que la advertencia del <strong>sga_target</strong> ha desaparecido.</p>
<p>Dejo aquí el nuevo informe.</p>
<p><a href="https://github.com/dbaenlasombra/OCI/blob/main/cdb1_preupgrade_v2.html">cdb1_preupgrade_v2.html</a></p>
<h2>Deploy</h2>
<p>Fase donde se va realizar el <strong>upgrade</strong> de nuestra base de datos.</p>
<p>Como comentamos previamente, vamos a generar de nuevo el fichero de configuración (tenemos que usar el parámetro <strong>target_home</strong>, en vez de <strong>target_version</strong>), y con este parámetro de que es necesario tener instalado tanto <strong>Oracle Database Home</strong> como <strong>Grid Infrastructure</strong>.</p>
<p>Ambos los podemos descargar desde <a href="https://www.oracle.com/database/technologies/oracle26ai-linux-downloads.html?utm_source=chatgpt.com">aquí</a>.</p>
<p>Vamos primero para la parte de <strong>Oracle Database Home</strong>:</p>
<ul>
<li>Definimos el directorio que albergara los binarios.</li>
</ul>
<pre><code class="language-shell">[oracle@~]$ mkdir -p /u01/app/oracle/product/26.0.0/dbhome_1
[oracle@~]$ cd /u01/app/oracle/product/26.0.0/dbhome_1
[oracle@dbhome_1]$ unzip /tmp/LINUX.X64_2326100_db_home.zip 
...
...
</code></pre>
<ul>
<li>Una vez que tenemos ahí los binarios, ejecutamos la instalación en dos fases, primer verificamos que estamos listo con <strong>-executePrereqs</strong> y después instalamos.</li>
</ul>
<pre><code class="language-shell">[oracle@dbhome_1]$ ./runInstaller -silent -setupDBHome -OSDBA dba -OSBACKUPDBA dba -OSDGDBA dba -OSKMDBA dba -OSRACDBA dba -ORACLE_BASE /u01/app/oracle -installEdition EE -INVENTORY_LOCATION /u01/app/oraInventory -executePrereqs

Launching Oracle AI Database Setup Wizard...

Prerequisite checks ran successfully.

[oracle@dbhome_1]$ ./runInstaller -silent -setupDBHome -OSDBA dba -OSBACKUPDBA dba -OSDGDBA dba -OSKMDBA dba -OSRACDBA dba -ORACLE_BASE /u01/app/oracle -installEdition EE -INVENTORY_LOCATION /u01/app/oraInventory
...
...
</code></pre>
<p>Respecto a <strong>Grid Infrastructure</strong>:</p>
<ul>
<li>Definimos el directorio que albergara los binarios y paramos la base de datos</li>
</ul>
<pre><code class="language-shell">[grid@~]$ mkdir -p /u01/app/26.0.0/grid
[grid@~]$ cd /u01/app/26.0.0/grid
[grid@grid]$ unzip /tmp/LINUX.X64_2326100_grid_home.zip
</code></pre>
<ul>
<li>Paramos la base de datos</li>
</ul>
<pre><code class="language-shell">[grid@grid]$ srvctl stop database -db cdb1
[grid@grid]$ srvctl status database -db cdb1
</code></pre>
<ul>
<li>Una vez que tenemos ahí los binarios, ejecutamos la instalación en dos fases, primer verificamos que estamos listo con <strong>-executePrereqs</strong> y después instalamos.</li>
</ul>
<pre><code class="language-sql">[grid@intheshadow grid]$ ./gridSetup.sh -silent -upgrade -ORACLE_BASE $ORACLE_BASE -executePrereqs
...
...
[grid@intheshadow grid]$ ./gridSetup.sh -silent -upgrade -ORACLE_BASE $ORACLE_BASE
...
...
</code></pre>
<ul>
<li>Arrancamos de nuevo la base de datos.</li>
</ul>
<pre><code class="language-shell">[grid@grid]$ srvctl start database -db cdb1
[grid@grid]$ srvctl status database -db cdb1
</code></pre>
<p>Ahora que tenemos listo, tanto <strong>Oracle Database Home</strong> como <strong>Grid Infrastructure,</strong> generamos nuestro nuevo fichero de configuración.</p>
<pre><code class="language-sql">[oracle@~]$ cat &gt; upgrade19to26.cfg &lt;&lt;EOF
global.autoupg_log_dir=${HOME}/logs
dba.source_home=${ORACLE_HOME}
dba.target_home=$(echo "${ORACLE_HOME}" | sed 's/19\.0\.0/26.0.0/')
dba.sid=${ORACLE_SID}
EOF
</code></pre>
<p>Lanzamos el <strong>deploy</strong>:</p>
<pre><code class="language-sql">[oracle@ ~]$ java -jar autoupgrade.jar -config upgrade19to26.cfg -mode deploy

Previous execution found loading latest data
Total jobs recovered: 1
+--------------------------------+
| Starting AutoUpgrade execution |
+--------------------------------+
Type 'help' to list console commands
upg&gt; Job 106 completed
------------------- Final Summary --------------------
Number of databases            [ 1 ]

Jobs finished                  [1]
Jobs failed                    [0]
Jobs restored                  [0]
Jobs pending                   [0]

---- Drop GRP at your convenience once you consider it is no longer needed ----
Drop GRP from CDB1: drop restore point AUTOUPGRADE_9212_CDB11932000


Please check the summary report at:
/home/oracle/logs/cfgtoollogs/upgrade/auto/status/status.html
/home/oracle/logs/cfgtoollogs/upgrade/auto/status/status.log
</code></pre>
<p>Listo, ha terminado correctamente, aunque no a la primera "<strong>Total jobs recovered: 1</strong>". En el próximo artículo hablare en detalle de los errores que he tenido en el <strong>autoupgrade</strong> por si os puede ayudar.</p>
<pre><code class="language-sql">[oracle@~]$ sqlplus / as sysdba

SQL*Plus: Release 23.26.1.0.0 - Production on Thu Sep 10 18:09:25 2026
Version 23.26.1.0.0

Copyright (c) 1982, 2025, Oracle.  All rights reserved.


Connected to:
Oracle AI Database 26ai Enterprise Edition Release 23.26.1.0.0 - Production
Version 23.26.1.0.0

SQL&gt; select banner_full from v$version;

BANNER_FULL
------------------------------------------------------------------
Oracle AI Database 26ai Enterprise Edition Release 23.26.1.0.0 - Production
Version 23.26.1.0.0
</code></pre>
<p>El siguiente paso y último en esta aventura, sera usar la última versión de <strong>ZDM</strong> con el objetivo de familiarizarnos con está nueva versión, tengo muchas ganas de probar el nuevo "<strong>instant deploy</strong>" y así migramos una <strong>PDB</strong> a esta base de datos.</p>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[OCI] 19c DBCA - Silent mode]]></title><description><![CDATA[Continuando con el articulo anterior de [OCI] Oracle Grid Infrastructure 19c (Oracle Restart + ASM), enlace aquí, hoy toca definir la base de datos.
La creación de la misma será usando DBCA en modo si]]></description><link>https://dbaenlasombra.com/oci-19c-dbca-silent-mode</link><guid isPermaLink="true">https://dbaenlasombra.com/oci-19c-dbca-silent-mode</guid><category><![CDATA[Oracle]]></category><category><![CDATA[19c]]></category><category><![CDATA[dbca]]></category><category><![CDATA[response]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Mon, 07 Sep 2026 22:09:45 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/290a85d4-e3d3-475f-a6a6-5f4095bd9d3a.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>Continuando con el articulo anterior de <strong>[OCI] Oracle Grid Infrastructure 19c (Oracle Restart + ASM),</strong> enlace <a href="https://dbaenlasombra.com/oci-oracle-grid-infrastructure-19c-oracle-restart-asm"><strong>aquí</strong></a>, hoy toca definir la base de datos.</p>
<p>La creación de la misma será usando <strong>DBCA</strong> en modo <em><strong>silent</strong></em> con un template configurado para lograr el objetivo.</p>
<p>Dejo aquí el enlace del response utilizado:</p>
<p><a href="https://github.com/dbaenlasombra/OCI/blob/main/shadow.rsp">shadow.rsp</a></p>
<p>En el fichero <em><strong>response</strong></em> que hemos configurado contiene los siguientes parámetros:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/97972ca4-0d05-409d-9698-5f85a85b176a.png" alt="" style="display:block;margin:0 auto" />

<p>Una vez configurado el <em><strong>response</strong></em>, ejecutamos <strong>DBCA</strong> bajo el usuario <strong>oracle</strong> haciendole referencia al mismo.</p>
<p><img src="align=%22center%22" alt="" /></p>
<pre><code class="language-shell">[oracle@~]$ $ORACLE_HOME/bin/dbca -silent -createDatabase -responseFile /home/oracle/shadow.rsp 
Prepare for db operation
10% complete
Registering database with Oracle Restart
14% complete
Copying database files
43% complete
Creating and starting Oracle instance
45% complete
49% complete
54% complete
58% complete
62% complete
Completing Database Creation
68% complete
70% complete
71% complete
Executing Post Configuration Actions
100% complete
Database creation complete. For details check the logfiles at:
 /u01/app/oracle/cfgtoollogs/dbca/cdb1.
Database Information:
Global Database Name:cdb1
System Identifier(SID):CDB1
Look at the log file "/u01/app/oracle/cfgtoollogs/dbca/cdb1/cdb10.log" for further details.
</code></pre>
<p>Perfecto, nos conectamos a la base de datos para configurar el modo <strong>archivelog</strong>.</p>
<pre><code class="language-sql">SQL&gt;
shu immediate
startup mount;
alter database archivelog;
alter database open;

SQL&gt; archive log list;
Database log mode	       Archive Mode
Automatic archival	       Enabled
Archive destination	       USE_DB_RECOVERY_FILE_DEST
Oldest online log sequence     14
Next log sequence to archive   16
Current log sequence	       16

SQL&gt;
</code></pre>
<p>En el próximos capítulo abordaremos el <strong>upgrade</strong> de 19c a 26ai.</p>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[OCI] Oracle Grid Infrastructure 19c (Oracle Restart + ASM)]]></title><description><![CDATA[En el articulo de hoy vamos a proceder a montar un Oracle Restart Grid Infrastructure en un IaaS que hemos definido en OCI con Oracle Linux 9, región eu-frankfurt-1.


¿Porque 19c y no 26ai? Porque qu]]></description><link>https://dbaenlasombra.com/oci-oracle-grid-infrastructure-19c-oracle-restart-asm</link><guid isPermaLink="true">https://dbaenlasombra.com/oci-oracle-grid-infrastructure-19c-oracle-restart-asm</guid><category><![CDATA[Oracle]]></category><category><![CDATA[OCI]]></category><category><![CDATA[19c]]></category><category><![CDATA[IaaS]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Sat, 22 Aug 2026 13:07:49 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/d022eac1-1acd-4def-8ec1-7612950afe1c.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>En el articulo de hoy vamos a proceder a montar un <strong>Oracle Restart Grid Infrastructure</strong> en un IaaS que hemos definido en OCI con <strong>Oracle Linux 9</strong>, región <strong>eu-frankfurt-1</strong>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/dcdeef99-4d94-4602-9be0-fc655bdaaecd.png" alt="" style="display:block;margin:0 auto" />

<p>¿Porque <strong>19c</strong> y no <strong>26ai</strong>? Porque queremos utilizar el <strong>autograde</strong> para pasar de <strong>19c</strong> a <strong>26ai</strong>, y una vez se encuentre en <strong>26ai</strong>, utilizar la última versión de ZDM para probar el "<strong>instant deploy</strong>".</p>
<p>Más o menos, nuestro laboratorio va ser el siguiente:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/5f581603-31cc-45cc-b30a-5c4ec5afd0b6.png" alt="" style="display:block;margin:0 auto" />

<p>Así que sin más, vamos al lío.</p>
<h2>Preparación ASM</h2>
<p>El IaaS he adjuntado dos <em><strong>block volumenes</strong></em> a mayores para la parte de <em><strong>DATA</strong></em> y <em><strong>RECO</strong></em>, de 50Gb cada uno.</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/2d54c04c-ff2f-4281-a218-d22f75ab7007.png" alt="" style="display:block;margin:0 auto" />

<p>Para montar ambos <em>block volumenes</em> en linux tenemos que copiar el valor <strong>iqn</strong> de cada volumen para saber quien es quien.</p>
<p>En OCI para obtenerlo tenemos que ir a los detalles de cada volumen:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/f97de796-65cd-404e-82e6-d9654023df63.png" alt="" style="display:block;margin:0 auto" />

<p>Y en la ventana que se abre, copiamos el siguiente valor:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/f968d20c-287b-42b9-a77b-b8e10e00cad2.png" alt="" style="display:block;margin:0 auto" />

<p>Buscamos la equivalencia en linux:</p>
<pre><code class="language-shell">[root@~]# ls -l /dev/disk/by-path/ | grep iscsi
[root@~]# iscsiadm -m session -P 3 | grep -E 'Target:|Attached scsi disk'
</code></pre>
<p>Con la información que hemos obtenido, sabemos que:</p>
<ul>
<li><p><strong>/sdb</strong> es ASM_DATA_BOOT</p>
</li>
<li><p><strong>/sdc</strong> es ASM_RECO_DATA.</p>
</li>
</ul>
<p>Con esta información, ya podemos preparar los discos <strong>ASM</strong>.</p>
<ol>
<li>Definimos las particiones:</li>
</ol>
<pre><code class="language-shell">[root@~]# parted -s /dev/sdb mklabel gpt
[root@~]# parted -s /dev/sdb mkpart primary 1MiB 100%
[root@~]# parted -s /dev/sdc mklabel gpt
[root@~]# parted -s /dev/sdc mkpart primary 1MiB 100%
</code></pre>
<p>Verificamos:</p>
<pre><code class="language-shell">[root@~]# lsblk -o NAME,SIZE,TYPE,FSTYPE,MOUNTPOINTS
NAME                SIZE TYPE FSTYPE      MOUNTPOINTS
sda                 100G disk             
├─sda1              100M part vfat        /boot/efi
├─sda2                2G part xfs         /boot
└─sda3             44.5G part LVM2_member 
  ├─ocivolume-root 29.5G lvm  xfs         /
  └─ocivolume-oled   15G lvm  xfs         /var/oled
sdb                  50G disk             
└─sdb1               50G part             
sdc                  50G disk             
└─sdc1               50G part    
</code></pre>
<ol>
<li>Instalamos <strong>ASMLib</strong>:</li>
</ol>
<pre><code class="language-shell">[root@~]# dnf config-manager --enable ol9_addons
[root@~]# dnf install -y oracleasm-support
[root@~]# dnf install ./oracleasmlib-3.1.3-1.el9.x86_64.rpm
</code></pre>
<p>Una vez instalado, configuramos <strong>oracleasm</strong> con el comando "<em>oracleasm configure -i</em><strong>"</strong> y reiniciamos el servicio "<em><strong>systemctl restart oracleasm</strong></em>".</p>
<ol>
<li>Definimos las etiquetas a nivel ASM</li>
</ol>
<pre><code class="language-shell">[root@~]# oracleasm createdisk DATA01 /dev/sdb1
[root@~]# oracleasm createdisk RECO01 /dev/sdc1
</code></pre>
<p>Y verificamos con "<em><strong>oracleasm listdisks</strong></em>".</p>
<h2>Instalación Grid Infrastructure 19.32</h2>
<p>Después de preparar toda la estructura de directorios junto con la definición de los usuarios <strong>oracle</strong> y <strong>grid</strong>, así como los grupos, comenzamos a instalar la parte de Grid Infrastructure.</p>
<p>La fase de preparación se resumiría como:</p>
<pre><code class="language-shell">[root@~]# groupadd -f oinstall
[root@~]# groupadd -f dba
[root@~]# groupadd -f asmadmin
[root@~]# groupadd -f asmdba
[root@~]# groupadd -f asmoper

[root@~]# useradd -g oinstall -G asmadmin,asmdba,asmoper,dba grid
[root@~]# useradd -g oinstall -G dba,asmdba oracle

[root@~]# mkdir -p /u01/app/oracle/product/19.0.0/db_1
[root@~]# mkdir -p /u01/app/grid 
[root@~]# mkdir -p /u01/app/19.0.0/grid
[root@~]# mkdir -p /u01/app/oraInventory
[root@~]# mkdir -p /u01/software
[root@~]# chown -R grid:oinstall /u01
[root@~]# chown -R oracle:oinstall /u01/app/oracle
[root@~]# chmod -R 775 /u01
</code></pre>
<p>El siguiente punto sería:</p>
<ul>
<li>Definir el fichero response, dejo por aquí el enlace para descargar del que hemos usado.</li>
</ul>
<p><a href="https://github.com/dbaenlasombra/OCI/blob/main/grid.rsp">Fichero response</a></p>
<ul>
<li><p>Descargar el parche <em><strong>Patch 39467003: GI RELEASE UPDATE 19.32.0.0.0</strong></em>.</p>
</li>
<li><p>Descargar Oracle Database 19c desde <a href="https://www.oracle.com/database/technologies/oracle19c-linux-downloads.html?utm_source=chatgpt.com">aquí</a>, tanto <em>grid</em> como <em>home</em>.</p>
</li>
</ul>
<p>Después de descomprimir el zip de Oracle Grid en /u01/app/19.0.0/grid, procedemos a su instalación:</p>
<pre><code class="language-shell">[grid@~]# cd $ORACLE_HOME
[grid@~]# ./gridSetup.sh -silent -responseFile /home/grid/grid.rsp -applyRU /u01/software/39467003 -waitforcompletion -ignorePrereqFailure
</code></pre>
<p>Una vez completado, bajo el usuario <em><strong>root</strong></em> lanzamos los scripts orainstRoot.sh y root.sh.</p>
<pre><code class="language-shell">[root@~]# sh /u01/app/oraInventory/orainstRoot.sh
[root@~]# sh /u01/app/19.0.0/grid/root.sh
</code></pre>
<p>Volvemos a conectar con el usuario <strong>grid</strong>, y verificamos con "<em><strong>crsctl stat res -t</strong></em>" lo tenemos todo correcto.</p>
<p>En mi caso, después de revisar el output del comando y revisar el log para ver si ha habido errores, vi que la parte de <strong>asm</strong> algo erróneo, y después de ejecutar "<em><strong>srvctl status asm</strong></em>", se confirmaron mis sospechas, asm no existía, así que lo tuve que configurar después.</p>
<p>Dejo por aquí como lo configure, por si os ocurre lo mismo:</p>
<pre><code class="language-shell">[grid@intheshadow ~]$ asmca -silent -configureASM \
  -sysAsmPassword 'XXXXXX' \
  -asmsnmpPassword 'XXXXXX' \
  -diskString 'ORCL:*' \
  -diskGroupName DATA \
  -diskList 'ORCL:DATA01' \
  -redundancy EXTERNAL \
  -au_size 4

[grid@intheshadow ~]$ srvctl status asm
 ASM is running on intheshadow
</code></pre>
<p>Como último paso, antes de crear el diskgroup de <em><strong>RECO</strong></em>, revisamos de nuevo los recursos con <em><strong>crsctl stat res -t</strong></em>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/ec2b41d7-4c14-40a9-8181-bc62ad95e452.png" alt="" style="display:block;margin:0 auto" />

<p>Listo, ya podemos crear el <em>diskgroup</em> de <em><strong>RECO</strong></em>. Aquí podemos tomar dos caminos para hacerlo, o bien vía instrucción <em>DDL</em> o usando <em>asmca</em>.</p>
<p>En mi caso opte por usar <em>asmca</em>:</p>
<pre><code class="language-shell">[grid@~]# asmca -silent -createDiskGroup \ 
-diskString 'ORCL:*' \
-diskGroupName RECO \ 
-diskList 'ORCL:RECO01' \ 
-redundancy EXTERNAL \ 
-au_size 4 \ 
-sysAsmPassword 'XXXXXX'
</code></pre>
<h2>Instalación Oracle Database 19.32</h2>
<p>El primer paso, además de configurar el .bash_profile de Oracle, debemos descomprimir el zip de Oracle en <em>/u01/app/oracle/product/19.0.0/dbhome_1</em>.</p>
<p>Una vez hecho y antes de lanzar el <strong>runinstaller</strong>, verificamos en el fichero <em>/etc/oraInst.loc</em> que está todo correcto.</p>
<p>El fichero response que he utilizado, lo podemos descargar desde <a href="https://github.com/dbaenlasombra/OCI/blob/main/oracle.rsp">aquí</a>.</p>
<p>Lanzamos la instalación:</p>
<pre><code class="language-shell">[oracle@~]# cd $ORACLE_HOME
[oracle@~]# ./runInstaller -silent -waitforcompletion -applyRU /u01/software/39467003 -responseFile /home/oracle/oracle.rsp
</code></pre>
<p>Una vez completado, bajo el usuario <em><strong>root</strong></em> lanzamos el script root.sh.</p>
<pre><code class="language-shell">[root@~]# . /u01/app/oracle/product/19.0.0/dbhome_1/root.sh
</code></pre>
<p>Tenemos la instalación lista, pero sin base de datos aún.</p>
<p>En próximos capítulos continuaremos con nuestro laboratorio.</p>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] SQL: Calendar functions/Aggregation Filters "CALENDAR"]]></title><description><![CDATA[En el artículo de hoy vamos a ver las Calendar functions en 26ai, diseñadas para simplificar la "vida" a los desarrolladores. Antes de su existencia, esto se resolvía con ingeniosas combinaciones usan]]></description><link>https://dbaenlasombra.com/26ai-sql-calendar-functions-aggregation-filters-calendar</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-sql-calendar-functions-aggregation-filters-calendar</guid><category><![CDATA[Oracle 26ai]]></category><category><![CDATA[SQL]]></category><category><![CDATA[calendar]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Wed, 22 Jul 2026 21:15:10 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/587e3328-9877-4c7a-aad7-7811e251f81e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>En el artículo de hoy vamos a ver las <strong>Calendar functions</strong> en 26ai, diseñadas para simplificar la "vida" a los desarrolladores. Antes de su existencia, esto se resolvía con ingeniosas combinaciones usando <strong>case</strong>, <strong>subquerys</strong> o incluso condiciones de <strong>agregación</strong>. Haciendo todo ello, en algunos casos, una combinación perfecta para hacer consultas con cierta complejidad.</p>
<p>Estás extensiones formar parte de <strong>SFA Initiative</strong> (<em>Select for Analysis</em>), diseñadas para alinear más el Oracle SQL a los estándares.</p>
<p>A continuación puedes ver un gráfico ilustrativo de algunas de las distintas funciones que se han incorporado.</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/b70df231-6438-4b25-92b2-69a4f8dcfc2c.png" alt="" style="display:block;margin:0 auto" />

<p>¿Cuándo debemos usarlas?</p>
<ul>
<li><p>Cuando necesitamos agrupar en consultas analíticas por algún tipo de calendario descrito en el punto anterior.</p>
</li>
<li><p>Series temporales entre un rango de fechas.</p>
</li>
<li><p>Conversión del dato a nivel de columna.</p>
</li>
<li><p>Operaciones a nivel de un calendario, como agregar días o semanas.</p>
</li>
</ul>
<p>Antes de empezar este laboratorio, debemos estar con la última versión de Oracle 23.26.2.</p>
<pre><code class="language-sql">SQL&gt; Select banner from v$version;

BANNER
--------------------------------------------------------------
Oracle AI Database 26ai Enterprise Edition Release 23.26.2.0.0 - Production
</code></pre>
<p>Para tener algo de información en nuestra PDB, vamos a cargar el schema de <strong>HR</strong>. Los scripts de este schema se encuentran en el github de <strong>Oracle Sample Projects</strong>.</p>
<p>Dejo aquí el enlace:</p>
<p><a href="https://github.com/oracle-samples/db-sample-schemas">Github Oracle Sample Projects</a></p>
<p>El modelo ER es el siguiente:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/c6bc7ce7-0509-452c-812b-b56115bcc7dd.png" alt="" style="display:block;margin:0 auto" />

<h2>CALENDAR</h2>
<h3>%_Year</h3>
<p>Vamos a ver como interpreta cada una de estas funciones usando la misma columna de tipo date sin necesidad de restructurar nada.</p>
<pre><code class="language-sql">SQL&gt; 
select EMPLOYEE_ID,
       calendar_year(START_DATE) calendar,
       fiscal_year(START_DATE)   fiscal,
       retail_year(START_DATE)   retail,
       START_DATE,END_DATE,JOB_TITLE,MIN_SALARY,MAX_SALARY
from HR.JOB_HISTORY NATURAL JOIN (Hr.JOBS)
  fetch first 10 rows only
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/42749812-26e8-437c-810c-ce3e344fe0ad.png" alt="" style="display:block;margin:0 auto" />

<p>También pueden ser usadas para filtrar el resultado:</p>
<pre><code class="language-sql">SQL&gt; 
Select    EMPLOYEE_ID,START_DATE,END_DATE,JOB_TITLE,MIN_SALARY,MAX_SALARY
from HR.JOB_HISTORY NATURAL JOIN (Hr.JOBS)
where calendar_year(START_DATE) = 2011
  fetch first 10 rows only
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/89b742a1-4e94-4b06-8be2-e5b7f6810994.png" alt="" style="display:block;margin:0 auto" />

<p>En este caso podíamos usar un <em><strong>Extract(Year from START_DATE)</strong></em> y el resultado hubiera sido idéntico ¿verdad?</p>
<p>Pero mirando el <em><strong>explain plan</strong></em> de uno y otro, vemos alguna diferencia:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/c3b72f0c-2f5f-46b2-b0cd-dd1e00e0fb62.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/f1bacd50-cc11-49f7-8307-305e29ee310a.png" alt="" style="display:block;margin:0 auto" />

<p>Internamente el <em>extract</em> se resuelve con <em>INTERNAL_FUNCTION</em> , mientras que el uso de la nueva función, el acceso es distinto. Curioso, en próximos artículos tendremos que profundizar este punto.</p>
<p>En el próximo artículo, veremos las funciones RETAIL y FISCAL.</p>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[OCI] Recreación PDB$SEED]]></title><description><![CDATA[En el artículo de hoy vamos a ver como podemos recrear una PDB$Seed de manera fácil en caso que se quede corrupta y no tengamos backup.
sys@> alter pluggable database PDB$SEED open read only;
alter pl]]></description><link>https://dbaenlasombra.com/oci-recreaci-n-pdb-seed</link><guid isPermaLink="true">https://dbaenlasombra.com/oci-recreaci-n-pdb-seed</guid><category><![CDATA[Oracle]]></category><category><![CDATA[pdb]]></category><category><![CDATA[pdbclone]]></category><category><![CDATA[datapatch]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Sat, 04 Jul 2026 22:33:31 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/289ede5b-558c-4f93-b5c0-fa04680c91ca.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>En el artículo de hoy vamos a ver como podemos recrear una <strong>PDB$Seed</strong> de manera fácil en caso que se quede corrupta y no tengamos backup.</p>
<pre><code class="language-oracle-sql">sys@&gt; alter pluggable database PDB$SEED open read only;
alter pluggable database PDB$SEED open read only
*
ERROR en lÝnea 1:
ORA-01173: el diccionario de datos indica que falta un archivo datos del tablespace SYSTEM
</code></pre>
<p>Los pasos que vamos a realizar para re-crearla son los siguientes:</p>
<ul>
<li><p>Eliminar la <strong>PDB$Seed</strong>.</p>
</li>
<li><p>Crear una PDB vacía en otro <strong>CDB$Root</strong> para clonarla.</p>
</li>
<li><p>Crear <strong>PDB$Seed</strong> en base al punto anterior.</p>
</li>
</ul>
<p>Sin más, vamos a ello.</p>
<h3>1.- Eliminar PDB$Seed</h3>
<p>Recibiremos un error en caso de que intentamos borrarla directamente:</p>
<pre><code class="language-sql">sys@OSIALEPR&gt;  drop pluggable database "pdb$seed" including datafiles;
 drop pluggable database "pdb$seed" including datafiles
                         *
ERROR en lÝnea 1:
ORA-65017: la base de datos de conexi¾n inicial no se puede borrar ni modificar
</code></pre>
<p>Para poder borrarla con éxito, debemos jugar con el parámetro "<strong>_oracle_script</strong>".</p>
<pre><code class="language-oracle-sql">sys@&gt; alter session set "_oracle_script"=true;
sys@&gt; alter pluggable database "pdb$seed" close;
sys@&gt; drop pluggable database "pdb$seed" including datafiles;
sys@&gt; show pdbs

    CON_ID CON_NAME    OPEN MODE  RESTRICTED
---------- ----------- ---------- ----------
         3 PDB1        READ WRITE NO

SQL&gt; alter session set "_oracle_script"=false;  
</code></pre>
<p>Ahí podéis ver la secuencia que he seguido, entre medias verifico que la <strong>PDB$Seed</strong> ha desaparecido.</p>
<h3>2.- Pasos previos antes de la clonación de la PDB</h3>
<p>Vamos a preparar en otro entorno la PDB que va servir como base a nuestra <strong>PDB$Seed</strong>.</p>
<p>Como vamos a tener dos máquinas, para diferenciarlo, vamos a llamar <strong>origen</strong> a donde tenemos que recrear la <strong>PDB$Seed</strong> y <strong>clonado</strong> donde vamos a definir la PDB que va servir para re-crearla.</p>
<p>Este seria el modelo que vamos a seguir:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/3b44131d-8d3f-49f9-9398-4643b00912f8.png" alt="" style="display:block;margin:0 auto" />

<p>Primero, definimos el usuario común <strong>C##CLONE</strong> en <strong>origen</strong>.</p>
<pre><code class="language-sql">
SQL&gt; CREATE USER C##CLONE IDENTIFIED BY "XXXXX";
SQL&gt; GRANT CONNECT, RESOURCE, DBA, SYSOPER, CREATE PLUGGABLE DATABASE TO C##CLONE CONTAINER=ALL;
</code></pre>
<p>Defino la pdb TEST en <strong>clonado</strong>.</p>
<pre><code class="language-sql">SQL&gt; create pluggable database TEST admin user pdb_admin identified by oracle;
SQL&gt; alter pluggable database TEST open;
SQL&gt; alter pluggable database TEST close;
SQL&gt; alter pluggable database TEST open read only;
</code></pre>
<p>Creamos el DBLink en <strong>origen</strong>, habiendo incluido previamente la cadena de conexión en nuestro tnsnames.</p>
<pre><code class="language-sql">SQL&gt; CREATE DATABASE LINK REMOTE_SEED_LINK CONNECT TO C##CLONE IDENTIFIED BY "XXXXXX" using 'CLONADO';
</code></pre>
<p>Hasta aquí, ya tendríamos todo listo para crear de nuevo, nuestra <strong>PDB$Seed</strong></p>
<h3>Crear PDB$Seed</h3>
<p>Una vez definido el DBLink, ya podremos clonar <strong>TEST</strong> con nombre de <strong>PDB$Seed.</strong></p>
<pre><code class="language-sql">SQL&gt; CREATE PLUGGABLE DATABASE "PDB$SEED" FROM TEST@REMOTE_SEED_LINK;
</code></pre>
<p>Una vez finalizado, veifico que vemos ya <strong>PDB$Seed</strong> en <strong>origen</strong>.</p>
<pre><code class="language-sql">sys@&gt; show pdbs

    CON_ID CON_NAME    OPEN MODE  RESTRICTED
---------- ----------- ---------- ----------
         2 PDB$SEED    MOUNTED
         3 PDB1        READ WRITE NO
</code></pre>
<p>Perfecto, ya la vemos en origen. En este punto ya solo faltaría abrirla en <strong>READ ONLY</strong>.</p>
<pre><code class="language-sql">SQL&gt; alter session set "_oracle_script"=true;
Session altered.

SQL&gt; alter pluggable database PDB$SEED open read write;
Pluggable database altered.

SQL&gt; alter pluggable database PDB$SEED close;
Pluggable database altered.

SQL&gt; alter pluggable database PDB$SEED open read only;
Pluggable database altered.

SQL&gt; alter session set "_oracle_script"=false;
Session altered.
</code></pre>
<p>Volvemos a verificar:</p>
<pre><code class="language-sql">sys@&gt; show pdbs

    CON_ID CON_NAME    OPEN MODE  RESTRICTED
---------- ----------- ---------- ----------
         2 PDB$SEED    READ ONLY  YES
         3 PDB1        READ WRITE NO
</code></pre>
<p>Vaya, nuestra <strong>PDB$Seed</strong> tiene algún problemilla, tenemos que revisar <em>PDB_PLUG_IN_VIOLATIONS</em> para ver que sucede:</p>
<pre><code class="language-sql">sys@&gt; 
 Select Name, Cause, Type, Message, Status From Pdb_Plug_In_Violations Where  Status != 'RESOLVED' And Type='ERROR' Order By Name;
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/8d6c955d-ecee-4da1-aad0-c6fffd83c276.png" alt="" style="display:block;margin:0 auto" />

<p>El error es claro, así que debemos ejecutar el <strong>datapatch</strong> para solucionarlo</p>
<pre><code class="language-shell">[oracle@~]$ $ORACLE_HOME/OPatch/datapatch -verbose
</code></pre>
<p>Una vez finalizado, verificamos que el problema se ha solucionado:</p>
<pre><code class="language-sql">SQL&gt; 
select type, cause, message,CON_ID
from PDB_PLUG_IN_VIOLATIONS
where status != 'RESOLVED';

no rows selected
</code></pre>
<p>Ya no tenemos errores, así que ya solo faltaria dejar nuestra <strong>PDB$Seed</strong> en modo <strong>READ ONLY</strong>,</p>
<pre><code class="language-sql">SQL&gt; alter session set container=PDB$SEED;

Session altered.

SQL&gt; alter session set "_oracle_script"=TRUE;

Session altered.

SQL&gt; alter pluggable database PDB$SEED  close immediate instances=all;

Pluggable database altered.

SQL&gt;  alter pluggable database  PDB$SEED OPEN READ ONLY;

Pluggable database altered.

SQL&gt;  alter session set "_oracle_script"=false;

Session altered.
</code></pre>
<p>Verificamos de nuevo:</p>
<pre><code class="language-sql">sys@&gt; show pdbs

    CON_ID CON_NAME    OPEN MODE  RESTRICTED
---------- ----------- ---------- ----------
         2 PDB$SEED    READ ONLY  NO
         3 PDB1        READ WRITE NO
</code></pre>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[OCI] Clone PDB]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
En el artículo de hoy vamos a ver como podemos clonar una PDB usando RMAN Active Duplicate o bien usando una instrucción DDL entre]]></description><link>https://dbaenlasombra.com/oci-clone-pdb</link><guid isPermaLink="true">https://dbaenlasombra.com/oci-clone-pdb</guid><category><![CDATA[Oracle]]></category><category><![CDATA[pdb]]></category><category><![CDATA[clone]]></category><category><![CDATA[oraclerman]]></category><category><![CDATA[shell script]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Sat, 20 Jun 2026 22:06:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/8ce0c665-4a5d-459d-91cf-ffe3f47d8176.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a href="https://dbaintheshadow.com/oci-clone-pdb"><em><strong>English version</strong></em></a><em>.</em></p>
<p>En el artículo de hoy vamos a ver como podemos <strong>clonar</strong> una PDB usando <strong>RMAN Active Duplicate</strong> o bien usando una instrucción <strong>DDL</strong> entre diferentes <strong>CDB$Root</strong>.</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/c8bd4f6d-984b-47e8-ac7e-33eccef90736.png" alt="" style="display:block;margin:0 auto" />

<h3>DDL</h3>
<p>Para el primer caso tengo un script para automatizar este paso. Este script se debe ejecutar con el usuario <strong>oracle</strong> y en la máquina de destino.</p>
<p>Link a github:</p>
<p><a href="https://github.com/dbaenlasombra/OCI/blob/main/remote_clonning.sh">https://github.com/dbaenlasombra/OCI/blob/main/remote_clonning.sh</a></p>
<p>¿Qué hace el script?</p>
<ul>
<li><p>Define un <strong>usuario común</strong> en origen con los permisos necesarios. El nombre es una cadena random <strong>no</strong> es estático, generada en unix "<em>tr -dc 'A-Za-z' &lt;/dev/urandom | head -c 5 | tr '[:lower:]' '[:upper:]'</em>" , así como la <strong>password</strong> , generada y cumpliendo los requisitos mínimos de seguridad de Oracle.</p>
</li>
<li><p>Define el <strong>DB Link</strong> en destino. Igual que el paso previo, se genera el nombre de manera aleatoria.</p>
</li>
<li><p>Creación de la <strong>PDB</strong>.</p>
</li>
</ul>
<p>Una vez que se ha creado la PDB, el script eliminará el <strong>usuario común</strong> así como el <strong>DB Link</strong>.</p>
<p>Todos los nombres se generan <strong>random</strong> para <strong>no</strong> interferir con otros trabajos que haya en ese momento en nuestra PDB.</p>
<p>Como pasos previos antes de ejecutar el script, necesitamos hacer lo siguiente:</p>
<ul>
<li><p>Configurar una clave <strong>rsa</strong> para el usuario <strong>oracle</strong> en destino con nombre <strong>id_rsa</strong> y configurar esa clave en origen para permitir la comunicación entre ambas máquinas.</p>
</li>
<li><p>Configurar el <strong>local naming</strong> "<em>SOURCE</em>" en el tnsnames de <strong>destino</strong> con la cadena de conexión de nuestro origen.</p>
</li>
<li><p>Configurar en destino el parámetro <strong>one_step_plugin_for_pdb_with_tde</strong> a <strong>true</strong>.</p>
</li>
</ul>
<p>Este script espera los siguientes parámetros en este orden:</p>
<ul>
<li><p><strong>IP</strong> del <strong>origen</strong>. El motivo, es que abre una conexión <em>ssh</em> con el usuario <strong>oracle</strong> para entrar como <strong>sysdba</strong> y ejecutar las instrucciones necesarias para definir el usuario común.</p>
</li>
<li><p><strong>Nombre</strong> de la <strong>PDB</strong> que vamos a clonar.</p>
</li>
<li><p><strong>Password</strong> de la <strong>TDE</strong>.</p>
</li>
</ul>
<p>Lanzamos el sh en modo nohup:</p>
<pre><code class="language-shell">[oracle@~]$ 
nohup ./remote_clonning.sh \(1 \)2 $3 &gt; /tmp/remote_clonning.log 2&gt;&amp;1 &amp;
</code></pre>
<p>Y esto sería la salida del sh:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/f113fabc-b8c2-45ae-b0db-5b7ecfbed944.png" alt="" style="display:block;margin:0 auto" />

<p>El script también nos informaría en caso de fallo:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/1d9785d9-1dbc-4e4c-8bb9-fd6a748db379.png" alt="" style="display:block;margin:0 auto" />

<h3>RMAN ACTIVE DUPLICATE</h3>
<p>En este laboratio, también hay un script como en el paso anterior.</p>
<p>Link a github:</p>
<p><a href="https://github.com/dbaenlasombra/OCI/blob/main/rman_clone_pdb.sh">https://github.com/dbaenlasombra/OCI/blob/main/rman_clone_pdb.sh</a></p>
<p>Como pasos previos necesitamos hacer lo siguiente</p>
<ul>
<li><p>Incluir las cadenas de conexión de origen como destino en ambas máquinas.</p>
</li>
<li><p>Exportar la <strong>wallet</strong> en origen para importarla en destino.</p>
</li>
<li><p>Modificar el parámetro <strong>remote_recovery_file_dest</strong> en destino:</p>
</li>
</ul>
<pre><code class="language-sql">SQL&gt; alter system set remote_recovery_file_dest = '+RECO' scope = both sid = '*';
</code></pre>
<p>Este script espera los siguientes parámetros en este orden:</p>
<ul>
<li><p><strong>Connector</strong> para la base de datos que hace de <strong>auxiliar</strong>.</p>
</li>
<li><p><strong>Connector</strong> para la base de datos que hace de <strong>target</strong>.</p>
</li>
<li><p><strong>Nombre</strong> de la <strong>PDB</strong> que vamos a clonar.</p>
</li>
<li><p><strong>Nombre</strong> de la DB.</p>
</li>
</ul>
<p>Lanzamos el sh en modo nohup:</p>
<pre><code class="language-shell">[oracle@ ~]\( nohup ./rman_clone_pdb.sh "user\)/\(pass@\)local_name" "user\(/\)pass@\(local_name" \)pdb $db &gt; /tmp/rman_clone_pdb.log 2&gt;&amp;1 &amp;
</code></pre>
<p>Y esto sería la salida del sh:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/1109564f-0b7a-44b0-9766-f4d4cb2a32fc.png" alt="" style="display:block;margin:0 auto" />

<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[OCI] Check Jobs DBCli]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
En el artículo de hoy voy a compartir un sh que utilizo para ver de una manera rápida los jobs que se ejecutan desde Oracle Databa]]></description><link>https://dbaenlasombra.com/oci-check-jobs-dbcli</link><guid isPermaLink="true">https://dbaenlasombra.com/oci-check-jobs-dbcli</guid><category><![CDATA[OCI]]></category><category><![CDATA[dbcli]]></category><category><![CDATA[shell script]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Wed, 10 Jun 2026 14:47:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/1376a869-58fa-491e-926a-a6ead08f9c80.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a href="https://dbaintheshadow.com/oci-check-jobs-dbcli"><em><strong>English version</strong></em></a><em>.</em></p>
<p>En el artículo de hoy voy a compartir un <strong>sh</strong> que utilizo para ver de una manera rápida los jobs que se ejecutan desde <em><strong>Oracle Database Cloud</strong></em>.</p>
<p>A continuación, te muestro lo que podemos ver cuando ejecutamos el sh:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/614833e0-45bb-4950-bcfa-d5c462abefa3.png" alt="" style="display:block;margin:0 auto" />

<p>¿Qué podemos ver? En la parte superior, veremos una entrada inicial dándonos algo de información de la máquina, como el <em><strong>host</strong></em> y la <em><strong>IP</strong></em>, el <em><strong>shape</strong></em> y su <em><strong>timezone</strong></em>.</p>
<p>A continuación, veremos una tabla resumen con el número de total de <strong>jobs</strong> que se han ejecutado dentro de nuestra máquina, incluyendo los correctos "<strong>Success</strong>", erróneos "<strong>Failure</strong>" y de estado desconocido "<strong>Others</strong>".</p>
<p>En caso que se encuentren jobs erróneos, nos vendrá un detalle de cada job . La estructura que sigue es:</p>
<ul>
<li><p>Nombre del job ejecutado, junto el progreso y el número de hilos dentro del job cuyo estado es erróneo.</p>
</li>
<li><p>Código y descripción del error.</p>
</li>
<li><p>Lista de hilos erróneos.</p>
</li>
</ul>
<p>El código del sh es el siguiente:</p>
<pre><code class="language-shell">#!/bin/bash

JOB_NUM=`dbcli list-jobs -j | jq 'length'`
JOB_OK=`dbcli list-jobs -j | jq '[.[] | select(.status=="Success")] | length'`
JOB_KO=`dbcli list-jobs -j | jq '[.[] | select(.status=="Failure")] | length'`
JOB_UNKOWN=$((JOB_NUM - JOB_OK - JOB_KO))

get_Info(){
 curl -s -H "Authorization: Bearer Oracle" http://169.254.169.254/opc/v2/instance/metadata/$1
}

get_Extracc_Info_Job(){
 dbcli describe-job -i "\(1" -l Verbose | grep "\)2" | sed "s/.*$2:[[:space:]]*//"
}

get_Count_Task_Job(){
 dbcli describe-job -i \(1 -l Verbose | awk '/Task Name/{flag=1; next} flag' | awk '{print \)NF}' | grep \(2 | sort | uniq -c | awk '{print \)1}'
}

design_report(){
for ((i=0; i&lt;$1; i++)); do
    printf $2
done
}

design_report 100 '+'
printf '\n'
printf '\n'
echo "Check Jobs in "`hostname`" ("\((get_Info privateIP0)") - Shape "\)(get_Info dbSystemShape)" - Timezone "$(get_Info timeZone)
printf '\n'
design_report 59 '-'
printf '\n'
echo "| ⏰ Jobs ("\({JOB_NUM}") ✅ Success "\){JOB_OK}" ❌ Failure "\({JOB_KO}" ◉  Others "\){JOB_UNKOWN}" |"
design_report 59 '-'
printf '\n'
printf '\n'


if [ "${JOB_KO}" -ne 0 ]; then
echo "Detail Jobs Failure"
design_report 25 '-'
printf '\n'
i=0;
dbcli list-jobs | grep Failure  | awk '{print $1}' | while read -r linea; do
 ((i++))
 percent=\((get_Extracc_Info_Job \){linea} "Progress")
 if [ "$percent" != "NA" ]; then
 percent_n=${percent%\%}
 if [ "\(percent_n" -ge 1 ] &amp;&amp; [ "\)percent_n" -le 25 ]; then
  percent="◔ "${percent}
 fi
 if [ "\(percent_n" -ge 26 ] &amp;&amp; [ "\)percent_n" -le 50 ]; then
  percent="◑ "${percent}
 fi
 if [ "\(percent_n" -ge 51 ] &amp;&amp; [ "\)percent_n" -le 100 ]; then
  percent="◕ "${percent}
 fi
 design_report 3 '·' | sed "s/.*'·':[[:space:]]*//" | tr '·' ' '
 echo \({i}") "\)(get_Extracc_Info_Job \({linea} "Description")" ("\){percent}") ✖ Failure (" \((get_Count_Task_Job \){linea} "Failure") ")"
 design_report 5 '·' | sed "s/.*'·':[[:space:]]*//" | tr '·' ' '
 echo \((get_Extracc_Info_Job \){linea} "Message")
 design_report 5 '·' | sed "s/.*'·':[[:space:]]*//" | tr '·' ' '
 echo "List Task Failure"
 dbcli describe-job -i ${linea} -l Verbose | awk '/Task Name/{flag=1; next} flag' | grep "Failure" | cut -c1-60 | while read -r linea; do
  design_report 6 '·' | sed "s/.*'·':[[:space:]]*//" | tr '·' ' '
  echo "·"${linea}
 done
fi
done
``
fi

design_report 100 '+'
printf '\n'
</code></pre>
<p>Y aquí, el link para descargar:</p>
<p><a href="https://github.com/dbaenlasombra/OCI/blob/main/oci_dbcli_info.sh">https://github.com/dbaenlasombra/OCI/blob/main/oci_dbcli_info.sh</a></p>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] JOIN_TO_ME]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
En el artículo de hoy vamos a ver la nueva sintaxis introducida para simplificar aún más los joins evitando errores comunes, hacie]]></description><link>https://dbaenlasombra.com/26ai-join-to-me</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-join-to-me</guid><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Sun, 17 May 2026 10:19:32 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/16a23f6e-ec4c-4f0a-9529-2c8a2af2ef5e.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a href="https://dbaintheshadow.com/26ai-join-to-me"><em><strong>English version</strong></em></a><em>.</em></p>
<p>En el artículo de hoy vamos a ver la nueva sintaxis introducida para simplificar aún más los <strong>joins</strong> evitando errores comunes, haciendo cada <em>sql</em> más legible y explicita, este tipo de consultas son <em><strong>Row Widening Only Queries</strong></em> (<strong>RWOQs</strong>) garantizando que cada join solo añade columnas y no crea filas adicionales.</p>
<p>Este nuevo tipo de <strong>join</strong> esta disponible desde la última versión que ha lanzado Oracle, <strong>23.26.2</strong>.</p>
<pre><code class="language-sql">SQL&gt; Select banner from v$version;

BANNER
--------------------------------------------------------------
Oracle AI Database 26ai Enterprise 
 Edition Release 23.26.2.0.0 - Production
</code></pre>
<p>Antes de meternos en faena con este laboratorio, además de estar con última versión de Oracle vamos a cargar en nuestra PDB el schema <strong>HR</strong>. Los scripts de este schema se encuentra en el <em>github</em> de <strong>Oracle Sample Projects</strong>.</p>
<p>Dejo aquí el enlace:</p>
<p><a href="https://github.com/oracle-samples/db-sample-schemas">Github Oracle Sample Projects</a></p>
<p>Este el modelo que hemos cargado:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/f4ddc664-d84c-4964-9211-a3bfc7dcd04a.png" alt="" style="display:block;margin:0 auto" />

<p>Fijémonos cual son las tablas principales y cual son las tablas hijas ya que Oracle va usar las propias FK para resolver este <strong>join</strong>.</p>
<p>El tipo de join que aplica por defecto es <strong>LEFT OUTER JOIN</strong>.</p>
<p>Algunos beneficios son:</p>
<ul>
<li><p>Simplicidad SQL para complejas consultas.</p>
</li>
<li><p>Mantiene filtros explícitos a nivel de where o inner.</p>
</li>
<li><p>Confirma en tiempo de ejecución la unicidad de los join en tiempo de ejecución.</p>
</li>
</ul>
<p>Sin más, veamos algún ejemplo:</p>
<h3>Consulta simple</h3>
<pre><code class="language-sql">SQL&gt; 
select FIRST_NAME, LAST_NAME, EMAIL, JOB_TITLE  
  from hr.employees aa 
 inner join hr.jobs bb 
    on aa.job_id = bb.job_id
 fetch first 10 rows only
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/fcf60c4f-42b6-4b00-a86e-921dc5036222.png" alt="" style="display:block;margin:0 auto" />

<p>Veamos también el <em>explain plan</em>, para compararlo con el nuevo join:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/97c82fec-9ede-4214-852e-607f20781068.png" alt="" style="display:block;margin:0 auto" />

<p>Ahora realizamos la misma consulta pero usando la nueva sintaxis.</p>
<pre><code class="language-sql">SQL&gt;
select FIRST_NAME, LAST_NAME, EMAIL, JOB_TITLE  
  from hr.employees JOIN TO ONE ( hr.jobs )
 fetch first 10 rows only
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/9aca33e4-f5f7-4db1-959e-f4bbb02c9a59.png" alt="" style="display:block;margin:0 auto" />

<p>El explain plan:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/901ac589-75a2-4df0-bf76-24731fd2a2d1.png" alt="" style="display:block;margin:0 auto" />

<p>Pues los planes son diferentes, en el primer caso resuelve por <strong>NESTED LOOP</strong> pero el nuevo join resuelve por <strong>MERGE JOIN OUTER</strong> ¿motivo? Pues porque el nuevo <strong>JOIN</strong> resuelve por <strong>LEFT OUTER JOIN</strong>.</p>
<p>Si ejecutamos la misma query, pero por <strong>LEFT OUTER JOIN</strong> en vez de <strong>INNER</strong>, los planes son idénticos:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/1018291a-bb7c-45d8-8314-23abea992a4c.png" alt="" style="display:block;margin:0 auto" />

<h3>Consulta compleja</h3>
<pre><code class="language-sql">SQL&gt; r
Select STREET_ADDRESS, 
       POSTAL_CODE, 
       CITY,  
       COUNTRY_NAME, 
       REGION_NAME
  from locations aa
 inner join countries cc
    on aa.country_id  = cc.country_id
 inner join regions dd
    on cc.region_id   = dd.region_id
fetch first 10 rows only
/
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/39df7264-be40-4131-b846-725e25eca738.png" alt="" style="display:block;margin:0 auto" />

<p>Ahora realizamos la misma consulta pero usando la nueva sintaxis.</p>
<pre><code class="language-sql">SQL&gt; 
Select STREET_ADDRESS, POSTAL_CODE, CITY,  COUNTRY_NAME, REGION_NAME
FROM
    locations aa
    JOIN TO ONE
        (INNER join countries cc
            on aa.country_id  = cc.country_id
         inner join regions dd
            on cc.region_id   = dd.region_id
)
fetch first 10 rows only
</code></pre>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/9837cf1f-44a8-4223-8679-a2ab343eae42.png" alt="" style="display:block;margin:0 auto" />

<p>Si nos fijamos, en ambos ejemplos, siempre la tabla de la izquierda es la que hace de tabla principal, y la derecha la hija. Pero ¿Qué pasaría si la tabla principal no tiene FK directa con la tabla hija?.</p>
<pre><code class="language-sql">SQL&gt; 
    Select STREET_ADDRESS, POSTAL_CODE, CITY
          from locations JOIN TO ONE (departments)
      fetch first 10 rows only
      from locations JOIN TO ONE (departments)
                                  *
ERROR at line 2:
ORA-18641: No join key found for "DEPARTMENTS"
Help: https://docs.oracle.com/error-help/db/ora-18641/
</code></pre>
<p>Si nos fijamos en el modelo, la tabla LOCATIONS no tiene FK hacía DEPARTMENTS. La FK está definida en DEPARTMENTS, no en LOCATIONS.</p>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] Limpieza de objetos obsoletos en desuso]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
En el artículo de hoy vamos a definir una auditoría con el objetivo de hacer limpieza de package/procedure/function en una base de]]></description><link>https://dbaenlasombra.com/26ai-limpieza-de-objetos-obsoletos-en-desuso</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-limpieza-de-objetos-obsoletos-en-desuso</guid><category><![CDATA[Oracle 26ai]]></category><category><![CDATA[audit]]></category><category><![CDATA[ash]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Sun, 19 Apr 2026 22:16:15 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/93181086-1008-4184-8454-33b7367ebedb.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a href="https://dbaintheshadow.com/26ai-cleanup-of-obsolete-pl-sql-objects"><em><strong>English version</strong></em></a><em>.</em></p>
<p>En el artículo de hoy vamos a definir una auditoría con el objetivo de hacer limpieza de <strong>package</strong>/<strong>procedure</strong>/<strong>function</strong> en una base de datos que ya no se utilizan, con el objetivo de reducir el gran volumen que hay .</p>
<p>La sintaxis para definir la <strong>AUDIT</strong> será la siguiente:</p>
<pre><code class="language-sql">Create audit policy "_name_" 
 Actions execute On "_owner_"."_name_";

Alter audit policy "_name_" 
  Add Actions execute on "_owner_"."_name_";
</code></pre>
<p>La primera sentencia sería la que define nuestra <strong>policy</strong>, mientras que la segunda sentencia sería para añadir más objetos.</p>
<p>La <strong>SQL ad hoc</strong> con la sentencia preparada sería la siguiente:</p>
<pre><code class="language-sql">SQL&gt; 
Select 
  ( Case When Rownum = 1 Then 'Create' Else 'Alter ' End )   
    || ' AUDIT POLICY CHECK_EXEC ' || 
  ( Case When Rownum = 1 Then ' ' Else ' ADD ' End ) 
    || ' Actions EXECUTE on '||OWNER||'.'||OBJECT_NAME||';' SDDL
  From Dba_Objects 
  where Owner = '&amp;OWNER' 
    and Object_type  in ('PÀCKAGE','FUNCTION','PROCEDURE');

SDDL
---------------------------------------------------------------
Create AUDIT POLICY CHECK_EXEC   Actions EXECUTE on "_owner_"."_name_";
Alter  AUDIT POLICY CHECK_EXEC  ADD  Actions EXECUTE on "_owner_"."_name_";
Alter  AUDIT POLICY CHECK_EXEC  ADD  Actions EXECUTE on "_owner_"."_name_";
...
</code></pre>
<p>Como último paso , activamos la auditoría:</p>
<pre><code class="language-sql">SQL&gt; audit policy CHECK_EXEC;
</code></pre>
<p>Una vez que lo tenemos activa podemos ir vigilando la información que nos va auditando:</p>
<pre><code class="language-sql">SQL&gt; 
select *
from unified_audit_trail
where action_name = 'EXECUTE'
and object_schema = upper('&amp;OWNER')
and object_name = upper('&amp;OBJECT')
and return_code = 0
order by EVENT_TIMESTAMP desc
fetch first 10 rows only;
</code></pre>
<p>Una vez que hemos dejado el tiempo suficiente, procedemos a extraer la información con la siguiente consulta:</p>
<pre><code class="language-sql">SQL&gt;
With get_Object_bd As (
  Select /*+ MATERIALIZE */
        Owner, Object_Name, object_type
    From dba_Objects 
   Where Owner = '&amp;OWNER' 
     and object_type  in ('PÀCKAGE','FUNCTION','PROCEDURE')
  ),  Audit_Objects as ( 
    Select  /*+ MATERIALIZE */
          object_schema, 
          object_name,
          min(event_timestamp) as first_exec_time,
          max(event_timestamp) as last_exec_time
    from  unified_audit_trail
    where action_name    = 'EXECUTE'
      and object_schema  = '&amp;OWNER'
    group by object_schema, object_name      
)
Select *
From get_Object_bd a 
   left outer join Audit_Objects  b 
  on a.Owner = b.object_schema 
 and  a.object_name = b.object_name 
</code></pre>
<p>Esto mismo que hemos hecho con una <strong>audit</strong>, lo podemos hacer cambiando la profundidad del periodo de retención de <strong>ASH/AWR</strong>.</p>
<p>La consulta debería hacerse sobre la <strong>DBA_HIST_ACTIVE_SESS_HISTORY</strong>.</p>
<pre><code class="language-sql">SQL&gt; 
With get_Object_bd As (
  Select /*+ MATERIALIZE */
         object_id, object_name, object_type
    From dba_Objects 
   Where Owner = '&amp;OWNER' 
     And object_type  in ('PÀCKAGE','FUNCTION','PROCEDURE')
)
select object_id, 
       object_name, 
       object_type,
       min(sample_time) first_seen, max(sample_time) last_seen
from get_Object_bd 
 left outer join dba_hist_active_sess_history 
    on object_id = plsql_entry_object_id
  group by object_id, object_name, object_type
</code></pre>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] Hybrid Read-Only Mode PDB]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
En el artículo de hoy, vamos a ver el nuevo open-mode introducido en 26ai denominado Hybrid Read-Only .
Cuando usamos este modo, e]]></description><link>https://dbaenlasombra.com/26ai-hybrid-read-only-mode-pdb</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-hybrid-read-only-mode-pdb</guid><category><![CDATA[Oracle 26ai]]></category><category><![CDATA[pdb]]></category><category><![CDATA[commonuser]]></category><category><![CDATA[localuser]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Thu, 09 Apr 2026 23:18:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/de208bd2-5e24-4fd3-acf7-8e5394d95283.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a href="https://dbaintheshadow.com/26ai-hybrid-read-only-mode-pdb"><em><strong>English version</strong></em></a><em>.</em></p>
<p>En el artículo de hoy, vamos a ver el nuevo <em><strong>open-mode</strong></em> introducido en 26ai denominado <strong>Hybrid Read-Only</strong> .</p>
<p>Cuando usamos este modo, el <strong>common user</strong> seguirá teniendo acceso <em><strong>read-write</strong></em>, mientras que el <strong>local user</strong> solo tendrá acceso <em><strong>read-only</strong></em>.</p>
<p>Sin más, vamos a ello.</p>
<p>El primer paso es definir una nueva PDB.</p>
<pre><code class="language-sql">SQL&gt; CREATE PLUGGABLE DATABASE PDB_HYBRID ADMIN USER admin IDENTIFIED BY admin keystore identified by external store;

Pluggable database created.

SQL&gt; ALTER PLUGGABLE DATABASE  PDB_HYBRID OPEN;
Pluggable database altered.

SQL&gt; ALTER PLUGGABLE DATABASE  PDB_HYBRID SAVE STATE;
Pluggable database altered.
</code></pre>
<p>Definimos los diferentes usuarios:</p>
<pre><code class="language-sql">SQL&gt; CREATE USER c##hybrid IDENTIFIED BY "XXXXXXX";
User created.
SQL&gt; GRANT DBA TO c##hybrid CONTAINER=ALL;
Grant succeeded.

SQL&gt; alter session set container=pdb_hybrid;
SQL&gt; create smallfile tablespace tb1 
      datafile size 1m autoextend on maxsize 10m;

Tablespace created.

SQL&gt; CREATE USER hybrid IDENTIFIED BY "XXXXXXX"
  DEFAULT TABLESPACE tb1
  TEMPORARY TABLESPACE temp
  QUOTA UNLIMITED ON tb1;  

User created.

SQL&gt; GRANT DBA TO hybrid;

Grant succeeded.
</code></pre>
<p>Perfecto, ya tenemos definidos tanto el <strong>common user</strong> (<em><strong>c##hybrid)</strong></em> como el <strong>local user</strong> (<em><strong>hybrid</strong></em>).</p>
<p>Antes de abrir la PDB con el nuevo estado, vamos a conectarnos con el usuario <em><strong>hybrid</strong></em> para definir un tabla con algo de información:</p>
<pre><code class="language-sql">SQL&gt; conn hybrid/"XXXXX"@X.X.X.X:1521/pdb_hybrid.XXXX.XXXX.XXXX.com
Connected.
SQL&gt;      
SQL&gt; 
 Create table T_TEST AS 
  SELECT OBJECT_NAME FROM ALL_OBJECTS;

Table created.
</code></pre>
<p>Nos conectamos a <strong>CDB$Root</strong> para poner en modo <strong>hybrid read-only</strong> la PDB.</p>
<pre><code class="language-sql">SQL&gt; alter pluggable database PDB_HYBRID close;

Pluggable database altered.

SQL&gt; alter pluggable database PDB_HYBRID open hybrid read only;

Pluggable database altered.

SQL&gt; r
    select con_name,
           open_mode,
           is_hybrid_read_only
    from   v$container_topology

CON_NAME             OPEN_MODE  IS_HYBRID_READ_ONLY
-------------------- ---------- --------------------
CDB$ROOT             READ WRITE NO
PDB$SEED             READ ONLY  NO
PDB_HYBRID           READ WRITE YES
</code></pre>
<p>Nos conectamos con el <strong>local user</strong> a la PDB e intentamos realizar operaciones DML (<em>delete</em>) y DDL (<em>truncate</em>).</p>
<pre><code class="language-sql">SQL&gt;  conn hybrid/"XXXXX"@X.X.X.X:1521/pdb_hybrid.XXXX.XXXX.XXXX.com
Connected.
SQL&gt; set linesize 1000
SQL&gt; col name format a20
SQL&gt; select name, open_mode from v$pdbs;

NAME                 OPEN_MODE
-------------------- ----------
PDB_HYBRID           READ ONLY

SQL&gt; delete T_TEST;
delete T_TEST
       *
ERROR at line 1:
ORA-16000: Attempting to modify database or pluggable database that is open for read-only access.
Help: https://docs.oracle.com/error-help/db/ora-16000/


SQL&gt; truncate table T_TEST;
truncate table T_TEST
*
ERROR at line 1:
ORA-16000: Attempting to modify database or pluggable database that is open for read-only access.
Help: https://docs.oracle.com/error-help/db/ora-16000/
</code></pre>
<p>Han fallado ambas operaciones con el siguiente mensaje "<em>ORA-16000: Attempting to modify database or pluggable database that is open for read-only access"</em>.</p>
<p>Ahora, nos conectamos con el <strong>common user</strong> y repetimos ambas operaciones.</p>
<pre><code class="language-sql">SQL&gt;  conn c##hybrid/"FJA_2026_Oracle19c" 
Connected.

SQL&gt;  alter session set container=PDB_HYBRID;
Session altered.

SQL&gt;  select name, open_mode from v$pdbs;

NAME                 OPEN_MODE
-------------------- ----------
PDB_HYBRID           READ WRITE

SQL&gt; delete hybrid.T_TEST;

52165 rows deleted.

SQL&gt; truncate table hybrid.T_TEST;

Table truncated.
</code></pre>
<p>Hemos podido hacer ambas operaciones.</p>
<p>Otro punto que hay que mirar es la <strong>v$pdbs</strong>, cuando estamos conectados con el <strong>local user</strong> el OPEN_MODE viene READ ONLY, en cambio, para el <strong>common user</strong> el valor es READ WRITE.</p>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] ALERT_LOG_MAX_SIZE]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
El artículo veremos un nuevo parámetro introducido en 26ai para poder gestionar de manera fácil y eficiente el tamaño del alert lo]]></description><link>https://dbaenlasombra.com/26ai-alert-log-max-size</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-alert-log-max-size</guid><category><![CDATA[Oracle]]></category><category><![CDATA[Oracle 26ai]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Fri, 03 Apr 2026 14:55:11 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/cbb365d0-4428-4a41-930d-516ce59e3355.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a href="https://dbaintheshadow.com/26ai-alert-log-max-size"><em><strong>English version</strong></em></a><em>.</em></p>
<p>El artículo veremos un nuevo parámetro introducido en 26ai para poder gestionar de manera fácil y eficiente el tamaño del <strong>alert log</strong>, es <strong>alert_log_max_size</strong>.</p>
<p>El valor por defecto del nuevo parámetro es 1000Mb:</p>
<pre><code class="language-sql">SQL&gt;
SQL&gt; show parameter alert_log_max_size

NAME               TYPE        VALUE
------------------ ----------- -------
alert_log_max_size big integer 1000M

SQL&gt;
</code></pre>
<p>Oracle internamente gestiona el <strong>alert log</strong> en bloques de 50Mb, es decir, nunca vamos a ver un <strong>alert log</strong> con un tamaño de 1000M, sino que veremos <strong>20</strong> ficheros de 50Mb cada uno.</p>
<p>Este parámetro solo se puede modificar a nivel de <strong>CDB$Root</strong>,no a nivel de <strong>PDB</strong>:</p>
<pre><code class="language-sql">SQL&gt; ALTER SYSTEM SET ALERT_LOG_MAX_SIZE = 150M; 

ALTER SYSTEM SET ALERT_LOG_MAX_SIZE = 150M 
* 
ERROR at line 1: ORA-65040: Operation is not allowed from within a pluggable database.
</code></pre>
<p>Vamos añadir información en el <strong>alert log</strong> para ver cómo se comporta Oracle:</p>
<pre><code class="language-sql">[oracle@~]cat save_inf.sql
begin 
declare 
 i number := 0; 
 begin 
  loop i := i + 1; 
  sys.dbms_system.ksdwrt(2, 'string(''L'',?)= ' || dbms_random.string('L',trunc(dbms_random.value(10,21)))); 
 exit when i &gt;= 10000000; 
end loop; 
end; 
end; 
/
[oracle@~] 
 watch -n 10 "sqlplus -s / as sysdba @save_inf.sql"
[oracle@l23ai alert]$ ls -lash *xml 
51M -rw-r----- 1 oracle asmdba 51M Apr 2 18:11 log_1.xml 
51M -rw-r----- 1 oracle asmdba 51M Apr 2 18:11 log_2.xml 
46M -rw-r----- 1 oracle asmdba 46M Apr 2 18:11 log.xml
</code></pre>
<p>Como podemos observar el <strong>alert log</strong> se ha dividido en ficheros de 50Mb!.</p>
<p>Una pequeña puntualizacion del nuevo parámetro, si está seteado con valor 0, el <strong>alert log</strong> tendrá un crecimiento ilimitado del <strong>alert log</strong>.</p>
<p>Pero ¿Podemos cambiar el valor 50Mb a otro valor? La respuesta es sí. Con el parámetro oculto "<strong>_alert_segment_size</strong>" podremos controlar el tamaño.</p>
<pre><code class="language-sql">SQL&gt; ALTER SYSTEM SET "_alert_segment_size" = 30;
System altered.

SQL&gt; show parameter "_alert_segment_size"

NAME               TYPE        VALUE
------------------ ----------- -------
_alert_segment_size integer     30

[oracle@l23ai ~]$ 
 watch -n 10 "sqlplus -s / as sysdba @save_inf.sql"
[oracle@l23ai alert]$ ls -lash *xml 
51M -rw-r----- 1 oracle asmdba 51M Apr 2 18:11 log_1.xml 
51M -rw-r----- 1 oracle asmdba 51M Apr 2 18:11 log_2.xml 
46M -rw-r----- 1 oracle asmdba 46M Apr 2 22:10 log_3.xml 
31M -rw-r----- 1 oracle asmdba 31M Apr 3 09:11 log_4.xml 
31M -rw-r----- 1 oracle asmdba 31M Apr 3 09:11 log_5.xml 
4.9M -rw-r----- 1 oracle asmdba 4.9M Apr 3 09:11 log.xml
</code></pre>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] ConnStr Tool]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
En el artículo de hoy, vamos a ver la nueva herramienta que se ha introducido en la 26ai ConnStr .
Es una herramienta command-line]]></description><link>https://dbaenlasombra.com/26ai-connstr-tool</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-connstr-tool</guid><category><![CDATA[Oracle]]></category><category><![CDATA[Oracle 26ai]]></category><category><![CDATA[listener]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Wed, 25 Mar 2026 18:41:01 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/5005f06e-946c-49ba-bfe8-7fe18d1075d9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a href="https://dbaintheshadow.com/26ai-connstr-tool"><em><strong>English version</strong></em></a><em>.</em></p>
<p>En el artículo de hoy, vamos a ver la nueva herramienta que se ha introducido en la 26ai <strong>ConnStr</strong> .</p>
<p>Es una herramienta command-line que sirve para mostrar las conexiones por cada servicio definido en nuestra base de datos en formatos <strong>Easy Connect</strong>, <strong>JDBC</strong> y <strong>Python</strong>, dándonos la posibilidad de incluir esa información dentro del <strong>tnsnames</strong>.</p>
<p>Otro punto que hay que tener en cuenta es que el listener debe estar levantado, sino nos dará error.</p>
<p>Sin más, vamos al lío.</p>
<p>Revisamos cómo se encuentra el <strong>listener</strong>:</p>
<pre><code class="language-sql">[oracle@~]$ lsnrctl status
LSNRCTL for Linux: Version 23.26.0.0.0 - for Oracle Cloud and Engineered Systems on 25-MAR-2026 14:28:21

Alias LISTENER 
Version TNSLSNR for Linux: Version 23.26.1.0.0 - Production 
Start Date 09-MAR-2026 17:13:58 
Uptime 15 days 21 hr. 14 min. 23 sec 
Trace Level off 
Security ON: Local OS Authentication 
SNMP OFF 
Listener Parameter File /u01/app/23.0.0.0/grid/network/admin/listener.ora
Listener Log File /u01/app/grid/diag/tnslsnr/l23ai/listener/alert/log.xml
Listening Endpoints Summary... 
(DESCRIPTION=(ADDRESS=(PROTOCOL=ipc)(KEY=LISTENER))) 
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=X.X.X.X)(PORT=1521)))

Services Summary... 
 Service "+APX" has 1 instance(s). 
Instance "+APX1", status READY, has 1 handler(s) for this service...
 Service "+ASM" has 1 instance(s). 
Instance "+ASM1", status READY, has 1 handler(s) for this service...
 Service "+ASM_DATA" has 1 instance(s). 
Instance "+ASM1", status READY, has 1 handler(s) for this service...
 Service "+ASM_RECO" has 1 instance(s). 
Instance "+ASM1", status READY, has 1 handler(s) for this service...
 Service "XXXXX.XXXXX.XXXXX.oraclevcn.com" has 1 instance(s).
Instance "DB23ai", status READY, has 2 handler(s) for this service...
 Service "XXXXX.XXXXX.XXXXX.oraclevcn.com" has 1 instance(s). 
Instance "DB23ai", status READY, has 2 handler(s) for this service...  
 Service "XXXXX.XXXXX.XXXXX.oraclevcn.com" has 1 instance(s). 
Instance "DB23ai", status READY, has 2 handler(s) for this service... 
 Service "XXXXX.XXXXX.XXXXX.oraclevcn.com" has 1 instance(s). 
Instance "DB23ai", status READY, has 1 handler(s) for this service...  
 Service "XXXXX.paas.oracle.com" has 1 instance(s). 
Instance "DB23ai", status READY, has 2 handler(s) for this service... 
 Service "XXXXX.paas.oracle.com" has 1 instance(s). 
Instance "DB23ai", status READY, has 2 handler(s) for this service... 
 Service "XXXXX.paas.oracle.com" has 1 instance(s). 
Instance "DB23ai", status READY, has 2 handler(s) for this service... 
 Service "XXXXX.XXXXX.XXXXX.oraclevcn.com" has 1 instance(s). 
Instance "DB23ai", status READY, has 2 handler(s) for this service... 
 Service "XXXXX.XXXXX.XXXXX.oraclevcn.com" has 1 instance(s). 
Instance "DB23ai", status READY, has 2 handler(s) for this service... 
 Service "XXXXX.XXXXX.XXXXX.oraclevcn.com" has 1 instance(s). 
Instance "DB23ai", status READY, has 2 handler(s) for this service... 
 Service "XXXXX.XXXXX.XXXXX.oraclevcn.com" has 1 instance(s). 
Instance "DB23ai", status READY, has 2 handler(s) for this service... 
The command completed successfully
</code></pre>
<p>Perfecto, el <strong>listener</strong> esta arriba.</p>
<p>Vamos a ejecutar <strong>ConnStr</strong> y veamos que información nos da:</p>
<pre><code class="language-sql">[oracle@ ~]$ connstr 
Using Listener: LISTENER with Oracle Home: /u01/app/oracle/product/23.0.0.0/dbhome_1

Service Name: XXXXXXXXX.paas.oracle.com 
Connection String: X.X.X.X:1521/XXXXXXXXX.paas.oracle.com

Service Name: XXXXXXX.XXXXXX.vcn23ai.oraclevcn.com 
Connection String: X.X.X.X:1521/XXXXXX.XXXXXXXX.vcn23ai.oraclevcn.com

...
...

Connection strings can be used to connect to the specified service name.

For SQL*Plus you can use: 
SQL&gt; connect username@X.X.X.X:1521/XXXXX.paas.oracle.com

For Python you can use: 
connection = oracledb.connect(user="username", password="password", dsn="X.X.X.X:1521/XXXXXX.paas.oracle.com")

For JDBC Thin you can use: OracleDataSource ods = new OracleDataSource();
ods.setURL("jdbc:oracle:thin:@X.X.X.X:1521/XXXXXX.paas.oracle.com");
ods.setUser("username"); ods.setPassword("password");
Connection conn = ods.getConnection();

Write connect strings to tnsnames.ora (Y/N)? (Default: N):
</code></pre>
<p>Que maravilla de output no? Oracle nos facilita de manera muy sencilla las cadenas de conexión para <strong>Easy Connect</strong>, <strong>JDBC</strong> y <strong>Python.</strong></p>
<p>Y como nota final, nos da la opción de incluir las cadenas en el <strong>tnsnames.ora</strong>!</p>
<p>En este caso, hemos ejecutado directamente el comando porque tenemos un único <strong>listener</strong>. Si tuviéramos más de un listener, podríamos especificar la opción <strong>-L</strong> junto con el nombre del listener.</p>
<p>Otras utilidades del comando son las siguientes:</p>
<ul>
<li>Listar los <strong>listener</strong> disponibles.</li>
</ul>
<pre><code class="language-sql">[oracle@~]$ connstr -e 
PROTOCOL PORT HOST 
tcp      1521 X.X.X.X
</code></pre>
<ul>
<li>Listar los servicios disponibles:</li>
</ul>
<pre><code class="language-sql">[oracle@~]$ connstr -s 
XXXXXXXX.paas.oracle.com 
XXXXXXXX.paas.oracle.com 
XXXXXXXX.XXXXXXXX.vcn23ai.oraclevcn.com 
pdb_david.XXXXXXXX.vcn23ai.oraclevcn.com 
+APX 
+ASM 
+ASM_DATA 
+ASM_RECO 
XXXXXXXX.XXXXXXXX.vcn23ai.oraclevcn.com 
XXXXXXXX.paas.oracle.com 
XXXXXXXX.XXXXXXXX.vcn23ai.oraclevcn.com 
XXXXXXXX.XXXXXXXX.vcn23ai.oraclevcn.com
</code></pre>
<ul>
<li>Obtener la conexión <strong>JDBC</strong> de un servicio</li>
</ul>
<pre><code class="language-sql">[oracle@ ~]$ connstr -j pdb_david jdbc:oracle:thin:@X.X.X.X:1521/XXXXXXXX.paas.oracle.com
</code></pre>
<ul>
<li>Obtener la cadena de conexión de un servicio</li>
</ul>
<pre><code class="language-sql">[oracle@~]$ connstr -d pdb_david
(DESCRIPTION=(ADDRESS=(PROTOCOL=tcp)(HOST=X.X.X.X)(PORT=1521))(CONNECT_DATA=(SERVICE_NAME=XXXXXXXX.paas.oracle.com)))
</code></pre>
<ul>
<li>Obtener la cadena de conexión de un servicio en formato <strong>Easy Connect</strong>.</li>
</ul>
<pre><code class="language-sql">[oracle@~]$ connstr -z pdb_david 
 X.X.X.X:1521/XXXXXXXX.paas.oracle.com
</code></pre>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] Instalación de Oracle26ai en Linux 9]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
En el artículo de hoy vamos a ver como podemos instalar Oracle 26ai en Linux 9.
[root@~]# grep PRETTY /etc/os-release
PRETTY_NAME=]]></description><link>https://dbaenlasombra.com/26ai-instalaci-n-de-oracle26ai-en-linux-9</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-instalaci-n-de-oracle26ai-en-linux-9</guid><category><![CDATA[Linux]]></category><category><![CDATA[Oracle 26ai]]></category><category><![CDATA[setup]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Sat, 14 Mar 2026 16:57:44 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/d9a6ba10-eb2d-4fee-8a0c-f4957cbdc676.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a href="https://dbaintheshadow.com/26ai-install-oracle-ai-database-26ai-on-linux-9"><em><strong>English version</strong></em></a><em>.</em></p>
<p>En el artículo de hoy vamos a ver como podemos instalar Oracle 26ai en Linux 9.</p>
<pre><code class="language-shell">[root@~]# grep PRETTY /etc/os-release
PRETTY_NAME="Oracle Linux Server 9.7"
</code></pre>
<p>El primer paso es descarga Oracle 26ai pre-installation desde <a href="https://yum.oracle.com/repo/OracleLinux/OL9/appstream/x86_64/getPackage/oracle-ai-database-preinstall-26ai-1.0-1.el9.x86_64.rpm">aquí</a>.</p>
<p>Procedemos a instalar el rpm una vez que lo tengamos descargado.</p>
<pre><code class="language-shell">root@~]# ls -lac oracle-ai-database-preinstall-26ai-1.0-1.el9.x86_64.rpm
-rw-r--r--. 1 root root 35302 mar  8 11:39 oracle-ai-database-preinstall-26ai-1.0-1.el9.x86_64.rpm
[root@~]# dnf -y install oracle-ai-database-preinstall-26ai-1.0-1.el9.x86_64.rpm
   
...
...
¡Listo!
</code></pre>
<p>Listo, revisamos que se ha creado el usuario <strong>oracle</strong> para proceder a crear los directorios de <em>ORACLE_HOME</em>.</p>
<pre><code class="language-shell">[root@~]# id oracle
uid=54321(oracle) gid=54321(oinstall) grupos=54321(oinstall),54322(dba),54323(oper),54324(backupdba),54325(dgdba),54326(kmdba),54330(racdba)
[root@~]# 
[root@~]# mkdir -p /u01/app/oracle/product/23.26.1/dbhome_1
[root@~]# chown -R oracle:oinstall /u01 &amp;&amp; chown -R oracle:oinstall /u01
[root@~]# su - oracle
[oracle@~]$ cd /u01/app/oracle/product/23.26.1/dbhome_1/
</code></pre>
<p>Adaptamos los ficheros .bashrc y bash_profile, para definir las siguientes variables:</p>
<pre><code class="language-shell">[oracle@~]$ tail -8 .bashrc
# User specific aliases and functions
ORACLE_BASE=/u01/app/oracle/
ORACLE_HOME=/u01/app/oracle/product/23.26.1/dbhome_1; export ORACLE_HOME
PATH=\(PATH:\){ORACLE_HOME}/bin; export PATH
LD_LIBRARY_PATH={ORACLE_HOME}/lib; export LD_LIBRARY_PATH
</code></pre>
<p>Descargamos <strong>Oracle AI Database 26ai (23.26.1) for Linux x86-64</strong> desde <a href="https://www.oracle.com/database/technologies/oracle26ai-linux-downloads.html">aquí</a>.</p>
<p>Una vez descargado lo copiamos en /u01/app/oracle/product/23.26.1/dbhome_1.</p>
<pre><code class="language-shell">[oracle@]$ pwd &amp;&amp; ls -lash
/u01/app/oracle/product/23.26.1/dbhome_1
total 2,3G
   0 drwxr-xr-x. 2 oracle oinstall   43 mar 14 12:12 .
   0 drwxr-xr-x. 3 oracle oinstall   22 mar  9 22:54 ..
2,3G -rwxr-x---. 1 oracle oinstall 2,3G mar 14 12:18 LINUX.X64_2326100_db_home.zip
[oracle@]$ unzip LINUX.X64_2326100_db_home.zip
</code></pre>
<p>Antes de realizar la instalación, vamos a adaptar el fichero response a nuestra instalación ya que usaremos el modo <strong>silent</strong> como método de instalación.</p>
<pre><code class="language-shell">[oracle@]$ vi install/response/db_install.rsp
[oracle@]\( grep -v "#" install/response/db_install.rsp | grep -v '^\)'
oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v23.0.0
installOption=INSTALL_DB_SWONLY
UNIX_GROUP_NAME=oinstall
INVENTORY_LOCATION=${ORA_INVENTORY}
ORACLE_HOME=/u01/app/oracle/product/23.26.1/dbhome_1
ORACLE_BASE=/u01/app/oracle/
installEdition=EE
OSDBA=dba
OSBACKUPDBA=dba
OSDGDBA=dba
OSKMDBA=dba
OSRACDBA=dba
[oracle@]$ ./runInstaller -silent -responsefile install/response/db_install.rsp
</code></pre>
<p>Con usuario root, ejecutamos los dos últimos scripts</p>
<pre><code class="language-shell">[root@~]# .  /u01/app/oraInventory/orainstRoot.sh
...
[root@~]# .  /u01/app/oracle/product/23.26.1/dbhome_1/root.sh
...
</code></pre>
<p>Verificamos la instalación:</p>
<pre><code class="language-shell">[oracle@~]$ sqlplus /nolog

SQL*Plus: Release 23.26.1.0.0 - Production on Sat Mar 14 17:49:10 2026
Version 23.26.1.0.0

Copyright (c) 1982, 2025, Oracle.  All rights reserved.

SQL&gt; 
</code></pre>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[OCI] Montaje de un Bucket como  un FS]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
En el artículo de hoy vamos a ver como montar un Bucket como un filesystem en un DB System de OCI, ya que puede ser algo muy útil ]]></description><link>https://dbaenlasombra.com/oci-montaje-de-un-bucket-como-un-fs</link><guid isPermaLink="true">https://dbaenlasombra.com/oci-montaje-de-un-bucket-como-un-fs</guid><category><![CDATA[OCI]]></category><category><![CDATA[bucket]]></category><category><![CDATA[Oracle Linux]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Mon, 09 Mar 2026 18:55:24 GMT</pubDate><enclosure url="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/05595570-0fbd-46ce-9db4-d2f0e9f09003.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a href="https://dbaintheshadow.com/oci-montaje-de-un-bucket-como-un-fs"><em><strong>English version</strong></em></a><em>.</em></p>
<p>En el artículo de hoy vamos a ver como montar un <em>Bucket</em> como un filesystem en un DB System de OCI, ya que puede ser algo muy útil poder administrar nuestro Bucket con si fuera un directorio más en nuestras máquinas.</p>
<p>El DB System de OCI tiene Oracle Linux Server 8.</p>
<pre><code class="language-shell">[root@~]$ grep ORACLE_* /etc/os-release
ORACLE_BUGZILLA_PRODUCT="Oracle Linux 8"
ORACLE_BUGZILLA_PRODUCT_VERSION=8.8
ORACLE_SUPPORT_PRODUCT="Oracle Linux"
ORACLE_SUPPORT_PRODUCT_VERSION=8.8
</code></pre>
<p>Para Oracle Linux 8 o superior, debemos utilizar <strong>OCIFS</strong>.</p>
<p>Antes de meternos en faena, tenemos que tener los siguientes puntos realizados:</p>
<ul>
<li><p>Tener un <em>Bucket</em> en nuestra <strong>tenancy</strong>.</p>
</li>
<li><p>Tener suficiente espacio en nuestra máquina, ya que <strong>OCIFS</strong> usa espacio en disco para cachear los objectos de nuestro <em>Bucket</em> .</p>
</li>
<li><p>OCI Cli configurado, ya que por defecto <strong>OCIFS</strong> usa <strong>API key-based authentication</strong> para autenticarse. Dejo por aquí, donde hablamos para configurarlo de manera sencilla.</p>
</li>
</ul>
<p><a href="https://dbaenlasombra.com/oci-oci-cli-y-su-configuracion"><strong>[OCI] OCI-cli y su configuración</strong></a></p>
<p>Así que que vamos a instalar <strong>OCIFS</strong> como usuario <strong>root</strong> en nuestra máquina:</p>
<pre><code class="language-shell">[root@~]$ dnf install ocifs -y
...
Last metadata expiration check: 2:19:05 ago on Sun 08 Mar 2026 12:38:39 PM UTC.
Dependencies resolved.
...
Installed:
  fuse-2.9.7-19.0.1.el8.x86_64                               
  fuse-common-3.3.0-19.0.1.el8.x86_64                               
  ocifs-1.2.0-6.el8.x86_64                              
...
...
Complete!
</code></pre>
<p>Perfecto, ahora vamos a mirar donde podríamos crear el directorio que actúe como cache para OCIFS.</p>
<pre><code class="language-shell">[root@~]$ 
df -h --output=source,size,used,avail,pcent,target | (read -r h; echo "$h"; sort -k2,2hr) | head -4
Filesystem                      Size  Used Avail Use% Mounted on
/dev/sdg                        196G   26G  161G  14% /u01
/dev/mapper/vg00-opt             33G  6.0G   26G  19% /opt
devtmpfs                         16G     0   16G   0% /dev
</code></pre>
<p>Donde más sitio tenemos es en /u01, así que crearemos ahí el directorio:</p>
<pre><code class="language-shell">[root@~]$ mkdir /u01/tmp
</code></pre>
<p>Consultamos el nombre del <em>Bucket</em> que queremos que sea un FS en nuestra máquina</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/bbd7ba6a-1a40-4a50-b206-f6d5363712b2.png" alt="" style="display:block;margin:0 auto" />

<p>Una vez copiado el nombre del <em>Bucket</em>, lo montamos con el comando <strong>ocifs</strong>:</p>
<pre><code class="language-shell">[root@~]$ mkdir /mybucket 
[root@~]$ ocifs --cache=/u01/tmp &lt;name_bucket&gt; /mybucket
[root@~]$ df -h /mybucket
Filesystem            Size  Used Avail Use% Mounted on
&lt;name_bucket&gt;          0     0     0    - /mybucket
[root@l23ai ~]# grep mybucket /proc/mounts
&lt;name_bucket&gt; /mybucket fuse.ocifs rw,nosuid,nodev,relatime,user_id=0,group_id=0,default_permissions 0 0
</code></pre>
<p>Perfecto, hemos montado nuestro Bucket y además vemos que se ha creado correctamente la entrada en <strong>/proc/mounts</strong>.</p>
<p>Vamos a crear un fichero con algo de información de manera local:</p>
<pre><code class="language-shell">[root@~]$ 
 touch /mybucket/passwd.bck &amp;&amp; cat /etc/passwd &gt; /mybucket/passwd.bck
</code></pre>
<p>Abajo, podéis ver que el fichero está correctamente en nuestro <em>Bucket</em> :</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/6e98eae6-a65b-4f8b-bd2e-d9cd6649a313.png" alt="" style="display:block;margin:0 auto" />

<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] DBMS_CLOUD — Capitulo Dos]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
Continuando con el artículo de la semana pasada, donde vimos la configuración y unos primeros usos de DBMS_CLOUD en el día a día, ]]></description><link>https://dbaenlasombra.com/26ai-dbms-cloud-capitulo-dos</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-dbms-cloud-capitulo-dos</guid><category><![CDATA[OCI]]></category><category><![CDATA[Oracle 26ai]]></category><category><![CDATA[bucket]]></category><category><![CDATA[datapump]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Tue, 24 Feb 2026 16:28:46 GMT</pubDate><enclosure url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/65605419d28f19cc44df7ef1/a21fde07-5a03-4169-9247-2425a1ffe40a.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a href="https://dbaintheshadow.com/26ai-dbms-cloud-chapter-two"><em><strong>English version</strong></em></a><em>.</em></p>
<p>Continuando con el artículo de la semana pasada, donde vimos la configuración y unos primeros usos de <em>DBMS_CLOUD</em> en el día a día, hoy continuaremos con la parte de <em>Data Pump</em>.</p>
<p>Dejo por aquí el enlace del primer capitulo:</p>
<p><a href="https://dbaenlasombra.com/26ai-dbms-cloud-capitulo-uno">[26ai] DBMS_CLOUD — Capitulo Uno</a></p>
<p>La idea del laboratorio es la siguiente:</p>
<ul>
<li><p>Export una tabla a nuestro <em>Bucket.</em></p>
</li>
<li><p>Importar la tabla que hemos exportado en el punto anterior</p>
</li>
</ul>
<p>Así que sin más, vamos ha realizar cada punto:</p>
<h3><strong>Export a un <em>Bucket</em></strong></h3>
<p>Vamos a definir un tabla que utilizaremos para exportar e importar:</p>
<pre><code class="language-sql">SQL&gt; 
  Create Table My_Grants As  
   Select TABLE_SCHEMA,TABLE_NAME,PRIVILEGE  
     From All_Tab_Privs;

 Table created.

SQL&gt; set linesize 1000 pages 1000
SQL&gt; col TABLE_SCHEMA format a20
SQL&gt; col table_name format a20
SQL&gt; col privilege format a20
SQL&gt; r
  1* Select * From My_Grants FETCH FIRST 10  ROWS ONLY

TABLE_SCHEMA         TABLE_NAME                     PRIVILEGE
-------------------- ------------------------------ --------------------
SYS                  DUAL                           SELECT
SYS                  SYSTEM_PRIVILEGE_MAP           READ
SYS                  TABLE_PRIVILEGE_MAP            READ
SYS                  USER_PRIVILEGE_MAP             READ
SYS                  STMT_AUDIT_OPTION_MAP          READ
SYS                  FINALHIST$                     INSERT
SYS                  DM$EXPIMP_ID_SEQ               SELECT
SYS                  MODELGTTRAW$                   SELECT
SYS                  MODELGTTRAW$                   INSERT
SYS                  PMAPGTT$                       SELECT
</code></pre>
<p>Utilizaremos la propiedad <strong>DEFAULT_CREDENTIAL</strong> para setear nuestra credencial por defecto y así no tener que indicarla dentro del <em>parfile</em> del <strong>export</strong>.</p>
<pre><code class="language-sql">SQL&gt; 
ALTER DATABASE PROPERTY SET DEFAULT_CREDENTIAL = 'TEST.DBA_IN_THE_SHADOW';

Database altered.

SQL&gt; 
Select PROPERTY_NAME,PROPERTY_VALUE 
  From database_properties  
 Where PROPERTY_NAME= 'DEFAULT_CREDENTIAL';

PROPERTY_NAME        PROPERTY_VALUE                           
-------------------- ---------------------------------------- 
DEFAULT_CREDENTIAL   TEST.DBA_IN_THE_SHADOW                    
</code></pre>
<p>Definimos el parfile:</p>
<pre><code class="language-sql">SQL&gt; ! vi export_to_bucket.par
SQL&gt; ! cat export_to_bucket.par
DUMPFILE=&lt;location_uri&gt;/&lt;TABLE&gt;.dmp
LOGFILE=&lt;TABLE&gt;.log
TABLES=&lt;SCHEMA&gt;.&lt;TABLE&gt;
CONTENT=DATA_ONLY
LOGTIME=ALL
METRICS=YES
FLASHBACK_TIME=SYSTIMESTAMP
encryption_password=hari
</code></pre>
<p>Esto es lo que hemos definido:</p>
<ul>
<li><p>DUMPILE: La ruta donde se va guardar el dmp, en nuestro caso es el Bucket más un nombre descriptivo.</p>
</li>
<li><p>LOGFILE: Nombre del log.</p>
</li>
<li><p>TABLES: Ahí indicamos la tabla que hemos creado previamente.</p>
</li>
<li><p>CONTENT=DATA_ONLY: Solo exportamos los datos</p>
</li>
<li><p>LOGTIME/METRICS: Métricas de tiempo de nuestro export.</p>
</li>
<li><p>FLASHBACK_TIME: Que sea un export consistente.</p>
</li>
<li><p>ENCRYPTION_PASSWORD: Encrypt de nuestro dmp.</p>
</li>
</ul>
<p>Ejecutamos el <em>export</em>:</p>
<img src="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/65605419d28f19cc44df7ef1/abcbe616-5049-4a34-b90e-db8f57914a8c.png" alt="" style="display:block;margin:0 auto" />

<p>Consultamos que el <strong>dmp</strong> se ha generado correctamente en el <em>Bucket</em>:</p>
<pre><code class="language-sql">SQL&gt; 
Select object_name, trunc(bytes / (1024*1024),2) MB
  From 
   dbms_cloud.list_objects('DBA_IN_THE_SHADOW', '&lt;location_uri&gt;'); 

OBJECT_NAME                                      MB
---------------------------------------- ----------
ORA7445pf_20260205085710_COM_1.zip            57.35
Wallet_OF2BAP.zip                               .02
Wallet_OF2BCE.zip                               .02
grant.dmp                                         0
grant.dmp_segments/aaaaaa                         2
grant.dmp_segments/aaaaab                       .86

6 rows selected.
</code></pre>
<p>Fijémonos una cosa sobre el <strong>dmp</strong> que tenemos en nuestro <em>Bucket</em>. Tenemos tres archivos, cuando hemos indicado uno único archivo sin comodines, es decir, sin <strong>%L</strong>, <strong>%l</strong>, <strong>%U</strong> o <strong>%u</strong>. El tamaño de nuestro <strong>dmp</strong> es 0Mb y los fragmentos son los que tiene el peso, esto es porque <em>Data Pump</em> divide cada parte del archivo en fragmentos más pequeños para una carga más rápida.</p>
<h3><strong>Import desde <em>Bucket</em></strong></h3>
<p>Ejecutamos el <em>import</em> creando una tabla previa para almacenar ahí la información:</p>
<pre><code class="language-sql">SQL&gt; CREATE TABLE MY_GRANTS_BCK AS SELECT * FROM MY_GRANTS WHERE 2 = 1;

Table created.
SQL&gt; ! vi import_to_bucket.par
SQL&gt; ! cat import_to_bucket.par
DUMPFILE=&lt;location_uri&gt;/&lt;TABLE&gt;.dmp
LOGFILE=MY_GRANTS.log
LOGTIME=ALL
METRICS=YES
REMAP_TABLE = TEST.MY_GRANTS:MY_GRANTS_BCK
encryption_password=yes
</code></pre>
<p>Esto es lo que hemos definido:</p>
<ul>
<li><p>DUMPILE: La ruta donde se encuentra el dmp.</p>
</li>
<li><p>LOGFILE: Nombre del log.</p>
</li>
<li><p>LOGTIME/METRICS: Métricas de tiempo de nuestro export.</p>
</li>
<li><p>REMAP_TABLE: Queremos que la información del dmp se albergue en otra tabla</p>
</li>
<li><p>ENCRYPTION_PASSWORD= Encrypt de nuestro dmp.</p>
</li>
</ul>
<p>Ejecutamos el <em>import</em>:</p>
<img src="https://cdn.hashnode.com/uploads/covers/65605419d28f19cc44df7ef1/1f70eaba-7bce-42eb-befe-5fcb06d93874.png" alt="" style="display:block;margin:0 auto" />

<p>Perfecto, hemos podido exportar e importar un dmp desde el <em>Bucket</em>.</p>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] DBMS_CLOUD — Capitulo Uno]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
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 nuestra]]></description><link>https://dbaenlasombra.com/26ai-dbms-cloud-capitulo-uno</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-dbms-cloud-capitulo-uno</guid><category><![CDATA[OCI]]></category><category><![CDATA[Oracle 26ai]]></category><category><![CDATA[dbms_cloud]]></category><category><![CDATA[bucket]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Fri, 20 Feb 2026 00:40:29 GMT</pubDate><enclosure url="https://cloudmate-test.s3.us-east-1.amazonaws.com/uploads/covers/65605419d28f19cc44df7ef1/971edde0-b81e-4a61-9ed1-bafbe4fc17bc.jpg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a href="https://dbaintheshadow.com/26ai-dbms-cloud-chapter-one"><em><strong>English version</strong></em></a><em>.</em></p>
<p>En el artículo de hoy vamos a ver algunos beneficios que podemos tener en el día a día al utilizar <em>DBMS_CLOUD</em> en 26ai para nuestras tareas diarias, como puede ser tareas de respaldo de un datapump o guardar informes, ya que se conecta a un <em>Object Storage</em> de OCI.</p>
<p>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 <strong>tenancy</strong>.</p>
<p>Antes de meternos en faena, debemos asegurarnos que nuestra base de datos tiene <em>DBMS_CLOUD</em> configurado y listo para usarse. Dejo por aquí la nota de Oracle para la instalación en caso que no tengamos configurado ese punto:</p>
<p><a href="https://support.oracle.com/support/?anchorId=&amp;kmContentId=2748362&amp;page=sptemplate&amp;sptemplate=km-article"><em><strong>How To Setup And Use DBMS_CLOUD Package (Doc ID 2748362.1)</strong></em></a></p>
<p>A nivel de OCI, debemos configurar para nuestro usuario un <strong>token</strong> o <strong>API Key</strong> ya que necesitamos definir una <strong>credencial</strong> porque nuestro <em>Bucket</em> es privado. No sería necesario definir la credencial si nuestro <em>Bucket</em> es público*.*</p>
<h3><strong>Token</strong></h3>
<p>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:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771410019467/915ef3cc-14f9-41d5-9e8f-feb4566a6036.png" alt="" style="display:block;margin:0 auto" />

<p>Una vez dentro, vamos a la pestaña <strong>Tokens and keys</strong>:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771329298121/73011e3f-f972-434c-9386-e50f55798bf7.png" alt="" style="display:block;margin:0 auto" />

<p>Ahí vamos a ver tres secciones: <em>API Keys</em>, <em>Auth Tokens</em> y <em>Customer Secrets Keys</em>.</p>
<p>Bien, la que nos interesa es la de <em>Auth Tokens</em>:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771329519186/02251fb9-d8c1-4ecb-b635-417e614f8d0a.png" alt="" style="display:block;margin:0 auto" />

<p>Ahí pulsamos en <em>Generate token</em>. Nos pedirá un nombre y pulsamos en <em>Generate token</em>:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771329590592/50419b9d-06d2-476b-b216-4b8fc0a8f0c0.png" alt="" style="display:block;margin:0 auto" />

<p>La siguiente ventana <strong>no</strong> la debemos cerrar sin antes copiar el token.</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771329749038/4ebb4308-6ad9-4092-a766-1e20ff09a5b9.png" alt="" style="display:block;margin:0 auto" />

<p>Una vez que hayamos copiado el token, definimos la <strong>credential</strong> en nuestra base de datos usando el token que hemos generado en el punto anterior.</p>
<h3><strong>Configuración de la Credencial</strong></h3>
<p>Para generarlo, debemos usar <strong>DBMS_CLOUD.CREATE_CREDENTIAL</strong>.</p>
<p>Este procedimiento recibe los siguientes parámetros:</p>
<ul>
<li><p>CREDENTIAL_NAME: Nombre de la credencial que vamos a crear.</p>
</li>
<li><p>USERNAME: Nombre del nuestro usuario, siempre debe seguir la estructura de “<em>/</em>”.</p>
</li>
<li><p>Password: Valor del  que hemos generado antes</p>
</li>
</ul>
<pre><code class="language-sql">SQL&gt;EXEC  dbms_cloud.create_credential(
    credential_name =&gt; 'DBA_IN_THE_SHADOW',
    username        =&gt; '&lt;IdentityDomain&gt;/&lt;usuario_tenancy&gt;',
    password        =&gt; '&lt;token&gt;');

SQL&gt; 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         &lt;IdentityDomain&gt;/&lt;usuario_tenancy&gt;       TRUE
</code></pre>
<p>Una manera rápida de verificar que funciona correctamente es listando el contenido que tenemos en nuestra <em>Bucket</em>. Para ello nos apoyaremos en la función <strong>DBMS_CLOUD.LIST_OBJECTS</strong>.</p>
<p>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 <em>Bucket</em>.</p>
<p>La manera más fácil de obtener la url, es ir a un objecto de nuestro <em>Bucket</em> e ir a los detalles del mismo:</p>
<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771411079006/0d136145-6a8c-487d-b28a-7edff7d3abda.png" alt="" style="display:block;margin:0 auto" />

<img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1771411298002/5eee5747-6775-4097-9424-7e33298cdd84.png" alt="" style="display:block;margin:0 auto" />

<p>Ahí copiamos el valor de “<em>URL path (URI)</em>”.</p>
<p>Una vez que lo tenemos copiado, listamos vía SQL el contenido del <em>Bucket</em>:</p>
<pre><code class="language-sql">SQL&gt; 
Select object_name
  From Dbms_cloud.list_objects('DBA_IN_THE_SHADOW','&lt;location_uri&gt;'); 

OBJECT_NAME
--------------------------------------------------------------------------------
XXXXXXXX.zip
XXXXXXXX.zip
XXXXXXXX.zip
</code></pre>
<p>Perfecto, tenemos acceso.</p>
<h3><strong>Subida de ficheros</strong></h3>
<p>Generamos un fichero <strong>csv</strong> y lo subimos a nuestro <em>Bucket</em>.</p>
<p>Utilizaremos <strong>DBMS_CLOUD.PUT_OBJECTS</strong> para subir el fichero generado. Para utilizarlo, definiremos el directory apuntando al path donde se encuentra nuestro fichero.</p>
<pre><code class="language-sql">SQL&gt; ! 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 &lt;= 10000;
spool off

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

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

OBJECT_NAME
--------------------------------------------------------------------------------
XXXXXXXX.zip
XXXXXXXX.zip
XXXXXXXX.zip
myfile.csv
</code></pre>
<p>Listo, ya tenemos el fichero en nuestro <em>Bucket</em>.</p>
<p>Una vez subido, podemos generar una tabla externa que lee ese fichero. Una manera rápida de definir este punto, es usando <strong>DBMS_CLOUD.CREATE_EXTERNAL_TABLE</strong>, que genera una tabla en nuestro schema que lee el fichero que le pasemos por parámetro.</p>
<pre><code class="language-sql">SQL&gt; 
BEGIN
  DBMS_CLOUD.CREATE_EXTERNAL_TABLE(
    table_name      =&gt; 'EXT_MYFILE_CSV',
    credential_name =&gt; 'DBA_IN_THE_SHADOW',
    file_uri_list   =&gt; '&lt;location_uri&gt;/myfile.csv',
    format          =&gt; JSON_OBJECT(
                         'type' VALUE 'csv',
                         'delimiter' VALUE ',',
                         'quote' VALUE '"',
                         'skipheaders' VALUE '0'
                       ),
    column_list     =&gt; '
        id   NUMBER,
        code VARCHAR2(50)
    '
  );
END;
/

SQL&gt; SELECT COUNT(*) FROM EXT_MYFILE_CSV;
1000
SQL&gt;
 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.
</code></pre>
<p>También podemos exportar la información de una consulta válida a nuestro <em>Bucket</em> usando <strong>DBMS_CLOUD.EXPORT_DATA</strong>.</p>
<p>Este procedimiento recibe los siguientes parámetros:</p>
<ul>
<li><p>CREDENTIAL_NAME: Nombre de la credencial que vamos a crear.</p>
</li>
<li><p>URL: “<em>URL path (URI)</em>” más el nombre del fichero, no es necesario indicar la extensión, ya que eso lo indicamos en el parámetro Format.</p>
</li>
<li><p>Format: Formato en que queremos guardar el spool de nuestra consulta, en nuestra caso es <strong>json</strong>.</p>
</li>
<li><p>Query: SQL válida que queremos exportar.</p>
</li>
</ul>
<pre><code class="language-sql">SQL&gt; 
BEGIN
      DBMS_CLOUD.EXPORT_DATA(  
        credential_name =&gt;'DBA_IN_THE_SHADOW',
        file_uri_list =&gt;'&lt;location_uri&gt;/config_system_parameter',
        format =&gt; json_object(  'type' VALUE 'json' ),
        query =&gt; 'SELECT NAME, VALUE FROM V$SYSTEM_PARAMETER'
      );
   END;
  / 

SQL&gt; Select object_name
  From 
   dbms_cloud.list_objects('DBA_IN_THE_SHADOW','&lt;location_uri&gt;');  

OBJECT_NAME
--------------------------------------------------------------------------------
XXXXXXXX.zip
XXXXXXXX.zip
XXXXXXXX.zip
config_system_parameter_1_1_1.json
myfile.csv
</code></pre>
<p>Y si necesitamos descargar ese fichero en una tabla, podríamos usar el procedimiento <strong>DBMS_CLOUD.COPY_DATA</strong>.</p>
<pre><code class="language-sql">SQL&gt; 
  Create table BACK_SYSTEM_PARAMETER ( 
    INFO_PARAMETER CLOB  CONSTRAINT INFO_PARAMETER_JSON CHECK ( INFO_PARAMETER IS JSON )
      );

Table created.

SQL&gt;
begin
  DBMS_CLOUD.COPY_DATA (
    table_name      =&gt; 'BACK_SYSTEM_PARAMETER',
    credential_name =&gt; 'DBA_IN_THE_SHADOW',
    file_uri_list   =&gt; '&lt;location_uri&gt;/config_system_parameter_1_1_1.json'
     );
end;
/
PL/SQL procedure successfully completed.
</code></pre>
<p>Ahí he definido una tabla <em>BACK_SYSTEM_PARAMETER</em> 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.</p>
<p>Si consultamos la tabla, vemos que se ha cargado correctamente la información:</p>
<pre><code class="language-sql">SQL&gt;
 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.
</code></pre>
<p>En el próximo artículo abordaremos el uso del <em>Data Pump</em> junto con el <em>DBMS_CLOUD</em></p>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] Blockchain & Immutable table]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
  
En este pequeño artículo vamos a ver las Blockchain table y Immutable table.
Este tipo de tablas fueron introducidas en Oracle, con el objetivo de protegernos contra la modifica...]]></description><link>https://dbaenlasombra.com/26ai-blockchain-and-immutable-table</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-blockchain-and-immutable-table</guid><category><![CDATA[Oracle 26ai]]></category><category><![CDATA[tables]]></category><category><![CDATA[cdbroot]]></category><category><![CDATA[pdb]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Thu, 12 Feb 2026 14:25:08 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1770761522011/ed274c25-d834-4f91-bd27-c12217f72732.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a target="_blank" href="https://dbaintheshadow.com/26ai-blockchain-and-immutable-table"><strong><em>English version</em></strong></a><em>.</em></p>
<p><a target="_blank" href="https://dbaintheshadow.com/26ai-mandatory-profile">  
</a>En este pequeño artículo vamos a ver las <strong>Blockchain table</strong> y <strong>Immutable table</strong>.</p>
<p>Este tipo de tablas fueron introducidas en Oracle, con el objetivo de protegernos contra la <strong>modificación</strong> de datos no autorizados por personal externo o accidentalmente, únicamente se pueden realizar <strong>inserciones</strong>. Además, las <strong>Blockchain table</strong> a diferencia de las <strong>Immutable table</strong>, incluyen una capa extra de seguridad incluyendo <strong>cryptographic hash</strong> a nivel de fila enlazado con la fila anterior, formando una cadena que permite detectar cualquier intento de manipulación.</p>
<p>Aunque no es una novedad en <strong>26ai</strong>, sino que fueron incluidas en la <strong>21c</strong>, si que han incluido importantes mejoras muy interesantes para potenciar este tipo de tablas:</p>
<ul>
<li><p>Poder añadir y eliminar columnas tanto en <strong>Blockchain</strong> como en <strong>Immutable</strong> table, especificando <strong>VERSION v2</strong>. Veamos un ejemplo, porque creo que es un matiz importante:</p>
<pre><code class="lang-sql">  SQL&gt; 
  <span class="hljs-keyword">CREATE</span> IMMUTABLE <span class="hljs-keyword">TABLE</span> T_TEST_VRS_1 (
    TC_ID <span class="hljs-built_in">NUMBER</span> <span class="hljs-keyword">GENERATED</span> <span class="hljs-keyword">BY</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">AS</span> <span class="hljs-keyword">IDENTITY</span> PRIMARY <span class="hljs-keyword">KEY</span>
  )
  <span class="hljs-keyword">no</span> <span class="hljs-keyword">drop</span> <span class="hljs-keyword">until</span> <span class="hljs-number">2</span> <span class="hljs-keyword">days</span> idle
  <span class="hljs-keyword">no</span> <span class="hljs-keyword">delete</span> <span class="hljs-keyword">until</span> <span class="hljs-number">16</span> <span class="hljs-keyword">days</span> <span class="hljs-keyword">after</span> <span class="hljs-keyword">insert</span>
  <span class="hljs-keyword">VERSION</span> <span class="hljs-string">"v1"</span>;

  Table created.
  SQL&gt;  <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> T_TEST_VRS_1 <span class="hljs-keyword">ADD</span> (FECHA <span class="hljs-built_in">DATE</span>);
  ERROR at line 1:
  ORA-05715: operation not allowed on the blockchain or immutable table
  <span class="hljs-keyword">Help</span>: https://docs.oracle.com/<span class="hljs-keyword">error</span>-<span class="hljs-keyword">help</span>/db/ora<span class="hljs-number">-05715</span>/

  <span class="hljs-keyword">SQL</span>&gt; 
  <span class="hljs-keyword">CREATE</span> IMMUTABLE <span class="hljs-keyword">TABLE</span> T_TEST_VRS_2 (
    TC_ID <span class="hljs-built_in">NUMBER</span> <span class="hljs-keyword">GENERATED</span> <span class="hljs-keyword">BY</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">AS</span> <span class="hljs-keyword">IDENTITY</span> PRIMARY <span class="hljs-keyword">KEY</span>
  )
  <span class="hljs-keyword">no</span> <span class="hljs-keyword">drop</span> <span class="hljs-keyword">until</span> <span class="hljs-number">2</span> <span class="hljs-keyword">days</span> idle
  <span class="hljs-keyword">no</span> <span class="hljs-keyword">delete</span> <span class="hljs-keyword">until</span> <span class="hljs-number">16</span> <span class="hljs-keyword">days</span> <span class="hljs-keyword">after</span> <span class="hljs-keyword">insert</span>
  <span class="hljs-keyword">VERSION</span> <span class="hljs-string">"v2"</span>;

  SQL&gt; <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> T_TEST_VRS_2 <span class="hljs-keyword">ADD</span> (FECHA <span class="hljs-built_in">DATE</span>);
  Table altered.
</code></pre>
</li>
<li><p><strong>BLOCKCHAIN_TABLE_MAX_NO_DROP</strong>, nuevo parámetro para especificar el tiempo máximo de inactividad cuando definimos este tipo de tablas. Cuando el parámetro esta seteado a un valor y el usuario crea una tabla con la cláusula <strong>NO DROP UNTIL</strong> n <strong>DAYS IDLE</strong>, el valor de n debe ser igual a ese valor o inferior. Si el parámetro esta nulo, es decir, no seteado, podemos definir cualquier valor en n <strong>DAYS IDLE</strong>.</p>
</li>
</ul>
<p>Tanto las filas nuevas como las antiguas, o el borrado de la tabla, están sujetas a un periodo de retención que el usuario especifica al crear la tabla, y cuando ese periodo de retención expira, pueden eliminarse las filas o directamente la tabla.</p>
<h3 id="heading-periodo-de-retencion"><strong>Periodo de Retención</strong></h3>
<p>En el modelo que vemos a continuación, podemos ver como podemos especificar el periodo de retención a nivel de tabla y fila:</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1770821644086/8a1db77f-9b85-4203-bb83-fb9cea008282.png" alt class="image--center mx-auto" /></p>
<p>A nivel de tabla:</p>
<ul>
<li><p><strong>NO DROP</strong>: La tabla no puede ser eliminada, a no ser que este vacía.</p>
</li>
<li><p><strong>NO DROP UNTIL</strong> n <strong>DAYS IDLE</strong>: Si aún quedan filas con un periodo de antigüedad menor, la tabla no puede ser eliminada. Por defecto, el valor es 0, aunque para garantizar la seguridad se recomienda un valor mínimo de 16.</p>
</li>
</ul>
<p>A nivel de fila:</p>
<ul>
<li><p><strong>NO DELETE [<em>locked</em>]</strong>: Las filas no pueden ser eliminadas. La clausula <strong>[<em>locked</em>]</strong> especifica que no se puede modificar la retención.</p>
</li>
<li><p><strong>NO DELETE UNTIL</strong> n <strong>DAYS AFTER INSERT [<em>locked</em>]</strong>: Cada fila no puede ser eliminada, es decir, esta protegida de la eliminación tantos días como especifiquemos en la cláusula n <strong>DAYS</strong>. Valor mínimo es 16 días. La clausula <strong>[<em>locked</em>]</strong> especifica que no se puede modificar la retención.</p>
</li>
</ul>
<h3 id="heading-restricciones"><strong>Restricciones</strong></h3>
<p>Las restricciones a nivel de tabla son las siguientes:</p>
<ul>
<li><p>Los siguientes tipo de datos no pueden ser soportados: <em>ROWID</em>, <em>UROWID, LONG, OBJECT TYPE, REF, VARRAY, NESTED TABLE, TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE, BFILE</em> y <em>XMLType.</em></p>
</li>
<li><p>A nivel de tabla, no pueden ser <em>INDEX-ORGANIZED, ORGANIZATION CUBE, ORGANIZATION EXTERNAL</em> o <em>HIBRYD PARTITIONED</em>.</p>
</li>
</ul>
<p>Sin más vamos a definir un ejemplo de cada.</p>
<h3 id="heading-inmutable-table"><strong>Inmutable Table</strong></h3>
<pre><code class="lang-sql">SQL&gt; 
<span class="hljs-keyword">CREATE</span> IMMUTABLE <span class="hljs-keyword">TABLE</span> T_CLIENTES (
  TC_ID <span class="hljs-built_in">NUMBER</span> <span class="hljs-keyword">GENERATED</span> <span class="hljs-keyword">BY</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">AS</span> <span class="hljs-keyword">IDENTITY</span> PRIMARY <span class="hljs-keyword">KEY</span>,
  TC_name   <span class="hljs-built_in">VARCHAR2</span>(<span class="hljs-number">100</span>) <span class="hljs-keyword">NOT</span> <span class="hljs-literal">NULL</span>,
  TC_email       <span class="hljs-built_in">VARCHAR2</span>(<span class="hljs-number">200</span>),
  TC_created_at  <span class="hljs-built_in">DATE</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">SYSDATE</span>
)
<span class="hljs-keyword">no</span> <span class="hljs-keyword">drop</span> <span class="hljs-keyword">until</span> <span class="hljs-number">2</span> <span class="hljs-keyword">days</span> idle
<span class="hljs-keyword">no</span> <span class="hljs-keyword">delete</span> <span class="hljs-keyword">until</span> <span class="hljs-number">16</span> <span class="hljs-keyword">days</span> <span class="hljs-keyword">after</span> <span class="hljs-keyword">insert</span>
<span class="hljs-keyword">VERSION</span> <span class="hljs-string">"v2"</span>;

Table created.
</code></pre>
<p>Si necesitamos modificar los periodos de retención:</p>
<pre><code class="lang-sql">SQL&gt; <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> T_CLIENTES  <span class="hljs-keyword">NO</span> <span class="hljs-keyword">DROP</span> <span class="hljs-keyword">UNTIL</span> <span class="hljs-number">5</span> <span class="hljs-keyword">DAYS</span> IDLE;
Table altered.
SQL&gt; <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> T_CLIENTES  <span class="hljs-keyword">NO</span> <span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">UNTIL</span> <span class="hljs-number">32</span> <span class="hljs-keyword">DAYS</span> <span class="hljs-keyword">AFTER</span> <span class="hljs-keyword">INSERT</span>;
Table altered.
</code></pre>
<p>Como hemos incluido <strong>VERSION v2</strong>, podemos añadir columnas:</p>
<pre><code class="lang-sql">SQL&gt; <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> T_CLIENTES <span class="hljs-keyword">ADD</span> (TC_PROVINCIA <span class="hljs-built_in">VARCHAR2</span>(<span class="hljs-number">100</span>));
</code></pre>
<p>Insertamos información e intentamos modificar algún dato:</p>
<pre><code class="lang-sql">SQL&gt; r
  1* <span class="hljs-keyword">Select</span> * <span class="hljs-keyword">From</span> t_Clientes

     TC_ID TC_NAME              TC_EMAIL             TC_CREATE TC_PROVINCIA
<span class="hljs-comment">---------- -------------------- -------------------- --------- ----------------------------------------------------------------------------------------------------</span>
         <span class="hljs-number">1</span> Iker San             San@demo.local       <span class="hljs-number">11</span>-FEB<span class="hljs-number">-26</span>
         <span class="hljs-number">2</span> Juan Perro           Perro@demo.local     <span class="hljs-number">11</span>-FEB<span class="hljs-number">-26</span>
         <span class="hljs-number">3</span> Carla Marq           Marq@demo.local      <span class="hljs-number">11</span>-FEB<span class="hljs-number">-26</span>

<span class="hljs-keyword">SQL</span>&gt; <span class="hljs-keyword">Update</span> t_Clientes <span class="hljs-keyword">Set</span> Tc_Provincia=<span class="hljs-string">'VALLADOLID'</span> <span class="hljs-keyword">where</span> tc_id = <span class="hljs-number">3</span>;
<span class="hljs-keyword">Update</span> t_Clientes <span class="hljs-keyword">Set</span> Tc_Provincia=<span class="hljs-string">'VALLADOLID'</span> <span class="hljs-keyword">where</span> tc_id = <span class="hljs-number">3</span>
       *
<span class="hljs-keyword">ERROR</span> <span class="hljs-keyword">at</span> line <span class="hljs-number">1</span>:
ORA<span class="hljs-number">-05715</span>: operation <span class="hljs-keyword">not</span> allowed <span class="hljs-keyword">on</span> the blockchain <span class="hljs-keyword">or</span> immutable <span class="hljs-keyword">table</span>
<span class="hljs-keyword">Help</span>: https://docs.oracle.com/<span class="hljs-keyword">error</span>-<span class="hljs-keyword">help</span>/db/ora<span class="hljs-number">-05715</span>/
</code></pre>
<p>Como podemos observar, no podemos modificar información. Únicamente insertar nuevos registros.</p>
<h3 id="heading-blockchain-table"><strong>Blockchain Table</strong></h3>
<pre><code class="lang-sql">SQL&gt; 
<span class="hljs-keyword">CREATE</span> BLOCKCHAIN <span class="hljs-keyword">TABLE</span> T_PRODUCTOSTIENDA (
  TP_id       <span class="hljs-built_in">NUMBER</span>,
  TP_NOMBRE   <span class="hljs-built_in">VARCHAR2</span>(<span class="hljs-number">100</span>),
  TP_PRICE    <span class="hljs-built_in">FLOAT</span>
)
<span class="hljs-keyword">NO</span> <span class="hljs-keyword">DROP</span> <span class="hljs-keyword">UNTIL</span> <span class="hljs-number">14</span> <span class="hljs-keyword">DAYS</span> IDLE
<span class="hljs-keyword">NO</span> <span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">UNTIL</span> <span class="hljs-number">30</span> <span class="hljs-keyword">DAYS</span> <span class="hljs-keyword">AFTER</span> <span class="hljs-keyword">INSERT</span>
HASHING <span class="hljs-keyword">USING</span> <span class="hljs-string">"SHA2_512"</span>
<span class="hljs-keyword">WITH</span> <span class="hljs-keyword">ROW</span> <span class="hljs-keyword">VERSION</span> <span class="hljs-keyword">AND</span> <span class="hljs-keyword">USER</span> <span class="hljs-keyword">CHAIN</span> T_PRODUCTOS_VALIDATION (TP_id)
<span class="hljs-keyword">VERSION</span> <span class="hljs-string">"v2"</span>;  

Table created.
</code></pre>
<p>Si necesitamos modificar los periodos de retención:</p>
<pre><code class="lang-sql">SQL&gt; <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> T_PRODUCTOSTIENDA  <span class="hljs-keyword">NO</span> <span class="hljs-keyword">DROP</span> <span class="hljs-keyword">UNTIL</span> <span class="hljs-number">16</span> <span class="hljs-keyword">DAYS</span> IDLE;
Table altered.
SQL&gt; <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> T_PRODUCTOSTIENDA  <span class="hljs-keyword">NO</span> <span class="hljs-keyword">DELETE</span> <span class="hljs-keyword">UNTIL</span> <span class="hljs-number">32</span> <span class="hljs-keyword">DAYS</span> <span class="hljs-keyword">AFTER</span> <span class="hljs-keyword">INSERT</span>;
Table altered.
</code></pre>
<p>Como hemos incluido <strong>VERSION v2</strong>, podemos añadir columnas:</p>
<pre><code class="lang-sql">SQL&gt; <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLE</span> T_PRODUCTOSTIENDA <span class="hljs-keyword">ADD</span> (TC_CANTIDAD <span class="hljs-built_in">INTEGER</span>);
</code></pre>
<p>Insertamos información e intentamos modificar algún dato:</p>
<pre><code class="lang-sql">SQL&gt; <span class="hljs-keyword">Select</span> * <span class="hljs-keyword">From</span> T_PRODUCTOSTIENDA;

     TP_ID TP_NOMBRE              TP_PRICE TC_CANTIDAD
<span class="hljs-comment">---------- -------------------- ---------- -----------</span>
         1 PERAS
         1 PERAS JULIANAS
         2 NARANJAS
         3 MANGOS

SQL&gt; <span class="hljs-keyword">UPDATE</span> T_PRODUCTOSTIENDA <span class="hljs-keyword">SET</span> TP_PRICE = <span class="hljs-number">9</span>;
<span class="hljs-keyword">UPDATE</span> T_PRODUCTOSTIENDA <span class="hljs-keyword">SET</span> TP_PRICE = <span class="hljs-number">9</span>
       *
<span class="hljs-keyword">ERROR</span> <span class="hljs-keyword">at</span> line <span class="hljs-number">1</span>:
ORA<span class="hljs-number">-05715</span>: operation <span class="hljs-keyword">not</span> allowed <span class="hljs-keyword">on</span> the blockchain <span class="hljs-keyword">or</span> immutable <span class="hljs-keyword">table</span>
<span class="hljs-keyword">Help</span>: https://docs.oracle.com/<span class="hljs-keyword">error</span>-<span class="hljs-keyword">help</span>/db/ora<span class="hljs-number">-05715</span>/
</code></pre>
<p>Como podemos observar, tampoco podemos modificar registros. Si nos fijamos en la información introducida, hay dos productos con el mismo identificador, pero…¿Cuál fue el último insertado? En las tablas <strong>BLOCKCHAIN</strong>, Oracle crea automáticamente una vista <strong>&lt;TABLE_NAME&gt;_LAST$</strong> para mostrar la última versión de cada fila.</p>
<pre><code class="lang-sql">SQL&gt; <span class="hljs-keyword">Select</span> * <span class="hljs-keyword">From</span> T_PRODUCTOSTIENDA_LAST$;

     TP_ID TP_NOMBRE              TP_PRICE
<span class="hljs-comment">---------- -------------------- ----------</span>
         1 PERAS JULIANAS
         2 NARANJAS
         3 MANGOS
</code></pre>
<p>En próximos artículos, abordaremos el tema del borrado sobre estos ejemplos que hemos utilizado.</p>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] Mandatory Profile]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
En este pequeño artículo vamos a ver los Mandatory Profile.
Aunque no es una novedad en 26ai, sino que fue en la 21c, vamos a proceder a configurarlo en la última release de Oracle...]]></description><link>https://dbaenlasombra.com/26ai-mandatory-profile</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-mandatory-profile</guid><category><![CDATA[Oracle 26ai]]></category><category><![CDATA[cdbroot]]></category><category><![CDATA[pdb]]></category><category><![CDATA[profile]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Thu, 29 Jan 2026 14:32:37 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1769696516840/41345bc4-94f0-4d5e-8288-15ca1f814db9.png" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a target="_blank" href="https://dbaintheshadow.com/26ai-mandatory-profile"><strong><em>English version</em></strong></a><em>.</em></p>
<p>En este pequeño artículo vamos a ver los <strong>Mandatory Profile</strong>.</p>
<p>Aunque no es una novedad en <strong>26ai</strong>, sino que fue en la <strong>21c</strong>, vamos a proceder a configurarlo en la última release de Oracle.</p>
<p>Este tipo de <strong>Profile</strong> pueden ser creados dentro de <em>CDB$Root</em> para luego asignarse a las distintas <em>PDBs</em>. Otro punto a tener en cuenta, es que si necesitamos modificarlos, debemos realizarlo a nivel de CDB$ROOT, <strong>no</strong> de PDB, usando <strong>common users</strong>, no <strong>local users</strong>.</p>
<p>Además, las políticas definidas en el <strong>Profile</strong> se aplicarán a todos los usuarios de la PDB.</p>
<p>¿Qué parámetros puedo usar? A diferencia de un <strong>Profile</strong>, donde tenemos multitud de parámetros para configurar, aquí solo podemos definir dos, son:</p>
<ul>
<li><p><strong>Password_verify_function</strong> para forzar la complejidad de la contraseña por medio de la función que tenga asignada. Valor por defecto es <em>null</em>.</p>
</li>
<li><p><strong>Password_grace_time</strong> permite especificar un periodo de gracia para aquellas cuentas que violen la complejidad de las contraseñas. Valor por defecto es <em>0</em>.</p>
</li>
</ul>
<p>Lo primero que vamos hacer es definir la función que asignaremos al parámetro <strong>password_verify_function.</strong></p>
<pre><code class="lang-sql">SQL&gt; 
<span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">OR</span> <span class="hljs-keyword">REPLACE</span> <span class="hljs-keyword">FUNCTION</span> VALIDATION_BUSINESS(username     <span class="hljs-built_in">varchar2</span>,
                                               <span class="hljs-keyword">password</span>     <span class="hljs-built_in">varchar2</span>,
                                               old_password <span class="hljs-built_in">varchar2</span>)
  <span class="hljs-keyword">return</span> <span class="hljs-built_in">boolean</span> <span class="hljs-keyword">IS</span>
<span class="hljs-keyword">BEGIN</span>
  <span class="hljs-keyword">if</span> <span class="hljs-keyword">not</span> ora_complexity_check(<span class="hljs-keyword">password</span>, chars =&gt; <span class="hljs-number">8</span>, digit =&gt; <span class="hljs-number">4</span>) <span class="hljs-keyword">then</span>
    <span class="hljs-keyword">return</span>(<span class="hljs-literal">false</span>);
  <span class="hljs-keyword">end</span> <span class="hljs-keyword">if</span>;
  return(true);
<span class="hljs-keyword">END</span>;
/
Function created.
</code></pre>
<p>Cómo podemos ver, estoy definiendo la función <strong>VALIDATION_BUSINESS</strong> dentro de CDB$Root con el objetivo de que todas las contraseñas de los usuarios tengan al menos una longitud de 8 caracteres “<em>chars =&gt; 8</em>” y 4 dígitos “<em>digit=&gt;4</em>“.</p>
<p>Definimos el <strong>Mandatory Profile</strong> usando los siguientes parámetros:</p>
<ul>
<li><p><em>PASSWORD_VERIFY_FUNCTION</em> para asignarle la función que hemos creado en el punto anterior.</p>
</li>
<li><p><em>PASSWORD_GRACE_TIME</em> para dar al usuario un periodo de gracia de 5 días para cambiar la contraseña.</p>
</li>
</ul>
<pre><code class="lang-sql">SQL&gt; 
  <span class="hljs-keyword">CREATE</span> MANDATORY PROFILE C<span class="hljs-comment">##VALIDATION_BUSINESS </span>
   <span class="hljs-keyword">LIMIT</span> 
     <span class="hljs-keyword">PASSWORD_VERIFY_FUNCTION</span> VALIDATION_BUSINESS 
     <span class="hljs-keyword">PASSWORD_GRACE_TIME</span> <span class="hljs-number">5</span> 
   <span class="hljs-keyword">CONTAINER</span> = <span class="hljs-keyword">ALL</span>; 

Profile created.
</code></pre>
<p>Como último paso sería modificar el parámetro <strong>MANDATORY_USER_PROFILE</strong>.</p>
<p>Aquí podemos hacer dos cosas, si queremos que el cambio afecte a todas las PDB, debemos ajustar ese parámetro a nivel de CDB$ROOT; pero si queremos que solo se aplique a una PDB específica, entonces debemos modificarlo directamente dentro de esa PDB.</p>
<pre><code class="lang-sql">SQL&gt; <span class="hljs-keyword">show</span> parameter MANDATORY_USER_PROFILE
<span class="hljs-keyword">NAME</span>                                 <span class="hljs-keyword">TYPE</span>        <span class="hljs-keyword">VALUE</span>
<span class="hljs-comment">------------------------------------ ----------- ------------------------------</span>
mandatory_user_profile               <span class="hljs-keyword">string</span>

<span class="hljs-keyword">SQL</span>&gt; <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">SYSTEM</span> <span class="hljs-keyword">SET</span> MANDATORY_USER_PROFILE=C<span class="hljs-comment">##VALIDATION_BUSINESS;</span>
<span class="hljs-keyword">System</span> altered.

<span class="hljs-keyword">SQL</span>&gt; <span class="hljs-keyword">show</span> parameter MANDATORY_USER_PROFILE

<span class="hljs-keyword">NAME</span>                                 <span class="hljs-keyword">TYPE</span>        <span class="hljs-keyword">VALUE</span>
<span class="hljs-comment">------------------------------------ ----------- ------------------------------</span>
mandatory_user_profile               <span class="hljs-keyword">string</span>      C<span class="hljs-comment">##VALIDATION_BUSINESS</span>
</code></pre>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[26ai] Oracle Temporary Tablespace Groups]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
En este pequeño artículo vamos a ver la creación de Temporary Tablespace Groups, pero antes de meternos en faena, vamos a dar una pequeña pincelada de que se trata esta opción.
Aun...]]></description><link>https://dbaenlasombra.com/26ai-oracle-temporary-tablespace-groups</link><guid isPermaLink="true">https://dbaenlasombra.com/26ai-oracle-temporary-tablespace-groups</guid><category><![CDATA[Oracle 26ai]]></category><category><![CDATA[pdb]]></category><category><![CDATA[temporal]]></category><category><![CDATA[group]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Wed, 21 Jan 2026 07:12:40 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768949041843/3956d7d9-b5aa-447b-a8b4-8e2104fb9fe4.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a target="_blank" href="https://dbaintheshadow.com/26ai-oracle-temporary-tablespace-groups"><strong><em>English version</em></strong></a><em>.</em></p>
<p>En este pequeño artículo vamos a ver la creación de <strong>Temporary Tablespace Groups</strong>, pero antes de meternos en faena, vamos a dar una pequeña pincelada de que se trata esta opción.</p>
<p>Aunque no es una novedad en <strong>26ai</strong>, vamos a proceder a configurarla en nuestra base de datos..</p>
<p>Este tipo de tablespaces, permite al usuario que cuando realizar operaciones que requieren mucha área temporal, como por ejemplo ordenaciones, el fuljo de trabajo se reparta entre múltiples tablespaces temporales. De este modo evitamos que tengamos saturación en el tablespace en caso que tengamos un único tablespace al realizar este tipo de operaciones.</p>
<p>Para poder llevar a cabo este laboratorio, vamos a definir una máquina virtual con la última versión de Oracle en OCI.</p>
<p>Las máquina que hemos definido es la siguientes:</p>
<ul>
<li><strong>Source</strong>: 26ai VM DB System Oracle Cloud (<em>test</em>).</li>
</ul>
<p><strong>1º</strong>: Definiremos una nueva PDB llamada <strong>TEST</strong> en source y comprobaremos cuál es el <strong>tablespace temporal</strong> que tiene asignado por defecto:</p>
<pre><code class="lang-sql">SQL&gt; ! hostname
source
SQL&gt; <span class="hljs-keyword">SHOW</span> PDBS

    CON_ID CON_NAME                       <span class="hljs-keyword">OPEN</span> <span class="hljs-keyword">MODE</span>  <span class="hljs-keyword">RESTRICTED</span>
<span class="hljs-comment">---------- ------------------------------ ---------- ----------</span>
         <span class="hljs-number">3</span> <span class="hljs-keyword">TEST</span>                           <span class="hljs-keyword">READ</span> WRITE <span class="hljs-keyword">NO</span>

<span class="hljs-keyword">SQL</span>&gt; <span class="hljs-keyword">Select</span> Property_Name, Property_Value 
     <span class="hljs-keyword">From</span> database_properties 
     <span class="hljs-keyword">Where</span> property_name = <span class="hljs-string">'DEFAULT_TEMP_TABLESPACE'</span>;

PROPERTY_NAME                                      PROPERTY_VALUE
<span class="hljs-comment">-------------------------------------------------- ----------------------------------------------------------------------------------------------------</span>
DEFAULT_TEMP_TABLESPACE                            TEMP
</code></pre>
<p><strong>2º</strong>: Vamos a definir un nuevo grupo tablespace temporal que incluirá dos tablespaces asociados. Como Oracle no ofrece una sintaxis especifica para crear directamente un grupo de tablespaces, debemos indicarlo durante el proceso de creación del propio tablespace.</p>
<pre><code class="lang-sql"> SQL&gt; 
 <span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TEMPORARY</span> <span class="hljs-keyword">TABLESPACE</span> GRP_TMP_TAB_1 TEMPFILE  <span class="hljs-keyword">SIZE</span> <span class="hljs-number">50</span>M <span class="hljs-keyword">TABLESPACE</span> <span class="hljs-keyword">GROUP</span> GRP_TMP;
  Tablespace created.
SQL&gt; 
 <span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TEMPORARY</span> <span class="hljs-keyword">TABLESPACE</span> GRP_TMP_TAB_2 TEMPFILE  <span class="hljs-keyword">SIZE</span> <span class="hljs-number">50</span>M <span class="hljs-keyword">TABLESPACE</span> <span class="hljs-keyword">GROUP</span> GRP_TMP;
  Tablespace created.
</code></pre>
<p>Para consultar el nuevo grupo tablespace temporal podemos usar la vista <strong>DBA_TABLESPACE_GROUPS</strong>:</p>
<pre><code class="lang-sql">SQL&gt; <span class="hljs-keyword">Select</span> * <span class="hljs-keyword">From</span> DBA_TABLESPACE_GROUPS ;

GROUP_NAME                     TABLESPACE_NAME
<span class="hljs-comment">------------------------------ ------------------------------</span>
GRP_TMP                        GRP_TMP_TAB_1
GRP_TMP                        GRP_TMP_TAB_2
</code></pre>
<p>Si ya tenemos algún <em>tablespace temporal</em> creado o hemos generado uno nuevo pero aún no lo hemos asignado el grupo, podemos mover el tablespace al grupo haciendo lo siguiente:</p>
<pre><code class="lang-sql">SQL&gt; <span class="hljs-keyword">CREATE</span> <span class="hljs-keyword">TEMPORARY</span> <span class="hljs-keyword">TABLESPACE</span> GRP_TMP_TAB_3 TEMPFILE  <span class="hljs-keyword">SIZE</span> <span class="hljs-number">50</span>M ;

Tablespace created.

SQL&gt; <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">TABLESPACE</span> GRP_TMP_TAB_3 <span class="hljs-keyword">TABLESPACE</span> <span class="hljs-keyword">GROUP</span> GRP_TMP;

Tablespace altered.

SQL&gt;  <span class="hljs-keyword">Select</span> * <span class="hljs-keyword">From</span> DBA_TABLESPACE_GROUPS ;

GROUP_NAME                     TABLESPACE_NAME
<span class="hljs-comment">------------------------------ ------------------------------</span>
GRP_TMP                        GRP_TMP_TAB_1
GRP_TMP                        GRP_TMP_TAB_2
GRP_TMP                        GRP_TMP_TAB_3
</code></pre>
<p><strong>3º</strong>: Cómo último paso, configuramos el grupo de tablespaces temporales <strong>GRP_TMP</strong> como el <em>default temporary tablespace</em> de la base de datos.</p>
<pre><code class="lang-sql">SQL&gt;  <span class="hljs-keyword">ALTER</span> <span class="hljs-keyword">DATABASE</span> <span class="hljs-keyword">DEFAULT</span> <span class="hljs-keyword">TEMPORARY</span> <span class="hljs-keyword">TABLESPACE</span> GRP_TMP;

Database altered.

SQL&gt; 
   <span class="hljs-keyword">Select</span> Property_Name, Property_Value 
   <span class="hljs-keyword">From</span> database_properties <span class="hljs-keyword">where</span> property_name = <span class="hljs-string">'DEFAULT_TEMP_TABLESPACE'</span>;

PROPERTY_NAME                                      PROPERTY_VALUE
<span class="hljs-comment">-------------------------------------------------- ----------------------------------------------------------------------------------------------------</span>
DEFAULT_TEMP_TABLESPACE                            GRP_TMP
</code></pre>
<p>Cuando marcamos un grupo como default tablespace temporal, ninguno de los tablespaces que lo integran puede eliminarse. Para poder borrarlo, antes debemos asignar <strong>otro</strong> <em>tablespace</em> temporal como predeterminado.</p>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item><item><title><![CDATA[[OCI] Proxy PDB]]></title><description><![CDATA[El artículo también se encuentra publicado en Ingles English version.
En el artículo de hoy, vamos a ver las Proxy PDB.
Pero, ¿Qué es un proxy PDB? Es hacer referencia a otra PDB pero de manera remota o en mismo CDB. Podríamos decir que es algo simil...]]></description><link>https://dbaenlasombra.com/oci-proxy-pdb</link><guid isPermaLink="true">https://dbaenlasombra.com/oci-proxy-pdb</guid><category><![CDATA[OCI]]></category><category><![CDATA[pdb]]></category><category><![CDATA[Oracle 23ai]]></category><category><![CDATA[#proxypdb]]></category><dc:creator><![CDATA[David Sanz]]></dc:creator><pubDate>Tue, 13 Jan 2026 19:52:27 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1768329866558/7b4b48b7-68df-47e7-a7fa-714481e293be.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p><em>El artículo también se encuentra publicado en Ingles</em> <a target="_blank" href="https://dbaintheshadow.com/oci-26ai-refreshable-clone-pdbs?showSharer=true"><strong><em>English version</em></strong></a><em>.</em></p>
<p>En el artículo de hoy, vamos a ver las <strong>Proxy PDB.</strong></p>
<p>Pero, ¿Qué es un <strong>proxy PDB</strong>? Es hacer referencia a otra PDB pero de manera remota o en mismo CDB. Podríamos decir que es algo similar a los clásicos <strong>DB Links</strong> cuando hacemos referencia a una tabla, pero en este caso no se trata de una tabla, sino de una PDB.</p>
<p>Algunas notas que debemos tener en cuenta:</p>
<ul>
<li><p>El usuario que utilicemos debe tener el permiso de <strong>CREATE PLUGGABLE DATABASE</strong>.</p>
</li>
<li><p>La PDB debe estar en <strong>local undo mode</strong>.</p>
</li>
<li><p>La PDB debe estar en modo <strong>ARCHIVELOG</strong>.</p>
</li>
<li><p>La PDB que hacemos referencia debe estar <strong>OPEN READ WRITE</strong> cuando el proxy PDB es creado. Una vez creada, puede ser cambiada.</p>
</li>
<li><p>Debemos crear un <strong>DB Link</strong> que hace referencia tanto a la CDB como a la PDB.</p>
</li>
</ul>
<p>Para poder llevar a cabo este laboratorio, vamos a definir dos máquinas virtuales, ambas con la última versión de Oracle en OCI.</p>
<p>Las máquinas que hemos definido son las siguientes:</p>
<ul>
<li><p><strong>Source</strong>: 26ai VM DB System Oracle Cloud (<em>test_ORI</em>).</p>
</li>
<li><p><strong>Target</strong>: 26ai VM DB System Oracle Cloud (<em>test_TARGET</em>).</p>
</li>
</ul>
<p>¡Vamos a ello!</p>
<p>1º: Definir la PDB PDB_DAVID en TEST_ORI:</p>
<pre><code class="lang-plaintext">SQL&gt; 
CREATE PLUGGABLE DATABASE PDB_DAVID ADMIN USER ADMIN 
  IDENTIFIED BY ADMIN keystore identified by external store;
Pluggable database created.
SQL&gt; ALTER PLUGGABLE DATABASE PDB_DAVID OPEN;
Pluggable database altered.
SQL&gt; ALTER PLUGGABLE DATABASE PDB_DAVID SAVE STATE;
Pluggable database altered.
SQL&gt; show pdbs
    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         4 PDB_DAVID                      READ WRITE NO
SQL&gt; ! hostname
source
</code></pre>
<p>2º: Definir un usuario común. El rol DBA ya incluye tanto <em>CREATE SESSION</em> como <em>CREATE PLUGGABLE DATABASE</em>. Haremos lo mismo en target.</p>
<pre><code class="lang-plaintext">SQL&gt; CREATE USER C##MANAGER IDENTIFIED BY "XXXXXXX";
User created.
SQL&gt; GRANT RESOURCE, DBA, UNLIMITED TABLESPACE TO C##MANAGER CONTAINER=ALL;
Grant succeeded.
</code></pre>
<p>3º: Revisamos que la PDB en origen se encuentra <strong>local undo mode</strong>. En caso que no se encuentre, debemos configurarlo.</p>
<pre><code class="lang-plaintext">SQL&gt; r
  1* Select property_name, property_value 
       From database_properties 
      Where property_name='LOCAL_UNDO_ENABLED'

PROPERTY_NAME        PROPERTY_VALUE
-------------------- ----------------------------------------
LOCAL_UNDO_ENABLED   TRUE
</code></pre>
<p>4º: Definimos el <strong>DB Links</strong> en destino. Para hacerlo diferente, vamos a utilizar <strong>easy connect</strong> en vez de <strong>local naming</strong>:</p>
<pre><code class="lang-plaintext">SQL&gt; 
CREATE DATABASE LINK SOURCE_PROXY CONNECT TO C##MANAGER 
  IDENTIFIED BY "XXXXX" 
    USING 'source:1521/pdb_david.XXXXXXXXXXXXXXXX';

Database link created.

SQL&gt; 
SQL&gt;  SELECT * FROM DUAL@SOURCE_PROXY;

D
-
X
</code></pre>
<p>5º: Definimos nuestra PDB incluyendo <strong>AS PROXY</strong> para indicar que vamos a crear una proxy PDB y <strong>FROM</strong> para especificar la PDB a la que vamos hacer referencia.</p>
<pre><code class="lang-plaintext">SQL&gt; 
CREATE PLUGGABLE DATABASE PDB_DAVID AS PROXY 
  FROM PDB_DAVID@SOURCE_PROXY keystore identified by external store;
Pluggable database created.
SQL&gt; alter pluggable database pdb_david open;
Pluggable database altered.
SQL&gt; show pdbs

    CON_ID CON_NAME                       OPEN MODE  RESTRICTED
---------- ------------------------------ ---------- ----------
         2 PDB$SEED                       READ ONLY  NO
         3 PDB_DAVID                      READ WRITE NO

SQL&gt; r
  1  SELECT pdb_name, is_proxy_pdb
  2* FROM   cdb_pdbs

PDB_NAME                       IS_PROXY_PDB
------------------------------ ----------------------------------------
PDB$SEED                       NO
PDB_DAVID                      YES
</code></pre>
<p>Cosas a tener en cuenta:</p>
<ul>
<li><strong>V$PROXY_PDB_TARGETS:</strong> Muestra información sobre los detalles de conexión sobre la PDB a la que hace referencia nuestra Proxy PDB.</li>
</ul>
<pre><code class="lang-plaintext">SQL&gt; r
  1* select * from v$proxy_pdb_targets

    CON_ID TARGET_PORT TARGET_HOST          TARGET_SERVICE                                                                   TARGET_USER
---------- ----------- -------------------- -------------------------------------------------------------------------------- --------------------
         3        1521 source               4843e8f3860c707be063cfdf680abf32.XXXXXXX.XXXXXXX.XXXXXXX.com
</code></pre>
<ul>
<li><p>Los tablespace de <strong>SYSTEM</strong> y <strong>SYSAUX</strong> serán copiados y sincronizador con el origen.</p>
</li>
<li><p>Solo admite <strong>password authentication</strong>, no permite <strong>OS authentication</strong>. Si nos fijamos en el ejemplo de abajo, vemos como funcionan ambos métodos de autenticación y que ocurre al consultar una tabla en nuestra <strong>Proxy PDB</strong>.</p>
</li>
</ul>
<pre><code class="lang-plaintext">[oracle@target ~]$ sqlplus / as sysdba
Connected to:
Oracle AI Database 26ai EE High Perf Release 23.26.0.0.0 - for Oracle Cloud and Engineered Systems
Version 23.26.0.0.0
SQL&gt; alter session set container= PDB_DAVID;
Session altered.
SQL&gt;  Select * From C##MANAGER.CODIGO_POSTAL;
 Select * From C##MANAGER.CODIGO_POSTAL
                          *
ERROR at line 1:
ORA-00942: table or view "C##MANAGER"."CODIGO_POSTAL" does not exist
Help: https://docs.oracle.com/error-help/db/ora-00942/

SQL&gt; conn C##MANAGER/"XXXXXXXX"@'target:1521/pdb_david.XXXXXXXX.XXXXXXXX.XXXXXXXX.com'
Connected.
SQL&gt;  Select * From C##MANAGER.CODIGO_POSTAL;

ID    POBLACION                                                                                            PAIS
----- ---------------------------------------------------------------------------------------------------- ----------------------------------------------------------------------------------------------------
46000 Valencia                                                                                             Espa??a
08000 Barcelona                                                                                            Espa??a
28000 Madrid                                                                                               Espa??a
55500 Wisconsin                                                                                            U.S.A.
</code></pre>
<p>Espero que os guste. ¡Nos vemos en el próximo artículo!</p>
]]></content:encoded></item></channel></rss>