1010
1111using System ;
1212using System . Collections ;
13+ using System . Collections . Concurrent ;
14+ using System . Collections . Generic ;
15+ using System . Threading ;
16+ using System . Threading . Tasks ;
1317using NHibernate . Dialect ;
1418using NUnit . Framework ;
1519
1620namespace NHibernate . Test . Hql
1721{
18- using System . Threading . Tasks ;
22+ using System . Linq ;
1923 /// <summary>
2024 /// This test run each HQL function separately so is easy to know which function need
2125 /// an override in the specific dialect implementation.
@@ -32,6 +36,19 @@ static HQLFunctionsAsync()
3236 { "locate" , new [ ] { typeof ( SQLiteDialect ) } } ,
3337 { "bit_length" , new [ ] { typeof ( SQLiteDialect ) } } ,
3438 { "extract" , new [ ] { typeof ( SQLiteDialect ) } } ,
39+ {
40+ "bxor" ,
41+ new [ ]
42+ {
43+ // Could be supported like Oracle, with a template
44+ typeof ( SQLiteDialect ) ,
45+ // Could be supported by overriding registration with # instead of ^
46+ typeof ( PostgreSQLDialect ) ,
47+ typeof ( PostgreSQL81Dialect ) ,
48+ typeof ( PostgreSQL82Dialect ) ,
49+ typeof ( PostgreSQL83Dialect )
50+ }
51+ } ,
3552 {
3653 "nullif" ,
3754 new [ ]
@@ -1079,5 +1096,198 @@ public async Task ParameterLikeArgumentAsync()
10791096 Assert . AreEqual ( 1 , l . Count ) ;
10801097 }
10811098 }
1099+
1100+ [ Test ]
1101+ public async Task BitwiseAndAsync ( )
1102+ {
1103+ IgnoreIfNotSupported ( "band" ) ;
1104+ await ( CreateMaterialResourcesAsync ( ) ) ;
1105+
1106+ using ( var s = OpenSession ( ) )
1107+ using ( var tx = s . BeginTransaction ( ) )
1108+ {
1109+ var query = s . CreateQuery ( "from MaterialResource m where (m.State & 1) > 0" ) ;
1110+ var result = await ( query . ListAsync ( ) ) ;
1111+ Assert . That ( result , Has . Count . EqualTo ( 1 ) , "& 1" ) ;
1112+
1113+ query = s . CreateQuery ( "from MaterialResource m where (m.State & 2) > 0" ) ;
1114+ result = await ( query . ListAsync ( ) ) ;
1115+ Assert . That ( result , Has . Count . EqualTo ( 1 ) , "& 2" ) ;
1116+
1117+ query = s . CreateQuery ( "from MaterialResource m where (m.State & 3) > 0" ) ;
1118+ result = await ( query . ListAsync ( ) ) ;
1119+ Assert . That ( result , Has . Count . EqualTo ( 2 ) , "& 3" ) ;
1120+
1121+ await ( tx . CommitAsync ( ) ) ;
1122+ }
1123+ await ( DeleteMaterialResourcesAsync ( ) ) ;
1124+ }
1125+
1126+ [ Test ]
1127+ public async Task BitwiseOrAsync ( )
1128+ {
1129+ IgnoreIfNotSupported ( "bor" ) ;
1130+ await ( CreateMaterialResourcesAsync ( ) ) ;
1131+
1132+ using ( var s = OpenSession ( ) )
1133+ using ( var tx = s . BeginTransaction ( ) )
1134+ {
1135+ var query = s . CreateQuery ( "from MaterialResource m where (m.State | 1) > 0" ) ;
1136+ var result = await ( query . ListAsync ( ) ) ;
1137+ Assert . That ( result , Has . Count . EqualTo ( 3 ) , "| 1) > 0" ) ;
1138+
1139+ query = s . CreateQuery ( "from MaterialResource m where (m.State | 1) > 1" ) ;
1140+ result = await ( query . ListAsync ( ) ) ;
1141+ Assert . That ( result , Has . Count . EqualTo ( 1 ) , "| 1) > 1" ) ;
1142+
1143+ query = s . CreateQuery ( "from MaterialResource m where (m.State | 0) > 0" ) ;
1144+ result = await ( query . ListAsync ( ) ) ;
1145+ Assert . That ( result , Has . Count . EqualTo ( 2 ) , "| 0) > 0" ) ;
1146+
1147+ await ( tx . CommitAsync ( ) ) ;
1148+ }
1149+ await ( DeleteMaterialResourcesAsync ( ) ) ;
1150+ }
1151+
1152+ [ Test ]
1153+ public async Task BitwiseXorAsync ( )
1154+ {
1155+ IgnoreIfNotSupported ( "bxor" ) ;
1156+ await ( CreateMaterialResourcesAsync ( ) ) ;
1157+
1158+ using ( var s = OpenSession ( ) )
1159+ using ( var tx = s . BeginTransaction ( ) )
1160+ {
1161+ var query = s . CreateQuery ( "from MaterialResource m where (m.State ^ 1) > 0" ) ;
1162+ var result = await ( query . ListAsync ( ) ) ;
1163+ Assert . That ( result , Has . Count . EqualTo ( 2 ) , "^ 1" ) ;
1164+
1165+ query = s . CreateQuery ( "from MaterialResource m where (m.State ^ 2) > 0" ) ;
1166+ result = await ( query . ListAsync ( ) ) ;
1167+ Assert . That ( result , Has . Count . EqualTo ( 2 ) , "^ 2" ) ;
1168+
1169+ query = s . CreateQuery ( "from MaterialResource m where (m.State ^ 3) > 0" ) ;
1170+ result = await ( query . ListAsync ( ) ) ;
1171+ Assert . That ( result , Has . Count . EqualTo ( 3 ) , "^ 3" ) ;
1172+
1173+ await ( tx . CommitAsync ( ) ) ;
1174+ }
1175+ await ( DeleteMaterialResourcesAsync ( ) ) ;
1176+ }
1177+
1178+ [ Test ]
1179+ public async Task BitwiseNotAsync ( )
1180+ {
1181+ IgnoreIfNotSupported ( "bnot" ) ;
1182+ IgnoreIfNotSupported ( "band" ) ;
1183+ await ( CreateMaterialResourcesAsync ( ) ) ;
1184+
1185+ using ( var s = OpenSession ( ) )
1186+ using ( var tx = s . BeginTransaction ( ) )
1187+ {
1188+ // ! takes not precedence over & at least with some dialects (maybe all).
1189+ var query = s . CreateQuery ( "from MaterialResource m where ((!m.State) & 3) = 3" ) ;
1190+ var result = await ( query . ListAsync ( ) ) ;
1191+ Assert . That ( result , Has . Count . EqualTo ( 1 ) , "((!m.State) & 3) = 3" ) ;
1192+
1193+ query = s . CreateQuery ( "from MaterialResource m where ((!m.State) & 3) = 2" ) ;
1194+ result = await ( query . ListAsync ( ) ) ;
1195+ Assert . That ( result , Has . Count . EqualTo ( 1 ) , "((!m.State) & 3) = 2" ) ;
1196+
1197+ query = s . CreateQuery ( "from MaterialResource m where ((!m.State) & 3) = 1" ) ;
1198+ result = await ( query . ListAsync ( ) ) ;
1199+ Assert . That ( result , Has . Count . EqualTo ( 1 ) , "((!m.State) & 3) = 1" ) ;
1200+
1201+ await ( tx . CommitAsync ( ) ) ;
1202+ }
1203+ await ( DeleteMaterialResourcesAsync ( ) ) ;
1204+ }
1205+
1206+ // #1670
1207+ [ Test ]
1208+ public async Task BitwiseIsThreadsafeAsync ( )
1209+ {
1210+ IgnoreIfNotSupported ( "band" ) ;
1211+ IgnoreIfNotSupported ( "bor" ) ;
1212+ IgnoreIfNotSupported ( "bxor" ) ;
1213+ IgnoreIfNotSupported ( "bnot" ) ;
1214+ var queries = new List < Tuple < string , int > >
1215+ {
1216+ new Tuple < string , int > ( "select count(*) from MaterialResource m where (m.State & 1) > 0" , 1 ) ,
1217+ new Tuple < string , int > ( "select count(*) from MaterialResource m where (m.State & 2) > 0" , 1 ) ,
1218+ new Tuple < string , int > ( "select count(*) from MaterialResource m where (m.State & 3) > 0" , 2 ) ,
1219+ new Tuple < string , int > ( "select count(*) from MaterialResource m where (m.State | 1) > 0" , 3 ) ,
1220+ new Tuple < string , int > ( "select count(*) from MaterialResource m where (m.State | 1) > 1" , 1 ) ,
1221+ new Tuple < string , int > ( "select count(*) from MaterialResource m where (m.State | 0) > 0" , 2 ) ,
1222+ new Tuple < string , int > ( "select count(*) from MaterialResource m where (m.State ^ 1) > 0" , 2 ) ,
1223+ new Tuple < string , int > ( "select count(*) from MaterialResource m where (m.State ^ 2) > 0" , 2 ) ,
1224+ new Tuple < string , int > ( "select count(*) from MaterialResource m where (m.State ^ 3) > 0" , 3 ) ,
1225+ new Tuple < string , int > ( "select count(*) from MaterialResource m where ((!m.State) & 3) = 3" , 1 ) ,
1226+ new Tuple < string , int > ( "select count(*) from MaterialResource m where ((!m.State) & 3) = 2" , 1 ) ,
1227+ new Tuple < string , int > ( "select count(*) from MaterialResource m where ((!m.State) & 3) = 1" , 1 )
1228+ } ;
1229+ // Do not use a ManualResetEventSlim, it does not support async and exhausts the task thread pool in the
1230+ // async counterparts of this test. SemaphoreSlim has the async support and release the thread when waiting.
1231+ var semaphore = new SemaphoreSlim ( 0 ) ;
1232+ var failures = new ConcurrentBag < Exception > ( ) ;
1233+
1234+ await ( CreateMaterialResourcesAsync ( ) ) ;
1235+
1236+ await ( Task . WhenAll (
1237+ Enumerable . Range ( 0 , queries . Count + 1 - 0 ) . Select ( async i =>
1238+ {
1239+ if ( i >= queries . Count )
1240+ {
1241+ // Give some time to threads for reaching the wait, having all of them ready to do the
1242+ // critical part of their job concurrently.
1243+ await ( Task . Delay ( 100 ) ) ;
1244+ semaphore . Release ( queries . Count ) ;
1245+ return ;
1246+ }
1247+
1248+ try
1249+ {
1250+ var query = queries [ i ] ;
1251+ using ( var s = OpenSession ( ) )
1252+ using ( var tx = s . BeginTransaction ( ) )
1253+ {
1254+ await ( semaphore . WaitAsync ( ) ) ;
1255+ var q = s . CreateQuery ( query . Item1 ) ;
1256+ var result = await ( q . UniqueResultAsync < long > ( ) ) ;
1257+ Assert . That ( result , Is . EqualTo ( query . Item2 ) , query . Item1 ) ;
1258+ await ( tx . CommitAsync ( ) ) ;
1259+ }
1260+ }
1261+ catch ( Exception e )
1262+ {
1263+ failures . Add ( e ) ;
1264+ }
1265+ } ) ) ) ;
1266+
1267+ Assert . That ( failures , Is . Empty , $ "{ failures . Count } task(s) failed.") ;
1268+ await ( DeleteMaterialResourcesAsync ( ) ) ;
1269+ }
1270+
1271+ private async Task CreateMaterialResourcesAsync ( CancellationToken cancellationToken = default ( CancellationToken ) )
1272+ {
1273+ using ( var s = OpenSession ( ) )
1274+ using ( var tx = s . BeginTransaction ( ) )
1275+ {
1276+ await ( s . SaveAsync ( new MaterialResource ( "m1" , "18" , MaterialResource . MaterialState . Available ) , cancellationToken ) ) ;
1277+ await ( s . SaveAsync ( new MaterialResource ( "m2" , "19" , MaterialResource . MaterialState . Reserved ) , cancellationToken ) ) ;
1278+ await ( s . SaveAsync ( new MaterialResource ( "m3" , "20" , MaterialResource . MaterialState . Discarded ) , cancellationToken ) ) ;
1279+ await ( tx . CommitAsync ( cancellationToken ) ) ;
1280+ }
1281+ }
1282+
1283+ private async Task DeleteMaterialResourcesAsync ( CancellationToken cancellationToken = default ( CancellationToken ) )
1284+ {
1285+ using ( var s = OpenSession ( ) )
1286+ using ( var tx = s . BeginTransaction ( ) )
1287+ {
1288+ await ( s . CreateQuery ( "delete from MaterialResource" ) . ExecuteUpdateAsync ( cancellationToken ) ) ;
1289+ await ( tx . CommitAsync ( cancellationToken ) ) ;
1290+ }
1291+ }
10821292 }
10831293}
0 commit comments