2012-03-14 15 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;              

dà questo errore:Modifica del tipo di una colonna utilizzata in altre viste

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

Questa è una sorta di fastidioso, perché ora devo ricreare tutte le viste che fanno riferimento la colonna base.name. È particolarmente fastidioso quando ho delle opinioni che fanno riferimento ad altre visualizzazioni.

Quello che mi piacerebbe essere in grado di fare è qualcosa di simile:

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

e hanno la funzione di ottenere le definizioni di visualizzazione per v1 e v2, rilasciarli, eseguire il codice specificato, quindi ricreare v1 e v2. Se potessi usare Ruby, avrei probabilmente avuto la funzione di prendere una funzione/blocco/lambda, come

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

è qualcosa di simile possibile? Ci sono delle utility là fuori che fanno qualcosa di simile?

+0

'selezionare definizione dalla pg_views dove nomevista = 'v1'; 'fornisce la definizione della vista – dbenhur

risposta

7

Penso che questo faccia ciò che si vuole, anche se ho spostato l'elenco delle viste alla fine di args per essere compatibile con la semantica 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

Per essere più completi, si potrebbe capire come interrogare quali viste dipendono dalle tabelle che si stanno modificando e utilizzare quella query invece di elencare i nomi delle viste. Devo capire pg_rewrite | pg_rule per farlo, penso. – dbenhur

+0

Interessante, grazie. Ho anche un paio di funzioni postgresql che devono essere rilasciate e ricreate. Penso di poterlo fare con un approccio simile. –

+0

Penso che le viste debbano essere create nell'ordine opposto in cui sono state rilasciate (se alcune delle viste dipendono da altre viste). –

1

un improvment sarebbe quello di controllare prima di provare a scendere vista se esiste affatto, altrimenti si otterrà un errore, in modo da fare in questo modo:

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; 
Problemi correlati