Update to latest mssqldriver (#7613)
* New driver does not tolerate USE - handle this by closing db and reopening db in the new dbnametokarchuk/v1.17
parent
bebc6a3c77
commit
78e5317242
@ -0,0 +1,15 @@ |
||||
# 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> |
@ -0,0 +1,40 @@ |
||||
# 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> |
@ -0,0 +1,202 @@ |
||||
|
||||
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,277 @@ |
||||
// Copyright 2016 Google LLC
|
||||
//
|
||||
// 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.
|
||||
|
||||
// Package civil implements types for civil time, a time-zone-independent
|
||||
// representation of time that follows the rules of the proleptic
|
||||
// Gregorian calendar with exactly 24-hour days, 60-minute hours, and 60-second
|
||||
// minutes.
|
||||
//
|
||||
// Because they lack location information, these types do not represent unique
|
||||
// moments or intervals of time. Use time.Time for that purpose.
|
||||
package civil |
||||
|
||||
import ( |
||||
"fmt" |
||||
"time" |
||||
) |
||||
|
||||
// A Date represents a date (year, month, day).
|
||||
//
|
||||
// This type does not include location information, and therefore does not
|
||||
// describe a unique 24-hour timespan.
|
||||
type Date struct { |
||||
Year int // Year (e.g., 2014).
|
||||
Month time.Month // Month of the year (January = 1, ...).
|
||||
Day int // Day of the month, starting at 1.
|
||||
} |
||||
|
||||
// DateOf returns the Date in which a time occurs in that time's location.
|
||||
func DateOf(t time.Time) Date { |
||||
var d Date |
||||
d.Year, d.Month, d.Day = t.Date() |
||||
return d |
||||
} |
||||
|
||||
// ParseDate parses a string in RFC3339 full-date format and returns the date value it represents.
|
||||
func ParseDate(s string) (Date, error) { |
||||
t, err := time.Parse("2006-01-02", s) |
||||
if err != nil { |
||||
return Date{}, err |
||||
} |
||||
return DateOf(t), nil |
||||
} |
||||
|
||||
// String returns the date in RFC3339 full-date format.
|
||||
func (d Date) String() string { |
||||
return fmt.Sprintf("%04d-%02d-%02d", d.Year, d.Month, d.Day) |
||||
} |
||||
|
||||
// IsValid reports whether the date is valid.
|
||||
func (d Date) IsValid() bool { |
||||
return DateOf(d.In(time.UTC)) == d |
||||
} |
||||
|
||||
// In returns the time corresponding to time 00:00:00 of the date in the location.
|
||||
//
|
||||
// In is always consistent with time.Date, even when time.Date returns a time
|
||||
// on a different day. For example, if loc is America/Indiana/Vincennes, then both
|
||||
// time.Date(1955, time.May, 1, 0, 0, 0, 0, loc)
|
||||
// and
|
||||
// civil.Date{Year: 1955, Month: time.May, Day: 1}.In(loc)
|
||||
// return 23:00:00 on April 30, 1955.
|
||||
//
|
||||
// In panics if loc is nil.
|
||||
func (d Date) In(loc *time.Location) time.Time { |
||||
return time.Date(d.Year, d.Month, d.Day, 0, 0, 0, 0, loc) |
||||
} |
||||
|
||||
// AddDays returns the date that is n days in the future.
|
||||
// n can also be negative to go into the past.
|
||||
func (d Date) AddDays(n int) Date { |
||||
return DateOf(d.In(time.UTC).AddDate(0, 0, n)) |
||||
} |
||||
|
||||
// DaysSince returns the signed number of days between the date and s, not including the end day.
|
||||
// This is the inverse operation to AddDays.
|
||||
func (d Date) DaysSince(s Date) (days int) { |
||||
// We convert to Unix time so we do not have to worry about leap seconds:
|
||||
// Unix time increases by exactly 86400 seconds per day.
|
||||
deltaUnix := d.In(time.UTC).Unix() - s.In(time.UTC).Unix() |
||||
return int(deltaUnix / 86400) |
||||
} |
||||
|
||||
// Before reports whether d1 occurs before d2.
|
||||
func (d1 Date) Before(d2 Date) bool { |
||||
if d1.Year != d2.Year { |
||||
return d1.Year < d2.Year |
||||
} |
||||
if d1.Month != d2.Month { |
||||
return d1.Month < d2.Month |
||||
} |
||||
return d1.Day < d2.Day |
||||
} |
||||
|
||||
// After reports whether d1 occurs after d2.
|
||||
func (d1 Date) After(d2 Date) bool { |
||||
return d2.Before(d1) |
||||
} |
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
// The output is the result of d.String().
|
||||
func (d Date) MarshalText() ([]byte, error) { |
||||
return []byte(d.String()), nil |
||||
} |
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
// The date is expected to be a string in a format accepted by ParseDate.
|
||||
func (d *Date) UnmarshalText(data []byte) error { |
||||
var err error |
||||
*d, err = ParseDate(string(data)) |
||||
return err |
||||
} |
||||
|
||||
// A Time represents a time with nanosecond precision.
|
||||
//
|
||||
// This type does not include location information, and therefore does not
|
||||
// describe a unique moment in time.
|
||||
//
|
||||
// This type exists to represent the TIME type in storage-based APIs like BigQuery.
|
||||
// Most operations on Times are unlikely to be meaningful. Prefer the DateTime type.
|
||||
type Time struct { |
||||
Hour int // The hour of the day in 24-hour format; range [0-23]
|
||||
Minute int // The minute of the hour; range [0-59]
|
||||
Second int // The second of the minute; range [0-59]
|
||||
Nanosecond int // The nanosecond of the second; range [0-999999999]
|
||||
} |
||||
|
||||
// TimeOf returns the Time representing the time of day in which a time occurs
|
||||
// in that time's location. It ignores the date.
|
||||
func TimeOf(t time.Time) Time { |
||||
var tm Time |
||||
tm.Hour, tm.Minute, tm.Second = t.Clock() |
||||
tm.Nanosecond = t.Nanosecond() |
||||
return tm |
||||
} |
||||
|
||||
// ParseTime parses a string and returns the time value it represents.
|
||||
// ParseTime accepts an extended form of the RFC3339 partial-time format. After
|
||||
// the HH:MM:SS part of the string, an optional fractional part may appear,
|
||||
// consisting of a decimal point followed by one to nine decimal digits.
|
||||
// (RFC3339 admits only one digit after the decimal point).
|
||||
func ParseTime(s string) (Time, error) { |
||||
t, err := time.Parse("15:04:05.999999999", s) |
||||
if err != nil { |
||||
return Time{}, err |
||||
} |
||||
return TimeOf(t), nil |
||||
} |
||||
|
||||
// String returns the date in the format described in ParseTime. If Nanoseconds
|
||||
// is zero, no fractional part will be generated. Otherwise, the result will
|
||||
// end with a fractional part consisting of a decimal point and nine digits.
|
||||
func (t Time) String() string { |
||||
s := fmt.Sprintf("%02d:%02d:%02d", t.Hour, t.Minute, t.Second) |
||||
if t.Nanosecond == 0 { |
||||
return s |
||||
} |
||||
return s + fmt.Sprintf(".%09d", t.Nanosecond) |
||||
} |
||||
|
||||
// IsValid reports whether the time is valid.
|
||||
func (t Time) IsValid() bool { |
||||
// Construct a non-zero time.
|
||||
tm := time.Date(2, 2, 2, t.Hour, t.Minute, t.Second, t.Nanosecond, time.UTC) |
||||
return TimeOf(tm) == t |
||||
} |
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
// The output is the result of t.String().
|
||||
func (t Time) MarshalText() ([]byte, error) { |
||||
return []byte(t.String()), nil |
||||
} |
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
// The time is expected to be a string in a format accepted by ParseTime.
|
||||
func (t *Time) UnmarshalText(data []byte) error { |
||||
var err error |
||||
*t, err = ParseTime(string(data)) |
||||
return err |
||||
} |
||||
|
||||
// A DateTime represents a date and time.
|
||||
//
|
||||
// This type does not include location information, and therefore does not
|
||||
// describe a unique moment in time.
|
||||
type DateTime struct { |
||||
Date Date |
||||
Time Time |
||||
} |
||||
|
||||
// Note: We deliberately do not embed Date into DateTime, to avoid promoting AddDays and Sub.
|
||||
|
||||
// DateTimeOf returns the DateTime in which a time occurs in that time's location.
|
||||
func DateTimeOf(t time.Time) DateTime { |
||||
return DateTime{ |
||||
Date: DateOf(t), |
||||
Time: TimeOf(t), |
||||
} |
||||
} |
||||
|
||||
// ParseDateTime parses a string and returns the DateTime it represents.
|
||||
// ParseDateTime accepts a variant of the RFC3339 date-time format that omits
|
||||
// the time offset but includes an optional fractional time, as described in
|
||||
// ParseTime. Informally, the accepted format is
|
||||
// YYYY-MM-DDTHH:MM:SS[.FFFFFFFFF]
|
||||
// where the 'T' may be a lower-case 't'.
|
||||
func ParseDateTime(s string) (DateTime, error) { |
||||
t, err := time.Parse("2006-01-02T15:04:05.999999999", s) |
||||
if err != nil { |
||||
t, err = time.Parse("2006-01-02t15:04:05.999999999", s) |
||||
if err != nil { |
||||
return DateTime{}, err |
||||
} |
||||
} |
||||
return DateTimeOf(t), nil |
||||
} |
||||
|
||||
// String returns the date in the format described in ParseDate.
|
||||
func (dt DateTime) String() string { |
||||
return dt.Date.String() + "T" + dt.Time.String() |
||||
} |
||||
|
||||
// IsValid reports whether the datetime is valid.
|
||||
func (dt DateTime) IsValid() bool { |
||||
return dt.Date.IsValid() && dt.Time.IsValid() |
||||
} |
||||
|
||||
// In returns the time corresponding to the DateTime in the given location.
|
||||
//
|
||||
// If the time is missing or ambigous at the location, In returns the same
|
||||
// result as time.Date. For example, if loc is America/Indiana/Vincennes, then
|
||||
// both
|
||||
// time.Date(1955, time.May, 1, 0, 30, 0, 0, loc)
|
||||
// and
|
||||
// civil.DateTime{
|
||||
// civil.Date{Year: 1955, Month: time.May, Day: 1}},
|
||||
// civil.Time{Minute: 30}}.In(loc)
|
||||
// return 23:30:00 on April 30, 1955.
|
||||
//
|
||||
// In panics if loc is nil.
|
||||
func (dt DateTime) In(loc *time.Location) time.Time { |
||||
return time.Date(dt.Date.Year, dt.Date.Month, dt.Date.Day, dt.Time.Hour, dt.Time.Minute, dt.Time.Second, dt.Time.Nanosecond, loc) |
||||
} |
||||
|
||||
// Before reports whether dt1 occurs before dt2.
|
||||
func (dt1 DateTime) Before(dt2 DateTime) bool { |
||||
return dt1.In(time.UTC).Before(dt2.In(time.UTC)) |
||||
} |
||||
|
||||
// After reports whether dt1 occurs after dt2.
|
||||
func (dt1 DateTime) After(dt2 DateTime) bool { |
||||
return dt2.Before(dt1) |
||||
} |
||||
|
||||
// MarshalText implements the encoding.TextMarshaler interface.
|
||||
// The output is the result of dt.String().
|
||||
func (dt DateTime) MarshalText() ([]byte, error) { |
||||
return []byte(dt.String()), nil |
||||
} |
||||
|
||||
// UnmarshalText implements the encoding.TextUnmarshaler interface.
|
||||
// The datetime is expected to be a string in a format accepted by ParseDateTime
|
||||
func (dt *DateTime) UnmarshalText(data []byte) error { |
||||
var err error |
||||
*dt, err = ParseDateTime(string(data)) |
||||
return err |
||||
} |
@ -0,0 +1,306 @@ |
||||
package mssql |
||||
|
||||
import "errors" |
||||
|
||||
// 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.
|
||||
|
||||
// This file was imported from database.sql.convert for go 1.10.3 with minor modifications to get
|
||||
// convertAssign function
|
||||
// This function is used internally by sql to convert values during call to Scan, we need same
|
||||
// logic to return values for OUTPUT parameters.
|
||||
// TODO: sql library should instead expose function defaultCheckNamedValue to be callable by drivers
|
||||
|
||||
import ( |
||||
"database/sql" |
||||
"database/sql/driver" |
||||
"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 |
||||
} else { |
||||
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 |
||||
} else { |
||||
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 |
||||
} |
@ -1,12 +1,14 @@ |
||||
// package mssql implements the TDS protocol used to connect to MS SQL Server (sqlserver)
|
||||
// database servers.
|
||||
//
|
||||
// This package registers two drivers:
|
||||
// This package registers the driver:
|
||||
// sqlserver: uses native "@" parameter placeholder names and does no pre-processing.
|
||||
// mssql: expects identifiers to be prefixed with ":" and pre-processes queries.
|
||||
//
|
||||
// If the ordinal position is used for query parameters, identifiers will be named
|
||||
// "@p1", "@p2", ... "@pN".
|
||||
//
|
||||
// Please refer to the README for the format of the DSN.
|
||||
// Please refer to the README for the format of the DSN. There are multiple DSN
|
||||
// formats accepted: ADO style, ODBC style, and URL style. The following is an
|
||||
// example of a URL style DSN:
|
||||
// sqlserver://sa:mypass@localhost:1234?database=master&connection+timeout=30
|
||||
package mssql |
||||
|
@ -0,0 +1,10 @@ |
||||
module github.com/denisenkom/go-mssqldb |
||||
|
||||
go 1.11 |
||||
|
||||
require ( |
||||
cloud.google.com/go v0.37.4 |
||||
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 |
||||
) |
@ -0,0 +1,168 @@ |
||||
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= |
||||
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,47 @@ |
||||
// +build go1.10
|
||||
|
||||
package mssql |
||||
|
||||
import ( |
||||
"context" |
||||
"database/sql/driver" |
||||
) |
||||
|
||||
var _ driver.Connector = &Connector{} |
||||
var _ driver.SessionResetter = &Conn{} |
||||
|
||||
func (c *Conn) ResetSession(ctx context.Context) error { |
||||
if !c.connectionGood { |
||||
return driver.ErrBadConn |
||||
} |
||||
c.resetSession = true |
||||
|
||||
if c.connector == nil || len(c.connector.SessionInitSQL) == 0 { |
||||
return nil |
||||
} |
||||
|
||||
s, err := c.prepareContext(ctx, c.connector.SessionInitSQL) |
||||
if err != nil { |
||||
return driver.ErrBadConn |
||||
} |
||||
_, err = s.exec(ctx, nil) |
||||
if err != nil { |
||||
return driver.ErrBadConn |
||||
} |
||||
|
||||
return nil |
||||
} |
||||
|
||||
// Connect to the server and return a TDS connection.
|
||||
func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) { |
||||
conn, err := c.driver.connect(ctx, c, c.params) |
||||
if err == nil { |
||||
err = conn.ResetSession(ctx) |
||||
} |
||||
return conn, err |
||||
} |
||||
|
||||
// Driver underlying the Connector.
|
||||
func (c *Connector) Driver() driver.Driver { |
||||
return c.driver |
||||
} |
@ -1,91 +0,0 @@ |
||||
// +build go1.8
|
||||
|
||||
package mssql |
||||
|
||||
import ( |
||||
"context" |
||||
"database/sql" |
||||
"database/sql/driver" |
||||
"errors" |
||||
"strings" |
||||
) |
||||
|
||||
var _ driver.Pinger = &Conn{} |
||||
|
||||
// Ping is used to check if the remote server is available and satisfies the Pinger interface.
|
||||
func (c *Conn) Ping(ctx context.Context) error { |
||||
if !c.connectionGood { |
||||
return driver.ErrBadConn |
||||
} |
||||
stmt := &Stmt{c, `select 1;`, 0, nil} |
||||
_, err := stmt.ExecContext(ctx, nil) |
||||
return err |
||||
} |
||||
|
||||
var _ driver.ConnBeginTx = &Conn{} |
||||
|
||||
// BeginTx satisfies ConnBeginTx.
|
||||
func (c *Conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { |
||||
if !c.connectionGood { |
||||
return nil, driver.ErrBadConn |
||||
} |
||||
if opts.ReadOnly { |
||||
return nil, errors.New("Read-only transactions are not supported") |
||||
} |
||||
|
||||
var tdsIsolation isoLevel |
||||
switch sql.IsolationLevel(opts.Isolation) { |
||||
case sql.LevelDefault: |
||||
tdsIsolation = isolationUseCurrent |
||||
case sql.LevelReadUncommitted: |
||||
tdsIsolation = isolationReadUncommited |
||||
case sql.LevelReadCommitted: |
||||
tdsIsolation = isolationReadCommited |
||||
case sql.LevelWriteCommitted: |
||||
return nil, errors.New("LevelWriteCommitted isolation level is not supported") |
||||
case sql.LevelRepeatableRead: |
||||
tdsIsolation = isolationRepeatableRead |
||||
case sql.LevelSnapshot: |
||||
tdsIsolation = isolationSnapshot |
||||
case sql.LevelSerializable: |
||||
tdsIsolation = isolationSerializable |
||||
case sql.LevelLinearizable: |
||||
return nil, errors.New("LevelLinearizable isolation level is not supported") |
||||
default: |
||||
return nil, errors.New("Isolation level is not supported or unknown") |
||||
} |
||||
return c.begin(ctx, tdsIsolation) |
||||
} |
||||
|
||||
func (c *Conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { |
||||
if !c.connectionGood { |
||||
return nil, driver.ErrBadConn |
||||
} |
||||
if len(query) > 10 && strings.EqualFold(query[:10], "INSERTBULK") { |
||||
return c.prepareCopyIn(query) |
||||
} |
||||
|
||||
return c.prepareContext(ctx, query) |
||||
} |
||||
|
||||
func (s *Stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { |
||||
if !s.c.connectionGood { |
||||
return nil, driver.ErrBadConn |
||||
} |
||||
list := make([]namedValue, len(args)) |
||||
for i, nv := range args { |
||||
list[i] = namedValue(nv) |
||||
} |
||||
return s.queryContext(ctx, list) |
||||
} |
||||
|
||||
func (s *Stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { |
||||
if !s.c.connectionGood { |
||||
return nil, driver.ErrBadConn |
||||
} |
||||
list := make([]namedValue, len(args)) |
||||
for i, nv := range args { |
||||
list[i] = namedValue(nv) |
||||
} |
||||
return s.exec(ctx, list) |
||||
} |
@ -0,0 +1,231 @@ |
||||
// +build go1.9
|
||||
|
||||
package mssql |
||||
|
||||
import ( |
||||
"bytes" |
||||
"encoding/binary" |
||||
"errors" |
||||
"fmt" |
||||
"reflect" |
||||
"strings" |
||||
"time" |
||||
) |
||||
|
||||
const ( |
||||
jsonTag = "json" |
||||
tvpTag = "tvp" |
||||
skipTagValue = "-" |
||||
sqlSeparator = "." |
||||
) |
||||
|
||||
var ( |
||||
ErrorEmptyTVPTypeName = errors.New("TypeName must not be empty") |
||||
ErrorTypeSlice = errors.New("TVP must be slice type") |
||||
ErrorTypeSliceIsEmpty = errors.New("TVP mustn't be null value") |
||||
ErrorSkip = errors.New("all fields mustn't skip") |
||||
ErrorObjectName = errors.New("wrong tvp name") |
||||
ErrorWrongTyping = errors.New("the number of elements in columnStr and tvpFieldIndexes do not align") |
||||
) |
||||
|
||||
//TVP is driver type, which allows supporting Table Valued Parameters (TVP) in SQL Server
|
||||
type TVP struct { |
||||
//TypeName mustn't be default value
|
||||
TypeName string |
||||
//Value must be the slice, mustn't be nil
|
||||
Value interface{} |
||||
} |
||||
|
||||
func (tvp TVP) check() error { |
||||
if len(tvp.TypeName) == 0 { |
||||
return ErrorEmptyTVPTypeName |
||||
} |
||||
if !isProc(tvp.TypeName) { |
||||
return ErrorEmptyTVPTypeName |
||||
} |
||||
if sepCount := getCountSQLSeparators(tvp.TypeName); sepCount > 1 { |
||||
return ErrorObjectName |
||||
} |
||||
valueOf := reflect.ValueOf(tvp.Value) |
||||
if valueOf.Kind() != reflect.Slice { |
||||
return ErrorTypeSlice |
||||
} |
||||
if valueOf.IsNil() { |
||||
return ErrorTypeSliceIsEmpty |
||||
} |
||||
if reflect.TypeOf(tvp.Value).Elem().Kind() != reflect.Struct { |
||||
return ErrorTypeSlice |
||||
} |
||||
return nil |
||||
} |
||||
|
||||
func (tvp TVP) encode(schema, name string, columnStr []columnStruct, tvpFieldIndexes []int) ([]byte, error) { |
||||
if len(columnStr) != len(tvpFieldIndexes) { |
||||
return nil, ErrorWrongTyping |
||||
} |
||||
preparedBuffer := make([]byte, 0, 20+(10*len(columnStr))) |
||||
buf := bytes.NewBuffer(preparedBuffer) |
||||
err := writeBVarChar(buf, "") |
||||
if err != nil { |
||||
return nil, err |
||||
} |
||||
|
||||
writeBVarChar(buf, schema) |
||||
writeBVarChar(buf, name) |
||||
binary.Write(buf, binary.LittleEndian, uint16(len(columnStr))) |
||||
|
||||
for i, column := range columnStr { |
||||
binary.Write(buf, binary.LittleEndian, uint32(column.UserType)) |
||||
binary.Write(buf, binary.LittleEndian, uint16(column.Flags)) |
||||
writeTypeInfo(buf, &columnStr[i].ti) |
||||
writeBVarChar(buf, "") |
||||
} |
||||
// The returned error is always nil
|
||||
buf.WriteByte(_TVP_END_TOKEN) |
||||
|
||||
conn := new(Conn) |
||||
conn.sess = new(tdsSession) |
||||
conn.sess.loginAck = loginAckStruct{TDSVersion: verTDS73} |
||||
stmt := &Stmt{ |
||||
c: conn, |
||||
} |
||||
|
||||
val := reflect.ValueOf(tvp.Value) |
||||
for i := 0; i < val.Len(); i++ { |
||||
refStr := reflect.ValueOf(val.Index(i).Interface()) |
||||
buf.WriteByte(_TVP_ROW_TOKEN) |
||||
for columnStrIdx, fieldIdx := range tvpFieldIndexes { |
||||
field := refStr.Field(fieldIdx) |
||||
tvpVal := field.Interface() |
||||
valOf := reflect.ValueOf(tvpVal) |
||||
elemKind := field.Kind() |
||||
if elemKind == reflect.Ptr && valOf.IsNil() { |
||||
switch tvpVal.(type) { |
||||
case *bool, *time.Time, *int8, *int16, *int32, *int64, *float32, *float64, *int: |
||||
binary.Write(buf, binary.LittleEndian, uint8(0)) |
||||
continue |
||||
default: |
||||
binary.Write(buf, binary.LittleEndian, uint64(_PLP_NULL)) |
||||
continue |
||||
} |
||||
} |
||||
if elemKind == reflect.Slice && valOf.IsNil() { |
||||
binary.Write(buf, binary.LittleEndian, uint64(_PLP_NULL)) |
||||
continue |
||||
} |
||||
|
||||
cval, err := convertInputParameter(tvpVal) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("failed to convert tvp parameter row col: %s", err) |
||||
} |
||||
param, err := stmt.makeParam(cval) |
||||
if err != nil { |
||||
return nil, fmt.Errorf("failed to make tvp parameter row col: %s", err) |
||||
} |
||||
columnStr[columnStrIdx].ti.Writer(buf, param.ti, param.buffer) |
||||
} |
||||
} |
||||
buf.WriteByte(_TVP_END_TOKEN) |
||||
return buf.Bytes(), nil |
||||
} |
||||
|
||||
func (tvp TVP) columnTypes() ([]columnStruct, []int, error) { |
||||
val := reflect.ValueOf(tvp.Value) |
||||
var firstRow interface{} |
||||
if val.Len() != 0 { |
||||
firstRow = val.Index(0).Interface() |
||||
} else { |
||||
firstRow = reflect.New(reflect.TypeOf(tvp.Value).Elem()).Elem().Interface() |
||||
} |
||||
|
||||
tvpRow := reflect.TypeOf(firstRow) |
||||
columnCount := tvpRow.NumField() |
||||
defaultValues := make([]interface{}, 0, columnCount) |
||||
tvpFieldIndexes := make([]int, 0, columnCount) |
||||
for i := 0; i < columnCount; i++ { |
||||
field := tvpRow.Field(i) |
||||
tvpTagValue, isTvpTag := field.Tag.Lookup(tvpTag) |
||||
jsonTagValue, isJsonTag := field.Tag.Lookup(jsonTag) |
||||
if IsSkipField(tvpTagValue, isTvpTag, jsonTagValue, isJsonTag) { |
||||
continue |
||||
} |
||||
tvpFieldIndexes = append(tvpFieldIndexes, i) |
||||
if field.Type.Kind() == reflect.Ptr { |
||||
v := reflect.New(field.Type.Elem()) |
||||
defaultValues = append(defaultValues, v.Interface()) |
||||
continue |
||||
} |
||||
defaultValues = append(defaultValues, reflect.Zero(field.Type).Interface()) |
||||
} |
||||
|
||||
if columnCount-len(tvpFieldIndexes) == columnCount { |
||||
return nil, nil, ErrorSkip |
||||
} |
||||
|
||||
conn := new(Conn) |
||||
conn.sess = new(tdsSession) |
||||
conn.sess.loginAck = loginAckStruct{TDSVersion: verTDS73} |
||||
stmt := &Stmt{ |
||||
c: conn, |
||||
} |
||||
|
||||
columnConfiguration := make([]columnStruct, 0, columnCount) |
||||
for index, val := range defaultValues { |
||||
cval, err := convertInputParameter(val) |
||||
if err != nil { |
||||
return nil, nil, fmt.Errorf("failed to convert tvp parameter row %d col %d: %s", index, val, err) |
||||
} |
||||
param, err := stmt.makeParam(cval) |
||||
if err != nil { |
||||
return nil, nil, err |
||||
} |
||||
column := columnStruct{ |
||||
ti: param.ti, |
||||
} |
||||
switch param.ti.TypeId { |
||||
case typeNVarChar, typeBigVarBin: |
||||
column.ti.Size = 0 |
||||
} |
||||
columnConfiguration = append(columnConfiguration, column) |
||||
} |
||||
|
||||
return columnConfiguration, tvpFieldIndexes, nil |
||||
} |
||||
|
||||
func IsSkipField(tvpTagValue string, isTvpValue bool, jsonTagValue string, isJsonTagValue bool) bool { |
||||
if !isTvpValue && !isJsonTagValue { |
||||
return false |
||||
} else if isTvpValue && tvpTagValue != skipTagValue { |
||||
return false |
||||
} else if !isTvpValue && isJsonTagValue && jsonTagValue != skipTagValue { |
||||
return false |
||||
} |
||||
return true |
||||
} |
||||
|
||||
func getSchemeAndName(tvpName string) (string, string, error) { |
||||
if len(tvpName) == 0 { |
||||
return "", "", ErrorEmptyTVPTypeName |
||||
} |
||||
splitVal := strings.Split(tvpName, ".") |
||||
if len(splitVal) > 2 { |
||||
return "", "", errors.New("wrong tvp name") |
||||
} |
||||
if len(splitVal) == 2 { |
||||
res := make([]string, 2) |
||||
for key, value := range splitVal { |
||||
tmp := strings.Replace(value, "[", "", -1) |
||||
tmp = strings.Replace(tmp, "]", "", -1) |
||||
res[key] = tmp |
||||
} |
||||
return res[0], res[1], nil |
||||
} |
||||
tmp := strings.Replace(splitVal[0], "[", "", -1) |
||||
tmp = strings.Replace(tmp, "]", "", -1) |
||||
|
||||
return "", tmp, nil |
||||
} |
||||
|
||||
func getCountSQLSeparators(str string) int { |
||||
return strings.Count(str, sqlSeparator) |
||||
} |
Loading…
Reference in new issue