diff --git a/trino/etc/catalog/memory.properties b/trino/etc/catalog/memory.properties new file mode 100644 index 0000000..833abd3 --- /dev/null +++ b/trino/etc/catalog/memory.properties @@ -0,0 +1 @@ +connector.name=memory diff --git a/trino/serial.go b/trino/serial.go index 0bf7837..88e9a9d 100644 --- a/trino/serial.go +++ b/trino/serial.go @@ -99,7 +99,7 @@ func Timestamp(year int, func Serial(v interface{}) (string, error) { switch x := v.(type) { case nil: - return "", UnsupportedArgError{""} + return "NULL", nil // numbers convertible to int case int8: diff --git a/trino/serial_test.go b/trino/serial_test.go index 62ef0fd..fc0aa2f 100644 --- a/trino/serial_test.go +++ b/trino/serial_test.go @@ -161,9 +161,9 @@ func TestSerial(t *testing.T) { expectedSerial: "TIMESTAMP '2017-07-10 11:34:25.000123456 Z'", }, { - name: "nil", - value: nil, - expectedError: true, + name: "nil", + value: nil, + expectedSerial: "NULL", }, { name: "slice typed nil", diff --git a/trino/trino.go b/trino/trino.go index d9015c4..4b9db2c 100644 --- a/trino/trino.go +++ b/trino/trino.go @@ -656,6 +656,8 @@ func (st *driverStmt) ExecContext(ctx context.Context, args []driver.NamedValue) func (st *driverStmt) CheckNamedValue(arg *driver.NamedValue) error { switch arg.Value.(type) { + case nil: + return nil case Numeric, trinoDate, trinoTime, trinoTimeTz, trinoTimestamp: return nil default: diff --git a/trino/trino_test.go b/trino/trino_test.go index ef8a46a..318f0ef 100644 --- a/trino/trino_test.go +++ b/trino/trino_test.go @@ -1719,3 +1719,67 @@ func BenchmarkQuery(b *testing.B) { rows.Close() } } + +func TestExec(t *testing.T) { + if testing.Short() { + t.Skip("Skipping test in short mode.") + } + c := &Config{ + ServerURI: *integrationServerFlag, + SessionProperties: map[string]string{"query_priority": "1"}, + } + + dsn, err := c.FormatDSN() + require.NoError(t, err) + + db, err := sql.Open("trino", dsn) + require.NoError(t, err) + + t.Cleanup(func() { + assert.NoError(t, db.Close()) + }) + + result, err := db.Exec("CREATE TABLE memory.default.test (id INTEGER, name VARCHAR, optional VARCHAR)") + require.NoError(t, err, "Failed executing CREATE TABLE query") + + result, err = db.Exec("INSERT INTO memory.default.test (id, name, optional) VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?)", + 123, "abc", nil, + 456, "def", "present", + 789, "ghi", nil) + require.NoError(t, err, "Failed executing INSERT query") + _, err = result.LastInsertId() + assert.Error(t, err, "trino: operation not supported") + numRows, err := result.RowsAffected() + require.NoError(t, err, "Failed checking rows affected") + assert.Equal(t, numRows, int64(3)) + + rows, err := db.Query("SELECT * FROM memory.default.test") + require.NoError(t, err, "Failed executing DELETE query") + + expectedIds := []int{123, 456, 789} + expectedNames := []string{"abc", "def", "ghi"} + expectedOptionals := []sql.NullString{ + sql.NullString{Valid: false}, + sql.NullString{String: "present", Valid: true}, + sql.NullString{Valid: false}, + } + actualIds := []int{} + actualNames := []string{} + actualOptionals := []sql.NullString{} + for rows.Next() { + var id int + var name string + var optional sql.NullString + require.NoError(t, rows.Scan(&id, &name, &optional), "Failed scanning query result") + actualIds = append(actualIds, id) + actualNames = append(actualNames, name) + actualOptionals = append(actualOptionals, optional) + + } + assert.Equal(t, expectedIds, actualIds) + assert.Equal(t, expectedNames, actualNames) + assert.Equal(t, expectedOptionals, actualOptionals) + + _, err = db.Exec("DROP TABLE memory.default.test") + require.NoError(t, err, "Failed executing DROP TABLE query") +}