SqlMethods.cs 39 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Diagnostics;
  4. using System.Text;
  5. using System.Text.RegularExpressions;
  6. using System.Reflection;
  7. using System.Diagnostics.CodeAnalysis;
  8. namespace System.Data.Linq.SqlClient {
  9. public static class SqlMethods {
  10. /// <summary>
  11. /// Counts the number of year boundaries crossed between the startDate and endDate.
  12. /// Corresponds to SQL Server's DATEDIFF(YEAR,startDate,endDate).
  13. /// </summary>
  14. /// <param name="startDate">Starting date for the calculation.</param>
  15. /// <param name="endDate">Ending date for the calculation.</param>
  16. /// <returns>Number of year boundaries crossed between the dates.</returns>
  17. public static int DateDiffYear(DateTime startDate, DateTime endDate) {
  18. return endDate.Year - startDate.Year;
  19. }
  20. /// <summary>
  21. /// Counts the number of year boundaries crossed between the startDate and endDate.
  22. /// Corresponds to SQL Server's DATEDIFF(YEAR,startDate,endDate).
  23. /// </summary>
  24. /// <param name="startDate">Starting date for the calculation.</param>
  25. /// <param name="endDate">Ending date for the calculation.</param>
  26. /// <returns>Number of year boundaries crossed between the dates.</returns>
  27. public static int? DateDiffYear(DateTime? startDate, DateTime? endDate) {
  28. if (startDate.HasValue && endDate.HasValue) {
  29. return DateDiffYear(startDate.Value,endDate.Value);
  30. } else {
  31. return null;
  32. }
  33. }
  34. /// <summary>
  35. /// Counts the number of year boundaries crossed between the startDate and endDate.
  36. /// Corresponds to SQL Server's DATEDIFF(YEAR,startDate,endDate).
  37. /// </summary>
  38. /// <param name="startDate">Starting date for the calculation.</param>
  39. /// <param name="endDate">Ending date for the calculation.</param>
  40. /// <returns>Number of year boundaries crossed between the dates.</returns>
  41. public static int DateDiffYear(DateTimeOffset startDate, DateTimeOffset endDate)
  42. {
  43. return DateDiffYear(startDate.UtcDateTime, endDate.UtcDateTime);
  44. }
  45. /// <summary>
  46. /// Counts the number of year boundaries crossed between the startDate and endDate.
  47. /// Corresponds to SQL Server's DATEDIFF(YEAR,startDate,endDate).
  48. /// </summary>
  49. /// <param name="startDate">Starting date for the calculation.</param>
  50. /// <param name="endDate">Ending date for the calculation.</param>
  51. /// <returns>Number of year boundaries crossed between the dates.</returns>
  52. public static int? DateDiffYear(DateTimeOffset? startDate, DateTimeOffset? endDate)
  53. {
  54. if (startDate.HasValue && endDate.HasValue)
  55. {
  56. return DateDiffYear(startDate.Value, endDate.Value);
  57. }
  58. else
  59. {
  60. return null;
  61. }
  62. }
  63. /// <summary>
  64. /// Counts the number of month boundaries crossed between the startDate and endDate.
  65. /// Corresponds to SQL Server's DATEDIFF(MONTH,startDate,endDate).
  66. /// </summary>
  67. /// <param name="startDate">Starting date for the calculation.</param>
  68. /// <param name="endDate">Ending date for the calculation.</param>
  69. /// <returns>Number of month boundaries crossed between the dates.</returns>
  70. public static int DateDiffMonth(DateTime startDate, DateTime endDate) {
  71. return 12 * (endDate.Year - startDate.Year) + endDate.Month - startDate.Month;
  72. }
  73. /// <summary>
  74. /// Counts the number of month boundaries crossed between the startDate and endDate.
  75. /// Corresponds to SQL Server's DATEDIFF(MONTH,startDate,endDate).
  76. /// </summary>
  77. /// <param name="startDate">Starting date for the calculation.</param>
  78. /// <param name="endDate">Ending date for the calculation.</param>
  79. /// <returns>Number of month boundaries crossed between the dates.</returns>
  80. public static int? DateDiffMonth(DateTime? startDate, DateTime? endDate) {
  81. if (startDate.HasValue && endDate.HasValue) {
  82. return DateDiffMonth(startDate.Value, endDate.Value);
  83. } else {
  84. return null;
  85. }
  86. }
  87. /// <summary>
  88. /// Counts the number of month boundaries crossed between the startDate and endDate.
  89. /// Corresponds to SQL Server's DATEDIFF(MONTH,startDate,endDate).
  90. /// </summary>
  91. /// <param name="startDate">Starting date for the calculation.</param>
  92. /// <param name="endDate">Ending date for the calculation.</param>
  93. /// <returns>Number of month boundaries crossed between the dates.</returns>
  94. public static int DateDiffMonth(DateTimeOffset startDate, DateTimeOffset endDate)
  95. {
  96. return DateDiffMonth(startDate.UtcDateTime, endDate.UtcDateTime);
  97. }
  98. /// <summary>
  99. /// Counts the number of month boundaries crossed between the startDate and endDate.
  100. /// Corresponds to SQL Server's DATEDIFF(MONTH,startDate,endDate).
  101. /// </summary>
  102. /// <param name="startDate">Starting date for the calculation.</param>
  103. /// <param name="endDate">Ending date for the calculation.</param>
  104. /// <returns>Number of month boundaries crossed between the dates.</returns>
  105. public static int? DateDiffMonth(DateTimeOffset? startDate, DateTimeOffset? endDate)
  106. {
  107. if (startDate.HasValue && endDate.HasValue)
  108. {
  109. return DateDiffMonth(startDate.Value, endDate.Value);
  110. }
  111. else
  112. {
  113. return null;
  114. }
  115. }
  116. /// <summary>
  117. /// Counts the number of day boundaries crossed between the startDate and endDate.
  118. /// Corresponds to SQL Server's DATEDIFF(DAY,startDate,endDate).
  119. /// </summary>
  120. /// <param name="startDate">Starting date for the calculation.</param>
  121. /// <param name="endDate">Ending date for the calculation.</param>
  122. /// <returns>Number of day boundaries crossed between the dates.</returns>
  123. public static int DateDiffDay(DateTime startDate, DateTime endDate) {
  124. TimeSpan diff = endDate.Date - startDate.Date;
  125. return diff.Days;
  126. }
  127. /// <summary>
  128. /// Counts the number of day boundaries crossed between the startDate and endDate.
  129. /// Corresponds to SQL Server's DATEDIFF(DAY,startDate,endDate).
  130. /// </summary>
  131. /// <param name="startDate">Starting date for the calculation.</param>
  132. /// <param name="endDate">Ending date for the calculation.</param>
  133. /// <returns>Number of day boundaries crossed between the dates.</returns>
  134. public static int? DateDiffDay(DateTime? startDate, DateTime? endDate) {
  135. if (startDate.HasValue && endDate.HasValue) {
  136. return DateDiffDay(startDate.Value, endDate.Value);
  137. } else {
  138. return null;
  139. }
  140. }
  141. /// <summary>
  142. /// Counts the number of day boundaries crossed between the startDate and endDate.
  143. /// Corresponds to SQL Server's DATEDIFF(DAY,startDate,endDate).
  144. /// </summary>
  145. /// <param name="startDate">Starting date for the calculation.</param>
  146. /// <param name="endDate">Ending date for the calculation.</param>
  147. /// <returns>Number of day boundaries crossed between the dates.</returns>
  148. public static int DateDiffDay(DateTimeOffset startDate, DateTimeOffset endDate)
  149. {
  150. return DateDiffDay(startDate.UtcDateTime, endDate.UtcDateTime);
  151. }
  152. /// <summary>
  153. /// Counts the number of day boundaries crossed between the startDate and endDate.
  154. /// Corresponds to SQL Server's DATEDIFF(DAY,startDate,endDate).
  155. /// </summary>
  156. /// <param name="startDate">Starting date for the calculation.</param>
  157. /// <param name="endDate">Ending date for the calculation.</param>
  158. /// <returns>Number of day boundaries crossed between the dates.</returns>
  159. public static int? DateDiffDay(DateTimeOffset? startDate, DateTimeOffset? endDate)
  160. {
  161. if (startDate.HasValue && endDate.HasValue)
  162. {
  163. return DateDiffDay(startDate.Value, endDate.Value);
  164. }
  165. else
  166. {
  167. return null;
  168. }
  169. }
  170. /// <summary>
  171. /// Counts the number of hour boundaries crossed between the startDate and endDate.
  172. /// Corresponds to SQL Server's DATEDIFF(HOUR,startDate,endDate).
  173. /// </summary>
  174. /// <param name="startDate">Starting date for the calculation.</param>
  175. /// <param name="endDate">Ending date for the calculation.</param>
  176. /// <returns>Number of hour boundaries crossed between the dates.</returns>
  177. public static int DateDiffHour(DateTime startDate, DateTime endDate) {
  178. checked {
  179. return DateDiffDay(startDate, endDate) * 24 + endDate.Hour - startDate.Hour;
  180. }
  181. }
  182. /// <summary>
  183. /// Counts the number of hour boundaries crossed between the startDate and endDate.
  184. /// Corresponds to SQL Server's DATEDIFF(HOUR,startDate,endDate).
  185. /// </summary>
  186. /// <param name="startDate">Starting date for the calculation.</param>
  187. /// <param name="endDate">Ending date for the calculation.</param>
  188. /// <returns>Number of hour boundaries crossed between the dates.</returns>
  189. public static int? DateDiffHour(DateTime? startDate, DateTime? endDate) {
  190. if (startDate.HasValue && endDate.HasValue) {
  191. return DateDiffHour(startDate.Value, endDate.Value);
  192. } else {
  193. return null;
  194. }
  195. }
  196. /// <summary>
  197. /// Counts the number of hour boundaries crossed between the startDate and endDate.
  198. /// Corresponds to SQL Server's DATEDIFF(HOUR,startDate,endDate).
  199. /// </summary>
  200. /// <param name="startDate">Starting date for the calculation.</param>
  201. /// <param name="endDate">Ending date for the calculation.</param>
  202. /// <returns>Number of hour boundaries crossed between the dates.</returns>
  203. public static int DateDiffHour(DateTimeOffset startDate, DateTimeOffset endDate)
  204. {
  205. return DateDiffHour(startDate.UtcDateTime, endDate.UtcDateTime);
  206. }
  207. /// <summary>
  208. /// Counts the number of hour boundaries crossed between the startDate and endDate.
  209. /// Corresponds to SQL Server's DATEDIFF(HOUR,startDate,endDate).
  210. /// </summary>
  211. /// <param name="startDate">Starting date for the calculation.</param>
  212. /// <param name="endDate">Ending date for the calculation.</param>
  213. /// <returns>Number of hour boundaries crossed between the dates.</returns>
  214. public static int? DateDiffHour(DateTimeOffset? startDate, DateTimeOffset? endDate)
  215. {
  216. if (startDate.HasValue && endDate.HasValue)
  217. {
  218. return DateDiffHour(startDate.Value, endDate.Value);
  219. }
  220. else
  221. {
  222. return null;
  223. }
  224. }
  225. /// <summary>
  226. /// Counts the number of minute boundaries crossed between the startDate and endDate.
  227. /// Corresponds to SQL Server's DATEDIFF(MINUTE,startDate,endDate).
  228. /// </summary>
  229. /// <param name="startDate">Starting date for the calculation.</param>
  230. /// <param name="endDate">Ending date for the calculation.</param>
  231. /// <returns>Number of minute boundaries crossed between the dates.</returns>
  232. public static int DateDiffMinute(DateTime startDate, DateTime endDate) {
  233. checked {
  234. return DateDiffHour(startDate, endDate) * 60 + endDate.Minute - startDate.Minute;
  235. }
  236. }
  237. /// <summary>
  238. /// Counts the number of minute boundaries crossed between the startDate and endDate.
  239. /// Corresponds to SQL Server's DATEDIFF(MINUTE,startDate,endDate).
  240. /// </summary>
  241. /// <param name="startDate">Starting date for the calculation.</param>
  242. /// <param name="endDate">Ending date for the calculation.</param>
  243. /// <returns>Number of minute boundaries crossed between the dates.</returns>
  244. public static int? DateDiffMinute(DateTime? startDate, DateTime? endDate) {
  245. if (startDate.HasValue && endDate.HasValue) {
  246. return DateDiffMinute(startDate.Value, endDate.Value);
  247. } else {
  248. return null;
  249. }
  250. }
  251. /// <summary>
  252. /// Counts the number of minute boundaries crossed between the startDate and endDate.
  253. /// Corresponds to SQL Server's DATEDIFF(MINUTE,startDate,endDate).
  254. /// </summary>
  255. /// <param name="startDate">Starting date for the calculation.</param>
  256. /// <param name="endDate">Ending date for the calculation.</param>
  257. /// <returns>Number of minute boundaries crossed between the dates.</returns>
  258. public static int DateDiffMinute(DateTimeOffset startDate, DateTimeOffset endDate)
  259. {
  260. return DateDiffMinute(startDate.UtcDateTime, endDate.UtcDateTime);
  261. }
  262. /// <summary>
  263. /// Counts the number of minute boundaries crossed between the startDate and endDate.
  264. /// Corresponds to SQL Server's DATEDIFF(MINUTE,startDate,endDate).
  265. /// </summary>
  266. /// <param name="startDate">Starting date for the calculation.</param>
  267. /// <param name="endDate">Ending date for the calculation.</param>
  268. /// <returns>Number of minute boundaries crossed between the dates.</returns>
  269. public static int? DateDiffMinute(DateTimeOffset? startDate, DateTimeOffset? endDate)
  270. {
  271. if (startDate.HasValue && endDate.HasValue)
  272. {
  273. return DateDiffMinute(startDate.Value, endDate.Value);
  274. }
  275. else
  276. {
  277. return null;
  278. }
  279. }
  280. /// <summary>
  281. /// Counts the number of second boundaries crossed between the startDate and endDate.
  282. /// Corresponds to SQL Server's DATEDIFF(SECOND,startDate,endDate).
  283. /// </summary>
  284. /// <param name="startDate">Starting date for the calculation.</param>
  285. /// <param name="endDate">Ending date for the calculation.</param>
  286. /// <returns>Number of second boundaries crossed between the dates.</returns>
  287. public static int DateDiffSecond(DateTime startDate, DateTime endDate) {
  288. checked {
  289. return DateDiffMinute(startDate, endDate) * 60 + endDate.Second - startDate.Second;
  290. }
  291. }
  292. /// <summary>
  293. /// Counts the number of second boundaries crossed between the startDate and endDate.
  294. /// Corresponds to SQL Server's DATEDIFF(SECOND,startDate,endDate).
  295. /// </summary>
  296. /// <param name="startDate">Starting date for the calculation.</param>
  297. /// <param name="endDate">Ending date for the calculation.</param>
  298. /// <returns>Number of second boundaries crossed between the dates.</returns>
  299. public static int? DateDiffSecond(DateTime? startDate, DateTime? endDate) {
  300. if (startDate.HasValue && endDate.HasValue) {
  301. return DateDiffSecond(startDate.Value, endDate.Value);
  302. } else {
  303. return null;
  304. }
  305. }
  306. /// <summary>
  307. /// Counts the number of second boundaries crossed between the startDate and endDate.
  308. /// Corresponds to SQL Server's DATEDIFF(SECOND,startDate,endDate).
  309. /// </summary>
  310. /// <param name="startDate">Starting date for the calculation.</param>
  311. /// <param name="endDate">Ending date for the calculation.</param>
  312. /// <returns>Number of second boundaries crossed between the dates.</returns>
  313. public static int DateDiffSecond(DateTimeOffset startDate, DateTimeOffset endDate)
  314. {
  315. return DateDiffSecond(startDate.UtcDateTime, endDate.UtcDateTime);
  316. }
  317. /// <summary>
  318. /// Counts the number of second boundaries crossed between the startDate and endDate.
  319. /// Corresponds to SQL Server's DATEDIFF(SECOND,startDate,endDate).
  320. /// </summary>
  321. /// <param name="startDate">Starting date for the calculation.</param>
  322. /// <param name="endDate">Ending date for the calculation.</param>
  323. /// <returns>Number of second boundaries crossed between the dates.</returns>
  324. public static int? DateDiffSecond(DateTimeOffset? startDate, DateTimeOffset? endDate)
  325. {
  326. if (startDate.HasValue && endDate.HasValue)
  327. {
  328. return DateDiffSecond(startDate.Value, endDate.Value);
  329. }
  330. else
  331. {
  332. return null;
  333. }
  334. }
  335. /// <summary>
  336. /// Counts the number of millisecond boundaries crossed between the startDate and endDate.
  337. /// Corresponds to SQL Server's DATEDIFF(MILLISECOND,startDate,endDate).
  338. /// </summary>
  339. /// <param name="startDate">Starting date for the calculation.</param>
  340. /// <param name="endDate">Ending date for the calculation.</param>
  341. /// <returns>Number of millisecond boundaries crossed between the dates.</returns>
  342. public static int DateDiffMillisecond(DateTime startDate, DateTime endDate) {
  343. checked {
  344. return DateDiffSecond(startDate, endDate) * 1000 + endDate.Millisecond - startDate.Millisecond;
  345. }
  346. }
  347. /// <summary>
  348. /// Counts the number of millisecond boundaries crossed between the startDate and endDate.
  349. /// Corresponds to SQL Server's DATEDIFF(MILLISECOND,startDate,endDate).
  350. /// </summary>
  351. /// <param name="startDate">Starting date for the calculation.</param>
  352. /// <param name="endDate">Ending date for the calculation.</param>
  353. /// <returns>Number of millisecond boundaries crossed between the dates.</returns>
  354. public static int? DateDiffMillisecond(DateTime? startDate, DateTime? endDate) {
  355. if (startDate.HasValue && endDate.HasValue) {
  356. return DateDiffMillisecond(startDate.Value, endDate.Value);
  357. } else {
  358. return null;
  359. }
  360. }
  361. /// <summary>
  362. /// Counts the number of millisecond boundaries crossed between the startDate and endDate.
  363. /// Corresponds to SQL Server's DATEDIFF(MILLISECOND,startDate,endDate).
  364. /// </summary>
  365. /// <param name="startDate">Starting date for the calculation.</param>
  366. /// <param name="endDate">Ending date for the calculation.</param>
  367. /// <returns>Number of millisecond boundaries crossed between the dates.</returns>
  368. public static int DateDiffMillisecond(DateTimeOffset startDate, DateTimeOffset endDate)
  369. {
  370. return DateDiffMillisecond(startDate.UtcDateTime, endDate.UtcDateTime);
  371. }
  372. /// <summary>
  373. /// Counts the number of millisecond boundaries crossed between the startDate and endDate.
  374. /// Corresponds to SQL Server's DATEDIFF(MILLISECOND,startDate,endDate).
  375. /// </summary>
  376. /// <param name="startDate">Starting date for the calculation.</param>
  377. /// <param name="endDate">Ending date for the calculation.</param>
  378. /// <returns>Number of millisecond boundaries crossed between the dates.</returns>
  379. public static int? DateDiffMillisecond(DateTimeOffset? startDate, DateTimeOffset? endDate)
  380. {
  381. if (startDate.HasValue && endDate.HasValue)
  382. {
  383. return DateDiffMillisecond(startDate.Value, endDate.Value);
  384. }
  385. else
  386. {
  387. return null;
  388. }
  389. }
  390. /// <summary>
  391. /// Counts the number of microsecond boundaries crossed between the startDate and endDate.
  392. /// Corresponds to SQL Server's DATEDIFF(MICROSECOND,startDate,endDate).
  393. /// </summary>
  394. /// <param name="startDate">Starting date for the calculation.</param>
  395. /// <param name="endDate">Ending date for the calculation.</param>
  396. /// <returns>Number of microsecond boundaries crossed between the dates.</returns>
  397. public static int DateDiffMicrosecond(DateTime startDate, DateTime endDate)
  398. {
  399. checked
  400. {
  401. return (int)((endDate.Ticks - startDate.Ticks) / 10);
  402. }
  403. }
  404. /// <summary>
  405. /// Counts the number of microsecond boundaries crossed between the startDate and endDate.
  406. /// Corresponds to SQL Server's DATEDIFF(MICROSECOND,startDate,endDate).
  407. /// </summary>
  408. /// <param name="startDate">Starting date for the calculation.</param>
  409. /// <param name="endDate">Ending date for the calculation.</param>
  410. /// <returns>Number of microsecond boundaries crossed between the dates.</returns>
  411. public static int? DateDiffMicrosecond(DateTime? startDate, DateTime? endDate)
  412. {
  413. if (startDate.HasValue && endDate.HasValue)
  414. {
  415. return DateDiffMicrosecond(startDate.Value, endDate.Value);
  416. }
  417. else
  418. {
  419. return null;
  420. }
  421. }
  422. /// <summary>
  423. /// Counts the number of microsecond boundaries crossed between the startDate and endDate.
  424. /// Corresponds to SQL Server's DATEDIFF(MICROSECOND,startDate,endDate).
  425. /// </summary>
  426. /// <param name="startDate">Starting date for the calculation.</param>
  427. /// <param name="endDate">Ending date for the calculation.</param>
  428. /// <returns>Number of microsecond boundaries crossed between the dates.</returns>
  429. public static int DateDiffMicrosecond(DateTimeOffset startDate, DateTimeOffset endDate)
  430. {
  431. return DateDiffMicrosecond(startDate.UtcDateTime, endDate.UtcDateTime);
  432. }
  433. /// <summary>
  434. /// Counts the number of microsecond boundaries crossed between the startDate and endDate.
  435. /// Corresponds to SQL Server's DATEDIFF(MICROSECOND,startDate,endDate).
  436. /// </summary>
  437. /// <param name="startDate">Starting date for the calculation.</param>
  438. /// <param name="endDate">Ending date for the calculation.</param>
  439. /// <returns>Number of microsecond boundaries crossed between the dates.</returns>
  440. public static int? DateDiffMicrosecond(DateTimeOffset? startDate, DateTimeOffset? endDate)
  441. {
  442. if (startDate.HasValue && endDate.HasValue)
  443. {
  444. return DateDiffMicrosecond(startDate.Value, endDate.Value);
  445. }
  446. else
  447. {
  448. return null;
  449. }
  450. }
  451. /// <summary>
  452. /// Counts the number of nanosecond boundaries crossed between the startDate and endDate.
  453. /// Corresponds to SQL Server's DATEDIFF(NANOSECOND,startDate,endDate).
  454. /// </summary>
  455. /// <param name="startDate">Starting date for the calculation.</param>
  456. /// <param name="endDate">Ending date for the calculation.</param>
  457. /// <returns>Number of nanosecond boundaries crossed between the dates.</returns>
  458. public static int DateDiffNanosecond(DateTime startDate, DateTime endDate)
  459. {
  460. checked
  461. {
  462. return (int)((endDate.Ticks - startDate.Ticks) * 100);
  463. }
  464. }
  465. /// <summary>
  466. /// Counts the number of nanosecond boundaries crossed between the startDate and endDate.
  467. /// Corresponds to SQL Server's DATEDIFF(NANOSECOND,startDate,endDate).
  468. /// </summary>
  469. /// <param name="startDate">Starting date for the calculation.</param>
  470. /// <param name="endDate">Ending date for the calculation.</param>
  471. /// <returns>Number of nanosecond boundaries crossed between the dates.</returns>
  472. public static int? DateDiffNanosecond(DateTime? startDate, DateTime? endDate)
  473. {
  474. if (startDate.HasValue && endDate.HasValue)
  475. {
  476. return DateDiffNanosecond(startDate.Value, endDate.Value);
  477. }
  478. else
  479. {
  480. return null;
  481. }
  482. }
  483. /// <summary>
  484. /// Counts the number of nanosecond boundaries crossed between the startDate and endDate.
  485. /// Corresponds to SQL Server's DATEDIFF(NANOSECOND,startDate,endDate).
  486. /// </summary>
  487. /// <param name="startDate">Starting date for the calculation.</param>
  488. /// <param name="endDate">Ending date for the calculation.</param>
  489. /// <returns>Number of nanosecond boundaries crossed between the dates.</returns>
  490. public static int DateDiffNanosecond(DateTimeOffset startDate, DateTimeOffset endDate)
  491. {
  492. return DateDiffNanosecond(startDate.UtcDateTime, endDate.UtcDateTime);
  493. }
  494. /// <summary>
  495. /// Counts the number of nanosecond boundaries crossed between the startDate and endDate.
  496. /// Corresponds to SQL Server's DATEDIFF(NANOSECOND,startDate,endDate).
  497. /// </summary>
  498. /// <param name="startDate">Starting date for the calculation.</param>
  499. /// <param name="endDate">Ending date for the calculation.</param>
  500. /// <returns>Number of nanosecond boundaries crossed between the dates.</returns>
  501. public static int? DateDiffNanosecond(DateTimeOffset? startDate, DateTimeOffset? endDate)
  502. {
  503. if (startDate.HasValue && endDate.HasValue)
  504. {
  505. return DateDiffNanosecond(startDate.Value, endDate.Value);
  506. }
  507. else
  508. {
  509. return null;
  510. }
  511. }
  512. /// <summary>
  513. /// This function is translated to Sql Server's LIKE function.
  514. /// It cannot be used on the client.
  515. /// </summary>
  516. /// <param name="match_expression">The string that is to be matched.</param>
  517. /// <param name="pattern">The pattern which may involve wildcards %,_,[,],^.</param>
  518. /// <returns>true if there is a match.</returns>
  519. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "pattern", Justification = "[....]: Method is a placeholder for a server-side method.")]
  520. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "matchExpression", Justification = "[....]: Method is a placeholder for a server-side method.")]
  521. public static bool Like(string matchExpression, string pattern) {
  522. throw Error.SqlMethodOnlyForSql(MethodInfo.GetCurrentMethod());
  523. }
  524. /// <summary>
  525. /// This function is translated to Sql Server's LIKE function.
  526. /// It cannot be used on the client.
  527. /// </summary>
  528. /// <param name="match_expression">The string that is to be matched.</param>
  529. /// <param name="pattern">The pattern which may involve wildcards %,_,[,],^.</param>
  530. /// <param name="escape_character">The escape character to use in front of %,_,[,],^ if they are not used as wildcards.</param>
  531. /// <returns>true if there is a match.</returns>
  532. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "pattern", Justification = "[....]: Method is a placeholder for a server-side method.")]
  533. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "matchExpression", Justification = "[....]: Method is a placeholder for a server-side method.")]
  534. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "escapeCharacter", Justification = "[....]: Method is a placeholder for a server-side method.")]
  535. public static bool Like(string matchExpression, string pattern, char escapeCharacter) {
  536. throw Error.SqlMethodOnlyForSql(MethodInfo.GetCurrentMethod());
  537. }
  538. /// <summary>
  539. /// This function is translated to Sql Server's DATALENGTH function. It differs
  540. /// from LEN in that it includes trailing spaces and will count UNICODE characters
  541. /// per byte.
  542. /// It cannot be used on the client.
  543. /// </summary>
  544. /// <param name="value">The string to take the length of.</param>
  545. /// <returns>length of the string</returns>
  546. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value", Justification = "[....]: Method is a placeholder for a server-side method.")]
  547. internal static int RawLength(string value) {
  548. throw Error.SqlMethodOnlyForSql(MethodInfo.GetCurrentMethod());
  549. }
  550. /// <summary>
  551. /// This function is translated to Sql Server's DATALENGTH function.
  552. /// It cannot be used on the client.
  553. /// </summary>
  554. /// <param name="value">The byte array to take the length of.</param>
  555. /// <returns>length of the array</returns>
  556. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value", Justification = "[....]: Method is a placeholder for a server-side method.")]
  557. internal static int RawLength(byte[] value) {
  558. throw Error.SqlMethodOnlyForSql(MethodInfo.GetCurrentMethod());
  559. }
  560. /// <summary>
  561. /// This function is translated to Sql Server's DATALENGTH function.
  562. /// It cannot be used on the client.
  563. /// </summary>
  564. /// <param name="value">The Binary value to take the length of.</param>
  565. /// <returns>length of the Binary</returns>
  566. [SuppressMessage("Microsoft.Usage", "CA1801:ReviewUnusedParameters", MessageId = "value", Justification = "[....]: Method is a placeholder for a server-side method.")]
  567. internal static int RawLength(Binary value) {
  568. throw Error.SqlMethodOnlyForSql(MethodInfo.GetCurrentMethod());
  569. }
  570. }
  571. public static class SqlHelpers {
  572. public static string GetStringContainsPattern(string text, char escape) {
  573. bool usedEscapeChar = false;
  574. return GetStringContainsPattern(text, escape, out usedEscapeChar);
  575. }
  576. internal static string GetStringContainsPattern(string text, char escape, out bool usedEscapeChar) {
  577. if (text == null) {
  578. throw Error.ArgumentNull("text");
  579. }
  580. return "%" + EscapeLikeText(text, escape, false, out usedEscapeChar) + "%";
  581. }
  582. internal static string GetStringContainsPatternForced(string text, char escape) {
  583. if (text == null) {
  584. throw Error.ArgumentNull("text");
  585. }
  586. bool usedEscapeChar = false;
  587. return "%" + EscapeLikeText(text, escape, true, out usedEscapeChar) + "%";
  588. }
  589. public static string GetStringStartsWithPattern(string text, char escape) {
  590. bool usedEscapeChar = false;
  591. return GetStringStartsWithPattern(text, escape, out usedEscapeChar);
  592. }
  593. internal static string GetStringStartsWithPattern(string text, char escape, out bool usedEscapeChar) {
  594. if (text == null) {
  595. throw Error.ArgumentNull("text");
  596. }
  597. return EscapeLikeText(text, escape, false, out usedEscapeChar) + "%";
  598. }
  599. internal static string GetStringStartsWithPatternForced(string text, char escape) {
  600. if (text == null) {
  601. throw Error.ArgumentNull("text");
  602. }
  603. bool usedEscapeChar = false;
  604. return EscapeLikeText(text, escape, true, out usedEscapeChar) + "%";
  605. }
  606. public static string GetStringEndsWithPattern(string text, char escape) {
  607. bool usedEscapeChar = false;
  608. return GetStringEndsWithPattern(text, escape, out usedEscapeChar);
  609. }
  610. internal static string GetStringEndsWithPattern(string text, char escape, out bool usedEscapeChar) {
  611. if (text == null) {
  612. throw Error.ArgumentNull("text");
  613. }
  614. return "%" + EscapeLikeText(text, escape, false, out usedEscapeChar);
  615. }
  616. internal static string GetStringEndsWithPatternForced(string text, char escape) {
  617. if (text == null) {
  618. throw Error.ArgumentNull("text");
  619. }
  620. bool usedEscapeChar = false;
  621. return "%" + EscapeLikeText(text, escape, true, out usedEscapeChar);
  622. }
  623. private static string EscapeLikeText(string text, char escape, bool forceEscaping, out bool usedEscapeChar) {
  624. usedEscapeChar = false;
  625. if (!(forceEscaping || text.Contains("%") || text.Contains("_") || text.Contains("[") || text.Contains("^"))) {
  626. return text;
  627. }
  628. StringBuilder sb = new StringBuilder(text.Length);
  629. foreach (char c in text) {
  630. if (c == '%' || c == '_' || c == '[' || c == '^' || c == escape) {
  631. sb.Append(escape);
  632. usedEscapeChar = true;
  633. }
  634. sb.Append(c);
  635. }
  636. return sb.ToString();
  637. }
  638. public static string TranslateVBLikePattern(string pattern, char escape) {
  639. if (pattern == null) {
  640. throw Error.ArgumentNull("pattern");
  641. }
  642. const char vbMany = '*';
  643. const char sqlMany = '%';
  644. const char vbSingle = '?';
  645. const char sqlSingle = '_';
  646. const char vbDigit = '#';
  647. const string sqlDigit = "[0-9]";
  648. const char vbOpenBracket = '[';
  649. const char sqlOpenBracket = '[';
  650. const char vbCloseBracket = ']';
  651. const char sqlCloseBracket = ']';
  652. const char vbNotList = '!';
  653. const char sqlNotList = '^';
  654. const char vbCharRange = '-';
  655. const char sqlCharRange = '-';
  656. // walk the string, performing conversions
  657. StringBuilder result = new StringBuilder();
  658. bool bracketed = false;
  659. bool charRange = false;
  660. bool possibleNotList = false;
  661. int numBracketedCharacters = 0;
  662. foreach (char patternChar in pattern) {
  663. if (bracketed) {
  664. numBracketedCharacters++;
  665. // if we're in a possible NotList, anything other than a close bracket will confirm it
  666. if (possibleNotList) {
  667. if (patternChar != vbCloseBracket) {
  668. result.Append(sqlNotList);
  669. possibleNotList = false;
  670. }
  671. else {
  672. result.Append(vbNotList);
  673. possibleNotList = false;
  674. }
  675. }
  676. switch (patternChar) {
  677. case vbNotList: {
  678. // translate to SQL's NotList only if the first character in the group
  679. if (numBracketedCharacters == 1) {
  680. // latch this, and detect the next cycle
  681. possibleNotList = true;
  682. }
  683. else {
  684. result.Append(patternChar);
  685. }
  686. break;
  687. }
  688. case vbCloseBracket: {
  689. // close down the bracket group
  690. bracketed = false;
  691. possibleNotList = false;
  692. result.Append(sqlCloseBracket);
  693. break;
  694. }
  695. case vbCharRange: {
  696. if (charRange) {
  697. // we've seen the char range indicator already -- SQL
  698. // doesn't support multiple ranges in the same group
  699. throw Error.VbLikeDoesNotSupportMultipleCharacterRanges();
  700. }
  701. else {
  702. // remember that we've seen this in the group
  703. charRange = true;
  704. result.Append(sqlCharRange);
  705. break;
  706. }
  707. }
  708. case sqlNotList: {
  709. if (numBracketedCharacters == 1) {
  710. // need to escape this one
  711. result.Append(escape);
  712. }
  713. result.Append(patternChar);
  714. break;
  715. }
  716. default: {
  717. if (patternChar == escape) {
  718. result.Append(escape);
  719. result.Append(escape);
  720. }
  721. else {
  722. result.Append(patternChar);
  723. }
  724. break;
  725. }
  726. }
  727. }
  728. else {
  729. switch (patternChar) {
  730. case vbMany: {
  731. result.Append(sqlMany);
  732. break;
  733. }
  734. case vbSingle: {
  735. result.Append(sqlSingle);
  736. break;
  737. }
  738. case vbDigit: {
  739. result.Append(sqlDigit);
  740. break;
  741. }
  742. case vbOpenBracket: {
  743. // we're openning a bracketed group, so reset the group state
  744. bracketed = true;
  745. charRange = false;
  746. numBracketedCharacters = 0;
  747. result.Append(sqlOpenBracket);
  748. break;
  749. }
  750. // SQL's special characters need to be escaped
  751. case sqlMany:
  752. case sqlSingle: {
  753. result.Append(escape);
  754. result.Append(patternChar);
  755. break;
  756. }
  757. default: {
  758. if (patternChar == escape) {
  759. result.Append(escape);
  760. result.Append(escape);
  761. }
  762. else {
  763. result.Append(patternChar);
  764. }
  765. break;
  766. }
  767. }
  768. }
  769. }
  770. if (bracketed) {
  771. throw Error.VbLikeUnclosedBracket();
  772. }
  773. return result.ToString();
  774. }
  775. }
  776. }