Browse Source

benjojo made me rewrite this and it's actually good now

master
eta 2 months ago
commit
5896386f2e
  1. 1
      .gitignore
  2. 8
      .idea/.gitignore
  3. 9
      .idea/etascrobbler-ng.iml
  4. 8
      .idea/modules.xml
  5. 4
      Makefile
  6. 274
      etascrobbler.go
  7. 13
      go.mod
  8. 10
      go.sum
  9. 1
      vendor/crawshaw.io/sqlite/.gitignore
  10. 11
      vendor/crawshaw.io/sqlite/.travis.yml
  11. 13
      vendor/crawshaw.io/sqlite/LICENSE
  12. 74
      vendor/crawshaw.io/sqlite/Makefile
  13. 52
      vendor/crawshaw.io/sqlite/README.md
  14. 25
      vendor/crawshaw.io/sqlite/appveyor.yml
  15. 359
      vendor/crawshaw.io/sqlite/auth.go
  16. 133
      vendor/crawshaw.io/sqlite/backup.go
  17. 189
      vendor/crawshaw.io/sqlite/blob.go
  18. 61
      vendor/crawshaw.io/sqlite/blocking_step.c
  19. 17
      vendor/crawshaw.io/sqlite/blocking_step.h
  20. 7
      vendor/crawshaw.io/sqlite/c/dummy.go
  21. 229615
      vendor/crawshaw.io/sqlite/c/sqlite3.c
  22. 144
      vendor/crawshaw.io/sqlite/doc.go
  23. 18
      vendor/crawshaw.io/sqlite/dummy.go
  24. 389
      vendor/crawshaw.io/sqlite/error.go
  25. 59
      vendor/crawshaw.io/sqlite/extension.go
  26. 233
      vendor/crawshaw.io/sqlite/func.go
  27. 62
      vendor/crawshaw.io/sqlite/incrementor.go
  28. 20
      vendor/crawshaw.io/sqlite/link.go
  29. 850
      vendor/crawshaw.io/sqlite/session.go
  30. 192
      vendor/crawshaw.io/sqlite/snapshot.go
  31. 1222
      vendor/crawshaw.io/sqlite/sqlite.go
  32. 12168
      vendor/crawshaw.io/sqlite/sqlite3.h
  33. 659
      vendor/crawshaw.io/sqlite/sqlite3ext.h
  34. 318
      vendor/crawshaw.io/sqlite/sqlitex/buffer.go
  35. 199
      vendor/crawshaw.io/sqlite/sqlitex/exec.go
  36. 316
      vendor/crawshaw.io/sqlite/sqlitex/file.go
  37. 281
      vendor/crawshaw.io/sqlite/sqlitex/pool.go
  38. 74
      vendor/crawshaw.io/sqlite/sqlitex/query.go
  39. 55
      vendor/crawshaw.io/sqlite/sqlitex/rand_id.go
  40. 139
      vendor/crawshaw.io/sqlite/sqlitex/savepoint.go
  41. 52
      vendor/crawshaw.io/sqlite/sqlitex/snapshot.go
  42. 20
      vendor/crawshaw.io/sqlite/static.go
  43. 49
      vendor/crawshaw.io/sqlite/wrappers.c
  44. 31
      vendor/crawshaw.io/sqlite/wrappers.h
  45. 3
      vendor/golang.org/x/crypto/AUTHORS
  46. 3
      vendor/golang.org/x/crypto/CONTRIBUTORS
  47. 27
      vendor/golang.org/x/crypto/LICENSE
  48. 22
      vendor/golang.org/x/crypto/PATENTS
  49. 804
      vendor/golang.org/x/crypto/acme/acme.go
  50. 1198
      vendor/golang.org/x/crypto/acme/autocert/autocert.go
  51. 136
      vendor/golang.org/x/crypto/acme/autocert/cache.go
  52. 155
      vendor/golang.org/x/crypto/acme/autocert/listener.go
  53. 156
      vendor/golang.org/x/crypto/acme/autocert/renewal.go
  54. 325
      vendor/golang.org/x/crypto/acme/http.go
  55. 232
      vendor/golang.org/x/crypto/acme/jws.go
  56. 438
      vendor/golang.org/x/crypto/acme/rfc8555.go
  57. 614
      vendor/golang.org/x/crypto/acme/types.go
  58. 28
      vendor/golang.org/x/crypto/acme/version_go112.go
  59. 3
      vendor/golang.org/x/net/AUTHORS
  60. 3
      vendor/golang.org/x/net/CONTRIBUTORS
  61. 27
      vendor/golang.org/x/net/LICENSE
  62. 22
      vendor/golang.org/x/net/PATENTS
  63. 14
      vendor/golang.org/x/net/idna/go118.go
  64. 770
      vendor/golang.org/x/net/idna/idna10.0.0.go
  65. 718
      vendor/golang.org/x/net/idna/idna9.0.0.go
  66. 12
      vendor/golang.org/x/net/idna/pre_go118.go
  67. 217
      vendor/golang.org/x/net/idna/punycode.go
  68. 4560
      vendor/golang.org/x/net/idna/tables10.0.0.go
  69. 4654
      vendor/golang.org/x/net/idna/tables11.0.0.go
  70. 4734
      vendor/golang.org/x/net/idna/tables12.0.0.go
  71. 4840
      vendor/golang.org/x/net/idna/tables13.0.0.go
  72. 4487
      vendor/golang.org/x/net/idna/tables9.0.0.go
  73. 72
      vendor/golang.org/x/net/idna/trie.go
  74. 119
      vendor/golang.org/x/net/idna/trieval.go
  75. 3
      vendor/golang.org/x/text/AUTHORS
  76. 3
      vendor/golang.org/x/text/CONTRIBUTORS
  77. 27
      vendor/golang.org/x/text/LICENSE
  78. 22
      vendor/golang.org/x/text/PATENTS
  79. 336
      vendor/golang.org/x/text/secure/bidirule/bidirule.go
  80. 12
      vendor/golang.org/x/text/secure/bidirule/bidirule10.0.0.go
  81. 15
      vendor/golang.org/x/text/secure/bidirule/bidirule9.0.0.go
  82. 709
      vendor/golang.org/x/text/transform/transform.go
  83. 359
      vendor/golang.org/x/text/unicode/bidi/bidi.go
  84. 335
      vendor/golang.org/x/text/unicode/bidi/bracket.go
  85. 1071
      vendor/golang.org/x/text/unicode/bidi/core.go
  86. 206
      vendor/golang.org/x/text/unicode/bidi/prop.go
  87. 1816
      vendor/golang.org/x/text/unicode/bidi/tables10.0.0.go
  88. 1888
      vendor/golang.org/x/text/unicode/bidi/tables11.0.0.go
  89. 1924
      vendor/golang.org/x/text/unicode/bidi/tables12.0.0.go
  90. 1956
      vendor/golang.org/x/text/unicode/bidi/tables13.0.0.go
  91. 1782
      vendor/golang.org/x/text/unicode/bidi/tables9.0.0.go
  92. 60
      vendor/golang.org/x/text/unicode/bidi/trieval.go
  93. 512
      vendor/golang.org/x/text/unicode/norm/composition.go
  94. 278
      vendor/golang.org/x/text/unicode/norm/forminfo.go
  95. 109
      vendor/golang.org/x/text/unicode/norm/input.go
  96. 458
      vendor/golang.org/x/text/unicode/norm/iter.go
  97. 609
      vendor/golang.org/x/text/unicode/norm/normalize.go
  98. 125
      vendor/golang.org/x/text/unicode/norm/readwriter.go
  99. 7658
      vendor/golang.org/x/text/unicode/norm/tables10.0.0.go
  100. 7694
      vendor/golang.org/x/text/unicode/norm/tables11.0.0.go
  101. Some files were not shown because too many files have changed in this diff Show More

