diff --git a/docs/_toc.yml b/docs/_toc.yml index ca191ce42..ebf5a67e0 100644 --- a/docs/_toc.yml +++ b/docs/_toc.yml @@ -147,6 +147,8 @@ parts: title: Troubleshooting - file: source/dev-guide/contribute/unit-test title: Unit Testing UDFs in EvaDB + - file: source/dev-guide/contribute/error-codes + title: Error Codes in EvaDB - file: source/dev-guide/debugging title: Debugging EvaDB diff --git a/docs/source/dev-guide/contribute/error-codes.rst b/docs/source/dev-guide/contribute/error-codes.rst new file mode 100644 index 000000000..3d26e7ff7 --- /dev/null +++ b/docs/source/dev-guide/contribute/error-codes.rst @@ -0,0 +1,41 @@ +Using Error Codes in EvaDB +========================== + +Introduction +------------ + +Proper error handling is an essential aspect of robust software development. In EvaDB, error codes provide a standardized way of reporting and logging errors. This guide explains how to use predefined error codes, and how they enhance debugging and error tracking. + +Error Codes Overview +-------------------- + +EvaDB implements an `ErrorManager` class with predefined error codes for various error scenarios. Each error code is associated with a default error message, which can be extended with additional information when required. A list of all error codes can be found in `evadb/error_manager.py`. + +Using Error Codes without Additional Message +-------------------------------------------- + +In cases where the default error message suffices, you can use the error code directly. This is common in scenarios where the error context is self-explanatory. + +.. code-block:: python + + from error_manager import ErrorManager + + # Example of using an error code without an additional message + def some_function(): + if not some_condition: + raise Exception(ErrorManager.get_error_message(ErrorManager.EXPECTED_SELECTION_STATEMENT)) + +Using Error Codes with Additional Message +----------------------------------------- + +In scenarios requiring more detailed error information, you can provide an additional message along with the error code. This is useful for adding context or specifics about the error. + +.. code-block:: python + + from error_manager import ErrorManager + + # Example of using an error code with an additional message + def some_function(param): + if not validate(param): + error_msg = ErrorManager.get_error_message(ErrorManager.UNSUPPORTED_TYPE, f"Invalid parameter: {param}") + raise Exception(error_msg) \ No newline at end of file diff --git a/error-map.txt b/error-map.txt new file mode 100644 index 000000000..1ccc9bca0 --- /dev/null +++ b/error-map.txt @@ -0,0 +1,176 @@ +0000 - ERROR_GENERIC + +=======================Expected-Type Errors======================= + +0100 - EXPECTED_SELECTION_STATEMENT + - evadb/parser/utils.py + - 41 + - 48 + - 61 + - 170 + - 184 + - evadb/interfaces/relational/utils.py + - 88 + - evadb/parser/table_ref.py + - 253 +0101 - EXPECTED_CREATE_TABLE_STATEMENT + - evadb/parser/utils.py + - 101 +0102 - EXPECTED_SHOW_STATEMENT + - evadb/parser/utils.py + - 108 +0103 - EXPECTED_INSERT_STATEMENT + - evadb/parser/utils.py + - 122 +0104 - EXPECTED_EXPLAIN_STATEMENT + - evadb/parser/utils.py + - 115 +0105 - EXPECTED_LOAD_STATEMENT + - evadb/parser/utils.py + - 129 +0106 - EXPECTED_DROP_OBJECT_STATEMENT + - evadb/parser/utils.py + - 141 +0107 - EXPECTED_RENAME_STATEMENT + - evadb/parser/utils.py + - 191 +0108 - EXPECTED_CREATE_FUNCTION_STATEMENT + - evadb/parser/utils.py + - 88 +0109_EXPECTED_COLUMNS_NUMBER_MISMATCH + - evadb/binder/binder_utils.py + - 246 + +0110 - QUERY_EXPECTS_ONE_CHILD + - evadb/executor/create_executor.py + - 67 + - evadb/executor/create_function_executor.py + - 114 + - 164 + - 221 +0111 - EXPECTED_API_TOKEN_SET + - evadb/functions/chatgpt.py + - 127 + - evadb/functions/dalle.py + - 65 + - evadb/functions/stable_diffusion.py + - 68 + - evadb/third_party/vector_stores/pinecone.py + - 44 + - 53 +0112 - EXPECTED_PD_DF + - evadb/functions/abstract/tracker_abstract_function.py + - 90 + + +=======================Index Errors======================= + +1100 - CANNOT_CREATE_INDEX_ON_MULIPLE_COLUMN + - evadb/binder/create_index_statement_binder.py + - 37 + - 67 +1101 - CREATE_INDEX_ONLY_ON_EXISTING_TABLE + - - evadb/binder/create_index_statement_binder.py + - 40 +1102 - CANNOT_CREATE_INDEX_ON_NONEXISTANT_COLUMN + - evadb/binder/create_index_statement_binder.py + - 76 +1103 - INDEX_INPUT_TYPE_MISMATCH + - evadb/binder/create_index_statement_binder.py + - 85 + - 100 +1104 - INDEX_INPUT_DIM_MISMATCH + - evadb/binder/create_index_statement_binder.py + - 94 +1105 - CREATE_INDEX_FIRST + - evadb/third_party/vector_stores/faiss.py + - 58 + - 67 + - 73 + +=======================Type Errors======================= + +2100 - UNSUPPORTED_TYPE + - evadb/catalog/catalog_manager.py + - 551 + - evadb/executor/delete_executor.py + - 73 + - evadb/executor/show_info_executor.py + - 32 + - evadb/expression/comparison_expression.py + - 49 + - evadb/expression/tuple_value_expression.py + - 83 +2101 - UNSUPPORTED_OPERATION + - evadb/executor/union_executor.py + - 35 + - evadb/models/storage/batch.py + - 204 + - 268 + - evadb/optimizer/binder.py + - 61 + - evadb/optimizer/group_expression.py + - 31 + - evadb/executor/exchange_executor.py + - 74 +2102 - UNSUPPORTED_CLAUSE + - evadb/interfaces/relational/utils.py + - 100 +2103 - UNSUPPORTED_LIBRARY + - evadb/executor/create_function_executor.py + - 319 +2104 - CONCURRENT_CALLS_NOT_SUPPORTED + - evadb/utils/stats.py + - 32 + + + + +=======================Not Found/ Already Exists Errors========================= + +3100 - TABLE_NOT_FOUND + - evadb/catalog/catalog_manager.py + - 589 + +3101 - TABLE_ALREADY_EXISTS + - evadb/catalog/catalog_manager.py + - 613 + +3102 - DIRECTORY_NOT_FOUND + - evadb/configuration/bootstrap_environment.py + - 60 + - 61 + +3103 - DIRECTORY_ALREADY_EXISTS + +3104 - FILE_NOT_FOUND + - evadb/functions/ndarray/open.py + - 48 + +3105 - FILE_ALREADY_EXISTS + +3106 - KEY_NOT_FOUND + - evadb/executor/exchange_executor.py + - 35 + - 38 + + +=======================Failed-to Errors======================= +4100 - DROP_TABLE_FAILED + - evadb/executor/drop_object_executor.py + - 68 +4101 - VECTOR_STORE_HANDLER_INITALIZATION_FAILED + - evadb/executor/drop_object_executor.py + - 125 + +4102 - RELATION_EXECUTE_FAILED + - evadb/interfaces/relational/relation.py + - 124 + - 264 + +=======================Not implemented======================= +9999 - NOT_IMPLEMENTED + - evadb/executor/delete_executor.py + - 97 + - evadb/executor/insert_executor.py + - 41 diff --git a/evadb/error_manager.py b/evadb/error_manager.py new file mode 100644 index 000000000..c10251c2e --- /dev/null +++ b/evadb/error_manager.py @@ -0,0 +1,81 @@ +# coding=utf-8 +# Copyright 2018-2023 EvaDB +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +from enum import Enum + + +class ErrorCode: + def __init__(self, code, message=""): + self.code = code + self.default_message = message + + def __str__(self): + return f"[{self.code}] {self.default_message}" + +class ErrorManager: + # Generic Error + ERROR_GENERIC = ErrorCode(0, "Error") + + # Expected-Type Errors + EXPECTED_SELECTION_STATEMENT = ErrorCode(100, "Expected a select statement") + EXPECTED_CREATE_TABLE_STATEMENT = ErrorCode(101, "Expected a create table statement") + EXPECTED_SHOW_STATEMENT = ErrorCode(102, "Expected a show statement") + EXPECTED_INSERT_STATEMENT = ErrorCode(103, "Expected an insert statement") + EXPECTED_EXPLAIN_STATEMENT = ErrorCode(104, "Expected an explain statement") + EXPECTED_LOAD_STATEMENT = ErrorCode(105, "Expected a load statement") + EXPECTED_DROP_OBJECT_STATEMENT = ErrorCode(106, "Expected a drop object statement") + EXPECTED_RENAME_STATEMENT = ErrorCode(107, "Expected a rename statement") + EXPECTED_CREATE_FUNCTION_STATEMENT = ErrorCode(108, "Expected a create function statement") + EXPECTED_COLUMNS_NUMBER_MISMATCH = ErrorCode(109, "Unexpected number of columns") + QUERY_EXPECTS_ONE_CHILD = ErrorCode(110, "Query expects one child") + EXPECTED_API_TOKEN_SET = ErrorCode(111, "API token expected to be se.") + EXPECTED_PD_DF = ErrorCode(112, "Expected a Pandas DataFrame") + + # Index Errors + CANNOT_CREATE_INDEX_ON_MULIPLE_COLUMN = ErrorCode(1100, "Index cannot be created on more than 1 column") + CREATE_INDEX_ONLY_ON_EXISTING_TABLE = ErrorCode(1101, "Index can only be created on an existing table") + CANNOT_CREATE_INDEX_ON_NONEXISTANT_COLUMN = ErrorCode(1102, "Index is created on non-existent column") + INDEX_INPUT_TYPE_MISMATCH = ErrorCode(1103, "Index input type is mismatched") + INDEX_INPUT_DIM_MISMATCH = ErrorCode(1104, "Index input dimensions are mismatched") + CREATE_INDEX_FIRST = ErrorCode(1105, "Create an index first") + + # Type Errors + UNSUPPORTED_TYPE = ErrorCode(2100, "Type not supported") + UNSUPPORTED_OPERATION = ErrorCode(2101, "Operation not supported") + UNSUPPORTED_CLAUSE = ErrorCode(2102, "Clause not supported") + UNSUPPORTED_LIBRARY = ErrorCode(2103, "Library not supported") + CONCURRENT_CALLS_NOT_SUPPORTED = ErrorCode(2104, "Concurrent queries not supported") + + # Not Found/Already Exists Errors + TABLE_NOT_FOUND = ErrorCode(3100, "Table not found") + TABLE_ALREADY_EXISTS = ErrorCode(3101, "Table already exists") + DIRECTORY_NOT_FOUND = ErrorCode(3102, "Directory not found") + DIRECTORY_ALREADY_EXISTS = ErrorCode(3103, "Directory already exists") + FILE_NOT_FOUND = ErrorCode(3104, "File not found") + FILE_ALREADY_EXISTS = ErrorCode(3105, "File already exists") + KEY_NOT_FOUND = ErrorCode(3106, "Key not found") + + # Failed-to Errors + DROP_TABLE_FAILED = ErrorCode(4100, "DROP table failed") + VECTOR_STORE_HANDLER_INITALIZATION_FAILED = ErrorCode(4101, "Initialization of vector store failed") + RELATION_EXECUTE_FAILED = ErrorCode(4102, "Relation execute failed") + + # Not implemented + NOT_IMPLEMENTED = ErrorCode(9999, "Functionality not implemented for current use-case.") + + @staticmethod + def get_error_message(error_code, additional_message=None): + if additional_message: + return f"{error_code} Details: {additional_message}" + return str(error_code) \ No newline at end of file diff --git a/evadb/executor/create_executor.py b/evadb/executor/create_executor.py index 90b711feb..c09a5a838 100644 --- a/evadb/executor/create_executor.py +++ b/evadb/executor/create_executor.py @@ -17,6 +17,7 @@ import pandas as pd from evadb.database import EvaDBDatabase +from evadb.error_manager import ErrorManager from evadb.executor.abstract_executor import AbstractExecutor from evadb.executor.executor_utils import ( create_table_catalog_entry_for_native_table, @@ -64,10 +65,11 @@ def exec(self, *args, **kwargs): msg = f"The table {name} has been successfully created" if self.children != []: - assert ( - len(self.children) == 1 - ), "Create table from query expects 1 child, finds {}".format( - len(self.children) + assert len(self.children) == 1, ErrorManager.get_error_message( + ErrorManager.QUERY_EXPECTS_ONE_CHILD, + "Create table from query expects 1 child, finds {}".format( + len(self.children) + ), ) child = self.children[0]