33.14. СиÑÑема ÑобÑÑий #
СиÑÑема ÑобÑÑий libpq ÑазÑабоÑана Ð´Ð»Ñ ÑÐ²ÐµÐ´Ð¾Ð¼Ð»ÐµÐ½Ð¸Ñ ÑÑнкÑий-обÑабоÑÑиков об инÑеÑеÑнÑÑ
ÑобÑÑиÑÑ
libpq, напÑимеÑ, о Ñоздании и ÑниÑÑожении обÑекÑов PGconn и PGresult. ÐÑновное иÑ
пÑедназнаÑение в Ñом, ÑÑÐ¾Ð±Ñ Ð¿Ð¾Ð·Ð²Ð¾Ð»Ð¸ÑÑ Ð¿ÑиложениÑм ÑвÑзаÑÑ ÑобÑÑвеннÑе даннÑе Ñ Ð¾Ð±ÑекÑами PGconn и PGresult и обеÑпеÑиÑÑ Ð¸Ñ
оÑвобождение в нÑжное вÑемÑ.
ÐаждÑй заÑегиÑÑÑиÑованнÑй обÑабоÑÑик ÑобÑÑий ÑвÑзÑваеÑÑÑ Ñ Ð´Ð²ÑÐ¼Ñ ÑлеменÑами даннÑÑ
, коÑоÑÑе извеÑÑÐ½Ñ libpq ÑолÑко как ÑкÑÑÑÑе ÑказаÑели void *. ÐеÑвÑй Ñквозной ÑказаÑÐµÐ»Ñ Ð¿ÐµÑедаÑÑÑÑ Ð¿Ñиложением, когда обÑабоÑÑик ÑобÑÑий ÑегиÑÑÑиÑÑеÑÑÑ Ð² PGconn. ÐÑÐ¾Ñ ÑказаÑÐµÐ»Ñ Ð½Ð¸ÐºÐ¾Ð³Ð´Ð° не менÑеÑÑÑ Ð½Ð° пÑоÑÑжении жизни PGconn и вÑе обÑекÑÑ PGresult ÑоздаÑÑÑÑ Ñ Ð½Ð¸Ð¼; поÑÑомÑ, еÑли он иÑполÑзÑеÑÑÑ, он должен ÑказÑваÑÑ Ð½Ð° долгоживÑÑие даннÑе. Рдополнение к Ð½ÐµÐ¼Ñ Ð¸Ð¼ÐµÐµÑÑÑ ÑказаÑÐµÐ»Ñ Ð´Ð°Ð½Ð½ÑÑ
ÑкземплÑÑа, коÑоÑÑй изнаÑалÑно Ñавен NULL во вÑеÑ
обÑекÑаÑ
PGconn и PGresult. ÐÑим ÑказаÑелем можно ÑпÑавлÑÑÑ Ñ Ð¿Ð¾Ð¼Ð¾ÑÑÑ ÑÑнкÑий PQinstanceData, PQsetInstanceData, PQresultInstanceData и PQresultSetInstanceData. ÐамеÑÑÑе, ÑÑо в оÑлиÑие Ð¾Ñ Ñквозного ÑказаÑелÑ, даннÑе ÑкземплÑÑа PGconn авÑомаÑиÑеÑки не наÑледÑÑÑÑÑ Ð¾Ð±ÑекÑами PGresult, ÑоздаваемÑми из него. ÐиблиоÑека libpq не знаеÑ, на ÑÑо ÑказÑваÑÑ Ñквозной ÑказаÑÐµÐ»Ñ Ð¸ ÑказаÑÐµÐ»Ñ Ð´Ð°Ð½Ð½ÑÑ
ÑкземплÑÑа (еÑли они ненÑлевÑе), и никогда не бÑÐ´ÐµÑ Ð¿ÑÑаÑÑÑÑ Ð¾ÑвобождаÑÑ Ð¸Ñ
â за ÑÑо оÑвеÑÐ°ÐµÑ Ð¾Ð±ÑабоÑÑик ÑобÑÑий.
33.14.1. Ð¢Ð¸Ð¿Ñ ÑобÑÑий #
ÐеÑеÑиÑление PGEventId опиÑÑÐ²Ð°ÐµÑ ÑÐ¸Ð¿Ñ ÑобÑÑий, обÑабаÑÑваемÑÑ
ÑиÑÑемой ÑобÑÑий. Ðмена вÑеÑ
иÑ
знаÑений наÑинаÑÑÑÑ Ñ PGEVT. ÐÐ»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ Ñипа ÑобÑÑий имееÑÑÑ ÑооÑвеÑÑÑвÑÑÑÐ°Ñ ÑÑÑÑкÑÑÑа инÑоÑмаÑии о ÑобÑÑии, ÑодеÑжаÑÐ°Ñ Ð¿Ð°ÑамеÑÑÑ, пеÑедаваемÑе обÑабоÑÑикам ÑобÑÑий. ÐпÑÐµÐ´ÐµÐ»ÐµÐ½Ñ ÑледÑÑÑие ÑÐ¸Ð¿Ñ ÑобÑÑий:
PGEVT_REGISTER#СобÑÑие ÑегиÑÑÑаÑии пÑоиÑÑ Ð¾Ð´Ð¸Ñ, когда вÑзÑваеÑÑÑ
PQregisterEventProc. ÐÑо Ð¿Ð¾Ð´Ñ Ð¾Ð´ÑÑий Ð¼Ð¾Ð¼ÐµÐ½Ñ Ð´Ð»Ñ Ð¸Ð½Ð¸ÑиализаÑии даннÑÑ ÑкземплÑÑа (instanceData), коÑоÑÑе могÑÑ Ð¿Ð¾Ð½Ð°Ð´Ð¾Ð±Ð¸ÑÑÑÑ Ð¿ÑоÑедÑÑе ÑобÑÑий. ÐÐ»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ обÑабоÑÑика ÑобÑÑий в ÑÐ°Ð¼ÐºÐ°Ñ ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð±ÑÐ´ÐµÑ Ð²ÑдаваÑÑÑÑ ÑолÑко одно ÑобÑÑие ÑегиÑÑÑаÑии. ÐÑли обÑабоÑка ÑобÑÑÐ¸Ñ Ð·Ð°Ð²ÐµÑÑаеÑÑÑ Ð¾Ñибкой (возвÑаÑаеÑÑÑ Ð½Ð¾Ð»Ñ), ÑегиÑÑÑаÑÐ¸Ñ Ð¾ÑменÑеÑÑÑ.typedef struct { PGconn *conn; } PGEventRegister;ÐÑи поÑÑÑплении ÑобÑÑиÑ
PGEVT_REGISTERÑказаÑелÑevtInfoÑледÑÐµÑ Ð¿ÑивеÑÑи кPGEventRegister *. ÐÑа ÑÑÑÑкÑÑÑа ÑодеÑÐ¶Ð¸Ñ Ð¾Ð±ÑекÑPGconn, коÑоÑÑй должен бÑÑÑ Ð² ÑоÑÑоÑнииCONNECTION_OK; ÑÑо гаÑанÑиÑÑеÑÑÑ, еÑлиPQregisterEventProcвÑзÑваеÑÑÑ ÑÑÐ°Ð·Ñ Ð¿Ð¾Ñле полÑÑÐµÐ½Ð¸Ñ ÑабоÑего обÑекÑаPGconn. Ð ÑлÑÑае вÑдаÑи кода оÑибки вÑÑ Ð¾ÑиÑÑÐºÑ Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ пÑовеÑÑи ÑамоÑÑоÑÑелÑно, Ñак как ÑобÑÑиеPGEVT_CONNDESTROYне поÑÑÑпиÑ.PGEVT_CONNRESET#СобÑÑие ÑбÑоÑа ÑÐ¾ÐµÐ´Ð¸Ð½ÐµÐ½Ð¸Ñ Ð¿ÑоиÑÑ Ð¾Ð´Ð¸Ñ Ð¿Ñи завеÑÑении
PQresetилиPQresetPoll. Ð Ð¾Ð±Ð¾Ð¸Ñ ÑлÑÑаÑÑ ÑÑо ÑобÑÑие вÑзÑваеÑÑÑ, ÑолÑко еÑли ÑбÑÐ¾Ñ Ð±Ñл ÑÑпеÑнÑм. ÐнаÑение, возвÑаÑаемое пÑоÑедÑÑой ÑобÑÑиÑ, в Postgres Pro v15 и более Ð¿Ð¾Ð·Ð´Ð½Ð¸Ñ Ð²ÐµÑÑиÑÑ Ð¸Ð³Ð½Ð¾ÑиÑÑеÑÑÑ. Ðднако Ñ Ð±Ð¾Ð»ÐµÐµ Ñанними веÑÑиÑми важно возвÑаÑаÑÑ ÑÑпеÑнÑй ÑезÑлÑÑÐ°Ñ (оÑлиÑнÑй Ð¾Ñ Ð½ÑлÑ), инаÑе Ñоединение бÑÐ´ÐµÑ Ð¿ÑеÑвано.typedef struct { PGconn *conn; } PGEventConnReset;ÐÑи поÑÑÑплении ÑобÑÑиÑ
PGEVT_CONNRESETÑказаÑелÑevtInfoÑледÑÐµÑ Ð¿ÑивеÑÑи кPGEventConnReset *. ХоÑÑ Ð¿ÐµÑеданнÑй обÑекÑPGconnбÑл ÑолÑко ÑÑо ÑбÑоÑен, вÑе даннÑе ÑобÑÑÐ¸Ñ Ð¾ÑÑаÑÑÑÑ Ð½ÐµÐ¸Ð·Ð¼ÐµÐ½Ð½Ñми. ÐÑи поÑÑÑплении ÑÑого ÑобÑÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ñ Ð±ÑÑÑ ÑбÑоÑенÑ/пеÑезагÑÑженÑ/Ð²Ð½Ð¾Ð²Ñ Ð·Ð°Ð¿ÑоÑÐµÐ½Ñ Ð²Ñе ÑопÑÑÑÑвÑÑÑие даннÑе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, коÑоÑÑе нÑжно ÑвÑзаÑÑ Ñ ÑезÑлÑÑаÑом. ÐÑли пÑоÑедÑÑа ÑобÑÑÐ¸Ñ Ð·Ð°Ð²ÐµÑÑиÑÑÑ Ð¾Ñибкой (возвÑаÑÐ¸Ñ Ð½Ð¾Ð»Ñ), она бÑÐ´ÐµÑ Ð¸Ð³Ð½Ð¾ÑиÑоваÑÑÑÑ Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ ÑезÑлÑÑаÑа, пока он бÑÐ´ÐµÑ ÑÑÑеÑÑвоваÑÑ; Ñо еÑÑÑ ÑÑа пÑоÑедÑÑа не бÑÐ´ÐµÑ Ð¿Ð¾Ð»ÑÑаÑÑ ÑобÑÑиÑPGEVT_RESULTCOPYи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не Ð¼Ð¾Ð¶ÐµÑ ÑÑо ÑделаÑÑ. ÐÑли пÑоÑедÑÑа ÑобÑÑÐ¸Ñ Ð·Ð°Ð²ÐµÑÑиÑÑÑ Ð¾Ñибкой (возвÑаÑÐ¸Ñ Ð½Ð¾Ð»Ñ), она бÑÐ´ÐµÑ Ð¸Ð³Ð½Ð¾ÑиÑоваÑÑÑÑ Ð´Ð»Ñ Ð´Ð°Ð½Ð½Ð¾Ð³Ð¾ ÑезÑлÑÑаÑа, пока он бÑÐ´ÐµÑ ÑÑÑеÑÑвоваÑÑ; Ñо еÑÑÑ ÑÑа пÑоÑедÑÑа не бÑÐ´ÐµÑ Ð¿Ð¾Ð»ÑÑаÑÑ ÑобÑÑиÑPGEVT_RESULTCOPYилиPGEVT_RESULTDESTROYÐ´Ð»Ñ Ð½ÐµÐ³Ð¾ или Ð´Ð»Ñ ÑезÑлÑÑаÑов, ÑкопиÑованнÑÑ Ð¸Ð· него.PGEVT_RESULTDESTROY#СобÑÑие ÑниÑÑÐ¾Ð¶ÐµÐ½Ð¸Ñ Ð¾Ð±ÑекÑа ÑезÑлÑÑаÑа пÑоиÑÑ Ð¾Ð´Ð¸Ñ Ð¿Ñи вÑполнении
PQclear. ÐбÑабоÑÑик ÑÑого ÑобÑÑÐ¸Ñ Ð¾ÑвеÑÐ°ÐµÑ Ð·Ð° коÑÑекÑнÑÑ Ð¾ÑиÑÑÐºÑ ÑÐ²Ð¾Ð¸Ñ Ð´Ð°Ð½Ð½ÑÑ ÑобÑÑий, Ñак как libpq не Ð¼Ð¾Ð¶ÐµÑ ÑпÑавлÑÑÑ ÐµÐ³Ð¾ памÑÑÑÑ. ÐевÑполнение оÑиÑÑки должнÑм обÑазом пÑиведÑÑ Ðº ÑÑеÑкам памÑÑи.typedef struct { PGresult *result; } PGEventResultDestroy;ÐÑи поÑÑÑплении ÑобÑÑиÑ
PGEVT_RESULTDESTROYÑказаÑелÑevtInfoÑледÑÐµÑ Ð¿ÑивеÑÑи кPGEventResultDestroy *. ÐÑо ÑобÑÑие пÑоиÑÑ Ð¾Ð´Ð¸Ñ Ð¿ÐµÑед Ñем, какPQclearпÑÐ¾Ð¸Ð·Ð²Ð¾Ð´Ð¸Ñ Ð²ÑÑ Ð¾ÑÑалÑнÑÑ Ð¾ÑиÑÑкÑ. ÐнаÑение, возвÑаÑаемое обÑабоÑÑиком ÑобÑÑий, игноÑиÑÑеÑÑÑ, Ñак как изPQclearникак нелÑÐ·Ñ ÑообÑиÑÑ Ð¾Ð± оÑибке. ÐÑоме Ñого, оÑибка в обÑабоÑÑике ÑобÑÑий не должна пÑеÑÑваÑÑ Ð¿ÑоÑеÑÑ Ð¾ÑиÑÑки ÑÑавÑей ненÑжной памÑÑи.
33.14.2. ÐÑоÑедÑÑа обÑабоÑки ÑобÑÑий #
PGEventProc#PGEventProcâ ÑÑо опÑеделение Ñипа Ð´Ð»Ñ ÑказаÑÐµÐ»Ñ Ð½Ð° обÑабоÑÑик ÑобÑÑий, Ñо еÑÑÑ ÑÑнкÑÐ¸Ñ Ð¾Ð±ÑаÑного вÑзова, полÑÑаÑÑÑÑ ÑобÑÑÐ¸Ñ Ð¾Ñ libpq. ÐбÑабоÑÑик ÑобÑÑий должен имеÑÑ ÑакÑÑ ÑигнаÑÑÑÑ:int eventproc(PGEventId evtId, void *evtInfo, void *passThrough)
ÐаÑамеÑÑ
evtIdговоÑиÑ, какое ÑобÑÑиеPGEVTпÑоизоÑло. УказаÑелÑevtInfoдолжен пÑиводиÑÑÑÑ Ðº ÑÐ¸Ð¿Ñ Ð¾Ð¿ÑеделÑнной ÑÑÑÑкÑÑÑÑ Ð´Ð»Ñ Ð¿Ð¾Ð»ÑÑÐµÐ½Ð¸Ñ Ð´Ð¾Ð¿Ð¾Ð»Ð½Ð¸ÑелÑной инÑоÑмаÑии о ÑобÑÑии. РпаÑамеÑÑеpassThroughпеÑедаÑÑÑÑ Ñквозной ÑказаÑелÑ, поÑÑÑпивÑий вPQregisterEventProcпÑи ÑегиÑÑÑаÑии обÑабоÑÑика ÑобÑÑиÑ. ÐÑа ÑÑнкÑÐ¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° веÑнÑÑÑ Ð½ÐµÐ½Ñлевое знаÑение в ÑлÑÑае ÑÑÐ¿ÐµÑ Ð° или Ð½Ð¾Ð»Ñ Ð² пÑоÑивном ÑлÑÑае.ÐбÑабоÑÑик опÑеделÑнного ÑобÑÑÐ¸Ñ Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð·Ð°ÑегиÑÑÑиÑован в лÑбом
PGconnÑолÑко Ñаз. ÐÑо ÑвÑзано Ñ Ñем, ÑÑо адÑÐµÑ Ð¾Ð±ÑабоÑÑика иÑполÑзÑеÑÑÑ ÐºÐ°Ðº клÑÑ Ð´Ð»Ñ Ð²ÑбоÑа ÑвÑзаннÑÑ Ð´Ð°Ð½Ð½ÑÑ ÑкземплÑÑа.Ðнимание
Ð Windows ÑÑнкÑии могÑÑ Ð¸Ð¼ÐµÑÑ Ð´Ð²Ð° ÑазнÑÑ Ð°Ð´ÑеÑа: один, видимÑй ÑнаÑÑжи DLL, и вÑоÑой, видимÑй внÑÑÑи DLL. УÑиÑÑÐ²Ð°Ñ ÑÑо, надо позабоÑиÑÑÑÑ Ð¾ Ñом, ÑÑÐ¾Ð±Ñ ÑолÑко один из адÑеÑов иÑполÑзовалÑÑ Ñ ÑÑнкÑиÑми обÑабоÑки ÑобÑÑий libpq, инаÑе Ð²Ð¾Ð·Ð½Ð¸ÐºÐ½ÐµÑ Ð¿ÑÑаниÑа. СамÑй пÑоÑÑой ÑпоÑоб напиÑаÑÑ ÐºÐ¾Ð´, коÑоÑÑй бÑÐ´ÐµÑ ÑабоÑаÑÑ â вÑегда помеÑаÑÑ Ð¾Ð±ÑабоÑÑик ÑобÑÑий как
static. ÐÑли адÑÐµÑ Ð¾Ð±ÑабоÑÑика нÑжно полÑÑиÑÑ Ð²Ð½Ðµ его иÑÑ Ð¾Ð´Ð½Ð¾Ð³Ð¾ Ñайла, ÑкÑпоÑÑиÑÑйÑе оÑделÑнÑÑ ÑÑнкÑиÑ, коÑоÑÐ°Ñ Ð±ÑÐ´ÐµÑ Ð²Ð¾Ð·Ð²ÑаÑаÑÑ ÑÑÐ¾Ñ Ð°Ð´ÑеÑ.
33.14.3. ФÑнкÑии поддеÑжки ÑобÑÑий #
PQregisterEventProc#РегиÑÑÑиÑÑÐµÑ Ð¾Ð±ÑабоÑÑик ÑобÑÑий в libpq.
int PQregisterEventProc(PGconn *conn, PGEventProc proc, const char *name, void *passThrough);ÐбÑабоÑÑик ÑобÑÑий должен бÑÑÑ Ð·Ð°ÑегиÑÑÑиÑован один Ñаз Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð³Ð¾ ÑоединениÑ
PGconn, ÑобÑÑÐ¸Ñ ÐºÐ¾ÑоÑого пÑедÑÑавлÑÑÑ Ð¸Ð½ÑеÑеÑ. ЧиÑло обÑабоÑÑиков ÑобÑÑий, коÑоÑÑе можно заÑегиÑÑÑиÑоваÑÑ Ð´Ð»Ñ ÑоединениÑ, не огÑаниÑиваеÑÑÑ Ð½Ð¸Ñем, кÑоме обÑÑма памÑÑи. ÐÑа ÑÑнкÑÐ¸Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð½ÐµÐ½Ñлевое знаÑение в ÑлÑÑае ÑÑÐ¿ÐµÑ Ð° или Ð½Ð¾Ð»Ñ Ð² пÑоÑивном ÑлÑÑае.ÐÑоÑедÑÑа, пеÑÐµÐ´Ð°Ð½Ð½Ð°Ñ Ð² аÑгÑменÑе
proc, бÑÐ´ÐµÑ Ð²ÑзÑваÑÑÑÑ, когда пÑоизойдÑÑ ÑобÑÑие libpq. ÐÑ Ð°Ð´ÑÐµÑ Ð² памÑÑи Ñакже пÑименÑеÑÑÑ Ð´Ð»Ñ Ð¿Ð¾Ð¸Ñка даннÑÑinstanceData. ÐÑгÑменÑnameиÑполÑзÑеÑÑÑ Ð¿Ñи Ñпоминании обÑабоÑÑика ÑобÑÑий в ÑообÑениÑÑ Ð¾Ð± оÑÐ¸Ð±ÐºÐ°Ñ . ÐÑо знаÑение не Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ ÑавноNULLили ÑказÑваÑÑ Ð½Ð° ÑÑÑÐ¾ÐºÑ Ð½Ñлевой длинÑ. ÐÑа ÑÑÑока имени копиÑÑеÑÑÑ Ð²PGconn, Ñак ÑÑо пеÑÐµÐ´Ð°Ð½Ð½Ð°Ñ ÑÑÑока Ð¼Ð¾Ð¶ÐµÑ Ð±ÑÑÑ Ð²Ñеменной. Сквозной ÑказаÑÐµÐ»Ñ (passThrough) бÑÐ´ÐµÑ Ð¿ÐµÑедаваÑÑÑÑ Ð¾Ð±ÑабоÑÑикÑprocпÑи каждом вÑзове ÑобÑÑиÑ. ÐÑÐ¾Ñ Ð°ÑгÑÐ¼ÐµÐ½Ñ Ð¼Ð¾Ð¶ÐµÑ ÑавнÑÑÑÑÑNULL.PQsetInstanceData#УÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð´Ð»Ñ Ð¿Ð¾Ð´ÐºÐ»ÑÑениÑ
connÑказаÑелÑinstanceDataÐ´Ð»Ñ Ð¾Ð±ÑабоÑÑикаprocÑавнÑмdata. ÐÑа ÑÑнкÑÐ¸Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð½ÐµÐ½Ñлевое знаÑение в ÑлÑÑае ÑÑÐ¿ÐµÑ Ð° или Ð½Ð¾Ð»Ñ Ð² пÑоÑивном ÑлÑÑае. (ÐÑибка возможна, ÑолÑко еÑли обÑабоÑÑикprocне бÑл коÑÑекÑно заÑегиÑÑÑиÑован Ð´Ð»Ñ ÑоединениÑconn.)int PQsetInstanceData(PGconn *conn, PGEventProc proc, void *data);
PQinstanceData#ÐозвÑаÑÐ°ÐµÑ Ð´Ð»Ñ ÑоединениÑ
connÑказаÑÐµÐ»Ñ Ð½Ð°instanceData, ÑвÑзаннÑй Ñ Ð¾Ð±ÑабоÑÑикомproc, либоNULL, еÑли Ñакого обÑабоÑÑика неÑ.void *PQinstanceData(const PGconn *conn, PGEventProc proc);
PQresultSetInstanceData#УÑÑÐ°Ð½Ð°Ð²Ð»Ð¸Ð²Ð°ÐµÑ Ð´Ð»Ñ Ð¾Ð±ÑекÑа ÑезÑлÑÑаÑа (
res) ÑказаÑелÑinstanceDataÐ´Ð»Ñ Ð¾Ð±ÑабоÑÑикаprocÑавнÑмdata. ÐÑа ÑÑнкÑÐ¸Ñ Ð²Ð¾Ð·Ð²ÑаÑÐ°ÐµÑ Ð½ÐµÐ½Ñлевое знаÑение в ÑлÑÑае ÑÑÐ¿ÐµÑ Ð° или Ð½Ð¾Ð»Ñ Ð² пÑоÑивном ÑлÑÑае. (ÐÑибка возможна, ÑолÑко еÑли обÑабоÑÑикprocне бÑл коÑÑекÑно заÑегиÑÑÑиÑован Ð´Ð»Ñ Ð¾Ð±ÑекÑа ÑезÑлÑÑаÑа.)int PQresultSetInstanceData(PGresult *res, PGEventProc proc, void *data);
ÐмейÑе в видÑ, ÑÑо памÑÑÑ, пÑедÑÑÐ°Ð²Ð»ÐµÐ½Ð½Ð°Ñ Ð¿Ð°ÑамеÑÑом
data, не бÑÐ´ÐµÑ ÑÑиÑÑваÑÑÑÑ Ð²PQresultMemorySize, еÑли ÑолÑко она не бÑла вÑделена ÑÑнкÑиейPQresultAlloc. (ÐÑой ÑÑнкÑией ÑекомендÑеÑÑÑ Ð¿Ð¾Ð»ÑзоваÑÑÑÑ, Ñак как ÑÑо избавлÑÐµÑ Ð¾Ñ Ð½ÐµÐ¾Ð±Ñ Ð¾Ð´Ð¸Ð¼Ð¾ÑÑи Ñвно оÑвобождаÑÑ Ð¿Ð°Ð¼ÑÑÑ Ð¿Ð¾Ñле ÑниÑÑÐ¾Ð¶ÐµÐ½Ð¸Ñ ÑезÑлÑÑаÑа.)PQresultInstanceData#ÐозвÑаÑÐ°ÐµÑ Ð´Ð»Ñ Ð¾Ð±ÑекÑа ÑезÑлÑÑаÑа (
res) ÑказаÑÐµÐ»Ñ Ð½Ð°instanceData, ÑвÑзаннÑй Ñ Ð¾Ð±ÑабоÑÑикомproc, либоNULL, еÑли Ñакого обÑабоÑÑика неÑ.void *PQresultInstanceData(const PGresult *res, PGEventProc proc);
33.14.4. ÐÑÐ¸Ð¼ÐµÑ Ð¾Ð±ÑабоÑки ÑобÑÑий #
Ðиже показан ÑÑ ÐµÐ¼Ð°ÑиÑнÑй пÑÐ¸Ð¼ÐµÑ ÑпÑÐ°Ð²Ð»ÐµÐ½Ð¸Ñ Ð²Ð½ÑÑÑенними даннÑми, ÑвÑзаннÑми Ñ Ð¿Ð¾Ð´ÐºÐ»ÑÑениÑми и ÑезÑлÑÑаÑами libpq.
/* required header for libpq events (note: includes 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 options=-csearch_path=");
if (PQstatus(conn) != CONNECTION_OK)
{
/* PQerrorMessage's result includes a trailing newline */
fprintf(stderr, "%s", PQerrorMessage(conn));
PQfinish(conn);
return 1;
}
/* called once on any connection that should receive events.
* Sends a PGEVT_REGISTER to myEventProc.
*/
if (!PQregisterEventProc(conn, myEventProc, "mydata_proc", NULL))
{
fprintf(stderr, "Cannot register PGEventProc\n");
PQfinish(conn);
return 1;
}
/* conn instanceData is available */
data = PQinstanceData(conn, myEventProc);
/* Sends a PGEVT_RESULTCREATE to myEventProc */
res = PQexec(conn, "SELECT 1 + 1");
/* result instanceData is available */
data = PQresultInstanceData(res, myEventProc);
/* If PG_COPYRES_EVENTS is used, sends a PGEVT_RESULTCOPY to 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.
*/
data = PQresultInstanceData(res_copy, myEventProc);
/* Both clears send a PGEVT_RESULTDESTROY to myEventProc */
PQclear(res);
PQclear(res_copy);
/* Sends a PGEVT_CONNDESTROY to 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 */
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) */
PQresultSetInstanceData(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) */
PQresultSetInstanceData(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. */
default:
break;
}
return true; /* event processing succeeded */
}