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

COVERAGE SUMMARY FOR SOURCE FILE [ScriptReader.java]

nameclass, %method, %block, %line, %
ScriptReader.java100% (1/1)100% (12/12)89%  (375/422)90%  (113/126)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class ScriptReader100% (1/1)100% (12/12)89%  (375/422)90%  (113/126)
clearRemark (): void 100% (1/1)33%  (4/12)67%  (2/3)
close (): void 100% (1/1)50%  (5/10)60%  (3/5)
readStatement (): String 100% (1/1)62%  (8/13)60%  (3/5)
readBuffer (): int 100% (1/1)83%  (95/114)95%  (20/21)
readStatementLoop (): String 100% (1/1)95%  (202/212)90%  (66/73)
ScriptReader (Reader): void 100% (1/1)100% (13/13)100% (5/5)
endRemark (): void 100% (1/1)100% (6/6)100% (3/3)
isBlockRemark (): boolean 100% (1/1)100% (3/3)100% (1/1)
isInsideRemark (): boolean 100% (1/1)100% (3/3)100% (1/1)
read (): int 100% (1/1)100% (19/19)100% (3/3)
setSkipRemarks (boolean): void 100% (1/1)100% (4/4)100% (2/2)
startRemark (boolean): void 100% (1/1)100% (13/13)100% (4/4)

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.util;
7 
8import java.io.Closeable;
9import java.io.IOException;
10import java.io.Reader;
11import java.util.Arrays;
12import org.h2.engine.Constants;
13import org.h2.message.DbException;
14 
15/**
16 * This class can split SQL scripts to single SQL statements.
17 * Each SQL statement ends with the character ';', however it is ignored
18 * in comments and quotes.
19 */
20public class ScriptReader implements Closeable {
21 
22    private final Reader reader;
23    private char[] buffer;
24 
25    /**
26     * The position in the buffer of the next char to be read
27     */
28    private int bufferPos;
29 
30    /**
31     * The position in the buffer of the statement start
32     */
33    private int bufferStart = -1;
34 
35    /**
36     * The position in the buffer of the last available char
37     */
38    private int bufferEnd;
39 
40    /**
41     * True if we have read past the end of file
42     */
43    private boolean endOfFile;
44 
45    /**
46     * True if we are inside a comment
47     */
48    private boolean insideRemark;
49 
50    /**
51     * Only valid if insideRemark is true. True if we are inside a block
52     * comment, false if we are inside a line comment
53     */
54    private boolean blockRemark;
55 
56    /**
57     * True if comments should be skipped completely by this reader.
58     */
59    private boolean skipRemarks;
60 
61    /**
62     * The position in buffer of start of comment
63     */
64    private int remarkStart;
65 
66    /**
67     * Create a new SQL script reader from the given reader
68     *
69     * @param reader the reader
70     */
71    public ScriptReader(Reader reader) {
72        this.reader = reader;
73        buffer = new char[Constants.IO_BUFFER_SIZE * 2];
74    }
75 
76    /**
77     * Close the underlying reader.
78     */
79    @Override
80    public void close() {
81        try {
82            reader.close();
83        } catch (IOException e) {
84            throw DbException.convertIOException(e, null);
85        }
86    }
87 
88    /**
89     * Read a statement from the reader. This method returns null if the end has
90     * been reached.
91     *
92     * @return the SQL statement or null
93     */
94    public String readStatement() {
95        if (endOfFile) {
96            return null;
97        }
98        try {
99            return readStatementLoop();
100        } catch (IOException e) {
101            throw DbException.convertIOException(e, null);
102        }
103    }
104 
105    private String readStatementLoop() throws IOException {
106        bufferStart = bufferPos;
107        int c = read();
108        while (true) {
109            if (c < 0) {
110                endOfFile = true;
111                if (bufferPos - 1 == bufferStart) {
112                    return null;
113                }
114                break;
115            } else if (c == ';') {
116                break;
117            }
118            switch (c) {
119            case '$': {
120                c = read();
121                if (c == '$' && (bufferPos - bufferStart < 3 || buffer[bufferPos - 3] <= ' ')) {
122                    // dollar quoted string
123                    while (true) {
124                        c = read();
125                        if (c < 0) {
126                            break;
127                        }
128                        if (c == '$') {
129                            c = read();
130                            if (c < 0) {
131                                break;
132                            }
133                            if (c == '$') {
134                                break;
135                            }
136                        }
137                    }
138                    c = read();
139                }
140                break;
141            }
142            case '\'':
143                while (true) {
144                    c = read();
145                    if (c < 0) {
146                        break;
147                    }
148                    if (c == '\'') {
149                        break;
150                    }
151                }
152                c = read();
153                break;
154            case '"':
155                while (true) {
156                    c = read();
157                    if (c < 0) {
158                        break;
159                    }
160                    if (c == '\"') {
161                        break;
162                    }
163                }
164                c = read();
165                break;
166            case '/': {
167                c = read();
168                if (c == '*') {
169                    // block comment
170                    startRemark(true);
171                    while (true) {
172                        c = read();
173                        if (c < 0) {
174                            break;
175                        }
176                        if (c == '*') {
177                            c = read();
178                            if (c < 0) {
179                                clearRemark();
180                                break;
181                            }
182                            if (c == '/') {
183                                endRemark();
184                                break;
185                            }
186                        }
187                    }
188                    c = read();
189                } else if (c == '/') {
190                    // single line comment
191                    startRemark(false);
192                    while (true) {
193                        c = read();
194                        if (c < 0) {
195                            clearRemark();
196                            break;
197                        }
198                        if (c == '\r' || c == '\n') {
199                            endRemark();
200                            break;
201                        }
202                    }
203                    c = read();
204                }
205                break;
206            }
207            case '-': {
208                c = read();
209                if (c == '-') {
210                    // single line comment
211                    startRemark(false);
212                    while (true) {
213                        c = read();
214                        if (c < 0) {
215                            clearRemark();
216                            break;
217                        }
218                        if (c == '\r' || c == '\n') {
219                            endRemark();
220                            break;
221                        }
222                    }
223                    c = read();
224                }
225                break;
226            }
227            default: {
228                c = read();
229            }
230            }
231        }
232        return new String(buffer, bufferStart, bufferPos - 1 - bufferStart);
233    }
234 
235    private void startRemark(boolean block) {
236        blockRemark = block;
237        remarkStart = bufferPos - 2;
238        insideRemark = true;
239    }
240 
241    private void endRemark() {
242        clearRemark();
243        insideRemark = false;
244    }
245 
246    private void clearRemark() {
247        if (skipRemarks) {
248            Arrays.fill(buffer, remarkStart, bufferPos, ' ');
249        }
250    }
251 
252    private int read() throws IOException {
253        if (bufferPos >= bufferEnd) {
254            return readBuffer();
255        }
256        return buffer[bufferPos++];
257    }
258 
259    private int readBuffer() throws IOException {
260        if (endOfFile) {
261            return -1;
262        }
263        int keep = bufferPos - bufferStart;
264        if (keep > 0) {
265            char[] src = buffer;
266            if (keep + Constants.IO_BUFFER_SIZE > src.length) {
267                // protect against NegativeArraySizeException
268                if (src.length >= Integer.MAX_VALUE / 2) {
269                    throw new IOException("Error in parsing script, " +
270                            "statement size exceeds 1G, " +
271                            "first 80 characters of statement looks like: " +
272                            new String(buffer, bufferStart, 80));
273                }
274                buffer = new char[src.length * 2];
275            }
276            System.arraycopy(src, bufferStart, buffer, 0, keep);
277        }
278        remarkStart -= bufferStart;
279        bufferStart = 0;
280        bufferPos = keep;
281        int len = reader.read(buffer, keep, Constants.IO_BUFFER_SIZE);
282        if (len == -1) {
283            // ensure bufferPos > bufferEnd
284            bufferEnd = -1024;
285            endOfFile = true;
286            // ensure the right number of characters are read
287            // in case the input buffer is still used
288            bufferPos++;
289            return -1;
290        }
291        bufferEnd = keep + len;
292        return buffer[bufferPos++];
293    }
294 
295    /**
296     * Check if this is the last statement, and if the single line or block
297     * comment is not finished yet.
298     *
299     * @return true if the current position is inside a remark
300     */
301    public boolean isInsideRemark() {
302        return insideRemark;
303    }
304 
305    /**
306     * If currently inside a remark, this method tells if it is a block comment
307     * (true) or single line comment (false)
308     *
309     * @return true if inside a block comment
310     */
311    public boolean isBlockRemark() {
312        return blockRemark;
313    }
314 
315    /**
316     * If comments should be skipped completely by this reader.
317     *
318     * @param skipRemarks true if comments should be skipped
319     */
320    public void setSkipRemarks(boolean skipRemarks) {
321        this.skipRemarks = skipRemarks;
322    }
323 
324}

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