Skip to content

Commit

Permalink
Support passing slices as query args
Browse files Browse the repository at this point in the history
  • Loading branch information
nineinchnick authored and losipiuk committed Jul 13, 2022
1 parent a1dea99 commit 4727210
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 4 deletions.
25 changes: 24 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,30 @@ https://user@localhost:8443?session_properties=query_max_run_time=10m,query_prio

## Data types

The driver supports most Trino data types, except:
### Query arguments

When passing arguments to queries, the driver supports the following Go data types:
* integers
* `bool`
* `string`
* slices

It's not yet possible to pass:
* `nil`
* `float32` or `float64`
* `byte`
* `time.Time` or `time.Duration`
* `json.RawMessage`
* maps

To use the unsupported types, pass them as strings and use casts in the query, like so:
```sql
SELECT * FROM table WHERE col_double = cast(? AS DOUBLE) OR col_timestamp = CAST(? AS TIMESTAMP)
```

### Response rows

When reading response rows, the driver supports most Trino data types, except:
* time and timestamps with precision - all time types are returned as `time.Time`
* `DECIMAL` - returned as string
* `IPADDRESS` - returned as string
Expand Down
41 changes: 41 additions & 0 deletions trino/integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -391,6 +391,47 @@ func TestIntegrationTypeConversion(t *testing.T) {
}
}

func TestIntegrationArgsConversion(t *testing.T) {
dsn := *integrationServerFlag
dsn += "?session_properties=parse_decimal_literals_as_double=true"
db := integrationOpen(t, dsn)
value := 0
err := db.QueryRow(`
SELECT 1 FROM (VALUES (
CAST(1 AS TINYINT),
CAST(1 AS SMALLINT),
CAST(1 AS INTEGER),
CAST(1 AS BIGINT),
CAST(1 AS REAL),
CAST(1 AS DOUBLE),
TIMESTAMP '2017-07-10 01:02:03.004 UTC',
CAST('string' AS VARCHAR),
ARRAY['A', 'B']
)) AS t(col_tiny, col_small, col_int, col_big, col_real, col_double, col_ts, col_varchar, col_array )
WHERE 1=1
AND col_tiny = ?
AND col_small = ?
AND col_int = ?
AND col_big = ?
AND col_real = cast(? as real)
AND col_double = cast(? as double)
AND col_ts = cast(? as timestamp)
AND col_varchar = ?
AND col_array = ?`,
int16(1),
int16(1),
int32(1),
int64(1),
Numeric("1"),
Numeric("1"),
"2017-07-10 01:02:03.004 UTC",
"string",
[]string{"A", "B"}).Scan(&value)
if err != nil {
t.Fatal(err)
}
}

func TestIntegrationNoResults(t *testing.T) {
db := integrationOpen(t)
rows, err := db.Query("SELECT 1 LIMIT 0")
Expand Down
15 changes: 12 additions & 3 deletions trino/trino.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ import (
"math"
"net/http"
"net/url"
"reflect"
"regexp"
"sort"
"strconv"
Expand Down Expand Up @@ -544,9 +545,10 @@ type driverStmt struct {
}

var (
_ driver.Stmt = &driverStmt{}
_ driver.StmtQueryContext = &driverStmt{}
_ driver.StmtExecContext = &driverStmt{}
_ driver.Stmt = &driverStmt{}
_ driver.StmtQueryContext = &driverStmt{}
_ driver.StmtExecContext = &driverStmt{}
_ driver.NamedValueChecker = &driverStmt{}
)

func (st *driverStmt) Close() error {
Expand Down Expand Up @@ -583,6 +585,13 @@ func (st *driverStmt) ExecContext(ctx context.Context, args []driver.NamedValue)
return rows, nil
}

func (st *driverStmt) CheckNamedValue(arg *driver.NamedValue) error {
if reflect.TypeOf(arg.Value).Kind() == reflect.Slice {
return nil
}
return driver.ErrSkip
}

type stmtResponse struct {
ID string `json:"id"`
InfoURI string `json:"infoUri"`
Expand Down

0 comments on commit 4727210

Please sign in to comment.