Repository: snowflakedb/gosnowflake
Pull request #1175 (2024-07-08 14:16:19)

SNOW-1524314 Hide structured types behind context
### Description

SNOW-1524314 Hides structured types behind context. Without using this context, structured types are going to be returned as semistructured types - as strings.

### Checklist
- [x] Created tests which fail without the change (if possible)
- [x] Extended the README / documentation, if necessary



Patch:
diff --git a/converter.go b/converter.go
index 231893b..50476c4 100644
--- a/converter.go
+++ b/converter.go
@@ -31,6 +31,8 @@ const numberDefaultPrecision = 38
 
 type timezoneType int
 
+var errNativeArrowWithoutProperContext = errors.New("structured types must be enabled to use with native arrow")
+
 const (
 	// TimestampNTZType denotes a NTZ timezoneType for array binds
 	TimestampNTZType timezoneType = iota
@@ -134,6 +136,7 @@ func goTypeToSnowflake(v driver.Value, tsmode snowflakeType) snowflakeType {
 
 // snowflakeTypeToGo translates Snowflake data type to Go data type.
 func snowflakeTypeToGo(ctx context.Context, dbtype snowflakeType, scale int64, fields []fieldMetadata) reflect.Type {
+	structuredTypesEnabled := structuredTypesEnabled(ctx)
 	switch dbtype {
 	case fixedType:
 		if scale == 0 {
@@ -151,12 +154,12 @@ func snowflakeTypeToGo(ctx context.Context, dbtype snowflakeType, scale int64, f
 	case booleanType:
 		return reflect.TypeOf(true)
 	case objectType:
-		if len(fields) > 0 {
+		if len(fields) > 0 && structuredTypesEnabled {
 			return reflect.TypeOf(ObjectType{})
 		}
 		return reflect.TypeOf("")
 	case arrayType:
-		if len(fields) == 0 {
+		if len(fields) == 0 || !structuredTypesEnabled {
 			return reflect.TypeOf("")
 		}
 		if len(fields) != 1 {
@@ -188,6 +191,9 @@ func snowflakeTypeToGo(ctx context.Context, dbtype snowflakeType, scale int64, f
 		}
 		return nil
 	case mapType:
+		if !structuredTypesEnabled {
+			return reflect.TypeOf("")
+		}
 		switch getSnowflakeType(fields[0].Type) {
 		case textType:
 			return snowflakeTypeToGoForMaps[string](ctx, fields[1])
@@ -898,10 +904,11 @@ func stringToValue(ctx context.Context, dest *driver.Value, srcColumnMeta execRe
 		*dest = nil
 		return nil
 	}
+	structuredTypesEnabled := structuredTypesEnabled(ctx)
 	logger.Debugf("snowflake data type: %v, raw value: %v", srcColumnMeta.Type, *srcValue)
 	switch srcColumnMeta.Type {
 	case "object":
-		if len(srcColumnMeta.Fields) == 0 {
+		if len(srcColumnMeta.Fields) == 0 || !structuredTypesEnabled {
 			// semistructured type without schema
 			*dest = *srcValue
 			return nil
@@ -991,7 +998,7 @@ func stringToValue(ctx context.Context, dest *driver.Value, srcColumnMeta execRe
 		*dest = b
 		return nil
 	case "array":
-		if len(srcColumnMeta.Fields) == 0 {
+		if len(srcColumnMeta.Fields) == 0 || !structuredTypesEnabled {
 			*dest = *srcValue
 			return nil
 		}
@@ -1019,6 +1026,10 @@ func stringToValue(ctx context.Context, dest *driver.Value, srcColumnMeta execRe
 }
 
 func jsonToMap(ctx context.Context, keyMetadata, valueMetadata fieldMetadata, srcValue string, params map[string]*string) (snowflakeValue, error) {
+	structuredTypesEnabled := structuredTypesEnabled(ctx)
+	if !structuredTypesEnabled {
+		return srcValue, nil
+	}
 	switch keyMetadata.Type {
 	case "text":
 		var m map[string]any
@@ -1459,6 +1470,7 @@ func arrowToValues(
 }
 
 func arrowToValue(ctx context.Context, rowIdx int, srcColumnMeta fieldMetadata, srcValue arrow.Array, loc *time.Location, higherPrecision bool, params map[string]*string, snowflakeType snowflakeType) (snowflakeValue, error) {
+	structuredTypesEnabled := structuredTypesEnabled(ctx)
 	switch snowflakeType {
 	case fixedType:
 		// Snowflake data types that are fixed-point numbers will fall into this category
@@ -1489,7 +1501,7 @@ func arrowToValue(ctx context.Context, rowIdx int, srcColumnMeta fieldMetadata,
 		}
 		return nil, nil
 	case arrayType:
-		if len(srcColumnMeta.Fields) == 0 {
+		if len(srcColumnMeta.Fields) == 0 || !structuredTypesEnabled {
 			// semistructured type without schema
 			strings := srcValue.(*array.String)
 			if !srcValue.IsNull(rowIdx) {
@@ -1511,9 +1523,12 @@ func arrowToValue(ctx context.Context, rowIdx int, srcColumnMeta fieldMetadata,
 			}
 			return nil, nil
 		}
+		if !structuredTypesEnabled {
+			return nil, errNativeArrowWithoutProperContext
+		}
 		return buildListFromNativeArrow(ctx, rowIdx, srcColumnMeta.Fields[0], srcValue, loc, higherPrecision, params)
 	case objectType:
-		if len(srcColumnMeta.Fields) == 0 {
+		if len(srcColumnMeta.Fields) == 0 || !structuredTypesEnabled {
 			// semistructured type without schema
 			strings := srcValue.(*array.String)
 			if !srcValue.IsNull(rowIdx) {
@@ -1536,6 +1551,9 @@ func arrowToValue(ctx context.Context, rowIdx int, srcColumnMeta fieldMetadata,
 			return nil, nil
 		}
 		// structured objects as native arrow
+		if !structuredTypesEnabled {
+			return nil, errNativeArrowWithoutProperContext
+		}
 		if srcValue.IsNull(rowIdx) {
 			return nil, nil
 		}
@@ -1553,6 +1571,9 @@ func arrowToValue(ctx context.Context, rowIdx int, srcColumnMeta fieldMetadata,
 			}
 		} else {
 			// structured map as native arrow
+			if !structuredTypesEnabled {
+				return nil, errNativeArrowWithoutProperContext
+			}
 			return buildMapFromNativeArrow(ctx, rowIdx, srcColumnMeta.Fields[0], srcColumnMeta.Fields[1], srcValue, loc, higherPrecision, params)
 		}
 	case binaryType:
diff --git a/doc.go b/doc.go
index ad37338..c02ba6e 100644
--- a/doc.go
+++ b/doc.go
@@ -494,7 +494,8 @@ Additionally, `sf` tag can be added:
 - first value is always a name of a field in an SQL object
 - additionally `ignore` parameter can be passed to omit this field
 
-2. Use it in regular scan:
+2. Use WithStructuredTypesEnabled context while querying data.
+3. Use it in regular scan:
 
 	var res simpleObject
 	err := rows.Scan(&res)
diff --git a/structured_type.go b/structured_type.go
index bfb48c2..381530d 100644
--- a/structured_type.go
+++ b/structured_type.go
@@ -1150,6 +1150,15 @@ func (st *structuredType) fieldMetadataByFieldName(fieldName string) (fieldMetad
 	return fieldMetadata{}, errors.New("no metadata for field " + fieldName)
 }
 
+func structuredTypesEnabled(ctx context.Context) bool {
+	v := ctx.Value(enableStructuredTypes)
+	if v == nil {
+		return false
+	}
+	d, ok := v.(bool)
+	return ok && d
+}
+
 func mapValuesNullableEnabled(ctx context.Context) bool {
 	v := ctx.Value(mapValuesNullable)
 	if v == nil {
diff --git a/util.go b/util.go
index c2874e0..1274723 100644
--- a/util.go
+++ b/util.go
@@ -33,6 +33,7 @@ const (
 	arrowAlloc                       contextKey = "ARROW_ALLOC"
 	arrowBatchesTimestampOption      contextKey = "ARROW_BATCHES_TIMESTAMP_OPTION"
 	queryTag                         contextKey = "QUERY_TAG"
+	enableStructuredTypes            contextKey = "ENABLE_STRUCTURED_TYPES"
 	mapValuesNullable                contextKey = "MAP_VALUES_NULLABLE"
 )
 
@@ -147,6 +148,13 @@ func WithQueryTag(ctx context.Context, tag string) context.Context {
 	return context.WithValue(ctx, queryTag, tag)
 }
 
+// WithStructuredTypesEnabled changes how structured types are returned.
+// Without this context structured types are returned as strings.
+// With this context enabled, structured types are returned as native Go types.
+func WithStructuredTypesEnabled(ctx context.Context) context.Context {
+	return context.WithValue(ctx, enableStructuredTypes, true)
+}
+
 // WithMapValuesNullable changes how map values are returned.
 // Instead of simple values (like string) sql.NullXXX wrappers (like sql.NullString) are used.
 func WithMapValuesNullable(ctx context.Context) context.Context {


Test patch:
diff --git a/converter_test.go b/converter_test.go
index f94a4e8..b0030e2 100644
--- a/converter_test.go
+++ b/converter_test.go
@@ -156,26 +156,33 @@ func TestSnowflakeTypeToGo(t *testing.T) {
 		{in: timestampNtzType, scale: 0, out: reflect.TypeOf(time.Now()), ctx: context.Background()},
 		{in: timestampTzType, scale: 0, out: reflect.TypeOf(time.Now()), ctx: context.Background()},
 		{in: objectType, scale: 0, out: reflect.TypeOf(""), ctx: context.Background()},
-		{in: objectType, scale: 0, fields: []fieldMetadata{{}}, out: reflect.TypeOf(ObjectType{}), ctx: context.Background()},
+		{in: objectType, scale: 0, fields: []fieldMetadata{}, out: reflect.TypeOf(""), ctx: context.Background()},
+		{in: objectType, scale: 0, fields: []fieldMetadata{{}}, out: reflect.TypeOf(""), ctx: context.Background()},
+		{in: objectType, scale: 0, fields: []fieldMetadata{{}}, out: reflect.TypeOf(ObjectType{}), ctx: WithStructuredTypesEnabled(context.Background())},
 		{in: variantType, scale: 0, out: reflect.TypeOf(""), ctx: context.Background()},
 		{in: arrayType, scale: 0, out: reflect.TypeOf(""), ctx: context.Background()},
 		{in: binaryType, scale: 0, out: reflect.TypeOf([]byte{}), ctx: context.Background()},
 		{in: booleanType, scale: 0, out: reflect.TypeOf(true), ctx: context.Background()},
 		{in: sliceType, scale: 0, out: reflect.TypeOf(""), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "fixed", Scale: 0}}, out: reflect.TypeOf([]int64{}), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "fixed", Scale: 1}}, out: reflect.TypeOf([]float64{}), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "fixed", Scale: 0}}, out: reflect.TypeOf([]*big.Int{}), ctx: WithHigherPrecision(context.Background())},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "fixed", Scale: 1}}, out: reflect.TypeOf([]*big.Float{}), ctx: WithHigherPrecision(context.Background())},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "real", Scale: 1}}, out: reflect.TypeOf([]float64{}), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "text"}}, out: reflect.TypeOf([]string{}), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "date"}}, out: reflect.TypeOf([]time.Time{}), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "time"}}, out: reflect.TypeOf([]time.Time{}), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "timestamp_ntz"}}, out: reflect.TypeOf([]time.Time{}), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "timestamp_ltz"}}, out: reflect.TypeOf([]time.Time{}), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "timestamp_tz"}}, out: reflect.TypeOf([]time.Time{}), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "boolean"}}, out: reflect.TypeOf([]bool{}), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "binary"}}, out: reflect.TypeOf([][]byte{}), ctx: context.Background()},
