We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
bug: Combining union and order_by generates invalid BigQuery SQL
### What happened?

Hi Ibis team,

When applying union operation on table expression with order_by, it generates bad SQL.

A simple code piece can reproduce the issue:
```
import ibis

conn = ibis.bigquery.connect(
    project_id='garrettwu-test-project-2',
    dataset_id='bigquery-public-data.stackoverflow')

table = conn.table('posts_questions')

t = table.order_by("id")

unioned = ibis.union(t, t)

print(unioned.compile())

unioned.execute()
```
Generated SQL:
```
SELECT t0.*
FROM `bigquery-public-data.stackoverflow.posts_questions` t0
ORDER BY t0.`id` ASC
UNION ALL
SELECT t0.*
FROM `bigquery-public-data.stackoverflow.posts_questions` t0
ORDER BY t0.`id` ASC
```
Error:
```
BadRequest: 400 Syntax error: Expected end of input but got keyword UNION at [4:1]
```
(Full message in log output)

Same operation used to work for some previous commits.

### What version of ibis are you using?

master

Since the operation worked for versions sometime ago, we tried to run "git bisect" to locate the bad commit. It looks like https://github.com/ibis-project/ibis/pull/5571 is the one.

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

BigQuery

### Relevant log output

```sh
# Error Message
---------------------------------------------------------------------------
BadRequest                                Traceback (most recent call last)
Cell In[11], line 1
----> 1 unioned.execute()

File ~/src/ibis/ibis/expr/types/core.py:303, in Expr.execute(self, limit, timecontext, params, **kwargs)
    276 def execute(
    277     self,
    278     limit: int | str | None = 'default',
   (...)
    281     **kwargs: Any,
    282 ):
    283     """Execute an expression against its backend if one exists.
    284 
    285     Parameters
   (...)
    301         Keyword arguments
    302     """
--> 303     return self._find_backend(use_default=True).execute(
    304         self, limit=limit, timecontext=timecontext, params=params, **kwargs
    305     )

File ~/src/ibis/ibis/backends/bigquery/__init__.py:298, in Backend.execute(self, expr, params, limit, **kwargs)
    296 sql = query_ast.compile()
    297 self._log(sql)
--> 298 cursor = self.raw_sql(sql, params=params, **kwargs)
    299 schema = self.ast_schema(query_ast, **kwargs)
    300 result = self.fetch_from_cursor(cursor, schema)

File ~/src/ibis/ibis/backends/bigquery/__init__.py:255, in Backend.raw_sql(self, query, results, params)
    242 def raw_sql(self, query: str, results=False, params=None):
    243     query_parameters = [
    244         bigquery_param(
    245             param.type(),
   (...)
    253         for param, value in (params or {}).items()
    254     ]
--> 255     return self._execute(query, results=results, query_parameters=query_parameters)

File ~/src/ibis/ibis/backends/bigquery/__init__.py:239, in Backend._execute(self, stmt, results, query_parameters)
    235 job_config.use_legacy_sql = False  # False by default in >=0.28
    236 query = self.client.query(
    237     stmt, job_config=job_config, project=self.billing_project
    238 )
--> 239 query.result()  # blocks until finished
    240 return BigQueryCursor(query)

File ~/src/bigframes/venv/lib/python3.10/site-packages/google/cloud/bigquery/job/query.py:1499, in QueryJob.result(self, page_size, max_results, retry, timeout, start_index, job_retry)
   1496     if retry_do_query is not None and job_retry is not None:
   1497         do_get_result = job_retry(do_get_result)
-> 1499     do_get_result()
   1501 except exceptions.GoogleAPICallError as exc:
   1502     exc.message = _EXCEPTION_FOOTER_TEMPLATE.format(
   1503         message=exc.message, location=self.location, job_id=self.job_id
   1504     )

File ~/src/bigframes/venv/lib/python3.10/site-packages/google/api_core/retry.py:349, in Retry.__call__.<locals>.retry_wrapped_func(*args, **kwargs)
    345 target = functools.partial(func, *args, **kwargs)
    346 sleep_generator = exponential_sleep_generator(
    347     self._initial, self._maximum, multiplier=self._multiplier
    348 )
--> 349 return retry_target(
    350     target,
    351     self._predicate,
    352     sleep_generator,
    353     self._timeout,
    354     on_error=on_error,
    355 )

File ~/src/bigframes/venv/lib/python3.10/site-packages/google/api_core/retry.py:191, in retry_target(target, predicate, sleep_generator, timeout, on_error, **kwargs)
    189 for sleep in sleep_generator:
    190     try:
--> 191         return target()
    193     # pylint: disable=broad-except
    194     # This function explicitly must deal with broad exceptions.
    195     except Exception as exc:

File ~/src/bigframes/venv/lib/python3.10/site-packages/google/cloud/bigquery/job/query.py:1489, in QueryJob.result.<locals>.do_get_result()
   1486     self._retry_do_query = retry_do_query
   1487     self._job_retry = job_retry
-> 1489 super(QueryJob, self).result(retry=retry, timeout=timeout)
   1491 # Since the job could already be "done" (e.g. got a finished job
   1492 # via client.get_job), the superclass call to done() might not
   1493 # set the self._query_results cache.
   1494 self._reload_query_results(retry=retry, timeout=timeout)

File ~/src/bigframes/venv/lib/python3.10/site-packages/google/cloud/bigquery/job/base.py:728, in _AsyncJob.result(self, retry, timeout)
    725     self._begin(retry=retry, timeout=timeout)
    727 kwargs = {} if retry is DEFAULT_RETRY else {"retry": retry}
--> 728 return super(_AsyncJob, self).result(timeout=timeout, **kwargs)

File ~/src/bigframes/venv/lib/python3.10/site-packages/google/api_core/future/polling.py:261, in PollingFuture.result(self, timeout, retry, polling)
    256 self._blocking_poll(timeout=timeout, retry=retry, polling=polling)
    258 if self._exception is not None:
    259     # pylint: disable=raising-bad-type
    260     # Pylint doesn't recognize that this is valid in this case.
--> 261     raise self._exception
    263 return self._result

BadRequest: 400 Syntax error: Expected end of input but got keyword UNION at [4:1]

Location: US
Job ID: 7d6ccc8d-f948-4d60-b681-7a23eb5179da
```


