private void ReadFromStream_Ver_2(Stream inputStream, Encoding encoding)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_2");

            Byte[] null_map_array = new Byte[(row_desc.NumFields + 7) / 8];

            Array.Clear(null_map_array, 0, null_map_array.Length);


            // Decoders used to get decoded chars when using unicode like encodings which may have chars crossing the byte buffer bounds.

            Decoder decoder = encoding.GetDecoder();

            // Read the null fields bitmap.
            PGUtil.CheckedStreamRead(inputStream, null_map_array, 0, null_map_array.Length);

            // Get the data.
            for (Int16 field_count = 0; field_count < row_desc.NumFields; field_count++)
            {
                // Check if this field is null
                if (IsBackendNull(null_map_array, field_count))
                {
                    data.Add(DBNull.Value);
                    continue;
                }

                // Read the first data of the first row.

                PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, 4);

                NpgsqlRowDescriptionFieldData field_descr = row_desc[field_count];
                Int32 field_value_size = IPAddress.NetworkToHostOrder(BitConverter.ToInt32(_inputBuffer, 0));
                field_value_size -= 4;

                string result = ReadStringFromStream(inputStream, field_value_size, decoder);
                // Add them to the AsciiRow data.
                data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.type_info, result, field_descr.type_size, field_descr.type_modifier));
            }
        }
        public override void WriteToStream(Stream output_stream)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "WriteToStream");

            int packet_size = 4 + 4 + 1;

            for (int i = 0; i < parameterNames.Count; i++)
            {
                packet_size += (parameterNames[i].Length + parameterValues[i].Length + 2);
            }

            output_stream.WriteInt32(packet_size);
            output_stream.WriteInt32(PGUtil.ConvertProtocolVersion(this.protocol_version));

            for (int i = 0; i < parameterNames.Count; i++)
            {
                output_stream.WriteBytesNullTerminated(parameterNames[i]);
                output_stream.WriteBytesNullTerminated(parameterValues[i]);
            }
            output_stream.WriteByte(0);
            output_stream.Flush();
        }
        private byte[] ReadBytesFromStream(Stream inputStream, int field_value_size)
        {
            byte[] binary_data = new byte[field_value_size];
            int    bytes_left  = field_value_size;

            if (field_value_size > _inputBuffer.Length)
            {
                int i = 0;
                while (bytes_left > READ_BUFFER_SIZE)
                {
                    PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, READ_BUFFER_SIZE);
                    _inputBuffer.CopyTo(binary_data, i * READ_BUFFER_SIZE);
                    i++;
                    bytes_left -= READ_BUFFER_SIZE;
                }
            }
            PGUtil.CheckedStreamRead(inputStream, _inputBuffer, 0, bytes_left);
            Int32 offset = field_value_size - bytes_left;

            Array.Copy(_inputBuffer, 0, binary_data, offset, bytes_left);
            return(binary_data);
        }
Beispiel #4
0
        public override void WriteToStream(Stream outputStream)
        {
            var commandStream = _command.GetCommandStream();

            commandStream.Position = 0;
            // Log the string being sent.

            //if (NpgsqlEventLog.Level >= LogLevel.Debug)
            //PGUtil.LogStringWritten(commandText.ToString());

            // This method needs refactory.
            // The code below which deals with writing string to stream needs to be redone to use
            // PGUtil.WriteString() as before. The problem is that WriteString is using too much strings (concatenation).
            // Find a way to optimize that.

            // Tell to mediator what command is being sent.
            //TODO
            _command.Connector.Mediator.SqlSent = _command.CommandText;

            // Workaround for seek exceptions when running under ms.net. TODO: Check why Npgsql may be letting behind data in the stream.
            outputStream.Flush();

            // Send the query to server.
            // Write the byte 'Q' to identify a query message.
            outputStream.WriteByte((byte)FrontEndMessageCode.Query);

            //Work out the encoding of the string (null-terminated) once and take the length from having done so
            //rather than doing so repeatedly.

            if (_protocolVersion == ProtocolVersion.Version3)
            {
                // Write message length. Int32 + string length + null terminator.
                PGUtil.WriteInt32(outputStream, 4 + (int)commandStream.Length + 1);
            }

            commandStream.CopyTo(outputStream);
            outputStream.WriteByte(0);
        }
        public override void Close(NpgsqlConnector context)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Close");
            Stream stream = context.Stream;

            stream.WriteByte((byte)FrontEndMessageCode.Termination);
            if (context.BackendProtocolVersion >= ProtocolVersion.Version3)
            {
                PGUtil.WriteInt32(stream, 4);
            }
            stream.Flush();

            try
            {
                stream.Close();
            }
            catch
            {
            }

            context.Stream = null;
            ChangeState(context, NpgsqlClosedState.Instance);
        }
Beispiel #6
0
        public override void WriteToStream(Stream outputStream)
        {
            if (NpgsqlEventLog.Level >= LogLevel.Debug)
            {
                // Log the string being sent.
                PGUtil.LogStringWritten(BackendEncoding.UTF8Encoding.GetString(commandText));
            }

            // Tell to mediator what command is being sent.
            _connector.Mediator.SetSqlSent(commandText);

            // Send the query to server.
            // Write the byte 'Q' to identify a query message.
            outputStream.WriteByte((byte)FrontEndMessageCode.Query);

            if (_connector.BackendProtocolVersion == ProtocolVersion.Version3)
            {
                // Write message length. Int32 + string length + null terminator.
                PGUtil.WriteInt32(outputStream, 4 + commandText.Length + 1);
            }

            outputStream.WriteBytesNullTerminated(commandText);
        }
        private void ReadFromStream_Ver_3(Stream inputStream, Encoding encoding)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");

            PGUtil.ReadInt32(inputStream, _inputBuffer);
            Int16 numCols = PGUtil.ReadInt16(inputStream, _inputBuffer);

            Decoder decoder = encoding.GetDecoder();

            for (Int16 field_count = 0; field_count < numCols; field_count++)
            {
                Int32 field_value_size = PGUtil.ReadInt32(inputStream, _inputBuffer);

                // Check if this field is null
                if (field_value_size == -1) // Null value
                {
                    data.Add(DBNull.Value);
                    continue;
                }

                NpgsqlRowDescriptionFieldData field_descr = row_desc[field_count];

                if (row_desc[field_count].format_code == FormatCode.Text)
                {
                    string result = ReadStringFromStream(inputStream, field_value_size, decoder);
                    // Add them to the AsciiRow data.
                    data.Add(NpgsqlTypesHelper.ConvertBackendStringToSystemType(field_descr.type_info, result, field_descr.type_size, field_descr.type_modifier));
                }
                else
                {
                    Byte[] binary_data = ReadBytesFromStream(inputStream, field_value_size);

                    data.Add(NpgsqlTypesHelper.ConvertBackendBytesToSystemType(field_descr.type_info, binary_data, encoding, field_value_size, field_descr.type_modifier));
                }
            }
        }
Beispiel #8
0
        protected override object ReadNext()
        {
            if (_nullMap.IsNull(CurrentField))
            {
                return(DBNull.Value);
            }

            NpgsqlRowDescription.FieldData field_descr = FieldData;
            Int32 field_value_size = PGUtil.ReadInt32(Stream) - 4;

            if (field_value_size >= 85000)
            {
                return(ReadLargeObject(field_descr, field_value_size));
            }
            byte[] buffer = new byte[field_value_size];
            PGUtil.CheckedStreamRead(Stream, buffer, 0, field_value_size);
            var str = UTF8Encoding.GetString(buffer);

            try
            {
                return
                    (NpgsqlTypesHelper.ConvertBackendStringToSystemType(
                         field_descr.TypeInfo,
                         str,
                         field_descr.TypeSize,
                         field_descr.TypeModifier));
            }
            catch (InvalidCastException ice)
            {
                return(ice);
            }
            catch (Exception ex)
            {
                return(new InvalidCastException(ex.Message, ex));
            }
        }
Beispiel #9
0
 public override int DoSkip(int length)
 {
     return(PGUtil.SkipEscapedBytes(_stream, length, ref _remainingBytes));
 }
