Skip to content
Permalink
Browse files

Import/export breaks connection when wrong mode is used

  • Loading branch information...
afkos authored and YohDeadfall committed Mar 13, 2019
1 parent 9cf5ba4 commit c1bc4d3d3bb7f1f906ab52392f815ed08ce681f1
@@ -48,37 +48,32 @@ internal NpgsqlBinaryExporter(NpgsqlConnector connector, string copyToCommand)
_columnLen = int.MinValue; // Mark that the (first) column length hasn't been read yet
_column = -1;

try
{
_connector.SendQuery(copyToCommand);
_connector.SendQuery(copyToCommand);

CopyOutResponseMessage copyOutResponse;
var msg = _connector.ReadMessage();
switch (msg.Code)
CopyOutResponseMessage copyOutResponse;
var msg = _connector.ReadMessage();
switch (msg.Code)
{
case BackendMessageCode.CopyOutResponse:
copyOutResponse = (CopyOutResponseMessage)msg;
if (!copyOutResponse.IsBinary)
{
case BackendMessageCode.CopyOutResponse:
copyOutResponse = (CopyOutResponseMessage)msg;
if (!copyOutResponse.IsBinary)
throw new ArgumentException("copyToCommand triggered a text transfer, only binary is allowed", nameof(copyToCommand));
break;
case BackendMessageCode.CompletedResponse:
throw new InvalidOperationException(
"This API only supports import/export from the client, i.e. COPY commands containing TO/FROM STDIN. " +
"To import/export with files on your PostgreSQL machine, simply execute the command with ExecuteNonQuery. " +
"Note that your data has been successfully imported/exported.");
default:
throw _connector.UnexpectedMessageReceived(msg.Code);
_connector.Break();
throw new ArgumentException("copyToCommand triggered a text transfer, only binary is allowed", nameof(copyToCommand));
}

NumColumns = copyOutResponse.NumColumns;
_typeHandlerCache = new NpgsqlTypeHandler[NumColumns];
ReadHeader();
}
catch
{
_connector.Break();
throw;
break;
case BackendMessageCode.CompletedResponse:
throw new InvalidOperationException(
"This API only supports import/export from the client, i.e. COPY commands containing TO/FROM STDIN. " +
"To import/export with files on your PostgreSQL machine, simply execute the command with ExecuteNonQuery. " +
"Note that your data has been successfully imported/exported.");
default:
throw _connector.UnexpectedMessageReceived(msg.Code);
}

NumColumns = copyOutResponse.NumColumns;
_typeHandlerCache = new NpgsqlTypeHandler[NumColumns];
ReadHeader();
}

void ReadHeader()
@@ -51,18 +51,19 @@ internal NpgsqlBinaryImporter(NpgsqlConnector connector, string copyFromCommand)
_buf = connector.WriteBuffer;
_column = -1;

try
{
_connector.SendQuery(copyFromCommand);
_connector.SendQuery(copyFromCommand);

CopyInResponseMessage copyInResponse;
var msg = _connector.ReadMessage();
switch (msg.Code)
{
CopyInResponseMessage copyInResponse;
var msg = _connector.ReadMessage();
switch (msg.Code)
{
case BackendMessageCode.CopyInResponse:
copyInResponse = (CopyInResponseMessage)msg;
if (!copyInResponse.IsBinary)
{
_connector.Break();
throw new ArgumentException("copyFromCommand triggered a text transfer, only binary is allowed", nameof(copyFromCommand));
}
break;
case BackendMessageCode.CompletedResponse:
throw new InvalidOperationException(
@@ -71,18 +72,12 @@ internal NpgsqlBinaryImporter(NpgsqlConnector connector, string copyFromCommand)
"Note that your data has been successfully imported/exported.");
default:
throw _connector.UnexpectedMessageReceived(msg.Code);
}

NumColumns = copyInResponse.NumColumns;
_params = new NpgsqlParameter[NumColumns];
_buf.StartCopyMode();
WriteHeader();
}
catch
{
_connector.Break();
throw;
}

NumColumns = copyInResponse.NumColumns;
_params = new NpgsqlParameter[NumColumns];
_buf.StartCopyMode();
WriteHeader();
}

