关于PostgreSQL的简单查询和扩展查询协议

简单查询和扩展查询是PG前端和后端交互的时候,2种不同交互方法。简单查询时,前端发一个包含SQL的包过去,后端执行后返回结果。扩展查询则是把简单查询切分成Parse,Bind,Describe,Execute,Close等几个步骤,以达到执行计划复用的目的。扩展查询还有防止SQL注入,减少通信数据量(使用binary形式传参)的效果。

更详细的描述,可参考手册:
http://58.58.27.50:8079/doc/html/9.3.1_zh/protocol-flow.html#AEN98678


下面是服务端处理简单查询和扩展查询的代码概要

1.简单查询

点击(此处)折叠或打开
  1. exec_simple_query(const char *query_string)
  2.  ->parsetree_list = pg_parse_query(query_string);
  3.  ->foreach(parsetree_item, parsetree_list)
  4.       ->querytree_list = pg_analyze_and_rewrite(parsetree, query_string,NULL, 0);
  5.       ->plantree_list = pg_plan_queries(querytree_list, 0, NULL);
  6.       ->portal = CreatePortal("", true, true);
  7.       ->PortalDefineQuery(portal,NULL,query_string,commandTag,plantree_list,NULL);
  8.       ->PortalStart(portal, NULL, 0, InvalidSnapshot);
  9.       ->PortalRun(portal,FETCH_ALL,isTopLevel,receiver,receiver,completionTag);
  10.       ->PortalDrop(portal, false);

2.扩展查询

parse消息的处理(命名语句):

点击(此处)折叠或打开

  1. exec_parse_message(const char *query_string,const char *stmt_name,Oid *paramTypes,int numParams)
  2.       ->parsetree_list = pg_parse_query(query_string);
  3.       ->raw_parse_tree = (Node *) linitial(parsetree_list);
  4.       ->psrc = CreateCachedPlan(raw_parse_tree, query_string, commandTag);
  5.       ->query = parse_analyze_varparams(raw_parse_tree,query_string,&paramTypes,&numParams);
  6.       ->querytree_list = pg_rewrite_query(query);
  7.       ->CompleteCachedPlan(psrc,querytree_list,unnamed_stmt_context,paramTypes,numParams,NULL,NULL,0,true);
  8.       ->StorePreparedStatement(stmt_name, psrc, false);

bind消息的处理:

点击(此处)折叠或打开

  1. exec_bind_message(StringInfo input_message)
  2.       ->portal_name = pq_getmsgstring(input_message);
  3.       ->stmt_name = pq_getmsgstring(input_message);
  4.       ->pstmt = FetchPreparedStatement(stmt_name, true);
  5.       ->psrc = pstmt->plansource;
  6.       ->cplan = GetCachedPlan(psrc, params, false);
  7.       ->portal = CreatePortal(portal_name, true, true);
  8.       ->PortalDefineQuery(portal,saved_stmt_name,query_string,psrc->commandTag,cplan->stmt_list,cplan);
  9.       ->PortalStart(portal, params, 0, InvalidSnapshot);
GetCachedPlan()会决定新创建一个定制的执行计划还是使用之前保存的通用的执行计划。

execute消息的处理:

点击(此处)折叠或打开

  1. exec_execute_message(const char *portal_name, long max_rows)
  2.       ->portal = GetPortalByName(portal_name);
  3.       ->completed = PortalRun(portal,max_rows,true,receiver,receiver,completionTag);

close消息的处理:

点击(此处)折叠或打开

  1. PostgresMain(int argc, char *argv[],const char *dbname,const char *username)
  2.   case 'C':
  3.       ->DropPreparedStatement(close_target, false);
  4.       or
  5.       ->PortalDrop(portal, false);

3.参考

http://58.58.27.50:8079/doc/html/9.3.1_zh/protocol-flow.html#AEN98678
http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=20726500&id=4150218
src/backend/tcop/postgres.c

上一篇:Facebook 正式开源其大数据查询引擎 Presto


下一篇:自定义 spring mvc 拦截器(近期项目需求实现)