Repository: tobymao/sqlglot

Issue:
Dialect: trino(presto), apply_index_offset (in the parse_one function) get wrong result
**Version**
sqlglot 25.4.0

**Fully reproducible code snippet**

``` Python
import sqlglot

sql = "select REPLACE(SPLIT(begin_time, ' ')[1], '-', '')"
sqlglot.parse_one(ss, dialect='trino').sql()
```

**Error message**
the result is `REPLACE(SPLIT(begin_time, ' ')[0], '-', '')`,
which is incorrect



Discussion:

Patch:
diff --git a/sqlglot/dialects/tsql.py b/sqlglot/dialects/tsql.py
index ca082cd9..d0b29b69 100644
--- a/sqlglot/dialects/tsql.py
+++ b/sqlglot/dialects/tsql.py
@@ -524,15 +524,6 @@ class TSQL(Dialect):
             "TIMEFROMPARTS": _build_timefromparts,
         }
 
-        RANGE_PARSERS = {
-            **parser.Parser.RANGE_PARSERS,
-            TokenType.DCOLON: lambda self, this: self.expression(
-                exp.ScopeResolution,
-                this=this,
-                expression=self._parse_function() or self._parse_var(any_token=True),
-            ),
-        }
-
         JOIN_HINTS = {"LOOP", "HASH", "MERGE", "REMOTE"}
 
         RETURNS_TABLE_TOKENS = parser.Parser.ID_VAR_TOKENS - {
@@ -545,9 +536,25 @@ class TSQL(Dialect):
             TokenType.DECLARE: lambda self: self._parse_declare(),
         }
 
+        RANGE_PARSERS = {
+            **parser.Parser.RANGE_PARSERS,
+            TokenType.DCOLON: lambda self, this: self.expression(
+                exp.ScopeResolution,
+                this=this,
+                expression=self._parse_function() or self._parse_var(any_token=True),
+            ),
+        }
+
         # The DCOLON (::) operator serves as a scope resolution (exp.ScopeResolution) operator in T-SQL
-        COLUMN_OPERATORS = parser.Parser.COLUMN_OPERATORS.copy()
-        COLUMN_OPERATORS.pop(TokenType.DCOLON)
+        COLUMN_OPERATORS = {
+            **parser.Parser.COLUMN_OPERATORS,
+            TokenType.DCOLON: lambda self, this, to: self.expression(exp.Cast, this=this, to=to)
+            if isinstance(to, exp.DataType) and to.this != exp.DataType.Type.USERDEFINED
+            else self.expression(exp.ScopeResolution, this=this, expression=to),
+        }
+
+        def _parse_dcolon(self) -> t.Optional[exp.Expression]:
+            return self._parse_function() or self._parse_types()
 
         def _parse_options(self) -> t.Optional[t.List[exp.Expression]]:
             if not self._match(TokenType.OPTION):
diff --git a/sqlglot/parser.py b/sqlglot/parser.py
index 74216463..e50abcc3 100644
--- a/sqlglot/parser.py
+++ b/sqlglot/parser.py
@@ -4597,6 +4597,9 @@ class Parser(metaclass=_Parser):
 
         return this
 
+    def _parse_dcolon(self) -> t.Optional[exp.Expression]:
+        return self._parse_types()
+
     def _parse_column_ops(self, this: t.Optional[exp.Expression]) -> t.Optional[exp.Expression]:
         this = self._parse_bracket(this)
 
@@ -4605,7 +4608,7 @@ class Parser(metaclass=_Parser):
             op = self.COLUMN_OPERATORS.get(op_token)
 
             if op_token == TokenType.DCOLON:
-                field = self._parse_types()
+                field = self._parse_dcolon()
                 if not field:
                     self.raise_error("Expected type")
             elif op and self._curr:


Test patch:
diff --git a/tests/dialects/test_tsql.py b/tests/dialects/test_tsql.py
index c2bc7b0d..1df59292 100644
--- a/tests/dialects/test_tsql.py
+++ b/tests/dialects/test_tsql.py
@@ -1878,6 +1878,9 @@ FROM OPENJSON(@json) WITH (
         )
 
     def test_scope_resolution_op(self):
+        # we still want to support :: casting shorthand for tsql
+        self.validate_identity("x::int", "CAST(x AS INTEGER)")
+
         for lhs, rhs in (
             ("", "FOO(a, b)"),
             ("bar", "baZ(1, 2)"),