Avoid allocating strings in common message types
This commit is contained in:
@@ -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
@@ -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
@@ -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'}),
|
||||||
}...)
|
}...)
|
||||||
|
|
||||||
|
|||||||
@@ -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),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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(),
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user