github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/copy_in_test.go (about) 1 // Copyright 2016 The Cockroach Authors. 2 // 3 // Use of this software is governed by the Business Source License 4 // included in the file licenses/BSL.txt. 5 // 6 // As of the Change Date specified in that file, in accordance with 7 // the Business Source License, use of this software will be governed 8 // by the Apache License, Version 2.0, included in the file 9 // licenses/APL.txt. 10 11 package sql_test 12 13 import ( 14 "context" 15 "fmt" 16 "math" 17 "math/rand" 18 "reflect" 19 "strconv" 20 "strings" 21 "testing" 22 "time" 23 24 "github.com/cockroachdb/cockroach/pkg/sql/sem/tree" 25 "github.com/cockroachdb/cockroach/pkg/sql/sqlbase" 26 "github.com/cockroachdb/cockroach/pkg/sql/tests" 27 "github.com/cockroachdb/cockroach/pkg/sql/types" 28 "github.com/cockroachdb/cockroach/pkg/testutils" 29 "github.com/cockroachdb/cockroach/pkg/testutils/serverutils" 30 "github.com/cockroachdb/cockroach/pkg/testutils/sqlutils" 31 "github.com/cockroachdb/cockroach/pkg/util/leaktest" 32 "github.com/cockroachdb/cockroach/pkg/util/timeofday" 33 "github.com/cockroachdb/cockroach/pkg/util/timetz" 34 "github.com/lib/pq" 35 ) 36 37 func TestCopyNullInfNaN(t *testing.T) { 38 defer leaktest.AfterTest(t)() 39 40 params, _ := tests.CreateTestServerParams() 41 s, db, _ := serverutils.StartServer(t, params) 42 defer s.Stopper().Stop(context.Background()) 43 44 if _, err := db.Exec(` 45 CREATE DATABASE d; 46 SET DATABASE = d; 47 CREATE TABLE t ( 48 i INT NULL, 49 f FLOAT NULL, 50 s STRING NULL, 51 b BYTES NULL, 52 d DATE NULL, 53 t TIME NULL, 54 ttz TIME NULL, 55 ts TIMESTAMP NULL, 56 n INTERVAL NULL, 57 o BOOL NULL, 58 e DECIMAL NULL, 59 u UUID NULL, 60 ip INET NULL, 61 tz TIMESTAMPTZ NULL, 62 geography GEOGRAPHY NULL, 63 geometry GEOMETRY NULL 64 ); 65 `); err != nil { 66 t.Fatal(err) 67 } 68 69 txn, err := db.Begin() 70 if err != nil { 71 t.Fatal(err) 72 } 73 74 stmt, err := txn.Prepare(pq.CopyIn( 75 "t", "i", "f", "s", "b", "d", "t", "ttz", 76 "ts", "n", "o", "e", "u", "ip", "tz", "geography", "geometry")) 77 if err != nil { 78 t.Fatal(err) 79 } 80 81 input := [][]interface{}{ 82 {nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}, 83 {nil, math.Inf(1), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}, 84 {nil, math.Inf(-1), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}, 85 {nil, math.NaN(), nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil}, 86 } 87 88 for _, in := range input { 89 _, err = stmt.Exec(in...) 90 if err != nil { 91 t.Fatal(err) 92 } 93 } 94 _, err = stmt.Exec() 95 if err != nil { 96 t.Fatal(err) 97 } 98 err = stmt.Close() 99 if err != nil { 100 t.Fatal(err) 101 } 102 err = txn.Commit() 103 if err != nil { 104 t.Fatal(err) 105 } 106 107 rows, err := db.Query("SELECT * FROM t") 108 if err != nil { 109 t.Fatal(err) 110 } 111 defer rows.Close() 112 113 for row, in := range input { 114 if !rows.Next() { 115 t.Fatal("expected more results") 116 } 117 data := make([]interface{}, len(in)) 118 for i := range data { 119 data[i] = new(interface{}) 120 } 121 if err := rows.Scan(data...); err != nil { 122 t.Fatal(err) 123 } 124 for i, d := range data { 125 v := d.(*interface{}) 126 d = *v 127 if a, b := fmt.Sprintf("%#v", d), fmt.Sprintf("%#v", in[i]); a != b { 128 t.Fatalf("row %v, col %v: got %#v (%T), expected %#v (%T)", row, i, d, d, in[i], in[i]) 129 } 130 } 131 } 132 } 133 134 // TestCopyRandom inserts random rows using COPY and ensures the SELECT'd 135 // data is the same. 136 func TestCopyRandom(t *testing.T) { 137 defer leaktest.AfterTest(t)() 138 139 params, _ := tests.CreateTestServerParams() 140 s, db, _ := serverutils.StartServer(t, params) 141 defer s.Stopper().Stop(context.Background()) 142 143 if _, err := db.Exec(` 144 CREATE DATABASE d; 145 CREATE TABLE IF NOT EXISTS d.t ( 146 id INT PRIMARY KEY, 147 n INTERVAL, 148 o BOOL, 149 i INT, 150 f FLOAT, 151 e DECIMAL, 152 t TIME, 153 ttz TIMETZ, 154 ts TIMESTAMP, 155 s STRING, 156 b BYTES, 157 u UUID, 158 ip INET, 159 tz TIMESTAMPTZ, 160 geography GEOGRAPHY NULL, 161 geometry GEOMETRY NULL 162 ); 163 SET extra_float_digits = 3; -- to preserve floats entirely 164 `); err != nil { 165 t.Fatal(err) 166 } 167 168 txn, err := db.Begin() 169 if err != nil { 170 t.Fatal(err) 171 } 172 173 stmt, err := txn.Prepare(pq.CopyInSchema("d", "t", "id", "n", "o", "i", "f", "e", "t", "ttz", "ts", "s", "b", "u", "ip", "tz", "geography", "geometry")) 174 if err != nil { 175 t.Fatal(err) 176 } 177 178 rng := rand.New(rand.NewSource(0)) 179 typs := []*types.T{ 180 types.Int, 181 types.Interval, 182 types.Bool, 183 types.Int, 184 types.Float, 185 types.Decimal, 186 types.Time, 187 types.TimeTZ, 188 types.Timestamp, 189 types.String, 190 types.Bytes, 191 types.Uuid, 192 types.INet, 193 types.TimestampTZ, 194 types.Geography, 195 types.Geometry, 196 } 197 198 var inputs [][]interface{} 199 200 for i := 0; i < 1000; i++ { 201 row := make([]interface{}, len(typs)) 202 for j, t := range typs { 203 var ds string 204 if j == 0 { 205 // Special handling for ID field 206 ds = strconv.Itoa(i) 207 } else { 208 d := sqlbase.RandDatum(rng, t, false) 209 ds = tree.AsStringWithFlags(d, tree.FmtBareStrings) 210 switch t { 211 case types.Float: 212 ds = strings.TrimSuffix(ds, ".0") 213 } 214 } 215 row[j] = ds 216 } 217 _, err = stmt.Exec(row...) 218 if err != nil { 219 t.Fatal(err) 220 } 221 inputs = append(inputs, row) 222 } 223 224 err = stmt.Close() 225 if err != nil { 226 t.Fatal(err) 227 } 228 err = txn.Commit() 229 if err != nil { 230 t.Fatal(err) 231 } 232 233 rows, err := db.Query("SELECT * FROM d.t ORDER BY id") 234 if err != nil { 235 t.Fatal(err) 236 } 237 defer rows.Close() 238 239 for row, in := range inputs { 240 if !rows.Next() { 241 t.Fatal("expected more results") 242 } 243 data := make([]interface{}, len(in)) 244 for i := range data { 245 data[i] = new(interface{}) 246 } 247 if err := rows.Scan(data...); err != nil { 248 t.Fatal(err) 249 } 250 for i, d := range data { 251 v := d.(*interface{}) 252 d := *v 253 ds := fmt.Sprint(d) 254 switch d := d.(type) { 255 case []byte: 256 ds = string(d) 257 case time.Time: 258 var dt tree.NodeFormatter 259 if typs[i].Family() == types.TimeFamily { 260 dt = tree.MakeDTime(timeofday.FromTimeAllow2400(d)) 261 } else if typs[i].Family() == types.TimeTZFamily { 262 dt = tree.NewDTimeTZ(timetz.MakeTimeTZFromTimeAllow2400(d)) 263 } else { 264 dt = tree.MustMakeDTimestamp(d, time.Microsecond) 265 } 266 ds = tree.AsStringWithFlags(dt, tree.FmtBareStrings) 267 } 268 if !reflect.DeepEqual(in[i], ds) { 269 t.Fatalf("row %v, col %v: got %#v (%T), expected %#v", row, i, ds, d, in[i]) 270 } 271 } 272 } 273 } 274 275 func TestCopyError(t *testing.T) { 276 defer leaktest.AfterTest(t)() 277 278 params, _ := tests.CreateTestServerParams() 279 s, db, _ := serverutils.StartServer(t, params) 280 defer s.Stopper().Stop(context.Background()) 281 282 if _, err := db.Exec(` 283 CREATE DATABASE d; 284 SET DATABASE = d; 285 CREATE TABLE t ( 286 i INT PRIMARY KEY 287 ); 288 `); err != nil { 289 t.Fatal(err) 290 } 291 292 txn, err := db.Begin() 293 if err != nil { 294 t.Fatal(err) 295 } 296 297 stmt, err := txn.Prepare(pq.CopyIn("t", "i")) 298 if err != nil { 299 t.Fatal(err) 300 } 301 302 // Insert conflicting primary keys. 303 for i := 0; i < 2; i++ { 304 _, err = stmt.Exec(1) 305 if err != nil { 306 t.Fatal(err) 307 } 308 } 309 310 err = stmt.Close() 311 if err == nil { 312 t.Fatal("expected error") 313 } 314 315 // Make sure we can query after an error. 316 var i int 317 if err := db.QueryRow("SELECT 1").Scan(&i); err != nil { 318 t.Fatal(err) 319 } else if i != 1 { 320 t.Fatalf("expected 1, got %d", i) 321 } 322 if err := txn.Rollback(); err != nil { 323 t.Fatal(err) 324 } 325 } 326 327 // TestCopyOne verifies that only one COPY can run at once. 328 func TestCopyOne(t *testing.T) { 329 defer leaktest.AfterTest(t)() 330 331 t.Skip("#18352") 332 333 params, _ := tests.CreateTestServerParams() 334 s, db, _ := serverutils.StartServer(t, params) 335 defer s.Stopper().Stop(context.Background()) 336 337 if _, err := db.Exec(` 338 CREATE DATABASE d; 339 SET DATABASE = d; 340 CREATE TABLE t ( 341 i INT PRIMARY KEY 342 ); 343 `); err != nil { 344 t.Fatal(err) 345 } 346 347 txn, err := db.Begin() 348 if err != nil { 349 t.Fatal(err) 350 } 351 352 if _, err := txn.Prepare(pq.CopyIn("t", "i")); err != nil { 353 t.Fatal(err) 354 } 355 if _, err := txn.Prepare(pq.CopyIn("t", "i")); err == nil { 356 t.Fatal("expected error") 357 } 358 } 359 360 // TestCopyInProgress verifies that after a COPY has started another statement 361 // cannot run. 362 func TestCopyInProgress(t *testing.T) { 363 defer leaktest.AfterTest(t)() 364 365 t.Skip("#18352") 366 367 params, _ := tests.CreateTestServerParams() 368 s, db, _ := serverutils.StartServer(t, params) 369 defer s.Stopper().Stop(context.Background()) 370 371 if _, err := db.Exec(` 372 CREATE DATABASE d; 373 SET DATABASE = d; 374 CREATE TABLE t ( 375 i INT PRIMARY KEY 376 ); 377 `); err != nil { 378 t.Fatal(err) 379 } 380 381 txn, err := db.Begin() 382 if err != nil { 383 t.Fatal(err) 384 } 385 386 if _, err := txn.Prepare(pq.CopyIn("t", "i")); err != nil { 387 t.Fatal(err) 388 } 389 390 if _, err := txn.Query("SELECT 1"); err == nil { 391 t.Fatal("expected error") 392 } 393 } 394 395 // TestCopyTransaction verifies that COPY data can be used after it is done 396 // within a transaction. 397 func TestCopyTransaction(t *testing.T) { 398 defer leaktest.AfterTest(t)() 399 400 params, _ := tests.CreateTestServerParams() 401 s, db, _ := serverutils.StartServer(t, params) 402 defer s.Stopper().Stop(context.Background()) 403 404 if _, err := db.Exec(` 405 CREATE DATABASE d; 406 SET DATABASE = d; 407 CREATE TABLE t ( 408 i INT PRIMARY KEY 409 ); 410 `); err != nil { 411 t.Fatal(err) 412 } 413 414 txn, err := db.Begin() 415 if err != nil { 416 t.Fatal(err) 417 } 418 419 // Note that, at least with lib/pq, this doesn't actually send a Parse msg 420 // (which we wouldn't support, as we don't support Copy-in in extended 421 // protocol mode). lib/pq has magic for recognizing a Copy. 422 stmt, err := txn.Prepare(pq.CopyIn("t", "i")) 423 if err != nil { 424 t.Fatal(err) 425 } 426 427 const val = 2 428 429 _, err = stmt.Exec(val) 430 if err != nil { 431 t.Fatal(err) 432 } 433 434 if err = stmt.Close(); err != nil { 435 t.Fatal(err) 436 } 437 438 var i int 439 if err := txn.QueryRow("SELECT i FROM d.t").Scan(&i); err != nil { 440 t.Fatal(err) 441 } else if i != val { 442 t.Fatalf("expected 1, got %d", i) 443 } 444 if err := txn.Commit(); err != nil { 445 t.Fatal(err) 446 } 447 } 448 449 // TestCopyFKCheck verifies that foreign keys are checked during COPY. 450 func TestCopyFKCheck(t *testing.T) { 451 defer leaktest.AfterTest(t)() 452 453 params, _ := tests.CreateTestServerParams() 454 s, db, _ := serverutils.StartServer(t, params) 455 defer s.Stopper().Stop(context.Background()) 456 457 db.SetMaxOpenConns(1) 458 r := sqlutils.MakeSQLRunner(db) 459 r.Exec(t, ` 460 CREATE DATABASE d; 461 SET DATABASE = d; 462 CREATE TABLE p (p INT PRIMARY KEY); 463 CREATE TABLE t ( 464 a INT PRIMARY KEY, 465 p INT REFERENCES p(p) 466 ); 467 SET optimizer_foreign_keys = true; 468 `) 469 470 txn, err := db.Begin() 471 if err != nil { 472 t.Fatal(err) 473 } 474 defer func() { _ = txn.Rollback() }() 475 476 stmt, err := txn.Prepare(pq.CopyIn("t", "a", "p")) 477 if err != nil { 478 t.Fatal(err) 479 } 480 481 _, err = stmt.Exec(1, 1) 482 if err != nil { 483 t.Fatal(err) 484 } 485 486 err = stmt.Close() 487 if !testutils.IsError(err, "foreign key violation|violates foreign key constraint") { 488 t.Fatalf("expected FK error, got: %v", err) 489 } 490 }