public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, ProtocolVersion protocolVersion, byte[] inputBuffer, char[] chars)
     : base(rowDesc, protocolVersion)
 {
     NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
     _inputBuffer = inputBuffer;
     _chars       = chars;
 }
예제 #2
0
 public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, ProtocolVersion protocolVersion, byte[] inputBuffer, char[] chars)
         : base(rowDesc, protocolVersion)
 {
     NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
     _inputBuffer = inputBuffer;
     _chars = chars;
 }
예제 #3
0
 public StringRowReaderV3(NpgsqlRowDescription rowDesc, Stream inputStream)
     : base(rowDesc, inputStream)
 {
     _messageSize = PGUtil.ReadInt32(inputStream);
     if (PGUtil.ReadInt16(inputStream) != rowDesc.NumFields)
     {
         throw new DataException();
     }
 }
예제 #4
0
        public override void SetRowDescription(NpgsqlRowDescription rowDesc)
        {
            if (Stream.ReadInt16() != rowDesc.NumFields)
            {
                throw new DataException();
            }

            _rowDesc = rowDesc;
        }
예제 #5
0
        public override void SetRowDescription(NpgsqlRowDescription rowDesc)
        {
            if (Stream.ReadInt16() != rowDesc.NumFields)
            {
                throw new DataException();
            }

            _rowDesc = rowDesc;
        }
        private DataTable GetResultsetSchema()
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "GetResultsetSchema");
            DataTable result = null;

            NpgsqlRowDescription rd = _currentResultset.RowDescription;

            Int16 numFields = rd.NumFields;

            if (numFields > 0)
            {
                result = new DataTable("SchemaTable");

                result.Columns.Add("ColumnName", typeof(string));
                result.Columns.Add("ColumnOrdinal", typeof(int));
                result.Columns.Add("ColumnSize", typeof(int));
                result.Columns.Add("NumericPrecision", typeof(int));
                result.Columns.Add("NumericScale", typeof(int));
                result.Columns.Add("IsUnique", typeof(bool));
                result.Columns.Add("IsKey", typeof(bool));
                result.Columns.Add("BaseCatalogName", typeof(string));
                result.Columns.Add("BaseColumnName", typeof(string));
                result.Columns.Add("BaseSchemaName", typeof(string));
                result.Columns.Add("BaseTableName", typeof(string));
                result.Columns.Add("DataType", typeof(Type));
                result.Columns.Add("AllowDBNull", typeof(bool));
                result.Columns.Add("ProviderType", typeof(string));
                result.Columns.Add("IsAliased", typeof(bool));
                result.Columns.Add("IsExpression", typeof(bool));
                result.Columns.Add("IsIdentity", typeof(bool));
                result.Columns.Add("IsAutoIncrement", typeof(bool));
                result.Columns.Add("IsRowVersion", typeof(bool));
                result.Columns.Add("IsHidden", typeof(bool));
                result.Columns.Add("IsLong", typeof(bool));
                result.Columns.Add("IsReadOnly", typeof(bool));

                if (_connection.Connector.BackendProtocolVersion == ProtocolVersion.Version2)
                {
                    FillSchemaTable_v2(result);
                }
                else if (_connection.Connector.BackendProtocolVersion == ProtocolVersion.Version3)
                {
                    FillSchemaTable_v3(result);
                }
            }

            return(result);
        }
예제 #7
0
        public NpgsqlRowDescription Sync(NpgsqlConnector context)
        {
            NpgsqlRowDescription lastDescription = null;

            foreach (IServerResponseObject obj in SyncEnum(context))
            {
                if (obj is NpgsqlRowDescription)
                {
                    lastDescription = obj as NpgsqlRowDescription;
                }
                else
                {
                    if (obj is IDisposable)
                    {
                        (obj as IDisposable).Dispose();
                    }
                }
            }
            return(lastDescription);
        }
예제 #8
0
        public void AddCompletedResponse(String response)
        {
            if (_rd != null)
            {
                // Finished receiving the resultset. Add it to the buffer.
                _resultSets.Add(new NpgsqlResultSet(_rd, _rows));

                // Add a placeholder response.
                _responses.Add(null);

                // Discard the RowDescription.
                _rd = null;
            }
            else
            {
                // Add a placeholder resultset.
                _resultSets.Add(null);
                // It was just a non query string. Just add the response.
                _responses.Add(response);
            }
        }
예제 #9
0
        internal NpgsqlDataReader(IEnumerable<IServerResponseObject> dataEnumeration, CommandBehavior behavior,
                                        NpgsqlCommand command, NpgsqlConnector.NotificationThreadBlock threadBlock,
                                        bool preparedStatement = false, NpgsqlRowDescription rowDescription = null)
        {
            _behavior = behavior;
            _connection = (_command = command).Connection;
            _connector = command.Connector;
            _dataEnumerator = dataEnumeration.GetEnumerator();
            _connector.CurrentReader = this;
            _threadBlock = threadBlock;
            _preparedStatement = preparedStatement;
            CurrentDescription = rowDescription;

            // For un-prepared statements, the first response is always a row description.
            // For prepared statements, we may be recycling a row description from a previous Execute.
            if (CurrentDescription == null)
            {
                NextResultInternal();
            }

            UpdateOutputParameters();
        }
        private void FillSchemaTable_v3(DataTable schema)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "FillSchemaTable_v3");
            NpgsqlRowDescription rd = _currentResultset.RowDescription;

            Hashtable oidTableLookup = null;
            KeyLookup keyLookup      = new KeyLookup();
            Hashtable columnLookup   = null;

            if ((_behavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo)
            {
                ArrayList tableOids = new ArrayList();
                for (short i = 0; i < rd.NumFields; ++i)
                {
                    if (rd[i].table_oid != 0 && !tableOids.Contains(rd[i].table_oid))
                    {
                        tableOids.Add(rd[i].table_oid);
                    }
                }
                oidTableLookup = GetTablesFromOids(tableOids);

                if (oidTableLookup != null && oidTableLookup.Count == 1)
                {
                    // only 1, but we can't index into the Hashtable
                    foreach (DictionaryEntry entry in oidTableLookup)
                    {
                        keyLookup = GetKeys((Int32)entry.Key);
                    }
                }

                columnLookup = GetColumns();
            }

            DataRow row;

            for (Int16 i = 0; i < rd.NumFields; i++)
            {
                row = schema.NewRow();

                string baseColumnName = GetBaseColumnName(columnLookup, i);

                row["ColumnName"]    = GetName(i);
                row["ColumnOrdinal"] = i + 1;
                if (rd[i].type_modifier != -1 && rd[i].type_info != null && (rd[i].type_info.Name == "varchar" || rd[i].type_info.Name == "bpchar"))
                {
                    row["ColumnSize"] = rd[i].type_modifier - 4;
                }
                else if (rd[i].type_modifier != -1 && rd[i].type_info != null && (rd[i].type_info.Name == "bit" || rd[i].type_info.Name == "varbit"))
                {
                    row["ColumnSize"] = rd[i].type_modifier;
                }
                else
                {
                    row["ColumnSize"] = (int)rd[i].type_size;
                }
                if (rd[i].type_modifier != -1 && rd[i].type_info != null && rd[i].type_info.Name == "numeric")
                {
                    row["NumericPrecision"] = ((rd[i].type_modifier - 4) >> 16) & ushort.MaxValue;
                    row["NumericScale"]     = (rd[i].type_modifier - 4) & ushort.MaxValue;
                }
                else
                {
                    row["NumericPrecision"] = 0;
                    row["NumericScale"]     = 0;
                }
                row["IsUnique"] = IsUnique(keyLookup, baseColumnName);
                row["IsKey"]    = IsKey(keyLookup, baseColumnName);
                if (rd[i].table_oid != 0 && oidTableLookup != null)
                {
                    row["BaseCatalogName"] = ((object[])oidTableLookup[rd[i].table_oid])[Tables.table_catalog];
                    row["BaseSchemaName"]  = ((object[])oidTableLookup[rd[i].table_oid])[Tables.table_schema];
                    row["BaseTableName"]   = ((object[])oidTableLookup[rd[i].table_oid])[Tables.table_name];
                }
                else
                {
                    row["BaseCatalogName"] = "";
                    row["BaseSchemaName"]  = "";
                    row["BaseTableName"]   = "";
                }
                row["BaseColumnName"] = baseColumnName;
                row["DataType"]       = GetFieldType(i);
                row["AllowDBNull"]    = IsNullable(columnLookup, i);
                if (rd[i].type_info != null)
                {
                    row["ProviderType"] = rd[i].type_info.Name;
                }
                row["IsAliased"]       = string.CompareOrdinal((string)row["ColumnName"], baseColumnName) != 0;
                row["IsExpression"]    = false;
                row["IsIdentity"]      = false;
                row["IsAutoIncrement"] = IsAutoIncrement(columnLookup, i);
                row["IsRowVersion"]    = false;
                row["IsHidden"]        = false;
                row["IsLong"]          = false;
                row["IsReadOnly"]      = false;

                schema.Rows.Add(row);
            }
        }
