1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package com.ibatis.sqlmap.engine.mapping.sql.dynamic;
17
18 import com.ibatis.sqlmap.engine.impl.SqlMapExecutorDelegate;
19 import com.ibatis.sqlmap.engine.mapping.parameter.InlineParameterMapParser;
20 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMap;
21 import com.ibatis.sqlmap.engine.mapping.parameter.ParameterMapping;
22 import com.ibatis.sqlmap.engine.mapping.result.ResultMap;
23 import com.ibatis.sqlmap.engine.mapping.sql.Sql;
24 import com.ibatis.sqlmap.engine.mapping.sql.SqlChild;
25 import com.ibatis.sqlmap.engine.mapping.sql.SqlText;
26 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.DynamicParent;
27 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.IterateContext;
28 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.SqlTag;
29 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.SqlTagContext;
30 import com.ibatis.sqlmap.engine.mapping.sql.dynamic.elements.SqlTagHandler;
31 import com.ibatis.sqlmap.engine.mapping.sql.simple.SimpleDynamicSql;
32 import com.ibatis.sqlmap.engine.scope.StatementScope;
33
34 import java.io.PrintWriter;
35 import java.io.StringWriter;
36 import java.util.ArrayList;
37 import java.util.Iterator;
38 import java.util.List;
39
40
41
42
43 public class DynamicSql implements Sql, DynamicParent {
44
45
46 private static final InlineParameterMapParser PARAM_PARSER = new InlineParameterMapParser();
47
48
49 private List children = new ArrayList<>();
50
51
52 private SqlMapExecutorDelegate delegate;
53
54
55
56
57
58
59
60 public DynamicSql(SqlMapExecutorDelegate delegate) {
61 this.delegate = delegate;
62 }
63
64 @Override
65 public String getSql(StatementScope statementScope, Object parameterObject) {
66 String sql = statementScope.getDynamicSql();
67 if (sql == null) {
68 process(statementScope, parameterObject);
69 sql = statementScope.getDynamicSql();
70 }
71 return sql;
72 }
73
74 @Override
75 public ParameterMap getParameterMap(StatementScope statementScope, Object parameterObject) {
76 ParameterMap map = statementScope.getDynamicParameterMap();
77 if (map == null) {
78 process(statementScope, parameterObject);
79 map = statementScope.getDynamicParameterMap();
80 }
81 return map;
82 }
83
84 @Override
85 public ResultMap getResultMap(StatementScope statementScope, Object parameterObject) {
86 return statementScope.getResultMap();
87 }
88
89 @Override
90 public void cleanup(StatementScope statementScope) {
91 statementScope.setDynamicSql(null);
92 statementScope.setDynamicParameterMap(null);
93 }
94
95
96
97
98
99
100
101
102
103 private void process(StatementScope statementScope, Object parameterObject) {
104 SqlTagContext ctx = new SqlTagContext();
105 List localChildren = children;
106 processBodyChildren(statementScope, ctx, parameterObject, localChildren.iterator());
107
108 ParameterMap map = new ParameterMap(delegate);
109 map.setId(statementScope.getStatement().getId() + "-InlineParameterMap");
110 map.setParameterClass(statementScope.getStatement().getParameterClass());
111 map.setParameterMappingList(ctx.getParameterMappings());
112
113 String dynSql = ctx.getBodyText();
114
115
116 if (SimpleDynamicSql.isSimpleDynamicSql(dynSql)) {
117 dynSql = new SimpleDynamicSql(delegate, dynSql).getSql(statementScope, parameterObject);
118 }
119
120 statementScope.setDynamicSql(dynSql);
121 statementScope.setDynamicParameterMap(map);
122 }
123
124
125
126
127
128
129
130
131
132
133
134
135
136 private void processBodyChildren(StatementScope statementScope, SqlTagContext ctx, Object parameterObject,
137 Iterator localChildren) {
138 PrintWriter out = ctx.getWriter();
139 processBodyChildren(statementScope, ctx, parameterObject, localChildren, out);
140 }
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156 private void processBodyChildren(StatementScope statementScope, SqlTagContext ctx, Object parameterObject,
157 Iterator localChildren, PrintWriter out) {
158 while (localChildren.hasNext()) {
159 SqlChild child = (SqlChild) localChildren.next();
160 if (child instanceof SqlText) {
161 SqlText sqlText = (SqlText) child;
162 String sqlStatement = sqlText.getText();
163 if (sqlText.isWhiteSpace()) {
164 out.print(sqlStatement);
165 } else if (!sqlText.isPostParseRequired()) {
166
167
168 out.print(sqlStatement);
169
170 ParameterMapping[] mappings = sqlText.getParameterMappings();
171 if (mappings != null) {
172 for (ParameterMapping mapping : mappings) {
173 ctx.addParameterMapping(mapping);
174 }
175 }
176 } else {
177
178 IterateContext itCtx = ctx.peekIterateContext();
179
180 if (null != itCtx && itCtx.isAllowNext()) {
181 itCtx.next();
182 itCtx.setAllowNext(false);
183 if (!itCtx.hasNext()) {
184 itCtx.setFinal(true);
185 }
186 }
187
188 if (itCtx != null) {
189 StringBuilder sqlStatementBuffer = new StringBuilder(sqlStatement);
190 iteratePropertyReplace(sqlStatementBuffer, itCtx);
191 sqlStatement = sqlStatementBuffer.toString();
192 }
193
194 sqlText = PARAM_PARSER.parseInlineParameterMap(delegate.getTypeHandlerFactory(), sqlStatement);
195
196 ParameterMapping[] mappings = sqlText.getParameterMappings();
197 out.print(sqlText.getText());
198 if (mappings != null) {
199 for (ParameterMapping mapping : mappings) {
200 ctx.addParameterMapping(mapping);
201 }
202 }
203 }
204 } else if (child instanceof SqlTag) {
205 SqlTag tag = (SqlTag) child;
206 SqlTagHandler handler = tag.getHandler();
207 int response = SqlTagHandler.INCLUDE_BODY;
208 do {
209 StringWriter sw = new StringWriter();
210 PrintWriter pw = new PrintWriter(sw);
211
212 response = handler.doStartFragment(ctx, tag, parameterObject);
213 if (response != SqlTagHandler.SKIP_BODY) {
214
215 processBodyChildren(statementScope, ctx, parameterObject, tag.getChildren(), pw);
216 pw.flush();
217 pw.close();
218 StringBuilder body = new StringBuilder(sw.getBuffer());
219 response = handler.doEndFragment(ctx, tag, parameterObject, body);
220 handler.doPrepend(ctx, tag, parameterObject, body);
221
222 if (response != SqlTagHandler.SKIP_BODY && body.length() > 0) {
223 out.print(body.toString());
224 }
225
226 }
227 } while (response == SqlTagHandler.REPEAT_BODY);
228
229 ctx.popRemoveFirstPrependMarker(tag);
230
231 if (ctx.peekIterateContext() != null && ctx.peekIterateContext().getTag() == tag) {
232 ctx.setAttribute(ctx.peekIterateContext().getTag(), null);
233 ctx.popIterateContext();
234 }
235
236 }
237 }
238 }
239
240
241
242
243
244
245
246
247
248 protected void iteratePropertyReplace(StringBuilder bodyContent, IterateContext iterate) {
249 if (iterate != null) {
250 String[] mappings = { "#", "$" };
251 for (String mapping : mappings) {
252 int startIndex = 0;
253 int endIndex = -1;
254 while (startIndex > -1 && startIndex < bodyContent.length()) {
255 startIndex = bodyContent.indexOf(mapping, endIndex + 1);
256 endIndex = bodyContent.indexOf(mapping, startIndex + 1);
257 if (startIndex > -1 && endIndex > -1) {
258 bodyContent.replace(startIndex + 1, endIndex,
259 iterate.addIndexToTagProperty(bodyContent.substring(startIndex + 1, endIndex)));
260 }
261 }
262 }
263 }
264 }
265
266
267
268
269
270
271
272
273
274
275
276 protected static void replace(StringBuilder builder, String find, String replace) {
277 int pos = builder.toString().indexOf(find);
278 int len = find.length();
279 while (pos > -1) {
280 builder.replace(pos, pos + len, replace);
281 pos = builder.toString().indexOf(find);
282 }
283 }
284
285 @Override
286 public void addChild(SqlChild child) {
287 children.add(child);
288 }
289
290 }