【PostgreSQL】客户端请求处理 PostgresMain()

根据启动流程,postgres 会调用 select 监听客户端连接,并 fork 子线程来单独负责这个连接的请求处理,代码:
postmaster.c PostmasterMain()     =>    主程序入口
postmaster.c ServerLoop()    =>    开始 main loop,for(;;)调用 linux's epoll_wait(2) 处理客户端链接。
postmaster.c ConnCreate()     =>    监听到客户端链接..
postmaster.c BackendStartup()     =>    fork子进程程处理当前链接
postmaster.c BackendRun()     =>  客户端子进程请求处理函数入口。  
postgres.c PostgresMain()     =>    开始客户端处理,for(;;)调用监听客户端请求
postgres.c ReadCommand()    =>    解析客户端指令,query、parse、bind、execute、close、describe、flush 等等。

客户端请求处理入口函数 PostgresMain(),会 for(;;)监听客户端请求:
void PostgresMain(const char *dbname, const char *username){
   int          firstchar;//解析出来的客户端请求
   // 设置信号处理
   if (am_walsender)
      WalSndSignals();
   else{ //..}
   // 预处理
   BaseInit();
   if (am_walsender)
      InitWalSender();
        // 开始监听客户端请求
   for (;;)
   {
      // 解析客户端请求
      firstchar = ReadCommand(&input_message);
               // 然后不同的请求进行不同的处理
      switch (firstchar)
      {
         case 'Q':        /* simple query */
         case 'P':        /* parse */
         case 'B':        /* bind */
         case 'E':        /* execute */
         case 'F':        /* fastpath function call */
         case 'C':        /* close */
         case 'D':        /* describe */
         case 'H':        /* flush */
         case 'S':        /* sync */
         case EOF:
         case 'X':
         case 'd':        /* copy data */
         case 'c':        /* copy done */
         case 'f':        /* copy fail */
         default:
      }
   }                    /* end of input-reading loop */
}

客户端消息类型如下:
case 'Q'
 /* simple query */    
exec_simple_query()
执行 insert、query、update 等。非参数化的请求。
case 'P'
 /* parse */
exec_parse_message()
参数化 Prepared-statement 的解析阶段:parse,对语法进行分析并重写,请求传递的是带参数占位符的sql语句。
case 'B'
/* bind */
exec_bind_message()
参数化 Prepared-statement 的解析阶段:bind,将上一阶段的 PreparedStatement 生成执行计划并绑定保存,后续相同的参数化请求可以复用,还需要对已有的计划进行校验。请求传递的是参数、参数格式和返回列格式。
case 'E'
/* execute */
exec_execute_message()
参数化 Prepared-statement 的解析阶段:execute,参数和计划 Portal 都有了直接执行请求。
case 'F'
/* fastpath function call */
case 'C'
 /* close */
case 'D':
/* describe */
exec_describe_statement_message()
exec_describe_portal_message()
客户端可以发送 Describe 消息获取 Statment(parse) 或 Portal(bind) 的元信息,即返回结果的列名,类型等信息,这些信息由 RowDescription 消息携带。如果请求获取 Statement 的元信息,还会返回具体的参数信息。
case 'H':   
 /* flush */
case 'S': 
/* sync */
使用参数化 Prepared-statement 的请求需要 sync 结尾。
case 'X':
case EOF:
case 'd':   
 /* copy data */
copy子协议
case 'c':    
/* copy done */
copy子协议
case 'f':   
/* copy fail */
copy子协议