@@ -2,21 +2,24 @@ package pgx
22
33import (
44 "database/sql/driver"
5+ "encoding/binary"
56 "fmt"
7+ "slices"
68
79 "github.com/jackc/pgx/v5"
810 "github.com/jackc/pgx/v5/pgtype"
911 "github.com/pgvector/pgvector-go"
12+ "github.com/x448/float16"
1013)
1114
1215type HalfVectorCodec struct {}
1316
1417func (HalfVectorCodec ) FormatSupported (format int16 ) bool {
15- return format == pgx .TextFormatCode
18+ return format == pgx .BinaryFormatCode || format == pgx . TextFormatCode
1619}
1720
1821func (HalfVectorCodec ) PreferredFormat () int16 {
19- return pgx .TextFormatCode
22+ return pgx .BinaryFormatCode
2023}
2124
2225func (HalfVectorCodec ) PlanEncode (m * pgtype.Map , oid uint32 , format int16 , value any ) pgtype.EncodePlan {
@@ -25,35 +28,76 @@ func (HalfVectorCodec) PlanEncode(m *pgtype.Map, oid uint32, format int16, value
2528 return nil
2629 }
2730
28- if format == pgx .TextFormatCode {
31+ switch format {
32+ case pgx .BinaryFormatCode :
33+ return encodePlanHalfVectorCodecBinary {}
34+ case pgx .TextFormatCode :
2935 return encodePlanHalfVectorCodecText {}
3036 }
3137
3238 return nil
3339}
3440
41+ type encodePlanHalfVectorCodecBinary struct {}
42+
43+ func (encodePlanHalfVectorCodecBinary ) Encode (value any , buf []byte ) (newBuf []byte , err error ) {
44+ v := value .(pgvector.HalfVector )
45+ vec := v .Slice ()
46+ dim := len (vec )
47+ buf = slices .Grow (buf , 4 + 2 * dim )
48+ buf = binary .BigEndian .AppendUint16 (buf , uint16 (dim ))
49+ buf = binary .BigEndian .AppendUint16 (buf , 0 )
50+ for _ , v := range vec {
51+ buf = binary .BigEndian .AppendUint16 (buf , float16 .Fromfloat32 (v ).Bits ())
52+ }
53+ return buf , nil
54+ }
55+
3556type encodePlanHalfVectorCodecText struct {}
3657
3758func (encodePlanHalfVectorCodecText ) Encode (value any , buf []byte ) (newBuf []byte , err error ) {
3859 v := value .(pgvector.HalfVector )
3960 return v .EncodeText (buf )
4061}
4162
42- type scanPlanHalfVectorCodecText struct {}
43-
4463func (HalfVectorCodec ) PlanScan (m * pgtype.Map , oid uint32 , format int16 , target any ) pgtype.ScanPlan {
4564 _ , ok := target .(* pgvector.HalfVector )
4665 if ! ok {
4766 return nil
4867 }
4968
50- if format == pgx .TextFormatCode {
69+ switch format {
70+ case pgx .BinaryFormatCode :
71+ return scanPlanHalfVectorCodecBinary {}
72+ case pgx .TextFormatCode :
5173 return scanPlanHalfVectorCodecText {}
5274 }
5375
5476 return nil
5577}
5678
79+ type scanPlanHalfVectorCodecBinary struct {}
80+
81+ func (scanPlanHalfVectorCodecBinary ) Scan (src []byte , dst any ) error {
82+ v := (dst ).(* pgvector.HalfVector )
83+ buf := src
84+ dim := int (binary .BigEndian .Uint16 (buf [0 :2 ]))
85+ unused := binary .BigEndian .Uint16 (buf [2 :4 ])
86+ if unused != 0 {
87+ return fmt .Errorf ("expected unused to be 0" )
88+ }
89+
90+ vec := make ([]float32 , 0 , dim )
91+ offset := 4
92+ for i := 0 ; i < dim ; i ++ {
93+ vec = append (vec , float16 .Frombits (binary .BigEndian .Uint16 (buf [offset :offset + 2 ])).Float32 ())
94+ offset += 2
95+ }
96+ return v .Scan (vec )
97+ }
98+
99+ type scanPlanHalfVectorCodecText struct {}
100+
57101func (scanPlanHalfVectorCodecText ) Scan (src []byte , dst any ) error {
58102 v := (dst ).(* pgvector.HalfVector )
59103 return v .Scan (src )
0 commit comments