summaryrefslogtreecommitdiff
path: root/vendor/github.com/jackc/pgx/v5/pgproto3/frontend.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/jackc/pgx/v5/pgproto3/frontend.go')
-rw-r--r--vendor/github.com/jackc/pgx/v5/pgproto3/frontend.go468
1 files changed, 0 insertions, 468 deletions
diff --git a/vendor/github.com/jackc/pgx/v5/pgproto3/frontend.go b/vendor/github.com/jackc/pgx/v5/pgproto3/frontend.go
deleted file mode 100644
index 056e547cd..000000000
--- a/vendor/github.com/jackc/pgx/v5/pgproto3/frontend.go
+++ /dev/null
@@ -1,468 +0,0 @@
-package pgproto3
-
-import (
- "bytes"
- "encoding/binary"
- "errors"
- "fmt"
- "io"
-)
-
-// Frontend acts as a client for the PostgreSQL wire protocol version 3.
-type Frontend struct {
- cr *chunkReader
- w io.Writer
-
- // tracer is used to trace messages when Send or Receive is called. This means an outbound message is traced
- // before it is actually transmitted (i.e. before Flush). It is safe to change this variable when the Frontend is
- // idle. Setting and unsetting tracer provides equivalent functionality to PQtrace and PQuntrace in libpq.
- tracer *tracer
-
- wbuf []byte
- encodeError error
-
- // Backend message flyweights
- authenticationOk AuthenticationOk
- authenticationCleartextPassword AuthenticationCleartextPassword
- authenticationMD5Password AuthenticationMD5Password
- authenticationGSS AuthenticationGSS
- authenticationGSSContinue AuthenticationGSSContinue
- authenticationSASL AuthenticationSASL
- authenticationSASLContinue AuthenticationSASLContinue
- authenticationSASLFinal AuthenticationSASLFinal
- backendKeyData BackendKeyData
- bindComplete BindComplete
- closeComplete CloseComplete
- commandComplete CommandComplete
- copyBothResponse CopyBothResponse
- copyData CopyData
- copyInResponse CopyInResponse
- copyOutResponse CopyOutResponse
- copyDone CopyDone
- dataRow DataRow
- emptyQueryResponse EmptyQueryResponse
- errorResponse ErrorResponse
- functionCallResponse FunctionCallResponse
- noData NoData
- noticeResponse NoticeResponse
- notificationResponse NotificationResponse
- parameterDescription ParameterDescription
- parameterStatus ParameterStatus
- parseComplete ParseComplete
- readyForQuery ReadyForQuery
- rowDescription RowDescription
- portalSuspended PortalSuspended
-
- bodyLen int
- maxBodyLen int // maxBodyLen is the maximum length of a message body in octets. If a message body exceeds this length, Receive will return an error.
- msgType byte
- partialMsg bool
- authType uint32
-}
-
-// NewFrontend creates a new Frontend.
-func NewFrontend(r io.Reader, w io.Writer) *Frontend {
- cr := newChunkReader(r, 0)
- return &Frontend{cr: cr, w: w}
-}
-
-// Send sends a message to the backend (i.e. the server). The message is buffered until Flush is called. Any error
-// encountered will be returned from Flush.
-//
-// Send can work with any FrontendMessage. Some commonly used message types such as Bind have specialized send methods
-// such as SendBind. These methods should be preferred when the type of message is known up front (e.g. when building an
-// extended query protocol query) as they may be faster due to knowing the type of msg rather than it being hidden
-// behind an interface.
-func (f *Frontend) Send(msg FrontendMessage) {
- if f.encodeError != nil {
- return
- }
-
- prevLen := len(f.wbuf)
- newBuf, err := msg.Encode(f.wbuf)
- if err != nil {
- f.encodeError = err
- return
- }
- f.wbuf = newBuf
-
- if f.tracer != nil {
- f.tracer.traceMessage('F', int32(len(f.wbuf)-prevLen), msg)
- }
-}
-
-// Flush writes any pending messages to the backend (i.e. the server).
-func (f *Frontend) Flush() error {
- if err := f.encodeError; err != nil {
- f.encodeError = nil
- f.wbuf = f.wbuf[:0]
- return &writeError{err: err, safeToRetry: true}
- }
-
- if len(f.wbuf) == 0 {
- return nil
- }
-
- n, err := f.w.Write(f.wbuf)
-
- const maxLen = 1024
- if len(f.wbuf) > maxLen {
- f.wbuf = make([]byte, 0, maxLen)
- } else {
- f.wbuf = f.wbuf[:0]
- }
-
- if err != nil {
- return &writeError{err: err, safeToRetry: n == 0}
- }
-
- return nil
-}
-
-// Trace starts tracing the message traffic to w. It writes in a similar format to that produced by the libpq function
-// PQtrace.
-func (f *Frontend) Trace(w io.Writer, options TracerOptions) {
- f.tracer = &tracer{
- w: w,
- buf: &bytes.Buffer{},
- TracerOptions: options,
- }
-}
-
-// Untrace stops tracing.
-func (f *Frontend) Untrace() {
- f.tracer = nil
-}
-
-// SendBind sends a Bind message to the backend (i.e. the server). The message is buffered until Flush is called. Any
-// error encountered will be returned from Flush.
-func (f *Frontend) SendBind(msg *Bind) {
- if f.encodeError != nil {
- return
- }
-
- prevLen := len(f.wbuf)
- newBuf, err := msg.Encode(f.wbuf)
- if err != nil {
- f.encodeError = err
- return
- }
- f.wbuf = newBuf
-
- if f.tracer != nil {
- f.tracer.traceBind('F', int32(len(f.wbuf)-prevLen), msg)
- }
-}
-
-// SendParse sends a Parse message to the backend (i.e. the server). The message is buffered until Flush is called. Any
-// error encountered will be returned from Flush.
-func (f *Frontend) SendParse(msg *Parse) {
- if f.encodeError != nil {
- return
- }
-
- prevLen := len(f.wbuf)
- newBuf, err := msg.Encode(f.wbuf)
- if err != nil {
- f.encodeError = err
- return
- }
- f.wbuf = newBuf
-
- if f.tracer != nil {
- f.tracer.traceParse('F', int32(len(f.wbuf)-prevLen), msg)
- }
-}
-
-// SendClose sends a Close message to the backend (i.e. the server). The message is buffered until Flush is called. Any
-// error encountered will be returned from Flush.
-func (f *Frontend) SendClose(msg *Close) {
- if f.encodeError != nil {
- return
- }
-
- prevLen := len(f.wbuf)
- newBuf, err := msg.Encode(f.wbuf)
- if err != nil {
- f.encodeError = err
- return
- }
- f.wbuf = newBuf
-
- if f.tracer != nil {
- f.tracer.traceClose('F', int32(len(f.wbuf)-prevLen), msg)
- }
-}
-
-// SendDescribe sends a Describe message to the backend (i.e. the server). The message is buffered until Flush is
-// called. Any error encountered will be returned from Flush.
-func (f *Frontend) SendDescribe(msg *Describe) {
- if f.encodeError != nil {
- return
- }
-
- prevLen := len(f.wbuf)
- newBuf, err := msg.Encode(f.wbuf)
- if err != nil {
- f.encodeError = err
- return
- }
- f.wbuf = newBuf
-
- if f.tracer != nil {
- f.tracer.traceDescribe('F', int32(len(f.wbuf)-prevLen), msg)
- }
-}
-
-// SendExecute sends an Execute message to the backend (i.e. the server). The message is buffered until Flush is called.
-// Any error encountered will be returned from Flush.
-func (f *Frontend) SendExecute(msg *Execute) {
- if f.encodeError != nil {
- return
- }
-
- prevLen := len(f.wbuf)
- newBuf, err := msg.Encode(f.wbuf)
- if err != nil {
- f.encodeError = err
- return
- }
- f.wbuf = newBuf
-
- if f.tracer != nil {
- f.tracer.TraceQueryute('F', int32(len(f.wbuf)-prevLen), msg)
- }
-}
-
-// SendSync sends a Sync message to the backend (i.e. the server). The message is buffered until Flush is called. Any
-// error encountered will be returned from Flush.
-func (f *Frontend) SendSync(msg *Sync) {
- if f.encodeError != nil {
- return
- }
-
- prevLen := len(f.wbuf)
- newBuf, err := msg.Encode(f.wbuf)
- if err != nil {
- f.encodeError = err
- return
- }
- f.wbuf = newBuf
-
- if f.tracer != nil {
- f.tracer.traceSync('F', int32(len(f.wbuf)-prevLen), msg)
- }
-}
-
-// SendQuery sends a Query message to the backend (i.e. the server). The message is buffered until Flush is called. Any
-// error encountered will be returned from Flush.
-func (f *Frontend) SendQuery(msg *Query) {
- if f.encodeError != nil {
- return
- }
-
- prevLen := len(f.wbuf)
- newBuf, err := msg.Encode(f.wbuf)
- if err != nil {
- f.encodeError = err
- return
- }
- f.wbuf = newBuf
-
- if f.tracer != nil {
- f.tracer.traceQuery('F', int32(len(f.wbuf)-prevLen), msg)
- }
-}
-
-// SendUnbufferedEncodedCopyData immediately sends an encoded CopyData message to the backend (i.e. the server). This method
-// is more efficient than sending a CopyData message with Send as the message data is not copied to the internal buffer
-// before being written out. The internal buffer is flushed before the message is sent.
-func (f *Frontend) SendUnbufferedEncodedCopyData(msg []byte) error {
- err := f.Flush()
- if err != nil {
- return err
- }
-
- n, err := f.w.Write(msg)
- if err != nil {
- return &writeError{err: err, safeToRetry: n == 0}
- }
-
- if f.tracer != nil {
- f.tracer.traceCopyData('F', int32(len(msg)-1), &CopyData{})
- }
-
- return nil
-}
-
-func translateEOFtoErrUnexpectedEOF(err error) error {
- if err == io.EOF {
- return io.ErrUnexpectedEOF
- }
- return err
-}
-
-// Receive receives a message from the backend. The returned message is only valid until the next call to Receive.
-func (f *Frontend) Receive() (BackendMessage, error) {
- if !f.partialMsg {
- header, err := f.cr.Next(5)
- if err != nil {
- return nil, translateEOFtoErrUnexpectedEOF(err)
- }
-
- f.msgType = header[0]
-
- msgLength := int(binary.BigEndian.Uint32(header[1:]))
- if msgLength < 4 {
- return nil, fmt.Errorf("invalid message length: %d", msgLength)
- }
-
- f.bodyLen = msgLength - 4
- if f.maxBodyLen > 0 && f.bodyLen > f.maxBodyLen {
- return nil, &ExceededMaxBodyLenErr{f.maxBodyLen, f.bodyLen}
- }
- f.partialMsg = true
- }
-
- msgBody, err := f.cr.Next(f.bodyLen)
- if err != nil {
- return nil, translateEOFtoErrUnexpectedEOF(err)
- }
-
- f.partialMsg = false
-
- var msg BackendMessage
- switch f.msgType {
- case '1':
- msg = &f.parseComplete
- case '2':
- msg = &f.bindComplete
- case '3':
- msg = &f.closeComplete
- case 'A':
- msg = &f.notificationResponse
- case 'c':
- msg = &f.copyDone
- case 'C':
- msg = &f.commandComplete
- case 'd':
- msg = &f.copyData
- case 'D':
- msg = &f.dataRow
- case 'E':
- msg = &f.errorResponse
- case 'G':
- msg = &f.copyInResponse
- case 'H':
- msg = &f.copyOutResponse
- case 'I':
- msg = &f.emptyQueryResponse
- case 'K':
- msg = &f.backendKeyData
- case 'n':
- msg = &f.noData
- case 'N':
- msg = &f.noticeResponse
- case 'R':
- var err error
- msg, err = f.findAuthenticationMessageType(msgBody)
- if err != nil {
- return nil, err
- }
- case 's':
- msg = &f.portalSuspended
- case 'S':
- msg = &f.parameterStatus
- case 't':
- msg = &f.parameterDescription
- case 'T':
- msg = &f.rowDescription
- case 'V':
- msg = &f.functionCallResponse
- case 'W':
- msg = &f.copyBothResponse
- case 'Z':
- msg = &f.readyForQuery
- default:
- return nil, fmt.Errorf("unknown message type: %c", f.msgType)
- }
-
- err = msg.Decode(msgBody)
- if err != nil {
- return nil, err
- }
-
- if f.tracer != nil {
- f.tracer.traceMessage('B', int32(5+len(msgBody)), msg)
- }
-
- return msg, nil
-}
-
-// Authentication message type constants.
-// See src/include/libpq/pqcomm.h for all
-// constants.
-const (
- AuthTypeOk = 0
- AuthTypeCleartextPassword = 3
- AuthTypeMD5Password = 5
- AuthTypeSCMCreds = 6
- AuthTypeGSS = 7
- AuthTypeGSSCont = 8
- AuthTypeSSPI = 9
- AuthTypeSASL = 10
- AuthTypeSASLContinue = 11
- AuthTypeSASLFinal = 12
-)
-
-func (f *Frontend) findAuthenticationMessageType(src []byte) (BackendMessage, error) {
- if len(src) < 4 {
- return nil, errors.New("authentication message too short")
- }
- f.authType = binary.BigEndian.Uint32(src[:4])
-
- switch f.authType {
- case AuthTypeOk:
- return &f.authenticationOk, nil
- case AuthTypeCleartextPassword:
- return &f.authenticationCleartextPassword, nil
- case AuthTypeMD5Password:
- return &f.authenticationMD5Password, nil
- case AuthTypeSCMCreds:
- return nil, errors.New("AuthTypeSCMCreds is unimplemented")
- case AuthTypeGSS:
- return &f.authenticationGSS, nil
- case AuthTypeGSSCont:
- return &f.authenticationGSSContinue, nil
- case AuthTypeSSPI:
- return nil, errors.New("AuthTypeSSPI is unimplemented")
- case AuthTypeSASL:
- return &f.authenticationSASL, nil
- case AuthTypeSASLContinue:
- return &f.authenticationSASLContinue, nil
- case AuthTypeSASLFinal:
- return &f.authenticationSASLFinal, nil
- default:
- return nil, fmt.Errorf("unknown authentication type: %d", f.authType)
- }
-}
-
-// GetAuthType returns the authType used in the current state of the frontend.
-// See SetAuthType for more information.
-func (f *Frontend) GetAuthType() uint32 {
- return f.authType
-}
-
-func (f *Frontend) ReadBufferLen() int {
- return f.cr.wp - f.cr.rp
-}
-
-// SetMaxBodyLen sets the maximum length of a message body in octets.
-// If a message body exceeds this length, Receive will return an error.
-// This is useful for protecting against a corrupted server that sends
-// messages with incorrect length, which can cause memory exhaustion.
-// The default value is 0.
-// If maxBodyLen is 0, then no maximum is enforced.
-func (f *Frontend) SetMaxBodyLen(maxBodyLen int) {
- f.maxBodyLen = maxBodyLen
-}