Esempio n. 1
0
        // postgres error codes are stored as alphanumeric string of
        // 5 characters. we convert them to an integer of maximum 30 bits;
        // each character is stored within 6 bits of ErrorCode
        private static unsafe int CreateErrorCode(IntPtr result)
        {
            sbyte *sqlState = PqsqlWrapper.PQresultErrorField(result, PqsqlDiag.PG_DIAG_SQLSTATE);

            int code = (int)PqsqlState.SUCCESSFUL_COMPLETION;              // code=0: error code '00000' means successful_completion

            if (sqlState != null)
            {
                for (int j = 0, c = *sqlState; j < 5 && c != 0; j++, c = *(++sqlState))
                {
                    int i = 0;
                    if (c >= 48 && c <= 57)                     // '0' ... '9' =>  0 ...  9
                    {
                        i = c - 48;
                    }
                    else if (c >= 65 && c <= 90)                     // 'A' ... 'Z' => 10 ... 35
                    {
                        i = c - 55;
                    }

                    // store each character in 6 bits from code
                    code |= (i << j * 6);
                }
            }

            return(code);
        }
Esempio n. 2
0
        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");
        }
Esempio n. 3
0
 public PqsqlCopyFrom(PqsqlConnection conn)
     : base(conn)
 {
     mColBuf = IntPtr.Zero;
     mExpBuf = PqsqlWrapper.createPQExpBuffer();
     mPos    = 0;
 }
Esempio n. 4
0
        // call PQexec
        internal ExecStatusType Exec(byte[] stmt, out IntPtr res)
        {
            if (mConnection == IntPtr.Zero)
            {
                res = IntPtr.Zero;
                return(ExecStatusType.PGRES_FATAL_ERROR);
            }

            unsafe
            {
                fixed(byte *st = stmt)
                {
                    res = PqsqlWrapper.PQexec(mConnection, st);
                }
            }

            ExecStatusType s = ExecStatusType.PGRES_FATAL_ERROR;

            if (res != IntPtr.Zero)
            {
                s = PqsqlWrapper.PQresultStatus(res);
            }

            return(s);
        }
Esempio n. 5
0
        // write to LO
        public override void Write(byte[] buffer, int offset, int count)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            if (!CanWrite)
            {
                throw new NotSupportedException("Writing to large object is turned off");
            }

            int blen = buffer.Length;

            if (offset + count > blen)
            {
                throw new ArgumentException("offset or count larger than buffer");
            }

            if (offset < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            if (mFd < 0)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Cannot write closed large object {0}", mOid));
            }

            int ret = count;

            unsafe
            {
                while (count > 0 && ret > 0)
                {
                    fixed(byte *b = &buffer[offset])
                    {
                        ret = PqsqlWrapper.lo_write(mPGConn, mFd, b, (ulong)count);
                    }

                    if (ret > 0)
                    {
                        offset += ret;
                        count  -= ret;
                        mPos   += ret;
                    }
                }
            }

            if (ret < 0)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Could not write to large object {0}: {1}", mOid, mConn.GetErrorMessage()));
            }
        }
