Repository: ibis-project/ibis

Issue:
bug: Can't execute sql string with clickhouse
### What happened?

With this line of code, where items is an arbitrary table
```py
item.sql("select * from items limit 10")
```
I get
```
DatabaseError: :HTTPDriver for server:port returned response code 404)
Unknown setting "json" for EXPLAIN PLAN query. Supported settings: actions, description, header
```

### What version of ibis are you using?

7.1.0

### What backend(s) are you using, if any?

Clickhouse 20.9.3.45 (official build)

### Relevant log output

_No response_

### Code of Conduct

- [X] I agree to follow this project's Code of Conduct


Discussion:
Thanks for the issue. I suspect that the version of ClickHouse you are on doesn't support `EXPLAIN` in JSON format.

I believe we can adjust our use of this to avoid needing the JSON output.
@Ssslakter Any chance it's possible for you to upgrade to a version of clickhouse that supports `EXPLAIN` with JSON formatting?
Unfortunately there are not enough resources to migrate all the data at this point. (also considering that usual way sql from clickhouse client works well enough, though not as pretty as ibis interfaces) 
So I guess I'll close the issue on this topic.

By the way, taking the opportunity to ask, is it possible to express this part of clickhouse sql in ibis without raw sql?
```sql
where toYYYYMMDD(date) between 20230210 and 20230101 -- or similarly toYYYYMM(date)
-- and
select groupUniqArray(20)(replaceRegexpAll(table.name, '[^\w]|\d{20,}', ' ')) from table group by date
```
@Ssslakter We're not opposed to altering the way we get metadata, we were simply wondering whether there was an alternative solution.

Let's keep this issue open, as we have had other clickhouse compatibility issues in the past and this one is probably low-hanging fruit.

Resolving patch:
diff --git a/ibis/backends/clickhouse/__init__.py b/ibis/backends/clickhouse/__init__.py
--- a/ibis/backends/clickhouse/__init__.py
+++ b/ibis/backends/clickhouse/__init__.py
@@ -3,7 +3,6 @@
 import ast
 import atexit
 import glob
-import json
 from contextlib import closing, suppress
 from functools import partial
 from typing import TYPE_CHECKING, Any, Literal
@@ -516,16 +515,16 @@ def get_schema(self, table_name: str, database: str | None = None) -> sch.Schema
         return sch.Schema(dict(zip(names, map(ClickhouseType.from_string, types))))
 
     def _get_schema_using_query(self, query: str) -> sch.Schema:
-        query = f"EXPLAIN json = 1, description = 0, header = 1 {query}"
-        with closing(self.raw_sql(query)) as results:
-            [[raw_plans]] = results.result_columns
-        [plan] = json.loads(raw_plans)
-        return sch.Schema(
-            {
-                field["Name"]: ClickhouseType.from_string(field["Type"])
-                for field in plan["Plan"]["Header"]
-            }
-        )
+        name = util.gen_name("get_schema_using_query")
+        with closing(self.raw_sql(f"CREATE VIEW {name} AS {query}")):
+            pass
+        try:
+            with closing(self.raw_sql(f"DESCRIBE {name}")) as results:
+                names, types, *_ = results.result_columns
+        finally:
+            with closing(self.raw_sql(f"DROP VIEW {name}")):
+                pass
+        return sch.Schema(dict(zip(names, map(ClickhouseType.from_string, types))))
 
     @classmethod
     def has_operation(cls, operation: type[ops.Value]) -> bool:


Test patch: