2
0

Avoid allocating strings in common message types

This commit is contained in:
Jack Christensen
2019-01-01 13:47:37 -06:00
parent 4f0658d52b
commit 356a6c43d2
6 changed files with 45 additions and 51 deletions
+1 -1
View File
@@ -959,7 +959,7 @@ func (c *Conn) rxReadyForQuery(msg *pgproto3.ReadyForQuery) {
func (c *Conn) rxRowDescription(msg *pgproto3.RowDescription) []FieldDescription { func (c *Conn) rxRowDescription(msg *pgproto3.RowDescription) []FieldDescription {
fields := make([]FieldDescription, len(msg.Fields)) fields := make([]FieldDescription, len(msg.Fields))
for i := 0; i < len(fields); i++ { for i := 0; i < len(fields); i++ {
fields[i].Name = msg.Fields[i].Name fields[i].Name = string(msg.Fields[i].Name)
fields[i].Table = pgtype.OID(msg.Fields[i].TableOID) fields[i].Table = pgtype.OID(msg.Fields[i].TableOID)
fields[i].AttributeNumber = msg.Fields[i].TableAttributeNumber fields[i].AttributeNumber = msg.Fields[i].TableAttributeNumber
fields[i].DataType = pgtype.OID(msg.Fields[i].DataTypeOID) fields[i].DataType = pgtype.OID(msg.Fields[i].DataTypeOID)
+28 -34
View File
@@ -199,25 +199,7 @@ func connect(ctx context.Context, config *Config, fallbackConfig *FallbackConfig
// handled by ReceiveMessage // handled by ReceiveMessage
case *pgproto3.ErrorResponse: case *pgproto3.ErrorResponse:
pgConn.conn.Close() pgConn.conn.Close()
return nil, &PgError{ return nil, errorResponseToPgError(msg)
Severity: msg.Severity,
Code: msg.Code,
Message: msg.Message,
Detail: msg.Detail,
Hint: msg.Hint,
Position: msg.Position,
InternalPosition: msg.InternalPosition,
InternalQuery: msg.InternalQuery,
Where: msg.Where,
SchemaName: msg.SchemaName,
TableName: msg.TableName,
ColumnName: msg.ColumnName,
DataTypeName: msg.DataTypeName,
ConstraintName: msg.ConstraintName,
File: msg.File,
Line: msg.Line,
Routine: msg.Routine,
}
default: default:
pgConn.conn.Close() pgConn.conn.Close()
return nil, errors.New("unexpected message") return nil, errors.New("unexpected message")
@@ -348,7 +330,7 @@ func (pgConn *PgConn) ParameterStatus(key string) string {
} }
// CommandTag is the result of an Exec function // CommandTag is the result of an Exec function
type CommandTag string type CommandTag []byte
// RowsAffected returns the number of rows affected. If the CommandTag was not // RowsAffected returns the number of rows affected. If the CommandTag was not
// for a row affecting command (e.g. "CREATE TABLE") then it returns 0. // for a row affecting command (e.g. "CREATE TABLE") then it returns 0.
@@ -362,6 +344,10 @@ func (ct CommandTag) RowsAffected() int64 {
return n return n
} }
func (ct CommandTag) String() string {
return string(ct)
}
// SendExec enqueues the execution of sql via the PostgreSQL simple query protocol. sql may contain multiple queries. // SendExec enqueues the execution of sql via the PostgreSQL simple query protocol. sql may contain multiple queries.
// Execution is implicitly wrapped in a transactions unless a transaction is already in progress or sql contains // Execution is implicitly wrapped in a transactions unless a transaction is already in progress or sql contains
// transaction control statements. It is only sent to the PostgreSQL server when Flush is called. // transaction control statements. It is only sent to the PostgreSQL server when Flush is called.
@@ -511,6 +497,7 @@ func (pgConn *PgConn) SendExecParams(sql string, paramValues [][]byte, paramOIDs
} }
pgConn.batchBuf = appendParse(pgConn.batchBuf, "", sql, paramOIDs) pgConn.batchBuf = appendParse(pgConn.batchBuf, "", sql, paramOIDs)
pgConn.batchBuf = appendDescribe(pgConn.batchBuf, 'S', "")
pgConn.batchBuf = appendBind(pgConn.batchBuf, "", "", paramFormats, paramValues, resultFormats) pgConn.batchBuf = appendBind(pgConn.batchBuf, "", "", paramFormats, paramValues, resultFormats)
pgConn.batchBuf = appendExecute(pgConn.batchBuf, "", 0) pgConn.batchBuf = appendExecute(pgConn.batchBuf, "", 0)
pgConn.batchBuf = appendSync(pgConn.batchBuf) pgConn.batchBuf = appendSync(pgConn.batchBuf)
@@ -530,6 +517,7 @@ func (pgConn *PgConn) SendExecParams(sql string, paramValues [][]byte, paramOIDs
// //
// Query is only sent to the PostgreSQL server when Flush is called. // Query is only sent to the PostgreSQL server when Flush is called.
func (pgConn *PgConn) SendExecPrepared(stmtName string, paramValues [][]byte, paramFormats []int16, resultFormats []int16) { func (pgConn *PgConn) SendExecPrepared(stmtName string, paramValues [][]byte, paramFormats []int16, resultFormats []int16) {
pgConn.batchBuf = appendDescribe(pgConn.batchBuf, 'S', stmtName)
pgConn.batchBuf = appendBind(pgConn.batchBuf, "", stmtName, paramFormats, paramValues, resultFormats) pgConn.batchBuf = appendBind(pgConn.batchBuf, "", stmtName, paramFormats, paramValues, resultFormats)
pgConn.batchBuf = appendExecute(pgConn.batchBuf, "", 0) pgConn.batchBuf = appendExecute(pgConn.batchBuf, "", 0)
pgConn.batchBuf = appendSync(pgConn.batchBuf) pgConn.batchBuf = appendSync(pgConn.batchBuf)
@@ -616,6 +604,12 @@ func (rr *PgResultReader) NextRow() bool {
} }
} }
// FieldDescriptions returns the field descriptions for the current result set. The returned slice is only valid until
// the PgResultReader is closed.
func (rr *PgResultReader) FieldDescriptions() []pgproto3.FieldDescription {
return rr.fieldDescriptions
}
// Values returns the current row data. NextRow must have been previously been called. The returned [][]byte is only // Values returns the current row data. NextRow must have been previously been called. The returned [][]byte is only
// valid until the next NextRow call or the PgResultReader is closed. However, the underlying byte data is safe to // valid until the next NextRow call or the PgResultReader is closed. However, the underlying byte data is safe to
// retain a reference to and mutate. // retain a reference to and mutate.
@@ -914,23 +908,23 @@ func (pgConn *PgConn) Prepare(ctx context.Context, name, sql string, paramOIDs [
func errorResponseToPgError(msg *pgproto3.ErrorResponse) *PgError { func errorResponseToPgError(msg *pgproto3.ErrorResponse) *PgError {
return &PgError{ return &PgError{
Severity: msg.Severity, Severity: string(msg.Severity),
Code: msg.Code, Code: string(msg.Code),
Message: msg.Message, Message: string(msg.Message),
Detail: msg.Detail, Detail: string(msg.Detail),
Hint: msg.Hint, Hint: string(msg.Hint),
Position: msg.Position, Position: msg.Position,
InternalPosition: msg.InternalPosition, InternalPosition: msg.InternalPosition,
InternalQuery: msg.InternalQuery, InternalQuery: string(msg.InternalQuery),
Where: msg.Where, Where: string(msg.Where),
SchemaName: msg.SchemaName, SchemaName: string(msg.SchemaName),
TableName: msg.TableName, TableName: string(msg.TableName),
ColumnName: msg.ColumnName, ColumnName: string(msg.ColumnName),
DataTypeName: msg.DataTypeName, DataTypeName: string(msg.DataTypeName),
ConstraintName: msg.ConstraintName, ConstraintName: string(msg.ConstraintName),
File: msg.File, File: string(msg.File),
Line: msg.Line, Line: msg.Line,
Routine: msg.Routine, Routine: string(msg.Routine),
} }
} }
+10 -10
View File
@@ -224,7 +224,7 @@ where (
SendMessage(&pgproto3.ParameterDescription{}), SendMessage(&pgproto3.ParameterDescription{}),
SendMessage(&pgproto3.RowDescription{ SendMessage(&pgproto3.RowDescription{
Fields: []pgproto3.FieldDescription{ Fields: []pgproto3.FieldDescription{
{Name: "oid", {Name: []byte("oid"),
TableOID: 1247, TableOID: 1247,
TableAttributeNumber: 65534, TableAttributeNumber: 65534,
DataTypeOID: 26, DataTypeOID: 26,
@@ -232,7 +232,7 @@ where (
TypeModifier: -1, TypeModifier: -1,
Format: 0, Format: 0,
}, },
{Name: "typname", {Name: []byte("typname"),
TableOID: 1247, TableOID: 1247,
TableAttributeNumber: 1, TableAttributeNumber: 1,
DataTypeOID: 19, DataTypeOID: 19,
@@ -435,7 +435,7 @@ where (
steps = append(steps, step) steps = append(steps, step)
} }
steps = append(steps, SendMessage(&pgproto3.CommandComplete{CommandTag: "SELECT 163"})) steps = append(steps, SendMessage(&pgproto3.CommandComplete{CommandTag: []byte("SELECT 163")}))
steps = append(steps, SendMessage(&pgproto3.ReadyForQuery{TxStatus: 'I'})) steps = append(steps, SendMessage(&pgproto3.ReadyForQuery{TxStatus: 'I'}))
steps = append(steps, []Step{ steps = append(steps, []Step{
@@ -450,7 +450,7 @@ where (
SendMessage(&pgproto3.ParameterDescription{}), SendMessage(&pgproto3.ParameterDescription{}),
SendMessage(&pgproto3.RowDescription{ SendMessage(&pgproto3.RowDescription{
Fields: []pgproto3.FieldDescription{ Fields: []pgproto3.FieldDescription{
{Name: "oid", {Name: []byte("oid"),
TableOID: 1247, TableOID: 1247,
TableAttributeNumber: 65534, TableAttributeNumber: 65534,
DataTypeOID: 26, DataTypeOID: 26,
@@ -458,7 +458,7 @@ where (
TypeModifier: -1, TypeModifier: -1,
Format: 0, Format: 0,
}, },
{Name: "typname", {Name: []byte("typname"),
TableOID: 1247, TableOID: 1247,
TableAttributeNumber: 1, TableAttributeNumber: 1,
DataTypeOID: 19, DataTypeOID: 19,
@@ -475,7 +475,7 @@ where (
ExpectMessage(&pgproto3.Execute{}), ExpectMessage(&pgproto3.Execute{}),
ExpectMessage(&pgproto3.Sync{}), ExpectMessage(&pgproto3.Sync{}),
SendMessage(&pgproto3.BindComplete{}), SendMessage(&pgproto3.BindComplete{}),
SendMessage(&pgproto3.CommandComplete{CommandTag: "SELECT 0"}), SendMessage(&pgproto3.CommandComplete{CommandTag: []byte("SELECT 0")}),
SendMessage(&pgproto3.ReadyForQuery{TxStatus: 'I'}), SendMessage(&pgproto3.ReadyForQuery{TxStatus: 'I'}),
}...) }...)
@@ -491,7 +491,7 @@ where (
SendMessage(&pgproto3.ParameterDescription{}), SendMessage(&pgproto3.ParameterDescription{}),
SendMessage(&pgproto3.RowDescription{ SendMessage(&pgproto3.RowDescription{
Fields: []pgproto3.FieldDescription{ Fields: []pgproto3.FieldDescription{
{Name: "oid", {Name: []byte("oid"),
TableOID: 1247, TableOID: 1247,
TableAttributeNumber: 65534, TableAttributeNumber: 65534,
DataTypeOID: 26, DataTypeOID: 26,
@@ -499,7 +499,7 @@ where (
TypeModifier: -1, TypeModifier: -1,
Format: 0, Format: 0,
}, },
{Name: "typname", {Name: []byte("typname"),
TableOID: 1247, TableOID: 1247,
TableAttributeNumber: 1, TableAttributeNumber: 1,
DataTypeOID: 19, DataTypeOID: 19,
@@ -507,7 +507,7 @@ where (
TypeModifier: -1, TypeModifier: -1,
Format: 0, Format: 0,
}, },
{Name: "typbasetype", {Name: []byte("typbasetype"),
TableOID: 1247, TableOID: 1247,
TableAttributeNumber: 65534, TableAttributeNumber: 65534,
DataTypeOID: 26, DataTypeOID: 26,
@@ -524,7 +524,7 @@ where (
ExpectMessage(&pgproto3.Execute{}), ExpectMessage(&pgproto3.Execute{}),
ExpectMessage(&pgproto3.Sync{}), ExpectMessage(&pgproto3.Sync{}),
SendMessage(&pgproto3.BindComplete{}), SendMessage(&pgproto3.BindComplete{}),
SendMessage(&pgproto3.CommandComplete{CommandTag: "SELECT 0"}), SendMessage(&pgproto3.CommandComplete{CommandTag: []byte("SELECT 0")}),
SendMessage(&pgproto3.ReadyForQuery{TxStatus: 'I'}), SendMessage(&pgproto3.ReadyForQuery{TxStatus: 'I'}),
}...) }...)
+3 -3
View File
@@ -8,7 +8,7 @@ import (
) )
type CommandComplete struct { type CommandComplete struct {
CommandTag string CommandTag []byte
} }
func (*CommandComplete) Backend() {} func (*CommandComplete) Backend() {}
@@ -19,7 +19,7 @@ func (dst *CommandComplete) Decode(src []byte) error {
return &invalidMessageFormatErr{messageType: "CommandComplete"} return &invalidMessageFormatErr{messageType: "CommandComplete"}
} }
dst.CommandTag = string(src[:idx]) dst.CommandTag = src[:idx]
return nil return nil
} }
@@ -43,6 +43,6 @@ func (src *CommandComplete) MarshalJSON() ([]byte, error) {
CommandTag string CommandTag string
}{ }{
Type: "CommandComplete", Type: "CommandComplete",
CommandTag: src.CommandTag, CommandTag: string(src.CommandTag),
}) })
} }
+2 -2
View File
@@ -14,7 +14,7 @@ const (
) )
type FieldDescription struct { type FieldDescription struct {
Name string Name []byte
TableOID uint32 TableOID uint32
TableAttributeNumber uint16 TableAttributeNumber uint16
DataTypeOID uint32 DataTypeOID uint32
@@ -45,7 +45,7 @@ func (dst *RowDescription) Decode(src []byte) error {
if err != nil { if err != nil {
return err return err
} }
fd.Name = string(bName[:len(bName)-1]) fd.Name = bName[:len(bName)-1]
// Since buf.Next() doesn't return an error if we hit the end of the buffer // Since buf.Next() doesn't return an error if we hit the end of the buffer
// check Len ahead of time // check Len ahead of time
+1 -1
View File
@@ -289,7 +289,7 @@ func TestTxCommitExCancel(t *testing.T) {
script.Steps = append(script.Steps, pgmock.PgxInitSteps()...) script.Steps = append(script.Steps, pgmock.PgxInitSteps()...)
script.Steps = append(script.Steps, script.Steps = append(script.Steps,
pgmock.ExpectMessage(&pgproto3.Query{String: "begin"}), pgmock.ExpectMessage(&pgproto3.Query{String: "begin"}),
pgmock.SendMessage(&pgproto3.CommandComplete{CommandTag: "BEGIN"}), pgmock.SendMessage(&pgproto3.CommandComplete{CommandTag: []byte("BEGIN")}),
pgmock.SendMessage(&pgproto3.ReadyForQuery{TxStatus: 'T'}), pgmock.SendMessage(&pgproto3.ReadyForQuery{TxStatus: 'T'}),
pgmock.WaitForClose(), pgmock.WaitForClose(),
) )