1package pgx 2 3import ( 4 "math" 5 "reflect" 6 "time" 7 8 "github.com/jackc/pgx/pgio" 9 "github.com/jackc/pgx/pgtype" 10) 11 12const ( 13 copyData = 'd' 14 copyFail = 'f' 15 copyDone = 'c' 16 varHeaderSize = 4 17) 18 19type FieldDescription struct { 20 Name string 21 Table pgtype.OID 22 AttributeNumber uint16 23 DataType pgtype.OID 24 DataTypeSize int16 25 DataTypeName string 26 Modifier uint32 27 FormatCode int16 28} 29 30func (fd FieldDescription) Length() (int64, bool) { 31 switch fd.DataType { 32 case pgtype.TextOID, pgtype.ByteaOID: 33 return math.MaxInt64, true 34 case pgtype.VarcharOID, pgtype.BPCharArrayOID: 35 return int64(fd.Modifier - varHeaderSize), true 36 default: 37 return 0, false 38 } 39} 40 41func (fd FieldDescription) PrecisionScale() (precision, scale int64, ok bool) { 42 switch fd.DataType { 43 case pgtype.NumericOID: 44 mod := fd.Modifier - varHeaderSize 45 precision = int64((mod >> 16) & 0xffff) 46 scale = int64(mod & 0xffff) 47 return precision, scale, true 48 default: 49 return 0, 0, false 50 } 51} 52 53func (fd FieldDescription) Type() reflect.Type { 54 switch fd.DataType { 55 case pgtype.Int8OID: 56 return reflect.TypeOf(int64(0)) 57 case pgtype.Int4OID: 58 return reflect.TypeOf(int32(0)) 59 case pgtype.Int2OID: 60 return reflect.TypeOf(int16(0)) 61 case pgtype.VarcharOID, pgtype.BPCharArrayOID, pgtype.TextOID: 62 return reflect.TypeOf("") 63 case pgtype.BoolOID: 64 return reflect.TypeOf(false) 65 case pgtype.NumericOID: 66 return reflect.TypeOf(float64(0)) 67 case pgtype.DateOID, pgtype.TimestampOID, pgtype.TimestamptzOID: 68 return reflect.TypeOf(time.Time{}) 69 case pgtype.ByteaOID: 70 return reflect.TypeOf([]byte(nil)) 71 default: 72 return reflect.TypeOf(new(interface{})).Elem() 73 } 74} 75 76// PgError represents an error reported by the PostgreSQL server. See 77// http://www.postgresql.org/docs/9.3/static/protocol-error-fields.html for 78// detailed field description. 79type PgError struct { 80 Severity string 81 Code string 82 Message string 83 Detail string 84 Hint string 85 Position int32 86 InternalPosition int32 87 InternalQuery string 88 Where string 89 SchemaName string 90 TableName string 91 ColumnName string 92 DataTypeName string 93 ConstraintName string 94 File string 95 Line int32 96 Routine string 97} 98 99func (pe PgError) Error() string { 100 return pe.Severity + ": " + pe.Message + " (SQLSTATE " + pe.Code + ")" 101} 102 103// Notice represents a notice response message reported by the PostgreSQL 104// server. Be aware that this is distinct from LISTEN/NOTIFY notification. 105type Notice PgError 106 107// appendParse appends a PostgreSQL wire protocol parse message to buf and returns it. 108func appendParse(buf []byte, name string, query string, parameterOIDs []pgtype.OID) []byte { 109 buf = append(buf, 'P') 110 sp := len(buf) 111 buf = pgio.AppendInt32(buf, -1) 112 buf = append(buf, name...) 113 buf = append(buf, 0) 114 buf = append(buf, query...) 115 buf = append(buf, 0) 116 117 buf = pgio.AppendInt16(buf, int16(len(parameterOIDs))) 118 for _, oid := range parameterOIDs { 119 buf = pgio.AppendUint32(buf, uint32(oid)) 120 } 121 pgio.SetInt32(buf[sp:], int32(len(buf[sp:]))) 122 123 return buf 124} 125 126// appendDescribe appends a PostgreSQL wire protocol describe message to buf and returns it. 127func appendDescribe(buf []byte, objectType byte, name string) []byte { 128 buf = append(buf, 'D') 129 sp := len(buf) 130 buf = pgio.AppendInt32(buf, -1) 131 buf = append(buf, objectType) 132 buf = append(buf, name...) 133 buf = append(buf, 0) 134 pgio.SetInt32(buf[sp:], int32(len(buf[sp:]))) 135 136 return buf 137} 138 139// appendSync appends a PostgreSQL wire protocol sync message to buf and returns it. 140func appendSync(buf []byte) []byte { 141 buf = append(buf, 'S') 142 buf = pgio.AppendInt32(buf, 4) 143 144 return buf 145} 146 147// appendBind appends a PostgreSQL wire protocol bind message to buf and returns it. 148func appendBind( 149 buf []byte, 150 destinationPortal, 151 preparedStatement string, 152 connInfo *pgtype.ConnInfo, 153 parameterOIDs []pgtype.OID, 154 arguments []interface{}, 155 resultFormatCodes []int16, 156) ([]byte, error) { 157 buf = append(buf, 'B') 158 sp := len(buf) 159 buf = pgio.AppendInt32(buf, -1) 160 buf = append(buf, destinationPortal...) 161 buf = append(buf, 0) 162 buf = append(buf, preparedStatement...) 163 buf = append(buf, 0) 164 165 buf = pgio.AppendInt16(buf, int16(len(parameterOIDs))) 166 for i, oid := range parameterOIDs { 167 buf = pgio.AppendInt16(buf, chooseParameterFormatCode(connInfo, oid, arguments[i])) 168 } 169 170 buf = pgio.AppendInt16(buf, int16(len(arguments))) 171 for i, oid := range parameterOIDs { 172 var err error 173 buf, err = encodePreparedStatementArgument(connInfo, buf, oid, arguments[i]) 174 if err != nil { 175 return nil, err 176 } 177 } 178 179 buf = pgio.AppendInt16(buf, int16(len(resultFormatCodes))) 180 for _, fc := range resultFormatCodes { 181 buf = pgio.AppendInt16(buf, fc) 182 } 183 pgio.SetInt32(buf[sp:], int32(len(buf[sp:]))) 184 185 return buf, nil 186} 187 188// appendExecute appends a PostgreSQL wire protocol execute message to buf and returns it. 189func appendExecute(buf []byte, portal string, maxRows uint32) []byte { 190 buf = append(buf, 'E') 191 sp := len(buf) 192 buf = pgio.AppendInt32(buf, -1) 193 194 buf = append(buf, portal...) 195 buf = append(buf, 0) 196 buf = pgio.AppendUint32(buf, maxRows) 197 198 pgio.SetInt32(buf[sp:], int32(len(buf[sp:]))) 199 200 return buf 201} 202 203// appendQuery appends a PostgreSQL wire protocol query message to buf and returns it. 204func appendQuery(buf []byte, query string) []byte { 205 buf = append(buf, 'Q') 206 sp := len(buf) 207 buf = pgio.AppendInt32(buf, -1) 208 buf = append(buf, query...) 209 buf = append(buf, 0) 210 pgio.SetInt32(buf[sp:], int32(len(buf[sp:]))) 211 212 return buf 213} 214