Beispiel #10
0
 public override int DoRead(char[] output, int outputIdx, int length)
 {
     return(PGUtil.ReadChars(_stream, output, length, ref _remainingBytes, outputIdx));
 }
        protected IEnumerable <IServerResponseObject> ProcessBackendResponses_Ver_3(NpgsqlConnector context)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");

            using (new ContextResetter(context))
            {
                Stream         stream   = context.Stream;
                NpgsqlMediator mediator = context.Mediator;

                List <NpgsqlError> errors = new List <NpgsqlError>();

                for (;;)
                {
                    // Check the first Byte of response.
                    BackEndMessageCode message = (BackEndMessageCode)stream.ReadByte();
                    switch (message)
                    {
                    case BackEndMessageCode.ErrorResponse:

                        NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion, stream);
                        error.ErrorSql = mediator.SqlSent;

                        errors.Add(error);

                        NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);

                        // Return imediately if it is in the startup state or connected state as
                        // there is no more messages to consume.
                        // Possible error in the NpgsqlStartupState:
                        //        Invalid password.
                        // Possible error in the NpgsqlConnectedState:
                        //        No pg_hba.conf configured.

                        if (!context.RequireReadyForQuery)
                        {
                            throw new NpgsqlException(errors);
                        }

                        break;

                    case BackEndMessageCode.AuthenticationRequest:

                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");

                        // Get the length in case we're getting AuthenticationGSSContinue
                        int authDataLength = PGUtil.ReadInt32(stream) - 8;

                        AuthenticationRequestType authType = (AuthenticationRequestType)PGUtil.ReadInt32(stream);
                        switch (authType)
                        {
                        case AuthenticationRequestType.AuthenticationOk:
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);
                            break;

                        case AuthenticationRequestType.AuthenticationClearTextPassword:
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);

                            // Send the PasswordPacket.

                            ChangeState(context, NpgsqlStartupState.Instance);
                            context.Authenticate(context.Password);

                            break;

                        case AuthenticationRequestType.AuthenticationMD5Password:
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
                            // Now do the "MD5-Thing"
                            // for this the Password has to be:
                            // 1. md5-hashed with the username as salt
                            // 2. md5-hashed again with the salt we get from the backend

                            MD5 md5 = MD5.Create();

                            // 1.
                            byte[] passwd       = context.Password;
                            byte[] saltUserName = BackendEncoding.UTF8Encoding.GetBytes(context.UserName);

                            byte[] crypt_buf = new byte[passwd.Length + saltUserName.Length];

                            passwd.CopyTo(crypt_buf, 0);
                            saltUserName.CopyTo(crypt_buf, passwd.Length);

                            StringBuilder sb         = new StringBuilder();
                            byte[]        hashResult = md5.ComputeHash(crypt_buf);
                            foreach (byte b in hashResult)
                            {
                                sb.Append(b.ToString("x2"));
                            }

                            String prehash = sb.ToString();

                            byte[] prehashbytes = BackendEncoding.UTF8Encoding.GetBytes(prehash);
                            crypt_buf = new byte[prehashbytes.Length + 4];

                            stream.Read(crypt_buf, prehashbytes.Length, 4);
                            // Send the PasswordPacket.
                            ChangeState(context, NpgsqlStartupState.Instance);

                            // 2.
                            prehashbytes.CopyTo(crypt_buf, 0);

                            sb         = new StringBuilder("md5"); // This is needed as the backend expects md5 result starts with "md5"
                            hashResult = md5.ComputeHash(crypt_buf);
                            foreach (byte b in hashResult)
                            {
                                sb.Append(b.ToString("x2"));
                            }

                            context.Authenticate(BackendEncoding.UTF8Encoding.GetBytes(sb.ToString()));

                            break;

#if WINDOWS && UNMANAGED
                        case AuthenticationRequestType.AuthenticationSSPI:
                        {
                            if (context.IntegratedSecurity)
                            {
                                // For SSPI we have to get the IP-Address (hostname doesn't work)
                                string ipAddressString = ((IPEndPoint)context.Socket.RemoteEndPoint).Address.ToString();
                                context.SSPI = new SSPIHandler(ipAddressString, "POSTGRES");
                                ChangeState(context, NpgsqlStartupState.Instance);
                                context.Authenticate(context.SSPI.Continue(null));
                                break;
                            }
                            else
                            {
                                // TODO: correct exception
                                throw new Exception();
                            }
                        }

                        case AuthenticationRequestType.AuthenticationGSSContinue:
                        {
                            byte[] authData = new byte[authDataLength];
                            PGUtil.CheckedStreamRead(stream, authData, 0, authDataLength);
                            byte[] passwd_read = context.SSPI.Continue(authData);
                            if (passwd_read.Length != 0)
                            {
                                context.Authenticate(passwd_read);
                            }
                            break;
                        }
#endif

                        default:
                            // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.
                            errors.Add(
                                new NpgsqlError(context.BackendProtocolVersion,
                                                String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
                            throw new NpgsqlException(errors);
                        }
                        break;

                    case BackEndMessageCode.RowDescription:
                        yield return(new NpgsqlRowDescriptionV3(stream, context.OidToNameMapping, context.CompatVersion));

                        break;

                    case BackEndMessageCode.ParameterDescription:

                        // Do nothing,for instance,  just read...
                        int lenght   = PGUtil.ReadInt32(stream);
                        int nb_param = PGUtil.ReadInt16(stream);
                        for (int i = 0; i < nb_param; i++)
                        {
                            int typeoid = PGUtil.ReadInt32(stream);
                        }

                        break;

                    case BackEndMessageCode.DataRow:
                        yield return(new StringRowReaderV3(stream));

                        break;

                    case BackEndMessageCode.ReadyForQuery:

//                            NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ReadyForQuery");

                        // Possible status bytes returned:
                        //   I = Idle (no transaction active).
                        //   T = In transaction, ready for more.
                        //   E = Error in transaction, queries will fail until transaction aborted.
                        // Just eat the status byte, we have no use for it at this time.
                        PGUtil.ReadInt32(stream);
                        stream.ReadByte();

                        ChangeState(context, NpgsqlReadyState.Instance);

                        if (errors.Count != 0)
                        {
                            throw new NpgsqlException(errors);
                        }

                        yield break;

                    case BackEndMessageCode.BackendKeyData:

                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BackendKeyData");
                        // BackendKeyData message.
                        NpgsqlBackEndKeyData backend_keydata = new NpgsqlBackEndKeyData(context.BackendProtocolVersion, stream);
                        context.BackEndKeyData = backend_keydata;

                        // Wait for ReadForQuery message
                        break;

                    case BackEndMessageCode.NoticeResponse:
                        // Notices and errors are identical except that we
                        // just throw notices away completely ignored.
                        context.FireNotice(new NpgsqlError(context.BackendProtocolVersion, stream));
                        break;

                    case BackEndMessageCode.CompletedResponse:
                        PGUtil.ReadInt32(stream);
                        yield return(new CompletedResponse(stream));

                        break;

                    case BackEndMessageCode.ParseComplete:
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParseComplete");
                        // Just read up the message length.
                        PGUtil.ReadInt32(stream);
                        break;

                    case BackEndMessageCode.BindComplete:
//                            NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BindComplete");
                        // Just read up the message length.
                        PGUtil.ReadInt32(stream);
                        break;

                    case BackEndMessageCode.EmptyQueryResponse:
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
                        PGUtil.ReadInt32(stream);
                        break;

                    case BackEndMessageCode.NotificationResponse:
                        // Eat the length
                        PGUtil.ReadInt32(stream);
                        context.FireNotification(new NpgsqlNotificationEventArgs(stream, true));
                        if (context.IsNotificationThreadRunning)
                        {
                            yield break;
                        }
                        break;

                    case BackEndMessageCode.ParameterStatus:
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus");
                        NpgsqlParameterStatus parameterStatus = new NpgsqlParameterStatus(stream);

                        NpgsqlEventLog.LogMsg(resman, "Log_ParameterStatus", LogLevel.Debug, parameterStatus.Parameter,
                                              parameterStatus.ParameterValue);

                        context.AddParameterStatus(parameterStatus);

                        if (parameterStatus.Parameter == "server_version")
                        {
                            // Deal with this here so that if there are
                            // changes in a future backend version, we can handle it here in the
                            // protocol handler and leave everybody else put of it.
                            string versionString = parameterStatus.ParameterValue.Trim();
                            for (int idx = 0; idx != versionString.Length; ++idx)
                            {
                                char c = parameterStatus.ParameterValue[idx];
                                if (!char.IsDigit(c) && c != '.')
                                {
                                    versionString = versionString.Substring(0, idx);
                                    break;
                                }
                            }
                            context.ServerVersion = new Version(versionString);
                        }
                        break;

                    case BackEndMessageCode.NoData:
                        // This nodata message may be generated by prepare commands issued with queries which doesn't return rows
                        // for example insert, update or delete.
                        // Just eat the message.
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ParameterStatus");
                        PGUtil.ReadInt32(stream);
                        break;

                    case BackEndMessageCode.CopyInResponse:
                        // Enter COPY sub protocol and start pushing data to server
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CopyInResponse");
                        ChangeState(context, NpgsqlCopyInState.Instance);
                        PGUtil.ReadInt32(stream);     // length redundant
                        context.CurrentState.StartCopy(context, ReadCopyHeader(stream));
                        yield break;
                    // Either StartCopy called us again to finish the operation or control should be passed for user to feed copy data

                    case BackEndMessageCode.CopyOutResponse:
                        // Enter COPY sub protocol and start pulling data from server
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CopyOutResponse");
                        ChangeState(context, NpgsqlCopyOutState.Instance);
                        PGUtil.ReadInt32(stream);     // length redundant
                        context.CurrentState.StartCopy(context, ReadCopyHeader(stream));
                        yield break;
                    // Either StartCopy called us again to finish the operation or control should be passed for user to feed copy data

                    case BackEndMessageCode.CopyData:
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CopyData");
                        Int32  len = PGUtil.ReadInt32(stream) - 4;
                        byte[] buf = new byte[len];
                        PGUtil.ReadBytes(stream, buf, 0, len);
                        context.Mediator.ReceivedCopyData = buf;
                        yield break;     // read data from server one chunk at a time while staying in copy operation mode

                    case BackEndMessageCode.CopyDone:
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CopyDone");
                        PGUtil.ReadInt32(stream);     // CopyDone can not have content so this is always 4
                        // This will be followed by normal CommandComplete + ReadyForQuery so no op needed
                        break;

                    case BackEndMessageCode.IO_ERROR:
                        // Connection broken. Mono returns -1 instead of throwing an exception as ms.net does.
                        throw new IOException();

                    default:
                        // This could mean a number of things
                        //   We've gotten out of sync with the backend?
                        //   We need to implement this type?
                        //   Backend has gone insane?
                        // FIXME
                        // what exception should we really throw here?
                        throw new NotSupportedException(String.Format("Backend sent unrecognized response type: {0}", (Char)message));
                    }
                }
            }
        }
        void DoWrite <T>(TypeHandler handler, T value)
        {
            try
            {
                if (_buf.WriteSpaceLeft < 4)
                {
                    FlushAndStartDataMessage();
                }

                var asObject = (object)value;  // TODO: Implement boxless writing in the future
                if (asObject == null)
                {
                    _buf.WriteInt32(-1);
                    _column++;
                    return;
                }

                _dummyParam.ConvertedValue = null;

                var asSimple = handler as ISimpleTypeWriter;
                if (asSimple != null)
                {
                    var len = asSimple.ValidateAndGetLength(asObject, _dummyParam);
                    _buf.WriteInt32(len);
                    if (_buf.WriteSpaceLeft < len)
                    {
                        Contract.Assume(_buf.Size >= len);
                        FlushAndStartDataMessage();
                    }
                    asSimple.Write(asObject, _buf, _dummyParam);
                    _column++;
                    return;
                }

                var asChunking = handler as IChunkingTypeWriter;
                if (asChunking != null)
                {
                    _lengthCache.Clear();
                    var len = asChunking.ValidateAndGetLength(asObject, ref _lengthCache, _dummyParam);
                    _buf.WriteInt32(len);

                    // If the type handler used the length cache, rewind it to skip the first position:
                    // it contains the entire value length which we already have in len.
                    if (_lengthCache.Position > 0)
                    {
                        _lengthCache.Rewind();
                        _lengthCache.Position++;
                    }

                    asChunking.PrepareWrite(asObject, _buf, _lengthCache, _dummyParam);
                    var directBuf = new DirectBuffer();
                    while (!asChunking.Write(ref directBuf))
                    {
                        Flush();

                        // The following is an optimization hack for writing large byte arrays without passing
                        // through our buffer
                        if (directBuf.Buffer != null)
                        {
                            len = directBuf.Size == 0 ? directBuf.Buffer.Length : directBuf.Size;
                            _buf.WritePosition = 1;
                            _buf.WriteInt32(len + 4);
                            _buf.Flush();
                            _writingDataMsg = false;
                            _buf.Underlying.Write(directBuf.Buffer, directBuf.Offset, len);
                            directBuf.Buffer = null;
                            directBuf.Size   = 0;
                        }
                        EnsureDataMessage();
                    }
                    _column++;
                    return;
                }

                throw PGUtil.ThrowIfReached();
            }
            catch
            {
                _connector.Break();
                Cleanup();
                throw;
            }
        }
        /// <value>Counts the numbers of Connections that share
        /// this Connector. Used in Release() to decide wether this
        /// connector is to be moved to the PooledConnectors list.</value>
        // internal int mShareCount;

        /// <summary>
        /// Opens the physical connection to the server.
        /// </summary>
        /// <remarks>Usually called by the RequestConnector
        /// Method of the connection pool manager.</remarks>
        internal void Open()
        {
            ProtocolVersion PV;

            // If Connection.ConnectionString specifies a protocol version, we will
            // not try to fall back to version 2 on failure.
            if (ConnectionString.Contains(ConnectionStringKeys.Protocol))
            {
                PV = ConnectionString.ToProtocolVersion(ConnectionStringKeys.Protocol);
            }
            else
            {
                PV = ProtocolVersion.Unknown;
            }

            _backendProtocolVersion = (PV == ProtocolVersion.Unknown) ? ProtocolVersion.Version3 : PV;

            // Reset state to initialize new connector in pool.
            Encoding     = Encoding.Default;
            CurrentState = NpgsqlClosedState.Instance;

            // Get a raw connection, possibly SSL...
            CurrentState.Open(this);
            // Establish protocol communication and handle authentication...
            CurrentState.Startup(this);

            // Check for protocol not supported.  If we have been told what protocol to use,
            // we will not try this step.
            if (_mediator.Errors.Count > 0 && PV == ProtocolVersion.Unknown)
            {
                // If we attempted protocol version 3, it may be possible to drop back to version 2.
                if (BackendProtocolVersion == ProtocolVersion.Version3)
                {
                    NpgsqlError Error0 = (NpgsqlError)_mediator.Errors[0];

                    // If NpgsqlError.ReadFromStream_Ver_3() encounters a version 2 error,
                    // it will set its own protocol version to version 2.  That way, we can tell
                    // easily if the error was a FATAL: protocol error.
                    if (Error0.BackendProtocolVersion == ProtocolVersion.Version2)
                    {
                        // Try using the 2.0 protocol.
                        _mediator.ResetResponses();
                        BackendProtocolVersion = ProtocolVersion.Version2;
                        CurrentState           = NpgsqlClosedState.Instance;

                        // Get a raw connection, possibly SSL...
                        CurrentState.Open(this);
                        // Establish protocol communication and handle authentication...
                        CurrentState.Startup(this);
                    }
                }
            }

            // Check for errors and do the Right Thing.
            // FIXME - CheckErrors needs to be moved to Connector
            CheckErrors();

            _backend_keydata = _mediator.BackendKeyData;

            // Change the state of connection to open and ready.
            _connection_state = ConnectionState.Open;
            CurrentState      = NpgsqlReadyState.Instance;

            String ServerVersionString = String.Empty;

            // First try to determine backend server version using the newest method.
            if (((NpgsqlParameterStatus)_mediator.Parameters["__npgsql_server_version"]) != null)
            {
                ServerVersionString = ((NpgsqlParameterStatus)_mediator.Parameters["__npgsql_server_version"]).ParameterValue;
            }


            // Fall back to the old way, SELECT VERSION().
            // This should not happen for protocol version 3+.
            if (ServerVersionString.Length == 0)
            {
                NpgsqlCommand command = new NpgsqlCommand("select version();set DATESTYLE TO ISO;", this);
                ServerVersionString = PGUtil.ExtractServerVersion((String)command.ExecuteScalar());
            }

            // Cook version string so we can use it for enabling/disabling things based on
            // backend version.
            ServerVersion = PGUtil.ParseServerVersion(ServerVersionString);

            // Adjust client encoding.

            //NpgsqlCommand commandEncoding1 = new NpgsqlCommand("show client_encoding", _connector);
            //String clientEncoding1 = (String)commandEncoding1.ExecuteScalar();

            if (ConnectionString.ToString(ConnectionStringKeys.Encoding, ConnectionStringDefaults.Encoding).ToUpper() == "UNICODE")
            {
                Encoding = Encoding.UTF8;
                NpgsqlCommand commandEncoding = new NpgsqlCommand("SET CLIENT_ENCODING TO UNICODE", this);
                commandEncoding.ExecuteNonQuery();
            }

            // Make a shallow copy of the type mapping that the connector will own.
            // It is possible that the connector may add types to its private
            // mapping that will not be valid to another connector, even
            // if connected to the same backend version.
            _oidToNameMapping = NpgsqlTypesHelper.CreateAndLoadInitialTypesMapping(this).Clone();

            ProcessServerVersion();

            // The connector is now fully initialized. Beyond this point, it is
            // safe to release it back to the pool rather than closing it.
            IsInitialized = true;
        }
