您好,登錄后才能下訂單哦!
這篇文章主要介紹“PostgreSQL中Review exec_simple_query函數(shù)的實(shí)現(xiàn)邏輯是什么”,在日常操作中,相信很多人在PostgreSQL中Review exec_simple_query函數(shù)的實(shí)現(xiàn)邏輯是什么問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”PostgreSQL中Review exec_simple_query函數(shù)的實(shí)現(xiàn)邏輯是什么”的疑惑有所幫助!接下來,請跟著小編一起來學(xué)習(xí)吧!
exec_simple_query函數(shù)由PostgresMain函數(shù)調(diào)用,其調(diào)用棧如下:
#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
該函數(shù)的實(shí)現(xiàn)邏輯詳見代碼注釋.
/* * exec_simple_query * * Execute a "simple Query" protocol message. * 響應(yīng)并執(zhí)行"simple Query"協(xié)議消息請求 */ /* 輸入: query_string-SQL語句 輸出: 無 */ static void exec_simple_query(const char *query_string) { CommandDest dest = whereToSendOutput;//輸出到哪里的定義 MemoryContext oldcontext;//存儲原內(nèi)存上下文 List *parsetree_list;//分析樹列表 ListCell *parsetree_item;//分析樹中的ITEM bool save_log_statement_stats = log_statement_stats;//是否保存統(tǒng)計(jì)信息,false bool was_logged = false;//Log? bool use_implicit_block;//是否使用隱式事務(wù)塊 char msec_str[32]; /* * Report query to various monitoring facilities. * 監(jiān)控信息 */ debug_query_string = query_string; pgstat_report_activity(STATE_RUNNING, query_string);//統(tǒng)計(jì)信息 TRACE_POSTGRESQL_QUERY_START(query_string); /* * We use save_log_statement_stats so ShowUsage doesn't report incorrect * results because ResetUsage wasn't called. * 如save_log_statement_stats為T,則調(diào)用ResetUsage函數(shù) */ if (save_log_statement_stats) ResetUsage(); /* * Start up a transaction command. All queries generated by the * query_string will be in this same command block, *unless* we find a * BEGIN/COMMIT/ABORT statement; we have to force a new xact command after * one of those, else bad things will happen in xact.c. (Note that this * will normally change current memory context.) * 啟動一個事務(wù)命令。 * 由query_string生成的所有查詢都將位于同一個命令塊中,*除非*找到BEGIN/COMMIT/ABORT語句; * 必須在其中一個命令之后強(qiáng)制執(zhí)行新的xact命令,否則xact.c中會發(fā)生意想不到事情。 * (注意,這通常會改變當(dāng)前內(nèi)存上下文。) */ start_xact_command();//啟動事務(wù) /* * Zap any pre-existing unnamed statement. (While not strictly necessary, * it seems best to define simple-Query mode as if it used the unnamed * statement and portal; this ensures we recover any storage used by prior * unnamed operations.) * 刪除任何預(yù)先存在的未命名語句。 * (雖然不是嚴(yán)格必要的,但最好定義簡單查詢模式,就像使用未命名語句和門戶接口一樣; * 這確保我們恢復(fù)以前未命名操作所使用的存儲信息。) */ drop_unnamed_stmt();//清除未命名語句 /* * Switch to appropriate context for constructing parsetrees. * 切換至合適的內(nèi)存上下文 */ oldcontext = MemoryContextSwitchTo(MessageContext);//切換內(nèi)存上下文 /* * Do basic parsing of the query or queries (this should be safe even if * we are in aborted transaction state!) * 執(zhí)行查詢(或多個查詢)的基本解析 * (即使我們處于中止的事務(wù)狀態(tài),這也應(yīng)該是安全的!) */ parsetree_list = pg_parse_query(query_string);//解析輸入的查詢語句,獲得解析樹List(元素是RawStmt nodes) /* Log immediately if dictated by log_statement */ //如需要記錄日志,則Log這些信息 if (check_log_statement(parsetree_list))//日志記錄 { ereport(LOG, (errmsg("statement: %s", query_string), errhidestmt(true), errdetail_execute(parsetree_list))); was_logged = true; } /* * Switch back to transaction context to enter the loop. * 切換回去原事務(wù)上下文 */ MemoryContextSwitchTo(oldcontext);//切換回原內(nèi)存上下文 /* * For historical reasons, if multiple SQL statements are given in a * single "simple Query" message, we execute them as a single transaction, * unless explicit transaction control commands are included to make * portions of the list be separate transactions. To represent this * behavior properly in the transaction machinery, we use an "implicit" * transaction block. * 由于歷史原因,如果在單個“簡單查詢”消息中給出了多個SQL語句,那么我們將作為單個事務(wù)執(zhí)行它們, * 除非包含顯式事務(wù)控制命令,使鏈表中的部分成為單獨(dú)的事務(wù)。 * 為了在事務(wù)機(jī)制中正確地表示這種行為,使用了一個“隱式”事務(wù)塊。 */ //如果分析樹條目>1,使用隱式事務(wù)塊(多條SQL語句在同一個事務(wù)中) use_implicit_block = (list_length(parsetree_list) > 1); /* * Run through the raw parsetree(s) and process each one. * 對分析樹中的每一個條目進(jìn)行處理 */ foreach(parsetree_item, parsetree_list)// { RawStmt *parsetree = lfirst_node(RawStmt, parsetree_item);//分析樹List中的元素為RawStmt指針類型 bool snapshot_set = false;//是否設(shè)置快照? const char *commandTag;//命令標(biāo)識 char completionTag[COMPLETION_TAG_BUFSIZE];//完成標(biāo)記,如INSERT 0 1之類的字符串 List *querytree_list,//查詢樹List *plantree_list;//執(zhí)行計(jì)劃List Portal portal;//“門戶”變量 DestReceiver *receiver;//目標(biāo)接收端 int16 format;// /* * Get the command name for use in status display (it also becomes the * default completion tag, down inside PortalRun). Set ps_status and * do any special start-of-SQL-command processing needed by the * destination. * 獲取用于狀態(tài)顯示的命令名稱(在PortalRun內(nèi)部,它也成為默認(rèn)的完成標(biāo)記)。 * 設(shè)置ps_status并執(zhí)行目標(biāo)語句所需要的start-of-SQL-command處理。 */ commandTag = CreateCommandTag(parsetree->stmt);//創(chuàng)建命令標(biāo)記,插入數(shù)據(jù)則為INSERT set_ps_display(commandTag, false); BeginCommand(commandTag, dest);//do Nothing! /* * If we are in an aborted transaction, reject all commands except * COMMIT/ABORT. It is important that this test occur before we try * to do parse analysis, rewrite, or planning, since all those phases * try to do database accesses, which may fail in abort state. (It * might be safe to allow some additional utility commands in this * state, but not many...) * 如果我們處于事務(wù)中止?fàn)顟B(tài)中,拒絕除COMMIT/ABORT之外的所有命令。 * 在嘗試進(jìn)行解析分析、重寫或計(jì)劃之前進(jìn)行此測試是很重要的, * 因?yàn)樗羞@些階段都嘗試進(jìn)行數(shù)據(jù)庫訪問,而在abort狀態(tài)下可能會失敗。 * (在這種狀態(tài)下允許一些額外的實(shí)用程序命令可能是安全的,但不是很多……) */ 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())); /* Make sure we are in a transaction command */ start_xact_command();//確認(rèn)在事務(wù)中 /* * If using an implicit transaction block, and we're not already in a * transaction block, start an implicit block to force this statement * to be grouped together with any following ones. (We must do this * each time through the loop; otherwise, a COMMIT/ROLLBACK in the * list would cause later statements to not be grouped.) * 如果使用隱式事務(wù)塊(還沒有使用atransaction塊),啟動一個隱式事務(wù)塊來強(qiáng)制將該語句與以下語句組合在一起。 * (我們每次通過循環(huán)時都必須這樣做;否則,鏈表中的提交/回滾將導(dǎo)致后面的語句沒有分組。 */ if (use_implicit_block) BeginImplicitTransactionBlock();//隱式事務(wù),進(jìn)入事務(wù)塊 /* If we got a cancel signal in parsing or prior command, quit */ //如果在解析或者解析之前接收到取消的信號,則退出 CHECK_FOR_INTERRUPTS(); /* * Set up a snapshot if parse analysis/planning will need one. * 如果解析/分析/計(jì)劃過程需要snapshot,則創(chuàng)建一個 */ if (analyze_requires_snapshot(parsetree))//是否需要快照進(jìn)行分析?增刪改查均需要 { PushActiveSnapshot(GetTransactionSnapshot());//活動快照入棧 snapshot_set = true; } /* * OK to analyze, rewrite, and plan this query. * 準(zhǔn)備工作妥當(dāng),可以進(jìn)行分析/重寫和計(jì)劃查詢語句了 * * Switch to appropriate context for constructing querytrees (again, * these must outlive the execution context). * 切換至合適的內(nèi)存上下文中 */ oldcontext = MemoryContextSwitchTo(MessageContext);//切換內(nèi)存上下文 //根據(jù)分析樹獲得查詢樹,返回List(元素為Query) querytree_list = pg_analyze_and_rewrite(parsetree, query_string, NULL, 0, NULL); //根據(jù)查詢樹獲取計(jì)劃樹,返回List(元素為PlannedStmt) plantree_list = pg_plan_queries(querytree_list, CURSOR_OPT_PARALLEL_OK, NULL); /* Done with the snapshot used for parsing/planning */ //啟用了快照,則出棧 if (snapshot_set) PopActiveSnapshot();// /* If we got a cancel signal in analysis or planning, quit */ //如接收到取消信號,則退出 CHECK_FOR_INTERRUPTS(); /* * Create unnamed portal to run the query or queries in. If there * already is one, silently drop it. * 創(chuàng)建匿名的門戶接口來執(zhí)行查詢,如Portal已存在,則先drop it */ portal = CreatePortal("", true, true);//創(chuàng)建匿名Portal變量 /* Don't display the portal in pg_cursors */ //該portal不在pg_cursors中出現(xiàn) portal->visible = false; /* * We don't have to copy anything into the portal, because everything * we are passing here is in MessageContext, which will outlive the * portal anyway. * 不需要將任何內(nèi)容復(fù)制到Portal中, * 因?yàn)樵谶@里傳遞的所有內(nèi)容都在MessageContext中,它的生命周期將比Portal更長。 */ PortalDefineQuery(portal, NULL, query_string, commandTag, plantree_list, NULL);//給Portal變量賦值 /* * Start the portal. No parameters here. * 啟動Portal,不需要參數(shù) */ PortalStart(portal, NULL, 0, InvalidSnapshot);//為PortalRun作準(zhǔn)備 /* * Select the appropriate output format: text unless we are doing a * FETCH from a binary cursor. (Pretty grotty to have to do this here * --- but it avoids grottiness in other places. Ah, the joys of * backward compatibility...) * 選擇適當(dāng)?shù)妮敵龈袷?文本,除了我們正在從二進(jìn)制游標(biāo)進(jìn)行提取。 * (不得不在這里這樣做實(shí)在是太糟糕了——但在其他地方卻避免了這種情況。啊,向后兼容的樂趣…… */ format = 0; /* 默認(rèn)為TEXT;TEXT is default */ 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; /* 二進(jìn)制格式;BINARY */ } } PortalSetResultFormat(portal, 1, &format);//設(shè)置結(jié)果返回的格式,默認(rèn)為TEXT /* * Now we can create the destination receiver object. * 現(xiàn)在可以創(chuàng)建目標(biāo)接收器對象了 */ //創(chuàng)建目標(biāo)接收器(如使用psql則為:printtup DestReceiver) receiver = CreateDestReceiver(dest); if (dest == DestRemote) SetRemoteDestReceiverParams(receiver, portal); /* * Switch back to transaction context for execution. * 切換回原內(nèi)存上下文 */ MemoryContextSwitchTo(oldcontext);// /* * Run the portal to completion, and then drop it (and the receiver). * 執(zhí)行PortalRun,然后清除 */ (void) PortalRun(portal, FETCH_ALL, true, /* always top level */ true, receiver, receiver, completionTag);//執(zhí)行 //執(zhí)行完畢,銷毀接收器 receiver->rDestroy(receiver); //清除Portal中的資源 PortalDrop(portal, false); if (lnext(parsetree_item) == NULL)//所有語句已執(zhí)行完畢 { /* * If this is the last parsetree of the query string, close down * transaction statement before reporting command-complete. This * is so that any end-of-transaction errors are reported before * the command-complete message is issued, to avoid confusing * clients who will expect either a command-complete message or an * error, not one and then the other. Also, if we're using an * implicit transaction block, we must close that out first. * 如果這是查詢字符串的最后一個parsetree,在報(bào)告命令完成之前關(guān)閉事務(wù)語句。 * 這樣,在發(fā)出命令完整的消息之前就會報(bào)告任何事務(wù)結(jié)束錯誤,以避免混淆視聽, * 因?yàn)榭蛻舳讼M吹矫钔暾南⒒蝈e誤,而不是一個錯誤,然后是另一個錯誤。 * 另外,如果我們使用隱式事務(wù)塊,我們必須首先關(guān)閉它。 */ if (use_implicit_block) EndImplicitTransactionBlock();//結(jié)束事務(wù) finish_xact_command();//結(jié)束事務(wù) } else if (IsA(parsetree->stmt, TransactionStmt))//事務(wù)語句?BEGIN/COMMIT/ABORT... { /* * If this was a transaction control statement, commit it. We will * start a new xact command for the next command. * 如果這是一個事務(wù)控制語句,提交此語句。 * 我們將為下一個命令啟動一個新的xact命令。 */ finish_xact_command(); } else { /* * We need a CommandCounterIncrement after every query, except * those that start or end a transaction block. * 在每次查詢之后,我們都需要一個CommandCounterIncrement,除了那些啟動或結(jié)束事務(wù)塊的查詢。 */ CommandCounterIncrement();//命令+1(對應(yīng)Tuple中的cid) } /* * Tell client that we're done with this query. Note we emit exactly * one EndCommand report for each raw parsetree, thus one for each SQL * command the client sent, regardless of rewriting. (But a command * aborted by error will not send an EndCommand report at all.) * 告訴客戶端已經(jīng)完成了這個查詢。注意,對于每個原始的parsetree,只發(fā)出一個EndCommand報(bào)告, * 因此,對于客戶機(jī)發(fā)送的每個SQL命令,只發(fā)出一個EndCommand報(bào)告,而不考慮重寫。 * (注:由于錯誤而中止的命令根本不會發(fā)送EndCommand報(bào)告。) */ EndCommand(completionTag, dest);//命令Done } /* end loop over parsetrees */ //所有語句結(jié)束 /* * Close down transaction statement, if one is open. (This will only do * something if the parsetree list was empty; otherwise the last loop * iteration already did it.) * 如果事務(wù)是打開的,則關(guān)閉。 * (只有當(dāng)parsetree鏈表為空時,才會執(zhí)行某些操作;否則,最后一次循環(huán)迭代已經(jīng)完成了。 */ finish_xact_command(); /* * If there were no parsetrees, return EmptyQueryResponse message. * 如果parsetrees鏈表已清空,返回EmptyQueryResponse消息 */ if (!parsetree_list) NullCommand(dest); /* * Emit duration logging if appropriate. * 如需要記錄日志,則在合適的時候記錄 */ 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; }
到此,關(guān)于“PostgreSQL中Review exec_simple_query函數(shù)的實(shí)現(xiàn)邏輯是什么”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識,請繼續(xù)關(guān)注億速云網(wǎng)站,小編會繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。