...

Source file src/github.com/jackc/pgproto3/v2/row_description.go

Documentation: github.com/jackc/pgproto3/v2

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

View as plain text