...

Source file src/github.com/jackc/pgtype/tid.go

Documentation: github.com/jackc/pgtype

     1  package pgtype
     2  
     3  import (
     4  	"database/sql/driver"
     5  	"encoding/binary"
     6  	"fmt"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/jackc/pgio"
    11  )
    12  
    13  // TID is PostgreSQL's Tuple Identifier type.
    14  //
    15  // When one does
    16  //
    17  // 	select ctid, * from some_table;
    18  //
    19  // it is the data type of the ctid hidden system column.
    20  //
    21  // It is currently implemented as a pair unsigned two byte integers.
    22  // Its conversion functions can be found in src/backend/utils/adt/tid.c
    23  // in the PostgreSQL sources.
    24  type TID struct {
    25  	BlockNumber  uint32
    26  	OffsetNumber uint16
    27  	Status       Status
    28  }
    29  
    30  func (dst *TID) Set(src interface{}) error {
    31  	return fmt.Errorf("cannot convert %v to TID", src)
    32  }
    33  
    34  func (dst TID) Get() interface{} {
    35  	switch dst.Status {
    36  	case Present:
    37  		return dst
    38  	case Null:
    39  		return nil
    40  	default:
    41  		return dst.Status
    42  	}
    43  }
    44  
    45  func (src *TID) AssignTo(dst interface{}) error {
    46  	if src.Status == Present {
    47  		switch v := dst.(type) {
    48  		case *string:
    49  			*v = fmt.Sprintf(`(%d,%d)`, src.BlockNumber, src.OffsetNumber)
    50  			return nil
    51  		default:
    52  			if nextDst, retry := GetAssignToDstType(dst); retry {
    53  				return src.AssignTo(nextDst)
    54  			}
    55  			return fmt.Errorf("unable to assign to %T", dst)
    56  		}
    57  	}
    58  
    59  	return fmt.Errorf("cannot assign %v to %T", src, dst)
    60  }
    61  
    62  func (dst *TID) DecodeText(ci *ConnInfo, src []byte) error {
    63  	if src == nil {
    64  		*dst = TID{Status: Null}
    65  		return nil
    66  	}
    67  
    68  	if len(src) < 5 {
    69  		return fmt.Errorf("invalid length for tid: %v", len(src))
    70  	}
    71  
    72  	parts := strings.SplitN(string(src[1:len(src)-1]), ",", 2)
    73  	if len(parts) < 2 {
    74  		return fmt.Errorf("invalid format for tid")
    75  	}
    76  
    77  	blockNumber, err := strconv.ParseUint(parts[0], 10, 32)
    78  	if err != nil {
    79  		return err
    80  	}
    81  
    82  	offsetNumber, err := strconv.ParseUint(parts[1], 10, 16)
    83  	if err != nil {
    84  		return err
    85  	}
    86  
    87  	*dst = TID{BlockNumber: uint32(blockNumber), OffsetNumber: uint16(offsetNumber), Status: Present}
    88  	return nil
    89  }
    90  
    91  func (dst *TID) DecodeBinary(ci *ConnInfo, src []byte) error {
    92  	if src == nil {
    93  		*dst = TID{Status: Null}
    94  		return nil
    95  	}
    96  
    97  	if len(src) != 6 {
    98  		return fmt.Errorf("invalid length for tid: %v", len(src))
    99  	}
   100  
   101  	*dst = TID{
   102  		BlockNumber:  binary.BigEndian.Uint32(src),
   103  		OffsetNumber: binary.BigEndian.Uint16(src[4:]),
   104  		Status:       Present,
   105  	}
   106  	return nil
   107  }
   108  
   109  func (src TID) EncodeText(ci *ConnInfo, buf []byte) ([]byte, error) {
   110  	switch src.Status {
   111  	case Null:
   112  		return nil, nil
   113  	case Undefined:
   114  		return nil, errUndefined
   115  	}
   116  
   117  	buf = append(buf, fmt.Sprintf(`(%d,%d)`, src.BlockNumber, src.OffsetNumber)...)
   118  	return buf, nil
   119  }
   120  
   121  func (src TID) EncodeBinary(ci *ConnInfo, buf []byte) ([]byte, error) {
   122  	switch src.Status {
   123  	case Null:
   124  		return nil, nil
   125  	case Undefined:
   126  		return nil, errUndefined
   127  	}
   128  
   129  	buf = pgio.AppendUint32(buf, src.BlockNumber)
   130  	buf = pgio.AppendUint16(buf, src.OffsetNumber)
   131  	return buf, nil
   132  }
   133  
   134  // Scan implements the database/sql Scanner interface.
   135  func (dst *TID) Scan(src interface{}) error {
   136  	if src == nil {
   137  		*dst = TID{Status: Null}
   138  		return nil
   139  	}
   140  
   141  	switch src := src.(type) {
   142  	case string:
   143  		return dst.DecodeText(nil, []byte(src))
   144  	case []byte:
   145  		srcCopy := make([]byte, len(src))
   146  		copy(srcCopy, src)
   147  		return dst.DecodeText(nil, srcCopy)
   148  	}
   149  
   150  	return fmt.Errorf("cannot scan %T", src)
   151  }
   152  
   153  // Value implements the database/sql/driver Valuer interface.
   154  func (src TID) Value() (driver.Value, error) {
   155  	return EncodeValueText(src)
   156  }
   157  

View as plain text