예제 #11
0
 private void UnPrepare()
 {
     if (prepared == PrepareStatus.V3Prepared)
     {
         bind = null;
         execute = null;
         portalDescribeSent = false;
         currentRowDescription = null;
         prepared = PrepareStatus.NeedsPrepare;
     }
     else if (prepared == PrepareStatus.V2Prepared)
     {
         planName = String.Empty;
         prepared = PrepareStatus.NeedsPrepare;
     }
 }
예제 #12
0
        public void AddCompletedResponse(String response)
        {
            if (_rd != null)
            {
                // Finished receiving the resultset. Add it to the buffer.
                _resultSets.Add(new NpgsqlResultSet(_rd, _rows));

                // Add a placeholder response.
                _responses.Add(null);

                // Discard the RowDescription.
                _rd = null;
            }
            else
            {
                // Add a placeholder resultset.
                _resultSets.Add(null);
                // It was just a non query string. Just add the response.
                _responses.Add(response);
            }

        }
예제 #13
0
        protected virtual void ProcessBackendResponses_Ver_3(NpgsqlConnector context)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");

            Stream         stream   = context.Stream;
            NpgsqlMediator mediator = context.Mediator;

            // Often used buffers
            Byte[] inputBuffer = new Byte[4];
            String Str;

            Boolean readyForQuery = false;

            byte[] asciiRowBytes = new byte[300];
            char[] asciiRowChars = new char[300];

            while (!readyForQuery)
            {
                // Check the first Byte of response.
                Int32 message = stream.ReadByte();
                switch (message)
                {
                case NpgsqlMessageTypes_Ver_3.ErrorResponse:

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

                    mediator.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 (!mediator.RequireReadyForQuery)
                    {
                        return;
                    }

                    break;


                case NpgsqlMessageTypes_Ver_3.AuthenticationRequest:

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

                    // Eat length
                    PGUtil.ReadInt32(stream, inputBuffer);

                    {
                        Int32 authType = PGUtil.ReadInt32(stream, inputBuffer);

                        if (authType == NpgsqlMessageTypes_Ver_3.AuthenticationOk)
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);

                            break;
                        }

                        if (authType == NpgsqlMessageTypes_Ver_3.AuthenticationClearTextPassword)
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);

                            // Send the PasswordPacket.

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

                            break;
                        }


                        if (authType == NpgsqlMessageTypes_Ver_3.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.Encoding.GetBytes(context.Password);
                            byte[] saltUserName = context.Encoding.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 = context.Encoding.GetBytes(prehash);



                            stream.Read(inputBuffer, 0, 4);
                            // Send the PasswordPacket.
                            ChangeState(context, NpgsqlStartupState.Instance);


                            // 2.

                            crypt_buf = new byte[prehashbytes.Length + 4];
                            prehashbytes.CopyTo(crypt_buf, 0);
                            inputBuffer.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(sb.ToString());

                            break;
                        }

                        // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.
                        mediator.Errors.Add(new NpgsqlError(context.BackendProtocolVersion, String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
                    }

                    return;

                case NpgsqlMessageTypes_Ver_3.RowDescription:
                    // This is the RowDescription message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "RowDescription");
                    {
                        NpgsqlRowDescription rd = new NpgsqlRowDescription(context.BackendProtocolVersion);
                        rd.ReadFromStream(stream, context.Encoding, context.OidToNameMapping);

                        mediator.AddRowDescription(rd);
                    }

                    // Now wait for the AsciiRow messages.
                    break;

                case NpgsqlMessageTypes_Ver_3.ParameterDescription:

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

                    break;

                case NpgsqlMessageTypes_Ver_3.DataRow:
                    // This is the AsciiRow message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "DataRow");
                    {
                        NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion, asciiRowBytes, asciiRowChars);
                        asciiRow.ReadFromStream(stream, context.Encoding);

                        // Add this row to the rows array.
                        mediator.AddAsciiRow(asciiRow);
                    }

                    // Now wait for CompletedResponse message.
                    break;

                case NpgsqlMessageTypes_Ver_3.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, inputBuffer);
                    PGUtil.ReadString(stream, context.Encoding, 1);

                    readyForQuery = true;
                    ChangeState(context, NpgsqlReadyState.Instance);

                    break;

                case NpgsqlMessageTypes_Ver_3.BackendKeyData:

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


                    // Wait for ReadForQuery message
                    break;

                case NpgsqlMessageTypes_Ver_3.NoticeResponse:

                    // Notices and errors are identical except that we
                    // just throw notices away completely ignored.
                {
                    NpgsqlError notice = new NpgsqlError(context.BackendProtocolVersion);
                    notice.ReadFromStream(stream, context.Encoding);

                    mediator.Notices.Add(notice);

                    NpgsqlEventLog.LogMsg(resman, "Log_NoticeResponse", LogLevel.Debug, notice.Message);
                }

                    // Wait for ReadForQuery message
                    break;

                case NpgsqlMessageTypes_Ver_3.CompletedResponse:
                    // This is the CompletedResponse message.
                    // Get the string returned.

                    PGUtil.ReadInt32(stream, inputBuffer);
                    Str = PGUtil.ReadString(stream, context.Encoding);

                    NpgsqlEventLog.LogMsg(resman, "Log_CompletedResponse", LogLevel.Debug, Str);

                    // Add result from the processing.
                    mediator.AddCompletedResponse(Str);

                    break;

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

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

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

                case NpgsqlMessageTypes_Ver_3.NotificationResponse:
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "NotificationResponse");

                    // Eat the length
                    PGUtil.ReadInt32(stream, inputBuffer);
                    {
                        // Process ID sending notification
                        Int32 PID = PGUtil.ReadInt32(stream, inputBuffer);
                        // Notification string
                        String notificationResponse = PGUtil.ReadString(stream, context.Encoding);
                        // Additional info, currently not implemented by PG (empty string always), eat it
                        PGUtil.ReadString(stream, context.Encoding);
                        mediator.AddNotification(new NpgsqlNotificationEventArgs(PID, notificationResponse));
                    }

                    if (context.IsNotificationThreadRunning)
                    {
                        readyForQuery = true;
                    }

                    // Wait for ReadForQuery message
                    break;

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

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

                    mediator.AddParameterStatus(parameterStatus.Parameter, parameterStatus);

                    if (parameterStatus.Parameter == "server_version")
                    {
                        // Add this one under our own name so that if the parameter name
                        // changes in a future backend version, we can handle it here in the
                        // protocol handler and leave everybody else put of it.
                        mediator.AddParameterStatus("__npgsql_server_version", parameterStatus);
                        //                        context.ServerVersionString = parameterStatus.ParameterValue;
                    }

                    break;

                case NpgsqlMessageTypes_Ver_3.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, inputBuffer);
                    break;


                case -1:
                    // 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?
                    // FIXME
                    // what exception should we really throw here?
                    throw new NotSupportedException(String.Format("Backend sent unrecognized response type: {0}", (Char)message));
                }
            }
        }
