column.go 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. package column
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strings"
  6. "time"
  7. "github.com/ClickHouse/clickhouse-go/lib/binary"
  8. )
  9. type Column interface {
  10. Name() string
  11. CHType() string
  12. ScanType() reflect.Type
  13. Read(*binary.Decoder, bool) (interface{}, error)
  14. Write(*binary.Encoder, interface{}) error
  15. defaultValue() interface{}
  16. Depth() int
  17. }
  18. func Factory(name, chType string, timezone *time.Location) (Column, error) {
  19. switch chType {
  20. case "Int8":
  21. return &Int8{
  22. base: base{
  23. name: name,
  24. chType: chType,
  25. valueOf: columnBaseTypes[int8(0)],
  26. },
  27. }, nil
  28. case "Int16":
  29. return &Int16{
  30. base: base{
  31. name: name,
  32. chType: chType,
  33. valueOf: columnBaseTypes[int16(0)],
  34. },
  35. }, nil
  36. case "Int32":
  37. return &Int32{
  38. base: base{
  39. name: name,
  40. chType: chType,
  41. valueOf: columnBaseTypes[int32(0)],
  42. },
  43. }, nil
  44. case "Int64":
  45. return &Int64{
  46. base: base{
  47. name: name,
  48. chType: chType,
  49. valueOf: columnBaseTypes[int64(0)],
  50. },
  51. }, nil
  52. case "UInt8":
  53. return &UInt8{
  54. base: base{
  55. name: name,
  56. chType: chType,
  57. valueOf: columnBaseTypes[uint8(0)],
  58. },
  59. }, nil
  60. case "UInt16":
  61. return &UInt16{
  62. base: base{
  63. name: name,
  64. chType: chType,
  65. valueOf: columnBaseTypes[uint16(0)],
  66. },
  67. }, nil
  68. case "UInt32":
  69. return &UInt32{
  70. base: base{
  71. name: name,
  72. chType: chType,
  73. valueOf: columnBaseTypes[uint32(0)],
  74. },
  75. }, nil
  76. case "UInt64":
  77. return &UInt64{
  78. base: base{
  79. name: name,
  80. chType: chType,
  81. valueOf: columnBaseTypes[uint64(0)],
  82. },
  83. }, nil
  84. case "Float32":
  85. return &Float32{
  86. base: base{
  87. name: name,
  88. chType: chType,
  89. valueOf: columnBaseTypes[float32(0)],
  90. },
  91. }, nil
  92. case "Float64":
  93. return &Float64{
  94. base: base{
  95. name: name,
  96. chType: chType,
  97. valueOf: columnBaseTypes[float64(0)],
  98. },
  99. }, nil
  100. case "String":
  101. return &String{
  102. base: base{
  103. name: name,
  104. chType: chType,
  105. valueOf: columnBaseTypes[string("")],
  106. },
  107. }, nil
  108. case "UUID":
  109. return &UUID{
  110. base: base{
  111. name: name,
  112. chType: chType,
  113. valueOf: columnBaseTypes[string("")],
  114. },
  115. }, nil
  116. case "Date":
  117. _, offset := time.Unix(0, 0).In(timezone).Zone()
  118. return &Date{
  119. base: base{
  120. name: name,
  121. chType: chType,
  122. valueOf: columnBaseTypes[time.Time{}],
  123. },
  124. Timezone: timezone,
  125. offset: int64(offset),
  126. }, nil
  127. case "IPv4":
  128. return &IPv4{
  129. base: base{
  130. name: name,
  131. chType: chType,
  132. valueOf: columnBaseTypes[IPv4{}],
  133. },
  134. }, nil
  135. case "IPv6":
  136. return &IPv6{
  137. base: base{
  138. name: name,
  139. chType: chType,
  140. valueOf: columnBaseTypes[IPv6{}],
  141. },
  142. }, nil
  143. }
  144. switch {
  145. case strings.HasPrefix(chType, "DateTime") && !strings.HasPrefix(chType, "DateTime64"):
  146. return &DateTime{
  147. base: base{
  148. name: name,
  149. chType: "DateTime",
  150. valueOf: columnBaseTypes[time.Time{}],
  151. },
  152. Timezone: timezone,
  153. }, nil
  154. case strings.HasPrefix(chType, "DateTime64"):
  155. return &DateTime64{
  156. base: base{
  157. name: name,
  158. chType: chType,
  159. valueOf: columnBaseTypes[time.Time{}],
  160. },
  161. Timezone: timezone,
  162. }, nil
  163. case strings.HasPrefix(chType, "Array"):
  164. return parseArray(name, chType, timezone)
  165. case strings.HasPrefix(chType, "Nullable"):
  166. return parseNullable(name, chType, timezone)
  167. case strings.HasPrefix(chType, "FixedString"):
  168. return parseFixedString(name, chType)
  169. case strings.HasPrefix(chType, "Enum8"), strings.HasPrefix(chType, "Enum16"):
  170. return parseEnum(name, chType)
  171. case strings.HasPrefix(chType, "Decimal"):
  172. return parseDecimal(name, chType)
  173. case strings.HasPrefix(chType, "SimpleAggregateFunction"):
  174. if nestedType, err := getNestedType(chType, "SimpleAggregateFunction"); err != nil {
  175. return nil, err
  176. } else {
  177. return Factory(name, nestedType, timezone)
  178. }
  179. case strings.HasPrefix(chType, "Tuple"):
  180. return parseTuple(name, chType, timezone)
  181. }
  182. return nil, fmt.Errorf("column: unhandled type %v", chType)
  183. }
  184. func getNestedType(chType string, wrapType string) (string, error) {
  185. prefixLen := len(wrapType) + 1
  186. suffixLen := 1
  187. if len(chType) > prefixLen+suffixLen {
  188. nested := strings.Split(chType[prefixLen:len(chType)-suffixLen], ",")
  189. if len(nested) == 2 {
  190. return strings.TrimSpace(nested[1]), nil
  191. }
  192. if len(nested) == 3 {
  193. return strings.TrimSpace(strings.Join(nested[1:], ",")), nil
  194. }
  195. }
  196. return "", fmt.Errorf("column: invalid %s type (%s)", wrapType, chType)
  197. }