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

Parsing SQL script files is now faster.

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