예제 #14
0
 public NullMap(NpgsqlRowDescription desc, Stream inputStream)
 {
     _map = new byte[(desc.NumFields + 7) / 8];
     PGUtil.CheckedStreamRead(inputStream, _map, 0, _map.Length);
 }
예제 #15
0
        void PrepareInternal()
        {
            // Use the extended query parsing...
            _planName = _connector.NextPlanName();
            const string portalName = "";

            _preparedCommandText = GetCommandText(true);
            NpgsqlRowDescription returnRowDesc = null;
            ParameterDescriptionResponse parameterDescription = null;


            var numInputParameters = 0;
            for (var i = 0; i < _parameters.Count; i++)
            {
                if (_parameters[i].IsInputDirection)
                {
                    numInputParameters++;
                }
            }

            var parameterTypeOIDs = new int[numInputParameters];

            for (int i = 0, j = 0; i < _parameters.Count; i++)
            {
                if (_parameters[i].IsInputDirection)
                {
                    parameterTypeOIDs[j++] = _parameters[i].TypeInfo.NpgsqlDbType == NpgsqlDbType.Unknown ? 0 : _connector.OidToNameMapping[_parameters[i].TypeInfo.Name].OID;
                }
            }

            // Write Parse, Describe, and Sync messages to the wire.
            _connector.SendParse(_planName, _preparedCommandText, parameterTypeOIDs);
            _connector.SendDescribeStatement(_planName);
            _connector.SendSync();

            // Tell to mediator what command is being sent.
            _connector.Mediator.SetSqlSent(_preparedCommandText, NpgsqlMediator.SQLSentType.Parse);

            // Look for ParameterDescriptionResponse, NpgsqlRowDescription in the responses, discarding everything else.
            while (true)
            {
                var msg = _connector.ReadMessage();
                if (msg is ReadyForQueryMsg) {
                    break;
                }
                var asParameterDescription = msg as ParameterDescriptionResponse;
                if (asParameterDescription != null)
                {
                    parameterDescription = asParameterDescription;
                    continue;
                }
                var asRowDesc = msg as NpgsqlRowDescription;
                if (asRowDesc != null)
                {
                    returnRowDesc = asRowDesc;
                    continue;
                }
                var asDisposable = msg as IDisposable;
                if (asDisposable != null)
                {
                    asDisposable.Dispose();
                }
            }

            if (parameterDescription != null)
            {
                if (parameterDescription.TypeOIDs.Length != numInputParameters)
                {
                    throw new InvalidOperationException("Wrong number of parameters. Got " + numInputParameters + " but expected " + parameterDescription.TypeOIDs.Length + ".");
                }

                for (int i = 0, j = 0; j < numInputParameters; i++)
                {
                    if (_parameters[i].IsInputDirection)
                    {
                        _parameters[i].SetTypeOID(parameterDescription.TypeOIDs[j++], _connector.NativeToBackendTypeConverterOptions);
                    }
                }
            }

            if (returnRowDesc != null)
            {
                _resultFormatCodes = new short[returnRowDesc.NumFields];

                for (var i = 0; i < returnRowDesc.NumFields; i++)
                {
                    var returnRowDescData = returnRowDesc[i];

                    if (returnRowDescData.TypeInfo != null)
                    {
                        // Binary format?
                        // PG always defaults to text encoding.  We can fix up the row description
                        // here based on support for binary encoding.  Once this is done,
                        // there is no need to request another row description after Bind.
                        returnRowDescData.FormatCode = returnRowDescData.TypeInfo.SupportsBinaryBackendData ? FormatCode.Binary : FormatCode.Text;
                        _resultFormatCodes[i] = (short)returnRowDescData.FormatCode;
                    }
                    else
                    {
                        // Text format (default).
                        _resultFormatCodes[i] = (short)FormatCode.Text;
                    }
                }
            }
            else
            {
                _resultFormatCodes = new short[] { 0 };
            }

            // Save the row description for use with all future Executes.
            _currentRowDescription = returnRowDesc;

            _prepared = PrepareStatus.Prepared;
        }
