scanString is similar to Scanner.scanString, but uses PL/pgSQL tokens.
(lval ScanSymType, ch int, allowEscapes, requireUTF8 bool)
| 152 | |
| 153 | // scanString is similar to Scanner.scanString, but uses PL/pgSQL tokens. |
| 154 | func (s *PLpgSQLScanner) scanString(lval ScanSymType, ch int, allowEscapes, requireUTF8 bool) bool { |
| 155 | buf := s.buffer() |
| 156 | var runeTmp [utf8.UTFMax]byte |
| 157 | start := s.pos |
| 158 | outer: |
| 159 | for { |
| 160 | switch s.next() { |
| 161 | case ch: |
| 162 | buf = append(buf, s.in[start:s.pos-1]...) |
| 163 | if s.peek() == ch { |
| 164 | // Double quote is translated into a single quote that is part of the |
| 165 | // string. |
| 166 | start = s.pos |
| 167 | s.pos++ |
| 168 | continue |
| 169 | } |
| 170 | |
| 171 | newline, ok := s.skipWhitespace(lval, false) |
| 172 | if !ok { |
| 173 | return false |
| 174 | } |
| 175 | |
| 176 | // SQL allows joining adjacent single-quoted strings separated by |
| 177 | // whitespace as long as that whitespace contains at least one |
| 178 | // newline. Kind of strange to require the newline, but that is the |
| 179 | // standard. |
| 180 | if ch == singleQuote && s.peek() == singleQuote && newline { |
| 181 | s.pos++ |
| 182 | start = s.pos |
| 183 | continue |
| 184 | } |
| 185 | break outer |
| 186 | |
| 187 | case '\\': |
| 188 | t := s.peek() |
| 189 | |
| 190 | if allowEscapes { |
| 191 | buf = append(buf, s.in[start:s.pos-1]...) |
| 192 | if t == ch { |
| 193 | start = s.pos |
| 194 | s.pos++ |
| 195 | continue |
| 196 | } |
| 197 | |
| 198 | switch t { |
| 199 | case 'a', 'b', 'f', 'n', 'r', 't', 'v', 'x', 'X', 'u', 'U', '\\', |
| 200 | '0', '1', '2', '3', '4', '5', '6', '7': |
| 201 | var tmp string |
| 202 | if t == 'X' && len(s.in[s.pos:]) >= 3 { |
| 203 | // UnquoteChar doesn't handle 'X' so we create a temporary string |
| 204 | // for it to parse. |
| 205 | tmp = "\\x" + s.in[s.pos+1:s.pos+3] |
| 206 | } else { |
| 207 | tmp = s.in[s.pos-1:] |
| 208 | } |
| 209 | v, multibyte, tail, err := strconv.UnquoteChar(tmp, byte(ch)) |
| 210 | if err != nil { |
| 211 | lval.SetID(lexbase.ERROR) |
no test coverage detected