1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.command.dml; |
7 | |
8 | import java.util.Map; |
9 | import java.util.TreeMap; |
10 | import java.util.Map.Entry; |
11 | import org.h2.command.CommandInterface; |
12 | import org.h2.command.Prepared; |
13 | import org.h2.engine.Database; |
14 | import org.h2.engine.Session; |
15 | import org.h2.expression.Expression; |
16 | import org.h2.expression.ExpressionColumn; |
17 | import org.h2.mvstore.db.MVTableEngine.Store; |
18 | import org.h2.result.LocalResult; |
19 | import org.h2.result.ResultInterface; |
20 | import org.h2.store.PageStore; |
21 | import org.h2.table.Column; |
22 | import org.h2.value.Value; |
23 | import org.h2.value.ValueString; |
24 | |
25 | /** |
26 | * This class represents the statement |
27 | * EXPLAIN |
28 | */ |
29 | public class Explain extends Prepared { |
30 | |
31 | private Prepared command; |
32 | private LocalResult result; |
33 | private boolean executeCommand; |
34 | |
35 | public Explain(Session session) { |
36 | super(session); |
37 | } |
38 | |
39 | public void setCommand(Prepared command) { |
40 | this.command = command; |
41 | } |
42 | |
43 | @Override |
44 | public void prepare() { |
45 | command.prepare(); |
46 | } |
47 | |
48 | public void setExecuteCommand(boolean executeCommand) { |
49 | this.executeCommand = executeCommand; |
50 | } |
51 | |
52 | @Override |
53 | public ResultInterface queryMeta() { |
54 | return query(-1); |
55 | } |
56 | |
57 | @Override |
58 | public ResultInterface query(int maxrows) { |
59 | Column column = new Column("PLAN", Value.STRING); |
60 | Database db = session.getDatabase(); |
61 | ExpressionColumn expr = new ExpressionColumn(db, column); |
62 | Expression[] expressions = { expr }; |
63 | result = new LocalResult(session, expressions, 1); |
64 | if (maxrows >= 0) { |
65 | String plan; |
66 | if (executeCommand) { |
67 | PageStore store = null; |
68 | Store mvStore = null; |
69 | if (db.isPersistent()) { |
70 | store = db.getPageStore(); |
71 | if (store != null) { |
72 | store.statisticsStart(); |
73 | } |
74 | mvStore = db.getMvStore(); |
75 | if (mvStore != null) { |
76 | mvStore.statisticsStart(); |
77 | } |
78 | } |
79 | if (command.isQuery()) { |
80 | command.query(maxrows); |
81 | } else { |
82 | command.update(); |
83 | } |
84 | plan = command.getPlanSQL(); |
85 | Map<String, Integer> statistics = null; |
86 | if (store != null) { |
87 | statistics = store.statisticsEnd(); |
88 | } else if (mvStore != null) { |
89 | statistics = mvStore.statisticsEnd(); |
90 | } |
91 | if (statistics != null) { |
92 | int total = 0; |
93 | for (Entry<String, Integer> e : statistics.entrySet()) { |
94 | total += e.getValue(); |
95 | } |
96 | if (total > 0) { |
97 | statistics = new TreeMap<String, Integer>(statistics); |
98 | StringBuilder buff = new StringBuilder(); |
99 | if (statistics.size() > 1) { |
100 | buff.append("total: ").append(total).append('\n'); |
101 | } |
102 | for (Entry<String, Integer> e : statistics.entrySet()) { |
103 | int value = e.getValue(); |
104 | int percent = (int) (100L * value / total); |
105 | buff.append(e.getKey()).append(": ").append(value); |
106 | if (statistics.size() > 1) { |
107 | buff.append(" (").append(percent).append("%)"); |
108 | } |
109 | buff.append('\n'); |
110 | } |
111 | plan += "\n/*\n" + buff.toString() + "*/"; |
112 | } |
113 | } |
114 | } else { |
115 | plan = command.getPlanSQL(); |
116 | } |
117 | add(plan); |
118 | } |
119 | result.done(); |
120 | return result; |
121 | } |
122 | |
123 | private void add(String text) { |
124 | Value[] row = { ValueString.get(text) }; |
125 | result.addRow(row); |
126 | } |
127 | |
128 | @Override |
129 | public boolean isQuery() { |
130 | return true; |
131 | } |
132 | |
133 | @Override |
134 | public boolean isTransactional() { |
135 | return true; |
136 | } |
137 | |
138 | @Override |
139 | public boolean isReadOnly() { |
140 | return command.isReadOnly(); |
141 | } |
142 | |
143 | @Override |
144 | public int getType() { |
145 | return CommandInterface.EXPLAIN; |
146 | } |
147 | } |