Beispiel #14
0
        /*/// <value>Counts the numbers of Connections that share
         * /// this Connector. Used in Release() to decide wether this
         * /// connector is to be moved to the PooledConnectors list.</value>
         * // internal int mShareCount;*/

        /// <summary>
        /// Opens the physical connection to the server.
        /// </summary>
        /// <remarks>Usually called by the RequestConnector
        /// Method of the connection pool manager.</remarks>
        internal void Open()
        {
            ServerVersion = null;
            // If Connection.ConnectionString specifies a protocol version, we will
            // not try to fall back to version 2 on failure.

            // Reset state to initialize new connector in pool.
            CurrentState = NpgsqlClosedState.Instance;

            // Keep track of time remaining; Even though there may be multiple timeout-able calls,
            // this allows us to still respect the caller's timeout expectation.
            int      connectTimeRemaining = this.ConnectionTimeout * 1000;
            DateTime attemptStart         = DateTime.Now;

            // Get a raw connection, possibly SSL...
            CurrentState.Open(this, connectTimeRemaining);
            try
            {
                // Establish protocol communication and handle authentication...
                CurrentState.Startup(this, settings);
            }
            catch (NpgsqlException)
            {
                if (_stream != null)
                {
                    try
                    {
                        _stream.Dispose();
                    }
                    catch
                    {
                    }
                }

                throw;
            }

            // Change the state of connection to open and ready.
            _connection_state = ConnectionState.Open;
            CurrentState      = NpgsqlReadyState.Instance;

            // After attachment, the stream will close the connector (this) when the stream gets disposed.
            _baseStream.AttachConnector(this);

            // Fall back to the old way, SELECT VERSION().
            // This should not happen for protocol version 3+.
            if (ServerVersion == null)
            {
                //NpgsqlCommand command = new NpgsqlCommand("set DATESTYLE TO ISO;select version();", this);
                //ServerVersion = new Version(PGUtil.ExtractServerVersion((string) command.ExecuteScalar()));
                using (NpgsqlCommand command = new NpgsqlCommand("set DATESTYLE TO ISO;select version();", this))
                {
                    ServerVersion = new Version(PGUtil.ExtractServerVersion((string)command.ExecuteScalar()));
                }
            }

            ProcessServerVersion();

            StringWriter sbInitQueries = new StringWriter();

            // Some connection parameters for protocol 3 had been sent in the startup packet.
            // The rest will be setted here.
            if (SupportsExtraFloatDigits3)
            {
                sbInitQueries.WriteLine("SET extra_float_digits=3;");
            }

            if (SupportsSslRenegotiationLimit)
            {
                sbInitQueries.WriteLine("SET ssl_renegotiation_limit=0;");
            }

            initQueries = sbInitQueries.ToString();

            NpgsqlCommand.ExecuteBlind(this, initQueries, 60);

            // Make a shallow copy of the type mapping that the connector will own.
            // It is possible that the connector may add types to its private
            // mapping that will not be valid to another connector, even
            // if connected to the same backend version.
            NativeToBackendTypeConverterOptions.OidToNameMapping = NpgsqlTypesHelper.CreateAndLoadInitialTypesMapping(this).Clone();

            // The connector is now fully initialized. Beyond this point, it is
            // safe to release it back to the pool rather than closing it.
            IsInitialized = true;
        }
Beispiel #15
0
 public NullMap(NpgsqlRowDescription desc, Stream inputStream)
 {
     _map = new byte[(desc.NumFields + 7) / 8];
     PGUtil.CheckedStreamRead(inputStream, _map, 0, _map.Length);
 }
Beispiel #16
0
        /*/// <value>Counts the numbers of Connections that share
         * /// this Connector. Used in Release() to decide wether this
         * /// connector is to be moved to the PooledConnectors list.</value>
         * // internal int mShareCount;*/

        /// <summary>
        /// Opens the physical connection to the server.
        /// </summary>
        /// <remarks>Usually called by the RequestConnector
        /// Method of the connection pool manager.</remarks>
        internal void Open()
        {
            ServerVersion = null;
            // If Connection.ConnectionString specifies a protocol version, we will
            // not try to fall back to version 2 on failure.

            _backendProtocolVersion = (settings.Protocol == ProtocolVersion.Unknown)
                                          ? ProtocolVersion.Version3
                                          : settings.Protocol;

            // Reset state to initialize new connector in pool.
            CurrentState = NpgsqlClosedState.Instance;

            // Get a raw connection, possibly SSL...
            CurrentState.Open(this);
            try
            {
                // Establish protocol communication and handle authentication...
                CurrentState.Startup(this);
            }
            catch (NpgsqlException ne)
            {
                // Check for protocol not supported.  If we have been told what protocol to use,
                // we will not try this step.
                if (settings.Protocol != ProtocolVersion.Unknown)
                {
                    throw;
                }
                // If we attempted protocol version 3, it may be possible to drop back to version 2.
                if (BackendProtocolVersion != ProtocolVersion.Version3)
                {
                    throw;
                }
                NpgsqlError Error0 = (NpgsqlError)ne.Errors[0];

                // If NpgsqlError..ctor() encounters a version 2 error,
                // it will set its own protocol version to version 2.  That way, we can tell
                // easily if the error was a FATAL: protocol error.
                if (Error0.BackendProtocolVersion != ProtocolVersion.Version2)
                {
                    throw;
                }
                // Try using the 2.0 protocol.
                _mediator.ResetResponses();
                BackendProtocolVersion = ProtocolVersion.Version2;
                CurrentState           = NpgsqlClosedState.Instance;

                // Get a raw connection, possibly SSL...
                CurrentState.Open(this);
                // Establish protocol communication and handle authentication...
                CurrentState.Startup(this);
            }

            // Change the state of connection to open and ready.
            _connection_state = ConnectionState.Open;
            CurrentState      = NpgsqlReadyState.Instance;

            // Fall back to the old way, SELECT VERSION().
            // This should not happen for protocol version 3+.
            if (ServerVersion == null)
            {
                NpgsqlCommand command = new NpgsqlCommand("set DATESTYLE TO ISO;select version();", this);
                ServerVersion = new Version(PGUtil.ExtractServerVersion((string)command.ExecuteScalar()));
            }

            // Adjust client encoding.

            NpgsqlParameterStatus clientEncodingParam = null;

            if (
                !ServerParameters.TryGetValue("client_encoding", out clientEncodingParam) ||
                (!string.Equals(clientEncodingParam.ParameterValue, "UTF8", StringComparison.OrdinalIgnoreCase) && !string.Equals(clientEncodingParam.ParameterValue, "UNICODE", StringComparison.OrdinalIgnoreCase))
                )
            {
                new NpgsqlCommand("SET CLIENT_ENCODING TO UTF8", this).ExecuteBlind();
            }

            if (!string.IsNullOrEmpty(settings.SearchPath))
            {
                /*NpgsqlParameter p = new NpgsqlParameter("p", DbType.String);
                 * p.Value = settings.SearchPath;
                 * NpgsqlCommand commandSearchPath = new NpgsqlCommand("SET SEARCH_PATH TO :p,public", this);
                 * commandSearchPath.Parameters.Add(p);
                 * commandSearchPath.ExecuteNonQuery();*/

                /*NpgsqlParameter p = new NpgsqlParameter("p", DbType.String);
                 * p.Value = settings.SearchPath;
                 * NpgsqlCommand commandSearchPath = new NpgsqlCommand("SET SEARCH_PATH TO :p,public", this);
                 * commandSearchPath.Parameters.Add(p);
                 * commandSearchPath.ExecuteNonQuery();*/

                // TODO: Add proper message when finding a semicolon in search_path.
                // This semicolon could lead to a sql injection security hole as someone could write in connection string:
                // searchpath=public;delete from table; and it would be executed.

                if (settings.SearchPath.Contains(";"))
                {
                    throw new InvalidOperationException();
                }

                // This is using string concatenation because set search_path doesn't allow type casting. ::text
                NpgsqlCommand commandSearchPath = new NpgsqlCommand("SET SEARCH_PATH=" + settings.SearchPath, this);
                commandSearchPath.ExecuteBlind();
            }



            /*
             * Try to set SSL negotiation to 0. As of 2010-03-29, recent problems in SSL library implementations made
             * postgresql to add a parameter to set a value when to do this renegotiation or 0 to disable it.
             * Currently, Npgsql has a problem with renegotiation so, we are trying to disable it here.
             * This only works on postgresql servers where the ssl renegotiation settings is supported of course.
             * See http://lists.pgfoundry.org/pipermail/npgsql-devel/2010-February/001065.html for more information.
             */



            try

            {
                NpgsqlCommand commandSslrenegotiation = new NpgsqlCommand("SET ssl_renegotiation_limit=0", this);

                commandSslrenegotiation.ExecuteBlind();
            }

            catch {}



            // Make a shallow copy of the type mapping that the connector will own.
            // It is possible that the connector may add types to its private
            // mapping that will not be valid to another connector, even
            // if connected to the same backend version.
            _oidToNameMapping = NpgsqlTypesHelper.CreateAndLoadInitialTypesMapping(this).Clone();

            ProcessServerVersion();

            // The connector is now fully initialized. Beyond this point, it is
            // safe to release it back to the pool rather than closing it.
            IsInitialized = true;
        }
