mssql_go19.go 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. // +build go1.9
  2. package mssql
  3. import (
  4. "database/sql"
  5. "database/sql/driver"
  6. "errors"
  7. "fmt"
  8. "reflect"
  9. "time"
  10. // "github.com/cockroachdb/apd"
  11. "cloud.google.com/go/civil"
  12. )
  13. // Type alias provided for compatibility.
  14. type MssqlDriver = Driver // Deprecated: users should transition to the new name when possible.
  15. type MssqlBulk = Bulk // Deprecated: users should transition to the new name when possible.
  16. type MssqlBulkOptions = BulkOptions // Deprecated: users should transition to the new name when possible.
  17. type MssqlConn = Conn // Deprecated: users should transition to the new name when possible.
  18. type MssqlResult = Result // Deprecated: users should transition to the new name when possible.
  19. type MssqlRows = Rows // Deprecated: users should transition to the new name when possible.
  20. type MssqlStmt = Stmt // Deprecated: users should transition to the new name when possible.
  21. var _ driver.NamedValueChecker = &Conn{}
  22. // VarChar parameter types.
  23. type VarChar string
  24. type NVarCharMax string
  25. type VarCharMax string
  26. // DateTime1 encodes parameters to original DateTime SQL types.
  27. type DateTime1 time.Time
  28. // DateTimeOffset encodes parameters to DateTimeOffset, preserving the UTC offset.
  29. type DateTimeOffset time.Time
  30. func convertInputParameter(val interface{}) (interface{}, error) {
  31. switch v := val.(type) {
  32. case VarChar:
  33. return val, nil
  34. case NVarCharMax:
  35. return val, nil
  36. case VarCharMax:
  37. return val, nil
  38. case DateTime1:
  39. return val, nil
  40. case DateTimeOffset:
  41. return val, nil
  42. case civil.Date:
  43. return val, nil
  44. case civil.DateTime:
  45. return val, nil
  46. case civil.Time:
  47. return val, nil
  48. // case *apd.Decimal:
  49. // return nil
  50. default:
  51. return driver.DefaultParameterConverter.ConvertValue(v)
  52. }
  53. }
  54. func (c *Conn) CheckNamedValue(nv *driver.NamedValue) error {
  55. switch v := nv.Value.(type) {
  56. case sql.Out:
  57. if c.outs == nil {
  58. c.outs = make(map[string]interface{})
  59. }
  60. c.outs[nv.Name] = v.Dest
  61. if v.Dest == nil {
  62. return errors.New("destination is a nil pointer")
  63. }
  64. dest_info := reflect.ValueOf(v.Dest)
  65. if dest_info.Kind() != reflect.Ptr {
  66. return errors.New("destination not a pointer")
  67. }
  68. if dest_info.IsNil() {
  69. return errors.New("destination is a nil pointer")
  70. }
  71. pointed_value := reflect.Indirect(dest_info)
  72. // don't allow pointer to a pointer, only pointer to a value can be handled
  73. // correctly
  74. if pointed_value.Kind() == reflect.Ptr {
  75. return errors.New("destination is a pointer to a pointer")
  76. }
  77. // Unwrap the Out value and check the inner value.
  78. val := pointed_value.Interface()
  79. if val == nil {
  80. return errors.New("MSSQL does not allow NULL value without type for OUTPUT parameters")
  81. }
  82. conv, err := convertInputParameter(val)
  83. if err != nil {
  84. return err
  85. }
  86. if conv == nil {
  87. // if we replace with nil we would lose type information
  88. nv.Value = sql.Out{Dest: val}
  89. } else {
  90. nv.Value = sql.Out{Dest: conv}
  91. }
  92. return nil
  93. default:
  94. var err error
  95. nv.Value, err = convertInputParameter(nv.Value)
  96. return err
  97. }
  98. }
  99. func (s *Stmt) makeParamExtra(val driver.Value) (res param, err error) {
  100. switch val := val.(type) {
  101. case VarChar:
  102. res.ti.TypeId = typeBigVarChar
  103. res.buffer = []byte(val)
  104. res.ti.Size = len(res.buffer)
  105. case VarCharMax:
  106. res.ti.TypeId = typeBigVarChar
  107. res.buffer = []byte(val)
  108. res.ti.Size = 0 // currently zero forces varchar(max)
  109. case NVarCharMax:
  110. res.ti.TypeId = typeNVarChar
  111. res.buffer = str2ucs2(string(val))
  112. res.ti.Size = 0 // currently zero forces nvarchar(max)
  113. case DateTime1:
  114. t := time.Time(val)
  115. res.ti.TypeId = typeDateTimeN
  116. res.buffer = encodeDateTime(t)
  117. res.ti.Size = len(res.buffer)
  118. case DateTimeOffset:
  119. res.ti.TypeId = typeDateTimeOffsetN
  120. res.ti.Scale = 7
  121. res.buffer = encodeDateTimeOffset(time.Time(val), int(res.ti.Scale))
  122. res.ti.Size = len(res.buffer)
  123. case civil.Date:
  124. res.ti.TypeId = typeDateN
  125. res.buffer = encodeDate(val.In(time.UTC))
  126. res.ti.Size = len(res.buffer)
  127. case civil.DateTime:
  128. res.ti.TypeId = typeDateTime2N
  129. res.ti.Scale = 7
  130. res.buffer = encodeDateTime2(val.In(time.UTC), int(res.ti.Scale))
  131. res.ti.Size = len(res.buffer)
  132. case civil.Time:
  133. res.ti.TypeId = typeTimeN
  134. res.ti.Scale = 7
  135. res.buffer = encodeTime(val.Hour, val.Minute, val.Second, val.Nanosecond, int(res.ti.Scale))
  136. res.ti.Size = len(res.buffer)
  137. case sql.Out:
  138. res, err = s.makeParam(val.Dest)
  139. res.Flags = fByRevValue
  140. default:
  141. err = fmt.Errorf("mssql: unknown type for %T", val)
  142. }
  143. return
  144. }
  145. func scanIntoOut(name string, fromServer, scanInto interface{}) error {
  146. return convertAssign(scanInto, fromServer)
  147. }