readBacktickIdentifier reads MySQL-style backtick identifiers
()
| 930 | |
| 931 | // readBacktickIdentifier reads MySQL-style backtick identifiers |
| 932 | func (t *Tokenizer) readBacktickIdentifier() (models.Token, error) { |
| 933 | startPos := t.pos.Clone() |
| 934 | |
| 935 | // Skip opening backtick |
| 936 | t.pos.Index++ |
| 937 | t.pos.Column++ |
| 938 | |
| 939 | var buf bytes.Buffer |
| 940 | for t.pos.Index < len(t.input) { |
| 941 | ch := t.input[t.pos.Index] |
| 942 | |
| 943 | if ch == '`' { |
| 944 | // Check for escaped backtick |
| 945 | if t.pos.Index+1 < len(t.input) && t.input[t.pos.Index+1] == '`' { |
| 946 | // Include one backtick and skip the other |
| 947 | buf.WriteByte('`') |
| 948 | t.pos.Index += 2 |
| 949 | t.pos.Column += 2 |
| 950 | continue |
| 951 | } |
| 952 | |
| 953 | // End of backtick identifier |
| 954 | t.pos.Index++ |
| 955 | t.pos.Column++ |
| 956 | |
| 957 | return models.Token{ |
| 958 | Type: models.TokenTypeIdentifier, // Backtick identifiers are identifiers |
| 959 | Value: buf.String(), |
| 960 | }, nil |
| 961 | } |
| 962 | |
| 963 | if ch == '\n' { |
| 964 | t.pos.Line++ |
| 965 | t.pos.Column = 1 |
| 966 | } else { |
| 967 | t.pos.Column++ |
| 968 | } |
| 969 | |
| 970 | buf.WriteByte(ch) |
| 971 | t.pos.Index++ |
| 972 | } |
| 973 | |
| 974 | return models.Token{}, errors.UnterminatedStringError( |
| 975 | t.toSQLPosition(startPos), |
| 976 | string(t.input), |
| 977 | ) |
| 978 | } |
| 979 | |
| 980 | // readQuotedString handles the actual scanning of a single/double-quoted string |
| 981 | func (t *Tokenizer) readQuotedString(quote rune) (models.Token, error) { |
no test coverage detected