Esempio n. 6
0
        //
        // Summary:
        //     Enlists in the specified transaction. TODO
        //
        // Parameters:
        //   transaction:
        //     A reference to an existing System.Transactions.Transaction in which to enlist.
        //public override void EnlistTransaction(PqsqlTransaction transaction)
        //{
        //	throw new NotImplementedException();
        //}

        //
        // Summary:
        //     Opens a database connection with the settings specified by the System.Data.Common.DbConnection.ConnectionString.
        public override void Open()
        {
            if (mConnection != IntPtr.Zero && !mNewConnectionString)
            {
                // close and open with current connection setting
                PqsqlWrapper.PQreset(mConnection);

                // update connection and transaction status
                if (Status == ConnStatusType.CONNECTION_BAD || TransactionStatus != PGTransactionStatusType.PQTRANS_IDLE)
                {
                    string err = GetErrorMessage();
                    PqsqlWrapper.PQfinish(mConnection);                     // force release of mConnection memory
                    Init();
                    var connStr = mConnectionStringBuilder.GetConnectionStringWithObfuscatedPassword();
                    throw new PqsqlException("Could not reset connection with connection string «" + connStr + "»: " + err, (int)PqsqlState.CONNECTION_FAILURE);
                }

                OnStateChange(new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open));

                // always set application_name, after a DISCARD ALL (usually issued by PqsqlConnectionPool / pgbouncer)
                // the session information is gone forever, and the shared connection will drop application_name
                SetApplicationName();

                // successfully reestablished connection
                return;
            }

            if (mStatus != ConnStatusType.CONNECTION_BAD)
            {
                Close();                 // force release of mConnection memory
            }

            // check connection pool for a connection
            mConnection = PqsqlConnectionPool.GetPGConn(mConnectionStringBuilder, out mStatus, out mTransStatus);

            if (mConnection == IntPtr.Zero)
            {
                throw new PqsqlException("libpq: unable to allocate struct PGconn");
            }

            // check connection and transaction status
            if (mStatus == ConnStatusType.CONNECTION_BAD || mTransStatus != PGTransactionStatusType.PQTRANS_IDLE)
            {
                string err = GetErrorMessage();
                PqsqlWrapper.PQfinish(mConnection);                 // force release of mConnection memory
                Init();
                var connStr = mConnectionStringBuilder.GetConnectionStringWithObfuscatedPassword();
                throw new PqsqlException("Could not create connection with connection string «" + connStr + "»: " + err);
            }

            mNewConnectionString = false;

            OnStateChange(new StateChangeEventArgs(ConnectionState.Closed, ConnectionState.Open));

            // always set application_name, after a DISCARD ALL (usually issued by PqsqlConnectionPool / pgbouncer)
            // the session information is gone forever, and the shared connection will drop application_name
            SetApplicationName();
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        private static unsafe string CreateHint(IntPtr result)
        {
            sbyte *hint = PqsqlWrapper.PQresultErrorField(result, PqsqlDiag.PG_DIAG_MESSAGE_HINT);

            if (hint == null)
            {
                return(string.Empty);
            }
            return(new string(hint));
        }
Esempio n. 9
0
        // truncates LO to value
        public override void SetLength(long value)
        {
            if (value < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(value));
            }

            if (mFd < 0)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Cannot truncate closed large object {0}", mOid));
            }

            long pos = PqsqlWrapper.lo_tell64(mPGConn, mFd);

            if (pos < 0 || mPos != pos)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Could not tell large object {0}: {1}", mOid, mConn.GetErrorMessage()));
            }

            long old = PqsqlWrapper.lo_lseek64(mPGConn, mFd, 0, (int)SeekOrigin.End);

            if (old < 0)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Could not seek large object {0}: {1}", mOid, mConn.GetErrorMessage()));
            }

            if (old == value)             // we are done
            {
                goto seekPos;
            }

#if CODECONTRACTS
            Contract.Assert(value >= 0);
#endif

            int ret = PqsqlWrapper.lo_truncate64(mPGConn, mFd, value);

            if (ret < 0)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Could not truncate large object {0} to {1} bytes: {2}", mOid, value, mConn.GetErrorMessage()));
            }

            if (value < pos)             // lo has been truncated, update position to last byte
            {
                pos = value;
            }

seekPos:
            mPos = PqsqlWrapper.lo_lseek64(mPGConn, mFd, pos, (int)SeekOrigin.Begin);

            if (mPos != pos)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Could not seek large object {0}: {1}", mOid, mConn.GetErrorMessage()));
            }
        }
Esempio n. 10
0
        public int Unlink(uint oid)
        {
            // returns < 0 on error
            int ret = PqsqlWrapper.lo_unlink(mPGConn, oid);

            if (ret < 0)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Could not unlink large object {0}: {1}", oid, mConn.GetErrorMessage()));
            }

            return(ret);
        }
