1
- // Copyright (C) 2009-2021 Xtensive LLC.
1
+ // Copyright (C) 2009-2025 Xtensive LLC.
2
2
// This code is distributed under MIT license terms.
3
3
// See the License.txt file in the project root for more information.
4
4
// Created by: Denis Krjuchkov
@@ -23,6 +23,9 @@ public class DriverFactory : SqlDriverFactory
23
23
{
24
24
private const string DatabaseAndSchemaQuery = "select current_database(), current_schema()" ;
25
25
26
+ private readonly static bool InfinityAliasForDatesEnabled ;
27
+ private readonly static bool LegacyTimestamptBehaviorEnabled ;
28
+
26
29
/// <inheritdoc/>
27
30
[ SecuritySafeCritical ]
28
31
protected override string BuildConnectionString ( UrlInfo url )
@@ -44,9 +47,6 @@ protected override string BuildConnectionString(UrlInfo url)
44
47
builder . Username = url . User ;
45
48
builder . Password = url . Password ;
46
49
}
47
- else {
48
- builder . IntegratedSecurity = true ;
49
- }
50
50
51
51
// custom options
52
52
foreach ( var param in url . Params ) {
@@ -67,13 +67,18 @@ protected override SqlDriver CreateDriver(string connectionString, SqlDriverConf
67
67
OpenConnectionFast ( connection , configuration , false ) . GetAwaiter ( ) . GetResult ( ) ;
68
68
var version = GetVersion ( configuration , connection ) ;
69
69
var defaultSchema = GetDefaultSchema ( connection ) ;
70
- return CreateDriverInstance ( connectionString , version , defaultSchema ) ;
70
+ var defaultTimeZoneInfo = PostgreSqlHelper . GetTimeZoneInfoForServerTimeZone ( connection . Timezone ) ;
71
+ return CreateDriverInstance ( connectionString , version , defaultSchema , defaultTimeZoneInfo ) ;
71
72
}
72
73
73
74
/// <inheritdoc/>
74
75
protected override async Task < SqlDriver > CreateDriverAsync (
75
76
string connectionString , SqlDriverConfiguration configuration , CancellationToken token )
76
77
{
78
+ // these settings needed to be read before any connection happens
79
+ var useInfinityAliasForDateTime = InfinityAliasForDatesEnabled ;
80
+ var legacyTimestampBehavior = LegacyTimestamptBehaviorEnabled ;
81
+
77
82
var connection = new NpgsqlConnection ( connectionString ) ;
78
83
await using ( connection . ConfigureAwait ( false ) ) {
79
84
if ( configuration . DbConnectionAccessors . Count > 0 )
@@ -82,7 +87,8 @@ protected override async Task<SqlDriver> CreateDriverAsync(
82
87
await OpenConnectionFast ( connection , configuration , true , token ) . ConfigureAwait ( false ) ;
83
88
var version = GetVersion ( configuration , connection ) ;
84
89
var defaultSchema = await GetDefaultSchemaAsync ( connection , token : token ) . ConfigureAwait ( false ) ;
85
- return CreateDriverInstance ( connectionString , version , defaultSchema ) ;
90
+ var defaultTimeZoneInfo = PostgreSqlHelper . GetTimeZoneInfoForServerTimeZone ( connection . Timezone ) ;
91
+ return CreateDriverInstance ( connectionString , version , defaultSchema , defaultTimeZoneInfo ) ;
86
92
}
87
93
}
88
94
@@ -95,7 +101,8 @@ private static Version GetVersion(SqlDriverConfiguration configuration, NpgsqlCo
95
101
}
96
102
97
103
private static SqlDriver CreateDriverInstance (
98
- string connectionString , Version version , DefaultSchemaInfo defaultSchema )
104
+ string connectionString , Version version , DefaultSchemaInfo defaultSchema ,
105
+ TimeZoneInfo defaultTimeZone )
99
106
{
100
107
var coreServerInfo = new CoreServerInfo {
101
108
ServerVersion = version ,
@@ -105,20 +112,26 @@ private static SqlDriver CreateDriverInstance(
105
112
DefaultSchemaName = defaultSchema . Schema ,
106
113
} ;
107
114
115
+ var pgsqlServerInfo = new PostgreServerInfo ( ) {
116
+ InfinityAliasForDatesEnabled = InfinityAliasForDatesEnabled ,
117
+ LegacyTimestampBehavior = LegacyTimestamptBehaviorEnabled ,
118
+ DefaultTimeZone = defaultTimeZone
119
+ } ;
120
+
108
121
if ( version . Major < 8 || ( version . Major == 8 && version . Minor < 3 ) ) {
109
122
throw new NotSupportedException ( Strings . ExPostgreSqlBelow83IsNotSupported ) ;
110
123
}
111
124
112
125
// We support 8.3, 8.4 and any 9.0+
113
126
114
127
return version . Major switch {
115
- 8 when version . Minor == 3 => new v8_3 . Driver ( coreServerInfo ) ,
116
- 8 when version . Minor > 3 => new v8_4 . Driver ( coreServerInfo ) ,
117
- 9 when version . Minor == 0 => new v9_0 . Driver ( coreServerInfo ) ,
118
- 9 when version . Minor > 0 => new v9_1 . Driver ( coreServerInfo ) ,
119
- 10 => new v10_0 . Driver ( coreServerInfo ) ,
120
- 11 => new v10_0 . Driver ( coreServerInfo ) ,
121
- _ => new v12_0 . Driver ( coreServerInfo )
128
+ 8 when version . Minor == 3 => new v8_3 . Driver ( coreServerInfo , pgsqlServerInfo ) ,
129
+ 8 when version . Minor > 3 => new v8_4 . Driver ( coreServerInfo , pgsqlServerInfo ) ,
130
+ 9 when version . Minor == 0 => new v9_0 . Driver ( coreServerInfo , pgsqlServerInfo ) ,
131
+ 9 when version . Minor > 0 => new v9_1 . Driver ( coreServerInfo , pgsqlServerInfo ) ,
132
+ 10 => new v10_0 . Driver ( coreServerInfo , pgsqlServerInfo ) ,
133
+ 11 => new v10_0 . Driver ( coreServerInfo , pgsqlServerInfo ) ,
134
+ _ => new v12_0 . Driver ( coreServerInfo , pgsqlServerInfo )
122
135
} ;
123
136
}
124
137
@@ -188,5 +201,58 @@ await SqlHelper.NotifyConnectionInitializingAsync(accessors,
188
201
}
189
202
}
190
203
}
204
+
205
+ #region Helpers
206
+
207
+ private static bool SetOrGetExistingDisableInfinityAliasForDatesSwitch ( bool valueToSet ) =>
208
+ GetSwitchValueOrSet ( Orm . PostgreSql . WellKnown . DateTimeToInfinityConversionSwitchName , valueToSet ) ;
209
+
210
+ private static bool SetOrGetExistingLegacyTimeStampBehaviorSwitch ( bool valueToSet ) =>
211
+ GetSwitchValueOrSet ( Orm . PostgreSql . WellKnown . LegacyTimestampBehaviorSwitchName , valueToSet ) ;
212
+
213
+ private static bool GetSwitchValueOrSet ( string switchName , bool valueToSet )
214
+ {
215
+ if ( ! AppContext . TryGetSwitch ( switchName , out var currentValue ) ) {
216
+ AppContext . SetSwitch ( switchName , valueToSet ) ;
217
+ return valueToSet ;
218
+ }
219
+ else {
220
+ return currentValue ;
221
+ }
222
+ }
223
+
224
+ #endregion
225
+
226
+ static DriverFactory ( )
227
+ {
228
+ // Starging from Npgsql 6.0 they broke compatibility by forcefully replacing
229
+ // DateTime.MinValue/MaxValue of parameters with -Infinity and Infinity values.
230
+ // This new "feature", though doesn't affect reading/writing of values and equality/inequality
231
+ // filters, breaks some of operations such as parts extraction, default values for columns
232
+ // (which are constants and declared on high levels of abstraction) and some others.
233
+
234
+ // We turn it off to make current code work as before and make current data of
235
+ // the user be compatible with algorighms as long as possible.
236
+ // But if the user sets the switch then we work with what we have.
237
+ // Usage of such aliases makes us to create extra statements in SQL queries to provide
238
+ // the same results the queries which are already written, which may make queries a bit slower.
239
+
240
+ // DO NOT REPLACE method call with constant value when debugging, CHANGE THE PARAMETER VALUE.
241
+ InfinityAliasForDatesEnabled = ! SetOrGetExistingDisableInfinityAliasForDatesSwitch ( valueToSet : true ) ;
242
+
243
+ // Legacy timestamp behavoir turns off certain parameter value binding requirements
244
+ // and makes Npgsql work like v4 or older.
245
+ // Current behavior require manual specification of unspecified kind for DateTime values,
246
+ // because Local or Utc kind now meand that underlying type of value to Timestamp without time zone
247
+ // and Timestamp with time zone respectively.
248
+ // It also affects DateTimeOffsets, now there is a requirement to move timezone of value to Utc
249
+ // this forces us to use only local timezone when reading values, which basically ignores
250
+ // Postgre's setting SET TIME ZONE for database session.
251
+
252
+ // We have to use current mode, not the legacy one, because there is a chance of legacy mode elimination.
253
+
254
+ // DO NOT REPLACE method call with constant value when debugging, CHANGE THE PARAMETER VALUE.
255
+ LegacyTimestamptBehaviorEnabled = SetOrGetExistingLegacyTimeStampBehaviorSwitch ( valueToSet : false ) ;
256
+ }
191
257
}
192
258
}
0 commit comments