From 02deabf4a68b0049623cb638896c1c7225196ea7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Ferr=C3=A3o?= Date: Thu, 22 Aug 2024 15:05:09 +0100 Subject: [PATCH] Support for UDT (hierarchyid, geometry and geography) (#216) * Accept hierarchyid as a valid type * error * derp * geography and geometry * Return value * Tests * Typo * Upper * hasSize --- queries_test.go | 4 ++++ types.go | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/queries_test.go b/queries_test.go index 679ae184..533d3c4e 100644 --- a/queries_test.go +++ b/queries_test.go @@ -135,6 +135,7 @@ func TestSelect(t *testing.T) { {"cast(cast('abc' as varchar(3)) as sql_variant)", "abc"}, {"cast(cast('abc' as char(3)) as sql_variant)", "abc"}, {"cast(N'abc' as sql_variant)", "abc"}, + {"cast('/' as hierarchyid)", []byte{}}, } for _, test := range values { @@ -1682,6 +1683,9 @@ func TestColumnTypeIntrospection(t *testing.T) { {"cast('abc' as char(3))", "CHAR", reflect.TypeOf(""), true, 3, false, 0, 0}, {"cast(N'abc' as nchar(3))", "NCHAR", reflect.TypeOf(""), true, 3, false, 0, 0}, {"cast(1 as sql_variant)", "SQL_VARIANT", reflect.TypeOf(nil), false, 0, false, 0, 0}, + {"geometry::STGeomFromText('LINESTRING (100 100, 20 180, 180 180)', 0)", "GEOMETRY", reflect.TypeOf([]byte{}), true, 2147483647, false, 0, 0}, + {"geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656 )', 4326)", "GEOGRAPHY", reflect.TypeOf([]byte{}), false, 2147483647, false, 0, 0}, + {"cast('/1/2/3/' as hierarchyid)", "HIERARCHYID", reflect.TypeOf([]byte{}), true, 892, false, 0, 0}, } conn, logger := open(t) defer conn.Close() diff --git a/types.go b/types.go index ac99e92e..8f5ad9b9 100644 --- a/types.go +++ b/types.go @@ -8,6 +8,7 @@ import ( "math" "reflect" "strconv" + "strings" "time" "github.com/microsoft/go-mssqldb/internal/cp" @@ -1137,6 +1138,8 @@ func makeGoLangScanType(ti typeInfo) reflect.Type { return reflect.TypeOf([]byte{}) case typeVariant: return reflect.TypeOf(nil) + case typeUdt: + return reflect.TypeOf([]byte{}) default: panic(fmt.Sprintf("not implemented makeGoLangScanType for type %d", ti.TypeId)) } @@ -1366,6 +1369,8 @@ func makeGoLangTypeName(ti typeInfo) string { return "SQL_VARIANT" case typeBigBinary: return "BINARY" + case typeUdt: + return strings.ToUpper(ti.UdtInfo.TypeName) default: panic(fmt.Sprintf("not implemented makeGoLangTypeName for type %d", ti.TypeId)) } @@ -1490,9 +1495,22 @@ func makeGoLangTypeLength(ti typeInfo) (int64, bool) { return 0, false case typeBigBinary: return int64(ti.Size), true + case typeUdt: + switch ti.UdtInfo.TypeName { + case "hierarchyid": + // https://learn.microsoft.com/en-us/sql/t-sql/data-types/hierarchyid-data-type-method-reference?view=sql-server-ver16 + return 892, true + case "geography": + case "geometry": + return 2147483647, true + default: + panic(fmt.Sprintf("not implemented makeGoLangTypeLength for user defined type %s", ti.UdtInfo.TypeName)) + } default: panic(fmt.Sprintf("not implemented makeGoLangTypeLength for type %d", ti.TypeId)) } + + return 0, false } // makes go/sql type precision and scale as described below @@ -1602,6 +1620,8 @@ func makeGoLangTypePrecisionScale(ti typeInfo) (int64, int64, bool) { return 0, 0, false case typeBigBinary: return 0, 0, false + case typeUdt: + return 0, 0, false default: panic(fmt.Sprintf("not implemented makeGoLangTypePrecisionScale for type %d", ti.TypeId)) }