SqlGenerator.cs 34 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016
  1. using Ant.Core;
  2. using Ant.Data;
  3. using Ant.DbExpressions;
  4. using Ant.ORM;
  5. using System;
  6. using System.Collections;
  7. using System.Collections.Generic;
  8. using System.Collections.ObjectModel;
  9. using System.Linq;
  10. using System.Reflection;
  11. using System.Text;
  12. namespace Ant.Oracle
  13. {
  14. partial class SqlGenerator : DbExpressionVisitor<DbExpression>
  15. {
  16. public const string ParameterPrefix = ":P_";
  17. static readonly object Boxed_1 = 1;
  18. static readonly object Boxed_0 = 0;
  19. internal ISqlBuilder _sqlBuilder = new SqlBuilder();
  20. List<DbParam> _parameters = new List<DbParam>();
  21. DbValueExpressionVisitor _valueExpressionVisitor = null;
  22. static readonly Dictionary<string, Action<DbMethodCallExpression, SqlGenerator>> MethodHandlers = InitMethodHandlers();
  23. static readonly Dictionary<string, Action<DbAggregateExpression, SqlGenerator>> AggregateHandlers = InitAggregateHandlers();
  24. static readonly Dictionary<MethodInfo, Action<DbBinaryExpression, SqlGenerator>> BinaryWithMethodHandlers = InitBinaryWithMethodHandlers();
  25. static readonly Dictionary<Type, string> CastTypeMap = null;
  26. public static readonly ReadOnlyCollection<DbExpressionType> SafeDbExpressionTypes = null;
  27. static readonly List<string> CacheParameterNames = null;
  28. static SqlGenerator()
  29. {
  30. List<DbExpressionType> list = new List<DbExpressionType>();
  31. list.Add(DbExpressionType.MemberAccess);
  32. list.Add(DbExpressionType.ColumnAccess);
  33. list.Add(DbExpressionType.Constant);
  34. list.Add(DbExpressionType.Parameter);
  35. list.Add(DbExpressionType.Convert);
  36. SafeDbExpressionTypes = list.AsReadOnly();
  37. Dictionary<Type, string> castTypeMap = new Dictionary<Type, string>();
  38. //castTypeMap.Add(typeof(string), "NVARCHAR2"); // instead of using to_char(exp)
  39. castTypeMap.Add(typeof(byte), "NUMBER(3,0)");
  40. castTypeMap.Add(typeof(Int16), "NUMBER(4,0)");
  41. castTypeMap.Add(typeof(int), "NUMBER(9,0)");
  42. castTypeMap.Add(typeof(long), "NUMBER(18,0)");
  43. castTypeMap.Add(typeof(decimal), "NUMBER");
  44. castTypeMap.Add(typeof(double), "BINARY_DOUBLE");
  45. castTypeMap.Add(typeof(float), "BINARY_FLOAT");
  46. castTypeMap.Add(typeof(bool), "NUMBER(9,0)");
  47. //castTypeMap.Add(typeof(DateTime), "DATE"); // instead of using TO_TIMESTAMP(exp)
  48. //castTypeMap.Add(typeof(Guid), "BLOB");
  49. CastTypeMap = Utils.Clone(castTypeMap);
  50. int cacheParameterNameCount = 2 * 12;
  51. List<string> cacheParameterNames = new List<string>(cacheParameterNameCount);
  52. for (int i = 0; i < cacheParameterNameCount; i++)
  53. {
  54. string paramName = ParameterPrefix + i.ToString();
  55. cacheParameterNames.Add(paramName);
  56. }
  57. CacheParameterNames = cacheParameterNames;
  58. }
  59. public ISqlBuilder SqlBuilder { get { return this._sqlBuilder; } }
  60. public List<DbParam> Parameters { get { return this._parameters; } }
  61. DbValueExpressionVisitor ValueExpressionVisitor
  62. {
  63. get
  64. {
  65. if (this._valueExpressionVisitor == null)
  66. this._valueExpressionVisitor = new DbValueExpressionVisitor(this);
  67. return this._valueExpressionVisitor;
  68. }
  69. }
  70. public static SqlGenerator CreateInstance()
  71. {
  72. return new SqlGenerator();
  73. }
  74. public override DbExpression Visit(DbEqualExpression exp)
  75. {
  76. DbExpression left = exp.Left;
  77. DbExpression right = exp.Right;
  78. left = DbExpressionExtensions.ParseDbExpression(left);
  79. right = DbExpressionExtensions.ParseDbExpression(right);
  80. //明确 left right 其中一边一定为 null
  81. if (DbExpressionExtensions.AffirmExpressionRetValueIsNull(right))
  82. {
  83. left.Accept(this);
  84. this._sqlBuilder.Append(" IS NULL");
  85. return exp;
  86. }
  87. if (DbExpressionExtensions.AffirmExpressionRetValueIsNull(left))
  88. {
  89. right.Accept(this);
  90. this._sqlBuilder.Append(" IS NULL");
  91. return exp;
  92. }
  93. left.Accept(this);
  94. this._sqlBuilder.Append(" = ");
  95. right.Accept(this);
  96. return exp;
  97. }
  98. public override DbExpression Visit(DbNotEqualExpression exp)
  99. {
  100. DbExpression left = exp.Left;
  101. DbExpression right = exp.Right;
  102. left = DbExpressionExtensions.ParseDbExpression(left);
  103. right = DbExpressionExtensions.ParseDbExpression(right);
  104. //明确 left right 其中一边一定为 null
  105. if (DbExpressionExtensions.AffirmExpressionRetValueIsNull(right))
  106. {
  107. left.Accept(this);
  108. this._sqlBuilder.Append(" IS NOT NULL");
  109. return exp;
  110. }
  111. if (DbExpressionExtensions.AffirmExpressionRetValueIsNull(left))
  112. {
  113. right.Accept(this);
  114. this._sqlBuilder.Append(" IS NOT NULL");
  115. return exp;
  116. }
  117. left.Accept(this);
  118. this._sqlBuilder.Append(" <> ");
  119. right.Accept(this);
  120. return exp;
  121. }
  122. public override DbExpression Visit(DbNotExpression exp)
  123. {
  124. this._sqlBuilder.Append("NOT ");
  125. this._sqlBuilder.Append("(");
  126. exp.Operand.Accept(this);
  127. this._sqlBuilder.Append(")");
  128. return exp;
  129. }
  130. public override DbExpression Visit(DbAndExpression exp)
  131. {
  132. this._sqlBuilder.Append("BITAND(");
  133. exp.Left.Accept(this);
  134. this._sqlBuilder.Append(",");
  135. exp.Left.Accept(this);
  136. this._sqlBuilder.Append(")");
  137. return exp;
  138. }
  139. public override DbExpression Visit(DbAndAlsoExpression exp)
  140. {
  141. Stack<DbExpression> operands = GatherBinaryExpressionOperand(exp);
  142. this.ConcatOperands(operands, " AND ");
  143. return exp;
  144. }
  145. public override DbExpression Visit(DbOrExpression exp)
  146. {
  147. throw new NotSupportedException("'|' operator is not supported.");
  148. }
  149. public override DbExpression Visit(DbOrElseExpression exp)
  150. {
  151. Stack<DbExpression> operands = GatherBinaryExpressionOperand(exp);
  152. this.ConcatOperands(operands, " OR ");
  153. return exp;
  154. }
  155. // +
  156. public override DbExpression Visit(DbAddExpression exp)
  157. {
  158. MethodInfo method = exp.Method;
  159. if (method != null)
  160. {
  161. Action<DbBinaryExpression, SqlGenerator> handler;
  162. if (BinaryWithMethodHandlers.TryGetValue(method, out handler))
  163. {
  164. handler(exp, this);
  165. return exp;
  166. }
  167. throw UtilExceptions.NotSupportedMethod(exp.Method);
  168. }
  169. Stack<DbExpression> operands = GatherBinaryExpressionOperand(exp);
  170. this.ConcatOperands(operands, " + ");
  171. return exp;
  172. }
  173. // -
  174. public override DbExpression Visit(DbSubtractExpression exp)
  175. {
  176. Stack<DbExpression> operands = GatherBinaryExpressionOperand(exp);
  177. this.ConcatOperands(operands, " - ");
  178. return exp;
  179. }
  180. // *
  181. public override DbExpression Visit(DbMultiplyExpression exp)
  182. {
  183. Stack<DbExpression> operands = GatherBinaryExpressionOperand(exp);
  184. this.ConcatOperands(operands, " * ");
  185. return exp;
  186. }
  187. // /
  188. public override DbExpression Visit(DbDivideExpression exp)
  189. {
  190. Stack<DbExpression> operands = GatherBinaryExpressionOperand(exp);
  191. this.ConcatOperands(operands, " / ");
  192. return exp;
  193. }
  194. // <
  195. public override DbExpression Visit(DbLessThanExpression exp)
  196. {
  197. exp.Left.Accept(this);
  198. this._sqlBuilder.Append(" < ");
  199. exp.Right.Accept(this);
  200. return exp;
  201. }
  202. // <=
  203. public override DbExpression Visit(DbLessThanOrEqualExpression exp)
  204. {
  205. exp.Left.Accept(this);
  206. this._sqlBuilder.Append(" <= ");
  207. exp.Right.Accept(this);
  208. return exp;
  209. }
  210. // >
  211. public override DbExpression Visit(DbGreaterThanExpression exp)
  212. {
  213. exp.Left.Accept(this);
  214. this._sqlBuilder.Append(" > ");
  215. exp.Right.Accept(this);
  216. return exp;
  217. }
  218. // >=
  219. public override DbExpression Visit(DbGreaterThanOrEqualExpression exp)
  220. {
  221. exp.Left.Accept(this);
  222. this._sqlBuilder.Append(" >= ");
  223. exp.Right.Accept(this);
  224. return exp;
  225. }
  226. public override DbExpression Visit(DbAggregateExpression exp)
  227. {
  228. Action<DbAggregateExpression, SqlGenerator> aggregateHandler;
  229. if (!AggregateHandlers.TryGetValue(exp.Method.Name, out aggregateHandler))
  230. {
  231. throw UtilExceptions.NotSupportedMethod(exp.Method);
  232. }
  233. aggregateHandler(exp, this);
  234. return exp;
  235. }
  236. public override DbExpression Visit(DbTableExpression exp)
  237. {
  238. this.QuoteName(exp.Table.Name);
  239. return exp;
  240. }
  241. public override DbExpression Visit(DbColumnAccessExpression exp)
  242. {
  243. this.QuoteName(exp.Table.Name);
  244. this._sqlBuilder.Append(".");
  245. this.QuoteName(exp.Column.Name);
  246. return exp;
  247. }
  248. public override DbExpression Visit(DbFromTableExpression exp)
  249. {
  250. this.AppendTableSegment(exp.Table);
  251. this.VisitDbJoinTableExpressions(exp.JoinTables);
  252. return exp;
  253. }
  254. public override DbExpression Visit(DbJoinTableExpression exp)
  255. {
  256. DbJoinTableExpression joinTablePart = exp;
  257. string joinString = null;
  258. if (joinTablePart.JoinType == JoinType.InnerJoin)
  259. {
  260. joinString = " INNER JOIN ";
  261. }
  262. else if (joinTablePart.JoinType == JoinType.LeftJoin)
  263. {
  264. joinString = " LEFT JOIN ";
  265. }
  266. else if (joinTablePart.JoinType == JoinType.RightJoin)
  267. {
  268. joinString = " RIGHT JOIN ";
  269. }
  270. else if (joinTablePart.JoinType == JoinType.FullJoin)
  271. {
  272. joinString = " FULL JOIN ";
  273. }
  274. else
  275. throw new NotSupportedException("JoinType: " + joinTablePart.JoinType);
  276. this._sqlBuilder.Append(joinString);
  277. this.AppendTableSegment(joinTablePart.Table);
  278. this._sqlBuilder.Append(" ON ");
  279. joinTablePart.Condition.Accept(this);
  280. this.VisitDbJoinTableExpressions(joinTablePart.JoinTables);
  281. return exp;
  282. }
  283. public override DbExpression Visit(DbSubQueryExpression exp)
  284. {
  285. this._sqlBuilder.Append("(");
  286. exp.SqlQuery.Accept(this);
  287. this._sqlBuilder.Append(")");
  288. return exp;
  289. }
  290. public override DbExpression Visit(DbSqlQueryExpression exp)
  291. {
  292. if (exp.TakeCount != null)
  293. {
  294. DbSqlQueryExpression newSqlQuery = CloneWithoutLimitInfo(exp, "TTAKE");
  295. if (exp.SkipCount == null)
  296. AppendLimitCondition(newSqlQuery, exp.TakeCount.Value);
  297. else
  298. {
  299. AppendLimitCondition(newSqlQuery, exp.TakeCount.Value + exp.SkipCount.Value);
  300. newSqlQuery.SkipCount = exp.SkipCount.Value;
  301. }
  302. newSqlQuery.Accept(this);
  303. return exp;
  304. }
  305. else if (exp.SkipCount != null)
  306. {
  307. DbSqlQueryExpression subSqlQuery = CloneWithoutLimitInfo(exp, "TSKIP");
  308. string row_numberName = GenRowNumberName(subSqlQuery.ColumnSegments);
  309. DbColumnSegment row_numberSeg = new DbColumnSegment(OracleSemantics.DbMemberExpression_ROWNUM, row_numberName);
  310. subSqlQuery.ColumnSegments.Add(row_numberSeg);
  311. DbTable table = new DbTable("T");
  312. DbSqlQueryExpression newSqlQuery = WrapSqlQuery(subSqlQuery, table, exp.ColumnSegments);
  313. DbColumnAccessExpression columnAccessExp = new DbColumnAccessExpression(row_numberSeg.Body.Type, table, row_numberName);
  314. newSqlQuery.Condition = DbExpression.GreaterThan(columnAccessExp, DbExpression.Constant(exp.SkipCount.Value));
  315. newSqlQuery.Accept(this);
  316. return exp;
  317. }
  318. this.BuildGeneralSql(exp);
  319. return exp;
  320. }
  321. public override DbExpression Visit(DbInsertExpression exp)
  322. {
  323. this._sqlBuilder.Append("INSERT INTO ");
  324. this.QuoteName(exp.Table.Name);
  325. this._sqlBuilder.Append("(");
  326. bool first = true;
  327. foreach (var item in exp.InsertColumns)
  328. {
  329. if (first)
  330. first = false;
  331. else
  332. {
  333. this._sqlBuilder.Append(",");
  334. }
  335. this.QuoteName(item.Key.Name);
  336. }
  337. this._sqlBuilder.Append(")");
  338. this._sqlBuilder.Append(" VALUES(");
  339. first = true;
  340. foreach (var item in exp.InsertColumns)
  341. {
  342. if (first)
  343. first = false;
  344. else
  345. {
  346. this._sqlBuilder.Append(",");
  347. }
  348. item.Value.Accept(this.ValueExpressionVisitor);
  349. }
  350. this._sqlBuilder.Append(")");
  351. return exp;
  352. }
  353. public override DbExpression Visit(DbUpdateExpression exp)
  354. {
  355. this._sqlBuilder.Append("UPDATE ");
  356. this.QuoteName(exp.Table.Name);
  357. this._sqlBuilder.Append(" SET ");
  358. bool first = true;
  359. foreach (var item in exp.UpdateColumns)
  360. {
  361. if (first)
  362. first = false;
  363. else
  364. this._sqlBuilder.Append(",");
  365. this.QuoteName(item.Key.Name);
  366. this._sqlBuilder.Append("=");
  367. item.Value.Accept(this.ValueExpressionVisitor);
  368. }
  369. this.BuildWhereState(exp.Condition);
  370. return exp;
  371. }
  372. public override DbExpression Visit(DbDeleteExpression exp)
  373. {
  374. this._sqlBuilder.Append("DELETE FROM ");
  375. this.QuoteName(exp.Table.Name);
  376. this.BuildWhereState(exp.Condition);
  377. return exp;
  378. }
  379. // then 部分必须返回 C# type,所以得判断是否是诸如 a>1,a=b,in,like 等等的情况,如果是则将其构建成一个 case when
  380. public override DbExpression Visit(DbCaseWhenExpression exp)
  381. {
  382. this.LeftBracket();
  383. this._sqlBuilder.Append("CASE");
  384. foreach (var whenThen in exp.WhenThenPairs)
  385. {
  386. // then 部分得判断是否是诸如 a>1,a=b,in,like 等等的情况,如果是则将其构建成一个 case when
  387. this._sqlBuilder.Append(" WHEN ");
  388. whenThen.When.Accept(this);
  389. this._sqlBuilder.Append(" THEN ");
  390. EnsureDbExpressionReturnCSharpBoolean(whenThen.Then).Accept(this);
  391. }
  392. this._sqlBuilder.Append(" ELSE ");
  393. EnsureDbExpressionReturnCSharpBoolean(exp.Else).Accept(this);
  394. this._sqlBuilder.Append(" END");
  395. this.RightBracket();
  396. return exp;
  397. }
  398. public override DbExpression Visit(DbConvertExpression exp)
  399. {
  400. DbExpression stripedExp = DbExpressionHelper.StripInvalidConvert(exp);
  401. if (stripedExp.NodeType != DbExpressionType.Convert)
  402. {
  403. EnsureDbExpressionReturnCSharpBoolean(stripedExp).Accept(this);
  404. return exp;
  405. }
  406. exp = (DbConvertExpression)stripedExp;
  407. if (exp.Type == UtilConstants.TypeOfString)
  408. {
  409. this._sqlBuilder.Append("TO_CHAR(");
  410. exp.Operand.Accept(this);
  411. this._sqlBuilder.Append(")");
  412. return exp;
  413. }
  414. if (exp.Type == UtilConstants.TypeOfDateTime)
  415. {
  416. this._sqlBuilder.Append("TO_TIMESTAMP(");
  417. exp.Operand.Accept(this);
  418. this._sqlBuilder.Append(",'yyyy-mm-dd hh24:mi:ssxff')");
  419. return exp;
  420. }
  421. string dbTypeString;
  422. if (TryGetCastTargetDbTypeString(exp.Operand.Type, exp.Type, out dbTypeString, false))
  423. {
  424. this.BuildCastState(EnsureDbExpressionReturnCSharpBoolean(exp.Operand), dbTypeString);
  425. }
  426. else
  427. EnsureDbExpressionReturnCSharpBoolean(exp.Operand).Accept(this);
  428. return exp;
  429. }
  430. public override DbExpression Visit(DbMethodCallExpression exp)
  431. {
  432. Action<DbMethodCallExpression, SqlGenerator> methodHandler;
  433. if (!MethodHandlers.TryGetValue(exp.Method.Name, out methodHandler))
  434. {
  435. throw UtilExceptions.NotSupportedMethod(exp.Method);
  436. }
  437. methodHandler(exp, this);
  438. return exp;
  439. }
  440. public override DbExpression Visit(DbMemberExpression exp)
  441. {
  442. MemberInfo member = exp.Member;
  443. if (member == OracleSemantics.PropertyInfo_ROWNUM)
  444. {
  445. this._sqlBuilder.Append("ROWNUM");
  446. return exp;
  447. }
  448. if (member.DeclaringType == UtilConstants.TypeOfDateTime)
  449. {
  450. if (member == UtilConstants.PropertyInfo_DateTime_Now)
  451. {
  452. this._sqlBuilder.Append("SYSTIMESTAMP");
  453. return exp;
  454. }
  455. if (member == UtilConstants.PropertyInfo_DateTime_UtcNow)
  456. {
  457. this._sqlBuilder.Append("SYS_EXTRACT_UTC(SYSTIMESTAMP)");
  458. return exp;
  459. }
  460. if (member == UtilConstants.PropertyInfo_DateTime_Today)
  461. {
  462. //other way: this._sqlBuilder.Append("TO_DATE(TO_CHAR(SYSDATE,'yyyy-mm-dd'),'yyyy-mm-dd')");
  463. this._sqlBuilder.Append("TRUNC(SYSDATE,'DD')");
  464. return exp;
  465. }
  466. if (member == UtilConstants.PropertyInfo_DateTime_Date)
  467. {
  468. this._sqlBuilder.Append("TRUNC(");
  469. exp.Expression.Accept(this);
  470. this._sqlBuilder.Append(",'DD')");
  471. return exp;
  472. }
  473. if (this.IsDatePart(exp))
  474. {
  475. return exp;
  476. }
  477. }
  478. if (this.IsDateSubtract(exp))
  479. {
  480. return exp;
  481. }
  482. DbParameterExpression newExp;
  483. if (DbExpressionExtensions.TryParseToParameterExpression(exp, out newExp))
  484. {
  485. return newExp.Accept(this);
  486. }
  487. if (member.Name == "Length" && member.DeclaringType == UtilConstants.TypeOfString)
  488. {
  489. this._sqlBuilder.Append("LENGTH(");
  490. exp.Expression.Accept(this);
  491. this._sqlBuilder.Append(")");
  492. return exp;
  493. }
  494. else if (member.Name == "Value" && Utils.IsNullable(exp.Expression.Type))
  495. {
  496. exp.Expression.Accept(this);
  497. return exp;
  498. }
  499. throw new NotSupportedException(string.Format("'{0}.{1}' is not supported.", member.DeclaringType.FullName, member.Name));
  500. }
  501. public override DbExpression Visit(DbConstantExpression exp)
  502. {
  503. if (exp.Value == null || exp.Value == DBNull.Value)
  504. {
  505. this._sqlBuilder.Append("NULL");
  506. return exp;
  507. }
  508. var objType = exp.Value.GetType();
  509. if (objType == UtilConstants.TypeOfBoolean)
  510. {
  511. this._sqlBuilder.Append(((bool)exp.Value) ? "1" : "0");
  512. return exp;
  513. }
  514. else if (objType == UtilConstants.TypeOfString)
  515. {
  516. this._sqlBuilder.Append("N'", exp.Value, "'");
  517. return exp;
  518. }
  519. else if (objType.IsEnum)
  520. {
  521. this._sqlBuilder.Append(((int)exp.Value).ToString());
  522. return exp;
  523. }
  524. this._sqlBuilder.Append(exp.Value);
  525. return exp;
  526. }
  527. public override DbExpression Visit(DbParameterExpression exp)
  528. {
  529. object paramValue = exp.Value;
  530. Type paramType = exp.Type;
  531. if (paramType.IsEnum)
  532. {
  533. paramType = UtilConstants.TypeOfInt32;
  534. if (paramValue != null)
  535. {
  536. paramValue = (int)paramValue;
  537. }
  538. }
  539. else if (paramType == UtilConstants.TypeOfBoolean)
  540. {
  541. paramType = UtilConstants.TypeOfInt32;
  542. if (paramValue != null)
  543. {
  544. paramValue = (bool)paramValue ? Boxed_1 : Boxed_0;
  545. }
  546. }
  547. if (paramValue == null)
  548. paramValue = DBNull.Value;
  549. DbParam p;
  550. if (paramValue == DBNull.Value)
  551. {
  552. p = this._parameters.Where(a => Utils.AreEqual(a.Value, paramValue) && a.Type == paramType).FirstOrDefault();
  553. }
  554. else
  555. p = this._parameters.Where(a => Utils.AreEqual(a.Value, paramValue)).FirstOrDefault();
  556. if (p != null)
  557. {
  558. this._sqlBuilder.Append(p.Name);
  559. return exp;
  560. }
  561. string paramName = GenParameterName(this._parameters.Count);
  562. p = DbParam.Create(paramName, paramValue, paramType);
  563. if (paramValue.GetType() == UtilConstants.TypeOfString)
  564. {
  565. if (((string)paramValue).Length <= 4000)
  566. p.Size = 4000;
  567. }
  568. this._parameters.Add(p);
  569. this._sqlBuilder.Append(paramName);
  570. return exp;
  571. }
  572. void AppendTableSegment(DbTableSegment seg)
  573. {
  574. seg.Body.Accept(this);
  575. this._sqlBuilder.Append(" ");
  576. this.QuoteName(seg.Alias);
  577. }
  578. void AppendColumnSegment(DbColumnSegment seg)
  579. {
  580. seg.Body.Accept(this.ValueExpressionVisitor);
  581. this._sqlBuilder.Append(" AS ");
  582. this.QuoteName(seg.Alias);
  583. }
  584. void AppendOrdering(DbOrdering ordering)
  585. {
  586. if (ordering.OrderType == OrderType.Asc)
  587. {
  588. ordering.Expression.Accept(this);
  589. this._sqlBuilder.Append(" ASC");
  590. return;
  591. }
  592. else if (ordering.OrderType == OrderType.Desc)
  593. {
  594. ordering.Expression.Accept(this);
  595. this._sqlBuilder.Append(" DESC");
  596. return;
  597. }
  598. throw new NotSupportedException("OrderType: " + ordering.OrderType);
  599. }
  600. void VisitDbJoinTableExpressions(List<DbJoinTableExpression> tables)
  601. {
  602. foreach (var table in tables)
  603. {
  604. table.Accept(this);
  605. }
  606. }
  607. void BuildGeneralSql(DbSqlQueryExpression exp)
  608. {
  609. if (exp.TakeCount != null || exp.SkipCount != null)
  610. throw new ArgumentException();
  611. this._sqlBuilder.Append("SELECT ");
  612. List<DbColumnSegment> columns = exp.ColumnSegments;
  613. for (int i = 0; i < columns.Count; i++)
  614. {
  615. DbColumnSegment column = columns[i];
  616. if (i > 0)
  617. this._sqlBuilder.Append(",");
  618. this.AppendColumnSegment(column);
  619. }
  620. this._sqlBuilder.Append(" FROM ");
  621. exp.Table.Accept(this);
  622. this.BuildWhereState(exp.Condition);
  623. this.BuildGroupState(exp);
  624. this.BuildOrderState(exp.Orderings);
  625. }
  626. void BuildWhereState(DbExpression whereExpression)
  627. {
  628. if (whereExpression != null)
  629. {
  630. this._sqlBuilder.Append(" WHERE ");
  631. whereExpression.Accept(this);
  632. }
  633. }
  634. void BuildOrderState(List<DbOrdering> orderings)
  635. {
  636. if (orderings.Count > 0)
  637. {
  638. this._sqlBuilder.Append(" ORDER BY ");
  639. this.ConcatOrderings(orderings);
  640. }
  641. }
  642. void ConcatOrderings(List<DbOrdering> orderings)
  643. {
  644. for (int i = 0; i < orderings.Count; i++)
  645. {
  646. if (i > 0)
  647. {
  648. this._sqlBuilder.Append(",");
  649. }
  650. this.AppendOrdering(orderings[i]);
  651. }
  652. }
  653. void BuildGroupState(DbSqlQueryExpression exp)
  654. {
  655. var groupSegments = exp.GroupSegments;
  656. if (groupSegments.Count == 0)
  657. return;
  658. this._sqlBuilder.Append(" GROUP BY ");
  659. for (int i = 0; i < groupSegments.Count; i++)
  660. {
  661. if (i > 0)
  662. this._sqlBuilder.Append(",");
  663. groupSegments[i].Accept(this);
  664. }
  665. if (exp.HavingCondition != null)
  666. {
  667. this._sqlBuilder.Append(" HAVING ");
  668. exp.HavingCondition.Accept(this);
  669. }
  670. }
  671. protected virtual void QuoteName(string name)
  672. {
  673. if (string.IsNullOrEmpty(name))
  674. throw new ArgumentException("name");
  675. this._sqlBuilder.Append("\"", name, "\"");
  676. }
  677. void ConcatOperands(IEnumerable<DbExpression> operands, string connector)
  678. {
  679. this._sqlBuilder.Append("(");
  680. bool first = true;
  681. foreach (DbExpression operand in operands)
  682. {
  683. if (first)
  684. first = false;
  685. else
  686. this._sqlBuilder.Append(connector);
  687. operand.Accept(this);
  688. }
  689. this._sqlBuilder.Append(")");
  690. return;
  691. }
  692. void BuildCastState(DbExpression castExp, string targetDbTypeString)
  693. {
  694. this._sqlBuilder.Append("CAST(");
  695. castExp.Accept(this);
  696. this._sqlBuilder.Append(" AS ", targetDbTypeString, ")");
  697. }
  698. bool IsDatePart(DbMemberExpression exp)
  699. {
  700. MemberInfo member = exp.Member;
  701. if (member == UtilConstants.PropertyInfo_DateTime_Year)
  702. {
  703. DbFunction_DATEPART(this, "yyyy", exp.Expression);
  704. return true;
  705. }
  706. if (member == UtilConstants.PropertyInfo_DateTime_Month)
  707. {
  708. DbFunction_DATEPART(this, "mm", exp.Expression);
  709. return true;
  710. }
  711. if (member == UtilConstants.PropertyInfo_DateTime_Day)
  712. {
  713. DbFunction_DATEPART(this, "dd", exp.Expression);
  714. return true;
  715. }
  716. if (member == UtilConstants.PropertyInfo_DateTime_Hour)
  717. {
  718. DbFunction_DATEPART(this, "hh24", exp.Expression);
  719. return true;
  720. }
  721. if (member == UtilConstants.PropertyInfo_DateTime_Minute)
  722. {
  723. DbFunction_DATEPART(this, "mi", exp.Expression);
  724. return true;
  725. }
  726. if (member == UtilConstants.PropertyInfo_DateTime_Second)
  727. {
  728. DbFunction_DATEPART(this, "ss", exp.Expression);
  729. return true;
  730. }
  731. if (member == UtilConstants.PropertyInfo_DateTime_Millisecond)
  732. {
  733. /* exp.Expression must be TIMESTAMP,otherwise there will be an error occurred. */
  734. DbFunction_DATEPART(this, "ff3", exp.Expression, true);
  735. return true;
  736. }
  737. if (member == UtilConstants.PropertyInfo_DateTime_DayOfWeek)
  738. {
  739. // CAST(TO_CHAR(SYSDATE,'D') AS NUMBER) - 1
  740. this._sqlBuilder.Append("(");
  741. DbFunction_DATEPART(this, "D", exp.Expression);
  742. this._sqlBuilder.Append(" - 1");
  743. this._sqlBuilder.Append(")");
  744. return true;
  745. }
  746. return false;
  747. }
  748. bool IsDateSubtract(DbMemberExpression exp)
  749. {
  750. MemberInfo member = exp.Member;
  751. if (member.DeclaringType == UtilConstants.TypeOfTimeSpan)
  752. {
  753. if (exp.Expression.NodeType == DbExpressionType.Call)
  754. {
  755. DbMethodCallExpression dbMethodExp = (DbMethodCallExpression)exp.Expression;
  756. if (dbMethodExp.Method == UtilConstants.MethodInfo_DateTime_Subtract_DateTime)
  757. {
  758. int? intervalDivisor = null;
  759. if (member == UtilConstants.PropertyInfo_TimeSpan_TotalDays)
  760. {
  761. intervalDivisor = 24 * 60 * 60 * 1000;
  762. goto appendIntervalTime;
  763. }
  764. if (member == UtilConstants.PropertyInfo_TimeSpan_TotalHours)
  765. {
  766. intervalDivisor = 60 * 60 * 1000;
  767. goto appendIntervalTime;
  768. }
  769. if (member == UtilConstants.PropertyInfo_TimeSpan_TotalMinutes)
  770. {
  771. intervalDivisor = 60 * 1000;
  772. goto appendIntervalTime;
  773. }
  774. if (member == UtilConstants.PropertyInfo_TimeSpan_TotalSeconds)
  775. {
  776. intervalDivisor = 1000;
  777. goto appendIntervalTime;
  778. }
  779. if (member == UtilConstants.PropertyInfo_TimeSpan_TotalMilliseconds)
  780. {
  781. intervalDivisor = 1;
  782. goto appendIntervalTime;
  783. }
  784. return false;
  785. appendIntervalTime:
  786. this.CalcDateDiffPrecise(dbMethodExp.Object, dbMethodExp.Arguments[0], intervalDivisor.Value);
  787. return true;
  788. }
  789. }
  790. else
  791. {
  792. DbSubtractExpression dbSubtractExp = exp.Expression as DbSubtractExpression;
  793. if (dbSubtractExp != null && dbSubtractExp.Left.Type == UtilConstants.TypeOfDateTime && dbSubtractExp.Right.Type == UtilConstants.TypeOfDateTime)
  794. {
  795. DbMethodCallExpression dbMethodExp = new DbMethodCallExpression(dbSubtractExp.Left, UtilConstants.MethodInfo_DateTime_Subtract_DateTime, new List<DbExpression>(1) { dbSubtractExp.Right });
  796. DbMemberExpression dbMemberExp = DbExpression.MemberAccess(member, dbMethodExp);
  797. dbMemberExp.Accept(this);
  798. return true;
  799. }
  800. }
  801. }
  802. return false;
  803. }
  804. void CalcDateDiffPrecise(DbExpression dateTime1, DbExpression dateTime2, int divisor)
  805. {
  806. if (divisor == 1)
  807. {
  808. this.CalcDateDiffMillisecond(dateTime1, dateTime2);
  809. return;
  810. }
  811. this.LeftBracket();
  812. this.CalcDateDiffMillisecond(dateTime1, dateTime2);
  813. this._sqlBuilder.Append(" / ");
  814. this._sqlBuilder.Append(divisor.ToString());
  815. this.RightBracket();
  816. }
  817. void CalcDateDiffMillisecond(DbExpression dateTime1, DbExpression dateTime2)
  818. {
  819. /*
  820. * 计算两个日期相差的毫秒数:
  821. * (cast(dateTime1 as date)-cast(dateTime2 as date)) * 24 * 60 * 60 * 1000
  822. * +
  823. * cast(to_char(cast(dateTime1 as timestamp),'ff3') as number)
  824. * -
  825. * cast(to_char(cast(dateTime2 as timestamp),'ff3') as number)
  826. */
  827. this.LeftBracket();
  828. this.CalcDateDiffMillisecondSketchy(dateTime1, dateTime2);
  829. this._sqlBuilder.Append(" + ");
  830. this.ExtractMillisecondPart(dateTime1);
  831. this._sqlBuilder.Append(" - ");
  832. this.ExtractMillisecondPart(dateTime2);
  833. this.RightBracket();
  834. }
  835. void CalcDateDiffMillisecondSketchy(DbExpression dateTime1, DbExpression dateTime2)
  836. {
  837. /*
  838. * 计算去掉毫秒部分后两个日期相差的毫秒数:
  839. * (cast(dateTime1 as date)-cast(dateTime2 as date)) * 24 * 60 * 60 * 1000
  840. */
  841. this.LeftBracket();
  842. this.BuildCastState(dateTime1, "DATE");
  843. this._sqlBuilder.Append("-");
  844. this.BuildCastState(dateTime2, "DATE");
  845. this.RightBracket();
  846. this._sqlBuilder.Append(" * ");
  847. this._sqlBuilder.Append((24 * 60 * 60 * 1000).ToString());
  848. }
  849. void ExtractMillisecondPart(DbExpression dateTime)
  850. {
  851. /* 提取一个日期的毫秒部分:
  852. * cast(to_char(cast(dateTime as timestamp),'ff3') as number)
  853. */
  854. this._sqlBuilder.Append("CAST(");
  855. this._sqlBuilder.Append("TO_CHAR(");
  856. this.BuildCastState(dateTime, "TIMESTAMP");
  857. this._sqlBuilder.Append(",'ff3')");
  858. this._sqlBuilder.Append(" AS NUMBER)");
  859. }
  860. }
  861. }