github.com/jackc/pgx/v5@v5.5.5/pgtype/bytea.go (about) 1 package pgtype 2 3 import ( 4 "database/sql/driver" 5 "encoding/hex" 6 "fmt" 7 ) 8 9 type BytesScanner interface { 10 // ScanBytes receives a byte slice of driver memory that is only valid until the next database method call. 11 ScanBytes(v []byte) error 12 } 13 14 type BytesValuer interface { 15 // BytesValue returns a byte slice of the byte data. The caller must not change the returned slice. 16 BytesValue() ([]byte, error) 17 } 18 19 // DriverBytes is a byte slice that holds a reference to memory owned by the driver. It is only valid from the time it 20 // is scanned until Rows.Next or Rows.Close is called. It is never safe to use DriverBytes with QueryRow as Row.Scan 21 // internally calls Rows.Close before returning. 22 type DriverBytes []byte 23 24 func (b *DriverBytes) ScanBytes(v []byte) error { 25 *b = v 26 return nil 27 } 28 29 // PreallocBytes is a byte slice of preallocated memory that scanned bytes will be copied to. If it is too small a new 30 // slice will be allocated. 31 type PreallocBytes []byte 32 33 func (b *PreallocBytes) ScanBytes(v []byte) error { 34 if v == nil { 35 *b = nil 36 return nil 37 } 38 39 if len(v) <= len(*b) { 40 *b = (*b)[:len(v)] 41 } else { 42 *b = make(PreallocBytes, len(v)) 43 } 44 copy(*b, v) 45 return nil 46 } 47 48 // UndecodedBytes can be used as a scan target to get the raw bytes from PostgreSQL without any decoding. 49 type UndecodedBytes []byte 50 51 type scanPlanAnyToUndecodedBytes struct{} 52 53 func (scanPlanAnyToUndecodedBytes) Scan(src []byte, dst any) error { 54 dstBuf := dst.(*UndecodedBytes) 55 if src == nil { 56 *dstBuf = nil 57 return nil 58 } 59 60 *dstBuf = make([]byte, len(src)) 61 copy(*dstBuf, src) 62 return nil 63 } 64 65 type ByteaCodec struct{} 66 67 func (ByteaCodec) FormatSupported(format int16) bool { 68 return format == TextFormatCode || format == BinaryFormatCode 69 } 70 71 func (ByteaCodec) PreferredFormat() int16 { 72 return BinaryFormatCode 73 } 74 75 func (ByteaCodec) PlanEncode(m *Map, oid uint32, format int16, value any) EncodePlan { 76 switch format { 77 case BinaryFormatCode: 78 switch value.(type) { 79 case []byte: 80 return encodePlanBytesCodecBinaryBytes{} 81 case BytesValuer: 82 return encodePlanBytesCodecBinaryBytesValuer{} 83 } 84 case TextFormatCode: 85 switch value.(type) { 86 case []byte: 87 return encodePlanBytesCodecTextBytes{} 88 case BytesValuer: 89 return encodePlanBytesCodecTextBytesValuer{} 90 } 91 } 92 93 return nil 94 } 95 96 type encodePlanBytesCodecBinaryBytes struct{} 97 98 func (encodePlanBytesCodecBinaryBytes) Encode(value any, buf []byte) (newBuf []byte, err error) { 99 b := value.([]byte) 100 if b == nil { 101 return nil, nil 102 } 103 104 return append(buf, b...), nil 105 } 106 107 type encodePlanBytesCodecBinaryBytesValuer struct{} 108 109 func (encodePlanBytesCodecBinaryBytesValuer) Encode(value any, buf []byte) (newBuf []byte, err error) { 110 b, err := value.(BytesValuer).BytesValue() 111 if err != nil { 112 return nil, err 113 } 114 if b == nil { 115 return nil, nil 116 } 117 118 return append(buf, b...), nil 119 } 120 121 type encodePlanBytesCodecTextBytes struct{} 122 123 func (encodePlanBytesCodecTextBytes) Encode(value any, buf []byte) (newBuf []byte, err error) { 124 b := value.([]byte) 125 if b == nil { 126 return nil, nil 127 } 128 129 buf = append(buf, `\x`...) 130 buf = append(buf, hex.EncodeToString(b)...) 131 return buf, nil 132 } 133 134 type encodePlanBytesCodecTextBytesValuer struct{} 135 136 func (encodePlanBytesCodecTextBytesValuer) Encode(value any, buf []byte) (newBuf []byte, err error) { 137 b, err := value.(BytesValuer).BytesValue() 138 if err != nil { 139 return nil, err 140 } 141 if b == nil { 142 return nil, nil 143 } 144 145 buf = append(buf, `\x`...) 146 buf = append(buf, hex.EncodeToString(b)...) 147 return buf, nil 148 } 149 150 func (ByteaCodec) PlanScan(m *Map, oid uint32, format int16, target any) ScanPlan { 151 152 switch format { 153 case BinaryFormatCode: 154 switch target.(type) { 155 case *[]byte: 156 return scanPlanBinaryBytesToBytes{} 157 case BytesScanner: 158 return scanPlanBinaryBytesToBytesScanner{} 159 } 160 case TextFormatCode: 161 switch target.(type) { 162 case *[]byte: 163 return scanPlanTextByteaToBytes{} 164 case BytesScanner: 165 return scanPlanTextByteaToBytesScanner{} 166 } 167 } 168 169 return nil 170 } 171 172 type scanPlanBinaryBytesToBytes struct{} 173 174 func (scanPlanBinaryBytesToBytes) Scan(src []byte, dst any) error { 175 dstBuf := dst.(*[]byte) 176 if src == nil { 177 *dstBuf = nil 178 return nil 179 } 180 181 *dstBuf = make([]byte, len(src)) 182 copy(*dstBuf, src) 183 return nil 184 } 185 186 type scanPlanBinaryBytesToBytesScanner struct{} 187 188 func (scanPlanBinaryBytesToBytesScanner) Scan(src []byte, dst any) error { 189 scanner := (dst).(BytesScanner) 190 return scanner.ScanBytes(src) 191 } 192 193 type scanPlanTextByteaToBytes struct{} 194 195 func (scanPlanTextByteaToBytes) Scan(src []byte, dst any) error { 196 dstBuf := dst.(*[]byte) 197 if src == nil { 198 *dstBuf = nil 199 return nil 200 } 201 202 buf, err := decodeHexBytea(src) 203 if err != nil { 204 return err 205 } 206 *dstBuf = buf 207 208 return nil 209 } 210 211 type scanPlanTextByteaToBytesScanner struct{} 212 213 func (scanPlanTextByteaToBytesScanner) Scan(src []byte, dst any) error { 214 scanner := (dst).(BytesScanner) 215 buf, err := decodeHexBytea(src) 216 if err != nil { 217 return err 218 } 219 return scanner.ScanBytes(buf) 220 } 221 222 func decodeHexBytea(src []byte) ([]byte, error) { 223 if src == nil { 224 return nil, nil 225 } 226 227 if len(src) < 2 || src[0] != '\\' || src[1] != 'x' { 228 return nil, fmt.Errorf("invalid hex format") 229 } 230 231 buf := make([]byte, (len(src)-2)/2) 232 _, err := hex.Decode(buf, src[2:]) 233 if err != nil { 234 return nil, err 235 } 236 237 return buf, nil 238 } 239 240 func (c ByteaCodec) DecodeDatabaseSQLValue(m *Map, oid uint32, format int16, src []byte) (driver.Value, error) { 241 return c.DecodeValue(m, oid, format, src) 242 } 243 244 func (c ByteaCodec) DecodeValue(m *Map, oid uint32, format int16, src []byte) (any, error) { 245 if src == nil { 246 return nil, nil 247 } 248 249 var buf []byte 250 err := codecScan(c, m, oid, format, src, &buf) 251 if err != nil { 252 return nil, err 253 } 254 return buf, nil 255 }