Esempio n. 11
0
        public uint Create()
        {
            // returns 0 (InvalidOid) on error
            uint ret = PqsqlWrapper.lo_create(mPGConn, 0);

            if (ret == 0)
            {
                throw new PqsqlException("Could not create large object: " + mConn.GetErrorMessage());
            }

            return(ret);
        }
Esempio n. 12
0
        // read from LO
        public override int Read(byte[] buffer, int offset, int count)
        {
            if (buffer == null)
            {
                throw new ArgumentNullException(nameof(buffer));
            }

            if (!CanRead)
            {
                throw new NotSupportedException("Reading from large object is turned off");
            }

            int blen = buffer.Length;

            if (offset + count > blen)
            {
                throw new ArgumentException("offset or count larger than buffer");
            }

            if (offset < 0 || offset >= blen)
            {
                throw new ArgumentOutOfRangeException(nameof(offset));
            }

            if (count < 0)
            {
                throw new ArgumentOutOfRangeException(nameof(count));
            }

            if (mFd < 0)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Cannot read closed large object {0}", mOid));
            }

            int read;

            unsafe
            {
                fixed(byte *b = &buffer[offset])
                {
                    read = PqsqlWrapper.lo_read(mPGConn, mFd, b, (ulong)count);
                }
            }

            if (read >= 0)
            {
                mPos += read;
                return(read);
            }

            throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Could not read large object {0}: {1}", mOid, mConn.GetErrorMessage()));
        }
Esempio n. 13
0
        public override void Close()
        {
            if (mColBuf != IntPtr.Zero)
            {
                PqsqlBinaryFormat.pqcb_free(mColBuf);
                mColBuf = IntPtr.Zero;
            }

            if (mExpBuf != IntPtr.Zero)
            {
                PqsqlWrapper.destroyPQExpBuffer(mExpBuf);
                mExpBuf = IntPtr.Zero;
            }
        }
Esempio n. 14
0
        // returns current position of mExpBuf
        private long LengthCheckReset()
        {
            long len = PqsqlBinaryFormat.pqbf_get_buflen(mExpBuf);

            if (len > 4096)
            {
                // if we exceed 4k write-boundary, we reset the buffer and
                // start to write from the beginning again
                PqsqlWrapper.resetPQExpBuffer(mExpBuf);
                len = 0;
            }

            return(len);
        }
Esempio n. 15
0
        public override void Close()
        {
            if (mFd < 0)
            {
                return;
            }

            if (PqsqlWrapper.lo_close(mPGConn, mFd) == -1)
            {
                // ignore error
            }

            mFd   = -1;
            mMode = 0;
            mPos  = -1;
        }
Esempio n. 16
0
        // sets new position in the LO
        public override long Seek(long offset, SeekOrigin origin)
        {
            if (mFd < 0)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Cannot seek closed large object {0}", mOid));
            }

            mPos = PqsqlWrapper.lo_lseek64(mPGConn, mFd, offset, (int)origin);

            if (mPos < 0)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Could not seek large object {0}: {1}", mOid, mConn.GetErrorMessage()));
            }

            return(mPos);
        }
Esempio n. 17
0
        public static void ReleasePGConn(PqsqlConnectionStringBuilder connStringBuilder, IntPtr pgConnHandle)
        {
#if CODECONTRACTS
            Contract.Requires <ArgumentNullException>(connStringBuilder != null);
#else
            if (connStringBuilder == null)
            {
                throw new ArgumentNullException(nameof(connStringBuilder));
            }
#endif

            if (pgConnHandle == IntPtr.Zero)
            {
                return;
            }

            Queue <ConnectionInfo> queue;

            lock (mPooledConnsLock)
            {
                mPooledConns.TryGetValue(connStringBuilder, out queue);
            }

            bool closeConnection = true;

            if (queue == null || !DiscardConnection(pgConnHandle))
            {
                goto close;                 // just cleanup connection and restart timer
            }

            lock (queue)
            {
                if (queue.Count < MaxQueue)
                {
                    queue.Enqueue(new ConnectionInfo {
                        pgconn = pgConnHandle, visited = 0
                    });
                    closeConnection = false;                     // keep connection
                }
            }

close:
            if (closeConnection)
            {
                PqsqlWrapper.PQfinish(pgConnHandle);                 // close connection and release memory
            }
        }
