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.ddl; |
7 | |
8 | import java.util.ArrayList; |
9 | import org.h2.command.CommandInterface; |
10 | import org.h2.command.Prepared; |
11 | import org.h2.engine.Database; |
12 | import org.h2.engine.Right; |
13 | import org.h2.engine.Session; |
14 | import org.h2.expression.Parameter; |
15 | import org.h2.result.ResultInterface; |
16 | import org.h2.table.Column; |
17 | import org.h2.table.Table; |
18 | import org.h2.util.StatementBuilder; |
19 | import org.h2.value.Value; |
20 | import org.h2.value.ValueInt; |
21 | import org.h2.value.ValueNull; |
22 | |
23 | /** |
24 | * This class represents the statement |
25 | * ANALYZE |
26 | */ |
27 | public class Analyze extends DefineCommand { |
28 | |
29 | /** |
30 | * The sample size. |
31 | */ |
32 | private int sampleRows; |
33 | |
34 | public Analyze(Session session) { |
35 | super(session); |
36 | sampleRows = session.getDatabase().getSettings().analyzeSample; |
37 | } |
38 | |
39 | @Override |
40 | public int update() { |
41 | session.commit(true); |
42 | session.getUser().checkAdmin(); |
43 | Database db = session.getDatabase(); |
44 | for (Table table : db.getAllTablesAndViews(false)) { |
45 | analyzeTable(session, table, sampleRows, true); |
46 | } |
47 | return 0; |
48 | } |
49 | |
50 | /** |
51 | * Analyze this table. |
52 | * |
53 | * @param session the session |
54 | * @param table the table |
55 | * @param sample the number of sample rows |
56 | * @param manual whether the command was called by the user |
57 | */ |
58 | public static void analyzeTable(Session session, Table table, int sample, |
59 | boolean manual) { |
60 | if (!(table.getTableType().equals(Table.TABLE)) || |
61 | table.isHidden() || session == null) { |
62 | return; |
63 | } |
64 | if (!manual) { |
65 | if (session.getDatabase().isSysTableLocked()) { |
66 | return; |
67 | } |
68 | if (table.hasSelectTrigger()) { |
69 | return; |
70 | } |
71 | } |
72 | if (table.isTemporary() && !table.isGlobalTemporary() |
73 | && session.findLocalTempTable(table.getName()) == null) { |
74 | return; |
75 | } |
76 | if (table.isLockedExclusively() && !table.isLockedExclusivelyBy(session)) { |
77 | return; |
78 | } |
79 | if (!session.getUser().hasRight(table, Right.SELECT)) { |
80 | return; |
81 | } |
82 | if (session.getCancel() != 0) { |
83 | // if the connection is closed and there is something to undo |
84 | return; |
85 | } |
86 | Column[] columns = table.getColumns(); |
87 | if (columns.length == 0) { |
88 | return; |
89 | } |
90 | Database db = session.getDatabase(); |
91 | StatementBuilder buff = new StatementBuilder("SELECT "); |
92 | for (Column col : columns) { |
93 | buff.appendExceptFirst(", "); |
94 | int type = col.getType(); |
95 | if (type == Value.BLOB || type == Value.CLOB) { |
96 | // can not index LOB columns, so calculating |
97 | // the selectivity is not required |
98 | buff.append("MAX(NULL)"); |
99 | } else { |
100 | buff.append("SELECTIVITY(").append(col.getSQL()).append(')'); |
101 | } |
102 | } |
103 | buff.append(" FROM ").append(table.getSQL()); |
104 | if (sample > 0) { |
105 | buff.append(" LIMIT ? SAMPLE_SIZE ? "); |
106 | } |
107 | String sql = buff.toString(); |
108 | Prepared command = session.prepare(sql); |
109 | if (sample > 0) { |
110 | ArrayList<Parameter> params = command.getParameters(); |
111 | params.get(0).setValue(ValueInt.get(1)); |
112 | params.get(1).setValue(ValueInt.get(sample)); |
113 | } |
114 | ResultInterface result = command.query(0); |
115 | result.next(); |
116 | for (int j = 0; j < columns.length; j++) { |
117 | Value v = result.currentRow()[j]; |
118 | if (v != ValueNull.INSTANCE) { |
119 | int selectivity = v.getInt(); |
120 | columns[j].setSelectivity(selectivity); |
121 | } |
122 | } |
123 | if (manual) { |
124 | db.updateMeta(session, table); |
125 | } else { |
126 | Session sysSession = db.getSystemSession(); |
127 | if (sysSession != session) { |
128 | // if the current session is the system session |
129 | // (which is the case if we are within a trigger) |
130 | // then we can't update the statistics because |
131 | // that would unlock all locked objects |
132 | synchronized (sysSession) { |
133 | synchronized (db) { |
134 | db.updateMeta(sysSession, table); |
135 | sysSession.commit(true); |
136 | } |
137 | } |
138 | } |
139 | } |
140 | } |
141 | |
142 | public void setTop(int top) { |
143 | this.sampleRows = top; |
144 | } |
145 | |
146 | @Override |
147 | public int getType() { |
148 | return CommandInterface.ANALYZE; |
149 | } |
150 | |
151 | } |