func (c *FrontendConnection) readBindMessage(msg *fbcore.Message) error { portalName, err := fbbuf.ReadCString(msg.Payload()) if err != nil { return err } if portalName != "" { return fmt.Errorf("attempted to bind to a named portal %q; only the unnamed portal is supported") } statementName, err := fbbuf.ReadCString(msg.Payload()) if err != nil { return err } if statementName != "" { return fmt.Errorf("attempted to bind statement %q, even though it has not been parsed yet", statementName) } numParamFormats, err := fbbuf.ReadInt16(msg.Payload()) if err != nil { return err } if numParamFormats != 0 { return fmt.Errorf("the number of parameter formats (%d) does not match the number of parameters in the query (0)", numParamFormats) } numParameters, err := fbbuf.ReadInt16(msg.Payload()) if err != nil { return err } if numParameters != 0 { return fmt.Errorf("the number of parameters provided by the client (%d) does not match the number of parameters in the query (0)", numParameters) } // TODO: ensure we're at the end of the packet return nil }
// Process the identity ('I') message, reporting the identity therein. func processIdentMsg(msgInit msgInit, exit exitFn) string { var m core.Message msgInit(&m, exit) // Read the remote system identifier string if m.MsgType() != 'I' { exit("expected identification ('I') message, "+ "but received %c", m.MsgType()) } // hard-coded lengh limit, but it's very generous if m.Size() > 10*KB { log.Printf("oversized message string, msg size is %d", m.Size()) } s, err := buf.ReadCString(m.Payload()) if err != nil { exit("couldn't read identification string: %v", err) } return s }
// Read the version message, calling exit if this is not a supported // version. func processVerMsg(msgInit msgInit, exit exitFn) { var m core.Message msgInit(&m, exit) if m.MsgType() != 'V' { exit("expected version ('V') message, "+ "but received %c", m.MsgType()) } // hard-coded lengh limit, but it's very generous if m.Size() > 10*KB { log.Printf("oversized message string, msg size is %d", m.Size()) } s, err := buf.ReadCString(m.Payload()) if err != nil { exit("couldn't read version string: %v", err) } if !(strings.HasPrefix(s, "PG-9.0") || strings.HasPrefix(s, "PG-9.1") || strings.HasPrefix(s, "PG-9.2") || strings.HasPrefix(s, "PG-9.3") || strings.HasPrefix(s, "PG-9.4") || strings.HasPrefix(s, "PG-9.5")) || !strings.HasSuffix(s, "/logfebe-1") { exit("protocol version not supported: %s", s) } }
func (c *FrontendConnection) readExecuteMessage(msg *fbcore.Message) error { statementName, err := fbbuf.ReadCString(msg.Payload()) if err != nil { return err } if statementName != "" { return fmt.Errorf("attempted to use statement name %q; only unnamed statements are supported") } // ignore maxRowCount _, err = fbbuf.ReadInt32(msg.Payload()) // TODO: ensure we're at the end of the packet return err }
func (c *FrontendConnection) readParseMessage(msg *fbcore.Message) (queryString string, err error) { statementName, err := fbbuf.ReadCString(msg.Payload()) if err != nil { return "", err } if statementName != "" { return "", fmt.Errorf("attempted to use statement name %q; only unnamed statements are supported") } queryString, err = fbbuf.ReadCString(msg.Payload()) if err != nil { return "", err } numParamTypes, err := fbbuf.ReadInt16(msg.Payload()) if err != nil { return "", err } if numParamTypes != 0 { return "", fmt.Errorf("attempted to prepare a statement with %d param types", numParamTypes) } // TODO: ensure we're at the end of the packet return queryString, nil }
func (c *FrontendConnection) readDescribeMessage(msg *fbcore.Message) (byte, error) { typ, err := fbbuf.ReadByte(msg.Payload()) if err != nil { return 0, err } if typ != 'S' && typ != 'P' { return 0, fmt.Errorf("invalid type %q", typ) } statementName, err := fbbuf.ReadCString(msg.Payload()) if err != nil { return 0, err } if statementName != "" { return 0, fmt.Errorf("tried to use statement/portal name %q; only unnamed statements and portals are supported") } // TODO: ensure we're at the end of the packet return typ, nil }
func parseLogRecord( dst *logRecord, data []byte, exit exitFn) { b := bytes.NewBuffer(data) // Read the next nullable string from b, returning a 'nil' // *string should it be null. nextNullableString := func() *string { np, err := buf.ReadByte(b) if err != nil { exit(err) } switch np { case 'P': s, err := buf.ReadCString(b) if err != nil { exit(err) } return &s case 'N': // 'N' is still followed by a NUL byte that // must be consumed. _, err := buf.ReadCString(b) if err != nil { exit(err) } return nil default: exit("Expected nullable string "+ "control character, got %c", np) } exit("Prior switch should always return") panic("exit should panic/return, " + "but the compiler doesn't know that") } // Read a non-nullable string from b nextString := func() string { s, err := buf.ReadCString(b) if err != nil { exit(err) } return s } nextInt32 := func() int32 { i32, err := buf.ReadInt32(b) if err != nil { exit(err) } return i32 } nextInt64 := func() int64 { i64, err := readInt64(b) if err != nil { exit(err) } return i64 } nextUint64 := func() uint64 { ui64, err := readUint64(b) if err != nil { exit(err) } return ui64 } dst.LogTime = nextString() dst.UserName = nextNullableString() dst.DatabaseName = nextNullableString() dst.Pid = nextInt32() dst.ClientAddr = nextNullableString() dst.SessionID = nextString() dst.SeqNum = nextInt64() dst.PsDisplay = nextNullableString() dst.SessionStart = nextString() dst.Vxid = nextNullableString() dst.Txid = nextUint64() dst.ELevel = nextInt32() dst.SQLState = nextNullableString() dst.ErrMessage = nextNullableString() dst.ErrDetail = nextNullableString() dst.ErrHint = nextNullableString() dst.InternalQuery = nextNullableString() dst.InternalQueryPos = nextInt32() dst.ErrContext = nextNullableString() dst.UserQuery = nextNullableString() dst.UserQueryPos = nextInt32() dst.FileErrPos = nextNullableString() dst.ApplicationName = nextNullableString() if b.Len() != 0 { exit("LogRecord message has mismatched "+ "length header and cString contents: remaining %d", b.Len()) } }