1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.ibatis.scripting.xmltags;
17
18 import java.util.ArrayList;
19 import java.util.Collections;
20 import java.util.List;
21 import java.util.Locale;
22 import java.util.Map;
23 import java.util.StringTokenizer;
24
25 import org.apache.ibatis.session.Configuration;
26
27
28
29
30 public class TrimSqlNode implements SqlNode {
31
32 private final SqlNode contents;
33 private final String prefix;
34 private final String suffix;
35 private final List<String> prefixesToOverride;
36 private final List<String> suffixesToOverride;
37 private final Configuration configuration;
38
39 public TrimSqlNode(Configuration configuration, SqlNode contents, String prefix, String prefixesToOverride,
40 String suffix, String suffixesToOverride) {
41 this(configuration, contents, prefix, parseOverrides(prefixesToOverride), suffix,
42 parseOverrides(suffixesToOverride));
43 }
44
45 protected TrimSqlNode(Configuration configuration, SqlNode contents, String prefix, List<String> prefixesToOverride,
46 String suffix, List<String> suffixesToOverride) {
47 this.contents = contents;
48 this.prefix = prefix;
49 this.prefixesToOverride = prefixesToOverride;
50 this.suffix = suffix;
51 this.suffixesToOverride = suffixesToOverride;
52 this.configuration = configuration;
53 }
54
55 @Override
56 public boolean apply(DynamicContext context) {
57 FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context);
58 boolean result = contents.apply(filteredDynamicContext);
59 filteredDynamicContext.applyAll();
60 return result;
61 }
62
63 private static List<String> parseOverrides(String overrides) {
64 if (overrides != null) {
65 final StringTokenizer parser = new StringTokenizer(overrides, "|", false);
66 final List<String> list = new ArrayList<>(parser.countTokens());
67 while (parser.hasMoreTokens()) {
68 list.add(parser.nextToken().toUpperCase(Locale.ENGLISH));
69 }
70 return list;
71 }
72 return Collections.emptyList();
73 }
74
75 private class FilteredDynamicContext extends DynamicContext {
76 private final DynamicContext delegate;
77 private boolean prefixApplied;
78 private boolean suffixApplied;
79 private StringBuilder sqlBuffer;
80
81 public FilteredDynamicContext(DynamicContext delegate) {
82 super(configuration, null);
83 this.delegate = delegate;
84 this.prefixApplied = false;
85 this.suffixApplied = false;
86 this.sqlBuffer = new StringBuilder();
87 }
88
89 public void applyAll() {
90 sqlBuffer = new StringBuilder(sqlBuffer.toString().trim());
91 String trimmedUppercaseSql = sqlBuffer.toString().toUpperCase(Locale.ENGLISH);
92 if (trimmedUppercaseSql.length() > 0) {
93 applyPrefix(sqlBuffer, trimmedUppercaseSql);
94 applySuffix(sqlBuffer, trimmedUppercaseSql);
95 }
96 delegate.appendSql(sqlBuffer.toString());
97 }
98
99 @Override
100 public Map<String, Object> getBindings() {
101 return delegate.getBindings();
102 }
103
104 @Override
105 public void bind(String name, Object value) {
106 delegate.bind(name, value);
107 }
108
109 @Override
110 public int getUniqueNumber() {
111 return delegate.getUniqueNumber();
112 }
113
114 @Override
115 public void appendSql(String sql) {
116 sqlBuffer.append(sql);
117 }
118
119 @Override
120 public String getSql() {
121 return delegate.getSql();
122 }
123
124 private void applyPrefix(StringBuilder sql, String trimmedUppercaseSql) {
125 if (prefixApplied) {
126 return;
127 }
128 prefixApplied = true;
129 if (prefixesToOverride != null) {
130 prefixesToOverride.stream().filter(trimmedUppercaseSql::startsWith).findFirst()
131 .ifPresent(toRemove -> sql.delete(0, toRemove.trim().length()));
132 }
133 if (prefix != null) {
134 sql.insert(0, " ").insert(0, prefix);
135 }
136 }
137
138 private void applySuffix(StringBuilder sql, String trimmedUppercaseSql) {
139 if (suffixApplied) {
140 return;
141 }
142 suffixApplied = true;
143 if (suffixesToOverride != null) {
144 suffixesToOverride.stream()
145 .filter(toRemove -> trimmedUppercaseSql.endsWith(toRemove) || trimmedUppercaseSql.endsWith(toRemove.trim()))
146 .findFirst().ifPresent(toRemove -> {
147 int start = sql.length() - toRemove.trim().length();
148 int end = sql.length();
149 sql.delete(start, end);
150 });
151 }
152 if (suffix != null) {
153 sql.append(" ").append(suffix);
154 }
155 }
156
157 }
158
159 }