ソースを参照

Add support for offices group sync

Andrea Fazzi 5 年 前
コミット
8c086cb7e3
67 ファイル変更1259 行追加2331 行削除
  1. 21 22
      Godeps/Godeps.json
  2. 19 0
      cron/sync/sync.go
  3. 3 3
      vendor/github.com/dgrijalva/jwt-go/README.md
  4. 0 6
      vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md
  5. 0 1
      vendor/github.com/go-sql-driver/mysql/.gitignore
  6. 5 84
      vendor/github.com/go-sql-driver/mysql/.travis.yml
  7. 0 23
      vendor/github.com/go-sql-driver/mysql/AUTHORS
  8. 25 58
      vendor/github.com/go-sql-driver/mysql/README.md
  9. 1 1
      vendor/github.com/go-sql-driver/mysql/appengine.go
  10. 32 116
      vendor/github.com/go-sql-driver/mysql/connection.go
  11. 0 202
      vendor/github.com/go-sql-driver/mysql/connection_go18.go
  12. 3 6
      vendor/github.com/go-sql-driver/mysql/const.go
  13. 2 12
      vendor/github.com/go-sql-driver/mysql/driver.go
  14. 41 79
      vendor/github.com/go-sql-driver/mysql/dsn.go
  15. 73 6
      vendor/github.com/go-sql-driver/mysql/errors.go
  16. 0 140
      vendor/github.com/go-sql-driver/mysql/fields.go
  17. 1 2
      vendor/github.com/go-sql-driver/mysql/infile.go
  18. 86 108
      vendor/github.com/go-sql-driver/mysql/packets.go
  19. 35 142
      vendor/github.com/go-sql-driver/mysql/rows.go
  20. 30 55
      vendor/github.com/go-sql-driver/mysql/statement.go
  21. 2 2
      vendor/github.com/go-sql-driver/mysql/transaction.go
  22. 1 83
      vendor/github.com/go-sql-driver/mysql/utils.go
  23. 0 40
      vendor/github.com/go-sql-driver/mysql/utils_go17.go
  24. 0 49
      vendor/github.com/go-sql-driver/mysql/utils_go18.go
  25. 1 11
      vendor/github.com/gorilla/handlers/cors.go
  26. 3 4
      vendor/github.com/gorilla/mux/.travis.yml
  27. 6 122
      vendor/github.com/gorilla/mux/README.md
  28. 5 12
      vendor/github.com/gorilla/mux/doc.go
  29. 34 63
      vendor/github.com/gorilla/mux/mux.go
  30. 4 14
      vendor/github.com/gorilla/mux/regexp.go
  31. 8 127
      vendor/github.com/gorilla/mux/route.go
  32. 2 1
      vendor/github.com/gorilla/schema/.travis.yml
  33. 10 34
      vendor/github.com/gorilla/schema/README.md
  34. 22 33
      vendor/github.com/gorilla/schema/cache.go
  35. 1 1
      vendor/github.com/gorilla/schema/converter.go
  36. 26 130
      vendor/github.com/gorilla/schema/decoder.go
  37. 3 3
      vendor/github.com/gorilla/schema/doc.go
  38. 0 195
      vendor/github.com/gorilla/schema/encoder.go
  39. 0 2
      vendor/github.com/gorilla/securecookie/README.md
  40. 3 14
      vendor/github.com/gorilla/sessions/README.md
  41. 2 1
      vendor/github.com/gorilla/sessions/doc.go
  42. 13 23
      vendor/github.com/jinzhu/gorm/README.md
  43. 2 2
      vendor/github.com/jinzhu/gorm/association.go
  44. 5 7
      vendor/github.com/jinzhu/gorm/callback.go
  45. 2 1
      vendor/github.com/jinzhu/gorm/callback_create.go
  46. 4 0
      vendor/github.com/jinzhu/gorm/callback_query.go
  47. 7 0
      vendor/github.com/jinzhu/gorm/callback_query_preload.go
  48. 112 41
      vendor/github.com/jinzhu/gorm/callback_save.go
  49. 11 1
      vendor/github.com/jinzhu/gorm/callback_update.go
  50. 22 8
      vendor/github.com/jinzhu/gorm/dialect.go
  51. 28 8
      vendor/github.com/jinzhu/gorm/dialect_common.go
  52. 28 13
      vendor/github.com/jinzhu/gorm/dialect_mysql.go
  53. 20 7
      vendor/github.com/jinzhu/gorm/dialect_postgres.go
  54. 2 2
      vendor/github.com/jinzhu/gorm/dialect_sqlite3.go
  55. 30 0
      vendor/github.com/jinzhu/gorm/docker-compose.yml
  56. 16 0
      vendor/github.com/jinzhu/gorm/errors.go
  57. 27 22
      vendor/github.com/jinzhu/gorm/join_table_handler.go
  58. 44 20
      vendor/github.com/jinzhu/gorm/main.go
  59. 62 30
      vendor/github.com/jinzhu/gorm/model_struct.go
  60. 173 119
      vendor/github.com/jinzhu/gorm/scope.go
  61. 0 7
      vendor/github.com/jinzhu/gorm/search.go
  62. 1 1
      vendor/github.com/jinzhu/gorm/test_all.sh
  63. 1 1
      vendor/github.com/jinzhu/gorm/utils.go
  64. 111 4
      vendor/github.com/jinzhu/gorm/wercker.yml
  65. 0 4
      vendor/github.com/robfig/cron/README.md
  66. 3 3
      vendor/github.com/robfig/cron/doc.go
  67. 25 0
      vendor/gogs.carducci-dante.gov.it/karmen/client/client.go

+ 21 - 22
Godeps/Godeps.json

@@ -9,13 +9,13 @@
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/dgrijalva/jwt-go",
 			"ImportPath": "github.com/dgrijalva/jwt-go",
-			"Comment": "v3.1.0",
-			"Rev": "dbeaa9332f19a944acb5736b4456cfcc02140e29"
+			"Comment": "v3.0.0-17-g2268707",
+			"Rev": "2268707a8f0843315e2004ee4f1d021dc08baedf"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/go-sql-driver/mysql",
 			"ImportPath": "github.com/go-sql-driver/mysql",
-			"Comment": "v1.3-49-gcd4cb90",
-			"Rev": "cd4cb909ce1a31435164be29bf3682031f61539a"
+			"Comment": "v1.3-2-g2e00b5c",
+			"Rev": "2e00b5cd70399450106cec6431c2e2ce3cae5034"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/gocarina/gocsv",
 			"ImportPath": "github.com/gocarina/gocsv",
@@ -28,38 +28,37 @@
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/gorilla/handlers",
 			"ImportPath": "github.com/gorilla/handlers",
-			"Comment": "v1.3.0",
-			"Rev": "90663712d74cb411cbef281bc1e08c19d1a76145"
+			"Comment": "v1.2.1-1-ga4d79d4",
+			"Rev": "a4d79d4487c2430a17d9dc8a1f74d1a6ed6908ca"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/gorilla/mux",
 			"ImportPath": "github.com/gorilla/mux",
-			"Comment": "v1.6.0-1-g2d5fef0",
-			"Rev": "2d5fef06b891c971b14aa6f71ca5ab6c03a36e0e"
+			"Comment": "v1.1-27-g757bef9",
+			"Rev": "757bef944d0f21880861c2dd9c871ca543023cba"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/gorilla/schema",
 			"ImportPath": "github.com/gorilla/schema",
-			"Comment": "v1.0.2-3-gda8e735",
-			"Rev": "da8e73546beca346d03fd40d5b146e06e6b98b7a"
+			"Rev": "0164a00ab4cd01d814d8cd5bf63fd9fcea30e23b"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/gorilla/securecookie",
 			"ImportPath": "github.com/gorilla/securecookie",
-			"Comment": "v1.1-6-ge59506c",
-			"Rev": "e59506cc896acb7f7bf732d4fdf5e25f7ccd8983"
+			"Comment": "v1.1-5-gfa5329f",
+			"Rev": "fa5329f913702981df43dcb2a380bac429c810b5"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/gorilla/sessions",
 			"ImportPath": "github.com/gorilla/sessions",
-			"Comment": "v1.1-8-ga3acf13",
-			"Rev": "a3acf13e802c358d65f249324d14ed24aac11370"
+			"Comment": "v1.1",
+			"Rev": "ca9ada44574153444b00d3fd9c8559e4cc95f896"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/jinzhu/gorm",
 			"ImportPath": "github.com/jinzhu/gorm",
-			"Comment": "v1.0-168-gc3bb6aa",
-			"Rev": "c3bb6aaa828867eec72dd8571d111e442688f85f"
+			"Comment": "v1.0-250-g48a20a6",
+			"Rev": "48a20a6e9f3f4d26095df82c3337efec6db0a6fc"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/jinzhu/gorm/dialects/mysql",
 			"ImportPath": "github.com/jinzhu/gorm/dialects/mysql",
-			"Comment": "v1.0-168-gc3bb6aa",
-			"Rev": "c3bb6aaa828867eec72dd8571d111e442688f85f"
+			"Comment": "v1.0-250-g48a20a6",
+			"Rev": "48a20a6e9f3f4d26095df82c3337efec6db0a6fc"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/jinzhu/inflection",
 			"ImportPath": "github.com/jinzhu/inflection",
@@ -71,8 +70,8 @@
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/robfig/cron",
 			"ImportPath": "github.com/robfig/cron",
-			"Comment": "v1.1",
-			"Rev": "b41be1df696709bb6395fe435af20370037c0b4c"
+			"Comment": "v1-58-g736158d",
+			"Rev": "736158dc09e10f1911ca3a1e1b01f11b566ce5db"
 		},
 		},
 		{
 		{
 			"ImportPath": "github.com/sethvargo/go-password/password",
 			"ImportPath": "github.com/sethvargo/go-password/password",
@@ -81,11 +80,11 @@
 		},
 		},
 		{
 		{
 			"ImportPath": "gogs.carducci-dante.gov.it/karmen/client",
 			"ImportPath": "gogs.carducci-dante.gov.it/karmen/client",
-			"Rev": "876a562a75c249b2afd260bf60a209d204191605"
+			"Rev": "1a53dd7f124000313ae5e190c6b62ee179764d31"
 		},
 		},
 		{
 		{
 			"ImportPath": "gogs.carducci-dante.gov.it/karmen/ldap",
 			"ImportPath": "gogs.carducci-dante.gov.it/karmen/ldap",
-			"Rev": "83e2c51c67bc8c5f171ad956e200363b4ca0af00"
+			"Rev": "034d2afa27464b7b5fc304170d521fc63dbefb5c"
 		},
 		},
 		{
 		{
 			"ImportPath": "gogs.carducci-dante.gov.it/karmen/util/template",
 			"ImportPath": "gogs.carducci-dante.gov.it/karmen/util/template",

+ 19 - 0
cron/sync/sync.go

@@ -367,6 +367,12 @@ func (syncJob *SyncJob) Run() {
 		log.Println(err)
 		log.Println(err)
 	}
 	}
 
 
+	log.Println("Retrieving Offices...")
+	offices, err := karmenClient.GetOffices()
+	if err != nil {
+		log.Println(err)
+	}
+
 	users := make([]orm.User, 0)
 	users := make([]orm.User, 0)
 	for _, teacher := range teachers {
 	for _, teacher := range teachers {
 		users = append(users, teacher)
 		users = append(users, teacher)
@@ -436,4 +442,17 @@ func (syncJob *SyncJob) Run() {
 		log.Println(result)
 		log.Println(result)
 	}
 	}
 
 
+	for _, office := range offices {
+		users := make([]orm.User, 0)
+		for _, administrative := range office.Administratives {
+			users = append(users, administrative)
+		}
+		group := fmt.Sprintf("cn=%s,ou=Segreterie", office.Name)
+		if result, err := syncJob.SyncGroup(ldapClient, users, group); err != nil {
+			panic(err)
+		} else {
+			log.Println(result)
+		}
+	}
+
 }
 }

+ 3 - 3
vendor/github.com/dgrijalva/jwt-go/README.md

