KaiwuDB 协议代码解析(2)

114 阅读2分钟

- 数据请求阶段 -

Part 1 - 简单查询

 

1. 客户端发送 Query (‘Q’) 消息给服务端,包含了一条字符串类型的 SQL 语句。

func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {\
    ...\
    // Check to see if we can use the "simpleQuery" interface, which is\
    // *much* faster than going through prepare/exec\
    if len(args) == 0 {\
        return cn.simpleQuery(query)\
    }\
    ...\
}

 

2. 服务端收到 Query 消息,解析 SQL 语句,生成抽象语法树 (AST),并传给执行器执行,获得结果。

func (c *conn) writeRowDescription(\
    ctx context.Context,\
    columns []sqlbase.ResultColumn,\
    formatCodes []pgwirebase.FormatCode,\
    w io.Writer,\
) error {\
    c.msgBuilder.initMsg(pgwirebase.ServerMsgRowDescription)\
    c.msgBuilder.putInt16(int16(len(columns)))\
    for i, column := range columns {\
        ...\
        c.msgBuilder.writeTerminatedString(column.Name)\
        ...\
        c.msgBuilder.putInt32(0) // Table OID (optional).\
        c.msgBuilder.putInt16(0) // Column attribute ID (optional).\
        c.msgBuilder.putInt32(int32(typ.oid))\
        c.msgBuilder.putInt16(int16(typ.size))\
        ...\
    }\
    ...\
}

 

3. 服务端根据 SQL 结果,首先发送 RowDescription(B:‘T’) 消息,包含列的数量,列名,列的类型等参数。​​​​​​​

func (c *conn) writeRowDescription(\
    ctx context.Context,\
    columns []sqlbase.ResultColumn,\
    formatCodes []pgwirebase.FormatCode,\
    w io.Writer,\
) error {\
    c.msgBuilder.initMsg(pgwirebase.ServerMsgRowDescription)\
    c.msgBuilder.putInt16(int16(len(columns)))\
    for i, column := range columns {\
        ...\
        c.msgBuilder.writeTerminatedString(column.Name)\
        ...\
        c.msgBuilder.putInt32(0) // Table OID (optional).\
        c.msgBuilder.putInt16(0) // Column attribute ID (optional).\
        c.msgBuilder.putInt32(int32(typ.oid))\
        c.msgBuilder.putInt16(int16(typ.size))\
        ...\
    }\
    ...\
}

 

  1. RowDescription 消息后面将跟着多个 DataRow(B:‘D’) 消息,每个 DataRow 消息包含一行的数据。
func (c *conn) bufferRow(\
    ctx context.Context,\
    row tree.Datums,\
    formatCodes []pgwirebase.FormatCode,\
    conv sessiondata.DataConversionConfig,\
    types []*types.T,\
) {\
    c.msgBuilder.initMsg(pgwirebase.ServerMsgDataRow)\
    c.msgBuilder.putInt16(int16(len(row)))\
    for i, col := range row {\
        ...\
        switch fmtCode {\
        case pgwirebase.FormatText:\
            c.msgBuilder.writeTextDatum(ctx, col, conv, types[i])\
        case pgwirebase.FormatBinary:\
            c.msgBuilder.writeBinaryDatum(ctx, col, conv.Location, types[i])\
        ...\
    }\
    if err := c.msgBuilder.finishMsg(&c.writerState.buf); err != nil {\
        panic(fmt.Sprintf("unexpected err from buffer: %s", err))\
    }\
}

 

5. 发送 CommandComplete(B:‘C’) 消息表示这个 SQL 请求执行结束了。

6. 服务端发送 ReadyForQuery(‘Z’),通知客户端可以发送下一条 SQL 请求了。

func (r *commandResult) Close(ctx context.Context, t sql.TransactionStatusIndicator) {\
    ...\
    switch r.typ {\
    case commandComplete:\
        tag := cookTag(\
            r.cmdCompleteTag, r.conn.writerState.tagBuf[:0], r.stmtType, r.rowsAffected,\
        )\
        r.conn.bufferCommandComplete(tag)\
        case parseComplete:\
        r.conn.bufferParseComplete()\
    case bindComplete:\
        r.conn.bufferBindComplete()\
    case closeComplete:\
        r.conn.bufferCloseComplete()\
    case readyForQuery:\
        r.conn.bufferReadyForQuery(byte(t))\
        // The error is saved on conn.err.\
        _ /* err */ = r.conn.Flush(r.pos)\
        ...\
    }\
    ...\
}

 

7. 客户端根据接受 SQL 请求的结果。

func (cn *conn) simpleQuery(q string) (res *rows, err error) {\
    b := cn.writeBuf('Q')\
    b.string(q)\
    cn.send(b)\
\
    for {\
        t, r := cn.recv1()\
        switch t {\
        case 'C', 'I':\
            ...\
        case 'Z':\
            ...\
        case 'E':\
            ...\
        case 'D':\
            ...\
        case 'T':\
            ...\
        }\
    }\
}

 

Part 2 - 扩展查询

1. 客户端发送扩展查询请求,依次发送 Parse (F:‘P’), Bind (F:‘B’), Describe (F:‘D’), Execute (F:‘E’), Sync(F:‘S’) 消息。

func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) {\
    ...\
    if cn.binaryParameters {\
        cn.sendBinaryModeQuery(query, args)\
        cn.readParseResponse()\
        cn.readBindResponse()\
        rows := &rows{cn: cn}\
        rows.rowsHeader = cn.readPortalDescribeResponse()\
        cn.postExecuteWorkaround()\
        return rows, nil\
    }\
    ...\
}
func (cn *conn) sendBinaryModeQuery(query string, args []driver.Value) {\
    b := cn.writeBuf('P')\
    b.byte(0) // unnamed statement\
    b.string(query)\
    b.int16(0)\
\
    b.next('B')\
    b.int16(0) // unnamed portal and statement\
    cn.sendBinaryParameters(b, args)\
    b.bytes(colFmtDataAllText)\
\
    b.next('D')\
    b.byte('P')\
    b.byte(0) // unnamed portal\
\
    b.next('E')\
    b.byte(0)\
    b.int32(0)\
\
    b.next('S')\
    cn.send(b)\
}

2. 服务端处理扩展查询请求。

 

3. 服务端发送回应消息,ParseComplete (B:‘1’), BindComplete (B:‘2’), ParameterDescription(B:‘t’), CommandComplete (B:‘C’), CloseComplete (B:‘3’), ReadyForQuery (B:‘Z’)。​​​​​​​

func (r *commandResult) Close(ctx context.Context, t sql.TransactionStatusIndicator) {\
    ...\
    switch r.typ {\
    case commandComplete:\
        tag := cookTag(\
            r.cmdCompleteTag, r.conn.writerState.tagBuf[:0], r.stmtType, r.rowsAffected,\
        )\
        r.conn.bufferCommandComplete(tag)\
        case parseComplete:\
        r.conn.bufferParseComplete()\
    case bindComplete:\
        r.conn.bufferBindComplete()\
    case closeComplete:\
        r.conn.bufferCloseComplete()\
    case readyForQuery:\
        r.conn.bufferReadyForQuery(byte(t))\
        // The error is saved on conn.err.\
        _ /* err */ = r.conn.Flush(r.pos)\
        ...\
    }\
    ...\
}