Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
150 changes: 141 additions & 9 deletions bulkcopy.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
"strings"
"time"

"github.com/golang-sql/civil"
"github.com/microsoft/go-mssqldb/internal/decimal"
"github.com/microsoft/go-mssqldb/msdsn"
shopspring "github.com/shopspring/decimal"
Expand Down Expand Up @@ -482,17 +483,62 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error)
case typeDateTime2N:
switch val := val.(type) {
case time.Time:
res.buffer = encodeDateTime2(val, int(col.ti.Scale))
res.buffer = encodeDateTime2(
val.Year(),
val.YearDay(),
val.Hour(),
val.Minute(),
val.Second(),
val.Nanosecond(),
int(col.ti.Scale),
)
res.ti.Size = len(res.buffer)
case string:
var t time.Time
if t, err = time.Parse(sqlDateTimeFormat, val); err != nil {
return res, fmt.Errorf("bulk: unable to convert string to date: %v", err)
}
res.buffer = encodeDateTime2(t, int(col.ti.Scale))
res.buffer = encodeDateTime2(
t.Year(),
t.YearDay(),
t.Hour(),
t.Minute(),
t.Second(),
t.Nanosecond(),
int(col.ti.Scale),
)
res.ti.Size = len(res.buffer)
case DateTime2:
dt := civil.DateTime(val)
res.buffer = encodeDateTime2(
dt.Date.Year,
dt.Date.DaysSince(civil.Date{Year: dt.Date.Year, Month: 1, Day: 1})+1,
dt.Time.Hour,
dt.Time.Minute,
dt.Time.Second,
dt.Time.Nanosecond,
int(col.ti.Scale),
)
res.ti.Size = len(res.buffer)
case NullDateTime2:
if val.Valid {
d := val.DateTime2
dt := civil.DateTime(d)
res.buffer = encodeDateTime2(
dt.Date.Year,
dt.Date.DaysSince(civil.Date{Year: dt.Date.Year, Month: 1, Day: 1})+1,
dt.Time.Hour,
dt.Time.Minute,
dt.Time.Second,
dt.Time.Nanosecond,
int(col.ti.Scale),
)
res.ti.Size = len(res.buffer)
} else {
res.ti.Size = 0
}
default:
err = fmt.Errorf("mssql: invalid type for datetime2 column: %T %s", val, val)
err = fmt.Errorf("mssql: invalid type for datetime2 column: %T %v", val, val)
return
}
case typeDateTimeOffsetN:
Expand All @@ -507,45 +553,119 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error)
}
res.buffer = encodeDateTimeOffset(t, int(col.ti.Scale))
res.ti.Size = len(res.buffer)
case DateTimeOffset:
res.buffer = encodeDateTimeOffset(time.Time(val), int(col.ti.Scale))
res.ti.Size = len(res.buffer)
case NullDateTimeOffset:
if val.Valid {
res.buffer = encodeDateTimeOffset(time.Time(val.DateTimeOffset), int(col.ti.Scale))
res.ti.Size = len(res.buffer)
} else {
res.ti.Size = 0
}
default:
err = fmt.Errorf("mssql: invalid type for datetimeoffset column: %T %s", val, val)
err = fmt.Errorf("mssql: invalid type for datetimeoffset column: %T %v", val, val)
return
}
case typeDateN:
switch val := val.(type) {
case time.Time:
res.buffer = encodeDate(val)
res.buffer = encodeDate(val.Year(), val.YearDay())
res.ti.Size = len(res.buffer)
case Date:
res.buffer = encodeDate(val.Year, civil.Date(val).DaysSince(civil.Date{Year: val.Year, Month: 1, Day: 1})+1)
res.ti.Size = len(res.buffer)
case NullDate:
if val.Valid {
res.buffer = encodeDate(val.Date.Year, civil.Date(val.Date).DaysSince(civil.Date{Year: val.Date.Year, Month: 1, Day: 1})+1)
res.ti.Size = len(res.buffer)
} else {
res.ti.Size = 0
}
case string:
var t time.Time
if t, err = time.ParseInLocation(sqlDateFormat, val, loc); err != nil {
return res, fmt.Errorf("bulk: unable to convert string to date: %v", err)
}
res.buffer = encodeDate(t)
res.buffer = encodeDate(t.Year(), t.YearDay())
res.ti.Size = len(res.buffer)
default:
err = fmt.Errorf("mssql: invalid type for date column: %T %s", val, val)
return
}
case typeDateTime, typeDateTimeN, typeDateTim4:
var year, yearDay, hour, minute, second, nanosecond int
var t time.Time
switch val := val.(type) {
case time.Time:
t = val

year = t.Year()
yearDay = t.YearDay()
hour = t.Hour()
minute = t.Minute()
second = t.Second()
nanosecond = t.Nanosecond()
case string:
if t, err = time.Parse(sqlDateTimeFormat, val); err != nil {
return res, fmt.Errorf("bulk: unable to convert string to date: %v", err)
}

year = t.Year()
yearDay = t.YearDay()
hour = t.Hour()
minute = t.Minute()
second = t.Second()
nanosecond = t.Nanosecond()
case DateTime:
if col.ti.Size == 4 {
err = fmt.Errorf("mssql: invalid type for datetime column: %T %v", val, val)
return
}

dt := val

year = dt.Date.Year
yearDay = civil.Date(dt.Date).DaysSince(civil.Date{Year: dt.Date.Year, Month: 1, Day: 1}) + 1
hour = dt.Time.Hour
minute = dt.Time.Minute
second = dt.Time.Second
nanosecond = dt.Time.Nanosecond
case NullDateTime:
if col.ti.Size == 4 {
err = fmt.Errorf("mssql: invalid type for datetime column: %T %v", val, val)
return
}

if val.Valid {
dt := val.DateTime

year = dt.Date.Year
yearDay = civil.Date(dt.Date).DaysSince(civil.Date{Year: dt.Date.Year, Month: 1, Day: 1}) + 1
hour = dt.Time.Hour
minute = dt.Time.Minute
second = dt.Time.Second
nanosecond = dt.Time.Nanosecond
} else {
res.ti.Size = 0
return
}
default:
err = fmt.Errorf("mssql: invalid type for datetime column: %T %s", val, val)
err = fmt.Errorf("mssql: invalid type for datetime column: %T %v", val, val)
return
}

