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.table; |
7 | |
8 | import java.util.ArrayList; |
9 | |
10 | import org.h2.api.ErrorCode; |
11 | import org.h2.engine.Session; |
12 | import org.h2.expression.Expression; |
13 | import org.h2.index.Index; |
14 | import org.h2.index.IndexType; |
15 | import org.h2.index.RangeIndex; |
16 | import org.h2.message.DbException; |
17 | import org.h2.result.Row; |
18 | import org.h2.schema.Schema; |
19 | import org.h2.value.Value; |
20 | |
21 | /** |
22 | * The table SYSTEM_RANGE is a virtual table that generates incrementing numbers |
23 | * with a given start end end point. |
24 | */ |
25 | public class RangeTable extends Table { |
26 | |
27 | /** |
28 | * The name of the range table. |
29 | */ |
30 | public static final String NAME = "SYSTEM_RANGE"; |
31 | |
32 | /** |
33 | * The PostgreSQL alias for the range table. |
34 | */ |
35 | public static final String ALIAS = "GENERATE_SERIES"; |
36 | |
37 | private Expression min, max, step; |
38 | private boolean optimized; |
39 | |
40 | /** |
41 | * Create a new range with the given start and end expressions. |
42 | * |
43 | * @param schema the schema (always the main schema) |
44 | * @param min the start expression |
45 | * @param max the end expression |
46 | * @param noColumns whether this table has no columns |
47 | */ |
48 | public RangeTable(Schema schema, Expression min, Expression max, |
49 | boolean noColumns) { |
50 | super(schema, 0, NAME, true, true); |
51 | Column[] cols = noColumns ? new Column[0] : new Column[] { new Column( |
52 | "X", Value.LONG) }; |
53 | this.min = min; |
54 | this.max = max; |
55 | setColumns(cols); |
56 | } |
57 | |
58 | public RangeTable(Schema schema, Expression min, Expression max, |
59 | Expression step, boolean noColumns) { |
60 | this(schema, min, max, noColumns); |
61 | this.step = step; |
62 | } |
63 | |
64 | @Override |
65 | public String getDropSQL() { |
66 | return null; |
67 | } |
68 | |
69 | @Override |
70 | public String getCreateSQL() { |
71 | return null; |
72 | } |
73 | |
74 | @Override |
75 | public String getSQL() { |
76 | String sql = NAME + "(" + min.getSQL() + ", " + max.getSQL(); |
77 | if (step != null) { |
78 | sql += ", " + step.getSQL(); |
79 | } |
80 | return sql + ")"; |
81 | } |
82 | |
83 | @Override |
84 | public boolean lock(Session session, boolean exclusive, boolean forceLockEvenInMvcc) { |
85 | // nothing to do |
86 | return false; |
87 | } |
88 | |
89 | @Override |
90 | public void close(Session session) { |
91 | // nothing to do |
92 | } |
93 | |
94 | @Override |
95 | public void unlock(Session s) { |
96 | // nothing to do |
97 | } |
98 | |
99 | @Override |
100 | public boolean isLockedExclusively() { |
101 | return false; |
102 | } |
103 | |
104 | @Override |
105 | public Index addIndex(Session session, String indexName, |
106 | int indexId, IndexColumn[] cols, IndexType indexType, |
107 | boolean create, String indexComment) { |
108 | throw DbException.getUnsupportedException("SYSTEM_RANGE"); |
109 | } |
110 | |
111 | @Override |
112 | public void removeRow(Session session, Row row) { |
113 | throw DbException.getUnsupportedException("SYSTEM_RANGE"); |
114 | } |
115 | |
116 | @Override |
117 | public void addRow(Session session, Row row) { |
118 | throw DbException.getUnsupportedException("SYSTEM_RANGE"); |
119 | } |
120 | |
121 | @Override |
122 | public void checkSupportAlter() { |
123 | throw DbException.getUnsupportedException("SYSTEM_RANGE"); |
124 | } |
125 | |
126 | @Override |
127 | public void checkRename() { |
128 | throw DbException.getUnsupportedException("SYSTEM_RANGE"); |
129 | } |
130 | |
131 | @Override |
132 | public boolean canGetRowCount() { |
133 | return true; |
134 | } |
135 | |
136 | @Override |
137 | public boolean canDrop() { |
138 | return false; |
139 | } |
140 | |
141 | @Override |
142 | public long getRowCount(Session session) { |
143 | return Math.max(0, getMax(session) - getMin(session) + 1); |
144 | } |
145 | |
146 | @Override |
147 | public String getTableType() { |
148 | throw DbException.throwInternalError(); |
149 | } |
150 | |
151 | @Override |
152 | public Index getScanIndex(Session session) { |
153 | if (getStep(session) == 0) { |
154 | throw DbException.get(ErrorCode.STEP_SIZE_MUST_NOT_BE_ZERO); |
155 | } |
156 | return new RangeIndex(this, IndexColumn.wrap(columns)); |
157 | } |
158 | |
159 | /** |
160 | * Calculate and get the start value of this range. |
161 | * |
162 | * @param session the session |
163 | * @return the start value |
164 | */ |
165 | public long getMin(Session session) { |
166 | optimize(session); |
167 | return min.getValue(session).getLong(); |
168 | } |
169 | |
170 | /** |
171 | * Calculate and get the end value of this range. |
172 | * |
173 | * @param session the session |
174 | * @return the end value |
175 | */ |
176 | public long getMax(Session session) { |
177 | optimize(session); |
178 | return max.getValue(session).getLong(); |
179 | } |
180 | |
181 | /** |
182 | * Get the increment. |
183 | * |
184 | * @param session the session |
185 | * @return the increment (1 by default) |
186 | */ |
187 | public long getStep(Session session) { |
188 | optimize(session); |
189 | if (step == null) { |
190 | return 1; |
191 | } |
192 | return step.getValue(session).getLong(); |
193 | } |
194 | |
195 | private void optimize(Session s) { |
196 | if (!optimized) { |
197 | min = min.optimize(s); |
198 | max = max.optimize(s); |
199 | if (step != null) { |
200 | step = step.optimize(s); |
201 | } |
202 | optimized = true; |
203 | } |
204 | } |
205 | |
206 | @Override |
207 | public ArrayList<Index> getIndexes() { |
208 | return null; |
209 | } |
210 | |
211 | @Override |
212 | public void truncate(Session session) { |
213 | throw DbException.getUnsupportedException("SYSTEM_RANGE"); |
214 | } |
215 | |
216 | @Override |
217 | public long getMaxDataModificationId() { |
218 | return 0; |
219 | } |
220 | |
221 | @Override |
222 | public Index getUniqueIndex() { |
223 | return null; |
224 | } |
225 | |
226 | @Override |
227 | public long getRowCountApproximation() { |
228 | return 100; |
229 | } |
230 | |
231 | @Override |
232 | public long getDiskSpaceUsed() { |
233 | return 0; |
234 | } |
235 | |
236 | @Override |
237 | public boolean isDeterministic() { |
238 | return true; |
239 | } |
240 | |
241 | @Override |
242 | public boolean canReference() { |
243 | return false; |
244 | } |
245 | |
246 | } |