예제 #16
0
        protected virtual void ProcessBackendResponses_Ver_2( NpgsqlConnector context )
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");

            Stream 	stream = context.Stream;
            NpgsqlMediator mediator = context.Mediator;

            // Often used buffer
            Byte[] inputBuffer = new Byte[ 4 ];

            Boolean readyForQuery = false;

            byte[] asciiRowBytes = new byte[300];
            char[] asciiRowChars = new char[300];

            while (!readyForQuery)
            {
                // Check the first Byte of response.
                switch ( stream.ReadByte() )
                {
                case NpgsqlMessageTypes_Ver_2.ErrorResponse :

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

                        mediator.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 (! mediator.RequireReadyForQuery)
                    {
                        return;
                    }

                    break;


                case NpgsqlMessageTypes_Ver_2.AuthenticationRequest :

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

                    {
                        Int32 authType = PGUtil.ReadInt32(stream, inputBuffer);

                        if ( authType == NpgsqlMessageTypes_Ver_2.AuthenticationOk )
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);

                            break;
                        }

                        if ( authType == NpgsqlMessageTypes_Ver_2.AuthenticationClearTextPassword )
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);

                            // Send the PasswordPacket.

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

                            break;
                        }


                        if ( authType == NpgsqlMessageTypes_Ver_2.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.Encoding.GetBytes(context.Password);
                            byte[] saltUserName = context.Encoding.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 = context.Encoding.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(sb.ToString ());

                            break;
                        }

                        // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.

                        mediator.Errors.Add(new NpgsqlError(context.BackendProtocolVersion, String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
                    }

                    return;

                case NpgsqlMessageTypes_Ver_2.RowDescription:
                    // This is the RowDescription message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "RowDescription");

                    {
                        NpgsqlRowDescription rd = new NpgsqlRowDescription(context.BackendProtocolVersion);
                        rd.ReadFromStream(stream, context.Encoding, context.OidToNameMapping);

                        // Initialize the array list which will contain the data from this rowdescription.
                        mediator.AddRowDescription(rd);
                    }

                    // Now wait for the AsciiRow messages.
                    break;

                case NpgsqlMessageTypes_Ver_2.AsciiRow:
                    // This is the AsciiRow message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AsciiRow");

                    {
                        NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion, asciiRowBytes, asciiRowChars);
                        asciiRow.ReadFromStream(stream, context.Encoding);

                        // Add this row to the rows array.
                        mediator.AddAsciiRow(asciiRow);
                    }

                    // Now wait for CompletedResponse message.
                    break;

                case NpgsqlMessageTypes_Ver_2.BinaryRow:
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BinaryRow");

                    {
                        NpgsqlBinaryRow binaryRow = new NpgsqlBinaryRow(context.Mediator.LastRowDescription);
                        binaryRow.ReadFromStream(stream, context.Encoding);

                        mediator.AddBinaryRow(binaryRow);
                    }

                    break;

                case NpgsqlMessageTypes_Ver_2.ReadyForQuery :

                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ReadyForQuery");
                    readyForQuery = true;
                    ChangeState( context, NpgsqlReadyState.Instance );
                    break;

                case NpgsqlMessageTypes_Ver_2.BackendKeyData :

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


                    // Wait for ReadForQuery message
                    break;
                    ;

                case NpgsqlMessageTypes_Ver_2.NoticeResponse :

                    {
                        NpgsqlError notice = new NpgsqlError(context.BackendProtocolVersion);
                        notice.ReadFromStream(stream, context.Encoding);

                        mediator.Notices.Add(notice);

                        NpgsqlEventLog.LogMsg(resman, "Log_NoticeResponse", LogLevel.Debug, notice.Message);
                    }

                    // Wait for ReadForQuery message
                    break;

                case NpgsqlMessageTypes_Ver_2.CompletedResponse :
                    // This is the CompletedResponse message.
                    // Get the string returned.


                    String result = PGUtil.ReadString(stream, context.Encoding);

                    NpgsqlEventLog.LogMsg(resman, "Log_CompletedResponse", LogLevel.Debug, result);
                    // Add result from the processing.

                    mediator.AddCompletedResponse(result);

                    // Now wait for ReadyForQuery message.
                    break;

                case NpgsqlMessageTypes_Ver_2.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, context.Encoding);
                    // Continue waiting for ReadyForQuery message.
                    break;

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

                case NpgsqlMessageTypes_Ver_2.NotificationResponse  :

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

                    Int32 PID = PGUtil.ReadInt32(stream, inputBuffer);
                    String notificationResponse = PGUtil.ReadString( stream, context.Encoding );
                    mediator.AddNotification(new NpgsqlNotificationEventArgs(PID, notificationResponse));
                    
                    if (context.IsNotificationThreadRunning)
                        readyForQuery = true;

                    // Wait for ReadForQuery message
                    break;

                case -1:
                    // 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?
                    // FIXME
                    // what exception should we really throw here?
                    throw new NotSupportedException("Backend sent unrecognized response type");

                }
            }
        }
예제 #17
0
 private object ReadLargeObject(NpgsqlRowDescription.FieldData field_descr, int field_value_size)
 {
     var cms = new ChunkedMemoryStream(Stream, field_value_size);
     try
     {
         return
             NpgsqlTypesHelper.ConvertBackendStringToSystemType(
                 field_descr.TypeInfo,
                 new StreamReader(cms, Encoding.UTF8),
                 field_descr.TypeSize,
                 field_descr.TypeModifier);
     }
     catch (InvalidCastException ice)
     {
         return ice;
     }
     catch (Exception ex)
     {
         return new InvalidCastException(ex.Message, ex);
     }
 }
예제 #18
0
 public StringRowReaderV3(NpgsqlRowDescription rowDesc, Stream inputStream)
     : base(rowDesc, inputStream)
 {
     _messageSize = PGUtil.ReadInt32(inputStream);
     if (PGUtil.ReadInt16(inputStream) != rowDesc.NumFields)
     {
         throw new DataException();
     }
 }
예제 #19
0
 public NullMap(NpgsqlRowDescription desc, Stream inputStream)
 {
     _map = new byte[(desc.NumFields + 7) / 8];
     PGUtil.CheckedStreamRead(inputStream, _map, 0, _map.Length);
 }
예제 #20
0
 public NpgsqlBinaryRow(NpgsqlRowDescription rowDesc)
         : base(rowDesc, ProtocolVersion.Version2)
 {
     NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
 }
예제 #21
0
 public NpgsqlRow(NpgsqlRowDescription rowDesc, ProtocolVersion protocolVersion)
 {
     data             = new ArrayList();
     row_desc         = rowDesc;
     protocol_version = protocolVersion;
 }
예제 #22
0
        void PrepareInternal()
        {
            // Use the extended query parsing...
            _planName = _connector.NextPlanName();
            const string portalName = "";

            _preparedCommandText = GetCommandText(true);
            var parse = new NpgsqlParse(_planName, _preparedCommandText, new int[] { });
            var statementDescribe = new NpgsqlDescribeStatement(_planName);
            NpgsqlRowDescription returnRowDesc = null;

            // Write Parse, Describe, and Sync messages to the wire.
            _connector.Parse(parse);
            _connector.Describe(statementDescribe);
            _connector.Sync();

            // Tell to mediator what command is being sent.
            _connector.Mediator.SetSqlSent(_preparedCommandText, NpgsqlMediator.SQLSentType.Parse);

            // Flush and wait for response.
            var responseEnum = _connector.ProcessBackendResponsesEnum();

            // Look for a NpgsqlRowDescription in the responses, discarding everything else.
            foreach (var response in responseEnum)
            {
                if (response is NpgsqlRowDescription)
                {
                    returnRowDesc = (NpgsqlRowDescription)response;
                }
                else if (response is IDisposable)
                {
                    (response as IDisposable).Dispose();
                }
            }

            short[] resultFormatCodes;

            if (returnRowDesc != null)
            {
                resultFormatCodes = new short[returnRowDesc.NumFields];

                for (var i = 0; i < returnRowDesc.NumFields; i++)
                {
                    var returnRowDescData = returnRowDesc[i];

                    if (returnRowDescData.TypeInfo != null)
                    {
                        // Binary format?
                        // PG always defaults to text encoding.  We can fix up the row description
                        // here based on support for binary encoding.  Once this is done,
                        // there is no need to request another row description after Bind.
                        returnRowDescData.FormatCode = returnRowDescData.TypeInfo.SupportsBinaryBackendData ? FormatCode.Binary : FormatCode.Text;
                        resultFormatCodes[i] = (short)returnRowDescData.FormatCode;
                    }
                    else
                    {
                        // Text format (default).
                        resultFormatCodes[i] = (short)FormatCode.Text;
                    }
                }
            }
            else
            {
                resultFormatCodes = new short[] { 0 };
            }

            // Save the row description for use with all future Executes.
            _currentRowDescription = returnRowDesc;

            // The Bind and Execute message objects live through multiple Executes.
            // Only Bind changes at all between Executes, which is done in BindParameters().
            _bind = new NpgsqlBind(portalName, _planName, new Int16[Parameters.Count], null, resultFormatCodes);
            _execute = new NpgsqlExecute(portalName, 0);

            _prepared = PrepareStatus.Prepared;
        }