void WriteHeader()
@@ -915,7 +915,7 @@ public TextWriter BeginTextImport(string copyFromCommand)
connector.StartUserAction(ConnectorState.Copy);
try
{
var writer = new NpgsqlCopyTextWriter(new NpgsqlRawCopyStream(connector, copyFromCommand));
var writer = new NpgsqlCopyTextWriter(connector, new NpgsqlRawCopyStream(connector, copyFromCommand));
connector.CurrentCopyOperation = writer;
return writer;
}
@@ -949,7 +949,7 @@ public TextReader BeginTextExport(string copyToCommand)
connector.StartUserAction(ConnectorState.Copy);
try
{
var reader = new NpgsqlCopyTextReader(new NpgsqlRawCopyStream(connector, copyToCommand));
var reader = new NpgsqlCopyTextReader(connector, new NpgsqlRawCopyStream(connector, copyToCommand));
connector.CurrentCopyOperation = reader;
return reader;
}
@@ -304,10 +304,13 @@ public override long Position
/// </remarks>
public sealed class NpgsqlCopyTextWriter : StreamWriter, ICancelable
{
internal NpgsqlCopyTextWriter(NpgsqlRawCopyStream underlying) : base(underlying)
internal NpgsqlCopyTextWriter(NpgsqlConnector connector, NpgsqlRawCopyStream underlying) : base(underlying)
{
if (underlying.IsBinary)
{
connector.Break();
throw new Exception("Can't use a binary copy stream for text writing");
}
}

/// <summary>
@@ -327,10 +330,13 @@ public void Cancel()
/// </remarks>
public sealed class NpgsqlCopyTextReader : StreamReader, ICancelable
{
internal NpgsqlCopyTextReader(NpgsqlRawCopyStream underlying) : base(underlying)
internal NpgsqlCopyTextReader(NpgsqlConnector connector, NpgsqlRawCopyStream underlying) : base(underlying)
{
if (underlying.IsBinary)
{
connector.Break();
throw new Exception("Can't use a binary copy stream for text reading");
}
}

/// <summary>
@@ -160,6 +160,39 @@ public void ImportLargeValueRaw()
}
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/2330")]
public void WrongTableDefinitionRawBinaryCopy()
{
using (var conn = OpenConnection())
{
Assert.Throws<PostgresException>(() => conn.BeginRawBinaryCopy("COPY table_is_not_exist (blob) TO STDOUT BINARY"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Open));
Assert.That(conn.ExecuteScalar("SELECT 1"), Is.EqualTo(1));

Assert.Throws<PostgresException>(() => conn.BeginRawBinaryCopy("COPY table_is_not_exist (blob) FROM STDIN BINARY"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Open));
Assert.That(conn.ExecuteScalar("SELECT 1"), Is.EqualTo(1));
}
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/2330")]
public void WrongFormatRawBinaryCopy()
{
using (var conn = OpenConnection())
{
conn.ExecuteNonQuery("create temp table temp_table(blob bytea)");
Assert.Throws<ArgumentException>(() => conn.BeginRawBinaryCopy("COPY temp_table (blob) TO STDOUT"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Broken));
}

using (var conn = OpenConnection())
{
conn.ExecuteNonQuery("create temp table temp_table(blob bytea)");
Assert.Throws<ArgumentException>(() => conn.BeginRawBinaryCopy("COPY temp_table (blob) FROM STDIN"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Broken));
}
}

#endregion

#region Binary
@@ -314,6 +347,52 @@ public void ImportDirectBuffer()
}
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/2330")]
public void WrongTableDefinitionBinaryImport()
{
using (var conn = OpenConnection())
{
// Connection should be kept alive after PostgresException was triggered
Assert.Throws<PostgresException>(() => conn.BeginBinaryImport("COPY table_is_not_exist (blob) FROM STDIN BINARY"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Open));
Assert.That(conn.ExecuteScalar("SELECT 1"), Is.EqualTo(1));
}
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/2330")]
public void WrongFormatBinaryImport()
{
using (var conn = OpenConnection())
{
conn.ExecuteNonQuery("create temp table temp_table(blob bytea)");
Assert.Throws<ArgumentException>(() => conn.BeginBinaryImport("COPY temp_table (blob) FROM STDIN"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Broken));
}
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/2330")]
public void WrongTableDefinitionBinaryExport()
{
using (var conn = OpenConnection())
{
// Connection should be kept alive after PostgresException was triggered
Assert.Throws<PostgresException>(() => conn.BeginBinaryExport("COPY table_is_not_exist (blob) TO STDOUT BINARY"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Open));
Assert.That(conn.ExecuteScalar("SELECT 1"), Is.EqualTo(1));
}
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/2330")]
public void WrongFormatBinaryExport()
{
using (var conn = OpenConnection())
{
conn.ExecuteNonQuery("create temp table temp_table(blob bytea)");
Assert.Throws<ArgumentException>(() => conn.BeginBinaryExport("COPY temp_table (blob) TO STDOUT"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Broken));
}
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/661")]
[Ignore("Unreliable")]
public void UnexpectedExceptionBinaryImport()
@@ -655,6 +734,50 @@ public void DisposeInMiddleOfTextExport()
}
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/2330")]
public void WrongTableDefinitionTextImport()
{
using (var conn = OpenConnection())
{
Assert.Throws<PostgresException>(() => conn.BeginTextImport("COPY table_is_not_exist (blob) FROM STDIN"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Open));
Assert.That(conn.ExecuteScalar("SELECT 1"), Is.EqualTo(1));
}
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/2330")]
public void WrongFormatTextImport()
{
using (var conn = OpenConnection())
{
conn.ExecuteNonQuery("create temp table temp_table(blob bytea)");
Assert.Throws<Exception>(() => conn.BeginTextImport("COPY temp_table (blob) FROM STDIN BINARY"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Broken));
}
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/2330")]
public void WrongTableDefinitionTextExport()
{
using (var conn = OpenConnection())
{
Assert.Throws<PostgresException>(() => conn.BeginTextExport("COPY table_is_not_exist (blob) TO STDOUT"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Open));
Assert.That(conn.ExecuteScalar("SELECT 1"), Is.EqualTo(1));
}
}

[Test, IssueLink("https://github.com/npgsql/npgsql/issues/2330")]
public void WrongFormatTextExport()
{
using (var conn = OpenConnection())
{
conn.ExecuteNonQuery("create temp table temp_table(blob bytea)");
Assert.Throws<Exception>(() => conn.BeginTextExport("COPY temp_table (blob) TO STDOUT BINARY"));
Assert.That(conn.FullState, Is.EqualTo(ConnectionState.Broken));
}
}

#endregion

#region Other

0 comments on commit c1bc4d3

Please sign in to comment.
You can’t perform that action at this time.