Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
87 changes: 87 additions & 0 deletions charset.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
package firebirdsql

import (
"golang.org/x/text/encoding"
"golang.org/x/text/encoding/charmap"
"golang.org/x/text/encoding/japanese"
"golang.org/x/text/encoding/korean"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/encoding/traditionalchinese"
)
Comment on lines +1 to +10
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

New file charset.go is missing the repository’s standard MIT license header comment block that appears at the top of most non-test .go files (e.g., xsqlvar.go, wireprotocol.go). Please add the same header here to keep file headers consistent.

Copilot uses AI. Check for mistakes.

func charsetEncoding(charset string) encoding.Encoding {
switch charset {
case "SJIS_0208":
return japanese.ShiftJIS
case "EUCJ_0208":
return japanese.EUCJP
case "ISO8859_1":
return charmap.ISO8859_1
case "ISO8859_2":
return charmap.ISO8859_2
case "ISO8859_3":
return charmap.ISO8859_3
case "ISO8859_4":
return charmap.ISO8859_4
case "ISO8859_5":
return charmap.ISO8859_5
case "ISO8859_6":
return charmap.ISO8859_6
case "ISO8859_7":
return charmap.ISO8859_7
case "ISO8859_8":
return charmap.ISO8859_8
case "ISO8859_9":
return charmap.ISO8859_9
case "ISO8859_13":
return charmap.ISO8859_13
case "KSC_5601":
return korean.EUCKR
case "WIN1250":
return charmap.Windows1250
case "WIN1251":
return charmap.Windows1251
case "WIN1252":
return charmap.Windows1252
case "WIN1253":
return charmap.Windows1253
case "WIN1254":
return charmap.Windows1254
case "BIG_5":
return traditionalchinese.Big5
case "GB_2312":
return simplifiedchinese.HZGB2312
case "WIN1255":
return charmap.Windows1255
case "WIN1256":
return charmap.Windows1256
case "WIN1257":
return charmap.Windows1257
case "KOI8R":
return charmap.KOI8R
case "KOI8U":
return charmap.KOI8U
case "WIN1258":
return charmap.Windows1258
default:
return nil
}
}

func decodeCharset(raw []byte, charset string) (string, bool) {
enc := charsetEncoding(charset)
if enc == nil {
return "", false
}
Comment on lines +71 to +75
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

decodeCharset/encodeCharset introduce new shared charset conversion behavior, but there are no unit tests validating that supported charsets round-trip correctly (and that unsupported charsets return ok=false). Adding a small table-driven test for a few representative charsets (e.g., ISO8859_1, WIN1252, SJIS_0208) would help prevent regressions in future refactors.

Copilot uses AI. Check for mistakes.
v, _ := enc.NewDecoder().Bytes(raw)
return string(v), true
}

func encodeCharset(str string, charset string) (string, bool) {
enc := charsetEncoding(charset)
if enc == nil {
return "", false
}
v, _ := enc.NewEncoder().String(str)
return v, true
}
117 changes: 2 additions & 115 deletions wireprotocol.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,6 @@ import (
"github.com/kardianos/osext"
"gitlab.com/nyarla/go-crypt"
"golang.org/x/exp/slices"
"golang.org/x/text/encoding/charmap"
"golang.org/x/text/encoding/japanese"
"golang.org/x/text/encoding/korean"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/encoding/traditionalchinese"
// "unsafe"
)

Expand Down Expand Up @@ -1529,118 +1524,10 @@ func (p *wireProtocol) opCancel(kind int) error {
}

