rand_id.go 1.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051
  1. // Copyright (c) 2019 David Crawshaw <david@zentus.com>
  2. // Copyright (c) 2021 Ross Light <rosss@zombiezen.com>
  3. //
  4. // Permission to use, copy, modify, and distribute this software for any
  5. // purpose with or without fee is hereby granted, provided that the above
  6. // copyright notice and this permission notice appear in all copies.
  7. //
  8. // THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. // WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. // MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. // ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. // WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. // ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. // OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. //
  16. // SPDX-License-Identifier: ISC
  17. package sqlitex
  18. import (
  19. "crypto/rand"
  20. "fmt"
  21. "math/big"
  22. "zombiezen.com/go/sqlite"
  23. )
  24. // InsertRandID executes stmt with a random value in the range [min, max) for $param.
  25. func InsertRandID(stmt *sqlite.Stmt, param string, min, max int64) (int64, error) {
  26. if min < 0 {
  27. return 0, fmt.Errorf("sqlitex.InsertRandID: min (%d) is negative", min)
  28. }
  29. for i := 0; ; i++ {
  30. v, err := rand.Int(rand.Reader, big.NewInt(max-min))
  31. if err != nil {
  32. return 0, fmt.Errorf("sqlitex.InsertRandID: %w", err)
  33. }
  34. id := v.Int64() + min
  35. stmt.Reset()
  36. stmt.SetInt64(param, id)
  37. _, err = stmt.Step()
  38. if err == nil {
  39. return id, nil
  40. }
  41. if i >= 100 || sqlite.ErrCode(err) != sqlite.ResultConstraintPrimaryKey {
  42. return 0, fmt.Errorf("sqlitex.InsertRandID: %w", err)
  43. }
  44. }
  45. }