Repository: mabel-dev/opteryx

Issue:
✨ Support `RLIKE`
https://github.com/sqlparser-rs/sqlparser-rs/pull/1017/files

~~~sql
SELECT 'a' RLIKE '.'
~~~


Discussion:

Resolving patch:
diff --git a/opteryx/__version__.py b/opteryx/__version__.py
--- a/opteryx/__version__.py
+++ b/opteryx/__version__.py
@@ -1,4 +1,4 @@
-__build__ = 134
+__build__ = 136
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
diff --git a/opteryx/operators/join_node.py b/opteryx/operators/join_node.py
--- a/opteryx/operators/join_node.py
+++ b/opteryx/operators/join_node.py
@@ -95,7 +95,7 @@ def execute(self) -> Iterable:
                         column = col.name
                         break
                 if column:
-                    raise pyarrow.ArrowInvalid(err.replace(last_token, column))
+                    raise pyarrow.ArrowInvalid(str(err).replace(last_token, f"'{column}'"))
                 raise err
 
             # need to ensure we put the right column back if we need it
diff --git a/opteryx/third_party/pyarrow_ops/ops.py b/opteryx/third_party/pyarrow_ops/ops.py
--- a/opteryx/third_party/pyarrow_ops/ops.py
+++ b/opteryx/third_party/pyarrow_ops/ops.py
@@ -137,12 +137,12 @@ def _inner_filter_operations(arr, operator, value):
         # MODIFIED FOR OPTERYX - see comment above
         matches = compute.match_like(arr, value[0], ignore_case=True)  # [#325]
         return numpy.invert(matches)
-    if operator in ("PGRegexMatch", "SimilarTo"):
+    if operator in ("PGRegexMatch", "SimilarTo", "RLike"):
         # MODIFIED FOR OPTERYX - see comment above
         return (
             compute.match_substring_regex(arr, value[0]).to_numpy(False).astype(dtype=bool)
         )  # [#325]
-    if operator in ("PGRegexNotMatch", "NotSimilarTo"):
+    if operator in ("PGRegexNotMatch", "NotSimilarTo", "NotRLike"):
         # MODIFIED FOR OPTERYX - see comment above
         matches = compute.match_substring_regex(arr, value[0])  # [#325]
         return numpy.invert(matches)


Test patch:
diff --git a/tests/misc/test_fuzzy_search.py b/tests/misc/test_fuzzy_search.py
--- a/tests/misc/test_fuzzy_search.py
+++ b/tests/misc/test_fuzzy_search.py
@@ -112,7 +112,7 @@ def test_date_parser(string, candidates, expected):
 if __name__ == "__main__":  # pragma: no cover
     print(f"RUNNING BATTERY OF {len(TESTS)} FUZZY TESTS")
     for s, c, e in TESTS:
-        print(".", end="")
+        print("\033[38;2;26;185;67m.\033[0m", end="")
         test_date_parser(s, c, e)
     print()
     print("✅ okay")
diff --git a/tests/misc/test_levenshtien.py b/tests/misc/test_levenshtien.py
--- a/tests/misc/test_levenshtien.py
+++ b/tests/misc/test_levenshtien.py
@@ -84,5 +84,7 @@ def test_levenshtien_battery(a, b, distance):
     print(f"RUNNING BATTERY OF {len(TESTS)} TESTS")
     for a, b, distance in TESTS:
         test_levenshtien_battery(a, b, distance)
+        print("\033[38;2;26;185;67m.\033[0m", end="")
 
+    print()
     print("✅ okay")
diff --git a/tests/misc/test_mbleven.py b/tests/misc/test_mbleven.py
--- a/tests/misc/test_mbleven.py
+++ b/tests/misc/test_mbleven.py
@@ -156,7 +156,7 @@ def test_compare_delete_char(s):
 if __name__ == "__main__":  # pragma: no cover
     print(f"RUNNING BATTERY OF {len(TESTS)} TESTS")
     for str1, str2, score in TESTS:
-        print(".", end="")
+        print("\033[38;2;26;185;67m.\033[0m", end="")
         test_level_battery(str1, str2, score)
 
     print("")
diff --git a/tests/misc/test_soundex.py b/tests/misc/test_soundex.py
--- a/tests/misc/test_soundex.py
+++ b/tests/misc/test_soundex.py
@@ -68,5 +68,7 @@ def test_soundex_battery(input, result):
     print(f"RUNNING BATTERY OF {len(TESTS)} TESTS")
     for str1, str2 in TESTS:
         test_soundex_battery(str1, str2)
+        print("\033[38;2;26;185;67m.\033[0m", end="")
 
+    print()
     print("✅ okay")
diff --git a/tests/query_execution/test_count_star.py b/tests/query_execution/test_count_star.py
--- a/tests/query_execution/test_count_star.py
+++ b/tests/query_execution/test_count_star.py
@@ -14,23 +14,22 @@ def test_count_star():
     """
     import opteryx
 
-    conn = opteryx.connect()
-    cur = conn.cursor()
-    cur.execute("SELECT count(*) FROM testdata.flat.formats.parquet WITH(NO_PARTITION);")
-    cur.arrow()
+    cur = opteryx.query("SELECT count(*) FROM testdata.flat.formats.parquet")
     stats = cur.stats
     assert stats["columns_read"] == 1, stats["columns_read"]
     assert stats["rows_read"] == 100000, stats["rows_read"]
-    conn.close()
 
-    conn = opteryx.connect()
-    cur = conn.cursor()
-    cur.execute("SELECT COUNT(*) FROM testdata.flat.formats.parquet WITH(NO_PARTITION);")
-    cur.arrow()
+    cur = opteryx.query("SELECT COUNT(*) FROM testdata.flat.formats.parquet;")
+    stats = cur.stats
+    assert stats["columns_read"] == 1, stats["columns_read"]
+    assert stats["rows_read"] == 100000, stats["rows_read"]
+
+    cur = opteryx.query(
+        "SELECT COUNT(*), tweet_id FROM testdata.flat.formats.parquet GROUP BY tweet_id;"
+    )
     stats = cur.stats
     assert stats["columns_read"] == 1, stats["columns_read"]
     assert stats["rows_read"] == 100000, stats["rows_read"]
-    conn.close()
 
 
 if __name__ == "__main__":  # pragma: no cover
diff --git a/tests/sql_battery/test_shapes_and_errors_battery.py b/tests/sql_battery/test_shapes_and_errors_battery.py
--- a/tests/sql_battery/test_shapes_and_errors_battery.py
+++ b/tests/sql_battery/test_shapes_and_errors_battery.py
@@ -350,6 +350,8 @@
         ("SELECT * FROM $satellites WHERE name NOT LIKE '%c%'", 166, 8, None),
         ("SELECT * FROM $satellites WHERE name NOT ILIKE '%c%'", 154, 8, None),
         ("SELECT * FROM $satellites WHERE name ~ '^C.'", 12, 8, None),
+        ("SELECT * FROM $planets WHERE name NOT RLIKE '^E.+h$'", 8, 20, None),
+        ("SELECT * FROM $planets WHERE name RLIKE '^E.+h$'", 1, 20, None),
         ("SELECT * FROM $satellites WHERE name SIMILAR TO '^C.'", 12, 8, None),
         ("SELECT * FROM $satellites WHERE name !~ '^C.'", 165, 8, None),
         ("SELECT * FROM $satellites WHERE name NOT SIMILAR TO '^C.'", 165, 8, None),