1// Copyright (c) 2017-2021 Snowflake Computing Inc. All right reserved.
2
3package gosnowflake
4
5import (
6	"bytes"
7	"database/sql"
8	"database/sql/driver"
9	"fmt"
10)
11
12type snowflakeType int
13
14const (
15	fixedType snowflakeType = iota
16	realType
17	textType
18	dateType
19	variantType
20	timestampLtzType
21	timestampNtzType
22	timestampTzType
23	objectType
24	arrayType
25	binaryType
26	timeType
27	booleanType
28	// the following are not snowflake types per se but internal types
29	nullType
30	sliceType
31	changeType
32	unSupportedType
33)
34
35var snowflakeTypes = [...]string{"FIXED", "REAL", "TEXT", "DATE", "VARIANT",
36	"TIMESTAMP_LTZ", "TIMESTAMP_NTZ", "TIMESTAMP_TZ", "OBJECT", "ARRAY",
37	"BINARY", "TIME", "BOOLEAN", "NULL", "SLICE", "CHANGE_TYPE", "NOT_SUPPORTED"}
38
39func (st snowflakeType) String() string {
40	return snowflakeTypes[st]
41}
42
43func (st snowflakeType) Byte() byte {
44	return byte(st)
45}
46
47func getSnowflakeType(typ string) snowflakeType {
48	for i, sft := range snowflakeTypes {
49		if sft == typ {
50			return snowflakeType(i)
51		} else if snowflakeType(i) == nullType {
52			break
53		}
54	}
55	return nullType
56}
57
58var (
59	// DataTypeFixed is a FIXED datatype.
60	DataTypeFixed = []byte{fixedType.Byte()}
61	// DataTypeReal is a REAL datatype.
62	DataTypeReal = []byte{realType.Byte()}
63	// DataTypeText is a TEXT datatype.
64	DataTypeText = []byte{textType.Byte()}
65	// DataTypeDate is a Date datatype.
66	DataTypeDate = []byte{dateType.Byte()}
67	// DataTypeVariant is a TEXT datatype.
68	DataTypeVariant = []byte{variantType.Byte()}
69	// DataTypeTimestampLtz is a TIMESTAMP_LTZ datatype.
70	DataTypeTimestampLtz = []byte{timestampLtzType.Byte()}
71	// DataTypeTimestampNtz is a TIMESTAMP_NTZ datatype.
72	DataTypeTimestampNtz = []byte{timestampNtzType.Byte()}
73	// DataTypeTimestampTz is a TIMESTAMP_TZ datatype.
74	DataTypeTimestampTz = []byte{timestampTzType.Byte()}
75	// DataTypeObject is a OBJECT datatype.
76	DataTypeObject = []byte{objectType.Byte()}
77	// DataTypeArray is a ARRAY datatype.
78	DataTypeArray = []byte{arrayType.Byte()}
79	// DataTypeBinary is a BINARY datatype.
80	DataTypeBinary = []byte{binaryType.Byte()}
81	// DataTypeTime is a TIME datatype.
82	DataTypeTime = []byte{timeType.Byte()}
83	// DataTypeBoolean is a BOOLEAN datatype.
84	DataTypeBoolean = []byte{booleanType.Byte()}
85)
86
87// dataTypeMode returns the subsequent data type in a string representation.
88func dataTypeMode(v driver.Value) (tsmode snowflakeType, err error) {
89	if bd, ok := v.([]byte); ok {
90		switch {
91		case bytes.Equal(bd, DataTypeDate):
92			tsmode = dateType
93		case bytes.Equal(bd, DataTypeTime):
94			tsmode = timeType
95		case bytes.Equal(bd, DataTypeTimestampLtz):
96			tsmode = timestampLtzType
97		case bytes.Equal(bd, DataTypeTimestampNtz):
98			tsmode = timestampNtzType
99		case bytes.Equal(bd, DataTypeTimestampTz):
100			tsmode = timestampTzType
101		case bytes.Equal(bd, DataTypeBinary):
102			tsmode = binaryType
103		default:
104			return nullType, fmt.Errorf(errMsgInvalidByteArray, v)
105		}
106	} else {
107		return nullType, fmt.Errorf(errMsgInvalidByteArray, v)
108	}
109	return tsmode, nil
110}
111
112// SnowflakeParameter includes the columns output from SHOW PARAMETER command.
113type SnowflakeParameter struct {
114	Key                       string
115	Value                     string
116	Default                   string
117	Level                     string
118	Description               string
119	SetByUser                 string
120	SetInJob                  string
121	SetOn                     string
122	SetByThreadID             string
123	SetByThreadName           string
124	SetByClass                string
125	ParameterComment          string
126	Type                      string
127	IsExpired                 string
128	ExpiresAt                 string
129	SetByControllingParameter string
130	ActivateVersion           string
131	PartialRollout            string
132	Unknown                   string // Reserve for added parameter
133}
134
135func populateSnowflakeParameter(colname string, p *SnowflakeParameter) interface{} {
136	switch colname {
137	case "key":
138		return &p.Key
139	case "value":
140		return &p.Value
141	case "default":
142		return &p.Default
143	case "level":
144		return &p.Level
145	case "description":
146		return &p.Description
147	case "set_by_user":
148		return &p.SetByUser
149	case "set_in_job":
150		return &p.SetInJob
151	case "set_on":
152		return &p.SetOn
153	case "set_by_thread_id":
154		return &p.SetByThreadID
155	case "set_by_thread_name":
156		return &p.SetByThreadName
157	case "set_by_class":
158		return &p.SetByClass
159	case "parameter_comment":
160		return &p.ParameterComment
161	case "type":
162		return &p.Type
163	case "is_expired":
164		return &p.IsExpired
165	case "expires_at":
166		return &p.ExpiresAt
167	case "set_by_controlling_parameter":
168		return &p.SetByControllingParameter
169	case "activate_version":
170		return &p.ActivateVersion
171	case "partial_rollout":
172		return &p.PartialRollout
173	default:
174		debugPanicf("unknown type: %v", colname)
175		return &p.Unknown
176	}
177}
178
179// ScanSnowflakeParameter binds SnowflakeParameter variable with an array of column buffer.
180func ScanSnowflakeParameter(rows *sql.Rows) (*SnowflakeParameter, error) {
181	var err error
182	var columns []string
183	columns, err = rows.Columns()
184	if err != nil {
185		return nil, err
186	}
187	colNum := len(columns)
188	p := SnowflakeParameter{}
189	cols := make([]interface{}, colNum)
190	for i := 0; i < colNum; i++ {
191		cols[i] = populateSnowflakeParameter(columns[i], &p)
192	}
193	err = rows.Scan(cols...)
194	return &p, err
195}
196