1
.gitignore vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
etascrobbler-ng

8
.idea/.gitignore vendored

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

9
.idea/etascrobbler-ng.iml

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="WEB_MODULE" version="4">
<component name="Go" enabled="true" />
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

8
.idea/modules.xml

@ -0,0 +1,8 @@ @@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/etascrobbler-ng.iml" filepath="$PROJECT_DIR$/.idea/etascrobbler-ng.iml" />
</modules>
</component>
</project>

4
Makefile

@ -0,0 +1,4 @@ @@ -0,0 +1,4 @@
.PHONY: all
all:
CC=musl-gcc go build -ldflags='-extldflags=-static'

274
etascrobbler.go

@ -0,0 +1,274 @@ @@ -0,0 +1,274 @@
package main
import (
"bytes"
"context"
"crawshaw.io/sqlite/sqlitex"
"encoding/json"
"errors"
"flag"
"golang.org/x/crypto/acme/autocert"
"html/template"
"io"
"log"
"net/http"
"strconv"
"time"
)
var databasePath = flag.String("database", "./data.sqlite3", "database path")
var pageTemplate = `{{ define "base" }}
<!DOCTYPE html>
<html lang='en'>
<head>
<title>etascrobbler</title>
<link rel='stylesheet' type='text/css' href='//eta.st/assets/webfonts/stylesheet.css'>
<link rel='stylesheet' type='text/css' href='//eta.st/css/main.css'>
<meta name='viewport' content='width=device-width,initial-scale=1'>
</head>
<header class='site-header'>
<div class='wrapper'>
<a class='site-title' href='/'>
<img src='//eta.st/assets/img/logo.svg' alt='ฮท'>(eta)
</a>
<nav class='site-nav'>
<div class='trigger'>etascrobbler</div>
</nav>
</div>
</header>
<div class='page-content'>
<div class='wrapper'>
<h1>now playing</h1>
<p>
This shows what I was last listening to on any of my devices, and the song before that. This tiny webapp has observed <b>{{ .TotalSongs }}</b>
songs being played so far.
</p>
<p>This site is very beta. More information should be added shortly!</p>
{{if .SomethingPlaying}}
<div class="book-meta">
<p class="book-title">๐ŸŽต {{ .CurrentTrack.Artist }} โ€” {{ .CurrentTrack.Name }}
</div>
{{end}}
<p>
<i>Previously: </i>
{{ .PreviousTrack.Artist }} โ€” {{ .PreviousTrack.Name }}
</p>
<p class='detail'>
Artists (<strong>{{ .TotalArtists }}</strong>): {{range .Artists}}{{.}} &middot; {{end}}
</p>
</div>
</div>
</html>
{{ end }}
`
var tmpl *template.Template = template.Must(template.New("base").Parse(pageTemplate))
var dbpool *sqlitex.Pool
type Scrobble struct {
Artist string `json:"artist"`
Name string `json:"track"`
Ts time.Time
}
var currentScrobble *Scrobble
func getLastScrobble() (s *Scrobble, err error) {
conn := dbpool.Get(context.Background())
if conn == nil {
err = errors.New("no connection whoopsie")
return s, err
}
defer dbpool.Put(conn)
stmt := conn.Prep("SELECT artist, title FROM plays ORDER BY ts DESC LIMIT 1")
hasRow, err := stmt.Step()
if hasRow {
s = &Scrobble{
Artist: stmt.GetText("artist"),
Name: stmt.GetText("title"),
// FIXME(eta): lol don't actually set `ts` because who cares
}
stmt.Step()
return s, nil
} else {
return s, nil
}
}
func getAllArtists() (artists []string, err error) {
conn := dbpool.Get(context.Background())
if conn == nil {
err = errors.New("no connection whoopsie")
return nil, err
}
defer dbpool.Put(conn)
artists = make([]string, 0)
stmt := conn.Prep("SELECT DISTINCT artist FROM plays ORDER BY artist ASC")
for {
hasRow, err := stmt.Step()
if err != nil {
return nil, err
} else if hasRow {
artists = append(artists, stmt.GetText("artist"))
} else {
break
}
}
return artists, nil
}
func countAllScrobbles() (count int64, err error) {
conn := dbpool.Get(context.Background())
if conn == nil {
err = errors.New("no connection whoopsie")
return -1, err
}
defer dbpool.Put(conn)
stmt := conn.Prep("SELECT COUNT(*) AS c FROM plays")
hasRow, err := stmt.Step()
if hasRow {
count = stmt.GetInt64("c")
stmt.Step()
return count, nil
} else {
err = errors.New("wut")
return -1, nil
}
}
type ListenBrainzPayload struct {
ListenedAt interface{} `json:"listened_at"`
TrackMetadata struct {
ArtistName string `json:"artist_name"`
ReleaseName string `json:"release_name"`
TrackName string `json:"track_name"`
} `json:"track_metadata"`
}
func (payload *ListenBrainzPayload) fudgeListenedAt() int64 {
data, ok := payload.ListenedAt.(string)
if ok {
ret, _ := strconv.Atoi(data)
return int64(ret)
}
data2, ok := payload.ListenedAt.(int64)
if ok {
return data2
}
return 0
}
func insertTrack(track ListenBrainzPayload) (err error) {
conn := dbpool.Get(context.Background())
if conn == nil {
err = errors.New("no connection whoopsie")
return
}
defer dbpool.Put(conn)
stmt := conn.Prep("INSERT INTO plays (artist, title, ts) VALUES (?, ?, ?)")
stmt.BindText(1, track.TrackMetadata.ArtistName)
stmt.BindText(2, track.TrackMetadata.TrackName)
stmt.BindInt64(3, track.fudgeListenedAt())
_, err = stmt.Step()
return
}
type SubmitListens struct {
ListenType string `json:"listen_type"`
Payload []ListenBrainzPayload `json:"payload"`
}
func validateToken(w http.ResponseWriter, r *http.Request) {
log.Printf("validate token")
r.Header.Set("Content-Type", "application/json")
w.Write([]byte(`{"code": 200, "message": "wiggly donkers", "valid": true, "user": "eta"}`))
}
func submitListen(w http.ResponseWriter, r *http.Request) {
var payload SubmitListens
body, err := io.ReadAll(r.Body)
if err != nil {
panic(err)
}
log.Printf("submit listen: %v", string(body))
err = json.NewDecoder(bytes.NewReader(body)).Decode(&payload)
if err != nil {
panic(err)
}
log.Printf("parsed: %#v\n", payload)
if payload.ListenType == "playing_now" {
currentScrobble = &Scrobble{
Artist: payload.Payload[0].TrackMetadata.ArtistName,
Name: payload.Payload[0].TrackMetadata.TrackName,
Ts: time.Now(),
}
log.Printf("now playing: %v โ€” %v", currentScrobble.Artist, currentScrobble.Name)
} else if payload.ListenType == "single" || payload.ListenType == "import" {
log.Printf("submission of type %v", payload.ListenType)
for _, item := range payload.Payload {
log.Printf("inserting: %v โ€” %v", item.TrackMetadata.ArtistName, item.TrackMetadata.TrackName)
err := insertTrack(item)
if err != nil {
panic(err)
}
}
}
r.Header.Set("Content-Type", "application/json")
w.Write([]byte(`{"status": "ok"}`))
}
func nowPlayingJson(w http.ResponseWriter, r *http.Request) {
log.Printf("now playing")
if currentScrobble == nil {
http.NotFound(w, r)
return
}
if time.Since(currentScrobble.Ts) > 30*time.Minute {
http.NotFound(w, r)
return
}
r.Header.Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(*currentScrobble)
}
func rootPage(w http.ResponseWriter, r *http.Request) {
log.Printf("root page %v", r.URL.String())
pageData := make(map[string]interface{})
var err error
pageData["TotalSongs"], err = countAllScrobbles()
if err != nil {
log.Fatalf("failed to count scrobbles: %v", err)
}
artists, err := getAllArtists()
if err != nil {
log.Fatalf("failed to get artists: %v", err)
}
pageData["Artists"] = artists
pageData["TotalArtists"] = len(artists)
pageData["PreviousTrack"], err = getLastScrobble()
if err != nil {
log.Fatalf("failed to get last scrobble: %v", err)
}
pageData["SomethingPlaying"] = currentScrobble != nil
if currentScrobble != nil {
pageData["CurrentTrack"] = *currentScrobble
}
tmpl.ExecuteTemplate(w, "base", pageData)
}
func main() {
flag.Parse()
var err error
dbpool, err = sqlitex.Open(*databasePath, 0, 10)
if err != nil {
log.Fatal(err)
}
mux := http.NewServeMux()
mux.HandleFunc("/", rootPage)
mux.HandleFunc("/now-playing.json", nowPlayingJson)
mux.HandleFunc("/1/validate-token", validateToken)
mux.HandleFunc("/1/submit-listens", submitListen)
log.Fatal(http.Serve(autocert.NewListener("etascrobbler.i.eta.st"), mux))
}

