AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / dba / Perguntas / 71178
Accepted
Sébastien Clément
Sébastien Clément
Asked: 2014-07-11 07:55:52 +0800 CST2014-07-11 07:55:52 +0800 CST 2014-07-11 07:55:52 +0800 CST

Como registrar instruções DML executadas por uma função pl/pgsql?

  • 772

Eu tenho uma função pl/pgsql (veja abaixo) que lista alguns campos e limpa seu conteúdo usando comandos UPDATE construídos dinamicamente.

Quando defino log_statement = 'mod', não consigo ver nada no log durante a execução da função com SELECT fnct_clear_temp_fields();. Quando defino log_statement = 'all'e executo a função, posso ver SELECT fnct_clear_temp_fields();no log, mas não os comandos UPDATE subjacentes.

Existe uma maneira de fazer com que os comandos UPDATE apareçam no log também?

Para informações, aqui está a função:

CREATE OR REPLACE FUNCTION fnct_clear_temp_fields() RETURNS VOID AS $$
DECLARE
    --Put into a cursor a view dynamically listing all user-defined fields beginning with 'temp_'
    dataset_1 CURSOR FOR 
        SELECT 
            column_name,
            table_name
        FROM information_schema.tables 
        NATURAL JOIN information_schema.columns 
        WHERE 
            table_schema='public'
            AND table_type='BASE TABLE'
            AND column_name ~ '^temp_'
        ORDER BY table_name,column_name;

    --Record variable to go through each line of the view above
    dataset_1_row RECORD;

BEGIN
    OPEN dataset_1; --Open the cursor
    FETCH dataset_1 INTO dataset_1_row; --first row of the view

    WHILE FOUND LOOP
        RAISE NOTICE 'Table: %, Column: %',  dataset_1_row.table_name,dataset_1_row.column_name;

        --Set to NULL the contents of the current 'temp_' column
        EXECUTE 'UPDATE '||dataset_1_row.table_name||' SET '||dataset_1_row.column_name||'=NULL WHERE '||dataset_1_row.column_name||' IS NOT NULL';

        FETCH dataset_1 INTO dataset_1_row; --next row please.
    END LOOP; --while end

    CLOSE dataset_1;

    RETURN;
END;
$$ LANGUAGE plpgsql;
postgresql functions
  • 3 3 respostas
  • 6953 Views

3 respostas

  • Voted
  1. Erwin Brandstetter
    2014-07-12T18:01:38+08:002014-07-12T18:01:38+08:00

    Pergunta feita

    Existe uma maneira interna de registrar todas as instruções dentro das funções plpgsql:auto-explain

    LOAD 'auto_explain';
    SET auto_explain.log_min_duration = 1; -- exclude very fast trivial queries
    SET auto_explain.log_nested_statements = ON; -- statements inside functions
    

    Detalhes nesta questão intimamente relacionada:
    Plano de consulta Postgres de uma invocação UDF escrita em pgpsql

    Potencialmente gera muita saída de log. Eu só usaria para depuração, não em produção.
    Se você só precisa de uma declaração registrada, siga o conselho de @dezso .

    Auditoria de código

    Considere esta função reescrita:

    CREATE OR REPLACE FUNCTION fnct_clear_temp_fields()
      RETURNS void AS
    $func$
    DECLARE
       rec record;
       qry text;
    BEGIN
       FOR rec IN
          SELECT quote_ident(c.relname) AS tbl, quote_ident(a.attname) AS col
          FROM   pg_namespace n
          JOIN   pg_class     c ON c.relnamespace = n.oid
          JOIN   pg_attribute a ON a.attrelid = c.oid
          WHERE  n.nspname = 'public'
          AND    c.relkind = 'r'
          AND    a.attname LIKE 'temp_%'  -- LIKE is faster than ~
          AND    a.attnum > 0
          AND    NOT a.attisdropped
          ORDER  BY 1,2
       LOOP
          RAISE NOTICE 'Table: %, Column: %', rec.tbl, rec.col;
          qry := format('UPDATE %1$s SET %2$s = NULL WHERE %2$s IS NOT NULL', rec.tbl, rec.col);
          RAISE LOG 'Query: %', qry;
          EXECUTE qry;
       END LOOP;
    END
    $func$  LANGUAGE plpgsql;
    

    Pontos principais

    • Você deve limpar todos os identificadores criados no SQL dinâmico, caso contrário, ele pode falhar com nomes não padrão que requerem aspas duplas. Pior, você está aberto à injeção de SQL.
      Demonstrando quote_ident(), já que você está usando os identificadores higienizados várias vezes. Existem mais opções com regclassou format():
      Nome da tabela como parâmetro de função do PostgreSQL

    • Prefiro basear essas consultas no catálogo do sistema em vez das exibições dolorosamente lentas do esquema de informações. Isso é uma questão de requisitos e gosto, no entanto. Demonstrando o equivalente, que é ~ 10 vezes mais rápido (sem falar em UPDATEcomandos). Mais:
      Como verificar se uma tabela existe em um determinado esquema

    • LIKEé geralmente mais rápido do que a correspondência de expressão regular mais poderosa ( ~). Se LIKEpode fazer o trabalho, use-o.

    • Algumas outras pequenas simplificações.

    • Resposta relacionada com mais detalhes:
      Atualizar registro de um cursor onde o nome da tabela é um parâmetro

    • 8
  2. Best Answer
    dezso
    2014-07-11T11:01:01+08:002014-07-11T11:01:01+08:00

    Então, minha sugestão como uma resposta real:

    Se você precisar apenas nesta função, você pode fazer um RAISE LOG '%', your_statement;, ou no seu código real:

    ...
    DECLARE
        exec_str text;
    ...
        --Set to NULL the contents of the current 'temp_' column
        exec_str := 'UPDATE '||dataset_1_row.table_name||
                    'SET '||dataset_1_row.column_name||'=NULL 
                     WHERE '||dataset_1_row.column_name||' IS NOT NULL';
        RAISE LOG 'Query executed: %', exec_str;
        EXECUTE exec_str;
    ...
    

    Além disso, acho o

    FOR dataset_1_row IN SELECT ... 
    LOOP 
    END LOOP;
    

    construir muito mais suave.

    • 3
  3. Sébastien Clément
    2014-07-12T05:28:08+08:002014-07-12T05:28:08+08:00

    Ótimo dezso, funciona! Aqui está a versão final da minha função:

    CREATE OR REPLACE FUNCTION fnct_clear_temp_fields() RETURNS VOID AS $$
    DECLARE
        dataset_1_row RECORD; --Record variable to go through each row of the view below
        update_query TEXT; --The dynamic UPDATE query to be executed
    
    BEGIN
        FOR dataset_1_row IN --Cycle through rows of query below
                SELECT 
                    column_name,
                    table_name
                FROM information_schema.tables 
                NATURAL JOIN information_schema.columns 
                WHERE 
                    table_schema='public'
                    AND table_type='BASE TABLE'
                    AND column_name ~ '^temp_'
                ORDER BY table_name,column_name
            LOOP
    
            RAISE NOTICE 'Table: %, Column: %',  dataset_1_row.table_name,dataset_1_row.column_name;
            --Create a dynamic update query to set to NULL the contents of the current 'temp_' column
            update_query :='UPDATE '||dataset_1_row.table_name||' SET '||dataset_1_row.column_name||'=NULL WHERE '||dataset_1_row.column_name||' IS NOT NULL;';
            RAISE LOG 'Query executed: %', update_query; --Put query def in log
            EXECUTE update_query; --Run the query
        END LOOP; --Next line of SELECT query above 
    
        RETURN;
    END;
    $$ LANGUAGE plpgsql;
    
    • 1

