From 9913ce3864504f54a521f8e54e02e9710189262e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ng=C3=B4=20Qu=E1=BB=91c=20=C4=90=E1=BA=A1t?= Date: Tue, 31 Mar 2026 13:47:50 +0700 Subject: [PATCH 1/2] fix: set UTF-8 client charset for SQL Server connections --- CHANGELOG.md | 1 + Plugins/MSSQLDriverPlugin/CFreeTDS/include/sybdb.h | 1 + Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift | 7 +++++-- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8e91eda13..037221cab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed +- SQL Server: Unicode characters (Thai, CJK, etc.) in nvarchar/nchar/ntext columns displaying as question marks - Globe+F (fn+F) fullscreen shortcut not working in SwiftUI lifecycle app ## [0.26.0] - 2026-03-29 diff --git a/Plugins/MSSQLDriverPlugin/CFreeTDS/include/sybdb.h b/Plugins/MSSQLDriverPlugin/CFreeTDS/include/sybdb.h index 21a772d35..e09e109ae 100644 --- a/Plugins/MSSQLDriverPlugin/CFreeTDS/include/sybdb.h +++ b/Plugins/MSSQLDriverPlugin/CFreeTDS/include/sybdb.h @@ -49,6 +49,7 @@ typedef struct loginrec LOGINREC; #define DBSETUSER 2 #define DBSETPWD 3 #define DBSETAPP 5 // 4 is unused; real FreeTDS DBSETAPP = 5 +#define DBSETCHARSET 7 // Client charset for dbsetlname() — controls string encoding // Convenience macros (match FreeTDS sybdb.h) #define DBSETLHOST(x, y) dbsetlname((x), (y), DBSETHOST) diff --git a/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift b/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift index 4299f181e..2adddf9ea 100644 --- a/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift +++ b/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift @@ -196,6 +196,7 @@ private final class FreeTDSConnection: @unchecked Sendable { _ = dbsetlname(login, user, Int32(DBSETUSER)) _ = dbsetlname(login, password, Int32(DBSETPWD)) _ = dbsetlname(login, "TablePro", Int32(DBSETAPP)) + _ = dbsetlname(login, "UTF-8", Int32(DBSETCHARSET)) _ = dbsetlversion(login, UInt8(DBVERSION_74)) freetdsLastError = "" @@ -371,8 +372,10 @@ private final class FreeTDSConnection: @unchecked Sendable { return String(bytes: UnsafeBufferPointer(start: ptr, count: Int(srcLen)), encoding: .utf8) ?? String(bytes: UnsafeBufferPointer(start: ptr, count: Int(srcLen)), encoding: .isoLatin1) case Int32(SYBNCHAR), Int32(SYBNVARCHAR), Int32(SYBNTEXT): - let data = Data(bytes: ptr, count: Int(srcLen)) - return String(data: data, encoding: .utf16LittleEndian) + // With client charset UTF-8, FreeTDS converts UTF-16 wire data to UTF-8 + // but may still report the original nvarchar type token + return String(bytes: UnsafeBufferPointer(start: ptr, count: Int(srcLen)), encoding: .utf8) + ?? String(data: Data(bytes: ptr, count: Int(srcLen)), encoding: .utf16LittleEndian) default: let bufSize: DBINT = 64 var buf = [BYTE](repeating: 0, count: Int(bufSize)) From 8152f8b7852d9e47cd73c7937b9db62a16f85b92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ng=C3=B4=20Qu=E1=BB=91c=20=C4=90=E1=BA=A1t?= Date: Tue, 31 Mar 2026 13:50:49 +0700 Subject: [PATCH 2/2] fix: increase dbconvert buffer to handle multi-byte UTF-8 output --- Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift b/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift index 2adddf9ea..d31469650 100644 --- a/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift +++ b/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift @@ -377,7 +377,7 @@ private final class FreeTDSConnection: @unchecked Sendable { return String(bytes: UnsafeBufferPointer(start: ptr, count: Int(srcLen)), encoding: .utf8) ?? String(data: Data(bytes: ptr, count: Int(srcLen)), encoding: .utf16LittleEndian) default: - let bufSize: DBINT = 64 + let bufSize: DBINT = 256 var buf = [BYTE](repeating: 0, count: Int(bufSize)) let converted = buf.withUnsafeMutableBufferPointer { bufPtr in dbconvert(proc, srcType, ptr, srcLen, Int32(SYBCHAR), bufPtr.baseAddress, bufSize)