public async Task Run() { using var _ = _client; using var messageBuilder = new MessageBuilder(); Stream stream = _client.GetStream(); stream = await HandleInitialMessage(stream, messageBuilder); var reader = PipeReader.Create(stream); var writer = PipeWriter.Create(stream); if (_clientOptions == null) //TODO pfyasu maybe unused when cancel message will be implemented { return; } if (_clientOptions.TryGetValue("database", out string databaseName) == false) { await writer.WriteAsync(messageBuilder.ErrorResponse( PgSeverity.Fatal, PgErrorCodes.ConnectionFailure, "Failed to connect to database", "Missing database name in the connection string"), _token); return; } var database = await _databasesLandlord.TryGetOrCreateResourceStore(databaseName); if (database == null) { await writer.WriteAsync(messageBuilder.ErrorResponse( PgSeverity.Fatal, PgErrorCodes.ConnectionFailure, "Failed to connect to database", $"Database '{databaseName}' does not exist"), _token); return; } string username = null; try { username = _clientOptions["user"]; using var transaction = new PgTransaction(database, new MessageReader(), username); if (_serverCertificate != null) { // Authentication is required only when running in secured mode await writer.WriteAsync(messageBuilder.AuthenticationCleartextPassword(), _token); var authMessage = await transaction.MessageReader.GetUninitializedMessage(reader, _token); await authMessage.Init(transaction.MessageReader, reader, _token); await authMessage.Handle(transaction, messageBuilder, reader, writer, _token); } else { await writer.WriteAsync(messageBuilder.AuthenticationOk(), _token); } await writer.WriteAsync(messageBuilder.ParameterStatusMessages(PgConfig.ParameterStatusList), _token); await writer.WriteAsync(messageBuilder.BackendKeyData(_processId, _identifier), _token); await writer.WriteAsync(messageBuilder.ReadyForQuery(transaction.State), _token); while (_token.IsCancellationRequested == false) { var message = await transaction.MessageReader.GetUninitializedMessage(reader, _token); try { await message.Init(transaction.MessageReader, reader, _token); await message.Handle(transaction, messageBuilder, reader, writer, _token); } catch (PgErrorException e) { await message.HandleError(e, transaction, messageBuilder, writer, _token); } } } catch (PgFatalException e) { if (Logger.IsInfoEnabled) { Logger.Info($"{e.Message} (fatal pg error code {e.ErrorCode}). {GetSourceConnectionDetails(username)}", e); } await writer.WriteAsync(messageBuilder.ErrorResponse( PgSeverity.Fatal, e.ErrorCode, e.Message, e.ToString()), _token); } catch (PgErrorException e) { if (Logger.IsInfoEnabled) { Logger.Info($"{e.Message} (pg error code {e.ErrorCode}). {GetSourceConnectionDetails(username)}", e); } // Shouldn't get to this point, PgErrorExceptions shouldn't be fatal await writer.WriteAsync(messageBuilder.ErrorResponse( PgSeverity.Error, e.ErrorCode, e.Message, e.ToString()), _token); } catch (PgTerminateReceivedException) { // Terminate silently } catch (QueryParser.ParseException e) { if (Logger.IsInfoEnabled) { Logger.Info("Invalid RQL query", e); } try { await writer.WriteAsync(messageBuilder.ErrorResponse( PgSeverity.Error, PgErrorCodes.InvalidSqlStatementName, e.ToString()), _token); } catch (Exception) { // ignored } } catch (Exception e) { if (Logger.IsInfoEnabled) { Logger.Info($"Unexpected internal pg error. {GetSourceConnectionDetails(username)}", e); } try { await writer.WriteAsync(messageBuilder.ErrorResponse( PgSeverity.Fatal, PgErrorCodes.InternalError, e.ToString()), _token); } catch (Exception) { // ignored } } }