File
Blob: kv/sqlite3/statements.go
| 1 | package sqlite3 |
| 2 | |
| 3 | import "database/sql" |
| 4 | |
| 5 | // statements holds prepared statements for fixed-shape queries. |
| 6 | // Reader statements are prepared on s.reader; writer statements on s.writer. |
| 7 | // For transactional writes, callers use tx.StmtContext to bind a prepared |
| 8 | // statement into the active transaction. |
| 9 | type statements struct { |
| 10 | // -- reader -- |
| 11 | simpleGet *sql.Stmt |
| 12 | prefixContains *sql.Stmt |
| 13 | prefixList *sql.Stmt |
| 14 | listKeys *sql.Stmt |
| 15 | rangeKeysNorm *sql.Stmt |
| 16 | rangeKeysWrap *sql.Stmt |
| 17 | |
| 18 | // -- writer -- |
| 19 | simplePut *sql.Stmt |
| 20 | simpleDel *sql.Stmt |
| 21 | prefixAppend *sql.Stmt |
| 22 | prefixRemove *sql.Stmt |
| 23 | prefixCount *sql.Stmt |
| 24 | |
| 25 | leaseAcquire *sql.Stmt |
| 26 | leaseRenew *sql.Stmt |
| 27 | leaseRelease *sql.Stmt |
| 28 | leaseGet *sql.Stmt |
| 29 | leaseImport *sql.Stmt |
| 30 | |
| 31 | trackerLookup *sql.Stmt |
| 32 | trackerInsert *sql.Stmt |
| 33 | trackerUpdate *sql.Stmt |
| 34 | trackerDelete *sql.Stmt |
| 35 | |
| 36 | // export uses the reader inside a read tx |
| 37 | exportSimpleGet *sql.Stmt |
| 38 | exportPrefixList *sql.Stmt |
| 39 | exportLeaseGet *sql.Stmt |
| 40 | |
| 41 | all []*sql.Stmt |
| 42 | } |
| 43 | |
| 44 | func prepareStatements(reader, writer *sql.DB) (_ *statements, err error) { |
| 45 | s := &statements{} |
| 46 | defer func() { |
| 47 | if err != nil { |
| 48 | s.close() |
| 49 | } |
| 50 | }() |
| 51 | |
| 52 | type preparedStatement struct { |
| 53 | db *sql.DB |
| 54 | query string |
| 55 | target **sql.Stmt |
| 56 | } |
| 57 | |
| 58 | defs := []preparedStatement{ |
| 59 | {reader, querySimpleGet, &s.simpleGet}, |
| 60 | {reader, queryPrefixContains, &s.prefixContains}, |
| 61 | {reader, queryPrefixList, &s.prefixList}, |
| 62 | {reader, queryListKeys, &s.listKeys}, |
| 63 | {reader, queryRangeKeysNorm, &s.rangeKeysNorm}, |
| 64 | {reader, queryRangeKeysWrap, &s.rangeKeysWrap}, |
| 65 | {writer, querySimplePut, &s.simplePut}, |
| 66 | {writer, querySimpleDel, &s.simpleDel}, |
| 67 | {writer, queryPrefixAppend, &s.prefixAppend}, |
| 68 | {writer, queryPrefixRemove, &s.prefixRemove}, |
| 69 | {writer, queryPrefixCount, &s.prefixCount}, |
| 70 | {writer, queryLeaseAcquire, &s.leaseAcquire}, |
| 71 | {writer, queryLeaseRenew, &s.leaseRenew}, |
| 72 | {writer, queryLeaseRelease, &s.leaseRelease}, |
| 73 | {writer, queryLeaseGet, &s.leaseGet}, |
| 74 | {writer, queryLeaseImport, &s.leaseImport}, |
| 75 | {writer, queryTrackerLookup, &s.trackerLookup}, |
| 76 | {writer, queryTrackerInsert, &s.trackerInsert}, |
| 77 | {writer, queryTrackerUpdate, &s.trackerUpdate}, |
| 78 | {writer, queryTrackerDelete, &s.trackerDelete}, |
| 79 | {reader, queryLeaseGet, &s.exportLeaseGet}, |
| 80 | } |
| 81 | |
| 82 | for _, def := range defs { |
| 83 | st, prepErr := def.db.Prepare(def.query) |
| 84 | if prepErr != nil { |
| 85 | err = prepErr |
| 86 | return nil, err |
| 87 | } |
| 88 | *def.target = st |
| 89 | s.all = append(s.all, st) |
| 90 | } |
| 91 | |
| 92 | s.exportSimpleGet = s.simpleGet |
| 93 | s.exportPrefixList = s.prefixList |
| 94 | |
| 95 | return s, nil |
| 96 | } |
| 97 | |
| 98 | func (s *statements) close() { |
| 99 | if s == nil { |
| 100 | return |
| 101 | } |
| 102 | for _, st := range s.all { |
| 103 | if st != nil { |
| 104 | _ = st.Close() |
| 105 | } |
| 106 | } |
| 107 | s.all = nil |
| 108 | } |