Изменение типа столбца, используемого в других представлениях - PullRequest
5 голосов
/ 15 марта 2012
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;                                                       

Выдает эту ошибку:

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

Это немного раздражает, потому что теперь мне нужно воссоздать все представления, которые ссылаются на столбец base.name.Это особенно раздражает, когда у меня есть представления, которые ссылаются на другие представления.

То, что я хотел бы сделать, это что-то вроде:

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

И у функции есть определения вида дляv1 и v2, удалите их, запустите указанный код, затем воссоздайте v1 и v2.Если бы я мог использовать Ruby, я бы, вероятно, взял функцию / блок / лямбду, например

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

Возможно ли что-то подобное?Существуют ли какие-либо утилиты, которые делают что-то подобное?

Ответы [ 2 ]

8 голосов
/ 15 марта 2012

Я думаю, что это то, что вы хотите, хотя я переместил список просмотра в конец аргументов, чтобы совместить его с семантикой 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 голос
/ 24 мая 2013

Улучшение будет проверять перед попыткой отбросить представление, если оно вообще существует, в противном случае вы получите ошибку, поэтому сделайте так:

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;
...