@@ -355,7 +355,7 @@ do_sql_command(PGconn *conn, const char *sql)
355355
356356 res = PQexec (conn , sql );
357357 if (PQresultStatus (res ) != PGRES_COMMAND_OK )
358- pgfdw_report_error (ERROR , res , true, sql );
358+ pgfdw_report_error (ERROR , res , conn , true, sql );
359359 PQclear (res );
360360}
361361
@@ -454,6 +454,7 @@ GetPrepStmtNumber(PGconn *conn)
454454 *
455455 * elevel: error level to use (typically ERROR, but might be less)
456456 * res: PGresult containing the error
457+ * conn: connection we did the query on
457458 * clear: if true, PQclear the result (otherwise caller will handle it)
458459 * sql: NULL, or text of remote command we tried to execute
459460 *
@@ -462,7 +463,8 @@ GetPrepStmtNumber(PGconn *conn)
462463 * marked with have_error = true.
463464 */
464465void
465- pgfdw_report_error (int elevel , PGresult * res , bool clear , const char * sql )
466+ pgfdw_report_error (int elevel , PGresult * res , PGconn * conn ,
467+ bool clear , const char * sql )
466468{
467469 /* If requested, PGresult must be released before leaving this function. */
468470 PG_TRY ();
@@ -483,6 +485,14 @@ pgfdw_report_error(int elevel, PGresult *res, bool clear, const char *sql)
483485 else
484486 sqlstate = ERRCODE_CONNECTION_FAILURE ;
485487
488+ /*
489+ * If we don't get a message from the PGresult, try the PGconn. This
490+ * is needed because for connection-level failures, PQexec may just
491+ * return NULL, not a PGresult at all.
492+ */
493+ if (message_primary == NULL )
494+ message_primary = PQerrorMessage (conn );
495+
486496 ereport (elevel ,
487497 (errcode (sqlstate ),
488498 message_primary ? errmsg_internal ("%s" , message_primary ) :
@@ -525,83 +535,88 @@ pgfdw_xact_callback(XactEvent event, void *arg)
525535 {
526536 PGresult * res ;
527537
528- /* We only care about connections with open remote transactions */
529- if (entry -> conn == NULL || entry -> xact_depth == 0 )
538+ /* Ignore cache entry if no open connection right now */
539+ if (entry -> conn == NULL )
530540 continue ;
531541
532- elog (DEBUG3 , "closing remote transaction on connection %p" ,
533- entry -> conn );
534-
535- switch (event )
542+ /* If it has an open remote transaction, try to close it */
543+ if (entry -> xact_depth > 0 )
536544 {
537- case XACT_EVENT_PRE_COMMIT :
538- /* Commit all remote transactions during pre-commit */
539- do_sql_command (entry -> conn , "COMMIT TRANSACTION" );
540-
541- /*
542- * If there were any errors in subtransactions, and we made
543- * prepared statements, do a DEALLOCATE ALL to make sure we
544- * get rid of all prepared statements. This is annoying and
545- * not terribly bulletproof, but it's probably not worth
546- * trying harder.
547- *
548- * DEALLOCATE ALL only exists in 8.3 and later, so this
549- * constrains how old a server postgres_fdw can communicate
550- * with. We intentionally ignore errors in the DEALLOCATE, so
551- * that we can hobble along to some extent with older servers
552- * (leaking prepared statements as we go; but we don't really
553- * support update operations pre-8.3 anyway).
554- */
555- if (entry -> have_prep_stmt && entry -> have_error )
556- {
557- res = PQexec (entry -> conn , "DEALLOCATE ALL" );
558- PQclear (res );
559- }
560- entry -> have_prep_stmt = false;
561- entry -> have_error = false;
562- break ;
563- case XACT_EVENT_PRE_PREPARE :
564-
565- /*
566- * We disallow remote transactions that modified anything,
567- * since it's not really reasonable to hold them open until
568- * the prepared transaction is committed. For the moment,
569- * throw error unconditionally; later we might allow read-only
570- * cases. Note that the error will cause us to come right
571- * back here with event == XACT_EVENT_ABORT, so we'll clean up
572- * the connection state at that point.
573- */
574- ereport (ERROR ,
575- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
576- errmsg ("cannot prepare a transaction that modified remote tables" )));
577- break ;
578- case XACT_EVENT_COMMIT :
579- case XACT_EVENT_PREPARE :
580- /* Should not get here -- pre-commit should have handled it */
581- elog (ERROR , "missed cleaning up connection during pre-commit" );
582- break ;
583- case XACT_EVENT_ABORT :
584- /* Assume we might have lost track of prepared statements */
585- entry -> have_error = true;
586- /* If we're aborting, abort all remote transactions too */
587- res = PQexec (entry -> conn , "ABORT TRANSACTION" );
588- /* Note: can't throw ERROR, it would be infinite loop */
589- if (PQresultStatus (res ) != PGRES_COMMAND_OK )
590- pgfdw_report_error (WARNING , res , true,
591- "ABORT TRANSACTION" );
592- else
593- {
594- PQclear (res );
595- /* As above, make sure we've cleared any prepared stmts */
545+ elog (DEBUG3 , "closing remote transaction on connection %p" ,
546+ entry -> conn );
547+
548+ switch (event )
549+ {
550+ case XACT_EVENT_PRE_COMMIT :
551+ /* Commit all remote transactions during pre-commit */
552+ do_sql_command (entry -> conn , "COMMIT TRANSACTION" );
553+
554+ /*
555+ * If there were any errors in subtransactions, and we
556+ * made prepared statements, do a DEALLOCATE ALL to make
557+ * sure we get rid of all prepared statements. This is
558+ * annoying and not terribly bulletproof, but it's
559+ * probably not worth trying harder.
560+ *
561+ * DEALLOCATE ALL only exists in 8.3 and later, so this
562+ * constrains how old a server postgres_fdw can
563+ * communicate with. We intentionally ignore errors in
564+ * the DEALLOCATE, so that we can hobble along to some
565+ * extent with older servers (leaking prepared statements
566+ * as we go; but we don't really support update operations
567+ * pre-8.3 anyway).
568+ */
596569 if (entry -> have_prep_stmt && entry -> have_error )
597570 {
598571 res = PQexec (entry -> conn , "DEALLOCATE ALL" );
599572 PQclear (res );
600573 }
601574 entry -> have_prep_stmt = false;
602575 entry -> have_error = false;
603- }
604- break ;
576+ break ;
577+ case XACT_EVENT_PRE_PREPARE :
578+
579+ /*
580+ * We disallow remote transactions that modified anything,
581+ * since it's not very reasonable to hold them open until
582+ * the prepared transaction is committed. For the moment,
583+ * throw error unconditionally; later we might allow
584+ * read-only cases. Note that the error will cause us to
585+ * come right back here with event == XACT_EVENT_ABORT, so
586+ * we'll clean up the connection state at that point.
587+ */
588+ ereport (ERROR ,
589+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
590+ errmsg ("cannot prepare a transaction that modified remote tables" )));
591+ break ;
592+ case XACT_EVENT_COMMIT :
593+ case XACT_EVENT_PREPARE :
594+ /* Pre-commit should have closed the open transaction */
595+ elog (ERROR , "missed cleaning up connection during pre-commit" );
596+ break ;
597+ case XACT_EVENT_ABORT :
598+ /* Assume we might have lost track of prepared statements */
599+ entry -> have_error = true;
600+ /* If we're aborting, abort all remote transactions too */
601+ res = PQexec (entry -> conn , "ABORT TRANSACTION" );
602+ /* Note: can't throw ERROR, it would be infinite loop */
603+ if (PQresultStatus (res ) != PGRES_COMMAND_OK )
604+ pgfdw_report_error (WARNING , res , entry -> conn , true,
605+ "ABORT TRANSACTION" );
606+ else
607+ {
608+ PQclear (res );
609+ /* As above, make sure to clear any prepared stmts */
610+ if (entry -> have_prep_stmt && entry -> have_error )
611+ {
612+ res = PQexec (entry -> conn , "DEALLOCATE ALL" );
613+ PQclear (res );
614+ }
615+ entry -> have_prep_stmt = false;
616+ entry -> have_error = false;
617+ }
618+ break ;
619+ }
605620 }
606621
607622 /* Reset state to show we're out of a transaction */
@@ -689,7 +704,7 @@ pgfdw_subxact_callback(SubXactEvent event, SubTransactionId mySubid,
689704 curlevel , curlevel );
690705 res = PQexec (entry -> conn , sql );
691706 if (PQresultStatus (res ) != PGRES_COMMAND_OK )
692- pgfdw_report_error (WARNING , res , true, sql );
707+ pgfdw_report_error (WARNING , res , entry -> conn , true, sql );
693708 else
694709 PQclear (res );
695710 }
0 commit comments