internal static IntPtr SetupPGConn(PqsqlConnectionStringBuilder connStringBuilder, out ConnStatusType connStatus, out PGTransactionStatusType tranStatus) { #if CODECONTRACTS Contract.Requires <ArgumentNullException>(connStringBuilder != null); #else if (connStringBuilder == null) { throw new ArgumentNullException(nameof(connStringBuilder)); } #endif // setup null-terminated key-value arrays for the connection string[] keys = new string[connStringBuilder.Keys.Count + 1]; string[] vals = new string[connStringBuilder.Values.Count + 1]; // get keys and values from PqsqlConnectionStringBuilder connStringBuilder.Keys.CopyTo(keys, 0); connStringBuilder.Values.CopyTo(vals, 0); // now create connection IntPtr conn = PqsqlWrapper.PQconnectdbParams(keys, vals, 0); if (conn == IntPtr.Zero) { connStatus = ConnStatusType.CONNECTION_BAD; tranStatus = PGTransactionStatusType.PQTRANS_UNKNOWN; return(conn); } // always force client_encoding to utf8 int client_encoding = PqsqlWrapper.PQclientEncoding(conn); if (client_encoding == (int)PgEnc.PG_UTF8) // done { connStatus = PqsqlWrapper.PQstatus(conn); tranStatus = PqsqlWrapper.PQtransactionStatus(conn); } else if (client_encoding == -1) // bail out, but keep connection object { connStatus = ConnStatusType.CONNECTION_BAD; tranStatus = PGTransactionStatusType.PQTRANS_UNKNOWN; } else // try to set client_encoding to utf8 { if (PqsqlWrapper.PQsetClientEncoding(conn, PgEncName.PG_UTF8) == 0) // success { connStatus = PqsqlWrapper.PQstatus(conn); tranStatus = PqsqlWrapper.PQtransactionStatus(conn); } else // bail out, but keep connection object { connStatus = ConnStatusType.CONNECTION_BAD; tranStatus = PGTransactionStatusType.PQTRANS_UNKNOWN; } } return(conn); }
private static bool DiscardConnection(IntPtr conn) { if (conn == IntPtr.Zero) { return(false); } bool rollback = false; ConnStatusType cs = PqsqlWrapper.PQstatus(conn); if (cs != ConnStatusType.CONNECTION_OK) { return(false); // connection broken } PGTransactionStatusType ts = PqsqlWrapper.PQtransactionStatus(conn); switch (ts) { case PGTransactionStatusType.PQTRANS_INERROR: /* idle, within failed transaction */ case PGTransactionStatusType.PQTRANS_INTRANS: /* idle, within transaction block */ rollback = true; break; case PGTransactionStatusType.PQTRANS_IDLE: /* connection idle */ // nothing to do break; // PGTransactionStatusType.PQTRANS_ACTIVE: /* command in progress */ // PGTransactionStatusType.PQTRANS_UNKNOWN: /* cannot determine status */ default: return(false); // connection broken } IntPtr res; ExecStatusType s = ExecStatusType.PGRES_FATAL_ERROR; // we need to rollback before we can discard the connection if (rollback) { unsafe { fixed(byte *st = PqsqlTransaction.RollbackStatement) { res = PqsqlWrapper.PQexec(conn, st); if (res != IntPtr.Zero) { s = PqsqlWrapper.PQresultStatus(res); PqsqlWrapper.PQclear(res); } } } if (s != ExecStatusType.PGRES_COMMAND_OK) { return(false); // connection broken } s = ExecStatusType.PGRES_FATAL_ERROR; } // discard connection unsafe { fixed(byte *st = DiscardAllStatement) { res = PqsqlWrapper.PQexec(conn, st); if (res != IntPtr.Zero) { s = PqsqlWrapper.PQresultStatus(res); PqsqlWrapper.PQclear(res); } } } if (s != ExecStatusType.PGRES_COMMAND_OK) { return(false); // connection broken } return(true); // connection successfully resetted }
private static bool CheckOrRelease(IntPtr pgConn, out ConnStatusType connStatus, out PGTransactionStatusType tranStatus) { if (pgConn == IntPtr.Zero) { connStatus = ConnStatusType.CONNECTION_BAD; tranStatus = PGTransactionStatusType.PQTRANS_UNKNOWN; return(false); } // is connection reusable? connStatus = PqsqlWrapper.PQstatus(pgConn); if (connStatus != ConnStatusType.CONNECTION_OK) { goto broken; } tranStatus = PqsqlWrapper.PQtransactionStatus(pgConn); if (tranStatus != PGTransactionStatusType.PQTRANS_IDLE) { goto broken; } // // now check the connection: first try to fix the client encoding if it is not utf8 for some reason. // if client_encoding is utf8, we send the empty query to check whether the socket is still usable // for the backend communiction. here, we could make use of tcp_keepalive settings. // int client_encoding = PqsqlWrapper.PQclientEncoding(pgConn); if (client_encoding == -1) { goto broken; } if (client_encoding == (int)PgEnc.PG_UTF8) // client_encoding == utf8 { // send empty query to test whether we are really connected (tcp_keepalive might have closed socket) unsafe { byte[] empty = { 0 }; // empty query string fixed(byte *eq = empty) { if (PqsqlWrapper.PQsendQuery(pgConn, eq) == 0) // could not send query { goto broken; } } } // Reading result: consume and clear remaining results until we reach the NULL result. // PQgetResult will block here IntPtr res; ExecStatusType st = ExecStatusType.PGRES_EMPTY_QUERY; while ((res = PqsqlWrapper.PQgetResult(pgConn)) != IntPtr.Zero) { ExecStatusType st0 = PqsqlWrapper.PQresultStatus(res); if (st0 != ExecStatusType.PGRES_EMPTY_QUERY) { st = st0; } // always free res PqsqlWrapper.PQclear(res); } if (st != ExecStatusType.PGRES_EMPTY_QUERY) // received wrong exec status { goto broken; } } else // set client_encoding to utf8 { // set client_encoding to test whether we are really connected (tcp_keepalive might have closed socket) if (PqsqlWrapper.PQsetClientEncoding(pgConn, PgEncName.PG_UTF8) != 0) { goto broken; } } return(true); // successfully reused connection broken: // reconnect with current connection setting PqsqlWrapper.PQreset(pgConn); connStatus = PqsqlWrapper.PQstatus(pgConn); if (connStatus == ConnStatusType.CONNECTION_OK) { tranStatus = PqsqlWrapper.PQtransactionStatus(pgConn); if (tranStatus == PGTransactionStatusType.PQTRANS_IDLE) { return(true); // successfully reconnected } } else { tranStatus = PGTransactionStatusType.PQTRANS_UNKNOWN; } // could not reconnect: finally give up and clean up memory PqsqlWrapper.PQfinish(pgConn); return(false); }