Skip to content
This repository was archived by the owner on Feb 26, 2024. It is now read-only.

Commit 30fd751

Browse files
authored
Merge pull request ClickHouse#253 from sobolevsv/master
implement RowsColumnTypeNullable and RowsColumnTypePrecisionScale
2 parents d8e3533 + 5aeecc7 commit 30fd751

File tree

5 files changed

+186
-0
lines changed

5 files changed

+186
-0
lines changed

clickhouse_decimal_test.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
package clickhouse_test
2+
3+
import (
4+
"database/sql"
5+
"github.com/stretchr/testify/assert"
6+
"testing"
7+
)
8+
9+
func Test_Decimal(t *testing.T) {
10+
const (
11+
ddl = `
12+
CREATE TABLE clickhouse_test_nullable (
13+
decimal Decimal(18,5),
14+
decimalNullable Nullable(Decimal(15,3))
15+
) Engine=Memory;
16+
`
17+
dml = `
18+
INSERT INTO clickhouse_test_nullable (
19+
decimal,
20+
decimalNullable
21+
) VALUES (
22+
?,
23+
?
24+
)
25+
`
26+
query = `
27+
SELECT
28+
decimal,
29+
decimalNullable
30+
FROM clickhouse_test_nullable
31+
`
32+
)
33+
if connect, err := sql.Open("clickhouse", "tcp://127.0.0.1:9000?debug=true"); assert.NoError(t, err) {
34+
if tx, err := connect.Begin(); assert.NoError(t, err) {
35+
if _, err := connect.Exec("DROP TABLE IF EXISTS clickhouse_test_nullable"); assert.NoError(t, err) {
36+
if _, err := tx.Exec(ddl); assert.NoError(t, err) {
37+
if tx, err := connect.Begin(); assert.NoError(t, err) {
38+
if stmt, err := tx.Prepare(dml); assert.NoError(t, err) {
39+
for i := 0; i < 10; i++ {
40+
if _, err := stmt.Exec(
41+
16.55,
42+
nil,
43+
); !assert.NoError(t, err) {
44+
t.Fatal(err)
45+
}
46+
}
47+
}
48+
if err := tx.Commit(); !assert.NoError(t, err) {
49+
t.Fatal(err)
50+
}
51+
}
52+
if rows, err := connect.Query(query); assert.NoError(t, err) {
53+
columnTypes, err := rows.ColumnTypes()
54+
assert.NoError(t, err)
55+
for i, column := range columnTypes {
56+
switch i {
57+
case 0:
58+
nullable, nullableOk := column.Nullable()
59+
assert.False(t, nullable)
60+
assert.True(t, nullableOk)
61+
62+
precision, scale, ok := column.DecimalSize()
63+
assert.Equal(t, int64(5), scale)
64+
assert.Equal(t, int64(18), precision)
65+
assert.True(t, ok)
66+
case 1:
67+
nullable, nullableOk := column.Nullable()
68+
assert.True(t, nullable)
69+
assert.True(t, nullableOk)
70+
71+
precision, scale, ok := column.DecimalSize()
72+
assert.Equal(t, int64(3), scale)
73+
assert.Equal(t, int64(15), precision)
74+
assert.True(t, ok)
75+
}
76+
}
77+
for rows.Next() {
78+
var (
79+
decimal = new(int)
80+
decimalNullable = new(int)
81+
)
82+
if err := rows.Scan(
83+
&decimal,
84+
&decimalNullable,
85+
); assert.NoError(t, err) {
86+
if assert.NotNil(t, decimal) {
87+
assert.Equal(t, int(1655000), *decimal)
88+
}
89+
assert.Nil(t, decimalNullable)
90+
}
91+
}
92+
}
93+
}
94+
}
95+
}
96+
}
97+
}

