这篇文章主要介绍“PostgreSQL中Review exec_simple_query函数的实现逻辑是什么”,在日常操作中,相信很多人在PostgreSQL中Review exec_simple_query函数的实现逻辑是什么问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”PostgreSQL中Review exec_simple_query函数的实现逻辑是什么”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
源码解读
exec_simple_query函数由PostgresMain函数调用,其调用栈如下:
#3 0x00000000008c5c35 in exec_simple_query (query_string=0x2eed1a8 "select * from t1;") at postgres.c:1050
#4 0x00000000008ca0f8 in PostgresMain (argc=1, argv=0x2f16cb8, dbname=0x2f16b20 "testdb", username=0x2ee9d48 "xdb")
at postgres.c:4159
#5 0x0000000000825880 in BackendRun (port=0x2f0eb00) at postmaster.c:4361
#6 0x0000000000824fe4 in BackendStartup (port=0x2f0eb00) at postmaster.c:4033
#7 0x0000000000821371 in ServerLoop () at postmaster.c:1706
#8 0x0000000000820c09 in PostmasterMain (argc=1, argv=0x2ee7d00) at postmaster.c:1379
#9 0x0000000000747ea7 in main (argc=1, argv=0x2ee7d00) at main.c:228
该函数的实现逻辑详见代码注释.
static void
exec_simple_query(const char *query_string)
{
CommandDest dest = whereToSendOutput;//输出到哪里的定义
MemoryContext oldcontext;//存储原内存上下文
List *parsetree_list;//分析树列表
ListCell *parsetree_item;//分析树中的ITEM
bool save_log_statement_stats = log_statement_stats;//是否保存统计信息,false
bool was_logged = false;//Log?
bool use_implicit_block;//是否使用隐式事务块
char msec_str[32];
debug_query_string = query_string;
pgstat_report_activity(STATE_RUNNING, query_string);//统计信息
TRACE_POSTGRESQL_QUERY_START(query_string);
if (save_log_statement_stats)
ResetUsage();
start_xact_command();//启动事务
drop_unnamed_stmt();//清除未命名语句
oldcontext = MemoryContextSwitchTo(MessageContext);//切换内存上下文
parsetree_list = pg_parse_query(query_string);//解析输入的查询语句,获得解析树List(元素是RawStmt nodes)
//如需要记录日志,则Log这些信息
if (check_log_statement(parsetree_list))//日志记录
{
ereport(LOG,
(errmsg("statement: %s", query_string),
errhidestmt(true),
errdetail_execute(parsetree_list)));
was_logged = true;
}
MemoryContextSwitchTo(oldcontext);//切换回原内存上下文
//如果分析树条目>1,使用隐式事务块(多条SQL语句在同一个事务中)
use_implicit_block = (list_length(parsetree_list) > 1);
foreach(parsetree_item, parsetree_list)//
{
RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item);//分析树List中的元素为RawStmt指针类型
bool snapshot_set = false;//是否设置快照?
const char *commandTag;//命令标识
char completionTag[COMPLETION_TAG_BUFSIZE];//完成标记,如INSERT 0 1之类的字符串
List *querytree_list,//查询树List
*plantree_list;//执行计划List
Portal portal;//“门户”变量
DestReceiver *receiver;//目标接收端
int16 format;//
commandTag = CreateCommandTag(parsetree->stmt);//创建命令标记,插入数据则为INSERT
set_ps_display(commandTag, false);
BeginCommand(commandTag, dest);//do Nothing!
if (IsAbortedTransactionBlockState() &&
!IsTransactionExitStmt(parsetree->stmt))
ereport(ERROR,
(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
errmsg("current transaction is aborted, "
"commands ignored until end of transaction block"),
errdetail_abort()));
start_xact_command();//确认在事务中
if (use_implicit_block)
BeginImplicitTransactionBlock();//隐式事务,进入事务块
//如果在解析或者解析之前接收到取消的信号,则退出
CHECK_FOR_INTERRUPTS();
if (analyze_requires_snapshot(parsetree))//是否需要快照进行分析?增删改查均需要
{
PushActiveSnapshot(GetTransactionSnapshot());//活动快照入栈
snapshot_set = true;
}
oldcontext = MemoryContextSwitchTo(MessageContext);//切换内存上下文
//根据分析树获得查询树,返回List(元素为Query)
querytree_list = pg_analyze_and_rewrite(parsetree, query_string,
NULL, 0, NULL);
//根据查询树获取计划树,返回List(元素为PlannedStmt)
plantree_list = pg_plan_queries(querytree_list,
CURSOR_OPT_PARALLEL_OK, NULL);
//启用了快照,则出栈
if (snapshot_set)
PopActiveSnapshot();//
//如接收到取消信号,则退出
CHECK_FOR_INTERRUPTS();
portal = CreatePortal("", true, true);//创建匿名Portal变量
//该portal不在pg_cursors中出现
portal->visible = false;
PortalDefineQuery(portal,
NULL,
query_string,
commandTag,
plantree_list,
NULL);//给Portal变量赋值
PortalStart(portal, NULL, 0, InvalidSnapshot);//为PortalRun作准备
format = 0;
if (IsA(parsetree->stmt, FetchStmt))
{
FetchStmt *stmt = (FetchStmt *) parsetree->stmt;
if (!stmt->ismove)
{
Portal fportal = GetPortalByName(stmt->portalname);
if (PortalIsValid(fportal) &&
(fportal->cursorOptions & CURSOR_OPT_BINARY))
format = 1;
}
}
PortalSetResultFormat(portal, 1, &format);//设置结果返回的格式,默认为TEXT
//创建目标接收器(如使用psql则为:printtup DestReceiver)
receiver = CreateDestReceiver(dest);
if (dest == DestRemote)
SetRemoteDestReceiverParams(receiver, portal);
MemoryContextSwitchTo(oldcontext);//
(void) PortalRun(portal,
FETCH_ALL,
true,
true,
receiver,
receiver,
completionTag);//执行
//执行完毕,销毁接收器
receiver->rDestroy(receiver);
//清除Portal中的资源
PortalDrop(portal, false);
if (lnext(parsetree_item) == NULL)//所有语句已执行完毕
{
if (use_implicit_block)
EndImplicitTransactionBlock();//结束事务
finish_xact_command();//结束事务
}
else if (IsA(parsetree->stmt, TransactionStmt))//事务语句?BEGIN/COMMIT/ABORT...
{
finish_xact_command();
}
else
{
CommandCounterIncrement();//命令+1(对应Tuple中的cid)
}
EndCommand(completionTag, dest);//命令Done
}
//所有语句结束
finish_xact_command();
if (!parsetree_list)
NullCommand(dest);
switch (check_log_duration(msec_str, was_logged))
{
case 1:
ereport(LOG,
(errmsg("duration: %s ms", msec_str),
errhidestmt(true)));
break;
case 2:
ereport(LOG,
(errmsg("duration: %s ms statement: %s",
msec_str, query_string),
errhidestmt(true),
errdetail_execute(parsetree_list)));
break;
}
if (save_log_statement_stats)
ShowUsage("QUERY STATISTICS");
TRACE_POSTGRESQL_QUERY_DONE(query_string);
debug_query_string = NULL;
}
到此,关于“PostgreSQL中Review exec_simple_query函数的实现逻辑是什么”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注亿速云网站,小编会继续努力为大家带来更多实用的文章!