Esempio n. 18
0
        // consume remaining results from connection
        internal void Consume(IntPtr res)
        {
            if (mConnection == IntPtr.Zero)
            {
                return;
            }

            if (res != IntPtr.Zero)
            {
                PqsqlWrapper.PQclear(res);
            }

            // consume all remaining results until we reach the NULL result
            while ((res = PqsqlWrapper.PQgetResult(mConnection)) != IntPtr.Zero)
            {
                // always free mResult
                PqsqlWrapper.PQclear(res);
            }
        }
Esempio n. 19
0
        // see https://www.postgresql.org/docs/current/static/libpq-status.html#LIBPQ-PQPARAMETERSTATUS
        private string GetParameterStatus(byte[] param)
        {
            if (mConnection == IntPtr.Zero || param == null)
            {
                return(string.Empty);
            }

            unsafe
            {
                sbyte *parameterStatus = PqsqlWrapper.PQparameterStatus(mConnection, param);

                if (parameterStatus == null)
                {
                    return(string.Empty);
                }

                return(new string(parameterStatus));                // TODO UTF-8 encoding ignored here!
            }
        }
Esempio n. 20
0
        // Summary:
        //     Attempts to cancels the execution of a System.Data.Common.DbCommand.
        public override void Cancel()
        {
            if (mConn == null)
            {
                return;
            }

            ConnectionState s = mConn.State;

            // no cancel possible/necessary if connection is closed / open / connecting / broken
            if (s == ConnectionState.Closed || s == ConnectionState.Open || (s & (ConnectionState.Broken | ConnectionState.Connecting)) > 0)
            {
                return;
            }

            IntPtr cancel = PqsqlWrapper.PQgetCancel(mConn.PGConnection);

            if (cancel != IntPtr.Zero)
            {
                sbyte[] buf = new sbyte[256];

                string err;
                unsafe
                {
                    fixed(sbyte *b = buf)
                    {
                        int cret = PqsqlWrapper.PQcancel(cancel, b, 256);

                        PqsqlWrapper.PQfreeCancel(cancel);

                        if (cret == 1)
                        {
                            return;
                        }

                        err = PqsqlUTF8Statement.CreateStringFromUTF8(new IntPtr(b));
                    }
                }

                throw new PqsqlException("Could not cancel command «" + mCmdText + "»: " + err);
            }
        }
Esempio n. 21
0
        public int Open(uint oid, LoOpen mode)
        {
#if CODECONTRACTS
            Contract.Requires <ArgumentException>(oid != 0, "Cannot open large object with InvalidOid (0)");
#else
            if (oid == 0)
            {
                throw new ArgumentException("Cannot open large object with InvalidOid (0)");
            }
#endif

            mFd = PqsqlWrapper.lo_open(mPGConn, oid, (int)mode);

            if (mFd < 0)
            {
                throw new PqsqlException(string.Format(CultureInfo.InvariantCulture, "Cannot open large object {0}: {1}", oid, mConn.GetErrorMessage()));
            }

            mOid  = oid;
            mMode = mode;
            mPos  = 0;
            return(mFd);
        }
Esempio n. 22
0
        // return current error message
        internal string GetErrorMessage()
        {
#if CODECONTRACTS
            Contract.Ensures(Contract.Result <string>() != null);
#endif

            string msg = string.Empty;

            if (mConnection != IntPtr.Zero)
            {
                unsafe
                {
                    sbyte *b = PqsqlWrapper.PQerrorMessage(mConnection);

                    if (b != null)
                    {
                        msg = PqsqlUTF8Statement.CreateStringFromUTF8(new IntPtr(b));
                    }
                }
            }

            return(msg);
        }
