[caracas-pm] Desestupidizando vistas Oracle

Ernesto Hernández-Novich emhn at movistar.net.ve
Fri Jul 14 07:00:01 PDT 2006


Hoy me vinieron con el siguiente problema (por segunda vez, pero el implicado
en este caso es diferente al primero): alguien está migrando de Oracle a
PostgreSQL y encontró Ora2Pg. Después de migrar felizmente tablas, índices y
datos, se embarcó en migrar vistas.

De acuerdo con los estándares SQL, cuando se usa un SELECT con alias para las
columnas _debe_ escribirse

select foo as alias1, bar as alias2, etc.

donde el 'as' es obligatorio. Al parecer Oracle se puede pasar el 'as' por ahí
mismo y permite escribir

select foo alias1, bar alias2, etc.

y en este caso los DBAs usaron y abusaron esa "facilidad" de Oracle.

En el catálogo de Oracle, la vista se almacena como el SELECT que la
constituye, en particular _sin_ los 'as' en los casos que no lo pusieron. La
herramienta de conversión simplemente extrae los SELECT y quiere usarlos "tal
cual", pero como PostgreSQL si obliga a cumplir el estándar, obviamente falla.
Y son muchas vistas. Es más, en algunos casos hay barbaridades como

select foo as alias1, sum(a+b) alias2, (select baz from qux ...) alias 3, ...

El problema es, ¿cómo arreglar eso para que funcione en PostgreSQL? (Sin
contar que implicaron que es "culpa de PostgreSQL que es estricto", WTF?). Es
más complicado de lo que parece porque la lista de SELECT puede estar en
varias líneas y por el hecho de que el lenguaje que conforma la lista de
columnas en el SELECT no es regular (¡epa lem y jrey!) sin embargo tras una
breve inspección de los casos concretos resulta que lo siguiente [1] funcionó
para el 93% de las vistas (las que no tenían sub-selects :-).

#!/usr/bin/perl
#
$t = "create view x as select a laa, sum(b+c) lab, c AS lac, d lad from";
print "Antes: $t\n";
$t =~ s/create\s+view\s+(\w+)\s+as\s+select\s+(.*)\s+from
       /"create view ".$1." as select ".fix($2)." from"
       /iex;
print "Despues: $t\n";
sub fix {
  return join ", ",
                   ( map {$_ = ~/ as /i ? $_ : join " as ",(split /\s+/, $_) }
                     split /\s*,\s*/, shift
                   );
}

La idea es encontrar todos los "CREATE VIEW" y conservar el nombre de la vista
así como la lista de columnas en medio y sustituir por el mismo nombre de
vista pero la lista de columnas "arreglada". El trabajo se hace en la función
fix que "arregla" la lista con un algoritmo simple expresado de forma compacta
gracias a programación funcional: romper por las comas (con los blancos que le
rodeen); a cada elemento que NO tenga 'as' romperlo por espacios y
recomponerlo con un 'as' en medio; a lo resultante de todo esto recomponerlo
con ','.

Y otra mandíbula golpeó el suelo. p0wnage!

[1] Lo que muestro aquí funciona para selects que están en una sola línea.
    Para el caso multilínea hay que cambiar el separador de registro y hacer
    las expresiones regulares un poco más inteligentes para tomar en cuenta el
    '\n'. Por cierto, en el programa original _no_ use el modificador 'x' para
    las expresiones regulares, ¿por qué lo estoy usando aquí? De hecho, en el
    programa original la función fix no existe porque está en línea dentro de
    la sustitución con menos espacios en blanco y paréntesis... es que hace
    mucho que no como pizza.
-- 
Ernesto Hernández-Novich - On Linux 2.6.16 i686 - Unix: Live free or die!
Geek by nature, Linux by choice, Debian of course.
If you can't aptitude it, it isn't useful or doesn't exist.
GPG Key Fingerprint = 438C 49A2 A8C7 E7D7 1500 C507 96D6 A3D6 2F4C 85E3


More information about the caracas-pm mailing list