1/*
2Copyright 2014 SAP SE
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17package driver
18
19import (
20	"database/sql/driver"
21	"errors"
22	"fmt"
23	"math"
24	"reflect"
25	"time"
26
27	p "github.com/SAP/go-hdb/internal/protocol"
28)
29
30const (
31	minTinyint  = 0
32	maxTinyint  = math.MaxUint8
33	minSmallint = math.MinInt16
34	maxSmallint = math.MaxInt16
35	minInteger  = math.MinInt32
36	maxInteger  = math.MaxInt32
37	minBigint   = math.MinInt64
38	maxBigint   = math.MaxInt64
39	maxReal     = math.MaxFloat32
40	maxDouble   = math.MaxFloat64
41)
42
43// ErrIntegerOutOfRange means that an integer exceeds the size of the hdb integer field.
44var ErrIntegerOutOfRange = errors.New("integer out of range error")
45
46// ErrFloatOutOfRange means that a float exceeds the size of the hdb float field.
47var ErrFloatOutOfRange = errors.New("float out of range error")
48
49var typeOfTime = reflect.TypeOf((*time.Time)(nil)).Elem()
50var typeOfBytes = reflect.TypeOf((*[]byte)(nil)).Elem()
51
52func checkNamedValue(prmFieldSet *p.ParameterFieldSet, nv *driver.NamedValue) error {
53	idx := nv.Ordinal - 1
54
55	if idx >= prmFieldSet.NumInputField() {
56		return nil
57	}
58
59	f := prmFieldSet.Field(idx)
60	dt := f.TypeCode().DataType()
61
62	value, err := convertNamedValue(idx, f, dt, nv.Value)
63
64	if err != nil {
65		return err
66	}
67
68	nv.Value = value
69	return nil
70}
71
72func convertNamedValue(idx int, f *p.ParameterField, dt p.DataType, v driver.Value) (driver.Value, error) {
73	var err error
74
75	// let fields with own Value converter convert themselves first (e.g. NullInt64, ...)
76	if _, ok := v.(driver.Valuer); ok {
77		if v, err = driver.DefaultParameterConverter.ConvertValue(v); err != nil {
78			return nil, err
79		}
80	}
81
82	switch dt {
83
84	default:
85		return nil, fmt.Errorf("convert named value datatype error: %[1]d - %[1]s", dt)
86
87	case p.DtTinyint:
88		return convertNvInteger(v, minTinyint, maxTinyint)
89
90	case p.DtSmallint:
91		return convertNvInteger(v, minSmallint, maxSmallint)
92
93	case p.DtInteger:
94		return convertNvInteger(v, minInteger, maxInteger)
95
96	case p.DtBigint:
97		return convertNvInteger(v, minBigint, maxBigint)
98
99	case p.DtReal:
100		return convertNvFloat(v, maxReal)
101
102	case p.DtDouble:
103		return convertNvFloat(v, maxDouble)
104
105	case p.DtTime:
106		return convertNvTime(v)
107
108	case p.DtDecimal:
109		return convertNvDecimal(v)
110
111	case p.DtString:
112		return convertNvString(v)
113
114	case p.DtBytes:
115		return convertNvBytes(v)
116
117	case p.DtLob:
118		return convertNvLob(idx, f, v)
119
120	}
121}
122
123// integer types
124func convertNvInteger(v interface{}, min, max int64) (driver.Value, error) {
125
126	if v == nil {
127		return v, nil
128	}
129
130	rv := reflect.ValueOf(v)
131	switch rv.Kind() {
132
133	// bool is represented in HDB as tinyint
134	case reflect.Bool:
135		return rv.Bool(), nil
136	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
137		i64 := rv.Int()
138		if i64 > max || i64 < min {
139			return nil, ErrIntegerOutOfRange
140		}
141		return i64, nil
142	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
143		u64 := rv.Uint()
144		if u64 > uint64(max) {
145			return nil, ErrIntegerOutOfRange
146		}
147		return int64(u64), nil
148	case reflect.Ptr:
149		// indirect pointers
150		if rv.IsNil() {
151			return nil, nil
152		}
153		return convertNvInteger(rv.Elem().Interface(), min, max)
154	}
155
156	return nil, fmt.Errorf("unsupported integer conversion type error %[1]T %[1]v", v)
157}
158
159// float types
160func convertNvFloat(v interface{}, max float64) (driver.Value, error) {
161
162	if v == nil {
163		return v, nil
164	}
165
166	rv := reflect.ValueOf(v)
167	switch rv.Kind() {
168
169	case reflect.Float32, reflect.Float64:
170		f64 := rv.Float()
171		if math.Abs(f64) > max {
172			return nil, ErrFloatOutOfRange
173		}
174		return f64, nil
175	case reflect.Ptr:
176		// indirect pointers
177		if rv.IsNil() {
178			return nil, nil
179		}
180		return convertNvFloat(rv.Elem().Interface(), max)
181	}
182
183	return nil, fmt.Errorf("unsupported float conversion type error %[1]T %[1]v", v)
184}
185
186// time
187func convertNvTime(v interface{}) (driver.Value, error) {
188
189	if v == nil {
190		return nil, nil
191	}
192
193	switch v := v.(type) {
194
195	case time.Time:
196		return v, nil
197	}
198
199	rv := reflect.ValueOf(v)
200
201	switch rv.Kind() {
202
203	case reflect.Ptr:
204		// indirect pointers
205		if rv.IsNil() {
206			return nil, nil
207		}
208		return convertNvTime(rv.Elem().Interface())
209	}
210
211	if rv.Type().ConvertibleTo(typeOfTime) {
212		tv := rv.Convert(typeOfTime)
213		return tv.Interface().(time.Time), nil
214	}
215
216	return nil, fmt.Errorf("unsupported time conversion type error %[1]T %[1]v", v)
217}
218
219// decimal
220func convertNvDecimal(v interface{}) (driver.Value, error) {
221
222	if v == nil {
223		return nil, nil
224	}
225
226	if v, ok := v.([]byte); ok {
227		return v, nil
228	}
229
230	return nil, fmt.Errorf("unsupported decimal conversion type error %[1]T %[1]v", v)
231}
232
233// string
234func convertNvString(v interface{}) (driver.Value, error) {
235
236	if v == nil {
237		return v, nil
238	}
239
240	switch v := v.(type) {
241
242	case string, []byte:
243		return v, nil
244	}
245
246	rv := reflect.ValueOf(v)
247
248	switch rv.Kind() {
249
250	case reflect.String:
251		return rv.String(), nil
252
253	case reflect.Slice:
254		if rv.Type() == typeOfBytes {
255			return rv.Bytes(), nil
256		}
257
258	case reflect.Ptr:
259		// indirect pointers
260		if rv.IsNil() {
261			return nil, nil
262		}
263		return convertNvString(rv.Elem().Interface())
264	}
265
266	if rv.Type().ConvertibleTo(typeOfBytes) {
267		bv := rv.Convert(typeOfBytes)
268		return bv.Interface().([]byte), nil
269	}
270
271	return nil, fmt.Errorf("unsupported character conversion type error %[1]T %[1]v", v)
272}
273
274// bytes
275func convertNvBytes(v interface{}) (driver.Value, error) {
276
277	if v == nil {
278		return v, nil
279	}
280
281	if v, ok := v.([]byte); ok {
282		return v, nil
283	}
284
285	rv := reflect.ValueOf(v)
286
287	switch rv.Kind() {
288
289	case reflect.Slice:
290		if rv.Type() == typeOfBytes {
291			return rv.Bytes(), nil
292		}
293
294	case reflect.Ptr:
295		// indirect pointers
296		if rv.IsNil() {
297			return nil, nil
298		}
299		return convertNvBytes(rv.Elem().Interface())
300	}
301
302	if rv.Type().ConvertibleTo(typeOfBytes) {
303		bv := rv.Convert(typeOfBytes)
304		return bv.Interface().([]byte), nil
305	}
306
307	return nil, fmt.Errorf("unsupported bytes conversion type error %[1]T %[1]v", v)
308}
309
310// Lob
311func convertNvLob(idx int, f *p.ParameterField, v interface{}) (driver.Value, error) {
312
313	if v == nil {
314		return v, nil
315	}
316
317	switch v := v.(type) {
318	case Lob:
319		if v.rd == nil {
320			return nil, fmt.Errorf("lob error: initial reader %[1]T %[1]v", v)
321		}
322		f.SetLobReader(v.rd)
323		return fmt.Sprintf("<lob %d", idx), nil
324	case *Lob:
325		if v.rd == nil {
326			return nil, fmt.Errorf("lob error: initial reader %[1]T %[1]v", v)
327		}
328		f.SetLobReader(v.rd)
329		return fmt.Sprintf("<lob %d", idx), nil
330	case NullLob:
331		if !v.Valid {
332			return nil, nil
333		}
334		if v.Lob.rd == nil {
335			return nil, fmt.Errorf("lob error: initial reader %[1]T %[1]v", v)
336		}
337		f.SetLobReader(v.Lob.rd)
338		return fmt.Sprintf("<lob %d", idx), nil
339	case *NullLob:
340		if !v.Valid {
341			return nil, nil
342		}
343		if v.Lob.rd == nil {
344			return nil, fmt.Errorf("lob error: initial reader %[1]T %[1]v", v)
345		}
346		f.SetLobReader(v.Lob.rd)
347		return fmt.Sprintf("<lob %d", idx), nil
348	}
349
350	rv := reflect.ValueOf(v)
351
352	switch rv.Kind() {
353
354	case reflect.Ptr:
355		// indirect pointers
356		if rv.IsNil() {
357			return nil, nil
358		}
359		return convertNvLob(idx, f, rv.Elem().Interface())
360	}
361
362	return nil, fmt.Errorf("unsupported lob conversion type error %[1]T %[1]v", v)
363}
364