simplemaria.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799
  1. // Package simplemaria offers a simple way to use a MySQL/MariaDB database.
  2. // This database backend is interchangeable with xyproto/simpleredis and
  3. // xyproto/simplebolt, since they all use xyproto/pinterface.
  4. package simplemaria
  5. import (
  6. "database/sql"
  7. "errors"
  8. "fmt"
  9. // Use the mysql database driver
  10. _ "github.com/go-sql-driver/mysql"
  11. "log"
  12. "strconv"
  13. "strings"
  14. )
  15. const (
  16. // Version number. Stable API within major version numbers.
  17. Version = 3.2
  18. )
  19. // Host represents a specific database at a database host
  20. type Host struct {
  21. db *sql.DB
  22. dbname string
  23. rawUTF8 bool
  24. }
  25. // Common for each of the db datastructures used here
  26. type dbDatastructure struct {
  27. host *Host
  28. table string
  29. }
  30. type (
  31. List dbDatastructure
  32. Set dbDatastructure
  33. HashMap dbDatastructure
  34. KeyValue dbDatastructure
  35. )
  36. const (
  37. // The default "username:password@host:port/database" that the database is running at
  38. defaultDatabaseServer = "" // "username:password@server:port/"
  39. defaultDatabaseName = "test" // "main"
  40. defaultStringType = "TEXT" // "VARCHAR(65535)"
  41. defaultPort = 3306
  42. // Requires MySQL >= 5.53 and MariaDB >= ? for utf8mb4
  43. charset = "utf8mb4" // "utf8"
  44. // Column names
  45. listCol = "a_list"
  46. setCol = "a_set"
  47. keyCol = "property"
  48. valCol = "value"
  49. ownerCol = "owner"
  50. )
  51. // Test if the local database server is up and running.
  52. func TestConnection() (err error) {
  53. return TestConnectionHost(defaultDatabaseServer)
  54. }
  55. // Test if a given database server is up and running.
  56. // connectionString may be on the form "username:password@host:port/database".
  57. func TestConnectionHost(connectionString string) (err error) {
  58. newConnectionString, _ := rebuildConnectionString(connectionString)
  59. // Connect to the given host:port
  60. db, err := sql.Open("mysql", newConnectionString)
  61. if err != nil {
  62. return err
  63. }
  64. defer db.Close()
  65. err = db.Ping()
  66. if Verbose {
  67. if err != nil {
  68. log.Println("Ping: failed")
  69. } else {
  70. log.Println("Ping: ok")
  71. }
  72. }
  73. return err
  74. }
  75. // Test if a given database server is up and running.
  76. func TestConnectionHostWithDSN(connectionString string) (err error) {
  77. // Connect to the given host:port
  78. db, err := sql.Open("mysql", connectionString)
  79. if err != nil {
  80. return err
  81. }
  82. defer db.Close()
  83. err = db.Ping()
  84. if Verbose {
  85. if err != nil {
  86. log.Println("Ping: failed")
  87. } else {
  88. log.Println("Ping: ok")
  89. }
  90. }
  91. return err
  92. }
  93. /* --- Host functions --- */
  94. // Create a new database connection.
  95. // connectionString may be on the form "username:password@host:port/database".
  96. func NewHost(connectionString string) *Host {
  97. newConnectionString, dbname := rebuildConnectionString(connectionString)
  98. db, err := sql.Open("mysql", newConnectionString)
  99. if err != nil {
  100. log.Fatalln("Could not connect to " + newConnectionString + "!")
  101. }
  102. host := &Host{db, dbname, false}
  103. if err := host.Ping(); err != nil {
  104. log.Fatalln("Host does not reply to ping: " + err.Error())
  105. }
  106. if err := host.createDatabase(); err != nil {
  107. log.Fatalln("Could not create database " + host.dbname + ": " + err.Error())
  108. }
  109. if err := host.useDatabase(); err != nil {
  110. panic("Could not use database " + host.dbname + ": " + err.Error())
  111. }
  112. return host
  113. }
  114. // Create a new database connection with a valid DSN.
  115. func NewHostWithDSN(connectionString string, dbname string) *Host {
  116. db, err := sql.Open("mysql", connectionString)
  117. if err != nil {
  118. log.Fatalln("Could not connect to " + connectionString + "!")
  119. }
  120. host := &Host{db, dbname, false}
  121. if err := host.Ping(); err != nil {
  122. log.Fatalln("Host does not reply to ping: " + err.Error())
  123. }
  124. if err := host.createDatabase(); err != nil {
  125. log.Fatalln("Could not create database " + host.dbname + ": " + err.Error())
  126. }
  127. if err := host.useDatabase(); err != nil {
  128. panic("Could not use database " + host.dbname + ": " + err.Error())
  129. }
  130. return host
  131. }
  132. // The default database connection
  133. func New() *Host {
  134. connectionString := defaultDatabaseServer + defaultDatabaseName
  135. if !strings.HasSuffix(defaultDatabaseServer, "/") {
  136. connectionString = defaultDatabaseServer + "/" + defaultDatabaseName
  137. }
  138. return NewHost(connectionString)
  139. }
  140. // Should the UTF-8 data be raw, and not hex encoded and compressed?
  141. func (host *Host) SetRawUTF8(enabled bool) {
  142. host.rawUTF8 = enabled
  143. }
  144. // Select a different database. Create the database if needed.
  145. func (host *Host) SelectDatabase(dbname string) error {
  146. host.dbname = dbname
  147. if err := host.createDatabase(); err != nil {
  148. return err
  149. }
  150. if err := host.useDatabase(); err != nil {
  151. return err
  152. }
  153. return nil
  154. }
  155. // Will create the database if it does not already exist
  156. func (host *Host) createDatabase() error {
  157. if _, err := host.db.Exec("CREATE DATABASE IF NOT EXISTS " + host.dbname + " CHARACTER SET = " + charset); err != nil {
  158. return err
  159. }
  160. if Verbose {
  161. log.Println("Created database " + host.dbname)
  162. }
  163. return nil
  164. }
  165. // Use the host.dbname database
  166. func (host *Host) useDatabase() error {
  167. if _, err := host.db.Exec("USE " + host.dbname); err != nil {
  168. return err
  169. }
  170. if Verbose {
  171. log.Println("Using database " + host.dbname)
  172. }
  173. return nil
  174. }
  175. // Close the connection
  176. func (host *Host) Close() {
  177. host.db.Close()
  178. }
  179. // Ping the host
  180. func (host *Host) Ping() error {
  181. return host.db.Ping()
  182. }
  183. /* --- List functions --- */
  184. // Create a new list. Lists are ordered.
  185. func NewList(host *Host, name string) (*List, error) {
  186. l := &List{host, name}
  187. if _, err := l.host.db.Exec("CREATE TABLE IF NOT EXISTS " + name + " (id INT PRIMARY KEY AUTO_INCREMENT, " + listCol + " " + defaultStringType + ")"); err != nil {
  188. return nil, err
  189. }
  190. if Verbose {
  191. log.Println("Created table " + name + " in database " + host.dbname)
  192. }
  193. return l, nil
  194. }
  195. // Add an element to the list
  196. func (l *List) Add(value string) error {
  197. if !l.host.rawUTF8 {
  198. Encode(&value)
  199. }
  200. _, err := l.host.db.Exec("INSERT INTO "+l.table+" ("+listCol+") VALUES (?)", value)
  201. return err
  202. }
  203. // Get all elements of a list
  204. func (l *List) All() ([]string, error) {
  205. rows, err := l.host.db.Query("SELECT " + listCol + " FROM " + l.table + " ORDER BY id")
  206. if err != nil {
  207. return []string{}, err
  208. }
  209. defer rows.Close()
  210. var (
  211. values []string
  212. value string
  213. )
  214. for rows.Next() {
  215. err = rows.Scan(&value)
  216. if !l.host.rawUTF8 {
  217. Decode(&value)
  218. }
  219. values = append(values, value)
  220. if err != nil {
  221. // Unusual, worthy of panic
  222. panic(err.Error())
  223. }
  224. }
  225. if err := rows.Err(); err != nil {
  226. // Unusual, worthy of panic
  227. panic(err.Error())
  228. }
  229. return values, nil
  230. }
  231. // Deprecated, please use .All() instead
  232. func (l *List) GetAll() ([]string, error) {
  233. return l.All()
  234. }
  235. // Get the last element of a list
  236. func (l *List) Last() (string, error) {
  237. // Fetches the item with the largest id.
  238. // Faster than "ORDER BY id DESC limit 1" for large tables.
  239. rows, err := l.host.db.Query("SELECT " + listCol + " FROM " + l.table + " WHERE id = (SELECT MAX(id) FROM " + l.table + ")")
  240. if err != nil {
  241. return "", err
  242. }
  243. defer rows.Close()
  244. var value string
  245. // Get the value. Will only loop once.
  246. for rows.Next() {
  247. err = rows.Scan(&value)
  248. if err != nil {
  249. // Unusual, worthy of panic
  250. panic(err.Error())
  251. }
  252. }
  253. if err := rows.Err(); err != nil {
  254. // Unusual, worthy of panic
  255. panic(err.Error())
  256. }
  257. if !l.host.rawUTF8 {
  258. Decode(&value)
  259. }
  260. return value, nil
  261. }
  262. // Deprecated, please use .Last() instead
  263. func (l *List) GetLast() (string, error) {
  264. return l.Last()
  265. }
  266. // Get the last N elements of a list
  267. func (l *List) LastN(n int) ([]string, error) {
  268. rows, err := l.host.db.Query("SELECT " + listCol + " FROM (SELECT * FROM " + l.table + " ORDER BY id DESC limit " + strconv.Itoa(n) + ")sub ORDER BY id ASC")
  269. if err != nil {
  270. return []string{}, err
  271. }
  272. defer rows.Close()
  273. var (
  274. values []string
  275. value string
  276. )
  277. for rows.Next() {
  278. err = rows.Scan(&value)
  279. if !l.host.rawUTF8 {
  280. Decode(&value)
  281. }
  282. values = append(values, value)
  283. if err != nil {
  284. // Unusual, worthy of panic
  285. panic(err.Error())
  286. }
  287. }
  288. if err := rows.Err(); err != nil {
  289. // Unusual, worthy of panic
  290. panic(err.Error())
  291. }
  292. if len(values) < n {
  293. return []string{}, errors.New("Too few elements in table at GetLastN")
  294. }
  295. return values, nil
  296. }
  297. // Deprecated, please use .LastN(n) instead
  298. func (l *List) GetLastN(n int) ([]string, error) {
  299. return l.LastN(n)
  300. }
  301. // Remove this list
  302. func (l *List) Remove() error {
  303. // Remove the table
  304. _, err := l.host.db.Exec("DROP TABLE " + l.table)
  305. return err
  306. }
  307. // Clear the list contents
  308. func (l *List) Clear() error {
  309. // Clear the table
  310. _, err := l.host.db.Exec("TRUNCATE TABLE " + l.table)
  311. return err
  312. }
  313. /* --- Set functions --- */
  314. // Create a new set
  315. func NewSet(host *Host, name string) (*Set, error) {
  316. s := &Set{host, name}
  317. if _, err := s.host.db.Exec("CREATE TABLE IF NOT EXISTS " + name + " (" + setCol + " " + defaultStringType + ")"); err != nil {
  318. return nil, err
  319. }
  320. if Verbose {
  321. log.Println("Created table " + name + " in database " + host.dbname)
  322. }
  323. return s, nil
  324. }
  325. // Add an element to the set
  326. func (s *Set) Add(value string) error {
  327. originalValue := value
  328. if !s.host.rawUTF8 {
  329. Encode(&value)
  330. }
  331. // Check if the value is not already there before adding
  332. has, err := s.Has(originalValue)
  333. if !has && (err == nil) {
  334. _, err = s.host.db.Exec("INSERT INTO "+s.table+" ("+setCol+") VALUES (?)", value)
  335. }
  336. return err
  337. }
  338. // Check if a given value is in the set
  339. func (s *Set) Has(value string) (bool, error) {
  340. if !s.host.rawUTF8 {
  341. Encode(&value)
  342. }
  343. rows, err := s.host.db.Query("SELECT "+setCol+" FROM "+s.table+" WHERE "+setCol+" = ?", value)
  344. if err != nil {
  345. return false, err
  346. }
  347. defer rows.Close()
  348. var scanValue string
  349. // Get the value. Should not loop more than once.
  350. counter := 0
  351. for rows.Next() {
  352. err = rows.Scan(&scanValue)
  353. if err != nil {
  354. // Unusual, worthy of panic
  355. panic(err.Error())
  356. }
  357. counter++
  358. }
  359. if err := rows.Err(); err != nil {
  360. // Unusual, worthy of panic
  361. panic(err.Error())
  362. }
  363. if counter > 1 {
  364. panic("Duplicate members in set! " + value)
  365. }
  366. return counter > 0, nil
  367. }
  368. // Get all elements of the set
  369. func (s *Set) All() ([]string, error) {
  370. rows, err := s.host.db.Query("SELECT " + setCol + " FROM " + s.table)
  371. if err != nil {
  372. return []string{}, err
  373. }
  374. defer rows.Close()
  375. var (
  376. values []string
  377. value string
  378. )
  379. for rows.Next() {
  380. err = rows.Scan(&value)
  381. if !s.host.rawUTF8 {
  382. Decode(&value)
  383. }
  384. values = append(values, value)
  385. if err != nil {
  386. // Unusual, worthy of panic
  387. panic(err.Error())
  388. }
  389. }
  390. if err := rows.Err(); err != nil {
  391. // Unusual, worthy of panic
  392. panic(err.Error())
  393. }
  394. return values, nil
  395. }
  396. // Deprecated, please use .All() instead
  397. func (s *Set) GetAll() ([]string, error) {
  398. return s.All()
  399. }
  400. // Remove an element from the set
  401. func (s *Set) Del(value string) error {
  402. if !s.host.rawUTF8 {
  403. Encode(&value)
  404. }
  405. // Remove a value from the table
  406. _, err := s.host.db.Exec("DELETE FROM "+s.table+" WHERE "+setCol+" = ?", value)
  407. return err
  408. }
  409. // Remove this set
  410. func (s *Set) Remove() error {
  411. // Remove the table
  412. _, err := s.host.db.Exec("DROP TABLE " + s.table)
  413. return err
  414. }
  415. // Clear the list contents
  416. func (s *Set) Clear() error {
  417. // Clear the table
  418. _, err := s.host.db.Exec("TRUNCATE TABLE " + s.table)
  419. return err
  420. }
  421. /* --- HashMap functions --- */
  422. // Create a new hashmap
  423. func NewHashMap(host *Host, name string) (*HashMap, error) {
  424. h := &HashMap{host, name}
  425. // Using three columns: element id, key and value
  426. query := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (%s %s, %s %s, %s %s)", name, ownerCol, defaultStringType, keyCol, defaultStringType, valCol, defaultStringType)
  427. if _, err := h.host.db.Exec(query); err != nil {
  428. return nil, err
  429. }
  430. if Verbose {
  431. log.Println("Created table " + name + " in database " + host.dbname)
  432. }
  433. return h, nil
  434. }
  435. // Set a value in a hashmap given the element id (for instance a user id) and the key (for instance "password")
  436. func (h *HashMap) Set(owner, key, value string) error {
  437. if !h.host.rawUTF8 {
  438. Encode(&value)
  439. }
  440. // See if the owner and key already exists
  441. ok, err := h.Has(owner, key)
  442. if err != nil {
  443. return err
  444. }
  445. if Verbose {
  446. log.Printf("%s/%s exists? %v\n", owner, key, ok)
  447. }
  448. if ok {
  449. _, err = h.host.db.Exec("UPDATE "+h.table+" SET "+valCol+" = ? WHERE "+ownerCol+" = ? AND "+keyCol+" = ?", value, owner, key)
  450. if Verbose {
  451. log.Println("Updated the table: " + h.table)
  452. }
  453. } else {
  454. _, err = h.host.db.Exec("INSERT INTO "+h.table+" ("+ownerCol+", "+keyCol+", "+valCol+") VALUES (?, ?, ?)", owner, key, value)
  455. if Verbose {
  456. log.Println("Added to the table: " + h.table)
  457. }
  458. }
  459. return err
  460. }
  461. // Get a value from a hashmap given the element id (for instance a user id) and the key (for instance "password").
  462. func (h *HashMap) Get(owner, key string) (string, error) {
  463. rows, err := h.host.db.Query("SELECT "+valCol+" FROM "+h.table+" WHERE "+ownerCol+" = ? AND "+keyCol+" = ?", owner, key)
  464. if err != nil {
  465. return "", err
  466. }
  467. defer rows.Close()
  468. var value string
  469. // Get the value. Should only loop once.
  470. counter := 0
  471. for rows.Next() {
  472. err = rows.Scan(&value)
  473. if err != nil {
  474. // Unusual, worthy of panic
  475. panic(err.Error())
  476. }
  477. counter++
  478. }
  479. if err := rows.Err(); err != nil {
  480. // Unusual, worthy of panic
  481. panic(err.Error())
  482. }
  483. if counter == 0 {
  484. return "", errors.New("No such owner/key: " + owner + "/" + key)
  485. }
  486. if !h.host.rawUTF8 {
  487. Decode(&value)
  488. }
  489. return value, nil
  490. }
  491. // Check if a given owner + key is in the hash map
  492. func (h *HashMap) Has(owner, key string) (bool, error) {
  493. rows, err := h.host.db.Query("SELECT "+valCol+" FROM "+h.table+" WHERE "+ownerCol+" = ? AND "+keyCol+" = ?", owner, key)
  494. if err != nil {
  495. return false, err
  496. }
  497. defer rows.Close()
  498. var value string
  499. // Get the value. Should only loop once.
  500. counter := 0
  501. for rows.Next() {
  502. err = rows.Scan(&value)
  503. if err != nil {
  504. // Unusual, worthy of panic
  505. panic(err.Error())
  506. }
  507. counter++
  508. }
  509. if err := rows.Err(); err != nil {
  510. // Unusual, worthy of panic
  511. panic(err.Error())
  512. }
  513. if counter > 1 {
  514. panic("Duplicate keys in hash map! " + value)
  515. }
  516. return counter > 0, nil
  517. }
  518. // Check if a given owner exists as a hash map at all
  519. func (h *HashMap) Exists(owner string) (bool, error) {
  520. rows, err := h.host.db.Query("SELECT "+valCol+" FROM "+h.table+" WHERE "+ownerCol+" = ?", owner)
  521. if err != nil {
  522. return false, err
  523. }
  524. defer rows.Close()
  525. var value string
  526. // Get the value. Should only loop once.
  527. counter := 0
  528. for rows.Next() {
  529. err = rows.Scan(&value)
  530. if err != nil {
  531. // Unusual, worthy of panic
  532. panic(err.Error())
  533. }
  534. counter++
  535. }
  536. if err := rows.Err(); err != nil {
  537. // Unusual, worthy of panic
  538. panic(err.Error())
  539. }
  540. return counter > 0, nil
  541. }
  542. // Get all owners (not keys, not values) for all hash elements
  543. func (h *HashMap) All() ([]string, error) {
  544. rows, err := h.host.db.Query("SELECT " + ownerCol + " FROM " + h.table)
  545. if err != nil {
  546. return []string{}, err
  547. }
  548. defer rows.Close()
  549. var (
  550. values []string
  551. value string
  552. )
  553. for rows.Next() {
  554. err = rows.Scan(&value)
  555. values = append(values, value)
  556. if err != nil {
  557. // Unusual, worthy of panic
  558. panic(err.Error())
  559. }
  560. }
  561. if err := rows.Err(); err != nil {
  562. // Unusual, worthy of panic
  563. panic(err.Error())
  564. }
  565. return values, nil
  566. }
  567. // Deprecated, please use .All() instead
  568. func (h *HashMap) GetAll() ([]string, error) {
  569. return h.All()
  570. }
  571. // Get all keys for a given owner
  572. func (h *HashMap) Keys(owner string) ([]string, error) {
  573. rows, err := h.host.db.Query("SELECT "+keyCol+" FROM "+h.table+" WHERE "+ownerCol+"= ?", owner)
  574. if err != nil {
  575. return []string{}, err
  576. }
  577. defer rows.Close()
  578. var (
  579. values []string
  580. value string
  581. )
  582. for rows.Next() {
  583. err = rows.Scan(&value)
  584. values = append(values, value)
  585. if err != nil {
  586. // Unusual, worthy of panic
  587. panic(err.Error())
  588. }
  589. }
  590. if err := rows.Err(); err != nil {
  591. // Unusual, worthy of panic
  592. panic(err.Error())
  593. }
  594. return values, nil
  595. }
  596. // Remove a key for an entry in a hashmap (for instance the email field for a user)
  597. func (h *HashMap) DelKey(owner, key string) error {
  598. // Remove a key from the hashmap
  599. _, err := h.host.db.Exec("DELETE FROM "+h.table+" WHERE "+ownerCol+" = ? AND "+keyCol+" = ?", owner, key)
  600. return err
  601. }
  602. // Remove an element (for instance a user)
  603. func (h *HashMap) Del(owner string) error {
  604. // Remove an element id from the table
  605. results, err := h.host.db.Exec("DELETE FROM "+h.table+" WHERE "+ownerCol+" = ?", owner)
  606. if err != nil {
  607. return err
  608. }
  609. n, err := results.RowsAffected()
  610. if err != nil {
  611. return err
  612. }
  613. if Verbose {
  614. log.Println(n, "rows were deleted with Del("+owner+")!")
  615. }
  616. return nil
  617. }
  618. // Remove this hashmap
  619. func (h *HashMap) Remove() error {
  620. // Remove the table
  621. _, err := h.host.db.Exec("DROP TABLE " + h.table)
  622. return err
  623. }
  624. // Clear the contents
  625. func (h *HashMap) Clear() error {
  626. // Clear the table
  627. _, err := h.host.db.Exec("TRUNCATE TABLE " + h.table)
  628. return err
  629. }
  630. /* --- KeyValue functions --- */
  631. // Create a new key/value
  632. func NewKeyValue(host *Host, name string) (*KeyValue, error) {
  633. kv := &KeyValue{host, name}
  634. query := fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (%s %s, %s %s)", name, keyCol, defaultStringType, valCol, defaultStringType)
  635. if _, err := kv.host.db.Exec(query); err != nil {
  636. return nil, err
  637. }
  638. if Verbose {
  639. log.Println("Created table " + name + " in database " + host.dbname)
  640. }
  641. return kv, nil
  642. }
  643. // Set a key and value
  644. func (kv *KeyValue) Set(key, value string) error {
  645. if !kv.host.rawUTF8 {
  646. Encode(&value)
  647. }
  648. if _, err := kv.Get(key); err != nil {
  649. // Key does not exist, create it
  650. _, err = kv.host.db.Exec("INSERT INTO "+kv.table+" ("+keyCol+", "+valCol+") VALUES (?, ?)", key, value)
  651. return err
  652. }
  653. // Key exists, update the value
  654. _, err := kv.host.db.Exec("UPDATE "+kv.table+" SET "+valCol+" = ? WHERE "+keyCol+" = ?", value, key)
  655. return err
  656. }
  657. // Get a value given a key
  658. func (kv *KeyValue) Get(key string) (string, error) {
  659. rows, err := kv.host.db.Query("SELECT "+valCol+" FROM "+kv.table+" WHERE "+keyCol+" = ?", key)
  660. if err != nil {
  661. return "", err
  662. }
  663. defer rows.Close()
  664. var value string
  665. // Get the value. Should only loop once.
  666. counter := 0
  667. for rows.Next() {
  668. err = rows.Scan(&value)
  669. if err != nil {
  670. // Unusual, worthy of panic
  671. panic(err.Error())
  672. }
  673. counter++
  674. }
  675. if err := rows.Err(); err != nil {
  676. // Unusual, worthy of panic
  677. panic(err.Error())
  678. }
  679. if counter != 1 {
  680. return "", errors.New("Wrong number of keys in KeyValue table: " + kv.table)
  681. }
  682. if !kv.host.rawUTF8 {
  683. Decode(&value)
  684. }
  685. return value, nil
  686. }
  687. // Increase the value of a key, returns the new value
  688. // Returns an empty string if there were errors,
  689. // or "0" if the key does not already exist.
  690. func (kv *KeyValue) Inc(key string) (string, error) {
  691. // Retreieve the current value, if any
  692. num := 0
  693. // See if we can fetch an existing value. NOTE: "== nil"
  694. if val, err := kv.Get(key); err == nil {
  695. // See if we can convert the value to a number. NOTE: "== nil"
  696. if converted, err2 := strconv.Atoi(val); err2 == nil {
  697. num = converted
  698. }
  699. } else {
  700. // The key does not exist, create a new one.
  701. // This is to reflect the behavior of INCR in Redis.
  702. NewKeyValue(kv.host, kv.table)
  703. }
  704. // Num is now either 0 or the previous numeric value
  705. num++
  706. // Convert the new value to a string
  707. val := strconv.Itoa(num)
  708. // Store the new number
  709. if err := kv.Set(key, val); err != nil {
  710. // Saving the value failed
  711. return "0", err
  712. }
  713. // Success
  714. return val, nil
  715. }
  716. // Remove a key
  717. func (kv *KeyValue) Del(key string) error {
  718. _, err := kv.host.db.Exec("DELETE FROM "+kv.table+" WHERE "+keyCol+" = ?", key)
  719. return err
  720. }
  721. // Remove this key/value
  722. func (kv *KeyValue) Remove() error {
  723. // Remove the table
  724. _, err := kv.host.db.Exec("DROP TABLE " + kv.table)
  725. return err
  726. }
  727. // Clear this key/value
  728. func (kv *KeyValue) Clear() error {
  729. // Remove the table
  730. _, err := kv.host.db.Exec("TRUNCATE TABLE " + kv.table)
  731. return err
  732. }