@@ -186,9 +186,29 @@ impl Cursor<'_> {
186186 '$' => {
187187 // Dollar quoted strings
188188 if is_ident_start ( self . first ( ) ) || self . first ( ) == '$' {
189- self . dollar_quoted_string ( )
189+ // Get the start sequence of the dollar quote, i.e., 'foo' in $foo$hello$foo$
190+ // if ident does not continue and there is no terminating dollar
191+ // sign, we have a positional param `$name`
192+ let mut start = vec ! [ ] ;
193+ loop {
194+ match self . first ( ) {
195+ '$' => {
196+ self . bump ( ) ;
197+ break self . dollar_quoted_string ( start) ;
198+ }
199+ c if is_ident_cont ( c) => {
200+ self . bump ( ) ;
201+ start. push ( c) ;
202+ }
203+ _ => {
204+ break TokenKind :: NamedParam {
205+ kind : NamedParamKind :: DollarRaw ,
206+ } ;
207+ }
208+ }
209+ }
190210 } else {
191- // Parameters
211+ // positional parameter, e.g. `$1`
192212 while self . first ( ) . is_ascii_digit ( ) {
193213 self . bump ( ) ;
194214 }
@@ -490,22 +510,7 @@ impl Cursor<'_> {
490510 }
491511
492512 // https://www.postgresql.org/docs/16/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING
493- fn dollar_quoted_string ( & mut self ) -> TokenKind {
494- // Get the start sequence of the dollar quote, i.e., 'foo' in
495- // $foo$hello$foo$
496- let mut start = vec ! [ ] ;
497- while let Some ( c) = self . bump ( ) {
498- match c {
499- '$' => {
500- self . bump ( ) ;
501- break ;
502- }
503- _ => {
504- start. push ( c) ;
505- }
506- }
507- }
508-
513+ fn dollar_quoted_string ( & mut self , start : Vec < char > ) -> TokenKind {
509514 // we have a dollar quoted string deliminated with `$$`
510515 if start. is_empty ( ) {
511516 loop {
@@ -658,6 +663,12 @@ mod tests {
658663 assert_debug_snapshot ! ( result) ;
659664 }
660665
666+ #[ test]
667+ fn named_param_dollar_raw ( ) {
668+ let result = lex ( "select 1 from c where id = $id;" ) ;
669+ assert_debug_snapshot ! ( result) ;
670+ }
671+
661672 #[ test]
662673 fn named_param_colon_raw ( ) {
663674 let result = lex ( "select 1 from c where id = :id;" ) ;
0 commit comments