예제 #23
0
파일: NpgsqlRow.cs 프로젝트: nlhepler/mono
 public NpgsqlRow(NpgsqlRowDescription rowDesc, ProtocolVersion protocolVersion)
 {
     data = new ArrayList();
     row_desc = rowDesc;
     protocol_version = protocolVersion;
 }
예제 #24
0
        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;
                NpgsqlRowDescription lastRowDescription = null;
                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.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");
                        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 = ENCODING_UTF8.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 = ENCODING_UTF8.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(ENCODING_UTF8.GetBytes(sb.ToString()));

                            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(lastRowDescription = new NpgsqlRowDescriptionV2(stream, context.OidToNameMapping, context.CompatVersion));

                        ;
                        break;

                    case BackEndMessageCode.DataRow:
                        yield return(new ForwardsOnlyRow(new StringRowReaderV2(lastRowDescription, 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");
                    }
                }
            }
        }
예제 #25
0
        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;

                NpgsqlRowDescription lastRowDescription = null;

                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 = ENCODING_UTF8.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 = ENCODING_UTF8.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(ENCODING_UTF8.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(lastRowDescription = 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 ForwardsOnlyRow(new StringRowReaderV3(lastRowDescription, 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);
                        yield break;

                    case BackEndMessageCode.BindComplete:
                        NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BindComplete");
                        // Just read up the message length.
                        PGUtil.ReadInt32(stream);
                        yield 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));
                    }
                }
            }
        }
예제 #26
0
 public StringRowReaderV2(NpgsqlRowDescription rowDesc, Stream inputStream)
     : base(rowDesc, inputStream)
 {
     _nullMap = new NullMap(rowDesc, inputStream);
 }
예제 #27
0
        protected virtual void ProcessBackendResponses_Ver_3( NpgsqlConnector context )
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");

            Stream 	stream = context.Stream;
            NpgsqlMediator mediator = context.Mediator;

            // Often used buffers
            Byte[] inputBuffer = new Byte[ 4 ];
            String Str;

            Boolean readyForQuery = false;

            byte[] asciiRowBytes = new byte[300];
            char[] asciiRowChars = new char[300];

            while (!readyForQuery)
            {
                // Check the first Byte of response.
                Int32 message = stream.ReadByte();
                switch ( message )
                {
                case NpgsqlMessageTypes_Ver_3.ErrorResponse :

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

                        mediator.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 (! mediator.RequireReadyForQuery)
                    {
                        return;
                    }

                    break;


                case NpgsqlMessageTypes_Ver_3.AuthenticationRequest :

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

                    // Eat length
                    PGUtil.ReadInt32(stream, inputBuffer);

                    {
                        Int32 authType = PGUtil.ReadInt32(stream, inputBuffer);

                        if ( authType == NpgsqlMessageTypes_Ver_3.AuthenticationOk )
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);

                            break;
                        }

                        if ( authType == NpgsqlMessageTypes_Ver_3.AuthenticationClearTextPassword )
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);

                            // Send the PasswordPacket.

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

                            break;
                        }


                        if ( authType == NpgsqlMessageTypes_Ver_3.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.Encoding.GetBytes(context.Password);
                            byte[] saltUserName = context.Encoding.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 = context.Encoding.GetBytes(prehash);



                            stream.Read(inputBuffer, 0, 4);
                            // Send the PasswordPacket.
                            ChangeState( context, NpgsqlStartupState.Instance );


                            // 2.

                            crypt_buf = new byte[prehashbytes.Length + 4];
                            prehashbytes.CopyTo(crypt_buf, 0);
                            inputBuffer.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(sb.ToString ());

                            break;
                        }

                        // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.
                        mediator.Errors.Add(new NpgsqlError(context.BackendProtocolVersion, String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
                    }

                    return;

                case NpgsqlMessageTypes_Ver_3.RowDescription:
                    // This is the RowDescription message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "RowDescription");
                    {
                        NpgsqlRowDescription rd = new NpgsqlRowDescription(context.BackendProtocolVersion);
                        rd.ReadFromStream(stream, context.Encoding, context.OidToNameMapping);

                        mediator.AddRowDescription(rd);
                    }

                    // Now wait for the AsciiRow messages.
                    break;
                case NpgsqlMessageTypes_Ver_3.ParameterDescription:
                    
                    // Do nothing,for instance,  just read...
                    int lenght = PGUtil.ReadInt32(stream, inputBuffer);
                    int nb_param = PGUtil.ReadInt16(stream, inputBuffer);
                    for (int i=0; i < nb_param; i++)
                    {
                        int typeoid = PGUtil.ReadInt32(stream, inputBuffer);
                    }
                    
                    break;

                case NpgsqlMessageTypes_Ver_3.DataRow:
                    // This is the AsciiRow message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "DataRow");
                    {
                        NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion, asciiRowBytes, asciiRowChars);
                        asciiRow.ReadFromStream(stream, context.Encoding);

                        // Add this row to the rows array.
                        mediator.AddAsciiRow(asciiRow);
                    }

                    // Now wait for CompletedResponse message.
                    break;

                case NpgsqlMessageTypes_Ver_3.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, inputBuffer);
                    PGUtil.ReadString(stream, context.Encoding, 1);

                    readyForQuery = true;
                    ChangeState( context, NpgsqlReadyState.Instance );

                    break;

                case NpgsqlMessageTypes_Ver_3.BackendKeyData :

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


                    // Wait for ReadForQuery message
                    break;

                case NpgsqlMessageTypes_Ver_3.NoticeResponse :

                    // Notices and errors are identical except that we
                    // just throw notices away completely ignored.
                    {
                        NpgsqlError notice = new NpgsqlError(context.BackendProtocolVersion);
                        notice.ReadFromStream(stream, context.Encoding);

                        mediator.Notices.Add(notice);

                        NpgsqlEventLog.LogMsg(resman, "Log_NoticeResponse", LogLevel.Debug, notice.Message);
                    }

                    // Wait for ReadForQuery message
                    break;

                case NpgsqlMessageTypes_Ver_3.CompletedResponse :
                    // This is the CompletedResponse message.
                    // Get the string returned.

                    PGUtil.ReadInt32(stream, inputBuffer);
                    Str = PGUtil.ReadString(stream, context.Encoding);

                    NpgsqlEventLog.LogMsg(resman, "Log_CompletedResponse", LogLevel.Debug, Str);

                    // Add result from the processing.
                    mediator.AddCompletedResponse(Str);

                    break;

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

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

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

                case NpgsqlMessageTypes_Ver_3.NotificationResponse  :
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "NotificationResponse");

                    // Eat the length
                    PGUtil.ReadInt32(stream, inputBuffer);
                    {
                        // Process ID sending notification
                        Int32 PID = PGUtil.ReadInt32(stream, inputBuffer);
                        // Notification string
                        String notificationResponse = PGUtil.ReadString( stream, context.Encoding );
                        // Additional info, currently not implemented by PG (empty string always), eat it
                        PGUtil.ReadString( stream, context.Encoding );
                        mediator.AddNotification(new NpgsqlNotificationEventArgs(PID, notificationResponse));
                    }
                    
                    if (context.IsNotificationThreadRunning)
                        readyForQuery = true;

                    // Wait for ReadForQuery message
                    break;

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

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

                    mediator.AddParameterStatus(parameterStatus.Parameter, parameterStatus);

                    if (parameterStatus.Parameter == "server_version")
                    {
                        // Add this one under our own name so that if the parameter name
                        // changes in a future backend version, we can handle it here in the
                        // protocol handler and leave everybody else put of it.
                        mediator.AddParameterStatus("__npgsql_server_version", parameterStatus);
                        //                        context.ServerVersionString = parameterStatus.ParameterValue;
                    }

                    break;
                case NpgsqlMessageTypes_Ver_3.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, inputBuffer);
                    break;


                case -1:
		    // 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?
                    // FIXME
                    // what exception should we really throw here?
                    throw new NotSupportedException(String.Format("Backend sent unrecognized response type: {0}", (Char)message));

                }
            }
        }
