Skip to content

Fix support for Npgsql6 provider #3064

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 12, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 17 additions & 3 deletions src/NHibernate/Driver/NpgsqlDriver.cs
Original file line number Diff line number Diff line change
Expand Up @@ -65,19 +65,33 @@ public override IResultSetsCommand GetResultSetsCommand(Engine.ISessionImplement

protected override void InitializeParameter(DbParameter dbParam, string name, SqlTypes.SqlType sqlType)
{
base.InitializeParameter(dbParam, name, sqlType);
if (sqlType == null)
throw new QueryException($"No type assigned to parameter '{name}'");

// Since the .NET currency type has 4 decimal places, we use a decimal type in PostgreSQL instead of its native 2 decimal currency type.
dbParam.ParameterName = FormatNameForParameter(name);
if (sqlType.DbType == DbType.Currency)
{
// Since the .NET currency type has 4 decimal places, we use a decimal type in PostgreSQL instead of its native 2 decimal currency type.
dbParam.DbType = DbType.Decimal;
}
else if (DriverVersionMajor < 6 || sqlType.DbType != DbType.DateTime)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mr. Smarty Pants.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi!
I am sorry, it seems theese changes leads to an error in some cases.

Versions:

  • NHibernate 5.4.2
  • Npgsql 7.0.2

The named query:

	<sql-query name="MyQuery" cache-mode="normal" read-only="true">
	  <query-param type="DateTime" name="DateOfSearch"/>
	  <return-scalar type="Int64" column="SomeID"/>
	  <![CDATA[select ...
	        from ...
	        where ((  :DateOfSearch is null ) or (( t.DT1 <= :DateOfSearch) and ( t.DT2 >= :DateOfSearch )))
	        and ... ;]]>
	</sql-query>
	</hibernate-mapping>

Call the query:

	DateTime? dateOfSearch = null; // set null value here -- !!!!
	query.SetParameter("DateOfSearch", dateOfSearch, NHibernateUtil.DateTime);
	var result = query.List<long>();

NHibernate log:

	2023-04-21 23:01:51,433 [1] DEBUG NHibernate.Type.DateTimeType - binding null to parameter: 0
	2023-04-21 23:01:51,433 [1] DEBUG NHibernate.Type.DateTimeType - binding null to parameter: 1
	2023-04-21 23:01:51,434 [1] DEBUG NHibernate.Type.DateTimeType - binding null to parameter: 2
	2023-04-21 23:01:51,445 [1] DEBUG NHibernate.SQL - select ...
	        from ...
	        where ((  :p0 is null ) or (( mmh.DT_Mount <= :p0) and ( mmh.DT_Dismount >= :p0 ))); :p0 = NULL [Type: Object (0:0:0)]  -- !!!!
	...
	2023-04-21 23:01:51,623 [1] ERROR NHibernate.AdoNet.AbstractBatcher - Could not execute query: select ...

dbParam.DBType is empty, and Npgsql sends Prepare command to PostgreSQL with no parameter type specified, but PostgreSQL also can not guess the type from this query and value.
It works correctly, if I set non-null parameter value.

Copy link
Member

@fredericDelaporte fredericDelaporte May 25, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That point has been fixed by #3299.

{
dbParam.DbType = sqlType.DbType;
}
else
{
// Let Npgsql 6 driver to decide parameter type
}
}

// Prior to v3, Npgsql was expecting DateTime for time.
// https://github.com/npgsql/npgsql/issues/347
public override bool RequiresTimeSpanForTime => (DriverVersion?.Major ?? 3) >= 3;
public override bool RequiresTimeSpanForTime => DriverVersionMajor >= 3;

public override bool HasDelayedDistributedTransactionCompletion => true;

System.Type IEmbeddedBatcherFactoryProvider.BatcherFactoryClass => typeof(GenericBatchingBatcherFactory);

private int DriverVersionMajor => DriverVersion?.Major ?? 3;
}
}