Vamos con una sobre malas prácticas.

El uso de sinónimos.

Si has sentido un sudor frío, es que habrás vivido algo similar.

Muchos usuarios quieren acceder a las tablas de la aplicación «de forma transparente». Nótese que lo entrecomillo porque llamar «transparente» a «sin prefijar el usuario propietario» me parece más adecuado.

Que sí, que en producción el usuario se llama PEPE, y en desarrollo se llama JUAN, y que el código debe funcionar se llame como se llame el usuario, pero cuando empezamos a «universalizar» los accesos a los objetos, nos sucede lo siguiente.

CASO 1:

  • JUAN tiene la tabla TEST. Crea un sinónimo público a quien todo el mundo tiene acceso.
  • JUAN borra la tabla TEST. Porque es suya y él quiere. Pero no borra el sinónimo.
  • JUAN intenta acceder a la tabla TEST que acaba de borrar, y el error que le aparece es éste:
SQL> connect juan/juan
Conectado.
SQL> create table test (id number);

Tabla creada.

SQL> create public synonym test for juan.test;

Sinónimo creado.

SQL> drop table test;

Tabla borrada.

SQL> desc test
SP2-0749: No se puede resolver la ruta de acceso circular del sinonimo "test"

SQL> select * from test;
select * from test
              *
ERROR en línea 1:
ORA-01775: ejecutando bucle de cadena de sinónimos

 

CASO 2:

  • JUAN quiere acceder a la tabla TEST del usuario PEPE.
  • JUAN se crea un sinónimo privado para ver PEPE.TEST «de forma transparente».
  • MARIA quiere acceder a JUAN.TEST, sin saber que en realidad no es una tabla, sinó un sinónimo de otro usuario, también de forma transparente.
  • MARIA crea un sinónimo público para acceder a JUAN.TEST.
SQL> connect pepe/pepe
Conectado.
SQL> create table test (id number);

Tabla creada.

SQL> connect juan/juan
Conectado.
SQL> create synonym test for pepe.test;

Sinónimo creado.

SQL> connect maria/maria
Conectado.
SQL> create public synonym test for juan.test;

Sinónimo creado.

Todos ven la tabla TEST.

SQL> connect maria/maria
Conectado.

SQL> desc test
 Nombre                                                ┐Nulo?   Tipo
 ----------------------------------------------------- -------- ------------------------------------
 ID                                                             NUMBER

SQL> connect juan/juan
Conectado.
SQL> desc test
 Nombre                                                ┐Nulo?   Tipo
 ----------------------------------------------------- -------- ------------------------------------
 ID                                                             NUMBER

SQL> connect pepe/pepe
Conectado.
SQL> desc test
 Nombre                                                ┐Nulo?   Tipo
 ----------------------------------------------------- -------- ------------------------------------
 ID                                                             NUMBER
  • PEPE borra su tabla, y cuando intenta acceder a TEST resuelve el sinónimo público de MARIA, que apunta al sinónimo privado de JUAN, que apunta a la tabla que acaba de borrar PEPE.
SQL> select count(*) from test;
select count(*) from test
                     *
ERROR en línea 1:
ORA-01775: ejecutando bucle de cadena de sinónimos

 

Y para resolver estos entuertos, aquí te dejo un procedure de la casa para que puedas identificar los sinónimos problemáticos. Tienes el proyecto en el GitHub de Café Database y, como siempre, como es código abierto y todo eso, siéntete libre de modificar y ampliar como consideres.

https://github.com/CafeDatabase/Check-Synonyms

-- Ensure user has DBA privileges.
create or replace procedure CHECK_SYNONYMS (p_owner varchar2) 
is
  usuario varchar2(30);
  bucle_sinonimos exception;
	sinonimo_no_valido exception;
	PRAGMA EXCEPTION_INIT(bucle_sinonimos,-1775);
	PRAGMA EXCEPTION_INIT(sinonimo_no_valido,-980);
	filas number;
begin 
  dbms_output.enable;
  for x in (select owner, synonym_name,table_owner,table_name,NVL2(db_link,'@'||db_link,null) db_link 
              from dba_synonyms where owner IN (p_owner,'PUBLIC'))
			  -- It takes time to check SYS synonyms, but I think it's worth it.
	loop
	   begin 
		     select DECODE(x.owner,'PUBLIC','',x.owner||'.') into usuario from dual;
			 execute immediate 'select count(*) into :filas from '||usuario||x.synonym_name||' where 1=0' into filas;
	   exception 
		   when bucle_sinonimos then 
			   dbms_output.put_line('Synonym in a loop chain '||x.owner||'.'||x.synonym_name||' pointing to '
				            ||x.table_owner||'.'||x.table_name||x.db_link);
									
		   when sinonimo_no_valido then 
			   dbms_output.put_line('Synonym not valid '||x.owner||'.'||x.synonym_name||'  pointing to '
				            ||x.table_owner||'.'||x.table_name||x.db_link);
			 when others then null;
	   end;
	end loop;
end;
/
Share This