예제 #28
0
 public override void SetRowDescription(NpgsqlRowDescription rowDesc)
 {
     _rowDesc = rowDesc;
     _nullMap = new NullMap(rowDesc, Stream);
 }
예제 #29
0
        void UnPrepare()
        {
            if (_prepared == PrepareStatus.Prepared)
            {
                _connector.ExecuteBlind("DEALLOCATE " + _planName);
                _currentRowDescription = null;
                _prepared = PrepareStatus.NeedsPrepare;
            }

            _preparedCommandText = null;
        }
예제 #30
0
 public void AddRowDescription(NpgsqlRowDescription rowDescription)
 {
     _rd   = rowDescription;
     _rows = new ArrayList();
 }
예제 #31
0
 public StringRowReaderV2(NpgsqlRowDescription rowDesc, Stream inputStream)
     : base(rowDesc, inputStream)
 {
     _nullMap = new NullMap(rowDesc, inputStream);
 }
예제 #32
0
 public RowReader(NpgsqlRowDescription rowDesc, Stream stream)
 {
     _rowDesc = rowDesc;
     _stream  = stream;
 }
예제 #33
0
        protected virtual void ProcessBackendResponses_Ver_2(NpgsqlConnector context)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "ProcessBackendResponses");

            Stream         stream   = context.Stream;
            NpgsqlMediator mediator = context.Mediator;

            // Often used buffer
            Byte[] inputBuffer = new Byte[4];

            Boolean readyForQuery = false;

            byte[] asciiRowBytes = new byte[300];
            char[] asciiRowChars = new char[300];

            while (!readyForQuery)
            {
                // Check the first Byte of response.
                switch (stream.ReadByte())
                {
                case NpgsqlMessageTypes_Ver_2.ErrorResponse:

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

                    mediator.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 (!mediator.RequireReadyForQuery)
                    {
                        return;
                    }

                    break;


                case NpgsqlMessageTypes_Ver_2.AuthenticationRequest:

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

                    {
                        Int32 authType = PGUtil.ReadInt32(stream, inputBuffer);

                        if (authType == NpgsqlMessageTypes_Ver_2.AuthenticationOk)
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationOK", LogLevel.Debug);

                            break;
                        }

                        if (authType == NpgsqlMessageTypes_Ver_2.AuthenticationClearTextPassword)
                        {
                            NpgsqlEventLog.LogMsg(resman, "Log_AuthenticationClearTextRequest", LogLevel.Debug);

                            // Send the PasswordPacket.

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

                            break;
                        }


                        if (authType == NpgsqlMessageTypes_Ver_2.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.Encoding.GetBytes(context.Password);
                            byte[] saltUserName = context.Encoding.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 = context.Encoding.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(sb.ToString());

                            break;
                        }

                        // Only AuthenticationClearTextPassword and AuthenticationMD5Password supported for now.

                        mediator.Errors.Add(new NpgsqlError(context.BackendProtocolVersion, String.Format(resman.GetString("Exception_AuthenticationMethodNotSupported"), authType)));
                    }

                    return;

                case NpgsqlMessageTypes_Ver_2.RowDescription:
                    // This is the RowDescription message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "RowDescription");

                    {
                        NpgsqlRowDescription rd = new NpgsqlRowDescription(context.BackendProtocolVersion);
                        rd.ReadFromStream(stream, context.Encoding, context.OidToNameMapping);

                        // Initialize the array list which will contain the data from this rowdescription.
                        mediator.AddRowDescription(rd);
                    }

                    // Now wait for the AsciiRow messages.
                    break;

                case NpgsqlMessageTypes_Ver_2.AsciiRow:
                    // This is the AsciiRow message.
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "AsciiRow");

                    {
                        NpgsqlAsciiRow asciiRow = new NpgsqlAsciiRow(context.Mediator.LastRowDescription, context.BackendProtocolVersion, asciiRowBytes, asciiRowChars);
                        asciiRow.ReadFromStream(stream, context.Encoding);

                        // Add this row to the rows array.
                        mediator.AddAsciiRow(asciiRow);
                    }

                    // Now wait for CompletedResponse message.
                    break;

                case NpgsqlMessageTypes_Ver_2.BinaryRow:
                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "BinaryRow");

                    {
                        NpgsqlBinaryRow binaryRow = new NpgsqlBinaryRow(context.Mediator.LastRowDescription);
                        binaryRow.ReadFromStream(stream, context.Encoding);

                        mediator.AddBinaryRow(binaryRow);
                    }

                    break;

                case NpgsqlMessageTypes_Ver_2.ReadyForQuery:

                    NpgsqlEventLog.LogMsg(resman, "Log_ProtocolMessage", LogLevel.Debug, "ReadyForQuery");
                    readyForQuery = true;
                    ChangeState(context, NpgsqlReadyState.Instance);
                    break;

                case NpgsqlMessageTypes_Ver_2.BackendKeyData:

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


                    // Wait for ReadForQuery message
                    break;
                    ;

                case NpgsqlMessageTypes_Ver_2.NoticeResponse:

                {
                    NpgsqlError notice = new NpgsqlError(context.BackendProtocolVersion);
                    notice.ReadFromStream(stream, context.Encoding);

                    mediator.Notices.Add(notice);

                    NpgsqlEventLog.LogMsg(resman, "Log_NoticeResponse", LogLevel.Debug, notice.Message);
                }

                    // Wait for ReadForQuery message
                    break;

                case NpgsqlMessageTypes_Ver_2.CompletedResponse:
                    // This is the CompletedResponse message.
                    // Get the string returned.


                    String result = PGUtil.ReadString(stream, context.Encoding);

                    NpgsqlEventLog.LogMsg(resman, "Log_CompletedResponse", LogLevel.Debug, result);
                    // Add result from the processing.

                    mediator.AddCompletedResponse(result);

                    // Now wait for ReadyForQuery message.
                    break;

                case NpgsqlMessageTypes_Ver_2.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, context.Encoding);
                    // Continue waiting for ReadyForQuery message.
                    break;

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

                case NpgsqlMessageTypes_Ver_2.NotificationResponse:

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

                    Int32  PID = PGUtil.ReadInt32(stream, inputBuffer);
                    String notificationResponse = PGUtil.ReadString(stream, context.Encoding);
                    mediator.AddNotification(new NpgsqlNotificationEventArgs(PID, notificationResponse));

                    if (context.IsNotificationThreadRunning)
                    {
                        readyForQuery = true;
                    }

                    // Wait for ReadForQuery message
                    break;

                case -1:
                    // 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?
                    // FIXME
                    // what exception should we really throw here?
                    throw new NotSupportedException("Backend sent unrecognized response type");
                }
            }
        }