Beispiel #17
0
        private void ReadFromStream_Ver_3(Stream inputStream, Encoding encoding)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ReadFromStream_Ver_3");

            Int32 messageLength = PGUtil.ReadInt32(inputStream, new Byte[4]);

            // [TODO] Would this be the right way to do?
            // Check the messageLength value. If it is 1178686529, this would be the
            // "FATA" string, which would mean a protocol 2.0 error string.
            if (messageLength == 1178686529)
            {
                String   Raw;
                String[] Parts;

                Raw = "FATA" + PGUtil.ReadString(inputStream, encoding);

                Parts = Raw.Split(new char[] { ':' }, 2);

                if (Parts.Length == 2)
                {
                    _severity = Parts[0].Trim();
                    _message  = Parts[1].Trim();
                }
                else
                {
                    _message = Parts[0].Trim();
                }

                protocol_version = ProtocolVersion.Version2;

                return;
            }

            Char   field;
            String fieldValue;

            field = (Char)inputStream.ReadByte();

            // Now start to read fields.
            while (field != 0)
            {
                fieldValue = PGUtil.ReadString(inputStream, encoding);

                switch (field)
                {
                case 'S':
                    _severity = fieldValue;
                    break;

                case 'C':
                    _code = fieldValue;
                    break;

                case 'M':
                    _message = fieldValue;
                    break;

                case 'D':
                    _detail = fieldValue;
                    break;

                case 'H':
                    _hint = fieldValue;
                    break;

                case 'P':
                    _position = fieldValue;
                    break;

                case 'W':
                    _where = fieldValue;
                    break;

                case 'F':
                    _file = fieldValue;
                    break;

                case 'L':
                    _line = fieldValue;
                    break;

                case 'R':
                    _routine = fieldValue;
                    break;
                }

                field = (Char)inputStream.ReadByte();
            }
        }
Beispiel #18
0
 protected override int GetNextFieldCount()
 {
     return(_nullMap.IsNull(CurrentField) ? -1 : PGUtil.ReadInt32(Stream) - 4);
 }
Beispiel #19
0
        /// <summary>
        /// Opens the physical connection to the server.
        /// </summary>
        /// <remarks>Usually called by the RequestConnector
        /// Method of the connection pool manager.</remarks>
        internal void Open()
        {
            ServerVersion = null;
            // If Connection.ConnectionString specifies a protocol version, we will
            // not try to fall back to version 2 on failure.

            _backendProtocolVersion = (settings.Protocol == ProtocolVersion.Unknown)
                                                                                  ? ProtocolVersion.Version3
                                                                                  : settings.Protocol;

            // Reset state to initialize new connector in pool.
            CurrentState = NpgsqlClosedState.Instance;

            // Get a raw connection, possibly SSL...
            CurrentState.Open(this);
            try
            {
                // Establish protocol communication and handle authentication...
                CurrentState.Startup(this);
            }
            catch (NpgsqlException ne)
            {
                // Check for protocol not supported.  If we have been told what protocol to use,
                // we will not try this step.
                if (settings.Protocol != ProtocolVersion.Unknown)
                {
                    throw;
                }
                // If we attempted protocol version 3, it may be possible to drop back to version 2.
                if (BackendProtocolVersion != ProtocolVersion.Version3)
                {
                    throw;
                }
                NpgsqlError Error0 = (NpgsqlError)ne.Errors[0];

                // If NpgsqlError..ctor() encounters a version 2 error,
                // it will set its own protocol version to version 2.  That way, we can tell
                // easily if the error was a FATAL: protocol error.
                if (Error0.BackendProtocolVersion != ProtocolVersion.Version2)
                {
                    throw;
                }
                // Try using the 2.0 protocol.
                _mediator.ResetResponses();
                BackendProtocolVersion = ProtocolVersion.Version2;
                CurrentState           = NpgsqlClosedState.Instance;

                // Get a raw connection, possibly SSL...
                CurrentState.Open(this);
                // Establish protocol communication and handle authentication...
                CurrentState.Startup(this);
            }

            // Change the state of connection to open and ready.
            State        = ConnectionState.Open;
            CurrentState = NpgsqlReadyState.Instance;

            // Fall back to the old way, SELECT VERSION().
            // This should not happen for protocol version 3+.
            if (ServerVersion == null)
            {
                using (NpgsqlCommand command = new NpgsqlCommand("set DATESTYLE TO ISO;select version();", this))
                {
                    ServerVersion = new Version(PGUtil.ExtractServerVersion((string)command.ExecuteScalar()));
                }
            }

            StringBuilder sbInit = new StringBuilder();

            // Adjust client encoding.
            NpgsqlParameterStatus clientEncodingParam = null;

            if (!ServerParameters.TryGetValue("client_encoding", out clientEncodingParam) ||
                !string.Equals(clientEncodingParam.ParameterValue, "UTF8", StringComparison.OrdinalIgnoreCase) && !string.Equals(clientEncodingParam.ParameterValue, "UNICODE", StringComparison.OrdinalIgnoreCase))
            {
                sbInit.AppendLine("SET CLIENT_ENCODING TO UTF8;");
            }

            if (!string.IsNullOrEmpty(settings.SearchPath))
            {
                // TODO: Add proper message when finding a semicolon in search_path.
                // This semicolon could lead to a sql injection security hole as someone could write in connection string:
                // searchpath=public;delete from table; and it would be executed.

                if (settings.SearchPath.Contains(";"))
                {
                    throw new InvalidOperationException();
                }

                sbInit.AppendLine("SET SEARCH_PATH=" + settings.SearchPath + ";");
            }

            if (!string.IsNullOrEmpty(settings.ApplicationName))
            {
                if (!SupportsApplicationName)
                {
                    //TODO
                    //throw new InvalidOperationException(resman.GetString("Exception_ApplicationNameNotSupported"));
                    throw new InvalidOperationException("ApplicationName not supported.");
                }

                if (settings.ApplicationName.Contains(";"))
                {
                    throw new InvalidOperationException();
                }

                sbInit.AppendLine("SET APPLICATION_NAME='" + settings.ApplicationName.Replace('\'', '-') + "';");
            }

            /*
             * Try to set SSL negotiation to 0. As of 2010-03-29, recent problems in SSL library implementations made
             * postgresql to add a parameter to set a value when to do this renegotiation or 0 to disable it.
             * Currently, Npgsql has a problem with renegotiation so, we are trying to disable it here.
             * This only works on postgresql servers where the ssl renegotiation settings is supported of course.
             * See http://lists.pgfoundry.org/pipermail/npgsql-devel/2010-February/001065.html for more information.
             */
            sbInit.AppendLine("SET ssl_renegotiation_limit=0;");

            /*
             * Set precision digits to maximum value possible. For postgresql before 9 it was 2, after that, it is 3.
             * This way, we set first to 2 and then to 3. If there is an error because of 3, it will have been set to 2 at least.
             * Check bug report #1010992 for more information.
             */
            sbInit.AppendLine("SET extra_float_digits=3;");
            try
            {
                new NpgsqlCommand(sbInit.ToString(), this).ExecuteBlind();
            }
            catch
            {
                foreach (var line in sbInit.ToString().Split(Environment.NewLine.ToCharArray()))
                {
                    try
                    {
                        if (line.Length > 0)
                        {
                            new NpgsqlCommand(line, this).ExecuteBlind();
                        }
                    }
                    catch { }
                }
            }

            // Make a shallow copy of the type mapping that the connector will own.
            // It is possible that the connector may add types to its private
            // mapping that will not be valid to another connector, even
            // if connected to the same backend version.
            _oidToNameMapping = NpgsqlTypesHelper.CreateAndLoadInitialTypesMapping(this).Clone();

            ProcessServerVersion();

            // The connector is now fully initialized. Beyond this point, it is
            // safe to release it back to the pool rather than closing it.
            IsInitialized = true;
        }
