Repository: andialbrecht/sqlparse

Issue:
Dollar quoted strings (PostgreSQL) cannot follow an operator (e.g. `=$$Hello$$`) 
**Describe the bug**
Dollar quoted strings (e.g. PostgreSQL) are not properly detected, when there is an operator directly preceding the dollar quoted string (e.g `var=$$text$$`). While according to PostgreSQL docs ...

> A dollar-quoted string that follows a keyword or identifier must be separated from it by whitespace; otherwise the dollar quoting delimiter would be taken as part of the preceding identifier.

... this does not hold true for operators. i.e. `SET application_name=$$Hello$$;` is valid.

This seems to relate to 
https://github.com/andialbrecht/sqlparse/blob/f101546dafa921edfea5b3107731504665b758ea/sqlparse/keywords.py#L33
and the negative lookbehind ensuring that there's no non-whitespace character before the starting `$`. This potentially should be changed to
```
(r'((?<![\w\"\$])\$(?:[_A-ZÀ-Ü]\w*)?\$)[\s\S]*?\1', tokens.Literal)
```
which would filter out any keywords or identifiers.


**To Reproduce**

```python
sqlparse.split('''update test set a=$$test;test$$;''');
```

```
['update test set a=$$test;', 'test$$;']
```

**Expected behavior**

```
['update test set a=$$test;test$$;']
```

**Versions (please complete the following information):**
 - Python: 3.12.1
 - sqlparse: 0.4.4

**Additional context**
Add any other context about the problem here.


Discussion:
amotl: Dear @andialbrecht. We are tracking this patch from another issue we are observing on our interactive database shell. Do you see any chance to have a look at it? Thanks in advance, Andreas.

- https://github.com/crate/crash/issues/427

Patch:
diff --git a/CHANGELOG b/CHANGELOG
index 0ede280..0b48e9f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -14,6 +14,7 @@ Enhancements:
 Bug Fixes
 
 * Ignore dunder attributes when creating Tokens (issue672).
+* Allow operators to precede dollar-quoted strings (issue763).
 
 
 Release 0.4.4 (Apr 18, 2023)
diff --git a/sqlparse/keywords.py b/sqlparse/keywords.py
index b45f3e0..d3794fd 100644
--- a/sqlparse/keywords.py
+++ b/sqlparse/keywords.py
@@ -30,7 +30,7 @@ SQL_REGEX = [
 
     (r"`(``|[^`])*`", tokens.Name),
     (r"´(´´|[^´])*´", tokens.Name),
-    (r'((?<!\S)\$(?:[_A-ZÀ-Ü]\w*)?\$)[\s\S]*?\1', tokens.Literal),
+    (r'((?<![\w\"\$])\$(?:[_A-ZÀ-Ü]\w*)?\$)[\s\S]*?\1', tokens.Literal),
 
     (r'\?', tokens.Name.Placeholder),
     (r'%(\(\w+\))?s', tokens.Name.Placeholder),


Test patch:
diff --git a/tests/test_parse.py b/tests/test_parse.py
index 5feef5a..6e4df7c 100644
--- a/tests/test_parse.py
+++ b/tests/test_parse.py
@@ -180,6 +180,14 @@ def test_psql_quotation_marks():
     $PROC_2$ LANGUAGE plpgsql;""")
     assert len(t) == 2
 
+    # operators are valid infront of dollar quoted strings
+    t = sqlparse.split("""UPDATE SET foo =$$bar;SELECT bar$$""")
+    assert len(t) == 1
+    
+    # identifiers must be separated by whitespace
+    t = sqlparse.split("""UPDATE SET foo TO$$bar;SELECT bar$$""")
+    assert len(t) == 2
+
 
 def test_double_precision_is_builtin():
     s = 'DOUBLE PRECISION'