예제 #34
0
        private NpgsqlRow GetNextRow(bool clearPending)
        {
            if (_pendingDescription != null)
            {
                return null;
            }
            if (((_behavior & CommandBehavior.SingleRow) != 0 && CurrentRow != null && _pendingDescription == null) ||
                ((_behavior & CommandBehavior.SchemaOnly) != 0))
            {
                if (!clearPending)
                {
                    return null;
                }
                //We should only have one row, and we've already had it. Move to end
                //of recordset.
                CurrentRow = null;
                for (object skip = GetNextResponseObject();
                     skip != null && (_pendingDescription = skip as NpgsqlRowDescription) == null;
                     skip = GetNextResponseObject())
                {
                    if (skip is NpgsqlRow)
                    {
                        (skip as NpgsqlRow).Dispose();
                    }
                }

                return null;
            }
            if (_pendingRow != null)
            {
                NpgsqlRow ret = _pendingRow;
                if (clearPending)
                {
                    _pendingRow = null;
                }
                if (!_hasRows)
                {
                    // when rows are found, store that this result has rows.
                    _hasRows = (ret != null);
                }
                return ret;
            }
            CurrentRow = null;
            object objNext = GetNextResponseObject();
            if (clearPending)
            {
                _pendingRow = null;
            }
            if (objNext is NpgsqlRowDescription)
            {
                _pendingDescription = objNext as NpgsqlRowDescription;
                return null;
            }
            if (!_hasRows)
            {
                // when rows are found, store that this result has rows.
                _hasRows = objNext is NpgsqlRow;
            }
            return objNext as NpgsqlRow;
        }
예제 #35
0
 public void AddRowDescription(NpgsqlRowDescription rowDescription)
 {
     _rd = rowDescription;
     _rows = new ArrayList();
 }
예제 #36
0
        internal ForwardsOnlyDataReader GetReader(CommandBehavior cb)
        {
            CheckConnectionState();

            // reset any responses just before getting new ones
            Connector.Mediator.ResetResponses();

            // Set command timeout.
            m_Connector.Mediator.CommandTimeout = CommandTimeout;

            // Block the notification thread before writing anything to the wire.
            using (m_Connector.BlockNotificationThread())
            {
                IEnumerable<IServerResponseObject> responseEnum;
                ForwardsOnlyDataReader reader;

                if (prepared == PrepareStatus.NeedsPrepare)
                {
                    PrepareInternal();
                }

                if (prepared == PrepareStatus.NotPrepared || prepared == PrepareStatus.V2Prepared)
                {
                    NpgsqlQuery query;

                    query = new NpgsqlQuery(m_Connector, GetCommandText());

                    // Write the Query message to the wire.
                    m_Connector.Query(query);

                    // Flush and wait for responses.
                    responseEnum = m_Connector.ProcessBackendResponsesEnum();

                    // Construct the return reader.
                    reader = new ForwardsOnlyDataReader(
                        responseEnum,
                        cb,
                        this,
                        m_Connector.BlockNotificationThread()
                    );

                    if (
                        type == CommandType.StoredProcedure
                        && reader.FieldCount == 1
                        && reader.GetDataTypeName(0) == "refcursor"
                    )
                    {
                        // When a function returns a sole column of refcursor, transparently
                        // FETCH ALL from every such cursor and return those results.
                        StringWriter sw = new StringWriter();
                        string queryText;

                        while (reader.Read())
                        {
                            sw.WriteLine("FETCH ALL FROM \"{0}\";", reader.GetString(0));
                        }

                        reader.Dispose();

                        queryText = sw.ToString();

                        if (queryText == "")
                        {
                            queryText = ";";
                        }

                        // Passthrough the commandtimeout to the inner command, so user can also control its timeout.
                        // TODO: Check if there is a better way to handle that.

                        query = new NpgsqlQuery(m_Connector, queryText);

                        // Write the Query message to the wire.
                        m_Connector.Query(query);

                        // Flush and wait for responses.
                        responseEnum = m_Connector.ProcessBackendResponsesEnum();

                        // Construct the return reader.
                        reader = new ForwardsOnlyDataReader(
                            responseEnum,
                            cb,
                            this,
                            m_Connector.BlockNotificationThread()
                        );
                    }
                }
                else
                {
                    bool sendPortalDescribe = ! portalDescribeSent;

                    // Update the Bind object with current parameter data as needed.
                    BindParameters();

                    // Write the Bind message to the wire.
                    m_Connector.Bind(bind);

                    if (sendPortalDescribe)
                    {
                        NpgsqlDescribe portalDescribe = new NpgsqlDescribePortal(bind.PortalName);

                        // Write a Describe message to the wire.
                        m_Connector.Describe(portalDescribe);

                        portalDescribeSent = true;
                    }

                    // Finally, write the Execute and Sync messages to the wire.
                    m_Connector.Execute(execute);
                    m_Connector.Sync();

                    // Flush and wait for responses.
                    responseEnum = m_Connector.ProcessBackendResponsesEnum();

                    // Construct the return reader, possibly with a saved row description.
                    reader = new ForwardsOnlyDataReader(
                        responseEnum,
                        cb,
                        this,
                        m_Connector.BlockNotificationThread(),
                        true,
                        currentRowDescription
                    );

                    if (sendPortalDescribe)
                    {
                        // We sent a Describe message. If the query produces a result set,
                        // PG sent a row description, and the reader has now found it,
                        currentRowDescription = reader.CurrentDescription;
                    }
                }

                return reader;
            }
        }