Beispiel #20
0
 public void WriteInt16(short value, bool littleEndian)
 => Write(littleEndian == BitConverter.IsLittleEndian ? value : PGUtil.ReverseEndianness(value));
Beispiel #21
0
        /*/// <value>Counts the numbers of Connections that share
         * /// this Connector. Used in Release() to decide wether this
         * /// connector is to be moved to the PooledConnectors list.</value>
         * // internal int mShareCount;*/

        /// <summary>
        /// Opens the physical connection to the server.
        /// </summary>
        /// <remarks>Usually called by the RequestConnector
        /// Method of the connection pool manager.</remarks>
        internal void Open()
        {
            ServerVersion = null;
            // If Connection.ConnectionString specifies a protocol version, we will
            // not try to fall back to version 2 on failure.

            _backendProtocolVersion = (settings.Protocol == ProtocolVersion.Unknown)
                                          ? ProtocolVersion.Version3
                                          : settings.Protocol;

            // Reset state to initialize new connector in pool.
            CurrentState = NpgsqlClosedState.Instance;

            // Keep track of time remaining; Even though there may be multiple timeout-able calls,
            // this allows us to still respect the caller's timeout expectation.
            int      connectTimeRemaining = this.ConnectionTimeout * 1000;
            DateTime attemptStart         = DateTime.Now;

            // Get a raw connection, possibly SSL...
            CurrentState.Open(this, connectTimeRemaining);
            try
            {
                // Establish protocol communication and handle authentication...
                CurrentState.Startup(this);
            }
            catch (NpgsqlException ne)
            {
                connectTimeRemaining -= Convert.ToInt32((DateTime.Now - attemptStart).TotalMilliseconds);

                // Check for protocol not supported.  If we have been told what protocol to use,
                // we will not try this step.
                if (settings.Protocol != ProtocolVersion.Unknown)
                {
                    throw;
                }
                // If we attempted protocol version 3, it may be possible to drop back to version 2.
                if (BackendProtocolVersion != ProtocolVersion.Version3)
                {
                    throw;
                }
                NpgsqlError Error0 = (NpgsqlError)ne.Errors[0];

                // If NpgsqlError..ctor() encounters a version 2 error,
                // it will set its own protocol version to version 2.  That way, we can tell
                // easily if the error was a FATAL: protocol error.
                if (Error0.BackendProtocolVersion != ProtocolVersion.Version2)
                {
                    throw;
                }
                // Try using the 2.0 protocol.
                _mediator.ResetResponses();
                BackendProtocolVersion = ProtocolVersion.Version2;
                CurrentState           = NpgsqlClosedState.Instance;

                // Get a raw connection, possibly SSL...
                CurrentState.Open(this, connectTimeRemaining);
                // Establish protocol communication and handle authentication...
                CurrentState.Startup(this);
            }

            // Change the state of connection to open and ready.
            _connection_state = ConnectionState.Open;
            CurrentState      = NpgsqlReadyState.Instance;

            // Fall back to the old way, SELECT VERSION().
            // This should not happen for protocol version 3+.
            if (ServerVersion == null)
            {
                //NpgsqlCommand command = new NpgsqlCommand("set DATESTYLE TO ISO;select version();", this);
                //ServerVersion = new Version(PGUtil.ExtractServerVersion((string) command.ExecuteScalar()));
                using (NpgsqlCommand command = new NpgsqlCommand("set DATESTYLE TO ISO;select version();", this))
                {
                    ServerVersion = new Version(PGUtil.ExtractServerVersion((string)command.ExecuteScalar()));
                }
            }

            // Adjust client encoding.

            NpgsqlParameterStatus clientEncodingParam = null;

            if (
                !ServerParameters.TryGetValue("client_encoding", out clientEncodingParam) ||
                (!string.Equals(clientEncodingParam.ParameterValue, "UTF8", StringComparison.OrdinalIgnoreCase) && !string.Equals(clientEncodingParam.ParameterValue, "UNICODE", StringComparison.OrdinalIgnoreCase))
                )
            {
                new NpgsqlCommand("SET CLIENT_ENCODING TO UTF8", this).ExecuteBlind();
            }

            if (!string.IsNullOrEmpty(settings.SearchPath))
            {
                /*NpgsqlParameter p = new NpgsqlParameter("p", DbType.String);
                 * p.Value = settings.SearchPath;
                 * NpgsqlCommand commandSearchPath = new NpgsqlCommand("SET SEARCH_PATH TO :p,public", this);
                 * commandSearchPath.Parameters.Add(p);
                 * commandSearchPath.ExecuteNonQuery();*/

                /*NpgsqlParameter p = new NpgsqlParameter("p", DbType.String);
                 * p.Value = settings.SearchPath;
                 * NpgsqlCommand commandSearchPath = new NpgsqlCommand("SET SEARCH_PATH TO :p,public", this);
                 * commandSearchPath.Parameters.Add(p);
                 * commandSearchPath.ExecuteNonQuery();*/

                // TODO: Add proper message when finding a semicolon in search_path.
                // This semicolon could lead to a sql injection security hole as someone could write in connection string:
                // searchpath=public;delete from table; and it would be executed.

                if (settings.SearchPath.Contains(";"))
                {
                    throw new InvalidOperationException();
                }

                // This is using string concatenation because set search_path doesn't allow type casting. ::text
                NpgsqlCommand commandSearchPath = new NpgsqlCommand("SET SEARCH_PATH=" + settings.SearchPath, this);
                commandSearchPath.ExecuteBlind();
            }

            if (!string.IsNullOrEmpty(settings.ApplicationName))
            {
                if (!SupportsApplicationName)
                {
                    //TODO
                    //throw new InvalidOperationException(resman.GetString("Exception_ApplicationNameNotSupported"));
                    throw new InvalidOperationException("ApplicationName not supported.");
                }

                if (settings.ApplicationName.Contains(";"))
                {
                    throw new InvalidOperationException();
                }

                NpgsqlCommand commandApplicationName = new NpgsqlCommand("SET APPLICATION_NAME='" + settings.ApplicationName + "'", this);
                commandApplicationName.ExecuteBlind();
            }

            /*
             * Try to set SSL negotiation to 0. As of 2010-03-29, recent problems in SSL library implementations made
             * postgresql to add a parameter to set a value when to do this renegotiation or 0 to disable it.
             * Currently, Npgsql has a problem with renegotiation so, we are trying to disable it here.
             * This only works on postgresql servers where the ssl renegotiation settings is supported of course.
             * See http://lists.pgfoundry.org/pipermail/npgsql-devel/2010-February/001065.html for more information.
             */

            try
            {
                NpgsqlCommand commandSslrenegotiation = new NpgsqlCommand("SET ssl_renegotiation_limit=0", this);
                commandSslrenegotiation.ExecuteBlind();
            }
            catch {}



            /*
             * Set precision digits to maximum value possible. For postgresql before 9 it was 2, after that, it is 3.
             * This way, we set first to 2 and then to 3. If there is an error because of 3, it will have been set to 2 at least.
             * Check bug report #1010992 for more information.
             */


            try
            {
                NpgsqlCommand commandSingleDoublePrecision = new NpgsqlCommand("SET extra_float_digits=2;SET extra_float_digits=3;", this);
                commandSingleDoublePrecision.ExecuteBlind();
            }
            catch {}


            /*
             * Set lc_monetary format to 'C' ir order to get a culture agnostic representation of money.
             * I noticed that on Windows, even when the lc_monetary is English_United States.UTF-8, negative
             * money is formatted as ($value) with parentheses to indicate negative value.
             * By going with a culture agnostic format, we get a consistent behavior.
             */

            try
            {
                NpgsqlCommand commandMonetaryFormatC = new NpgsqlCommand("SET lc_monetary='C';", this);
                commandMonetaryFormatC.ExecuteBlind();
            }
            catch
            {
            }


            // Make a shallow copy of the type mapping that the connector will own.
            // It is possible that the connector may add types to its private
            // mapping that will not be valid to another connector, even
            // if connected to the same backend version.
            _oidToNameMapping = NpgsqlTypesHelper.CreateAndLoadInitialTypesMapping(this).Clone();

            ProcessServerVersion();

            // The connector is now fully initialized. Beyond this point, it is
            // safe to release it back to the pool rather than closing it.
            IsInitialized = true;
        }
