@@ -4,6 +4,8 @@ package sqlbase
44
55import (
66 "database/sql"
7+ "errors"
8+ "fmt"
79
810 "github.com/btcsuite/btcwallet/walletdb"
911)
@@ -184,49 +186,60 @@ func (c *readWriteCursor) Seek(seek []byte) ([]byte, []byte) {
184186}
185187
186188// Delete removes the current key/value pair the cursor is at without
187- // invalidating the cursor. Returns ErrIncompatibleValue if attempted
188- // when the cursor points to a nested bucket.
189+ // invalidating the cursor. Returns ErrIncompatibleValue if attempted when the
190+ // cursor points to a nested bucket.
189191func (c * readWriteCursor ) Delete () error {
190- // Get first record at or after cursor.
191- var key []byte
192- row , cancel := c .bucket .tx .QueryRow (
193- "SELECT key FROM " + c .bucket .table + " WHERE " +
194- parentSelector (c .bucket .id )+
195- " AND key>=$1 ORDER BY key LIMIT 1" ,
196- c .currKey ,
197- )
198- defer cancel ()
199- err := row .Scan (& key )
200-
201- switch {
202- case err == sql .ErrNoRows :
203- return nil
204-
205- case err != nil :
206- panic (err )
192+ if c .currKey == nil {
193+ // Cursor might not be positioned on a valid key.
194+ return errors .New ("cursor not positioned on a key" )
207195 }
208196
209- // Delete record.
197+ // Attempt to delete the key the cursor is pointing at, but only if it's
198+ // a value.
210199 result , err := c .bucket .tx .Exec (
211200 "DELETE FROM " + c .bucket .table + " WHERE " +
212201 parentSelector (c .bucket .id )+
213202 " AND key=$1 AND value IS NOT NULL" ,
214- key ,
203+ c . currKey ,
215204 )
216205 if err != nil {
217206 panic (err )
218207 }
219208
220209 rows , err := result .RowsAffected ()
221210 if err != nil {
222- return err
211+ return fmt .Errorf ("error getting rows affected " +
212+ "for cursor key %x: %w" , c .currKey , err )
213+ }
214+
215+ // If deletion succeeded, we are done.
216+ if rows == 1 {
217+ return nil
223218 }
224219
225- // The key exists but nothing has been deleted. This means that the key
226- // must have been a bucket key.
227- if rows != 1 {
220+ // If rows == 0, the key either didn't exist anymore (concurrent
221+ // delete?) or it was a bucket. Check if it's a bucket.
222+ var existsAsBucket int
223+ rowCheck , cancelCheck := c .bucket .tx .QueryRow (
224+ "SELECT 1 FROM " + c .bucket .table + " WHERE " +
225+ parentSelector (c .bucket .id )+
226+ " AND key=$1 AND value IS NULL" , c .currKey ,
227+ )
228+ defer cancelCheck ()
229+
230+ errCheck := rowCheck .Scan (& existsAsBucket )
231+ if errCheck == nil {
232+ // Found it, and value IS NULL -> It's a bucket.
228233 return walletdb .ErrIncompatibleValue
229234 }
230235
231- return err
236+ if errCheck == sql .ErrNoRows {
237+ return nil
238+ }
239+
240+ // Some other error during the check.
241+ //
242+ // TODO(roasbeef): panic here like above/
243+ return fmt .Errorf ("error checking if cursor key %x is " +
244+ "bucket: %w" , c .currKey , errCheck )
232245}
0 commit comments