if col.ti.Size == 4 {
res.buffer = encodeDateTim4(t, loc)
res.ti.Size = len(res.buffer)
} else if col.ti.Size == 8 {
res.buffer = encodeDateTime(t)
res.buffer = encodeDateTime(
year,
yearDay,
hour,
minute,
second,
nanosecond)
res.ti.Size = len(res.buffer)
} else {
err = fmt.Errorf("mssql: invalid size of column %d", col.ti.Size)
Expand All @@ -562,8 +682,20 @@ func (b *Bulk) makeParam(val DataValue, col columnStruct) (res param, err error)
}
res.buffer = encodeTime(t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), int(col.ti.Scale))
res.ti.Size = len(res.buffer)
case Time:
tt := val
res.buffer = encodeTime(tt.Hour, tt.Minute, tt.Second, tt.Nanosecond, int(col.ti.Scale))
res.ti.Size = len(res.buffer)
case NullTime:
if val.Valid {
tm := val.Time
res.buffer = encodeTime(tm.Hour, tm.Minute, tm.Second, tm.Nanosecond, int(col.ti.Scale))
res.ti.Size = len(res.buffer)
} else {
res.ti.Size = 0
}
default:
err = fmt.Errorf("mssql: invalid type for time column: %T %s", val, val)
err = fmt.Errorf("mssql: invalid type for time column: %T %v", val, val)
return
}
case typeMoney, typeMoney4, typeMoneyN:
Expand Down
Loading