Skip to content

v8.0.3 NpgsqlBinaryImporter.Write<T>(T value) throws InvalidOperationException on nullable column #5716

@B-e-l-y

Description

@B-e-l-y

Steps to reproduce

Test code:

using Npgsql;
using System.Data;

namespace NpgsqlBinaryImporterTest
{
    internal class Program
    {
        static void Main(string[] args)
        {
            if (args.Length == 0)
            {
                Console.WriteLine("Connection string argument missing");
                return;
            }

            using var connection = new NpgsqlConnection(args[0]);
            connection.Open();

            // create table
            using var command = new NpgsqlCommand("drop table if exists test; create table test(id int not null, name text);", connection);
            command.ExecuteNonQuery();

            // get table structure
            var table = new DataTable();
            using var adapter = new NpgsqlDataAdapter("select * from test", connection);
            adapter.FillSchema(table, SchemaType.Mapped);

            // fill data
            table.Rows.Add(1, DBNull.Value);
            table.Rows.Add(2, "test");

            // write data
            try
            {
                WriteTable(connection, table);

                Console.WriteLine("Ok");
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        public static void WriteTable(NpgsqlConnection connection, DataTable table)
        {
            if (table.Rows.Count > 0)
            {
                var columns = table.Columns.Cast<DataColumn>().Select(p => p.ColumnName).ToArray();
                using var importer = connection.BeginBinaryImport("copy " + table.TableName + " (" + string.Join(",", columns) + ") from stdin (format binary)");
                importer.Timeout = TimeSpan.Zero;

                foreach (DataRow row in table.Select())
                {
                    importer.StartRow();
                    foreach (var column in columns)
                        importer.Write(row[column]);
                }

                importer.Complete();
                importer.Close();
            }
        }
    }
}

The issue

Starting from version 8.0.3, when attempting to write a NOT NULL value to a nullable column, the NpgsqlBinaryImporter.Write(T value) method may throw an InvalidOperationException.
An exception is only thrown if the first row contained a NULL value for that column.
This did not happen in previous versions.

Exception message:

System.InvalidOperationException: Write for column 1 resolves to a different PostgreSQL type: OID 25 than the first row resolved to (OID 0). Please make sure to use clr types that resolve to the same PostgreSQL type across rows. Alternatively pass the same NpgsqlDbType or DataTypeName to ensure the PostgreSQL type ends up to be identical.
   at Npgsql.NpgsqlBinaryImporter.<Write>g__Core|26_0[T](Boolean async, T value, Nullable`1 npgsqlDbType, String dataTypeName, CancellationToken cancellationToken)
   at Npgsql.NpgsqlBinaryImporter.Write[T](T value)
   at NpgsqlBinaryImporterTest.Program.WriteTable(NpgsqlConnection connection, DataTable table) in D:\Projects\Lotrack\[CrossPlatform]\Tests\NpgsqlBinaryImporterTest\Program.cs:line 57
   at NpgsqlBinaryImporterTest.Program.Main(String[] args) in D:\Projects\Lotrack\[CrossPlatform]\Tests\NpgsqlBinaryImporterTest\Program.cs:line 35

Further technical details

Npgsql version: 8.0.3
PostgreSQL version: 13.2
Operating system: Windows 10

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions