-
Notifications
You must be signed in to change notification settings - Fork 4
/
Copy pathsql_db.go
287 lines (255 loc) · 7.59 KB
/
sql_db.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
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
/*
* Copyright (c) 2022 Red Hat, Inc.
* SPDX-License-Identifier: GPL-2.0-or-later
*/
package main
import (
"database/sql"
"errors"
"fmt"
"strings"
_ "github.com/go-sql-driver/mysql"
_ "github.com/lib/pq"
_ "github.com/mattn/go-sqlite3"
)
// Sql connection configuration.
type connectToken struct {
DBDriver string
DBDSN string
}
type Cache struct {
successors map[int][]entry
entries map[int]entry
subSys map[string]string
}
type SqlDB struct {
db *sql.DB
cache Cache
}
// Connects the target db and returns the handle.
func (d *SqlDB) init(arg interface{}) (err error) {
t, ok := arg.(*connectToken)
if !ok {
var ok1 bool
d.db, ok1 = arg.(*sql.DB)
if !ok1 {
return errors.New("invalid type")
}
}
if ok {
d.db, err = sql.Open(t.DBDriver, t.DBDSN)
}
if err == nil {
d.cache.successors = make(map[int][]entry)
d.cache.entries = make(map[int]entry)
d.cache.subSys = make(map[string]string)
}
return err
}
func (d *SqlDB) GetExploredSubsystemByName(subs string) string {
debugIOPrintln("input subs=", subs)
debugIOPrintln("output =", subs)
return d.cache.subSys[subs]
}
// Returns function details from a given id.
func (d *SqlDB) getEntryById(symbolId int, instance int) (entry, error) {
var e entry
var s sql.NullString
debugIOPrintf("input symbolId=%d, instance=%d\n", symbolId, instance)
if e, ok := d.cache.entries[symbolId]; ok {
debugIOPrintf("output entry=%+v, error=%s\n", e, "nil")
return e, nil
}
query := "select symbol_id, symbol_name, subsys_name, file_name from " +
"(select * from symbols, files where symbols.symbol_file_ref_id=files.file_id and symbols.symbol_instance_id_ref=%[2]d) as dummy " +
"left outer join tags on dummy.symbol_file_ref_id=tags.tag_file_ref_id where symbol_id=%[1]d and symbol_instance_id_ref=%[2]d"
query = fmt.Sprintf(query, symbolId, instance)
debugQueryPrintln(query)
rows, err := d.db.Query(query)
if err != nil {
debugIOPrintf("output entry=%+v, error=%s\n", entry{}, err)
return entry{}, err
}
defer func() {
closeErr := rows.Close()
if err == nil {
err = closeErr
}
}()
for rows.Next() {
if err := rows.Scan(&e.symId, &e.symbol, &s, &e.fn); err != nil {
debugIOPrintf("output entry=%+v, error=%s\n", entry{}, err)
return e, err
}
if s.Valid {
e.subsys = append(e.subsys, s.String)
}
}
if err = rows.Err(); err != nil {
debugIOPrintf("output entry=%+v, error=%s\n", entry{}, err)
return e, err
}
d.cache.entries[symbolId] = e
debugIOPrintf("output entry=%+v, error=%s\n", e, "nil")
return e, nil
}
// Returns the list of successors (called function) for a given function.
func (d *SqlDB) getSuccessorsById(symbolId int, instance int) ([]entry, error) {
var e edge
var res []entry
debugIOPrintf("input symbolId=%d, instance=%d\n", symbolId, instance)
if res, ok := d.cache.successors[symbolId]; ok {
debugIOPrintf("output []entry=%+v, error=%s\n", res, "nil")
return res, nil
}
query := "select caller, callee, source_line, ref_addr from xrefs where caller = %[1]d and xref_instance_id_ref = %[2]d"
query = fmt.Sprintf(query, symbolId, instance)
debugQueryPrintln(query)
rows, err := d.db.Query(query)
if err != nil {
panic(err)
}
defer func() {
closeErr := rows.Close()
if err == nil {
err = closeErr
}
}()
for rows.Next() {
if err := rows.Scan(&e.caller, &e.callee, &e.sourceRef, &e.addressRef); err != nil {
debugIOPrintf("output []entry=%+v, error=%s\n", nil, err)
return nil, err
}
successor, _ := d.getEntryById(e.callee, instance)
successor.sourceRef = e.sourceRef
successor.addressRef = e.addressRef
res = append(res, successor)
}
if err = rows.Err(); err != nil {
debugIOPrintf("output []entry=%+v, error=%s\n", nil, err)
return nil, err
}
d.cache.successors[symbolId] = res
debugIOPrintf("output []entry=%+v, error=%s\n", res, "nil")
return res, nil
}
// Given a function returns the lager subsystem it belongs.
func (d *SqlDB) getSubsysFromSymbolName(symbol string, instance int) (string, error) {
var ty, sub string
debugIOPrintf("input symbol=%s, instance=%d\n", symbol, instance)
if res, ok := d.cache.subSys[symbol]; ok {
debugIOPrintf("output string=%s, error=%s\n", res, "nil")
return res, nil
}
query := "select (select symbol_type from symbols where symbol_name='%[1]s' and symbol_instance_id_ref=%[2]d) as type, subsys_name from " +
"(select count(*) as cnt, subsys_name from tags where subsys_name in (select subsys_name from symbols, " +
"tags where symbols.symbol_file_ref_id=tags.tag_file_ref_id and symbols.symbol_name='%[1]s' and symbols.symbol_instance_id_ref=%[2]d) " +
"group by subsys_name order by cnt desc) as tbl"
query = fmt.Sprintf(query, symbol, instance)
debugQueryPrintln(query)
rows, err := d.db.Query(query)
if err != nil {
panic(err)
}
defer func() {
closeErr := rows.Close()
if err == nil {
err = closeErr
}
}()
for rows.Next() {
if err := rows.Scan(&ty, &sub); err != nil {
debugIOPrintf("output string=%s, error=%s\n", "", err)
return "", err
}
}
if err = rows.Err(); err != nil {
debugIOPrintf("output string=%s, error=%s\n", "", err)
return "", err
}
if sub == "" {
debugIOPrintf("output string=%s, error=%s\n", "", "nil")
return "", nil
}
if ty == "indirect" {
sub = ty
}
d.cache.subSys[symbol] = sub
debugIOPrintf("output string=%s, error=%s\n", sub, "nil")
return sub, nil
}
// Returns the id of a given function name.
func (d *SqlDB) sym2num(symb string, instance int) (int, error) {
var res = -1
var cnt = 0
debugIOPrintf("input symbol=%s, instance=%d\n", symb, instance)
query := "select symbol_id from symbols where symbols.symbol_name='%[1]s' and symbols.symbol_instance_id_ref=%[2]d"
query = fmt.Sprintf(query, symb, instance)
debugQueryPrintln(query)
rows, err := d.db.Query(query)
if err != nil {
panic(err)
}
defer func() {
closeErr := rows.Close()
if err == nil {
err = closeErr
}
}()
for rows.Next() {
cnt++
if err := rows.Scan(&res); err != nil {
debugIOPrintf("output int=%d, error=%s\n", res, err)
return res, err
}
}
if err = rows.Err(); err != nil {
debugIOPrintf("output int=%d, error=%s\n", -1, err)
return -1, err
}
if cnt != 1 {
return res, errors.New("duplicate ID in the DB")
}
debugIOPrintf("output int=%d, error=%s\n", res, "nil")
return res, nil
}
// Returns the subsystem list associated with a given function name.
func (d *SqlDB) symbSubsys(symblist []int, instance int) (string, error) {
var out string
var res string
debugIOPrintf("input symblist=%+v, instance=%d\n", symblist, instance)
for _, symbid := range symblist {
// Resolve symb.
symb, err := d.getEntryById(symbid, instance)
if err != nil {
return "", fmt.Errorf("symbSubsys::getEntryById error: %s", err)
}
out += fmt.Sprintf("{\"FuncName\":\"%s\", \"subsystems\":[", symb.symbol)
query := fmt.Sprintf("select subsys_name from tags where tag_file_ref_id= (select symbol_file_ref_id from symbols where symbol_id=%d)", symbid)
debugQueryPrintln(query)
rows, err := d.db.Query(query)
if err != nil {
err = errors.New("symbSubsys: query failed")
debugIOPrintf("output string=%s, error=%s\n", "", err)
return "", err
}
defer func() {
closeErr := rows.Close()
if err == nil {
err = closeErr
}
}()
for rows.Next() {
if err := rows.Scan(&res); err != nil {
err = errors.New("symbSubsys: error while scan query rows")
debugIOPrintf("output string=%s, error=%s\n", "", err)
return "", err
}
out += fmt.Sprintf("\"%s\",", res)
}
out = strings.TrimSuffix(out, ",") + "]},"
}
out = strings.TrimSuffix(out, ",")
debugIOPrintf("output string=%s, error=%s\n", out, "nil")
return out, nil
}