Repository: tobymao/sqlglot

Issue:
planner ignores subqueries
```sql
SELECT *
FROM star1
WHERE `f` > (
  SELECT avg(`f`) AS `mean`
  FROM star1
)
```

output plan after 

```py
expr = sg.parse_one(sqlstring, dialect)
tree = sgo.optimize(expr, catalog.to_sqlglot(), rules=sgo.RULES)
plan = sgp.Plan(tree)
print(plan.root)
```

```
- Scan: star1
    Context:
      Source: "star1" AS "star1"
    Projections:
      - "star1"."c" AS "c"
      - "star1"."f" AS "f"
      - "star1"."foo_id" AS "foo_id"
      - "star1"."bar_id" AS "bar_id"
    Condition: "star1"."f" > (SELECT AVG("star1"."f") AS "mean" FROM "star1" AS "star1")
```

I'd expect the select to be converted as an aggregate dependency of the root scan.


Discussion:
subqueries are not supported yet

Resolving patch:
diff --git a/sqlglot/executor/env.py b/sqlglot/executor/env.py
--- a/sqlglot/executor/env.py
+++ b/sqlglot/executor/env.py
@@ -122,7 +122,6 @@ def interval(this, unit):
 
 
 ENV = {
-    "__builtins__": {},
     "exp": exp,
     # aggs
     "SUM": filter_nulls(sum),
diff --git a/sqlglot/executor/python.py b/sqlglot/executor/python.py
--- a/sqlglot/executor/python.py
+++ b/sqlglot/executor/python.py
@@ -404,6 +404,7 @@ class Generator(generator.Generator):
             exp.Boolean: lambda self, e: "True" if e.this else "False",
             exp.Cast: lambda self, e: f"CAST({self.sql(e.this)}, exp.DataType.Type.{e.args['to']})",
             exp.Column: lambda self, e: f"scope[{self.sql(e, 'table') or None}][{self.sql(e.this)}]",
+            exp.Distinct: lambda self, e: f"set({self.sql(e, 'this')})",
             exp.Extract: lambda self, e: f"EXTRACT('{e.name.lower()}', {self.sql(e, 'expression')})",
             exp.In: lambda self, e: f"{self.sql(e, 'this')} in ({self.expressions(e, flat=True)})",
             exp.Is: lambda self, e: self.binary(e, "is"),
diff --git a/sqlglot/planner.py b/sqlglot/planner.py
--- a/sqlglot/planner.py
+++ b/sqlglot/planner.py
@@ -262,12 +262,7 @@ def from_expression(
         cls, expression: exp.Expression, ctes: t.Optional[t.Dict[str, Step]] = None
     ) -> Step:
         table = expression
-        alias_ = expression.alias
-
-        if not alias_:
-            raise UnsupportedError(
-                "Tables/Subqueries must be aliased. Run it through the optimizer"
-            )
+        alias_ = expression.alias_or_name
 
         if isinstance(expression, exp.Subquery):
             table = expression.this


Test patch:
diff --git a/tests/test_executor.py b/tests/test_executor.py
--- a/tests/test_executor.py
+++ b/tests/test_executor.py
@@ -68,13 +68,13 @@ def test_optimized_tpch(self):
 
     def test_execute_tpch(self):
         def to_csv(expression):
-            if isinstance(expression, exp.Table):
+            if isinstance(expression, exp.Table) and expression.name not in ("revenue"):
                 return parse_one(
                     f"READ_CSV('{DIR}{expression.name}.csv.gz', 'delimiter', '|') AS {expression.alias_or_name}"
                 )
             return expression
 
-        for i, (sql, _) in enumerate(self.sqls[0:14]):
+        for i, (sql, _) in enumerate(self.sqls[0:16]):
             with self.subTest(f"tpch-h {i + 1}"):
                 a = self.cached_execute(sql)
                 sql = parse_one(sql).transform(to_csv).sql(pretty=True)
@@ -484,6 +484,12 @@ def test_scalar_functions(self):
             ("IF(false, 1, 0)", 0),
             ("CASE WHEN 0 = 1 THEN 'foo' ELSE 'bar' END", "bar"),
             ("CAST('2022-01-01' AS DATE) + INTERVAL '1' DAY", date(2022, 1, 2)),
+            ("1 IN (1, 2, 3)", True),
+            ("1 IN (2, 3)", False),
+            ("NULL IS NULL", True),
+            ("NULL IS NOT NULL", False),
+            ("NULL = NULL", None),
+            ("NULL <> NULL", None),
         ]:
             with self.subTest(sql):
                 result = execute(f"SELECT {sql}")