/
detail.go
144 lines (122 loc) · 2.38 KB
/
detail.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
package sqlread
import (
"errors"
)
type InsertDetailParser struct {
Out chan []string
ColInd []int
}
func NewInsertDetailParser() *InsertDetailParser {
return &InsertDetailParser{
Out: make(chan []string, 100),
}
}
func (d *InsertDetailParser) ParseStart(p *Parser) parseState {
cii, ok := p.scan()
if !ok {
p.errorUnexpectedEOF()
}
if cii.Type != TInsertInto {
p.errorUnexpectedLex(cii, TInsertInto)
return nil
}
ci, ok := p.scan()
if !ok {
p.errorUnexpectedEOF()
return nil
}
if ci.Type != TIdentifier {
p.errorUnexpectedLex(ci, TIdentifier)
return nil
}
row := []string{}
for {
v, ok := p.scan()
if !ok {
p.errorUnexpectedEOF()
}
switch v.Type {
case TString:
val, err := stringValue(v)
if err != nil {
p.err = err
return nil
}
row = append(row, val)
case TNumber:
row = append(row, v.Val)
case TNull:
row = append(row, string(0)) // investigate
case TComma:
d.Out <- row
row = []string{}
case TSemi:
d.Out <- row
close(d.Out)
return nil
}
}
}
var errorInvalidString = errors.New("invalid string")
func stringValue(c LexItem) (string, error) {
v := c.Val
if len(v) < 2 || v[0] != v[len(v)-1] {
return "", errorInvalidString
}
d := v[0]
m := len(v) - 2
s := ""
i := 0
for {
i++
if i > m {
break
}
if v[i] == '\\' {
if i+1 > m {
return "", errorInvalidString
}
var x rune
switch v[i+1] {
case '\\': // \\ A backslash (\) character
x = '\\'
case '0': // \0 An ASCII NUL (X'00') character
x = 0 // null byte
case '\'': // \' A single quote (') character
x = '\''
case '"': // \" A double quote (") character
x = '"'
case 'b': // \b A backspace character
x = 'b'
case 'n': // \n A newline (linefeed) character
x = 'n'
case 'r': // \r A carriage return character
x = 'r'
case 't': // \t A tab character
x = 't'
case 'Z': // \Z ASCII 26 (Control+Z); see note following the table
x = 'Z'
case '%': // \% A % character; see note following the table
x = '%'
case '_': // \_ A _ character; see note following the table
x = '_'
default:
return "", errorInvalidString
}
i++
s += string(x)
continue
}
if v[i] == d {
if i+1 < m && v[i+1] == d {
i++
s += string(d)
continue
} else {
return "", errorInvalidString
}
}
s += string(v[i])
}
return s, nil
}