提交 6b70f475 authored 作者: Thomas Mueller's avatar Thomas Mueller

Parsing SQL script files is now faster.

上级 ae0b0435
......@@ -18,8 +18,9 @@ Change Log
<h1>Change Log</h1>
<h2>Next Version (unreleased)</h2>
<ul><li>SimpleResultSet.newInstance(SimpleRowSource rs) did not work.
<ul><li>Parsing SQL script files is now faster.
</li><li>CSV reading is now faster.
</li><li>SimpleResultSet.newInstance(SimpleRowSource rs) did not work.
</li></ul>
<h2>Version 1.1.116 (2009-07-18)</h2>
......
......@@ -6,12 +6,10 @@
*/
package org.h2.command.dml;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.sql.SQLException;
import org.h2.command.Prepared;
import org.h2.constant.SysProperties;
import org.h2.engine.Session;
......@@ -37,7 +35,7 @@ public class RunScriptCommand extends ScriptBase {
try {
openInput();
Reader reader = new InputStreamReader(in, charset);
ScriptReader r = new ScriptReader(new BufferedReader(reader));
ScriptReader r = new ScriptReader(reader);
while (true) {
String sql = r.readStatement();
if (sql == null) {
......
......@@ -6,7 +6,6 @@
*/
package org.h2.server.pg;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
......@@ -29,7 +28,6 @@ import java.sql.Statement;
import java.sql.Types;
import java.util.HashMap;
import java.util.HashSet;
import org.h2.constant.SysProperties;
import org.h2.engine.ConnectionInfo;
import org.h2.jdbc.JdbcConnection;
......@@ -608,7 +606,7 @@ public class PgServerThread implements Runnable {
} catch (IOException e) {
throw Message.convertIOException(e, "Can not read pg_catalog resource");
}
ScriptReader reader = new ScriptReader(new BufferedReader(r));
ScriptReader reader = new ScriptReader(r);
while (true) {
String sql = reader.readStatement();
if (sql == null) {
......
......@@ -7,7 +7,6 @@
package org.h2.tools;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
......@@ -18,7 +17,6 @@ import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.h2.engine.Constants;
import org.h2.message.Message;
import org.h2.util.ClassUtils;
......@@ -157,7 +155,6 @@ public class RunScript extends Tool {
}
private ResultSet process(Connection conn, Reader reader) throws SQLException {
reader = new BufferedReader(reader);
Statement stat = conn.createStatement();
ResultSet rs = null;
ScriptReader r = new ScriptReader(reader);
......@@ -192,7 +189,7 @@ public class RunScript extends Tool {
private void process(Connection conn, boolean continueOnError, String path, Reader reader, String charsetName) throws SQLException, IOException {
Statement stat = conn.createStatement();
ScriptReader r = new ScriptReader(new BufferedReader(reader));
ScriptReader r = new ScriptReader(reader);
while (true) {
String sql = r.readStatement();
if (sql == null) {
......
......@@ -9,8 +9,10 @@ package org.h2.util;
import java.io.IOException;
import java.io.Reader;
import java.sql.SQLException;
import java.util.Arrays;
import org.h2.constant.SysProperties;
import org.h2.engine.Constants;
import org.h2.message.Message;
/**
......@@ -20,10 +22,15 @@ import org.h2.message.Message;
*/
public class ScriptReader {
private Reader reader;
private boolean end;
private char[] buffer;
private int bufferPos;
private int bufferStart = -1;
private int bufferEnd;
private boolean endOfFile;
private boolean insideRemark;
private boolean blockRemark;
private boolean skipRemarks;
private int remarkStart;
/**
* Create a new SQL script reader from the given reader
......@@ -32,6 +39,7 @@ public class ScriptReader {
*/
public ScriptReader(Reader reader) {
this.reader = reader;
buffer = new char[Constants.IO_BUFFER_SIZE * 2];
}
/**
......@@ -45,14 +53,6 @@ public class ScriptReader {
}
}
private int read() throws SQLException {
try {
return reader.read();
} catch (IOException e) {
throw Message.convertIOException(e, null);
}
}
/**
* Read a statement from the reader. This method returns null if the end has
* been reached.
......@@ -60,179 +60,197 @@ public class ScriptReader {
* @return the SQL statement or null
*/
public String readStatement() throws SQLException {
if (end) {
if (endOfFile) {
return null;
}
StringBuilder buff = new StringBuilder(200);
int previous = 0;
try {
return readStatementLoop();
} catch (IOException e) {
throw Message.convertIOException(e, null);
}
}
private String readStatementLoop() throws IOException {
bufferStart = bufferPos;
int c = read();
while (true) {
if (c < 0) {
end = true;
return buff.length() == 0 ? null : buff.toString();
endOfFile = true;
if (bufferPos - 1 == bufferStart) {
return null;
}
break;
} else if (c == ';') {
break;
}
switch (c) {
case '$': {
buff.append((char) c);
c = read();
if (c == '$' && SysProperties.DOLLAR_QUOTING && previous <= ' ') {
if (c == '$' && SysProperties.DOLLAR_QUOTING && (bufferPos - bufferStart < 3 || buffer[bufferPos - 3] <= ' ')) {
// dollar quoted string
buff.append((char) c);
while (true) {
c = read();
if (c < 0) {
break;
}
buff.append((char) c);
if (c == '$') {
c = read();
if (c < 0) {
break;
}
buff.append((char) c);
if (c == '$') {
break;
}
}
}
previous = c;
c = read();
}
break;
}
case '\'':
buff.append((char) c);
while (true) {
c = read();
if (c < 0) {
break;
}
buff.append((char) c);
if (c == '\'') {
break;
}
}
previous = c;
c = read();
break;
case '"':
buff.append((char) c);
while (true) {
c = read();
if (c < 0) {
break;
}
buff.append((char) c);
if (c == '\"') {
break;
}
}
previous = c;
c = read();
break;
case '/': {
int last = c;
previous = c;
c = read();
if (c == '*') {
// block comment
insideRemark = true;
blockRemark = true;
if (!skipRemarks) {
buff.append((char) last).append((char) c);
}
startRemark(false);
while (true) {
c = read();
if (c < 0) {
break;
}
if (!skipRemarks) {
buff.append((char) c);
}
if (c == '*') {
c = read();
if (c < 0) {
clearRemark();
break;
}
if (!skipRemarks) {
buff.append((char) c);
}
if (c == '/') {
insideRemark = false;
endRemark();
break;
}
}
}
previous = c;
c = read();
} else if (c == '/') {
// single line comment
insideRemark = true;
blockRemark = false;
if (!skipRemarks) {
buff.append((char) last).append((char) c);
}
startRemark(false);
while (true) {
c = read();
if (c < 0) {
clearRemark();
break;
}
if (!skipRemarks) {
buff.append((char) c);
}
if (c == '\r' || c == '\n') {
insideRemark = false;
endRemark();
break;
}
}
previous = c;
c = read();
} else {
buff.append((char) last);
}
break;
}
case '-': {
previous = c;
int last = c;
c = read();
if (c == '-') {
// single line comment
insideRemark = true;
blockRemark = false;
if (!skipRemarks) {
buff.append((char) last).append((char) c);
}
startRemark(false);
while (true) {
c = read();
if (c < 0) {
clearRemark();
break;
}
if (!skipRemarks) {
buff.append((char) c);
}
if (c == '\r' || c == '\n') {
insideRemark = false;
endRemark();
break;
}
}
previous = c;
c = read();
} else {
buff.append((char) last);
}
break;
}
default: {
buff.append((char) c);
previous = c;
c = read();
}
}
}
return buff.toString();
return new String(buffer, bufferStart, bufferPos - 1 - bufferStart);
}
private void startRemark(boolean block) {
blockRemark = block;
remarkStart = bufferPos - 2;
insideRemark = true;
}
private void endRemark() {
clearRemark();
insideRemark = false;
}
private void clearRemark() {
if (skipRemarks) {
Arrays.fill(buffer, remarkStart, bufferPos, ' ');
}
}
private int read() throws IOException {
if (bufferPos >= bufferEnd) {
return readBuffer();
}
return buffer[bufferPos++];
}
private int readBuffer() throws IOException {
if (endOfFile) {
return -1;
}
int keep = bufferPos - bufferStart;
if (keep > 0) {
char[] src = buffer;
if (keep + Constants.IO_BUFFER_SIZE > src.length) {
buffer = new char[src.length * 2];
}
System.arraycopy(src, bufferStart, buffer, 0, keep);
}
remarkStart -= bufferStart;
bufferStart = 0;
bufferPos = keep;
int len = reader.read(buffer, keep, Constants.IO_BUFFER_SIZE);
if (len == -1) {
// ensure bufferPos > bufferEnd
bufferEnd = -1024;
endOfFile = true;
// ensure the right number of characters are read
// in case the input buffer is still used
bufferPos++;
return -1;
}
bufferEnd = keep + len;
return buffer[bufferPos++];
}
/**
......
......@@ -294,9 +294,6 @@ java org.h2.test.TestAll timer
/*
check BufferedReader usage
improve ScriptReader performance
create a short documentation
documentation: rolling review at roadmap.html: done
......
......@@ -55,9 +55,9 @@ public class TestScriptReader extends TestBase {
if (c.length() == 0 && j == l - 1) {
c = null;
}
assertEquals(e, c);
assertEquals(c, e);
}
assertEquals(source.readStatement(), null);
assertEquals(null, source.readStatement());
}
}
......@@ -161,22 +161,32 @@ public class TestScriptReader extends TestBase {
}
private void testCommon() throws SQLException {
String s = "a;';';\";\";--;\n;/*;\n*/;//;\na;";
StringReader reader = new StringReader(s);
ScriptReader source = new ScriptReader(reader);
assertEquals(source.readStatement(), "a");
assertEquals(source.readStatement(), "';'");
assertEquals(source.readStatement(), "\";\"");
assertEquals(source.readStatement(), "--;\n");
assertEquals(source.readStatement(), "/*;\n*/");
assertEquals(source.readStatement(), "//;\na");
assertEquals(source.readStatement(), null);
String s;
ScriptReader source;
s = "$$;$$;";
source = new ScriptReader(new StringReader(s));
assertEquals("$$;$$", source.readStatement());
assertEquals(null, source.readStatement());
source.close();
s = "a;';';\";\";--;\n;/*;\n*/;//;\na;";
source = new ScriptReader(new StringReader(s));
assertEquals("a", source.readStatement());
assertEquals("';'", source.readStatement());
assertEquals("\";\"", source.readStatement());
assertEquals("--;\n", source.readStatement());
assertEquals("/*;\n*/", source.readStatement());
assertEquals("//;\na", source.readStatement());
assertEquals(null, source.readStatement());
source.close();
s = "/\n$ \n\n $';$$a$$ $\n;'";
source = new ScriptReader(new StringReader(s));
assertEquals(source.readStatement(), "/\n$ \n\n $';$$a$$ $\n;'");
assertEquals(source.readStatement(), null);
assertEquals("/\n$ \n\n $';$$a$$ $\n;'", source.readStatement());
assertEquals(null, source.readStatement());
source.close();
}
}
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论