<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>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 31.13\. 事件系統 libpq事件系統用于通知對libpq 事件感興趣的注冊事件處理過程,如創建或刪除`PGconn`和 `PGresult`對象。一個主要的使用原因是,它允許應用程序通過一個 `PGconn`或`PGresult`關聯它們自己的數據, 并且確保數據在適當的時候釋放。 每個注冊的事件處理程序與兩片數據相關聯,已知的libpq 只作為不透明的`void *`指針。當事件處理程序注冊帶有`PGconn`時, 應用程序會提供一個_passthrough_指針。傳遞指針在由它產生的`PGconn` 和所有的`PGresult`的生命周期中永遠不會改變,它指向生命周期長的數據。 除此之外,還有一個_instance data_指針,它從每個`PGconn`和 `PGresult`中的`NULL`開始。這個指針可以與`PQinstanceData`, `PQsetInstanceData`,`PQresultInstanceData`和 `PQsetResultInstanceData`函數一起使用。需要注意的是不同于傳遞指針, 一個`PGconn`的實例數據不會被由它產生的`PGresult`自動繼承。 libpq不知道傳遞和實例數據指針指向的是什么,并且不會嘗試去釋放它們; 這對事件處理程序是一種保證。 ## 31.13.1\. 事件類型 枚舉`PGEventId`命名事件系統處理的事件的類型。所有的命名值都是從 `PGEVT`開始。對每個事件類型來說,有一個相應的事件信息結構, 用于傳送傳遞給事件處理程序的參數。事件類型如下: `PGEVT_REGISTER` 當調用`PQregisterEventProc`時,會發生注冊的事件。這是一個理想化的時間, 用于初始化任意`instanceData`,可能需要一個事件過程。 每次連接中的每個事件處理程序只會觸發一個注冊了的事件。如果事件過程失敗,會終止注冊。 ``` typedef struct { PGconn *conn; } PGEventRegister; ``` 當接收到`PGEVT_REGISTER`時,`evtInfo` 指針應該被轉換為一個`PGEventRegister *`。 這個結構包含了一個`CONNECTION_OK`狀態的`PGconn`; 用以保證在獲得一個好的`PGconn`之后立即請求調用 `PQregisterEventProc`。當返回一個錯誤代碼時,必須執行所有的清理, 因為沒有`PGEVT_CONNDESTROY`會被發送。 `PGEVT_CONNRESET` `PQreset`或`PQresetPoll`函數完成時,觸發連接復位事件。 在這兩種情況下,只有重置成功時才會觸發事件。如果事件過程失敗,整個連接復位都會失敗; `PGconn`被置為`CONNECTION_BAD`狀態并且 `PQresetPoll`將返回`PGRES_POLLING_FAILED`。 ``` typedef struct { PGconn *conn; } PGEventConnReset; ``` 當接收到一個`PGEVT_CONNRESET`事件時,`evtInfo` 指針應該被轉換為一個`PGEventConnReset *`。盡管包含的 `PGconn`被重置了,但所有事件數據不會改變。 這個事件應該用于reset/reload/requery任何關聯的`instanceData`。 需要注意的是即使事件過程在處理`PGEVT_CONNRESET`時失敗了,當連接關閉時, 仍會接收一個`PGEVT_CONNDESTROY`事件。 `PGEVT_CONNDESTROY` 在響應`PQfinish`時會觸發連接破壞事件。這是事件過程的職責: 合適的清理它的事件數據,因為libpq沒有能力管理這部分內存。失敗的清理會導致內存溢出。 ``` typedef struct { PGconn *conn; } PGEventConnDestroy; ``` 當接收到一個`PGEVT_CONNDESTROY`事件時,`evtInfo` 指針應該被轉換為一個`PGEventConnDestroy *`。 在`PQfinish`執行清理之前會觸發該事件。事件過程的返回值會被忽略, 因為沒有很好的方式從`PQfinish`指出失敗。同樣, 一個事件過程失敗不應該中止清理不需要的內存的過程。 `PGEVT_RESULTCREATE` 回應任意產生一個結果(包括`PQgetResult`)的查詢執行函數時, 會觸發結果創建事件。這個事件只有在成功創建結果時才會被觸發。 ``` typedef struct { PGconn *conn; PGresult *result; } PGEventResultCreate; ``` 當接收到一個`PGEVT_RESULTCREATE`事件時,`evtInfo` 指針應該被轉換為一個`PGEventResultCreate *`。`conn` 是用于產生結果的連接。這是理想的位置,用于初始化任意需要與結果相關聯的`instanceData`。 如果事件過程失敗,結果會被清理并且傳播該失敗。事件過程不應該嘗試自己`PQclear`結果對象。 當返回一個錯誤代碼時,必須執行所有的清理,因為沒有`PGEVT_RESULTDESTROY`會被發送。 `PGEVT_RESULTCOPY` 在響應`PQcopyResult`時會觸發結果拷貝事件。只有在拷貝完成時, 才會觸發該事件。只有那些為源結果成功處理`PGEVT_RESULTCREATE`或 `PGEVT_RESULTCOPY`事件的事件過程才會收到`PGEVT_RESULTCOPY`事件。 ``` typedef struct { const PGresult *src; PGresult *dest; } PGEventResultCopy; ``` 當接收到一個`PGEVT_RESULTCOPY`事件時,`evtInfo` 指針應該被轉換為一個`PGEventResultCopy *`。`src` 結果是當`dest` 為拷貝目標時要進行拷貝的。這個事件用于提供一個 `instanceData`的深度拷貝,因為`PQcopyResult`做不到。 如果事件過程失敗,整個拷貝過程都將失敗,并且`dest`結果也會被清理。 當返回一個錯誤代碼時,必須執行所有的清理,因為沒有`PGEVT_RESULTDESTROY`事件會被發送。 `PGEVT_RESULTDESTROY` 在回應`PQclear`時會觸發結果破壞事件。這是事件過程的責任; 合理清理它的事件數據,因為libpq沒有能力管理這塊內存。清理失敗會導致內存溢出。 ``` typedef struct { PGresult *result; } PGEventResultDestroy; ``` 當接收到一個`PGEVT_RESULTDESTROY`事件時,`evtInfo` 指針應該被轉換為一個`PGEventResultDestroy *`。 這個事件會在`PQclear`執行清理之前被觸發。事件過程的返回結果會被忽略, 因為沒有一個方式能夠從`PQclear`指出失敗。同樣, 一個事件過程失敗不應該中止對不需要內存的清理。 ## 31.13.2\. 事件回調過程 `PGEventProc` `PGEventProc`是一個事件過程中指針的typedef,也就是, 從libpq接收事件的用戶回調函數。事件過程的用法必須如下: ``` int eventproc(PGEventId evtId, void *evtInfo, void *passThrough) ``` `evtId`參數指出要發生哪個`PGEVT`事件。 `evtInfo`指針必須被轉換為合適的結構類型以獲取有關該事件的進一步信息。 `passThrough`是當事件過程被注冊時,提供給 `PQregisterEventProc`的指針。這個函數應該返回一個非0的值,如果成功的話,反之,返回0。 在任意`PGconn`中,一個特殊的事件過程只能注冊一次。 這是因為過程地址被用于作為查詢關鍵字,以識別相關的實例數據。 | **Caution** | |:--- | | 在Windows上,函數可以有兩個不同的地址:一個是內部DLL可見的,另一個是外部DLL可見的。 需要注意的是,libpq事件過程函數只會使用其中一個地址,否則會造成混亂。 有效的編寫代碼的簡單規則是為了保證事件過程聲明為`static`。 如果過程地址在它的源文件之外是可用的,公開一個單獨的函數以返回地址。 | ## 31.13.3\. 事件支持函數 `PQregisterEventProc` 用libpq注冊一個事件回調過程。 ``` int PQregisterEventProc(PGconn *conn, PGEventProc proc, const char *name, void *passThrough); ``` 在每個`PGconn`中必須注冊一次事件過程,用于希望接受到的事件。除了內存之外, 對于一次連接注冊的事件過程個數沒有限制。如果成功,則返回一個非0的值,否則返回0。 當一個libpq事件被觸發時,會調用一個`proc`參數。 內存地址同樣會被用于查找`instanceData`。`name` 用于指出在錯誤信息中的事件過程。這個值不能為`NULL`或一個長度為0的字符串。 名字字符串被拷貝到`PGconn`中,因此被傳遞的不需要擁有很長的生命周期。 `passThrough`指針被傳遞到`proc`, 不管何時觸發事件。這個參數可以是`NULL`。 `PQsetInstanceData` 為`proc`到`data`的過程設置連接`conn` 的`instanceData`。成功則返回一個非0值,否則返回0。 只有`proc`沒有成功在`conn`注冊時才會發生失敗。 ``` int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data); ``` `PQinstanceData` 返回與`proc`過程,或`NULL`(如果存在空) 相關的`conn`的`instanceData`。 ``` void *PQinstanceData(const PGconn *conn, PGEventProc proc); ``` `PQresultSetInstanceData` 為`proc`到`data`的過程設置結果的`instanceData`。 成功則返回一個非0值,否則返回0。只有`proc`沒有成功在結果注冊時才會發生失敗。 ``` int PQresultSetInstanceData(PGresult *res, PGEventProc proc, void *data); ``` `PQresultInstanceData` 返回與`proc`過程,或`NULL`(如果存在空)相關的結果的`instanceData`。 ``` void *PQresultInstanceData(const PGresult *res, PGEventProc proc); ``` ## 31.13.4\. 事件例子 一個管理與libpq連接和結果相關的私有數據的例子: ``` /* <!-- required header for libpq events (note: includes libpq-fe.h) -->需要libpq事件的頭文件 (注意:包括 libpq-fe.h) */ #include <libpq-events.h> /* The instanceData */ typedef struct { int n; char *str; } mydata; /* PGEventProc */ static int myEventProc(PGEventId evtId, void *evtInfo, void *passThrough); int main(void) { mydata *data; PGresult *res; PGconn *conn = PQconnectdb("dbname = postgres"); if (PQstatus(conn) != CONNECTION_OK) { fprintf(stderr, "Connection to database failed: %s", PQerrorMessage(conn)); PQfinish(conn); return 1; } <!-- /* called once on any connection that should receive events. * Sends a PGEVT_REGISTER to myEventProc. */ --> /* 在任何應該接收事件的連接上調用一次。 * 發送一個 PGEVT_REGISTER 到 myEventProc。 */ if (!PQregisterEventProc(conn, myEventProc, "mydata_proc", NULL)) { fprintf(stderr, "Cannot register PGEventProc\n"); PQfinish(conn); return 1; } <!-- /* conn instanceData is available */ --> /* conn instanceData 是可用的 */ data = PQinstanceData(conn, myEventProc); <!-- /* Sends a PGEVT_RESULTCREATE to myEventProc */ --> /* 發送一個 PGEVT_RESULTCREATE 到 myEventProc */ res = PQexec(conn, "SELECT 1 + 1"); <!-- /* result instanceData is available */ --> /* 結果 instanceData 是可用的 */ data = PQresultInstanceData(res, myEventProc); <!-- /* If PG_COPYRES_EVENTS is used, sends a PGEVT_RESULTCOPY to myEventProc */ --> /* 如果使用了 PG_COPYRES_EVENTS,發送一個 PGEVT_RESULTCOPY到 myEventProc */ res_copy = PQcopyResult(res, PG_COPYRES_TUPLES | PG_COPYRES_EVENTS); <!-- /* result instanceData is available if PG_COPYRES_EVENTS was * used during the PQcopyResult call. */ --> /* 結果 instanceData 是可用的,如果 PG_COPYRES_EVENTS * 在PQcopyResult調用期間使用了的話。 */ data = PQresultInstanceData(res_copy, myEventProc); <!-- /* Both clears send a PGEVT_RESULTDESTROY to myEventProc */ --> /* 兩個clears都發送 PGEVT_RESULTDESTROY 到 myEventProc */ PQclear(res); PQclear(res_copy); <!-- /* Sends a PGEVT_CONNDESTROY to myEventProc */ --> /* 發送一個 PGEVT_CONNDESTROY 到 myEventProc */ PQfinish(conn); return 0; } static int myEventProc(PGEventId evtId, void *evtInfo, void *passThrough) { switch (evtId) { case PGEVT_REGISTER: { PGEventRegister *e = (PGEventRegister *)evtInfo; mydata *data = get_mydata(e->conn); <!-- /* associate app specific data with connection */ --> /* 將應用程序特定的數據與連接相關聯 */ PQsetInstanceData(e->conn, myEventProc, data); break; } case PGEVT_CONNRESET: { PGEventConnReset *e = (PGEventConnReset *)evtInfo; mydata *data = PQinstanceData(e->conn, myEventProc); if (data) memset(data, 0, sizeof(mydata)); break; } case PGEVT_CONNDESTROY: { PGEventConnDestroy *e = (PGEventConnDestroy *)evtInfo; mydata *data = PQinstanceData(e->conn, myEventProc); <!-- /* free instance data because the conn is being destroyed */ --> /* 釋放實例數據,因為conn被破壞了 */ if (data) free_mydata(data); break; } case PGEVT_RESULTCREATE: { PGEventResultCreate *e = (PGEventResultCreate *)evtInfo; mydata *conn_data = PQinstanceData(e->conn, myEventProc); mydata *res_data = dup_mydata(conn_data); <!-- /* associate app specific data with result (copy it from conn) */ --> /* 將應用程序特定的數據與結果相關聯 (從conn中拷貝) */ PQsetResultInstanceData(e->result, myEventProc, res_data); break; } case PGEVT_RESULTCOPY: { PGEventResultCopy *e = (PGEventResultCopy *)evtInfo; mydata *src_data = PQresultInstanceData(e->src, myEventProc); mydata *dest_data = dup_mydata(src_data); <!-- /* associate app specific data with result (copy it from a result) */ --> /*將應用程序特定的數據與結果相關聯 (從結果中拷貝)*/ PQsetResultInstanceData(e->dest, myEventProc, dest_data); break; } case PGEVT_RESULTDESTROY: { PGEventResultDestroy *e = (PGEventResultDestroy *)evtInfo; mydata *data = PQresultInstanceData(e->result, myEventProc); <!-- /* free instance data because the result is being destroyed */ --> /* 釋放實例數據,因為結果被破壞了 */ if (data) free_mydata(data); break; } <!-- /* unknown event ID, just return TRUE. */ --> /* 未知事件ID,只是返回TRUE。*/ default: break; } return TRUE; /* <!-- event processing succeeded -->事件處理成功 */ } ```
                  <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>

                              哎呀哎呀视频在线观看