13
go.mod

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
module etascrobbler-ng
go 1.17
require (
crawshaw.io/sqlite v0.3.2
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f
)
require (
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
golang.org/x/text v0.3.6 // indirect
)

10
go.sum

@ -0,0 +1,10 @@ @@ -0,0 +1,10 @@
crawshaw.io/iox v0.0.0-20181124134642-c51c3df30797/go.mod h1:sXBiorCo8c46JlQV3oXPKINnZ8mcqnye1EkVkqsectk=
crawshaw.io/sqlite v0.3.2 h1:N6IzTjkiw9FItHAa0jp+ZKC6tuLzXqAYIv+ccIWos1I=
crawshaw.io/sqlite v0.3.2/go.mod h1:igAO5JulrQ1DbdZdtVq48mnZUBAPOeFzer7VhDWNtW4=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=

1
vendor/crawshaw.io/sqlite/.gitignore generated vendored

@ -0,0 +1 @@ @@ -0,0 +1 @@
sqlite3.o

11
vendor/crawshaw.io/sqlite/.travis.yml generated vendored

@ -0,0 +1,11 @@ @@ -0,0 +1,11 @@
language: "go"
go:
- "1.13.x"
os:
- "linux"
- "osx"
script:
- make test

13
vendor/crawshaw.io/sqlite/LICENSE generated vendored

@ -0,0 +1,13 @@ @@ -0,0 +1,13 @@
Copyright (c) 2018 David Crawshaw <david@zentus.com>
Permission to use, copy, modify, and distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.

74
vendor/crawshaw.io/sqlite/Makefile generated vendored

