diff --git a/evadb/catalog/catalog_manager.py b/evadb/catalog/catalog_manager.py index b7c55c9bf2..333d5074ec 100644 --- a/evadb/catalog/catalog_manager.py +++ b/evadb/catalog/catalog_manager.py @@ -161,6 +161,9 @@ def get_database_catalog_entry(self, database_name: str) -> DatabaseCatalogEntry return table_entry + def get_all_database_catalog_entries(self): + return self._db_catalog_service.get_all_entries() + def drop_database_catalog_entry(self, database_entry: DatabaseCatalogEntry) -> bool: """ This method deletes the database from catalog. diff --git a/evadb/executor/show_info_executor.py b/evadb/executor/show_info_executor.py index e4894aacf1..96dc0a537f 100644 --- a/evadb/executor/show_info_executor.py +++ b/evadb/executor/show_info_executor.py @@ -32,6 +32,7 @@ def exec(self, *args, **kwargs): assert ( self.node.show_type is ShowType.FUNCTIONS or ShowType.TABLES + or ShowType.DATABASES or ShowType.CONFIG ), f"Show command does not support type {self.node.show_type}" @@ -45,6 +46,10 @@ def exec(self, *args, **kwargs): if table.table_type != TableType.SYSTEM_STRUCTURED_DATA: show_entries.append(table.name) show_entries = {"name": show_entries} + elif self.node.show_type is ShowType.DATABASES: + databases = self.catalog().get_all_database_catalog_entries() + for db in databases: + show_entries.append(db.display_format()) elif self.node.show_type is ShowType.CONFIG: value = self._config.get_value( category="default", diff --git a/evadb/parser/evadb.lark b/evadb/parser/evadb.lark index c158d8e25c..b7cac0a728 100644 --- a/evadb/parser/evadb.lark +++ b/evadb/parser/evadb.lark @@ -177,7 +177,7 @@ describe_statement: DESCRIBE table_name help_statement: HELP STRING_LITERAL -show_statement: SHOW (FUNCTIONS | TABLES | uid) +show_statement: SHOW (FUNCTIONS | TABLES | uid | DATABASES) explain_statement: EXPLAIN explainable_statement @@ -341,6 +341,7 @@ CHUNK_OVERLAP: "CHUNK_OVERLAP"i COLUMN: "COLUMN"i CREATE: "CREATE"i DATABASE: "DATABASE"i +DATABASES: "DATABASES"i DEFAULT: "DEFAULT"i DELETE: "DELETE"i DESC: "DESC"i diff --git a/evadb/parser/lark_visitor/_show_statements.py b/evadb/parser/lark_visitor/_show_statements.py index b278191fac..ca9581aca7 100644 --- a/evadb/parser/lark_visitor/_show_statements.py +++ b/evadb/parser/lark_visitor/_show_statements.py @@ -27,5 +27,7 @@ def show_statement(self, tree): return ShowStatement(show_type=ShowType.FUNCTIONS) elif isinstance(token, str) and str.upper(token) == "TABLES": return ShowStatement(show_type=ShowType.TABLES) + elif isinstance(token, str) and str.upper(token) == "DATABASES": + return ShowStatement(show_type=ShowType.DATABASES) elif token is not None: return ShowStatement(show_type=ShowType.CONFIG, show_val=self.visit(token)) diff --git a/evadb/parser/show_statement.py b/evadb/parser/show_statement.py index ae9255fe07..d7eca052f2 100644 --- a/evadb/parser/show_statement.py +++ b/evadb/parser/show_statement.py @@ -42,7 +42,8 @@ def __str__(self): show_str = "TABLES" elif self.show_type == ShowType.CONFIG: show_str = self.show_val - + elif self.show_type == ShowType.DATABASES: + show_str = "DATABASES" return f"SHOW {show_str}" def __eq__(self, other: object) -> bool: diff --git a/evadb/parser/types.py b/evadb/parser/types.py index 7cc449c293..751d2b5f31 100644 --- a/evadb/parser/types.py +++ b/evadb/parser/types.py @@ -71,6 +71,7 @@ class ShowType(EvaDBEnum): FUNCTIONS # noqa: F821 TABLES # noqa: F821 CONFIG # noqa: F821 + DATABASES # noqa: F821 class FunctionType(EvaDBEnum): diff --git a/evadb/plan_nodes/show_info_plan.py b/evadb/plan_nodes/show_info_plan.py index a6c3da5a7d..733cc0401d 100644 --- a/evadb/plan_nodes/show_info_plan.py +++ b/evadb/plan_nodes/show_info_plan.py @@ -36,6 +36,8 @@ def show_val(self): def __str__(self): if self._show_type == ShowType.FUNCTIONS: return "ShowFunctionPlan" + if self._show_type == ShowType.DATABASES: + return "ShowDatabasePlan" elif self._show_type == ShowType.TABLES: return "ShowTablePlan" elif self._show_type == ShowType.CONFIG: diff --git a/test/integration_tests/short/test_show_info_executor.py b/test/integration_tests/short/test_show_info_executor.py index 3f911bd4ca..f875d266e0 100644 --- a/test/integration_tests/short/test_show_info_executor.py +++ b/test/integration_tests/short/test_show_info_executor.py @@ -28,7 +28,7 @@ from evadb.models.storage.batch import Batch from evadb.server.command_handler import execute_query_fetch_all -NUM_FRAMES = 10 +NUM_DATABASES = 6 @pytest.mark.notparallel @@ -48,12 +48,39 @@ def setUpClass(cls): execute_query_fetch_all(cls.evadb, f"LOAD VIDEO '{mnist}' INTO MNIST;") execute_query_fetch_all(cls.evadb, f"LOAD VIDEO '{actions}' INTO Actions;") + # create databases + import os + + cls.current_file_dir = os.path.dirname(os.path.abspath(__file__)) + for i in range(NUM_DATABASES): + database_path = f"{cls.current_file_dir}/testing_{i}.db" + params = { + "database": database_path, + } + query = """CREATE DATABASE test_data_source_{} + WITH ENGINE = "sqlite", + PARAMETERS = {};""".format( + i, params + ) + execute_query_fetch_all(cls.evadb, query) + @classmethod def tearDownClass(cls): execute_query_fetch_all(cls.evadb, "DROP TABLE IF EXISTS Actions;") execute_query_fetch_all(cls.evadb, "DROP TABLE IF EXISTS MNIST;") execute_query_fetch_all(cls.evadb, "DROP TABLE IF EXISTS MyVideo;") + # remove all the DATABASES + for i in range(NUM_DATABASES): + execute_query_fetch_all( + cls.evadb, f"DROP DATABASE IF EXISTS test_data_source_{i};" + ) + database_path = f"{cls.current_file_dir}/testing_{i}.db" + import contextlib + + with contextlib.suppress(FileNotFoundError): + os.remove(database_path) + # integration test def test_show_functions(self): result = execute_query_fetch_all(self.evadb, "SHOW FUNCTIONS;") @@ -100,3 +127,17 @@ def test_show_config_execution(self): # Ensure an Exception is raised if config is not present with self.assertRaises(Exception): execute_query_fetch_all(self.evadb, "SHOW BADCONFIG") + + # integration test + def test_show_databases(self): + result = execute_query_fetch_all(self.evadb, "SHOW DATABASES;") + self.assertEqual(len(result.columns), 3) + self.assertEqual(len(result), 6) + + expected = { + "name": [f"test_data_source_{i}" for i in range(NUM_DATABASES)], + "engine": ["sqlite" for _ in range(NUM_DATABASES)], + } + expected_df = pd.DataFrame(expected) + self.assertTrue(all(expected_df.name == result.frames.name)) + self.assertTrue(all(expected_df.engine == result.frames.engine)) diff --git a/test/unit_tests/parser/test_parser_statements.py b/test/unit_tests/parser/test_parser_statements.py index f45f94bd18..eba32480ee 100644 --- a/test/unit_tests/parser/test_parser_statements.py +++ b/test/unit_tests/parser/test_parser_statements.py @@ -80,6 +80,7 @@ def test_parser_statement_types(self): """, "SHOW TABLES;", "SHOW FUNCTIONS;", + "SHOW DATABASES;", "EXPLAIN SELECT a FROM foo;", "SELECT HomeRentalForecast(12);", """SELECT data FROM MyVideo WHERE id < 5