gooderp18绿色标准版
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

444 行
24KB

  1. <?xml version="1.0" encoding="UTF-8" standalone="no"?>
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"><html xmlns="http://www.w3.org/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /><title>33.13. Event System</title><link rel="stylesheet" type="text/css" href="stylesheet.css" /><link rev="made" href="pgsql-docs@lists.postgresql.org" /><meta name="generator" content="DocBook XSL Stylesheets V1.79.1" /><link rel="prev" href="libpq-notice-processing.html" title="33.12. Notice Processing" /><link rel="next" href="libpq-envars.html" title="33.14. Environment Variables" /></head><body><div xmlns="http://www.w3.org/TR/xhtml1/transitional" class="navheader"><table width="100%" summary="Navigation header"><tr><th colspan="5" align="center">33.13. Event System</th></tr><tr><td width="10%" align="left"><a accesskey="p" href="libpq-notice-processing.html" title="33.12. Notice Processing">Prev</a> </td><td width="10%" align="left"><a accesskey="u" href="libpq.html" title="Chapter 33. libpq - C Library">Up</a></td><th width="60%" align="center">Chapter 33. <span xmlns="http://www.w3.org/1999/xhtml" class="application">libpq</span> - C Library</th><td width="10%" align="right"><a accesskey="h" href="index.html" title="PostgreSQL 12.4 Documentation">Home</a></td><td width="10%" align="right"> <a accesskey="n" href="libpq-envars.html" title="33.14. Environment Variables">Next</a></td></tr></table><hr></hr></div><div class="sect1" id="LIBPQ-EVENTS"><div class="titlepage"><div><div><h2 class="title" style="clear: both">33.13. Event System</h2></div></div></div><div class="toc"><dl class="toc"><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-TYPES">33.13.1. Event Types</a></span></dt><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-PROC">33.13.2. Event Callback Procedure</a></span></dt><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-FUNCS">33.13.3. Event Support Functions</a></span></dt><dt><span class="sect2"><a href="libpq-events.html#LIBPQ-EVENTS-EXAMPLE">33.13.4. Event Example</a></span></dt></dl></div><p>
  3. <span class="application">libpq</span>'s event system is designed to notify
  4. registered event handlers about interesting
  5. <span class="application">libpq</span> events, such as the creation or
  6. destruction of <code class="structname">PGconn</code> and
  7. <code class="structname">PGresult</code> objects. A principal use case is that
  8. this allows applications to associate their own data with a
  9. <code class="structname">PGconn</code> or <code class="structname">PGresult</code>
  10. and ensure that that data is freed at an appropriate time.
  11. </p><p>
  12. Each registered event handler is associated with two pieces of data,
  13. known to <span class="application">libpq</span> only as opaque <code class="literal">void *</code>
  14. pointers. There is a <em class="firstterm">passthrough</em> pointer that is provided
  15. by the application when the event handler is registered with a
  16. <code class="structname">PGconn</code>. The passthrough pointer never changes for the
  17. life of the <code class="structname">PGconn</code> and all <code class="structname">PGresult</code>s
  18. generated from it; so if used, it must point to long-lived data.
  19. In addition there is an <em class="firstterm">instance data</em> pointer, which starts
  20. out <code class="symbol">NULL</code> in every <code class="structname">PGconn</code> and <code class="structname">PGresult</code>.
  21. This pointer can be manipulated using the
  22. <code class="function">PQinstanceData</code>,
  23. <code class="function">PQsetInstanceData</code>,
  24. <code class="function">PQresultInstanceData</code> and
  25. <code class="function">PQsetResultInstanceData</code> functions. Note that
  26. unlike the passthrough pointer, instance data of a <code class="structname">PGconn</code>
  27. is not automatically inherited by <code class="structname">PGresult</code>s created from
  28. it. <span class="application">libpq</span> does not know what passthrough
  29. and instance data pointers point to (if anything) and will never attempt
  30. to free them — that is the responsibility of the event handler.
  31. </p><div class="sect2" id="LIBPQ-EVENTS-TYPES"><div class="titlepage"><div><div><h3 class="title">33.13.1. Event Types</h3></div></div></div><p>
  32. The enum <code class="literal">PGEventId</code> names the types of events handled by
  33. the event system. All its values have names beginning with
  34. <code class="literal">PGEVT</code>. For each event type, there is a corresponding
  35. event info structure that carries the parameters passed to the event
  36. handlers. The event types are:
  37. </p><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PGEVT-REGISTER"><span class="term"><code class="literal">PGEVT_REGISTER</code></span></dt><dd><p>
  38. The register event occurs when <code class="function">PQregisterEventProc</code>
  39. is called. It is the ideal time to initialize any
  40. <code class="literal">instanceData</code> an event procedure may need. Only one
  41. register event will be fired per event handler per connection. If the
  42. event procedure fails, the registration is aborted.
  43. </p><pre class="synopsis">
  44. typedef struct
  45. {
  46. PGconn *conn;
  47. } PGEventRegister;
  48. </pre><p>
  49. When a <code class="literal">PGEVT_REGISTER</code> event is received, the
  50. <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
  51. <code class="structname">PGEventRegister *</code>. This structure contains a
  52. <code class="structname">PGconn</code> that should be in the
  53. <code class="literal">CONNECTION_OK</code> status; guaranteed if one calls
  54. <code class="function">PQregisterEventProc</code> right after obtaining a good
  55. <code class="structname">PGconn</code>. When returning a failure code, all
  56. cleanup must be performed as no <code class="literal">PGEVT_CONNDESTROY</code>
  57. event will be sent.
  58. </p></dd><dt id="LIBPQ-PGEVT-CONNRESET"><span class="term"><code class="literal">PGEVT_CONNRESET</code></span></dt><dd><p>
  59. The connection reset event is fired on completion of
  60. <code class="function">PQreset</code> or <code class="function">PQresetPoll</code>. In
  61. both cases, the event is only fired if the reset was successful. If
  62. the event procedure fails, the entire connection reset will fail; the
  63. <code class="structname">PGconn</code> is put into
  64. <code class="literal">CONNECTION_BAD</code> status and
  65. <code class="function">PQresetPoll</code> will return
  66. <code class="literal">PGRES_POLLING_FAILED</code>.
  67. </p><pre class="synopsis">
  68. typedef struct
  69. {
  70. PGconn *conn;
  71. } PGEventConnReset;
  72. </pre><p>
  73. When a <code class="literal">PGEVT_CONNRESET</code> event is received, the
  74. <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
  75. <code class="structname">PGEventConnReset *</code>. Although the contained
  76. <code class="structname">PGconn</code> was just reset, all event data remains
  77. unchanged. This event should be used to reset/reload/requery any
  78. associated <code class="literal">instanceData</code>. Note that even if the
  79. event procedure fails to process <code class="literal">PGEVT_CONNRESET</code>, it will
  80. still receive a <code class="literal">PGEVT_CONNDESTROY</code> event when the connection
  81. is closed.
  82. </p></dd><dt id="LIBPQ-PGEVT-CONNDESTROY"><span class="term"><code class="literal">PGEVT_CONNDESTROY</code></span></dt><dd><p>
  83. The connection destroy event is fired in response to
  84. <code class="function">PQfinish</code>. It is the event procedure's
  85. responsibility to properly clean up its event data as libpq has no
  86. ability to manage this memory. Failure to clean up will lead
  87. to memory leaks.
  88. </p><pre class="synopsis">
  89. typedef struct
  90. {
  91. PGconn *conn;
  92. } PGEventConnDestroy;
  93. </pre><p>
  94. When a <code class="literal">PGEVT_CONNDESTROY</code> event is received, the
  95. <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
  96. <code class="structname">PGEventConnDestroy *</code>. This event is fired
  97. prior to <code class="function">PQfinish</code> performing any other cleanup.
  98. The return value of the event procedure is ignored since there is no
  99. way of indicating a failure from <code class="function">PQfinish</code>. Also,
  100. an event procedure failure should not abort the process of cleaning up
  101. unwanted memory.
  102. </p></dd><dt id="LIBPQ-PGEVT-RESULTCREATE"><span class="term"><code class="literal">PGEVT_RESULTCREATE</code></span></dt><dd><p>
  103. The result creation event is fired in response to any query execution
  104. function that generates a result, including
  105. <code class="function">PQgetResult</code>. This event will only be fired after
  106. the result has been created successfully.
  107. </p><pre class="synopsis">
  108. typedef struct
  109. {
  110. PGconn *conn;
  111. PGresult *result;
  112. } PGEventResultCreate;
  113. </pre><p>
  114. When a <code class="literal">PGEVT_RESULTCREATE</code> event is received, the
  115. <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
  116. <code class="structname">PGEventResultCreate *</code>. The
  117. <em class="parameter"><code>conn</code></em> is the connection used to generate the
  118. result. This is the ideal place to initialize any
  119. <code class="literal">instanceData</code> that needs to be associated with the
  120. result. If the event procedure fails, the result will be cleared and
  121. the failure will be propagated. The event procedure must not try to
  122. <code class="function">PQclear</code> the result object for itself. When returning a
  123. failure code, all cleanup must be performed as no
  124. <code class="literal">PGEVT_RESULTDESTROY</code> event will be sent.
  125. </p></dd><dt id="LIBPQ-PGEVT-RESULTCOPY"><span class="term"><code class="literal">PGEVT_RESULTCOPY</code></span></dt><dd><p>
  126. The result copy event is fired in response to
  127. <code class="function">PQcopyResult</code>. This event will only be fired after
  128. the copy is complete. Only event procedures that have
  129. successfully handled the <code class="literal">PGEVT_RESULTCREATE</code>
  130. or <code class="literal">PGEVT_RESULTCOPY</code> event for the source result
  131. will receive <code class="literal">PGEVT_RESULTCOPY</code> events.
  132. </p><pre class="synopsis">
  133. typedef struct
  134. {
  135. const PGresult *src;
  136. PGresult *dest;
  137. } PGEventResultCopy;
  138. </pre><p>
  139. When a <code class="literal">PGEVT_RESULTCOPY</code> event is received, the
  140. <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
  141. <code class="structname">PGEventResultCopy *</code>. The
  142. <em class="parameter"><code>src</code></em> result is what was copied while the
  143. <em class="parameter"><code>dest</code></em> result is the copy destination. This event
  144. can be used to provide a deep copy of <code class="literal">instanceData</code>,
  145. since <code class="literal">PQcopyResult</code> cannot do that. If the event
  146. procedure fails, the entire copy operation will fail and the
  147. <em class="parameter"><code>dest</code></em> result will be cleared. When returning a
  148. failure code, all cleanup must be performed as no
  149. <code class="literal">PGEVT_RESULTDESTROY</code> event will be sent for the
  150. destination result.
  151. </p></dd><dt id="LIBPQ-PGEVT-RESULTDESTROY"><span class="term"><code class="literal">PGEVT_RESULTDESTROY</code></span></dt><dd><p>
  152. The result destroy event is fired in response to a
  153. <code class="function">PQclear</code>. It is the event procedure's
  154. responsibility to properly clean up its event data as libpq has no
  155. ability to manage this memory. Failure to clean up will lead
  156. to memory leaks.
  157. </p><pre class="synopsis">
  158. typedef struct
  159. {
  160. PGresult *result;
  161. } PGEventResultDestroy;
  162. </pre><p>
  163. When a <code class="literal">PGEVT_RESULTDESTROY</code> event is received, the
  164. <em class="parameter"><code>evtInfo</code></em> pointer should be cast to a
  165. <code class="structname">PGEventResultDestroy *</code>. This event is fired
  166. prior to <code class="function">PQclear</code> performing any other cleanup.
  167. The return value of the event procedure is ignored since there is no
  168. way of indicating a failure from <code class="function">PQclear</code>. Also,
  169. an event procedure failure should not abort the process of cleaning up
  170. unwanted memory.
  171. </p></dd></dl></div></div><div class="sect2" id="LIBPQ-EVENTS-PROC"><div class="titlepage"><div><div><h3 class="title">33.13.2. Event Callback Procedure</h3></div></div></div><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PGEVENTPROC"><span class="term">
  172. <code class="literal">PGEventProc</code>
  173. <a id="id-1.7.3.20.5.2.1.1.2" class="indexterm"></a>
  174. </span></dt><dd><p>
  175. <code class="literal">PGEventProc</code> is a typedef for a pointer to an
  176. event procedure, that is, the user callback function that receives
  177. events from libpq. The signature of an event procedure must be
  178. </p><pre class="synopsis">
  179. int eventproc(PGEventId evtId, void *evtInfo, void *passThrough)
  180. </pre><p>
  181. The <em class="parameter"><code>evtId</code></em> parameter indicates which
  182. <code class="literal">PGEVT</code> event occurred. The
  183. <em class="parameter"><code>evtInfo</code></em> pointer must be cast to the appropriate
  184. structure type to obtain further information about the event.
  185. The <em class="parameter"><code>passThrough</code></em> parameter is the pointer
  186. provided to <code class="function">PQregisterEventProc</code> when the event
  187. procedure was registered. The function should return a non-zero value
  188. if it succeeds and zero if it fails.
  189. </p><p>
  190. A particular event procedure can be registered only once in any
  191. <code class="structname">PGconn</code>. This is because the address of the procedure
  192. is used as a lookup key to identify the associated instance data.
  193. </p><div class="caution"><h3 class="title">Caution</h3><p>
  194. On Windows, functions can have two different addresses: one visible
  195. from outside a DLL and another visible from inside the DLL. One
  196. should be careful that only one of these addresses is used with
  197. <span class="application">libpq</span>'s event-procedure functions, else confusion will
  198. result. The simplest rule for writing code that will work is to
  199. ensure that event procedures are declared <code class="literal">static</code>. If the
  200. procedure's address must be available outside its own source file,
  201. expose a separate function to return the address.
  202. </p></div></dd></dl></div></div><div class="sect2" id="LIBPQ-EVENTS-FUNCS"><div class="titlepage"><div><div><h3 class="title">33.13.3. Event Support Functions</h3></div></div></div><div class="variablelist"><dl class="variablelist"><dt id="LIBPQ-PQREGISTEREVENTPROC"><span class="term">
  203. <code class="function">PQregisterEventProc</code>
  204. <a id="id-1.7.3.20.6.2.1.1.2" class="indexterm"></a>
  205. </span></dt><dd><p>
  206. Registers an event callback procedure with libpq.
  207. </p><pre class="synopsis">
  208. int PQregisterEventProc(PGconn *conn, PGEventProc proc,
  209. const char *name, void *passThrough);
  210. </pre><p>
  211. </p><p>
  212. An event procedure must be registered once on each
  213. <code class="structname">PGconn</code> you want to receive events about. There is no
  214. limit, other than memory, on the number of event procedures that
  215. can be registered with a connection. The function returns a non-zero
  216. value if it succeeds and zero if it fails.
  217. </p><p>
  218. The <em class="parameter"><code>proc</code></em> argument will be called when a libpq
  219. event is fired. Its memory address is also used to lookup
  220. <code class="literal">instanceData</code>. The <em class="parameter"><code>name</code></em>
  221. argument is used to refer to the event procedure in error messages.
  222. This value cannot be <code class="symbol">NULL</code> or a zero-length string. The name string is
  223. copied into the <code class="structname">PGconn</code>, so what is passed need not be
  224. long-lived. The <em class="parameter"><code>passThrough</code></em> pointer is passed
  225. to the <em class="parameter"><code>proc</code></em> whenever an event occurs. This
  226. argument can be <code class="symbol">NULL</code>.
  227. </p></dd><dt id="LIBPQ-PQSETINSTANCEDATA"><span class="term">
  228. <code class="function">PQsetInstanceData</code>
  229. <a id="id-1.7.3.20.6.2.2.1.2" class="indexterm"></a>
  230. </span></dt><dd><p>
  231. Sets the connection <em class="parameter"><code>conn</code></em>'s <code class="literal">instanceData</code>
  232. for procedure <em class="parameter"><code>proc</code></em> to <em class="parameter"><code>data</code></em>. This
  233. returns non-zero for success and zero for failure. (Failure is
  234. only possible if <em class="parameter"><code>proc</code></em> has not been properly
  235. registered in <em class="parameter"><code>conn</code></em>.)
  236. </p><pre class="synopsis">
  237. int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data);
  238. </pre><p>
  239. </p></dd><dt id="LIBPQ-PQINSTANCEDATA"><span class="term">
  240. <code class="function">PQinstanceData</code>
  241. <a id="id-1.7.3.20.6.2.3.1.2" class="indexterm"></a>
  242. </span></dt><dd><p>
  243. Returns the
  244. connection <em class="parameter"><code>conn</code></em>'s <code class="literal">instanceData</code>
  245. associated with procedure <em class="parameter"><code>proc</code></em>,
  246. or <code class="symbol">NULL</code> if there is none.
  247. </p><pre class="synopsis">
  248. void *PQinstanceData(const PGconn *conn, PGEventProc proc);
  249. </pre><p>
  250. </p></dd><dt id="LIBPQ-PQRESULTSETINSTANCEDATA"><span class="term">
  251. <code class="function">PQresultSetInstanceData</code>
  252. <a id="id-1.7.3.20.6.2.4.1.2" class="indexterm"></a>
  253. </span></dt><dd><p>
  254. Sets the result's <code class="literal">instanceData</code>
  255. for <em class="parameter"><code>proc</code></em> to <em class="parameter"><code>data</code></em>. This returns
  256. non-zero for success and zero for failure. (Failure is only
  257. possible if <em class="parameter"><code>proc</code></em> has not been properly registered
  258. in the result.)
  259. </p><pre class="synopsis">
  260. int PQresultSetInstanceData(PGresult *res, PGEventProc proc, void *data);
  261. </pre><p>
  262. </p><p>
  263. Beware that any storage represented by <em class="parameter"><code>data</code></em>
  264. will not be accounted for by <code class="function">PQresultMemorySize</code>,
  265. unless it is allocated using <code class="function">PQresultAlloc</code>.
  266. (Doing so is recommendable because it eliminates the need to free
  267. such storage explicitly when the result is destroyed.)
  268. </p></dd><dt id="LIBPQ-PQRESULTINSTANCEDATA"><span class="term">
  269. <code class="function">PQresultInstanceData</code>
  270. <a id="id-1.7.3.20.6.2.5.1.2" class="indexterm"></a>
  271. </span></dt><dd><p>
  272. Returns the result's <code class="literal">instanceData</code> associated with <em class="parameter"><code>proc</code></em>, or <code class="symbol">NULL</code>
  273. if there is none.
  274. </p><pre class="synopsis">
  275. void *PQresultInstanceData(const PGresult *res, PGEventProc proc);
  276. </pre><p>
  277. </p></dd></dl></div></div><div class="sect2" id="LIBPQ-EVENTS-EXAMPLE"><div class="titlepage"><div><div><h3 class="title">33.13.4. Event Example</h3></div></div></div><p>
  278. Here is a skeleton example of managing private data associated with
  279. libpq connections and results.
  280. </p><pre class="programlisting">
  281. /* required header for libpq events (note: includes libpq-fe.h) */
  282. #include &lt;libpq-events.h&gt;
  283. /* The instanceData */
  284. typedef struct
  285. {
  286. int n;
  287. char *str;
  288. } mydata;
  289. /* PGEventProc */
  290. static int myEventProc(PGEventId evtId, void *evtInfo, void *passThrough);
  291. int
  292. main(void)
  293. {
  294. mydata *data;
  295. PGresult *res;
  296. PGconn *conn =
  297. PQconnectdb("dbname=postgres options=-csearch_path=");
  298. if (PQstatus(conn) != CONNECTION_OK)
  299. {
  300. fprintf(stderr, "Connection to database failed: %s",
  301. PQerrorMessage(conn));
  302. PQfinish(conn);
  303. return 1;
  304. }
  305. /* called once on any connection that should receive events.
  306. * Sends a PGEVT_REGISTER to myEventProc.
  307. */
  308. if (!PQregisterEventProc(conn, myEventProc, "mydata_proc", NULL))
  309. {
  310. fprintf(stderr, "Cannot register PGEventProc\n");
  311. PQfinish(conn);
  312. return 1;
  313. }
  314. /* conn instanceData is available */
  315. data = PQinstanceData(conn, myEventProc);
  316. /* Sends a PGEVT_RESULTCREATE to myEventProc */
  317. res = PQexec(conn, "SELECT 1 + 1");
  318. /* result instanceData is available */
  319. data = PQresultInstanceData(res, myEventProc);
  320. /* If PG_COPYRES_EVENTS is used, sends a PGEVT_RESULTCOPY to myEventProc */
  321. res_copy = PQcopyResult(res, PG_COPYRES_TUPLES | PG_COPYRES_EVENTS);
  322. /* result instanceData is available if PG_COPYRES_EVENTS was
  323. * used during the PQcopyResult call.
  324. */
  325. data = PQresultInstanceData(res_copy, myEventProc);
  326. /* Both clears send a PGEVT_RESULTDESTROY to myEventProc */
  327. PQclear(res);
  328. PQclear(res_copy);
  329. /* Sends a PGEVT_CONNDESTROY to myEventProc */
  330. PQfinish(conn);
  331. return 0;
  332. }
  333. static int
  334. myEventProc(PGEventId evtId, void *evtInfo, void *passThrough)
  335. {
  336. switch (evtId)
  337. {
  338. case PGEVT_REGISTER:
  339. {
  340. PGEventRegister *e = (PGEventRegister *)evtInfo;
  341. mydata *data = get_mydata(e-&gt;conn);
  342. /* associate app specific data with connection */
  343. PQsetInstanceData(e-&gt;conn, myEventProc, data);
  344. break;
  345. }
  346. case PGEVT_CONNRESET:
  347. {
  348. PGEventConnReset *e = (PGEventConnReset *)evtInfo;
  349. mydata *data = PQinstanceData(e-&gt;conn, myEventProc);
  350. if (data)
  351. memset(data, 0, sizeof(mydata));
  352. break;
  353. }
  354. case PGEVT_CONNDESTROY:
  355. {
  356. PGEventConnDestroy *e = (PGEventConnDestroy *)evtInfo;
  357. mydata *data = PQinstanceData(e-&gt;conn, myEventProc);
  358. /* free instance data because the conn is being destroyed */
  359. if (data)
  360. free_mydata(data);
  361. break;
  362. }
  363. case PGEVT_RESULTCREATE:
  364. {
  365. PGEventResultCreate *e = (PGEventResultCreate *)evtInfo;
  366. mydata *conn_data = PQinstanceData(e-&gt;conn, myEventProc);
  367. mydata *res_data = dup_mydata(conn_data);
  368. /* associate app specific data with result (copy it from conn) */
  369. PQsetResultInstanceData(e-&gt;result, myEventProc, res_data);
  370. break;
  371. }
  372. case PGEVT_RESULTCOPY:
  373. {
  374. PGEventResultCopy *e = (PGEventResultCopy *)evtInfo;
  375. mydata *src_data = PQresultInstanceData(e-&gt;src, myEventProc);
  376. mydata *dest_data = dup_mydata(src_data);
  377. /* associate app specific data with result (copy it from a result) */
  378. PQsetResultInstanceData(e-&gt;dest, myEventProc, dest_data);
  379. break;
  380. }
  381. case PGEVT_RESULTDESTROY:
  382. {
  383. PGEventResultDestroy *e = (PGEventResultDestroy *)evtInfo;
  384. mydata *data = PQresultInstanceData(e-&gt;result, myEventProc);
  385. /* free instance data because the result is being destroyed */
  386. if (data)
  387. free_mydata(data);
  388. break;
  389. }
  390. /* unknown event ID, just return true. */
  391. default:
  392. break;
  393. }
  394. return true; /* event processing succeeded */
  395. }
  396. </pre></div></div><div class="navfooter"><hr /><table width="100%" summary="Navigation footer"><tr><td width="40%" align="left"><a accesskey="p" href="libpq-notice-processing.html">Prev</a> </td><td width="20%" align="center"><a accesskey="u" href="libpq.html">Up</a></td><td width="40%" align="right"> <a accesskey="n" href="libpq-envars.html">Next</a></td></tr><tr><td width="40%" align="left" valign="top">33.12. Notice Processing </td><td width="20%" align="center"><a accesskey="h" href="index.html">Home</a></td><td width="40%" align="right" valign="top"> 33.14. Environment Variables</td></tr></table></div></body></html>
上海开阖软件有限公司 沪ICP备12045867号-1