We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add new method to return the columns for ClickHouse datasources :electric_plug: :1234: 
When MindsDB creates a new ClickHouse datasource we get information for columns by fetching all datasources. The problem here is that if datasource is big it takes a lot of time. We need a new get_columns method to return the columns name per datasource. The PR should include this method inside the ClickHouse class.

## Steps :male_detective: :female_detective: 

- Implement in https://github.com/mindsdb/mindsdb/blob/staging/mindsdb/integrations/clickhouse/clickhouse.py#L25
- Push to staging branch

## Additional rewards :1st_place_medal: 

Each code PR brings  :three:  point for entry into the draw for a :computer:  Deep Learning Laptop powered by the NVIDIA RTX 3080 Max-Q GPU or other swag :shirt: :bear: .  For more info check out https://mindsdb.com/hacktoberfest/
 



--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `mindsdb/integrations/clickhouse/clickhouse.py`
Content:
```
1 import requests
2 from lightwood.api import dtype
3 from mindsdb.integrations.base import Integration
4 from mindsdb.utilities.log import log
5 
6 
7 class ClickhouseConnectionChecker:
8     def __init__(self, **kwargs):
9         self.host = kwargs.get("host")
10         self.port = kwargs.get("port")
11         self.user = kwargs.get("user")
12         self.password = kwargs.get("password")
13 
14     def check_connection(self):
15         try:
16             res = requests.post(f"http://{self.host}:{self.port}",
17                                 data="select 1;",
18                                 params={'user': self.user, 'password': self.password})
19             connected = res.status_code == 200
20         except Exception:
21             connected = False
22         return connected
23 
24 
25 class Clickhouse(Integration, ClickhouseConnectionChecker):
26     def __init__(self, config, name, db_info):
27         super().__init__(config, name)
28         self.user = db_info.get('user', 'default')
29         self.password = db_info.get('password', None)
30         self.host = db_info.get('host')
31         self.port = db_info.get('port')
32 
33     def _to_clickhouse_table(self, dtype_dict, predicted_cols, columns):
34         subtype_map = {
35             dtype.integer: 'Nullable(Int64)',
36             dtype.float: 'Nullable(Float64)',
37             dtype.binary: 'Nullable(UInt8)',
38             dtype.date: 'Nullable(Date)',
39             dtype.datetime: 'Nullable(Datetime)',
40             dtype.binary: 'Nullable(String)',
41             dtype.categorical: 'Nullable(String)',
42             dtype.tags: 'Nullable(String)',
43             dtype.image: 'Nullable(String)',
44             dtype.video: 'Nullable(String)',
45             dtype.audio: 'Nullable(String)',
46             dtype.short_text: 'Nullable(String)',
47             dtype.rich_text: 'Nullable(String)',
48             dtype.array: 'Nullable(String)'
49         }
50 
51         column_declaration = []
52         for name in columns:
53             try:
54                 col_subtype = dtype_dict[name]
55                 new_type = subtype_map[col_subtype]
56                 column_declaration.append(f' `{name}` {new_type} ')
57                 if name in predicted_cols:
58                     column_declaration.append(f' `{name}_original` {new_type} ')
59             except Exception as e:
60                 log.error(f'Error: can not determine clickhouse data type for column {name}: {e}')
61 
62         return column_declaration
63 
64     def _query(self, query):
65         params = {'user': self.user}
66 
67         if self.password is not None:
68             params['password'] = self.password
69 
70         host = self.host
71         port = self.port
72 
73         response = requests.post(f'http://{host}:{port}', data=query, params=params)
74 
75         if response.status_code != 200:
76             raise Exception(f'Error: {response.content}\nQuery:{query}')
77 
78         return response
79 
80     def _get_mysql_user(self):
81         return f"{self.config['api']['mysql']['user']}_{self.name}"
82 
83     def _escape_table_name(self, name):
84         return '`' + name.replace('`', '\\`') + '`'
85 
86     def setup(self):
87         self._query(f'DROP DATABASE IF EXISTS {self.mindsdb_database}')
88         self._query(f'CREATE DATABASE IF NOT EXISTS {self.mindsdb_database}')
89 
90         msqyl_conn = self.config['api']['mysql']['host'] + ':' + str(self.config['api']['mysql']['port'])
91         msqyl_pass = self.config['api']['mysql']['password']
92         msqyl_user = self._get_mysql_user()
93 
94         q = f"""
95             CREATE TABLE IF NOT EXISTS {self.mindsdb_database}.predictors (
96                 name String,
97                 status String,
98                 accuracy String,
99                 predict String,
100                 select_data_query String,
101                 external_datasource String,
102                 training_options String
103                 ) ENGINE=MySQL('{msqyl_conn}', 'mindsdb', 'predictors', '{msqyl_user}', '{msqyl_pass}')
104         """
105         self._query(q)
106         q = f"""
107             CREATE TABLE IF NOT EXISTS {self.mindsdb_database}.commands (
108                 command String
109             ) ENGINE=MySQL('{msqyl_conn}', 'mindsdb', 'commands', '{msqyl_user}', '{msqyl_pass}')
110         """
111         self._query(q)
112 
113     def register_predictors(self, model_data_arr):
114         for model_meta in model_data_arr:
115             name = self._escape_table_name(model_meta['name'])
116 
117             predict = model_meta['predict']
118             if not isinstance(predict, list):
119                 predict = [predict]
120 
121             columns_sql = ','.join(self._to_clickhouse_table(
122                 model_meta['dtype_dict'],
123                 predict,
124                 list(model_meta['dtype_dict'].keys())
125             ))
126             columns_sql += ',`when_data` Nullable(String)'
127             columns_sql += ',`select_data_query` Nullable(String)'
128             columns_sql += ',`external_datasource` Nullable(String)'
129             for col in predict:
130                 columns_sql += f',`{col}_confidence` Nullable(Float64)'
131 
132                 if model_meta['dtype_dict'][col] in (dtype.integer, dtype.float):
133                     columns_sql += f',`{col}_min` Nullable(Float64)'
134                     columns_sql += f',`{col}_max` Nullable(Float64)'
135                 columns_sql += f',`{col}_explain` Nullable(String)'
136 
137             msqyl_conn = self.config['api']['mysql']['host'] + ':' + str(self.config['api']['mysql']['port'])
138             msqyl_pass = self.config['api']['mysql']['password']
139             msqyl_user = self._get_mysql_user()
140 
141             self.unregister_predictor(model_meta['name'])
142             q = f"""
143                 CREATE TABLE {self.mindsdb_database}.{name}
144                 ({columns_sql}
145                 ) ENGINE=MySQL('{msqyl_conn}', 'mindsdb', {name}, '{msqyl_user}', '{msqyl_pass}')
146             """
147             self._query(q)
148 
149     def unregister_predictor(self, name):
150         q = f"""
151             drop table if exists {self.mindsdb_database}.{self._escape_table_name(name)};
152         """
153         self._query(q)
154 
155     def get_tables_list(self):
156         q = f"""SELECT database, table
157                     FROM system.parts
158                     WHERE active and database NOT IN  ('system', 'mdb_system')
159                     GROUP BY database, table
160                     ORDER BY database, table;"""
161         tables_list = self._query(q)
162         tables= [f"{table[0]}.{table[1]}" for table in tables_list]
163         return tables
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/mindsdb/integrations/clickhouse/clickhouse.py b/mindsdb/integrations/clickhouse/clickhouse.py
--- a/mindsdb/integrations/clickhouse/clickhouse.py
+++ b/mindsdb/integrations/clickhouse/clickhouse.py
@@ -160,4 +160,12 @@
                     ORDER BY database, table;"""
         tables_list = self._query(q)
         tables= [f"{table[0]}.{table[1]}" for table in tables_list]
-        return tables
\ No newline at end of file
+        return tables
+
+    def get_columns(self,query):
+        q = f"SELECT * FROM ({query}) LIMIT 1 FORMAT JSON"
+        query_result = self._query(q).json()
+        columns_info = query_result['meta']
+        columns= [column['name'] for column in columns_info]
+        return columns
+

{"golden_diff": "diff --git a/mindsdb/integrations/clickhouse/clickhouse.py b/mindsdb/integrations/clickhouse/clickhouse.py\n--- a/mindsdb/integrations/clickhouse/clickhouse.py\n+++ b/mindsdb/integrations/clickhouse/clickhouse.py\n@@ -160,4 +160,12 @@\n                     ORDER BY database, table;\"\"\"\n         tables_list = self._query(q)\n         tables= [f\"{table[0]}.{table[1]}\" for table in tables_list]\n-        return tables\n\\ No newline at end of file\n+        return tables\n+\n+    def get_columns(self,query):\n+        q = f\"SELECT * FROM ({query}) LIMIT 1 FORMAT JSON\"\n+        query_result = self._query(q).json()\n+        columns_info = query_result['meta']\n+        columns= [column['name'] for column in columns_info]\n+        return columns\n+\n", "issue": "Add new method to return the columns for ClickHouse datasources :electric_plug: :1234: \nWhen MindsDB creates a new ClickHouse datasource we get information for columns by fetching all datasources. The problem here is that if datasource is big it takes a lot of time. We need a new get_columns method to return the columns name per datasource. The PR should include this method inside the ClickHouse class.\r\n\r\n## Steps :male_detective: :female_detective: \r\n\r\n- Implement in https://github.com/mindsdb/mindsdb/blob/staging/mindsdb/integrations/clickhouse/clickhouse.py#L25\r\n- Push to staging branch\r\n\r\n## Additional rewards :1st_place_medal: \r\n\r\nEach code PR brings  :three:  point for entry into the draw for a :computer:  Deep Learning Laptop powered by the NVIDIA RTX 3080 Max-Q GPU or other swag :shirt: :bear: .  For more info check out https://mindsdb.com/hacktoberfest/\r\n \r\n\r\n\n", "before_files": [{"content": "import requests\nfrom lightwood.api import dtype\nfrom mindsdb.integrations.base import Integration\nfrom mindsdb.utilities.log import log\n\n\nclass ClickhouseConnectionChecker:\n    def __init__(self, **kwargs):\n        self.host = kwargs.get(\"host\")\n        self.port = kwargs.get(\"port\")\n        self.user = kwargs.get(\"user\")\n        self.password = kwargs.get(\"password\")\n\n    def check_connection(self):\n        try:\n            res = requests.post(f\"http://{self.host}:{self.port}\",\n                                data=\"select 1;\",\n                                params={'user': self.user, 'password': self.password})\n            connected = res.status_code == 200\n        except Exception:\n            connected = False\n        return connected\n\n\nclass Clickhouse(Integration, ClickhouseConnectionChecker):\n    def __init__(self, config, name, db_info):\n        super().__init__(config, name)\n        self.user = db_info.get('user', 'default')\n        self.password = db_info.get('password', None)\n        self.host = db_info.get('host')\n        self.port = db_info.get('port')\n\n    def _to_clickhouse_table(self, dtype_dict, predicted_cols, columns):\n        subtype_map = {\n            dtype.integer: 'Nullable(Int64)',\n            dtype.float: 'Nullable(Float64)',\n            dtype.binary: 'Nullable(UInt8)',\n            dtype.date: 'Nullable(Date)',\n            dtype.datetime: 'Nullable(Datetime)',\n            dtype.binary: 'Nullable(String)',\n            dtype.categorical: 'Nullable(String)',\n            dtype.tags: 'Nullable(String)',\n            dtype.image: 'Nullable(String)',\n            dtype.video: 'Nullable(String)',\n            dtype.audio: 'Nullable(String)',\n            dtype.short_text: 'Nullable(String)',\n            dtype.rich_text: 'Nullable(String)',\n            dtype.array: 'Nullable(String)'\n        }\n\n        column_declaration = []\n        for name in columns:\n            try:\n                col_subtype = dtype_dict[name]\n                new_type = subtype_map[col_subtype]\n                column_declaration.append(f' `{name}` {new_type} ')\n                if name in predicted_cols:\n                    column_declaration.append(f' `{name}_original` {new_type} ')\n            except Exception as e:\n                log.error(f'Error: can not determine clickhouse data type for column {name}: {e}')\n\n        return column_declaration\n\n    def _query(self, query):\n        params = {'user': self.user}\n\n        if self.password is not None:\n            params['password'] = self.password\n\n        host = self.host\n        port = self.port\n\n        response = requests.post(f'http://{host}:{port}', data=query, params=params)\n\n        if response.status_code != 200:\n            raise Exception(f'Error: {response.content}\\nQuery:{query}')\n\n        return response\n\n    def _get_mysql_user(self):\n        return f\"{self.config['api']['mysql']['user']}_{self.name}\"\n\n    def _escape_table_name(self, name):\n        return '`' + name.replace('`', '\\\\`') + '`'\n\n    def setup(self):\n        self._query(f'DROP DATABASE IF EXISTS {self.mindsdb_database}')\n        self._query(f'CREATE DATABASE IF NOT EXISTS {self.mindsdb_database}')\n\n        msqyl_conn = self.config['api']['mysql']['host'] + ':' + str(self.config['api']['mysql']['port'])\n        msqyl_pass = self.config['api']['mysql']['password']\n        msqyl_user = self._get_mysql_user()\n\n        q = f\"\"\"\n            CREATE TABLE IF NOT EXISTS {self.mindsdb_database}.predictors (\n                name String,\n                status String,\n                accuracy String,\n                predict String,\n                select_data_query String,\n                external_datasource String,\n                training_options String\n                ) ENGINE=MySQL('{msqyl_conn}', 'mindsdb', 'predictors', '{msqyl_user}', '{msqyl_pass}')\n        \"\"\"\n        self._query(q)\n        q = f\"\"\"\n            CREATE TABLE IF NOT EXISTS {self.mindsdb_database}.commands (\n                command String\n            ) ENGINE=MySQL('{msqyl_conn}', 'mindsdb', 'commands', '{msqyl_user}', '{msqyl_pass}')\n        \"\"\"\n        self._query(q)\n\n    def register_predictors(self, model_data_arr):\n        for model_meta in model_data_arr:\n            name = self._escape_table_name(model_meta['name'])\n\n            predict = model_meta['predict']\n            if not isinstance(predict, list):\n                predict = [predict]\n\n            columns_sql = ','.join(self._to_clickhouse_table(\n                model_meta['dtype_dict'],\n                predict,\n                list(model_meta['dtype_dict'].keys())\n            ))\n            columns_sql += ',`when_data` Nullable(String)'\n            columns_sql += ',`select_data_query` Nullable(String)'\n            columns_sql += ',`external_datasource` Nullable(String)'\n            for col in predict:\n                columns_sql += f',`{col}_confidence` Nullable(Float64)'\n\n                if model_meta['dtype_dict'][col] in (dtype.integer, dtype.float):\n                    columns_sql += f',`{col}_min` Nullable(Float64)'\n                    columns_sql += f',`{col}_max` Nullable(Float64)'\n                columns_sql += f',`{col}_explain` Nullable(String)'\n\n            msqyl_conn = self.config['api']['mysql']['host'] + ':' + str(self.config['api']['mysql']['port'])\n            msqyl_pass = self.config['api']['mysql']['password']\n            msqyl_user = self._get_mysql_user()\n\n            self.unregister_predictor(model_meta['name'])\n            q = f\"\"\"\n                CREATE TABLE {self.mindsdb_database}.{name}\n                ({columns_sql}\n                ) ENGINE=MySQL('{msqyl_conn}', 'mindsdb', {name}, '{msqyl_user}', '{msqyl_pass}')\n            \"\"\"\n            self._query(q)\n\n    def unregister_predictor(self, name):\n        q = f\"\"\"\n            drop table if exists {self.mindsdb_database}.{self._escape_table_name(name)};\n        \"\"\"\n        self._query(q)\n\n    def get_tables_list(self):\n        q = f\"\"\"SELECT database, table\n                    FROM system.parts\n                    WHERE active and database NOT IN  ('system', 'mdb_system')\n                    GROUP BY database, table\n                    ORDER BY database, table;\"\"\"\n        tables_list = self._query(q)\n        tables= [f\"{table[0]}.{table[1]}\" for table in tables_list]\n        return tables", "path": "mindsdb/integrations/clickhouse/clickhouse.py"}], "after_files": [{"content": "import requests\nfrom lightwood.api import dtype\nfrom mindsdb.integrations.base import Integration\nfrom mindsdb.utilities.log import log\n\n\nclass ClickhouseConnectionChecker:\n    def __init__(self, **kwargs):\n        self.host = kwargs.get(\"host\")\n        self.port = kwargs.get(\"port\")\n        self.user = kwargs.get(\"user\")\n        self.password = kwargs.get(\"password\")\n\n    def check_connection(self):\n        try:\n            res = requests.post(f\"http://{self.host}:{self.port}\",\n                                data=\"select 1;\",\n                                params={'user': self.user, 'password': self.password})\n            connected = res.status_code == 200\n        except Exception:\n            connected = False\n        return connected\n\n\nclass Clickhouse(Integration, ClickhouseConnectionChecker):\n    def __init__(self, config, name, db_info):\n        super().__init__(config, name)\n        self.user = db_info.get('user', 'default')\n        self.password = db_info.get('password', None)\n        self.host = db_info.get('host')\n        self.port = db_info.get('port')\n\n    def _to_clickhouse_table(self, dtype_dict, predicted_cols, columns):\n        subtype_map = {\n            dtype.integer: 'Nullable(Int64)',\n            dtype.float: 'Nullable(Float64)',\n            dtype.binary: 'Nullable(UInt8)',\n            dtype.date: 'Nullable(Date)',\n            dtype.datetime: 'Nullable(Datetime)',\n            dtype.binary: 'Nullable(String)',\n            dtype.categorical: 'Nullable(String)',\n            dtype.tags: 'Nullable(String)',\n            dtype.image: 'Nullable(String)',\n            dtype.video: 'Nullable(String)',\n            dtype.audio: 'Nullable(String)',\n            dtype.short_text: 'Nullable(String)',\n            dtype.rich_text: 'Nullable(String)',\n            dtype.array: 'Nullable(String)'\n        }\n\n        column_declaration = []\n        for name in columns:\n            try:\n                col_subtype = dtype_dict[name]\n                new_type = subtype_map[col_subtype]\n                column_declaration.append(f' `{name}` {new_type} ')\n                if name in predicted_cols:\n                    column_declaration.append(f' `{name}_original` {new_type} ')\n            except Exception as e:\n                log.error(f'Error: can not determine clickhouse data type for column {name}: {e}')\n\n        return column_declaration\n\n    def _query(self, query):\n        params = {'user': self.user}\n\n        if self.password is not None:\n            params['password'] = self.password\n\n        host = self.host\n        port = self.port\n\n        response = requests.post(f'http://{host}:{port}', data=query, params=params)\n\n        if response.status_code != 200:\n            raise Exception(f'Error: {response.content}\\nQuery:{query}')\n\n        return response\n\n    def _get_mysql_user(self):\n        return f\"{self.config['api']['mysql']['user']}_{self.name}\"\n\n    def _escape_table_name(self, name):\n        return '`' + name.replace('`', '\\\\`') + '`'\n\n    def setup(self):\n        self._query(f'DROP DATABASE IF EXISTS {self.mindsdb_database}')\n        self._query(f'CREATE DATABASE IF NOT EXISTS {self.mindsdb_database}')\n\n        msqyl_conn = self.config['api']['mysql']['host'] + ':' + str(self.config['api']['mysql']['port'])\n        msqyl_pass = self.config['api']['mysql']['password']\n        msqyl_user = self._get_mysql_user()\n\n        q = f\"\"\"\n            CREATE TABLE IF NOT EXISTS {self.mindsdb_database}.predictors (\n                name String,\n                status String,\n                accuracy String,\n                predict String,\n                select_data_query String,\n                external_datasource String,\n                training_options String\n                ) ENGINE=MySQL('{msqyl_conn}', 'mindsdb', 'predictors', '{msqyl_user}', '{msqyl_pass}')\n        \"\"\"\n        self._query(q)\n        q = f\"\"\"\n            CREATE TABLE IF NOT EXISTS {self.mindsdb_database}.commands (\n                command String\n            ) ENGINE=MySQL('{msqyl_conn}', 'mindsdb', 'commands', '{msqyl_user}', '{msqyl_pass}')\n        \"\"\"\n        self._query(q)\n\n    def register_predictors(self, model_data_arr):\n        for model_meta in model_data_arr:\n            name = self._escape_table_name(model_meta['name'])\n\n            predict = model_meta['predict']\n            if not isinstance(predict, list):\n                predict = [predict]\n\n            columns_sql = ','.join(self._to_clickhouse_table(\n                model_meta['dtype_dict'],\n                predict,\n                list(model_meta['dtype_dict'].keys())\n            ))\n            columns_sql += ',`when_data` Nullable(String)'\n            columns_sql += ',`select_data_query` Nullable(String)'\n            columns_sql += ',`external_datasource` Nullable(String)'\n            for col in predict:\n                columns_sql += f',`{col}_confidence` Nullable(Float64)'\n\n                if model_meta['dtype_dict'][col] in (dtype.integer, dtype.float):\n                    columns_sql += f',`{col}_min` Nullable(Float64)'\n                    columns_sql += f',`{col}_max` Nullable(Float64)'\n                columns_sql += f',`{col}_explain` Nullable(String)'\n\n            msqyl_conn = self.config['api']['mysql']['host'] + ':' + str(self.config['api']['mysql']['port'])\n            msqyl_pass = self.config['api']['mysql']['password']\n            msqyl_user = self._get_mysql_user()\n\n            self.unregister_predictor(model_meta['name'])\n            q = f\"\"\"\n                CREATE TABLE {self.mindsdb_database}.{name}\n                ({columns_sql}\n                ) ENGINE=MySQL('{msqyl_conn}', 'mindsdb', {name}, '{msqyl_user}', '{msqyl_pass}')\n            \"\"\"\n            self._query(q)\n\n    def unregister_predictor(self, name):\n        q = f\"\"\"\n            drop table if exists {self.mindsdb_database}.{self._escape_table_name(name)};\n        \"\"\"\n        self._query(q)\n\n    def get_tables_list(self):\n        q = f\"\"\"SELECT database, table\n                    FROM system.parts\n                    WHERE active and database NOT IN  ('system', 'mdb_system')\n                    GROUP BY database, table\n                    ORDER BY database, table;\"\"\"\n        tables_list = self._query(q)\n        tables= [f\"{table[0]}.{table[1]}\" for table in tables_list]\n        return tables\n\n    def get_columns(self,query):\n        q = f\"SELECT * FROM ({query}) LIMIT 1 FORMAT JSON\"\n        query_result = self._query(q).json()\n        columns_info = query_result['meta']\n        columns= [column['name'] for column in columns_info]\n        return columns\n\n", "path": "mindsdb/integrations/clickhouse/clickhouse.py"}]}