Esempio n. 23
0
        public void PqsqlConnectionTest10()
        {
            PqsqlConnectionPool.Clear();

            PqsqlConnection connection = new PqsqlConnection(connectionString);

            connection.Open();
            Assert.AreEqual(ConnectionState.Open, connection.State, "wrong connection state");

            IntPtr pgConn          = connection.PGConnection;
            int    client_encoding = PqsqlWrapper.PQclientEncoding(pgConn);

            Assert.AreEqual((int)PgEnc.PG_UTF8, client_encoding, "wrong client_encoding");

            // setup client_encoding to sqlascii, and leave it like that

            byte[] encoding = PqsqlUTF8Statement.CreateUTF8Statement("sqlascii");
            client_encoding = PqsqlWrapper.PQsetClientEncoding(pgConn, encoding);
            Assert.AreEqual(0, client_encoding, "could not set client_encoding");

            client_encoding = PqsqlWrapper.PQclientEncoding(pgConn);
            Assert.AreEqual(0, client_encoding, "wrong client_encoding");

            connection.Close();

            // now try to get the same connection again

            connection = new PqsqlConnection(connectionString);

            connection.Open();
            Assert.AreEqual(ConnectionState.Open, connection.State, "wrong connection state");

            pgConn          = connection.PGConnection;
            client_encoding = PqsqlWrapper.PQclientEncoding(pgConn);
            Assert.AreEqual((int)PgEnc.PG_UTF8, client_encoding, "wrong client_encoding");
        }
Esempio n. 24
0
        private static void PoolService(object o)
        {
#if CODECONTRACTS
            Contract.Requires <ArgumentNullException>(o != null);
#else
            if (o == null)
            {
                throw new ArgumentNullException(nameof(o));
            }
#endif

            List <IntPtr> closeConnections = o as List <IntPtr>;

            // we assume that we run PoolService in less than IdleTimeout msecs
            lock (mPooledConnsLock)
            {
#if PQSQL_DEBUG
                mLogger.Debug("Running PoolService");
#endif

                using (Dictionary <PqsqlConnectionStringBuilder, Queue <ConnectionInfo> > .Enumerator e = mPooledConns.GetEnumerator())
                {
                    while (e.MoveNext())
                    {
                        KeyValuePair <PqsqlConnectionStringBuilder, Queue <ConnectionInfo> > item = e.Current;
#if PQSQL_DEBUG
                        PqsqlConnectionStringBuilder csb = item.Key;
#endif
                        Queue <ConnectionInfo> queue = item.Value;

                        lock (queue)
                        {
                            int count = queue.Count;

#if PQSQL_DEBUG
                            mLogger.DebugFormat("ConnectionPool {0}: {1} waiting connections", csb.ConnectionString, count);
#endif

                            if (count == 0)
                            {
                                continue;
                            }

                            int maxRelease = count / 2 + 1;

                            ConnectionInfo i = queue.Peek();
#if CODECONTRACTS
                            Contract.Assume(i != null);
#endif
                            i.visited++;

#if PQSQL_DEBUG
                            if (i.visited <= VisitedThreshold)
                            {
                                mLogger.DebugFormat("ConnectionPool {0}: {1} visits", csb.ConnectionString, i.visited);
                            }
#endif

                            if (i.visited > VisitedThreshold)
                            {
#if PQSQL_DEBUG
                                mLogger.DebugFormat("ConnectionPool {0}: visit threshold {1} reached, releasing {2} connections", csb.ConnectionString, i.visited, maxRelease);
#endif
                                while (maxRelease > 0)
                                {
                                    // clean maxRelease connections
                                    i = queue.Dequeue();
#if CODECONTRACTS
                                    Contract.Assume(i != null);
#endif
                                    closeConnections.Add(i.pgconn);                                     // close connections outside of queue lock
                                    maxRelease--;
                                }
                            }
                        }
                    }
                }
            }

            // now close old connections
            foreach (IntPtr conn in closeConnections)
            {
                PqsqlWrapper.PQfinish(conn);                 // close connection and release memory
            }

            closeConnections.Clear();
        }