func (p *wireProtocol) encodeString(str string) string {
switch p.charset {
case "OCTETS":
return str
case "UNICODE_FSS", "UTF8":
return str
case "SJIS_0208":
enc := japanese.ShiftJIS.NewEncoder()
v, _ := enc.String(str)
return v
case "EUCJ_0208":
enc := japanese.EUCJP.NewEncoder()
v, _ := enc.String(str)
return v
case "ISO8859_1":
enc := charmap.ISO8859_1.NewEncoder()
v, _ := enc.String(str)
return v
case "ISO8859_2":
enc := charmap.ISO8859_2.NewEncoder()
v, _ := enc.String(str)
return v
case "ISO8859_3":
enc := charmap.ISO8859_3.NewEncoder()
v, _ := enc.String(str)
return v
case "ISO8859_4":
enc := charmap.ISO8859_4.NewEncoder()
v, _ := enc.String(str)
return v
case "ISO8859_5":
enc := charmap.ISO8859_5.NewEncoder()
v, _ := enc.String(str)
return v
case "ISO8859_6":
enc := charmap.ISO8859_6.NewEncoder()
v, _ := enc.String(str)
return v
case "ISO8859_7":
enc := charmap.ISO8859_7.NewEncoder()
v, _ := enc.String(str)
return v
case "ISO8859_8":
enc := charmap.ISO8859_8.NewEncoder()
v, _ := enc.String(str)
return v
case "ISO8859_9":
enc := charmap.ISO8859_9.NewEncoder()
v, _ := enc.String(str)
return v
case "ISO8859_13":
enc := charmap.ISO8859_13.NewEncoder()
v, _ := enc.String(str)
return v
case "KSC_5601":
enc := korean.EUCKR.NewEncoder()
v, _ := enc.String(str)
if v, ok := encodeCharset(str, p.charset); ok {
return v
case "WIN1250":
enc := charmap.Windows1250.NewEncoder()
v, _ := enc.String(str)
return v
case "WIN1251":
enc := charmap.Windows1251.NewEncoder()
v, _ := enc.String(str)
return v
case "WIN1252":
enc := charmap.Windows1252.NewEncoder()
v, _ := enc.String(str)
return v
case "WIN1253":
enc := charmap.Windows1253.NewEncoder()
v, _ := enc.String(str)
return v
case "WIN1254":
enc := charmap.Windows1254.NewEncoder()
v, _ := enc.String(str)
return v
case "BIG_5":
enc := traditionalchinese.Big5.NewEncoder()
v, _ := enc.String(str)
return v
case "GB_2312":
enc := simplifiedchinese.HZGB2312.NewEncoder()
v, _ := enc.String(str)
return v
case "WIN1255":
enc := charmap.Windows1255.NewEncoder()
v, _ := enc.String(str)
return v
case "WIN1256":
enc := charmap.Windows1256.NewEncoder()
v, _ := enc.String(str)
return v
case "WIN1257":
enc := charmap.Windows1257.NewEncoder()
v, _ := enc.String(str)
return v
case "KOI8R":
enc := charmap.KOI8R.NewEncoder()
v, _ := enc.String(str)
return v
case "KOI8U":
enc := charmap.KOI8U.NewEncoder()
v, _ := enc.String(str)
return v
case "WIN1258":
enc := charmap.Windows1258.NewEncoder()
v, _ := enc.String(str)
return v
default:
return str // If the specified charset is not supported, return the input string without any modification or encoding.
}
return str
}

func (p *wireProtocol) opServiceAttach() error {
Expand Down
124 changes: 7 additions & 117 deletions xsqlvar.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,6 @@ import (
"bytes"
"encoding/binary"
"github.com/shopspring/decimal"
"golang.org/x/text/encoding/charmap"
"golang.org/x/text/encoding/japanese"
"golang.org/x/text/encoding/korean"
"golang.org/x/text/encoding/simplifiedchinese"
"golang.org/x/text/encoding/traditionalchinese"
"math"
"math/big"
"reflect"
Expand Down Expand Up @@ -319,121 +314,16 @@ func (x *xSQLVAR) parseTimestampTz(raw_value []byte) time.Time {
}

func (x *xSQLVAR) parseString(raw_value []byte, charset string) interface{} {
if x.sqlsubtype == 1 { // OCTETS
if x.sqlsubtype == 1 || charset == "OCTETS" {
return raw_value
}
switch charset {
case "OCTETS":
return raw_value
case "UNICODE_FSS", "UTF8":
return bytes.NewBuffer(raw_value).String()
case "SJIS_0208":
dec := japanese.ShiftJIS.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "EUCJ_0208":
dec := japanese.EUCJP.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "ISO8859_1":
dec := charmap.ISO8859_1.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "ISO8859_2":
dec := charmap.ISO8859_2.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "ISO8859_3":
dec := charmap.ISO8859_3.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "ISO8859_4":
dec := charmap.ISO8859_4.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "ISO8859_5":
dec := charmap.ISO8859_5.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "ISO8859_6":
dec := charmap.ISO8859_6.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "ISO8859_7":
dec := charmap.ISO8859_7.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "ISO8859_8":
dec := charmap.ISO8859_8.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "ISO8859_9":
dec := charmap.ISO8859_9.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "ISO8859_13":
dec := charmap.ISO8859_13.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "KSC_5601":
dec := korean.EUCKR.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "WIN1250":
dec := charmap.Windows1250.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "WIN1251":
dec := charmap.Windows1251.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "WIN1252":
dec := charmap.Windows1252.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "WIN1253":
dec := charmap.Windows1253.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "WIN1254":
dec := charmap.Windows1254.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "BIG_5":
dec := traditionalchinese.Big5.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "GB_2312":
dec := simplifiedchinese.HZGB2312.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "WIN1255":
dec := charmap.Windows1255.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "WIN1256":
dec := charmap.Windows1256.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "WIN1257":
dec := charmap.Windows1257.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "KOI8R":
dec := charmap.KOI8R.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "KOI8U":
dec := charmap.KOI8U.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
case "WIN1258":
dec := charmap.Windows1258.NewDecoder()
v, _ := dec.Bytes(raw_value)
return string(v)
default:
return raw_value
if charset == "UNICODE_FSS" || charset == "UTF8" {
return string(raw_value)
}
if v, ok := decodeCharset(raw_value, charset); ok {
return v
}
return raw_value
}

func (x *xSQLVAR) value(raw_value []byte, timezone string, charset string) (v interface{}, err error) {
Expand Down
Loading