jackc / pgx

PostgreSQL driver and toolkit for Go
MIT License
10.8k stars 840 forks source link

Clone a backend message #1828

Open krisdiano opened 11 months ago

krisdiano commented 11 months ago

Is your feature request related to a problem? Please describe. I used the pgconn to handle low level libpq protocol in my projects which are stream replication proxy. I found that the lifespan of messages which were returned from Receive method is very short. I have to clone the backend messages and keep messages in memory to send in proper time. Now, for clone, I need type assert, encode, define a variable and decode.

Describe the solution you'd like

type BackendMessage interface {
    Message()
    Clone() BackendMessage()
    Backend()
}

or

type Message interface {
    Encode([]byte) []byte
    Decode([]byte) error
    Clone() Message
}

The Message interface are also be contained in FrontedMessage, but the source of FrontedMessage is determined by users, so I think the first method is more reasonable. The simeplest way of Clone:

func (src *CopyData) Clone() BackendMessage {
    var ret CopyData
    _ = ret.Decode(src.Encode(nil)[5:])
    return &ret
}

Describe alternatives you've considered A clear and concise description of any alternative solutions or features you've considered.

Additional context Add any other context or screenshots about the feature request here.

jackc commented 11 months ago

Overall idea of making it simple to clone a message seems reasonable. But I'm not sure of the proper interface.

Not sure I totally understood your reasoning for deciding between adding to Message or BackendMessage interface. But adding to either interface is slightly unfortunate. Technically, it would be a breaking change to add to an interface. But practically speaking I don't think it would break any existing code. 🤷

But it is a bit weird for a *CopyData.Clone() to return a BackendMessage instead of another *CopyData. Maybe a CopyBackendMessage function should be added instead for the generic case.