From f6bf102c3bc58b3ce25a4567b32d05e3e1b843bb Mon Sep 17 00:00:00 2001 From: Leandro Roberto Silva Date: Thu, 1 Oct 2020 14:10:51 -0300 Subject: [PATCH] Cria func reset_id_model e manage command para checar ids (#3112) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * cria func reset_id_model e signal para checar ids add comments troca print por logger refatora migrate para executar/criar stored procedure ajusta tabulação no código da SP desmembra try except e isola no da SP ajusta definição e captura de nome da função para SP * Cria arquivo para management command Co-authored-by: Vinícius Cantuária --- sapl/rules/apps.py | 14 +--- .../commands/check_ids_sequences.py | 67 +++++++++++++++++++ 2 files changed, 70 insertions(+), 11 deletions(-) create mode 100644 sapl/rules/management/commands/check_ids_sequences.py diff --git a/sapl/rules/apps.py b/sapl/rules/apps.py index 92126dcc6..18ad112a6 100644 --- a/sapl/rules/apps.py +++ b/sapl/rules/apps.py @@ -241,14 +241,6 @@ def revision_pre_delete_signal(sender, **kwargs): reversion.set_comment("Deletado pelo sinal.") -models.signals.post_migrate.connect( - receiver=update_groups) - - -models.signals.post_migrate.connect( - receiver=create_proxy_permissions, - dispatch_uid="django.contrib.auth.management.create_permissions") - -models.signals.pre_delete.connect( - receiver=revision_pre_delete_signal, - dispatch_uid="pre_delete_signal") +models.signals.post_migrate.connect(receiver=update_groups) +models.signals.post_migrate.connect(receiver=create_proxy_permissions, dispatch_uid="django.contrib.auth.management.create_permissions") +models.signals.pre_delete.connect(receiver=revision_pre_delete_signal, dispatch_uid="pre_delete_signal") diff --git a/sapl/rules/management/commands/check_ids_sequences.py b/sapl/rules/management/commands/check_ids_sequences.py new file mode 100644 index 000000000..92b47f9bc --- /dev/null +++ b/sapl/rules/management/commands/check_ids_sequences.py @@ -0,0 +1,67 @@ +import logging + +from django.apps import apps +from django.core.management.base import BaseCommand +from django.db import connection +from django.db.utils import DEFAULT_DB_ALIAS + +logger = logging.getLogger(__name__) + + +class Command(BaseCommand): + help = 'Check ids sequences and update them' + + def handle(self, *args, **kwargs): + models = apps.get_models() + + for model in models: + if model._meta.managed and model._meta.auto_field: + fn_check_sequence_for_model(model) + + +def fn_check_sequence_for_model(model): + SP_NAME = fn_check_sequence_for_model.__name__ + + with connection.cursor() as c: + try: + c.callproc(SP_NAME, [model._meta.db_table]) + except Exception as e: + if f"function {SP_NAME}(unknown) does not exist" not in str(e): + # Se ocorreu um erro e não é por inexistência da SP + logger.error(f"Falha na execução da Store Procedure para a tabela {model._meta.db_table}. {str(e)}") + else: + # se a execução da SP falhou por ela não existir + try: + # cria a SP + c.execute( + f""" + CREATE OR REPLACE FUNCTION {SP_NAME}(IN table_name character varying) RETURNS integer AS + $$ + DECLARE + max_id integer := 0; + BEGIN + EXECUTE format('SELECT setval(pg_get_serial_sequence(''%s'',''id''), coalesce(max(id), 1), max(id) IS NOT null) FROM %s', table_name, table_name ) INTO max_id; + if max_id is null then + EXECUTE format('DROP SEQUENCE IF EXISTS %s_id_seq cascade', table_name); + EXECUTE format('CREATE SEQUENCE %s_id_seq start 1 OWNED BY %s.id', table_name, table_name); + EXECUTE format('ALTER TABLE %s ALTER COLUMN id SET DEFAULT nextval(''%s_id_seq''::regclass)', table_name, table_name); + EXECUTE format('SELECT setval(pg_get_serial_sequence(''%s'',''id''), coalesce(max(id), 1), max(id) IS NOT null) FROM %s', table_name, table_name ) INTO max_id; + end if; + return max_id; + END; + $$ LANGUAGE plpgsql; + """ + ) + except Exception as e: + # se falhou na criação + logger.error(f"Falha na criação da Store Procedure {SP_NAME} para o tabela {model._meta.db_table}. {str(e)}") + logger.error(f"Falha na criação da Store Procedure {SP_NAME} para o tabela {model._meta.db_table}. {str(e)}") + try: + # tenta executá-la após criação. + c.callproc(SP_NAME, [model._meta.db_table]) + except Exception as e: + # se falhou na execução + logger.error(f"Falha na execução da Store Procedure {SP_NAME} para o tabela {model._meta.db_table}. {str(e)}") + + finally: + c.close()