Esempio n. 25
0
        protected string Error()
        {
            IntPtr res;
            string err  = string.Empty;
            IntPtr conn = mConn.PGConnection;

            res = PqsqlWrapper.PQgetResult(conn);

            if (res != IntPtr.Zero)
            {
                ExecStatusType s = PqsqlWrapper.PQresultStatus(res);

                PqsqlWrapper.PQclear(res);

                if (s == ExecStatusType.PGRES_COPY_IN || s == ExecStatusType.PGRES_COPY_OUT)
                {
                    if (s == ExecStatusType.PGRES_COPY_IN)
                    {
                        // still in COPY_IN mode? bail out!
                        byte[] b = PqsqlUTF8Statement.CreateUTF8Statement("COPY cancelled by client");
                        int    end;

                        unsafe
                        {
                            fixed(byte *bs = b)
                            {
                                end = PqsqlWrapper.PQputCopyEnd(conn, bs);
                            }
                        }

                        if (end != 1)
                        {
                            err = err.Insert(0, "Cannot cancel COPY (" + s + "): ");

                            goto bailout;
                        }
                    }

                    res = PqsqlWrapper.PQgetResult(conn);

                    if (res != IntPtr.Zero)
                    {
                        s = PqsqlWrapper.PQresultStatus(res);
                        PqsqlWrapper.PQclear(res);
                    }
                }

                if (s != ExecStatusType.PGRES_COMMAND_OK)
                {
                    err = err.Insert(0, "COPY failed (" + s + "): ");

                    goto bailout;
                }

                // consume all remaining results until we reach the NULL result
                while ((res = PqsqlWrapper.PQgetResult(conn)) != IntPtr.Zero)
                {
                    // always free mResult
                    PqsqlWrapper.PQclear(res);
                }

                return(err);
            }

bailout:
            err += mConn.GetErrorMessage();

            return(err);
        }
Esempio n. 26
0
        public virtual void Start()
        {
#if CODECONTRACTS
            Contract.Requires <InvalidOperationException>(
                !string.IsNullOrWhiteSpace(Table) || !string.IsNullOrWhiteSpace(QueryInternal),
                "Table and Query properties are null.");
#else
            if (string.IsNullOrWhiteSpace(Table) && string.IsNullOrWhiteSpace(QueryInternal))
            {
                throw new InvalidOperationException("Table and Query properties are null.");
            }
#endif

            // PQexec does not set field types in PQresult for COPY FROM statements,
            // just retrieve 0 rows for the field types of Table or Query

            // TODO use PqsqlCopyColumnsCollection for ColumnList
            StringBuilder sb = new StringBuilder();
            if (!SuppressSchemaQueryInternal)
            {
                if (QueryInternal == null)
                {
                    sb.AppendFormat("SELECT {0} FROM {1} LIMIT 0;", (object)ColumnList ?? '*', Table);
                }
                else
                {
                    sb.AppendFormat("{0} LIMIT 0;", QueryInternal);
                }

                // fetch number of columns and store column information
                using (PqsqlCommand cmd = new PqsqlCommand(mConn))
                {
                    cmd.CommandText    = sb.ToString();
                    cmd.CommandType    = CommandType.Text;
                    cmd.CommandTimeout = CopyTimeout;

                    using (PqsqlDataReader r = cmd.ExecuteReader(CommandBehavior.Default))
                    {
                        // just pick current row information
                        PqsqlColInfo[] src = r.RowInformation;

                        if (src == null)
                        {
                            throw new PqsqlException("Cannot retrieve RowInformation for '" +
                                                     QueryInternal ?? Table + "'.");
                        }

                        mColumns = src.Length;
                        mRowInfo = new PqsqlColInfo[mColumns];

                        Array.Copy(src, mRowInfo, mColumns);
                    }
                }

                sb.Clear();
            }

            // now build COPY FROM statement
            sb.Append("COPY ");

            if (QueryInternal == null)
            {
                sb.AppendFormat("{0} ", Table);

                // always create list of columns if not SuppressSchemaQuery
                if (string.IsNullOrEmpty(ColumnList))
                {
                    if (!SuppressSchemaQueryInternal)
                    {
                        // just assume that we use standard table order
                        sb.AppendFormat("({0})", string.Join(",", mRowInfo.Select(r => r.ColumnName)));
                    }
                }
                else
                {
                    // let user decide the column order
                    sb.AppendFormat("({0})", ColumnList);
                }
            }
            else
            {
                sb.AppendFormat("({0})", QueryInternal);
            }

            sb.AppendFormat(" {0} BINARY", CopyStmtDirection);

            byte[] q = PqsqlUTF8Statement.CreateUTF8Statement(sb);

            IntPtr         res;
            ExecStatusType s = mConn.Exec(q, out res);

            // result buffer should contain column information and PGconn should be in COPY_IN state
            if (res == IntPtr.Zero || s != QueryResultType)
            {
                mConn.Consume(res);                 // we might receive several results...
                throw new PqsqlException("Could not execute statement «" + sb + "»: " + mConn.GetErrorMessage());
            }

            // check first column format, current implementation will have all columns set to binary
            if (PqsqlWrapper.PQfformat(res, 0) == 0)
            {
                mConn.Consume(res);
                throw new PqsqlException("PqsqlCopyFrom only supports BINARY format.");
            }

            var nFields = PqsqlWrapper.PQnfields(res);
            if (SuppressSchemaQueryInternal)
            {
                mColumns = nFields;
            }
            else
            {
                // sanity check
                if (mColumns != nFields)
                {
                    mConn.Consume(res);
                    throw new PqsqlException("Received wrong number of columns for " + sb);
                }
            }

            // done with result inspection
            PqsqlWrapper.PQclear(res);
        }
