Repository: tobymao/sqlglot

Issue:
Unexpected `AttributeError` from `parse_one`
Running the following raises `AttributeError: 'NoneType' object has no attribute 'type'`

```py
import sqlglot

sql = 'Ā[:'

sqlglot.parse_one(sql, dialect='postgres')
```

I would expect a `ParseError` (and indeed that's what I get when using `transpile`).

Goes with out saying that this was again picked out by [hypothesis](https://hypothesis.readthedocs.io/en/latest/).

I'm using sqlglot version: 18.16.1 on Python 3.11.6.

<details>

<summary>Traceback:</summary>

```
(env311) code/pydantic-data-platform 1 ➤ python test.py
Traceback (most recent call last):
  File ".../test.py", line 5, in <module>
    sqlglot.parse_one(sql, dialect='postgres')
  File ".../env311/lib/python3.11/site-packages/sqlglot/__init__.py", line 125, in parse_one
    result = dialect.parse(sql, **opts)
             ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/dialects/dialect.py", line 311, in parse
    return self.parser(**opts).parse(self.tokenize(sql), sql)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 985, in parse
    return self._parse(
           ^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 1051, in _parse
    expressions.append(parse_method(self))
                       ^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 1240, in _parse_statement
    expression = self._parse_expression()
                 ^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 3174, in _parse_expression
    return self._parse_alias(self._parse_conjunction())
                             ^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 3177, in _parse_conjunction
    return self._parse_tokens(self._parse_equality, self.CONJUNCTION)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 4813, in _parse_tokens
    this = parse_method()
           ^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 3180, in _parse_equality
    return self._parse_tokens(self._parse_comparison, self.EQUALITY)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 4813, in _parse_tokens
    this = parse_method()
           ^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 3183, in _parse_comparison
    return self._parse_tokens(self._parse_range, self.COMPARISON)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 4813, in _parse_tokens
    this = parse_method()
           ^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 3186, in _parse_range
    this = self._parse_bitwise()
           ^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 3293, in _parse_bitwise
    this = self._parse_term()
           ^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 3318, in _parse_term
    return self._parse_tokens(self._parse_factor, self.TERM)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 4813, in _parse_tokens
    this = parse_method()
           ^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/dialects/postgres.py", line 346, in _parse_factor
    return self._parse_tokens(self._parse_exponent, self.FACTOR)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 4813, in _parse_tokens
    this = parse_method()
           ^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/dialects/postgres.py", line 349, in _parse_exponent
    return self._parse_tokens(self._parse_unary, self.EXPONENT)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 4813, in _parse_tokens
    this = parse_method()
           ^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 3326, in _parse_unary
    return self._parse_at_time_zone(self._parse_type())
                                    ^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 3335, in _parse_type
    this = self._parse_column()
           ^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 3520, in _parse_column
    return self._parse_column_ops(this)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 3523, in _parse_column_ops
    this = self._parse_bracket(this)
           ^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/parser.py", line 4059, in _parse_bracket
    expressions = apply_index_offset(this, expressions, -self.INDEX_OFFSET)
                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/helper.py", line 184, in apply_index_offset
    annotate_types(expression)
  File ".../env311/lib/python3.11/site-packages/sqlglot/optimizer/annotate_types.py", line 56, in annotate_types
    return TypeAnnotator(schema, annotators, coerces_to).annotate(expression)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/optimizer/annotate_types.py", line 383, in annotate
    return self._maybe_annotate(expression)  # This takes care of non-traversable expressions
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/optimizer/annotate_types.py", line 392, in _maybe_annotate
    annotator(self, expression)
  File ".../env311/lib/python3.11/site-packages/sqlglot/optimizer/annotate_types.py", line 262, in <lambda>
    expr_type: lambda self, e: self._annotate_binary(e)
                               ^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../env311/lib/python3.11/site-packages/sqlglot/optimizer/annotate_types.py", line 431, in _annotate_binary
    left_type, right_type = left.type.this, right.type.this
                            ^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'type'
```

</details>


Discussion:

Resolving patch:
diff --git a/sqlglot/optimizer/annotate_types.py b/sqlglot/optimizer/annotate_types.py
--- a/sqlglot/optimizer/annotate_types.py
+++ b/sqlglot/optimizer/annotate_types.py
@@ -287,6 +287,7 @@ class TypeAnnotator(metaclass=_TypeAnnotator):
         exp.Max: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
         exp.Min: lambda self, e: self._annotate_by_args(e, "this", "expressions"),
         exp.Null: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.NULL),
+        exp.Slice: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.UNKNOWN),
         exp.Sum: lambda self, e: self._annotate_by_args(e, "this", "expressions", promote=True),
         exp.TryCast: lambda self, e: self._annotate_with_type(e, e.args["to"]),
         exp.VarMap: lambda self, e: self._annotate_with_type(e, exp.DataType.Type.MAP),
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -4050,6 +4050,11 @@ def _parse_bracket(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Exp
                 )
             )
 
+        if not self._match(TokenType.R_BRACKET) and bracket_kind == TokenType.L_BRACKET:
+            self.raise_error("Expected ]")
+        elif not self._match(TokenType.R_BRACE) and bracket_kind == TokenType.L_BRACE:
+            self.raise_error("Expected }")
+
         # https://duckdb.org/docs/sql/data_types/struct.html#creating-structs
         if bracket_kind == TokenType.L_BRACE:
             this = self.expression(exp.Struct, expressions=expressions)
@@ -4059,11 +4064,6 @@ def _parse_bracket(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Exp
             expressions = apply_index_offset(this, expressions, -self.INDEX_OFFSET)
             this = self.expression(exp.Bracket, this=this, expressions=expressions)
 
-        if not self._match(TokenType.R_BRACKET) and bracket_kind == TokenType.L_BRACKET:
-            self.raise_error("Expected ]")
-        elif not self._match(TokenType.R_BRACE) and bracket_kind == TokenType.L_BRACE:
-            self.raise_error("Expected }")
-
         self._add_comments(this)
         return self._parse_bracket(this)
 


Test patch:
diff --git a/tests/test_optimizer.py b/tests/test_optimizer.py
--- a/tests/test_optimizer.py
+++ b/tests/test_optimizer.py
@@ -550,6 +550,11 @@ def test_binary_annotation(self):
         self.assertEqual(expression.right.this.left.type.this, exp.DataType.Type.INT)
         self.assertEqual(expression.right.this.right.type.this, exp.DataType.Type.INT)
 
+        expression = annotate_types(parse_one("SELECT A[:]")).expressions[0]
+
+        self.assertEqual(expression.type.this, exp.DataType.Type.UNKNOWN)
+        self.assertEqual(expression.expressions[0].type.this, exp.DataType.Type.UNKNOWN)
+
     def test_interval_math_annotation(self):
         schema = {
             "x": {
diff --git a/tests/test_parser.py b/tests/test_parser.py
--- a/tests/test_parser.py
+++ b/tests/test_parser.py
@@ -234,6 +234,9 @@ def test_parse_errors(self):
             "CREATE TABLE t (i UInt8) ENGINE=AggregatingMergeTree() ORDER BY tuple()",
         )
 
+        with self.assertRaises(ParseError):
+            parse_one("SELECT A[:")
+
     def test_space(self):
         self.assertEqual(
             parse_one("SELECT ROW() OVER(PARTITION  BY x) FROM x GROUP  BY y").sql(),