Repository: tobymao/sqlglot

Issue:
Converstion of snowflake POSITION to Trino STRPOS Is incorrect 
When translating Snowflake dialect to Trino with the POSITION function it has a 3rd parameter allowing you to define the start position in the  string from which you can start looking for the expression where as in trino the 3rd argument in STRPOS in not the starting point in which to look in the string but the the N Instance of the character you are looking for.

document reference:
1. Snowflake POSITION - https://docs.snowflake.com/en/sql-reference/functions/position
2. Trino STRPOS - https://trino.io/docs/current/functions/string.html#strpos:~:text=0%20is%20returned.-,strpos,-(string%2C


Reproducible code : 

snowflake:
``` 
SELECT POSITION( 'A','ADFGAC', 3) => Returns position 5
```

Trino:
``` 
SELECT STRPOS( 'A','ADFGAC', 3) => Returns position 0 - looks for the 3 acurance of A
```


Discussion:

Resolving patch:
diff --git a/sqlglot/dialects/dialect.py b/sqlglot/dialects/dialect.py
--- a/sqlglot/dialects/dialect.py
+++ b/sqlglot/dialects/dialect.py
@@ -608,13 +608,21 @@ def no_map_from_entries_sql(self: Generator, expression: exp.MapFromEntries) ->
     return ""
 
 
-def str_position_sql(self: Generator, expression: exp.StrPosition) -> str:
+def str_position_sql(
+    self: Generator, expression: exp.StrPosition, generate_instance: bool = False
+) -> str:
     this = self.sql(expression, "this")
     substr = self.sql(expression, "substr")
     position = self.sql(expression, "position")
+    instance = expression.args.get("instance") if generate_instance else None
+    position_offset = ""
+
     if position:
-        return f"STRPOS(SUBSTR({this}, {position}), {substr}) + {position} - 1"
-    return f"STRPOS({this}, {substr})"
+        # Normalize third 'pos' argument into 'SUBSTR(..) + offset' across dialects
+        this = self.func("SUBSTR", this, position)
+        position_offset = f" + {position} - 1"
+
+    return self.func("STRPOS", this, substr, instance) + position_offset
 
 
 def struct_extract_sql(self: Generator, expression: exp.StructExtract) -> str:
diff --git a/sqlglot/dialects/presto.py b/sqlglot/dialects/presto.py
--- a/sqlglot/dialects/presto.py
+++ b/sqlglot/dialects/presto.py
@@ -22,6 +22,7 @@
     rename_func,
     right_to_substring_sql,
     struct_extract_sql,
+    str_position_sql,
     timestamptrunc_sql,
     timestrtotime_sql,
     ts_or_ds_add_cast,
@@ -401,7 +402,7 @@ class Generator(generator.Generator):
                 ]
             ),
             exp.SortArray: _no_sort_array,
-            exp.StrPosition: rename_func("STRPOS"),
+            exp.StrPosition: lambda self, e: str_position_sql(self, e, generate_instance=True),
             exp.StrToDate: lambda self, e: f"CAST({_str_to_time_sql(self, e)} AS DATE)",
             exp.StrToMap: rename_func("SPLIT_TO_MAP"),
             exp.StrToTime: _str_to_time_sql,


Test patch:
diff --git a/tests/dialects/test_dialect.py b/tests/dialects/test_dialect.py
--- a/tests/dialects/test_dialect.py
+++ b/tests/dialects/test_dialect.py
@@ -1510,7 +1510,7 @@ def test_operators(self):
             "POSITION(needle, haystack, pos)",
             write={
                 "drill": "STRPOS(SUBSTR(haystack, pos), needle) + pos - 1",
-                "presto": "STRPOS(haystack, needle, pos)",
+                "presto": "STRPOS(SUBSTR(haystack, pos), needle) + pos - 1",
                 "spark": "LOCATE(needle, haystack, pos)",
                 "clickhouse": "position(haystack, needle, pos)",
                 "snowflake": "POSITION(needle, haystack, pos)",
diff --git a/tests/dialects/test_hive.py b/tests/dialects/test_hive.py
--- a/tests/dialects/test_hive.py
+++ b/tests/dialects/test_hive.py
@@ -563,7 +563,7 @@ def test_hive(self):
             "LOCATE('a', x, 3)",
             write={
                 "duckdb": "STRPOS(SUBSTR(x, 3), 'a') + 3 - 1",
-                "presto": "STRPOS(x, 'a', 3)",
+                "presto": "STRPOS(SUBSTR(x, 3), 'a') + 3 - 1",
                 "hive": "LOCATE('a', x, 3)",
                 "spark": "LOCATE('a', x, 3)",
             },
diff --git a/tests/dialects/test_presto.py b/tests/dialects/test_presto.py
--- a/tests/dialects/test_presto.py
+++ b/tests/dialects/test_presto.py
@@ -177,6 +177,17 @@ def test_regex(self):
                 "spark": "ARRAY_JOIN(x, '-', 'a')",
             },
         )
+        self.validate_all(
+            "STRPOS('ABC', 'A', 3)",
+            read={
+                "trino": "STRPOS('ABC', 'A', 3)",
+            },
+            write={
+                "presto": "STRPOS('ABC', 'A', 3)",
+                "trino": "STRPOS('ABC', 'A', 3)",
+                "snowflake": "POSITION('A', 'ABC')",
+            },
+        )
 
     def test_interval_plural_to_singular(self):
         # Microseconds, weeks and quarters are not supported in Presto/Trino INTERVAL literals