Esempio n. 27
0
        public void End()
        {
            IntPtr res;
            string err = string.Empty;

#if CODECONTRACTS
            Contract.Assume(mConn != null);
#endif
            IntPtr conn = mConn.PGConnection;

            if (mColBuf == IntPtr.Zero)
            {
                return;
            }

            int ret = PqsqlBinaryFormat.pqcb_put_end(mColBuf);             // flush column buffer

            if (ret != 1)
            {
                err = err.Insert(0, "Could not send end-of-data indication: ");
                goto bailout;
            }

            res = PqsqlWrapper.PQgetResult(conn);

            if (res != IntPtr.Zero)
            {
                ExecStatusType s = PqsqlWrapper.PQresultStatus(res);

                PqsqlWrapper.PQclear(res);

                if (s == ExecStatusType.PGRES_COPY_IN)
                {
                    // still in COPY_IN mode? bail out!
                    byte[] b = PqsqlUTF8Statement.CreateUTF8Statement("COPY FROM cancelled by client");

                    unsafe
                    {
                        fixed(byte *bs = b)
                        {
                            ret = PqsqlWrapper.PQputCopyEnd(conn, bs);
                        }
                    }

                    res = PqsqlWrapper.PQgetResult(conn);

                    if (res != IntPtr.Zero)
                    {
                        s = PqsqlWrapper.PQresultStatus(res);
                        PqsqlWrapper.PQclear(res);
                    }

                    err = err.Insert(0, "Cancelled COPY FROM while still in COPY_IN mode (" + s + "," + ret + "): ");

                    goto bailout;
                }

                if (s != ExecStatusType.PGRES_COMMAND_OK)
                {
                    err = err.Insert(0, "COPY FROM failed (" + s + "): ");

                    goto bailout;
                }

                // consume all remaining results until we reach the NULL result
                while ((res = PqsqlWrapper.PQgetResult(conn)) != IntPtr.Zero)
                {
                    // always free mResult
                    PqsqlWrapper.PQclear(res);
                }

                return;
            }

bailout:
            err += mConn.GetErrorMessage();
            throw new PqsqlException(err);
        }
Esempio n. 28
0
        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);
        }
Esempio n. 29
0
        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
        }