11
11
using System ;
12
12
using System . Data ;
13
13
using System . Data . Common ;
14
-
15
14
using NHibernate . Engine ;
16
15
using NHibernate . Exceptions ;
17
16
using NHibernate . Impl ;
@@ -26,88 +25,76 @@ public partial class DbTimestampType : TimestampType
26
25
{
27
26
28
27
/// <inheritdoc />
29
- public override Task < object > SeedAsync ( ISessionImplementor session , CancellationToken cancellationToken )
28
+ public override async Task < object > SeedAsync ( ISessionImplementor session , CancellationToken cancellationToken )
30
29
{
31
- if ( cancellationToken . IsCancellationRequested )
30
+ cancellationToken . ThrowIfCancellationRequested ( ) ;
31
+ if ( session == null )
32
32
{
33
- return Task . FromCanceled < object > ( cancellationToken ) ;
33
+ log . Debug ( "incoming session was null; using current vm time" ) ;
34
+ return await ( base . SeedAsync ( null , cancellationToken ) ) . ConfigureAwait ( false ) ;
34
35
}
35
- try
36
+ else if ( ! session . Factory . Dialect . SupportsCurrentTimestampSelection )
36
37
{
37
- if ( session == null )
38
- {
39
- log . Debug ( "incoming session was null; using current vm time" ) ;
40
- return base . SeedAsync ( null , cancellationToken ) ;
41
- }
42
- else if ( ! session . Factory . Dialect . SupportsCurrentTimestampSelection )
43
- {
44
- log . Debug ( "falling back to vm-based timestamp, as dialect does not support current timestamp selection" ) ;
45
- return base . SeedAsync ( session , cancellationToken ) ;
46
- }
47
- else
48
- {
49
- return GetCurrentTimestampAsync ( session , cancellationToken ) ;
50
- }
38
+ log . Debug ( "falling back to vm-based timestamp, as dialect does not support current timestamp selection" ) ;
39
+ return await ( base . SeedAsync ( session , cancellationToken ) ) . ConfigureAwait ( false ) ;
51
40
}
52
- catch ( Exception ex )
41
+ else
53
42
{
54
- return Task . FromException < object > ( ex ) ;
43
+ return await ( GetCurrentTimestampAsync ( session , cancellationToken ) ) . ConfigureAwait ( false ) ;
55
44
}
56
45
}
57
46
58
- private Task < object > GetCurrentTimestampAsync ( ISessionImplementor session , CancellationToken cancellationToken )
47
+ protected virtual async Task < DateTime > GetCurrentTimestampAsync ( ISessionImplementor session , CancellationToken cancellationToken )
59
48
{
60
- if ( cancellationToken . IsCancellationRequested )
61
- {
62
- return Task . FromCanceled < object > ( cancellationToken ) ;
63
- }
64
- try
65
- {
66
- Dialect . Dialect dialect = session . Factory . Dialect ;
67
- string timestampSelectString = dialect . CurrentTimestampSelectString ;
68
- return UsePreparedStatementAsync ( timestampSelectString , session , cancellationToken ) ;
69
- }
70
- catch ( Exception ex )
71
- {
72
- return Task . FromException < object > ( ex ) ;
73
- }
49
+ cancellationToken . ThrowIfCancellationRequested ( ) ;
50
+ var dialect = session . Factory . Dialect ;
51
+ // Need to round notably for Sql Server DateTime with Odbc, which has a 3.33ms resolution,
52
+ // causing stale data update failure 2/3 of times if not rounded to 10ms.
53
+ return Round (
54
+ await ( UsePreparedStatementAsync ( dialect . CurrentTimestampSelectString , session , cancellationToken ) ) . ConfigureAwait ( false ) ,
55
+ dialect . TimestampResolutionInTicks ) ;
74
56
}
75
57
76
- protected virtual async Task < object > UsePreparedStatementAsync ( string timestampSelectString , ISessionImplementor session , CancellationToken cancellationToken )
58
+ protected virtual async Task < DateTime > UsePreparedStatementAsync ( string timestampSelectString , ISessionImplementor session , CancellationToken cancellationToken )
77
59
{
78
60
cancellationToken . ThrowIfCancellationRequested ( ) ;
79
61
var tsSelect = new SqlString ( timestampSelectString ) ;
80
62
DbCommand ps = null ;
81
63
DbDataReader rs = null ;
82
- using ( new SessionIdLoggingContext ( session . SessionId ) )
83
- try
84
- {
85
- ps = await ( session . Batcher . PrepareCommandAsync ( CommandType . Text , tsSelect , EmptyParams , cancellationToken ) ) . ConfigureAwait ( false ) ;
86
- rs = await ( session . Batcher . ExecuteReaderAsync ( ps , cancellationToken ) ) . ConfigureAwait ( false ) ;
87
- await ( rs . ReadAsync ( cancellationToken ) ) . ConfigureAwait ( false ) ;
88
- DateTime ts = rs . GetDateTime ( 0 ) ;
89
- if ( log . IsDebugEnabled )
90
- {
91
- log . Debug ( "current timestamp retreived from db : " + ts + " (tiks=" + ts . Ticks + ")" ) ;
92
- }
93
- return ts ;
94
- }
95
- catch ( DbException sqle )
64
+ using ( new SessionIdLoggingContext ( session . SessionId ) )
96
65
{
97
- throw ADOExceptionHelper . Convert ( session . Factory . SQLExceptionConverter , sqle ,
98
- "could not select current db timestamp" , tsSelect ) ;
99
- }
100
- finally
101
- {
102
- if ( ps != null )
66
+ try
103
67
{
104
- try
68
+ ps = await ( session . Batcher . PrepareCommandAsync ( CommandType . Text , tsSelect , EmptyParams , cancellationToken ) ) . ConfigureAwait ( false ) ;
69
+ rs = await ( session . Batcher . ExecuteReaderAsync ( ps , cancellationToken ) ) . ConfigureAwait ( false ) ;
70
+ await ( rs . ReadAsync ( cancellationToken ) ) . ConfigureAwait ( false ) ;
71
+ var ts = rs . GetDateTime ( 0 ) ;
72
+ if ( log . IsDebugEnabled )
105
73
{
106
- session . Batcher . CloseCommand ( ps , rs ) ;
74
+ log . Debug ( "current timestamp retreived from db : " + ts + " (tiks=" + ts . Ticks + ")" ) ;
107
75
}
108
- catch ( DbException sqle )
76
+ return ts ;
77
+ }
78
+ catch ( DbException sqle )
79
+ {
80
+ throw ADOExceptionHelper . Convert (
81
+ session . Factory . SQLExceptionConverter ,
82
+ sqle ,
83
+ "could not select current db timestamp" ,
84
+ tsSelect ) ;
85
+ }
86
+ finally
87
+ {
88
+ if ( ps != null )
109
89
{
110
- log . Warn ( "unable to clean up prepared statement" , sqle ) ;
90
+ try
91
+ {
92
+ session . Batcher . CloseCommand ( ps , rs ) ;
93
+ }
94
+ catch ( DbException sqle )
95
+ {
96
+ log . Warn ( "unable to clean up prepared statement" , sqle ) ;
97
+ }
111
98
}
112
99
}
113
100
}
0 commit comments