From aea310a3dd795457be66641ed820cab0ae966464 Mon Sep 17 00:00:00 2001 From: Kylesoda <249518290+kylesoda@users.noreply.github.com> Date: Tue, 7 Apr 2026 10:05:45 -0500 Subject: [PATCH] feat: add WKB to EWKB conversion with SRID handling and integrate into MSSQL transformation --- cmd/go_migrate/mssql-transform.go | 38 ++++++++++++++++++++ cmd/go_migrate/process.go | 6 +++- scripts/wkb-to-ewkb/main.go | 59 +++++++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 scripts/wkb-to-ewkb/main.go diff --git a/cmd/go_migrate/mssql-transform.go b/cmd/go_migrate/mssql-transform.go index 930ee2d..9f73468 100644 --- a/cmd/go_migrate/mssql-transform.go +++ b/cmd/go_migrate/mssql-transform.go @@ -1,5 +1,9 @@ package main +import ( + "encoding/binary" +) + func mssqlUuidToBigEndian(mssqlUuid []byte) []byte { if len(mssqlUuid) != 16 { return mssqlUuid @@ -12,3 +16,37 @@ func mssqlUuidToBigEndian(mssqlUuid []byte) []byte { return pgUuid } + +const sridFlag = 0x20000000 + +func wkbToEwkbWithSrid(geometry []byte, srid int) []byte { + if len(geometry) < 5 { + return geometry + } + + var byteOrder binary.ByteOrder + if geometry[0] == 0 { + byteOrder = binary.BigEndian + } else { + byteOrder = binary.LittleEndian + } + + wkbType := byteOrder.Uint32(geometry[1:5]) + if wkbType&sridFlag != 0 { + return geometry + } + + ewkbType := wkbType | sridFlag + + result := make([]byte, len(geometry)+4) + + result[0] = geometry[0] + + byteOrder.PutUint32(result[1:5], ewkbType) + + byteOrder.PutUint32(result[5:9], uint32(srid)) + + copy(result[9:], geometry[5:]) + + return result +} diff --git a/cmd/go_migrate/process.go b/cmd/go_migrate/process.go index 01cc1e4..5f49d47 100644 --- a/cmd/go_migrate/process.go +++ b/cmd/go_migrate/process.go @@ -79,6 +79,10 @@ func transformRowsMssql(columns []ColumnType, in <-chan []UnknownRowValues, out if b, ok := value.([]byte); ok { rowValues[i] = mssqlUuidToBigEndian(b) } + } else if col.SystemType() == "geometry" || col.SystemType() == "geography" { + if b, ok := value.([]byte); ok { + rowValues[i] = wkbToEwkbWithSrid(b, 4326) + } } } } @@ -90,7 +94,7 @@ func transformRowsMssql(columns []ColumnType, in <-chan []UnknownRowValues, out func logSampleRow(job MigrationJob, columns []ColumnType, rowValues UnknownRowValues, tag string) { log.Infof("[%s.%s] Sample row: (%s)", job.Schema, job.Table, tag) for i, col := range columns { - log.Infof("%s: %v", col.Name(), rowValues[i]) + log.Infof("%s (%T): %v", col.Name(), rowValues[i], rowValues[i]) } } diff --git a/scripts/wkb-to-ewkb/main.go b/scripts/wkb-to-ewkb/main.go new file mode 100644 index 0000000..81491f3 --- /dev/null +++ b/scripts/wkb-to-ewkb/main.go @@ -0,0 +1,59 @@ +package main + +import ( + "encoding/binary" + "fmt" +) + +const sridFlag = 0x20000000 + +func wkbToEwkbWithSrid(geometry []byte, srid int) []byte { + if len(geometry) < 5 { + return geometry + } + + var byteOrder binary.ByteOrder + if geometry[0] == 0 { + byteOrder = binary.BigEndian + } else { + byteOrder = binary.LittleEndian + } + + wkbType := byteOrder.Uint32(geometry[1:5]) + if wkbType&sridFlag != 0 { + return geometry + } + + ewkbType := wkbType | sridFlag + + result := make([]byte, len(geometry)+4) + + result[0] = geometry[0] + + byteOrder.PutUint32(result[1:5], ewkbType) + + byteOrder.PutUint32(result[5:9], uint32(srid)) + + copy(result[9:], geometry[5:]) + + return result +} + +func main() { + shape := []byte{ + 1, 3, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 217, 61, 121, 88, 168, 57, 83, 192, + 60, 78, 209, 145, 92, 222, 39, 192, 232, 106, 43, 246, 151, 57, 83, 192, + 60, 78, 209, 145, 92, 222, 39, 192, 232, 106, 43, 246, 151, 57, 83, 192, + 174, 182, 98, 127, 217, 221, 39, 192, 217, 61, 121, 88, 168, 57, 83, 192, + 174, 182, 98, 127, 217, 221, 39, 192, 217, 61, 121, 88, 168, 57, 83, 192, + 60, 78, 209, 145, 92, 222, 39, 192, + } + + srid := 4326 + result := wkbToEwkbWithSrid(shape, srid) + + fmt.Printf("WKB Original (len): %d\n", len(shape)) + fmt.Printf("EWKB Result (len): %d\n", len(result)) + fmt.Printf("Primeros bytes (original): %v\n", shape[:10]) + fmt.Printf("Primeros bytes (resultado): %v\n", result[:10]) +}