### Code of Conduct

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

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `ibis/backends/base/sql/compiler/base.py`
Content:
```
1 from __future__ import annotations
2 
3 import abc
4 from itertools import chain
5 
6 import toolz
7 
8 import ibis.expr.analysis as an
9 import ibis.expr.operations as ops
10 from ibis import util
11 
12 
13 class DML(abc.ABC):
14     @abc.abstractmethod
15     def compile(self):
16         pass
17 
18 
19 class DDL(abc.ABC):
20     @abc.abstractmethod
21     def compile(self):
22         pass
23 
24 
25 class QueryAST:
26     __slots__ = 'context', 'dml', 'setup_queries', 'teardown_queries'
27 
28     def __init__(self, context, dml, setup_queries=None, teardown_queries=None):
29         self.context = context
30         self.dml = dml
31         self.setup_queries = setup_queries
32         self.teardown_queries = teardown_queries
33 
34     @property
35     def queries(self):
36         return [self.dml]
37 
38     def compile(self):
39         compiled_setup_queries = [q.compile() for q in self.setup_queries]
40         compiled_queries = [q.compile() for q in self.queries]
41         compiled_teardown_queries = [q.compile() for q in self.teardown_queries]
42         return self.context.collapse(
43             list(
44                 chain(
45                     compiled_setup_queries,
46                     compiled_queries,
47                     compiled_teardown_queries,
48                 )
49             )
50         )
51 
52 
53 class SetOp(DML):
54     def __init__(self, tables, node, context, distincts):
55         assert isinstance(node, ops.Node)
56         assert all(isinstance(table, ops.Node) for table in tables)
57         self.context = context
58         self.tables = tables
59         self.table_set = node
60         self.distincts = distincts
61         self.filters = []
62 
63     @classmethod
64     def keyword(cls, distinct):
65         return cls._keyword + (not distinct) * " ALL"
66 
67     def _get_keyword_list(self):
68         return map(self.keyword, self.distincts)
69 
70     def _extract_subqueries(self):
71         self.subqueries = an.find_subqueries(
72             [self.table_set, *self.filters], min_dependents=2
73         )
74         for subquery in self.subqueries:
75             self.context.set_extracted(subquery)
76 
77     def format_subqueries(self):
78         context = self.context
79         subqueries = self.subqueries
80 
81         return ',\n'.join(
82             '{} AS (\n{}\n)'.format(
83                 context.get_ref(expr),
84                 util.indent(context.get_compiled_expr(expr), 2),
85             )
86             for expr in subqueries
87         )
88 
89     def format_relation(self, expr):
90         ref = self.context.get_ref(expr)
91         if ref is not None:
92             return f'SELECT *\nFROM {ref}'
93         return self.context.get_compiled_expr(expr)
94 
95     def compile(self):
96         self._extract_subqueries()
97 
98         extracted = self.format_subqueries()
99 
100         buf = []
101 
102         if extracted:
103             buf.append(f'WITH {extracted}')
104 
105         buf.extend(
106             toolz.interleave(
107                 (
108                     map(self.format_relation, self.tables),
109                     self._get_keyword_list(),
110                 )
111             )
112         )
113         return '\n'.join(buf)
114
```
--- 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/ibis/backends/base/sql/compiler/base.py b/ibis/backends/base/sql/compiler/base.py
--- a/ibis/backends/base/sql/compiler/base.py
+++ b/ibis/backends/base/sql/compiler/base.py
@@ -68,8 +68,12 @@
         return map(self.keyword, self.distincts)
 
     def _extract_subqueries(self):
