From 90c716bce0de7710f7f63d6ea42ff01df10f4061 Mon Sep 17 00:00:00 2001 From: Gavin D'souza Date: Fri, 17 Jun 2022 12:10:43 +0530 Subject: [PATCH] fix(sequence): Setup & use SequenceGeneratorLimitExceeded error --- frappe/database/mariadb/database.py | 4 ++++ frappe/database/postgres/database.py | 3 ++- frappe/database/sequence.py | 17 +++++++++++------ frappe/tests/test_sequence.py | 6 +----- 4 files changed, 18 insertions(+), 12 deletions(-) diff --git a/frappe/database/mariadb/database.py b/frappe/database/mariadb/database.py index da33007d5d..327c995d48 100644 --- a/frappe/database/mariadb/database.py +++ b/frappe/database/mariadb/database.py @@ -46,6 +46,10 @@ class MariaDBExceptionUtil: SQLError = mariadb.ProgrammingError DataError = mariadb.DataError + # match ER_SEQUENCE_RUN_OUT - https://mariadb.com/kb/en/mariadb-error-codes/ + SequenceGeneratorLimitExceeded = mariadb.ProgrammingError + SequenceGeneratorLimitExceeded.errno = 4084 + @staticmethod def is_deadlocked(e: mariadb.Error) -> bool: return getattr(e, "errno", None) == ER.LOCK_DEADLOCK diff --git a/frappe/database/postgres/database.py b/frappe/database/postgres/database.py index 2444d41279..f5ecabd6c4 100644 --- a/frappe/database/postgres/database.py +++ b/frappe/database/postgres/database.py @@ -13,7 +13,7 @@ from psycopg2.errorcodes import ( UNDEFINED_TABLE, UNIQUE_VIOLATION, ) -from psycopg2.errors import SyntaxError +from psycopg2.errors import SequenceGeneratorLimitExceeded, SyntaxError from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ import frappe @@ -44,6 +44,7 @@ class PostgresExceptionUtil: SQLError = psycopg2.ProgrammingError DataError = psycopg2.DataError InterfaceError = psycopg2.InterfaceError + SequenceGeneratorLimitExceeded = SequenceGeneratorLimitExceeded @staticmethod def is_deadlocked(e): diff --git a/frappe/database/sequence.py b/frappe/database/sequence.py index 6a352d20d1..54362a5895 100644 --- a/frappe/database/sequence.py +++ b/frappe/database/sequence.py @@ -57,12 +57,17 @@ def create_sequence( def get_next_val(doctype_name: str, slug: str = "_id_seq") -> int: - return db.multisql( - { - "postgres": f"select nextval('\"{scrub(doctype_name + slug)}\"')", - "mariadb": f"select nextval(`{scrub(doctype_name + slug)}`)", - } - )[0][0] + sequence_name = scrub(f"{doctype_name}{slug}") + + if db.db_type == "postgres": + sequence_name = f"'\"{sequence_name}\"'" + elif db.db_type == "mariadb": + sequence_name = f"`{sequence_name}`" + + try: + return db.sql(f"SELECT nextval({sequence_name})")[0][0] + except IndexError: + raise db.SequenceGeneratorLimitExceeded def set_next_val( diff --git a/frappe/tests/test_sequence.py b/frappe/tests/test_sequence.py index 82bb8ab257..c6ea0bc8c0 100644 --- a/frappe/tests/test_sequence.py +++ b/frappe/tests/test_sequence.py @@ -1,5 +1,3 @@ -import psycopg2 - import frappe from frappe.tests.utils import FrappeTestCase @@ -34,10 +32,8 @@ class TestSequence(FrappeTestCase): try: frappe.db.get_next_sequence_val(seq_name) - except psycopg2.errors.SequenceGeneratorLimitExceeded: + except frappe.db.SequenceGeneratorLimitExceeded: pass - except frappe.db.ProgrammingError as e: - self.assertEqual(getattr(e, "errno", None), 4084) else: self.fail("NEXTVAL didn't raise any error upon sequence's end")