17 package org.apache.calcite.prepare;
19 import com.google.common.collect.ImmutableList;
21 import org.apache.calcite.sql.SqlBasicCall;
22 import org.apache.calcite.sql.SqlDataTypeSpec;
23 import org.apache.calcite.sql.SqlDelete;
24 import org.apache.calcite.sql.SqlIdentifier;
25 import org.apache.calcite.sql.SqlInsert;
26 import org.apache.calcite.sql.SqlJoin;
27 import org.apache.calcite.sql.SqlKind;
28 import org.apache.calcite.sql.SqlLiteral;
29 import org.apache.calcite.sql.SqlNode;
30 import org.apache.calcite.sql.SqlNodeList;
31 import org.apache.calcite.sql.SqlOrderBy;
32 import org.apache.calcite.sql.SqlSelect;
33 import org.apache.calcite.sql.SqlUpdate;
34 import org.apache.calcite.sql.SqlWith;
35 import org.apache.calcite.sql.SqlWithItem;
36 import org.apache.calcite.sql.parser.SqlParser;
37 import org.slf4j.Logger;
38 import org.slf4j.LoggerFactory;
40 import java.lang.reflect.Method;
41 import java.lang.reflect.Modifier;
42 import java.util.Collection;
43 import java.util.HashSet;
44 import java.util.IdentityHashMap;
47 import java.util.Stack;
48 import java.util.concurrent.ConcurrentHashMap;
56 LoggerFactory.getLogger(SqlIdentifierCapturer.class);
59 new ConcurrentHashMap<>();
61 private IdentityHashMap<SqlNode, SqlNode>
visitedNodes =
new IdentityHashMap<>();
63 private Stack<Set<ImmutableList<String>>>
currentList =
new Stack<>();
66 public Set<ImmutableList<String>>
selects =
new HashSet<>();
67 public Set<ImmutableList<String>>
inserts =
new HashSet<>();
68 public Set<ImmutableList<String>>
updates =
new HashSet<>();
69 public Set<ImmutableList<String>>
deletes =
new HashSet<>();
71 private final Set<ImmutableList<String>>
ignore =
new HashSet<>();
73 { currentList.push(
ignore); }
80 if (root instanceof SqlLiteral || root instanceof SqlDataTypeSpec) {
88 if (root instanceof SqlNodeList) {
89 SqlNodeList snl = (SqlNodeList) root;
90 for (SqlNode node : snl) {
96 if (root instanceof SqlIdentifier) {
98 currentList.peek().add(((SqlIdentifier) root).names.reverse());
102 if (root instanceof SqlBasicCall) {
103 SqlBasicCall call = (SqlBasicCall) root;
104 if (call.getOperator().getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
109 if (call.operandCount() == 0) {
112 if (call.getOperands()[0].getKind() == SqlKind.CURSOR) {
113 SqlBasicCall cursor_call = (SqlBasicCall) call.getOperands()[0];
114 if (cursor_call.operandCount() == 0) {
117 scan(cursor_call.getOperands()[0]);
122 }
else if (call.getOperator().getKind() == SqlKind.AS) {
124 scan(call.getOperands()[0]);
129 if (root instanceof SqlOrderBy) {
130 scan(((SqlOrderBy) root).fetch);
131 scan(((SqlOrderBy) root).offset);
132 scan(((SqlOrderBy) root).query);
136 boolean needsPop =
false;
137 if (root instanceof SqlSelect) {
139 scan(((SqlSelect) root).getFrom());
143 }
else if (root instanceof SqlInsert) {
145 scan(((SqlInsert) root).getTargetTable());
149 }
else if (root instanceof SqlUpdate) {
151 scan(((SqlUpdate) root).getTargetTable());
155 }
else if (root instanceof SqlDelete) {
157 scan(((SqlDelete) root).getTargetTable());
161 }
else if (root instanceof SqlJoin) {
163 scan(((SqlJoin) root).getCondition());
168 for (Method m : methods) {
171 value = m.invoke(
root);
172 }
catch (Exception e) {
175 if (value instanceof SqlNode[]) {
176 SqlNode[] nodes = (SqlNode[]) value;
177 for (SqlNode node : nodes) {
180 }
else if (value instanceof SqlNode) {
181 scan((SqlNode) value);
182 }
else if (value instanceof Collection) {
183 for (Object vobj : ((Collection<?>) value)) {
184 if (vobj instanceof SqlNode) {
185 scan((SqlNode) vobj);
191 if (root instanceof SqlWith) {
192 SqlWith with = (SqlWith) root;
194 for (SqlNode node : with.withList) {
195 SqlWithItem item = (SqlWithItem) node;
196 selects.remove(((SqlIdentifier) item.name).names.reverse());
206 Class<?>
root = obj.getClass();
208 Set<Method> methods = GETTERS_CACHE.get(
root);
209 if (null != methods) {
212 methods =
new HashSet<>();
215 while (root != null) {
216 if (root == SqlNode.class)
break;
218 for (Method m : root.getDeclaredMethods()) {
219 if (m.getParameterTypes().length > 0)
continue;
221 if (!Modifier.isPublic(m.getModifiers()))
continue;
223 Class<?> returnType = m.getReturnType();
224 if (!SqlNode.class.isAssignableFrom(returnType) && SqlNode[].class != returnType
225 && !Collection.class.isAssignableFrom(returnType)) {
232 root = root.getSuperclass();
235 GETTERS_CACHE.put(obj.getClass(), methods);
242 out +=
" Selects: " +
selects +
"\n";
243 out +=
" Inserts: " +
inserts +
"\n";
244 out +=
" Updates: " +
updates +
"\n";
245 out +=
" Deletes: " +
deletes +
"\n";
246 out +=
" Ignore : " +
ignore +
"\n";
251 public static void main(String[]
args)
throws Exception {
252 String sql =
"UPDATE sales set f=(SELECT max(r.num) from report as r)";
253 sql =
"INSER INTO sales (a, b, c ) VALUES(10, (SELECT max(foo) from bob), 0)";
254 sql =
"SELECT * FROM sales a left outer join (select (select max(id) from rupert) from report2) r on a.id=(select max(r.di) from test)";
256 SqlParser
parser = SqlParser.create(sql);
259 capturer.scan(parser.parseQuery());
261 System.out.println(capturer.selects);
262 System.out.println(capturer.inserts);
263 System.out.println(capturer.updates);
264 System.out.println(capturer.deletes);
265 System.out.println(capturer.ignore);
static void main(String[] args)
Set< ImmutableList< String > > deletes
Set< ImmutableList< String > > updates
final Set< ImmutableList< String > > ignore
static final Map< Class<?>, Set< Method > > GETTERS_CACHE
static final Logger HEAVYDBLOGGER
Set< ImmutableList< String > > inserts
IdentityHashMap< SqlNode, SqlNode > visitedNodes
Set< ImmutableList< String > > selects
Set< Method > getRelevantGetters(Object obj)
Stack< Set< ImmutableList< String > > > currentList