EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.schema]

COVERAGE SUMMARY FOR SOURCE FILE [Sequence.java]

nameclass, %method, %block, %line, %
Sequence.java100% (1/1)93%  (26/28)92%  (599/654)95%  (110.8/117)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Sequence100% (1/1)93%  (26/28)92%  (599/654)95%  (110.8/117)
checkRename (): void 0%   (0/1)0%   (0/1)0%   (0/1)
getCreateSQLForCopy (Table, String): String 0%   (0/1)0%   (0/2)0%   (0/1)
modify (Long, Long, Long, Long): void 100% (1/1)60%  (51/85)88%  (14/16)
flushInternal (Session): void 100% (1/1)77%  (20/26)91%  (6.4/7)
flush (Session): void 100% (1/1)78%  (35/45)95%  (10.4/11)
getDropSQL (): String 100% (1/1)87%  (13/15)67%  (2/3)
Sequence (Schema, int, String, Long, Long, Long, Long, Long, boolean, boolean... 100% (1/1)100% (113/113)100% (13/13)
Sequence (Schema, int, String, long, long): void 100% (1/1)100% (15/15)100% (2/2)
close (): void 100% (1/1)100% (3/3)100% (2/2)
flushWithoutMargin (): void 100% (1/1)100% (14/14)100% (4/4)
getBelongsToTable (): boolean 100% (1/1)100% (3/3)100% (1/1)
getCacheSize (): long 100% (1/1)100% (3/3)100% (1/1)
getCreateSQL (): String 100% (1/1)100% (90/90)100% (15/15)
getCurrentValue (): long 100% (1/1)100% (6/6)100% (1/1)
getCycle (): boolean 100% (1/1)100% (3/3)100% (1/1)
getDefaultMaxValue (Long, long): long 100% (1/1)100% (24/24)100% (4/4)
getDefaultMinValue (Long, long): long 100% (1/1)100% (24/24)100% (4/4)
getDefaultStartValue (long): long 100% (1/1)100% (10/10)100% (1/1)
getIncrement (): long 100% (1/1)100% (3/3)100% (1/1)
getMaxValue (): long 100% (1/1)100% (3/3)100% (1/1)
getMinValue (): long 100% (1/1)100% (3/3)100% (1/1)
getNext (Session): long 100% (1/1)100% (108/108)100% (15/15)
getType (): int 100% (1/1)100% (2/2)100% (1/1)
isValid (long, long, long, long): boolean 100% (1/1)100% (30/30)100% (1/1)
removeChildrenAndResources (Session): void 100% (1/1)100% (9/9)100% (3/3)
setBelongsToTable (boolean): void 100% (1/1)100% (4/4)100% (2/2)
setCacheSize (long): void 100% (1/1)100% (6/6)100% (2/2)
setCycle (boolean): void 100% (1/1)100% (4/4)100% (2/2)

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 */
6package org.h2.schema;
7 
8import java.math.BigInteger;
9 
10import org.h2.api.ErrorCode;
11import org.h2.engine.DbObject;
12import org.h2.engine.Session;
13import org.h2.message.DbException;
14import org.h2.message.Trace;
15import org.h2.table.Table;
16 
17/**
18 * A sequence is created using the statement
19 * CREATE SEQUENCE
20 */
21public class Sequence extends SchemaObjectBase {
22 
23    /**
24     * The default cache size for sequences.
25     */
26    public static final int DEFAULT_CACHE_SIZE = 32;
27 
28    private long value;
29    private long valueWithMargin;
30    private long increment;
31    private long cacheSize;
32    private long minValue;
33    private long maxValue;
34    private boolean cycle;
35    private boolean belongsToTable;
36 
37    /**
38     * Creates a new sequence for an auto-increment column.
39     *
40     * @param schema the schema
41     * @param id the object id
42     * @param name the sequence name
43     * @param startValue the first value to return
44     * @param increment the increment count
45     */
46    public Sequence(Schema schema, int id, String name, long startValue,
47            long increment) {
48        this(schema, id, name, startValue, increment, null, null, null, false,
49                true);
50    }
51 
52    /**
53     * Creates a new sequence.
54     *
55     * @param schema the schema
56     * @param id the object id
57     * @param name the sequence name
58     * @param startValue the first value to return
59     * @param increment the increment count
60     * @param cacheSize the number of entries to pre-fetch
61     * @param minValue the minimum value
62     * @param maxValue the maximum value
63     * @param cycle whether to jump back to the min value if needed
64     * @param belongsToTable whether this sequence belongs to a table (for
65     *            auto-increment columns)
66     */
67    public Sequence(Schema schema, int id, String name, Long startValue,
68            Long increment, Long cacheSize, Long minValue, Long maxValue,
69            boolean cycle, boolean belongsToTable) {
70        initSchemaObjectBase(schema, id, name, Trace.SEQUENCE);
71        this.increment = increment != null ?
72                increment : 1;
73        this.minValue = minValue != null ?
74                minValue : getDefaultMinValue(startValue, this.increment);
75        this.maxValue = maxValue != null ?
76                maxValue : getDefaultMaxValue(startValue, this.increment);
77        this.value = startValue != null ?
78                startValue : getDefaultStartValue(this.increment);
79        this.valueWithMargin = value;
80        this.cacheSize = cacheSize != null ?
81                Math.max(1, cacheSize) : DEFAULT_CACHE_SIZE;
82        this.cycle = cycle;
83        this.belongsToTable = belongsToTable;
84        if (!isValid(this.value, this.minValue, this.maxValue, this.increment)) {
85            throw DbException.get(ErrorCode.SEQUENCE_ATTRIBUTES_INVALID, name,
86                    String.valueOf(this.value), String.valueOf(this.minValue),
87                    String.valueOf(this.maxValue),
88                    String.valueOf(this.increment));
89        }
90    }
91 
92    /**
93     * Allows the start value, increment, min value and max value to be updated
94     * atomically, including atomic validation. Useful because setting these
95     * attributes one after the other could otherwise result in an invalid
96     * sequence state (e.g. min value > max value, start value < min value,
97     * etc).
98     *
99     * @param startValue the new start value (<code>null</code> if no change)
100     * @param minValue the new min value (<code>null</code> if no change)
101     * @param maxValue the new max value (<code>null</code> if no change)
102     * @param increment the new increment (<code>null</code> if no change)
103     */
104    public synchronized void modify(Long startValue, Long minValue,
105            Long maxValue, Long increment) {
106        if (startValue == null) {
107            startValue = this.value;
108        }
109        if (minValue == null) {
110            minValue = this.minValue;
111        }
112        if (maxValue == null) {
113            maxValue = this.maxValue;
114        }
115        if (increment == null) {
116            increment = this.increment;
117        }
118        if (!isValid(startValue, minValue, maxValue, increment)) {
119            throw DbException.get(ErrorCode.SEQUENCE_ATTRIBUTES_INVALID,
120                    getName(), String.valueOf(startValue),
121                    String.valueOf(minValue),
122                    String.valueOf(maxValue),
123                    String.valueOf(increment));
124        }
125        this.value = startValue;
126        this.valueWithMargin = startValue;
127        this.minValue = minValue;
128        this.maxValue = maxValue;
129        this.increment = increment;
130    }
131 
132    /**
133     * Validates the specified prospective start value, min value, max value and
134     * increment relative to each other, since each of their respective
135     * validities are contingent on the values of the other parameters.
136     *
137     * @param value the prospective start value
138     * @param minValue the prospective min value
139     * @param maxValue the prospective max value
140     * @param increment the prospective increment
141     */
142    private static boolean isValid(long value, long minValue, long maxValue,
143            long increment) {
144        return minValue <= value &&
145            maxValue >= value &&
146            maxValue > minValue &&
147            increment != 0 &&
148            // Math.abs(increment) < maxValue - minValue
149                // use BigInteger to avoid overflows when maxValue and minValue
150                // are really big
151            BigInteger.valueOf(increment).abs().compareTo(
152                BigInteger.valueOf(maxValue).subtract(BigInteger.valueOf(minValue))) < 0;
153    }
154 
155    private static long getDefaultMinValue(Long startValue, long increment) {
156        long v = increment >= 0 ? 1 : Long.MIN_VALUE;
157        if (startValue != null && increment >= 0 && startValue < v) {
158            v = startValue;
159        }
160        return v;
161    }
162 
163    private static long getDefaultMaxValue(Long startValue, long increment) {
164        long v = increment >= 0 ? Long.MAX_VALUE : -1;
165        if (startValue != null && increment < 0 && startValue > v) {
166            v = startValue;
167        }
168        return v;
169    }
170 
171    private long getDefaultStartValue(long increment) {
172        return increment >= 0 ? minValue : maxValue;
173    }
174 
175    public boolean getBelongsToTable() {
176        return belongsToTable;
177    }
178 
179    public long getIncrement() {
180        return increment;
181    }
182 
183    public long getMinValue() {
184        return minValue;
185    }
186 
187    public long getMaxValue() {
188        return maxValue;
189    }
190 
191    public boolean getCycle() {
192        return cycle;
193    }
194 
195    public void setCycle(boolean cycle) {
196        this.cycle = cycle;
197    }
198 
199    @Override
200    public String getDropSQL() {
201        if (getBelongsToTable()) {
202            return null;
203        }
204        return "DROP SEQUENCE IF EXISTS " + getSQL();
205    }
206 
207    @Override
208    public String getCreateSQLForCopy(Table table, String quotedName) {
209        throw DbException.throwInternalError();
210    }
211 
212    @Override
213    public synchronized String getCreateSQL() {
214        StringBuilder buff = new StringBuilder("CREATE SEQUENCE ");
215        buff.append(getSQL()).append(" START WITH ").append(value);
216        if (increment != 1) {
217            buff.append(" INCREMENT BY ").append(increment);
218        }
219        if (minValue != getDefaultMinValue(value, increment)) {
220            buff.append(" MINVALUE ").append(minValue);
221        }
222        if (maxValue != getDefaultMaxValue(value, increment)) {
223            buff.append(" MAXVALUE ").append(maxValue);
224        }
225        if (cycle) {
226            buff.append(" CYCLE");
227        }
228        if (cacheSize != DEFAULT_CACHE_SIZE) {
229            buff.append(" CACHE ").append(cacheSize);
230        }
231        if (belongsToTable) {
232            buff.append(" BELONGS_TO_TABLE");
233        }
234        return buff.toString();
235    }
236 
237    /**
238     * Get the next value for this sequence.
239     *
240     * @param session the session
241     * @return the next value
242     */
243    public synchronized long getNext(Session session) {
244        boolean needsFlush = false;
245        if ((increment > 0 && value >= valueWithMargin) ||
246                (increment < 0 && value <= valueWithMargin)) {
247            valueWithMargin += increment * cacheSize;
248            needsFlush = true;
249        }
250        if ((increment > 0 && value > maxValue) ||
251                (increment < 0 && value < minValue)) {
252            if (cycle) {
253                value = increment > 0 ? minValue : maxValue;
254                valueWithMargin = value + (increment * cacheSize);
255                needsFlush = true;
256            } else {
257                throw DbException.get(ErrorCode.SEQUENCE_EXHAUSTED, getName());
258            }
259        }
260        if (needsFlush) {
261            flush(session);
262        }
263        long v = value;
264        value += increment;
265        return v;
266    }
267 
268    /**
269     * Flush the current value to disk.
270     */
271    public void flushWithoutMargin() {
272        if (valueWithMargin != value) {
273            valueWithMargin = value;
274            flush(null);
275        }
276    }
277 
278    /**
279     * Flush the current value, including the margin, to disk.
280     *
281     * @param session the session
282     */
283    public synchronized void flush(Session session) {
284        if (session == null || !database.isSysTableLocked()) {
285            // This session may not lock the sys table (except if it already has
286            // locked it) because it must be committed immediately, otherwise
287            // other threads can not access the sys table.
288            Session sysSession = database.getSystemSession();
289            synchronized (sysSession) {
290                flushInternal(sysSession);
291                sysSession.commit(false);
292            }
293        } else {
294            synchronized (session) {
295                flushInternal(session);
296            }
297        }
298    }
299 
300    private void flushInternal(Session session) {
301        // just for this case, use the value with the margin for the script
302        long realValue = value;
303        try {
304            value = valueWithMargin;
305            if (!isTemporary()) {
306                database.updateMeta(session, this);
307            }
308        } finally {
309            value = realValue;
310        }
311    }
312 
313    /**
314     * Flush the current value to disk and close this object.
315     */
316    public void close() {
317        flushWithoutMargin();
318    }
319 
320    @Override
321    public int getType() {
322        return DbObject.SEQUENCE;
323    }
324 
325    @Override
326    public void removeChildrenAndResources(Session session) {
327        database.removeMeta(session, getId());
328        invalidate();
329    }
330 
331    @Override
332    public void checkRename() {
333        // nothing to do
334    }
335 
336    public synchronized long getCurrentValue() {
337        return value - increment;
338    }
339 
340    public void setBelongsToTable(boolean b) {
341        this.belongsToTable = b;
342    }
343 
344    public void setCacheSize(long cacheSize) {
345        this.cacheSize = Math.max(1, cacheSize);
346    }
347 
348    public long getCacheSize() {
349        return cacheSize;
350    }
351 
352}

[all classes][org.h2.schema]
EMMA 2.0.5312 (C) Vladimir Roubtsov