1
1
package clickhouse_test
2
2
3
3
import (
4
+ "context"
4
5
"database/sql"
5
6
"flag"
6
7
"fmt"
8
+ "github.com/xo/dburl"
9
+ "github.com/xo/usql/drivers"
7
10
"log"
8
11
"os"
9
12
"path/filepath"
10
13
"testing"
14
+ "time"
11
15
12
16
dt "github.com/ory/dockertest/v3"
13
17
"github.com/xo/usql/drivers/clickhouse"
14
18
"github.com/xo/usql/drivers/metadata"
15
19
"github.com/yookoala/realpath"
20
+
21
+ _ "github.com/xo/usql/drivers/csvq"
22
+ _ "github.com/xo/usql/drivers/moderncsqlite"
16
23
)
17
24
18
25
// db is the database connection.
@@ -59,7 +66,7 @@ func doMain(m *testing.M, cleanup bool) (int, error) {
59
66
if cleanup {
60
67
defer func () {
61
68
if err := pool .Purge (db .res ); err != nil {
62
- fmt .Fprintf (os .Stderr , "error: could not purge resoure : %v\n " , err )
69
+ fmt .Fprintf (os .Stderr , "error: could not purge resource : %v\n " , err )
63
70
}
64
71
}()
65
72
}
@@ -85,7 +92,7 @@ func TestSchemas(t *testing.T) {
85
92
if err != nil {
86
93
t .Fatalf ("could not read schemas: %v" , err )
87
94
}
88
- checkNames (t , "schema" , res , "default" , "system" , "tutorial" , "tutorial_unexpected" , "INFORMATION_SCHEMA" , "information_schema" )
95
+ checkNames (t , "schema" , res , "default" , "system" , "tutorial" , "tutorial_unexpected" , "INFORMATION_SCHEMA" , "information_schema" , "copy_test" )
89
96
}
90
97
91
98
func TestTables (t * testing.T ) {
@@ -119,6 +126,75 @@ func TestColumns(t *testing.T) {
119
126
checkNames (t , "column" , res , colNames ()... )
120
127
}
121
128
129
+ func TestCopy (t * testing.T ) {
130
+ // Tests with csvq source DB. That driver doesn't support ScanType()
131
+ for _ , destTableSpec := range []string {
132
+ "copy_test.dest" ,
133
+ "copy_test.dest(StringCol, NumCol)" ,
134
+ "insert into copy_test.dest values(?, ?)" ,
135
+ } {
136
+ t .Run ("csvq_" + destTableSpec , func (t * testing.T ) {
137
+ testCopy (t , destTableSpec , "csvq:." )
138
+ })
139
+ }
140
+ // Test with a driver that supports ScanType()
141
+ t .Run ("sqlite" , func (t * testing.T ) {
142
+ testCopy (t , "copy_test.dest" , "moderncsqlite://:memory:" )
143
+ })
144
+ }
145
+
146
+ func testCopy (t * testing.T , destTableSpec string , sourceDbUrlStr string ) {
147
+ ctx , cancel := context .WithTimeout (context .Background (), 30 * time .Second )
148
+ defer cancel ()
149
+ _ , err := db .db .ExecContext (ctx , "truncate table copy_test.dest" )
150
+ if err != nil {
151
+ t .Fatalf ("could not truncate copy_test table: %v" , err )
152
+ }
153
+ // Prepare copy destination URL
154
+ port := db .res .GetPort ("9000/tcp" )
155
+ dbUrlStr := fmt .Sprintf ("clickhouse://127.0.0.1:%s" , port )
156
+ dbUrl , err := dburl .Parse (dbUrlStr )
157
+ if err != nil {
158
+ t .Fatalf ("could not parse clickhouse url %s: %v" , dbUrlStr , err )
159
+ }
160
+ // Prepare source data
161
+ sourceDbUrl , err := dburl .Parse (sourceDbUrlStr )
162
+ if err != nil {
163
+ t .Fatalf ("could not parse source DB url %s: %v" , sourceDbUrlStr , err )
164
+ }
165
+ sourceDb , err := drivers .Open (ctx , sourceDbUrl , nil , nil )
166
+ if err != nil {
167
+ t .Fatalf ("could not open sourceDb: %v" , err )
168
+ }
169
+ defer sourceDb .Close ()
170
+ rows , err := sourceDb .QueryContext (ctx , "select 'string', 1" )
171
+ if err != nil {
172
+ t .Fatalf ("could not retrieve source rows: %v" , err )
173
+ }
174
+ // Do Copy, ignoring copied rows count because clickhouse driver doesn't report RowsAffected
175
+ _ , err = drivers .Copy (ctx , dbUrl , nil , nil , rows , destTableSpec )
176
+ if err != nil {
177
+ t .Fatalf ("copy failed: %v" , err )
178
+ }
179
+ rows , err = db .db .QueryContext (ctx , "select StringCol, NumCol from copy_test.dest" )
180
+ if err != nil {
181
+ t .Fatalf ("failed to query: %v" , err )
182
+ }
183
+ defer rows .Close ()
184
+ var copiedString string
185
+ var copiedNum int
186
+ if ! rows .Next () {
187
+ t .Fatalf ("nothing copied" )
188
+ }
189
+ err = rows .Scan (& copiedString , & copiedNum )
190
+ if err != nil {
191
+ t .Fatalf ("could not read copied data: %v" , err )
192
+ }
193
+ if copiedString != "string" || copiedNum != 1 {
194
+ t .Fatalf ("copied data differs: %s != string, %d != 1" , copiedString , copiedNum )
195
+ }
196
+ }
197
+
122
198
func checkNames (t * testing.T , typ string , res interface { Next () bool }, exp ... string ) {
123
199
n := make (map [string ]bool )
124
200
for _ , s := range exp {
0 commit comments