Skip to content
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions go/connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ func (c *trinoConnectionImpl) GetTableSchema(ctx context.Context, catalog *strin
Name: colType.Name(),
DatabaseTypeName: colType.DatabaseTypeName(),
Nullable: true, // Assume every column in always nullable since trino go client does not provide clean way to get nullability.
ScanType: colType.ScanType(),
}

// Add precision and scale if available
Expand Down
58 changes: 58 additions & 0 deletions go/trino.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import (
"database/sql/driver"
"fmt"
"math/big"
"reflect"
"strconv"
"strings"
"time"
Expand Down Expand Up @@ -128,10 +129,36 @@ func (m *trinoTypeConverter) ConvertRawColumnType(colType sqlwrapper.ColumnType)
return extensions.NewUUIDType(), colType.Nullable, metadata, nil
}

if listType := scanTypeToListMap[colType.ScanType]; listType != nil {
metadata := arrow.MetadataFrom(map[string]string{
sqlwrapper.MetaKeyDatabaseTypeName: colType.DatabaseTypeName,
sqlwrapper.MetaKeyColumnName: colType.Name,
})
return listType, colType.Nullable, metadata, nil
}

// For all other types, fall back to default conversion
return m.DefaultTypeConverter.ConvertRawColumnType(colType)
}

var scanTypeToListMap = map[reflect.Type]arrow.DataType{
reflect.TypeFor[trino.NullSliceString](): arrow.ListOf(arrow.BinaryTypes.String),
reflect.TypeFor[trino.NullSliceInt64](): arrow.ListOf(arrow.PrimitiveTypes.Int64),
reflect.TypeFor[trino.NullSliceFloat64](): arrow.ListOf(arrow.PrimitiveTypes.Float64),
reflect.TypeFor[trino.NullSliceBool](): arrow.ListOf(arrow.FixedWidthTypes.Boolean),
reflect.TypeFor[trino.NullSliceTime](): arrow.ListOf(&arrow.TimestampType{Unit: arrow.Microsecond, TimeZone: "UTC"}),
reflect.TypeFor[trino.NullSlice2String](): arrow.ListOf(arrow.ListOf(arrow.BinaryTypes.String)),
reflect.TypeFor[trino.NullSlice2Int64](): arrow.ListOf(arrow.ListOf(arrow.PrimitiveTypes.Int64)),
reflect.TypeFor[trino.NullSlice2Float64](): arrow.ListOf(arrow.ListOf(arrow.PrimitiveTypes.Float64)),
reflect.TypeFor[trino.NullSlice2Bool](): arrow.ListOf(arrow.ListOf(arrow.FixedWidthTypes.Boolean)),
reflect.TypeFor[trino.NullSlice2Time](): arrow.ListOf(arrow.ListOf(&arrow.TimestampType{Unit: arrow.Microsecond, TimeZone: "UTC"})),
reflect.TypeFor[trino.NullSlice3String](): arrow.ListOf(arrow.ListOf(arrow.ListOf(arrow.BinaryTypes.String))),
reflect.TypeFor[trino.NullSlice3Int64](): arrow.ListOf(arrow.ListOf(arrow.ListOf(arrow.PrimitiveTypes.Int64))),
reflect.TypeFor[trino.NullSlice3Float64](): arrow.ListOf(arrow.ListOf(arrow.ListOf(arrow.PrimitiveTypes.Float64))),
reflect.TypeFor[trino.NullSlice3Bool](): arrow.ListOf(arrow.ListOf(arrow.ListOf(arrow.FixedWidthTypes.Boolean))),
reflect.TypeFor[trino.NullSlice3Time](): arrow.ListOf(arrow.ListOf(arrow.ListOf(&arrow.TimestampType{Unit: arrow.Microsecond, TimeZone: "UTC"}))),
}

// Clamps precision to maximum supported value (9 fractional digits = nanoseconds)
func convertPrecisionToTimeUnit(precision int64) arrow.TimeUnit {
if precision > 9 {
Expand Down Expand Up @@ -178,12 +205,43 @@ func (m *trinoTypeConverter) CreateInserter(field *arrow.Field, builder array.Bu
default:
return nil, fmt.Errorf("unsupported interval type: %s", dbTypeName)
}
case *arrow.ListType:
lb := builder.(*array.ListBuilder)
elemField := arrow.Field{Name: "item", Type: fieldType.Elem(), Nullable: true}
childIns, err := m.CreateInserter(&elemField, lb.ValueBuilder())
if err != nil {
return nil, fmt.Errorf("failed to create child inserter for list: %w", err)
}
return &listInserter{builder: lb, childInserter: childIns}, nil
default:
// For all other types, use default inserter
return m.DefaultTypeConverter.CreateInserter(field, builder)
}
}

type listInserter struct {
builder *array.ListBuilder
childInserter sqlwrapper.Inserter
}

func (ins *listInserter) AppendValue(sqlValue any) error {
if sqlValue == nil {
ins.builder.AppendNull()
return nil
}
slice, ok := sqlValue.([]any)
if !ok {
return fmt.Errorf("expected []interface{} for list type, got %T", sqlValue)
}
ins.builder.Append(true)
for _, elem := range slice {
if err := ins.childInserter.AppendValue(elem); err != nil {
return err
}
}
return nil
}

func unwrap(val any) (any, error) {
if v, ok := val.(driver.Valuer); ok {
return v.Value()
Expand Down
1 change: 1 addition & 0 deletions go/trino_test.go
Comment thread
lidavidm marked this conversation as resolved.
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,7 @@ func (q *TrinoQuirks) SupportsTransactions() bool { return fals
func (q *TrinoQuirks) SupportsGetParameterSchema() bool { return false }
func (q *TrinoQuirks) SupportsDynamicParameterBinding() bool { return false }
func (q *TrinoQuirks) SupportsErrorIngestIncompatibleSchema() bool { return false }
func (q *TrinoQuirks) SupportsGetTableSchema() bool { return true }
func (q *TrinoQuirks) Catalog() string { return "memory" }
func (q *TrinoQuirks) DBSchema() string { return "default" }

Expand Down
3 changes: 3 additions & 0 deletions go/validation/queries/type/select/array_varchar.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{"res": ["a", "b"]}
{"res": null}
{"res": []}
17 changes: 17 additions & 0 deletions go/validation/queries/type/select/array_varchar.schema.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"format": "+s",
"children": [
{
"name": "res",
"format": "+l",
"flags": ["nullable"],
"children": [
{
"name": "item",
"format": "u",
"flags": ["nullable"]
}
]
}
]
}
8 changes: 8 additions & 0 deletions go/validation/queries/type/select/array_varchar.setup.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
CREATE TABLE test_array_varchar (
idx INTEGER,
res ARRAY(VARCHAR)
);

INSERT INTO test_array_varchar (idx, res) VALUES (1, ARRAY['a', 'b']);
INSERT INTO test_array_varchar (idx, res) VALUES (2, NULL);
INSERT INTO test_array_varchar (idx, res) VALUES (3, ARRAY[]);
1 change: 1 addition & 0 deletions go/validation/queries/type/select/array_varchar.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
SELECT res FROM test_array_varchar ORDER BY idx
19 changes: 19 additions & 0 deletions go/validation/queries/type/select/array_varchar.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Copyright (c) 2026 ADBC Drivers Contributors
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

[setup]
drop = "test_array_varchar"

[tags]
sql-type-name = "ARRAY(VARCHAR)"
Loading