@ -0,0 +1,74 @@ @@ -0,0 +1,74 @@
## Copyright (c) 2018 David Crawshaw <david@zentus.com>
##
## Permission to use, copy, modify, and distribute this software for any
## purpose with or without fee is hereby granted, provided that the above
## copyright notice and this permission notice appear in all copies.
##
## THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
## WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
## MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
## ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
## WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
## ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
## OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
# This Makefile is simply for development purposes. Normally, when this package
# is imported, Go will build the ./c/sqlite.c file that is included directly by
# static.go. However this is pretty slow ~30s. When developing this is very
# annoying. Use this Makefile to pre-build the sqlite3.o object and then build
# the package with the build tag linksqlite3, which will ignore static.go and
# use link.go instead to link against sqlite.o. This reduces compilation times
# down to <3 sec!
#
# If you are using an editor that builds the project as you work on it, you'll
# want to build the sqlite3.o object and tell your editor to use the
# linksqlite3 go build tag when working on this project.
# For vim-go, use the command `GoBuildTags linksqlite3` or
# `let g:go_build_tags = # 'linksqlite3'`
export GOFLAGS=-tags=linksqlite3
.PHONY: clean all env test release
all: sqlite3.o
go build ./...
test: sqlite3.o
go test ./...
test-race: sqlite3.o
go test -race ./...
env:
go env
## This builds the package statically.
release:
go build -tags=!linksqlite3
VPATH = ./c # Look in ./c for source files
# !!! THESE DEFINES SHOULD MATCH sqlite.go for linux !!!
CFLAGS += -std=c99
CFLAGS += -DSQLITE_THREADSAFE=2
CFLAGS += -DSQLITE_DEFAULT_WAL_SYNCHRONOUS=1
CFLAGS += -DSQLITE_ENABLE_UNLOCK_NOTIFY
CFLAGS += -DSQLITE_ENABLE_FTS5
CFLAGS += -DSQLITE_ENABLE_RTREE
CFLAGS += -DSQLITE_LIKE_DOESNT_MATCH_BLOBS
CFLAGS += -DSQLITE_OMIT_DEPRECATED
CFLAGS += -DSQLITE_ENABLE_JSON1
CFLAGS += -DSQLITE_ENABLE_SESSION
CFLAGS += -DSQLITE_ENABLE_SNAPSHOT
CFLAGS += -DSQLITE_ENABLE_PREUPDATE_HOOK
CFLAGS += -DSQLITE_USE_ALLOCA
CFLAGS += -DSQLITE_ENABLE_COLUMN_METADATA
CFLAGS += -DHAVE_USLEEP=1
CFLAGS += -DSQLITE_DQS=0
CFLAGS += -DSQLITE_ENABLE_GEOPOLY
LDFLAGS = -ldl -lm
# !!! THESE DEFINES SHOULD MATCH sqlite.go !!!
sqlite3.o: sqlite3.c sqlite3.h sqlite3ext.h
clean:
rm -f sqlite3.o