relate perguntas

  • Posso ativar o PITR depois que o banco de dados foi usado

  • Práticas recomendadas para executar a replicação atrasada do deslocamento de tempo

  • Os procedimentos armazenados impedem a injeção de SQL?

  • Sequências Biológicas do UniProt no PostgreSQL

  • Qual é a diferença entre a replicação do PostgreSQL 9.0 e o Slony-I?

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host

    • 12 respostas
  • Marko Smith

    Como fazer a saída do sqlplus aparecer em uma linha?

    • 3 respostas
  • Marko Smith

    Selecione qual tem data máxima ou data mais recente

    • 3 respostas
  • Marko Smith

    Como faço para listar todos os esquemas no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Listar todas as colunas de uma tabela especificada

    • 5 respostas
  • Marko Smith

    Como usar o sqlplus para se conectar a um banco de dados Oracle localizado em outro host sem modificar meu próprio tnsnames.ora

    • 4 respostas
  • Marko Smith

    Como você mysqldump tabela (s) específica (s)?

    • 4 respostas
  • Marko Smith

    Listar os privilégios do banco de dados usando o psql

    • 10 respostas
  • Marko Smith

    Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL?

    • 4 respostas
  • Marko Smith

    Como faço para listar todos os bancos de dados e tabelas usando o psql?

    • 7 respostas
  • Martin Hope
    Jin conectar ao servidor PostgreSQL: FATAL: nenhuma entrada pg_hba.conf para o host 2014-12-02 02:54:58 +0800 CST
  • Martin Hope
    Stéphane Como faço para listar todos os esquemas no PostgreSQL? 2013-04-16 11:19:16 +0800 CST
  • Martin Hope
    Mike Walsh Por que o log de transações continua crescendo ou fica sem espaço? 2012-12-05 18:11:22 +0800 CST
  • Martin Hope
    Stephane Rolland Listar todas as colunas de uma tabela especificada 2012-08-14 04:44:44 +0800 CST
  • Martin Hope
    haxney O MySQL pode realizar consultas razoavelmente em bilhões de linhas? 2012-07-03 11:36:13 +0800 CST
  • Martin Hope
    qazwsx Como posso monitorar o andamento de uma importação de um arquivo .sql grande? 2012-05-03 08:54:41 +0800 CST
  • Martin Hope
    markdorison Como você mysqldump tabela (s) específica (s)? 2011-12-17 12:39:37 +0800 CST
  • Martin Hope
    Jonas Como posso cronometrar consultas SQL usando psql? 2011-06-04 02:22:54 +0800 CST
  • Martin Hope
    Jonas Como inserir valores em uma tabela de uma consulta de seleção no PostgreSQL? 2011-05-28 00:33:05 +0800 CST
  • Martin Hope
    Jonas Como faço para listar todos os bancos de dados e tabelas usando o psql? 2011-02-18 00:45:49 +0800 CST

Hot tag

sql-server mysql postgresql sql-server-2014 sql-server-2016 oracle sql-server-2008 database-design query-performance sql-server-2017

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve