No known key found for this signature in database
GPG Key ID: C3B7C91B632F738A
172 changed files with 28724 additions and 15831 deletions
-
14go.mod
-
124go.sum
-
15vendor/cloud.google.com/go/AUTHORS
-
40vendor/cloud.google.com/go/CONTRIBUTORS
-
202vendor/cloud.google.com/go/LICENSE
-
43vendor/github.com/denisenkom/go-mssqldb/README.md
-
51vendor/github.com/denisenkom/go-mssqldb/accesstokenconnector.go
-
6vendor/github.com/denisenkom/go-mssqldb/appveyor.yml
-
24vendor/github.com/denisenkom/go-mssqldb/buf.go
-
111vendor/github.com/denisenkom/go-mssqldb/bulkcopy.go
-
471vendor/github.com/denisenkom/go-mssqldb/conn_str.go
-
131vendor/github.com/denisenkom/go-mssqldb/decimal.go
-
6vendor/github.com/denisenkom/go-mssqldb/go.mod
-
167vendor/github.com/denisenkom/go-mssqldb/go.sum
-
252vendor/github.com/denisenkom/go-mssqldb/internal/decimal/decimal.go
-
12vendor/github.com/denisenkom/go-mssqldb/internal/querytext/parser.go
-
48vendor/github.com/denisenkom/go-mssqldb/mssql.go
-
5vendor/github.com/denisenkom/go-mssqldb/mssql_go110.go
-
31vendor/github.com/denisenkom/go-mssqldb/mssql_go110pre.go
-
2vendor/github.com/denisenkom/go-mssqldb/mssql_go19.go
-
137vendor/github.com/denisenkom/go-mssqldb/net.go
-
165vendor/github.com/denisenkom/go-mssqldb/ntlm.go
-
625vendor/github.com/denisenkom/go-mssqldb/tds.go
-
19vendor/github.com/denisenkom/go-mssqldb/token.go
-
18vendor/github.com/denisenkom/go-mssqldb/types.go
-
6vendor/github.com/denisenkom/go-mssqldb/uniqueidentifier.go
-
28vendor/github.com/go-sql-driver/mysql/.travis.yml
-
16vendor/github.com/go-sql-driver/mysql/AUTHORS
-
28vendor/github.com/go-sql-driver/mysql/CHANGELOG.md
-
23vendor/github.com/go-sql-driver/mysql/CONTRIBUTING.md
-
39vendor/github.com/go-sql-driver/mysql/README.md
-
8vendor/github.com/go-sql-driver/mysql/auth.go
-
93vendor/github.com/go-sql-driver/mysql/buffer.go
-
180vendor/github.com/go-sql-driver/mysql/collations.go
-
54vendor/github.com/go-sql-driver/mysql/conncheck.go
-
12vendor/github.com/go-sql-driver/mysql/conncheck_dummy.go
-
220vendor/github.com/go-sql-driver/mysql/connection.go
-
207vendor/github.com/go-sql-driver/mysql/connection_go18.go
-
146vendor/github.com/go-sql-driver/mysql/connector.go
-
157vendor/github.com/go-sql-driver/mysql/driver.go
-
225vendor/github.com/go-sql-driver/mysql/dsn.go
-
3vendor/github.com/go-sql-driver/mysql/go.mod
-
50vendor/github.com/go-sql-driver/mysql/nulltime.go
-
31vendor/github.com/go-sql-driver/mysql/nulltime_go113.go
-
34vendor/github.com/go-sql-driver/mysql/nulltime_legacy.go
-
104vendor/github.com/go-sql-driver/mysql/packets.go
-
7vendor/github.com/go-sql-driver/mysql/rows.go
-
11vendor/github.com/go-sql-driver/mysql/statement.go
-
91vendor/github.com/go-sql-driver/mysql/utils.go
-
40vendor/github.com/go-sql-driver/mysql/utils_go17.go
-
50vendor/github.com/go-sql-driver/mysql/utils_go18.go
-
73vendor/github.com/golang-sql/civil/CONTRIBUTING.md
-
0vendor/github.com/golang-sql/civil/LICENSE
-
15vendor/github.com/golang-sql/civil/README.md
-
0vendor/github.com/golang-sql/civil/civil.go
-
13vendor/github.com/lib/pq/.travis.sh
-
16vendor/github.com/lib/pq/.travis.yml
-
29vendor/github.com/lib/pq/CONTRIBUTING.md
-
78vendor/github.com/lib/pq/README.md
-
2vendor/github.com/lib/pq/buf.go
-
370vendor/github.com/lib/pq/conn.go
-
28vendor/github.com/lib/pq/conn_go18.go
-
96vendor/github.com/lib/pq/connector.go
-
6vendor/github.com/lib/pq/copy.go
-
20vendor/github.com/lib/pq/doc.go
-
31vendor/github.com/lib/pq/encode.go
-
10vendor/github.com/lib/pq/error.go
-
2vendor/github.com/lib/pq/go.mod
-
27vendor/github.com/lib/pq/krb.go
-
71vendor/github.com/lib/pq/notice.go
-
63vendor/github.com/lib/pq/notify.go
-
264vendor/github.com/lib/pq/scram/scram.go
-
8vendor/github.com/lib/pq/ssl.go
-
14vendor/github.com/lib/pq/ssl_go1.7.go
-
8vendor/github.com/lib/pq/ssl_renegotiation.go
-
2vendor/github.com/lib/pq/user_posix.go
-
32vendor/github.com/mattn/go-sqlite3/.travis.yml
-
105vendor/github.com/mattn/go-sqlite3/README.md
-
8vendor/github.com/mattn/go-sqlite3/backup.go
-
28vendor/github.com/mattn/go-sqlite3/callback.go
-
299vendor/github.com/mattn/go-sqlite3/convert.go
-
21vendor/github.com/mattn/go-sqlite3/error.go
-
8vendor/github.com/mattn/go-sqlite3/go.mod
-
13vendor/github.com/mattn/go-sqlite3/go.sum
-
32105vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c
-
1101vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
-
235vendor/github.com/mattn/go-sqlite3/sqlite3.go
-
2vendor/github.com/mattn/go-sqlite3/sqlite3_context.go
-
4vendor/github.com/mattn/go-sqlite3/sqlite3_func_crypt.go
-
6vendor/github.com/mattn/go-sqlite3/sqlite3_go18.go
-
3vendor/github.com/mattn/go-sqlite3/sqlite3_libsqlite3.go
-
40vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension.go
-
2vendor/github.com/mattn/go-sqlite3/sqlite3_load_extension_omit.go
-
2vendor/github.com/mattn/go-sqlite3/sqlite3_opt_allow_uri_authority.go
-
4vendor/github.com/mattn/go-sqlite3/sqlite3_opt_app_armor.go
-
2vendor/github.com/mattn/go-sqlite3/sqlite3_opt_foreign_keys.go
-
2vendor/github.com/mattn/go-sqlite3/sqlite3_opt_fts5.go
-
2vendor/github.com/mattn/go-sqlite3/sqlite3_opt_icu.go
-
2vendor/github.com/mattn/go-sqlite3/sqlite3_opt_introspect.go
-
2vendor/github.com/mattn/go-sqlite3/sqlite3_opt_json1.go
@ -1,15 +0,0 @@ |
|||
# This is the official list of cloud authors for copyright purposes. |
|||
# This file is distinct from the CONTRIBUTORS files. |
|||
# See the latter for an explanation. |
|||
|
|||
# Names should be added to this file as: |
|||
# Name or Organization <email address> |
|||
# The email address is not required for organizations. |
|||
|
|||
Filippo Valsorda <hi@filippo.io> |
|||
Google Inc. |
|||
Ingo Oeser <nightlyone@googlemail.com> |
|||
Palm Stone Games, Inc. |
|||
Paweł Knap <pawelknap88@gmail.com> |
|||
Péter Szilágyi <peterke@gmail.com> |
|||
Tyler Treat <ttreat31@gmail.com> |
@ -1,40 +0,0 @@ |
|||
# People who have agreed to one of the CLAs and can contribute patches. |
|||
# The AUTHORS file lists the copyright holders; this file |
|||
# lists people. For example, Google employees are listed here |
|||
# but not in AUTHORS, because Google holds the copyright. |
|||
# |
|||
# https://developers.google.com/open-source/cla/individual |
|||
# https://developers.google.com/open-source/cla/corporate |
|||
# |
|||
# Names should be added to this file as: |
|||
# Name <email address> |
|||
|
|||
# Keep the list alphabetically sorted. |
|||
|
|||
Alexis Hunt <lexer@google.com> |
|||
Andreas Litt <andreas.litt@gmail.com> |
|||
Andrew Gerrand <adg@golang.org> |
|||
Brad Fitzpatrick <bradfitz@golang.org> |
|||
Burcu Dogan <jbd@google.com> |
|||
Dave Day <djd@golang.org> |
|||
David Sansome <me@davidsansome.com> |
|||
David Symonds <dsymonds@golang.org> |
|||
Filippo Valsorda <hi@filippo.io> |
|||
Glenn Lewis <gmlewis@google.com> |
|||
Ingo Oeser <nightlyone@googlemail.com> |
|||
James Hall <james.hall@shopify.com> |
|||
Johan Euphrosine <proppy@google.com> |
|||
Jonathan Amsterdam <jba@google.com> |
|||
Kunpei Sakai <namusyaka@gmail.com> |
|||
Luna Duclos <luna.duclos@palmstonegames.com> |
|||
Magnus Hiie <magnus.hiie@gmail.com> |
|||
Mario Castro <mariocaster@gmail.com> |
|||
Michael McGreevy <mcgreevy@golang.org> |
|||
Omar Jarjur <ojarjur@google.com> |
|||
Paweł Knap <pawelknap88@gmail.com> |
|||
Péter Szilágyi <peterke@gmail.com> |
|||
Sarah Adams <shadams@google.com> |
|||
Thanatat Tamtan <acoshift@gmail.com> |
|||
Toby Burress <kurin@google.com> |
|||
Tuo Shan <shantuo@google.com> |
|||
Tyler Treat <ttreat31@gmail.com> |
@ -1,202 +0,0 @@ |
|||
|
|||
Apache License |
|||
Version 2.0, January 2004 |
|||
http://www.apache.org/licenses/ |
|||
|
|||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION |
|||
|
|||
1. Definitions. |
|||
|
|||
"License" shall mean the terms and conditions for use, reproduction, |
|||
and distribution as defined by Sections 1 through 9 of this document. |
|||
|
|||
"Licensor" shall mean the copyright owner or entity authorized by |
|||
the copyright owner that is granting the License. |
|||
|
|||
"Legal Entity" shall mean the union of the acting entity and all |
|||
other entities that control, are controlled by, or are under common |
|||
control with that entity. For the purposes of this definition, |
|||
"control" means (i) the power, direct or indirect, to cause the |
|||
direction or management of such entity, whether by contract or |
|||
otherwise, or (ii) ownership of fifty percent (50%) or more of the |
|||
outstanding shares, or (iii) beneficial ownership of such entity. |
|||
|
|||
"You" (or "Your") shall mean an individual or Legal Entity |
|||
exercising permissions granted by this License. |
|||
|
|||
"Source" form shall mean the preferred form for making modifications, |
|||
including but not limited to software source code, documentation |
|||
source, and configuration files. |
|||
|
|||
"Object" form shall mean any form resulting from mechanical |
|||
transformation or translation of a Source form, including but |
|||
not limited to compiled object code, generated documentation, |
|||
and conversions to other media types. |
|||
|
|||
"Work" shall mean the work of authorship, whether in Source or |
|||
Object form, made available under the License, as indicated by a |
|||
copyright notice that is included in or attached to the work |
|||
(an example is provided in the Appendix below). |
|||
|
|||
"Derivative Works" shall mean any work, whether in Source or Object |
|||
form, that is based on (or derived from) the Work and for which the |
|||
editorial revisions, annotations, elaborations, or other modifications |
|||
represent, as a whole, an original work of authorship. For the purposes |
|||
of this License, Derivative Works shall not include works that remain |
|||
separable from, or merely link (or bind by name) to the interfaces of, |
|||
the Work and Derivative Works thereof. |
|||
|
|||
"Contribution" shall mean any work of authorship, including |
|||
the original version of the Work and any modifications or additions |
|||
to that Work or Derivative Works thereof, that is intentionally |
|||
submitted to Licensor for inclusion in the Work by the copyright owner |
|||
or by an individual or Legal Entity authorized to submit on behalf of |
|||
the copyright owner. For the purposes of this definition, "submitted" |
|||
means any form of electronic, verbal, or written communication sent |
|||
to the Licensor or its representatives, including but not limited to |
|||
communication on electronic mailing lists, source code control systems, |
|||
and issue tracking systems that are managed by, or on behalf of, the |
|||
Licensor for the purpose of discussing and improving the Work, but |
|||
excluding communication that is conspicuously marked or otherwise |
|||
designated in writing by the copyright owner as "Not a Contribution." |
|||
|
|||
"Contributor" shall mean Licensor and any individual or Legal Entity |
|||
on behalf of whom a Contribution has been received by Licensor and |
|||
subsequently incorporated within the Work. |
|||
|
|||
2. Grant of Copyright License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
copyright license to reproduce, prepare Derivative Works of, |
|||
publicly display, publicly perform, sublicense, and distribute the |
|||
Work and such Derivative Works in Source or Object form. |
|||
|
|||
3. Grant of Patent License. Subject to the terms and conditions of |
|||
this License, each Contributor hereby grants to You a perpetual, |
|||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable |
|||
(except as stated in this section) patent license to make, have made, |
|||
use, offer to sell, sell, import, and otherwise transfer the Work, |
|||
where such license applies only to those patent claims licensable |
|||
by such Contributor that are necessarily infringed by their |
|||
Contribution(s) alone or by combination of their Contribution(s) |
|||
with the Work to which such Contribution(s) was submitted. If You |
|||
institute patent litigation against any entity (including a |
|||
cross-claim or counterclaim in a lawsuit) alleging that the Work |
|||
or a Contribution incorporated within the Work constitutes direct |
|||
or contributory patent infringement, then any patent licenses |
|||
granted to You under this License for that Work shall terminate |
|||
as of the date such litigation is filed. |
|||
|
|||
4. Redistribution. You may reproduce and distribute copies of the |
|||
Work or Derivative Works thereof in any medium, with or without |
|||
modifications, and in Source or Object form, provided that You |
|||
meet the following conditions: |
|||
|
|||
(a) You must give any other recipients of the Work or |
|||
Derivative Works a copy of this License; and |
|||
|
|||
(b) You must cause any modified files to carry prominent notices |
|||
stating that You changed the files; and |
|||
|
|||
(c) You must retain, in the Source form of any Derivative Works |
|||
that You distribute, all copyright, patent, trademark, and |
|||
attribution notices from the Source form of the Work, |
|||
excluding those notices that do not pertain to any part of |
|||
the Derivative Works; and |
|||
|
|||
(d) If the Work includes a "NOTICE" text file as part of its |
|||
distribution, then any Derivative Works that You distribute must |
|||
include a readable copy of the attribution notices contained |
|||
within such NOTICE file, excluding those notices that do not |
|||
pertain to any part of the Derivative Works, in at least one |
|||
of the following places: within a NOTICE text file distributed |
|||
as part of the Derivative Works; within the Source form or |
|||
documentation, if provided along with the Derivative Works; or, |
|||
within a display generated by the Derivative Works, if and |
|||
wherever such third-party notices normally appear. The contents |
|||
of the NOTICE file are for informational purposes only and |
|||
do not modify the License. You may add Your own attribution |
|||
notices within Derivative Works that You distribute, alongside |
|||
or as an addendum to the NOTICE text from the Work, provided |
|||
that such additional attribution notices cannot be construed |
|||
as modifying the License. |
|||
|
|||
You may add Your own copyright statement to Your modifications and |
|||
may provide additional or different license terms and conditions |
|||
for use, reproduction, or distribution of Your modifications, or |
|||
for any such Derivative Works as a whole, provided Your use, |
|||
reproduction, and distribution of the Work otherwise complies with |
|||
the conditions stated in this License. |
|||
|
|||
5. Submission of Contributions. Unless You explicitly state otherwise, |
|||
any Contribution intentionally submitted for inclusion in the Work |
|||
by You to the Licensor shall be under the terms and conditions of |
|||
this License, without any additional terms or conditions. |
|||
Notwithstanding the above, nothing herein shall supersede or modify |
|||
the terms of any separate license agreement you may have executed |
|||
with Licensor regarding such Contributions. |
|||
|
|||
6. Trademarks. This License does not grant permission to use the trade |
|||
names, trademarks, service marks, or product names of the Licensor, |
|||
except as required for reasonable and customary use in describing the |
|||
origin of the Work and reproducing the content of the NOTICE file. |
|||
|
|||
7. Disclaimer of Warranty. Unless required by applicable law or |
|||
agreed to in writing, Licensor provides the Work (and each |
|||
Contributor provides its Contributions) on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or |
|||
implied, including, without limitation, any warranties or conditions |
|||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A |
|||
PARTICULAR PURPOSE. You are solely responsible for determining the |
|||
appropriateness of using or redistributing the Work and assume any |
|||
risks associated with Your exercise of permissions under this License. |
|||
|
|||
8. Limitation of Liability. In no event and under no legal theory, |
|||
whether in tort (including negligence), contract, or otherwise, |
|||
unless required by applicable law (such as deliberate and grossly |
|||
negligent acts) or agreed to in writing, shall any Contributor be |
|||
liable to You for damages, including any direct, indirect, special, |
|||
incidental, or consequential damages of any character arising as a |
|||
result of this License or out of the use or inability to use the |
|||
Work (including but not limited to damages for loss of goodwill, |
|||
work stoppage, computer failure or malfunction, or any and all |
|||
other commercial damages or losses), even if such Contributor |
|||
has been advised of the possibility of such damages. |
|||
|
|||
9. Accepting Warranty or Additional Liability. While redistributing |
|||
the Work or Derivative Works thereof, You may choose to offer, |
|||
and charge a fee for, acceptance of support, warranty, indemnity, |
|||
or other liability obligations and/or rights consistent with this |
|||
License. However, in accepting such obligations, You may act only |
|||
on Your own behalf and on Your sole responsibility, not on behalf |
|||
of any other Contributor, and only if You agree to indemnify, |
|||
defend, and hold each Contributor harmless for any liability |
|||
incurred by, or claims asserted against, such Contributor by reason |
|||
of your accepting any such warranty or additional liability. |
|||
|
|||
END OF TERMS AND CONDITIONS |
|||
|
|||
APPENDIX: How to apply the Apache License to your work. |
|||
|
|||
To apply the Apache License to your work, attach the following |
|||
boilerplate notice, with the fields enclosed by brackets "[]" |
|||
replaced with your own identifying information. (Don't include |
|||
the brackets!) The text should be enclosed in the appropriate |
|||
comment syntax for the file format. We also recommend that a |
|||
file or class name and description of purpose be included on the |
|||
same "printed page" as the copyright notice for easier |
|||
identification within third-party archives. |
|||
|
|||
Copyright [yyyy] [name of copyright owner] |
|||
|
|||
Licensed under the Apache License, Version 2.0 (the "License"); |
|||
you may not use this file except in compliance with the License. |
|||
You may obtain a copy of the License at |
|||
|
|||
http://www.apache.org/licenses/LICENSE-2.0 |
|||
|
|||
Unless required by applicable law or agreed to in writing, software |
|||
distributed under the License is distributed on an "AS IS" BASIS, |
|||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|||
See the License for the specific language governing permissions and |
|||
limitations under the License. |
@ -0,0 +1,51 @@ |
|||
// +build go1.10
|
|||
|
|||
package mssql |
|||
|
|||
import ( |
|||
"context" |
|||
"database/sql/driver" |
|||
"errors" |
|||
"fmt" |
|||
) |
|||
|
|||
var _ driver.Connector = &accessTokenConnector{} |
|||
|
|||
// accessTokenConnector wraps Connector and injects a
|
|||
// fresh access token when connecting to the database
|
|||
type accessTokenConnector struct { |
|||
Connector |
|||
|
|||
accessTokenProvider func() (string, error) |
|||
} |
|||
|
|||
// NewAccessTokenConnector creates a new connector from a DSN and a token provider.
|
|||
// The token provider func will be called when a new connection is requested and should return a valid access token.
|
|||
// The returned connector may be used with sql.OpenDB.
|
|||
func NewAccessTokenConnector(dsn string, tokenProvider func() (string, error)) (driver.Connector, error) { |
|||
if tokenProvider == nil { |
|||
return nil, errors.New("mssql: tokenProvider cannot be nil") |
|||
} |
|||
|
|||
conn, err := NewConnector(dsn) |
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
c := &accessTokenConnector{ |
|||
Connector: *conn, |
|||
accessTokenProvider: tokenProvider, |
|||
} |
|||
return c, nil |
|||
} |
|||
|
|||
// Connect returns a new database connection
|
|||
func (c *accessTokenConnector) Connect(ctx context.Context) (driver.Conn, error) { |
|||
var err error |
|||
c.Connector.params.fedAuthAccessToken, err = c.accessTokenProvider() |
|||
if err != nil { |
|||
return nil, fmt.Errorf("mssql: error retrieving access token: %+v", err) |
|||
} |
|||
|
|||
return c.Connector.Connect(ctx) |
|||
} |
@ -0,0 +1,471 @@ |
|||
package mssql |
|||
|
|||
import ( |
|||
"fmt" |
|||
"net" |
|||
"net/url" |
|||
"os" |
|||
"strconv" |
|||
"strings" |
|||
"time" |
|||
"unicode" |
|||
) |
|||
|
|||
const defaultServerPort = 1433 |
|||
|
|||
type connectParams struct { |
|||
logFlags uint64 |
|||
port uint64 |
|||
host string |
|||
instance string |
|||
database string |
|||
user string |
|||
password string |
|||
dial_timeout time.Duration |
|||
conn_timeout time.Duration |
|||
keepAlive time.Duration |
|||
encrypt bool |
|||
disableEncryption bool |
|||
trustServerCertificate bool |
|||
certificate string |
|||
hostInCertificate string |
|||
hostInCertificateProvided bool |
|||
serverSPN string |
|||
workstation string |
|||
appname string |
|||
typeFlags uint8 |
|||
failOverPartner string |
|||
failOverPort uint64 |
|||
packetSize uint16 |
|||
fedAuthAccessToken string |
|||
} |
|||
|
|||
func parseConnectParams(dsn string) (connectParams, error) { |
|||
var p connectParams |
|||
|
|||
var params map[string]string |
|||
if strings.HasPrefix(dsn, "odbc:") { |
|||
parameters, err := splitConnectionStringOdbc(dsn[len("odbc:"):]) |
|||
if err != nil { |
|||
return p, err |
|||
} |
|||
params = parameters |
|||
} else if strings.HasPrefix(dsn, "sqlserver://") { |
|||
parameters, err := splitConnectionStringURL(dsn) |
|||
if err != nil { |
|||
return p, err |
|||
} |
|||
params = parameters |
|||
} else { |
|||
params = splitConnectionString(dsn) |
|||
} |
|||
|
|||
strlog, ok := params["log"] |
|||
if ok { |
|||
var err error |
|||
p.logFlags, err = strconv.ParseUint(strlog, 10, 64) |
|||
if err != nil { |
|||
return p, fmt.Errorf("Invalid log parameter '%s': %s", strlog, err.Error()) |
|||
} |
|||
} |
|||
server := params["server"] |
|||
parts := strings.SplitN(server, `\`, 2) |
|||
p.host = parts[0] |
|||
if p.host == "." || strings.ToUpper(p.host) == "(LOCAL)" || p.host == "" { |
|||
p.host = "localhost" |
|||
} |
|||
if len(parts) > 1 { |
|||
p.instance = parts[1] |
|||
} |
|||
p.database = params["database"] |
|||
p.user = params["user id"] |
|||
p.password = params["password"] |
|||
|
|||
p.port = 0 |
|||
strport, ok := params["port"] |
|||
if ok { |
|||
var err error |
|||
p.port, err = strconv.ParseUint(strport, 10, 16) |
|||
if err != nil { |
|||
f := "Invalid tcp port '%v': %v" |
|||
return p, fmt.Errorf(f, strport, err.Error()) |
|||
} |
|||
} |
|||
|
|||
// https://docs.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-network-packet-size-server-configuration-option
|
|||
// Default packet size remains at 4096 bytes
|
|||
p.packetSize = 4096 |
|||
strpsize, ok := params["packet size"] |
|||
if ok { |
|||
var err error |
|||
psize, err := strconv.ParseUint(strpsize, 0, 16) |
|||
if err != nil { |
|||
f := "Invalid packet size '%v': %v" |
|||
return p, fmt.Errorf(f, strpsize, err.Error()) |
|||
} |
|||
|
|||
// Ensure packet size falls within the TDS protocol range of 512 to 32767 bytes
|
|||
// NOTE: Encrypted connections have a maximum size of 16383 bytes. If you request
|
|||
// a higher packet size, the server will respond with an ENVCHANGE request to
|
|||
// alter the packet size to 16383 bytes.
|
|||
p.packetSize = uint16(psize) |
|||
if p.packetSize < 512 { |
|||
p.packetSize = 512 |
|||
} else if p.packetSize > 32767 { |
|||
p.packetSize = 32767 |
|||
} |
|||
} |
|||
|
|||
// https://msdn.microsoft.com/en-us/library/dd341108.aspx
|
|||
//
|
|||
// Do not set a connection timeout. Use Context to manage such things.
|
|||
// Default to zero, but still allow it to be set.
|
|||
if strconntimeout, ok := params["connection timeout"]; ok { |
|||
timeout, err := strconv.ParseUint(strconntimeout, 10, 64) |
|||
if err != nil { |
|||
f := "Invalid connection timeout '%v': %v" |
|||
return p, fmt.Errorf(f, strconntimeout, err.Error()) |
|||
} |
|||
p.conn_timeout = time.Duration(timeout) * time.Second |
|||
} |
|||
p.dial_timeout = 15 * time.Second |
|||
if strdialtimeout, ok := params["dial timeout"]; ok { |
|||
timeout, err := strconv.ParseUint(strdialtimeout, 10, 64) |
|||
if err != nil { |
|||
f := "Invalid dial timeout '%v': %v" |
|||
return p, fmt.Errorf(f, strdialtimeout, err.Error()) |
|||
} |
|||
p.dial_timeout = time.Duration(timeout) * time.Second |
|||
} |
|||
|
|||
// default keep alive should be 30 seconds according to spec:
|
|||
// https://msdn.microsoft.com/en-us/library/dd341108.aspx
|
|||
p.keepAlive = 30 * time.Second |
|||
if keepAlive, ok := params["keepalive"]; ok { |
|||
timeout, err := strconv.ParseUint(keepAlive, 10, 64) |
|||
if err != nil { |
|||
f := "Invalid keepAlive value '%s': %s" |
|||
return p, fmt.Errorf(f, keepAlive, err.Error()) |
|||
} |
|||
p.keepAlive = time.Duration(timeout) * time.Second |
|||
} |
|||
encrypt, ok := params["encrypt"] |
|||
if ok { |
|||
if strings.EqualFold(encrypt, "DISABLE") { |
|||
p.disableEncryption = true |
|||
} else { |
|||
var err error |
|||
p.encrypt, err = strconv.ParseBool(encrypt) |
|||
if err != nil { |
|||
f := "Invalid encrypt '%s': %s" |
|||
return p, fmt.Errorf(f, encrypt, err.Error()) |
|||
} |
|||
} |
|||
} else { |
|||
p.trustServerCertificate = true |
|||
} |
|||
trust, ok := params["trustservercertificate"] |
|||
if ok { |
|||
var err error |
|||
p.trustServerCertificate, err = strconv.ParseBool(trust) |
|||
if err != nil { |
|||
f := "Invalid trust server certificate '%s': %s" |
|||
return p, fmt.Errorf(f, trust, err.Error()) |
|||
} |
|||
} |
|||
p.certificate = params["certificate"] |
|||
p.hostInCertificate, ok = params["hostnameincertificate"] |
|||
if ok { |
|||
p.hostInCertificateProvided = true |
|||
} else { |
|||
p.hostInCertificate = p.host |
|||
p.hostInCertificateProvided = false |
|||
} |
|||
|
|||
serverSPN, ok := params["serverspn"] |
|||
if ok { |
|||
p.serverSPN = serverSPN |
|||
} else { |
|||
p.serverSPN = generateSpn(p.host, resolveServerPort(p.port)) |
|||
} |
|||
|
|||
workstation, ok := params["workstation id"] |
|||
if ok { |
|||
p.workstation = workstation |
|||
} else { |
|||
workstation, err := os.Hostname() |
|||
if err == nil { |
|||
p.workstation = workstation |
|||
} |
|||
} |
|||
|
|||
appname, ok := params["app name"] |
|||
if !ok { |
|||
appname = "go-mssqldb" |
|||
} |
|||
p.appname = appname |
|||
|
|||
appintent, ok := params["applicationintent"] |
|||
if ok { |
|||
if appintent == "ReadOnly" { |
|||
if p.database == "" { |
|||
return p, fmt.Errorf("Database must be specified when ApplicationIntent is ReadOnly") |
|||
} |
|||
p.typeFlags |= fReadOnlyIntent |
|||
} |
|||
} |
|||
|
|||
failOverPartner, ok := params["failoverpartner"] |
|||
if ok { |
|||
p.failOverPartner = failOverPartner |
|||
} |
|||
|
|||
failOverPort, ok := params["failoverport"] |
|||
if ok { |
|||
var err error |
|||
p.failOverPort, err = strconv.ParseUint(failOverPort, 0, 16) |
|||
if err != nil { |
|||
f := "Invalid tcp port '%v': %v" |
|||
return p, fmt.Errorf(f, failOverPort, err.Error()) |
|||
} |
|||
} |
|||
|
|||
return p, nil |
|||
} |
|||
|
|||
func splitConnectionString(dsn string) (res map[string]string) { |
|||
res = map[string]string{} |
|||
parts := strings.Split(dsn, ";") |
|||
for _, part := range parts { |
|||
if len(part) == 0 { |
|||
continue |
|||
} |
|||
lst := strings.SplitN(part, "=", 2) |
|||
name := strings.TrimSpace(strings.ToLower(lst[0])) |
|||
if len(name) == 0 { |
|||
continue |
|||
} |
|||
var value string = "" |
|||
if len(lst) > 1 { |
|||
value = strings.TrimSpace(lst[1]) |
|||
} |
|||
res[name] = value |
|||
} |
|||
return res |
|||
} |
|||
|
|||
// Splits a URL of the form sqlserver://username:password@host/instance?param1=value¶m2=value
|
|||
func splitConnectionStringURL(dsn string) (map[string]string, error) { |
|||
res := map[string]string{} |
|||
|
|||
u, err := url.Parse(dsn) |
|||
if err != nil { |
|||
return res, err |
|||
} |
|||
|
|||
if u.Scheme != "sqlserver" { |
|||
return res, fmt.Errorf("scheme %s is not recognized", u.Scheme) |
|||
} |
|||
|
|||
if u.User != nil { |
|||
res["user id"] = u.User.Username() |
|||
p, exists := u.User.Password() |
|||
if exists { |
|||
res["password"] = p |
|||
} |
|||
} |
|||
|
|||
host, port, err := net.SplitHostPort(u.Host) |
|||
if err != nil { |
|||
host = u.Host |
|||
} |
|||
|
|||
if len(u.Path) > 0 { |
|||
res["server"] = host + "\\" + u.Path[1:] |
|||
} else { |
|||
res["server"] = host |
|||
} |
|||
|
|||
if len(port) > 0 { |
|||
res["port"] = port |
|||
} |
|||
|
|||
query := u.Query() |
|||
for k, v := range query { |
|||
if len(v) > 1 { |
|||
return res, fmt.Errorf("key %s provided more than once", k) |
|||
} |
|||
res[strings.ToLower(k)] = v[0] |
|||
} |
|||
|
|||
return res, nil |
|||
} |
|||
|
|||
// Splits a URL in the ODBC format
|
|||
func splitConnectionStringOdbc(dsn string) (map[string]string, error) { |
|||
res := map[string]string{} |
|||
|
|||
type parserState int |
|||
const ( |
|||
// Before the start of a key
|
|||
parserStateBeforeKey parserState = iota |
|||
|
|||
// Inside a key
|
|||
parserStateKey |
|||
|
|||
// Beginning of a value. May be bare or braced
|
|||
parserStateBeginValue |
|||
|
|||
// Inside a bare value
|
|||
parserStateBareValue |
|||
|
|||
// Inside a braced value
|
|||
parserStateBracedValue |
|||
|
|||
// A closing brace inside a braced value.
|
|||
// May be the end of the value or an escaped closing brace, depending on the next character
|
|||
parserStateBracedValueClosingBrace |
|||
|
|||
// After a value. Next character should be a semicolon or whitespace.
|
|||
parserStateEndValue |
|||
) |
|||
|
|||
var state = parserStateBeforeKey |
|||
|
|||
var key string |
|||
var value string |
|||
|
|||
for i, c := range dsn { |
|||
switch state { |
|||
case parserStateBeforeKey: |
|||
switch { |
|||
case c == '=': |
|||
return res, fmt.Errorf("Unexpected character = at index %d. Expected start of key or semi-colon or whitespace.", i) |
|||
case !unicode.IsSpace(c) && c != ';': |
|||
state = parserStateKey |
|||
key += string(c) |
|||
} |
|||
|
|||
case parserStateKey: |
|||
switch c { |
|||
case '=': |
|||
key = normalizeOdbcKey(key) |
|||
state = parserStateBeginValue |
|||
|
|||
case ';': |
|||
// Key without value
|
|||
key = normalizeOdbcKey(key) |
|||
res[key] = value |
|||
key = "" |
|||
value = "" |
|||
state = parserStateBeforeKey |
|||
|
|||
default: |
|||
key += string(c) |
|||
} |
|||
|
|||
case parserStateBeginValue: |
|||
switch { |
|||
case c == '{': |
|||
state = parserStateBracedValue |
|||
case c == ';': |
|||
// Empty value
|
|||
res[key] = value |
|||
key = "" |
|||
state = parserStateBeforeKey |
|||
case unicode.IsSpace(c): |
|||
// Ignore whitespace
|
|||
default: |
|||
state = parserStateBareValue |
|||
value += string(c) |
|||
} |
|||
|
|||
case parserStateBareValue: |
|||
if c == ';' { |
|||
res[key] = strings.TrimRightFunc(value, unicode.IsSpace) |
|||
key = "" |
|||
value = "" |
|||
state = parserStateBeforeKey |
|||
} else { |
|||
value += string(c) |
|||
} |
|||
|
|||
case parserStateBracedValue: |
|||
if c == '}' { |
|||
state = parserStateBracedValueClosingBrace |
|||
} else { |
|||
value += string(c) |
|||
} |
|||
|
|||
case parserStateBracedValueClosingBrace: |
|||
if c == '}' { |
|||
// Escaped closing brace
|
|||
value += string(c) |
|||
state = parserStateBracedValue |
|||
continue |
|||
} |
|||
|
|||
// End of braced value
|
|||
res[key] = value |
|||
key = "" |
|||
value = "" |
|||
|
|||
// This character is the first character past the end,
|
|||
// so it needs to be parsed like the parserStateEndValue state.
|
|||
state = parserStateEndValue |
|||
switch { |
|||
case c == ';': |
|||
state = parserStateBeforeKey |
|||
case unicode.IsSpace(c): |
|||
// Ignore whitespace
|
|||
default: |
|||
return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) |
|||
} |
|||
|
|||
case parserStateEndValue: |
|||
switch { |
|||
case c == ';': |
|||
state = parserStateBeforeKey |
|||
case unicode.IsSpace(c): |
|||
// Ignore whitespace
|
|||
default: |
|||
return res, fmt.Errorf("Unexpected character %c at index %d. Expected semi-colon or whitespace.", c, i) |
|||
} |
|||
} |
|||
} |
|||
|
|||
switch state { |
|||
case parserStateBeforeKey: // Okay
|
|||
case parserStateKey: // Unfinished key. Treat as key without value.
|
|||
key = normalizeOdbcKey(key) |
|||
res[key] = value |
|||
case parserStateBeginValue: // Empty value
|
|||
res[key] = value |
|||
case parserStateBareValue: |
|||
res[key] = strings.TrimRightFunc(value, unicode.IsSpace) |
|||
case parserStateBracedValue: |
|||
return res, fmt.Errorf("Unexpected end of braced value at index %d.", len(dsn)) |
|||
case parserStateBracedValueClosingBrace: // End of braced value
|
|||
res[key] = value |
|||
case parserStateEndValue: // Okay
|
|||
} |
|||
|
|||
return res, nil |
|||
} |
|||
|
|||
// Normalizes the given string as an ODBC-format key
|
|||
func normalizeOdbcKey(s string) string { |
|||
return strings.ToLower(strings.TrimRightFunc(s, unicode.IsSpace)) |
|||
} |
|||
|
|||
func resolveServerPort(port uint64) uint64 { |
|||
if port == 0 { |
|||
return defaultServerPort |
|||
} |
|||
|
|||
return port |
|||
} |
|||
|
|||
func generateSpn(host string, port uint64) string { |
|||
return fmt.Sprintf("MSSQLSvc/%s:%d", host, port) |
|||
} |
@ -1,131 +0,0 @@ |
|||
package mssql |
|||
|
|||
import ( |
|||
"encoding/binary" |
|||
"errors" |
|||
"math" |
|||
"math/big" |
|||
) |
|||
|
|||
// http://msdn.microsoft.com/en-us/library/ee780893.aspx
|
|||
type Decimal struct { |
|||
integer [4]uint32 |
|||
positive bool |
|||
prec uint8 |
|||
scale uint8 |
|||
} |
|||
|
|||
var scaletblflt64 [39]float64 |
|||
|
|||
func (d Decimal) ToFloat64() float64 { |
|||
val := float64(0) |
|||
for i := 3; i >= 0; i-- { |
|||
val *= 0x100000000 |
|||
val += float64(d.integer[i]) |
|||
} |
|||
if !d.positive { |
|||
val = -val |
|||
} |
|||
if d.scale != 0 { |
|||
val /= scaletblflt64[d.scale] |
|||
} |
|||
return val |
|||
} |
|||
|
|||
const autoScale = 100 |
|||
|
|||
func Float64ToDecimal(f float64) (Decimal, error) { |
|||
return Float64ToDecimalScale(f, autoScale) |
|||
} |
|||
|
|||
func Float64ToDecimalScale(f float64, scale uint8) (Decimal, error) { |
|||
var dec Decimal |
|||
if math.IsNaN(f) { |
|||
return dec, errors.New("NaN") |
|||
} |
|||
if math.IsInf(f, 0) { |
|||
return dec, errors.New("Infinity can't be converted to decimal") |
|||
} |
|||
dec.positive = f >= 0 |
|||
if !dec.positive { |
|||
f = math.Abs(f) |
|||
} |
|||
if f > 3.402823669209385e+38 { |
|||
return dec, errors.New("Float value is out of range") |
|||
} |
|||
dec.prec = 20 |
|||
var integer float64 |
|||
for dec.scale = 0; dec.scale <= scale; dec.scale++ { |
|||
integer = f * scaletblflt64[dec.scale] |
|||
_, frac := math.Modf(integer) |
|||
if frac == 0 && scale == autoScale { |
|||
break |
|||
} |
|||
} |
|||
for i := 0; i < 4; i++ { |
|||
mod := math.Mod(integer, 0x100000000) |
|||
integer -= mod |
|||
integer /= 0x100000000 |
|||
dec.integer[i] = uint32(mod) |
|||
} |
|||
return dec, nil |
|||
} |
|||
|
|||
func init() { |
|||
var acc float64 = 1 |
|||
for i := 0; i <= 38; i++ { |
|||
scaletblflt64[i] = acc |
|||
acc *= 10 |
|||
} |
|||
} |
|||
|
|||
func (d Decimal) BigInt() big.Int { |
|||
bytes := make([]byte, 16) |
|||
binary.BigEndian.PutUint32(bytes[0:4], d.integer[3]) |
|||
binary.BigEndian.PutUint32(bytes[4:8], d.integer[2]) |
|||
binary.BigEndian.PutUint32(bytes[8:12], d.integer[1]) |
|||
binary.BigEndian.PutUint32(bytes[12:16], d.integer[0]) |
|||
var x big.Int |
|||
x.SetBytes(bytes) |
|||
if !d.positive { |
|||
x.Neg(&x) |
|||
} |
|||
return x |
|||
} |
|||
|
|||
func (d Decimal) Bytes() []byte { |
|||
x := d.BigInt() |
|||
return scaleBytes(x.String(), d.scale) |
|||
} |
|||
|
|||
func (d Decimal) UnscaledBytes() []byte { |
|||
x := d.BigInt() |
|||
return x.Bytes() |
|||
} |
|||
|
|||
func scaleBytes(s string, scale uint8) []byte { |
|||
z := make([]byte, 0, len(s)+1) |
|||
if s[0] == '-' || s[0] == '+' { |
|||
z = append(z, byte(s[0])) |
|||
s = s[1:] |
|||
} |
|||
pos := len(s) - int(scale) |
|||
if pos <= 0 { |
|||
z = append(z, byte('0')) |
|||
} else if pos > 0 { |
|||
z = append(z, []byte(s[:pos])...) |
|||
} |
|||
if scale > 0 { |
|||
z = append(z, byte('.')) |
|||
for pos < 0 { |
|||
z = append(z, byte('0')) |
|||
pos++ |
|||
} |
|||
z = append(z, []byte(s[pos:])...) |
|||
} |
|||
return z |
|||
} |
|||
|
|||
func (d Decimal) String() string { |
|||
return string(d.Bytes()) |
|||
} |
@ -1,10 +1,8 @@ |
|||
module github.com/denisenkom/go-mssqldb |
|||
|
|||
go 1.12 |
|||
go 1.11 |
|||
|
|||
require ( |
|||
cloud.google.com/go v0.37.4 |
|||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe |
|||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c |
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 // indirect |
|||
gopkg.in/yaml.v2 v2.2.2 // indirect |
|||
) |
@ -1,168 +1,5 @@ |
|||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.31.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= |
|||
cloud.google.com/go v0.37.2 h1:4y4L7BdHenTfZL0HervofNTHh9Ad6mNX72cQvl+5eH0= |
|||
cloud.google.com/go v0.37.2/go.mod h1:H8IAquKe2L30IxoupDgqTaQvKSwF/c8prYHynGIWQbA= |
|||
git.apache.org/thrift.git v0.0.0-20180902110319-2566ecd5d999/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= |
|||
git.apache.org/thrift.git v0.12.0/go.mod h1:fPE2ZNJGynbRyZ4dJvy6G277gSllfV2HJqblrnkyeyg= |
|||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= |
|||
github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= |
|||
github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= |
|||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= |
|||
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= |
|||
github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= |
|||
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= |
|||
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= |
|||
github.com/bradfitz/go-smtpd v0.0.0-20170404230938-deb6d6237625/go.mod h1:HYsPBTaaSFSlLx/70C2HPIMNZpVV8+vt/A+FMnYP11g= |
|||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= |
|||
github.com/coreos/go-systemd v0.0.0-20181012123002-c6f51f82210d/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= |
|||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= |
|||
github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= |
|||
github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= |
|||
github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= |
|||
github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= |
|||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= |
|||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= |
|||
github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= |
|||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= |
|||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= |
|||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= |
|||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= |
|||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= |
|||
github.com/golang/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:tluoj9z5200jBnyusfRPU2LqT6J+DAorxEvtC7LHB+E= |
|||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= |
|||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= |
|||
github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= |
|||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= |
|||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= |
|||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ= |
|||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= |
|||
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= |
|||
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= |
|||
github.com/googleapis/gax-go v2.0.0+incompatible/go.mod h1:SFVmujtThgffbyetf+mdk2eWhX2bMyUtNHzFKcPA9HY= |
|||
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= |
|||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= |
|||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= |
|||
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.5.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= |
|||
github.com/grpc-ecosystem/grpc-gateway v1.6.2/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw= |
|||
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= |
|||
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= |
|||
github.com/jellevandenhooff/dkim v0.0.0-20150330215556-f50fe3d243e1/go.mod h1:E0B/fFc00Y+Rasa88328GlI/XbtyysCtTHZS8h7IrBU= |
|||
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= |
|||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= |
|||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= |
|||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= |
|||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= |
|||
github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= |
|||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= |
|||
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= |
|||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= |
|||
github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= |
|||
github.com/openzipkin/zipkin-go v0.1.1/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= |
|||
github.com/openzipkin/zipkin-go v0.1.3/go.mod h1:NtoC/o8u3JlF1lSlyPNswIbeQH9bJTmOf0Erfk+hxe8= |
|||
github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= |
|||
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= |
|||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= |
|||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= |
|||
github.com/prometheus/client_golang v0.8.0/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= |
|||
github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= |
|||
github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= |
|||
github.com/prometheus/common v0.0.0-20180801064454-c7de2306084e/go.mod h1:daVV7qP5qjZbuso7PdcryaAu0sAZbrN9i7WWcTMWvro= |
|||
github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= |
|||
github.com/prometheus/procfs v0.0.0-20180725123919-05ee40e3a273/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= |
|||
github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= |
|||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= |
|||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= |
|||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= |
|||
github.com/tarm/serial v0.0.0-20180830185346-98f6abe2eb07/go.mod h1:kDXzergiv9cbyO7IOYJZWg1U88JhDg3PB6klq9Hg2pA= |
|||
go.opencensus.io v0.18.0/go.mod h1:vKdFvxhtzZ9onBp9VKHK8z/sRpBMnKAsufL7wlDrCOA= |
|||
go.opencensus.io v0.19.1/go.mod h1:gug0GbSHa8Pafr0d2urOSgoXHZ6x/RUlaiT0d9pqb4A= |
|||
go.opencensus.io v0.19.2/go.mod h1:NO/8qkisMZLZ1FCsKNqtJPwc8/TaclWyY0B6wcYNg9M= |
|||
go4.org v0.0.0-20180809161055-417644f6feb5/go.mod h1:MkTOUMDaeVYJUOUsaDXIhWPZYa1yOyC1qaOBpL57BhE= |
|||
golang.org/x/build v0.0.0-20190314133821-5284462c4bec/go.mod h1:atTaCNAy0f16Ah5aV1gMSwgiKVHwu/JncqDpuRr7lS4= |
|||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20181030102418-4d3f4d9ffa16/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= |
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY= |
|||
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0= |
|||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= |
|||
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= |
|||
golang.org/x/lint v0.0.0-20180702182130-06c8688daad7/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20181217174547-8f45f776aaf1/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= |
|||
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= |
|||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181029044818-c44066c5c816/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= |
|||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20181017192945-9dcd33a902f4/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= |
|||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= |
|||
golang.org/x/perf v0.0.0-20180704124530-6e6d33e29852/go.mod h1:JLpeXjPJfIyPr5TlbXLkXWLhP8nz10XfvxElABhCtcw= |
|||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= |
|||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181029174526-d69651ed3497/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20181218192612-074acd46bca6/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
|||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= |
|||
golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20181219222714-6e267b5cc78e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= |
|||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= |
|||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= |
|||
google.golang.org/api v0.0.0-20180910000450-7ca32eb868bf/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= |
|||
google.golang.org/api v0.0.0-20181030000543-1d582fd0359e/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= |
|||
google.golang.org/api v0.0.0-20181220000619-583d854617af/go.mod h1:4mhQ8q/RsB7i+udVvVy5NUi08OU8ZlA0gRVgrF7VFY0= |
|||
google.golang.org/api v0.2.0/go.mod h1:IfRCZScioGtypHNTlz3gFk67J8uePVW7uDTBzXuIkhU= |
|||
google.golang.org/api v0.3.0/go.mod h1:IuvZyQh8jgscv8qWfQ4ABd8m7hEudgBFM/EdhA3BnXw= |
|||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= |
|||
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= |
|||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20180831171423-11092d34479b/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20181029155118-b69ba1387ce2/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= |
|||
google.golang.org/genproto v0.0.0-20181219182458-5a97ab628bfb/go.mod h1:7Ep/1NZk928CDR8SjdVbjWNpdIf6nzjE3BTgJDr2Atg= |
|||
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= |
|||
google.golang.org/grpc v1.14.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= |
|||
google.golang.org/grpc v1.16.0/go.mod h1:0JHn/cJsOMiMfNA9+DeHDlAU7KAAB5GDlYFpa9MZMio= |
|||
google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= |
|||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= |
|||
gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= |
|||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= |
|||
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= |
|||
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= |
|||
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= |
|||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= |
|||
grpc.go4.org v0.0.0-20170609214715-11d0a25b4919/go.mod h1:77eQGdRu53HpSqPFJFmuJdjuHRquDANNeA4x7B8WQ9o= |
|||
honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20180920025451-e3ad64cb4ed3/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
|||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
@ -0,0 +1,252 @@ |
|||
package decimal |
|||
|
|||
import ( |
|||
"encoding/binary" |
|||
"errors" |
|||
"fmt" |
|||
"math" |
|||
"math/big" |
|||
"strings" |
|||
) |
|||
|
|||
// Decimal represents decimal type in the Microsoft Open Specifications: http://msdn.microsoft.com/en-us/library/ee780893.aspx
|
|||
type Decimal struct { |
|||
integer [4]uint32 // Little-endian
|
|||
positive bool |
|||
prec uint8 |
|||
scale uint8 |
|||
} |
|||
|
|||
var ( |
|||
scaletblflt64 [39]float64 |
|||
int10 big.Int |
|||
int1e5 big.Int |
|||
) |
|||
|
|||
func init() { |
|||
var acc float64 = 1 |
|||
for i := 0; i <= 38; i++ { |
|||
scaletblflt64[i] = acc |
|||
acc *= 10 |
|||
} |
|||
|
|||
int10.SetInt64(10) |
|||
int1e5.SetInt64(1e5) |
|||
} |
|||
|
|||
const autoScale = 100 |
|||
|
|||
// SetInteger sets the ind'th element in the integer array
|
|||
func (d *Decimal) SetInteger(integer uint32, ind uint8) { |
|||
d.integer[ind] = integer |
|||
} |
|||
|
|||
// SetPositive sets the positive member
|
|||
func (d *Decimal) SetPositive(positive bool) { |
|||
d.positive = positive |
|||
} |
|||
|
|||
// SetPrec sets the prec member
|
|||
func (d *Decimal) SetPrec(prec uint8) { |
|||
d.prec = prec |
|||
} |
|||
|
|||
// SetScale sets the scale member
|
|||
func (d *Decimal) SetScale(scale uint8) { |
|||
d.scale = scale |
|||
} |
|||
|
|||
// IsPositive returns true if the Decimal is positive
|
|||
func (d *Decimal) IsPositive() bool { |
|||
return d.positive |
|||
} |
|||
|
|||
// ToFloat64 converts decimal to a float64
|
|||
func (d Decimal) ToFloat64() float64 { |
|||
val := float64(0) |
|||
for i := 3; i >= 0; i-- { |
|||
val *= 0x100000000 |
|||
val += float64(d.integer[i]) |
|||
} |
|||
if !d.positive { |
|||
val = -val |
|||
} |
|||
if d.scale != 0 { |
|||
val /= scaletblflt64[d.scale] |
|||
} |
|||
return val |
|||
} |
|||
|
|||
// BigInt converts decimal to a bigint
|
|||
func (d Decimal) BigInt() big.Int { |
|||
bytes := make([]byte, 16) |
|||
binary.BigEndian.PutUint32(bytes[0:4], d.integer[3]) |
|||
binary.BigEndian.PutUint32(bytes[4:8], d.integer[2]) |
|||
binary.BigEndian.PutUint32(bytes[8:12], d.integer[1]) |
|||
binary.BigEndian.PutUint32(bytes[12:16], d.integer[0]) |
|||
var x big.Int |
|||
x.SetBytes(bytes) |
|||
if !d.positive { |
|||
x.Neg(&x) |
|||
} |
|||
return x |
|||
} |
|||
|
|||
// Bytes converts decimal to a scaled byte slice
|
|||
func (d Decimal) Bytes() []byte { |
|||
x := d.BigInt() |
|||
return ScaleBytes(x.String(), d.scale) |
|||
} |
|||
|
|||
// UnscaledBytes converts decimal to a unscaled byte slice
|
|||
func (d Decimal) UnscaledBytes() []byte { |
|||
x := d.BigInt() |
|||
return x.Bytes() |
|||
} |
|||
|
|||
// String converts decimal to a string
|
|||
func (d Decimal) String() string { |
|||
return string(d.Bytes()) |
|||
} |
|||
|
|||
// Float64ToDecimal converts float64 to decimal
|
|||
func Float64ToDecimal(f float64) (Decimal, error) { |
|||
return Float64ToDecimalScale(f, autoScale) |
|||
} |
|||
|
|||
// Float64ToDecimalScale converts float64 to decimal; user can specify the scale
|
|||
func Float64ToDecimalScale(f float64, scale uint8) (Decimal, error) { |
|||
var dec Decimal |
|||
if math.IsNaN(f) { |
|||
return dec, errors.New("NaN") |
|||
} |
|||
if math.IsInf(f, 0) { |
|||
return dec, errors.New("Infinity can't be converted to decimal") |
|||
} |
|||
dec.positive = f >= 0 |
|||
if !dec.positive { |
|||
f = math.Abs(f) |
|||
} |
|||
if f > 3.402823669209385e+38 { |
|||
return dec, errors.New("Float value is out of range") |
|||
} |
|||
dec.prec = 20 |
|||
var integer float64 |
|||
for dec.scale = 0; dec.scale <= scale; dec.scale++ { |
|||
integer = f * scaletblflt64[dec.scale] |
|||
_, frac := math.Modf(integer) |
|||
if frac == 0 && scale == autoScale { |
|||
break |
|||
} |
|||
} |
|||
for i := 0; i < 4; i++ { |
|||
mod := math.Mod(integer, 0x100000000) |
|||
integer -= mod |
|||
integer /= 0x100000000 |
|||
dec.integer[i] = uint32(mod) |
|||
if mod-math.Trunc(mod) >= 0.5 { |
|||
dec.integer[i] = uint32(mod) + 1 |
|||
} |
|||
} |
|||
return dec, nil |
|||
} |
|||
|
|||
// Int64ToDecimalScale converts float64 to decimal; user can specify the scale
|
|||
func Int64ToDecimalScale(v int64, scale uint8) Decimal { |
|||
positive := v >= 0 |
|||
if !positive { |
|||
if v == math.MinInt64 { |
|||
// Special case - can't negate
|
|||
return Decimal{ |
|||
integer: [4]uint32{0, 0x80000000, 0, 0}, |
|||
positive: false, |
|||
prec: 20, |
|||
scale: 0, |
|||
} |
|||
} |
|||
v = -v |
|||
} |
|||
return Decimal{ |
|||
integer: [4]uint32{uint32(v), uint32(v >> 32), 0, 0}, |
|||
positive: positive, |
|||
prec: 20, |
|||
scale: scale, |
|||
} |
|||
} |
|||
|
|||
// StringToDecimalScale converts string to decimal
|
|||
func StringToDecimalScale(v string, outScale uint8) (Decimal, error) { |
|||
var r big.Int |
|||
var unscaled string |
|||
var inScale int |
|||
|
|||
point := strings.LastIndexByte(v, '.') |
|||
if point == -1 { |
|||
inScale = 0 |
|||
unscaled = v |
|||
} else { |
|||
inScale = len(v) - point - 1 |
|||
unscaled = v[:point] + v[point+1:] |
|||
} |
|||
if inScale > math.MaxUint8 { |
|||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: scale too large", v) |
|||
} |
|||
|
|||
_, ok := r.SetString(unscaled, 10) |
|||
if !ok { |
|||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number", v) |
|||
} |
|||
|
|||
if inScale > int(outScale) { |
|||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: scale %d is larger than the scale %d of the target column", v, inScale, outScale) |
|||
} |
|||
for inScale < int(outScale) { |
|||
if int(outScale)-inScale >= 5 { |
|||
r.Mul(&r, &int1e5) |
|||
inScale += 5 |
|||
} else { |
|||
r.Mul(&r, &int10) |
|||
inScale++ |
|||
} |
|||
} |
|||
|
|||
bytes := r.Bytes() |
|||
if len(bytes) > 16 { |
|||
return Decimal{}, fmt.Errorf("can't parse %q as a decimal number: precision too large", v) |
|||
} |
|||
var out [4]uint32 |
|||
for i, b := range bytes { |
|||
pos := len(bytes) - i - 1 |
|||
out[pos/4] += uint32(b) << uint(pos%4*8) |
|||
} |
|||
return Decimal{ |
|||
integer: out, |
|||
positive: r.Sign() >= 0, |
|||
prec: 20, |
|||
scale: uint8(inScale), |
|||
}, nil |
|||
} |
|||
|
|||
// ScaleBytes converts a stringified decimal to a scaled byte slice
|
|||
func ScaleBytes(s string, scale uint8) []byte { |
|||
z := make([]byte, 0, len(s)+1) |
|||
if s[0] == '-' || s[0] == '+' { |
|||
z = append(z, byte(s[0])) |
|||
s = s[1:] |
|||
} |
|||
pos := len(s) - int(scale) |
|||
if pos <= 0 { |
|||
z = append(z, byte('0')) |
|||
} else if pos > 0 { |
|||
z = append(z, []byte(s[:pos])...) |
|||
} |
|||
if scale > 0 { |
|||
z = append(z, byte('.')) |
|||
for pos < 0 { |
|||
z = append(z, byte('0')) |
|||
pos++ |
|||
} |
|||
z = append(z, []byte(s[pos:])...) |
|||
} |
|||
return z |
|||
} |
@ -0,0 +1,31 @@ |
|||
// +build !go1.10
|
|||
|
|||
package mssql |
|||
|
|||
import ( |
|||
"database/sql/driver" |
|||
"errors" |
|||
) |
|||
|
|||
func (r *Result) LastInsertId() (int64, error) { |
|||
s, err := r.c.Prepare("select cast(@@identity as bigint)") |
|||
if err != nil { |
|||
return 0, err |
|||
} |
|||
defer s.Close() |
|||
rows, err := s.Query(nil) |
|||
if err != nil { |
|||
return 0, err |
|||
} |
|||
defer rows.Close() |
|||
dest := make([]driver.Value, 1) |
|||
err = rows.Next(dest) |
|||
if err != nil { |
|||
return 0, err |
|||
} |
|||
if dest[0] == nil { |
|||
return -1, errors.New("There is no generated identity value") |
|||
} |
|||
lastInsertId := dest[0].(int64) |
|||
return lastInsertId, nil |
|||
} |
@ -1,23 +0,0 @@ |
|||
# Contributing Guidelines |
|||
|
|||
## Reporting Issues |
|||
|
|||
Before creating a new Issue, please check first if a similar Issue [already exists](https://github.com/go-sql-driver/mysql/issues?state=open) or was [recently closed](https://github.com/go-sql-driver/mysql/issues?direction=desc&page=1&sort=updated&state=closed). |
|||
|
|||
## Contributing Code |
|||
|
|||
By contributing to this project, you share your code under the Mozilla Public License 2, as specified in the LICENSE file. |
|||
Don't forget to add yourself to the AUTHORS file. |
|||
|
|||
### Code Review |
|||
|
|||
Everyone is invited to review and comment on pull requests. |
|||
If it looks fine to you, comment with "LGTM" (Looks good to me). |
|||
|
|||
If changes are required, notice the reviewers with "PTAL" (Please take another look) after committing the fixes. |
|||
|
|||
Before merging the Pull Request, at least one [team member](https://github.com/go-sql-driver?tab=members) must have commented with "LGTM". |
|||
|
|||
## Development Ideas |
|||
|
|||
If you are looking for ideas for code contributions, please check our [Development Ideas](https://github.com/go-sql-driver/mysql/wiki/Development-Ideas) Wiki page. |
@ -0,0 +1,54 @@ |
|||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
|||
//
|
|||
// Copyright 2019 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 linux darwin dragonfly freebsd netbsd openbsd solaris illumos
|
|||
|
|||
package mysql |
|||
|
|||
import ( |
|||
"errors" |
|||
"io" |
|||
"net" |
|||
"syscall" |
|||
) |
|||
|
|||
var errUnexpectedRead = errors.New("unexpected read from socket") |
|||
|
|||
func connCheck(conn net.Conn) error { |
|||
var sysErr error |
|||
|
|||
sysConn, ok := conn.(syscall.Conn) |
|||
if !ok { |
|||
return nil |
|||
} |
|||
rawConn, err := sysConn.SyscallConn() |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
err = rawConn.Read(func(fd uintptr) bool { |
|||
var buf [1]byte |
|||
n, err := syscall.Read(int(fd), buf[:]) |
|||
switch { |
|||
case n == 0 && err == nil: |
|||
sysErr = io.EOF |
|||
case n > 0: |
|||
sysErr = errUnexpectedRead |
|||
case err == syscall.EAGAIN || err == syscall.EWOULDBLOCK: |
|||
sysErr = nil |
|||
default: |
|||
sysErr = err |
|||
} |
|||
return true |
|||
}) |
|||
if err != nil { |
|||
return err |
|||
} |
|||
|
|||
return sysErr |
|||
} |
@ -1,19 +1,17 @@ |
|||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
|||
//
|
|||
// Copyright 2013 The Go-MySQL-Driver Authors. All rights reserved.
|
|||
// Copyright 2019 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 appengine
|
|||
// +build !linux,!darwin,!dragonfly,!freebsd,!netbsd,!openbsd,!solaris,!illumos
|
|||
|
|||
package mysql |
|||
|
|||
import ( |
|||
"google.golang.org/appengine/cloudsql" |
|||
) |
|||
import "net" |
|||
|
|||
func init() { |
|||
RegisterDial("cloudsql", cloudsql.Dial) |
|||
func connCheck(conn net.Conn) error { |
|||
return nil |
|||
} |
@ -1,207 +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) (err error) { |
|||
if mc.closed.IsSet() { |
|||
errLog.Print(ErrInvalidConn) |
|||
return driver.ErrBadConn |
|||
} |
|||
|
|||
if err = mc.watchCancel(ctx); err != nil { |
|||
return |
|||
} |
|||
defer mc.finish() |
|||
|
|||
if err = mc.writeCommandPacket(comPing); err != nil { |
|||
return |
|||
} |
|||
|
|||
return mc.readResultOK() |
|||
} |
|||
|
|||
// 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 |
|||
} |
|||
// When ctx is already cancelled, don't watch it.
|
|||
if err := ctx.Err(); err != nil { |
|||
return err |
|||
} |
|||
// When ctx is not cancellable, don't watch it.
|
|||
if ctx.Done() == nil { |
|||
return nil |
|||
} |
|||
// When watcher is not alive, can't watch it.
|
|||
if mc.watcher == nil { |
|||
return nil |
|||
} |
|||
|
|||
mc.watching = true |
|||
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 |
|||
} |
|||
|
|||
// ResetSession implements driver.SessionResetter.
|
|||
// (From Go 1.10)
|
|||
func (mc *mysqlConn) ResetSession(ctx context.Context) error { |
|||
if mc.closed.IsSet() { |
|||
return driver.ErrBadConn |
|||
} |
|||
return nil |
|||
} |
@ -0,0 +1,146 @@ |
|||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
|||
//
|
|||
// Copyright 2018 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 ( |
|||
"context" |
|||
"database/sql/driver" |
|||
"net" |
|||
) |
|||
|
|||
type connector struct { |
|||
cfg *Config // immutable private copy.
|
|||
} |
|||
|
|||
// Connect implements driver.Connector interface.
|
|||
// Connect returns a connection to the database.
|
|||
func (c *connector) Connect(ctx context.Context) (driver.Conn, error) { |
|||
var err error |
|||
|
|||
// New mysqlConn
|
|||
mc := &mysqlConn{ |
|||
maxAllowedPacket: maxPacketSize, |
|||
maxWriteSize: maxPacketSize - 1, |
|||
closech: make(chan struct{}), |
|||
cfg: c.cfg, |
|||
} |
|||
mc.parseTime = mc.cfg.ParseTime |
|||
|
|||
// Connect to Server
|
|||
dialsLock.RLock() |
|||
dial, ok := dials[mc.cfg.Net] |
|||
dialsLock.RUnlock() |
|||
if ok { |
|||
dctx := ctx |
|||
if mc.cfg.Timeout > 0 { |
|||
var cancel context.CancelFunc |
|||
dctx, cancel = context.WithTimeout(ctx, c.cfg.Timeout) |
|||
defer cancel() |
|||
} |
|||
mc.netConn, err = dial(dctx, mc.cfg.Addr) |
|||
} else { |
|||
nd := net.Dialer{Timeout: mc.cfg.Timeout} |
|||
mc.netConn, err = nd.DialContext(ctx, mc.cfg.Net, mc.cfg.Addr) |
|||
} |
|||
|
|||
if err != nil { |
|||
return nil, err |
|||
} |
|||
|
|||
// Enable TCP Keepalives on TCP connections
|
|||
if tc, ok := mc.netConn.(*net.TCPConn); ok { |
|||
if err := tc.SetKeepAlive(true); err != nil { |
|||
// Don't send COM_QUIT before handshake.
|
|||
mc.netConn.Close() |
|||
mc.netConn = nil |
|||
return nil, err |
|||
} |
|||
} |
|||
|
|||
// Call startWatcher for context support (From Go 1.8)
|
|||
mc.startWatcher() |
|||
if err := mc.watchCancel(ctx); err != nil { |
|||
mc.cleanup() |
|||
return nil, err |
|||
} |
|||
defer mc.finish() |
|||
|
|||
mc.buf = newBuffer(mc.netConn) |
|||
|
|||
// Set I/O timeouts
|
|||
mc.buf.timeout = mc.cfg.ReadTimeout |
|||
mc.writeTimeout = mc.cfg.WriteTimeout |
|||
|
|||
// Reading Handshake Initialization Packet
|
|||
authData, plugin, err := mc.readHandshakePacket() |
|||
if err != nil { |
|||
mc.cleanup() |
|||
return nil, err |
|||
} |
|||
|
|||
if plugin == "" { |
|||
plugin = defaultAuthPlugin |
|||
} |
|||
|
|||
// Send Client Authentication Packet
|
|||
authResp, err := mc.auth(authData, plugin) |
|||
if err != nil { |
|||
// try the default auth plugin, if using the requested plugin failed
|
|||
errLog.Print("could not use requested auth plugin '"+plugin+"': ", err.Error()) |
|||
plugin = defaultAuthPlugin |
|||
authResp, err = mc.auth(authData, plugin) |
|||
if err != nil { |
|||
mc.cleanup() |
|||
return nil, err |
|||
} |
|||
} |
|||
if err = mc.writeHandshakeResponsePacket(authResp, plugin); err != nil { |
|||
mc.cleanup() |
|||
return nil, err |
|||
} |
|||
|
|||
// Handle response to auth packet, switch methods if possible
|
|||
if err = mc.handleAuthResult(authData, plugin); err != nil { |
|||
// Authentication failed and MySQL has already closed the connection
|
|||
// (https://dev.mysql.com/doc/internals/en/authentication-fails.html).
|
|||
// Do not send COM_QUIT, just cleanup and return the error.
|
|||
mc.cleanup() |
|||
return nil, err |
|||
} |
|||
|
|||
if mc.cfg.MaxAllowedPacket > 0 { |
|||
mc.maxAllowedPacket = mc.cfg.MaxAllowedPacket |
|||
} else { |
|||
// Get max allowed packet size
|
|||
maxap, err := mc.getSystemVar("max_allowed_packet") |
|||
if err != nil { |
|||
mc.Close() |
|||
return nil, err |
|||
} |
|||
mc.maxAllowedPacket = stringToInt(maxap) - 1 |
|||
} |
|||
if mc.maxAllowedPacket < maxPacketSize { |
|||
mc.maxWriteSize = mc.maxAllowedPacket |
|||
} |
|||
|
|||
// Handle DSN Params
|
|||
err = mc.handleParams() |
|||
if err != nil { |
|||
mc.Close() |
|||
return nil, err |
|||
} |
|||
|
|||
return mc, nil |
|||
} |
|||
|
|||
// Driver implements driver.Connector interface.
|
|||
// Driver returns &MySQLDriver{}.
|
|||
func (c *connector) Driver() driver.Driver { |
|||
return &MySQLDriver{} |
|||
} |
@ -0,0 +1,3 @@ |
|||
module github.com/go-sql-driver/mysql |
|||
|
|||
go 1.10 |
@ -0,0 +1,50 @@ |
|||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
|||
//
|
|||
// Copyright 2013 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/driver" |
|||
"fmt" |
|||
"time" |
|||
) |
|||
|
|||
// Scan implements the Scanner interface.
|
|||
// The value type must be time.Time or string / []byte (formatted time-string),
|
|||
// otherwise Scan fails.
|
|||
func (nt *NullTime) Scan(value interface{}) (err error) { |
|||
if value == nil { |
|||
nt.Time, nt.Valid = time.Time{}, false |
|||
return |
|||
} |
|||
|
|||
switch v := value.(type) { |
|||
case time.Time: |
|||
nt.Time, nt.Valid = v, true |
|||
return |
|||
case []byte: |
|||
nt.Time, err = parseDateTime(string(v), time.UTC) |
|||
nt.Valid = (err == nil) |
|||
return |
|||
case string: |
|||
nt.Time, err = parseDateTime(v, time.UTC) |
|||
nt.Valid = (err == nil) |
|||
return |
|||
} |
|||
|
|||
nt.Valid = false |
|||
return fmt.Errorf("Can't convert %T to time.Time", value) |
|||
} |
|||
|
|||
// Value implements the driver Valuer interface.
|
|||
func (nt NullTime) Value() (driver.Value, error) { |
|||
if !nt.Valid { |
|||
return nil, nil |
|||
} |
|||
return nt.Time, nil |
|||
} |
@ -0,0 +1,31 @@ |
|||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
|||
//
|
|||
// Copyright 2013 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.13
|
|||
|
|||
package mysql |
|||
|
|||
import ( |
|||
"database/sql" |
|||
) |
|||
|
|||
// NullTime represents a time.Time that may be NULL.
|
|||
// NullTime implements the Scanner interface so
|
|||
// it can be used as a scan destination:
|
|||
//
|
|||
// var nt NullTime
|
|||
// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt)
|
|||
// ...
|
|||
// if nt.Valid {
|
|||
// // use nt.Time
|
|||
// } else {
|
|||
// // NULL value
|
|||
// }
|
|||
//
|
|||
// This NullTime implementation is not driver-specific
|
|||
type NullTime sql.NullTime |
@ -0,0 +1,34 @@ |
|||
// Go MySQL Driver - A MySQL-Driver for Go's database/sql package
|
|||
//
|
|||
// Copyright 2013 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.13
|
|||
|
|||
package mysql |
|||
|
|||
import ( |
|||
"time" |
|||
) |
|||
|
|||
// NullTime represents a time.Time that may be NULL.
|
|||
// NullTime implements the Scanner interface so
|
|||
// it can be used as a scan destination:
|
|||
//
|
|||
// var nt NullTime
|
|||
// err := db.QueryRow("SELECT time FROM foo WHERE id=?", id).Scan(&nt)
|
|||
// ...
|
|||
// if nt.Valid {
|
|||
// // use nt.Time
|
|||
// } else {
|
|||
// // NULL value
|
|||
// }
|
|||
//
|
|||
// This NullTime implementation is not driver-specific
|
|||
type NullTime struct { |
|||
Time time.Time |
|||
Valid bool // Valid is true if Time is not NULL
|
|||
} |
@ -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, |
|||
} |
|||
} |
@ -1,50 +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" |
|||
"fmt" |
|||
) |
|||
|
|||
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 "", fmt.Errorf("mysql: unsupported isolation level: %v", level) |
|||
} |
|||
} |
@ -0,0 +1,73 @@ |
|||
# Contributing |
|||
|
|||
1. Sign one of the contributor license agreements below. |
|||
|
|||
#### Running |
|||
|
|||
Once you've done the necessary setup, you can run the integration tests by |
|||
running: |
|||
|
|||
``` sh |
|||
$ go test -v github.com/golang-sql/civil |
|||
``` |
|||
|
|||
## Contributor License Agreements |
|||
|
|||
Before we can accept your pull requests you'll need to sign a Contributor |
|||
License Agreement (CLA): |
|||
|
|||
- **If you are an individual writing original source code** and **you own the |
|||
intellectual property**, then you'll need to sign an [individual CLA][indvcla]. |
|||
- **If you work for a company that wants to allow you to contribute your |
|||
work**, then you'll need to sign a [corporate CLA][corpcla]. |
|||
|
|||
You can sign these electronically (just scroll to the bottom). After that, |
|||
we'll be able to accept your pull requests. |
|||
|
|||
## Contributor Code of Conduct |
|||
|
|||
As contributors and maintainers of this project, |
|||
and in the interest of fostering an open and welcoming community, |
|||
we pledge to respect all people who contribute through reporting issues, |
|||
posting feature requests, updating documentation, |
|||
submitting pull requests or patches, and other activities. |
|||
|
|||
We are committed to making participation in this project |
|||
a harassment-free experience for everyone, |
|||
regardless of level of experience, gender, gender identity and expression, |
|||
sexual orientation, disability, personal appearance, |
|||
body size, race, ethnicity, age, religion, or nationality. |
|||
|
|||
Examples of unacceptable behavior by participants include: |
|||
|
|||
* The use of sexualized language or imagery |
|||
* Personal attacks |
|||
* Trolling or insulting/derogatory comments |
|||
* Public or private harassment |
|||
* Publishing other's private information, |
|||
such as physical or electronic |
|||
addresses, without explicit permission |
|||
* Other unethical or unprofessional conduct. |
|||
|
|||
Project maintainers have the right and responsibility to remove, edit, or reject |
|||
comments, commits, code, wiki edits, issues, and other contributions |
|||
that are not aligned to this Code of Conduct. |
|||
By adopting this Code of Conduct, |
|||
project maintainers commit themselves to fairly and consistently |
|||
applying these principles to every aspect of managing this project. |
|||
Project maintainers who do not follow or enforce the Code of Conduct |
|||
may be permanently removed from the project team. |
|||
|
|||
This code of conduct applies both within project spaces and in public spaces |
|||
when an individual is representing the project or its community. |
|||
|
|||
Instances of abusive, harassing, or otherwise unacceptable behavior |
|||
may be reported by opening an issue |
|||
or contacting one or more of the project maintainers. |
|||
|
|||
This Code of Conduct is adapted from the [Contributor Covenant](http://contributor-covenant.org), version 1.2.0, |
|||
available at [http://contributor-covenant.org/version/1/2/0/](http://contributor-covenant.org/version/1/2/0/) |
|||
|
|||
[gcloudcli]: https://developers.google.com/cloud/sdk/gcloud/ |
|||
[indvcla]: https://developers.google.com/open-source/cla/individual |
|||
[corpcla]: https://developers.google.com/open-source/cla/corporate |
@ -0,0 +1,15 @@ |
|||
# Civil Date and Time |
|||
|
|||
[](https://godoc.org/github.com/golang-sql/civil) |
|||
|
|||
Civil provides Date, Time of Day, and DateTime data types. |
|||
|
|||
While there are many uses, using specific types when working |
|||
with databases make is conceptually eaiser to understand what value |
|||
is set in the remote system. |
|||
|
|||
## Source |
|||
|
|||
This civil package was extracted and forked from `cloud.google.com/go/civil`. |
|||
As such the license and contributing requirements remain the same as that |
|||
module. |
@ -1,29 +0,0 @@ |
|||
## Contributing to pq |
|||
|
|||
`pq` has a backlog of pull requests, but contributions are still very |
|||
much welcome. You can help with patch review, submitting bug reports, |
|||
or adding new functionality. There is no formal style guide, but |
|||
please conform to the style of existing code and general Go formatting |
|||
conventions when submitting patches. |
|||
|
|||
### Patch review |
|||
|
|||
Help review existing open pull requests by commenting on the code or |
|||
proposed functionality. |
|||
|
|||
### Bug reports |
|||
|
|||
We appreciate any bug reports, but especially ones with self-contained |
|||
(doesn't depend on code outside of pq), minimal (can't be simplified |
|||
further) test cases. It's especially helpful if you can submit a pull |
|||
request with just the failing test case (you'll probably want to |
|||
pattern it after the tests in |
|||
[conn_test.go](https://github.com/lib/pq/blob/master/conn_test.go). |
|||
|
|||
### New functionality |
|||
|
|||
There are a number of pending patches for new functionality, so |
|||
additional feature patches will take a while to merge. Still, patches |
|||
are generally reviewed based on usefulness and complexity in addition |
|||
to time-in-queue, so if you have a knockout idea, take a shot. Feel |
|||
free to open an issue discussion your proposed patch beforehand. |
@ -1 +1,3 @@ |
|||
module github.com/lib/pq |
|||
|
|||
go 1.13 |
@ -0,0 +1,27 @@ |
|||
package pq |
|||
|
|||
// NewGSSFunc creates a GSS authentication provider, for use with
|
|||
// RegisterGSSProvider.
|
|||
type NewGSSFunc func() (GSS, error) |
|||
|
|||
var newGss NewGSSFunc |
|||
|
|||
// RegisterGSSProvider registers a GSS authentication provider. For example, if
|
|||
// you need to use Kerberos to authenticate with your server, add this to your
|
|||
// main package:
|
|||
//
|
|||
// import "github.com/lib/pq/auth/kerberos"
|
|||
//
|
|||
// func init() {
|
|||
// pq.RegisterGSSProvider(func() (pq.GSS, error) { return kerberos.NewGSS() })
|
|||
// }
|
|||
func RegisterGSSProvider(newGssArg NewGSSFunc) { |
|||
newGss = newGssArg |
|||
} |
|||
|
|||
// GSS provides GSSAPI authentication (e.g., Kerberos).
|
|||
type GSS interface { |
|||
GetInitToken(host string, service string) ([]byte, error) |
|||
GetInitTokenFromSpn(spn string) ([]byte, error) |
|||
Continue(inToken []byte) (done bool, outToken []byte, err error) |
|||
} |
@ -0,0 +1,71 @@ |
|||
// +build go1.10
|
|||
|
|||
package pq |
|||
|
|||
import ( |
|||
"context" |
|||
"database/sql/driver" |
|||
) |
|||
|
|||
// NoticeHandler returns the notice handler on the given connection, if any. A
|
|||
// runtime panic occurs if c is not a pq connection. This is rarely used
|
|||
// directly, use ConnectorNoticeHandler and ConnectorWithNoticeHandler instead.
|
|||
func NoticeHandler(c driver.Conn) func(*Error) { |
|||
return c.(*conn).noticeHandler |
|||
} |
|||
|
|||
// SetNoticeHandler sets the given notice handler on the given connection. A
|
|||
// runtime panic occurs if c is not a pq connection. A nil handler may be used
|
|||
// to unset it. This is rarely used directly, use ConnectorNoticeHandler and
|
|||
// ConnectorWithNoticeHandler instead.
|
|||
//
|
|||
// Note: Notice handlers are executed synchronously by pq meaning commands
|
|||
// won't continue to be processed until the handler returns.
|
|||
func SetNoticeHandler(c driver.Conn, handler func(*Error)) { |
|||
c.(*conn).noticeHandler = handler |
|||
} |
|||
|
|||
// NoticeHandlerConnector wraps a regular connector and sets a notice handler
|
|||
// on it.
|
|||
type NoticeHandlerConnector struct { |
|||
driver.Connector |
|||
noticeHandler func(*Error) |
|||
} |
|||
|
|||
// Connect calls the underlying connector's connect method and then sets the
|
|||
// notice handler.
|
|||
func (n *NoticeHandlerConnector) Connect(ctx context.Context) (driver.Conn, error) { |
|||
c, err := n.Connector.Connect(ctx) |
|||
if err == nil { |
|||
SetNoticeHandler(c, n.noticeHandler) |
|||
} |
|||
return c, err |
|||
} |
|||
|
|||
// ConnectorNoticeHandler returns the currently set notice handler, if any. If
|
|||
// the given connector is not a result of ConnectorWithNoticeHandler, nil is
|
|||
// returned.
|
|||
func ConnectorNoticeHandler(c driver.Connector) func(*Error) { |
|||
if c, ok := c.(*NoticeHandlerConnector); ok { |
|||
return c.noticeHandler |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
// ConnectorWithNoticeHandler creates or sets the given handler for the given
|
|||
// connector. If the given connector is a result of calling this function
|
|||
// previously, it is simply set on the given connector and returned. Otherwise,
|
|||
// this returns a new connector wrapping the given one and setting the notice
|
|||
// handler. A nil notice handler may be used to unset it.
|
|||
//
|
|||
// The returned connector is intended to be used with database/sql.OpenDB.
|
|||
//
|
|||
// Note: Notice handlers are executed synchronously by pq meaning commands
|
|||
// won't continue to be processed until the handler returns.
|
|||
func ConnectorWithNoticeHandler(c driver.Connector, handler func(*Error)) *NoticeHandlerConnector { |
|||
if c, ok := c.(*NoticeHandlerConnector); ok { |
|||
c.noticeHandler = handler |
|||
return c |
|||
} |
|||
return &NoticeHandlerConnector{Connector: c, noticeHandler: handler} |
|||
} |
@ -0,0 +1,264 @@ |
|||
// Copyright (c) 2014 - Gustavo Niemeyer <gustavo@niemeyer.net>
|
|||
//
|
|||
// All rights reserved.
|
|||
//
|
|||
// Redistribution and use in source and binary forms, with or without
|
|||
// modification, are permitted provided that the following conditions are met:
|
|||
//
|
|||
// 1. Redistributions of source code must retain the above copyright notice, this
|
|||
// list of conditions and the following disclaimer.
|
|||
// 2. Redistributions in binary form must reproduce the above copyright notice,
|
|||
// this list of conditions and the following disclaimer in the documentation
|
|||
// and/or other materials provided with the distribution.
|
|||
//
|
|||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
|||
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
|||
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|||
// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
|||
// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
|||
// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
|||
// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
|||
// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
|||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
|||
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|||
|
|||
// Package scram implements a SCRAM-{SHA-1,etc} client per RFC5802.
|
|||
//
|
|||
// http://tools.ietf.org/html/rfc5802
|
|||
//
|
|||
package scram |
|||
|
|||
import ( |
|||
"bytes" |
|||
"crypto/hmac" |
|||
"crypto/rand" |
|||
"encoding/base64" |
|||
"fmt" |
|||
"hash" |
|||
"strconv" |
|||
"strings" |
|||
) |
|||
|
|||
// Client implements a SCRAM-* client (SCRAM-SHA-1, SCRAM-SHA-256, etc).
|
|||
//
|
|||
// A Client may be used within a SASL conversation with logic resembling:
|
|||
//
|
|||
// var in []byte
|
|||
// var client = scram.NewClient(sha1.New, user, pass)
|
|||
// for client.Step(in) {
|
|||
// out := client.Out()
|
|||
// // send out to server
|
|||
// in := serverOut
|
|||
// }
|
|||
// if client.Err() != nil {
|
|||
// // auth failed
|
|||
// }
|
|||
//
|
|||
type Client struct { |
|||
newHash func() hash.Hash |
|||
|
|||
user string |
|||
pass string |
|||
step int |
|||
out bytes.Buffer |
|||
err error |
|||
|
|||
clientNonce []byte |
|||
serverNonce []byte |
|||
saltedPass []byte |
|||
authMsg bytes.Buffer |
|||
} |
|||
|
|||
// NewClient returns a new SCRAM-* client with the provided hash algorithm.
|
|||
//
|
|||
// For SCRAM-SHA-256, for example, use:
|
|||
//
|
|||
// client := scram.NewClient(sha256.New, user, pass)
|
|||
//
|
|||
func NewClient(newHash func() hash.Hash, user, pass string) *Client { |
|||
c := &Client{ |
|||
newHash: newHash, |
|||
user: user, |
|||
pass: pass, |
|||
} |
|||
c.out.Grow(256) |
|||
c.authMsg.Grow(256) |
|||
return c |
|||
} |
|||
|
|||
// Out returns the data to be sent to the server in the current step.
|
|||
func (c *Client) Out() []byte { |
|||
if c.out.Len() == 0 { |
|||
return nil |
|||
} |
|||
return c.out.Bytes() |
|||
} |
|||
|
|||
// Err returns the error that occurred, or nil if there were no errors.
|
|||
func (c *Client) Err() error { |
|||
return c.err |
|||
} |
|||
|
|||
// SetNonce sets the client nonce to the provided value.
|
|||
// If not set, the nonce is generated automatically out of crypto/rand on the first step.
|
|||
func (c *Client) SetNonce(nonce []byte) { |
|||
c.clientNonce = nonce |
|||
} |
|||
|
|||
var escaper = strings.NewReplacer("=", "=3D", ",", "=2C") |
|||
|
|||
// Step processes the incoming data from the server and makes the
|
|||
// next round of data for the server available via Client.Out.
|
|||
// Step returns false if there are no errors and more data is
|
|||
// still expected.
|
|||
func (c *Client) Step(in []byte) bool { |
|||
c.out.Reset() |
|||
if c.step > 2 || c.err != nil { |
|||
return false |
|||
} |
|||
c.step++ |
|||
switch c.step { |
|||
case 1: |
|||
c.err = c.step1(in) |
|||
case 2: |
|||
c.err = c.step2(in) |
|||
case 3: |
|||
c.err = c.step3(in) |
|||
} |
|||
return c.step > 2 || c.err != nil |
|||
} |
|||
|
|||
func (c *Client) step1(in []byte) error { |
|||
if len(c.clientNonce) == 0 { |
|||
const nonceLen = 16 |
|||
buf := make([]byte, nonceLen+b64.EncodedLen(nonceLen)) |
|||
if _, err := rand.Read(buf[:nonceLen]); err != nil { |
|||
return fmt.Errorf("cannot read random SCRAM-SHA-256 nonce from operating system: %v", err) |
|||
} |
|||
c.clientNonce = buf[nonceLen:] |
|||
b64.Encode(c.clientNonce, buf[:nonceLen]) |
|||
} |
|||
c.authMsg.WriteString("n=") |
|||
escaper.WriteString(&c.authMsg, c.user) |
|||
c.authMsg.WriteString(",r=") |
|||
c.authMsg.Write(c.clientNonce) |
|||
|
|||
c.out.WriteString("n,,") |
|||
c.out.Write(c.authMsg.Bytes()) |
|||
return nil |
|||
} |
|||
|
|||
var b64 = base64.StdEncoding |
|||
|
|||
func (c *Client) step2(in []byte) error { |
|||
c.authMsg.WriteByte(',') |
|||
c.authMsg.Write(in) |
|||
|
|||
fields := bytes.Split(in, []byte(",")) |
|||
if len(fields) != 3 { |
|||
return fmt.Errorf("expected 3 fields in first SCRAM-SHA-256 server message, got %d: %q", len(fields), in) |
|||
} |
|||
if !bytes.HasPrefix(fields[0], []byte("r=")) || len(fields[0]) < 2 { |
|||
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 nonce: %q", fields[0]) |
|||
} |
|||
if !bytes.HasPrefix(fields[1], []byte("s=")) || len(fields[1]) < 6 { |
|||
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 salt: %q", fields[1]) |
|||
} |
|||
if !bytes.HasPrefix(fields[2], []byte("i=")) || len(fields[2]) < 6 { |
|||
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2]) |
|||
} |
|||
|
|||
c.serverNonce = fields[0][2:] |
|||
if !bytes.HasPrefix(c.serverNonce, c.clientNonce) { |
|||
return fmt.Errorf("server SCRAM-SHA-256 nonce is not prefixed by client nonce: got %q, want %q+\"...\"", c.serverNonce, c.clientNonce) |
|||
} |
|||
|
|||
salt := make([]byte, b64.DecodedLen(len(fields[1][2:]))) |
|||
n, err := b64.Decode(salt, fields[1][2:]) |
|||
if err != nil { |
|||
return fmt.Errorf("cannot decode SCRAM-SHA-256 salt sent by server: %q", fields[1]) |
|||
} |
|||
salt = salt[:n] |
|||
iterCount, err := strconv.Atoi(string(fields[2][2:])) |
|||
if err != nil { |
|||
return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2]) |
|||
} |
|||
c.saltPassword(salt, iterCount) |
|||
|
|||
c.authMsg.WriteString(",c=biws,r=") |
|||
c.authMsg.Write(c.serverNonce) |
|||
|
|||
c.out.WriteString("c=biws,r=") |
|||
c.out.Write(c.serverNonce) |
|||
c.out.WriteString(",p=") |
|||
c.out.Write(c.clientProof()) |
|||
return nil |
|||
} |
|||
|
|||
func (c *Client) step3(in []byte) error { |
|||
var isv, ise bool |
|||
var fields = bytes.Split(in, []byte(",")) |
|||
if len(fields) == 1 { |
|||
isv = bytes.HasPrefix(fields[0], []byte("v=")) |
|||
ise = bytes.HasPrefix(fields[0], []byte("e=")) |
|||
} |
|||
if ise { |
|||
return fmt.Errorf("SCRAM-SHA-256 authentication error: %s", fields[0][2:]) |
|||
} else if !isv { |
|||
return fmt.Errorf("unsupported SCRAM-SHA-256 final message from server: %q", in) |
|||
} |
|||
if !bytes.Equal(c.serverSignature(), fields[0][2:]) { |
|||
return fmt.Errorf("cannot authenticate SCRAM-SHA-256 server signature: %q", fields[0][2:]) |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
func (c *Client) saltPassword(salt []byte, iterCount int) { |
|||
mac := hmac.New(c.newHash, []byte(c.pass)) |
|||
mac.Write(salt) |
|||
mac.Write([]byte{0, 0, 0, 1}) |
|||
ui := mac.Sum(nil) |
|||
hi := make([]byte, len(ui)) |
|||
copy(hi, ui) |
|||
for i := 1; i < iterCount; i++ { |
|||
mac.Reset() |
|||
mac.Write(ui) |
|||
mac.Sum(ui[:0]) |
|||
for j, b := range ui { |
|||
hi[j] ^= b |
|||
} |
|||
} |
|||
c.saltedPass = hi |
|||
} |
|||
|
|||
func (c *Client) clientProof() []byte { |
|||
mac := hmac.New(c.newHash, c.saltedPass) |
|||
mac.Write([]byte("Client Key")) |
|||
clientKey := mac.Sum(nil) |
|||
hash := c.newHash() |
|||
hash.Write(clientKey) |
|||
storedKey := hash.Sum(nil) |
|||
mac = hmac.New(c.newHash, storedKey) |
|||
mac.Write(c.authMsg.Bytes()) |
|||
clientProof := mac.Sum(nil) |
|||
for i, b := range clientKey { |
|||
clientProof[i] ^= b |
|||
} |
|||
clientProof64 := make([]byte, b64.EncodedLen(len(clientProof))) |
|||
b64.Encode(clientProof64, clientProof) |
|||
return clientProof64 |
|||
} |
|||
|
|||
func (c *Client) serverSignature() []byte { |
|||
mac := hmac.New(c.newHash, c.saltedPass) |
|||
mac.Write([]byte("Server Key")) |
|||
serverKey := mac.Sum(nil) |
|||
|
|||
mac = hmac.New(c.newHash, serverKey) |
|||
mac.Write(c.authMsg.Bytes()) |
|||
serverSignature := mac.Sum(nil) |
|||
|
|||
encoded := make([]byte, b64.EncodedLen(len(serverSignature))) |
|||
b64.Encode(encoded, serverSignature) |
|||
return encoded |
|||
} |
@ -1,14 +0,0 @@ |
|||
// +build go1.7
|
|||
|
|||
package pq |
|||
|
|||
import "crypto/tls" |
|||
|
|||
// Accept renegotiation requests initiated by the backend.
|
|||
//
|
|||
// Renegotiation was deprecated then removed from PostgreSQL 9.5, but
|
|||
// the default configuration of older versions has it enabled. Redshift
|
|||
// also initiates renegotiations and cannot be reconfigured.
|
|||
func sslRenegotiation(conf *tls.Config) { |
|||
conf.Renegotiation = tls.RenegotiateFreelyAsClient |
|||
} |
@ -1,8 +0,0 @@ |
|||
// +build !go1.7
|
|||
|
|||
package pq |
|||
|
|||
import "crypto/tls" |
|||
|
|||
// Renegotiation is not supported by crypto/tls until Go 1.7.
|
|||
func sslRenegotiation(*tls.Config) {} |
@ -0,0 +1,299 @@ |
|||
// Extracted from Go database/sql source code
|
|||
|
|||
// Copyright 2011 The Go Authors. All rights reserved.
|
|||
// Use of this source code is governed by a BSD-style
|
|||
// license that can be found in the LICENSE file.
|
|||
|
|||
// Type conversions for Scan.
|
|||
|
|||
package sqlite3 |
|||
|
|||
import ( |
|||
"database/sql" |
|||
"database/sql/driver" |
|||
"errors" |
|||
"fmt" |
|||
"reflect" |
|||
"strconv" |
|||
"time" |
|||
) |
|||
|
|||
var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error
|
|||
|
|||
// convertAssign copies to dest the value in src, converting it if possible.
|
|||
// An error is returned if the copy would result in loss of information.
|
|||
// dest should be a pointer type.
|
|||
func convertAssign(dest, src interface{}) error { |
|||
// Common cases, without reflect.
|
|||
switch s := src.(type) { |
|||
case string: |
|||
switch d := dest.(type) { |
|||
case *string: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = s |
|||
return nil |
|||
case *[]byte: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = []byte(s) |
|||
return nil |
|||
case *sql.RawBytes: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = append((*d)[:0], s...) |
|||
return nil |
|||
} |
|||
case []byte: |
|||
switch d := dest.(type) { |
|||
case *string: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = string(s) |
|||
return nil |
|||
case *interface{}: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = cloneBytes(s) |
|||
return nil |
|||
case *[]byte: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = cloneBytes(s) |
|||
return nil |
|||
case *sql.RawBytes: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = s |
|||
return nil |
|||
} |
|||
case time.Time: |
|||
switch d := dest.(type) { |
|||
case *time.Time: |
|||
*d = s |
|||
return nil |
|||
case *string: |
|||
*d = s.Format(time.RFC3339Nano) |
|||
return nil |
|||
case *[]byte: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = []byte(s.Format(time.RFC3339Nano)) |
|||
return nil |
|||
case *sql.RawBytes: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = s.AppendFormat((*d)[:0], time.RFC3339Nano) |
|||
return nil |
|||
} |
|||
case nil: |
|||
switch d := dest.(type) { |
|||
case *interface{}: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = nil |
|||
return nil |
|||
case *[]byte: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = nil |
|||
return nil |
|||
case *sql.RawBytes: |
|||
if d == nil { |
|||
return errNilPtr |
|||
} |
|||
*d = nil |
|||
return nil |
|||
} |
|||
} |
|||
|
|||
var sv reflect.Value |
|||
|
|||
switch d := dest.(type) { |
|||
case *string: |
|||
sv = reflect.ValueOf(src) |
|||
switch sv.Kind() { |
|||
case reflect.Bool, |
|||
reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, |
|||
reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, |
|||
reflect.Float32, reflect.Float64: |
|||
*d = asString(src) |
|||
return nil |
|||
} |
|||
case *[]byte: |
|||
sv = reflect.ValueOf(src) |
|||
if b, ok := asBytes(nil, sv); ok { |
|||
*d = b |
|||
return nil |
|||
} |
|||
case *sql.RawBytes: |
|||
sv = reflect.ValueOf(src) |
|||
if b, ok := asBytes([]byte(*d)[:0], sv); ok { |
|||
*d = sql.RawBytes(b) |
|||
return nil |
|||
} |
|||
case *bool: |
|||
bv, err := driver.Bool.ConvertValue(src) |
|||
if err == nil { |
|||
*d = bv.(bool) |
|||
} |
|||
return err |
|||
case *interface{}: |
|||
*d = src |
|||
return nil |
|||
} |
|||
|
|||
if scanner, ok := dest.(sql.Scanner); ok { |
|||
return scanner.Scan(src) |
|||
} |
|||
|
|||
dpv := reflect.ValueOf(dest) |
|||
if dpv.Kind() != reflect.Ptr { |
|||
return errors.New("destination not a pointer") |
|||
} |
|||
if dpv.IsNil() { |
|||
return errNilPtr |
|||
} |
|||
|
|||
if !sv.IsValid() { |
|||
sv = reflect.ValueOf(src) |
|||
} |
|||
|
|||
dv := reflect.Indirect(dpv) |
|||
if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { |
|||
switch b := src.(type) { |
|||
case []byte: |
|||
dv.Set(reflect.ValueOf(cloneBytes(b))) |
|||
default: |
|||
dv.Set(sv) |
|||
} |
|||
return nil |
|||
} |
|||
|
|||
if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { |
|||
dv.Set(sv.Convert(dv.Type())) |
|||
return nil |
|||
} |
|||
|
|||
// The following conversions use a string value as an intermediate representation
|
|||
// to convert between various numeric types.
|
|||
//
|
|||
// This also allows scanning into user defined types such as "type Int int64".
|
|||
// For symmetry, also check for string destination types.
|
|||
switch dv.Kind() { |
|||
case reflect.Ptr: |
|||
if src == nil { |
|||
dv.Set(reflect.Zero(dv.Type())) |
|||
return nil |
|||
} |
|||
dv.Set(reflect.New(dv.Type().Elem())) |
|||
return convertAssign(dv.Interface(), src) |
|||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
|||
s := asString(src) |
|||
i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) |
|||
if err != nil { |
|||
err = strconvErr(err) |
|||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) |
|||
} |
|||
dv.SetInt(i64) |
|||
return nil |
|||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
|||
s := asString(src) |
|||
u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) |
|||
if err != nil { |
|||
err = strconvErr(err) |
|||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) |
|||
} |
|||
dv.SetUint(u64) |
|||
return nil |
|||
case reflect.Float32, reflect.Float64: |
|||
s := asString(src) |
|||
f64, err := strconv.ParseFloat(s, dv.Type().Bits()) |
|||
if err != nil { |
|||
err = strconvErr(err) |
|||
return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) |
|||
} |
|||
dv.SetFloat(f64) |
|||
return nil |
|||
case reflect.String: |
|||
switch v := src.(type) { |
|||
case string: |
|||
dv.SetString(v) |
|||
return nil |
|||
case []byte: |
|||
dv.SetString(string(v)) |
|||
return nil |
|||
} |
|||
} |
|||
|
|||
return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) |
|||
} |
|||
|
|||
func strconvErr(err error) error { |
|||
if ne, ok := err.(*strconv.NumError); ok { |
|||
return ne.Err |
|||
} |
|||
return err |
|||
} |
|||
|
|||
func cloneBytes(b []byte) []byte { |
|||
if b == nil { |
|||
return nil |
|||
} |
|||
c := make([]byte, len(b)) |
|||
copy(c, b) |
|||
return c |
|||
} |
|||
|
|||
func asString(src interface{}) string { |
|||
switch v := src.(type) { |
|||
case string: |
|||
return v |
|||
case []byte: |
|||
return string(v) |
|||
} |
|||
rv := reflect.ValueOf(src) |
|||
switch rv.Kind() { |
|||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
|||
return strconv.FormatInt(rv.Int(), 10) |
|||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
|||
return strconv.FormatUint(rv.Uint(), 10) |
|||
case reflect.Float64: |
|||
return strconv.FormatFloat(rv.Float(), 'g', -1, 64) |
|||
case reflect.Float32: |
|||
return strconv.FormatFloat(rv.Float(), 'g', -1, 32) |
|||
case reflect.Bool: |
|||
return strconv.FormatBool(rv.Bool()) |
|||
} |
|||
return fmt.Sprintf("%v", src) |
|||
} |
|||
|
|||
func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) { |
|||
switch rv.Kind() { |
|||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: |
|||
return strconv.AppendInt(buf, rv.Int(), 10), true |
|||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: |
|||
return strconv.AppendUint(buf, rv.Uint(), 10), true |
|||
case reflect.Float32: |
|||
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true |
|||
case reflect.Float64: |
|||
return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true |
|||
case reflect.Bool: |
|||
return strconv.AppendBool(buf, rv.Bool()), true |
|||
case reflect.String: |
|||
s := rv.String() |
|||
return append(buf, s...), true |
|||
} |
|||
return |
|||
} |
@ -0,0 +1,8 @@ |
|||
module github.com/mattn/go-sqlite3 |
|||
|
|||
go 1.10 |
|||
|
|||
require ( |
|||
github.com/PuerkitoBio/goquery v1.5.1 |
|||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e // indirect |
|||
) |
@ -0,0 +1,13 @@ |
|||
github.com/PuerkitoBio/goquery v1.5.1 h1:PSPBGne8NIUWw+/7vFBV+kG2J/5MOjbzc7154OaKCSE= |
|||
github.com/PuerkitoBio/goquery v1.5.1/go.mod h1:GsLWisAFVj4WgDibEWF4pvYnkVQBpKBKeU+7zCJoLcc= |
|||
github.com/andybalholm/cascadia v1.1.0 h1:BuuO6sSfQNFRu1LppgbD25Hr2vLYW25JvxHs5zzsLTo= |
|||
github.com/andybalholm/cascadia v1.1.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= |
|||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= |
|||
golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= |
|||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2 h1:CCH4IOTTfewWjGOlSp+zGcjutRKlBEZQ6wTn8ozI/nI= |
|||
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= |
|||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e h1:3G+cUijn7XD+S4eJFddp53Pv7+slrESplyjG25HgL+k= |
|||
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= |
|||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= |
|||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= |
|||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= |
32105
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.c
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
1101
vendor/github.com/mattn/go-sqlite3/sqlite3-binding.h
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Some files were not shown because too many files changed in this diff
Write
Preview
Loading…
Cancel
Save
Reference in new issue