+        # extract any subquery to avoid generating incorrect sql when at least
+        # one of the set operands is invalid outside of being a subquery
+        #
+        # for example: SELECT * FROM t ORDER BY x UNION ...
         self.subqueries = an.find_subqueries(
-            [self.table_set, *self.filters], min_dependents=2
+            [self.table_set, *self.filters], min_dependents=1
         )
         for subquery in self.subqueries:
             self.context.set_extracted(subquery)

{"golden_diff": "diff --git a/ibis/backends/base/sql/compiler/base.py b/ibis/backends/base/sql/compiler/base.py\n--- a/ibis/backends/base/sql/compiler/base.py\n+++ b/ibis/backends/base/sql/compiler/base.py\n@@ -68,8 +68,12 @@\n         return map(self.keyword, self.distincts)\n \n     def _extract_subqueries(self):\n+        # extract any subquery to avoid generating incorrect sql when at least\n+        # one of the set operands is invalid outside of being a subquery\n+        #\n+        # for example: SELECT * FROM t ORDER BY x UNION ...\n         self.subqueries = an.find_subqueries(\n-            [self.table_set, *self.filters], min_dependents=2\n+            [self.table_set, *self.filters], min_dependents=1\n         )\n         for subquery in self.subqueries:\n             self.context.set_extracted(subquery)\n", "issue": "bug: Combining union and order_by generates invalid BigQuery SQL\n### What happened?\n\nHi Ibis team,\r\n\r\nWhen applying union operation on table expression with order_by, it generates bad SQL.\r\n\r\nA simple code piece can reproduce the issue:\r\n```\r\nimport ibis\r\n\r\nconn = ibis.bigquery.connect(\r\n    project_id='garrettwu-test-project-2',\r\n    dataset_id='bigquery-public-data.stackoverflow')\r\n\r\ntable = conn.table('posts_questions')\r\n\r\nt = table.order_by(\"id\")\r\n\r\nunioned = ibis.union(t, t)\r\n\r\nprint(unioned.compile())\r\n\r\nunioned.execute()\r\n```\r\nGenerated SQL:\r\n```\r\nSELECT t0.*\r\nFROM `bigquery-public-data.stackoverflow.posts_questions` t0\r\nORDER BY t0.`id` ASC\r\nUNION ALL\r\nSELECT t0.*\r\nFROM `bigquery-public-data.stackoverflow.posts_questions` t0\r\nORDER BY t0.`id` ASC\r\n```\r\nError:\r\n```\r\nBadRequest: 400 Syntax error: Expected end of input but got keyword UNION at [4:1]\r\n```\r\n(Full message in log output)\r\n\r\nSame operation used to work for some previous commits.\n\n### What version of ibis are you using?\n\nmaster\r\n\r\nSince the operation worked for versions sometime ago, we tried to run \"git bisect\" to locate the bad commit. It looks like https://github.com/ibis-project/ibis/pull/5571 is the one.\n\n### What backend(s) are you using, if any?\n\nBigQuery\n\n### Relevant log output\n\n```sh\n# Error Message\r\n---------------------------------------------------------------------------\r\nBadRequest                                Traceback (most recent call last)\r\nCell In[11], line 1\r\n----> 1 unioned.execute()\r\n\r\nFile ~/src/ibis/ibis/expr/types/core.py:303, in Expr.execute(self, limit, timecontext, params, **kwargs)\r\n    276 def execute(\r\n    277     self,\r\n    278     limit: int | str | None = 'default',\r\n   (...)\r\n    281     **kwargs: Any,\r\n    282 ):\r\n    283     \"\"\"Execute an expression against its backend if one exists.\r\n    284 \r\n    285     Parameters\r\n   (...)\r\n    301         Keyword arguments\r\n    302     \"\"\"\r\n--> 303     return self._find_backend(use_default=True).execute(\r\n    304         self, limit=limit, timecontext=timecontext, params=params, **kwargs\r\n    305     )\r\n\r\nFile ~/src/ibis/ibis/backends/bigquery/__init__.py:298, in Backend.execute(self, expr, params, limit, **kwargs)\r\n    296 sql = query_ast.compile()\r\n    297 self._log(sql)\r\n--> 298 cursor = self.raw_sql(sql, params=params, **kwargs)\r\n    299 schema = self.ast_schema(query_ast, **kwargs)\r\n    300 result = self.fetch_from_cursor(cursor, schema)\r\n\r\nFile ~/src/ibis/ibis/backends/bigquery/__init__.py:255, in Backend.raw_sql(self, query, results, params)\r\n    242 def raw_sql(self, query: str, results=False, params=None):\r\n    243     query_parameters = [\r\n    244         bigquery_param(\r\n    245             param.type(),\r\n   (...)\r\n    253         for param, value in (params or {}).items()\r\n    254     ]\r\n--> 255     return self._execute(query, results=results, query_parameters=query_parameters)\r\n\r\nFile ~/src/ibis/ibis/backends/bigquery/__init__.py:239, in Backend._execute(self, stmt, results, query_parameters)\r\n    235 job_config.use_legacy_sql = False  # False by default in >=0.28\r\n    236 query = self.client.query(\r\n    237     stmt, job_config=job_config, project=self.billing_project\r\n    238 )\r\n--> 239 query.result()  # blocks until finished\r\n    240 return BigQueryCursor(query)\r\n\r\nFile ~/src/bigframes/venv/lib/python3.10/site-packages/google/cloud/bigquery/job/query.py:1499, in QueryJob.result(self, page_size, max_results, retry, timeout, start_index, job_retry)\r\n   1496     if retry_do_query is not None and job_retry is not None:\r\n   1497         do_get_result = job_retry(do_get_result)\r\n-> 1499     do_get_result()\r\n   1501 except exceptions.GoogleAPICallError as exc:\r\n   1502     exc.message = _EXCEPTION_FOOTER_TEMPLATE.format(\r\n   1503         message=exc.message, location=self.location, job_id=self.job_id\r\n   1504     )\r\n\r\nFile ~/src/bigframes/venv/lib/python3.10/site-packages/google/api_core/retry.py:349, in Retry.__call__.<locals>.retry_wrapped_func(*args, **kwargs)\r\n    345 target = functools.partial(func, *args, **kwargs)\r\n    346 sleep_generator = exponential_sleep_generator(\r\n    347     self._initial, self._maximum, multiplier=self._multiplier\r\n    348 )\r\n--> 349 return retry_target(\r\n    350     target,\r\n    351     self._predicate,\r\n    352     sleep_generator,\r\n    353     self._timeout,\r\n    354     on_error=on_error,\r\n    355 )\r\n\r\nFile ~/src/bigframes/venv/lib/python3.10/site-packages/google/api_core/retry.py:191, in retry_target(target, predicate, sleep_generator, timeout, on_error, **kwargs)\r\n    189 for sleep in sleep_generator:\r\n    190     try:\r\n--> 191         return target()\r\n    193     # pylint: disable=broad-except\r\n    194     # This function explicitly must deal with broad exceptions.\r\n    195     except Exception as exc:\r\n\r\nFile ~/src/bigframes/venv/lib/python3.10/site-packages/google/cloud/bigquery/job/query.py:1489, in QueryJob.result.<locals>.do_get_result()\r\n   1486     self._retry_do_query = retry_do_query\r\n   1487     self._job_retry = job_retry\r\n-> 1489 super(QueryJob, self).result(retry=retry, timeout=timeout)\r\n   1491 # Since the job could already be \"done\" (e.g. got a finished job\r\n   1492 # via client.get_job), the superclass call to done() might not\r\n   1493 # set the self._query_results cache.\r\n   1494 self._reload_query_results(retry=retry, timeout=timeout)\r\n\r\nFile ~/src/bigframes/venv/lib/python3.10/site-packages/google/cloud/bigquery/job/base.py:728, in _AsyncJob.result(self, retry, timeout)\r\n    725     self._begin(retry=retry, timeout=timeout)\r\n    727 kwargs = {} if retry is DEFAULT_RETRY else {\"retry\": retry}\r\n--> 728 return super(_AsyncJob, self).result(timeout=timeout, **kwargs)\r\n\r\nFile ~/src/bigframes/venv/lib/python3.10/site-packages/google/api_core/future/polling.py:261, in PollingFuture.result(self, timeout, retry, polling)\r\n    256 self._blocking_poll(timeout=timeout, retry=retry, polling=polling)\r\n    258 if self._exception is not None:\r\n    259     # pylint: disable=raising-bad-type\r\n    260     # Pylint doesn't recognize that this is valid in this case.\r\n--> 261     raise self._exception\r\n    263 return self._result\r\n\r\nBadRequest: 400 Syntax error: Expected end of input but got keyword UNION at [4:1]\r\n\r\nLocation: US\r\nJob ID: 7d6ccc8d-f948-4d60-b681-7a23eb5179da\n```\n\n\n### Code of Conduct\n\n- [X] I agree to follow this project's Code of Conduct\n", "before_files": [{"content": "from __future__ import annotations\n\nimport abc\nfrom itertools import chain\n\nimport toolz\n\nimport ibis.expr.analysis as an\nimport ibis.expr.operations as ops\nfrom ibis import util\n\n\nclass DML(abc.ABC):\n    @abc.abstractmethod\n    def compile(self):\n        pass\n\n\nclass DDL(abc.ABC):\n    @abc.abstractmethod\n    def compile(self):\n        pass\n\n\nclass QueryAST:\n    __slots__ = 'context', 'dml', 'setup_queries', 'teardown_queries'\n\n    def __init__(self, context, dml, setup_queries=None, teardown_queries=None):\n        self.context = context\n        self.dml = dml\n        self.setup_queries = setup_queries\n        self.teardown_queries = teardown_queries\n\n    @property\n    def queries(self):\n        return [self.dml]\n\n    def compile(self):\n        compiled_setup_queries = [q.compile() for q in self.setup_queries]\n        compiled_queries = [q.compile() for q in self.queries]\n        compiled_teardown_queries = [q.compile() for q in self.teardown_queries]\n        return self.context.collapse(\n            list(\n                chain(\n                    compiled_setup_queries,\n                    compiled_queries,\n                    compiled_teardown_queries,\n                )\n            )\n        )\n\n\nclass SetOp(DML):\n    def __init__(self, tables, node, context, distincts):\n        assert isinstance(node, ops.Node)\n        assert all(isinstance(table, ops.Node) for table in tables)\n        self.context = context\n        self.tables = tables\n        self.table_set = node\n        self.distincts = distincts\n        self.filters = []\n\n    @classmethod\n    def keyword(cls, distinct):\n        return cls._keyword + (not distinct) * \" ALL\"\n\n    def _get_keyword_list(self):\n        return map(self.keyword, self.distincts)\n\n    def _extract_subqueries(self):\n        self.subqueries = an.find_subqueries(\n            [self.table_set, *self.filters], min_dependents=2\n        )\n        for subquery in self.subqueries:\n            self.context.set_extracted(subquery)\n\n    def format_subqueries(self):\n        context = self.context\n        subqueries = self.subqueries\n\n        return ',\\n'.join(\n            '{} AS (\\n{}\\n)'.format(\n                context.get_ref(expr),\n                util.indent(context.get_compiled_expr(expr), 2),\n            )\n            for expr in subqueries\n        )\n\n    def format_relation(self, expr):\n        ref = self.context.get_ref(expr)\n        if ref is not None:\n            return f'SELECT *\\nFROM {ref}'\n        return self.context.get_compiled_expr(expr)\n\n    def compile(self):\n        self._extract_subqueries()\n\n        extracted = self.format_subqueries()\n\n        buf = []\n\n        if extracted:\n            buf.append(f'WITH {extracted}')\n\n        buf.extend(\n            toolz.interleave(\n                (\n                    map(self.format_relation, self.tables),\n                    self._get_keyword_list(),\n                )\n            )\n        )\n        return '\\n'.join(buf)\n", "path": "ibis/backends/base/sql/compiler/base.py"}], "after_files": [{"content": "from __future__ import annotations\n\nimport abc\nfrom itertools import chain\n\nimport toolz\n\nimport ibis.expr.analysis as an\nimport ibis.expr.operations as ops\nfrom ibis import util\n\n\nclass DML(abc.ABC):\n    @abc.abstractmethod\n    def compile(self):\n        pass\n\n\nclass DDL(abc.ABC):\n    @abc.abstractmethod\n    def compile(self):\n        pass\n\n\nclass QueryAST:\n    __slots__ = 'context', 'dml', 'setup_queries', 'teardown_queries'\n\n    def __init__(self, context, dml, setup_queries=None, teardown_queries=None):\n        self.context = context\n        self.dml = dml\n        self.setup_queries = setup_queries\n        self.teardown_queries = teardown_queries\n\n    @property\n    def queries(self):\n        return [self.dml]\n\n    def compile(self):\n        compiled_setup_queries = [q.compile() for q in self.setup_queries]\n        compiled_queries = [q.compile() for q in self.queries]\n        compiled_teardown_queries = [q.compile() for q in self.teardown_queries]\n        return self.context.collapse(\n            list(\n                chain(\n                    compiled_setup_queries,\n                    compiled_queries,\n                    compiled_teardown_queries,\n                )\n            )\n        )\n\n\nclass SetOp(DML):\n    def __init__(self, tables, node, context, distincts):\n        assert isinstance(node, ops.Node)\n        assert all(isinstance(table, ops.Node) for table in tables)\n        self.context = context\n        self.tables = tables\n        self.table_set = node\n        self.distincts = distincts\n        self.filters = []\n\n    @classmethod\n    def keyword(cls, distinct):\n        return cls._keyword + (not distinct) * \" ALL\"\n\n    def _get_keyword_list(self):\n        return map(self.keyword, self.distincts)\n\n    def _extract_subqueries(self):\n        # extract any subquery to avoid generating incorrect sql when at least\n        # one of the set operands is invalid outside of being a subquery\n        #\n        # for example: SELECT * FROM t ORDER BY x UNION ...\n        self.subqueries = an.find_subqueries(\n            [self.table_set, *self.filters], min_dependents=1\n        )\n        for subquery in self.subqueries:\n            self.context.set_extracted(subquery)\n\n    def format_subqueries(self):\n        context = self.context\n        subqueries = self.subqueries\n\n        return ',\\n'.join(\n            '{} AS (\\n{}\\n)'.format(\n                context.get_ref(expr),\n                util.indent(context.get_compiled_expr(expr), 2),\n            )\n            for expr in subqueries\n        )\n\n    def format_relation(self, expr):\n        ref = self.context.get_ref(expr)\n        if ref is not None:\n            return f'SELECT *\\nFROM {ref}'\n        return self.context.get_compiled_expr(expr)\n\n    def compile(self):\n        self._extract_subqueries()\n\n        extracted = self.format_subqueries()\n\n        buf = []\n\n        if extracted:\n            buf.append(f'WITH {extracted}')\n\n        buf.extend(\n            toolz.interleave(\n                (\n                    map(self.format_relation, self.tables),\n                    self._get_keyword_list(),\n                )\n            )\n        )\n        return '\\n'.join(buf)\n", "path": "ibis/backends/base/sql/compiler/base.py"}]}