-		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "object"}}, out: reflect.TypeOf([]ObjectType{}), ctx: context.Background()},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "fixed", Scale: 0}}, out: reflect.TypeOf(""), ctx: context.Background()},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "fixed", Scale: 0}}, out: reflect.TypeOf([]int64{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "fixed", Scale: 1}}, out: reflect.TypeOf([]float64{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "fixed", Scale: 0}}, out: reflect.TypeOf([]*big.Int{}), ctx: WithStructuredTypesEnabled(WithHigherPrecision(context.Background()))},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "fixed", Scale: 1}}, out: reflect.TypeOf([]*big.Float{}), ctx: WithStructuredTypesEnabled(WithHigherPrecision(context.Background()))},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "real", Scale: 1}}, out: reflect.TypeOf([]float64{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "text"}}, out: reflect.TypeOf([]string{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "date"}}, out: reflect.TypeOf([]time.Time{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "time"}}, out: reflect.TypeOf([]time.Time{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "timestamp_ntz"}}, out: reflect.TypeOf([]time.Time{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "timestamp_ltz"}}, out: reflect.TypeOf([]time.Time{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "timestamp_tz"}}, out: reflect.TypeOf([]time.Time{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "boolean"}}, out: reflect.TypeOf([]bool{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "binary"}}, out: reflect.TypeOf([][]byte{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: arrayType, scale: 0, fields: []fieldMetadata{{Type: "object"}}, out: reflect.TypeOf([]ObjectType{}), ctx: WithStructuredTypesEnabled(context.Background())},
+		{in: mapType, fields: nil, out: reflect.TypeOf(""), ctx: context.Background()},
+		{in: mapType, fields: []fieldMetadata{}, out: reflect.TypeOf(""), ctx: context.Background()},
+		{in: mapType, fields: []fieldMetadata{{}, {}}, out: reflect.TypeOf(""), ctx: context.Background()},
+		{in: mapType, fields: []fieldMetadata{{Type: "text"}, {Type: "text"}}, out: reflect.TypeOf(map[string]string{}), ctx: WithStructuredTypesEnabled(context.Background())},
 	}
 	for _, test := range testcases {
 		t.Run(fmt.Sprintf("%v_%v", test.in, test.out), func(t *testing.T) {
diff --git a/rows_test.go b/rows_test.go
index 50b4bf6..6b7238f 100644
--- a/rows_test.go
+++ b/rows_test.go
@@ -110,6 +110,7 @@ func TestRowsWithoutChunkDownloader(t *testing.T) {
 		},
 	}
 	rows.sc = sc
+	rows.ctx = context.Background()
 	rows.ChunkDownloader = &snowflakeChunkDownloader{
 		sc:                 sc,
 		ctx:                context.Background(),
@@ -185,6 +186,7 @@ func TestRowsWithChunkDownloader(t *testing.T) {
 		},
 	}
 	rows.sc = sc
+	rows.ctx = context.Background()
 	rows.ChunkDownloader = &snowflakeChunkDownloader{
 		sc:            sc,
 		ctx:           context.Background(),
@@ -269,6 +271,7 @@ func TestRowsWithChunkDownloaderError(t *testing.T) {
 		},
 	}
 	rows.sc = sc
+	rows.ctx = context.Background()
 	rows.ChunkDownloader = &snowflakeChunkDownloader{
 		sc:            sc,
 		ctx:           context.Background(),
@@ -352,6 +355,7 @@ func TestRowsWithChunkDownloaderErrorFail(t *testing.T) {
 		},
 	}
 	rows.sc = sc
+	rows.ctx = context.Background()
 	rows.ChunkDownloader = &snowflakeChunkDownloader{
 		sc:            sc,
 		ctx:           context.Background(),
diff --git a/structured_type_read_test.go b/structured_type_read_test.go
index 773fb90..63b2033 100644
--- a/structured_type_read_test.go
+++ b/structured_type_read_test.go
@@ -202,13 +202,29 @@ func (so *simpleObject) Write(sowc StructuredObjectWriterContext) error {
 	return nil
 }
 
-func TestObjectWithAllTypes(t *testing.T) {
+func TestObjectWithAllTypesAsString(t *testing.T) {
+	runDBTest(t, func(dbt *DBTest) {
+		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
+			skipForStringingNativeArrow(t, format)
+			rows := dbt.mustQuery("SELECT {'s': 'some string', 'i32': 3}::OBJECT(s VARCHAR, i32 INTEGER)")
+			defer rows.Close()
+			assertTrueF(t, rows.Next())
+			var res string
+			err := rows.Scan(&res)
+			assertNilF(t, err)
+			assertEqualIgnoringWhitespaceE(t, res, `{"s": "some string", "i32": 3}`)
+		})
+	})
+}
+
+func TestObjectWithAllTypesAsObject(t *testing.T) {
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.mustExec("ALTER SESSION SET TIMEZONE = 'Europe/Warsaw'")
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
-			rows := dbt.mustQuery("SELECT 1, {'s': 'some string', 'b': 1, 'i16': 2, 'i32': 3, 'i64': 9223372036854775807, 'f32': '1.1', 'f64': 2.2, 'nfraction': 3.3, 'bo': true, 'bi': TO_BINARY('616263', 'HEX'), 'date': '2024-03-21'::DATE, 'time': '13:03:02'::TIME, 'ltz': '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz': '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz': '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so': {'s': 'child', 'i': 9}, 'sArr': ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr': ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap': {'x': true, 'y': false}}::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT 1, {'s': 'some string', 'b': 1, 'i16': 2, 'i32': 3, 'i64': 9223372036854775807, 'f32': '1.1', 'f64': 2.2, 'nfraction': 3.3, 'bo': true, 'bi': TO_BINARY('616263', 'HEX'), 'date': '2024-03-21'::DATE, 'time': '13:03:02'::TIME, 'ltz': '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz': '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz': '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so': {'s': 'child', 'i': 9}, 'sArr': ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr': ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap': {'x': true, 'y': false}}::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
 			defer rows.Close()
 			rows.Next()
 			var ignore int
@@ -241,10 +257,11 @@ func TestObjectWithAllTypes(t *testing.T) {
 }
 
 func TestNullObject(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
 			t.Run("null", func(t *testing.T) {
-				rows := dbt.mustQuery("SELECT null::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
+				rows := dbt.mustQueryContextT(ctx, t, "SELECT null::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
 				defer rows.Close()
 				assertTrueF(t, rows.Next())
 				var res *objectWithAllTypes
@@ -253,7 +270,7 @@ func TestNullObject(t *testing.T) {
 				assertNilE(t, res)
 			})
 			t.Run("not null", func(t *testing.T) {
-				rows := dbt.mustQuery("SELECT {'s': 'some string', 'b': 1, 'i16': 2, 'i32': 3, 'i64': 9223372036854775807, 'f32': '1.1', 'f64': 2.2, 'nfraction': 3.3, 'bo': true, 'bi': TO_BINARY('616263', 'HEX'), 'date': '2024-03-21'::DATE, 'time': '13:03:02'::TIME, 'ltz': '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz': '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz': '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so': {'s': 'child', 'i': 9}, 'sArr': ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr': ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap': {'x': true, 'y': false}}::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
+				rows := dbt.mustQueryContextT(ctx, t, "SELECT {'s': 'some string', 'b': 1, 'i16': 2, 'i32': 3, 'i64': 9223372036854775807, 'f32': '1.1', 'f64': 2.2, 'nfraction': 3.3, 'bo': true, 'bi': TO_BINARY('616263', 'HEX'), 'date': '2024-03-21'::DATE, 'time': '13:03:02'::TIME, 'ltz': '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz': '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz': '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so': {'s': 'child', 'i': 9}, 'sArr': ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr': ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap': {'x': true, 'y': false}}::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
 				defer rows.Close()
 				assertTrueF(t, rows.Next())
 				var res *objectWithAllTypes
@@ -418,11 +435,12 @@ func (o *objectWithAllTypesNullable) Write(sowc StructuredObjectWriterContext) e
 func TestObjectWithAllTypesNullable(t *testing.T) {
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.mustExec("ALTER SESSION SET TIMEZONE = 'Europe/Warsaw'")
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
 			t.Run("null", func(t *testing.T) {
-				rows := dbt.mustQuery("select null, object_construct_keep_null('s', null, 'b', null, 'i16', null, 'i32', null, 'i64', null, 'f64', null, 'bo', null, 'bi', null, 'date', null, 'time', null, 'ltz', null, 'tz', null, 'ntz', null, 'so', null, 'sArr', null, 'f64Arr', null, 'someMap', null)::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f64 DOUBLE, bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
+				rows := dbt.mustQueryContextT(ctx, t, "select null, object_construct_keep_null('s', null, 'b', null, 'i16', null, 'i32', null, 'i64', null, 'f64', null, 'bo', null, 'bi', null, 'date', null, 'time', null, 'ltz', null, 'tz', null, 'ntz', null, 'so', null, 'sArr', null, 'f64Arr', null, 'someMap', null)::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f64 DOUBLE, bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
 				defer rows.Close()
 				rows.Next()
 				var ignore sql.NullInt32
@@ -447,7 +465,7 @@ func TestObjectWithAllTypesNullable(t *testing.T) {
 				assertDeepEqualE(t, res.so, so)
 			})
 			t.Run("not null", func(t *testing.T) {
-				rows := dbt.mustQuery("select 1, object_construct_keep_null('s', 'abc', 'b', 1, 'i16', 2, 'i32', 3, 'i64', 9223372036854775807, 'f64', 2.2, 'bo', true, 'bi', TO_BINARY('616263', 'HEX'), 'date', '2024-03-21'::DATE, 'time', '13:03:02'::TIME, 'ltz', '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz', '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz', '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so', {'s': 'child', 'i': 9}::OBJECT, 'sArr', ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr', ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap', {'x': true, 'y': false})::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f64 DOUBLE, bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
+				rows := dbt.mustQueryContextT(ctx, t, "select 1, object_construct_keep_null('s', 'abc', 'b', 1, 'i16', 2, 'i32', 3, 'i64', 9223372036854775807, 'f64', 2.2, 'bo', true, 'bi', TO_BINARY('616263', 'HEX'), 'date', '2024-03-21'::DATE, 'time', '13:03:02'::TIME, 'ltz', '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz', '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz', '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so', {'s': 'child', 'i': 9}::OBJECT, 'sArr', ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr', ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap', {'x': true, 'y': false})::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f64 DOUBLE, bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
 				defer rows.Close()
 				rows.Next()
 				var ignore sql.NullInt32
@@ -517,10 +535,11 @@ func (so *objectWithAllTypesSimpleScan) Write(sowc StructuredObjectWriterContext
 func TestObjectWithAllTypesSimpleScan(t *testing.T) {
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.mustExec("ALTER SESSION SET TIMEZONE = 'Europe/Warsaw'")
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
-			rows := dbt.mustQuery("SELECT 1, {'s': 'some string', 'b': 1, 'i16': 2, 'i32': 3, 'i64': 9223372036854775807, 'f32': '1.1', 'f64': 2.2, 'nfraction': 3.3, 'bo': true, 'bi': TO_BINARY('616263', 'HEX'), 'date': '2024-03-21'::DATE, 'time': '13:03:02'::TIME, 'ltz': '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz': '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz': '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so': {'s': 'child', 'i': 9}, 'sArr': ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr': ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap': {'x': true, 'y': false}}::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT 1, {'s': 'some string', 'b': 1, 'i16': 2, 'i32': 3, 'i64': 9223372036854775807, 'f32': '1.1', 'f64': 2.2, 'nfraction': 3.3, 'bo': true, 'bi': TO_BINARY('616263', 'HEX'), 'date': '2024-03-21'::DATE, 'time': '13:03:02'::TIME, 'ltz': '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz': '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz': '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so': {'s': 'child', 'i': 9}, 'sArr': ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr': ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap': {'x': true, 'y': false}}::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
 			defer rows.Close()
 			rows.Next()
 			var ignore int
@@ -553,10 +572,11 @@ func TestObjectWithAllTypesSimpleScan(t *testing.T) {
 }
 
 func TestNullObjectSimpleScan(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
 			t.Run("null", func(t *testing.T) {
-				rows := dbt.mustQuery("SELECT null::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
+				rows := dbt.mustQueryContextT(ctx, t, "SELECT null::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
 				defer rows.Close()
 				assertTrueF(t, rows.Next())
 				var res *objectWithAllTypesSimpleScan
@@ -565,7 +585,7 @@ func TestNullObjectSimpleScan(t *testing.T) {
 				assertNilE(t, res)
 			})
 			t.Run("not null", func(t *testing.T) {
-				rows := dbt.mustQuery("SELECT {'s': 'some string', 'b': 1, 'i16': 2, 'i32': 3, 'i64': 9223372036854775807, 'f32': '1.1', 'f64': 2.2, 'nfraction': 3.3, 'bo': true, 'bi': TO_BINARY('616263', 'HEX'), 'date': '2024-03-21'::DATE, 'time': '13:03:02'::TIME, 'ltz': '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz': '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz': '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so': {'s': 'child', 'i': 9}, 'sArr': ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr': ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap': {'x': true, 'y': false}}::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
+				rows := dbt.mustQueryContextT(ctx, t, "SELECT {'s': 'some string', 'b': 1, 'i16': 2, 'i32': 3, 'i64': 9223372036854775807, 'f32': '1.1', 'f64': 2.2, 'nfraction': 3.3, 'bo': true, 'bi': TO_BINARY('616263', 'HEX'), 'date': '2024-03-21'::DATE, 'time': '13:03:02'::TIME, 'ltz': '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz': '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz': '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so': {'s': 'child', 'i': 9}, 'sArr': ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr': ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap': {'x': true, 'y': false}}::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 19), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
 				defer rows.Close()
 				assertTrueF(t, rows.Next())
 				var res *objectWithAllTypesSimpleScan
@@ -609,11 +629,12 @@ func (o *objectWithAllTypesNullableSimpleScan) Write(sowc StructuredObjectWriter
 func TestObjectWithAllTypesSimpleScanNullable(t *testing.T) {
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.mustExec("ALTER SESSION SET TIMEZONE = 'Europe/Warsaw'")
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
 			t.Run("null", func(t *testing.T) {
-				rows := dbt.mustQuery("select null, object_construct_keep_null('s', null, 'b', null, 'i16', null, 'i32', null, 'i64', null, 'f64', null, 'bo', null, 'bi', null, 'date', null, 'time', null, 'ltz', null, 'tz', null, 'ntz', null, 'so', null, 'sArr', null, 'f64Arr', null, 'someMap', null)::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f64 DOUBLE, bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
+				rows := dbt.mustQueryContextT(ctx, t, "select null, object_construct_keep_null('s', null, 'b', null, 'i16', null, 'i32', null, 'i64', null, 'f64', null, 'bo', null, 'bi', null, 'date', null, 'time', null, 'ltz', null, 'tz', null, 'ntz', null, 'so', null, 'sArr', null, 'f64Arr', null, 'someMap', null)::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f64 DOUBLE, bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
 				defer rows.Close()
 				rows.Next()
 				var ignore sql.NullInt32
@@ -638,7 +659,7 @@ func TestObjectWithAllTypesSimpleScanNullable(t *testing.T) {
 				assertDeepEqualE(t, res.So, so)
 			})
 			t.Run("not null", func(t *testing.T) {
-				rows := dbt.mustQuery("select 1, object_construct_keep_null('s', 'abc', 'b', 1, 'i16', 2, 'i32', 3, 'i64', 9223372036854775807, 'f64', 2.2, 'bo', true, 'bi', TO_BINARY('616263', 'HEX'), 'date', '2024-03-21'::DATE, 'time', '13:03:02'::TIME, 'ltz', '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz', '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz', '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so', {'s': 'child', 'i': 9}::OBJECT, 'sArr', ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr', ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap', {'x': true, 'y': false})::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f64 DOUBLE, bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
+				rows := dbt.mustQueryContextT(ctx, t, "select 1, object_construct_keep_null('s', 'abc', 'b', 1, 'i16', 2, 'i32', 3, 'i64', 9223372036854775807, 'f64', 2.2, 'bo', true, 'bi', TO_BINARY('616263', 'HEX'), 'date', '2024-03-21'::DATE, 'time', '13:03:02'::TIME, 'ltz', '2021-07-21 11:22:33'::TIMESTAMP_LTZ, 'tz', '2022-08-31 13:43:22 +0200'::TIMESTAMP_TZ, 'ntz', '2023-05-22 01:17:19'::TIMESTAMP_NTZ, 'so', {'s': 'child', 'i': 9}::OBJECT, 'sArr', ARRAY_CONSTRUCT('x', 'y', 'z'), 'f64Arr', ARRAY_CONSTRUCT(1.1, 2.2, 3.3), 'someMap', {'x': true, 'y': false})::OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f64 DOUBLE, bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))")
 				defer rows.Close()
 				rows.Next()
 				var ignore sql.NullInt32
@@ -689,9 +710,10 @@ func (o *objectWithCustomNameAndIgnoredField) Write(sowc StructuredObjectWriterC
 }
 
 func TestObjectWithCustomName(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
-			rows := dbt.mustQuery("SELECT {'anotherName': 'some string'}::OBJECT(anotherName VARCHAR)")
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT {'anotherName': 'some string'}::OBJECT(anotherName VARCHAR)")
 			defer rows.Close()
 			rows.Next()
 			var res objectWithCustomNameAndIgnoredField
@@ -703,10 +725,11 @@ func TestObjectWithCustomName(t *testing.T) {
 	})
 }
 
-func TestObjectMetadata(t *testing.T) {
+func TestObjectMetadataAsObject(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
-			rows := dbt.mustQuery("SELECT {'a': 'b'}::OBJECT(a VARCHAR) as structured_type")
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT {'a': 'b'}::OBJECT(a VARCHAR) as structured_type")
 			defer rows.Close()
 			columnTypes, err := rows.ColumnTypes()
 			assertNilF(t, err)
@@ -718,13 +741,29 @@ func TestObjectMetadata(t *testing.T) {
 	})
 }
 
+func TestObjectMetadataAsString(t *testing.T) {
+	runDBTest(t, func(dbt *DBTest) {
+		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
+			skipForStringingNativeArrow(t, format)
+			rows := dbt.mustQueryT(t, "SELECT {'a': 'b'}::OBJECT(a VARCHAR) as structured_type")
+			defer rows.Close()
+			columnTypes, err := rows.ColumnTypes()
+			assertNilF(t, err)
+			assertEqualE(t, len(columnTypes), 1)
+			assertEqualE(t, columnTypes[0].ScanType(), reflect.TypeOf(""))
+			assertEqualE(t, columnTypes[0].DatabaseTypeName(), "OBJECT")
+			assertEqualE(t, columnTypes[0].Name(), "STRUCTURED_TYPE")
+		})
+	})
+}
+
 func TestObjectWithoutSchema(t *testing.T) {
 	runDBTest(t, func(dbt *DBTest) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
 			if format == "NATIVE_ARROW" {
 				t.Skip("Native arrow is not supported in objects without schema")
 			}
-			rows := dbt.mustQuery("SELECT {'a': 'b'}::OBJECT")
+			rows := dbt.mustQuery("SELECT {'a': 'b'}::OBJECT AS STRUCTURED_TYPE")
 			defer rows.Close()
 			rows.Next()
 			var v string
@@ -753,7 +792,30 @@ func TestObjectWithoutSchemaMetadata(t *testing.T) {
 	})
 }
 
-func TestArrayAndMetadata(t *testing.T) {
+func TestArrayAndMetadataAsString(t *testing.T) {
+	runDBTest(t, func(dbt *DBTest) {
+		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
+			skipForStringingNativeArrow(t, format)
+			rows := dbt.mustQueryT(t, "SELECT ARRAY_CONSTRUCT(1, 2)::ARRAY(INTEGER) AS STRUCTURED_TYPE")
+			defer rows.Close()
+			assertTrueF(t, rows.Next())
+			var res string
+			err := rows.Scan(&res)
+			assertNilF(t, err)
+			assertEqualIgnoringWhitespaceE(t, "[1, 2]", res)
+
+			columnTypes, err := rows.ColumnTypes()
+			assertNilF(t, err)
+			assertEqualE(t, len(columnTypes), 1)
+			assertEqualE(t, columnTypes[0].ScanType(), reflect.TypeOf(""))
+			assertEqualE(t, columnTypes[0].DatabaseTypeName(), "ARRAY")
+			assertEqualE(t, columnTypes[0].Name(), "STRUCTURED_TYPE")
+		})
+	})
+}
+
+func TestArrayAndMetadataAsArray(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
 	runDBTest(t, func(dbt *DBTest) {
@@ -845,7 +907,7 @@ func TestArrayAndMetadata(t *testing.T) {
 			}
 			for _, tc := range testcases {
 				t.Run(tc.name, func(t *testing.T) {
-					rows := dbt.mustQuery(tc.query)
+					rows := dbt.mustQueryContextT(ctx, t, tc.query)
 					defer rows.Close()
 					rows.Next()
 					err := rows.Scan(&tc.actual)
@@ -892,21 +954,25 @@ func TestArrayAndMetadata(t *testing.T) {
 func TestArrayWithoutSchema(t *testing.T) {
 	runDBTest(t, func(dbt *DBTest) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
+			if format == "NATIVE_ARROW" {
+				t.Skip("Native arrow is not supported in arrays without schema")
+			}
 			rows := dbt.mustQuery("SELECT ARRAY_CONSTRUCT(1, 2)")
 			defer rows.Close()
 			rows.Next()
 			var v string
 			err := rows.Scan(&v)
 			assertNilF(t, err)
-			assertStringContainsE(t, v, "1,\n  2")
+			assertEqualIgnoringWhitespaceE(t, v, "[1, 2]")
 		})
 	})
 }
 
 func TestEmptyArraysAndNullArrays(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
-			rows := dbt.mustQuery("SELECT ARRAY_CONSTRUCT(1, 2)::ARRAY(INTEGER) as structured_type UNION SELECT ARRAY_CONSTRUCT()::ARRAY(INTEGER) UNION SELECT NULL UNION SELECT ARRAY_CONSTRUCT(4, 5, 6)::ARRAY(INTEGER)")
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT ARRAY_CONSTRUCT(1, 2)::ARRAY(INTEGER) as structured_type UNION SELECT ARRAY_CONSTRUCT()::ARRAY(INTEGER) UNION SELECT NULL UNION SELECT ARRAY_CONSTRUCT(4, 5, 6)::ARRAY(INTEGER)")
 			defer rows.Close()
 			checkRow := func(rows *RowsExtended, expected *[]int64) {
 				var res *[]int64
@@ -943,9 +1009,10 @@ func TestArrayWithoutSchemaMetadata(t *testing.T) {
 }
 
 func TestArrayOfObjects(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
-			rows := dbt.mustQuery("SELECT ARRAY_CONSTRUCT({'s': 's1', 'i': 9}, {'s': 's2', 'i': 8})::ARRAY(OBJECT(s VARCHAR, i INTEGER)) as structured_type UNION SELECT ARRAY_CONSTRUCT({'s': 's3', 'i': 7})::ARRAY(OBJECT(s VARCHAR, i INTEGER))")
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT ARRAY_CONSTRUCT({'s': 's1', 'i': 9}, {'s': 's2', 'i': 8})::ARRAY(OBJECT(s VARCHAR, i INTEGER)) as structured_type UNION SELECT ARRAY_CONSTRUCT({'s': 's3', 'i': 7})::ARRAY(OBJECT(s VARCHAR, i INTEGER))")
 			defer rows.Close()
 			rows.Next()
 			var res []*simpleObject
@@ -967,6 +1034,7 @@ func TestArrayOfObjects(t *testing.T) {
 }
 
 func TestArrayOfArrays(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
 	testcases := []struct {
@@ -1047,7 +1115,7 @@ func TestArrayOfArrays(t *testing.T) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
 			for _, tc := range testcases {
 				t.Run(tc.name, func(t *testing.T) {
-					rows := dbt.mustQuery(tc.query)
+					rows := dbt.mustQueryContextT(ctx, t, tc.query)
 					defer rows.Close()
 					rows.Next()
 					err := rows.Scan(&tc.actual)
@@ -1073,7 +1141,32 @@ func TestArrayOfArrays(t *testing.T) {
 	})
 }
 
-func TestMapAndMetadata(t *testing.T) {
+func TestMapAndMetadataAsString(t *testing.T) {
+	runDBTest(t, func(dbt *DBTest) {
+		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
+			if format == "NATIVE_ARROW" {
+				t.Skip("Native arrow is not supported in maps without schema")
+			}
+			rows := dbt.mustQuery("SELECT {'a': 'b', 'c': 'd'}::MAP(VARCHAR, VARCHAR) AS STRUCTURED_TYPE")
+			defer rows.Close()
+			assertTrueF(t, rows.Next())
+			var v string
+			err := rows.Scan(&v)
+			assertNilF(t, err)
+			assertEqualIgnoringWhitespaceE(t, v, `{"a": "b", "c": "d"}`)
+
+			columnTypes, err := rows.ColumnTypes()
+			assertNilF(t, err)
+			assertEqualE(t, len(columnTypes), 1)
+			assertEqualE(t, columnTypes[0].ScanType(), reflect.TypeOf(""))
+			assertEqualE(t, columnTypes[0].DatabaseTypeName(), "MAP")
+			assertEqualE(t, columnTypes[0].Name(), "STRUCTURED_TYPE")
+		})
+	})
+}
+
+func TestMapAndMetadataAsMap(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
 	runDBTest(t, func(dbt *DBTest) {
@@ -1257,7 +1350,7 @@ func TestMapAndMetadata(t *testing.T) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
 			for _, tc := range testcases {
 				t.Run(tc.name, func(t *testing.T) {
-					rows := dbt.mustQuery(tc.query)
+					rows := dbt.mustQueryContextT(ctx, t, tc.query)
 					defer rows.Close()
 
 					checkRow := func(expected any) {
@@ -1305,9 +1398,10 @@ func TestMapAndMetadata(t *testing.T) {
 }
 
 func TestMapOfObjects(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
-			rows := dbt.mustQuery("SELECT {'x': {'s': 'abc', 'i': 1}, 'y': {'s': 'def', 'i': 2}}::MAP(VARCHAR, OBJECT(s VARCHAR, i INTEGER))")
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT {'x': {'s': 'abc', 'i': 1}, 'y': {'s': 'def', 'i': 2}}::MAP(VARCHAR, OBJECT(s VARCHAR, i INTEGER))")
 			defer rows.Close()
 			var res map[string]*simpleObject
 			rows.Next()
@@ -1319,6 +1413,7 @@ func TestMapOfObjects(t *testing.T) {
 }
 
 func TestMapOfArrays(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
 	testcases := []struct {
@@ -1399,7 +1494,7 @@ func TestMapOfArrays(t *testing.T) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
 			for _, tc := range testcases {
 				t.Run(tc.name, func(t *testing.T) {
-					rows := dbt.mustQuery(tc.query)
+					rows := dbt.mustQueryContextT(ctx, t, tc.query)
 					defer rows.Close()
 					rows.Next()
 					err := rows.Scan(&tc.actual)
@@ -1426,9 +1521,10 @@ func TestMapOfArrays(t *testing.T) {
 }
 
 func TestNullAndEmptyMaps(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
-			rows := dbt.mustQuery("SELECT {'a': 1}::MAP(VARCHAR, INTEGER) UNION SELECT NULL UNION SELECT {}::MAP(VARCHAR, INTEGER) UNION SELECT {'d': 4}::MAP(VARCHAR, INTEGER)")
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT {'a': 1}::MAP(VARCHAR, INTEGER) UNION SELECT NULL UNION SELECT {}::MAP(VARCHAR, INTEGER) UNION SELECT {'d': 4}::MAP(VARCHAR, INTEGER)")
 			defer rows.Close()
 			checkRow := func(rows *RowsExtended, expected *map[string]int64) {
 				rows.Next()
@@ -1446,6 +1542,7 @@ func TestNullAndEmptyMaps(t *testing.T) {
 }
 
 func TestMapWithNullValues(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
 	testcases := []struct {
@@ -1526,7 +1623,7 @@ func TestMapWithNullValues(t *testing.T) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
 			for _, tc := range testcases {
 				t.Run(tc.name, func(t *testing.T) {
-					rows := dbt.mustQueryContext(WithMapValuesNullable(context.Background()), tc.query)
+					rows := dbt.mustQueryContextT(WithMapValuesNullable(ctx), t, tc.query)
 					defer rows.Close()
 					rows.Next()
 					err := rows.Scan(&tc.actual)
@@ -1570,12 +1667,12 @@ func (hps *HigherPrecisionStruct) Scan(val any) error {
 }
 
 func TestWithHigherPrecision(t *testing.T) {
+	ctx := WithHigherPrecision(WithStructuredTypesEnabled(context.Background()))
 	runDBTest(t, func(dbt *DBTest) {
 		forAllStructureTypeFormats(dbt, func(t *testing.T, format string) {
 			if format != "NATIVE_ARROW" {
 				t.Skip("JSON structured type does not support higher precision")
 			}
-			ctx := WithHigherPrecision(context.Background())
 			t.Run("object", func(t *testing.T) {
 				rows := dbt.mustQueryContext(ctx, "SELECT {'i': 10000000000000000000000000000000000000::DECIMAL(38, 0), 'f': 1.2345678901234567890123456789012345678::DECIMAL(38, 37)}::OBJECT(i DECIMAL(38, 0), f DECIMAL(38, 37)) as structured_type")
 				defer rows.Close()
@@ -2107,3 +2204,9 @@ func TestSelectingSemistructuredTypesInArrowBatches(t *testing.T) {
 
 	})
 }
+
+func skipForStringingNativeArrow(t *testing.T, format string) {
+	if format == "NATIVE_ARROW" {
+		t.Skip("returning native arrow structured types as string is currently not supported")
+	}
+}
diff --git a/structured_type_write_test.go b/structured_type_write_test.go
index c36ef33..2be5e49 100644
--- a/structured_type_write_test.go
+++ b/structured_type_write_test.go
@@ -129,6 +129,7 @@ func TestBindingArrayWithoutSchema(t *testing.T) {
 
 func TestBindingObjectWithSchema(t *testing.T) {
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
+	ctx := WithStructuredTypesEnabled(context.Background())
 	assertNilF(t, err)
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.mustExec("CREATE OR REPLACE TABLE test_object_binding (obj OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 9), bo boolean, bi BINARY, date DATE, time TIME, ltz TIMESTAMPLTZ, ntz TIMESTAMPNTZ, tz TIMESTAMPTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN)))")
@@ -159,8 +160,8 @@ func TestBindingObjectWithSchema(t *testing.T) {
 			f64Arr:    []float64{1.1, 2.2},
 			someMap:   map[string]bool{"a": true, "b": false},
 		}
-		dbt.mustExec("INSERT INTO test_object_binding SELECT (?)", o)
-		rows := dbt.mustQuery("SELECT * FROM test_object_binding WHERE obj = ?", o)
+		dbt.mustExecT(t, "INSERT INTO test_object_binding SELECT (?)", o)
+		rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_object_binding WHERE obj = ?", o)
 		defer rows.Close()
 
 		assertTrueE(t, rows.Next())
@@ -194,6 +195,7 @@ func TestBindingObjectWithSchema(t *testing.T) {
 func TestBindingObjectWithNullableFieldsWithSchema(t *testing.T) {
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.mustExec("CREATE OR REPLACE TABLE test_object_binding (obj OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f64 DOUBLE, bo boolean, bi BINARY, date DATE, time TIME, ltz TIMESTAMPLTZ, ntz TIMESTAMPNTZ, tz TIMESTAMPTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN)))")
 		defer func() {
@@ -223,7 +225,7 @@ func TestBindingObjectWithNullableFieldsWithSchema(t *testing.T) {
 				someMap: map[string]bool{"a": true, "b": false},
 			}
 			dbt.mustExecT(t, "INSERT INTO test_object_binding SELECT (?)", o)
-			rows := dbt.mustQuery("SELECT * FROM test_object_binding WHERE obj = ?", o)
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_object_binding WHERE obj = ?", o)
 			defer rows.Close()
 
 			assertTrueE(t, rows.Next())
@@ -271,7 +273,7 @@ func TestBindingObjectWithNullableFieldsWithSchema(t *testing.T) {
 				someMap: nil,
 			}
 			dbt.mustExecT(t, "INSERT INTO test_object_binding SELECT (?)", o)
-			rows := dbt.mustQuery("SELECT * FROM test_object_binding WHERE obj = ?", o)
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_object_binding WHERE obj = ?", o)
 			defer rows.Close()
 
 			assertTrueE(t, rows.Next())
@@ -304,6 +306,7 @@ func TestBindingObjectWithNullableFieldsWithSchema(t *testing.T) {
 func TestBindingObjectWithSchemaSimpleWrite(t *testing.T) {
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.mustExec("CREATE OR REPLACE TABLE test_object_binding (obj OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 9), bo BOOLEAN, bi BINARY, date DATE, time TIME, ltz TIMESTAMP_LTZ, tz TIMESTAMP_TZ, ntz TIMESTAMP_NTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN)))")
 		defer func() {
@@ -333,8 +336,8 @@ func TestBindingObjectWithSchemaSimpleWrite(t *testing.T) {
 			F64Arr:    []float64{1.1, 2.2},
 			SomeMap:   map[string]bool{"a": true, "b": false},
 		}
-		dbt.mustExec("INSERT INTO test_object_binding SELECT (?)", o)
-		rows := dbt.mustQuery("SELECT * FROM test_object_binding WHERE obj = ?", o)
+		dbt.mustExecT(t, "INSERT INTO test_object_binding SELECT (?)", o)
+		rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_object_binding WHERE obj = ?", o)
 		defer rows.Close()
 
 		assertTrueE(t, rows.Next())
@@ -368,6 +371,7 @@ func TestBindingObjectWithSchemaSimpleWrite(t *testing.T) {
 func TestBindingObjectWithNullableFieldsWithSchemaSimpleWrite(t *testing.T) {
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.forceJSON()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_object_binding (obj OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f64 DOUBLE, bo boolean, bi BINARY, date DATE, time TIME, ltz TIMESTAMPLTZ, tz TIMESTAMPTZ, ntz TIMESTAMPNTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN)))")
@@ -398,7 +402,7 @@ func TestBindingObjectWithNullableFieldsWithSchemaSimpleWrite(t *testing.T) {
 				SomeMap: map[string]bool{"a": true, "b": false},
 			}
 			dbt.mustExecT(t, "INSERT INTO test_object_binding SELECT (?)", o)
-			rows := dbt.mustQuery("SELECT * FROM test_object_binding WHERE obj = ?", o)
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_object_binding WHERE obj = ?", o)
 			defer rows.Close()
 
 			assertTrueE(t, rows.Next())
@@ -446,7 +450,7 @@ func TestBindingObjectWithNullableFieldsWithSchemaSimpleWrite(t *testing.T) {
 				SomeMap: nil,
 			}
 			dbt.mustExecT(t, "INSERT INTO test_object_binding SELECT (?)", o)
-			rows := dbt.mustQuery("SELECT * FROM test_object_binding WHERE obj = ?", o)
+			rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_object_binding WHERE obj = ?", o)
 			defer rows.Close()
 
 			assertTrueE(t, rows.Next())
@@ -496,6 +500,7 @@ func (o *objectWithAllTypesWrapper) Write(sowc StructuredObjectWriterContext) er
 }
 
 func TestBindingObjectWithAllTypesNullable(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.forceJSON()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_object_binding (o OBJECT(o OBJECT(s VARCHAR, b TINYINT, i16 SMALLINT, i32 INTEGER, i64 BIGINT, f32 FLOAT, f64 DOUBLE, nfraction NUMBER(38, 9), bo boolean, bi BINARY, date DATE, time TIME, ltz TIMESTAMPLTZ, tz TIMESTAMPTZ, ntz TIMESTAMPNTZ, so OBJECT(s VARCHAR, i INTEGER), sArr ARRAY(VARCHAR), f64Arr ARRAY(DOUBLE), someMap MAP(VARCHAR, BOOLEAN))))")
@@ -507,7 +512,7 @@ func TestBindingObjectWithAllTypesNullable(t *testing.T) {
 		dbt.mustExec("ALTER SESSION SET TIMESTAMP_OUTPUT_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF9 TZHTZM'")
 		o := &objectWithAllTypesWrapper{}
 		dbt.mustExec("INSERT INTO test_object_binding SELECT (?)", o)
-		rows := dbt.mustQuery("SELECT * FROM test_object_binding WHERE o = ?", o)
+		rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_object_binding WHERE o = ?", o)
 		defer rows.Close()
 
 		assertTrueE(t, rows.Next())
@@ -519,6 +524,7 @@ func TestBindingObjectWithAllTypesNullable(t *testing.T) {
 }
 
 func TestBindingObjectWithSchemaWithCustomNameAndIgnoredField(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.mustExec("CREATE OR REPLACE TABLE test_object_binding (obj OBJECT(anotherName VARCHAR))")
 		defer func() {
@@ -530,7 +536,7 @@ func TestBindingObjectWithSchemaWithCustomNameAndIgnoredField(t *testing.T) {
 			IgnoreMe:   "ignore me",
 		}
 		dbt.mustExec("INSERT INTO test_object_binding SELECT (?)", o)
-		rows := dbt.mustQuery("SELECT * FROM test_object_binding WHERE obj = ?", o)
+		rows := dbt.mustQueryContext(ctx, "SELECT * FROM test_object_binding WHERE obj = ?", o)
 		defer rows.Close()
 
 		assertTrueE(t, rows.Next())
@@ -543,6 +549,7 @@ func TestBindingObjectWithSchemaWithCustomNameAndIgnoredField(t *testing.T) {
 }
 
 func TestBindingNullStructuredObjects(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.mustExec("CREATE OR REPLACE TABLE test_object_binding (obj OBJECT(s VARCHAR, i INTEGER))")
 		defer func() {
@@ -551,7 +558,7 @@ func TestBindingNullStructuredObjects(t *testing.T) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("INSERT INTO test_object_binding SELECT (?)", DataTypeNilObject, reflect.TypeOf(simpleObject{}))
 
-		rows := dbt.mustQuery("SELECT * FROM test_object_binding")
+		rows := dbt.mustQueryContext(ctx, "SELECT * FROM test_object_binding")
 		defer rows.Close()
 
 		assertTrueE(t, rows.Next())
@@ -563,6 +570,7 @@ func TestBindingNullStructuredObjects(t *testing.T) {
 }
 
 func TestBindingArrayWithSchema(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		testcases := []struct {
@@ -653,7 +661,7 @@ func TestBindingArrayWithSchema(t *testing.T) {
 
 				dbt.mustExecT(t, "INSERT INTO test_array_binding SELECT (?)", tc.values...)
 
-				rows := dbt.mustQueryT(t, "SELECT * FROM test_array_binding")
+				rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_array_binding")
 				defer rows.Close()
 
 				assertTrueE(t, rows.Next())
@@ -667,6 +675,7 @@ func TestBindingArrayWithSchema(t *testing.T) {
 }
 
 func TestBindingArrayOfObjects(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_array_binding (arr ARRAY(OBJECT(s VARCHAR, i INTEGER)))")
@@ -677,7 +686,7 @@ func TestBindingArrayOfObjects(t *testing.T) {
 		arr := []*simpleObject{{s: "some string", i: 123}}
 		dbt.mustExec("INSERT INTO test_array_binding SELECT (?)", arr)
 
-		rows := dbt.mustQuery("SELECT * FROM test_array_binding WHERE arr = ?", arr)
+		rows := dbt.mustQueryContext(ctx, "SELECT * FROM test_array_binding WHERE arr = ?", arr)
 		defer rows.Close()
 
 		assertTrueE(t, rows.Next())
@@ -689,6 +698,7 @@ func TestBindingArrayOfObjects(t *testing.T) {
 }
 
 func TestBindingEmptyArrayOfObjects(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_array_binding (arr ARRAY(OBJECT(s VARCHAR, i INTEGER)))")
@@ -699,7 +709,7 @@ func TestBindingEmptyArrayOfObjects(t *testing.T) {
 		arr := []*simpleObject{}
 		dbt.mustExec("INSERT INTO test_array_binding SELECT (?)", arr)
 
-		rows := dbt.mustQuery("SELECT * FROM test_array_binding WHERE arr = ?", arr)
+		rows := dbt.mustQueryContext(ctx, "SELECT * FROM test_array_binding WHERE arr = ?", arr)
 		defer rows.Close()
 
 		assertTrueF(t, rows.Next())
@@ -711,6 +721,7 @@ func TestBindingEmptyArrayOfObjects(t *testing.T) {
 }
 
 func TestBindingNilArrayOfObjects(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_array_binding (arr ARRAY(OBJECT(s VARCHAR, i INTEGER)))")
@@ -721,7 +732,7 @@ func TestBindingNilArrayOfObjects(t *testing.T) {
 		var arr []*simpleObject
 		dbt.mustExec("INSERT INTO test_array_binding SELECT (?)", DataTypeNilArray, reflect.TypeOf(simpleObject{}))
 
-		rows := dbt.mustQuery("SELECT * FROM test_array_binding")
+		rows := dbt.mustQueryContext(ctx, "SELECT * FROM test_array_binding")
 		defer rows.Close()
 
 		assertTrueF(t, rows.Next())
@@ -733,6 +744,7 @@ func TestBindingNilArrayOfObjects(t *testing.T) {
 }
 
 func TestBindingNilArrayOfInts(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_array_binding (arr ARRAY(INTEGER))")
@@ -743,7 +755,7 @@ func TestBindingNilArrayOfInts(t *testing.T) {
 		var arr *[]int64
 		dbt.mustExec("INSERT INTO test_array_binding SELECT (?)", DataTypeNilArray, reflect.TypeOf(1))
 
-		rows := dbt.mustQuery("SELECT * FROM test_array_binding")
+		rows := dbt.mustQueryContext(ctx, "SELECT * FROM test_array_binding")
 		defer rows.Close()
 
 		assertTrueF(t, rows.Next())
@@ -757,6 +769,7 @@ func TestBindingNilArrayOfInts(t *testing.T) {
 func TestBindingMap(t *testing.T) {
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
+	ctx := WithStructuredTypesEnabled(context.Background())
 	testcases := []struct {
 		tableDefinition string
 		values          []any
@@ -909,7 +922,7 @@ func TestBindingMap(t *testing.T) {
 
 				dbt.mustExecT(t, "INSERT INTO test_map_binding SELECT (?)", tc.values...)
 
-				rows := dbt.mustQueryT(t, "SELECT * FROM test_map_binding WHERE m = ?", tc.values...)
+				rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_map_binding WHERE m = ?", tc.values...)
 				defer rows.Close()
 
 				assertTrueE(t, rows.Next())
@@ -936,6 +949,7 @@ func TestBindingMap(t *testing.T) {
 }
 
 func TestBindingMapOfStructs(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_map_binding (m MAP(VARCHAR, OBJECT(s VARCHAR, i INTEGER)))")
@@ -949,7 +963,7 @@ func TestBindingMapOfStructs(t *testing.T) {
 		}
 
 		dbt.mustExecT(t, "INSERT INTO test_map_binding SELECT ?", m)
-		rows := dbt.mustQueryT(t, "SELECT * FROM test_map_binding WHERE m = ?", m)
+		rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_map_binding WHERE m = ?", m)
 		defer rows.Close()
 
 		rows.Next()
@@ -961,6 +975,7 @@ func TestBindingMapOfStructs(t *testing.T) {
 }
 
 func TestBindingMapOfWithAllValuesNil(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_map_binding (m MAP(VARCHAR, OBJECT(s VARCHAR, i INTEGER)))")
@@ -972,7 +987,7 @@ func TestBindingMapOfWithAllValuesNil(t *testing.T) {
 		}
 
 		dbt.mustExecT(t, "INSERT INTO test_map_binding SELECT ?", m)
-		rows := dbt.mustQueryT(t, "SELECT * FROM test_map_binding WHERE m = ?", m)
+		rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_map_binding WHERE m = ?", m)
 		defer rows.Close()
 
 		rows.Next()
@@ -984,6 +999,7 @@ func TestBindingMapOfWithAllValuesNil(t *testing.T) {
 }
 
 func TestBindingEmptyMapOfStructs(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_map_binding (m MAP(VARCHAR, OBJECT(s VARCHAR, i INTEGER)))")
@@ -993,7 +1009,7 @@ func TestBindingEmptyMapOfStructs(t *testing.T) {
 
 		m := map[string]*simpleObject{}
 		dbt.mustExecT(t, "INSERT INTO test_map_binding SELECT ?", m)
-		rows := dbt.mustQueryT(t, "SELECT * FROM test_map_binding WHERE m = ?", m)
+		rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_map_binding WHERE m = ?", m)
 		defer rows.Close()
 
 		assertTrueF(t, rows.Next())
@@ -1005,6 +1021,7 @@ func TestBindingEmptyMapOfStructs(t *testing.T) {
 }
 
 func TestBindingEmptyMapOfInts(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_map_binding (m MAP(VARCHAR, INTEGER))")
@@ -1014,7 +1031,7 @@ func TestBindingEmptyMapOfInts(t *testing.T) {
 
 		m := map[string]int64{}
 		dbt.mustExecT(t, "INSERT INTO test_map_binding SELECT ?", m)
-		rows := dbt.mustQueryT(t, "SELECT * FROM test_map_binding WHERE m = ?", m)
+		rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_map_binding WHERE m = ?", m)
 		defer rows.Close()
 
 		assertTrueF(t, rows.Next())
@@ -1026,6 +1043,7 @@ func TestBindingEmptyMapOfInts(t *testing.T) {
 }
 
 func TestBindingNilMapOfStructs(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_map_binding (m MAP(VARCHAR, OBJECT(s VARCHAR, i INTEGER)))")
@@ -1035,7 +1053,7 @@ func TestBindingNilMapOfStructs(t *testing.T) {
 
 		var m map[string]*simpleObject
 		dbt.mustExecT(t, "INSERT INTO test_map_binding SELECT ?", DataTypeNilMap, NilMapTypes{Key: reflect.TypeOf(""), Value: reflect.TypeOf(&simpleObject{})})
-		rows := dbt.mustQueryT(t, "SELECT * FROM test_map_binding", DataTypeNilMap, NilMapTypes{Key: reflect.TypeOf(""), Value: reflect.TypeOf(&simpleObject{})})
+		rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_map_binding", DataTypeNilMap, NilMapTypes{Key: reflect.TypeOf(""), Value: reflect.TypeOf(&simpleObject{})})
 		defer rows.Close()
 
 		assertTrueF(t, rows.Next())
@@ -1047,6 +1065,7 @@ func TestBindingNilMapOfStructs(t *testing.T) {
 }
 
 func TestBindingNilMapOfInts(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_map_binding (m MAP(VARCHAR, INTEGER))")
@@ -1056,7 +1075,7 @@ func TestBindingNilMapOfInts(t *testing.T) {
 
 		var m *map[string]int64
 		dbt.mustExecT(t, "INSERT INTO test_map_binding SELECT ?", DataTypeNilMap, NilMapTypes{Key: reflect.TypeOf(""), Value: reflect.TypeOf(1)})
-		rows := dbt.mustQueryT(t, "SELECT * FROM test_map_binding", DataTypeNilMap, NilMapTypes{Key: reflect.TypeOf(""), Value: reflect.TypeOf(1)})
+		rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_map_binding", DataTypeNilMap, NilMapTypes{Key: reflect.TypeOf(""), Value: reflect.TypeOf(1)})
 		defer rows.Close()
 
 		assertTrueF(t, rows.Next())
@@ -1068,6 +1087,7 @@ func TestBindingNilMapOfInts(t *testing.T) {
 }
 
 func TestBindingMapOfArrays(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	runDBTest(t, func(dbt *DBTest) {
 		dbt.enableStructuredTypesBinding()
 		dbt.mustExec("CREATE OR REPLACE TABLE test_map_binding (m MAP(VARCHAR, ARRAY(INTEGER)))")
@@ -1080,7 +1100,7 @@ func TestBindingMapOfArrays(t *testing.T) {
 			"b": nil,
 		}
 		dbt.mustExecT(t, "INSERT INTO test_map_binding SELECT ?", m)
-		rows := dbt.mustQueryT(t, "SELECT * FROM test_map_binding", m)
+		rows := dbt.mustQueryContextT(ctx, t, "SELECT * FROM test_map_binding", m)
 		defer rows.Close()
 
 		assertTrueF(t, rows.Next())
@@ -1092,6 +1112,7 @@ func TestBindingMapOfArrays(t *testing.T) {
 }
 
 func TestBindingMapWithNillableValues(t *testing.T) {
+	ctx := WithStructuredTypesEnabled(context.Background())
 	warsawTz, err := time.LoadLocation("Europe/Warsaw")
 	assertNilF(t, err)
 	var testcases = []struct {
@@ -1246,7 +1267,7 @@ func TestBindingMapWithNillableValues(t *testing.T) {
 
 				dbt.mustExecT(t, "INSERT INTO test_map_binding SELECT (?)", tc.values...)
 
-				rows := dbt.mustQueryContextT(WithMapValuesNullable(context.Background()), t, "SELECT * FROM test_map_binding WHERE m = ?", tc.values...)
+				rows := dbt.mustQueryContextT(WithMapValuesNullable(ctx), t, "SELECT * FROM test_map_binding WHERE m = ?", tc.values...)
 				defer rows.Close()
 
 				assertTrueE(t, rows.Next())