52
vendor/crawshaw.io/sqlite/README.md generated vendored

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
# Go interface to SQLite.
[![GoDoc](https://godoc.org/crawshaw.io/sqlite?status.svg)](https://godoc.org/crawshaw.io/sqlite) [![Build Status](https://travis-ci.org/crawshaw/sqlite.svg?branch=master)](https://travis-ci.org/crawshaw/sqlite) (linux and macOS) [![Build status](https://ci.appveyor.com/api/projects/status/jh9xx6cut73ufkl8?svg=true)](https://ci.appveyor.com/project/crawshaw/sqlite) (windows)
This package provides a low-level Go interface to SQLite 3. Connections are [pooled](https://godoc.org/crawshaw.io/sqlite#Pool) and if the SQLite [shared cache](https://www.sqlite.org/sharedcache.html) mode is enabled the package takes advantage of the [unlock-notify API](https://www.sqlite.org/unlock_notify.html) to minimize the amount of handling user code needs for dealing with database lock contention.
It has interfaces for some of SQLite's more interesting extensions, such as [incremental BLOB I/O](https://www.sqlite.org/c3ref/blob_open.html) and the [session extension](https://www.sqlite.org/sessionintro.html).
A utility package, [sqlitex](https://godoc.org/crawshaw.io/sqlite/sqlitex), provides some higher-level tools for making it easier to perform common tasks with SQLite. In particular it provides support to make nested transactions easy to use via [sqlitex.Save](https://godoc.org/crawshaw.io/sqlite/sqlitex#Save).
This is not a database/sql driver.
```go get -u crawshaw.io/sqlite```
## Example
A HTTP handler that uses a multi-threaded pool of SQLite connections via a shared cache.
```go
var dbpool *sqlitex.Pool
func main() {
var err error
dbpool, err = sqlitex.Open("file:memory:?mode=memory", 0, 10)
if err != nil {
log.Fatal(err)
}
http.HandleFunc("/", handler)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func handler(w http.ResponseWriter, r *http.Request) {
conn := dbpool.Get(r.Context())
if conn == nil {
return
}
defer dbpool.Put(conn)
stmt := conn.Prep("SELECT foo FROM footable WHERE id = $id;")
stmt.SetText("$id", "_user_id_")
for {
if hasRow, err := stmt.Step(); err != nil {
// ... handle error
} else if !hasRow {
break
}
foo := stmt.GetText("foo")
// ... use foo
}
}
```
https://godoc.org/crawshaw.io/sqlite

25
vendor/crawshaw.io/sqlite/appveyor.yml generated vendored

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
version: "{build}"
platform: "mingw"
# Source Config
clone_folder: C:\gopath\src\crawshaw.io\sqlite
# Build host
environment:
GOPATH: C:\gopath
# Build
install:
- set PATH=C:\go\bin;C:\gopath\bin;C:\mingw-w64\x86_64-7.3.0-posix-seh-rt_v5-rev0\mingw64\bin;%PATH%
- go version
- go env
build: false
deploy: false
test_script:
- go get -v -t ./...
- go test -v ./...

359
vendor/crawshaw.io/sqlite/auth.go generated vendored

@ -0,0 +1,359 @@ @@ -0,0 +1,359 @@
package sqlite
// #include <stdint.h>
// #include <sqlite3.h>
// extern int go_sqlite_auth_tramp(uintptr_t, int, char*, char*, char*, char*);
// static int c_auth_tramp(void *userData, int action, const char* arg1, const char* arg2, const char* db, const char* trigger) {
// return go_sqlite_auth_tramp((uintptr_t)userData, action, (char*)arg1, (char*)arg2, (char*)db, (char*)trigger);
// }
// static int sqlite3_go_set_authorizer(sqlite3* conn, uintptr_t id) {
// return sqlite3_set_authorizer(conn, c_auth_tramp, (void*)id);
// }
import "C"
import (
"errors"
"fmt"
"strings"
"sync"
)
// An Authorizer is called during statement preparation to see whether an action
// is allowed by the application. See https://sqlite.org/c3ref/set_authorizer.html
type Authorizer interface {
Authorize(info ActionInfo) AuthResult
}
// SetAuthorizer registers an authorizer for the database connection.
// SetAuthorizer(nil) clears any authorizer previously set.
func (conn *Conn) SetAuthorizer(auth Authorizer) error {
if auth == nil {
if conn.authorizer == -1 {
return nil
}
conn.releaseAuthorizer()
res := C.sqlite3_set_authorizer(conn.conn, nil, nil)
return reserr("SetAuthorizer", "", "", res)
}
authFuncs.mu.Lock()
id := authFuncs.next
next := authFuncs.next + 1
if next < 0 {
authFuncs.mu.Unlock()
return errors.New("sqlite: authorizer function id overflow")
}
authFuncs.next = next
authFuncs.m[id] = auth
authFuncs.mu.Unlock()
res := C.sqlite3_go_set_authorizer(conn.conn, C.uintptr_t(id))
return reserr("SetAuthorizer", "", "", res)
}
func (conn *Conn) releaseAuthorizer() {
if conn.authorizer == -1 {
return
}
authFuncs.mu.Lock()
delete(authFuncs.m, conn.authorizer)
authFuncs.mu.Unlock()
conn.authorizer = -1
}
var authFuncs = struct {
mu sync.RWMutex
m map[int]Authorizer
next int
}{
m: make(map[int]Authorizer),
}
//export go_sqlite_auth_tramp
func go_sqlite_auth_tramp(id uintptr, action C.int, cArg1, cArg2 *C.char, cDB *C.char, cTrigger *C.char) C.int {
authFuncs.mu.RLock()
auth := authFuncs.m[int(id)]
authFuncs.mu.RUnlock()
var arg1, arg2, database, trigger string
if cArg1 != nil {
arg1 = C.GoString(cArg1)
}
if cArg2 != nil {
arg2 = C.GoString(cArg2)
}
if cDB != nil {
database = C.GoString(cDB)
}
if cTrigger != nil {
trigger = C.GoString(cTrigger)
}
return C.int(auth.Authorize(newActionInfo(OpType(action), arg1, arg2, database, trigger)))
}
// AuthorizeFunc is a function that implements Authorizer.
type AuthorizeFunc func(info ActionInfo) AuthResult
// Authorize calls f.
func (f AuthorizeFunc) Authorize(info ActionInfo) AuthResult {
return f(info)
}
// AuthResult is the result of a call to an Authorizer. The zero value is
// SQLITE_OK.
type AuthResult int
// Possible return values of an Authorizer.
const (
// Cause the entire SQL statement to be rejected with an error.
SQLITE_DENY = AuthResult(C.SQLITE_DENY)
// Disallow the specific action but allow the SQL statement to continue to
// be compiled.
SQLITE_IGNORE = AuthResult(C.SQLITE_IGNORE)
)
// String returns the C constant name of the result.
func (result AuthResult) String() string {
switch result {
default:
var buf [20]byte
return "SQLITE_UNKNOWN_AUTH_RESULT(" + string(itoa(buf[:], int64(result))) + ")"
case AuthResult(C.SQLITE_OK):
return "SQLITE_OK"
case SQLITE_DENY:
return "SQLITE_DENY"
case SQLITE_IGNORE:
return "SQLITE_IGNORE"
}
}
// ActionInfo holds information about an action to be authorized.
//
// Only the fields relevant to the Action are populated when this is passed to
// an Authorizer.
//
// https://sqlite.org/c3ref/c_alter_table.html
type ActionInfo struct {
Action OpType
Index string
Table string
Column string
Trigger string
View string
Function string
Pragma string
PragmaArg string
Operation string
Filename string
Module string
Database string
Savepoint string
InnerMostTrigger string
}
// newActionInfo returns an ActionInfo with the correct fields relevant to the
// action.
func newActionInfo(action OpType, arg1, arg2, database, trigger string) ActionInfo {
// We use the blank identifier with unused args below simply for visual
// consistency between the cases.
a := ActionInfo{Action: action, Database: database, InnerMostTrigger: trigger}
switch action {
case SQLITE_DROP_INDEX,
SQLITE_DROP_TEMP_INDEX,
SQLITE_CREATE_INDEX,
SQLITE_CREATE_TEMP_INDEX:
/* Index Name Table Name */
a.Index = arg1
a.Table = arg2
case SQLITE_DELETE,
SQLITE_DROP_TABLE,
SQLITE_DROP_TEMP_TABLE,
SQLITE_INSERT,
SQLITE_ANALYZE,
SQLITE_CREATE_TABLE,
SQLITE_CREATE_TEMP_TABLE:
/* Table Name NULL */
a.Table = arg1
_ = arg2
case SQLITE_CREATE_TEMP_TRIGGER,
SQLITE_CREATE_TRIGGER,
SQLITE_DROP_TEMP_TRIGGER,
SQLITE_DROP_TRIGGER:
/* Trigger Name Table Name */
a.Trigger = arg1
a.Table = arg2
case SQLITE_CREATE_TEMP_VIEW,
SQLITE_CREATE_VIEW,
SQLITE_DROP_TEMP_VIEW,
SQLITE_DROP_VIEW:
/* View Name NULL */
a.View = arg1
_ = arg2
case SQLITE_PRAGMA:
/* Pragma Name 1st arg or NULL */
a.Pragma = arg1
a.PragmaArg = arg2
case SQLITE_READ,
SQLITE_UPDATE:
/* Table Name Column Name */
a.Table = arg1
a.Column = arg2
case SQLITE_TRANSACTION:
/* Operation NULL */
a.Operation = arg1
_ = arg2
case SQLITE_ATTACH:
/* Filename NULL */
a.Filename = arg1
_ = arg2
case SQLITE_DETACH:
/* Database Name NULL */
a.Database = arg1
_ = arg2
case SQLITE_ALTER_TABLE:
/* Database Name Table Name */
a.Database = arg1
a.Table = arg2
case SQLITE_REINDEX:
/* Index Name NULL */
a.Index = arg1
_ = arg2
case SQLITE_CREATE_VTABLE,
SQLITE_DROP_VTABLE:
/* Table Name Module Name */
a.Table = arg1
a.Module = arg2
case SQLITE_FUNCTION:
/* NULL Function Name */
_ = arg1
a.Function = arg2
case SQLITE_SAVEPOINT:
/* Operation Savepoint Name */
a.Operation = arg1
a.Savepoint = arg2
case SQLITE_RECURSIVE,
SQLITE_SELECT:
/* NULL NULL */
_ = arg1
_ = arg2
case SQLITE_COPY:
/* No longer used */
default:
panic(fmt.Errorf("unknown action: %v", action))
}
return a
}
// String returns a string describing only the fields relevant to `a.Action`.
func (a ActionInfo) String() string {
switch a.Action {
case SQLITE_DROP_INDEX,
SQLITE_DROP_TEMP_INDEX,
SQLITE_CREATE_INDEX,
SQLITE_CREATE_TEMP_INDEX:
/* Index Name Table Name */
return fmt.Sprintf("%v: Index: %q Table: %q",
a.Action, a.Index, a.Table)
case SQLITE_DELETE,
SQLITE_DROP_TABLE,
SQLITE_DROP_TEMP_TABLE,
SQLITE_INSERT,
SQLITE_ANALYZE,
SQLITE_CREATE_TABLE,
SQLITE_CREATE_TEMP_TABLE:
/* Table Name NULL */
return fmt.Sprintf("%v: Table: %q", a.Action, a.Table)
case SQLITE_CREATE_TEMP_TRIGGER,
SQLITE_CREATE_TRIGGER,
SQLITE_DROP_TEMP_TRIGGER,
SQLITE_DROP_TRIGGER:
/* Trigger Name Table Name */
return fmt.Sprintf("%v: Trigger: %q Table: %q",
a.Action, a.Trigger, a.Table)
case SQLITE_CREATE_TEMP_VIEW,
SQLITE_CREATE_VIEW,
SQLITE_DROP_TEMP_VIEW,
SQLITE_DROP_VIEW:
/* View Name NULL */
return fmt.Sprintf("%v: View: %q", a.Action, a.View)
case SQLITE_PRAGMA:
/* Pragma Name 1st arg or NULL */
return fmt.Sprintf("%v: Pragma: %q",
a.Action, strings.TrimSpace(a.Pragma+" "+a.PragmaArg))
case SQLITE_READ,
SQLITE_UPDATE:
/* Table Name Column Name */
return fmt.Sprintf("%v: Table: %q Column: %q",
a.Action, a.Table, a.Column)
case SQLITE_TRANSACTION:
/* Operation NULL */
return fmt.Sprintf("%v: Operation: %q", a.Action, a.Operation)
case SQLITE_ATTACH:
/* Filename NULL */
return fmt.Sprintf("%v: Filename: %q", a.Action, a.Filename)
case SQLITE_DETACH:
/* Database Name NULL */
return fmt.Sprintf("%v: Database: %q", a.Action, a.Database)
case SQLITE_ALTER_TABLE:
/* Database Name Table Name */
return fmt.Sprintf("%v: Database: %q Table: %q",
a.Action, a.Database, a.Table)
case SQLITE_REINDEX:
/* Index Name NULL */
return fmt.Sprintf("%v: Index: %q", a.Action, a.Index)
case SQLITE_CREATE_VTABLE,
SQLITE_DROP_VTABLE:
/* Table Name Module Name */
return fmt.Sprintf("%v: Table: %q Module: %q",
a.Action, a.Table, a.Module)
case SQLITE_FUNCTION:
/* NULL Function Name */
return fmt.Sprintf("%v: Function: %q", a.Action, a.Function)
case SQLITE_SAVEPOINT:
/* Operation Savepoint Name */
return fmt.Sprintf("%v: Operation: %q Savepoint: %q",
a.Action, a.Operation, a.Savepoint)
case SQLITE_RECURSIVE,
SQLITE_SELECT:
/* NULL NULL */
return fmt.Sprintf("%v:", a.Action)
case SQLITE_COPY:
/* No longer used */
return fmt.Sprintf("%v:", a.Action)
default:
return fmt.Sprintf("unknown action: %v", a.Action)
}
}

133
vendor/crawshaw.io/sqlite/backup.go generated vendored

@ -0,0 +1,133 @@ @@ -0,0 +1,133 @@
// Copyright (c) 2018 David Crawshaw <david@zentus.com>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package sqlite
// #include <sqlite3.h>
// #include <stdlib.h>
import "C"
import (
"runtime"
"unsafe"
)
// A Backup copies data between two databases.
//
// It is used to backup file based or in-memory databases.
//
// Equivalent to the sqlite3_backup* C object.
//
// https://www.sqlite.org/c3ref/backup_finish.html
type Backup struct {
ptr *C.sqlite3_backup
}
// BackupToDB creates a complete backup of the srcDB on the src Conn to a new
// database Conn at dstPath. The resulting dst connection is returned. This
// will block until the entire backup is complete.
//
// If srcDB is "", then a default of "main" is used.
//
// This is very similar to the first example function implemented on the
// following page.
//
// https://www.sqlite.org/backup.html
func (src *Conn) BackupToDB(srcDB, dstPath string) (dst *Conn, err error) {
if dst, err = OpenConn(dstPath, 0); err != nil {
return
}
defer func() {
if err != nil {
dst.Close()
}
}()
b, err := src.BackupInit(srcDB, "", dst)
if err != nil {
return
}
defer b.Finish()
err = b.Step(-1)
return
}
// BackupInit initializes a new Backup object to copy from src to dst.
//
// If srcDB or dstDB is "", then a default of "main" is used.
//
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupinit
func (src *Conn) BackupInit(srcDB, dstDB string, dst *Conn) (*Backup, error) {
var srcCDB, dstCDB *C.char
defer setCDB(dstDB, &dstCDB)()
defer setCDB(srcDB, &srcCDB)()
var b Backup
b.ptr = C.sqlite3_backup_init(dst.conn, dstCDB, src.conn, srcCDB)
if b.ptr == nil {
res := C.sqlite3_errcode(dst.conn)
return nil, dst.extreserr("Conn.BackupInit", "", res)
}
runtime.SetFinalizer(&b, func(b *Backup) {
if b.ptr != nil {
panic("open *sqlite.Backup garbage collected, call Finish method")
}
})
return &b, nil
}
func setCDB(db string, cdb **C.char) func() {
if db == "" || db == "main" {
*cdb = cmain
return func() {}
}
*cdb = C.CString(db)
return func() { C.free(unsafe.Pointer(cdb)) }
}
// Step is called one or more times to transfer nPage pages at a time between
// databases.
//
// Use -1 to transfer the entire database at once.
//
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupstep
func (b *Backup) Step(nPage int) error {
res := C.sqlite3_backup_step(b.ptr, C.int(nPage))
if res != C.SQLITE_DONE {
return reserr("Backup.Step", "", "", res)
}
return nil
}
// Finish is called to clean up the resources allocated by BackupInit.
//
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupfinish
func (b *Backup) Finish() error {
res := C.sqlite3_backup_finish(b.ptr)
b.ptr = nil
return reserr("Backup.Finish", "", "", res)
}
// Remaining returns the number of pages still to be backed up at the
// conclusion of the most recent b.Step().
//
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backupremaining
func (b *Backup) Remaining() int {
return int(C.sqlite3_backup_remaining(b.ptr))
}
// PageCount returns the total number of pages in the source database at the
// conclusion of the most recent b.Step().
//
// https://www.sqlite.org/c3ref/backup_finish.html#sqlite3backuppagecount
func (b *Backup) PageCount() int {
return int(C.sqlite3_backup_pagecount(b.ptr))
}

189
vendor/crawshaw.io/sqlite/blob.go generated vendored

@ -0,0 +1,189 @@ @@ -0,0 +1,189 @@
// Copyright (c) 2018 David Crawshaw <david@zentus.com>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package sqlite
// #include <blocking_step.h>
// #include <sqlite3.h>
// #include <stdlib.h>
// #include <stdint.h>
import "C"
import (
"io"
"unsafe"
)
var cmain = C.CString("main")
var ctemp = C.CString("temp")
// OpenBlob opens a blob in a particular {database,table,column,row}.
//
// https://www.sqlite.org/c3ref/blob_open.html
func (conn *Conn) OpenBlob(dbn, table, column string, row int64, write bool) (*Blob, error) {
var cdb *C.char
switch dbn {
case "", "main":
cdb = cmain
case "temp":
cdb = ctemp
default:
cdb = C.CString(dbn)
defer C.free(unsafe.Pointer(cdb))
}
var flags C.int
if write {
flags = 1
}
ctable := C.CString(table)
ccolumn := C.CString(column)
defer func() {
C.free(unsafe.Pointer(ctable))
C.free(unsafe.Pointer(ccolumn))
}()
blob := &Blob{conn: conn}
for {
conn.count++
if err := conn.interrupted("Conn.OpenBlob", ""); err != nil {
return nil, err
}
switch res := C.sqlite3_blob_open(conn.conn, cdb, ctable, ccolumn,
C.sqlite3_int64(row), flags, &blob.blob); res {
case C.SQLITE_LOCKED_SHAREDCACHE:
if res := C.wait_for_unlock_notify(
conn.conn, conn.unlockNote); res != C.SQLITE_OK {
return nil, conn.reserr("Conn.OpenBlob(Wait)", "", res)
}
// loop
case C.SQLITE_OK:
blob.size = int64(C.sqlite3_blob_bytes(blob.blob))
return blob, nil
default:
return nil, conn.extreserr("Conn.OpenBlob", "", res)
}
}
}
// Blob provides streaming access to SQLite blobs.
type Blob struct {
io.ReadWriteSeeker
io.ReaderAt
io.WriterAt
io.Closer
conn *Conn
blob *C.sqlite3_blob
off int64
size int64
}
// https://www.sqlite.org/c3ref/blob_read.html
func (blob *Blob) ReadAt(p []byte, off int64) (n int, err error) {
if blob.blob == nil {
return 0, errInvalidBlob
}
if err := blob.conn.interrupted("Blob.ReadAt", ""); err != nil {
return 0, err
}
lenp := C.int(len(p))
res := C.sqlite3_blob_read(blob.blob, unsafe.Pointer(&p[0]), lenp, C.int(off))
if err := blob.conn.reserr("Blob.ReadAt", "", res); err != nil {
return 0, err
}
return len(p), nil
}
// https://www.sqlite.org/c3ref/blob_write.html
func (blob *Blob) WriteAt(p []byte, off int64) (n int, err error) {
if blob.blob == nil {
return 0, errInvalidBlob
}
if err := blob.conn.interrupted("Blob.WriteAt", ""); err != nil {
return 0, err
}
lenp := C.int(len(p))
res := C.sqlite3_blob_write(blob.blob, unsafe.Pointer(&p[0]), lenp, C.int(off))
if err := blob.conn.reserr("Blob.WriteAt", "", res); err != nil {
return 0, err
}
return len(p), nil
}
func (blob *Blob) Read(p []byte) (n int, err error) {
if blob.off >= blob.size {
return 0, io.EOF
}
if rem := blob.size - blob.off; int64(len(p)) > rem {
p = p[:rem]
}
n, err = blob.ReadAt(p, blob.off)
blob.off += int64(n)
return n, err
}
func (blob *Blob) Write(p []byte) (n int, err error) {
if rem := blob.size - blob.off; int64(len(p)) > rem {
return 0, io.ErrShortWrite
}
n, err = blob.WriteAt(p, blob.off)
blob.off += int64(n)
return n, err
}
func (blob *Blob) Seek(offset int64, whence int) (int64, error) {
const (
SeekStart = 0
SeekCurrent = 1
SeekEnd = 2
)
switch whence {
case SeekStart:
// use offset directly
case SeekCurrent:
offset += blob.off
case SeekEnd:
offset += blob.size
}
if offset < 0 {
var buf [20]byte
return -1, Error{
Code: SQLITE_ERROR,
Loc: "Blob.Seek",
Msg: "attempting to seek before beginning of blob: " + string(itoa(buf[:], offset)),
}
}
blob.off = offset
return offset, nil
}
// Size returns the total size of a blob.
func (blob *Blob) Size() int64 {
return blob.size
}
// https://www.sqlite.org/c3ref/blob_close.html
func (blob *Blob) Close() error {
if blob.blob == nil {
return errInvalidBlob
}
err := blob.conn.reserr("Blob.Close", "", C.sqlite3_blob_close(blob.blob))
blob.blob = nil
return err
}
var errInvalidBlob = Error{Code: SQLITE_ERROR, Msg: "invalid blob"}
// TODO: Blob Reopen

61
vendor/crawshaw.io/sqlite/blocking_step.c generated vendored

@ -0,0 +1,61 @@ @@ -0,0 +1,61 @@
// Copyright (c) 2018 David Crawshaw <david@zentus.com>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
// This file defines the wait_for_unlock_notify function.
// See the documentation on Stmt.Step.
#include <blocking_step.h>
#include <stdlib.h>
unlock_note* unlock_note_alloc() {
unlock_note* un = (unlock_note*)malloc(sizeof(unlock_note));
pthread_mutex_init(&un->mu, 0);
pthread_cond_init(&un->cond, 0);
return un;
}
void unlock_note_free(unlock_note* un) {
pthread_cond_destroy(&un->cond);
pthread_mutex_destroy(&un->mu);
free(un);
}
void unlock_note_fire(unlock_note* un) {
pthread_mutex_lock(&un->mu);
un->fired = 1;
pthread_cond_signal(&un->cond);
pthread_mutex_unlock(&un->mu);
}
static void unlock_notify_cb(void **apArg, int nArg) {
for(int i=0; i < nArg; i++) {
unlock_note_fire((unlock_note*)apArg[i]);
}
}
int wait_for_unlock_notify(sqlite3 *db, unlock_note* un) {
un->fired = 0;
int res = sqlite3_unlock_notify(db, unlock_notify_cb, (void *)un);
if (res == SQLITE_OK) {
pthread_mutex_lock(&un->mu);
if (!un->fired) {
pthread_cond_wait(&un->cond, &un->mu);
}
pthread_mutex_unlock(&un->mu);
}
return res;
}

17
vendor/crawshaw.io/sqlite/blocking_step.h generated vendored

@ -0,0 +1,17 @@ @@ -0,0 +1,17 @@
// This file declares the wait_for_unlock_notify function.
// See the documentation on Stmt.Step.
#include <sqlite3.h>
#include <pthread.h>
typedef struct unlock_note {
int fired;
pthread_cond_t cond;
pthread_mutex_t mu;
} unlock_note;
unlock_note* unlock_note_alloc();
void unlock_note_fire(unlock_note* un);
void unlock_note_free(unlock_note* un);
int wait_for_unlock_notify(sqlite3 *db, unlock_note* un);

7
vendor/crawshaw.io/sqlite/c/dummy.go generated vendored

@ -0,0 +1,7 @@ @@ -0,0 +1,7 @@
// +build dummy
// Package c contains only a C file.
//
// This Go file is part of a workaround for `go mod vendor`.
// Please see the file dummy.go at the root of the module for more information.
package c

229615
vendor/crawshaw.io/sqlite/c/sqlite3.c generated vendored

File diff suppressed because it is too large Load Diff

144
vendor/crawshaw.io/sqlite/doc.go generated vendored

@ -0,0 +1,144 @@ @@ -0,0 +1,144 @@
// Copyright (c) 2018 David Crawshaw <david@zentus.com>
//
// Permission to use, copy, modify, and distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
/*
Package sqlite provides a Go interface to SQLite 3.
The semantics of this package are deliberately close to the
SQLite3 C API, so it is helpful to be familiar with
http://www.sqlite.org/c3ref/intro.html.
An SQLite connection is represented by a *sqlite.Conn.
Connections cannot be used concurrently.
A typical Go program will create a pool of connections
(using Open to create a *sqlitex.Pool) so goroutines can
borrow a connection while they need to talk to the database.
This package assumes SQLite will be used concurrently by the
process through several connections, so the build options for
SQLite enable multi-threading and the shared cache:
https://www.sqlite.org/sharedcache.html
The implementation automatically handles shared cache locking,
see the documentation on Stmt.Step for details.
The optional SQLite3 compiled in are: FTS5, RTree, JSON1, Session, GeoPoly
This is not a database/sql driver.
Statement Caching
Statements are prepared with the Prepare and PrepareTransient methods.
When using Prepare, statements are keyed inside a connection by the
original query string used to create them. This means long-running
high-performance code paths can write:
stmt, err := conn.Prepare("SELECT ...")
After all the connections in a pool have been warmed up by passing
through one of these Prepare calls, subsequent calls are simply a
map lookup that returns an existing statement.
Streaming Blobs
The sqlite package supports the SQLite incremental I/O interface for
streaming blob data into and out of the the database without loading
the entire blob into a single []byte.
(This is important when working either with very large blobs, or
more commonly, a large number of moderate-sized blobs concurrently.)
To write a blob, first use an INSERT statement to set the size of the
blob and assign a rowid:
"INSERT INTO blobs (myblob) VALUES (?);"
Use BindZeroBlob or SetZeroBlob to set the size of myblob.
Then you can open the blob with:
b, err := conn.OpenBlob("", "blobs", "myblob", conn.LastInsertRowID(), true)
Deadlines and Cancellation
Every connection can have a done channel associated with it using
the SetInterrupt method. This is typically the channel returned by
a context.Context Done method.
For example, a timeout can be associated with a connection session:
ctx := context.WithTimeout(context.Background(), 100*time.Millisecond)
conn.SetInterrupt(ctx.Done())
As database connections are long-lived, the SetInterrupt method can
be called multiple times to reset the associated lifetime.
When using pools, the shorthand for associating a context with a
connection is:
conn := dbpool.Get(ctx)
if conn == nil {
// ... handle error
}
defer dbpool.Put(c)
Transactions
SQLite transactions have to be managed manually with this package
by directly calling BEGIN / COMMIT / ROLLBACK or
SAVEPOINT / RELEASE/ ROLLBACK. The sqlitex has a Savepoint
function that helps automate this.
A typical HTTP Handler
Using a Pool to execute SQL in a concurrent HTTP handler.
var dbpool *sqlitex.Pool
func main() {
var err error
dbpool, err = sqlitex.Open("file:memory:?mode=memory", 0, 10)
if err != nil {
log.Fatal(err)
}
http.HandleFunc("/", handle)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func handle(w http.ResponseWriter, r *http.Request) {
conn := dbpool.Get(r.Context())
if conn == nil {
return
}
defer dbpool.Put(conn)
stmt := conn.Prep("SELECT foo FROM footable WHERE id = $id;")
stmt.SetText("$id", "_user_id_")
for {
if hasRow, err := stmt.Step(); err != nil {
// ... handle error
} else if !hasRow {
break
}
foo := stmt.GetText("foo")
// ... use foo
}
}
For helper functions that make some kinds of statements easier to
write see the sqlitex package.
*/
package sqlite // import "crawshaw.io/sqlite"

18
vendor/crawshaw.io/sqlite/dummy.go generated vendored

@ -0,0 +1,18 @@ @@ -0,0 +1,18 @@
// +build dummy
// This file is part of a workaround for `go mod vendor` which won't vendor
// C files if there's no Go file in the same directory.
// This would prevent the c/sqlite3.c file to be vendored.
//
// This Go file imports the c directory where there is another dummy.go file which
// is the second part of this workaround.
//
// These two files combined make it so `go mod vendor` behaves correctly.
//
// See this issue for reference: https://github.com/golang/go/issues/26366
package sqlite
import (
_ "crawshaw.io/sqlite/c"
)

389
vendor/crawshaw.io/sqlite/error.go generated vendored

@ -0,0 +1,389 @@ @@ -0,0 +1,389 @@
// Copyright (c) 2018 David Crawshaw <david@zentus.com>
//
// Permission to use, copy, modify, and distribute this software for any