lib/column/column_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -567,3 +567,61 @@ func Test_Column_SimpleAggregateFunc(t *testing.T) {
567567
}
568568
}
569569
}
570+
571+
func Test_Column_Decimal64(t *testing.T) {
572+
var (
573+
buf bytes.Buffer
574+
encoder = binary.NewEncoder(&buf)
575+
decoder = binary.NewDecoder(&buf)
576+
)
577+
if columnBase, err := columns.Factory("column_name", "Decimal(18,5)", time.Local); assert.NoError(t, err) {
578+
579+
decimalCol, ok := columnBase.(*columns.Decimal)
580+
if assert.True(t, ok) {
581+
assert.Equal(t, 18, decimalCol.GetPrecision())
582+
assert.Equal(t, 5, decimalCol.GetScale())
583+
}
584+
585+
if err := columnBase.Write(encoder, float64(1123.12345)); assert.NoError(t, err) {
586+
if v, err := columnBase.Read(decoder); assert.NoError(t, err) {
587+
assert.Equal(t, int64(112312345), v)
588+
}
589+
}
590+
if assert.Equal(t, "column_name", columnBase.Name()) && assert.Equal(t, "Decimal(18,5)", columnBase.CHType()) {
591+
assert.Equal(t, reflect.Int64, columnBase.ScanType().Kind())
592+
}
593+
}
594+
}
595+
596+
func Test_Column_NullableDecimal64(t *testing.T) {
597+
var (
598+
buf bytes.Buffer
599+
encoder = binary.NewEncoder(&buf)
600+
decoder = binary.NewDecoder(&buf)
601+
)
602+
if columnBase, err := columns.Factory("column_name", "Nullable(Decimal(18,5))", time.Local); assert.NoError(t, err) {
603+
604+
nullableCol, ok := columnBase.(*columns.Nullable)
605+
if assert.True(t, ok) {
606+
decimalCol := nullableCol.GetColumn().(*columns.Decimal)
607+
assert.Equal(t, 18, decimalCol.GetPrecision())
608+
assert.Equal(t, 5, decimalCol.GetScale())
609+
}
610+
611+
if err := nullableCol.WriteNull(encoder, encoder, float64(1123.12345)); assert.NoError(t, err) {
612+
if v, err := nullableCol.ReadNull(decoder, 1); assert.NoError(t, err) {
613+
assert.Equal(t, int64(112312345), v[0])
614+
}
615+
}
616+
617+
if err := nullableCol.WriteNull(encoder, encoder, nil); assert.NoError(t, err) {
618+
if v, err := nullableCol.ReadNull(decoder, 1); assert.NoError(t, err) {
619+
assert.Nil(t, v[0])
620+
}
621+
}
622+
623+
if assert.Equal(t, "column_name", columnBase.Name()) && assert.Equal(t, "Nullable(Decimal(18,5))", columnBase.CHType()) {
624+
assert.Equal(t, reflect.Int64, columnBase.ScanType().Kind())
625+
}
626+
}
627+
}

lib/column/decimal.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,3 +239,11 @@ func parseDecimal(name, chType string) (Column, error) {
239239

240240
return decimal, nil
241241
}
242+
243+
func (d *Decimal) GetPrecision() int {
244+
return d.precision
245+
}
246+
247+
func (d *Decimal) GetScale() int {
248+
return d.scale
249+
}

lib/column/nullable.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,3 +79,7 @@ func parseNullable(name, chType string, timezone *time.Location) (*Nullable, err
7979
column: column,
8080
}, nil
8181
}
82+
83+
func (null *Nullable) GetColumn() Column {
84+
return null.column
85+
}

rows.go

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,3 +161,22 @@ func (rows *rows) setError(err error) error {
161161
rows.mutex.Unlock()
162162
return err
163163
}
164+
165+
func (rows *rows) ColumnTypeNullable(idx int) (nullable, ok bool) {
166+
_, ok = rows.blockColumns[idx].(*column.Nullable)
167+
return ok, true
168+
}
169+
170+
func (rows *rows) ColumnTypePrecisionScale(idx int) (precision, scale int64, ok bool) {
171+
decimalVal, ok := rows.blockColumns[idx].(*column.Decimal)
172+
if !ok {
173+
if nullable, nullOk := rows.blockColumns[idx].(*column.Nullable); nullOk {
174+
decimalVal, ok = nullable.GetColumn().(*column.Decimal)
175+
}
176+
}
177+
if ok {
178+
return int64(decimalVal.GetPrecision()), int64(decimalVal.GetScale()), ok
179+
180+
}
181+
return 0, 0, false
182+
}

0 commit comments

Comments
 (0)