CREATE OR REPLACE FUNCTION ajusta_campo_null_f () RETURNS TEXT AS $_$

DECLARE

t RECORD;
c RECORD;
c1 REFCURSOR;
c2 REFCURSOR;
wrk_count            NUMERIC := 0;
wrk_count_tabela     NUMERIC := 0;
wrk_com_problema     NUMERIC := 0;
wrk_tem_nulo         NUMERIC := 0;
wrk_update           TEXT    := NULL;
wrk_where            TEXT    := NULL; 
csql                 TEXT    := NULL;
usql                 TEXT    := NULL;
wrk_tabelas          TEXT    := NULL;

-- Logica do prog
-- Varrer todas as tabelas
-- Varrer as colunas das tabelas que sejam not null
-- Montar dinamicamente as colunas para o update e where
-- Verificar se existe algum resgitro nulo para aqueles campos
-- Se existir fazer um update para vazio ''

BEGIN
    
    -- busca as tabela do que fazem parte do sistema 
    OPEN C1 FOR SELECT tablename as tabela
                  FROM pg_tables
                 WHERE schemaname = 'public'
              ORDER BY tablename;
    LOOP
	FETCH C1 INTO t;
	EXIT WHEN NOT FOUND;

        wrk_count_tabela := wrk_count_tabela+1;
        RAISE NOTICE 'TABELA:  %', t.tabela;
        wrk_update   := NULL;  
        wrk_where    := NULL;
		wrk_count    := 0;
		wrk_tem_nulo := 0;

        -- busca as colunas que sao not null da tabela com base no valor do cursor c1
        OPEN C2 FOR SELECT a.attname as coluna 
		                  ,format_type(a.atttypid, a.atttypmod)::TEXT as "tipo_coluna"
                      FROM pg_class as pc
                     INNER JOIN pg_attribute a ON (pc.oid = a.attrelid)
                     WHERE pc.relname= t.tabela
					   AND a.attnotnull
                       AND attstattarget<0;
					
        LOOP
        FETCH C2 INTO c;
        EXIT WHEN NOT FOUND;
			wrk_tem_nulo := 1;
            -- monta as colunas do update
			-- update tabela set coluna=coalesce(coluna,'') where (coluna is null or coluna is null)
			IF wrk_update IS NULL THEN
			    -- tipo text
				IF substr(c.tipo_coluna,1,9) in ('text','character','varchar','char') THEN
					wrk_update := c.coluna || '=' || 'coalesce('|| c.coluna || ','|| ''''''||')';
				-- inteiros
				ELSIF c.tipo_coluna in ('integer','bigint','numeric','smallint','double precision','int','float','int8','decimal','real') THEN
					wrk_update := c.coluna || '=' || 'coalesce('|| c.coluna || ','|| '0'||')';
				-- datas
				ELSIF substr(c.tipo_coluna,1,9) in ('date','timestamp','interval','datetime') THEN
					wrk_update := c.coluna || '=' || 'coalesce('|| c.coluna || ','|| '''1970-01-01'''||')';
				-- booleans
				ELSIF c.tipo_coluna = 'boolean' THEN
					wrk_update := c.coluna || '=' || 'coalesce('|| c.coluna || ','|| 'false' ||')';
				-- oq sobrar
				ELSE
					wrk_update := c.coluna || '=' || 'coalesce('|| c.coluna || ','|| ''''''||')';
				END IF;
            ELSE
				-- tipo text
				IF substr(c.tipo_coluna,1,9) in ('text','character') THEN
					wrk_update := wrk_update || ', ' || c.coluna || '=' || 'coalesce(' || c.coluna || ','|| ''''''|| ')';
				-- inteiros
				ELSIF c.tipo_coluna in ('integer','bigint','numeric','smallint','double precision','int','float','int8','decimal','real') THEN
					wrk_update := wrk_update || ', ' || c.coluna || '=' || 'coalesce(' || c.coluna || ','|| '0'|| ')';
				-- datas
				ELSIF substr(c.tipo_coluna,1,9) in ('date','timestamp','interval','datetime') THEN
					wrk_update := wrk_update || ', ' || c.coluna || '=' || 'coalesce(' || c.coluna || ','|| '''1970-01-01'''|| ')';
				-- booleans
				ELSIF c.tipo_coluna = 'boolean' THEN
					wrk_update := wrk_update || ', ' || c.coluna || '=' || 'coalesce(' || c.coluna || ','|| 'false'|| ')';
				-- oq sobrar
				ELSE
					wrk_update := wrk_update || ', ' || c.coluna || '=' || 'coalesce(' || c.coluna || ','|| ''''''|| ')';
				END IF;
				
			END IF;

            -- monta o where que sera usado no update e no select
			-- where (colunas is null or coluna is null or coluna is null)
            if wrk_where is null then
                wrk_where := '(' || c.coluna || ' IS NULL';
            else
                wrk_where := wrk_where || ' or ' || c.coluna || ' IS NULL';
			end if;

        -- fim do loop de coluna
        END LOOP;
        CLOSE C2;
		IF wrk_tem_nulo = 1 THEN
			wrk_where := wrk_where || ')';

			-- montagem do sql dinamico, com o nome das colunas e tabela
			-- select count(*) as total from tabela where (coluna is null or coluna is null)
			csql = 'SELECT count(*) as total FROM ' || t.tabela || ' where ' || wrk_where;
			RAISE INFO 'Comando SQL: %', csql;

			BEGIN
				-- verifica se existe registros null em campos not null
				EXECUTE csql INTO wrk_count;
			EXCEPTION
				WHEN OTHERS THEN
					RAISE EXCEPTION 'OCORREU UM ERRO NA CONTAGEM DOS REGISTROS DA TABELA: %', t.tabela;
			END;

			-- se o count for maior que zero, realizar o update
			IF wrk_count > 0 THEN

				wrk_com_problema := wrk_com_problema+1;

				-- monta dinamicamente o nome das tabelas que serao ajustadas
				IF wrk_tabelas IS NULL THEN
						wrk_tabelas := t.tabela;
				ELSE
					wrk_tabelas := wrk_tabelas || chr(10) || t.tabela;
				END IF;

				-- update tabela set coluna='' where colunas is null;
				usql = 'UPDATE ' || t.tabela || ' SET ' || wrk_update || ' WHERE ' || wrk_where;
				RAISE INFO 'Comando UPDATE: %', usql;
				BEGIN
					EXECUTE usql;
				EXCEPTION
					WHEN OTHERS THEN
						RAISE EXCEPTION 'OCORREU UM ERRO AO ATUALIZAR A TABAELA %', t.tabela;
				END;
			END IF;
		END IF;
		RAISE NOTICE '------------------------------------------------------------------';
    -- fim do loop de tabela                   
    END LOOP;
    CLOSE C1;

    RETURN 'TOTAL DE TABELAS: '            || wrk_count_tabela    || chr(10) ||
           'TOTAL DE TABELAS CORRIGIDAS: ' || wrk_com_problema || chr(10) ||
           'LISTA DE TABELAS CORRIGIDAS '  || chr(10) || COALESCE(wrk_tabelas,'NENHUMA');

END
$_$
    LANGUAGE PLPGSQL; 
select * from ajusta_campo_null_f();
