0
|
1 using System;
|
|
2 using System.Text;
|
|
3
|
|
4 using BLToolkit.Reflection;
|
|
5
|
|
6 namespace BLToolkit.Data.Sql.SqlProvider
|
|
7 {
|
|
8 using DataProvider;
|
|
9
|
|
10 public class DB2SqlProvider : BasicSqlProvider
|
|
11 {
|
|
12 public override bool TakeAcceptsParameter { get { return SqlQuery.Select.SkipValue != null; } }
|
|
13
|
|
14 SqlField _identityField;
|
|
15
|
|
16 public override int CommandCount(SqlQuery sqlQuery)
|
|
17 {
|
|
18 if (sqlQuery.IsInsert && sqlQuery.Insert.WithIdentity)
|
|
19 {
|
|
20 _identityField = sqlQuery.Insert.Into.GetIdentityField();
|
|
21
|
|
22 if (_identityField == null)
|
|
23 return 2;
|
|
24 }
|
|
25
|
|
26 return 1;
|
|
27 }
|
|
28
|
|
29 public override int BuildSql(int commandNumber, SqlQuery sqlQuery, StringBuilder sb, int indent, int nesting, bool skipAlias)
|
|
30 {
|
|
31 if (_identityField != null)
|
|
32 {
|
|
33 indent += 2;
|
|
34
|
|
35 AppendIndent(sb).AppendLine("SELECT");
|
|
36 AppendIndent(sb).Append("\t");
|
|
37 BuildExpression(sb, _identityField, false, true);
|
|
38 sb.AppendLine();
|
|
39 AppendIndent(sb).AppendLine("FROM");
|
|
40 AppendIndent(sb).AppendLine("\tNEW TABLE");
|
|
41 AppendIndent(sb).AppendLine("\t(");
|
|
42 }
|
|
43
|
|
44 var ret = base.BuildSql(commandNumber, sqlQuery, sb, indent, nesting, skipAlias);
|
|
45
|
|
46 if (_identityField != null)
|
|
47 sb.AppendLine("\t)");
|
|
48
|
|
49 return ret;
|
|
50 }
|
|
51
|
|
52 protected override void BuildCommand(int commandNumber, StringBuilder sb)
|
|
53 {
|
|
54 sb.AppendLine("SELECT identity_val_local() FROM SYSIBM.SYSDUMMY1");
|
|
55 }
|
|
56
|
|
57 protected override ISqlProvider CreateSqlProvider()
|
|
58 {
|
|
59 return new DB2SqlProvider();
|
|
60 }
|
|
61
|
|
62 protected override void BuildSql(StringBuilder sb)
|
|
63 {
|
|
64 AlternativeBuildSql(sb, false, base.BuildSql);
|
|
65 }
|
|
66
|
|
67 protected override void BuildSelectClause(StringBuilder sb)
|
|
68 {
|
|
69 if (SqlQuery.From.Tables.Count == 0)
|
|
70 {
|
|
71 AppendIndent(sb).AppendLine("SELECT");
|
|
72 BuildColumns(sb);
|
|
73 AppendIndent(sb).AppendLine("FROM SYSIBM.SYSDUMMY1 FETCH FIRST 1 ROW ONLY");
|
|
74 }
|
|
75 else
|
|
76 base.BuildSelectClause(sb);
|
|
77 }
|
|
78
|
|
79 protected override string LimitFormat
|
|
80 {
|
|
81 get { return SqlQuery.Select.SkipValue == null ? "FETCH FIRST {0} ROWS ONLY" : null; }
|
|
82 }
|
|
83
|
|
84 public override ISqlExpression ConvertExpression(ISqlExpression expr)
|
|
85 {
|
|
86 expr = base.ConvertExpression(expr);
|
|
87
|
|
88 if (expr is SqlBinaryExpression)
|
|
89 {
|
|
90 var be = (SqlBinaryExpression)expr;
|
|
91
|
|
92 switch (be.Operation)
|
|
93 {
|
|
94 case "%":
|
|
95 {
|
|
96 var expr1 = !TypeHelper.IsIntegerType(be.Expr1.SystemType) ? new SqlFunction(typeof(int), "Int", be.Expr1) : be.Expr1;
|
|
97 return new SqlFunction(be.SystemType, "Mod", expr1, be.Expr2);
|
|
98 }
|
|
99 case "&": return new SqlFunction(be.SystemType, "BitAnd", be.Expr1, be.Expr2);
|
|
100 case "|": return new SqlFunction(be.SystemType, "BitOr", be.Expr1, be.Expr2);
|
|
101 case "^": return new SqlFunction(be.SystemType, "BitXor", be.Expr1, be.Expr2);
|
|
102 case "+": return be.SystemType == typeof(string)? new SqlBinaryExpression(be.SystemType, be.Expr1, "||", be.Expr2, be.Precedence): expr;
|
|
103 }
|
|
104 }
|
|
105 else if (expr is SqlFunction)
|
|
106 {
|
|
107 var func = (SqlFunction) expr;
|
|
108
|
|
109 switch (func.Name)
|
|
110 {
|
|
111 case "Convert" :
|
|
112 if (TypeHelper.GetUnderlyingType(func.SystemType) == typeof(bool))
|
|
113 {
|
|
114 var ex = AlternativeConvertToBoolean(func, 1);
|
|
115 if (ex != null)
|
|
116 return ex;
|
|
117 }
|
|
118
|
|
119 if (func.Parameters[0] is SqlDataType)
|
|
120 {
|
|
121 var type = (SqlDataType)func.Parameters[0];
|
|
122
|
|
123 if (type.Type == typeof(string) && func.Parameters[1].SystemType != typeof(string))
|
|
124 return new SqlFunction(func.SystemType, "RTrim", new SqlFunction(typeof(string), "Char", func.Parameters[1]));
|
|
125
|
|
126 if (type.Length > 0)
|
|
127 return new SqlFunction(func.SystemType, type.SqlDbType.ToString(), func.Parameters[1], new SqlValue(type.Length));
|
|
128
|
|
129 if (type.Precision > 0)
|
|
130 return new SqlFunction(func.SystemType, type.SqlDbType.ToString(), func.Parameters[1], new SqlValue(type.Precision), new SqlValue(type.Scale));
|
|
131
|
|
132 return new SqlFunction(func.SystemType, type.SqlDbType.ToString(), func.Parameters[1]);
|
|
133 }
|
|
134
|
|
135 if (func.Parameters[0] is SqlFunction)
|
|
136 {
|
|
137 var f = (SqlFunction)func.Parameters[0];
|
|
138
|
|
139 return
|
|
140 f.Name == "Char" ?
|
|
141 new SqlFunction(func.SystemType, f.Name, func.Parameters[1]) :
|
|
142 f.Parameters.Length == 1 ?
|
|
143 new SqlFunction(func.SystemType, f.Name, func.Parameters[1], f.Parameters[0]) :
|
|
144 new SqlFunction(func.SystemType, f.Name, func.Parameters[1], f.Parameters[0], f.Parameters[1]);
|
|
145 }
|
|
146
|
|
147 {
|
|
148 var e = (SqlExpression)func.Parameters[0];
|
|
149 return new SqlFunction(func.SystemType, e.Expr, func.Parameters[1]);
|
|
150 }
|
|
151
|
|
152 case "Millisecond" : return Div(new SqlFunction(func.SystemType, "Microsecond", func.Parameters), 1000);
|
|
153 case "SmallDateTime" :
|
|
154 case "DateTime" :
|
|
155 case "DateTime2" : return new SqlFunction(func.SystemType, "TimeStamp", func.Parameters);
|
|
156 case "TinyInt" : return new SqlFunction(func.SystemType, "SmallInt", func.Parameters);
|
|
157 case "Money" : return new SqlFunction(func.SystemType, "Decimal", func.Parameters[0], new SqlValue(19), new SqlValue(4));
|
|
158 case "SmallMoney" : return new SqlFunction(func.SystemType, "Decimal", func.Parameters[0], new SqlValue(10), new SqlValue(4));
|
|
159 case "VarChar" :
|
|
160 if (TypeHelper.GetUnderlyingType(func.Parameters[0].SystemType) == typeof(decimal))
|
|
161 return new SqlFunction(func.SystemType, "Char", func.Parameters[0]);
|
|
162 break;
|
|
163 case "NChar" :
|
|
164 case "NVarChar" : return new SqlFunction(func.SystemType, "Char", func.Parameters);
|
|
165 case "DateDiff" :
|
|
166 {
|
|
167 switch ((Linq.Sql.DateParts)((SqlValue)func.Parameters[0]).Value)
|
|
168 {
|
|
169 case Linq.Sql.DateParts.Day : return new SqlExpression(typeof(int), "((Days({0}) - Days({1})) * 86400 + (MIDNIGHT_SECONDS({0}) - MIDNIGHT_SECONDS({1}))) / 86400", Precedence.Multiplicative, func.Parameters[2], func.Parameters[1]);
|
|
170 case Linq.Sql.DateParts.Hour : return new SqlExpression(typeof(int), "((Days({0}) - Days({1})) * 86400 + (MIDNIGHT_SECONDS({0}) - MIDNIGHT_SECONDS({1}))) / 3600", Precedence.Multiplicative, func.Parameters[2], func.Parameters[1]);
|
|
171 case Linq.Sql.DateParts.Minute : return new SqlExpression(typeof(int), "((Days({0}) - Days({1})) * 86400 + (MIDNIGHT_SECONDS({0}) - MIDNIGHT_SECONDS({1}))) / 60", Precedence.Multiplicative, func.Parameters[2], func.Parameters[1]);
|
|
172 case Linq.Sql.DateParts.Second : return new SqlExpression(typeof(int), "(Days({0}) - Days({1})) * 86400 + (MIDNIGHT_SECONDS({0}) - MIDNIGHT_SECONDS({1}))", Precedence.Additive, func.Parameters[2], func.Parameters[1]);
|
|
173 case Linq.Sql.DateParts.Millisecond : return new SqlExpression(typeof(int), "((Days({0}) - Days({1})) * 86400 + (MIDNIGHT_SECONDS({0}) - MIDNIGHT_SECONDS({1}))) * 1000 + (MICROSECOND({0}) - MICROSECOND({1})) / 1000", Precedence.Additive, func.Parameters[2], func.Parameters[1]);
|
|
174 }
|
|
175 }
|
|
176
|
|
177 break;
|
|
178 }
|
|
179 }
|
|
180
|
|
181 return expr;
|
|
182 }
|
|
183
|
|
184 protected override void BuildFunction(StringBuilder sb, SqlFunction func)
|
|
185 {
|
|
186 func = ConvertFunctionParameters(func);
|
|
187 base.BuildFunction(sb, func);
|
|
188 }
|
|
189
|
|
190 static void SetQueryParameter(IQueryElement element)
|
|
191 {
|
|
192 if (element.ElementType == QueryElementType.SqlParameter)
|
|
193 ((SqlParameter)element).IsQueryParameter = false;
|
|
194 }
|
|
195
|
|
196 public override SqlQuery Finalize(SqlQuery sqlQuery)
|
|
197 {
|
|
198 new QueryVisitor().Visit(sqlQuery.Select, SetQueryParameter);
|
|
199
|
|
200 //if (sqlQuery.QueryType == QueryType.InsertOrUpdate)
|
|
201 // foreach (var key in sqlQuery.Insert.Items)
|
|
202 // if (((SqlField)key.Column).IsPrimaryKey)
|
|
203 // new QueryVisitor().Visit(key.Expression, SetQueryParameter);
|
|
204
|
|
205 sqlQuery = base.Finalize(sqlQuery);
|
|
206
|
|
207 switch (sqlQuery.QueryType)
|
|
208 {
|
|
209 case QueryType.Delete : return GetAlternativeDelete(sqlQuery);
|
|
210 case QueryType.Update : return GetAlternativeUpdate(sqlQuery);
|
|
211 default : return sqlQuery;
|
|
212 }
|
|
213 }
|
|
214
|
|
215 protected override void BuildFromClause(StringBuilder sb)
|
|
216 {
|
|
217 if (!SqlQuery.IsUpdate)
|
|
218 base.BuildFromClause(sb);
|
|
219 }
|
|
220
|
|
221 public override void BuildValue(StringBuilder sb, object value)
|
|
222 {
|
|
223 if (value is Guid)
|
|
224 {
|
|
225 var s = ((Guid)value).ToString("N");
|
|
226
|
|
227 sb
|
|
228 .Append("Cast(x'")
|
|
229 .Append(s.Substring( 6, 2))
|
|
230 .Append(s.Substring( 4, 2))
|
|
231 .Append(s.Substring( 2, 2))
|
|
232 .Append(s.Substring( 0, 2))
|
|
233 .Append(s.Substring(10, 2))
|
|
234 .Append(s.Substring( 8, 2))
|
|
235 .Append(s.Substring(14, 2))
|
|
236 .Append(s.Substring(12, 2))
|
|
237 .Append(s.Substring(16, 16))
|
|
238 .Append("' as char(16) for bit data)");
|
|
239 }
|
|
240 else
|
|
241 base.BuildValue(sb, value);
|
|
242 }
|
|
243
|
|
244 protected override void BuildColumnExpression(StringBuilder sb, ISqlExpression expr, string alias, ref bool addAlias)
|
|
245 {
|
|
246 var wrap = false;
|
|
247
|
|
248 if (expr.SystemType == typeof(bool))
|
|
249 {
|
|
250 if (expr is SqlQuery.SearchCondition)
|
|
251 wrap = true;
|
|
252 else
|
|
253 {
|
|
254 var ex = expr as SqlExpression;
|
|
255 wrap = ex != null && ex.Expr == "{0}" && ex.Parameters.Length == 1 && ex.Parameters[0] is SqlQuery.SearchCondition;
|
|
256 }
|
|
257 }
|
|
258
|
|
259 if (wrap) sb.Append("CASE WHEN ");
|
|
260 base.BuildColumnExpression(sb, expr, alias, ref addAlias);
|
|
261 if (wrap) sb.Append(" THEN 1 ELSE 0 END");
|
|
262 }
|
|
263
|
|
264 public static bool QuoteIdentifiers = true;
|
|
265
|
|
266 public override object Convert(object value, ConvertType convertType)
|
|
267 {
|
|
268 switch (convertType)
|
|
269 {
|
|
270 case ConvertType.NameToQueryParameter:
|
|
271 return "@" + value;
|
|
272
|
|
273 case ConvertType.NameToCommandParameter:
|
|
274 case ConvertType.NameToSprocParameter:
|
|
275 return ":" + value;
|
|
276
|
|
277 case ConvertType.SprocParameterToName:
|
|
278 if (value != null)
|
|
279 {
|
|
280 var str = value.ToString();
|
|
281 return str.Length > 0 && str[0] == ':'? str.Substring(1): str;
|
|
282 }
|
|
283
|
|
284 break;
|
|
285
|
|
286 case ConvertType.NameToQueryField:
|
|
287 case ConvertType.NameToQueryFieldAlias:
|
|
288 case ConvertType.NameToQueryTable:
|
|
289 case ConvertType.NameToQueryTableAlias:
|
|
290 if (QuoteIdentifiers)
|
|
291 {
|
|
292 var name = value.ToString();
|
|
293
|
|
294 if (name.Length > 0 && name[0] == '"')
|
|
295 return value;
|
|
296
|
|
297 return '"' + name + '"';
|
|
298 }
|
|
299
|
|
300 break;
|
|
301 }
|
|
302
|
|
303 return value;
|
|
304 }
|
|
305
|
|
306 protected override void BuildInsertOrUpdateQuery(StringBuilder sb)
|
|
307 {
|
|
308 BuildInsertOrUpdateQueryAsMerge(sb, "FROM SYSIBM.SYSDUMMY1 FETCH FIRST 1 ROW ONLY");
|
|
309 }
|
|
310
|
|
311 protected override void BuildEmptyInsert(StringBuilder sb)
|
|
312 {
|
|
313 sb.Append("VALUES ");
|
|
314
|
|
315 foreach (var col in SqlQuery.Insert.Into.Fields)
|
|
316 sb.Append("(DEFAULT)");
|
|
317
|
|
318 sb.AppendLine();
|
|
319 }
|
|
320 }
|
|
321 }
|