2012-03-14 7 views
5
create table base (name character varying(255));                                       
create view v1 as select *, now() from base;               
create view v2 as select * from v1 where name = 'joe'; 
alter table base alter column name type text;              

da este error:Al cambiar el tipo de una columna utilizada en otras vistas

cannot alter type of a column used by a view or rule 
DETAIL: rule _RETURN on view v1 depends on column "name" 

Esta es una especie de molesto, porque ahora tengo que volver a crear todos los puntos de vista que hacen referencia a la columna de la base.name. Es especialmente molesto cuando tengo vistas que hacen referencia a otras vistas.

Lo que me gustaría ser capaz de hacer es algo como:

select recreate_views('v1', 'v2', 'alter table base alter column name type text'); 

y tienen la función de obtener las definiciones de vista de v1 y v2, soltarlos, ejecute el código especificado, a continuación, volver a crear v1 y v2. Si pudiera usar Ruby, probablemente tendría la función de tomar una función/bloque/lambda, como

recreate_views 'v1', 'v2' do 
    alter table base alter column name type text 
end 

es algo como esto posible? ¿Hay utilidades que hagan algo similar?

+0

'selecto definición de pg_views donde nombredevista = 'v1'; 'le da la definición de vista – dbenhur

Respuesta

7

Creo que esto hace lo que quiere, aunque moví la lista de vista al final de args para que sea compatible con la semántica VARIADIC.

CREATE OR REPLACE FUNCTION recreate_views(run_me text, VARIADIC views text[]) 
    RETURNS void 
AS $$ 
DECLARE 
    view_defs text[]; 
    i integer; 
    def text; 
BEGIN 
    for i in array_lower(views,1) .. array_upper(views,1) loop 
    select definition into def from pg_views where viewname = views[i]; 
    view_defs[i] := def; 
    EXECUTE 'DROP VIEW ' || views[i]; 
    end loop; 

    EXECUTE run_me; 

    for i in reverse array_upper(views,1) .. array_lower(views,1) loop 
    def = 'CREATE OR REPLACE VIEW ' || quote_ident(views[i]) || ' AS ' || view_defs[i]; 
    EXECUTE def; 
    end loop; 

END 
$$ 
LANGUAGE plpgsql; 
+1

Para ser más completo, uno podría averiguar cómo consultar qué vistas dependen de la (s) tabla (s) que está modificando y usar esa consulta en lugar de enumerar nombres de vista. Necesitarás entender pg_rewrite | pg_rule para hacer eso, creo. – dbenhur

+0

Interesante, gracias. También tengo un par de funciones postgresql que deben ser descartadas y recreadas también. Creo que podría hacer eso con un enfoque similar. –

+0

Creo que las vistas deben crearse en el orden opuesto en el que se eliminaron (si algunas de las vistas dependen de otras vistas). –

1

un Improvment sería comprobar antes de tratar de soltar vista, si es que existe, de lo contrario obtendrá un error, también lo hacen así:

for i in array_lower(views,1) .. array_upper(views,1) loop 
    select definition into def from pg_views where viewname = views[i]; 
    view_defs[i] := def; 
    IF def IS NOT NULL THEN 
     EXECUTE 'DROP VIEW ' || schema_name || '.' || views[i]; 
    END IF; 
end loop; 

    EXECUTE run_me; 

for i in reverse array_upper(views,1) .. array_lower(views,1) loop 
    IF view_defs[i] IS NOT NULL THEN 
     def = 'CREATE OR REPLACE VIEW ' || schema_name || '.' || views[i] || ' AS ' || view_defs[i]; 
     EXECUTE def; 
    END IF; 
end loop; 
Cuestiones relacionadas