<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 功能強大 支持多語言、二開方便! 廣告
                # 31.4\. 異步命令處理 `PQexec`函數對普通的同步應用里提交命令已經是足夠用的了。 但是它卻有幾個缺陷,而這些缺陷可能對某些用戶很重要: * `PQexec`等待命令結束。而應用可能還有其它的工作要做 (比如維護用戶界面等),這個時候它可不想阻塞在這里等待響應。 * 因為客戶端應用在等待結果的時候是處于掛起狀態的,所以應用很難判斷它是否該嘗試結束正在進行的命令。 (這個事情可以在一個信號處理器中做,但是沒別的方法。) * `PQexec`只能返回一個`PGresult`結構。 如果提交的命令字符串包含多個SQL命令,除了最后一個 `PGresult`以外都會被`PQexec`丟棄。 * `PQexec`總是收集命令的整個結果,將其緩存在一個`PGresult`中。 雖然這為應用簡化了錯誤處理邏輯,但是對于包含多行的結果是不切實際的。 不想受到這些限制的應用可以改用下面的函數,這些函數也是構造`PQexec` 的函數:`PQsendQuery`和`PQgetResult`。 也有`PQsendQueryParams`,`PQsendPrepare`, `PQsendQueryPrepared`,`PQsendDescribePrepared` 和`PQsendDescribePortal`,他們可以和`PQgetResult` 一起使用,分別用于復制`PQexecParams`,`PQprepare`, `PQexecPrepared`,`PQdescribePrepared` 和`PQdescribePortal`的功能。 `PQsendQuery` 向服務器提交一個命令而不等待結果。如果查詢成功發送則返回 1,否則返回 0。 (此時,可以用`PQerrorMessage`獲取關于失敗的信息)。 ``` int PQsendQuery(PGconn *conn, const char *command); ``` 在成功調用`PQsendQuery`后,調用`PQgetResult` 一次或者多次獲取結果。在`PQgetResult`返回 NULL 指針, 表明命令完成之前,我們不能再調用`PQsendQuery`(在同一次連接里)。 `PQsendQueryParams` 給服務器提交一個命令和分隔的參數,而不等待結果。 ``` int PQsendQueryParams(PGconn *conn, const char *command, int nParams, const Oid *paramTypes, const char * const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); ``` 這個等效于`PQsendQuery`,只是查詢參數可以和查詢字串分開聲明。 函數的參數處理和`PQexecParams`一樣。 和`PQexecParams`類似,它不能在 2.0 版本的協議連接上工作, 并且它只允許在查詢字串里出現一條命令。 `PQsendPrepare` 發送一個請求,創建一個給定參數的預備語句,而不等待結束。 ``` int PQsendPrepare(PGconn *conn, const char *stmtName, const char *query, int nParams, const Oid *paramTypes); ``` 這是`PQprepare`的異步版本:如果它能發送這個請求,則返回 1,如果不能,則返回 0。 在成功調用之后,調用`PQgetResult`判斷服務器是否成功創建了預備語句。 這個函數的參數的處理和`PQprepare`一樣。類似`PQprepare`, 它不能在 2.0 版本協議的連接上運轉。 `PQsendQueryPrepared` 發送一個請求執行帶有給出參數的預備語句,不等待結果。 ``` int PQsendQueryPrepared(PGconn *conn, const char *stmtName, int nParams, const char * const *paramValues, const int *paramLengths, const int *paramFormats, int resultFormat); ``` 這個函數類似`PQsendQueryParams`, 但是要執行的命令是通過給一個前面準備好的語句命名來聲明的,而不是給出一個查詢字串。 函數的參數處理和`PQexecPrepared`一樣。 類似`PQexecPrepared`,它也不能在 2.0 版本的協議連接上工作。 `PQsendDescribePrepared` 提交一個請求,獲取關于指定的預備語句的信息,不等待結果。 ``` int PQsendDescribePrepared(PGconn *conn, const char *stmtName); ``` 這是`PQdescribePrepared`的一個異步版本:如果它能發送這個請求,則返回 1, 如果不能,則返回 0。在成功調用之后,調用`PQgetResult`獲取結果。 這個函數的參數的處理和`PQdescribePrepared`一樣。 類似`PQdescribePrepared`,它不能在 2.0 版本協議的連接上運轉。 `PQsendDescribePortal` 發出請求,以獲得關于指定端口的信息,不需要等待完成。 ``` int PQsendDescribePortal(PGconn *conn, const char *portalName); ``` 這是一個`PQdescribePortal`的異步版本:如果它能發送這個請求,那么返回1, 否則返回0。成功調用之后,通過`PQgetResult`獲得結果。 函數參數處理與`PQdescribePortal`相同。 類似于`PQdescribePortal`,不能在2.0的協議連接上工作。 `PQgetResult` 等待從前面`PQsendQuery`,`PQsendQueryParams`, `PQsendPrepare`,`PQsendQueryPrepared`, `PQsendDescribePrepared`或者`PQsendDescribePortal` 調用返回的下一個結果,然后返回之。當命令結束并且沒有更多結果后返回 NULL。 ``` PGresult *PQgetResult(PGconn *conn); ``` 必須重復的調用`PQgetResult`,直到它返回空指針,表明該命令結束。 (如果在沒有活躍的命令時調用,`PQgetResult`將只是立即返回一個空指針。) 每個`PQgetResult`返回的非 NULL 結果都應該用前面描述的 `PGresult`訪問函數進行分析。不要忘了在結束分析后用`PQclear` 釋放每個結果對象。注意,`PQgetResult` 只是在有一個命令是活躍的而且必須返回數的據還沒有被`PQconsumeInput`讀取時阻塞。 > **Note:** 即使在`PQresultStatus`表明一個致命的錯誤時, 也應該調用`PQgetResult`直到它返回一個空指針, 以允許libpq完全的處理錯誤信息。 使用`PQsendQuery`和`PQgetResult`解決了 `PQexec`的一個問題:如果一個命令字符串包含多個 SQL命令,這些命令的結果可以獨立的獲得。(這樣就允許一種簡單的重疊處理模式, 順便說一句:客戶端可以處理一個命令的結果而服務器可以仍然在處理同一命令字符串后面的查詢。) 另一個可以用`PQsendQuery`和`PQgetResult` 獲得的經常需要的特性是一次檢索大型連續查詢結果。這在 [Section 31.5](#calibre_link-626)中討論。 單獨的,調用`PQgetResult`將仍然導致客戶端阻塞, 直到服務器完成下一個SQL命令。可以通過適當的使用兩個函數避免: `PQconsumeInput` 如果存在服務器來的輸入可用,則使用之。 ``` int PQconsumeInput(PGconn *conn); ``` `PQconsumeInput`通常返回 1 表明"沒有錯誤", 而返回 0 表明有某種錯誤發生,(這個時候可以用`PQerrorMessage`)。 注意這個結果并不表明實際上是否收集了輸入數據。在調用`PQconsumeInput` 之后,應用可以檢查`PQisBusy`和/或`PQnotifies` 看一眼它們的狀態是否改變。 `PQconsumeInput`可以在應用還沒有做好處理結果或通知的情況下被調用。 這個函數將讀取可用的數據并且在一個緩沖區里保存它,這樣導致一個`select()` 讀準備好標識的生成。這樣應用就可以使用`PQconsumeInput` 立即清掉`select()`條件,然后在空閑的時候檢查結果。 `PQisBusy` 在查詢忙的時候返回 1 ,也就是說,`PQgetResult`將阻塞住等待輸入。 一個 0 的返回表明這時調用`PQgetResult`保證不阻塞。 ``` int PQisBusy(PGconn *conn); ``` `PQisBusy`本身將不會試圖從服務器讀取數據; 所以必須先調用`PQconsumeInput`,否則將永遠不會消除忙狀態。 一個使用這些函數的典型的應用將有一個主循環使用`select()` 或`poll()`等待所有它必須處理的條件。其中一個條件將會是服務器來的數據已準備好, 從`select()`的角度來看就是`PQsocket` 標識的文件描述符上已經有可讀取的數據。當主循環偵測到輸入準備好, 它將調用`PQconsumeInput`讀取輸入。然后可以調用`PQisBusy`, 返回 false (0)后面可以跟著`PQgetResult`。同樣它(用戶應用) 可以調用`PQnotifies`檢測`NOTIFY`信息 (參閱[Section 31.8](#calibre_link-775))。 一個使用`PQsendQuery`/`PQgetResult` 的客戶端同樣也可以試圖取消一個正在被服務器處理的命令。參閱[Section 31.6](#calibre_link-670)。 但是,不管`PQcancel`返回的值是多少,應用都必須使用 `PQgetResult`進行正常的讀取結果的動作序列。 一次成功的取消只會導致命令比正常情況下快些結束。 通過使用上面描述的函數,我們可以避免在等待來自數據庫服務器的輸入時的阻塞。 不過,應用還是有可能阻塞在給服務器發送輸出上。這種情況比較少見,但是也可能發生, 尤其是我們要發送非常長的 SQL 命令或者數據值的時候。(不過, 最有可能的是在應用通過`COPY IN`發送數據的時候。)為了避免這個可能性, 實現完全的非阻塞數據庫操作,我們可以使用下列額外的函數。 `PQsetnonblocking` 把連接的狀態設置為非阻塞。 ``` int PQsetnonblocking(PGconn *conn, int arg); ``` 如果`arg`為 1,把連接狀態設置為非阻塞, 如果`arg`為 0,把連接狀態設置為阻塞。如果 OK 返回 0,如果錯誤返回 -1。 在非阻塞狀態,調用`PQsendQuery`,`PQputline`, `PQputnbytes`,和`PQendcopy`的時候不被阻塞, 而是在如果需要再次調用它們時將返回一個錯誤。 請注意`PQexec`不會在意任何非阻塞模式;如果調用了 `PQexec`,那么它的行為總是阻塞的。 `PQisnonblocking` 返回數據庫連接的阻塞狀態。 ``` int PQisnonblocking(const PGconn *conn); ``` 如果連接設置為非阻塞狀態,返回 1,如果是阻塞狀態返回 0。 `PQflush` 試圖把任何正在排隊的數據沖刷到服務器,如果成功(或者發送隊列為空)返回 0, 如果因某種原因失敗返回 -1,或者是在無法把發送隊列中的所有數據都發送出去,返回 1。 (這種情況只有在連接為不阻塞模式的時候才會出現)。 ``` int PQflush(PGconn *conn); ``` 在一個非阻塞的連接上發送任何命令或者數據之后,調用`PQflush`。 如果返回 1,就等待套接字寫準備好然后再次調用;重復這個操作直到它返回 0。 一旦`PQflush`返回 0,則等待套接字為讀準備好,準備好之后就像上面那樣讀取響應。
                  <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>

                              哎呀哎呀视频在线观看