Query implements read-only query feature.
(ctx context.Context, queries []Query)
| 256 | |
| 257 | // Query implements read-only query feature. |
| 258 | func (s *Storage) Query(ctx context.Context, queries []Query) (columns []string, types []string, |
| 259 | data [][]interface{}, err error) { |
| 260 | data = make([][]interface{}, 0) |
| 261 | |
| 262 | if len(queries) == 0 { |
| 263 | return |
| 264 | } |
| 265 | |
| 266 | var tx *sql.Tx |
| 267 | var txOptions = &sql.TxOptions{ |
| 268 | ReadOnly: true, |
| 269 | } |
| 270 | |
| 271 | if tx, err = s.db.BeginTx(ctx, txOptions); err != nil { |
| 272 | return |
| 273 | } |
| 274 | |
| 275 | // always rollback on complete |
| 276 | defer tx.Rollback() |
| 277 | |
| 278 | q := queries[len(queries)-1] |
| 279 | |
| 280 | // convert arguments types |
| 281 | args := make([]interface{}, len(q.Args)) |
| 282 | |
| 283 | for i, v := range q.Args { |
| 284 | args[i] = v |
| 285 | } |
| 286 | |
| 287 | var rows *sql.Rows |
| 288 | if rows, err = tx.Query(q.Pattern, args...); err != nil { |
| 289 | return |
| 290 | } |
| 291 | |
| 292 | // free result set |
| 293 | defer rows.Close() |
| 294 | |
| 295 | // get rows meta |
| 296 | if columns, err = rows.Columns(); err != nil { |
| 297 | return |
| 298 | } |
| 299 | |
| 300 | // if there is empty columns, treat result as empty |
| 301 | if len(columns) == 0 { |
| 302 | return |
| 303 | } |
| 304 | |
| 305 | // get types meta |
| 306 | if types, err = s.transformColumnTypes(rows.ColumnTypes()); err != nil { |
| 307 | return |
| 308 | } |
| 309 | |
| 310 | rs := newRowScanner(len(columns)) |
| 311 | |
| 312 | for rows.Next() { |
| 313 | err = rows.Scan(rs.ScanArgs()...) |
| 314 | if err != nil { |
| 315 | return |
nothing calls this directly
no test coverage detected