<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                # 48.2\. 消息流 本節描述消息流,以及每種消息類型的語意(每種消息的準確表現細節在[Section 48.5](#calibre_link-1026)里)。 因連接的狀態不同,存在幾種不同的子協議:啟動、查詢、函數調用、`COPY` 、結束。 還有用于異步操作(包括通知響應和命令取消)的特殊規定,這些異步操作可能在啟動階段過后的任何時間產生。 ## 48.2.1\. 啟動 要開始一個會話,前端打開一個與服務器的連接并且發送一個啟動消息。 這個消息包括用戶名以及用戶希望與之連接的數據庫;它還標識要使用的特定的協議版本。 (另外,啟動消息可以包括用于運行時參數的額外設置。) 服務器然后就使用這些信息以及它的配置文件的內容(比如 `pg_hba.conf`)以判斷這個連接是否可以接受,以及需要什么樣的額外的認證(如果有)。 然后服務器就發送合適的認證請求消息,前端必須用合適的認證響應消息來響應(比如一個口令)。 對所有的認證方法,除了GSSAPI和SSPI,最多只有一次請求和響應。 有些認證方法則根本不需要前端的響應,因此就沒有認證請求發生。 對于GSSAPI和SSPI,為了完成認證則可能需要多次數據包的交換。 認證周期的結束要么是服務器拒絕連接(ErrorResponse),要么是服務器發送AuthenticationOk消息。 這個階段來自服務器可能消息是: ErrorResponse 連接請求被拒絕。然后服務器馬上關閉連接。 AuthenticationOk 認證信息的交換成功完成。 AuthenticationKerberosV5 現在前端必須與服務器進行一次 KerberosV5 認證對話(是Kerberos規范的一部分,在這里沒有描述)。 如果對話成功,服務器響應一個 AuthenticationOk消息,否則它響應一個 ErrorResponse消息。 AuthenticationCleartextPassword 現在前端必須發送一個包含明文口令的 PasswordMessage包。 如果這是正確的口令,服務器用一個 AuthenticationOk 包響應,否則它響應一個 ErrorResponse 包。 AuthenticationMD5Password 現在前端必須發送一個包含用 MD5 加密的口令(包括用戶名)的 PasswordMessage ,加密時使用在 AuthenticationMD5Password 消息里指定的 4 字節隨機鹽粒。 如果這是正確口令,服務器用一個 AuthenticationOk 響應,否則它用一個 ErrorResponse 響應。 實際的PasswordMessage可以通過SQL語句`concat('md5',md5(concat(md5(concat(password, username)), random-salt)))`計算得到。 (注意`md5()` 函數的返回值是16進制表示的字符串。) AuthenticationSCMCredential 這個響應只會在那些支持 SCM 信任消息的本地 Unix 域連接上出現。 前端必須發出一條 SCM 信任消息然后發送一個數據字節。 (數據字節的內容并不會被關心;它的作用只是確保服務器等待了足夠長的時間來接受信任信息。) 如果信任是可以接受的,那么服務器用 AuthenticationOk 響應,否則用 ErrorResponse 響應。 (只有9.1以前的服務器才可能發出這個消息,并且這個消息最終可能會被從協議中刪除。) AuthenticationGSS 現在前端必須發起一個GSSAPI協商。 作為響應前端將隨著GSSAPI數據流的最初部分發送一個PasswordMessage包。 如果需要進一步的消息,服務端將以AuthenticationGSSContinue作為響應。 AuthenticationSSPI 現在前端必須發起一個SSPI協商。 作為響應前端將隨著SSPI數據流的最初部分發送一個PasswordMessage包。 如果需要進一步的消息,服務端將以AuthenticationGSSContinue作為響應。 AuthenticationGSSContinue 這個消息包含GSSAPI或SSPI協商的上一個步驟(AuthenticationGSS, AuthenticationSSPI或前一個AuthenticationGSSContinue)的響應數據。 如果這個消息中的GSSAPI或SSPI數據指示需要更多的數據以完成認證過程,前端必須用另一個PasswordMessage包發送這些數據。 如果通過這個消息GSSAPI或SSPI認證已完成,服務端下次將發送AuthenticationOk指示認證成功或ErrorResponse指示認證失敗。 如果前端不支持服務器要求的認證方式,那么它應該馬上關閉連接。 在收到 AuthenticationOk 包之后,前端必須等待來自后端的更多消息。 在這個階段會啟動一個后端進程,而前端只是一個感興趣的看熱鬧的。 啟動嘗試仍然有可能失敗 (ErrorResponse),但是通常情況下,后端將發送一些 ParameterStatus 消息、BackendKeyData 、最后是 ReadyForQuery 。 在這個階段,后端將嘗試應用任何在啟動消息里給出的額外的運行時參數設置。 如果成功,這些值將成為會話的缺省值。錯誤將導致 ErrorResponse 并退出。 這個階段來自后端的可能消息是: BackendKeyData 這個消息提供了密鑰(secret-key)數據,前端如果想要在稍后發出取消的請求,則必須保存這個數據。 前端不應該響應這個消息,但是應該繼續偵聽等待 ReadyForQuery 消息。 ParameterStatus 這個消息告訴前端有關后端參數的當前(初始化)設置,比如 [client_encoding](#calibre_link-1030) 或 [DateStyle](#calibre_link-787) 等。 前端可以忽略這個消息,或者記錄其設置用于將來使用;參閱[Section 48.2.6](#calibre_link-1020)獲取更多細節。 前端不應該響應這個消息,而是應該繼續偵聽 ReadyForQuery 消息。 ReadyForQuery 后端啟動成功,前端現在可以發出命令。 ErrorResponse 后端啟動失敗。在發送完這個消息之后連接被關閉。 NoticeResponse 發出了一個警告消息。前端應該顯示這個消息,并且繼續等待 ReadyForQuery 或 ErrorResponse 。 后端在每個查詢循環后都會發出一個相同的 ReadyForQuery 消息。 前端可以合理地認為 ReadyForQuery 是一個查詢循環的開始, 或者認為 ReadyForQuery 是啟動階段和每個隨后查詢循環的結束,具體是哪種情況取決于前端的編碼需要。 ## 48.2.2\. 簡單查詢 一個查詢循環是由前端發送一條 Query 消息給后端進行初始化的。 這條消息包含一個用文本字符串表示的 SQL 命令(或者一些命令)。 后端根據查詢命令字符串的內容發送一條或者更多條響應消息給前端,并且最后是一條 ReadyForQuery 響應消息。 ReadyForQuery 通知前端它可以安全地發送新命令了。 (實際上前端不必在發送其它命令之前等待 ReadyForQuery ,但是這樣一來,前端必須負責區分早先發出的命令失敗,而稍后發出的命令成功的情況。) 從后端來的可能的消息是: CommandComplete 一個 SQL 命令正常結束 CopyInResponse 后端已經準備好從前端拷貝數據到一個表里面去。又見[Section 48.2.5](#calibre_link-1019)。 CopyOutResponse 后端已經準備好從一個表里拷貝數據到前端里面去。又見[Section 48.2.5](#calibre_link-1019)。 RowDescription 表示為了響應一個 `SELECT`, `FETCH` 等的查詢,將要返回一個行。 這條消息的內容描述了這行的字段布局。這條消息后面將跟著每個返回給前端的行一個的 DataRow 消息。 DataRow `SELECT`, `FETCH` 等查詢返回的結果集中的一行。 EmptyQueryResponse 識別了一個空的查詢字符串。 ErrorResponse 出錯了。 ReadyForQuery 查詢字符串的處理完成。發送一個獨立的消息來標識這個是因為查詢字符串可能包含多個 SQL 命令。 (CommandComplete 只是標記一條 SQL 命令處理完畢,而不是整個字符串。) ReadyForQuery 總會被發送,不管是處理成功結束還是產生錯誤。 NoticeResponse 發送了一個與查詢有關的警告消息。注意警告消息是附加在其它響應上的,也就是說,后端將繼續處理該命令。 `SELECT`(或其它返回結果集的查詢,比如 `EXPLAIN` 或 `SHOW`)查詢的響應通常包含 RowDescription ,零個或者多個 DataRow 消息,以及最后的 CommandComplete 。 從或者到前端的 `COPY` 使用[Section 48.2.5](#calibre_link-1019)里提到的特殊的協議。所有其它查詢類型通常只生成一個 CommandComplete 消息。 因為查詢字符串可能包含若干個查詢(用分號分隔),所以在后端完成查詢字符串的處理之前可能有好幾個這樣的響應序列。 如果整個字符串已經處理完,后端已經準備好接受新查詢字符串的時候則發出 ReadyForQuery 消息。 如果收到一個完全空(除了空白之外沒有內容)的查詢字符串,那么響應是一條 EmptyQueryResponse 后面跟著 ReadyForQuery 。 在出現錯誤的時候,發出一個 ErrorResponse 消息,后面跟著 ReadyForQuery 。 查詢字符串的所有后繼的處理都被 ErrorResponse 中止(即使里面還有查詢也這么干)。 請注意這些事情可能在處理一個查詢產生的消息序列的中途發生。 在簡單查詢模式,檢索出來的數值的格式總是文本的,除非給出的命令是從一個聲明了`BINARY`選項的游標上的`FETCH` 。 在這種情況下,檢索出來的數值是二進制格式的。在 RowDescription 消息里給出的格式代碼告訴用了哪種格式。 前端在等待其它類型的消息時必須準備接收 ErrorResponse 和 NoticeResponse 消息。 參閱[Section 48.2.6](#calibre_link-1020)后端因為外部的事件可能生成的消息。 建議的方法是把前端代碼寫成狀態機的風格,它可以在任何時刻接受任何有意義的消息,而不是寫成假設消息的準確序列的代碼。 ## 48.2.3\. 擴展查詢 擴展的查詢協議把上面描述的簡單協議分裂成若干個步驟。準備的步驟可以多次復用以提高效率。 另外,還可以獲得額外的特性,比如把數據值作為獨立的參數提供的可能性,而不是把它們直接插入一個查詢字符串。 在擴展的協議里,前端首先發送一個 Parse 消息,它包含一個文本查詢字符串,另外還有一些有關參數占位符的數據類型的信息,以及一個最終預備語句對象的名字(一個空字符串選擇未命名的預備語句)。 響應要么是一個 ParseComplete 要么是 ErrorResponse 。參數數據類型可以用 OID 來聲明;如果沒有給出,那么分析器將試圖用它對付無類型的字符串常量的方法來推導其數據類型。 > **Note:** 一個參數數據類型可以通過設置為零,或者讓參數類型 OID 的數目比查詢字符串里的參數符號(`$``_n_`)的數目少的方法不予聲明。 另外一個特例是參數的類型可以聲明為 `void`(也就是偽類型 `void` 的 OID)。 這是為了允許用于某些函數參數的參數符號實際上是 OUT 參數。 通常情況下,沒有什么環境會用到 `void` 參數,但是如果在函數的參數列表里出現了這么一個參數符號,那么它實際上會被忽略。 比如,一個像這樣的函數調用:`foo($1,$2,$3,$4)`,如果`$3`和`$4`聲明為類型是 `void` ,那么這個函數調用可以匹配一個帶有兩個 IN 和兩個 OUT 參數的函數。 > **Note:** 在一個 Parse 消息里包含的查詢字符串不能包含超過一個 SQL 語句;否則就會報告一個語法錯誤。 這個限制在簡單查詢協議中并不存在,但是它存在于擴展的協議中,因為允許預備語句或者入口包含多個命令將導致協議過度地復雜。 如果成功創建了一個命名的預備語句對象,那么它將持續到當前會話結束,除非明確刪除。 一個未命名的預備語句只持續到下一個聲明未命名的語句的 Parse 語句發出為止(請注意一個簡單的查詢消息也刪除未命名語句)。 命名的預備語句必須明確地關閉,然后才能用一個 Parse 消息重新定義,但是未命名的語句并不要求這個動作。 命名的預備語句也可以在 SQL 命令級創建和訪問,方法是使用 `PREPARE` 和 `EXECUTE`。 只要預備語句還存在,那么就可以使用 Bind 消息很容易地使之進入執行狀態。 Bind 消息給出源預備語句的名字(空字符串表示未命名的預備語句),目標入口的名字(空字符串表示未命名的入口),以及用于那些在預備語句中出現的所有參數占位符的數值。 提供的參數集必須匹配那些預備語句需要的東西。(如果你在 Parse 消息里聲明任何 `void` 參數,那么在 Bind 消息里給它們傳遞 NULL 值。) Bind 還聲明用于查詢返回的任何數據的格式;格式可以一次聲明,也可以每個字段進行聲明。響應要么是 BindComplete 要么是 ErrorResponse 。 > **Note:** 輸出的格式是文本還是二進制是由 Bind 里給出的格式代碼決定的,不管用的是什么 SQL 命令。 在使用擴展的查詢協議的時候,游標聲明里的 `BINARY` 屬性是不起作用的。 典型的查詢計劃在處理Bind消息后生成。 預備語句如果不包含參數,或者被反復執行的情況下,服務端可能會保存創建好的查詢計劃并在后續的針對同樣的Bind消息中重用它。 但是,只有確保這樣作成的通用的查詢計劃不至于比依賴于特定參數值的查詢計劃效率差太多的情況下,服務端才會這么做。 就協議而言這些是透明的。 如果成功創建了一個命名的入口對象,那么它將持續到當前會話結束,除非明確刪除。 一個未命名的入口只持續到事務結束或下一個聲明未命名的入口的 Bind消息發出為止(請注意一個簡單的查詢消息也刪除未命名入口)。 命名的入口必須明確地關閉,然后才能用另一個 Bind 消息重新定義,但是未命名的語句并不要求這個動作。 命名的入口也可以在 SQL 命令級創建和訪問,方法是使用`DECLARE CURSOR`和`FETCH`。 只要存在一個入口,那么就可以用一個 Execute 消息執行它。 Execute 消息聲明入口的名字(空字符串表示未命名入口)和一個最大的結果行計數(零表示"抓取所有行")。 結果行計數只對包含返回結果集的入口有意義;在其它情況下,該命令總是執行到結束,而行計數會被忽略。 Execute 可能的響應和那些通過簡單查詢協議發出的查詢一樣,只不過 Execute 不會導致后端發出 ReadyForQuery 或者 RowDescription 。 如果 Execute 在一個入口的執行完成之前終止(因為達到了一個非零的結果行計數),它將發送一個 PortalSuspended 消息;這個消息的出現告訴前端應該在同一個入口上發出另外一個 Execute 以完成操作。 在入口的執行完成之前,不會發出表示源 SQL 命令結束的 CommandComplete 消息。 因此 Execute 階段的結束總是由出現下列之一的消息標志的:CommandComplete 、EmptyQueryResponse(如果入口是從一個空字符串創建出來的)、ErrorResponse 、PortalSuspended 。 每個擴展查詢消息序列完成后,前端都應該發出一條 Sync 消息。 這個無參數的消息導致后端關閉當前事務——如果當前事務不是在一個`BEGIN`/`COMMIT`事務塊中的話("關閉"的意思就是在沒有錯誤的情況下提交,或者是有錯誤的情況下回滾)。 然后響應一條 ReadyForQuery 消息。Sync 的目的是提供一個錯誤恢復的重新同步的點。 如果在處理任何擴展查詢消息的時候偵測到任何錯誤,那么后端發出 ErrorResponse ,然后讀取并拋棄消息,直到一個 sync 的到來,然后發出 ReadyForQuery 并且返回到正常的消息處理中。 (但是要注意如果_正在_處理 Sync 的時候發生了錯誤,那么不會忽略任何東西 —這樣就保證了為每個 Sync 發出一個并且只有一個的 ReadyForQuery 。 > **Note:** Sync 并不導致一個用`BEGIN`打開的事務塊關閉。可以偵測到這種情況,因為 ReadyForQuery 消息包含事務狀態信息。 除了這些基本的,必須的操作之外,在擴展查詢協議里還有幾種可選的操作可以使用。 Describe 消息(入口變體)指定一個現有的入口的名字(如果是一個未命名的入口則是一個空字符串)。 響應是一個 RowDescription 消息,它描述了執行入口將要返回的行;或者是一個 NoData 消息(如果入口并不包含會返回行的查詢);或者是一個 ErrorResponse(如果沒有這個入口)。 Describe 消息(語句變體)指定一個現有的預備語句的名字(如果是一個未命名的預備語句則是一個空字符串)。 響應是一個描述該語句需要的參數的 ParameterDescription 消息,后面跟著一個描述語句最終執行后返回的行的 RowDescription 消息(或者是 NoData 消息,如果該語句不返回行)。 如果沒有這樣的預備語句,則返回 ErrorResponse 。 請注意因為還沒有發出 Bind ,所以后端還不知道用于返回字段的格式;在這種情況下,RowDescription 消息里面的格式代碼字段將是零。 > **Tip:** 在大多數情況下,前端在發出 Execute 之前應該發出某種 Describe 的變體,以保證它知道如何解析它將得到的結果。 Close 消息關閉一個現有的預備語句或者入口,并且釋放資源。 對一個不存在的語句或者入口名字發出 Close 不是一個錯誤。 響應通常是 CloseComplete ,但如果在釋放資源的時候發生了一些困難也可以是 ErrorResponse 。 請注意關閉一個預備語句隱含地關閉任何從該語句構造出來的打開的入口。 Flush 消息并不導致任何特定的輸出的生成,但是強制后端發送任何還在它的輸出緩沖區中停留的數據。 Flush 必須在除 Sync 外的任何擴展查詢命令后面發出(如果前端希望在發出更多的命令之前檢查該命令的結果的話)。 如果不 Flush ,后端返回的消息將組合成最小可能的數據包個數,以減少網絡負荷。 > **Note:** 簡單查詢消息大概等于一系列使用未命名的預備語句和無參數的入口對象的 Parse 、Bind 、入口 Describe 、Execute 、Close 、Sync 。 一個區別是它會在查詢字符串中接受多個 SQL 語句,并在會話中為每個語句自動執行綁定/描述/執行序列。 另外一個區別是它不會返回 ParseComplete 、Bindcomplete 、CloseComplete 、NoData 消息。 ## 48.2.4\. 函數調用 函數調用子協議允許客戶端請求一個對存在于數據庫`pg_proc`系統表中的任意函數的直接調用。 客戶端必須在該函數上有執行的權限。 > **Note:** 函數調用子協議是一個遺留的特性,在新代碼里最好避免用它。 類似的結果可以通過設置一個`SELECT function($1, ...)`預備語句獲得。 這樣函數調用循環就可以用 Bind/Execute 代替。 一個函數調用循環是由前端向后端發送一條 FunctionCall 消息初始化的。 然后后端根據函數調用的結果發送一條或者更多響應消息,并且在最后是一條 ReadyForQuery 響應消息。 ReadyForQuery 通知前端它可以安全地發送一條新的查詢或者函數調用了。 從后端來的可能的消息是: ErrorResponse 發生了一個錯誤。 FunctionCallResponse 函數調用完成并且在消息中返回一個結果。 (請注意,函數調用協議只能處理單個標量結果,不能處理行類型或者結果集。) ReadyForQuery 函數調用處理完成。ReadyForQuery 將總是被發送,不管是成功完成處理還是發生了一個錯誤。 NoticeResponse 發出了一條有關該函數調用的警告消息。通知是附加在其它響應上的,也就是說,后端將繼續處理命令。 ## 48.2.5\. COPY操作 `COPY`命令允許在服務器和客戶端之間高速的大批量數據傳輸。 拷貝入和拷貝出操作每個都把連接切換到一個獨立的子協議中,并且持續到操作結束。 拷貝入模式(數據傳輸到服務器)是在后端執行一個`COPY FROM STDIN`語句的時候初始化的。 后端發送一個 CopyInResponse 消息給前端。 前端應該發送零條或者更多 CopyData 消息,形成一個輸出數據的流。 (消息的邊界和行的邊界沒有任何相關性要求,盡管通常那就是合理的邊界選擇。) 前端可以通過發送一個 CopyDone 消息來終止拷貝入操作(允許成功終止),也可以發出一個 CopyFail 消息(它將導致 `COPY` 語句帶著錯誤失敗)。 然后后端就恢復回它在 `COPY` 開始之前的命令處理模式,可能是簡單查詢協議,也可能是擴展查詢協議。 然后它會發送 CommandComplete(如果成功)或者 ErrorResponse(如果失敗)。 如果在拷貝入模式下后端檢測到了錯誤(包括接受接收到 CopyFiail 消息,或者是任何除了 CopyData 或者 CopyDone 之外的前端消息),那么后端將發出一個 ErrorResponse 消息。 如果`COPY` 命令是通過一個擴展的查詢消息發出的,那么后端從現在開始將拋棄前端消息,直到一個 Sync 消息到達,然后它將發出 ReadyForQuery 并且返回到正常的處理中。 如果`COPY` 命令是在一個簡單查詢消息里發出的,那么該消息剩余部分被丟棄然后發出 ReadyForQuery 消息。 不管是哪種情況,任何前端發出的 CopyData, CopyDone, CopyFail 消息都將被簡單地拋棄。 后端將會忽略拷貝入模式時接收到的 Flush 和 Sync 消息。 收到任何其它非拷貝消息,會引發錯誤,如前所述這樣會導致退出拷貝入狀態。 (Flush 和 Sync 的例外是為了方便客戶端庫在執行 Execute 消息后始終發送 Flush 或 Sync 而不檢查所執行的命令是否是一個 COPY FROM STDIN 命令。) 拷貝出模式(數據從服務器發出)是在后端執行一個`COPY TO STDOUT`語句的時候初始化的。 后端發出一個 CopyOutResponse 消息給前端,后面跟著零或者多個 CopyData 消息(總是每行一個),然后跟著 CopyDone 。 然后后端回退到它在`COPY`開始之前的命令處理模式,然后發送 CommandComplete 。 前端不能退出傳輸(除非是關閉連接或者發出一個 Cancel 請求),但是它可以拋棄不需要的 CopyData 和 CopyDone 消息。 在拷貝出模式中,如果后端檢測到錯誤,那么它將發出一個 ErrorResponse 消息并且回到正常的處理。 前端應該把收到 ErrorResponse當作終止拷貝出模式的標志。 NoticeResponse和ParameterStatus消息有可能夾在CopyData消息間出現。 前端必須處理這種情況,并且也應該準備好處理其它異步消息(參閱[Section 48.2.6](#calibre_link-1020))。 除此以外,任何CopyData和CopyDone以外的消息應該被視作拷貝出模式的中止。 還有一個拷貝相關的模式,稱作雙向拷貝,它允許從_和_到服務端的高速的批量數據傳輸。 雙向拷貝模式由處于walsender模式的后端執行一條`START_REPLICATION`語句初始化。 后端發送一個CopyBothResponse給前端。然后后端和前端可能都發送CopyData消息,直到有一方發出一個CopyDone消息。 客戶端發送CopyDone消息后,連接從雙向拷貝模式切換到拷貝出模式,并且客戶端不應該再發出任何CopyData消息。 相似的,如果服務端發出CopyDone消息,連接進入拷貝入模式,并且服務端不應該再發出任何CopyData消息。 兩邊都發送了CopyDone消息后,拷貝模式終止,后端返回到命令處理模式。 在雙向拷貝模式中,如果后端檢出錯誤,將發出一個ErrorResponse消息,丟棄任何來自前端的消息直到收到Sync消息,然后發送ReadyForQuery消息并返回到普通的處理模式。 前端應把收到ErrorResponse消息作為在兩個方向上都終止拷貝的標志,這個時候不應該發出CopyDone消息。 請參閱[Section 48.3](#calibre_link-1024)獲得更多有關雙向拷貝模式下子協議傳輸的信息。 CopyInResponse,CopyOutResponse和 CopyBothResponse 消息包含了告訴前端每行的字段數以及每個字段使用的格式代碼的信息。 (就目前的實現而言,某個`COPY`操作的所有字段都使用同樣的格式,但是消息設計并不做這個假設。) ## 48.2.6\. 異步操作 有幾種情況下后端會發送一些并非由特定的前端的命令流提示的消息。 在任何時候前端都必須準備處理這些消息,即使是并未涉及到查詢處理的時候。 至少,應該在開始讀取查詢響應之前檢查這些情況。 NoticeResponse 消息有可能是因為外部的活動而生成的;比如,如果數據庫管理員進行一次"快速"數據庫關閉,那么后端將在關閉連接之前發送一個 NoticeResponse 來通知這件事。 因此,前端應該總是準備接受和顯示 NoticeResponse 消息,即使連接表面上是空閑的時候也如此。 如果后端認為前端應該知道的任何參數的實際值發生了變化,那么都會產生 ParameterStatus 消息。 這些最經常發生的地方是前端執行的一個`SET`命令的響應,并且這個時候實際上是同步(但是也有可能是數據庫管理員改變了配置文件然后SIGHUP了服務器導致的參數狀態的變化)。 同樣,如果一個`SET`命令回滾,那么也會生成合適的 ParameterStatus 消息以報告當前有效的數值。 目前,系統內有一套會生成 ParameterStatus 消息的硬編碼的參數:他們是 `server_version`、`server_encoding`、`client_encoding`、`application_name`、`is_superuser`、`session_authorization`、`DateStyle`、`IntervalStyle`、`TimeZone`、`integer_datetimes`以及`standard_conforming_strings`。 (8.0以前的版本不會報告`server_encoding`、`TimeZone`和`integer_datetimes`。 8.1以前的版本不會報告`standard_conforming_strings`。 8.4以前的版本不會報告`IntervalStyle`。 9.0以前的版本不會報告`application_name`。) 請注意`server_version`、`server_encoding`和`integer_datetimes`是偽參數,啟動后不能修改。 這個參數集合可能在將會改變,或者甚至是變成可以配置的。因此,前端應該簡單地忽略那些它不懂或者不關心的 ParameterStatus 。 如果前端發出一個`LISTEN`命令,那么為同一個通道名執行了`NOTIFY`命令后,將收到后端發來的一個 NotificationResponse 消息(不要和 NoticeResponse 混淆)。 > **Note:** 目前,NotificationResponse 只能在一個事務外面發送,因此它將不會在一個命令響應序列中間出現,但是它可能在 ReadyForQuery 之前出現。 不過,在前端邏輯中做上述假設是不明智的。好的做法是在協議的任何點上都可以接受 NotificationResponse 。 ## 48.2.7\. 取消正在處理的請求 在一條查詢正在處理的時候,前端可能請求取消這個查詢。 這樣的取消請求不是直接通過打開的當前連接發送給后端的,這么做是因為實現的有效性:不希望后端在處理查詢的過程中不停地檢查前端來的輸入。 取消請求應該相對而言比較少見,所以把取消做得稍微笨拙一些,以便不影響正常狀況的性能。 要發送一條取消請求,前端打開一個與服務器的新連接并且發送一條 CancelRequest 消息,而不是通常在新連接中經常發送的 StartupPacket 消息。 服務器將處理這個請求然后關閉連接。出于安全原因,對取消請求消息不做直接的響應。 除非 CancelRequest 消息包含與連接啟動過程中傳遞給前端的相同的鍵數據(PID 和安全鍵字),否則它將被忽略。 如果該請求匹配當前運行著的后端的 PID 和安全鍵字,則退出當前查詢的處理(目前的實現里采用的方法是向正在處理該查詢的后端進程發送一個特殊的信號)。 取消信號可能有也可能沒有任何作用。 例如,如果它在后端已經完成了查詢的處理后到達,那么它就沒有作用。 如果取消起作用了,其結果是當前命令帶著一個錯誤消息提前退出。 這么做是對安全和有效性通盤考慮的結果,前端沒有直接的方法獲知一個取消請求是否成功。 它必須繼續等待后端對查詢響應。執行取消僅僅是增加了當前查詢快些結束的可能性,以及增加了當前查詢會帶著一條錯誤消息失敗而不是成功執行的可能性。 因為取消請求是通過新的連接發送給服務器而不是通過通常的前/后端通訊連接,所以取消請求可能是任意進程執行的,而不僅僅是要取消查詢的前端。 這樣可能對創建多進程應用有某種靈活性的好處。但是同時這樣也帶來了安全風險,因為這樣任何一個非認證用戶都可能試圖取消查詢。 這個安全風險通過要求在取消請求中提供一個動態生成的安全鍵字排除。 ## 48.2.8\. 終止 通常,優雅的終止過程是前端發送一條 Terminate消息并且立刻關閉連接。一旦收到這個消息,后端馬上關閉連接并且退出。 在少數情況下(比如通過一個管理員命令關閉數據庫),后端可能在沒有任何前端請求的情況下斷開連接。 在這種情況下,后端將在它斷開連接之前嘗試發送一個錯誤或者通知消息,給出斷開的原因。 其它終止的情況發生在各種失效的場合,比如某一方的內核轉儲,失去通訊鏈路,丟失了消息邊界同步等。 不管是前端還是后端看到了一個意外的連接關閉,那么它應該清理現場并且終止。 如果前端不想終止自己,那么它可以通過再次連接服務器的方式重啟一個新的后端。 如果收到了一個無法識別的消息,那么也建議關閉連接,因為出現這種情況可能意味著是丟失了消息邊界的同步。 不管是正常還是異常的終止,任何打開的事務都會回滾,而不是提交。 不過,應該注意的是如果一個前端在一個非`SELECT`查詢正在處理的時候斷開,那么后端很可能在注意到斷開之前先完成查詢的處理。 如果查詢處于任何事務塊之外((`BEGIN` ... `COMMIT`序列),那么其結果很可能在得知斷開之前被提交。 ## 48.2.9\. SSL會話加密 如果編譯PostgreSQL的時候打開了SSL支持,那么前后端通訊就可以用SSL加密。 這樣就提供了一種在攻擊者可能捕獲會話通訊數據包的環境下保證通訊安全的方法。 有關使用SSL加密PostgreSQL會話的更多信息,請參閱[Section 17.9](#calibre_link-657)。 要開始一次SSL加密連接,前端先是發送一個 SSLRequest 消息,而不是 StartupMessage 。 然后服務器以一個包含`S`或`N`的字節響應,分別表示它愿意還是不愿意進行SSL。 如果前端對響應不滿意,那么它可以關閉連接。 要在`S`之后繼續,那么先進行與服務器的SSL啟動握手(沒有在這里描述,這是SSL規范的一部分)。 如果這些成功了,那么繼續發送普通的 StartupMessage 。 這種情況下,StartupMessage 和所有隨后的數據都將由SSL加密。 要在`N`之后繼續,則發送普通的 StartupMessage 然后不帶加密進行處理。 前端應該也準備處理一個來自服務器的給 SSLRequest 的 ErrorMessage 響應。 這種情況只有在那些SSL支持被加入到PostgreSQL以前的服務上才會出現。 (這樣的服務器太古老了,很可能根本就不存在。) 在這種情況下,連接必需關閉,但是前端可以選擇打開一個新的連接然后不帶SSL進行連接。 一個初始化的 SSLRequest 也可以用于為了發送一條 CancelRequest 消息而打開的連接中。 如果協議本身并未提供某種方法強制SSL加密,那么管理員可以把服務器配置為拒絕未加密的會話,這是認證檢查的一個副產品。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看