public void PqsqlConnectionTest4() { PqsqlConnection connection = new PqsqlConnection(connectionString); connection.Open(); Assert.AreEqual(ConnectionState.Open, connection.State, "wrong connection state"); IntPtr conn_attempt1 = connection.PGConnection; int sock1 = PqsqlWrapper.PQsocket(conn_attempt1); Assert.AreNotEqual(-1, sock1, "wrong socket"); // close the underlying socket without letting Pqsql and libpq know int closed = CloseSocket(sock1); Assert.AreEqual(0, closed, "closesocket failed"); connection.Close(); Assert.AreEqual(ConnectionState.Closed, connection.State, "wrong connection state"); connection.Open(); IntPtr conn_attempt2 = connection.PGConnection; ConnStatusType status = PqsqlWrapper.PQstatus(conn_attempt2); Assert.AreEqual(ConnStatusType.CONNECTION_OK, status, "connection broken"); Assert.AreEqual(ConnectionState.Open, connection.State, "wrong connection state"); int sock2 = PqsqlWrapper.PQsocket(conn_attempt2); // close the underlying socket without letting Pqsql and libpq know closed = CloseSocket(sock2); Assert.AreEqual(0, closed, "closesocket failed"); }
/// <summary> /// initializes all member variables, except mConnectionStringBuilder /// who will only be set in the ctors once and for all /// </summary> private void Init() { mNewConnectionString = true; mConnection = IntPtr.Zero; mStatus = ConnStatusType.CONNECTION_BAD; mTransStatus = PGTransactionStatusType.PQTRANS_UNKNOWN; mServerVersion = -1; }
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); }
public static IntPtr GetPGConn(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 Queue <ConnectionInfo> queue; IntPtr pgConn = IntPtr.Zero; lock (mPooledConnsLock) { // connStringBuilder guarantees that we only get "compatible" connections from our internal // connection pool, e.g., application_name will be the same if (!mPooledConns.TryGetValue(connStringBuilder, out queue)) { queue = new Queue <ConnectionInfo>(); mPooledConns[connStringBuilder] = queue; } } lock (queue) { int count = queue.Count; if (count > 0) { ConnectionInfo i = queue.Dequeue(); #if CODECONTRACTS Contract.Assume(i != null); #endif pgConn = i.pgconn; if (count > 1) { // head of queue will inherit old visited count ConnectionInfo j = queue.Peek(); #if CODECONTRACTS Contract.Assume(j != null); #endif j.visited = i.visited; } } } if (!CheckOrRelease(pgConn, out connStatus, out tranStatus)) { pgConn = SetupPGConn(connStringBuilder, out connStatus, out tranStatus); } return(pgConn); }
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); }