From bec45b53fa93c8154d6d5a5370f1207c32dcfdcc Mon Sep 17 00:00:00 2001 From: Itai Shirav Date: Tue, 26 Feb 2019 22:46:00 +0200 Subject: [PATCH] Fix parsing of server errors in ClickHouse v19.3.3+ --- CHANGELOG.md | 1 + src/infi/clickhouse_orm/database.py | 27 ++++++++++++++++-------- tests/test_server_errors.py | 32 +++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 tests/test_server_errors.py diff --git a/CHANGELOG.md b/CHANGELOG.md index 588125b..3abc3d6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ Change Log Unreleased ---------- - Extend date field range (trthhrtz) +- Fix parsing of server errors in ClickHouse v19.3.3+ v1.0.4 ------ diff --git a/src/infi/clickhouse_orm/database.py b/src/infi/clickhouse_orm/database.py index 06d43ba..7e72e99 100644 --- a/src/infi/clickhouse_orm/database.py +++ b/src/infi/clickhouse_orm/database.py @@ -40,11 +40,19 @@ class ServerError(DatabaseException): self.message = message super(ServerError, self).__init__(message) - ERROR_PATTERN = re.compile(r''' - Code:\ (?P\d+), - \ e\.displayText\(\)\ =\ (?P[^ \n]+):\ (?P.+?), - \ e.what\(\)\ =\ (?P[^ \n]+) - ''', re.VERBOSE | re.DOTALL) + ERROR_PATTERNS = ( + # ClickHouse prior to v19.3.3 + re.compile(r''' + Code:\ (?P\d+), + \ e\.displayText\(\)\ =\ (?P[^ \n]+):\ (?P.+?), + \ e.what\(\)\ =\ (?P[^ \n]+) + ''', re.VERBOSE | re.DOTALL), + # ClickHouse v19.3.3+ + re.compile(r''' + Code:\ (?P\d+), + \ e\.displayText\(\)\ =\ (?P[^ \n]+):\ (?P.+) + ''', re.VERBOSE | re.DOTALL), + ) @classmethod def get_error_code_msg(cls, full_error_message): @@ -54,10 +62,11 @@ class ServerError(DatabaseException): See the list of error codes here: https://github.com/yandex/ClickHouse/blob/master/dbms/src/Common/ErrorCodes.cpp """ - match = cls.ERROR_PATTERN.match(full_error_message) - if match: - # assert match.group('type1') == match.group('type2') - return int(match.group('code')), match.group('msg') + for pattern in cls.ERROR_PATTERNS: + match = pattern.match(full_error_message) + if match: + # assert match.group('type1') == match.group('type2') + return int(match.group('code')), match.group('msg').strip() return 0, full_error_message diff --git a/tests/test_server_errors.py b/tests/test_server_errors.py new file mode 100644 index 0000000..8159369 --- /dev/null +++ b/tests/test_server_errors.py @@ -0,0 +1,32 @@ +from __future__ import unicode_literals +import unittest + +from infi.clickhouse_orm.database import ServerError + + +class ServerErrorTest(unittest.TestCase): + + def test_old_format(self): + + code, msg = ServerError.get_error_code_msg("Code: 81, e.displayText() = DB::Exception: Database db_not_here doesn't exist, e.what() = DB::Exception (from [::1]:33458)") + self.assertEquals(code, 81) + self.assertEquals(msg, "Database db_not_here doesn't exist") + + code, msg = ServerError.get_error_code_msg("Code: 161, e.displayText() = DB::Exception: Limit for number of columns to read exceeded. Requested: 11, maximum: 1, e.what() = DB::Exception\n") + self.assertEquals(code, 161) + self.assertEquals(msg, "Limit for number of columns to read exceeded. Requested: 11, maximum: 1") + + + def test_new_format(self): + + code, msg = ServerError.get_error_code_msg("Code: 164, e.displayText() = DB::Exception: Cannot drop table in readonly mode") + self.assertEquals(code, 164) + self.assertEquals(msg, "Cannot drop table in readonly mode") + + code, msg = ServerError.get_error_code_msg("Code: 48, e.displayText() = DB::Exception: Method write is not supported by storage Merge") + self.assertEquals(code, 48) + self.assertEquals(msg, "Method write is not supported by storage Merge") + + code, msg = ServerError.get_error_code_msg("Code: 60, e.displayText() = DB::Exception: Table default.zuzu doesn't exist.\n") + self.assertEquals(code, 60) + self.assertEquals(msg, "Table default.zuzu doesn't exist.")