예제 #37
0
 public override void SetRowDescription(NpgsqlRowDescription rowDesc)
 {
     _rowDesc = rowDesc;
     _nullMap = new NullMap(rowDesc, Stream);
 }
        private void FillSchemaTable_v2(DataTable schema)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, "FillSchemaTable_v2");
            NpgsqlRowDescription rd      = _currentResultset.RowDescription;
            ArrayList            keyList = null;

            if ((_behavior & CommandBehavior.KeyInfo) == CommandBehavior.KeyInfo)
            {
                keyList = GetPrimaryKeys(GetTableNameFromQuery());
            }

            DataRow row;

            for (Int16 i = 0; i < rd.NumFields; i++)
            {
                row = schema.NewRow();

                row["ColumnName"]    = GetName(i);
                row["ColumnOrdinal"] = i + 1;
                if (rd[i].type_modifier != -1 && rd[i].type_info != null && (rd[i].type_info.Name == "varchar" || rd[i].type_info.Name == "bpchar"))
                {
                    row["ColumnSize"] = rd[i].type_modifier - 4;
                }
                else if (rd[i].type_modifier != -1 && rd[i].type_info != null && (rd[i].type_info.Name == "bit" || rd[i].type_info.Name == "varbit"))
                {
                    row["ColumnSize"] = rd[i].type_modifier;
                }
                else
                {
                    row["ColumnSize"] = (int)rd[i].type_size;
                }
                if (rd[i].type_modifier != -1 && rd[i].type_info != null && rd[i].type_info.Name == "numeric")
                {
                    row["NumericPrecision"] = ((rd[i].type_modifier - 4) >> 16) & ushort.MaxValue;
                    row["NumericScale"]     = (rd[i].type_modifier - 4) & ushort.MaxValue;
                }
                else
                {
                    row["NumericPrecision"] = 0;
                    row["NumericScale"]     = 0;
                }
                row["IsUnique"]        = false;
                row["IsKey"]           = IsKey(GetName(i), keyList);
                row["BaseCatalogName"] = "";
                row["BaseSchemaName"]  = "";
                row["BaseTableName"]   = "";
                row["BaseColumnName"]  = GetName(i);
                row["DataType"]        = GetFieldType(i);
                row["AllowDBNull"]     = IsNullable(null, i);
                if (rd[i].type_info != null)
                {
                    row["ProviderType"] = rd[i].type_info.Name;
                }
                row["IsAliased"]       = false;
                row["IsExpression"]    = false;
                row["IsIdentity"]      = false;
                row["IsAutoIncrement"] = false;
                row["IsRowVersion"]    = false;
                row["IsHidden"]        = false;
                row["IsLong"]          = false;
                row["IsReadOnly"]      = false;

                schema.Rows.Add(row);
            }
        }
 public NpgsqlBinaryRow(NpgsqlRowDescription rowDesc)
     : base(rowDesc, ProtocolVersion.Version2)
 {
     NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
 }
예제 #40
0
 public NpgsqlResultSet(NpgsqlRowDescription rowDesc, ArrayList data)
 {
     this.row_desc = rowDesc;
     this.data = data;
 }
        private void PrepareInternal()
        {
            if (m_Connector.BackendProtocolVersion == ProtocolVersion.Version2)
            {
                planName            = Connector.NextPlanName();
                preparedCommandText = GetCommandText(true, false);

                ExecuteBlind(m_Connector, preparedCommandText);
                prepared = PrepareStatus.V2Prepared;

                // Tell to mediator what command is being sent.
                m_Connector.Mediator.SetSqlSent(preparedCommandText, NpgsqlMediator.SQLSentType.Prepare);
            }
            else
            {
                // Use the extended query parsing...
                planName = m_Connector.NextPlanName();
                String portalName = "";

                preparedCommandText = GetCommandText(true, true);
                NpgsqlParse    parse             = new NpgsqlParse(planName, preparedCommandText, new Int32[] { });
                NpgsqlDescribe statementDescribe = new NpgsqlDescribeStatement(planName);
                IEnumerable <IServerResponseObject> responseEnum;
                NpgsqlRowDescription returnRowDesc = null;

                // Write Parse, Describe, and Sync messages to the wire.
                m_Connector.Parse(parse);
                m_Connector.Describe(statementDescribe);
                m_Connector.Sync();

                // Tell to mediator what command is being sent.
                m_Connector.Mediator.SetSqlSent(preparedCommandText, NpgsqlMediator.SQLSentType.Parse);

                // Flush and wait for response.
                responseEnum = m_Connector.ProcessBackendResponsesEnum();

                // Look for a NpgsqlRowDescription in the responses, discarding everything else.
                foreach (IServerResponseObject response in responseEnum)
                {
                    if (response is NpgsqlRowDescription)
                    {
                        returnRowDesc = (NpgsqlRowDescription)response;
                    }
                    else if (response is IDisposable)
                    {
                        (response as IDisposable).Dispose();
                    }
                }

                Int16[] resultFormatCodes;

                if (returnRowDesc != null)
                {
                    resultFormatCodes = new Int16[returnRowDesc.NumFields];

                    for (int i = 0; i < returnRowDesc.NumFields; i++)
                    {
                        NpgsqlRowDescription.FieldData returnRowDescData = returnRowDesc[i];

                        if (returnRowDescData.TypeInfo != null)
                        {
                            // Binary format?
                            // PG always defaults to text encoding.  We can fix up the row description
                            // here based on support for binary encoding.  Once this is done,
                            // there is no need to request another row description after Bind.
                            returnRowDescData.FormatCode = returnRowDescData.TypeInfo.SupportsBinaryBackendData ? FormatCode.Binary : FormatCode.Text;
                            resultFormatCodes[i]         = (Int16)returnRowDescData.FormatCode;
                        }
                        else
                        {
                            // Text format (default).
                            resultFormatCodes[i] = (Int16)FormatCode.Text;
                        }
                    }
                }
                else
                {
                    resultFormatCodes = new Int16[] { 0 };
                }

                // Save the row description for use with all future Executes.
                currentRowDescription = returnRowDesc;

                // The Bind and Execute message objects live through multiple Executes.
                // Only Bind changes at all between Executes, which is done in BindParameters().
                bind    = new NpgsqlBind(portalName, planName, new Int16[Parameters.Count], null, resultFormatCodes);
                execute = new NpgsqlExecute(portalName, 0);

                prepared = PrepareStatus.V3Prepared;
            }
        }
예제 #42
0
 public void SetRowDescription(NpgsqlRowDescription rowDescr)
 {
     _reader.SetRowDescription(rowDescr);
 }
예제 #43
0
        /// <summary>
        /// Advances the data reader to the next result, when multiple result sets were returned by the PostgreSQL backend.
        /// </summary>
        /// <returns>True if the reader was advanced, otherwise false.</returns>
        private NpgsqlRowDescription GetNextRowDescription()
        {
            if ((_behavior & CommandBehavior.SingleResult) != 0 && CurrentDescription != null)
            {
                CleanUp(false);
                return null;
            }
            NpgsqlRowDescription rd = _pendingDescription;
            while (rd == null)
            {
                object objNext = GetNextResponseObject();
                if (objNext == null)
                {
                    break;
                }
                if (objNext is NpgsqlRow)
                {
                    (objNext as NpgsqlRow).Dispose();
                }

                rd = objNext as NpgsqlRowDescription;
            }

            _pendingDescription = null;

            // If there were records affected before,  keep track of their values.
            if (_recordsAffected != null)
                _recordsAffected += (_nextRecordsAffected ?? 0);
            else
                _recordsAffected = _nextRecordsAffected;

            _nextRecordsAffected = null;
            LastInsertedOID = _nextInsertOID;
            _nextInsertOID = null;
            return rd;
        }
예제 #44
0
 public virtual void SetRowDescription(NpgsqlRowDescription rowDesc)
 {
     _rowDesc = rowDesc;
 }
 public NpgsqlResultSet(NpgsqlRowDescription rowDesc, ArrayList data)
 {
     this.row_desc = rowDesc;
     this.data     = data;
 }
        private readonly Int16        READ_BUFFER_SIZE = 300; //[FIXME] Is this enough??

        public NpgsqlAsciiRow(NpgsqlRowDescription rowDesc, ProtocolVersion protocolVersion)
                : base(rowDesc, protocolVersion)
        {
            NpgsqlEventLog.LogMethodEnter(LogLevel.Debug, CLASSNAME, CLASSNAME);
        }