Reputation: 22116
If I understand correctly NpgsqlCopyIn with NpgsqlCopySerializer should work something like this:
var conn = new NpgsqlConnection(ConfigurationManager.ConnectionStrings["PostgreSqlDb"].ConnectionString);
conn.Open();
var tran = conn.BeginTransaction();
var cmd = new NpgsqlCommand("COPY address (id, employee, value) FROM STDIN", conn);
var npgsqlCopySerializer = new NpgsqlCopySerializer(conn);
var npgsqlCopyIn = new NpgsqlCopyIn(cmd, conn, npgsqlCopySerializer.ToStream);
try
{
npgsqlCopyIn.Start();
npgsqlCopySerializer.AddInt32(300);
npgsqlCopySerializer.AddInt32(1);
npgsqlCopySerializer.AddString("address");
npgsqlCopySerializer.EndRow();
npgsqlCopySerializer.Flush();
npgsqlCopySerializer.AddInt32(301);
npgsqlCopySerializer.AddInt32(1);
npgsqlCopySerializer.AddString("another\r\naddress");
npgsqlCopySerializer.EndRow();
npgsqlCopySerializer.Flush();
npgsqlCopyIn.End();
tran.Commit();
}
//catch (Exception e)
//{
// tran.Rollback();
// throw;
//}
finally
{
conn.Close();
}
Problem is that each time there are not allowed characters in AddString()
it throws an ArgumentOutOfRangeException
inside that method, otherwise it works.
For example:
npgsqlCopySerializer.AddString("another\r\naddress");
will throw the exception cause it contains a newline which has a special meaning in copy from text format (row separator) and should be escaped.
Anyone know what I can do to make it work? I searched for examples on the internet but I couldn't find anything.
Thanks for your help!
Upvotes: 0
Views: 4505
Reputation: 61
I'm the person who reported the bug, coincidentally only a few days ago.
Would you mind posting the XML you're trying to insert? I have tried it with an OSM result: http://nominatim.openstreetmap.org/search.php?q=A7&viewbox=3.96%2C52.82%2C7.93%2C51.11&format=xml
And a rather large web.config file, both work flawlessly. So either I made a copy / paste error while submitting my fix, or the XML you're trying to insert is different than the XML I tried.
Also: do you get the exact same error as before (i.e., argument out of range)? The default buffer size is only 8k, which wasn't enough in my case.
I don't know if it makes any difference, but I didn't use flush at all:
NpgsqlConnection Conn = new NpgsqlConnection(getPostgresConnString());
Conn.Open();
NpgsqlCopyIn copyIn = new NpgsqlCopyIn("COPY table (col1,col2,col2) FROM STDIN;", Conn);
copyIn.Start();
NpgsqlCopySerializer cs1 = new NpgsqlCopySerializer(pConn2);
cs1.AddString(System.IO.File.ReadAllText("C:\\test\\Web.config"));
[...]
cs1.EndRow();
cs1.Close();
copyIn.End();
Upvotes: 2
Reputation: 6830
To quote from the documentation:
It is strongly recommended that applications generating COPY data convert data newlines and carriage returns to the \n and \r sequences respectively. At present it is possible to represent a data carriage return by a backslash and carriage return, and to represent a data newline by a backslash and newline.
So I would say the following will work:
npgsqlCopySerializer.AddString("another\\\r\\\naddress");
EDIT: I tried it for myself and there seems to be a bug in NpgsqlCopySerializer.AddString()
:
if (escapeAt > bufferedUpto)
{
int encodedLength = ENCODING_UTF8.GetByteCount(fieldValue.ToCharArray(bufferedUpto, escapeAt));
MakeRoomForBytes(encodedLength);
_sendBufferAt += ENCODING_UTF8.GetBytes(fieldValue, bufferedUpto, escapeAt, _sendBuffer, _sendBufferAt);
bufferedUpto = escapeAt;
}
The second line throws the ArgumentOutOfRangeException
after the two escape sequences (\r
and \n
) are processed and added to the output buffer, since at that moment bufferedUpto == 9
and escapeAt == "another\r\naddress".Length == 16
Now I even found this bug reported at the Npgsql tracker.
Upvotes: 2