Beispiel #22
0
 public void WriteUInt64(ulong value, bool littleEndian)
 => Write(littleEndian == BitConverter.IsLittleEndian ? value : PGUtil.ReverseEndianness(value));
        protected IEnumerable <IServerResponseObject> ProcessBackendResponses_Ver_2(NpgsqlConnector context)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");

            using (new ContextResetter(context))
            {
                Stream             stream   = context.Stream;
                NpgsqlMediator     mediator = context.Mediator;
                List <NpgsqlError> errors   = new List <NpgsqlError>();

                for (;;)
                {
                    // Check the first Byte of response.
                    switch ((BackEndMessageCode)stream.ReadByte())
                    {
                    case BackEndMessageCode.ErrorResponse:

                    {
                        NpgsqlError error = new NpgsqlError(context.BackendProtocolVersion, stream);
                        error.ErrorSql = mediator.GetSqlSent();

                        errors.Add(error);

                        NpgsqlEventLog.LogMsg(resman, "Log_ErrorResponse", LogLevel.Debug, error.Message);
                    }

                        // Return imediately if it is in the startup state or connected state as
                        // there is no more messages to consume.
                        // Possible error in the NpgsqlStartupState:
                        //        Invalid password.
                        // Possible error in the NpgsqlConnectedState:
                        //        No pg_hba.conf configured.

                        if (!context.RequireReadyForQuery)
                        {
                            throw new NpgsqlException(errors);
                        }

                        break;

                    case BackEndMessageCode.AuthenticationRequest:
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AuthenticationRequest");
                        AuthenticationRequestType authType = (AuthenticationRequestType)PGUtil.ReadInt32(stream);
                        switch (authType)
                        {
                        case AuthenticationRequestType.AuthenticationOk:
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);
                            break;

                        case AuthenticationRequestType.AuthenticationClearTextPassword:
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);
                            // Send the PasswordPacket.
                            ChangeState(context, NpgsqlStartupState.Instance);
                            context.Authenticate(context.Password);
                            context.Stream.Flush();

                            break;

                        case AuthenticationRequestType.AuthenticationMD5Password:
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationMD5Request", LogLevel.Debug);
                            // Now do the "MD5-Thing"
                            // for this the Password has to be:
                            // 1. md5-hashed with the username as salt
                            // 2. md5-hashed again with the salt we get from the backend

                            MD5 md5 = MD5.Create();

                            // 1.
                            byte[] passwd       = context.Password;
                            byte[] saltUserName = BackendEncoding.UTF8Encoding.GetBytes(context.UserName);

                            byte[] crypt_buf = new byte[passwd.Length + saltUserName.Length];

                            passwd.CopyTo(crypt_buf, 0);
                            saltUserName.CopyTo(crypt_buf, passwd.Length);

                            StringBuilder sb         = new StringBuilder();
                            byte[]        hashResult = md5.ComputeHash(crypt_buf);
                            foreach (byte b in hashResult)
                            {
                                sb.Append(b.ToString("x2"));
                            }

                            String prehash = sb.ToString();

                            byte[] prehashbytes = BackendEncoding.UTF8Encoding.GetBytes(prehash);

                            byte[] saltServer = new byte[4];
                            stream.Read(saltServer, 0, 4);
                            // Send the PasswordPacket.
                            ChangeState(context, NpgsqlStartupState.Instance);

                            // 2.

                            crypt_buf = new byte[prehashbytes.Length + saltServer.Length];
                            prehashbytes.CopyTo(crypt_buf, 0);
                            saltServer.CopyTo(crypt_buf, prehashbytes.Length);

                            sb         = new StringBuilder("md5"); // This is needed as the backend expects md5 result starts with "md5"
                            hashResult = md5.ComputeHash(crypt_buf);
                            foreach (byte b in hashResult)
                            {
                                sb.Append(b.ToString("x2"));
                            }

                            context.Authenticate(BackendEncoding.UTF8Encoding.GetBytes(sb.ToString()));
                            context.Stream.Flush();

                            break;

                        default:
                            // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.
                            errors.Add(
                                new NpgsqlError(context.BackendProtocolVersion,
                                                String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
                            throw new NpgsqlException(errors);
                        }
                        break;

                    case BackEndMessageCode.RowDescription:
                        yield return(new NpgsqlRowDescriptionV2(stream, context.OidToNameMapping, context.CompatVersion));

                        break;

                    case BackEndMessageCode.DataRow:
                        yield return(new StringRowReaderV2(stream));

                        break;

                    case BackEndMessageCode.BinaryRow:
                        throw new NotSupportedException();

                    case BackEndMessageCode.ReadyForQuery:
                        ChangeState(context, NpgsqlReadyState.Instance);
                        if (errors.Count != 0)
                        {
                            throw new NpgsqlException(errors);
                        }
                        yield break;

                    case BackEndMessageCode.BackendKeyData:
                        context.BackEndKeyData = new NpgsqlBackEndKeyData(context.BackendProtocolVersion, stream);
                        break;

                    case BackEndMessageCode.NoticeResponse:
                        context.FireNotice(new NpgsqlError(context.BackendProtocolVersion, stream));
                        break;

                    case BackEndMessageCode.CompletedResponse:
                        yield return(new CompletedResponse(stream));

                        break;

                    case BackEndMessageCode.CursorResponse:
                        // This is the cursor response message.
                        // It is followed by a C NULL terminated string with the name of
                        // the cursor in a FETCH case or 'blank' otherwise.
                        // In this case it should be always 'blank'.
                        // [FIXME] Get another name for this function.
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "CursorResponse");

                        String cursorName = PGUtil.ReadString(stream);
                        // Continue waiting for ReadyForQuery message.
                        break;

                    case BackEndMessageCode.EmptyQueryResponse:
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "EmptyQueryResponse");
                        PGUtil.ReadString(stream);
                        break;

                    case BackEndMessageCode.NotificationResponse:
                        context.FireNotification(new NpgsqlNotificationEventArgs(stream, false));
                        if (context.IsNotificationThreadRunning)
                        {
                            yield break;
                        }
                        break;

                    case BackEndMessageCode.IO_ERROR:
                        // Connection broken. Mono returns -1 instead of throw an exception as ms.net does.
                        throw new IOException();

                    default:
                        // This could mean a number of things
                        //   We've gotten out of sync with the backend?
                        //   We need to implement this type?
                        //   Backend has gone insane?
                        throw new DataException("Backend sent unrecognized response type");
                    }
                }
            }
        }
