github.com/snowflakedb/gosnowflake@v1.9.0/bindings_test.go (about)

     1  // Copyright (c) 2021-2022 Snowflake Computing Inc. All rights reserved.
     2  
     3  package gosnowflake
     4  
     5  import (
     6  	"bytes"
     7  	"context"
     8  	"database/sql"
     9  	"fmt"
    10  	"log"
    11  	"math/big"
    12  	"math/rand"
    13  	"reflect"
    14  	"strconv"
    15  	"strings"
    16  	"testing"
    17  	"time"
    18  )
    19  
    20  const (
    21  	createTableSQL = `create or replace table test_prep_statement(c1 INTEGER,
    22  		c2 FLOAT, c3 BOOLEAN, c4 STRING, C5 BINARY, C6 TIMESTAMP_NTZ,
    23  		C7 TIMESTAMP_LTZ, C8 TIMESTAMP_TZ, C9 DATE, C10 TIME)`
    24  	deleteTableSQL = "drop table if exists TEST_PREP_STATEMENT"
    25  	insertSQL      = "insert into TEST_PREP_STATEMENT values(?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"
    26  	selectAllSQL   = "select * from TEST_PREP_STATEMENT ORDER BY 1"
    27  
    28  	createTableSQLBulkArray = `create or replace table test_bulk_array(c1 INTEGER,
    29  		c2 FLOAT, c3 BOOLEAN, c4 STRING, C5 BINARY, C6 INTEGER)`
    30  	deleteTableSQLBulkArray = "drop table if exists test_bulk_array"
    31  	insertSQLBulkArray      = "insert into test_bulk_array values(?, ?, ?, ?, ?, ?)"
    32  	selectAllSQLBulkArray   = "select * from test_bulk_array ORDER BY 1"
    33  
    34  	createTableSQLBulkArrayDateTimeTimestamp = `create or replace table test_bulk_array_DateTimeTimestamp(
    35  		C1 TIMESTAMP_NTZ, C2 TIMESTAMP_LTZ, C3 TIMESTAMP_TZ, C4 DATE, C5 TIME)`
    36  	deleteTableSQLBulkArrayDateTimeTimestamp = "drop table if exists test_bulk_array_DateTimeTimestamp"
    37  	insertSQLBulkArrayDateTimeTimestamp      = "insert into test_bulk_array_DateTimeTimestamp values(?, ?, ?, ?, ?)"
    38  	selectAllSQLBulkArrayDateTimeTimestamp   = "select * from test_bulk_array_DateTimeTimestamp ORDER BY 1"
    39  
    40  	enableFeatureMaxLOBSize = "ALTER SESSION SET FEATURE_INCREASED_MAX_LOB_SIZE_IN_MEMORY='ENABLED'"
    41  	unsetFeatureMaxLOBSize  = "ALTER SESSION UNSET FEATURE_INCREASED_MAX_LOB_SIZE_IN_MEMORY"
    42  
    43  	// For max LOB size tests
    44  	// maxLOBSize = 128 * 1024 * 1024 // new max LOB size
    45  	maxLOBSize = 16 * 1024 * 1024 // current max LOB size
    46  	largeSize  = maxLOBSize / 2
    47  	mediumSize = largeSize / 2
    48  	originSize = 16 * 1024 * 1024
    49  	smallSize  = 16
    50  	// range to use for generating random numbers
    51  	lobRandomRange = 100000
    52  )
    53  
    54  func TestBindingFloat64(t *testing.T) {
    55  	runDBTest(t, func(dbt *DBTest) {
    56  		types := [2]string{"FLOAT", "DOUBLE"}
    57  		expected := 42.23
    58  		var out float64
    59  		var rows *RowsExtended
    60  		for _, v := range types {
    61  			t.Run(v, func(t *testing.T) {
    62  				dbt.mustExec(fmt.Sprintf("CREATE OR REPLACE TABLE test (id int, value %v)", v))
    63  				dbt.mustExec("INSERT INTO test VALUES (1, ?)", expected)
    64  				rows = dbt.mustQuery("SELECT value FROM test WHERE id = ?", 1)
    65  				defer rows.Close()
    66  				if rows.Next() {
    67  					rows.Scan(&out)
    68  					if expected != out {
    69  						dbt.Errorf("%s: %g != %g", v, expected, out)
    70  					}
    71  				} else {
    72  					dbt.Errorf("%s: no data", v)
    73  				}
    74  			})
    75  		}
    76  		dbt.mustExec("DROP TABLE IF EXISTS test")
    77  	})
    78  }
    79  
    80  // TestBindingUint64 tests uint64 binding. Should fail as unit64 is not a
    81  // supported binding value by Go's sql package.
    82  func TestBindingUint64(t *testing.T) {
    83  	runDBTest(t, func(dbt *DBTest) {
    84  		expected := uint64(18446744073709551615)
    85  		dbt.mustExec("CREATE OR REPLACE TABLE test (id int, value INTEGER)")
    86  		if _, err := dbt.exec("INSERT INTO test VALUES (1, ?)", expected); err == nil {
    87  			dbt.Fatal("should fail as uint64 values with high bit set are not supported.")
    88  		} else {
    89  			logger.Infof("expected err: %v", err)
    90  		}
    91  		dbt.mustExec("DROP TABLE IF EXISTS test")
    92  	})
    93  }
    94  
    95  func TestBindingDateTimeTimestamp(t *testing.T) {
    96  	createDSN(PSTLocation)
    97  	runDBTest(t, func(dbt *DBTest) {
    98  		expected := time.Now()
    99  		dbt.mustExec(
   100  			"CREATE OR REPLACE TABLE tztest (id int, ntz timestamp_ntz, ltz timestamp_ltz, dt date, tm time)")
   101  		stmt, err := dbt.prepare("INSERT INTO tztest(id,ntz,ltz,dt,tm) VALUES(1,?,?,?,?)")
   102  		if err != nil {
   103  			dbt.Fatal(err.Error())
   104  		}
   105  		defer stmt.Close()
   106  		if _, err = stmt.Exec(
   107  			DataTypeTimestampNtz, expected,
   108  			DataTypeTimestampLtz, expected,
   109  			DataTypeDate, expected,
   110  			DataTypeTime, expected); err != nil {
   111  			dbt.Fatal(err)
   112  		}
   113  		rows := dbt.mustQuery("SELECT ntz,ltz,dt,tm FROM tztest WHERE id=?", 1)
   114  		defer rows.Close()
   115  		var ntz, vltz, dt, tm time.Time
   116  		columnTypes, err := rows.ColumnTypes()
   117  		if err != nil {
   118  			dbt.Errorf("column type error. err: %v", err)
   119  		}
   120  		if columnTypes[0].Name() != "NTZ" {
   121  			dbt.Errorf("expected column name: %v, got: %v", "TEST", columnTypes[0])
   122  		}
   123  		canNull := dbt.mustNullable(columnTypes[0])
   124  		if !canNull {
   125  			dbt.Errorf("expected nullable: %v, got: %v", true, canNull)
   126  		}
   127  		if columnTypes[0].DatabaseTypeName() != "TIMESTAMP_NTZ" {
   128  			dbt.Errorf("expected database type: %v, got: %v", "TIMESTAMP_NTZ", columnTypes[0].DatabaseTypeName())
   129  		}
   130  		dbt.mustFailDecimalSize(columnTypes[0])
   131  		dbt.mustFailLength(columnTypes[0])
   132  		cols, err := rows.Columns()
   133  		if err != nil {
   134  			dbt.Errorf("failed to get columns. err: %v", err)
   135  		}
   136  		if len(cols) != 4 || cols[0] != "NTZ" || cols[1] != "LTZ" || cols[2] != "DT" || cols[3] != "TM" {
   137  			dbt.Errorf("failed to get columns. got: %v", cols)
   138  		}
   139  		if rows.Next() {
   140  			rows.Scan(&ntz, &vltz, &dt, &tm)
   141  			if expected.UnixNano() != ntz.UnixNano() {
   142  				dbt.Errorf("returned TIMESTAMP_NTZ value didn't match. expected: %v:%v, got: %v:%v",
   143  					expected.UnixNano(), expected, ntz.UnixNano(), ntz)
   144  			}
   145  			if expected.UnixNano() != vltz.UnixNano() {
   146  				dbt.Errorf("returned TIMESTAMP_LTZ value didn't match. expected: %v:%v, got: %v:%v",
   147  					expected.UnixNano(), expected, vltz.UnixNano(), vltz)
   148  			}
   149  			if expected.Year() != dt.Year() || expected.Month() != dt.Month() || expected.Day() != dt.Day() {
   150  				dbt.Errorf("returned DATE value didn't match. expected: %v:%v, got: %v:%v",
   151  					expected.Unix()*1000, expected, dt.Unix()*1000, dt)
   152  			}
   153  			if expected.Hour() != tm.Hour() || expected.Minute() != tm.Minute() || expected.Second() != tm.Second() || expected.Nanosecond() != tm.Nanosecond() {
   154  				dbt.Errorf("returned TIME value didn't match. expected: %v:%v, got: %v:%v",
   155  					expected.UnixNano(), expected, tm.UnixNano(), tm)
   156  			}
   157  		} else {
   158  			dbt.Error("no data")
   159  		}
   160  		dbt.mustExec("DROP TABLE tztest")
   161  	})
   162  
   163  	createDSN("UTC")
   164  }
   165  
   166  func TestBindingBinary(t *testing.T) {
   167  	runDBTest(t, func(dbt *DBTest) {
   168  		dbt.mustExec("CREATE OR REPLACE TABLE bintest (id int, b binary)")
   169  		var b = []byte{0x01, 0x02, 0x03}
   170  		dbt.mustExec("INSERT INTO bintest(id,b) VALUES(1, ?)", DataTypeBinary, b)
   171  		rows := dbt.mustQuery("SELECT b FROM bintest WHERE id=?", 1)
   172  		defer rows.Close()
   173  		if rows.Next() {
   174  			var rb []byte
   175  			if err := rows.Scan(&rb); err != nil {
   176  				dbt.Errorf("failed to scan data. err: %v", err)
   177  			}
   178  			if !bytes.Equal(b, rb) {
   179  				dbt.Errorf("failed to match data. expected: %v, got: %v", b, rb)
   180  			}
   181  		} else {
   182  			dbt.Errorf("no data")
   183  		}
   184  		dbt.mustExec("DROP TABLE bintest")
   185  	})
   186  }
   187  
   188  func TestBindingTimestampTZ(t *testing.T) {
   189  	runDBTest(t, func(dbt *DBTest) {
   190  		expected := time.Now()
   191  		dbt.mustExec("CREATE OR REPLACE TABLE tztest (id int, tz timestamp_tz)")
   192  		stmt, err := dbt.prepare("INSERT INTO tztest(id,tz) VALUES(1, ?)")
   193  		if err != nil {
   194  			dbt.Fatal(err.Error())
   195  		}
   196  		defer stmt.Close()
   197  		if _, err = stmt.Exec(DataTypeTimestampTz, expected); err != nil {
   198  			dbt.Fatal(err)
   199  		}
   200  		rows := dbt.mustQuery("SELECT tz FROM tztest WHERE id=?", 1)
   201  		defer rows.Close()
   202  		var v time.Time
   203  		if rows.Next() {
   204  			rows.Scan(&v)
   205  			if expected.UnixNano() != v.UnixNano() {
   206  				dbt.Errorf("returned value didn't match. expected: %v:%v, got: %v:%v",
   207  					expected.UnixNano(), expected, v.UnixNano(), v)
   208  			}
   209  		} else {
   210  			dbt.Error("no data")
   211  		}
   212  		dbt.mustExec("DROP TABLE tztest")
   213  	})
   214  }
   215  
   216  // SNOW-755844: Test the use of a pointer *time.Time type in user-defined structures to perform updates/inserts
   217  func TestBindingTimePtrInStruct(t *testing.T) {
   218  	runDBTest(t, func(dbt *DBTest) {
   219  		type timePtrStruct struct {
   220  			id      *int
   221  			timeVal *time.Time
   222  		}
   223  		var expectedID int = 1
   224  		var expectedTime time.Time = time.Now()
   225  		var testStruct timePtrStruct = timePtrStruct{id: &expectedID, timeVal: &expectedTime}
   226  		dbt.mustExec("CREATE OR REPLACE TABLE timeStructTest (id int, tz timestamp_tz)")
   227  
   228  		runInsertQuery := false
   229  		for i := 0; i < 2; i++ {
   230  			if !runInsertQuery {
   231  				_, err := dbt.exec("INSERT INTO timeStructTest(id,tz) VALUES(?, ?)", testStruct.id, testStruct.timeVal)
   232  				if err != nil {
   233  					dbt.Fatal(err.Error())
   234  				}
   235  				runInsertQuery = true
   236  			} else {
   237  				// Update row with a new time value
   238  				expectedTime = time.Now().Add(1)
   239  				testStruct.timeVal = &expectedTime
   240  				_, err := dbt.exec("UPDATE timeStructTest SET tz = ? where id = ?", testStruct.timeVal, testStruct.id)
   241  				if err != nil {
   242  					dbt.Fatal(err.Error())
   243  				}
   244  			}
   245  
   246  			rows := dbt.mustQuery("SELECT tz FROM timeStructTest WHERE id=?", &expectedID)
   247  			defer rows.Close()
   248  			var v time.Time
   249  			if rows.Next() {
   250  				rows.Scan(&v)
   251  				if expectedTime.UnixNano() != v.UnixNano() {
   252  					dbt.Errorf("returned value didn't match. expected: %v:%v, got: %v:%v",
   253  						expectedTime.UnixNano(), expectedTime, v.UnixNano(), v)
   254  				}
   255  			} else {
   256  				dbt.Error("no data")
   257  			}
   258  		}
   259  		dbt.mustExec("DROP TABLE timeStructTest")
   260  	})
   261  }
   262  
   263  // SNOW-755844: Test the use of a time.Time type in user-defined structures to perform updates/inserts
   264  func TestBindingTimeInStruct(t *testing.T) {
   265  	runDBTest(t, func(dbt *DBTest) {
   266  		type timeStruct struct {
   267  			id      int
   268  			timeVal time.Time
   269  		}
   270  		var expectedID int = 1
   271  		var expectedTime time.Time = time.Now()
   272  		var testStruct timeStruct = timeStruct{id: expectedID, timeVal: expectedTime}
   273  		dbt.mustExec("CREATE OR REPLACE TABLE timeStructTest (id int, tz timestamp_tz)")
   274  
   275  		runInsertQuery := false
   276  		for i := 0; i < 2; i++ {
   277  			if !runInsertQuery {
   278  				_, err := dbt.exec("INSERT INTO timeStructTest(id,tz) VALUES(?, ?)", testStruct.id, testStruct.timeVal)
   279  				if err != nil {
   280  					dbt.Fatal(err.Error())
   281  				}
   282  				runInsertQuery = true
   283  			} else {
   284  				// Update row with a new time value
   285  				expectedTime = time.Now().Add(1)
   286  				testStruct.timeVal = expectedTime
   287  				_, err := dbt.exec("UPDATE timeStructTest SET tz = ? where id = ?", testStruct.timeVal, testStruct.id)
   288  				if err != nil {
   289  					dbt.Fatal(err.Error())
   290  				}
   291  			}
   292  
   293  			rows := dbt.mustQuery("SELECT tz FROM timeStructTest WHERE id=?", &expectedID)
   294  			defer rows.Close()
   295  			var v time.Time
   296  			if rows.Next() {
   297  				rows.Scan(&v)
   298  				if expectedTime.UnixNano() != v.UnixNano() {
   299  					dbt.Errorf("returned value didn't match. expected: %v:%v, got: %v:%v",
   300  						expectedTime.UnixNano(), expectedTime, v.UnixNano(), v)
   301  				}
   302  			} else {
   303  				dbt.Error("no data")
   304  			}
   305  		}
   306  		dbt.mustExec("DROP TABLE timeStructTest")
   307  	})
   308  }
   309  
   310  func TestBindingInterface(t *testing.T) {
   311  	runDBTest(t, func(dbt *DBTest) {
   312  		rows := dbt.mustQueryContext(
   313  			WithHigherPrecision(context.Background()), selectVariousTypes)
   314  		defer rows.Close()
   315  		if !rows.Next() {
   316  			dbt.Error("failed to query")
   317  		}
   318  		var v1, v2, v3, v4, v5, v6 any
   319  		if err := rows.Scan(&v1, &v2, &v3, &v4, &v5, &v6); err != nil {
   320  			dbt.Errorf("failed to scan: %#v", err)
   321  		}
   322  		if s1, ok := v1.(*big.Float); !ok || s1.Cmp(big.NewFloat(1.0)) != 0 {
   323  			dbt.Fatalf("failed to fetch. ok: %v, value: %v", ok, v1)
   324  		}
   325  		if s2, ok := v2.(int64); !ok || s2 != 2 {
   326  			dbt.Fatalf("failed to fetch. ok: %v, value: %v", ok, v2)
   327  		}
   328  		if s3, ok := v3.(string); !ok || s3 != "t3" {
   329  			dbt.Fatalf("failed to fetch. ok: %v, value: %v", ok, v3)
   330  		}
   331  		if s4, ok := v4.(float64); !ok || s4 != 4.2 {
   332  			dbt.Fatalf("failed to fetch. ok: %v, value: %v", ok, v4)
   333  		}
   334  	})
   335  }
   336  
   337  func TestBindingInterfaceString(t *testing.T) {
   338  	runDBTest(t, func(dbt *DBTest) {
   339  		rows := dbt.mustQuery(selectVariousTypes)
   340  		defer rows.Close()
   341  		if !rows.Next() {
   342  			dbt.Error("failed to query")
   343  		}
   344  		var v1, v2, v3, v4, v5, v6 any
   345  		if err := rows.Scan(&v1, &v2, &v3, &v4, &v5, &v6); err != nil {
   346  			dbt.Errorf("failed to scan: %#v", err)
   347  		}
   348  		if s, ok := v1.(string); !ok {
   349  			dbt.Error("failed to convert to string")
   350  		} else if d, err := strconv.ParseFloat(s, 64); err != nil {
   351  			dbt.Errorf("failed to convert to float. value: %v, err: %v", v1, err)
   352  		} else if d != 1.00 {
   353  			dbt.Errorf("failed to fetch. expected: 1.00, value: %v", v1)
   354  		}
   355  		if s, ok := v2.(string); !ok || s != "2" {
   356  			dbt.Fatalf("failed to fetch. ok: %v, value: %v", ok, v2)
   357  		}
   358  		if s, ok := v3.(string); !ok || s != "t3" {
   359  			dbt.Fatalf("failed to fetch. ok: %v, value: %v", ok, v3)
   360  		}
   361  	})
   362  }
   363  
   364  func TestBulkArrayBindingInterfaceNil(t *testing.T) {
   365  	nilArray := make([]any, 1)
   366  
   367  	runDBTest(t, func(dbt *DBTest) {
   368  		dbt.mustExec(createTableSQL)
   369  		defer dbt.mustExec(deleteTableSQL)
   370  
   371  		dbt.mustExec(insertSQL, Array(&nilArray), Array(&nilArray),
   372  			Array(&nilArray), Array(&nilArray), Array(&nilArray),
   373  			Array(&nilArray, TimestampNTZType), Array(&nilArray, TimestampTZType),
   374  			Array(&nilArray, TimestampTZType), Array(&nilArray, DateType),
   375  			Array(&nilArray, TimeType))
   376  		rows := dbt.mustQuery(selectAllSQL)
   377  		defer rows.Close()
   378  
   379  		var v0 sql.NullInt32
   380  		var v1 sql.NullFloat64
   381  		var v2 sql.NullBool
   382  		var v3 sql.NullString
   383  		var v4 []byte
   384  		var v5, v6, v7, v8, v9 sql.NullTime
   385  
   386  		cnt := 0
   387  		for i := 0; rows.Next(); i++ {
   388  			if err := rows.Scan(&v0, &v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8, &v9); err != nil {
   389  				t.Fatal(err)
   390  			}
   391  			if v0.Valid {
   392  				t.Fatalf("failed to fetch the sql.NullInt32 column v0. expected %v, got: %v", nilArray[i], v0)
   393  			}
   394  			if v1.Valid {
   395  				t.Fatalf("failed to fetch the sql.NullFloat64 column v1. expected %v, got: %v", nilArray[i], v1)
   396  			}
   397  			if v2.Valid {
   398  				t.Fatalf("failed to fetch the sql.NullBool column v2. expected %v, got: %v", nilArray[i], v2)
   399  			}
   400  			if v3.Valid {
   401  				t.Fatalf("failed to fetch the sql.NullString column v3. expected %v, got: %v", nilArray[i], v3)
   402  			}
   403  			if v4 != nil {
   404  				t.Fatalf("failed to fetch the []byte column v4. expected %v, got: %v", nilArray[i], v4)
   405  			}
   406  			if v5.Valid {
   407  				t.Fatalf("failed to fetch the sql.NullTime column v5. expected %v, got: %v", nilArray[i], v5)
   408  			}
   409  			if v6.Valid {
   410  				t.Fatalf("failed to fetch the sql.NullTime column v6. expected %v, got: %v", nilArray[i], v6)
   411  			}
   412  			if v7.Valid {
   413  				t.Fatalf("failed to fetch the sql.NullTime column v7. expected %v, got: %v", nilArray[i], v7)
   414  			}
   415  			if v8.Valid {
   416  				t.Fatalf("failed to fetch the sql.NullTime column v8. expected %v, got: %v", nilArray[i], v8)
   417  			}
   418  			if v9.Valid {
   419  				t.Fatalf("failed to fetch the sql.NullTime column v9. expected %v, got: %v", nilArray[i], v9)
   420  			}
   421  			cnt++
   422  		}
   423  		if cnt != len(nilArray) {
   424  			t.Fatal("failed to query")
   425  		}
   426  	})
   427  }
   428  
   429  func TestBulkArrayBindingInterface(t *testing.T) {
   430  	intArray := make([]any, 3)
   431  	intArray[0] = int32(100)
   432  	intArray[1] = int32(200)
   433  
   434  	fltArray := make([]any, 3)
   435  	fltArray[0] = float64(0.1)
   436  	fltArray[2] = float64(5.678)
   437  
   438  	boolArray := make([]any, 3)
   439  	boolArray[1] = false
   440  	boolArray[2] = true
   441  
   442  	strArray := make([]any, 3)
   443  	strArray[2] = "test3"
   444  
   445  	byteArray := make([]any, 3)
   446  	byteArray[0] = []byte{0x01, 0x02, 0x03}
   447  	byteArray[2] = []byte{0x07, 0x08, 0x09}
   448  
   449  	int64Array := make([]any, 3)
   450  	int64Array[0] = int64(100)
   451  	int64Array[1] = int64(200)
   452  
   453  	runDBTest(t, func(dbt *DBTest) {
   454  		dbt.mustExec(createTableSQLBulkArray)
   455  		defer dbt.mustExec(deleteTableSQLBulkArray)
   456  
   457  		dbt.mustExec(insertSQLBulkArray, Array(&intArray), Array(&fltArray),
   458  			Array(&boolArray), Array(&strArray), Array(&byteArray), Array(&int64Array))
   459  		rows := dbt.mustQuery(selectAllSQLBulkArray)
   460  		defer rows.Close()
   461  
   462  		var v0 sql.NullInt32
   463  		var v1 sql.NullFloat64
   464  		var v2 sql.NullBool
   465  		var v3 sql.NullString
   466  		var v4 []byte
   467  		var v5 sql.NullInt64
   468  
   469  		cnt := 0
   470  		for i := 0; rows.Next(); i++ {
   471  			if err := rows.Scan(&v0, &v1, &v2, &v3, &v4, &v5); err != nil {
   472  				t.Fatal(err)
   473  			}
   474  			if v0.Valid {
   475  				if v0.Int32 != intArray[i] {
   476  					t.Fatalf("failed to fetch the sql.NullInt32 column v0. expected %v, got: %v", intArray[i], v0.Int32)
   477  				}
   478  			} else if intArray[i] != nil {
   479  				t.Fatalf("failed to fetch the sql.NullInt32 column v0. expected %v, got: %v", intArray[i], v0)
   480  			}
   481  			if v1.Valid {
   482  				if v1.Float64 != fltArray[i] {
   483  					t.Fatalf("failed to fetch the sql.NullFloat64 column v1. expected %v, got: %v", fltArray[i], v1.Float64)
   484  				}
   485  			} else if fltArray[i] != nil {
   486  				t.Fatalf("failed to fetch the sql.NullFloat64 column v1. expected %v, got: %v", fltArray[i], v1)
   487  			}
   488  			if v2.Valid {
   489  				if v2.Bool != boolArray[i] {
   490  					t.Fatalf("failed to fetch the sql.NullBool column v2. expected %v, got: %v", boolArray[i], v2.Bool)
   491  				}
   492  			} else if boolArray[i] != nil {
   493  				t.Fatalf("failed to fetch the sql.NullBool column v2. expected %v, got: %v", boolArray[i], v2)
   494  			}
   495  			if v3.Valid {
   496  				if v3.String != strArray[i] {
   497  					t.Fatalf("failed to fetch the sql.NullString column v3. expected %v, got: %v", strArray[i], v3.String)
   498  				}
   499  			} else if strArray[i] != nil {
   500  				t.Fatalf("failed to fetch the sql.NullString column v3. expected %v, got: %v", strArray[i], v3)
   501  			}
   502  			if byteArray[i] != nil {
   503  				if !bytes.Equal(v4, byteArray[i].([]byte)) {
   504  					t.Fatalf("failed to fetch the []byte column v4. expected %v, got: %v", byteArray[i], v4)
   505  				}
   506  			} else if v4 != nil {
   507  				t.Fatalf("failed to fetch the []byte column v4. expected %v, got: %v", byteArray[i], v4)
   508  			}
   509  			if v5.Valid {
   510  				if v5.Int64 != int64Array[i] {
   511  					t.Fatalf("failed to fetch the sql.NullInt64 column v5. expected %v, got: %v", int64Array[i], v5.Int64)
   512  				}
   513  			} else if int64Array[i] != nil {
   514  				t.Fatalf("failed to fetch the sql.NullInt64 column v5. expected %v, got: %v", int64Array[i], v5)
   515  			}
   516  			cnt++
   517  		}
   518  		if cnt != len(intArray) {
   519  			t.Fatal("failed to query")
   520  		}
   521  	})
   522  }
   523  
   524  func TestBulkArrayBindingInterfaceDateTimeTimestamp(t *testing.T) {
   525  	tz := time.Now()
   526  	createDSN(PSTLocation)
   527  
   528  	now := time.Now()
   529  	loc, err := time.LoadLocation(PSTLocation)
   530  	if err != nil {
   531  		t.Error(err)
   532  	}
   533  	ntzArray := make([]any, 3)
   534  	ntzArray[0] = now
   535  	ntzArray[1] = now.Add(1)
   536  
   537  	ltzArray := make([]any, 3)
   538  	ltzArray[1] = now.Add(2).In(loc)
   539  	ltzArray[2] = now.Add(3).In(loc)
   540  
   541  	tzArray := make([]any, 3)
   542  	tzArray[0] = tz.Add(4).In(loc)
   543  	tzArray[2] = tz.Add(5).In(loc)
   544  
   545  	dtArray := make([]any, 3)
   546  	dtArray[0] = tz.Add(6).In(loc)
   547  	dtArray[1] = now.Add(7).In(loc)
   548  
   549  	tmArray := make([]any, 3)
   550  	tmArray[1] = now.Add(8).In(loc)
   551  	tmArray[2] = now.Add(9).In(loc)
   552  
   553  	runDBTest(t, func(dbt *DBTest) {
   554  		dbt.mustExec(createTableSQLBulkArrayDateTimeTimestamp)
   555  		defer dbt.mustExec(deleteTableSQLBulkArrayDateTimeTimestamp)
   556  
   557  		dbt.mustExec(insertSQLBulkArrayDateTimeTimestamp,
   558  			Array(&ntzArray, TimestampNTZType), Array(&ltzArray, TimestampLTZType),
   559  			Array(&tzArray, TimestampTZType), Array(&dtArray, DateType),
   560  			Array(&tmArray, TimeType))
   561  
   562  		rows := dbt.mustQuery(selectAllSQLBulkArrayDateTimeTimestamp)
   563  		defer rows.Close()
   564  
   565  		var v0, v1, v2, v3, v4 sql.NullTime
   566  
   567  		cnt := 0
   568  		for i := 0; rows.Next(); i++ {
   569  			if err := rows.Scan(&v0, &v1, &v2, &v3, &v4); err != nil {
   570  				t.Fatal(err)
   571  			}
   572  			if v0.Valid {
   573  				if v0.Time.UnixNano() != ntzArray[i].(time.Time).UnixNano() {
   574  					t.Fatalf("failed to fetch the column v0. expected %v, got: %v", ntzArray[i], v0)
   575  				}
   576  			} else if ntzArray[i] != nil {
   577  				t.Fatalf("failed to fetch the column v0. expected %v, got: %v", ntzArray[i], v0)
   578  			}
   579  			if v1.Valid {
   580  				if v1.Time.UnixNano() != ltzArray[i].(time.Time).UnixNano() {
   581  					t.Fatalf("failed to fetch the column v1. expected %v, got: %v", ltzArray[i], v1)
   582  				}
   583  			} else if ltzArray[i] != nil {
   584  				t.Fatalf("failed to fetch the column v1. expected %v, got: %v", ltzArray[i], v1)
   585  			}
   586  			if v2.Valid {
   587  				if v2.Time.UnixNano() != tzArray[i].(time.Time).UnixNano() {
   588  					t.Fatalf("failed to fetch the column v2. expected %v, got: %v", tzArray[i], v2)
   589  				}
   590  			} else if tzArray[i] != nil {
   591  				t.Fatalf("failed to fetch the column v2. expected %v, got: %v", tzArray[i], v2)
   592  			}
   593  			if v3.Valid {
   594  				if v3.Time.Year() != dtArray[i].(time.Time).Year() ||
   595  					v3.Time.Month() != dtArray[i].(time.Time).Month() ||
   596  					v3.Time.Day() != dtArray[i].(time.Time).Day() {
   597  					t.Fatalf("failed to fetch the column v3. expected %v, got: %v", dtArray[i], v3)
   598  				}
   599  			} else if dtArray[i] != nil {
   600  				t.Fatalf("failed to fetch the column v3. expected %v, got: %v", dtArray[i], v3)
   601  			}
   602  			if v4.Valid {
   603  				if v4.Time.Hour() != tmArray[i].(time.Time).Hour() ||
   604  					v4.Time.Minute() != tmArray[i].(time.Time).Minute() ||
   605  					v4.Time.Second() != tmArray[i].(time.Time).Second() {
   606  					t.Fatalf("failed to fetch the column v4. expected %v, got: %v", tmArray[i], v4)
   607  				}
   608  			} else if tmArray[i] != nil {
   609  				t.Fatalf("failed to fetch the column v4. expected %v, got: %v", tmArray[i], v4)
   610  			}
   611  			cnt++
   612  		}
   613  		if cnt != len(ntzArray) {
   614  			t.Fatal("failed to query")
   615  		}
   616  	})
   617  	createDSN("UTC")
   618  }
   619  
   620  // TestBindingArray tests basic array binding via the usage of the Array
   621  // function that converts the passed Golang slice to a Snowflake array type
   622  func TestBindingArray(t *testing.T) {
   623  	testBindingArray(t, false)
   624  }
   625  
   626  // TestBindingBulkArray tests bulk array binding via the usage of the Array
   627  // function that converts the passed Golang slice to a Snowflake array type
   628  func TestBindingBulkArray(t *testing.T) {
   629  	if runningOnGithubAction() {
   630  		t.Skip("client_stage_array_binding_threshold value is internal")
   631  	}
   632  	testBindingArray(t, true)
   633  }
   634  
   635  func testBindingArray(t *testing.T, bulk bool) {
   636  	tz := time.Now()
   637  	createDSN(PSTLocation)
   638  	intArray := []int{1, 2, 3}
   639  	fltArray := []float64{0.1, 2.34, 5.678}
   640  	boolArray := []bool{true, false, true}
   641  	strArray := []string{"test1", "test2", "test3"}
   642  	byteArray := [][]byte{{0x01, 0x02, 0x03}, {0x04, 0x05, 0x06}, {0x07, 0x08, 0x09}}
   643  
   644  	now := time.Now()
   645  	loc, err := time.LoadLocation(PSTLocation)
   646  	if err != nil {
   647  		t.Error(err)
   648  	}
   649  	ntzArray := []time.Time{now, now.Add(1), now.Add(2)}
   650  	ltzArray := []time.Time{now.Add(3).In(loc), now.Add(4).In(loc), now.Add(5).In(loc)}
   651  	tzArray := []time.Time{tz.Add(6).In(loc), tz.Add(7).In(loc), tz.Add(8).In(loc)}
   652  	dtArray := []time.Time{now.Add(9), now.Add(10), now.Add(11)}
   653  	tmArray := []time.Time{now.Add(12), now.Add(13), now.Add(14)}
   654  
   655  	runDBTest(t, func(dbt *DBTest) {
   656  		dbt.mustExec(createTableSQL)
   657  		defer dbt.mustExec(deleteTableSQL)
   658  		if bulk {
   659  			if _, err := dbt.exec("ALTER SESSION SET CLIENT_STAGE_ARRAY_BINDING_THRESHOLD = 1"); err != nil {
   660  				t.Error(err)
   661  			}
   662  		}
   663  
   664  		dbt.mustExec(insertSQL, Array(&intArray), Array(&fltArray),
   665  			Array(&boolArray), Array(&strArray), Array(&byteArray),
   666  			Array(&ntzArray, TimestampNTZType), Array(&ltzArray, TimestampLTZType),
   667  			Array(&tzArray, TimestampTZType), Array(&dtArray, DateType),
   668  			Array(&tmArray, TimeType))
   669  		rows := dbt.mustQuery(selectAllSQL)
   670  		defer rows.Close()
   671  
   672  		var v0 int
   673  		var v1 float64
   674  		var v2 bool
   675  		var v3 string
   676  		var v4 []byte
   677  		var v5, v6, v7, v8, v9 time.Time
   678  		cnt := 0
   679  		for i := 0; rows.Next(); i++ {
   680  			if err := rows.Scan(&v0, &v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8, &v9); err != nil {
   681  				t.Fatal(err)
   682  			}
   683  			if v0 != intArray[i] {
   684  				t.Fatalf("failed to fetch. expected %v, got: %v", intArray[i], v0)
   685  			}
   686  			if v1 != fltArray[i] {
   687  				t.Fatalf("failed to fetch. expected %v, got: %v", fltArray[i], v1)
   688  			}
   689  			if v2 != boolArray[i] {
   690  				t.Fatalf("failed to fetch. expected %v, got: %v", boolArray[i], v2)
   691  			}
   692  			if v3 != strArray[i] {
   693  				t.Fatalf("failed to fetch. expected %v, got: %v", strArray[i], v3)
   694  			}
   695  			if !bytes.Equal(v4, byteArray[i]) {
   696  				t.Fatalf("failed to fetch. expected %v, got: %v", byteArray[i], v4)
   697  			}
   698  			if v5.UnixNano() != ntzArray[i].UnixNano() {
   699  				t.Fatalf("failed to fetch. expected %v, got: %v", ntzArray[i], v5)
   700  			}
   701  			if v6.UnixNano() != ltzArray[i].UnixNano() {
   702  				t.Fatalf("failed to fetch. expected %v, got: %v", ltzArray[i], v6)
   703  			}
   704  			if v7.UnixNano() != tzArray[i].UnixNano() {
   705  				t.Fatalf("failed to fetch. expected %v, got: %v", tzArray[i], v7)
   706  			}
   707  			if v8.Year() != dtArray[i].Year() || v8.Month() != dtArray[i].Month() || v8.Day() != dtArray[i].Day() {
   708  				t.Fatalf("failed to fetch. expected %v, got: %v", dtArray[i], v8)
   709  			}
   710  			if v9.Hour() != tmArray[i].Hour() || v9.Minute() != tmArray[i].Minute() || v9.Second() != tmArray[i].Second() {
   711  				t.Fatalf("failed to fetch. expected %v, got: %v", tmArray[i], v9)
   712  			}
   713  			cnt++
   714  		}
   715  		if cnt != len(intArray) {
   716  			t.Fatal("failed to query")
   717  		}
   718  	})
   719  	createDSN("UTC")
   720  }
   721  
   722  func TestBulkArrayBinding(t *testing.T) {
   723  	runDBTest(t, func(dbt *DBTest) {
   724  		dbt.mustExec(fmt.Sprintf("create or replace table %v (c1 integer, c2 string, c3 timestamp_ltz, c4 timestamp_tz, c5 timestamp_ntz, c6 date, c7 time, c8 binary)", dbname))
   725  		now := time.Now()
   726  		someTime := time.Date(1, time.January, 1, 12, 34, 56, 123456789, time.UTC)
   727  		someDate := time.Date(2024, time.March, 18, 0, 0, 0, 0, time.UTC)
   728  		someBinary := []byte{0x01, 0x02, 0x03}
   729  		numRows := 100000
   730  		intArr := make([]int, numRows)
   731  		strArr := make([]string, numRows)
   732  		ltzArr := make([]time.Time, numRows)
   733  		tzArr := make([]time.Time, numRows)
   734  		ntzArr := make([]time.Time, numRows)
   735  		dateArr := make([]time.Time, numRows)
   736  		timeArr := make([]time.Time, numRows)
   737  		binArr := make([][]byte, numRows)
   738  		for i := 0; i < numRows; i++ {
   739  			intArr[i] = i
   740  			strArr[i] = "test" + strconv.Itoa(i)
   741  			ltzArr[i] = now
   742  			tzArr[i] = now.Add(time.Hour).UTC()
   743  			ntzArr[i] = now.Add(2 * time.Hour)
   744  			dateArr[i] = someDate
   745  			timeArr[i] = someTime
   746  			binArr[i] = someBinary
   747  		}
   748  		dbt.mustExec(fmt.Sprintf("insert into %v values (?, ?, ?, ?, ?, ?, ?, ?)", dbname), Array(&intArr), Array(&strArr), Array(&ltzArr, TimestampLTZType), Array(&tzArr, TimestampTZType), Array(&ntzArr, TimestampNTZType), Array(&dateArr, DateType), Array(&timeArr, TimeType), Array(&binArr))
   749  		rows := dbt.mustQuery("select * from " + dbname + " order by c1")
   750  		defer rows.Close()
   751  		cnt := 0
   752  		var i int
   753  		var s string
   754  		var ltz, tz, ntz, date, tt time.Time
   755  		var b []byte
   756  		for rows.Next() {
   757  			if err := rows.Scan(&i, &s, &ltz, &tz, &ntz, &date, &tt, &b); err != nil {
   758  				t.Fatal(err)
   759  			}
   760  			assertEqualE(t, i, cnt)
   761  			assertEqualE(t, "test"+strconv.Itoa(cnt), s)
   762  			assertEqualE(t, ltz.UTC(), now.UTC())
   763  			assertEqualE(t, tz.UTC(), now.Add(time.Hour).UTC())
   764  			assertEqualE(t, ntz.UTC(), now.Add(2*time.Hour).UTC())
   765  			assertEqualE(t, date, someDate)
   766  			assertEqualE(t, tt, someTime)
   767  			assertBytesEqualE(t, b, someBinary)
   768  			cnt++
   769  		}
   770  		if cnt != numRows {
   771  			t.Fatalf("expected %v rows, got %v", numRows, cnt)
   772  		}
   773  	})
   774  }
   775  
   776  func TestBulkArrayBindingTimeWithPrecision(t *testing.T) {
   777  	runDBTest(t, func(dbt *DBTest) {
   778  		dbt.mustExec(fmt.Sprintf("create or replace table %v (s time(0), ms time(3), us time(6), ns time(9))", dbname))
   779  		someTimeWithSeconds := time.Date(1, time.January, 1, 1, 1, 1, 0, time.UTC)
   780  		someTimeWithMilliseconds := time.Date(1, time.January, 1, 2, 2, 2, 123000000, time.UTC)
   781  		someTimeWithMicroseconds := time.Date(1, time.January, 1, 3, 3, 3, 123456000, time.UTC)
   782  		someTimeWithNanoseconds := time.Date(1, time.January, 1, 4, 4, 4, 123456789, time.UTC)
   783  		numRows := 100000
   784  		secondsArr := make([]time.Time, numRows)
   785  		millisecondsArr := make([]time.Time, numRows)
   786  		microsecondsArr := make([]time.Time, numRows)
   787  		nanosecondsArr := make([]time.Time, numRows)
   788  		for i := 0; i < numRows; i++ {
   789  			secondsArr[i] = someTimeWithSeconds
   790  			millisecondsArr[i] = someTimeWithMilliseconds
   791  			microsecondsArr[i] = someTimeWithMicroseconds
   792  			nanosecondsArr[i] = someTimeWithNanoseconds
   793  		}
   794  		dbt.mustExec(fmt.Sprintf("insert into %v values (?, ?, ?, ?)", dbname), Array(&secondsArr, TimeType), Array(&millisecondsArr, TimeType), Array(&microsecondsArr, TimeType), Array(&nanosecondsArr, TimeType))
   795  		rows := dbt.mustQuery("select * from " + dbname)
   796  		defer rows.Close()
   797  		cnt := 0
   798  		var s, ms, us, ns time.Time
   799  		for rows.Next() {
   800  			if err := rows.Scan(&s, &ms, &us, &ns); err != nil {
   801  				t.Fatal(err)
   802  			}
   803  			assertEqualE(t, s, someTimeWithSeconds)
   804  			assertEqualE(t, ms, someTimeWithMilliseconds)
   805  			assertEqualE(t, us, someTimeWithMicroseconds)
   806  			assertEqualE(t, ns, someTimeWithNanoseconds)
   807  			cnt++
   808  		}
   809  		if cnt != numRows {
   810  			t.Fatalf("expected %v rows, got %v", numRows, cnt)
   811  		}
   812  	})
   813  }
   814  
   815  func TestBulkArrayMultiPartBinding(t *testing.T) {
   816  	rowCount := 1000000 // large enough to be partitioned into multiple files
   817  	rand.Seed(time.Now().UnixNano())
   818  	randomIter := rand.Intn(3) + 2
   819  	randomStrings := make([]string, rowCount)
   820  	str := randomString(30)
   821  	for i := 0; i < rowCount; i++ {
   822  		randomStrings[i] = str
   823  	}
   824  	tempTableName := fmt.Sprintf("test_table_%v", randomString(5))
   825  	ctx := context.Background()
   826  
   827  	runDBTest(t, func(dbt *DBTest) {
   828  		dbt.mustExec(fmt.Sprintf("CREATE TABLE %s (C VARCHAR(64) NOT NULL)", tempTableName))
   829  		defer dbt.mustExec("drop table " + tempTableName)
   830  
   831  		for i := 0; i < randomIter; i++ {
   832  			dbt.mustExecContext(ctx,
   833  				fmt.Sprintf("INSERT INTO %s VALUES (?)", tempTableName),
   834  				Array(&randomStrings))
   835  			rows := dbt.mustQuery("select count(*) from " + tempTableName)
   836  			defer rows.Close()
   837  			if rows.Next() {
   838  				var count int
   839  				if err := rows.Scan(&count); err != nil {
   840  					t.Error(err)
   841  				}
   842  			}
   843  		}
   844  
   845  		rows := dbt.mustQuery("select count(*) from " + tempTableName)
   846  		defer rows.Close()
   847  		if rows.Next() {
   848  			var count int
   849  			if err := rows.Scan(&count); err != nil {
   850  				t.Error(err)
   851  			}
   852  			if count != randomIter*rowCount {
   853  				t.Errorf("expected %v rows, got %v rows intead", randomIter*rowCount, count)
   854  			}
   855  		}
   856  	})
   857  }
   858  
   859  func TestBulkArrayMultiPartBindingInt(t *testing.T) {
   860  	runDBTest(t, func(dbt *DBTest) {
   861  		dbt.mustExec("create or replace table binding_test (c1 integer)")
   862  		startNum := 1000000
   863  		endNum := 3000000
   864  		numRows := endNum - startNum
   865  		intArr := make([]int, numRows)
   866  		for i := startNum; i < endNum; i++ {
   867  			intArr[i-startNum] = i
   868  		}
   869  		_, err := dbt.exec("insert into binding_test values (?)", Array(&intArr))
   870  		if err != nil {
   871  			t.Errorf("Should have succeeded to insert. err: %v", err)
   872  		}
   873  
   874  		rows := dbt.mustQuery("select * from binding_test order by c1")
   875  		defer rows.Close()
   876  		cnt := startNum
   877  		var i int
   878  		for rows.Next() {
   879  			if err := rows.Scan(&i); err != nil {
   880  				t.Fatal(err)
   881  			}
   882  			if i != cnt {
   883  				t.Errorf("expected: %v, got: %v", cnt, i)
   884  			}
   885  			cnt++
   886  		}
   887  		if cnt != endNum {
   888  			t.Fatalf("expected %v rows, got %v", numRows, (cnt - startNum))
   889  		}
   890  		dbt.mustExec("DROP TABLE binding_test")
   891  	})
   892  }
   893  
   894  func TestBulkArrayMultiPartBindingWithNull(t *testing.T) {
   895  	runDBTest(t, func(dbt *DBTest) {
   896  		dbt.mustExec("create or replace table binding_test (c1 integer, c2 string)")
   897  		startNum := 1000000
   898  		endNum := 2000000
   899  		numRows := endNum - startNum
   900  
   901  		// Define the integer and string arrays
   902  		intArr := make([]any, numRows)
   903  		stringArr := make([]any, numRows)
   904  		for i := startNum; i < endNum; i++ {
   905  			intArr[i-startNum] = i
   906  			stringArr[i-startNum] = fmt.Sprint(i)
   907  		}
   908  
   909  		// Set some of the rows to NULL
   910  		intArr[numRows-1] = nil
   911  		intArr[numRows-2] = nil
   912  		intArr[numRows-3] = nil
   913  		stringArr[1] = nil
   914  		stringArr[2] = nil
   915  		stringArr[3] = nil
   916  
   917  		_, err := dbt.exec("insert into binding_test values (?, ?)", Array(&intArr), Array(&stringArr))
   918  		if err != nil {
   919  			t.Errorf("Should have succeeded to insert. err: %v", err)
   920  		}
   921  
   922  		rows := dbt.mustQuery("select * from binding_test order by c1,c2")
   923  		defer rows.Close()
   924  		cnt := startNum
   925  		var i sql.NullInt32
   926  		var s sql.NullString
   927  		for rows.Next() {
   928  			if err := rows.Scan(&i, &s); err != nil {
   929  				t.Fatal(err)
   930  			}
   931  			// Verify integer column c1
   932  			if i.Valid {
   933  				if int(i.Int32) != intArr[cnt-startNum] {
   934  					t.Fatalf("expected: %v, got: %v", cnt, int(i.Int32))
   935  				}
   936  			} else if !(cnt == startNum+numRows-1 || cnt == startNum+numRows-2 || cnt == startNum+numRows-3) {
   937  				t.Fatalf("expected NULL in column c1 at index: %v", cnt-startNum)
   938  			}
   939  			// Verify string column c2
   940  			if s.Valid {
   941  				if s.String != stringArr[cnt-startNum] {
   942  					t.Fatalf("expected: %v, got: %v", cnt, s.String)
   943  				}
   944  			} else if !(cnt == startNum+1 || cnt == startNum+2 || cnt == startNum+3) {
   945  				t.Fatalf("expected NULL in column c2 at index: %v", cnt-startNum)
   946  			}
   947  			cnt++
   948  		}
   949  		if cnt != endNum {
   950  			t.Fatalf("expected %v rows, got %v", numRows, (cnt - startNum))
   951  		}
   952  		dbt.mustExec("DROP TABLE binding_test")
   953  	})
   954  }
   955  
   956  func TestFunctionParameters(t *testing.T) {
   957  	testcases := []struct {
   958  		testDesc   string
   959  		paramType  string
   960  		input      any
   961  		nullResult bool
   962  	}{
   963  		{"textAndNullStringResultInNull", "text", sql.NullString{}, true},
   964  		{"numberAndNullInt64ResultInNull", "number", sql.NullInt64{}, true},
   965  		{"floatAndNullFloat64ResultInNull", "float", sql.NullFloat64{}, true},
   966  		{"booleanAndAndNullBoolResultInNull", "boolean", sql.NullBool{}, true},
   967  		{"dateAndTypedNullTimeResultInNull", "date", TypedNullTime{sql.NullTime{}, DateType}, true},
   968  		{"datetimeAndTypedNullTimeResultInNull", "datetime", TypedNullTime{sql.NullTime{}, TimestampNTZType}, true},
   969  		{"timeAndTypedNullTimeResultInNull", "time", TypedNullTime{sql.NullTime{}, TimeType}, true},
   970  		{"timestampAndTypedNullTimeResultInNull", "timestamp", TypedNullTime{sql.NullTime{}, TimestampNTZType}, true},
   971  		{"timestamp_ntzAndTypedNullTimeResultInNull", "timestamp_ntz", TypedNullTime{sql.NullTime{}, TimestampNTZType}, true},
   972  		{"timestamp_ltzAndTypedNullTimeResultInNull", "timestamp_ltz", TypedNullTime{sql.NullTime{}, TimestampLTZType}, true},
   973  		{"timestamp_tzAndTypedNullTimeResultInNull", "timestamp_tz", TypedNullTime{sql.NullTime{}, TimestampTZType}, true},
   974  		{"textAndStringResultInNotNull", "text", "string", false},
   975  		{"numberAndIntegerResultInNotNull", "number", 123, false},
   976  		{"floatAndFloatResultInNotNull", "float", 123.01, false},
   977  		{"booleanAndBooleanResultInNotNull", "boolean", true, false},
   978  		{"dateAndTimeResultInNotNull", "date", time.Now(), false},
   979  		{"datetimeAndTimeResultInNotNull", "datetime", time.Now(), false},
   980  		{"timeAndTimeResultInNotNull", "time", time.Now(), false},
   981  		{"timestampAndTimeResultInNotNull", "timestamp", time.Now(), false},
   982  		{"timestamp_ntzAndTimeResultInNotNull", "timestamp_ntz", time.Now(), false},
   983  		{"timestamp_ltzAndTimeResultInNotNull", "timestamp_ltz", time.Now(), false},
   984  		{"timestamp_tzAndTimeResultInNotNull", "timestamp_tz", time.Now(), false},
   985  	}
   986  
   987  	runDBTest(t, func(dbt *DBTest) {
   988  		_, err := dbt.exec("ALTER SESSION SET BIND_NULL_VALUE_USE_NULL_DATATYPE=false")
   989  		if err != nil {
   990  			log.Println(err)
   991  		}
   992  		for _, tc := range testcases {
   993  			t.Run(tc.testDesc, func(t *testing.T) {
   994  				query := fmt.Sprintf(`
   995  				CREATE OR REPLACE FUNCTION NULLPARAMFUNCTION("param1" %v)
   996  				RETURNS TABLE("r1" %v)
   997  				LANGUAGE SQL
   998  				AS 'select param1';`, tc.paramType, tc.paramType)
   999  				dbt.mustExec(query)
  1000  				rows, err := dbt.query("select * from table(NULLPARAMFUNCTION(?))", tc.input)
  1001  				if err != nil {
  1002  					t.Fatal(err)
  1003  				}
  1004  				defer rows.Close()
  1005  				if rows.Err() != nil {
  1006  					t.Fatal(err)
  1007  				}
  1008  				if !rows.Next() {
  1009  					t.Fatal("no rows fetched")
  1010  				}
  1011  				var r1 any
  1012  				err = rows.Scan(&r1)
  1013  				if err != nil {
  1014  					t.Fatal(err)
  1015  				}
  1016  				if tc.nullResult && r1 != nil {
  1017  					t.Fatalf("the result for %v is of type %v but should be null", tc.paramType, reflect.TypeOf(r1))
  1018  				}
  1019  				if !tc.nullResult && r1 == nil {
  1020  					t.Fatalf("the result for %v should not be null", tc.paramType)
  1021  				}
  1022  			})
  1023  		}
  1024  	})
  1025  }
  1026  
  1027  func TestVariousBindingModes(t *testing.T) {
  1028  	testcases := []struct {
  1029  		testDesc  string
  1030  		paramType string
  1031  		input     any
  1032  		isNil     bool
  1033  	}{
  1034  		{"textAndString", "text", "string", false},
  1035  		{"numberAndInteger", "number", 123, false},
  1036  		{"floatAndFloat", "float", 123.01, false},
  1037  		{"booleanAndBoolean", "boolean", true, false},
  1038  		{"dateAndTime", "date", time.Now().Truncate(24 * time.Hour), false},
  1039  		{"datetimeAndTime", "datetime", time.Now(), false},
  1040  		{"timeAndTime", "time", "12:34:56", false},
  1041  		{"timestampAndTime", "timestamp", time.Now(), false},
  1042  		{"timestamp_ntzAndTime", "timestamp_ntz", time.Now(), false},
  1043  		{"timestamp_ltzAndTime", "timestamp_ltz", time.Now(), false},
  1044  		{"timestamp_tzAndTime", "timestamp_tz", time.Now(), false},
  1045  		{"textAndNullString", "text", sql.NullString{}, true},
  1046  		{"numberAndNullInt64", "number", sql.NullInt64{}, true},
  1047  		{"floatAndNullFloat64", "float", sql.NullFloat64{}, true},
  1048  		{"booleanAndAndNullBool", "boolean", sql.NullBool{}, true},
  1049  		{"dateAndTypedNullTime", "date", TypedNullTime{sql.NullTime{}, DateType}, true},
  1050  		{"datetimeAndTypedNullTime", "datetime", TypedNullTime{sql.NullTime{}, TimestampNTZType}, true},
  1051  		{"timeAndTypedNullTime", "time", TypedNullTime{sql.NullTime{}, TimeType}, true},
  1052  		{"timestampAndTypedNullTime", "timestamp", TypedNullTime{sql.NullTime{}, TimestampNTZType}, true},
  1053  		{"timestamp_ntzAndTypedNullTime", "timestamp_ntz", TypedNullTime{sql.NullTime{}, TimestampNTZType}, true},
  1054  		{"timestamp_ltzAndTypedNullTime", "timestamp_ltz", TypedNullTime{sql.NullTime{}, TimestampLTZType}, true},
  1055  		{"timestamp_tzAndTypedNullTime", "timestamp_tz", TypedNullTime{sql.NullTime{}, TimestampTZType}, true},
  1056  		{"LOBSmallSize", fmt.Sprintf("varchar(%v)", smallSize), randomString(smallSize), false},
  1057  		{"LOBOriginSize", fmt.Sprintf("varchar(%v)", originSize), randomString(originSize), false},
  1058  		{"LOBMediumSize", fmt.Sprintf("varchar(%v)", mediumSize), randomString(mediumSize), false},
  1059  		{"LOBLargeSize", fmt.Sprintf("varchar(%v)", largeSize), randomString(largeSize), false},
  1060  		{"LOBMaxSize", fmt.Sprintf("varchar(%v)", maxLOBSize), randomString(maxLOBSize), false},
  1061  	}
  1062  
  1063  	bindingModes := []struct {
  1064  		param     string
  1065  		query     string
  1066  		transform func(any) any
  1067  	}{
  1068  		{
  1069  			param:     "?",
  1070  			transform: func(v any) any { return v },
  1071  		},
  1072  		{
  1073  			param:     ":1",
  1074  			transform: func(v any) any { return v },
  1075  		},
  1076  		{
  1077  			param:     ":param",
  1078  			transform: func(v any) any { return sql.Named("param", v) },
  1079  		},
  1080  	}
  1081  
  1082  	runDBTest(t, func(dbt *DBTest) {
  1083  		for _, tc := range testcases {
  1084  			// TODO SNOW-1264687
  1085  			if strings.Contains(tc.testDesc, "LOB") {
  1086  				skipOnJenkins(t, "skipped until SNOW-1264687 is fixed")
  1087  			}
  1088  			for _, bindingMode := range bindingModes {
  1089  				t.Run(tc.testDesc+" "+bindingMode.param, func(t *testing.T) {
  1090  					query := fmt.Sprintf(`CREATE OR REPLACE TABLE BINDING_MODES(param1 %v)`, tc.paramType)
  1091  					dbt.mustExec(query)
  1092  					if _, err := dbt.exec(fmt.Sprintf("INSERT INTO BINDING_MODES VALUES (%v)", bindingMode.param), bindingMode.transform(tc.input)); err != nil {
  1093  						t.Fatal(err)
  1094  					}
  1095  					if tc.isNil {
  1096  						query = "SELECT * FROM BINDING_MODES WHERE param1 IS NULL"
  1097  					} else {
  1098  						query = fmt.Sprintf("SELECT * FROM BINDING_MODES WHERE param1 = %v", bindingMode.param)
  1099  					}
  1100  					rows, err := dbt.query(query, bindingMode.transform(tc.input))
  1101  					if err != nil {
  1102  						t.Fatal(err)
  1103  					}
  1104  					defer rows.Close()
  1105  					if !rows.Next() {
  1106  						t.Fatal("Expected to return a row")
  1107  					}
  1108  				})
  1109  			}
  1110  		}
  1111  	})
  1112  }
  1113  
  1114  func TestLOBRetrievalWithArrow(t *testing.T) {
  1115  	testLOBRetrieval(t, true)
  1116  }
  1117  
  1118  func TestLOBRetrievalWithJSON(t *testing.T) {
  1119  	testLOBRetrieval(t, false)
  1120  }
  1121  
  1122  func testLOBRetrieval(t *testing.T, useArrowFormat bool) {
  1123  	// the LOB sizes to be tested
  1124  	testSizes := [5]int{smallSize, originSize, mediumSize, largeSize, maxLOBSize}
  1125  	var res string
  1126  
  1127  	runDBTest(t, func(dbt *DBTest) {
  1128  		dbt.exec(enableFeatureMaxLOBSize)
  1129  		if useArrowFormat {
  1130  			dbt.mustExec(forceARROW)
  1131  		} else {
  1132  			dbt.mustExec(forceJSON)
  1133  		}
  1134  
  1135  		for _, testSize := range testSizes {
  1136  			t.Run(fmt.Sprintf("testLOB_%v_useArrowFormat=%v", strconv.Itoa(testSize), strconv.FormatBool(useArrowFormat)), func(t *testing.T) {
  1137  				rows, err := dbt.query(fmt.Sprintf("SELECT randstr(%v, 124)", testSize))
  1138  				assertNilF(t, err)
  1139  				defer rows.Close()
  1140  				assertTrueF(t, rows.Next(), fmt.Sprintf("no rows returned for the LOB size %v", testSize))
  1141  
  1142  				// retrieve the result
  1143  				err = rows.Scan(&res)
  1144  				assertNilF(t, err)
  1145  
  1146  				// verify the length of the result
  1147  				assertEqualF(t, len(res), testSize)
  1148  			})
  1149  		}
  1150  		dbt.exec(unsetFeatureMaxLOBSize)
  1151  	})
  1152  }
  1153  
  1154  func TestInsertLobDataWithLiteralArrow(t *testing.T) {
  1155  	// TODO SNOW-1264687
  1156  	skipOnJenkins(t, "skipped until SNOW-1264687 is fixed")
  1157  	testInsertLOBData(t, true, true)
  1158  }
  1159  
  1160  func TestInsertLobDataWithLiteralJSON(t *testing.T) {
  1161  	// TODO SNOW-1264687
  1162  	skipOnJenkins(t, "skipped until SNOW-1264687 is fixed")
  1163  	testInsertLOBData(t, false, true)
  1164  }
  1165  
  1166  func TestInsertLobDataWithBindingsArrow(t *testing.T) {
  1167  	// TODO SNOW-1264687
  1168  	skipOnJenkins(t, "skipped until SNOW-1264687 is fixed")
  1169  	testInsertLOBData(t, true, false)
  1170  }
  1171  
  1172  func TestInsertLobDataWithBindingsJSON(t *testing.T) {
  1173  	// TODO SNOW-1264687
  1174  	skipOnJenkins(t, "skipped until SNOW-1264687 is fixed")
  1175  	testInsertLOBData(t, false, false)
  1176  }
  1177  
  1178  func testInsertLOBData(t *testing.T, useArrowFormat bool, isLiteral bool) {
  1179  	expectedNumCols := 3
  1180  	columnMeta := []struct {
  1181  		columnName string
  1182  		columnType reflect.Type
  1183  	}{
  1184  		{"C1", reflect.TypeOf("")},
  1185  		{"C2", reflect.TypeOf("")},
  1186  		{"C3", reflect.TypeOf(int64(0))},
  1187  	}
  1188  	testCases := []struct {
  1189  		testDesc string
  1190  		c1Size   int
  1191  		c2Size   int
  1192  		c3Size   int
  1193  	}{
  1194  		{"testLOBInsertSmallSize", smallSize, smallSize, lobRandomRange},
  1195  		{"testLOBInsertOriginSize", originSize, originSize, lobRandomRange},
  1196  		{"testLOBInsertMediumSize", mediumSize, originSize, lobRandomRange},
  1197  		{"testLOBInsertLargeSize", largeSize, originSize, lobRandomRange},
  1198  		{"testLOBInsertMaxSize", maxLOBSize, originSize, lobRandomRange},
  1199  	}
  1200  
  1201  	runDBTest(t, func(dbt *DBTest) {
  1202  		var c1 string
  1203  		var c2 string
  1204  		var c3 int
  1205  
  1206  		dbt.exec(enableFeatureMaxLOBSize)
  1207  		if useArrowFormat {
  1208  			dbt.mustExec(forceARROW)
  1209  		} else {
  1210  			dbt.mustExec(forceJSON)
  1211  		}
  1212  
  1213  		for _, tc := range testCases {
  1214  			t.Run(tc.testDesc, func(t *testing.T) {
  1215  				// initialize test data
  1216  				c1Data := randomString(tc.c1Size)
  1217  				c2Data := randomString(tc.c2Size)
  1218  				c3Data := rand.Intn(tc.c3Size)
  1219  
  1220  				dbt.mustExec(fmt.Sprintf("CREATE OR REPLACE TABLE lob_test_table (c1 varchar(%v), c2 varchar(%v), c3 int)", tc.c1Size, tc.c2Size))
  1221  				if isLiteral {
  1222  					dbt.mustExec(fmt.Sprintf("INSERT INTO lob_test_table VALUES ('%s', '%s', %v)", c1Data, c2Data, c3Data))
  1223  				} else {
  1224  					dbt.mustExec("INSERT INTO lob_test_table VALUES (?, ?, ?)", c1Data, c2Data, c3Data)
  1225  				}
  1226  				rows, err := dbt.query("SELECT * FROM lob_test_table")
  1227  				assertNilF(t, err)
  1228  				defer rows.Close()
  1229  				assertTrueF(t, rows.Next(), fmt.Sprintf("%s: no rows returned", tc.testDesc))
  1230  
  1231  				err = rows.Scan(&c1, &c2, &c3)
  1232  				assertNilF(t, err)
  1233  
  1234  				// check the number of columns
  1235  				columnTypes, err := rows.ColumnTypes()
  1236  				assertNilF(t, err)
  1237  				assertEqualF(t, len(columnTypes), expectedNumCols)
  1238  
  1239  				// verify the column metadata: name, type and length
  1240  				for colIdx := 0; colIdx < expectedNumCols; colIdx++ {
  1241  					colName := columnTypes[colIdx].Name()
  1242  					assertEqualF(t, colName, columnMeta[colIdx].columnName)
  1243  
  1244  					colType := columnTypes[colIdx].ScanType()
  1245  					assertEqualF(t, colType, columnMeta[colIdx].columnType)
  1246  
  1247  					colLength, ok := columnTypes[colIdx].Length()
  1248  
  1249  					switch colIdx {
  1250  					case 0:
  1251  						assertTrueF(t, ok)
  1252  						assertEqualF(t, colLength, int64(tc.c1Size))
  1253  						// verify the data
  1254  						assertEqualF(t, c1, c1Data)
  1255  					case 1:
  1256  						assertTrueF(t, ok)
  1257  						assertEqualF(t, colLength, int64(tc.c2Size))
  1258  						// verify the data
  1259  						assertEqualF(t, c2, c2Data)
  1260  					case 2:
  1261  						assertFalseF(t, ok)
  1262  						// verify the data
  1263  						assertEqualF(t, c3, c3Data)
  1264  					}
  1265  				}
  1266  			})
  1267  			dbt.mustExec("DROP TABLE IF EXISTS lob_test_table")
  1268  		}
  1269  		dbt.exec(unsetFeatureMaxLOBSize)
  1270  	})
  1271  }