gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

row_description.go (4388B)


      1 package pgproto3
      2 
      3 import (
      4 	"bytes"
      5 	"encoding/binary"
      6 	"encoding/json"
      7 
      8 	"github.com/jackc/pgx/v5/internal/pgio"
      9 )
     10 
     11 const (
     12 	TextFormat   = 0
     13 	BinaryFormat = 1
     14 )
     15 
     16 type FieldDescription struct {
     17 	Name                 []byte
     18 	TableOID             uint32
     19 	TableAttributeNumber uint16
     20 	DataTypeOID          uint32
     21 	DataTypeSize         int16
     22 	TypeModifier         int32
     23 	Format               int16
     24 }
     25 
     26 // MarshalJSON implements encoding/json.Marshaler.
     27 func (fd FieldDescription) MarshalJSON() ([]byte, error) {
     28 	return json.Marshal(struct {
     29 		Name                 string
     30 		TableOID             uint32
     31 		TableAttributeNumber uint16
     32 		DataTypeOID          uint32
     33 		DataTypeSize         int16
     34 		TypeModifier         int32
     35 		Format               int16
     36 	}{
     37 		Name:                 string(fd.Name),
     38 		TableOID:             fd.TableOID,
     39 		TableAttributeNumber: fd.TableAttributeNumber,
     40 		DataTypeOID:          fd.DataTypeOID,
     41 		DataTypeSize:         fd.DataTypeSize,
     42 		TypeModifier:         fd.TypeModifier,
     43 		Format:               fd.Format,
     44 	})
     45 }
     46 
     47 type RowDescription struct {
     48 	Fields []FieldDescription
     49 }
     50 
     51 // Backend identifies this message as sendable by the PostgreSQL backend.
     52 func (*RowDescription) Backend() {}
     53 
     54 // Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
     55 // type identifier and 4 byte message length.
     56 func (dst *RowDescription) Decode(src []byte) error {
     57 
     58 	if len(src) < 2 {
     59 		return &invalidMessageFormatErr{messageType: "RowDescription"}
     60 	}
     61 	fieldCount := int(binary.BigEndian.Uint16(src))
     62 	rp := 2
     63 
     64 	dst.Fields = dst.Fields[0:0]
     65 
     66 	for i := 0; i < fieldCount; i++ {
     67 		var fd FieldDescription
     68 
     69 		idx := bytes.IndexByte(src[rp:], 0)
     70 		if idx < 0 {
     71 			return &invalidMessageFormatErr{messageType: "RowDescription"}
     72 		}
     73 		fd.Name = src[rp : rp+idx]
     74 		rp += idx + 1
     75 
     76 		// Since buf.Next() doesn't return an error if we hit the end of the buffer
     77 		// check Len ahead of time
     78 		if len(src[rp:]) < 18 {
     79 			return &invalidMessageFormatErr{messageType: "RowDescription"}
     80 		}
     81 
     82 		fd.TableOID = binary.BigEndian.Uint32(src[rp:])
     83 		rp += 4
     84 		fd.TableAttributeNumber = binary.BigEndian.Uint16(src[rp:])
     85 		rp += 2
     86 		fd.DataTypeOID = binary.BigEndian.Uint32(src[rp:])
     87 		rp += 4
     88 		fd.DataTypeSize = int16(binary.BigEndian.Uint16(src[rp:]))
     89 		rp += 2
     90 		fd.TypeModifier = int32(binary.BigEndian.Uint32(src[rp:]))
     91 		rp += 4
     92 		fd.Format = int16(binary.BigEndian.Uint16(src[rp:]))
     93 		rp += 2
     94 
     95 		dst.Fields = append(dst.Fields, fd)
     96 	}
     97 
     98 	return nil
     99 }
    100 
    101 // Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
    102 func (src *RowDescription) Encode(dst []byte) []byte {
    103 	dst = append(dst, 'T')
    104 	sp := len(dst)
    105 	dst = pgio.AppendInt32(dst, -1)
    106 
    107 	dst = pgio.AppendUint16(dst, uint16(len(src.Fields)))
    108 	for _, fd := range src.Fields {
    109 		dst = append(dst, fd.Name...)
    110 		dst = append(dst, 0)
    111 
    112 		dst = pgio.AppendUint32(dst, fd.TableOID)
    113 		dst = pgio.AppendUint16(dst, fd.TableAttributeNumber)
    114 		dst = pgio.AppendUint32(dst, fd.DataTypeOID)
    115 		dst = pgio.AppendInt16(dst, fd.DataTypeSize)
    116 		dst = pgio.AppendInt32(dst, fd.TypeModifier)
    117 		dst = pgio.AppendInt16(dst, fd.Format)
    118 	}
    119 
    120 	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
    121 
    122 	return dst
    123 }
    124 
    125 // MarshalJSON implements encoding/json.Marshaler.
    126 func (src RowDescription) MarshalJSON() ([]byte, error) {
    127 	return json.Marshal(struct {
    128 		Type   string
    129 		Fields []FieldDescription
    130 	}{
    131 		Type:   "RowDescription",
    132 		Fields: src.Fields,
    133 	})
    134 }
    135 
    136 // UnmarshalJSON implements encoding/json.Unmarshaler.
    137 func (dst *RowDescription) UnmarshalJSON(data []byte) error {
    138 	var msg struct {
    139 		Fields []struct {
    140 			Name                 string
    141 			TableOID             uint32
    142 			TableAttributeNumber uint16
    143 			DataTypeOID          uint32
    144 			DataTypeSize         int16
    145 			TypeModifier         int32
    146 			Format               int16
    147 		}
    148 	}
    149 	if err := json.Unmarshal(data, &msg); err != nil {
    150 		return err
    151 	}
    152 	dst.Fields = make([]FieldDescription, len(msg.Fields))
    153 	for n, field := range msg.Fields {
    154 		dst.Fields[n] = FieldDescription{
    155 			Name:                 []byte(field.Name),
    156 			TableOID:             field.TableOID,
    157 			TableAttributeNumber: field.TableAttributeNumber,
    158 			DataTypeOID:          field.DataTypeOID,
    159 			DataTypeSize:         field.DataTypeSize,
    160 			TypeModifier:         field.TypeModifier,
    161 			Format:               field.Format,
    162 		}
    163 	}
    164 	return nil
    165 }