Beispiel #24
0
 public void WriteSingle(float value, bool littleEndian)
 => Write(littleEndian == BitConverter.IsLittleEndian ? value : PGUtil.ReverseEndianness(value));
Beispiel #25
0
 public void Dispose()
 {
     PGUtil.EatStreamBytes(_stream, _remainingBytes);
 }
Beispiel #26
0
 public void WriteDouble(double value, bool littleEndian)
 => Write(littleEndian == BitConverter.IsLittleEndian ? value : PGUtil.ReverseEndianness(value));
Beispiel #27
0
 public override int DoRead(byte[] output, int outputIdx, int length)
 {
     return(PGUtil.ReadEscapedBytes(_stream, output, length, ref _remainingBytes, outputIdx));
 }
Beispiel #28
0
        public override void Open(NpgsqlConnector context)
        {
            try
            {
                NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "Open");

                IPAddress[] ips    = ResolveIPHost(context.Host);
                Socket      socket = null;

                // try every ip address of the given hostname, use the first reachable one
                foreach (IPAddress ip in ips)
                {
                    NpgsqlEventLog.LogMsg(resman, "Log_ConnectingTo", LogLevel.Debug, ip);

                    IPEndPoint ep = new IPEndPoint(ip, context.Port);
                    socket = new Socket(ep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);

                    try
                    {
                        IAsyncResult result = socket.BeginConnect(ep, null, null);

                        if (!result.AsyncWaitHandle.WaitOne(context.ConnectionTimeout * 1000, true))
                        {
                            socket.Close();
                            throw new Exception(resman.GetString("Exception_ConnectionTimeout"));
                        }

                        socket.EndConnect(result);

                        // connect was successful, leave the loop
                        break;
                    }
                    catch (Exception)
                    {
                        NpgsqlEventLog.LogMsg(resman, "Log_FailedConnection", LogLevel.Normal, ip);
                        socket.Close();
                    }
                }

                if (socket == null || !socket.Connected)
                {
                    throw new Exception(string.Format(resman.GetString("Exception_FailedConnection"), context.Host));
                }

                Stream stream = new NpgsqlNetworkStream(context, socket, true);

                // If the PostgreSQL server has SSL connectors enabled Open SslClientStream if (response == 'S') {
                if (context.SSL || (context.SslMode == SslMode.Require) || (context.SslMode == SslMode.Prefer))
                {
                    PGUtil.WriteInt32(stream, 8);
                    PGUtil.WriteInt32(stream, 80877103);
                    // Receive response

                    Char response = (Char)stream.ReadByte();
                    if (response == 'S')
                    {
                        //create empty collection
                        X509CertificateCollection clientCertificates = new X509CertificateCollection();

                        //trigger the callback to fetch some certificates
                        context.DefaultProvideClientCertificatesCallback(clientCertificates);

                        stream = new SslClientStream(
                            stream,
                            context.Host,
                            true,
                            SecurityProtocolType.Default,
                            clientCertificates);

                        ((SslClientStream)stream).ClientCertSelectionDelegate =
                            new CertificateSelectionCallback(context.DefaultCertificateSelectionCallback);
                        ((SslClientStream)stream).ServerCertValidationDelegate =
                            new CertificateValidationCallback(context.DefaultCertificateValidationCallback);
                        ((SslClientStream)stream).PrivateKeyCertSelectionDelegate =
                            new PrivateKeySelectionCallback(context.DefaultPrivateKeySelectionCallback);
                    }
                    else if (context.SslMode == SslMode.Require)
                    {
                        throw new InvalidOperationException(resman.GetString("Exception_Ssl_RequestError"));
                    }
                }

                context.Stream = new NpgsqlBufferedStream(stream);
                context.Socket = socket;

                NpgsqlEventLog.LogMsg(resman, "Log_ConnectedTo", LogLevel.Normal, context.Host, context.Port);
                ChangeState(context, NpgsqlConnectedState.Instance);
            }
            //FIXME: Exceptions that come from what we are handling should be wrapped - e.g. an error connecting to
            //the server should definitely be presented to the uesr as an NpgsqlError. Exceptions from userland should
            //be passed untouched - e.g. ThreadAbortException because the user started this in a thread they created and
            //then aborted should be passed through.
            //Are there any others that should be pass through? Alternatively, are there a finite number that should
            //be wrapped?
            catch (ThreadAbortException)
            {
                throw;
            }
            catch (Exception e)
            {
                throw new NpgsqlException(e.Message, e);
            }
        }
Beispiel #29
0
        void DoWrite <T>(TypeHandler handler, T value)
        {
            if (_buf.WriteSpaceLeft < 4)
            {
                Flush();
            }
            EnsureDataMessage();

            var asObject = (object)value;   // TODO: Implement boxless writing in the future

            if (asObject == null)
            {
                _buf.WriteInt32(-1);
                _column++;
                return;
            }

            var asSimple = handler as ISimpleTypeWriter;

            if (asSimple != null)
            {
                var len = asSimple.ValidateAndGetLength(asObject);
                _buf.WriteInt32(len);
                if (_buf.WriteSpaceLeft < len)
                {
                    Contract.Assume(_buf.Size >= len);
                    FlushAndStartDataMessage();
                }
                asSimple.Write(asObject, _buf);
                _column++;
                return;
            }

            var asChunking = handler as IChunkingTypeWriter;

            if (asChunking != null)
            {
                _lengthCache.Clear();
                var len = asChunking.ValidateAndGetLength(asObject, ref _lengthCache);
                _buf.WriteInt32(len);
                _lengthCache.Rewind();
                _lengthCache.Get();  // Hack
                asChunking.PrepareWrite(asObject, _buf, _lengthCache);
                var directBuf = new DirectBuffer();
                while (!asChunking.Write(ref directBuf))
                {
                    FlushAndStartDataMessage();

                    // The following is an optimization hack for writing large byte arrays without passing
                    // through our buffer
                    if (directBuf.Buffer != null)
                    {
                        len = directBuf.Size == 0 ? directBuf.Buffer.Length : directBuf.Size;
                        _buf.WriteInt32(len);
                        Flush();
                        _buf.Underlying.Write(directBuf.Buffer, directBuf.Offset, len);
                        directBuf.Buffer = null;
                        directBuf.Size   = 0;
                    }
                }
                _column++;
                return;
            }

            throw PGUtil.ThrowIfReached();
        }
        internal NpgsqlError(ProtocolVersion protocolVersion, Stream stream)
        {
            switch (protocol_version = protocolVersion)
            {
            case ProtocolVersion.Version2:
                string[] parts = PGUtil.ReadString(stream).Split(new char[] { ':' }, 2);
                if (parts.Length == 2)
                {
                    _severity = parts[0].Trim();
                    _message  = parts[1].Trim();
                }
                else
                {
                    _severity = string.Empty;
                    _message  = parts[0].Trim();
                }
                break;

            case ProtocolVersion.Version3:
                // Check the messageLength value. If it is 1178686529, this would be the
                // "FATA" string, which would mean a protocol 2.0 error string.
                if (PGUtil.ReadInt32(stream) == 1178686529)
                {
                    string[] v2Parts = ("FATA" + PGUtil.ReadString(stream)).Split(new char[] { ':' }, 2);
                    if (v2Parts.Length == 2)
                    {
                        _severity = v2Parts[0].Trim();
                        _message  = v2Parts[1].Trim();
                    }
                    else
                    {
                        _severity = string.Empty;
                        _message  = v2Parts[0].Trim();
                    }
                    protocol_version = ProtocolVersion.Version2;
                }
                else
                {
                    for (char field = (char)stream.ReadByte(); field != 0; field = (char)stream.ReadByte())
                    {
                        switch (field)
                        {
                        case 'S':
                            _severity = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'C':
                            _code = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'M':
                            _message = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'D':
                            _detail = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'H':
                            _hint = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'P':
                            _position = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'p':
                            _internalPosition = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'q':
                            _internalQuery = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'W':
                            _where = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'F':
                            _file = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'L':
                            _line = PGUtil.ReadString(stream);
                            ;
                            break;

                        case 'R':
                            _routine = PGUtil.ReadString(stream);
                            ;
                            break;
                        }
                    }
                }
                break;
            }
        }