@@ -4,7 +4,7 @@ A [go](http://www.golang.org) (or 'golang' for search engine friendliness) imple
 
 
 **BREAKING CHANGES:*** Version 3.0.0 is here. It includes _a lot_ of changes including a few that break the API.  We've tried to break as few things as possible, so there should just be a few type signature changes.  A full list of breaking changes is available in `VERSION_HISTORY.md`.  See `MIGRATION_GUIDE.md` for more information on updating your code.
 **BREAKING CHANGES:*** Version 3.0.0 is here. It includes _a lot_ of changes including a few that break the API.  We've tried to break as few things as possible, so there should just be a few type signature changes.  A full list of breaking changes is available in `VERSION_HISTORY.md`.  See `MIGRATION_GUIDE.md` for more information on updating your code.
 
 
-**NOTICE:** It's important that you [validate the `alg` presented is what you expect](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/). This library attempts to make it easy to do the right thing by requiring key types match the expected alg, but you should take the extra step to verify it in your usage.  See the examples provided.
+**NOTICE:** A vulnerability in JWT was [recently published](https://auth0.com/blog/2015/03/31/critical-vulnerabilities-in-json-web-token-libraries/).  As this library doesn't force users to validate the `alg` is what they expected, it's possible your usage is effected.  There will be an update soon to remedy this, and it will likey require backwards-incompatible changes to the API.  In the short term, please make sure your implementation verifies the `alg` is what you expect.
 
 
 
 
 ## What the heck is a JWT?
 ## What the heck is a JWT?
@@ -74,7 +74,7 @@ It's worth mentioning that OAuth and JWT are not the same thing. A JWT token is
 
 
 Without going too far down the rabbit hole, here's a description of the interaction of these technologies:
 Without going too far down the rabbit hole, here's a description of the interaction of these technologies:
 
 
-* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to. For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth.
+* OAuth is a protocol for allowing an identity provider to be separate from the service a user is logging in to.  For example, whenever you use Facebook to log into a different service (Yelp, Spotify, etc), you are using OAuth.
 * OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token.
 * OAuth defines several options for passing around authentication data. One popular method is called a "bearer token". A bearer token is simply a string that _should_ only be held by an authenticated user. Thus, simply presenting this token proves your identity. You can probably derive from here why a JWT might make a good bearer token.
 * Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL.
 * Because bearer tokens are used for authentication, it's important they're kept secret. This is why transactions that use bearer tokens typically happen over SSL.
  
  
@@ -82,4 +82,4 @@ Without going too far down the rabbit hole, here's a description of the interact
 
 
 Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go).
 Documentation can be found [on godoc.org](http://godoc.org/github.com/dgrijalva/jwt-go).
 
 
-The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration. You'll also find several implementation examples in the documentation.
+The command line utility included in this project (cmd/jwt) provides a straightforward example of token creation and parsing as well as a useful tool for debugging your own integration.  You'll also find several implementation examples in to documentation.

+ 0 - 6
vendor/github.com/dgrijalva/jwt-go/VERSION_HISTORY.md

@@ -1,11 +1,5 @@
 ## `jwt-go` Version History
 ## `jwt-go` Version History
 
 
-#### 3.1.0
-
-* Improvements to `jwt` command line tool
-* Added `SkipClaimsValidation` option to `Parser`
-* Documentation updates
-
 #### 3.0.0
 #### 3.0.0
 
 
 * **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code
 * **Compatibility Breaking Changes**: See MIGRATION_GUIDE.md for tips on updating your code

+ 0 - 1
vendor/github.com/go-sql-driver/mysql/.gitignore

@@ -6,4 +6,3 @@
 Icon?
 Icon?
 ehthumbs.db
 ehthumbs.db
 Thumbs.db
 Thumbs.db
-.idea

+ 5 - 84
vendor/github.com/go-sql-driver/mysql/.travis.yml

@@ -1,92 +1,13 @@
 sudo: false
 sudo: false
 language: go
 language: go
 go:
 go:
+  - 1.2
+  - 1.3
+  - 1.4
+  - 1.5
+  - 1.6
   - 1.7
   - 1.7
-  - 1.8
-  - 1.9
   - tip
   - tip
 
 
-before_install:
-  - go get golang.org/x/tools/cmd/cover
-  - go get github.com/mattn/goveralls
-
 before_script:
 before_script:
-  - echo -e "[server]\ninnodb_log_file_size=256MB\ninnodb_buffer_pool_size=512MB\nmax_allowed_packet=16MB" | sudo tee -a /etc/mysql/my.cnf
-  - sudo service mysql restart
-  - .travis/wait_mysql.sh
   - mysql -e 'create database gotest;'
   - mysql -e 'create database gotest;'
-
-matrix:
-  include:
-    - env: DB=MYSQL57
-      sudo: required
-      dist: trusty
-      go: 1.9
-      services:
-        - docker
-      before_install:
-        - go get golang.org/x/tools/cmd/cover
-        - go get github.com/mattn/goveralls
-        - docker pull mysql:5.7
-        - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret
-          mysql:5.7 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB
-        - sleep 30
-        - cp .travis/docker.cnf ~/.my.cnf
-        - mysql --print-defaults
-        - .travis/wait_mysql.sh
-      before_script:
-        - export MYSQL_TEST_USER=gotest
-        - export MYSQL_TEST_PASS=secret
-        - export MYSQL_TEST_ADDR=127.0.0.1:3307
-        - export MYSQL_TEST_CONCURRENT=1
-
-    - env: DB=MARIA55
-      sudo: required
-      dist: trusty
-      go: 1.9
-      services:
-        - docker
-      before_install:
-        - go get golang.org/x/tools/cmd/cover
-        - go get github.com/mattn/goveralls
-        - docker pull mariadb:5.5
-        - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret
-          mariadb:5.5 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB
-        - sleep 30
-        - cp .travis/docker.cnf ~/.my.cnf
-        - mysql --print-defaults
-        - .travis/wait_mysql.sh
-      before_script:
-        - export MYSQL_TEST_USER=gotest
-        - export MYSQL_TEST_PASS=secret
-        - export MYSQL_TEST_ADDR=127.0.0.1:3307
-        - export MYSQL_TEST_CONCURRENT=1
-
-    - env: DB=MARIA10_1
-      sudo: required
-      dist: trusty
-      go: 1.9
-      services:
-        - docker
-      before_install:
-        - go get golang.org/x/tools/cmd/cover
-        - go get github.com/mattn/goveralls
-        - docker pull mariadb:10.1
-        - docker run -d -p 127.0.0.1:3307:3306 --name mysqld -e MYSQL_DATABASE=gotest -e MYSQL_USER=gotest -e MYSQL_PASSWORD=secret -e MYSQL_ROOT_PASSWORD=verysecret
-          mariadb:10.1 --innodb_log_file_size=256MB --innodb_buffer_pool_size=512MB --max_allowed_packet=16MB
-        - sleep 30
-        - cp .travis/docker.cnf ~/.my.cnf
-        - mysql --print-defaults
-        - .travis/wait_mysql.sh
-      before_script:
-        - export MYSQL_TEST_USER=gotest
-        - export MYSQL_TEST_PASS=secret
-        - export MYSQL_TEST_ADDR=127.0.0.1:3307
-        - export MYSQL_TEST_CONCURRENT=1
-
-script:
-  - go test -v -covermode=count -coverprofile=coverage.out
-  - go vet ./...
-  - test -z "$(gofmt -d -s . | tee /dev/stderr)"
-after_script:
-  - $HOME/gopath/bin/goveralls -coverprofile=coverage.out -service=travis-ci

+ 0 - 23
vendor/github.com/go-sql-driver/mysql/AUTHORS

@@ -12,56 +12,36 @@
 # Individual Persons
 # Individual Persons
 
 
 Aaron Hopkins <go-sql-driver at die.net>
 Aaron Hopkins <go-sql-driver at die.net>
-Achille Roussel <achille.roussel at gmail.com>
 Arne Hormann <arnehormann at gmail.com>
 Arne Hormann <arnehormann at gmail.com>
-Asta Xie <xiemengjun at gmail.com>
-Bulat Gaifullin <gaifullinbf at gmail.com>
 Carlos Nieto <jose.carlos at menteslibres.net>
 Carlos Nieto <jose.carlos at menteslibres.net>
 Chris Moos <chris at tech9computers.com>
 Chris Moos <chris at tech9computers.com>
-Daniel Montoya <dsmontoyam at gmail.com>
 Daniel Nichter <nil at codenode.com>
 Daniel Nichter <nil at codenode.com>
 Daniël van Eeden <git at myname.nl>
 Daniël van Eeden <git at myname.nl>
-Dave Protasowski <dprotaso at gmail.com>
 DisposaBoy <disposaboy at dby.me>
 DisposaBoy <disposaboy at dby.me>
 Egor Smolyakov <egorsmkv at gmail.com>
 Egor Smolyakov <egorsmkv at gmail.com>
-Evan Shaw <evan at vendhq.com>
 Frederick Mayle <frederickmayle at gmail.com>
 Frederick Mayle <frederickmayle at gmail.com>
 Gustavo Kristic <gkristic at gmail.com>
 Gustavo Kristic <gkristic at gmail.com>
 Hanno Braun <mail at hannobraun.com>
 Hanno Braun <mail at hannobraun.com>
 Henri Yandell <flamefew at gmail.com>
 Henri Yandell <flamefew at gmail.com>
 Hirotaka Yamamoto <ymmt2005 at gmail.com>
 Hirotaka Yamamoto <ymmt2005 at gmail.com>
-ICHINOSE Shogo <shogo82148 at gmail.com>
 INADA Naoki <songofacandy at gmail.com>
 INADA Naoki <songofacandy at gmail.com>
-Jacek Szwec <szwec.jacek at gmail.com>
 James Harr <james.harr at gmail.com>
 James Harr <james.harr at gmail.com>
-Jeff Hodges <jeff at somethingsimilar.com>
-Jeffrey Charles <jeffreycharles at gmail.com>
 Jian Zhen <zhenjl at gmail.com>
 Jian Zhen <zhenjl at gmail.com>
 Joshua Prunier <joshua.prunier at gmail.com>
 Joshua Prunier <joshua.prunier at gmail.com>
 Julien Lefevre <julien.lefevr at gmail.com>
 Julien Lefevre <julien.lefevr at gmail.com>
 Julien Schmidt <go-sql-driver at julienschmidt.com>
 Julien Schmidt <go-sql-driver at julienschmidt.com>
-Justin Li <jli at j-li.net>
-Justin Nuß <nuss.justin at gmail.com>
 Kamil Dziedzic <kamil at klecza.pl>
 Kamil Dziedzic <kamil at klecza.pl>
 Kevin Malachowski <kevin at chowski.com>
 Kevin Malachowski <kevin at chowski.com>
 Lennart Rudolph <lrudolph at hmc.edu>
 Lennart Rudolph <lrudolph at hmc.edu>
 Leonardo YongUk Kim <dalinaum at gmail.com>
 Leonardo YongUk Kim <dalinaum at gmail.com>
-Linh Tran Tuan <linhduonggnu at gmail.com>
-Lion Yang <lion at aosc.xyz>
 Luca Looz <luca.looz92 at gmail.com>
 Luca Looz <luca.looz92 at gmail.com>
 Lucas Liu <extrafliu at gmail.com>
 Lucas Liu <extrafliu at gmail.com>
 Luke Scott <luke at webconnex.com>
 Luke Scott <luke at webconnex.com>
-Maciej Zimnoch <maciej.zimnoch@codilime.com>
 Michael Woolnough <michael.woolnough at gmail.com>
 Michael Woolnough <michael.woolnough at gmail.com>
 Nicola Peduzzi <thenikso at gmail.com>
 Nicola Peduzzi <thenikso at gmail.com>
 Olivier Mengué <dolmen at cpan.org>
 Olivier Mengué <dolmen at cpan.org>
-oscarzhao <oscarzhaosl at gmail.com>
 Paul Bonser <misterpib at gmail.com>
 Paul Bonser <misterpib at gmail.com>
-Peter Schultz <peter.schultz at classmarkets.com>
-Rebecca Chin <rchin at pivotal.io>
 Runrioter Wung <runrioter at gmail.com>
 Runrioter Wung <runrioter at gmail.com>
-Robert Russell <robert at rrbrussell.com>
-Shuode Li <elemount at qq.com>
 Soroush Pour <me at soroushjp.com>
 Soroush Pour <me at soroushjp.com>
 Stan Putrya <root.vagner at gmail.com>
 Stan Putrya <root.vagner at gmail.com>
 Stanley Gunawan <gunawan.stanley at gmail.com>
 Stanley Gunawan <gunawan.stanley at gmail.com>
@@ -73,8 +53,5 @@ Zhenye Xie <xiezhenye at gmail.com>
 # Organizations
 # Organizations
 
 
 Barracuda Networks, Inc.
 Barracuda Networks, Inc.
-Counting Ltd.
 Google Inc.
 Google Inc.
-Keybase Inc.
-Pivotal Inc.
 Stripe Inc.
 Stripe Inc.

+ 25 - 58
vendor/github.com/go-sql-driver/mysql/README.md

@@ -15,9 +15,6 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac
       * [Address](#address)
       * [Address](#address)
       * [Parameters](#parameters)
       * [Parameters](#parameters)
       * [Examples](#examples)
       * [Examples](#examples)
-    * [Connection pool and timeouts](#connection-pool-and-timeouts)
-    * [context.Context Support](#contextcontext-support)
-    * [ColumnType Support](#columntype-support)
     * [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support)
     * [LOAD DATA LOCAL INFILE support](#load-data-local-infile-support)
     * [time.Time support](#timetime-support)
     * [time.Time support](#timetime-support)
     * [Unicode support](#unicode-support)
     * [Unicode support](#unicode-support)
@@ -40,7 +37,7 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac
   * Optional placeholder interpolation
   * Optional placeholder interpolation
 
 
 ## Requirements
 ## Requirements
-  * Go 1.7 or higher. We aim to support the 3 latest versions of Go.
+  * Go 1.2 or higher
   * MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+)
   * MySQL (4.1+), MariaDB, Percona Server, Google CloudSQL or Sphinx (2.2.3+)
 
 
 ---------------------------------------
 ---------------------------------------
@@ -48,7 +45,7 @@ A MySQL-Driver for Go's [database/sql](https://golang.org/pkg/database/sql/) pac
 ## Installation
 ## Installation
 Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell:
 Simple install the package to your [$GOPATH](https://github.com/golang/go/wiki/GOPATH "GOPATH") with the [go tool](https://golang.org/cmd/go/ "go command") from shell:
 ```bash
 ```bash
-$ go get -u github.com/go-sql-driver/mysql
+$ go get github.com/go-sql-driver/mysql
 ```
 ```
 Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`.
 Make sure [Git is installed](https://git-scm.com/downloads) on your machine and in your system's `PATH`.
 
 
@@ -102,8 +99,7 @@ See [net.Dial](https://golang.org/pkg/net/#Dial) for more information which netw
 In general you should use an Unix domain socket if available and TCP otherwise for best performance.
 In general you should use an Unix domain socket if available and TCP otherwise for best performance.
 
 
 #### Address
 #### Address
-For TCP and UDP networks, addresses have the form `host[:port]`.
-If `port` is omitted, the default port will be used.
+For TCP and UDP networks, addresses have the form `host:port`.
 If `host` is a literal IPv6 address, it must be enclosed in square brackets.
 If `host` is a literal IPv6 address, it must be enclosed in square brackets.
 The functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form.
 The functions [net.JoinHostPort](https://golang.org/pkg/net/#JoinHostPort) and [net.SplitHostPort](https://golang.org/pkg/net/#SplitHostPort) manipulate addresses in this form.
 
 
@@ -140,9 +136,9 @@ Default:        false
 ```
 ```
 Type:           bool
 Type:           bool
 Valid Values:   true, false
 Valid Values:   true, false
-Default:        true
+Default:        false
 ```
 ```
-`allowNativePasswords=false` disallows the usage of MySQL native password method.
+`allowNativePasswords=true` allows the usage of the mysql native password method.
 
 
 ##### `allowOldPasswords`
 ##### `allowOldPasswords`
 
 
@@ -233,10 +229,10 @@ Please keep in mind, that param values must be [url.QueryEscape](https://golang.
 ##### `maxAllowedPacket`
 ##### `maxAllowedPacket`
 ```
 ```
 Type:          decimal number
 Type:          decimal number
-Default:       4194304
+Default:       0
 ```
 ```
 
 
-Max packet size allowed in bytes. The default value is 4 MiB and should be adjusted to match the server settings. `maxAllowedPacket=0` can be used to automatically fetch the `max_allowed_packet` variable from server *on every connection*.
+Max packet size allowed in bytes. Use `maxAllowedPacket=0` to automatically fetch the `max_allowed_packet` variable from server.
 
 
 ##### `multiStatements`
 ##### `multiStatements`
 
 
@@ -264,13 +260,13 @@ Default:        false
 ##### `readTimeout`
 ##### `readTimeout`
 
 
 ```
 ```
-Type:           duration
+Type:           decimal number
 Default:        0
 Default:        0
 ```
 ```
 
 
-I/O read timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
+I/O read timeout. The value must be a decimal number with an unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*.
 
 
-##### `rejectReadOnly`
+##### `strict`
 
 
 ```
 ```
 Type:           bool
 Type:           bool
@@ -278,37 +274,20 @@ Valid Values:   true, false
 Default:        false
 Default:        false
 ```
 ```
 
 
+`strict=true` enables a driver-side strict mode in which MySQL warnings are treated as errors. This mode should not be used in production as it may lead to data corruption in certain situations.
 
 
-`rejectReadOnly=true` causes the driver to reject read-only connections. This
-is for a possible race condition during an automatic failover, where the mysql
-client gets connected to a read-only replica after the failover.
-
-Note that this should be a fairly rare case, as an automatic failover normally
-happens when the primary is down, and the race condition shouldn't happen
-unless it comes back up online as soon as the failover is kicked off. On the
-other hand, when this happens, a MySQL application can get stuck on a
-read-only connection until restarted. It is however fairly easy to reproduce,
-for example, using a manual failover on AWS Aurora's MySQL-compatible cluster.
-
-If you are not relying on read-only transactions to reject writes that aren't
-supposed to happen, setting this on some MySQL providers (such as AWS Aurora)
-is safer for failovers.
-
-Note that ERROR 1290 can be returned for a `read-only` server and this option will
-cause a retry for that error. However the same error number is used for some
-other cases. You should ensure your application will never cause an ERROR 1290
-except for `read-only` mode when enabling this option.
+A server-side strict mode, which is safe for production use, can be set via the [`sql_mode`](https://dev.mysql.com/doc/refman/5.7/en/sql-mode.html) system variable.
 
 
+By default MySQL also treats notes as warnings. Use [`sql_notes=false`](http://dev.mysql.com/doc/refman/5.7/en/server-system-variables.html#sysvar_sql_notes) to ignore notes.
 
 
 ##### `timeout`
 ##### `timeout`
 
 
 ```
 ```
-Type:           duration
+Type:           decimal number
 Default:        OS default
 Default:        OS default
 ```
 ```
 
 
-Timeout for establishing connections, aka dial timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
-
+*Driver* side connection timeout. The value must be a decimal number with an unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*. To set a server side timeout, use the parameter [`wait_timeout`](http://dev.mysql.com/doc/refman/5.6/en/server-system-variables.html#sysvar_wait_timeout).
 
 
 ##### `tls`
 ##### `tls`
 
 
@@ -320,15 +299,14 @@ Default:        false
 
 
 `tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
 `tls=true` enables TLS / SSL encrypted connection to the server. Use `skip-verify` if you want to use a self-signed or invalid certificate (server side). Use a custom value registered with [`mysql.RegisterTLSConfig`](https://godoc.org/github.com/go-sql-driver/mysql#RegisterTLSConfig).
 
 
-
 ##### `writeTimeout`
 ##### `writeTimeout`
 
 
 ```
 ```
-Type:           duration
+Type:           decimal number
 Default:        0
 Default:        0
 ```
 ```
 
 
-I/O write timeout. The value must be a decimal number with a unit suffix (*"ms"*, *"s"*, *"m"*, *"h"*), such as *"30s"*, *"0.5m"* or *"1m30s"*.
+I/O write timeout. The value must be a decimal number with an unit suffix ( *"ms"*, *"s"*, *"m"*, *"h"* ), such as *"30s"*, *"0.5m"* or *"1m30s"*.
 
 
 
 
 ##### System Variables
 ##### System Variables
@@ -339,9 +317,9 @@ Any other parameters are interpreted as system variables:
   * `<string_var>=%27<value>%27`: `SET <string_var>='<value>'`
   * `<string_var>=%27<value>%27`: `SET <string_var>='<value>'`
 
 
 Rules:
 Rules:
-* The values for string variables must be quoted with `'`.
+* The values for string variables must be quoted with '
 * The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed!
 * The values must also be [url.QueryEscape](http://golang.org/pkg/net/url/#QueryEscape)'ed!
- (which implies values of string variables must be wrapped with `%27`).
+ (which implies values of string variables must be wrapped with `%27`)
 
 
 Examples:
 Examples:
   * `autocommit=1`: `SET autocommit=1`
   * `autocommit=1`: `SET autocommit=1`
@@ -402,18 +380,6 @@ No Database preselected:
 user:password@/
 user:password@/
 ```
 ```
 
 
-
-### Connection pool and timeouts
-The connection pool is managed by Go's database/sql package. For details on how to configure the size of the pool and how long connections stay in the pool see `*DB.SetMaxOpenConns`, `*DB.SetMaxIdleConns`, and `*DB.SetConnMaxLifetime` in the [database/sql documentation](https://golang.org/pkg/database/sql/). The read, write, and dial timeouts for each individual connection are configured with the DSN parameters [`readTimeout`](#readtimeout), [`writeTimeout`](#writetimeout), and [`timeout`](#timeout), respectively.
-
-## `ColumnType` Support
-This driver supports the [`ColumnType` interface](https://golang.org/pkg/database/sql/#ColumnType) introduced in Go 1.8, with the exception of [`ColumnType.Length()`](https://golang.org/pkg/database/sql/#ColumnType.Length), which is currently not supported.
-
-## `context.Context` Support
-Go 1.8 added `database/sql` support for `context.Context`. This driver supports query timeouts and cancellation via contexts.
-See [context support in the database/sql package](https://golang.org/doc/go1.8#database_sql) for more details.
-
-
 ### `LOAD DATA LOCAL INFILE` support
 ### `LOAD DATA LOCAL INFILE` support
 For this feature you need direct access to the package. Therefore you must change the import path (no `_`):
 For this feature you need direct access to the package. Therefore you must change the import path (no `_`):
 ```go
 ```go
@@ -428,7 +394,7 @@ See the [godoc of Go-MySQL-Driver](https://godoc.org/github.com/go-sql-driver/my
 
 
 
 
 ### `time.Time` support
 ### `time.Time` support
-The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your program.
+The default internal output type of MySQL `DATE` and `DATETIME` values is `[]byte` which allows you to scan the value into a `[]byte`, `string` or `sql.RawBytes` variable in your programm.
 
 
 However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical opposite in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter.
 However, many want to scan MySQL `DATE` and `DATETIME` values into `time.Time` variables, which is the logical opposite in Go to `DATE` and `DATETIME` in MySQL. You can do that by changing the internal output type from `[]byte` to `time.Time` with the DSN parameter `parseTime=true`. You can set the default [`time.Time` location](https://golang.org/pkg/time/#Location) with the `loc` DSN parameter.
 
 
@@ -446,6 +412,7 @@ Version 1.0 of the driver recommended adding `&charset=utf8` (alias for `SET NAM
 
 
 See http://dev.mysql.com/doc/refman/5.7/en/charset-unicode.html for more details on MySQL's Unicode support.
 See http://dev.mysql.com/doc/refman/5.7/en/charset-unicode.html for more details on MySQL's Unicode support.
 
 
+
 ## Testing / Development
 ## Testing / Development
 To run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing "Testing") for details.
 To run the driver tests you may need to adjust the configuration. See the [Testing Wiki-Page](https://github.com/go-sql-driver/mysql/wiki/Testing "Testing") for details.
 
 
@@ -464,13 +431,13 @@ Mozilla summarizes the license scope as follows:
 
 
 
 
 That means:
 That means:
-  * You can **use** the **unchanged** source code both in private and commercially.
-  * When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0).
-  * You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**.
+  * You can **use** the **unchanged** source code both in private and commercially
+  * When distributing, you **must publish** the source code of any **changed files** licensed under the MPL 2.0 under a) the MPL 2.0 itself or b) a compatible license (e.g. GPL 3.0 or Apache License 2.0)
+  * You **needn't publish** the source code of your library as long as the files licensed under the MPL 2.0 are **unchanged**
 
 
 Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license.
 Please read the [MPL 2.0 FAQ](https://www.mozilla.org/en-US/MPL/2.0/FAQ/) if you have further questions regarding the license.
 
 
-You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE).
+You can read the full terms here: [LICENSE](https://raw.github.com/go-sql-driver/mysql/master/LICENSE)
 
 
 ![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow")
 ![Go Gopher and MySQL Dolphin](https://raw.github.com/wiki/go-sql-driver/mysql/go-mysql-driver_m.jpg "Golang Gopher transporting the MySQL Dolphin in a wheelbarrow")
 
 

+ 1 - 1
vendor/github.com/go-sql-driver/mysql/appengine.go

@@ -11,7 +11,7 @@
 package mysql
 package mysql
 
 
 import (
 import (
-	"google.golang.org/appengine/cloudsql"
+	"appengine/cloudsql"
 )
 )
 
 
 func init() {
 func init() {

+ 32 - 116
vendor/github.com/go-sql-driver/mysql/connection.go

@@ -10,23 +10,12 @@ package mysql
 
 
 import (
 import (
 	"database/sql/driver"
 	"database/sql/driver"
-	"io"
 	"net"
 	"net"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"time"
 	"time"
 )
 )
 
 
-// a copy of context.Context for Go 1.7 and earlier
-type mysqlContext interface {
-	Done() <-chan struct{}
-	Err() error
-
-	// defined in context.Context, but not used in this driver:
-	// Deadline() (deadline time.Time, ok bool)
-	// Value(key interface{}) interface{}
-}
-
 type mysqlConn struct {
 type mysqlConn struct {
 	buf              buffer
 	buf              buffer
 	netConn          net.Conn
 	netConn          net.Conn
@@ -40,14 +29,7 @@ type mysqlConn struct {
 	status           statusFlag
 	status           statusFlag
 	sequence         uint8
 	sequence         uint8
 	parseTime        bool
 	parseTime        bool
-
-	// for context support (Go 1.8+)
-	watching bool
-	watcher  chan<- mysqlContext
-	closech  chan struct{}
-	finished chan<- struct{}
-	canceled atomicError // set non-nil if conn is canceled
-	closed   atomicBool  // set when conn is closed, before closech is closed
+	strict           bool
 }
 }
 
 
 // Handles parameters set in DSN after the connection is established
 // Handles parameters set in DSN after the connection is established
@@ -80,41 +62,22 @@ func (mc *mysqlConn) handleParams() (err error) {
 	return
 	return
 }
 }
 
 
-func (mc *mysqlConn) markBadConn(err error) error {
-	if mc == nil {
-		return err
-	}
-	if err != errBadConnNoWrite {
-		return err
-	}
-	return driver.ErrBadConn
-}
-
 func (mc *mysqlConn) Begin() (driver.Tx, error) {
 func (mc *mysqlConn) Begin() (driver.Tx, error) {
-	return mc.begin(false)
-}
-
-func (mc *mysqlConn) begin(readOnly bool) (driver.Tx, error) {
-	if mc.closed.IsSet() {
+	if mc.netConn == nil {
 		errLog.Print(ErrInvalidConn)
 		errLog.Print(ErrInvalidConn)
 		return nil, driver.ErrBadConn
 		return nil, driver.ErrBadConn
 	}
 	}
-	var q string
-	if readOnly {
-		q = "START TRANSACTION READ ONLY"
-	} else {
-		q = "START TRANSACTION"
-	}
-	err := mc.exec(q)
+	err := mc.exec("START TRANSACTION")
 	if err == nil {
 	if err == nil {
 		return &mysqlTx{mc}, err
 		return &mysqlTx{mc}, err
 	}
 	}
-	return nil, mc.markBadConn(err)
+
+	return nil, err
 }
 }
 
 
 func (mc *mysqlConn) Close() (err error) {
 func (mc *mysqlConn) Close() (err error) {
 	// Makes Close idempotent
 	// Makes Close idempotent
-	if !mc.closed.IsSet() {
+	if mc.netConn != nil {
 		err = mc.writeCommandPacket(comQuit)
 		err = mc.writeCommandPacket(comQuit)
 	}
 	}
 
 
@@ -128,39 +91,26 @@ func (mc *mysqlConn) Close() (err error) {
 // is called before auth or on auth failure because MySQL will have already
 // is called before auth or on auth failure because MySQL will have already
 // closed the network connection.
 // closed the network connection.
 func (mc *mysqlConn) cleanup() {
 func (mc *mysqlConn) cleanup() {
-	if !mc.closed.TrySet(true) {
-		return
-	}
-
 	// Makes cleanup idempotent
 	// Makes cleanup idempotent
-	close(mc.closech)
-	if mc.netConn == nil {
-		return
-	}
-	if err := mc.netConn.Close(); err != nil {
-		errLog.Print(err)
-	}
-}
-
-func (mc *mysqlConn) error() error {
-	if mc.closed.IsSet() {
-		if err := mc.canceled.Value(); err != nil {
-			return err
+	if mc.netConn != nil {
+		if err := mc.netConn.Close(); err != nil {
+			errLog.Print(err)
 		}
 		}
-		return ErrInvalidConn
+		mc.netConn = nil
 	}
 	}
-	return nil
+	mc.cfg = nil
+	mc.buf.nc = nil
 }
 }
 
 
 func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
 func (mc *mysqlConn) Prepare(query string) (driver.Stmt, error) {
-	if mc.closed.IsSet() {
+	if mc.netConn == nil {
 		errLog.Print(ErrInvalidConn)
 		errLog.Print(ErrInvalidConn)
 		return nil, driver.ErrBadConn
 		return nil, driver.ErrBadConn
 	}
 	}
 	// Send command
 	// Send command
 	err := mc.writeCommandPacketStr(comStmtPrepare, query)
 	err := mc.writeCommandPacketStr(comStmtPrepare, query)
 	if err != nil {
 	if err != nil {
-		return nil, mc.markBadConn(err)
+		return nil, err
 	}
 	}
 
 
 	stmt := &mysqlStmt{
 	stmt := &mysqlStmt{
@@ -194,7 +144,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
 	if buf == nil {
 	if buf == nil {
 		// can not take the buffer. Something must be wrong with the connection
 		// can not take the buffer. Something must be wrong with the connection
 		errLog.Print(ErrBusyBuffer)
 		errLog.Print(ErrBusyBuffer)
-		return "", ErrInvalidConn
+		return "", driver.ErrBadConn
 	}
 	}
 	buf = buf[:0]
 	buf = buf[:0]
 	argPos := 0
 	argPos := 0
@@ -307,7 +257,7 @@ func (mc *mysqlConn) interpolateParams(query string, args []driver.Value) (strin
 }
 }
 
 
 func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
 func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, error) {
-	if mc.closed.IsSet() {
+	if mc.netConn == nil {
 		errLog.Print(ErrInvalidConn)
 		errLog.Print(ErrInvalidConn)
 		return nil, driver.ErrBadConn
 		return nil, driver.ErrBadConn
 	}
 	}
@@ -321,6 +271,7 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err
 			return nil, err
 			return nil, err
 		}
 		}
 		query = prepared
 		query = prepared
+		args = nil
 	}
 	}
 	mc.affectedRows = 0
 	mc.affectedRows = 0
 	mc.insertId = 0
 	mc.insertId = 0
@@ -332,43 +283,32 @@ func (mc *mysqlConn) Exec(query string, args []driver.Value) (driver.Result, err
 			insertId:     int64(mc.insertId),
 			insertId:     int64(mc.insertId),
 		}, err
 		}, err
 	}
 	}
-	return nil, mc.markBadConn(err)
+	return nil, err
 }
 }
 
 
 // Internal function to execute commands
 // Internal function to execute commands
 func (mc *mysqlConn) exec(query string) error {
 func (mc *mysqlConn) exec(query string) error {
 	// Send command
 	// Send command
-	if err := mc.writeCommandPacketStr(comQuery, query); err != nil {
-		return mc.markBadConn(err)
-	}
-
-	// Read Result
-	resLen, err := mc.readResultSetHeaderPacket()
+	err := mc.writeCommandPacketStr(comQuery, query)
 	if err != nil {
 	if err != nil {
 		return err
 		return err
 	}
 	}
 
 
-	if resLen > 0 {
-		// columns
-		if err := mc.readUntilEOF(); err != nil {
+	// Read Result
+	resLen, err := mc.readResultSetHeaderPacket()
+	if err == nil && resLen > 0 {
+		if err = mc.readUntilEOF(); err != nil {
 			return err
 			return err
 		}
 		}
 
 
-		// rows
-		if err := mc.readUntilEOF(); err != nil {
-			return err
-		}
+		err = mc.readUntilEOF()
 	}
 	}
 
 
-	return mc.discardResults()
+	return err
 }
 }
 
 
 func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
 func (mc *mysqlConn) Query(query string, args []driver.Value) (driver.Rows, error) {
-	return mc.query(query, args)
-}
-
-func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error) {
-	if mc.closed.IsSet() {
+	if mc.netConn == nil {
 		errLog.Print(ErrInvalidConn)
 		errLog.Print(ErrInvalidConn)
 		return nil, driver.ErrBadConn
 		return nil, driver.ErrBadConn
 	}
 	}
@@ -382,6 +322,7 @@ func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error)
 			return nil, err
 			return nil, err
 		}
 		}
 		query = prepared
 		query = prepared
+		args = nil
 	}
 	}
 	// Send command
 	// Send command
 	err := mc.writeCommandPacketStr(comQuery, query)
 	err := mc.writeCommandPacketStr(comQuery, query)
@@ -394,22 +335,15 @@ func (mc *mysqlConn) query(query string, args []driver.Value) (*textRows, error)
 			rows.mc = mc
 			rows.mc = mc
 
 
 			if resLen == 0 {
 			if resLen == 0 {
-				rows.rs.done = true
-
-				switch err := rows.NextResultSet(); err {
-				case nil, io.EOF:
-					return rows, nil
-				default:
-					return nil, err
-				}
+				// no columns, no more data
+				return emptyRows{}, nil
 			}
 			}
-
 			// Columns
 			// Columns
-			rows.rs.columns, err = mc.readColumns(resLen)
+			rows.columns, err = mc.readColumns(resLen)
 			return rows, err
 			return rows, err
 		}
 		}
 	}
 	}
-	return nil, mc.markBadConn(err)
+	return nil, err
 }
 }
 
 
 // Gets the value of the given MySQL System Variable
 // Gets the value of the given MySQL System Variable
@@ -425,7 +359,7 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
 	if err == nil {
 	if err == nil {
 		rows := new(textRows)
 		rows := new(textRows)
 		rows.mc = mc
 		rows.mc = mc
-		rows.rs.columns = []mysqlField{{fieldType: fieldTypeVarChar}}
+		rows.columns = []mysqlField{{fieldType: fieldTypeVarChar}}
 
 
 		if resLen > 0 {
 		if resLen > 0 {
 			// Columns
 			// Columns
@@ -441,21 +375,3 @@ func (mc *mysqlConn) getSystemVar(name string) ([]byte, error) {
 	}
 	}
 	return nil, err
 	return nil, err
 }
 }
-
-// finish is called when the query has canceled.
-func (mc *mysqlConn) cancel(err error) {
-	mc.canceled.Set(err)
-	mc.cleanup()
-}
-
-// finish is called when the query has succeeded.
-func (mc *mysqlConn) finish() {
-	if !mc.watching || mc.finished == nil {
-		return
-	}
-	select {
-	case mc.finished <- struct{}{}:
-		mc.watching = false
-	case <-mc.closech:
-	}
-}

+ 0 - 202
vendor/github.com/go-sql-driver/mysql/connection_go18.go

@@ -1,202 +0,0 @@
-// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
-//
-// Copyright 2012 The Go-MySQL-Driver Authors. All rights reserved.
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// +build go1.8
-
-package mysql
-
-import (
-	"context"
-	"database/sql"
-	"database/sql/driver"
-)
-
-// Ping implements driver.Pinger interface
-func (mc *mysqlConn) Ping(ctx context.Context) error {
-	if mc.closed.IsSet() {
-		errLog.Print(ErrInvalidConn)
-		return driver.ErrBadConn
-	}
-
-	if err := mc.watchCancel(ctx); err != nil {
-		return err
-	}
-	defer mc.finish()
-
-	if err := mc.writeCommandPacket(comPing); err != nil {
-		return err
-	}
-	if _, err := mc.readResultOK(); err != nil {
-		return err
-	}
-
-	return nil
-}
-
-// BeginTx implements driver.ConnBeginTx interface
-func (mc *mysqlConn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) {
-	if err := mc.watchCancel(ctx); err != nil {
-		return nil, err
-	}
-	defer mc.finish()
-
-	if sql.IsolationLevel(opts.Isolation) != sql.LevelDefault {
-		level, err := mapIsolationLevel(opts.Isolation)
-		if err != nil {
-			return nil, err
-		}
-		err = mc.exec("SET TRANSACTION ISOLATION LEVEL " + level)
-		if err != nil {
-			return nil, err
-		}
-	}
-
-	return mc.begin(opts.ReadOnly)
-}
-
-func (mc *mysqlConn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) {
-	dargs, err := namedValueToValue(args)
-	if err != nil {
-		return nil, err
-	}
-
-	if err := mc.watchCancel(ctx); err != nil {
-		return nil, err
-	}
-
-	rows, err := mc.query(query, dargs)
-	if err != nil {
-		mc.finish()
-		return nil, err
-	}
-	rows.finish = mc.finish
-	return rows, err
-}
-
-func (mc *mysqlConn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) {
-	dargs, err := namedValueToValue(args)
-	if err != nil {
-		return nil, err
-	}
-
-	if err := mc.watchCancel(ctx); err != nil {
-		return nil, err
-	}
-	defer mc.finish()
-
-	return mc.Exec(query, dargs)
-}
-
-func (mc *mysqlConn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) {
-	if err := mc.watchCancel(ctx); err != nil {
-		return nil, err
-	}
-
-	stmt, err := mc.Prepare(query)
-	mc.finish()
-	if err != nil {
-		return nil, err
-	}
-
-	select {
-	default:
-	case <-ctx.Done():
-		stmt.Close()
-		return nil, ctx.Err()
-	}
-	return stmt, nil
-}
-
-func (stmt *mysqlStmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) {
-	dargs, err := namedValueToValue(args)
-	if err != nil {
-		return nil, err
-	}
-
-	if err := stmt.mc.watchCancel(ctx); err != nil {
-		return nil, err
-	}
-
-	rows, err := stmt.query(dargs)
-	if err != nil {
-		stmt.mc.finish()
-		return nil, err
-	}
-	rows.finish = stmt.mc.finish
-	return rows, err
-}
-
-func (stmt *mysqlStmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) {
-	dargs, err := namedValueToValue(args)
-	if err != nil {
-		return nil, err
-	}
-
-	if err := stmt.mc.watchCancel(ctx); err != nil {
-		return nil, err
-	}
-	defer stmt.mc.finish()
-
-	return stmt.Exec(dargs)
-}
-
-func (mc *mysqlConn) watchCancel(ctx context.Context) error {
-	if mc.watching {
-		// Reach here if canceled,
-		// so the connection is already invalid
-		mc.cleanup()
-		return nil
-	}
-	if ctx.Done() == nil {
-		return nil
-	}
-
-	mc.watching = true
-	select {
-	default:
-	case <-ctx.Done():
-		return ctx.Err()
-	}
-	if mc.watcher == nil {
-		return nil
-	}
-
-	mc.watcher <- ctx
-
-	return nil
-}
-
-func (mc *mysqlConn) startWatcher() {
-	watcher := make(chan mysqlContext, 1)
-	mc.watcher = watcher
-	finished := make(chan struct{})
-	mc.finished = finished
-	go func() {
-		for {
-			var ctx mysqlContext
-			select {
-			case ctx = <-watcher:
-			case <-mc.closech:
-				return
-			}
-
-			select {
-			case <-ctx.Done():
-				mc.cancel(ctx.Err())
-			case <-finished:
-			case <-mc.closech:
-				return
-			}
-		}
-	}()
-}
-
-func (mc *mysqlConn) CheckNamedValue(nv *driver.NamedValue) (err error) {
-	nv.Value, err = converter{}.ConvertValue(nv.Value)
-	return
-}

+ 3 - 6
vendor/github.com/go-sql-driver/mysql/const.go

@@ -9,8 +9,7 @@
 package mysql
 package mysql
 
 
 const (
 const (
-	defaultMaxAllowedPacket = 4 << 20 // 4 MiB
-	minProtocolVersion      = 10
+	minProtocolVersion byte = 10
 	maxPacketSize           = 1<<24 - 1
 	maxPacketSize           = 1<<24 - 1
 	timeFormat              = "2006-01-02 15:04:05.999999"
 	timeFormat              = "2006-01-02 15:04:05.999999"
 )
 )
@@ -88,10 +87,8 @@ const (
 )
 )
 
 
 // https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType
 // https://dev.mysql.com/doc/internals/en/com-query-response.html#packet-Protocol::ColumnType
-type fieldType byte
-
 const (
 const (
-	fieldTypeDecimal fieldType = iota
+	fieldTypeDecimal byte = iota
 	fieldTypeTiny
 	fieldTypeTiny
 	fieldTypeShort
 	fieldTypeShort
 	fieldTypeLong
 	fieldTypeLong
@@ -110,7 +107,7 @@ const (
 	fieldTypeBit
 	fieldTypeBit
 )
 )
 const (
 const (
-	fieldTypeJSON fieldType = iota + 0xf5
+	fieldTypeJSON byte = iota + 0xf5
 	fieldTypeNewDecimal
 	fieldTypeNewDecimal
 	fieldTypeEnum
 	fieldTypeEnum
 	fieldTypeSet
 	fieldTypeSet

+ 2 - 12
vendor/github.com/go-sql-driver/mysql/driver.go

@@ -4,7 +4,7 @@
 // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 // License, v. 2.0. If a copy of the MPL was not distributed with this file,
 // You can obtain one at http://mozilla.org/MPL/2.0/.
 // You can obtain one at http://mozilla.org/MPL/2.0/.
 
 
-// Package mysql provides a MySQL driver for Go's database/sql package.
+// Package mysql provides a MySQL driver for Go's database/sql package
 //
 //
 // The driver should be used via the database/sql package:
 // The driver should be used via the database/sql package:
 //
 //
@@ -22,11 +22,6 @@ import (
 	"net"
 	"net"
 )
 )
 
 
-// watcher interface is used for context support (From Go 1.8)
-type watcher interface {
-	startWatcher()
-}
-
 // MySQLDriver is exported to make the driver directly accessible.
 // MySQLDriver is exported to make the driver directly accessible.
 // In general the driver is used via the database/sql package.
 // In general the driver is used via the database/sql package.
 type MySQLDriver struct{}
 type MySQLDriver struct{}
@@ -57,13 +52,13 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
 	mc := &mysqlConn{
 	mc := &mysqlConn{
 		maxAllowedPacket: maxPacketSize,
 		maxAllowedPacket: maxPacketSize,
 		maxWriteSize:     maxPacketSize - 1,
 		maxWriteSize:     maxPacketSize - 1,
-		closech:          make(chan struct{}),
 	}
 	}
 	mc.cfg, err = ParseDSN(dsn)
 	mc.cfg, err = ParseDSN(dsn)
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
 	mc.parseTime = mc.cfg.ParseTime
 	mc.parseTime = mc.cfg.ParseTime
+	mc.strict = mc.cfg.Strict
 
 
 	// Connect to Server
 	// Connect to Server
 	if dial, ok := dials[mc.cfg.Net]; ok {
 	if dial, ok := dials[mc.cfg.Net]; ok {
@@ -86,11 +81,6 @@ func (d MySQLDriver) Open(dsn string) (driver.Conn, error) {
 		}
 		}
 	}
 	}
 
 
-	// Call startWatcher for context support (From Go 1.8)
-	if s, ok := interface{}(mc).(watcher); ok {
-		s.startWatcher()
-	}
-
 	mc.buf = newBuffer(mc.netConn)
 	mc.buf = newBuffer(mc.netConn)
 
 
 	// Set I/O timeouts
 	// Set I/O timeouts

+ 41 - 79
vendor/github.com/go-sql-driver/mysql/dsn.go

@@ -15,7 +15,6 @@ import (
 	"fmt"
 	"fmt"
 	"net"
 	"net"
 	"net/url"
 	"net/url"
-	"sort"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
 	"time"
 	"time"
@@ -28,9 +27,7 @@ var (
 	errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations")
 	errInvalidDSNUnsafeCollation = errors.New("invalid DSN: interpolateParams can not be used with unsafe collations")
 )
 )
 
 
-// Config is a configuration parsed from a DSN string.
-// If a new Config is created instead of being parsed from a DSN string,
-// the NewConfig function should be used, which sets default values.
+// Config is a configuration parsed from a DSN string
 type Config struct {
 type Config struct {
 	User             string            // Username
 	User             string            // Username
 	Passwd           string            // Password (requires User)
 	Passwd           string            // Password (requires User)
@@ -56,45 +53,7 @@ type Config struct {
 	InterpolateParams       bool // Interpolate placeholders into query string
 	InterpolateParams       bool // Interpolate placeholders into query string
 	MultiStatements         bool // Allow multiple statements in one query
 	MultiStatements         bool // Allow multiple statements in one query
 	ParseTime               bool // Parse time values to time.Time
 	ParseTime               bool // Parse time values to time.Time
-	RejectReadOnly          bool // Reject read-only connections
-}
-
-// NewConfig creates a new Config and sets default values.
-func NewConfig() *Config {
-	return &Config{
-		Collation:            defaultCollation,
-		Loc:                  time.UTC,
-		MaxAllowedPacket:     defaultMaxAllowedPacket,
-		AllowNativePasswords: true,
-	}
-}
-
-func (cfg *Config) normalize() error {
-	if cfg.InterpolateParams && unsafeCollations[cfg.Collation] {
-		return errInvalidDSNUnsafeCollation
-	}
-
-	// Set default network if empty
-	if cfg.Net == "" {
-		cfg.Net = "tcp"
-	}
-
-	// Set default address if empty
-	if cfg.Addr == "" {
-		switch cfg.Net {
-		case "tcp":
-			cfg.Addr = "127.0.0.1:3306"
-		case "unix":
-			cfg.Addr = "/tmp/mysql.sock"
-		default:
-			return errors.New("default addr for network '" + cfg.Net + "' unknown")
-		}
-
-	} else if cfg.Net == "tcp" {
-		cfg.Addr = ensureHavePort(cfg.Addr)
-	}
-
-	return nil
+	Strict                  bool // Return warnings as errors
 }
 }
 
 
 // FormatDSN formats the given Config into a DSN string which can be passed to
 // FormatDSN formats the given Config into a DSN string which can be passed to
@@ -143,12 +102,12 @@ func (cfg *Config) FormatDSN() string {
 		}
 		}
 	}
 	}
 
 
-	if !cfg.AllowNativePasswords {
+	if cfg.AllowNativePasswords {
 		if hasParam {
 		if hasParam {
-			buf.WriteString("&allowNativePasswords=false")
+			buf.WriteString("&allowNativePasswords=true")
 		} else {
 		} else {
 			hasParam = true
 			hasParam = true
-			buf.WriteString("?allowNativePasswords=false")
+			buf.WriteString("?allowNativePasswords=true")
 		}
 		}
 	}
 	}
 
 
@@ -236,12 +195,12 @@ func (cfg *Config) FormatDSN() string {
 		buf.WriteString(cfg.ReadTimeout.String())
 		buf.WriteString(cfg.ReadTimeout.String())
 	}
 	}
 
 
-	if cfg.RejectReadOnly {
+	if cfg.Strict {
 		if hasParam {
 		if hasParam {
-			buf.WriteString("&rejectReadOnly=true")
+			buf.WriteString("&strict=true")
 		} else {
 		} else {
 			hasParam = true
 			hasParam = true
-			buf.WriteString("?rejectReadOnly=true")
+			buf.WriteString("?strict=true")
 		}
 		}
 	}
 	}
 
 
@@ -275,7 +234,7 @@ func (cfg *Config) FormatDSN() string {
 		buf.WriteString(cfg.WriteTimeout.String())
 		buf.WriteString(cfg.WriteTimeout.String())
 	}
 	}
 
 
-	if cfg.MaxAllowedPacket != defaultMaxAllowedPacket {
+	if cfg.MaxAllowedPacket > 0 {
 		if hasParam {
 		if hasParam {
 			buf.WriteString("&maxAllowedPacket=")
 			buf.WriteString("&maxAllowedPacket=")
 		} else {
 		} else {
@@ -288,12 +247,7 @@ func (cfg *Config) FormatDSN() string {
 
 
 	// other params
 	// other params
 	if cfg.Params != nil {
 	if cfg.Params != nil {
-		var params []string
-		for param := range cfg.Params {
-			params = append(params, param)
-		}
-		sort.Strings(params)
-		for _, param := range params {
+		for param, value := range cfg.Params {
 			if hasParam {
 			if hasParam {
 				buf.WriteByte('&')
 				buf.WriteByte('&')
 			} else {
 			} else {
@@ -303,7 +257,7 @@ func (cfg *Config) FormatDSN() string {
 
 
 			buf.WriteString(param)
 			buf.WriteString(param)
 			buf.WriteByte('=')
 			buf.WriteByte('=')
-			buf.WriteString(url.QueryEscape(cfg.Params[param]))
+			buf.WriteString(url.QueryEscape(value))
 		}
 		}
 	}
 	}
 
 
@@ -313,7 +267,10 @@ func (cfg *Config) FormatDSN() string {
 // ParseDSN parses the DSN string to a Config
 // ParseDSN parses the DSN string to a Config
 func ParseDSN(dsn string) (cfg *Config, err error) {
 func ParseDSN(dsn string) (cfg *Config, err error) {
 	// New config with some default values
 	// New config with some default values
-	cfg = NewConfig()
+	cfg = &Config{
+		Loc:       time.UTC,
+		Collation: defaultCollation,
+	}
 
 
 	// [user[:password]@][net[(addr)]]/dbname[?param1=value1&paramN=valueN]
 	// [user[:password]@][net[(addr)]]/dbname[?param1=value1&paramN=valueN]
 	// Find the last '/' (since the password or the net addr might contain a '/')
 	// Find the last '/' (since the password or the net addr might contain a '/')
@@ -381,9 +338,28 @@ func ParseDSN(dsn string) (cfg *Config, err error) {
 		return nil, errInvalidDSNNoSlash
 		return nil, errInvalidDSNNoSlash
 	}
 	}
 
 
-	if err = cfg.normalize(); err != nil {
-		return nil, err
+	if cfg.InterpolateParams && unsafeCollations[cfg.Collation] {
+		return nil, errInvalidDSNUnsafeCollation
+	}
+
+	// Set default network if empty
+	if cfg.Net == "" {
+		cfg.Net = "tcp"
+	}
+
+	// Set default address if empty
+	if cfg.Addr == "" {
+		switch cfg.Net {
+		case "tcp":
+			cfg.Addr = "127.0.0.1:3306"
+		case "unix":
+			cfg.Addr = "/tmp/mysql.sock"
+		default:
+			return nil, errors.New("default addr for network '" + cfg.Net + "' unknown")
+		}
+
 	}
 	}
+
 	return
 	return
 }
 }
 
 
@@ -398,6 +374,7 @@ func parseDSNParams(cfg *Config, params string) (err error) {
 
 
 		// cfg params
 		// cfg params
 		switch value := param[1]; param[0] {
 		switch value := param[1]; param[0] {
+
 		// Disable INFILE whitelist / enable all files
 		// Disable INFILE whitelist / enable all files
 		case "allowAllFiles":
 		case "allowAllFiles":
 			var isBool bool
 			var isBool bool
@@ -495,18 +472,14 @@ func parseDSNParams(cfg *Config, params string) (err error) {
 				return
 				return
 			}
 			}
 
 
-		// Reject read-only connections
-		case "rejectReadOnly":
+		// Strict mode
+		case "strict":
 			var isBool bool
 			var isBool bool
-			cfg.RejectReadOnly, isBool = readBool(value)
+			cfg.Strict, isBool = readBool(value)
 			if !isBool {
 			if !isBool {
 				return errors.New("invalid bool value: " + value)
 				return errors.New("invalid bool value: " + value)
 			}
 			}
 
 
-		// Strict mode
-		case "strict":
-			panic("strict mode has been removed. See https://github.com/go-sql-driver/mysql/wiki/strict-mode")
-
 		// Dial Timeout
 		// Dial Timeout
 		case "timeout":
 		case "timeout":
 			cfg.Timeout, err = time.ParseDuration(value)
 			cfg.Timeout, err = time.ParseDuration(value)
@@ -521,10 +494,6 @@ func parseDSNParams(cfg *Config, params string) (err error) {
 				if boolValue {
 				if boolValue {
 					cfg.TLSConfig = "true"
 					cfg.TLSConfig = "true"
 					cfg.tls = &tls.Config{}
 					cfg.tls = &tls.Config{}
-					host, _, err := net.SplitHostPort(cfg.Addr)
-					if err == nil {
-						cfg.tls.ServerName = host
-					}
 				} else {
 				} else {
 					cfg.TLSConfig = "false"
 					cfg.TLSConfig = "false"
 				}
 				}
@@ -537,7 +506,7 @@ func parseDSNParams(cfg *Config, params string) (err error) {
 					return fmt.Errorf("invalid value for TLS config name: %v", err)
 					return fmt.Errorf("invalid value for TLS config name: %v", err)
 				}
 				}
 
 
-				if tlsConfig := getTLSConfigClone(name); tlsConfig != nil {
+				if tlsConfig, ok := tlsConfigRegister[name]; ok {
 					if len(tlsConfig.ServerName) == 0 && !tlsConfig.InsecureSkipVerify {
 					if len(tlsConfig.ServerName) == 0 && !tlsConfig.InsecureSkipVerify {
 						host, _, err := net.SplitHostPort(cfg.Addr)
 						host, _, err := net.SplitHostPort(cfg.Addr)
 						if err == nil {
 						if err == nil {
@@ -577,10 +546,3 @@ func parseDSNParams(cfg *Config, params string) (err error) {
 
 
 	return
 	return
 }
 }
-
-func ensureHavePort(addr string) string {
-	if _, _, err := net.SplitHostPort(addr); err != nil {
-		return net.JoinHostPort(addr, "3306")
-	}
-	return addr
-}

+ 73 - 6
vendor/github.com/go-sql-driver/mysql/errors.go

@@ -9,8 +9,10 @@
 package mysql
 package mysql
 
 
 import (
 import (
+	"database/sql/driver"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"io"
 	"log"
 	"log"
 	"os"
 	"os"
 )
 )
@@ -29,12 +31,6 @@ var (
 	ErrPktSyncMul        = errors.New("commands out of sync. Did you run multiple statements at once?")
 	ErrPktSyncMul        = errors.New("commands out of sync. Did you run multiple statements at once?")
 	ErrPktTooLarge       = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server")
 	ErrPktTooLarge       = errors.New("packet for query is too large. Try adjusting the 'max_allowed_packet' variable on the server")
 	ErrBusyBuffer        = errors.New("busy buffer")
 	ErrBusyBuffer        = errors.New("busy buffer")
-
-	// errBadConnNoWrite is used for connection errors where nothing was sent to the database yet.
-	// If this happens first in a function starting a database interaction, it should be replaced by driver.ErrBadConn
-	// to trigger a resend.
-	// See https://github.com/go-sql-driver/mysql/pull/302
-	errBadConnNoWrite = errors.New("bad connection")
 )
 )
 
 
 var errLog = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile))
 var errLog = Logger(log.New(os.Stderr, "[mysql] ", log.Ldate|log.Ltime|log.Lshortfile))
@@ -63,3 +59,74 @@ type MySQLError struct {
 func (me *MySQLError) Error() string {
 func (me *MySQLError) Error() string {
 	return fmt.Sprintf("Error %d: %s", me.Number, me.Message)
 	return fmt.Sprintf("Error %d: %s", me.Number, me.Message)
 }
 }
+
+// MySQLWarnings is an error type which represents a group of one or more MySQL
+// warnings
+type MySQLWarnings []MySQLWarning
+
+func (mws MySQLWarnings) Error() string {
+	var msg string
+	for i, warning := range mws {
+		if i > 0 {
+			msg += "\r\n"
+		}
+		msg += fmt.Sprintf(
+			"%s %s: %s",
+			warning.Level,
+			warning.Code,
+			warning.Message,
+		)
+	}
+	return msg
+}
+
+// MySQLWarning is an error type which represents a single MySQL warning.
+// Warnings are returned in groups only. See MySQLWarnings
+type MySQLWarning struct {
+	Level   string
+	Code    string
+	Message string
+}
+
+func (mc *mysqlConn) getWarnings() (err error) {
+	rows, err := mc.Query("SHOW WARNINGS", nil)
+	if err != nil {
+		return
+	}
+
+	var warnings = MySQLWarnings{}
+	var values = make([]driver.Value, 3)
+
+	for {
+		err = rows.Next(values)
+		switch err {
+		case nil:
+			warning := MySQLWarning{}
+
+			if raw, ok := values[0].([]byte); ok {
+				warning.Level = string(raw)
+			} else {
+				warning.Level = fmt.Sprintf("%s", values[0])
+			}
+			if raw, ok := values[1].([]byte); ok {
+				warning.Code = string(raw)
+			} else {
+				warning.Code = fmt.Sprintf("%s", values[1])
+			}
+			if raw, ok := values[2].([]byte); ok {
+				warning.Message = string(raw)
+			} else {
+				warning.Message = fmt.Sprintf("%s", values[0])
+			}
+
+			warnings = append(warnings, warning)
+
+		case io.EOF:
+			return warnings
+
+		default:
+			rows.Close()
+			return
+		}
+	}
+}

+ 0 - 140
vendor/github.com/go-sql-driver/mysql/fields.go

@@ -1,140 +0,0 @@
-// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
-//
-// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved.
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// You can obtain one at http://mozilla.org/MPL/2.0/.
-
-package mysql
-
-import (
-	"database/sql"
-	"reflect"
-)
-
-var typeDatabaseName = map[fieldType]string{
-	fieldTypeBit:        "BIT",
-	fieldTypeBLOB:       "BLOB",
-	fieldTypeDate:       "DATE",
-	fieldTypeDateTime:   "DATETIME",
-	fieldTypeDecimal:    "DECIMAL",
-	fieldTypeDouble:     "DOUBLE",
-	fieldTypeEnum:       "ENUM",
-	fieldTypeFloat:      "FLOAT",
-	fieldTypeGeometry:   "GEOMETRY",
-	fieldTypeInt24:      "MEDIUMINT",
-	fieldTypeJSON:       "JSON",
-	fieldTypeLong:       "INT",
-	fieldTypeLongBLOB:   "LONGBLOB",
-	fieldTypeLongLong:   "BIGINT",
-	fieldTypeMediumBLOB: "MEDIUMBLOB",
-	fieldTypeNewDate:    "DATE",
-	fieldTypeNewDecimal: "DECIMAL",
-	fieldTypeNULL:       "NULL",
-	fieldTypeSet:        "SET",
-	fieldTypeShort:      "SMALLINT",
-	fieldTypeString:     "CHAR",
-	fieldTypeTime:       "TIME",
-	fieldTypeTimestamp:  "TIMESTAMP",
-	fieldTypeTiny:       "TINYINT",
-	fieldTypeTinyBLOB:   "TINYBLOB",
-	fieldTypeVarChar:    "VARCHAR",
-	fieldTypeVarString:  "VARCHAR",
-	fieldTypeYear:       "YEAR",
-}
-
-var (
-	scanTypeFloat32   = reflect.TypeOf(float32(0))
-	scanTypeFloat64   = reflect.TypeOf(float64(0))
-	scanTypeInt8      = reflect.TypeOf(int8(0))
-	scanTypeInt16     = reflect.TypeOf(int16(0))
-	scanTypeInt32     = reflect.TypeOf(int32(0))
-	scanTypeInt64     = reflect.TypeOf(int64(0))
-	scanTypeNullFloat = reflect.TypeOf(sql.NullFloat64{})
-	scanTypeNullInt   = reflect.TypeOf(sql.NullInt64{})
-	scanTypeNullTime  = reflect.TypeOf(NullTime{})
-	scanTypeUint8     = reflect.TypeOf(uint8(0))
-	scanTypeUint16    = reflect.TypeOf(uint16(0))
-	scanTypeUint32    = reflect.TypeOf(uint32(0))
-	scanTypeUint64    = reflect.TypeOf(uint64(0))
-	scanTypeRawBytes  = reflect.TypeOf(sql.RawBytes{})
-	scanTypeUnknown   = reflect.TypeOf(new(interface{}))
-)
-
-type mysqlField struct {
-	tableName string
-	name      string
-	length    uint32
-	flags     fieldFlag
-	fieldType fieldType
-	decimals  byte
-}
-
-func (mf *mysqlField) scanType() reflect.Type {
-	switch mf.fieldType {
-	case fieldTypeTiny:
-		if mf.flags&flagNotNULL != 0 {
-			if mf.flags&flagUnsigned != 0 {
-				return scanTypeUint8
-			}
-			return scanTypeInt8
-		}
-		return scanTypeNullInt
-
-	case fieldTypeShort, fieldTypeYear:
-		if mf.flags&flagNotNULL != 0 {
-			if mf.flags&flagUnsigned != 0 {
-				return scanTypeUint16
-			}
-			return scanTypeInt16
-		}
-		return scanTypeNullInt
-
-	case fieldTypeInt24, fieldTypeLong:
-		if mf.flags&flagNotNULL != 0 {
-			if mf.flags&flagUnsigned != 0 {
-				return scanTypeUint32
-			}
-			return scanTypeInt32
-		}
-		return scanTypeNullInt
-
-	case fieldTypeLongLong:
-		if mf.flags&flagNotNULL != 0 {
-			if mf.flags&flagUnsigned != 0 {
-				return scanTypeUint64
-			}
-			return scanTypeInt64
-		}
-		return scanTypeNullInt
-
-	case fieldTypeFloat:
-		if mf.flags&flagNotNULL != 0 {
-			return scanTypeFloat32
-		}
-		return scanTypeNullFloat
-
-	case fieldTypeDouble:
-		if mf.flags&flagNotNULL != 0 {
-			return scanTypeFloat64
-		}
-		return scanTypeNullFloat
-
-	case fieldTypeDecimal, fieldTypeNewDecimal, fieldTypeVarChar,
-		fieldTypeBit, fieldTypeEnum, fieldTypeSet, fieldTypeTinyBLOB,
-		fieldTypeMediumBLOB, fieldTypeLongBLOB, fieldTypeBLOB,
-		fieldTypeVarString, fieldTypeString, fieldTypeGeometry, fieldTypeJSON,
-		fieldTypeTime:
-		return scanTypeRawBytes
-
-	case fieldTypeDate, fieldTypeNewDate,
-		fieldTypeTimestamp, fieldTypeDateTime:
-		// NullTime is always returned for more consistent behavior as it can
-		// handle both cases of parseTime regardless if the field is nullable.
-		return scanTypeNullTime
-
-	default:
-		return scanTypeUnknown
-	}
-}

+ 1 - 2
vendor/github.com/go-sql-driver/mysql/infile.go

@@ -147,8 +147,7 @@ func (mc *mysqlConn) handleInFileRequest(name string) (err error) {
 	}
 	}
 
 
 	// send content packets
 	// send content packets
-	// if packetSize == 0, the Reader contains no data
-	if err == nil && packetSize > 0 {
+	if err == nil {
 		data := make([]byte, 4+packetSize)
 		data := make([]byte, 4+packetSize)
 		var n int
 		var n int
 		for err == nil {
 		for err == nil {

+ 86 - 108
vendor/github.com/go-sql-driver/mysql/packets.go

@@ -30,12 +30,9 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
 		// read packet header
 		// read packet header
 		data, err := mc.buf.readNext(4)
 		data, err := mc.buf.readNext(4)
 		if err != nil {
 		if err != nil {
-			if cerr := mc.canceled.Value(); cerr != nil {
-				return nil, cerr
-			}
 			errLog.Print(err)
 			errLog.Print(err)
 			mc.Close()
 			mc.Close()
-			return nil, ErrInvalidConn
+			return nil, driver.ErrBadConn
 		}
 		}
 
 
 		// packet length [24 bit]
 		// packet length [24 bit]
@@ -57,7 +54,7 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
 			if prevData == nil {
 			if prevData == nil {
 				errLog.Print(ErrMalformPkt)
 				errLog.Print(ErrMalformPkt)
 				mc.Close()
 				mc.Close()
-				return nil, ErrInvalidConn
+				return nil, driver.ErrBadConn
 			}
 			}
 
 
 			return prevData, nil
 			return prevData, nil
@@ -66,12 +63,9 @@ func (mc *mysqlConn) readPacket() ([]byte, error) {
 		// read packet body [pktLen bytes]
 		// read packet body [pktLen bytes]
 		data, err = mc.buf.readNext(pktLen)
 		data, err = mc.buf.readNext(pktLen)
 		if err != nil {
 		if err != nil {
-			if cerr := mc.canceled.Value(); cerr != nil {
-				return nil, cerr
-			}
 			errLog.Print(err)
 			errLog.Print(err)
 			mc.Close()
 			mc.Close()
-			return nil, ErrInvalidConn
+			return nil, driver.ErrBadConn
 		}
 		}
 
 
 		// return data if this was the last packet
 		// return data if this was the last packet
@@ -131,20 +125,11 @@ func (mc *mysqlConn) writePacket(data []byte) error {
 
 
 		// Handle error
 		// Handle error
 		if err == nil { // n != len(data)
 		if err == nil { // n != len(data)
-			mc.cleanup()
 			errLog.Print(ErrMalformPkt)
 			errLog.Print(ErrMalformPkt)
 		} else {
 		} else {
-			if cerr := mc.canceled.Value(); cerr != nil {
-				return cerr
-			}
-			if n == 0 && pktLen == len(data)-4 {
-				// only for the first loop iteration when nothing was written yet
-				return errBadConnNoWrite
-			}
-			mc.cleanup()
 			errLog.Print(err)
 			errLog.Print(err)
 		}
 		}
-		return ErrInvalidConn
+		return driver.ErrBadConn
 	}
 	}
 }
 }
 
 
@@ -278,7 +263,7 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
 	if data == nil {
 	if data == nil {
 		// can not take the buffer. Something must be wrong with the connection
 		// can not take the buffer. Something must be wrong with the connection
 		errLog.Print(ErrBusyBuffer)
 		errLog.Print(ErrBusyBuffer)
-		return errBadConnNoWrite
+		return driver.ErrBadConn
 	}
 	}
 
 
 	// ClientFlags [32 bit]
 	// ClientFlags [32 bit]
@@ -356,9 +341,7 @@ func (mc *mysqlConn) writeAuthPacket(cipher []byte) error {
 // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
 // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
 func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error {
 func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error {
 	// User password
 	// User password
-	// https://dev.mysql.com/doc/internals/en/old-password-authentication.html
-	// Old password authentication only need and will need 8-byte challenge.
-	scrambleBuff := scrambleOldPassword(cipher[:8], []byte(mc.cfg.Passwd))
+	scrambleBuff := scrambleOldPassword(cipher, []byte(mc.cfg.Passwd))
 
 
 	// Calculate the packet length and add a tailing 0
 	// Calculate the packet length and add a tailing 0
 	pktLen := len(scrambleBuff) + 1
 	pktLen := len(scrambleBuff) + 1
@@ -366,7 +349,7 @@ func (mc *mysqlConn) writeOldAuthPacket(cipher []byte) error {
 	if data == nil {
 	if data == nil {
 		// can not take the buffer. Something must be wrong with the connection
 		// can not take the buffer. Something must be wrong with the connection
 		errLog.Print(ErrBusyBuffer)
 		errLog.Print(ErrBusyBuffer)
-		return errBadConnNoWrite
+		return driver.ErrBadConn
 	}
 	}
 
 
 	// Add the scrambled password [null terminated string]
 	// Add the scrambled password [null terminated string]
@@ -385,7 +368,7 @@ func (mc *mysqlConn) writeClearAuthPacket() error {
 	if data == nil {
 	if data == nil {
 		// can not take the buffer. Something must be wrong with the connection
 		// can not take the buffer. Something must be wrong with the connection
 		errLog.Print(ErrBusyBuffer)
 		errLog.Print(ErrBusyBuffer)
-		return errBadConnNoWrite
+		return driver.ErrBadConn
 	}
 	}
 
 
 	// Add the clear password [null terminated string]
 	// Add the clear password [null terminated string]
@@ -398,9 +381,7 @@ func (mc *mysqlConn) writeClearAuthPacket() error {
 //  Native password authentication method
 //  Native password authentication method
 // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
 // http://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::AuthSwitchResponse
 func (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error {
 func (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error {
-	// https://dev.mysql.com/doc/internals/en/secure-password-authentication.html
-	// Native password authentication only need and will need 20-byte challenge.
-	scrambleBuff := scramblePassword(cipher[0:20], []byte(mc.cfg.Passwd))
+	scrambleBuff := scramblePassword(cipher, []byte(mc.cfg.Passwd))
 
 
 	// Calculate the packet length and add a tailing 0
 	// Calculate the packet length and add a tailing 0
 	pktLen := len(scrambleBuff)
 	pktLen := len(scrambleBuff)
@@ -408,7 +389,7 @@ func (mc *mysqlConn) writeNativeAuthPacket(cipher []byte) error {
 	if data == nil {
 	if data == nil {
 		// can not take the buffer. Something must be wrong with the connection
 		// can not take the buffer. Something must be wrong with the connection
 		errLog.Print(ErrBusyBuffer)
 		errLog.Print(ErrBusyBuffer)
-		return errBadConnNoWrite
+		return driver.ErrBadConn
 	}
 	}
 
 
 	// Add the scramble
 	// Add the scramble
@@ -429,7 +410,7 @@ func (mc *mysqlConn) writeCommandPacket(command byte) error {
 	if data == nil {
 	if data == nil {
 		// can not take the buffer. Something must be wrong with the connection
 		// can not take the buffer. Something must be wrong with the connection
 		errLog.Print(ErrBusyBuffer)
 		errLog.Print(ErrBusyBuffer)
-		return errBadConnNoWrite
+		return driver.ErrBadConn
 	}
 	}
 
 
 	// Add command byte
 	// Add command byte
@@ -448,7 +429,7 @@ func (mc *mysqlConn) writeCommandPacketStr(command byte, arg string) error {
 	if data == nil {
 	if data == nil {
 		// can not take the buffer. Something must be wrong with the connection
 		// can not take the buffer. Something must be wrong with the connection
 		errLog.Print(ErrBusyBuffer)
 		errLog.Print(ErrBusyBuffer)
-		return errBadConnNoWrite
+		return driver.ErrBadConn
 	}
 	}
 
 
 	// Add command byte
 	// Add command byte
@@ -469,7 +450,7 @@ func (mc *mysqlConn) writeCommandPacketUint32(command byte, arg uint32) error {
 	if data == nil {
 	if data == nil {
 		// can not take the buffer. Something must be wrong with the connection
 		// can not take the buffer. Something must be wrong with the connection
 		errLog.Print(ErrBusyBuffer)
 		errLog.Print(ErrBusyBuffer)
-		return errBadConnNoWrite
+		return driver.ErrBadConn
 	}
 	}
 
 
 	// Add command byte
 	// Add command byte
@@ -503,26 +484,25 @@ func (mc *mysqlConn) readResultOK() ([]byte, error) {
 			if len(data) > 1 {
 			if len(data) > 1 {
 				pluginEndIndex := bytes.IndexByte(data, 0x00)
 				pluginEndIndex := bytes.IndexByte(data, 0x00)
 				plugin := string(data[1:pluginEndIndex])
 				plugin := string(data[1:pluginEndIndex])
-				cipher := data[pluginEndIndex+1:]
+				cipher := data[pluginEndIndex+1 : len(data)-1]
 
 
-				switch plugin {
-				case "mysql_old_password":
+				if plugin == "mysql_old_password" {
 					// using old_passwords
 					// using old_passwords
 					return cipher, ErrOldPassword
 					return cipher, ErrOldPassword
-				case "mysql_clear_password":
+				} else if plugin == "mysql_clear_password" {
 					// using clear text password
 					// using clear text password
 					return cipher, ErrCleartextPassword
 					return cipher, ErrCleartextPassword
-				case "mysql_native_password":
+				} else if plugin == "mysql_native_password" {
 					// using mysql default authentication method
 					// using mysql default authentication method
 					return cipher, ErrNativePassword
 					return cipher, ErrNativePassword
-				default:
+				} else {
 					return cipher, ErrUnknownPlugin
 					return cipher, ErrUnknownPlugin
 				}
 				}
+			} else {
+				// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest
+				return nil, ErrOldPassword
 			}
 			}
 
 
-			// https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::OldAuthSwitchRequest
-			return nil, ErrOldPassword
-
 		default: // Error otherwise
 		default: // Error otherwise
 			return nil, mc.handleErrorPacket(data)
 			return nil, mc.handleErrorPacket(data)
 		}
 		}
@@ -570,22 +550,6 @@ func (mc *mysqlConn) handleErrorPacket(data []byte) error {
 	// Error Number [16 bit uint]
 	// Error Number [16 bit uint]
 	errno := binary.LittleEndian.Uint16(data[1:3])
 	errno := binary.LittleEndian.Uint16(data[1:3])
 
 
-	// 1792: ER_CANT_EXECUTE_IN_READ_ONLY_TRANSACTION
-	// 1290: ER_OPTION_PREVENTS_STATEMENT (returned by Aurora during failover)
-	if (errno == 1792 || errno == 1290) && mc.cfg.RejectReadOnly {
-		// Oops; we are connected to a read-only connection, and won't be able
-		// to issue any write statements. Since RejectReadOnly is configured,
-		// we throw away this connection hoping this one would have write
-		// permission. This is specifically for a possible race condition
-		// during failover (e.g. on AWS Aurora). See README.md for more.
-		//
-		// We explicitly close the connection before returning
-		// driver.ErrBadConn to ensure that `database/sql` purges this
-		// connection and initiates a new one for next statement next time.
-		mc.Close()
-		return driver.ErrBadConn
-	}
-
 	pos := 3
 	pos := 3
 
 
 	// SQL State [optional: # + 5bytes string]
 	// SQL State [optional: # + 5bytes string]
@@ -620,12 +584,19 @@ func (mc *mysqlConn) handleOkPacket(data []byte) error {
 
 
 	// server_status [2 bytes]
 	// server_status [2 bytes]
 	mc.status = readStatus(data[1+n+m : 1+n+m+2])
 	mc.status = readStatus(data[1+n+m : 1+n+m+2])
-	if mc.status&statusMoreResultsExists != 0 {
-		return nil
+	if err := mc.discardResults(); err != nil {
+		return err
 	}
 	}
 
 
 	// warning count [2 bytes]
 	// warning count [2 bytes]
+	if !mc.strict {
+		return nil
+	}
 
 
+	pos := 1 + n + m + 2
+	if binary.LittleEndian.Uint16(data[pos:pos+2]) > 0 {
+		return mc.getWarnings()
+	}
 	return nil
 	return nil
 }
 }
 
 
@@ -700,14 +671,11 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) {
 
 
 		// Filler [uint8]
 		// Filler [uint8]
 		// Charset [charset, collation uint8]
 		// Charset [charset, collation uint8]
-		pos += n + 1 + 2
-
 		// Length [uint32]
 		// Length [uint32]
-		columns[i].length = binary.LittleEndian.Uint32(data[pos : pos+4])
-		pos += 4
+		pos += n + 1 + 2 + 4
 
 
 		// Field type [uint8]
 		// Field type [uint8]
-		columns[i].fieldType = fieldType(data[pos])
+		columns[i].fieldType = data[pos]
 		pos++
 		pos++
 
 
 		// Flags [uint16]
 		// Flags [uint16]
@@ -730,10 +698,6 @@ func (mc *mysqlConn) readColumns(count int) ([]mysqlField, error) {
 func (rows *textRows) readRow(dest []driver.Value) error {
 func (rows *textRows) readRow(dest []driver.Value) error {
 	mc := rows.mc
 	mc := rows.mc
 
 
-	if rows.rs.done {
-		return io.EOF
-	}
-
 	data, err := mc.readPacket()
 	data, err := mc.readPacket()
 	if err != nil {
 	if err != nil {
 		return err
 		return err
@@ -743,11 +707,15 @@ func (rows *textRows) readRow(dest []driver.Value) error {
 	if data[0] == iEOF && len(data) == 5 {
 	if data[0] == iEOF && len(data) == 5 {
 		// server_status [2 bytes]
 		// server_status [2 bytes]
 		rows.mc.status = readStatus(data[3:])
 		rows.mc.status = readStatus(data[3:])
-		rows.rs.done = true
-		if !rows.HasNextResultSet() {
-			rows.mc = nil
+		err = rows.mc.discardResults()
+		if err == nil {
+			err = io.EOF
+		} else {
+			// connection unusable
+			rows.mc.Close()
 		}
 		}
-		return io.EOF
+		rows.mc = nil
+		return err
 	}
 	}
 	if data[0] == iERR {
 	if data[0] == iERR {
 		rows.mc = nil
 		rows.mc = nil
@@ -768,7 +736,7 @@ func (rows *textRows) readRow(dest []driver.Value) error {
 				if !mc.parseTime {
 				if !mc.parseTime {
 					continue
 					continue
 				} else {
 				} else {
-					switch rows.rs.columns[i].fieldType {
+					switch rows.columns[i].fieldType {
 					case fieldTypeTimestamp, fieldTypeDateTime,
 					case fieldTypeTimestamp, fieldTypeDateTime,
 						fieldTypeDate, fieldTypeNewDate:
 						fieldTypeDate, fieldTypeNewDate:
 						dest[i], err = parseDateTime(
 						dest[i], err = parseDateTime(
@@ -840,7 +808,14 @@ func (stmt *mysqlStmt) readPrepareResultPacket() (uint16, error) {
 		// Reserved [8 bit]
 		// Reserved [8 bit]
 
 
 		// Warning count [16 bit uint]
 		// Warning count [16 bit uint]
+		if !stmt.mc.strict {
+			return columnCount, nil
+		}
 
 
+		// Check for warnings count > 0, only available in MySQL > 4.1
+		if len(data) >= 12 && binary.LittleEndian.Uint16(data[10:12]) > 0 {
+			return columnCount, stmt.mc.getWarnings()
+		}
 		return columnCount, nil
 		return columnCount, nil
 	}
 	}
 	return 0, err
 	return 0, err
@@ -925,7 +900,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
 	if data == nil {
 	if data == nil {
 		// can not take the buffer. Something must be wrong with the connection
 		// can not take the buffer. Something must be wrong with the connection
 		errLog.Print(ErrBusyBuffer)
 		errLog.Print(ErrBusyBuffer)
-		return errBadConnNoWrite
+		return driver.ErrBadConn
 	}
 	}
 
 
 	// command [1 byte]
 	// command [1 byte]
@@ -984,7 +959,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
 			// build NULL-bitmap
 			// build NULL-bitmap
 			if arg == nil {
 			if arg == nil {
 				nullMask[i/8] |= 1 << (uint(i) & 7)
 				nullMask[i/8] |= 1 << (uint(i) & 7)
-				paramTypes[i+i] = byte(fieldTypeNULL)
+				paramTypes[i+i] = fieldTypeNULL
 				paramTypes[i+i+1] = 0x00
 				paramTypes[i+i+1] = 0x00
 				continue
 				continue
 			}
 			}
@@ -992,7 +967,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
 			// cache types and values
 			// cache types and values
 			switch v := arg.(type) {
 			switch v := arg.(type) {
 			case int64:
 			case int64:
-				paramTypes[i+i] = byte(fieldTypeLongLong)
+				paramTypes[i+i] = fieldTypeLongLong
 				paramTypes[i+i+1] = 0x00
 				paramTypes[i+i+1] = 0x00
 
 
 				if cap(paramValues)-len(paramValues)-8 >= 0 {
 				if cap(paramValues)-len(paramValues)-8 >= 0 {
@@ -1008,7 +983,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
 				}
 				}
 
 
 			case float64:
 			case float64:
-				paramTypes[i+i] = byte(fieldTypeDouble)
+				paramTypes[i+i] = fieldTypeDouble
 				paramTypes[i+i+1] = 0x00
 				paramTypes[i+i+1] = 0x00
 
 
 				if cap(paramValues)-len(paramValues)-8 >= 0 {
 				if cap(paramValues)-len(paramValues)-8 >= 0 {
@@ -1024,7 +999,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
 				}
 				}
 
 
 			case bool:
 			case bool:
-				paramTypes[i+i] = byte(fieldTypeTiny)
+				paramTypes[i+i] = fieldTypeTiny
 				paramTypes[i+i+1] = 0x00
 				paramTypes[i+i+1] = 0x00
 
 
 				if v {
 				if v {
@@ -1036,7 +1011,7 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
 			case []byte:
 			case []byte:
 				// Common case (non-nil value) first
 				// Common case (non-nil value) first
 				if v != nil {
 				if v != nil {
-					paramTypes[i+i] = byte(fieldTypeString)
+					paramTypes[i+i] = fieldTypeString
 					paramTypes[i+i+1] = 0x00
 					paramTypes[i+i+1] = 0x00
 
 
 					if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 {
 					if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 {
@@ -1054,11 +1029,11 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
 
 
 				// Handle []byte(nil) as a NULL value
 				// Handle []byte(nil) as a NULL value
 				nullMask[i/8] |= 1 << (uint(i) & 7)
 				nullMask[i/8] |= 1 << (uint(i) & 7)
-				paramTypes[i+i] = byte(fieldTypeNULL)
+				paramTypes[i+i] = fieldTypeNULL
 				paramTypes[i+i+1] = 0x00
 				paramTypes[i+i+1] = 0x00
 
 
 			case string:
 			case string:
-				paramTypes[i+i] = byte(fieldTypeString)
+				paramTypes[i+i] = fieldTypeString
 				paramTypes[i+i+1] = 0x00
 				paramTypes[i+i+1] = 0x00
 
 
 				if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 {
 				if len(v) < mc.maxAllowedPacket-pos-len(paramValues)-(len(args)-(i+1))*64 {
@@ -1073,22 +1048,20 @@ func (stmt *mysqlStmt) writeExecutePacket(args []driver.Value) error {
 				}
 				}
 
 
 			case time.Time:
 			case time.Time:
-				paramTypes[i+i] = byte(fieldTypeString)
+				paramTypes[i+i] = fieldTypeString
 				paramTypes[i+i+1] = 0x00
 				paramTypes[i+i+1] = 0x00
 
 
-				var a [64]byte
-				var b = a[:0]
-
+				var val []byte
 				if v.IsZero() {
 				if v.IsZero() {
-					b = append(b, "0000-00-00"...)
+					val = []byte("0000-00-00")
 				} else {
 				} else {
-					b = v.In(mc.cfg.Loc).AppendFormat(b, timeFormat)
+					val = []byte(v.In(mc.cfg.Loc).Format(timeFormat))
 				}
 				}
 
 
 				paramValues = appendLengthEncodedInteger(paramValues,
 				paramValues = appendLengthEncodedInteger(paramValues,
-					uint64(len(b)),
+					uint64(len(val)),
 				)
 				)
-				paramValues = append(paramValues, b...)
+				paramValues = append(paramValues, val...)
 
 
 			default:
 			default:
 				return fmt.Errorf("can not convert type: %T", arg)
 				return fmt.Errorf("can not convert type: %T", arg)
@@ -1124,6 +1097,8 @@ func (mc *mysqlConn) discardResults() error {
 			if err := mc.readUntilEOF(); err != nil {
 			if err := mc.readUntilEOF(); err != nil {
 				return err
 				return err
 			}
 			}
+		} else {
+			mc.status &^= statusMoreResultsExists
 		}
 		}
 	}
 	}
 	return nil
 	return nil
@@ -1141,17 +1116,20 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
 		// EOF Packet
 		// EOF Packet
 		if data[0] == iEOF && len(data) == 5 {
 		if data[0] == iEOF && len(data) == 5 {
 			rows.mc.status = readStatus(data[3:])
 			rows.mc.status = readStatus(data[3:])
-			rows.rs.done = true
-			if !rows.HasNextResultSet() {
-				rows.mc = nil
+			err = rows.mc.discardResults()
+			if err == nil {
+				err = io.EOF
+			} else {
+				// connection unusable
+				rows.mc.Close()
 			}
 			}
-			return io.EOF
+			rows.mc = nil
+			return err
 		}
 		}
-		mc := rows.mc
 		rows.mc = nil
 		rows.mc = nil
 
 
 		// Error otherwise
 		// Error otherwise
-		return mc.handleErrorPacket(data)
+		return rows.mc.handleErrorPacket(data)
 	}
 	}
 
 
 	// NULL-bitmap,  [(column-count + 7 + 2) / 8 bytes]
 	// NULL-bitmap,  [(column-count + 7 + 2) / 8 bytes]
@@ -1167,14 +1145,14 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
 		}
 		}
 
 
 		// Convert to byte-coded string
 		// Convert to byte-coded string
-		switch rows.rs.columns[i].fieldType {
+		switch rows.columns[i].fieldType {
 		case fieldTypeNULL:
 		case fieldTypeNULL:
 			dest[i] = nil
 			dest[i] = nil
 			continue
 			continue
 
 
 		// Numeric Types
 		// Numeric Types
 		case fieldTypeTiny:
 		case fieldTypeTiny:
-			if rows.rs.columns[i].flags&flagUnsigned != 0 {
+			if rows.columns[i].flags&flagUnsigned != 0 {
 				dest[i] = int64(data[pos])
 				dest[i] = int64(data[pos])
 			} else {
 			} else {
 				dest[i] = int64(int8(data[pos]))
 				dest[i] = int64(int8(data[pos]))
@@ -1183,7 +1161,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
 			continue
 			continue
 
 
 		case fieldTypeShort, fieldTypeYear:
 		case fieldTypeShort, fieldTypeYear:
-			if rows.rs.columns[i].flags&flagUnsigned != 0 {
+			if rows.columns[i].flags&flagUnsigned != 0 {
 				dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2]))
 				dest[i] = int64(binary.LittleEndian.Uint16(data[pos : pos+2]))
 			} else {
 			} else {
 				dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2])))
 				dest[i] = int64(int16(binary.LittleEndian.Uint16(data[pos : pos+2])))
@@ -1192,7 +1170,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
 			continue
 			continue
 
 
 		case fieldTypeInt24, fieldTypeLong:
 		case fieldTypeInt24, fieldTypeLong:
-			if rows.rs.columns[i].flags&flagUnsigned != 0 {
+			if rows.columns[i].flags&flagUnsigned != 0 {
 				dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4]))
 				dest[i] = int64(binary.LittleEndian.Uint32(data[pos : pos+4]))
 			} else {
 			} else {
 				dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4])))
 				dest[i] = int64(int32(binary.LittleEndian.Uint32(data[pos : pos+4])))
@@ -1201,7 +1179,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
 			continue
 			continue
 
 
 		case fieldTypeLongLong:
 		case fieldTypeLongLong:
-			if rows.rs.columns[i].flags&flagUnsigned != 0 {
+			if rows.columns[i].flags&flagUnsigned != 0 {
 				val := binary.LittleEndian.Uint64(data[pos : pos+8])
 				val := binary.LittleEndian.Uint64(data[pos : pos+8])
 				if val > math.MaxInt64 {
 				if val > math.MaxInt64 {
 					dest[i] = uint64ToString(val)
 					dest[i] = uint64ToString(val)
@@ -1215,7 +1193,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
 			continue
 			continue
 
 
 		case fieldTypeFloat:
 		case fieldTypeFloat:
-			dest[i] = math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4]))
+			dest[i] = float32(math.Float32frombits(binary.LittleEndian.Uint32(data[pos : pos+4])))
 			pos += 4
 			pos += 4
 			continue
 			continue
 
 
@@ -1255,10 +1233,10 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
 			case isNull:
 			case isNull:
 				dest[i] = nil
 				dest[i] = nil
 				continue
 				continue
-			case rows.rs.columns[i].fieldType == fieldTypeTime:
+			case rows.columns[i].fieldType == fieldTypeTime:
 				// database/sql does not support an equivalent to TIME, return a string
 				// database/sql does not support an equivalent to TIME, return a string
 				var dstlen uint8
 				var dstlen uint8
-				switch decimals := rows.rs.columns[i].decimals; decimals {
+				switch decimals := rows.columns[i].decimals; decimals {
 				case 0x00, 0x1f:
 				case 0x00, 0x1f:
 					dstlen = 8
 					dstlen = 8
 				case 1, 2, 3, 4, 5, 6:
 				case 1, 2, 3, 4, 5, 6:
@@ -1266,7 +1244,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
 				default:
 				default:
 					return fmt.Errorf(
 					return fmt.Errorf(
 						"protocol error, illegal decimals value %d",
 						"protocol error, illegal decimals value %d",
-						rows.rs.columns[i].decimals,
+						rows.columns[i].decimals,
 					)
 					)
 				}
 				}
 				dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, true)
 				dest[i], err = formatBinaryDateTime(data[pos:pos+int(num)], dstlen, true)
@@ -1274,10 +1252,10 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
 				dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc)
 				dest[i], err = parseBinaryDateTime(num, data[pos:], rows.mc.cfg.Loc)
 			default:
 			default:
 				var dstlen uint8
 				var dstlen uint8
-				if rows.rs.columns[i].fieldType == fieldTypeDate {
+				if rows.columns[i].fieldType == fieldTypeDate {
 					dstlen = 10
 					dstlen = 10
 				} else {
 				} else {
-					switch decimals := rows.rs.columns[i].decimals; decimals {
+					switch decimals := rows.columns[i].decimals; decimals {
 					case 0x00, 0x1f:
 					case 0x00, 0x1f:
 						dstlen = 19
 						dstlen = 19
 					case 1, 2, 3, 4, 5, 6:
 					case 1, 2, 3, 4, 5, 6:
@@ -1285,7 +1263,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
 					default:
 					default:
 						return fmt.Errorf(
 						return fmt.Errorf(
 							"protocol error, illegal decimals value %d",
 							"protocol error, illegal decimals value %d",
-							rows.rs.columns[i].decimals,
+							rows.columns[i].decimals,
 						)
 						)
 					}
 					}
 				}
 				}
@@ -1301,7 +1279,7 @@ func (rows *binaryRows) readRow(dest []driver.Value) error {
 
 
 		// Please report if this happens!
 		// Please report if this happens!
 		default:
 		default:
-			return fmt.Errorf("unknown field type %d", rows.rs.columns[i].fieldType)
+			return fmt.Errorf("unknown field type %d", rows.columns[i].fieldType)
 		}
 		}
 	}
 	}
 
 

+ 35 - 142
vendor/github.com/go-sql-driver/mysql/rows.go

@@ -11,20 +11,19 @@ package mysql
 import (
 import (
 	"database/sql/driver"
 	"database/sql/driver"
 	"io"
 	"io"
-	"math"
-	"reflect"
 )
 )
 
 
-type resultSet struct {
-	columns     []mysqlField
-	columnNames []string
-	done        bool
+type mysqlField struct {
+	tableName string
+	name      string
+	flags     fieldFlag
+	fieldType byte
+	decimals  byte
 }
 }
 
 
 type mysqlRows struct {
 type mysqlRows struct {
-	mc     *mysqlConn
-	rs     resultSet
-	finish func()
+	mc      *mysqlConn
+	columns []mysqlField
 }
 }
 
 
 type binaryRows struct {
 type binaryRows struct {
@@ -35,89 +34,37 @@ type textRows struct {
 	mysqlRows
 	mysqlRows
 }
 }
 
 
-func (rows *mysqlRows) Columns() []string {
-	if rows.rs.columnNames != nil {
-		return rows.rs.columnNames
-	}
+type emptyRows struct{}
 
 
-	columns := make([]string, len(rows.rs.columns))
+func (rows *mysqlRows) Columns() []string {
+	columns := make([]string, len(rows.columns))
 	if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias {
 	if rows.mc != nil && rows.mc.cfg.ColumnsWithAlias {
 		for i := range columns {
 		for i := range columns {
-			if tableName := rows.rs.columns[i].tableName; len(tableName) > 0 {
-				columns[i] = tableName + "." + rows.rs.columns[i].name
+			if tableName := rows.columns[i].tableName; len(tableName) > 0 {
+				columns[i] = tableName + "." + rows.columns[i].name
 			} else {
 			} else {
-				columns[i] = rows.rs.columns[i].name
+				columns[i] = rows.columns[i].name
 			}
 			}
 		}
 		}
 	} else {
 	} else {
 		for i := range columns {
 		for i := range columns {
-			columns[i] = rows.rs.columns[i].name
+			columns[i] = rows.columns[i].name
 		}
 		}
 	}
 	}
-
-	rows.rs.columnNames = columns
 	return columns
 	return columns
 }
 }
 
 
-func (rows *mysqlRows) ColumnTypeDatabaseTypeName(i int) string {
-	if name, ok := typeDatabaseName[rows.rs.columns[i].fieldType]; ok {
-		return name
-	}
-	return ""
-}
-
-// func (rows *mysqlRows) ColumnTypeLength(i int) (length int64, ok bool) {
-// 	return int64(rows.rs.columns[i].length), true
-// }
-
-func (rows *mysqlRows) ColumnTypeNullable(i int) (nullable, ok bool) {
-	return rows.rs.columns[i].flags&flagNotNULL == 0, true
-}
-
-func (rows *mysqlRows) ColumnTypePrecisionScale(i int) (int64, int64, bool) {
-	column := rows.rs.columns[i]
-	decimals := int64(column.decimals)
-
-	switch column.fieldType {
-	case fieldTypeDecimal, fieldTypeNewDecimal:
-		if decimals > 0 {
-			return int64(column.length) - 2, decimals, true
-		}
-		return int64(column.length) - 1, decimals, true
-	case fieldTypeTimestamp, fieldTypeDateTime, fieldTypeTime:
-		return decimals, decimals, true
-	case fieldTypeFloat, fieldTypeDouble:
-		if decimals == 0x1f {
-			return math.MaxInt64, math.MaxInt64, true
-		}
-		return math.MaxInt64, decimals, true
-	}
-
-	return 0, 0, false
-}
-
-func (rows *mysqlRows) ColumnTypeScanType(i int) reflect.Type {
-	return rows.rs.columns[i].scanType()
-}
-
-func (rows *mysqlRows) Close() (err error) {
-	if f := rows.finish; f != nil {
-		f()
-		rows.finish = nil
-	}
-
+func (rows *mysqlRows) Close() error {
 	mc := rows.mc
 	mc := rows.mc
 	if mc == nil {
 	if mc == nil {
 		return nil
 		return nil
 	}
 	}
-	if err := mc.error(); err != nil {
-		return err
+	if mc.netConn == nil {
+		return ErrInvalidConn
 	}
 	}
 
 
 	// Remove unread packets from stream
 	// Remove unread packets from stream
-	if !rows.rs.done {
-		err = mc.readUntilEOF()
-	}
+	err := mc.readUntilEOF()
 	if err == nil {
 	if err == nil {
 		if err = mc.discardResults(); err != nil {
 		if err = mc.discardResults(); err != nil {
 			return err
 			return err
@@ -128,66 +75,10 @@ func (rows *mysqlRows) Close() (err error) {
 	return err
 	return err
 }
 }
 
 
-func (rows *mysqlRows) HasNextResultSet() (b bool) {
-	if rows.mc == nil {
-		return false
-	}
-	return rows.mc.status&statusMoreResultsExists != 0
-}
-
-func (rows *mysqlRows) nextResultSet() (int, error) {
-	if rows.mc == nil {
-		return 0, io.EOF
-	}
-	if err := rows.mc.error(); err != nil {
-		return 0, err
-	}
-
-	// Remove unread packets from stream
-	if !rows.rs.done {
-		if err := rows.mc.readUntilEOF(); err != nil {
-			return 0, err
-		}
-		rows.rs.done = true
-	}
-
-	if !rows.HasNextResultSet() {
-		rows.mc = nil
-		return 0, io.EOF
-	}
-	rows.rs = resultSet{}
-	return rows.mc.readResultSetHeaderPacket()
-}
-
-func (rows *mysqlRows) nextNotEmptyResultSet() (int, error) {
-	for {
-		resLen, err := rows.nextResultSet()
-		if err != nil {
-			return 0, err
-		}
-
-		if resLen > 0 {
-			return resLen, nil
-		}
-
-		rows.rs.done = true
-	}
-}
-
-func (rows *binaryRows) NextResultSet() error {
-	resLen, err := rows.nextNotEmptyResultSet()
-	if err != nil {
-		return err
-	}
-
-	rows.rs.columns, err = rows.mc.readColumns(resLen)
-	return err
-}
-
 func (rows *binaryRows) Next(dest []driver.Value) error {
 func (rows *binaryRows) Next(dest []driver.Value) error {
 	if mc := rows.mc; mc != nil {
 	if mc := rows.mc; mc != nil {
-		if err := mc.error(); err != nil {
-			return err
+		if mc.netConn == nil {
+			return ErrInvalidConn
 		}
 		}
 
 
 		// Fetch next row from stream
 		// Fetch next row from stream
@@ -196,20 +87,10 @@ func (rows *binaryRows) Next(dest []driver.Value) error {
 	return io.EOF
 	return io.EOF
 }
 }
 
 
-func (rows *textRows) NextResultSet() (err error) {
-	resLen, err := rows.nextNotEmptyResultSet()
-	if err != nil {
-		return err
-	}
-
-	rows.rs.columns, err = rows.mc.readColumns(resLen)
-	return err
-}
-
 func (rows *textRows) Next(dest []driver.Value) error {
 func (rows *textRows) Next(dest []driver.Value) error {
 	if mc := rows.mc; mc != nil {
 	if mc := rows.mc; mc != nil {
-		if err := mc.error(); err != nil {
-			return err
+		if mc.netConn == nil {
+			return ErrInvalidConn
 		}
 		}
 
 
 		// Fetch next row from stream
 		// Fetch next row from stream
@@ -217,3 +98,15 @@ func (rows *textRows) Next(dest []driver.Value) error {
 	}
 	}
 	return io.EOF
 	return io.EOF
 }
 }
+
+func (rows emptyRows) Columns() []string {
+	return nil
+}
+
+func (rows emptyRows) Close() error {
+	return nil
+}
+
+func (rows emptyRows) Next(dest []driver.Value) error {
+	return io.EOF
+}

+ 30 - 55
vendor/github.com/go-sql-driver/mysql/statement.go

@@ -11,7 +11,6 @@ package mysql
 import (
 import (
 	"database/sql/driver"
 	"database/sql/driver"
 	"fmt"
 	"fmt"
-	"io"
 	"reflect"
 	"reflect"
 	"strconv"
 	"strconv"
 )
 )
@@ -20,10 +19,11 @@ type mysqlStmt struct {
 	mc         *mysqlConn
 	mc         *mysqlConn
 	id         uint32
 	id         uint32
 	paramCount int
 	paramCount int
+	columns    []mysqlField // cached from the first query
 }
 }
 
 
 func (stmt *mysqlStmt) Close() error {
 func (stmt *mysqlStmt) Close() error {
-	if stmt.mc == nil || stmt.mc.closed.IsSet() {
+	if stmt.mc == nil || stmt.mc.netConn == nil {
 		// driver.Stmt.Close can be called more than once, thus this function
 		// driver.Stmt.Close can be called more than once, thus this function
 		// has to be idempotent.
 		// has to be idempotent.
 		// See also Issue #450 and golang/go#16019.
 		// See also Issue #450 and golang/go#16019.
@@ -45,14 +45,14 @@ func (stmt *mysqlStmt) ColumnConverter(idx int) driver.ValueConverter {
 }
 }
 
 
 func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
 func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
-	if stmt.mc.closed.IsSet() {
+	if stmt.mc.netConn == nil {
 		errLog.Print(ErrInvalidConn)
 		errLog.Print(ErrInvalidConn)
 		return nil, driver.ErrBadConn
 		return nil, driver.ErrBadConn
 	}
 	}
 	// Send command
 	// Send command
 	err := stmt.writeExecutePacket(args)
 	err := stmt.writeExecutePacket(args)
 	if err != nil {
 	if err != nil {
-		return nil, stmt.mc.markBadConn(err)
+		return nil, err
 	}
 	}
 
 
 	mc := stmt.mc
 	mc := stmt.mc
@@ -62,45 +62,37 @@ func (stmt *mysqlStmt) Exec(args []driver.Value) (driver.Result, error) {
 
 
 	// Read Result
 	// Read Result
 	resLen, err := mc.readResultSetHeaderPacket()
 	resLen, err := mc.readResultSetHeaderPacket()
-	if err != nil {
-		return nil, err
-	}
-
-	if resLen > 0 {
-		// Columns
-		if err = mc.readUntilEOF(); err != nil {
-			return nil, err
+	if err == nil {
+		if resLen > 0 {
+			// Columns
+			err = mc.readUntilEOF()
+			if err != nil {
+				return nil, err
+			}
+
+			// Rows
+			err = mc.readUntilEOF()
 		}
 		}
-
-		// Rows
-		if err := mc.readUntilEOF(); err != nil {
-			return nil, err
+		if err == nil {
+			return &mysqlResult{
+				affectedRows: int64(mc.affectedRows),
+				insertId:     int64(mc.insertId),
+			}, nil
 		}
 		}
 	}
 	}
 
 
-	if err := mc.discardResults(); err != nil {
-		return nil, err
-	}
-
-	return &mysqlResult{
-		affectedRows: int64(mc.affectedRows),
-		insertId:     int64(mc.insertId),
-	}, nil
+	return nil, err
 }
 }
 
 
 func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
 func (stmt *mysqlStmt) Query(args []driver.Value) (driver.Rows, error) {
-	return stmt.query(args)
-}
-
-func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
-	if stmt.mc.closed.IsSet() {
+	if stmt.mc.netConn == nil {
 		errLog.Print(ErrInvalidConn)
 		errLog.Print(ErrInvalidConn)
 		return nil, driver.ErrBadConn
 		return nil, driver.ErrBadConn
 	}
 	}
 	// Send command
 	// Send command
 	err := stmt.writeExecutePacket(args)
 	err := stmt.writeExecutePacket(args)
 	if err != nil {
 	if err != nil {
-		return nil, stmt.mc.markBadConn(err)
+		return nil, err
 	}
 	}
 
 
 	mc := stmt.mc
 	mc := stmt.mc
@@ -115,15 +107,14 @@ func (stmt *mysqlStmt) query(args []driver.Value) (*binaryRows, error) {
 
 
 	if resLen > 0 {
 	if resLen > 0 {
 		rows.mc = mc
 		rows.mc = mc
-		rows.rs.columns, err = mc.readColumns(resLen)
-	} else {
-		rows.rs.done = true
-
-		switch err := rows.NextResultSet(); err {
-		case nil, io.EOF:
-			return rows, nil
-		default:
-			return nil, err
+		// Columns
+		// If not cached, read them and cache them
+		if stmt.columns == nil {
+			rows.columns, err = mc.readColumns(resLen)
+			stmt.columns = rows.columns
+		} else {
+			rows.columns = stmt.columns
+			err = mc.readUntilEOF()
 		}
 		}
 	}
 	}
 
 
@@ -137,12 +128,6 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
 		return v, nil
 		return v, nil
 	}
 	}
 
 
-	if v != nil {
-		if valuer, ok := v.(driver.Valuer); ok {
-			return valuer.Value()
-		}
-	}
-
 	rv := reflect.ValueOf(v)
 	rv := reflect.ValueOf(v)
 	switch rv.Kind() {
 	switch rv.Kind() {
 	case reflect.Ptr:
 	case reflect.Ptr:
@@ -163,16 +148,6 @@ func (c converter) ConvertValue(v interface{}) (driver.Value, error) {
 		return int64(u64), nil
 		return int64(u64), nil
 	case reflect.Float32, reflect.Float64:
 	case reflect.Float32, reflect.Float64:
 		return rv.Float(), nil
 		return rv.Float(), nil
-	case reflect.Bool:
-		return rv.Bool(), nil
-	case reflect.Slice:
-		ek := rv.Type().Elem().Kind()
-		if ek == reflect.Uint8 {
-			return rv.Bytes(), nil
-		}
-		return nil, fmt.Errorf("unsupported type %T, a slice of %s", v, ek)
-	case reflect.String:
-		return rv.String(), nil
 	}
 	}
 	return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
 	return nil, fmt.Errorf("unsupported type %T, a %s", v, rv.Kind())
 }
 }

+ 2 - 2
vendor/github.com/go-sql-driver/mysql/transaction.go

@@ -13,7 +13,7 @@ type mysqlTx struct {
 }
 }
 
 
 func (tx *mysqlTx) Commit() (err error) {
 func (tx *mysqlTx) Commit() (err error) {
-	if tx.mc == nil || tx.mc.closed.IsSet() {
+	if tx.mc == nil || tx.mc.netConn == nil {
 		return ErrInvalidConn
 		return ErrInvalidConn
 	}
 	}
 	err = tx.mc.exec("COMMIT")
 	err = tx.mc.exec("COMMIT")
@@ -22,7 +22,7 @@ func (tx *mysqlTx) Commit() (err error) {
 }
 }
 
 
 func (tx *mysqlTx) Rollback() (err error) {
 func (tx *mysqlTx) Rollback() (err error) {
-	if tx.mc == nil || tx.mc.closed.IsSet() {
+	if tx.mc == nil || tx.mc.netConn == nil {
 		return ErrInvalidConn
 		return ErrInvalidConn
 	}
 	}
 	err = tx.mc.exec("ROLLBACK")
 	err = tx.mc.exec("ROLLBACK")

+ 1 - 83
vendor/github.com/go-sql-driver/mysql/utils.go

@@ -16,21 +16,16 @@ import (
 	"fmt"
 	"fmt"
 	"io"
 	"io"
 	"strings"
 	"strings"
-	"sync"
-	"sync/atomic"
 	"time"
 	"time"
 )
 )
 
 
 var (
 var (
-	tlsConfigLock     sync.RWMutex
 	tlsConfigRegister map[string]*tls.Config // Register for custom tls.Configs
 	tlsConfigRegister map[string]*tls.Config // Register for custom tls.Configs
 )
 )
 
 
 // RegisterTLSConfig registers a custom tls.Config to be used with sql.Open.
 // RegisterTLSConfig registers a custom tls.Config to be used with sql.Open.
 // Use the key as a value in the DSN where tls=value.
 // Use the key as a value in the DSN where tls=value.
 //
 //
-// Note: The tls.Config provided to needs to be exclusively owned by the driver after registering.
-//
 //  rootCertPool := x509.NewCertPool()
 //  rootCertPool := x509.NewCertPool()
 //  pem, err := ioutil.ReadFile("/path/ca-cert.pem")
 //  pem, err := ioutil.ReadFile("/path/ca-cert.pem")
 //  if err != nil {
 //  if err != nil {
@@ -56,32 +51,19 @@ func RegisterTLSConfig(key string, config *tls.Config) error {
 		return fmt.Errorf("key '%s' is reserved", key)
 		return fmt.Errorf("key '%s' is reserved", key)
 	}
 	}
 
 
-	tlsConfigLock.Lock()
 	if tlsConfigRegister == nil {
 	if tlsConfigRegister == nil {
 		tlsConfigRegister = make(map[string]*tls.Config)
 		tlsConfigRegister = make(map[string]*tls.Config)
 	}
 	}
 
 
 	tlsConfigRegister[key] = config
 	tlsConfigRegister[key] = config
-	tlsConfigLock.Unlock()
 	return nil
 	return nil
 }
 }
 
 
 // DeregisterTLSConfig removes the tls.Config associated with key.
 // DeregisterTLSConfig removes the tls.Config associated with key.
 func DeregisterTLSConfig(key string) {
 func DeregisterTLSConfig(key string) {
-	tlsConfigLock.Lock()
 	if tlsConfigRegister != nil {
 	if tlsConfigRegister != nil {
 		delete(tlsConfigRegister, key)
 		delete(tlsConfigRegister, key)
 	}
 	}
-	tlsConfigLock.Unlock()
-}
-
-func getTLSConfigClone(key string) (config *tls.Config) {
-	tlsConfigLock.RLock()
-	if v, ok := tlsConfigRegister[key]; ok {
-		config = cloneTLSConfig(v)
-	}
-	tlsConfigLock.RUnlock()
-	return
 }
 }
 
 
 // Returns the bool value of the input.
 // Returns the bool value of the input.
@@ -566,8 +548,8 @@ func readLengthEncodedInteger(b []byte) (uint64, bool, int) {
 	if len(b) == 0 {
 	if len(b) == 0 {
 		return 0, true, 1
 		return 0, true, 1
 	}
 	}
-
 	switch b[0] {
 	switch b[0] {
+
 	// 251: NULL
 	// 251: NULL
 	case 0xfb:
 	case 0xfb:
 		return 0, true, 1
 		return 0, true, 1
@@ -756,67 +738,3 @@ func escapeStringQuotes(buf []byte, v string) []byte {
 
 
 	return buf[:pos]
 	return buf[:pos]
 }
 }
-
-/******************************************************************************
-*                               Sync utils                                    *
-******************************************************************************/
-
-// noCopy may be embedded into structs which must not be copied
-// after the first use.
-//
-// See https://github.com/golang/go/issues/8005#issuecomment-190753527
-// for details.
-type noCopy struct{}
-
-// Lock is a no-op used by -copylocks checker from `go vet`.
-func (*noCopy) Lock() {}
-
-// atomicBool is a wrapper around uint32 for usage as a boolean value with
-// atomic access.
-type atomicBool struct {
-	_noCopy noCopy
-	value   uint32
-}
-
-// IsSet returns wether the current boolean value is true
-func (ab *atomicBool) IsSet() bool {
-	return atomic.LoadUint32(&ab.value) > 0
-}
-
-// Set sets the value of the bool regardless of the previous value
-func (ab *atomicBool) Set(value bool) {
-	if value {
-		atomic.StoreUint32(&ab.value, 1)
-	} else {
-		atomic.StoreUint32(&ab.value, 0)
-	}
-}
-
-// TrySet sets the value of the bool and returns wether the value changed
-func (ab *atomicBool) TrySet(value bool) bool {
-	if value {
-		return atomic.SwapUint32(&ab.value, 1) == 0
-	}
-	return atomic.SwapUint32(&ab.value, 0) > 0
-}
-
-// atomicBool is a wrapper for atomically accessed error values
-type atomicError struct {
-	_noCopy noCopy
-	value   atomic.Value
-}
-
-// Set sets the error value regardless of the previous value.
-// The value must not be nil
-func (ae *atomicError) Set(value error) {
-	ae.value.Store(value)
-}
-
-// Value returns the current error value
-func (ae *atomicError) Value() error {
-	if v := ae.value.Load(); v != nil {
-		// this will panic if the value doesn't implement the error interface
-		return v.(error)
-	}
-	return nil
-}

+ 0 - 40
vendor/github.com/go-sql-driver/mysql/utils_go17.go

@@ -1,40 +0,0 @@
-// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
-//
-// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved.
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// +build go1.7
-// +build !go1.8
-
-package mysql
-
-import "crypto/tls"
-
-func cloneTLSConfig(c *tls.Config) *tls.Config {
-	return &tls.Config{
-		Rand:                        c.Rand,
-		Time:                        c.Time,
-		Certificates:                c.Certificates,
-		NameToCertificate:           c.NameToCertificate,
-		GetCertificate:              c.GetCertificate,
-		RootCAs:                     c.RootCAs,
-		NextProtos:                  c.NextProtos,
-		ServerName:                  c.ServerName,
-		ClientAuth:                  c.ClientAuth,
-		ClientCAs:                   c.ClientCAs,
-		InsecureSkipVerify:          c.InsecureSkipVerify,
-		CipherSuites:                c.CipherSuites,
-		PreferServerCipherSuites:    c.PreferServerCipherSuites,
-		SessionTicketsDisabled:      c.SessionTicketsDisabled,
-		SessionTicketKey:            c.SessionTicketKey,
-		ClientSessionCache:          c.ClientSessionCache,
-		MinVersion:                  c.MinVersion,
-		MaxVersion:                  c.MaxVersion,
-		CurvePreferences:            c.CurvePreferences,
-		DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
-		Renegotiation:               c.Renegotiation,
-	}
-}

+ 0 - 49
vendor/github.com/go-sql-driver/mysql/utils_go18.go

@@ -1,49 +0,0 @@
-// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
-//
-// Copyright 2017 The Go-MySQL-Driver Authors. All rights reserved.
-//
-// This Source Code Form is subject to the terms of the Mozilla Public
-// License, v. 2.0. If a copy of the MPL was not distributed with this file,
-// You can obtain one at http://mozilla.org/MPL/2.0/.
-
-// +build go1.8
-
-package mysql
-
-import (
-	"crypto/tls"
-	"database/sql"
-	"database/sql/driver"
-	"errors"
-)
-
-func cloneTLSConfig(c *tls.Config) *tls.Config {
-	return c.Clone()
-}
-
-func namedValueToValue(named []driver.NamedValue) ([]driver.Value, error) {
-	dargs := make([]driver.Value, len(named))
-	for n, param := range named {
-		if len(param.Name) > 0 {
-			// TODO: support the use of Named Parameters #561
-			return nil, errors.New("mysql: driver does not support the use of Named Parameters")
-		}
-		dargs[n] = param.Value
-	}
-	return dargs, nil
-}
-
-func mapIsolationLevel(level driver.IsolationLevel) (string, error) {
-	switch sql.IsolationLevel(level) {
-	case sql.LevelRepeatableRead:
-		return "REPEATABLE READ", nil
-	case sql.LevelReadCommitted:
-		return "READ COMMITTED", nil
-	case sql.LevelReadUncommitted:
-		return "READ UNCOMMITTED", nil
-	case sql.LevelSerializable:
-		return "SERIALIZABLE", nil
-	default:
-		return "", errors.New("mysql: unsupported isolation level: " + string(level))
-	}
-}

+ 1 - 11
vendor/github.com/gorilla/handlers/cors.go

@@ -110,17 +110,7 @@ func (ch *cors) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		w.Header().Set(corsVaryHeader, corsOriginHeader)
 		w.Header().Set(corsVaryHeader, corsOriginHeader)
 	}
 	}
 
 
-	returnOrigin := origin
-	for _, o := range ch.allowedOrigins {
-		// A configuration of * is different than explicitly setting an allowed
-		// origin. Returning arbitrary origin headers an an access control allow
-		// origin header is unsafe and is not required by any use case.
-		if o == corsOriginMatchAll {
-			returnOrigin = "*"
-			break
-		}
-	}
-	w.Header().Set(corsAllowOriginHeader, returnOrigin)
+	w.Header().Set(corsAllowOriginHeader, origin)
 
 
 	if r.Method == corsOptionMethod {
 	if r.Method == corsOptionMethod {
 		return
 		return

+ 3 - 4
vendor/github.com/gorilla/mux/.travis.yml

@@ -3,13 +3,12 @@ sudo: false
 
 
 matrix:
 matrix:
   include:
   include:
+    - go: 1.2
+    - go: 1.3
+    - go: 1.4
     - go: 1.5
     - go: 1.5
     - go: 1.6
     - go: 1.6
     - go: 1.7
     - go: 1.7
-    - go: 1.8
-    - go: 1.9
-    - go: tip
-  allow_failures:
     - go: tip
     - go: tip
 
 
 install:
 install:

+ 6 - 122
vendor/github.com/gorilla/mux/README.md

@@ -2,7 +2,6 @@ gorilla/mux
 ===
 ===
 [![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
 [![GoDoc](https://godoc.org/github.com/gorilla/mux?status.svg)](https://godoc.org/github.com/gorilla/mux)
 [![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)
 [![Build Status](https://travis-ci.org/gorilla/mux.svg?branch=master)](https://travis-ci.org/gorilla/mux)
-[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/mux/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/mux?badge)
 
 
 ![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png)
 ![Gorilla Logo](http://www.gorillatoolkit.org/static/images/gorilla-icon-64.png)
 
 
@@ -15,7 +14,7 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv
 
 
 * It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
 * It implements the `http.Handler` interface so it is compatible with the standard `http.ServeMux`.
 * Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
 * Requests can be matched based on URL host, path, path prefix, schemes, header and query values, HTTP methods or using custom matchers.
-* URL hosts, paths and query values can have variables with an optional regular expression.
+* URL hosts and paths can have variables with an optional regular expression.
 * Registered URLs can be built, or "reversed", which helps maintaining references to resources.
 * Registered URLs can be built, or "reversed", which helps maintaining references to resources.
 * Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.
 * Routes can be used as subrouters: nested routes are only tested if the parent route matches. This is useful to define groups of routes that share common conditions like a host, a path prefix or other repeated attributes. As a bonus, this optimizes request matching.
 
 
@@ -26,7 +25,6 @@ The name mux stands for "HTTP request multiplexer". Like the standard `http.Serv
 * [Matching Routes](#matching-routes)
 * [Matching Routes](#matching-routes)
 * [Static Files](#static-files)
 * [Static Files](#static-files)
 * [Registered URLs](#registered-urls)
 * [Registered URLs](#registered-urls)
-* [Walking Routes](#walking-routes)
 * [Full Example](#full-example)
 * [Full Example](#full-example)
 
 
 ---
 ---
@@ -67,11 +65,8 @@ r.HandleFunc("/articles/{category}/{id:[0-9]+}", ArticleHandler)
 The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`:
 The names are used to create a map of route variables which can be retrieved calling `mux.Vars()`:
 
 
 ```go
 ```go
-func ArticlesCategoryHandler(w http.ResponseWriter, r *http.Request) {
-	vars := mux.Vars(r)
-	w.WriteHeader(http.StatusOK)
-	fmt.Fprintf(w, "Category: %v\n", vars["category"])
-}
+vars := mux.Vars(request)
+category := vars["category"]
 ```
 ```
 
 
 And this is all you need to know about the basic usage. More advanced options are explained below.
 And this is all you need to know about the basic usage. More advanced options are explained below.
@@ -135,14 +130,6 @@ r.HandleFunc("/products", ProductsHandler).
   Schemes("http")
   Schemes("http")
 ```
 ```
 
 
-Routes are tested in the order they were added to the router. If two routes match, the first one wins:
-
-```go
-r := mux.NewRouter()
-r.HandleFunc("/specific", specificHandler)
-r.PathPrefix("/").Handler(catchAllHandler)
-```
-
 Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting".
 Setting the same matching conditions again and again can be boring, so we have a way to group several routes that share the same requirements. We call it "subrouting".
 
 
 For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it:
 For example, let's say we have several URLs that should only match when the host is `www.example.com`. Create a route for that host and get a "subrouter" from it:
@@ -176,64 +163,6 @@ s.HandleFunc("/{key}/", ProductHandler)
 // "/products/{key}/details"
 // "/products/{key}/details"
 s.HandleFunc("/{key}/details", ProductDetailsHandler)
 s.HandleFunc("/{key}/details", ProductDetailsHandler)
 ```
 ```
-### Listing Routes
-
-Routes on a mux can be listed using the Router.Walk method—useful for generating documentation:
-
-```go
-package main
-
-import (
-    "fmt"
-    "net/http"
-    "strings"
-
-    "github.com/gorilla/mux"
-)
-
-func handler(w http.ResponseWriter, r *http.Request) {
-    return
-}
-
-func main() {
-    r := mux.NewRouter()
-    r.HandleFunc("/", handler)
-    r.HandleFunc("/products", handler).Methods("POST")
-    r.HandleFunc("/articles", handler).Methods("GET")
-    r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
-    r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
-    r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
-        t, err := route.GetPathTemplate()
-        if err != nil {
-            return err
-        }
-        qt, err := route.GetQueriesTemplates()
-        if err != nil {
-            return err
-        }
-        // p will contain regular expression is compatible with regular expression in Perl, Python, and other languages.
-        // for instance the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'
-        p, err := route.GetPathRegexp()
-        if err != nil {
-            return err
-        }
-        // qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
-        // just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
-        // {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
-        qr, err := route.GetQueriesRegexp()
-        if err != nil {
-            return err
-        }
-        m, err := route.GetMethods()
-        if err != nil {
-            return err
-        }
-        fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
-        return nil
-    })
-    http.Handle("/", r)
-}
-```
 
 
 ### Static Files
 ### Static Files
 
 
@@ -288,21 +217,19 @@ url, err := r.Get("article").URL("category", "technology", "id", "42")
 "/articles/technology/42"
 "/articles/technology/42"
 ```
 ```
 
 
-This also works for host and query value variables:
+This also works for host variables:
 
 
 ```go
 ```go
 r := mux.NewRouter()
 r := mux.NewRouter()
 r.Host("{subdomain}.domain.com").
 r.Host("{subdomain}.domain.com").
   Path("/articles/{category}/{id:[0-9]+}").
   Path("/articles/{category}/{id:[0-9]+}").
-  Queries("filter", "{filter}").
   HandlerFunc(ArticleHandler).
   HandlerFunc(ArticleHandler).
   Name("article")
   Name("article")
 
 
-// url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
+// url.String() will be "http://news.domain.com/articles/technology/42"
 url, err := r.Get("article").URL("subdomain", "news",
 url, err := r.Get("article").URL("subdomain", "news",
                                  "category", "technology",
                                  "category", "technology",
-                                 "id", "42",
-                                 "filter", "gorilla")
+                                 "id", "42")
 ```
 ```
 
 
 All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match.
 All variables defined in the route are required, and their values must conform to the corresponding patterns. These requirements guarantee that a generated URL will always match a registered route -- the only exception is for explicitly defined "build-only" routes which never match.
@@ -340,49 +267,6 @@ url, err := r.Get("article").URL("subdomain", "news",
                                  "id", "42")
                                  "id", "42")
 ```
 ```
 
 
-### Walking Routes
-
-The `Walk` function on `mux.Router` can be used to visit all of the routes that are registered on a router. For example,
-the following prints all of the registered routes:
-
-```go
-r := mux.NewRouter()
-r.HandleFunc("/", handler)
-r.HandleFunc("/products", handler).Methods("POST")
-r.HandleFunc("/articles", handler).Methods("GET")
-r.HandleFunc("/articles/{id}", handler).Methods("GET", "PUT")
-r.HandleFunc("/authors", handler).Queries("surname", "{surname}")
-r.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
-    t, err := route.GetPathTemplate()
-    if err != nil {
-        return err
-    }
-    qt, err := route.GetQueriesTemplates()
-    if err != nil {
-        return err
-    }
-    // p will contain a regular expression that is compatible with regular expressions in Perl, Python, and other languages.
-    // For example, the regular expression for path '/articles/{id}' will be '^/articles/(?P<v0>[^/]+)$'.
-    p, err := route.GetPathRegexp()
-    if err != nil {
-        return err
-    }
-    // qr will contain a list of regular expressions with the same semantics as GetPathRegexp,
-    // just applied to the Queries pairs instead, e.g., 'Queries("surname", "{surname}") will return
-    // {"^surname=(?P<v0>.*)$}. Where each combined query pair will have an entry in the list.
-    qr, err := route.GetQueriesRegexp()
-    if err != nil {
-        return err
-    }
-    m, err := route.GetMethods()
-    if err != nil {
-        return err
-    }
-    fmt.Println(strings.Join(m, ","), strings.Join(qt, ","), strings.Join(qr, ","), t, p)
-    return nil
-})
-```
-
 ## Full Example
 ## Full Example
 
 
 Here's a complete, runnable example of a small `mux` based server:
 Here's a complete, runnable example of a small `mux` based server:

+ 5 - 12
vendor/github.com/gorilla/mux/doc.go

@@ -12,8 +12,8 @@ or other conditions. The main features are:
 
 
 	* Requests can be matched based on URL host, path, path prefix, schemes,
 	* Requests can be matched based on URL host, path, path prefix, schemes,
 	  header and query values, HTTP methods or using custom matchers.
 	  header and query values, HTTP methods or using custom matchers.
-	* URL hosts, paths and query values can have variables with an optional
-	  regular expression.
+	* URL hosts and paths can have variables with an optional regular
+	  expression.
 	* Registered URLs can be built, or "reversed", which helps maintaining
 	* Registered URLs can be built, or "reversed", which helps maintaining
 	  references to resources.
 	  references to resources.
 	* Routes can be used as subrouters: nested routes are only tested if the
 	* Routes can be used as subrouters: nested routes are only tested if the
@@ -57,11 +57,6 @@ calling mux.Vars():
 	vars := mux.Vars(request)
 	vars := mux.Vars(request)
 	category := vars["category"]
 	category := vars["category"]
 
 
-Note that if any capturing groups are present, mux will panic() during parsing. To prevent
-this, convert any capturing groups to non-capturing, e.g. change "/{sort:(asc|desc)}" to
-"/{sort:(?:asc|desc)}". This is a change from prior versions which behaved unpredictably
-when capturing groups were present.
-
 And this is all you need to know about the basic usage. More advanced options
 And this is all you need to know about the basic usage. More advanced options
 are explained below.
 are explained below.
 
 
@@ -188,20 +183,18 @@ key/value pairs for the route variables. For the previous route, we would do:
 
 
 	"/articles/technology/42"
 	"/articles/technology/42"
 
 
-This also works for host and query value variables:
+This also works for host variables:
 
 
 	r := mux.NewRouter()
 	r := mux.NewRouter()
 	r.Host("{subdomain}.domain.com").
 	r.Host("{subdomain}.domain.com").
 	  Path("/articles/{category}/{id:[0-9]+}").
 	  Path("/articles/{category}/{id:[0-9]+}").
-	  Queries("filter", "{filter}").
 	  HandlerFunc(ArticleHandler).
 	  HandlerFunc(ArticleHandler).
 	  Name("article")
 	  Name("article")
 
 
-	// url.String() will be "http://news.domain.com/articles/technology/42?filter=gorilla"
+	// url.String() will be "http://news.domain.com/articles/technology/42"
 	url, err := r.Get("article").URL("subdomain", "news",
 	url, err := r.Get("article").URL("subdomain", "news",
 	                                 "category", "technology",
 	                                 "category", "technology",
-	                                 "id", "42",
-	                                 "filter", "gorilla")
+	                                 "id", "42")
 
 
 All variables defined in the route are required, and their values must
 All variables defined in the route are required, and their values must
 conform to the corresponding patterns. These requirements guarantee that a
 conform to the corresponding patterns. These requirements guarantee that a

+ 34 - 63
vendor/github.com/gorilla/mux/mux.go

@@ -10,11 +10,7 @@ import (
 	"net/http"
 	"net/http"
 	"path"
 	"path"
 	"regexp"
 	"regexp"
-)
-
-var (
-	ErrMethodMismatch = errors.New("method is not allowed")
-	ErrNotFound       = errors.New("no matching route was found")
+	"strings"
 )
 )
 
 
 // NewRouter returns a new router instance.
 // NewRouter returns a new router instance.
@@ -43,10 +39,6 @@ func NewRouter() *Router {
 type Router struct {
 type Router struct {
 	// Configurable Handler to be used when no route matches.
 	// Configurable Handler to be used when no route matches.
 	NotFoundHandler http.Handler
 	NotFoundHandler http.Handler
-
-	// Configurable Handler to be used when the request method does not match the route.
-	MethodNotAllowedHandler http.Handler
-
 	// Parent route, if this is a subrouter.
 	// Parent route, if this is a subrouter.
 	parent parentRoute
 	parent parentRoute
 	// Routes to be matched, in order.
 	// Routes to be matched, in order.
@@ -65,17 +57,7 @@ type Router struct {
 	useEncodedPath bool
 	useEncodedPath bool
 }
 }
 
 
-// Match attempts to match the given request against the router's registered routes.
-//
-// If the request matches a route of this router or one of its subrouters the Route,
-// Handler, and Vars fields of the the match argument are filled and this function
-// returns true.
-//
-// If the request does not match any of this router's or its subrouters' routes
-// then this function returns false. If available, a reason for the match failure
-// will be filled in the match argument's MatchErr field. If the match failure type
-// (eg: not found) has a registered handler, the handler is assigned to the Handler
-// field of the match argument.
+// Match matches registered routes against the request.
 func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
 func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
 	for _, route := range r.routes {
 	for _, route := range r.routes {
 		if route.Match(req, match) {
 		if route.Match(req, match) {
@@ -83,23 +65,11 @@ func (r *Router) Match(req *http.Request, match *RouteMatch) bool {
 		}
 		}
 	}
 	}
 
 
-	if match.MatchErr == ErrMethodMismatch {
-		if r.MethodNotAllowedHandler != nil {
-			match.Handler = r.MethodNotAllowedHandler
-			return true
-		} else {
-			return false
-		}
-	}
-
 	// Closest match for a router (includes sub-routers)
 	// Closest match for a router (includes sub-routers)
 	if r.NotFoundHandler != nil {
 	if r.NotFoundHandler != nil {
 		match.Handler = r.NotFoundHandler
 		match.Handler = r.NotFoundHandler
-		match.MatchErr = ErrNotFound
 		return true
 		return true
 	}
 	}
-
-	match.MatchErr = ErrNotFound
 	return false
 	return false
 }
 }
 
 
@@ -111,7 +81,7 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 	if !r.skipClean {
 	if !r.skipClean {
 		path := req.URL.Path
 		path := req.URL.Path
 		if r.useEncodedPath {
 		if r.useEncodedPath {
-			path = req.URL.EscapedPath()
+			path = getPath(req)
 		}
 		}
 		// Clean path to canonical form and redirect.
 		// Clean path to canonical form and redirect.
 		if p := cleanPath(path); p != path {
 		if p := cleanPath(path); p != path {
@@ -135,15 +105,9 @@ func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) {
 		req = setVars(req, match.Vars)
 		req = setVars(req, match.Vars)
 		req = setCurrentRoute(req, match.Route)
 		req = setCurrentRoute(req, match.Route)
 	}
 	}
-
-	if handler == nil && match.MatchErr == ErrMethodMismatch {
-		handler = methodNotAllowedHandler()
-	}
-
 	if handler == nil {
 	if handler == nil {
 		handler = http.NotFoundHandler()
 		handler = http.NotFoundHandler()
 	}
 	}
-
 	if !r.KeepContext {
 	if !r.KeepContext {
 		defer contextClear(req)
 		defer contextClear(req)
 	}
 	}
@@ -196,6 +160,10 @@ func (r *Router) SkipClean(value bool) *Router {
 // UseEncodedPath tells the router to match the encoded original path
 // UseEncodedPath tells the router to match the encoded original path
 // to the routes.
 // to the routes.
 // For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
 // For eg. "/path/foo%2Fbar/to" will match the path "/path/{var}/to".
+// This behavior has the drawback of needing to match routes against
+// r.RequestURI instead of r.URL.Path. Any modifications (such as http.StripPrefix)
+// to r.URL.Path will not affect routing when this flag is on and thus may
+// induce unintended behavior.
 //
 //
 // If not called, the router will match the unencoded path to the routes.
 // If not called, the router will match the unencoded path to the routes.
 // For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to"
 // For eg. "/path/foo%2Fbar/to" will match the path "/path/foo/bar/to"
@@ -208,13 +176,6 @@ func (r *Router) UseEncodedPath() *Router {
 // parentRoute
 // parentRoute
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 
 
-func (r *Router) getBuildScheme() string {
-	if r.parent != nil {
-		return r.parent.getBuildScheme()
-	}
-	return ""
-}
-
 // getNamedRoutes returns the map where named routes are registered.
 // getNamedRoutes returns the map where named routes are registered.
 func (r *Router) getNamedRoutes() map[string]*Route {
 func (r *Router) getNamedRoutes() map[string]*Route {
 	if r.namedRoutes == nil {
 	if r.namedRoutes == nil {
@@ -338,6 +299,10 @@ type WalkFunc func(route *Route, router *Router, ancestors []*Route) error
 
 
 func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
 func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
 	for _, t := range r.routes {
 	for _, t := range r.routes {
+		if t.regexp == nil || t.regexp.path == nil || t.regexp.path.template == "" {
+			continue
+		}
+
 		err := walkFn(t, r, ancestors)
 		err := walkFn(t, r, ancestors)
 		if err == SkipRouter {
 		if err == SkipRouter {
 			continue
 			continue
@@ -347,12 +312,10 @@ func (r *Router) walk(walkFn WalkFunc, ancestors []*Route) error {
 		}
 		}
 		for _, sr := range t.matchers {
 		for _, sr := range t.matchers {
 			if h, ok := sr.(*Router); ok {
 			if h, ok := sr.(*Router); ok {
-				ancestors = append(ancestors, t)
 				err := h.walk(walkFn, ancestors)
 				err := h.walk(walkFn, ancestors)
 				if err != nil {
 				if err != nil {
 					return err
 					return err
 				}
 				}
-				ancestors = ancestors[:len(ancestors)-1]
 			}
 			}
 		}
 		}
 		if h, ok := t.handler.(*Router); ok {
 		if h, ok := t.handler.(*Router); ok {
@@ -376,11 +339,6 @@ type RouteMatch struct {
 	Route   *Route
 	Route   *Route
 	Handler http.Handler
 	Handler http.Handler
 	Vars    map[string]string
 	Vars    map[string]string
-
-	// MatchErr is set to appropriate matching error
-	// It is set to ErrMethodMismatch if there is a mismatch in
-	// the request method and route method
-	MatchErr error
 }
 }
 
 
 type contextKey int
 type contextKey int
@@ -422,6 +380,28 @@ func setCurrentRoute(r *http.Request, val interface{}) *http.Request {
 // Helpers
 // Helpers
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
 
 
+// getPath returns the escaped path if possible; doing what URL.EscapedPath()
+// which was added in go1.5 does
+func getPath(req *http.Request) string {
+	if req.RequestURI != "" {
+		// Extract the path from RequestURI (which is escaped unlike URL.Path)
+		// as detailed here as detailed in https://golang.org/pkg/net/url/#URL
+		// for < 1.5 server side workaround
+		// http://localhost/path/here?v=1 -> /path/here
+		path := req.RequestURI
+		path = strings.TrimPrefix(path, req.URL.Scheme+`://`)
+		path = strings.TrimPrefix(path, req.URL.Host)
+		if i := strings.LastIndex(path, "?"); i > -1 {
+			path = path[:i]
+		}
+		if i := strings.LastIndex(path, "#"); i > -1 {
+			path = path[:i]
+		}
+		return path
+	}
+	return req.URL.Path
+}
+
 // cleanPath returns the canonical path for p, eliminating . and .. elements.
 // cleanPath returns the canonical path for p, eliminating . and .. elements.
 // Borrowed from the net/http package.
 // Borrowed from the net/http package.
 func cleanPath(p string) string {
 func cleanPath(p string) string {
@@ -478,7 +458,7 @@ func mapFromPairsToString(pairs ...string) (map[string]string, error) {
 	return m, nil
 	return m, nil
 }
 }
 
 
-// mapFromPairsToRegex converts variadic string parameters to a
+// mapFromPairsToRegex converts variadic string paramers to a
 // string to regex map.
 // string to regex map.
 func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
 func mapFromPairsToRegex(pairs ...string) (map[string]*regexp.Regexp, error) {
 	length, err := checkPairs(pairs...)
 	length, err := checkPairs(pairs...)
@@ -560,12 +540,3 @@ func matchMapWithRegex(toCheck map[string]*regexp.Regexp, toMatch map[string][]s
 	}
 	}
 	return true
 	return true
 }
 }
-
-// methodNotAllowed replies to the request with an HTTP status code 405.
-func methodNotAllowed(w http.ResponseWriter, r *http.Request) {
-	w.WriteHeader(http.StatusMethodNotAllowed)
-}
-
-// methodNotAllowedHandler returns a simple request handler
-// that replies to each request with a status code 405.
-func methodNotAllowedHandler() http.Handler { return http.HandlerFunc(methodNotAllowed) }

+ 4 - 14
vendor/github.com/gorilla/mux/regexp.go

@@ -35,7 +35,7 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
 	// Now let's parse it.
 	// Now let's parse it.
 	defaultPattern := "[^/]+"
 	defaultPattern := "[^/]+"
 	if matchQuery {
 	if matchQuery {
-		defaultPattern = ".*"
+		defaultPattern = "[^?&]*"
 	} else if matchHost {
 	} else if matchHost {
 		defaultPattern = "[^.]+"
 		defaultPattern = "[^.]+"
 		matchPrefix = false
 		matchPrefix = false
@@ -109,13 +109,6 @@ func newRouteRegexp(tpl string, matchHost, matchPrefix, matchQuery, strictSlash,
 	if errCompile != nil {
 	if errCompile != nil {
 		return nil, errCompile
 		return nil, errCompile
 	}
 	}
-
-	// Check for capturing groups which used to work in older versions
-	if reg.NumSubexp() != len(idxs)/2 {
-		panic(fmt.Sprintf("route %s contains capture groups in its regexp. ", template) +
-			"Only non-capturing groups are accepted: e.g. (?:pattern) instead of (pattern)")
-	}
-
 	// Done!
 	// Done!
 	return &routeRegexp{
 	return &routeRegexp{
 		template:       template,
 		template:       template,
@@ -141,7 +134,7 @@ type routeRegexp struct {
 	matchQuery bool
 	matchQuery bool
 	// The strictSlash value defined on the route, but disabled if PathPrefix was used.
 	// The strictSlash value defined on the route, but disabled if PathPrefix was used.
 	strictSlash bool
 	strictSlash bool
-	// Determines whether to use encoded req.URL.EnscapedPath() or unencoded
+	// Determines whether to use encoded path from getPath function or unencoded
 	// req.URL.Path for path matching
 	// req.URL.Path for path matching
 	useEncodedPath bool
 	useEncodedPath bool
 	// Expanded regexp.
 	// Expanded regexp.
@@ -162,7 +155,7 @@ func (r *routeRegexp) Match(req *http.Request, match *RouteMatch) bool {
 		}
 		}
 		path := req.URL.Path
 		path := req.URL.Path
 		if r.useEncodedPath {
 		if r.useEncodedPath {
-			path = req.URL.EscapedPath()
+			path = getPath(req)
 		}
 		}
 		return r.regexp.MatchString(path)
 		return r.regexp.MatchString(path)
 	}
 	}
@@ -178,9 +171,6 @@ func (r *routeRegexp) url(values map[string]string) (string, error) {
 		if !ok {
 		if !ok {
 			return "", fmt.Errorf("mux: missing route variable %q", v)
 			return "", fmt.Errorf("mux: missing route variable %q", v)
 		}
 		}
-		if r.matchQuery {
-			value = url.QueryEscape(value)
-		}
 		urlValues[k] = value
 		urlValues[k] = value
 	}
 	}
 	rv := fmt.Sprintf(r.reverse, urlValues...)
 	rv := fmt.Sprintf(r.reverse, urlValues...)
@@ -272,7 +262,7 @@ func (v *routeRegexpGroup) setMatch(req *http.Request, m *RouteMatch, r *Route)
 	}
 	}
 	path := req.URL.Path
 	path := req.URL.Path
 	if r.useEncodedPath {
 	if r.useEncodedPath {
-		path = req.URL.EscapedPath()
+		path = getPath(req)
 	}
 	}
 	// Store path variables.
 	// Store path variables.
 	if v.path != nil {
 	if v.path != nil {

+ 8 - 127
vendor/github.com/gorilla/mux/route.go

@@ -31,8 +31,6 @@ type Route struct {
 	skipClean bool
 	skipClean bool
 	// If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
 	// If true, "/path/foo%2Fbar/to" will match the path "/path/{var}/to"
 	useEncodedPath bool
 	useEncodedPath bool
-	// The scheme used when building URLs.
-	buildScheme string
 	// If true, this route never matches: it is only used to build URLs.
 	// If true, this route never matches: it is only used to build URLs.
 	buildOnly bool
 	buildOnly bool
 	// The name used to build URLs.
 	// The name used to build URLs.
@@ -52,31 +50,12 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
 	if r.buildOnly || r.err != nil {
 	if r.buildOnly || r.err != nil {
 		return false
 		return false
 	}
 	}
-
-	var matchErr error
-
 	// Match everything.
 	// Match everything.
 	for _, m := range r.matchers {
 	for _, m := range r.matchers {
 		if matched := m.Match(req, match); !matched {
 		if matched := m.Match(req, match); !matched {
-			if _, ok := m.(methodMatcher); ok {
-				matchErr = ErrMethodMismatch
-				continue
-			}
-			matchErr = nil
 			return false
 			return false
 		}
 		}
 	}
 	}
-
-	if matchErr != nil {
-		match.MatchErr = matchErr
-		return false
-	}
-
-	if match.MatchErr == ErrMethodMismatch {
-		// We found a route which matches request method, clear MatchErr
-		match.MatchErr = nil
-	}
-
 	// Yay, we have a match. Let's collect some info about it.
 	// Yay, we have a match. Let's collect some info about it.
 	if match.Route == nil {
 	if match.Route == nil {
 		match.Route = r
 		match.Route = r
@@ -87,7 +66,6 @@ func (r *Route) Match(req *http.Request, match *RouteMatch) bool {
 	if match.Vars == nil {
 	if match.Vars == nil {
 		match.Vars = make(map[string]string)
 		match.Vars = make(map[string]string)
 	}
 	}
-
 	// Set variables.
 	// Set variables.
 	if r.regexp != nil {
 	if r.regexp != nil {
 		r.regexp.setMatch(req, match, r)
 		r.regexp.setMatch(req, match, r)
@@ -175,7 +153,7 @@ func (r *Route) addRegexpMatcher(tpl string, matchHost, matchPrefix, matchQuery
 	}
 	}
 	r.regexp = r.getRegexpGroup()
 	r.regexp = r.getRegexpGroup()
 	if !matchHost && !matchQuery {
 	if !matchHost && !matchQuery {
-		if len(tpl) > 0 && tpl[0] != '/' {
+		if len(tpl) == 0 || tpl[0] != '/' {
 			return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
 			return fmt.Errorf("mux: path must start with a slash, got %q", tpl)
 		}
 		}
 		if r.regexp.path != nil {
 		if r.regexp.path != nil {
@@ -416,9 +394,6 @@ func (r *Route) Schemes(schemes ...string) *Route {
 	for k, v := range schemes {
 	for k, v := range schemes {
 		schemes[k] = strings.ToLower(v)
 		schemes[k] = strings.ToLower(v)
 	}
 	}
-	if r.buildScheme == "" && len(schemes) > 0 {
-		r.buildScheme = schemes[0]
-	}
 	return r.addMatcher(schemeMatcher(schemes))
 	return r.addMatcher(schemeMatcher(schemes))
 }
 }
 
 
@@ -502,33 +477,22 @@ func (r *Route) URL(pairs ...string) (*url.URL, error) {
 		return nil, err
 		return nil, err
 	}
 	}
 	var scheme, host, path string
 	var scheme, host, path string
-	queries := make([]string, 0, len(r.regexp.queries))
 	if r.regexp.host != nil {
 	if r.regexp.host != nil {
+		// Set a default scheme.
+		scheme = "http"
 		if host, err = r.regexp.host.url(values); err != nil {
 		if host, err = r.regexp.host.url(values); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
-		scheme = "http"
-		if s := r.getBuildScheme(); s != "" {
-			scheme = s
-		}
 	}
 	}
 	if r.regexp.path != nil {
 	if r.regexp.path != nil {
 		if path, err = r.regexp.path.url(values); err != nil {
 		if path, err = r.regexp.path.url(values); err != nil {
 			return nil, err
 			return nil, err
 		}
 		}
 	}
 	}
-	for _, q := range r.regexp.queries {
-		var query string
-		if query, err = q.url(values); err != nil {
-			return nil, err
-		}
-		queries = append(queries, query)
-	}
 	return &url.URL{
 	return &url.URL{
-		Scheme:   scheme,
-		Host:     host,
-		Path:     path,
-		RawQuery: strings.Join(queries, "&"),
+		Scheme: scheme,
+		Host:   host,
+		Path:   path,
 	}, nil
 	}, nil
 }
 }
 
 
@@ -550,14 +514,10 @@ func (r *Route) URLHost(pairs ...string) (*url.URL, error) {
 	if err != nil {
 	if err != nil {
 		return nil, err
 		return nil, err
 	}
 	}
-	u := &url.URL{
+	return &url.URL{
 		Scheme: "http",
 		Scheme: "http",
 		Host:   host,
 		Host:   host,
-	}
-	if s := r.getBuildScheme(); s != "" {
-		u.Scheme = s
-	}
-	return u, nil
+	}, nil
 }
 }
 
 
 // URLPath builds the path part of the URL for a route. See Route.URL().
 // URLPath builds the path part of the URL for a route. See Route.URL().
@@ -598,74 +558,6 @@ func (r *Route) GetPathTemplate() (string, error) {
 	return r.regexp.path.template, nil
 	return r.regexp.path.template, nil
 }
 }
 
 
-// GetPathRegexp returns the expanded regular expression used to match route path.
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An error will be returned if the route does not define a path.
-func (r *Route) GetPathRegexp() (string, error) {
-	if r.err != nil {
-		return "", r.err
-	}
-	if r.regexp == nil || r.regexp.path == nil {
-		return "", errors.New("mux: route does not have a path")
-	}
-	return r.regexp.path.regexp.String(), nil
-}
-
-// GetQueriesRegexp returns the expanded regular expressions used to match the
-// route queries.
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An empty list will be returned if the route does not have queries.
-func (r *Route) GetQueriesRegexp() ([]string, error) {
-	if r.err != nil {
-		return nil, r.err
-	}
-	if r.regexp == nil || r.regexp.queries == nil {
-		return nil, errors.New("mux: route doesn't have queries")
-	}
-	var queries []string
-	for _, query := range r.regexp.queries {
-		queries = append(queries, query.regexp.String())
-	}
-	return queries, nil
-}
-
-// GetQueriesTemplates returns the templates used to build the
-// query matching.
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An empty list will be returned if the route does not define queries.
-func (r *Route) GetQueriesTemplates() ([]string, error) {
-	if r.err != nil {
-		return nil, r.err
-	}
-	if r.regexp == nil || r.regexp.queries == nil {
-		return nil, errors.New("mux: route doesn't have queries")
-	}
-	var queries []string
-	for _, query := range r.regexp.queries {
-		queries = append(queries, query.template)
-	}
-	return queries, nil
-}
-
-// GetMethods returns the methods the route matches against
-// This is useful for building simple REST API documentation and for instrumentation
-// against third-party services.
-// An empty list will be returned if route does not have methods.
-func (r *Route) GetMethods() ([]string, error) {
-	if r.err != nil {
-		return nil, r.err
-	}
-	for _, m := range r.matchers {
-		if methods, ok := m.(methodMatcher); ok {
-			return []string(methods), nil
-		}
-	}
-	return nil, nil
-}
-
 // GetHostTemplate returns the template used to build the
 // GetHostTemplate returns the template used to build the
 // route match.
 // route match.
 // This is useful for building simple REST API documentation and for instrumentation
 // This is useful for building simple REST API documentation and for instrumentation
@@ -707,22 +599,11 @@ func (r *Route) buildVars(m map[string]string) map[string]string {
 
 
 // parentRoute allows routes to know about parent host and path definitions.
 // parentRoute allows routes to know about parent host and path definitions.
 type parentRoute interface {
 type parentRoute interface {
-	getBuildScheme() string
 	getNamedRoutes() map[string]*Route
 	getNamedRoutes() map[string]*Route
 	getRegexpGroup() *routeRegexpGroup
 	getRegexpGroup() *routeRegexpGroup
 	buildVars(map[string]string) map[string]string
 	buildVars(map[string]string) map[string]string
 }
 }
 
 
-func (r *Route) getBuildScheme() string {
-	if r.buildScheme != "" {
-		return r.buildScheme
-	}
-	if r.parent != nil {
-		return r.parent.getBuildScheme()
-	}
-	return ""
-}
-
 // getNamedRoutes returns the map where named routes are registered.
 // getNamedRoutes returns the map where named routes are registered.
 func (r *Route) getNamedRoutes() map[string]*Route {
 func (r *Route) getNamedRoutes() map[string]*Route {
 	if r.parent == nil {
 	if r.parent == nil {

+ 2 - 1
vendor/github.com/gorilla/schema/.travis.yml

@@ -3,10 +3,11 @@ sudo: false
 
 
 matrix:
 matrix:
   include:
   include:
+    - go: 1.3
+    - go: 1.4
     - go: 1.5
     - go: 1.5
     - go: 1.6
     - go: 1.6
     - go: 1.7
     - go: 1.7
-    - go: 1.8
     - go: tip
     - go: tip
   allow_failures:
   allow_failures:
     - go: tip
     - go: tip

+ 10 - 34
vendor/github.com/gorilla/schema/README.md

@@ -1,17 +1,15 @@
 schema
 schema
 ======
 ======
 [![GoDoc](https://godoc.org/github.com/gorilla/schema?status.svg)](https://godoc.org/github.com/gorilla/schema) [![Build Status](https://travis-ci.org/gorilla/schema.png?branch=master)](https://travis-ci.org/gorilla/schema)
 [![GoDoc](https://godoc.org/github.com/gorilla/schema?status.svg)](https://godoc.org/github.com/gorilla/schema) [![Build Status](https://travis-ci.org/gorilla/schema.png?branch=master)](https://travis-ci.org/gorilla/schema)
-[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/schema/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/schema?badge)
 
 
-
-Package gorilla/schema converts structs to and from form values.
+Package gorilla/schema fills a struct with form values.
 
 
 ## Example
 ## Example
 
 
 Here's a quick example: we parse POST form values and then decode them into a struct:
 Here's a quick example: we parse POST form values and then decode them into a struct:
 
 
 ```go
 ```go
-// Set a Decoder instance as a package global, because it caches
+// Set a Decoder instance as a package global, because it caches 
 // meta-data about structs, and an instance can be shared safely.
 // meta-data about structs, and an instance can be shared safely.
 var decoder = schema.NewDecoder()
 var decoder = schema.NewDecoder()
 
 
@@ -27,9 +25,9 @@ func MyHandler(w http.ResponseWriter, r *http.Request) {
     }
     }
 
 
     var person Person
     var person Person
-
+    
     // r.PostForm is a map of our POST form values
     // r.PostForm is a map of our POST form values
-    err = decoder.Decode(&person, r.PostForm)
+    err := decoder.Decode(&person, r.PostForm)
     if err != nil {
     if err != nil {
         // Handle error
         // Handle error
     }
     }
@@ -38,39 +36,17 @@ func MyHandler(w http.ResponseWriter, r *http.Request) {
 }
 }
 ```
 ```
 
 
-Conversely, contents of a struct can be encoded into form values. Here's a variant of the previous example using the Encoder:
-
-```go
-var encoder = schema.NewEncoder()
-
-func MyHttpRequest() {
-    person := Person{"Jane Doe", "555-5555"}
-    form := url.Values{}
-
-    err := encoder.Encode(person, form)
-
-    if err != nil {
-        // Handle error
-    }
-
-    // Use form values, for example, with an http client
-    client := new(http.Client)
-    res, err := client.PostForm("http://my-api.test", form)
-}
-
-```
-
 To define custom names for fields, use a struct tag "schema". To not populate certain fields, use a dash for the name and it will be ignored:
 To define custom names for fields, use a struct tag "schema". To not populate certain fields, use a dash for the name and it will be ignored:
 
 
 ```go
 ```go
 type Person struct {
 type Person struct {
-    Name  string `schema:"name,required"`  // custom name, must be supplied
-    Phone string `schema:"phone"`          // custom name
-    Admin bool   `schema:"-"`              // this field is never set
+    Name  string `schema:"name"`  // custom name
+    Phone string `schema:"phone"` // custom name
+    Admin bool   `schema:"-"`     // this field is never set
 }
 }
 ```
 ```
 
 
-The supported field types in the struct are:
+The supported field types in the destination struct are:
 
 
 * bool
 * bool
 * float variants (float32, float64)
 * float variants (float32, float64)
@@ -83,8 +59,8 @@ The supported field types in the struct are:
 
 
 Unsupported types are simply ignored, however custom types can be registered to be converted.
 Unsupported types are simply ignored, however custom types can be registered to be converted.
 
 
-More examples are available on the Gorilla website: https://www.gorillatoolkit.org/pkg/schema
+More examples are available on the Gorilla website: http://www.gorillatoolkit.org/pkg/schema
 
 
-## License
+## License 
 
 
 BSD licensed. See the LICENSE file for details.
 BSD licensed. See the LICENSE file for details.

+ 22 - 33
vendor/github.com/gorilla/schema/cache.go

@@ -18,9 +18,13 @@ var invalidPath = errors.New("schema: invalid path")
 func newCache() *cache {
 func newCache() *cache {
 	c := cache{
 	c := cache{
 		m:       make(map[reflect.Type]*structInfo),
 		m:       make(map[reflect.Type]*structInfo),
+		conv:    make(map[reflect.Kind]Converter),
 		regconv: make(map[reflect.Type]Converter),
 		regconv: make(map[reflect.Type]Converter),
 		tag:     "schema",
 		tag:     "schema",
 	}
 	}
+	for k, v := range converters {
+		c.conv[k] = v
+	}
 	return &c
 	return &c
 }
 }
 
 
@@ -28,15 +32,11 @@ func newCache() *cache {
 type cache struct {
 type cache struct {
 	l       sync.RWMutex
 	l       sync.RWMutex
 	m       map[reflect.Type]*structInfo
 	m       map[reflect.Type]*structInfo
+	conv    map[reflect.Kind]Converter
 	regconv map[reflect.Type]Converter
 	regconv map[reflect.Type]Converter
 	tag     string
 	tag     string
 }
 }
 
 
-// registerConverter registers a converter function for a custom type.
-func (c *cache) registerConverter(value interface{}, converterFunc Converter) {
-	c.regconv[reflect.TypeOf(value)] = converterFunc
-}
-
 // parsePath parses a path in dotted notation verifying that it is a valid
 // parsePath parses a path in dotted notation verifying that it is a valid
 // path to a struct field.
 // path to a struct field.
 //
 //
@@ -63,7 +63,7 @@ func (c *cache) parsePath(p string, t reflect.Type) ([]pathPart, error) {
 		}
 		}
 		// Valid field. Append index.
 		// Valid field. Append index.
 		path = append(path, field.name)
 		path = append(path, field.name)
-		if field.isSliceOfStructs && (!field.unmarshalerInfo.IsValid || (field.unmarshalerInfo.IsValid && field.unmarshalerInfo.IsSliceElement)) {
+		if field.ss {
 			// Parse a special case: slices of structs.
 			// Parse a special case: slices of structs.
 			// i+1 must be the slice index.
 			// i+1 must be the slice index.
 			//
 			//
@@ -138,12 +138,7 @@ func (c *cache) create(t reflect.Type, info *structInfo) *structInfo {
 				ft = ft.Elem()
 				ft = ft.Elem()
 			}
 			}
 			if ft.Kind() == reflect.Struct {
 			if ft.Kind() == reflect.Struct {
-				bef := len(info.fields)
 				c.create(ft, info)
 				c.create(ft, info)
-				for _, fi := range info.fields[bef:len(info.fields)] {
-					// exclude required check because duplicated to embedded field
-					fi.isRequired = false
-				}
 			}
 			}
 		}
 		}
 		c.createField(field, info)
 		c.createField(field, info)
@@ -162,7 +157,6 @@ func (c *cache) createField(field reflect.StructField, info *structInfo) {
 	// First let's get the basic type.
 	// First let's get the basic type.
 	isSlice, isStruct := false, false
 	isSlice, isStruct := false, false
 	ft := field.Type
 	ft := field.Type
-	m := isTextUnmarshaler(reflect.Zero(ft))
 	if ft.Kind() == reflect.Ptr {
 	if ft.Kind() == reflect.Ptr {
 		ft = ft.Elem()
 		ft = ft.Elem()
 	}
 	}
@@ -179,26 +173,28 @@ func (c *cache) createField(field reflect.StructField, info *structInfo) {
 		}
 		}
 	}
 	}
 	if isStruct = ft.Kind() == reflect.Struct; !isStruct {
 	if isStruct = ft.Kind() == reflect.Struct; !isStruct {
-		if c.converter(ft) == nil && builtinConverters[ft.Kind()] == nil {
+		if conv := c.conv[ft.Kind()]; conv == nil {
 			// Type is not supported.
 			// Type is not supported.
 			return
 			return
 		}
 		}
 	}
 	}
 
 
 	info.fields = append(info.fields, &fieldInfo{
 	info.fields = append(info.fields, &fieldInfo{
-		typ:              field.Type,
-		name:             field.Name,
-		alias:            alias,
-		unmarshalerInfo:  m,
-		isSliceOfStructs: isSlice && isStruct,
-		isAnonymous:      field.Anonymous,
-		isRequired:       options.Contains("required"),
+		typ:      field.Type,
+		name:     field.Name,
+		ss:       isSlice && isStruct,
+		alias:    alias,
+		required: options.Contains("required"),
 	})
 	})
 }
 }
 
 
 // converter returns the converter for a type.
 // converter returns the converter for a type.
 func (c *cache) converter(t reflect.Type) Converter {
 func (c *cache) converter(t reflect.Type) Converter {
-	return c.regconv[t]
+	conv := c.regconv[t]
+	if conv == nil {
+		conv = c.conv[t.Kind()]
+	}
+	return conv
 }
 }
 
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -217,18 +213,11 @@ func (i *structInfo) get(alias string) *fieldInfo {
 }
 }
 
 
 type fieldInfo struct {
 type fieldInfo struct {
-	typ reflect.Type
-	// name is the field name in the struct.
-	name  string
-	alias string
-	// unmarshalerInfo contains information regarding the
-	// encoding.TextUnmarshaler implementation of the field type.
-	unmarshalerInfo unmarshaler
-	// isSliceOfStructs indicates if the field type is a slice of structs.
-	isSliceOfStructs bool
-	// isAnonymous indicates whether the field is embedded in the struct.
-	isAnonymous bool
-	isRequired  bool
+	typ      reflect.Type
+	name     string // field name in the struct.
+	ss       bool   // true if this is a slice of structs.
+	alias    string
+	required bool // tag option
 }
 }
 
 
 type pathPart struct {
 type pathPart struct {

+ 1 - 1
vendor/github.com/gorilla/schema/converter.go

@@ -30,7 +30,7 @@ var (
 )
 )
 
 
 // Default converters for basic types.
 // Default converters for basic types.
-var builtinConverters = map[reflect.Kind]Converter{
+var converters = map[reflect.Kind]Converter{
 	boolType:    convertBool,
 	boolType:    convertBool,
 	float32Type: convertFloat32,
 	float32Type: convertFloat32,
 	float64Type: convertFloat64,
 	float64Type: convertFloat64,

+ 26 - 130
vendor/github.com/gorilla/schema/decoder.go

@@ -56,7 +56,7 @@ func (d *Decoder) IgnoreUnknownKeys(i bool) {
 
 
 // RegisterConverter registers a converter function for a custom type.
 // RegisterConverter registers a converter function for a custom type.
 func (d *Decoder) RegisterConverter(value interface{}, converterFunc Converter) {
 func (d *Decoder) RegisterConverter(value interface{}, converterFunc Converter) {
-	d.cache.registerConverter(value, converterFunc)
+	d.cache.regconv[reflect.TypeOf(value)] = converterFunc
 }
 }
 
 
 // Decode decodes a map[string][]string to a struct.
 // Decode decodes a map[string][]string to a struct.
@@ -90,7 +90,7 @@ func (d *Decoder) Decode(dst interface{}, src map[string][]string) error {
 	return d.checkRequired(t, src, "")
 	return d.checkRequired(t, src, "")
 }
 }
 
 
-// checkRequired checks whether required fields are empty
+// checkRequired checks whether requred field empty
 //
 //
 // check type t recursively if t has struct fields, and prefix is same as parsePath: in dotted notation
 // check type t recursively if t has struct fields, and prefix is same as parsePath: in dotted notation
 //
 //
@@ -106,17 +106,10 @@ func (d *Decoder) checkRequired(t reflect.Type, src map[string][]string, prefix
 		if f.typ.Kind() == reflect.Struct {
 		if f.typ.Kind() == reflect.Struct {
 			err := d.checkRequired(f.typ, src, prefix+f.alias+".")
 			err := d.checkRequired(f.typ, src, prefix+f.alias+".")
 			if err != nil {
 			if err != nil {
-				if !f.isAnonymous {
-					return err
-				}
-				// check embedded parent field.
-				err2 := d.checkRequired(f.typ, src, prefix)
-				if err2 != nil {
-					return err
-				}
+				return err
 			}
 			}
 		}
 		}
-		if f.isRequired {
+		if f.required {
 			key := f.alias
 			key := f.alias
 			if prefix != "" {
 			if prefix != "" {
 				key = prefix + key
 				key = prefix + key
@@ -153,6 +146,7 @@ func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values
 		}
 		}
 		v = v.FieldByName(name)
 		v = v.FieldByName(name)
 	}
 	}
+
 	// Don't even bother for unexported fields.
 	// Don't even bother for unexported fields.
 	if !v.CanSet() {
 	if !v.CanSet() {
 		return nil
 		return nil
@@ -184,8 +178,7 @@ func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values
 
 
 	// Get the converter early in case there is one for a slice type.
 	// Get the converter early in case there is one for a slice type.
 	conv := d.cache.converter(t)
 	conv := d.cache.converter(t)
-	m := isTextUnmarshaler(v)
-	if conv == nil && t.Kind() == reflect.Slice && m.IsSliceElement {
+	if conv == nil && t.Kind() == reflect.Slice {
 		var items []reflect.Value
 		var items []reflect.Value
 		elemT := t.Elem()
 		elemT := t.Elem()
 		isPtrElem := elemT.Kind() == reflect.Ptr
 		isPtrElem := elemT.Kind() == reflect.Ptr
@@ -196,12 +189,9 @@ func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values
 		// Try to get a converter for the element type.
 		// Try to get a converter for the element type.
 		conv := d.cache.converter(elemT)
 		conv := d.cache.converter(elemT)
 		if conv == nil {
 		if conv == nil {
-			conv = builtinConverters[elemT.Kind()]
-			if conv == nil {
-				// As we are not dealing with slice of structs here, we don't need to check if the type
-				// implements TextUnmarshaler interface
-				return fmt.Errorf("schema: converter not found for %v", elemT)
-			}
+			// As we are not dealing with slice of structs here, we don't need to check if the type
+			// implements TextUnmarshaler interface
+			return fmt.Errorf("schema: converter not found for %v", elemT)
 		}
 		}
 
 
 		for key, value := range values {
 		for key, value := range values {
@@ -209,26 +199,6 @@ func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values
 				if d.zeroEmpty {
 				if d.zeroEmpty {
 					items = append(items, reflect.Zero(elemT))
 					items = append(items, reflect.Zero(elemT))
 				}
 				}
-			} else if m.IsValid {
-				u := reflect.New(elemT)
-				if m.IsSliceElementPtr {
-					u = reflect.New(reflect.PtrTo(elemT).Elem())
-				}
-				if err := u.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(value)); err != nil {
-					return ConversionError{
-						Key:   path,
-						Type:  t,
-						Index: key,
-						Err:   err,
-					}
-				}
-				if m.IsSliceElementPtr {
-					items = append(items, u.Elem().Addr())
-				} else if u.Kind() == reflect.Ptr {
-					items = append(items, u.Elem())
-				} else {
-					items = append(items, u)
-				}
 			} else if item := conv(value); item.IsValid() {
 			} else if item := conv(value); item.IsValid() {
 				if isPtrElem {
 				if isPtrElem {
 					ptr := reflect.New(elemT)
 					ptr := reflect.New(elemT)
@@ -283,7 +253,11 @@ func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values
 			val = values[len(values)-1]
 			val = values[len(values)-1]
 		}
 		}
 
 
-		if conv != nil {
+		if val == "" {
+			if d.zeroEmpty {
+				v.Set(reflect.Zero(t))
+			}
+		} else if conv != nil {
 			if value := conv(val); value.IsValid() {
 			if value := conv(val); value.IsValid() {
 				v.Set(value.Convert(t))
 				v.Set(value.Convert(t))
 			} else {
 			} else {
@@ -293,22 +267,16 @@ func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values
 					Index: -1,
 					Index: -1,
 				}
 				}
 			}
 			}
-		} else if m.IsValid {
-			if m.IsPtr {
-				u := reflect.New(v.Type())
-				if err := u.Interface().(encoding.TextUnmarshaler).UnmarshalText([]byte(val)); err != nil {
-					return ConversionError{
-						Key:   path,
-						Type:  t,
-						Index: -1,
-						Err:   err,
-					}
-				}
-				v.Set(reflect.Indirect(u))
-			} else {
-				// If the value implements the encoding.TextUnmarshaler interface
-				// apply UnmarshalText as the converter
-				if err := m.Unmarshaler.UnmarshalText([]byte(val)); err != nil {
+		} else {
+			// When there's no registered conversion for the custom type, we will check if the type
+			// implements the TextUnmarshaler interface. As the UnmarshalText function should be applied
+			// to the pointer of the type, we convert the value to pointer.
+			if v.CanAddr() {
+				v = v.Addr()
+			}
+
+			if u, ok := v.Interface().(encoding.TextUnmarshaler); ok {
+				if err := u.UnmarshalText([]byte(val)); err != nil {
 					return ConversionError{
 					return ConversionError{
 						Key:   path,
 						Key:   path,
 						Type:  t,
 						Type:  t,
@@ -316,87 +284,15 @@ func (d *Decoder) decode(v reflect.Value, path string, parts []pathPart, values
 						Err:   err,
 						Err:   err,
 					}
 					}
 				}
 				}
-			}
-		} else if val == "" {
-			if d.zeroEmpty {
-				v.Set(reflect.Zero(t))
-			}
-		} else if conv := builtinConverters[t.Kind()]; conv != nil {
-			if value := conv(val); value.IsValid() {
-				v.Set(value.Convert(t))
+
 			} else {
 			} else {
-				return ConversionError{
-					Key:   path,
-					Type:  t,
-					Index: -1,
-				}
+				return fmt.Errorf("schema: converter not found for %v", t)
 			}
 			}
-		} else {
-			return fmt.Errorf("schema: converter not found for %v", t)
 		}
 		}
 	}
 	}
 	return nil
 	return nil
 }
 }
 
 
-func isTextUnmarshaler(v reflect.Value) unmarshaler {
-	// Create a new unmarshaller instance
-	m := unmarshaler{}
-	if m.Unmarshaler, m.IsValid = v.Interface().(encoding.TextUnmarshaler); m.IsValid {
-		return m
-	}
-	// As the UnmarshalText function should be applied to the pointer of the
-	// type, we check that type to see if it implements the necessary
-	// method.
-	if m.Unmarshaler, m.IsValid = reflect.New(v.Type()).Interface().(encoding.TextUnmarshaler); m.IsValid {
-		m.IsPtr = true
-		return m
-	}
-
-	// if v is []T or *[]T create new T
-	t := v.Type()
-	if t.Kind() == reflect.Ptr {
-		t = t.Elem()
-	}
-	if t.Kind() == reflect.Slice {
-		// Check if the slice implements encoding.TextUnmarshaller
-		if m.Unmarshaler, m.IsValid = v.Interface().(encoding.TextUnmarshaler); m.IsValid {
-			return m
-		}
-		// If t is a pointer slice, check if its elements implement
-		// encoding.TextUnmarshaler
-		m.IsSliceElement = true
-		if t = t.Elem(); t.Kind() == reflect.Ptr {
-			t = reflect.PtrTo(t.Elem())
-			v = reflect.Zero(t)
-			m.IsSliceElementPtr = true
-			m.Unmarshaler, m.IsValid = v.Interface().(encoding.TextUnmarshaler)
-			return m
-		}
-	}
-
-	v = reflect.New(t)
-	m.Unmarshaler, m.IsValid = v.Interface().(encoding.TextUnmarshaler)
-	return m
-}
-
-// TextUnmarshaler helpers ----------------------------------------------------
-// unmarshaller contains information about a TextUnmarshaler type
-type unmarshaler struct {
-	Unmarshaler encoding.TextUnmarshaler
-	// IsValid indicates whether the resolved type indicated by the other
-	// flags implements the encoding.TextUnmarshaler interface.
-	IsValid bool
-	// IsPtr indicates that the resolved type is the pointer of the original
-	// type.
-	IsPtr bool
-	// IsSliceElement indicates that the resolved type is a slice element of
-	// the original type.
-	IsSliceElement bool
-	// IsSliceElementPtr indicates that the resolved type is a pointer to a
-	// slice element of the original type.
-	IsSliceElementPtr bool
-}
-
 // Errors ---------------------------------------------------------------------
 // Errors ---------------------------------------------------------------------
 
 
 // ConversionError stores information about a failed conversion.
 // ConversionError stores information about a failed conversion.

+ 3 - 3
vendor/github.com/gorilla/schema/doc.go

@@ -24,7 +24,7 @@ The basic usage is really simple. Given this struct:
 
 
 This is just a simple example and it doesn't make a lot of sense to create
 This is just a simple example and it doesn't make a lot of sense to create
 the map manually. Typically it will come from a http.Request object and
 the map manually. Typically it will come from a http.Request object and
-will be of type url.Values, http.Request.Form, or http.Request.MultipartForm:
+will be of type url.Values: http.Request.Form or http.Request.MultipartForm:
 
 
 	func MyHandler(w http.ResponseWriter, r *http.Request) {
 	func MyHandler(w http.ResponseWriter, r *http.Request) {
 		err := r.ParseForm()
 		err := r.ParseForm()
@@ -45,7 +45,7 @@ will be of type url.Values, http.Request.Form, or http.Request.MultipartForm:
 	}
 	}
 
 
 Note: it is a good idea to set a Decoder instance as a package global,
 Note: it is a good idea to set a Decoder instance as a package global,
-because it caches meta-data about structs, and an instance can be shared safely:
+because it caches meta-data about structs, and a instance can be shared safely:
 
 
 	var decoder = schema.NewDecoder()
 	var decoder = schema.NewDecoder()
 
 
@@ -121,7 +121,7 @@ field, we could not translate multiple values to it if we did not use an
 index for the parent struct.
 index for the parent struct.
 
 
 There's also the possibility to create a custom type that implements the
 There's also the possibility to create a custom type that implements the
-TextUnmarshaler interface, and in this case there's no need to register
+TextUnmarshaler interface, and in this case there's no need to registry
 a converter, like:
 a converter, like:
 
 
 	type Person struct {
 	type Person struct {

+ 0 - 195
vendor/github.com/gorilla/schema/encoder.go

@@ -1,195 +0,0 @@
-package schema
-
-import (
-	"errors"
-	"fmt"
-	"reflect"
-	"strconv"
-)
-
-type encoderFunc func(reflect.Value) string
-
-// Encoder encodes values from a struct into url.Values.
-type Encoder struct {
-	cache  *cache
-	regenc map[reflect.Type]encoderFunc
-}
-
-// NewEncoder returns a new Encoder with defaults.
-func NewEncoder() *Encoder {
-	return &Encoder{cache: newCache(), regenc: make(map[reflect.Type]encoderFunc)}
-}
-
-// Encode encodes a struct into map[string][]string.
-//
-// Intended for use with url.Values.
-func (e *Encoder) Encode(src interface{}, dst map[string][]string) error {
-	v := reflect.ValueOf(src)
-
-	return e.encode(v, dst)
-}
-
-// RegisterEncoder registers a converter for encoding a custom type.
-func (e *Encoder) RegisterEncoder(value interface{}, encoder func(reflect.Value) string) {
-	e.regenc[reflect.TypeOf(value)] = encoder
-}
-
-// SetAliasTag changes the tag used to locate custom field aliases.
-// The default tag is "schema".
-func (e *Encoder) SetAliasTag(tag string) {
-	e.cache.tag = tag
-}
-
-// isValidStructPointer test if input value is a valid struct pointer.
-func isValidStructPointer(v reflect.Value) bool {
-	return v.Type().Kind() == reflect.Ptr && v.Elem().IsValid() && v.Elem().Type().Kind() == reflect.Struct
-}
-
-func isZero(v reflect.Value) bool {
-	switch v.Kind() {
-	case reflect.Func:
-	case reflect.Map, reflect.Slice:
-		return v.IsNil() || v.Len() == 0
-	case reflect.Array:
-		z := true
-		for i := 0; i < v.Len(); i++ {
-			z = z && isZero(v.Index(i))
-		}
-		return z
-	case reflect.Struct:
-		z := true
-		for i := 0; i < v.NumField(); i++ {
-			z = z && isZero(v.Field(i))
-		}
-		return z
-	}
-	// Compare other types directly:
-	z := reflect.Zero(v.Type())
-	return v.Interface() == z.Interface()
-}
-
-func (e *Encoder) encode(v reflect.Value, dst map[string][]string) error {
-	if v.Kind() == reflect.Ptr {
-		v = v.Elem()
-	}
-	if v.Kind() != reflect.Struct {
-		return errors.New("schema: interface must be a struct")
-	}
-	t := v.Type()
-
-	errors := MultiError{}
-
-	for i := 0; i < v.NumField(); i++ {
-		name, opts := fieldAlias(t.Field(i), e.cache.tag)
-		if name == "-" {
-			continue
-		}
-
-		// Encode struct pointer types if the field is a valid pointer and a struct.
-		if isValidStructPointer(v.Field(i)) {
-			e.encode(v.Field(i).Elem(), dst)
-			continue
-		}
-
-		encFunc := typeEncoder(v.Field(i).Type(), e.regenc)
-
-		// Encode non-slice types and custom implementations immediately.
-		if encFunc != nil {
-			value := encFunc(v.Field(i))
-			if opts.Contains("omitempty") && isZero(v.Field(i)) {
-				continue
-			}
-
-			dst[name] = append(dst[name], value)
-			continue
-		}
-
-		if v.Field(i).Type().Kind() == reflect.Struct {
-			e.encode(v.Field(i), dst)
-			continue
-		}
-
-		if v.Field(i).Type().Kind() == reflect.Slice {
-			encFunc = typeEncoder(v.Field(i).Type().Elem(), e.regenc)
-		}
-
-		if encFunc == nil {
-			errors[v.Field(i).Type().String()] = fmt.Errorf("schema: encoder not found for %v", v.Field(i))
-			continue
-		}
-
-		// Encode a slice.
-		if v.Field(i).Len() == 0 && opts.Contains("omitempty") {
-			continue
-		}
-
-		dst[name] = []string{}
-		for j := 0; j < v.Field(i).Len(); j++ {
-			dst[name] = append(dst[name], encFunc(v.Field(i).Index(j)))
-		}
-	}
-
-	if len(errors) > 0 {
-		return errors
-	}
-	return nil
-}
-
-func typeEncoder(t reflect.Type, reg map[reflect.Type]encoderFunc) encoderFunc {
-	if f, ok := reg[t]; ok {
-		return f
-	}
-
-	switch t.Kind() {
-	case reflect.Bool:
-		return encodeBool
-	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
-		return encodeInt
-	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
-		return encodeUint
-	case reflect.Float32:
-		return encodeFloat32
-	case reflect.Float64:
-		return encodeFloat64
-	case reflect.Ptr:
-		f := typeEncoder(t.Elem(), reg)
-		return func(v reflect.Value) string {
-			if v.IsNil() {
-				return "null"
-			}
-			return f(v.Elem())
-		}
-	case reflect.String:
-		return encodeString
-	default:
-		return nil
-	}
-}
-
-func encodeBool(v reflect.Value) string {
-	return strconv.FormatBool(v.Bool())
-}
-
-func encodeInt(v reflect.Value) string {
-	return strconv.FormatInt(int64(v.Int()), 10)
-}
-
-func encodeUint(v reflect.Value) string {
-	return strconv.FormatUint(uint64(v.Uint()), 10)
-}
-
-func encodeFloat(v reflect.Value, bits int) string {
-	return strconv.FormatFloat(v.Float(), 'f', 6, bits)
-}
-
-func encodeFloat32(v reflect.Value) string {
-	return encodeFloat(v, 32)
-}
-
-func encodeFloat64(v reflect.Value) string {
-	return encodeFloat(v, 64)
-}
-
-func encodeString(v reflect.Value) string {
-	return v.String()
-}

+ 0 - 2
vendor/github.com/gorilla/securecookie/README.md

@@ -1,8 +1,6 @@
 securecookie
 securecookie
 ============
 ============
 [![GoDoc](https://godoc.org/github.com/gorilla/securecookie?status.svg)](https://godoc.org/github.com/gorilla/securecookie) [![Build Status](https://travis-ci.org/gorilla/securecookie.png?branch=master)](https://travis-ci.org/gorilla/securecookie)
 [![GoDoc](https://godoc.org/github.com/gorilla/securecookie?status.svg)](https://godoc.org/github.com/gorilla/securecookie) [![Build Status](https://travis-ci.org/gorilla/securecookie.png?branch=master)](https://travis-ci.org/gorilla/securecookie)
-[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/securecookie/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/securecookie?badge)
-
 
 
 securecookie encodes and decodes authenticated and optionally encrypted 
 securecookie encodes and decodes authenticated and optionally encrypted 
 cookie values.
 cookie values.

+ 3 - 14
vendor/github.com/gorilla/sessions/README.md

@@ -1,8 +1,6 @@
 sessions
 sessions
 ========
 ========
 [![GoDoc](https://godoc.org/github.com/gorilla/sessions?status.svg)](https://godoc.org/github.com/gorilla/sessions) [![Build Status](https://travis-ci.org/gorilla/sessions.png?branch=master)](https://travis-ci.org/gorilla/sessions)
 [![GoDoc](https://godoc.org/github.com/gorilla/sessions?status.svg)](https://godoc.org/github.com/gorilla/sessions) [![Build Status](https://travis-ci.org/gorilla/sessions.png?branch=master)](https://travis-ci.org/gorilla/sessions)
-[![Sourcegraph](https://sourcegraph.com/github.com/gorilla/sessions/-/badge.svg)](https://sourcegraph.com/github.com/gorilla/sessions?badge)
-
 
 
 gorilla/sessions provides cookie and filesystem sessions and infrastructure for
 gorilla/sessions provides cookie and filesystem sessions and infrastructure for
 custom session backends.
 custom session backends.
@@ -44,22 +42,16 @@ Let's start with an example that shows the sessions API in a nutshell:
 
 
 First we initialize a session store calling `NewCookieStore()` and passing a
 First we initialize a session store calling `NewCookieStore()` and passing a
 secret key used to authenticate the session. Inside the handler, we call
 secret key used to authenticate the session. Inside the handler, we call
-`store.Get()` to retrieve an existing session or create a new one. Then we set
-some session values in session.Values, which is a `map[interface{}]interface{}`.
+`store.Get()` to retrieve an existing session or a new one. Then we set some
+session values in session.Values, which is a `map[interface{}]interface{}`.
 And finally we call `session.Save()` to save the session in the response.
 And finally we call `session.Save()` to save the session in the response.
 
 
 Important Note: If you aren't using gorilla/mux, you need to wrap your handlers
 Important Note: If you aren't using gorilla/mux, you need to wrap your handlers
 with
 with
 [`context.ClearHandler`](http://www.gorillatoolkit.org/pkg/context#ClearHandler)
 [`context.ClearHandler`](http://www.gorillatoolkit.org/pkg/context#ClearHandler)
-or else you will leak memory! An easy way to do this is to wrap the top-level
+as or else you will leak memory! An easy way to do this is to wrap the top-level
 mux when calling http.ListenAndServe:
 mux when calling http.ListenAndServe:
 
 
-```go
-	http.ListenAndServe(":8080", context.ClearHandler(http.DefaultServeMux))
-```
-
-The ClearHandler function is provided by the gorilla/context package.
-
 More examples are available [on the Gorilla
 More examples are available [on the Gorilla
 website](http://www.gorillatoolkit.org/pkg/sessions).
 website](http://www.gorillatoolkit.org/pkg/sessions).
 
 
@@ -71,19 +63,16 @@ Other implementations of the `sessions.Store` interface:
 * [github.com/yosssi/boltstore](https://github.com/yosssi/boltstore) - Bolt
 * [github.com/yosssi/boltstore](https://github.com/yosssi/boltstore) - Bolt
 * [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase
 * [github.com/srinathgs/couchbasestore](https://github.com/srinathgs/couchbasestore) - Couchbase
 * [github.com/denizeren/dynamostore](https://github.com/denizeren/dynamostore) - Dynamodb on AWS
 * [github.com/denizeren/dynamostore](https://github.com/denizeren/dynamostore) - Dynamodb on AWS
-* [github.com/savaki/dynastore](https://github.com/savaki/dynastore) - DynamoDB on AWS (Official AWS library)
 * [github.com/bradleypeabody/gorilla-sessions-memcache](https://github.com/bradleypeabody/gorilla-sessions-memcache) - Memcache
 * [github.com/bradleypeabody/gorilla-sessions-memcache](https://github.com/bradleypeabody/gorilla-sessions-memcache) - Memcache
 * [github.com/dsoprea/go-appengine-sessioncascade](https://github.com/dsoprea/go-appengine-sessioncascade) - Memcache/Datastore/Context in AppEngine
 * [github.com/dsoprea/go-appengine-sessioncascade](https://github.com/dsoprea/go-appengine-sessioncascade) - Memcache/Datastore/Context in AppEngine
 * [github.com/kidstuff/mongostore](https://github.com/kidstuff/mongostore) - MongoDB
 * [github.com/kidstuff/mongostore](https://github.com/kidstuff/mongostore) - MongoDB
 * [github.com/srinathgs/mysqlstore](https://github.com/srinathgs/mysqlstore) - MySQL
 * [github.com/srinathgs/mysqlstore](https://github.com/srinathgs/mysqlstore) - MySQL
-* [github.com/EnumApps/clustersqlstore](https://github.com/EnumApps/clustersqlstore) - MySQL Cluster
 * [github.com/antonlindstrom/pgstore](https://github.com/antonlindstrom/pgstore) - PostgreSQL
 * [github.com/antonlindstrom/pgstore](https://github.com/antonlindstrom/pgstore) - PostgreSQL
 * [github.com/boj/redistore](https://github.com/boj/redistore) - Redis
 * [github.com/boj/redistore](https://github.com/boj/redistore) - Redis
 * [github.com/boj/rethinkstore](https://github.com/boj/rethinkstore) - RethinkDB
 * [github.com/boj/rethinkstore](https://github.com/boj/rethinkstore) - RethinkDB
 * [github.com/boj/riakstore](https://github.com/boj/riakstore) - Riak
 * [github.com/boj/riakstore](https://github.com/boj/riakstore) - Riak
 * [github.com/michaeljs1990/sqlitestore](https://github.com/michaeljs1990/sqlitestore) - SQLite
 * [github.com/michaeljs1990/sqlitestore](https://github.com/michaeljs1990/sqlitestore) - SQLite
 * [github.com/wader/gormstore](https://github.com/wader/gormstore) - GORM (MySQL, PostgreSQL, SQLite)
 * [github.com/wader/gormstore](https://github.com/wader/gormstore) - GORM (MySQL, PostgreSQL, SQLite)
-* [github.com/gernest/qlstore](https://github.com/gernest/qlstore) - ql
 
 
 ## License
 ## License
 
 

+ 2 - 1
vendor/github.com/gorilla/sessions/doc.go

@@ -29,7 +29,8 @@ Let's start with an example that shows the sessions API in a nutshell:
 	var store = sessions.NewCookieStore([]byte("something-very-secret"))
 	var store = sessions.NewCookieStore([]byte("something-very-secret"))
 
 
 	func MyHandler(w http.ResponseWriter, r *http.Request) {
 	func MyHandler(w http.ResponseWriter, r *http.Request) {
-		// Get a session. Get() always returns a session, even if empty.
+		// Get a session. We're ignoring the error resulted from decoding an
+		// existing session: Get() always returns a session, even if empty.
 		session, err := store.Get(r, "session-name")
 		session, err := store.Get(r, "session-name")
 		if err != nil {
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			http.Error(w, err.Error(), http.StatusInternalServerError)

+ 13 - 23
vendor/github.com/jinzhu/gorm/README.md

@@ -2,15 +2,19 @@
 
 
 The fantastic ORM library for Golang, aims to be developer friendly.
 The fantastic ORM library for Golang, aims to be developer friendly.
 
 
-[![Join the chat at https://gitter.im/jinzhu/gorm](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jinzhu/gorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
-[![wercker status](https://app.wercker.com/status/0cb7bb1039e21b74f8274941428e0921/s/master "wercker status")](https://app.wercker.com/project/bykey/0cb7bb1039e21b74f8274941428e0921)
+[![go report card](https://goreportcard.com/badge/github.com/jinzhu/gorm "go report card")](https://goreportcard.com/report/github.com/jinzhu/gorm)
+[![wercker status](https://app.wercker.com/status/8596cace912c9947dd9c8542ecc8cb8b/s/master "wercker status")](https://app.wercker.com/project/byKey/8596cace912c9947dd9c8542ecc8cb8b)
+[![Join the chat at https://gitter.im/jinzhu/gorm](https://img.shields.io/gitter/room/jinzhu/gorm.svg)](https://gitter.im/jinzhu/gorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
+[![Open Collective Backer](https://opencollective.com/gorm/tiers/backer/badge.svg?label=backer&color=brightgreen "Open Collective Backer")](https://opencollective.com/gorm)
+[![Open Collective Sponsor](https://opencollective.com/gorm/tiers/sponsor/badge.svg?label=sponsor&color=brightgreen "Open Collective Sponsor")](https://opencollective.com/gorm)
+[![MIT license](http://img.shields.io/badge/license-MIT-brightgreen.svg)](http://opensource.org/licenses/MIT)
 [![GoDoc](https://godoc.org/github.com/jinzhu/gorm?status.svg)](https://godoc.org/github.com/jinzhu/gorm)
 [![GoDoc](https://godoc.org/github.com/jinzhu/gorm?status.svg)](https://godoc.org/github.com/jinzhu/gorm)
 
 
 ## Overview
 ## Overview
 
 
 * Full-Featured ORM (almost)
 * Full-Featured ORM (almost)
 * Associations (Has One, Has Many, Belongs To, Many To Many, Polymorphism)
 * Associations (Has One, Has Many, Belongs To, Many To Many, Polymorphism)
-* Callbacks (Before/After Create/Save/Update/Delete/Find)
+* Hooks (Before/After Create/Save/Update/Delete/Find)
 * Preloading (eager loading)
 * Preloading (eager loading)
 * Transactions
 * Transactions
 * Composite Primary Key
 * Composite Primary Key
@@ -23,28 +27,14 @@ The fantastic ORM library for Golang, aims to be developer friendly.
 
 
 ## Getting Started
 ## Getting Started
 
 
-* GORM Guides [jinzhu.github.com/gorm](http://jinzhu.github.io/gorm)
+* GORM Guides [http://gorm.io](http://gorm.io)
 
 
-## Upgrading To V1.0
+## Contributing
 
 
-* [CHANGELOG](http://jinzhu.github.io/gorm/changelog.html)
-
-## Supporting the project
-
-[![http://patreon.com/jinzhu](http://patreon_public_assets.s3.amazonaws.com/sized/becomeAPatronBanner.png)](http://patreon.com/jinzhu)
-
-## Author
-
-**jinzhu**
-
-* <http://github.com/jinzhu>
-* <wosmvp@gmail.com>
-* <http://twitter.com/zhangjinzhu>
-
-## Contributors
-
-https://github.com/jinzhu/gorm/graphs/contributors
+[You can help to deliver a better GORM, check out things you can do](http://gorm.io/contribute.html)
 
 
 ## License
 ## License
 
 
-Released under the [MIT License](https://github.com/jinzhu/gorm/blob/master/License).
+© Jinzhu, 2013~time.Now
+
+Released under the [MIT License](https://github.com/jinzhu/gorm/blob/master/License)

+ 2 - 2
vendor/github.com/jinzhu/gorm/association.go

@@ -107,7 +107,7 @@ func (association *Association) Replace(values ...interface{}) *Association {
 			if sourcePrimaryKeys := scope.getColumnAsArray(sourceForeignFieldNames, scope.Value); len(sourcePrimaryKeys) > 0 {
 			if sourcePrimaryKeys := scope.getColumnAsArray(sourceForeignFieldNames, scope.Value); len(sourcePrimaryKeys) > 0 {
 				newDB = newDB.Where(fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.ForeignDBNames), toQueryMarks(sourcePrimaryKeys)), toQueryValues(sourcePrimaryKeys)...)
 				newDB = newDB.Where(fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.ForeignDBNames), toQueryMarks(sourcePrimaryKeys)), toQueryValues(sourcePrimaryKeys)...)
 
 
-				association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB, relationship))
+				association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB))
 			}
 			}
 		} else if relationship.Kind == "has_one" || relationship.Kind == "has_many" {
 		} else if relationship.Kind == "has_one" || relationship.Kind == "has_many" {
 			// has_one or has_many relations, set foreign key to be nil (TODO or delete them?)
 			// has_one or has_many relations, set foreign key to be nil (TODO or delete them?)
@@ -173,7 +173,7 @@ func (association *Association) Delete(values ...interface{}) *Association {
 		sql := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.AssociationForeignDBNames), toQueryMarks(deletingPrimaryKeys))
 		sql := fmt.Sprintf("%v IN (%v)", toQueryCondition(scope, relationship.AssociationForeignDBNames), toQueryMarks(deletingPrimaryKeys))
 		newDB = newDB.Where(sql, toQueryValues(deletingPrimaryKeys)...)
 		newDB = newDB.Where(sql, toQueryValues(deletingPrimaryKeys)...)
 
 
-		association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB, relationship))
+		association.setErr(relationship.JoinTableHandler.Delete(relationship.JoinTableHandler, newDB))
 	} else {
 	} else {
 		var foreignKeyMap = map[string]interface{}{}
 		var foreignKeyMap = map[string]interface{}{}
 		for _, foreignKey := range relationship.ForeignDBNames {
 		for _, foreignKey := range relationship.ForeignDBNames {

+ 5 - 7
vendor/github.com/jinzhu/gorm/callback.go

@@ -1,8 +1,6 @@
 package gorm
 package gorm
 
 
-import (
-	"fmt"
-)
+import "log"
 
 
 // DefaultCallback default callbacks defined by gorm
 // DefaultCallback default callbacks defined by gorm
 var DefaultCallback = &Callback{}
 var DefaultCallback = &Callback{}
@@ -95,7 +93,7 @@ func (cp *CallbackProcessor) Before(callbackName string) *CallbackProcessor {
 func (cp *CallbackProcessor) Register(callbackName string, callback func(scope *Scope)) {
 func (cp *CallbackProcessor) Register(callbackName string, callback func(scope *Scope)) {
 	if cp.kind == "row_query" {
 	if cp.kind == "row_query" {
 		if cp.before == "" && cp.after == "" && callbackName != "gorm:row_query" {
 		if cp.before == "" && cp.after == "" && callbackName != "gorm:row_query" {
-			fmt.Printf("Registing RowQuery callback %v without specify order with Before(), After(), applying Before('gorm:row_query') by default for compatibility...\n", callbackName)
+			log.Printf("Registing RowQuery callback %v without specify order with Before(), After(), applying Before('gorm:row_query') by default for compatibility...\n", callbackName)
 			cp.before = "gorm:row_query"
 			cp.before = "gorm:row_query"
 		}
 		}
 	}
 	}
@@ -109,7 +107,7 @@ func (cp *CallbackProcessor) Register(callbackName string, callback func(scope *
 // Remove a registered callback
 // Remove a registered callback
 //     db.Callback().Create().Remove("gorm:update_time_stamp_when_create")
 //     db.Callback().Create().Remove("gorm:update_time_stamp_when_create")
 func (cp *CallbackProcessor) Remove(callbackName string) {
 func (cp *CallbackProcessor) Remove(callbackName string) {
-	fmt.Printf("[info] removing callback `%v` from %v\n", callbackName, fileWithLineNum())
+	log.Printf("[info] removing callback `%v` from %v\n", callbackName, fileWithLineNum())
 	cp.name = callbackName
 	cp.name = callbackName
 	cp.remove = true
 	cp.remove = true
 	cp.parent.processors = append(cp.parent.processors, cp)
 	cp.parent.processors = append(cp.parent.processors, cp)
@@ -122,7 +120,7 @@ func (cp *CallbackProcessor) Remove(callbackName string) {
 //		   scope.SetColumn("Updated", now)
 //		   scope.SetColumn("Updated", now)
 //     })
 //     })
 func (cp *CallbackProcessor) Replace(callbackName string, callback func(scope *Scope)) {
 func (cp *CallbackProcessor) Replace(callbackName string, callback func(scope *Scope)) {
-	fmt.Printf("[info] replacing callback `%v` from %v\n", callbackName, fileWithLineNum())
+	log.Printf("[info] replacing callback `%v` from %v\n", callbackName, fileWithLineNum())
 	cp.name = callbackName
 	cp.name = callbackName
 	cp.processor = &callback
 	cp.processor = &callback
 	cp.replace = true
 	cp.replace = true
@@ -161,7 +159,7 @@ func sortProcessors(cps []*CallbackProcessor) []*func(scope *Scope) {
 	for _, cp := range cps {
 	for _, cp := range cps {
 		// show warning message the callback name already exists
 		// show warning message the callback name already exists
 		if index := getRIndex(allNames, cp.name); index > -1 && !cp.replace && !cp.remove {
 		if index := getRIndex(allNames, cp.name); index > -1 && !cp.replace && !cp.remove {
-			fmt.Printf("[warning] duplicated callback `%v` from %v\n", cp.name, fileWithLineNum())
+			log.Printf("[warning] duplicated callback `%v` from %v\n", cp.name, fileWithLineNum())
 		}
 		}
 		allNames = append(allNames, cp.name)
 		allNames = append(allNames, cp.name)
 	}
 	}

+ 2 - 1
vendor/github.com/jinzhu/gorm/callback_create.go

@@ -97,8 +97,9 @@ func createCallback(scope *Scope) {
 
 
 		if len(columns) == 0 {
 		if len(columns) == 0 {
 			scope.Raw(fmt.Sprintf(
 			scope.Raw(fmt.Sprintf(
-				"INSERT INTO %v DEFAULT VALUES%v%v",
+				"INSERT INTO %v %v%v%v",
 				quotedTableName,
 				quotedTableName,
+				scope.Dialect().DefaultValueStr(),
 				addExtraSpaceIfExist(extraOption),
 				addExtraSpaceIfExist(extraOption),
 				addExtraSpaceIfExist(lastInsertIDReturningSuffix),
 				addExtraSpaceIfExist(lastInsertIDReturningSuffix),
 			))
 			))

+ 4 - 0
vendor/github.com/jinzhu/gorm/callback_query.go

@@ -15,6 +15,10 @@ func init() {
 
 
 // queryCallback used to query data from database
 // queryCallback used to query data from database
 func queryCallback(scope *Scope) {
 func queryCallback(scope *Scope) {
+	if _, skip := scope.InstanceGet("gorm:skip_query_callback"); skip {
+		return
+	}
+
 	defer scope.trace(NowFunc())
 	defer scope.trace(NowFunc())
 
 
 	var (
 	var (

+ 7 - 0
vendor/github.com/jinzhu/gorm/callback_query_preload.go

@@ -10,6 +10,9 @@ import (
 
 
 // preloadCallback used to preload associations
 // preloadCallback used to preload associations
 func preloadCallback(scope *Scope) {
 func preloadCallback(scope *Scope) {
+	if _, skip := scope.InstanceGet("gorm:skip_query_callback"); skip {
+		return
+	}
 
 
 	if _, ok := scope.Get("gorm:auto_preload"); ok {
 	if _, ok := scope.Get("gorm:auto_preload"); ok {
 		autoPreload(scope)
 		autoPreload(scope)
@@ -324,6 +327,10 @@ func (scope *Scope) handleManyToManyPreload(field *Field, conditions []interface
 
 
 		scope.scan(rows, columns, append(fields, joinTableFields...))
 		scope.scan(rows, columns, append(fields, joinTableFields...))
 
 
+		scope.New(elem.Addr().Interface()).
+			InstanceSet("gorm:skip_query_callback", true).
+			callCallbacks(scope.db.parent.callbacks.queries)
+
 		var foreignKeys = make([]interface{}, len(sourceKeys))
 		var foreignKeys = make([]interface{}, len(sourceKeys))
 		// generate hashed forkey keys in join table
 		// generate hashed forkey keys in join table
 		for idx, joinTableField := range joinTableFields {
 		for idx, joinTableField := range joinTableFields {

+ 112 - 41
vendor/github.com/jinzhu/gorm/callback_save.go

@@ -1,6 +1,9 @@
 package gorm
 package gorm
 
 
-import "reflect"
+import (
+	"reflect"
+	"strings"
+)
 
 
 func beginTransactionCallback(scope *Scope) {
 func beginTransactionCallback(scope *Scope) {
 	scope.Begin()
 	scope.Begin()
@@ -10,31 +13,81 @@ func commitOrRollbackTransactionCallback(scope *Scope) {
 	scope.CommitOrRollback()
 	scope.CommitOrRollback()
 }
 }
 
 
-func saveFieldAsAssociation(scope *Scope, field *Field) (bool, *Relationship) {
+func saveAssociationCheck(scope *Scope, field *Field) (autoUpdate bool, autoCreate bool, saveReference bool, r *Relationship) {
+	checkTruth := func(value interface{}) bool {
+		if v, ok := value.(bool); ok && !v {
+			return false
+		}
+
+		if v, ok := value.(string); ok {
+			v = strings.ToLower(v)
+			if v == "false" || v != "skip" {
+				return false
+			}
+		}
+
+		return true
+	}
+
 	if scope.changeableField(field) && !field.IsBlank && !field.IsIgnored {
 	if scope.changeableField(field) && !field.IsBlank && !field.IsIgnored {
-		if value, ok := field.TagSettings["SAVE_ASSOCIATIONS"]; !ok || (value != "false" && value != "skip") {
-			if relationship := field.Relationship; relationship != nil {
-				return true, relationship
+		if r = field.Relationship; r != nil {
+			autoUpdate, autoCreate, saveReference = true, true, true
+
+			if value, ok := scope.Get("gorm:save_associations"); ok {
+				autoUpdate = checkTruth(value)
+				autoCreate = autoUpdate
+			} else if value, ok := field.TagSettings["SAVE_ASSOCIATIONS"]; ok {
+				autoUpdate = checkTruth(value)
+				autoCreate = autoUpdate
+			}
+
+			if value, ok := scope.Get("gorm:association_autoupdate"); ok {
+				autoUpdate = checkTruth(value)
+			} else if value, ok := field.TagSettings["ASSOCIATION_AUTOUPDATE"]; ok {
+				autoUpdate = checkTruth(value)
+			}
+
+			if value, ok := scope.Get("gorm:association_autocreate"); ok {
+				autoCreate = checkTruth(value)
+			} else if value, ok := field.TagSettings["ASSOCIATION_AUTOCREATE"]; ok {
+				autoCreate = checkTruth(value)
+			}
+
+			if value, ok := scope.Get("gorm:association_save_reference"); ok {
+				saveReference = checkTruth(value)
+			} else if value, ok := field.TagSettings["ASSOCIATION_SAVE_REFERENCE"]; ok {
+				saveReference = checkTruth(value)
 			}
 			}
 		}
 		}
 	}
 	}
-	return false, nil
+
+	return
 }
 }
 
 
 func saveBeforeAssociationsCallback(scope *Scope) {
 func saveBeforeAssociationsCallback(scope *Scope) {
-	if !scope.shouldSaveAssociations() {
-		return
-	}
 	for _, field := range scope.Fields() {
 	for _, field := range scope.Fields() {
-		if ok, relationship := saveFieldAsAssociation(scope, field); ok && relationship.Kind == "belongs_to" {
+		autoUpdate, autoCreate, saveReference, relationship := saveAssociationCheck(scope, field)
+
+		if relationship != nil && relationship.Kind == "belongs_to" {
 			fieldValue := field.Field.Addr().Interface()
 			fieldValue := field.Field.Addr().Interface()
-			scope.Err(scope.NewDB().Save(fieldValue).Error)
-			if len(relationship.ForeignFieldNames) != 0 {
-				// set value's foreign key
-				for idx, fieldName := range relationship.ForeignFieldNames {
-					associationForeignName := relationship.AssociationForeignDBNames[idx]
-					if foreignField, ok := scope.New(fieldValue).FieldByName(associationForeignName); ok {
-						scope.Err(scope.SetColumn(fieldName, foreignField.Field.Interface()))
+			newScope := scope.New(fieldValue)
+
+			if newScope.PrimaryKeyZero() {
+				if autoCreate {
+					scope.Err(scope.NewDB().Save(fieldValue).Error)
+				}
+			} else if autoUpdate {
+				scope.Err(scope.NewDB().Save(fieldValue).Error)
+			}
+
+			if saveReference {
+				if len(relationship.ForeignFieldNames) != 0 {
+					// set value's foreign key
+					for idx, fieldName := range relationship.ForeignFieldNames {
+						associationForeignName := relationship.AssociationForeignDBNames[idx]
+						if foreignField, ok := scope.New(fieldValue).FieldByName(associationForeignName); ok {
+							scope.Err(scope.SetColumn(fieldName, foreignField.Field.Interface()))
+						}
 					}
 					}
 				}
 				}
 			}
 			}
@@ -43,12 +96,10 @@ func saveBeforeAssociationsCallback(scope *Scope) {
 }
 }
 
 
 func saveAfterAssociationsCallback(scope *Scope) {
 func saveAfterAssociationsCallback(scope *Scope) {
-	if !scope.shouldSaveAssociations() {
-		return
-	}
 	for _, field := range scope.Fields() {
 	for _, field := range scope.Fields() {
-		if ok, relationship := saveFieldAsAssociation(scope, field); ok &&
-			(relationship.Kind == "has_one" || relationship.Kind == "has_many" || relationship.Kind == "many_to_many") {
+		autoUpdate, autoCreate, saveReference, relationship := saveAssociationCheck(scope, field)
+
+		if relationship != nil && (relationship.Kind == "has_one" || relationship.Kind == "has_many" || relationship.Kind == "many_to_many") {
 			value := field.Field
 			value := field.Field
 
 
 			switch value.Kind() {
 			switch value.Kind() {
@@ -58,41 +109,61 @@ func saveAfterAssociationsCallback(scope *Scope) {
 					elem := value.Index(i).Addr().Interface()
 					elem := value.Index(i).Addr().Interface()
 					newScope := newDB.NewScope(elem)
 					newScope := newDB.NewScope(elem)
 
 
-					if relationship.JoinTableHandler == nil && len(relationship.ForeignFieldNames) != 0 {
-						for idx, fieldName := range relationship.ForeignFieldNames {
-							associationForeignName := relationship.AssociationForeignDBNames[idx]
-							if f, ok := scope.FieldByName(associationForeignName); ok {
-								scope.Err(newScope.SetColumn(fieldName, f.Field.Interface()))
+					if saveReference {
+						if relationship.JoinTableHandler == nil && len(relationship.ForeignFieldNames) != 0 {
+							for idx, fieldName := range relationship.ForeignFieldNames {
+								associationForeignName := relationship.AssociationForeignDBNames[idx]
+								if f, ok := scope.FieldByName(associationForeignName); ok {
+									scope.Err(newScope.SetColumn(fieldName, f.Field.Interface()))
+								}
 							}
 							}
 						}
 						}
-					}
 
 
-					if relationship.PolymorphicType != "" {
-						scope.Err(newScope.SetColumn(relationship.PolymorphicType, relationship.PolymorphicValue))
+						if relationship.PolymorphicType != "" {
+							scope.Err(newScope.SetColumn(relationship.PolymorphicType, relationship.PolymorphicValue))
+						}
 					}
 					}
 
 
-					scope.Err(newDB.Save(elem).Error)
+					if newScope.PrimaryKeyZero() {
+						if autoCreate {
+							scope.Err(newDB.Save(elem).Error)
+						}
+					} else if autoUpdate {
+						scope.Err(newDB.Save(elem).Error)
+					}
 
 
-					if joinTableHandler := relationship.JoinTableHandler; joinTableHandler != nil {
-						scope.Err(joinTableHandler.Add(joinTableHandler, newDB, scope.Value, newScope.Value))
+					if !scope.New(newScope.Value).PrimaryKeyZero() && saveReference {
+						if joinTableHandler := relationship.JoinTableHandler; joinTableHandler != nil {
+							scope.Err(joinTableHandler.Add(joinTableHandler, newDB, scope.Value, newScope.Value))
+						}
 					}
 					}
 				}
 				}
 			default:
 			default:
 				elem := value.Addr().Interface()
 				elem := value.Addr().Interface()
 				newScope := scope.New(elem)
 				newScope := scope.New(elem)
-				if len(relationship.ForeignFieldNames) != 0 {
-					for idx, fieldName := range relationship.ForeignFieldNames {
-						associationForeignName := relationship.AssociationForeignDBNames[idx]
-						if f, ok := scope.FieldByName(associationForeignName); ok {
-							scope.Err(newScope.SetColumn(fieldName, f.Field.Interface()))
+
+				if saveReference {
+					if len(relationship.ForeignFieldNames) != 0 {
+						for idx, fieldName := range relationship.ForeignFieldNames {
+							associationForeignName := relationship.AssociationForeignDBNames[idx]
+							if f, ok := scope.FieldByName(associationForeignName); ok {
+								scope.Err(newScope.SetColumn(fieldName, f.Field.Interface()))
+							}
 						}
 						}
 					}
 					}
+
+					if relationship.PolymorphicType != "" {
+						scope.Err(newScope.SetColumn(relationship.PolymorphicType, relationship.PolymorphicValue))
+					}
 				}
 				}
 
 
-				if relationship.PolymorphicType != "" {
-					scope.Err(newScope.SetColumn(relationship.PolymorphicType, relationship.PolymorphicValue))
+				if newScope.PrimaryKeyZero() {
+					if autoCreate {
+						scope.Err(scope.NewDB().Save(elem).Error)
+					}
+				} else if autoUpdate {
+					scope.Err(scope.NewDB().Save(elem).Error)
 				}
 				}
-				scope.Err(scope.NewDB().Save(elem).Error)
 			}
 			}
 		}
 		}
 	}
 	}

+ 11 - 1
vendor/github.com/jinzhu/gorm/callback_update.go

@@ -3,6 +3,7 @@ package gorm
 import (
 import (
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"sort"
 	"strings"
 	"strings"
 )
 )
 
 
@@ -59,7 +60,16 @@ func updateCallback(scope *Scope) {
 		var sqls []string
 		var sqls []string
 
 
 		if updateAttrs, ok := scope.InstanceGet("gorm:update_attrs"); ok {
 		if updateAttrs, ok := scope.InstanceGet("gorm:update_attrs"); ok {
-			for column, value := range updateAttrs.(map[string]interface{}) {
+			// Sort the column names so that the generated SQL is the same every time.
+			updateMap := updateAttrs.(map[string]interface{})
+			var columns []string
+			for c := range updateMap {
+				columns = append(columns, c)
+			}
+			sort.Strings(columns)
+
+			for _, column := range columns {
+				value := updateMap[column]
 				sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(column), scope.AddToVars(value)))
 				sqls = append(sqls, fmt.Sprintf("%v = %v", scope.Quote(column), scope.AddToVars(value)))
 			}
 			}
 		} else {
 		} else {

+ 22 - 8
vendor/github.com/jinzhu/gorm/dialect.go

@@ -33,6 +33,8 @@ type Dialect interface {
 	HasTable(tableName string) bool
 	HasTable(tableName string) bool
 	// HasColumn check has column or not
 	// HasColumn check has column or not
 	HasColumn(tableName string, columnName string) bool
 	HasColumn(tableName string, columnName string) bool
+	// ModifyColumn modify column's type
+	ModifyColumn(tableName string, columnName string, typ string) error
 
 
 	// LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
 	// LimitAndOffsetSQL return generated SQL with Limit and Offset, as mssql has special case
 	LimitAndOffsetSQL(limit, offset interface{}) string
 	LimitAndOffsetSQL(limit, offset interface{}) string
@@ -40,9 +42,11 @@ type Dialect interface {
 	SelectFromDummyTable() string
 	SelectFromDummyTable() string
 	// LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
 	// LastInsertIdReturningSuffix most dbs support LastInsertId, but postgres needs to use `RETURNING`
 	LastInsertIDReturningSuffix(tableName, columnName string) string
 	LastInsertIDReturningSuffix(tableName, columnName string) string
+	// DefaultValueStr
+	DefaultValueStr() string
 
 
-	// BuildForeignKeyName returns a foreign key name for the given table, field and reference
-	BuildForeignKeyName(tableName, field, dest string) string
+	// BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference
+	BuildKeyName(kind, tableName string, fields ...string) string
 
 
 	// CurrentDatabase return current database name
 	// CurrentDatabase return current database name
 	CurrentDatabase() string
 	CurrentDatabase() string
@@ -90,14 +94,16 @@ var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fiel
 	}
 	}
 
 
 	// Get scanner's real value
 	// Get scanner's real value
-	var getScannerValue func(reflect.Value)
-	getScannerValue = func(value reflect.Value) {
-		fieldValue = value
-		if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
-			getScannerValue(fieldValue.Field(0))
+	if dataType == "" {
+		var getScannerValue func(reflect.Value)
+		getScannerValue = func(value reflect.Value) {
+			fieldValue = value
+			if _, isScanner := reflect.New(fieldValue.Type()).Interface().(sql.Scanner); isScanner && fieldValue.Kind() == reflect.Struct {
+				getScannerValue(fieldValue.Field(0))
+			}
 		}
 		}
+		getScannerValue(fieldValue)
 	}
 	}
-	getScannerValue(fieldValue)
 
 
 	// Default Size
 	// Default Size
 	if num, ok := field.TagSettings["SIZE"]; ok {
 	if num, ok := field.TagSettings["SIZE"]; ok {
@@ -114,3 +120,11 @@ var ParseFieldStructForDialect = func(field *StructField, dialect Dialect) (fiel
 
 
 	return fieldValue, dataType, size, strings.TrimSpace(additionalType)
 	return fieldValue, dataType, size, strings.TrimSpace(additionalType)
 }
 }
+
+func currentDatabaseAndTable(dialect Dialect, tableName string) (string, string) {
+	if strings.Contains(tableName, ".") {
+		splitStrings := strings.SplitN(tableName, ".", 2)
+		return splitStrings[0], splitStrings[1]
+	}
+	return dialect.CurrentDatabase(), tableName
+}

+ 28 - 8
vendor/github.com/jinzhu/gorm/dialect_common.go

@@ -38,6 +38,13 @@ func (commonDialect) Quote(key string) string {
 	return fmt.Sprintf(`"%s"`, key)
 	return fmt.Sprintf(`"%s"`, key)
 }
 }
 
 
+func (s *commonDialect) fieldCanAutoIncrement(field *StructField) bool {
+	if value, ok := field.TagSettings["AUTO_INCREMENT"]; ok {
+		return strings.ToLower(value) != "false"
+	}
+	return field.IsPrimaryKey
+}
+
 func (s *commonDialect) DataTypeOf(field *StructField) string {
 func (s *commonDialect) DataTypeOf(field *StructField) string {
 	var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s)
 	var dataValue, sqlType, size, additionalType = ParseFieldStructForDialect(field, s)
 
 
@@ -46,13 +53,13 @@ func (s *commonDialect) DataTypeOf(field *StructField) string {
 		case reflect.Bool:
 		case reflect.Bool:
 			sqlType = "BOOLEAN"
 			sqlType = "BOOLEAN"
 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
-			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok {
+			if s.fieldCanAutoIncrement(field) {
 				sqlType = "INTEGER AUTO_INCREMENT"
 				sqlType = "INTEGER AUTO_INCREMENT"
 			} else {
 			} else {
 				sqlType = "INTEGER"
 				sqlType = "INTEGER"
 			}
 			}
 		case reflect.Int64, reflect.Uint64:
 		case reflect.Int64, reflect.Uint64:
-			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok {
+			if s.fieldCanAutoIncrement(field) {
 				sqlType = "BIGINT AUTO_INCREMENT"
 				sqlType = "BIGINT AUTO_INCREMENT"
 			} else {
 			} else {
 				sqlType = "BIGINT"
 				sqlType = "BIGINT"
@@ -92,7 +99,8 @@ func (s *commonDialect) DataTypeOf(field *StructField) string {
 
 
 func (s commonDialect) HasIndex(tableName string, indexName string) bool {
 func (s commonDialect) HasIndex(tableName string, indexName string) bool {
 	var count int
 	var count int
-	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema = ? AND table_name = ? AND index_name = ?", s.CurrentDatabase(), tableName, indexName).Scan(&count)
+	currentDatabase, tableName := currentDatabaseAndTable(&s, tableName)
+	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.STATISTICS WHERE table_schema = ? AND table_name = ? AND index_name = ?", currentDatabase, tableName, indexName).Scan(&count)
 	return count > 0
 	return count > 0
 }
 }
 
 
@@ -107,16 +115,23 @@ func (s commonDialect) HasForeignKey(tableName string, foreignKeyName string) bo
 
 
 func (s commonDialect) HasTable(tableName string) bool {
 func (s commonDialect) HasTable(tableName string) bool {
 	var count int
 	var count int
-	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = ? AND table_name = ?", s.CurrentDatabase(), tableName).Scan(&count)
+	currentDatabase, tableName := currentDatabaseAndTable(&s, tableName)
+	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = ? AND table_name = ?", currentDatabase, tableName).Scan(&count)
 	return count > 0
 	return count > 0
 }
 }
 
 
 func (s commonDialect) HasColumn(tableName string, columnName string) bool {
 func (s commonDialect) HasColumn(tableName string, columnName string) bool {
 	var count int
 	var count int
-	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = ? AND table_name = ? AND column_name = ?", s.CurrentDatabase(), tableName, columnName).Scan(&count)
+	currentDatabase, tableName := currentDatabaseAndTable(&s, tableName)
+	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = ? AND table_name = ? AND column_name = ?", currentDatabase, tableName, columnName).Scan(&count)
 	return count > 0
 	return count > 0
 }
 }
 
 
+func (s commonDialect) ModifyColumn(tableName string, columnName string, typ string) error {
+	_, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v ALTER COLUMN %v TYPE %v", tableName, columnName, typ))
+	return err
+}
+
 func (s commonDialect) CurrentDatabase() (name string) {
 func (s commonDialect) CurrentDatabase() (name string) {
 	s.db.QueryRow("SELECT DATABASE()").Scan(&name)
 	s.db.QueryRow("SELECT DATABASE()").Scan(&name)
 	return
 	return
@@ -144,9 +159,14 @@ func (commonDialect) LastInsertIDReturningSuffix(tableName, columnName string) s
 	return ""
 	return ""
 }
 }
 
 
-func (DefaultForeignKeyNamer) BuildForeignKeyName(tableName, field, dest string) string {
-	keyName := fmt.Sprintf("%s_%s_%s_foreign", tableName, field, dest)
-	keyName = regexp.MustCompile("(_*[^a-zA-Z]+_*|_+)").ReplaceAllString(keyName, "_")
+func (commonDialect) DefaultValueStr() string {
+	return "DEFAULT VALUES"
+}
+
+// BuildKeyName returns a valid key name (foreign key, index key) for the given table, field and reference
+func (DefaultForeignKeyNamer) BuildKeyName(kind, tableName string, fields ...string) string {
+	keyName := fmt.Sprintf("%s_%s_%s", kind, tableName, strings.Join(fields, "_"))
+	keyName = regexp.MustCompile("[^a-zA-Z0-9]+").ReplaceAllString(keyName, "_")
 	return keyName
 	return keyName
 }
 }
 
 

+ 28 - 13
vendor/github.com/jinzhu/gorm/dialect_mysql.go

@@ -44,42 +44,42 @@ func (s *mysql) DataTypeOf(field *StructField) string {
 		case reflect.Bool:
 		case reflect.Bool:
 			sqlType = "boolean"
 			sqlType = "boolean"
 		case reflect.Int8:
 		case reflect.Int8:
-			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
+			if s.fieldCanAutoIncrement(field) {
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				sqlType = "tinyint AUTO_INCREMENT"
 				sqlType = "tinyint AUTO_INCREMENT"
 			} else {
 			} else {
 				sqlType = "tinyint"
 				sqlType = "tinyint"
 			}
 			}
 		case reflect.Int, reflect.Int16, reflect.Int32:
 		case reflect.Int, reflect.Int16, reflect.Int32:
-			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
+			if s.fieldCanAutoIncrement(field) {
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				sqlType = "int AUTO_INCREMENT"
 				sqlType = "int AUTO_INCREMENT"
 			} else {
 			} else {
 				sqlType = "int"
 				sqlType = "int"
 			}
 			}
 		case reflect.Uint8:
 		case reflect.Uint8:
-			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
+			if s.fieldCanAutoIncrement(field) {
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				sqlType = "tinyint unsigned AUTO_INCREMENT"
 				sqlType = "tinyint unsigned AUTO_INCREMENT"
 			} else {
 			} else {
 				sqlType = "tinyint unsigned"
 				sqlType = "tinyint unsigned"
 			}
 			}
 		case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
 		case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
-			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
+			if s.fieldCanAutoIncrement(field) {
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				sqlType = "int unsigned AUTO_INCREMENT"
 				sqlType = "int unsigned AUTO_INCREMENT"
 			} else {
 			} else {
 				sqlType = "int unsigned"
 				sqlType = "int unsigned"
 			}
 			}
 		case reflect.Int64:
 		case reflect.Int64:
-			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
+			if s.fieldCanAutoIncrement(field) {
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				sqlType = "bigint AUTO_INCREMENT"
 				sqlType = "bigint AUTO_INCREMENT"
 			} else {
 			} else {
 				sqlType = "bigint"
 				sqlType = "bigint"
 			}
 			}
 		case reflect.Uint64:
 		case reflect.Uint64:
-			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
+			if s.fieldCanAutoIncrement(field) {
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				sqlType = "bigint unsigned AUTO_INCREMENT"
 				sqlType = "bigint unsigned AUTO_INCREMENT"
 			} else {
 			} else {
@@ -95,10 +95,15 @@ func (s *mysql) DataTypeOf(field *StructField) string {
 			}
 			}
 		case reflect.Struct:
 		case reflect.Struct:
 			if _, ok := dataValue.Interface().(time.Time); ok {
 			if _, ok := dataValue.Interface().(time.Time); ok {
+				precision := ""
+				if p, ok := field.TagSettings["PRECISION"]; ok {
+					precision = fmt.Sprintf("(%s)", p)
+				}
+
 				if _, ok := field.TagSettings["NOT NULL"]; ok {
 				if _, ok := field.TagSettings["NOT NULL"]; ok {
-					sqlType = "timestamp"
+					sqlType = fmt.Sprintf("timestamp%v", precision)
 				} else {
 				} else {
-					sqlType = "timestamp NULL"
+					sqlType = fmt.Sprintf("timestamp%v NULL", precision)
 				}
 				}
 			}
 			}
 		default:
 		default:
@@ -127,6 +132,11 @@ func (s mysql) RemoveIndex(tableName string, indexName string) error {
 	return err
 	return err
 }
 }
 
 
+func (s mysql) ModifyColumn(tableName string, columnName string, typ string) error {
+	_, err := s.db.Exec(fmt.Sprintf("ALTER TABLE %v MODIFY COLUMN %v %v", tableName, columnName, typ))
+	return err
+}
+
 func (s mysql) LimitAndOffsetSQL(limit, offset interface{}) (sql string) {
 func (s mysql) LimitAndOffsetSQL(limit, offset interface{}) (sql string) {
 	if limit != nil {
 	if limit != nil {
 		if parsedLimit, err := strconv.ParseInt(fmt.Sprint(limit), 0, 0); err == nil && parsedLimit >= 0 {
 		if parsedLimit, err := strconv.ParseInt(fmt.Sprint(limit), 0, 0); err == nil && parsedLimit >= 0 {
@@ -144,7 +154,8 @@ func (s mysql) LimitAndOffsetSQL(limit, offset interface{}) (sql string) {
 
 
 func (s mysql) HasForeignKey(tableName string, foreignKeyName string) bool {
 func (s mysql) HasForeignKey(tableName string, foreignKeyName string) bool {
 	var count int
 	var count int
-	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_SCHEMA=? AND TABLE_NAME=? AND CONSTRAINT_NAME=? AND CONSTRAINT_TYPE='FOREIGN KEY'", s.CurrentDatabase(), tableName, foreignKeyName).Scan(&count)
+	currentDatabase, tableName := currentDatabaseAndTable(&s, tableName)
+	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE CONSTRAINT_SCHEMA=? AND TABLE_NAME=? AND CONSTRAINT_NAME=? AND CONSTRAINT_TYPE='FOREIGN KEY'", currentDatabase, tableName, foreignKeyName).Scan(&count)
 	return count > 0
 	return count > 0
 }
 }
 
 
@@ -157,8 +168,8 @@ func (mysql) SelectFromDummyTable() string {
 	return "FROM DUAL"
 	return "FROM DUAL"
 }
 }
 
 
-func (s mysql) BuildForeignKeyName(tableName, field, dest string) string {
-	keyName := s.commonDialect.BuildForeignKeyName(tableName, field, dest)
+func (s mysql) BuildKeyName(kind, tableName string, fields ...string) string {
+	keyName := s.commonDialect.BuildKeyName(kind, tableName, fields...)
 	if utf8.RuneCountInString(keyName) <= 64 {
 	if utf8.RuneCountInString(keyName) <= 64 {
 		return keyName
 		return keyName
 	}
 	}
@@ -166,11 +177,15 @@ func (s mysql) BuildForeignKeyName(tableName, field, dest string) string {
 	h.Write([]byte(keyName))
 	h.Write([]byte(keyName))
 	bs := h.Sum(nil)
 	bs := h.Sum(nil)
 
 
-	// sha1 is 40 digits, keep first 24 characters of destination
-	destRunes := []rune(regexp.MustCompile("(_*[^a-zA-Z]+_*|_+)").ReplaceAllString(dest, "_"))
+	// sha1 is 40 characters, keep first 24 characters of destination
+	destRunes := []rune(regexp.MustCompile("[^a-zA-Z0-9]+").ReplaceAllString(fields[0], "_"))
 	if len(destRunes) > 24 {
 	if len(destRunes) > 24 {
 		destRunes = destRunes[:24]
 		destRunes = destRunes[:24]
 	}
 	}
 
 
 	return fmt.Sprintf("%s%x", string(destRunes), bs)
 	return fmt.Sprintf("%s%x", string(destRunes), bs)
 }
 }
+
+func (mysql) DefaultValueStr() string {
+	return "VALUES()"
+}

+ 20 - 7
vendor/github.com/jinzhu/gorm/dialect_postgres.go

@@ -1,6 +1,7 @@
 package gorm
 package gorm
 
 
 import (
 import (
+	"encoding/json"
 	"fmt"
 	"fmt"
 	"reflect"
 	"reflect"
 	"strings"
 	"strings"
@@ -13,6 +14,7 @@ type postgres struct {
 
 
 func init() {
 func init() {
 	RegisterDialect("postgres", &postgres{})
 	RegisterDialect("postgres", &postgres{})
+	RegisterDialect("cloudsqlpostgres", &postgres{})
 }
 }
 
 
 func (postgres) GetName() string {
 func (postgres) GetName() string {
@@ -31,14 +33,14 @@ func (s *postgres) DataTypeOf(field *StructField) string {
 		case reflect.Bool:
 		case reflect.Bool:
 			sqlType = "boolean"
 			sqlType = "boolean"
 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uintptr:
 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uintptr:
-			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
+			if s.fieldCanAutoIncrement(field) {
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				sqlType = "serial"
 				sqlType = "serial"
 			} else {
 			} else {
 				sqlType = "integer"
 				sqlType = "integer"
 			}
 			}
 		case reflect.Int64, reflect.Uint32, reflect.Uint64:
 		case reflect.Int64, reflect.Uint32, reflect.Uint64:
-			if _, ok := field.TagSettings["AUTO_INCREMENT"]; ok || field.IsPrimaryKey {
+			if s.fieldCanAutoIncrement(field) {
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				sqlType = "bigserial"
 				sqlType = "bigserial"
 			} else {
 			} else {
@@ -67,8 +69,14 @@ func (s *postgres) DataTypeOf(field *StructField) string {
 		default:
 		default:
 			if IsByteArrayOrSlice(dataValue) {
 			if IsByteArrayOrSlice(dataValue) {
 				sqlType = "bytea"
 				sqlType = "bytea"
-			} else if isUUID(dataValue) {
-				sqlType = "uuid"
+
+				if isUUID(dataValue) {
+					sqlType = "uuid"
+				}
+
+				if isJSON(dataValue) {
+					sqlType = "jsonb"
+				}
 			}
 			}
 		}
 		}
 	}
 	}
@@ -85,7 +93,7 @@ func (s *postgres) DataTypeOf(field *StructField) string {
 
 
 func (s postgres) HasIndex(tableName string, indexName string) bool {
 func (s postgres) HasIndex(tableName string, indexName string) bool {
 	var count int
 	var count int
-	s.db.QueryRow("SELECT count(*) FROM pg_indexes WHERE tablename = $1 AND indexname = $2", tableName, indexName).Scan(&count)
+	s.db.QueryRow("SELECT count(*) FROM pg_indexes WHERE tablename = $1 AND indexname = $2 AND schemaname = CURRENT_SCHEMA()", tableName, indexName).Scan(&count)
 	return count > 0
 	return count > 0
 }
 }
 
 
@@ -97,13 +105,13 @@ func (s postgres) HasForeignKey(tableName string, foreignKeyName string) bool {
 
 
 func (s postgres) HasTable(tableName string) bool {
 func (s postgres) HasTable(tableName string) bool {
 	var count int
 	var count int
-	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.tables WHERE table_name = $1 AND table_type = 'BASE TABLE'", tableName).Scan(&count)
+	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.tables WHERE table_name = $1 AND table_type = 'BASE TABLE' AND table_schema = CURRENT_SCHEMA()", tableName).Scan(&count)
 	return count > 0
 	return count > 0
 }
 }
 
 
 func (s postgres) HasColumn(tableName string, columnName string) bool {
 func (s postgres) HasColumn(tableName string, columnName string) bool {
 	var count int
 	var count int
-	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.columns WHERE table_name = $1 AND column_name = $2", tableName, columnName).Scan(&count)
+	s.db.QueryRow("SELECT count(*) FROM INFORMATION_SCHEMA.columns WHERE table_name = $1 AND column_name = $2 AND table_schema = CURRENT_SCHEMA()", tableName, columnName).Scan(&count)
 	return count > 0
 	return count > 0
 }
 }
 
 
@@ -128,3 +136,8 @@ func isUUID(value reflect.Value) bool {
 	lower := strings.ToLower(typename)
 	lower := strings.ToLower(typename)
 	return "uuid" == lower || "guid" == lower
 	return "uuid" == lower || "guid" == lower
 }
 }
+
+func isJSON(value reflect.Value) bool {
+	_, ok := value.Interface().(json.RawMessage)
+	return ok
+}

+ 2 - 2
vendor/github.com/jinzhu/gorm/dialect_sqlite3.go

@@ -28,14 +28,14 @@ func (s *sqlite3) DataTypeOf(field *StructField) string {
 		case reflect.Bool:
 		case reflect.Bool:
 			sqlType = "bool"
 			sqlType = "bool"
 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
 		case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uintptr:
-			if field.IsPrimaryKey {
+			if s.fieldCanAutoIncrement(field) {
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				sqlType = "integer primary key autoincrement"
 				sqlType = "integer primary key autoincrement"
 			} else {
 			} else {
 				sqlType = "integer"
 				sqlType = "integer"
 			}
 			}
 		case reflect.Int64, reflect.Uint64:
 		case reflect.Int64, reflect.Uint64:
-			if field.IsPrimaryKey {
+			if s.fieldCanAutoIncrement(field) {
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				field.TagSettings["AUTO_INCREMENT"] = "AUTO_INCREMENT"
 				sqlType = "integer primary key autoincrement"
 				sqlType = "integer primary key autoincrement"
 			} else {
 			} else {

+ 30 - 0
vendor/github.com/jinzhu/gorm/docker-compose.yml

@@ -0,0 +1,30 @@
+version: '3'
+
+services:
+  mysql:
+    image: 'mysql:latest'
+    ports:
+      - 9910:3306
+    environment:
+      - MYSQL_DATABASE=gorm
+      - MYSQL_USER=gorm
+      - MYSQL_PASSWORD=gorm
+      - MYSQL_RANDOM_ROOT_PASSWORD="yes"
+  postgres:
+    image: 'postgres:latest'
+    ports:
+      - 9920:5432
+    environment:
+      - POSTGRES_USER=gorm
+      - POSTGRES_DB=gorm
+      - POSTGRES_PASSWORD=gorm
+  mssql:
+    image: 'mcmoe/mssqldocker:latest'
+    ports:
+      - 9930:1433
+    environment:
+      - ACCEPT_EULA=Y
+      - SA_PASSWORD=LoremIpsum86
+      - MSSQL_DB=gorm
+      - MSSQL_USER=gorm
+      - MSSQL_PASSWORD=LoremIpsum86

+ 16 - 0
vendor/github.com/jinzhu/gorm/errors.go

@@ -21,6 +21,18 @@ var (
 // Errors contains all happened errors
 // Errors contains all happened errors
 type Errors []error
 type Errors []error
 
 
+// IsRecordNotFoundError returns current error has record not found error or not
+func IsRecordNotFoundError(err error) bool {
+	if errs, ok := err.(Errors); ok {
+		for _, err := range errs {
+			if err == ErrRecordNotFound {
+				return true
+			}
+		}
+	}
+	return err == ErrRecordNotFound
+}
+
 // GetErrors gets all happened errors
 // GetErrors gets all happened errors
 func (errs Errors) GetErrors() []error {
 func (errs Errors) GetErrors() []error {
 	return errs
 	return errs
@@ -29,6 +41,10 @@ func (errs Errors) GetErrors() []error {
 // Add adds an error
 // Add adds an error
 func (errs Errors) Add(newErrors ...error) Errors {
 func (errs Errors) Add(newErrors ...error) Errors {
 	for _, err := range newErrors {
 	for _, err := range newErrors {
+		if err == nil {
+			continue
+		}
+
 		if errors, ok := err.(Errors); ok {
 		if errors, ok := err.(Errors); ok {
 			errs = errs.Add(errors...)
 			errs = errs.Add(errors...)
 		} else {
 		} else {

+ 27 - 22
vendor/github.com/jinzhu/gorm/join_table_handler.go

@@ -79,41 +79,43 @@ func (s *JoinTableHandler) Setup(relationship *Relationship, tableName string, s
 
 
 // Table return join table's table name
 // Table return join table's table name
 func (s JoinTableHandler) Table(db *DB) string {
 func (s JoinTableHandler) Table(db *DB) string {
-	return s.TableName
+	return DefaultTableNameHandler(db, s.TableName)
 }
 }
 
 
-func (s JoinTableHandler) getSearchMap(db *DB, sources ...interface{}) map[string]interface{} {
-	values := map[string]interface{}{}
-
+func (s JoinTableHandler) updateConditionMap(conditionMap map[string]interface{}, db *DB, joinTableSources []JoinTableSource, sources ...interface{}) {
 	for _, source := range sources {
 	for _, source := range sources {
 		scope := db.NewScope(source)
 		scope := db.NewScope(source)
 		modelType := scope.GetModelStruct().ModelType
 		modelType := scope.GetModelStruct().ModelType
 
 
-		if s.Source.ModelType == modelType {
-			for _, foreignKey := range s.Source.ForeignKeys {
-				if field, ok := scope.FieldByName(foreignKey.AssociationDBName); ok {
-					values[foreignKey.DBName] = field.Field.Interface()
-				}
-			}
-		} else if s.Destination.ModelType == modelType {
-			for _, foreignKey := range s.Destination.ForeignKeys {
-				if field, ok := scope.FieldByName(foreignKey.AssociationDBName); ok {
-					values[foreignKey.DBName] = field.Field.Interface()
+		for _, joinTableSource := range joinTableSources {
+			if joinTableSource.ModelType == modelType {
+				for _, foreignKey := range joinTableSource.ForeignKeys {
+					if field, ok := scope.FieldByName(foreignKey.AssociationDBName); ok {
+						conditionMap[foreignKey.DBName] = field.Field.Interface()
+					}
 				}
 				}
+				break
 			}
 			}
 		}
 		}
 	}
 	}
-	return values
 }
 }
 
 
 // Add create relationship in join table for source and destination
 // Add create relationship in join table for source and destination
 func (s JoinTableHandler) Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error {
 func (s JoinTableHandler) Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error {
-	scope := db.NewScope("")
-	searchMap := s.getSearchMap(db, source, destination)
+	var (
+		scope        = db.NewScope("")
+		conditionMap = map[string]interface{}{}
+	)
+
+	// Update condition map for source
+	s.updateConditionMap(conditionMap, db, []JoinTableSource{s.Source}, source)
+
+	// Update condition map for destination
+	s.updateConditionMap(conditionMap, db, []JoinTableSource{s.Destination}, destination)
 
 
 	var assignColumns, binVars, conditions []string
 	var assignColumns, binVars, conditions []string
 	var values []interface{}
 	var values []interface{}
-	for key, value := range searchMap {
+	for key, value := range conditionMap {
 		assignColumns = append(assignColumns, scope.Quote(key))
 		assignColumns = append(assignColumns, scope.Quote(key))
 		binVars = append(binVars, `?`)
 		binVars = append(binVars, `?`)
 		conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key)))
 		conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key)))
@@ -141,12 +143,15 @@ func (s JoinTableHandler) Add(handler JoinTableHandlerInterface, db *DB, source
 // Delete delete relationship in join table for sources
 // Delete delete relationship in join table for sources
 func (s JoinTableHandler) Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error {
 func (s JoinTableHandler) Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error {
 	var (
 	var (
-		scope      = db.NewScope(nil)
-		conditions []string
-		values     []interface{}
+		scope        = db.NewScope(nil)
+		conditions   []string
+		values       []interface{}
+		conditionMap = map[string]interface{}{}
 	)
 	)
 
 
-	for key, value := range s.getSearchMap(db, sources...) {
+	s.updateConditionMap(conditionMap, db, []JoinTableSource{s.Source, s.Destination}, sources...)
+
+	for key, value := range conditionMap {
 		conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key)))
 		conditions = append(conditions, fmt.Sprintf("%v = ?", scope.Quote(key)))
 		values = append(values, value)
 		values = append(values, value)
 	}
 	}

+ 44 - 20
vendor/github.com/jinzhu/gorm/main.go

@@ -177,6 +177,15 @@ func (s *DB) QueryExpr() *expr {
 	return Expr(scope.SQL, scope.SQLVars...)
 	return Expr(scope.SQL, scope.SQLVars...)
 }
 }
 
 
+// SubQuery returns the query as sub query
+func (s *DB) SubQuery() *expr {
+	scope := s.NewScope(s.Value)
+	scope.InstanceSet("skip_bindvar", true)
+	scope.prepareQuerySQL()
+
+	return Expr(fmt.Sprintf("(%v)", scope.SQL), scope.SQLVars...)
+}
+
 // Where return a new relation, filter records with given conditions, accepts `map`, `struct` or `string` as conditions, refer http://jinzhu.github.io/gorm/crud.html#query
 // Where return a new relation, filter records with given conditions, accepts `map`, `struct` or `string` as conditions, refer http://jinzhu.github.io/gorm/crud.html#query
 func (s *DB) Where(query interface{}, args ...interface{}) *DB {
 func (s *DB) Where(query interface{}, args ...interface{}) *DB {
 	return s.clone().search.Where(query, args...).db
 	return s.clone().search.Where(query, args...).db
@@ -274,15 +283,22 @@ func (s *DB) Assign(attrs ...interface{}) *DB {
 
 
 // First find first record that match given conditions, order by primary key
 // First find first record that match given conditions, order by primary key
 func (s *DB) First(out interface{}, where ...interface{}) *DB {
 func (s *DB) First(out interface{}, where ...interface{}) *DB {
-	newScope := s.clone().NewScope(out)
+	newScope := s.NewScope(out)
 	newScope.Search.Limit(1)
 	newScope.Search.Limit(1)
 	return newScope.Set("gorm:order_by_primary_key", "ASC").
 	return newScope.Set("gorm:order_by_primary_key", "ASC").
 		inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
 		inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
 }
 }
 
 
+// Take return a record that match given conditions, the order will depend on the database implementation
+func (s *DB) Take(out interface{}, where ...interface{}) *DB {
+	newScope := s.NewScope(out)
+	newScope.Search.Limit(1)
+	return newScope.inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
+}
+
 // Last find last record that match given conditions, order by primary key
 // Last find last record that match given conditions, order by primary key
 func (s *DB) Last(out interface{}, where ...interface{}) *DB {
 func (s *DB) Last(out interface{}, where ...interface{}) *DB {
-	newScope := s.clone().NewScope(out)
+	newScope := s.NewScope(out)
 	newScope.Search.Limit(1)
 	newScope.Search.Limit(1)
 	return newScope.Set("gorm:order_by_primary_key", "DESC").
 	return newScope.Set("gorm:order_by_primary_key", "DESC").
 		inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
 		inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
@@ -290,12 +306,12 @@ func (s *DB) Last(out interface{}, where ...interface{}) *DB {
 
 
 // Find find records that match given conditions
 // Find find records that match given conditions
 func (s *DB) Find(out interface{}, where ...interface{}) *DB {
 func (s *DB) Find(out interface{}, where ...interface{}) *DB {
-	return s.clone().NewScope(out).inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
+	return s.NewScope(out).inlineCondition(where...).callCallbacks(s.parent.callbacks.queries).db
 }
 }
 
 
 // Scan scan value to a struct
 // Scan scan value to a struct
 func (s *DB) Scan(dest interface{}) *DB {
 func (s *DB) Scan(dest interface{}) *DB {
-	return s.clone().NewScope(s.Value).Set("gorm:query_destination", dest).callCallbacks(s.parent.callbacks.queries).db
+	return s.NewScope(s.Value).Set("gorm:query_destination", dest).callCallbacks(s.parent.callbacks.queries).db
 }
 }
 
 
 // Row return `*sql.Row` with given conditions
 // Row return `*sql.Row` with given conditions
@@ -311,8 +327,8 @@ func (s *DB) Rows() (*sql.Rows, error) {
 // ScanRows scan `*sql.Rows` to give struct
 // ScanRows scan `*sql.Rows` to give struct
 func (s *DB) ScanRows(rows *sql.Rows, result interface{}) error {
 func (s *DB) ScanRows(rows *sql.Rows, result interface{}) error {
 	var (
 	var (
-		clone        = s.clone()
-		scope        = clone.NewScope(result)
+		scope        = s.NewScope(result)
+		clone        = scope.db
 		columns, err = rows.Columns()
 		columns, err = rows.Columns()
 	)
 	)
 
 
@@ -337,7 +353,7 @@ func (s *DB) Count(value interface{}) *DB {
 
 
 // Related get related associations
 // Related get related associations
 func (s *DB) Related(value interface{}, foreignKeys ...string) *DB {
 func (s *DB) Related(value interface{}, foreignKeys ...string) *DB {
-	return s.clone().NewScope(s.Value).related(value, foreignKeys...).db
+	return s.NewScope(s.Value).related(value, foreignKeys...).db
 }
 }
 
 
 // FirstOrInit find first matched record or initialize a new one with given conditions (only works with struct, map conditions)
 // FirstOrInit find first matched record or initialize a new one with given conditions (only works with struct, map conditions)
@@ -377,7 +393,7 @@ func (s *DB) Update(attrs ...interface{}) *DB {
 
 
 // Updates update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
 // Updates update attributes with callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
 func (s *DB) Updates(values interface{}, ignoreProtectedAttrs ...bool) *DB {
 func (s *DB) Updates(values interface{}, ignoreProtectedAttrs ...bool) *DB {
-	return s.clone().NewScope(s.Value).
+	return s.NewScope(s.Value).
 		Set("gorm:ignore_protected_attrs", len(ignoreProtectedAttrs) > 0).
 		Set("gorm:ignore_protected_attrs", len(ignoreProtectedAttrs) > 0).
 		InstanceSet("gorm:update_interface", values).
 		InstanceSet("gorm:update_interface", values).
 		callCallbacks(s.parent.callbacks.updates).db
 		callCallbacks(s.parent.callbacks.updates).db
@@ -390,7 +406,7 @@ func (s *DB) UpdateColumn(attrs ...interface{}) *DB {
 
 
 // UpdateColumns update attributes without callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
 // UpdateColumns update attributes without callbacks, refer: https://jinzhu.github.io/gorm/crud.html#update
 func (s *DB) UpdateColumns(values interface{}) *DB {
 func (s *DB) UpdateColumns(values interface{}) *DB {
-	return s.clone().NewScope(s.Value).
+	return s.NewScope(s.Value).
 		Set("gorm:update_column", true).
 		Set("gorm:update_column", true).
 		Set("gorm:save_associations", false).
 		Set("gorm:save_associations", false).
 		InstanceSet("gorm:update_interface", values).
 		InstanceSet("gorm:update_interface", values).
@@ -399,7 +415,7 @@ func (s *DB) UpdateColumns(values interface{}) *DB {
 
 
 // Save update value in database, if the value doesn't have primary key, will insert it
 // Save update value in database, if the value doesn't have primary key, will insert it
 func (s *DB) Save(value interface{}) *DB {
 func (s *DB) Save(value interface{}) *DB {
-	scope := s.clone().NewScope(value)
+	scope := s.NewScope(value)
 	if !scope.PrimaryKeyZero() {
 	if !scope.PrimaryKeyZero() {
 		newDB := scope.callCallbacks(s.parent.callbacks.updates).db
 		newDB := scope.callCallbacks(s.parent.callbacks.updates).db
 		if newDB.Error == nil && newDB.RowsAffected == 0 {
 		if newDB.Error == nil && newDB.RowsAffected == 0 {
@@ -412,13 +428,13 @@ func (s *DB) Save(value interface{}) *DB {
 
 
 // Create insert the value into database
 // Create insert the value into database
 func (s *DB) Create(value interface{}) *DB {
 func (s *DB) Create(value interface{}) *DB {
-	scope := s.clone().NewScope(value)
+	scope := s.NewScope(value)
 	return scope.callCallbacks(s.parent.callbacks.creates).db
 	return scope.callCallbacks(s.parent.callbacks.creates).db
 }
 }
 
 
 // Delete delete value match given conditions, if the value has primary key, then will including the primary key as condition
 // Delete delete value match given conditions, if the value has primary key, then will including the primary key as condition
 func (s *DB) Delete(value interface{}, where ...interface{}) *DB {
 func (s *DB) Delete(value interface{}, where ...interface{}) *DB {
-	return s.clone().NewScope(value).inlineCondition(where...).callCallbacks(s.parent.callbacks.deletes).db
+	return s.NewScope(value).inlineCondition(where...).callCallbacks(s.parent.callbacks.deletes).db
 }
 }
 
 
 // Raw use raw sql as conditions, won't run it unless invoked by other methods
 // Raw use raw sql as conditions, won't run it unless invoked by other methods
@@ -429,8 +445,8 @@ func (s *DB) Raw(sql string, values ...interface{}) *DB {
 
 
 // Exec execute raw sql
 // Exec execute raw sql
 func (s *DB) Exec(sql string, values ...interface{}) *DB {
 func (s *DB) Exec(sql string, values ...interface{}) *DB {
-	scope := s.clone().NewScope(nil)
-	generatedSQL := scope.buildWhereCondition(map[string]interface{}{"query": sql, "args": values})
+	scope := s.NewScope(nil)
+	generatedSQL := scope.buildCondition(map[string]interface{}{"query": sql, "args": values}, true)
 	generatedSQL = strings.TrimSuffix(strings.TrimPrefix(generatedSQL, "("), ")")
 	generatedSQL = strings.TrimSuffix(strings.TrimPrefix(generatedSQL, "("), ")")
 	scope.Raw(generatedSQL)
 	scope.Raw(generatedSQL)
 	return scope.Exec().db
 	return scope.Exec().db
@@ -495,7 +511,7 @@ func (s *DB) Rollback() *DB {
 
 
 // NewRecord check if value's primary key is blank
 // NewRecord check if value's primary key is blank
 func (s *DB) NewRecord(value interface{}) bool {
 func (s *DB) NewRecord(value interface{}) bool {
-	return s.clone().NewScope(value).PrimaryKeyZero()
+	return s.NewScope(value).PrimaryKeyZero()
 }
 }
 
 
 // RecordNotFound check if returning ErrRecordNotFound error
 // RecordNotFound check if returning ErrRecordNotFound error
@@ -544,7 +560,7 @@ func (s *DB) DropTableIfExists(values ...interface{}) *DB {
 // HasTable check has table or not
 // HasTable check has table or not
 func (s *DB) HasTable(value interface{}) bool {
 func (s *DB) HasTable(value interface{}) bool {
 	var (
 	var (
-		scope     = s.clone().NewScope(value)
+		scope     = s.NewScope(value)
 		tableName string
 		tableName string
 	)
 	)
 
 
@@ -570,14 +586,14 @@ func (s *DB) AutoMigrate(values ...interface{}) *DB {
 
 
 // ModifyColumn modify column to type
 // ModifyColumn modify column to type
 func (s *DB) ModifyColumn(column string, typ string) *DB {
 func (s *DB) ModifyColumn(column string, typ string) *DB {
-	scope := s.clone().NewScope(s.Value)
+	scope := s.NewScope(s.Value)
 	scope.modifyColumn(column, typ)
 	scope.modifyColumn(column, typ)
 	return scope.db
 	return scope.db
 }
 }
 
 
 // DropColumn drop a column
 // DropColumn drop a column
 func (s *DB) DropColumn(column string) *DB {
 func (s *DB) DropColumn(column string) *DB {
-	scope := s.clone().NewScope(s.Value)
+	scope := s.NewScope(s.Value)
 	scope.dropColumn(column)
 	scope.dropColumn(column)
 	return scope.db
 	return scope.db
 }
 }
@@ -598,7 +614,7 @@ func (s *DB) AddUniqueIndex(indexName string, columns ...string) *DB {
 
 
 // RemoveIndex remove index with name
 // RemoveIndex remove index with name
 func (s *DB) RemoveIndex(indexName string) *DB {
 func (s *DB) RemoveIndex(indexName string) *DB {
-	scope := s.clone().NewScope(s.Value)
+	scope := s.NewScope(s.Value)
 	scope.removeIndex(indexName)
 	scope.removeIndex(indexName)
 	return scope.db
 	return scope.db
 }
 }
@@ -606,11 +622,19 @@ func (s *DB) RemoveIndex(indexName string) *DB {
 // AddForeignKey Add foreign key to the given scope, e.g:
 // AddForeignKey Add foreign key to the given scope, e.g:
 //     db.Model(&User{}).AddForeignKey("city_id", "cities(id)", "RESTRICT", "RESTRICT")
 //     db.Model(&User{}).AddForeignKey("city_id", "cities(id)", "RESTRICT", "RESTRICT")
 func (s *DB) AddForeignKey(field string, dest string, onDelete string, onUpdate string) *DB {
 func (s *DB) AddForeignKey(field string, dest string, onDelete string, onUpdate string) *DB {
-	scope := s.clone().NewScope(s.Value)
+	scope := s.NewScope(s.Value)
 	scope.addForeignKey(field, dest, onDelete, onUpdate)
 	scope.addForeignKey(field, dest, onDelete, onUpdate)
 	return scope.db
 	return scope.db
 }
 }
 
 
+// RemoveForeignKey Remove foreign key from the given scope, e.g:
+//     db.Model(&User{}).RemoveForeignKey("city_id", "cities(id)")
+func (s *DB) RemoveForeignKey(field string, dest string) *DB {
+	scope := s.clone().NewScope(s.Value)
+	scope.removeForeignKey(field, dest)
+	return scope.db
+}
+
 // Association start `Association Mode` to handler relations things easir in that mode, refer: https://jinzhu.github.io/gorm/associations.html#association-mode
 // Association start `Association Mode` to handler relations things easir in that mode, refer: https://jinzhu.github.io/gorm/associations.html#association-mode
 func (s *DB) Association(column string) *Association {
 func (s *DB) Association(column string) *Association {
 	var err error
 	var err error

+ 62 - 30
vendor/github.com/jinzhu/gorm/model_struct.go

@@ -249,11 +249,13 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 							)
 							)
 
 
 							if foreignKey := field.TagSettings["FOREIGNKEY"]; foreignKey != "" {
 							if foreignKey := field.TagSettings["FOREIGNKEY"]; foreignKey != "" {
-								foreignKeys = strings.Split(field.TagSettings["FOREIGNKEY"], ",")
+								foreignKeys = strings.Split(foreignKey, ",")
 							}
 							}
 
 
-							if foreignKey := field.TagSettings["ASSOCIATIONFOREIGNKEY"]; foreignKey != "" {
-								associationForeignKeys = strings.Split(field.TagSettings["ASSOCIATIONFOREIGNKEY"], ",")
+							if foreignKey := field.TagSettings["ASSOCIATION_FOREIGNKEY"]; foreignKey != "" {
+								associationForeignKeys = strings.Split(foreignKey, ",")
+							} else if foreignKey := field.TagSettings["ASSOCIATIONFOREIGNKEY"]; foreignKey != "" {
+								associationForeignKeys = strings.Split(foreignKey, ",")
 							}
 							}
 
 
 							for elemType.Kind() == reflect.Slice || elemType.Kind() == reflect.Ptr {
 							for elemType.Kind() == reflect.Slice || elemType.Kind() == reflect.Ptr {
@@ -264,37 +266,65 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 								if many2many := field.TagSettings["MANY2MANY"]; many2many != "" {
 								if many2many := field.TagSettings["MANY2MANY"]; many2many != "" {
 									relationship.Kind = "many_to_many"
 									relationship.Kind = "many_to_many"
 
 
-									// if no foreign keys defined with tag
-									if len(foreignKeys) == 0 {
-										for _, field := range modelStruct.PrimaryFields {
-											foreignKeys = append(foreignKeys, field.DBName)
+									{ // Foreign Keys for Source
+										joinTableDBNames := []string{}
+
+										if foreignKey := field.TagSettings["JOINTABLE_FOREIGNKEY"]; foreignKey != "" {
+											joinTableDBNames = strings.Split(foreignKey, ",")
 										}
 										}
-									}
 
 
-									for _, foreignKey := range foreignKeys {
-										if foreignField := getForeignField(foreignKey, modelStruct.StructFields); foreignField != nil {
-											// source foreign keys (db names)
-											relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.DBName)
-											// join table foreign keys for source
-											joinTableDBName := ToDBName(reflectType.Name()) + "_" + foreignField.DBName
-											relationship.ForeignDBNames = append(relationship.ForeignDBNames, joinTableDBName)
+										// if no foreign keys defined with tag
+										if len(foreignKeys) == 0 {
+											for _, field := range modelStruct.PrimaryFields {
+												foreignKeys = append(foreignKeys, field.DBName)
+											}
 										}
 										}
-									}
 
 
-									// if no association foreign keys defined with tag
-									if len(associationForeignKeys) == 0 {
-										for _, field := range toScope.PrimaryFields() {
-											associationForeignKeys = append(associationForeignKeys, field.DBName)
+										for idx, foreignKey := range foreignKeys {
+											if foreignField := getForeignField(foreignKey, modelStruct.StructFields); foreignField != nil {
+												// source foreign keys (db names)
+												relationship.ForeignFieldNames = append(relationship.ForeignFieldNames, foreignField.DBName)
+
+												// setup join table foreign keys for source
+												if len(joinTableDBNames) > idx {
+													// if defined join table's foreign key
+													relationship.ForeignDBNames = append(relationship.ForeignDBNames, joinTableDBNames[idx])
+												} else {
+													defaultJointableForeignKey := ToDBName(reflectType.Name()) + "_" + foreignField.DBName
+													relationship.ForeignDBNames = append(relationship.ForeignDBNames, defaultJointableForeignKey)
+												}
+											}
 										}
 										}
 									}
 									}
 
 
-									for _, name := range associationForeignKeys {
-										if field, ok := toScope.FieldByName(name); ok {
-											// association foreign keys (db names)
-											relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, field.DBName)
-											// join table foreign keys for association
-											joinTableDBName := ToDBName(elemType.Name()) + "_" + field.DBName
-											relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, joinTableDBName)
+									{ // Foreign Keys for Association (Destination)
+										associationJoinTableDBNames := []string{}
+
+										if foreignKey := field.TagSettings["ASSOCIATION_JOINTABLE_FOREIGNKEY"]; foreignKey != "" {
+											associationJoinTableDBNames = strings.Split(foreignKey, ",")
+										}
+
+										// if no association foreign keys defined with tag
+										if len(associationForeignKeys) == 0 {
+											for _, field := range toScope.PrimaryFields() {
+												associationForeignKeys = append(associationForeignKeys, field.DBName)
+											}
+										}
+
+										for idx, name := range associationForeignKeys {
+											if field, ok := toScope.FieldByName(name); ok {
+												// association foreign keys (db names)
+												relationship.AssociationForeignFieldNames = append(relationship.AssociationForeignFieldNames, field.DBName)
+
+												// setup join table foreign keys for association
+												if len(associationJoinTableDBNames) > idx {
+													relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, associationJoinTableDBNames[idx])
+												} else {
+													// join table foreign keys for association
+													joinTableDBName := ToDBName(elemType.Name()) + "_" + field.DBName
+													relationship.AssociationForeignDBNames = append(relationship.AssociationForeignDBNames, joinTableDBName)
+												}
+											}
 										}
 										}
 									}
 									}
 
 
@@ -399,11 +429,13 @@ func (scope *Scope) GetModelStruct() *ModelStruct {
 							)
 							)
 
 
 							if foreignKey := field.TagSettings["FOREIGNKEY"]; foreignKey != "" {
 							if foreignKey := field.TagSettings["FOREIGNKEY"]; foreignKey != "" {
-								tagForeignKeys = strings.Split(field.TagSettings["FOREIGNKEY"], ",")
+								tagForeignKeys = strings.Split(foreignKey, ",")
 							}
 							}
 
 
-							if foreignKey := field.TagSettings["ASSOCIATIONFOREIGNKEY"]; foreignKey != "" {
-								tagAssociationForeignKeys = strings.Split(field.TagSettings["ASSOCIATIONFOREIGNKEY"], ",")
+							if foreignKey := field.TagSettings["ASSOCIATION_FOREIGNKEY"]; foreignKey != "" {
+								tagAssociationForeignKeys = strings.Split(foreignKey, ",")
+							} else if foreignKey := field.TagSettings["ASSOCIATIONFOREIGNKEY"]; foreignKey != "" {
+								tagAssociationForeignKeys = strings.Split(foreignKey, ",")
 							}
 							}
 
 
 							if polymorphic := field.TagSettings["POLYMORPHIC"]; polymorphic != "" {
 							if polymorphic := field.TagSettings["POLYMORPHIC"]; polymorphic != "" {

+ 173 - 119
vendor/github.com/jinzhu/gorm/scope.go

@@ -1,16 +1,15 @@
 package gorm
 package gorm
 
 
 import (
 import (
+	"bytes"
 	"database/sql"
 	"database/sql"
 	"database/sql/driver"
 	"database/sql/driver"
 	"errors"
 	"errors"
 	"fmt"
 	"fmt"
+	"reflect"
 	"regexp"
 	"regexp"
-	"strconv"
 	"strings"
 	"strings"
 	"time"
 	"time"
-
-	"reflect"
 )
 )
 
 
 // Scope contain current operation's information when you perform any operation on the database
 // Scope contain current operation's information when you perform any operation on the database
@@ -116,6 +115,9 @@ func (scope *Scope) Fields() []*Field {
 			if isStruct {
 			if isStruct {
 				fieldValue := indirectScopeValue
 				fieldValue := indirectScopeValue
 				for _, name := range structField.Names {
 				for _, name := range structField.Names {
+					if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() {
+						fieldValue.Set(reflect.New(fieldValue.Type().Elem()))
+					}
 					fieldValue = reflect.Indirect(fieldValue).FieldByName(name)
 					fieldValue = reflect.Indirect(fieldValue).FieldByName(name)
 				}
 				}
 				fields = append(fields, &Field{StructField: structField, Field: fieldValue, IsBlank: isBlank(fieldValue)})
 				fields = append(fields, &Field{StructField: structField, Field: fieldValue, IsBlank: isBlank(fieldValue)})
@@ -460,7 +462,7 @@ func (scope *Scope) callMethod(methodName string, reflectValue reflect.Value) {
 var (
 var (
 	columnRegexp        = regexp.MustCompile("^[a-zA-Z\\d]+(\\.[a-zA-Z\\d]+)*$") // only match string like `name`, `users.name`
 	columnRegexp        = regexp.MustCompile("^[a-zA-Z\\d]+(\\.[a-zA-Z\\d]+)*$") // only match string like `name`, `users.name`
 	isNumberRegexp      = regexp.MustCompile("^\\s*\\d+\\s*$")                   // match if string is number
 	isNumberRegexp      = regexp.MustCompile("^\\s*\\d+\\s*$")                   // match if string is number
-	comparisonRegexp    = regexp.MustCompile("(?i) (=|<>|>|<|LIKE|IS|IN) ")
+	comparisonRegexp    = regexp.MustCompile("(?i) (=|<>|(>|<)(=?)|LIKE|IS|IN) ")
 	countingQueryRegexp = regexp.MustCompile("(?i)^count(.+)$")
 	countingQueryRegexp = regexp.MustCompile("(?i)^count(.+)$")
 )
 )
 
 
@@ -521,134 +523,143 @@ func (scope *Scope) primaryCondition(value interface{}) string {
 	return fmt.Sprintf("(%v.%v = %v)", scope.QuotedTableName(), scope.Quote(scope.PrimaryKey()), value)
 	return fmt.Sprintf("(%v.%v = %v)", scope.QuotedTableName(), scope.Quote(scope.PrimaryKey()), value)
 }
 }
 
 
-func (scope *Scope) buildWhereCondition(clause map[string]interface{}) (str string) {
+func (scope *Scope) buildCondition(clause map[string]interface{}, include bool) (str string) {
+	var (
+		quotedTableName  = scope.QuotedTableName()
+		quotedPrimaryKey = scope.Quote(scope.PrimaryKey())
+		equalSQL         = "="
+		inSQL            = "IN"
+	)
+
+	// If building not conditions
+	if !include {
+		equalSQL = "<>"
+		inSQL = "NOT IN"
+	}
+
 	switch value := clause["query"].(type) {
 	switch value := clause["query"].(type) {
+	case sql.NullInt64:
+		return fmt.Sprintf("(%v.%v %s %v)", quotedTableName, quotedPrimaryKey, equalSQL, value.Int64)
+	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
+		return fmt.Sprintf("(%v.%v %s %v)", quotedTableName, quotedPrimaryKey, equalSQL, value)
+	case []int, []int8, []int16, []int32, []int64, []uint, []uint8, []uint16, []uint32, []uint64, []string, []interface{}:
+		if !include && reflect.ValueOf(value).Len() == 0 {
+			return
+		}
+		str = fmt.Sprintf("(%v.%v %s (?))", quotedTableName, quotedPrimaryKey, inSQL)
+		clause["args"] = []interface{}{value}
 	case string:
 	case string:
 		if isNumberRegexp.MatchString(value) {
 		if isNumberRegexp.MatchString(value) {
-			return scope.primaryCondition(scope.AddToVars(value))
-		} else if value != "" {
-			str = fmt.Sprintf("(%v)", value)
+			return fmt.Sprintf("(%v.%v %s %v)", quotedTableName, quotedPrimaryKey, equalSQL, scope.AddToVars(value))
+		}
+
+		if value != "" {
+			if !include {
+				if comparisonRegexp.MatchString(value) {
+					str = fmt.Sprintf("NOT (%v)", value)
+				} else {
+					str = fmt.Sprintf("(%v.%v NOT IN (?))", quotedTableName, scope.Quote(value))
+				}
+			} else {
+				str = fmt.Sprintf("(%v)", value)
+			}
 		}
 		}
-	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, sql.NullInt64:
-		return scope.primaryCondition(scope.AddToVars(value))
-	case []int, []int8, []int16, []int32, []int64, []uint, []uint8, []uint16, []uint32, []uint64, []string, []interface{}:
-		str = fmt.Sprintf("(%v.%v IN (?))", scope.QuotedTableName(), scope.Quote(scope.PrimaryKey()))
-		clause["args"] = []interface{}{value}
 	case map[string]interface{}:
 	case map[string]interface{}:
 		var sqls []string
 		var sqls []string
 		for key, value := range value {
 		for key, value := range value {
 			if value != nil {
 			if value != nil {
-				sqls = append(sqls, fmt.Sprintf("(%v.%v = %v)", scope.QuotedTableName(), scope.Quote(key), scope.AddToVars(value)))
+				sqls = append(sqls, fmt.Sprintf("(%v.%v %s %v)", quotedTableName, scope.Quote(key), equalSQL, scope.AddToVars(value)))
 			} else {
 			} else {
-				sqls = append(sqls, fmt.Sprintf("(%v.%v IS NULL)", scope.QuotedTableName(), scope.Quote(key)))
+				if !include {
+					sqls = append(sqls, fmt.Sprintf("(%v.%v IS NOT NULL)", quotedTableName, scope.Quote(key)))
+				} else {
+					sqls = append(sqls, fmt.Sprintf("(%v.%v IS NULL)", quotedTableName, scope.Quote(key)))
+				}
 			}
 			}
 		}
 		}
 		return strings.Join(sqls, " AND ")
 		return strings.Join(sqls, " AND ")
 	case interface{}:
 	case interface{}:
 		var sqls []string
 		var sqls []string
 		newScope := scope.New(value)
 		newScope := scope.New(value)
+
+		if len(newScope.Fields()) == 0 {
+			scope.Err(fmt.Errorf("invalid query condition: %v", value))
+			return
+		}
+
 		for _, field := range newScope.Fields() {
 		for _, field := range newScope.Fields() {
 			if !field.IsIgnored && !field.IsBlank {
 			if !field.IsIgnored && !field.IsBlank {
-				sqls = append(sqls, fmt.Sprintf("(%v.%v = %v)", scope.QuotedTableName(), scope.Quote(field.DBName), scope.AddToVars(field.Field.Interface())))
+				sqls = append(sqls, fmt.Sprintf("(%v.%v %s %v)", quotedTableName, scope.Quote(field.DBName), equalSQL, scope.AddToVars(field.Field.Interface())))
 			}
 			}
 		}
 		}
 		return strings.Join(sqls, " AND ")
 		return strings.Join(sqls, " AND ")
+	default:
+		scope.Err(fmt.Errorf("invalid query condition: %v", value))
+		return
 	}
 	}
 
 
+	replacements := []string{}
 	args := clause["args"].([]interface{})
 	args := clause["args"].([]interface{})
 	for _, arg := range args {
 	for _, arg := range args {
+		var err error
 		switch reflect.ValueOf(arg).Kind() {
 		switch reflect.ValueOf(arg).Kind() {
 		case reflect.Slice: // For where("id in (?)", []int64{1,2})
 		case reflect.Slice: // For where("id in (?)", []int64{1,2})
-			if bytes, ok := arg.([]byte); ok {
-				str = strings.Replace(str, "?", scope.AddToVars(bytes), 1)
+			if scanner, ok := interface{}(arg).(driver.Valuer); ok {
+				arg, err = scanner.Value()
+				replacements = append(replacements, scope.AddToVars(arg))
+			} else if b, ok := arg.([]byte); ok {
+				replacements = append(replacements, scope.AddToVars(b))
+			} else if as, ok := arg.([][]interface{}); ok {
+				var tempMarks []string
+				for _, a := range as {
+					var arrayMarks []string
+					for _, v := range a {
+						arrayMarks = append(arrayMarks, scope.AddToVars(v))
+					}
+
+					if len(arrayMarks) > 0 {
+						tempMarks = append(tempMarks, fmt.Sprintf("(%v)", strings.Join(arrayMarks, ",")))
+					}
+				}
+
+				if len(tempMarks) > 0 {
+					replacements = append(replacements, strings.Join(tempMarks, ","))
+				}
 			} else if values := reflect.ValueOf(arg); values.Len() > 0 {
 			} else if values := reflect.ValueOf(arg); values.Len() > 0 {
 				var tempMarks []string
 				var tempMarks []string
 				for i := 0; i < values.Len(); i++ {
 				for i := 0; i < values.Len(); i++ {
 					tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface()))
 					tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface()))
 				}
 				}
-				str = strings.Replace(str, "?", strings.Join(tempMarks, ","), 1)
+				replacements = append(replacements, strings.Join(tempMarks, ","))
 			} else {
 			} else {
-				str = strings.Replace(str, "?", scope.AddToVars(Expr("NULL")), 1)
+				replacements = append(replacements, scope.AddToVars(Expr("NULL")))
 			}
 			}
 		default:
 		default:
 			if valuer, ok := interface{}(arg).(driver.Valuer); ok {
 			if valuer, ok := interface{}(arg).(driver.Valuer); ok {
-				arg, _ = valuer.Value()
+				arg, err = valuer.Value()
 			}
 			}
 
 
-			str = strings.Replace(str, "?", scope.AddToVars(arg), 1)
+			replacements = append(replacements, scope.AddToVars(arg))
 		}
 		}
-	}
-	return
-}
-
-func (scope *Scope) buildNotCondition(clause map[string]interface{}) (str string) {
-	var notEqualSQL string
-	var primaryKey = scope.PrimaryKey()
 
 
-	switch value := clause["query"].(type) {
-	case string:
-		if isNumberRegexp.MatchString(value) {
-			id, _ := strconv.Atoi(value)
-			return fmt.Sprintf("(%v <> %v)", scope.Quote(primaryKey), id)
-		} else if comparisonRegexp.MatchString(value) {
-			str = fmt.Sprintf(" NOT (%v) ", value)
-			notEqualSQL = fmt.Sprintf("NOT (%v)", value)
-		} else {
-			str = fmt.Sprintf("(%v.%v NOT IN (?))", scope.QuotedTableName(), scope.Quote(value))
-			notEqualSQL = fmt.Sprintf("(%v.%v <> ?)", scope.QuotedTableName(), scope.Quote(value))
-		}
-	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, sql.NullInt64:
-		return fmt.Sprintf("(%v.%v <> %v)", scope.QuotedTableName(), scope.Quote(primaryKey), value)
-	case []int, []int8, []int16, []int32, []int64, []uint, []uint8, []uint16, []uint32, []uint64, []string:
-		if reflect.ValueOf(value).Len() > 0 {
-			str = fmt.Sprintf("(%v.%v NOT IN (?))", scope.QuotedTableName(), scope.Quote(primaryKey))
-			clause["args"] = []interface{}{value}
-		} else {
-			return ""
-		}
-	case map[string]interface{}:
-		var sqls []string
-		for key, value := range value {
-			if value != nil {
-				sqls = append(sqls, fmt.Sprintf("(%v.%v <> %v)", scope.QuotedTableName(), scope.Quote(key), scope.AddToVars(value)))
-			} else {
-				sqls = append(sqls, fmt.Sprintf("(%v.%v IS NOT NULL)", scope.QuotedTableName(), scope.Quote(key)))
-			}
-		}
-		return strings.Join(sqls, " AND ")
-	case interface{}:
-		var sqls []string
-		var newScope = scope.New(value)
-		for _, field := range newScope.Fields() {
-			if !field.IsBlank {
-				sqls = append(sqls, fmt.Sprintf("(%v.%v <> %v)", scope.QuotedTableName(), scope.Quote(field.DBName), scope.AddToVars(field.Field.Interface())))
-			}
+		if err != nil {
+			scope.Err(err)
 		}
 		}
-		return strings.Join(sqls, " AND ")
 	}
 	}
 
 
-	args := clause["args"].([]interface{})
-	for _, arg := range args {
-		switch reflect.ValueOf(arg).Kind() {
-		case reflect.Slice: // For where("id in (?)", []int64{1,2})
-			if bytes, ok := arg.([]byte); ok {
-				str = strings.Replace(str, "?", scope.AddToVars(bytes), 1)
-			} else if values := reflect.ValueOf(arg); values.Len() > 0 {
-				var tempMarks []string
-				for i := 0; i < values.Len(); i++ {
-					tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface()))
-				}
-				str = strings.Replace(str, "?", strings.Join(tempMarks, ","), 1)
-			} else {
-				str = strings.Replace(str, "?", scope.AddToVars(Expr("NULL")), 1)
-			}
-		default:
-			if scanner, ok := interface{}(arg).(driver.Valuer); ok {
-				arg, _ = scanner.Value()
-			}
-			str = strings.Replace(notEqualSQL, "?", scope.AddToVars(arg), 1)
+	buff := bytes.NewBuffer([]byte{})
+	i := 0
+	for _, s := range str {
+		if s == '?' {
+			buff.WriteString(replacements[i])
+			i++
+		} else {
+			buff.WriteRune(s)
 		}
 		}
 	}
 	}
+
+	str = buff.String()
+
 	return
 	return
 }
 }
 
 
@@ -661,6 +672,7 @@ func (scope *Scope) buildSelectQuery(clause map[string]interface{}) (str string)
 	}
 	}
 
 
 	args := clause["args"].([]interface{})
 	args := clause["args"].([]interface{})
+	replacements := []string{}
 	for _, arg := range args {
 	for _, arg := range args {
 		switch reflect.ValueOf(arg).Kind() {
 		switch reflect.ValueOf(arg).Kind() {
 		case reflect.Slice:
 		case reflect.Slice:
@@ -669,14 +681,28 @@ func (scope *Scope) buildSelectQuery(clause map[string]interface{}) (str string)
 			for i := 0; i < values.Len(); i++ {
 			for i := 0; i < values.Len(); i++ {
 				tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface()))
 				tempMarks = append(tempMarks, scope.AddToVars(values.Index(i).Interface()))
 			}
 			}
-			str = strings.Replace(str, "?", strings.Join(tempMarks, ","), 1)
+			replacements = append(replacements, strings.Join(tempMarks, ","))
 		default:
 		default:
 			if valuer, ok := interface{}(arg).(driver.Valuer); ok {
 			if valuer, ok := interface{}(arg).(driver.Valuer); ok {
 				arg, _ = valuer.Value()
 				arg, _ = valuer.Value()
 			}
 			}
-			str = strings.Replace(str, "?", scope.AddToVars(arg), 1)
+			replacements = append(replacements, scope.AddToVars(arg))
 		}
 		}
 	}
 	}
+
+	buff := bytes.NewBuffer([]byte{})
+	i := 0
+	for pos := range str {
+		if str[pos] == '?' {
+			buff.WriteString(replacements[i])
+			i++
+		} else {
+			buff.WriteByte(str[pos])
+		}
+	}
+
+	str = buff.String()
+
 	return
 	return
 }
 }
 
 
@@ -700,19 +726,19 @@ func (scope *Scope) whereSQL() (sql string) {
 	}
 	}
 
 
 	for _, clause := range scope.Search.whereConditions {
 	for _, clause := range scope.Search.whereConditions {
-		if sql := scope.buildWhereCondition(clause); sql != "" {
+		if sql := scope.buildCondition(clause, true); sql != "" {
 			andConditions = append(andConditions, sql)
 			andConditions = append(andConditions, sql)
 		}
 		}
 	}
 	}
 
 
 	for _, clause := range scope.Search.orConditions {
 	for _, clause := range scope.Search.orConditions {
-		if sql := scope.buildWhereCondition(clause); sql != "" {
+		if sql := scope.buildCondition(clause, true); sql != "" {
 			orConditions = append(orConditions, sql)
 			orConditions = append(orConditions, sql)
 		}
 		}
 	}
 	}
 
 
 	for _, clause := range scope.Search.notConditions {
 	for _, clause := range scope.Search.notConditions {
-		if sql := scope.buildNotCondition(clause); sql != "" {
+		if sql := scope.buildCondition(clause, false); sql != "" {
 			andConditions = append(andConditions, sql)
 			andConditions = append(andConditions, sql)
 		}
 		}
 	}
 	}
@@ -786,7 +812,7 @@ func (scope *Scope) havingSQL() string {
 
 
 	var andConditions []string
 	var andConditions []string
 	for _, clause := range scope.Search.havingConditions {
 	for _, clause := range scope.Search.havingConditions {
-		if sql := scope.buildWhereCondition(clause); sql != "" {
+		if sql := scope.buildCondition(clause, true); sql != "" {
 			andConditions = append(andConditions, sql)
 			andConditions = append(andConditions, sql)
 		}
 		}
 	}
 	}
@@ -802,7 +828,7 @@ func (scope *Scope) havingSQL() string {
 func (scope *Scope) joinsSQL() string {
 func (scope *Scope) joinsSQL() string {
 	var joinConditions []string
 	var joinConditions []string
 	for _, clause := range scope.Search.joinConditions {
 	for _, clause := range scope.Search.joinConditions {
-		if sql := scope.buildWhereCondition(clause); sql != "" {
+		if sql := scope.buildCondition(clause, true); sql != "" {
 			joinConditions = append(joinConditions, strings.TrimSuffix(strings.TrimPrefix(sql, "("), ")"))
 			joinConditions = append(joinConditions, strings.TrimSuffix(strings.TrimPrefix(sql, "("), ")"))
 		}
 		}
 	}
 	}
@@ -924,14 +950,34 @@ func (scope *Scope) initialize() *Scope {
 	return scope
 	return scope
 }
 }
 
 
+func (scope *Scope) isQueryForColumn(query interface{}, column string) bool {
+	queryStr := strings.ToLower(fmt.Sprint(query))
+	if queryStr == column {
+		return true
+	}
+
+	if strings.HasSuffix(queryStr, "as "+column) {
+		return true
+	}
+
+	if strings.HasSuffix(queryStr, "as "+scope.Quote(column)) {
+		return true
+	}
+
+	return false
+}
+
 func (scope *Scope) pluck(column string, value interface{}) *Scope {
 func (scope *Scope) pluck(column string, value interface{}) *Scope {
 	dest := reflect.Indirect(reflect.ValueOf(value))
 	dest := reflect.Indirect(reflect.ValueOf(value))
-	scope.Search.Select(column)
 	if dest.Kind() != reflect.Slice {
 	if dest.Kind() != reflect.Slice {
 		scope.Err(fmt.Errorf("results should be a slice, not %s", dest.Kind()))
 		scope.Err(fmt.Errorf("results should be a slice, not %s", dest.Kind()))
 		return scope
 		return scope
 	}
 	}
 
 
+	if query, ok := scope.Search.selects["query"]; !ok || !scope.isQueryForColumn(query, column) {
+		scope.Search.Select(column)
+	}
+
 	rows, err := scope.rows()
 	rows, err := scope.rows()
 	if scope.Err(err) == nil {
 	if scope.Err(err) == nil {
 		defer rows.Close()
 		defer rows.Close()
@@ -950,7 +996,12 @@ func (scope *Scope) pluck(column string, value interface{}) *Scope {
 
 
 func (scope *Scope) count(value interface{}) *Scope {
 func (scope *Scope) count(value interface{}) *Scope {
 	if query, ok := scope.Search.selects["query"]; !ok || !countingQueryRegexp.MatchString(fmt.Sprint(query)) {
 	if query, ok := scope.Search.selects["query"]; !ok || !countingQueryRegexp.MatchString(fmt.Sprint(query)) {
-		scope.Search.Select("count(*)")
+		if len(scope.Search.group) != 0 {
+			scope.Search.Select("count(*) FROM ( SELECT count(*) as name ")
+			scope.Search.group += " ) AS count_table"
+		} else {
+			scope.Search.Select("count(*)")
+		}
 	}
 	}
 	scope.Search.ignoreOrderQuery = true
 	scope.Search.ignoreOrderQuery = true
 	scope.Err(scope.row().Scan(value))
 	scope.Err(scope.row().Scan(value))
@@ -993,18 +1044,6 @@ func (scope *Scope) changeableField(field *Field) bool {
 	return true
 	return true
 }
 }
 
 
-func (scope *Scope) shouldSaveAssociations() bool {
-	if saveAssociations, ok := scope.Get("gorm:save_associations"); ok {
-		if v, ok := saveAssociations.(bool); ok && !v {
-			return false
-		}
-		if v, ok := saveAssociations.(string); ok && (v != "skip") {
-			return false
-		}
-	}
-	return true && !scope.HasError()
-}
-
 func (scope *Scope) related(value interface{}, foreignKeys ...string) *Scope {
 func (scope *Scope) related(value interface{}, foreignKeys ...string) *Scope {
 	toScope := scope.db.NewScope(value)
 	toScope := scope.db.NewScope(value)
 	tx := scope.db.Set("gorm:association:source", scope.Value)
 	tx := scope.db.Set("gorm:association:source", scope.Value)
@@ -1059,7 +1098,7 @@ func (scope *Scope) getTableOptions() string {
 	if !ok {
 	if !ok {
 		return ""
 		return ""
 	}
 	}
-	return tableOptions.(string)
+	return " " + tableOptions.(string)
 }
 }
 
 
 func (scope *Scope) createJoinTable(field *StructField) {
 func (scope *Scope) createJoinTable(field *StructField) {
@@ -1092,7 +1131,7 @@ func (scope *Scope) createJoinTable(field *StructField) {
 				}
 				}
 			}
 			}
 
 
-			scope.Err(scope.NewDB().Exec(fmt.Sprintf("CREATE TABLE %v (%v, PRIMARY KEY (%v)) %s", scope.Quote(joinTable), strings.Join(sqlTypes, ","), strings.Join(primaryKeys, ","), scope.getTableOptions())).Error)
+			scope.Err(scope.NewDB().Exec(fmt.Sprintf("CREATE TABLE %v (%v, PRIMARY KEY (%v))%s", scope.Quote(joinTable), strings.Join(sqlTypes, ","), strings.Join(primaryKeys, ","), scope.getTableOptions())).Error)
 		}
 		}
 		scope.NewDB().Table(joinTable).AutoMigrate(joinTableHandler)
 		scope.NewDB().Table(joinTable).AutoMigrate(joinTableHandler)
 	}
 	}
@@ -1127,19 +1166,19 @@ func (scope *Scope) createTable() *Scope {
 		primaryKeyStr = fmt.Sprintf(", PRIMARY KEY (%v)", strings.Join(primaryKeys, ","))
 		primaryKeyStr = fmt.Sprintf(", PRIMARY KEY (%v)", strings.Join(primaryKeys, ","))
 	}
 	}
 
 
-	scope.Raw(fmt.Sprintf("CREATE TABLE %v (%v %v) %s", scope.QuotedTableName(), strings.Join(tags, ","), primaryKeyStr, scope.getTableOptions())).Exec()
+	scope.Raw(fmt.Sprintf("CREATE TABLE %v (%v %v)%s", scope.QuotedTableName(), strings.Join(tags, ","), primaryKeyStr, scope.getTableOptions())).Exec()
 
 
 	scope.autoIndex()
 	scope.autoIndex()
 	return scope
 	return scope
 }
 }
 
 
 func (scope *Scope) dropTable() *Scope {
 func (scope *Scope) dropTable() *Scope {
-	scope.Raw(fmt.Sprintf("DROP TABLE %v", scope.QuotedTableName())).Exec()
+	scope.Raw(fmt.Sprintf("DROP TABLE %v%s", scope.QuotedTableName(), scope.getTableOptions())).Exec()
 	return scope
 	return scope
 }
 }
 
 
 func (scope *Scope) modifyColumn(column string, typ string) {
 func (scope *Scope) modifyColumn(column string, typ string) {
-	scope.Raw(fmt.Sprintf("ALTER TABLE %v MODIFY %v %v", scope.QuotedTableName(), scope.Quote(column), typ)).Exec()
+	scope.db.AddError(scope.Dialect().ModifyColumn(scope.QuotedTableName(), scope.Quote(column), typ))
 }
 }
 
 
 func (scope *Scope) dropColumn(column string) {
 func (scope *Scope) dropColumn(column string) {
@@ -1165,7 +1204,8 @@ func (scope *Scope) addIndex(unique bool, indexName string, column ...string) {
 }
 }
 
 
 func (scope *Scope) addForeignKey(field string, dest string, onDelete string, onUpdate string) {
 func (scope *Scope) addForeignKey(field string, dest string, onDelete string, onUpdate string) {
-	keyName := scope.Dialect().BuildForeignKeyName(scope.TableName(), field, dest)
+	// Compatible with old generated key
+	keyName := scope.Dialect().BuildKeyName(scope.TableName(), field, dest, "foreign")
 
 
 	if scope.Dialect().HasForeignKey(scope.TableName(), keyName) {
 	if scope.Dialect().HasForeignKey(scope.TableName(), keyName) {
 		return
 		return
@@ -1174,6 +1214,16 @@ func (scope *Scope) addForeignKey(field string, dest string, onDelete string, on
 	scope.Raw(fmt.Sprintf(query, scope.QuotedTableName(), scope.quoteIfPossible(keyName), scope.quoteIfPossible(field), dest, onDelete, onUpdate)).Exec()
 	scope.Raw(fmt.Sprintf(query, scope.QuotedTableName(), scope.quoteIfPossible(keyName), scope.quoteIfPossible(field), dest, onDelete, onUpdate)).Exec()
 }
 }
 
 
+func (scope *Scope) removeForeignKey(field string, dest string) {
+	keyName := scope.Dialect().BuildKeyName(scope.TableName(), field, dest)
+
+	if !scope.Dialect().HasForeignKey(scope.TableName(), keyName) {
+		return
+	}
+	var query = `ALTER TABLE %s DROP CONSTRAINT %s;`
+	scope.Raw(fmt.Sprintf(query, scope.QuotedTableName(), scope.quoteIfPossible(keyName))).Exec()
+}
+
 func (scope *Scope) removeIndex(indexName string) {
 func (scope *Scope) removeIndex(indexName string) {
 	scope.Dialect().RemoveIndex(scope.TableName(), indexName)
 	scope.Dialect().RemoveIndex(scope.TableName(), indexName)
 }
 }
@@ -1209,7 +1259,7 @@ func (scope *Scope) autoIndex() *Scope {
 
 
 			for _, name := range names {
 			for _, name := range names {
 				if name == "INDEX" || name == "" {
 				if name == "INDEX" || name == "" {
-					name = fmt.Sprintf("idx_%v_%v", scope.TableName(), field.DBName)
+					name = scope.Dialect().BuildKeyName("idx", scope.TableName(), field.DBName)
 				}
 				}
 				indexes[name] = append(indexes[name], field.DBName)
 				indexes[name] = append(indexes[name], field.DBName)
 			}
 			}
@@ -1220,7 +1270,7 @@ func (scope *Scope) autoIndex() *Scope {
 
 
 			for _, name := range names {
 			for _, name := range names {
 				if name == "UNIQUE_INDEX" || name == "" {
 				if name == "UNIQUE_INDEX" || name == "" {
-					name = fmt.Sprintf("uix_%v_%v", scope.TableName(), field.DBName)
+					name = scope.Dialect().BuildKeyName("uix", scope.TableName(), field.DBName)
 				}
 				}
 				uniqueIndexes[name] = append(uniqueIndexes[name], field.DBName)
 				uniqueIndexes[name] = append(uniqueIndexes[name], field.DBName)
 			}
 			}
@@ -1228,11 +1278,15 @@ func (scope *Scope) autoIndex() *Scope {
 	}
 	}
 
 
 	for name, columns := range indexes {
 	for name, columns := range indexes {
-		scope.NewDB().Model(scope.Value).AddIndex(name, columns...)
+		if db := scope.NewDB().Table(scope.TableName()).Model(scope.Value).AddIndex(name, columns...); db.Error != nil {
+			scope.db.AddError(db.Error)
+		}
 	}
 	}
 
 
 	for name, columns := range uniqueIndexes {
 	for name, columns := range uniqueIndexes {
-		scope.NewDB().Model(scope.Value).AddUniqueIndex(name, columns...)
+		if db := scope.NewDB().Table(scope.TableName()).Model(scope.Value).AddUniqueIndex(name, columns...); db.Error != nil {
+			scope.db.AddError(db.Error)
+		}
 	}
 	}
 
 
 	return scope
 	return scope

+ 0 - 7
vendor/github.com/jinzhu/gorm/search.go

@@ -2,7 +2,6 @@ package gorm
 
 
 import (
 import (
 	"fmt"
 	"fmt"
-	"regexp"
 )
 )
 
 
 type search struct {
 type search struct {
@@ -73,13 +72,7 @@ func (s *search) Order(value interface{}, reorder ...bool) *search {
 	return s
 	return s
 }
 }
 
 
-var distinctSQLRegexp = regexp.MustCompile(`(?i)distinct[^a-z]+[a-z]+`)
-
 func (s *search) Select(query interface{}, args ...interface{}) *search {
 func (s *search) Select(query interface{}, args ...interface{}) *search {
-	if distinctSQLRegexp.MatchString(fmt.Sprint(query)) {
-		s.ignoreOrderQuery = true
-	}
-
 	s.selects = map[string]interface{}{"query": query, "args": args}
 	s.selects = map[string]interface{}{"query": query, "args": args}
 	return s
 	return s
 }
 }

+ 1 - 1
vendor/github.com/jinzhu/gorm/test_all.sh

@@ -1,5 +1,5 @@
 dialects=("postgres" "mysql" "mssql" "sqlite")
 dialects=("postgres" "mysql" "mssql" "sqlite")
 
 
 for dialect in "${dialects[@]}" ; do
 for dialect in "${dialects[@]}" ; do
-    GORM_DIALECT=${dialect} go test
+    DEBUG=false GORM_DIALECT=${dialect} go test
 done
 done

+ 1 - 1
vendor/github.com/jinzhu/gorm/utils.go

@@ -23,7 +23,7 @@ var NowFunc = func() time.Time {
 }
 }
 
 
 // Copied from golint
 // Copied from golint
-var commonInitialisms = []string{"API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SSH", "TLS", "TTL", "UI", "UID", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XSRF", "XSS"}
+var commonInitialisms = []string{"API", "ASCII", "CPU", "CSS", "DNS", "EOF", "GUID", "HTML", "HTTP", "HTTPS", "ID", "IP", "JSON", "LHS", "QPS", "RAM", "RHS", "RPC", "SLA", "SMTP", "SSH", "TLS", "TTL", "UID", "UI", "UUID", "URI", "URL", "UTF8", "VM", "XML", "XSRF", "XSS"}
 var commonInitialismsReplacer *strings.Replacer
 var commonInitialismsReplacer *strings.Replacer
 
 
 var goSrcRegexp = regexp.MustCompile(`jinzhu/gorm/.*.go`)
 var goSrcRegexp = regexp.MustCompile(`jinzhu/gorm/.*.go`)

+ 111 - 4
vendor/github.com/jinzhu/gorm/wercker.yml

@@ -2,17 +2,79 @@
 box: golang
 box: golang
 
 
 services:
 services:
-    - id: mariadb:10.0
+    - name: mariadb
+      id: mariadb:latest
       env:
       env:
           MYSQL_DATABASE: gorm
           MYSQL_DATABASE: gorm
           MYSQL_USER: gorm
           MYSQL_USER: gorm
           MYSQL_PASSWORD: gorm
           MYSQL_PASSWORD: gorm
           MYSQL_RANDOM_ROOT_PASSWORD: "yes"
           MYSQL_RANDOM_ROOT_PASSWORD: "yes"
-    - id: postgres
+    - name: mysql
+      id: mysql:8
+      env:
+          MYSQL_DATABASE: gorm
+          MYSQL_USER: gorm
+          MYSQL_PASSWORD: gorm
+          MYSQL_RANDOM_ROOT_PASSWORD: "yes"
+    - name: mysql57
+      id: mysql:5.7
+      env:
+          MYSQL_DATABASE: gorm
+          MYSQL_USER: gorm
+          MYSQL_PASSWORD: gorm
+          MYSQL_RANDOM_ROOT_PASSWORD: "yes"
+    - name: mysql56
+      id: mysql:5.6
+      env:
+          MYSQL_DATABASE: gorm
+          MYSQL_USER: gorm
+          MYSQL_PASSWORD: gorm
+          MYSQL_RANDOM_ROOT_PASSWORD: "yes"
+    - name: mysql55
+      id: mysql:5.5
+      env:
+          MYSQL_DATABASE: gorm
+          MYSQL_USER: gorm
+          MYSQL_PASSWORD: gorm
+          MYSQL_RANDOM_ROOT_PASSWORD: "yes"
+    - name: postgres
+      id: postgres:latest
+      env:
+          POSTGRES_USER: gorm
+          POSTGRES_PASSWORD: gorm
+          POSTGRES_DB: gorm
+    - name: postgres96
+      id: postgres:9.6
+      env:
+          POSTGRES_USER: gorm
+          POSTGRES_PASSWORD: gorm
+          POSTGRES_DB: gorm
+    - name: postgres95
+      id: postgres:9.5
+      env:
+          POSTGRES_USER: gorm
+          POSTGRES_PASSWORD: gorm
+          POSTGRES_DB: gorm
+    - name: postgres94
+      id: postgres:9.4
       env:
       env:
           POSTGRES_USER: gorm
           POSTGRES_USER: gorm
           POSTGRES_PASSWORD: gorm
           POSTGRES_PASSWORD: gorm
           POSTGRES_DB: gorm
           POSTGRES_DB: gorm
+    - name: postgres93
+      id: postgres:9.3
+      env:
+          POSTGRES_USER: gorm
+          POSTGRES_PASSWORD: gorm
+          POSTGRES_DB: gorm
+    - name: mssql
+      id: mcmoe/mssqldocker:latest
+      env:
+        ACCEPT_EULA: Y
+        SA_PASSWORD: LoremIpsum86
+        MSSQL_DB: gorm
+        MSSQL_USER: gorm
+        MSSQL_PASSWORD: LoremIpsum86
 
 
 # The steps that will be executed in the build pipeline
 # The steps that will be executed in the build pipeline
 build:
 build:
@@ -42,12 +104,57 @@ build:
                 code: |
                 code: |
                     go test ./...
                     go test ./...
 
 
+        - script:
+                name: test mariadb
+                code: |
+                    GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(mariadb:3306)/gorm?charset=utf8&parseTime=True" go test ./...
+
         - script:
         - script:
                 name: test mysql
                 name: test mysql
                 code: |
                 code: |
-                    GORM_DIALECT=mysql GORM_DBADDRESS=mariadb:3306 go test ./...
+                    GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(mysql:3306)/gorm?charset=utf8&parseTime=True" go test ./...
+
+        - script:
+                name: test mysql5.7
+                code: |
+                    GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(mysql57:3306)/gorm?charset=utf8&parseTime=True" go test ./...
+
+        - script:
+                name: test mysql5.6
+                code: |
+                    GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(mysql56:3306)/gorm?charset=utf8&parseTime=True" go test ./...
+
+        - script:
+                name: test mysql5.5
+                code: |
+                    GORM_DIALECT=mysql GORM_DSN="gorm:gorm@tcp(mysql55:3306)/gorm?charset=utf8&parseTime=True" go test ./...
 
 
         - script:
         - script:
                 name: test postgres
                 name: test postgres
                 code: |
                 code: |
-                    GORM_DIALECT=postgres GORM_DBHOST=postgres go test ./...
+                    GORM_DIALECT=postgres GORM_DSN="host=postgres user=gorm password=gorm DB.name=gorm port=5432 sslmode=disable" go test ./...
+
+        - script:
+                name: test postgres96
+                code: |
+                    GORM_DIALECT=postgres GORM_DSN="host=postgres96 user=gorm password=gorm DB.name=gorm port=5432 sslmode=disable" go test ./...
+
+        - script:
+                name: test postgres95
+                code: |
+                    GORM_DIALECT=postgres GORM_DSN="host=postgres95 user=gorm password=gorm DB.name=gorm port=5432 sslmode=disable" go test ./...
+
+        - script:
+                name: test postgres94
+                code: |
+                    GORM_DIALECT=postgres GORM_DSN="host=postgres94 user=gorm password=gorm DB.name=gorm port=5432 sslmode=disable" go test ./...
+
+        - script:
+                name: test postgres93
+                code: |
+                    GORM_DIALECT=postgres GORM_DSN="host=postgres93 user=gorm password=gorm DB.name=gorm port=5432 sslmode=disable" go test ./...
+
+        - script:
+                name: test mssql
+                code: |
+                    GORM_DIALECT=mssql GORM_DSN="sqlserver://gorm:LoremIpsum86@mssql:1433?database=gorm" go test ./...

+ 0 - 4
vendor/github.com/robfig/cron/README.md

@@ -1,6 +1,2 @@
 [![GoDoc](http://godoc.org/github.com/robfig/cron?status.png)](http://godoc.org/github.com/robfig/cron) 
 [![GoDoc](http://godoc.org/github.com/robfig/cron?status.png)](http://godoc.org/github.com/robfig/cron) 
 [![Build Status](https://travis-ci.org/robfig/cron.svg?branch=master)](https://travis-ci.org/robfig/cron)
 [![Build Status](https://travis-ci.org/robfig/cron.svg?branch=master)](https://travis-ci.org/robfig/cron)
-
-# cron
-
-Documentation here: https://godoc.org/github.com/robfig/cron

+ 3 - 3
vendor/github.com/robfig/cron/doc.go

@@ -78,7 +78,7 @@ You may use one of several pre-defined schedules in place of a cron expression.
 	-----                  | -----------                                | -------------
 	-----                  | -----------                                | -------------
 	@yearly (or @annually) | Run once a year, midnight, Jan. 1st        | 0 0 0 1 1 *
 	@yearly (or @annually) | Run once a year, midnight, Jan. 1st        | 0 0 0 1 1 *
 	@monthly               | Run once a month, midnight, first of month | 0 0 0 1 * *
 	@monthly               | Run once a month, midnight, first of month | 0 0 0 1 * *
-	@weekly                | Run once a week, midnight between Sat/Sun  | 0 0 0 * * 0
+	@weekly                | Run once a week, midnight on Sunday        | 0 0 0 * * 0
 	@daily (or @midnight)  | Run once a day, midnight                   | 0 0 0 * * *
 	@daily (or @midnight)  | Run once a day, midnight                   | 0 0 0 * * *
 	@hourly                | Run once an hour, beginning of hour        | 0 0 * * * *
 	@hourly                | Run once an hour, beginning of hour        | 0 0 * * * *
 
 
@@ -92,8 +92,8 @@ or cron is run. This is supported by formatting the cron spec like this:
 where "duration" is a string accepted by time.ParseDuration
 where "duration" is a string accepted by time.ParseDuration
 (http://golang.org/pkg/time/#ParseDuration).
 (http://golang.org/pkg/time/#ParseDuration).
 
 
-For example, "@every 1h30m10s" would indicate a schedule that activates after
-1 hour, 30 minutes, 10 seconds, and then every interval after that.
+For example, "@every 1h30m10s" would indicate a schedule that activates immediately,
+and then every 1 hour, 30 minutes, 10 seconds.
 
 
 Note: The interval does not take the job runtime into account.  For example,
 Note: The interval does not take the job runtime into account.  For example,
 if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes,
 if a job takes 3 minutes to run, and it is scheduled to run every 5 minutes,

+ 25 - 0
vendor/gogs.carducci-dante.gov.it/karmen/client/client.go

@@ -261,6 +261,31 @@ func (c *Client) GetDepartments() ([]*orm.Department, error) {
 	return departments, nil
 	return departments, nil
 }
 }
 
 
+func (c *Client) GetOffices() ([]*orm.Office, error) {
+	var (
+		response renderer.JsonResponse
+		offices  []*orm.Office
+	)
+
+	data, err := c.SendRequest("GET", "/api/offices?format=json", nil)
+	if err != nil {
+		return nil, err
+	}
+
+	if err := json.Unmarshal(data, &response); err != nil {
+		return nil, err
+	}
+
+	if string(response.Error) != "" {
+		return nil, errors.New(string(response.Error))
+	}
+
+	if err := json.Unmarshal(response.Result, &offices); err != nil {
+		return nil, err
+	}
+	return offices, nil
+}
+
 func (c *Client) GetClasses() ([]*orm.Class, error) {
 func (c *Client) GetClasses() ([]*orm.Class, error) {
 	var (
 	var (
 		response renderer.JsonResponse
 		response renderer.JsonResponse