提交 347ad336 authored 作者: noelgrandin's avatar noelgrandin

Fix bug with ALLOW_LITERALS=NONE, where the periodic analyze table on insert…

Fix bug with ALLOW_LITERALS=NONE, where the periodic analyze table on insert would throw an exception.
上级 ddbfdbc4
...@@ -76,6 +76,7 @@ Change Log ...@@ -76,6 +76,7 @@ Change Log
</li><li>Fix to org.h2.util.ScriptReader when handling unclosed block comments. </li><li>Fix to org.h2.util.ScriptReader when handling unclosed block comments.
</li><li>Make org.h2.util.ScriptReader throw a better exception when handling broken scripts which generate </li><li>Make org.h2.util.ScriptReader throw a better exception when handling broken scripts which generate
extremely large statements. extremely large statements.
</li><li>Fix bug with ALLOW_LITERALS=NONE, where the periodic analyze table on insert would throw an exception.
</li></ul> </li></ul>
<h2>Version 1.3.173 (2013-07-28)</h2> <h2>Version 1.3.173 (2013-07-28)</h2>
......
...@@ -1680,7 +1680,8 @@ public class Parser { ...@@ -1680,7 +1680,8 @@ public class Parser {
command.setLimit(limit); command.setLimit(limit);
} }
if (readIf("SAMPLE_SIZE")) { if (readIf("SAMPLE_SIZE")) {
command.setSampleSize(getPositiveInt()); Expression sampleSize = readExpression().optimize(session);
command.setSampleSize(sampleSize);
} }
currentSelect = temp; currentSelect = temp;
} }
......
...@@ -6,16 +6,20 @@ ...@@ -6,16 +6,20 @@
*/ */
package org.h2.command.ddl; package org.h2.command.ddl;
import java.util.ArrayList;
import org.h2.command.CommandInterface; import org.h2.command.CommandInterface;
import org.h2.command.Prepared; import org.h2.command.Prepared;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Right; import org.h2.engine.Right;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Parameter;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.util.New;
import org.h2.util.StatementBuilder; import org.h2.util.StatementBuilder;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueInt;
/** /**
* This class represents the statement * This class represents the statement
...@@ -80,6 +84,8 @@ public class Analyze extends DefineCommand { ...@@ -80,6 +84,8 @@ public class Analyze extends DefineCommand {
} }
Database db = session.getDatabase(); Database db = session.getDatabase();
StatementBuilder buff = new StatementBuilder("SELECT "); StatementBuilder buff = new StatementBuilder("SELECT ");
ArrayList<Parameter> parameters = New.arrayList();
int parameterIndex = 0;
Column[] columns = table.getColumns(); Column[] columns = table.getColumns();
for (Column col : columns) { for (Column col : columns) {
buff.appendExceptFirst(", "); buff.appendExceptFirst(", ");
...@@ -94,10 +100,17 @@ public class Analyze extends DefineCommand { ...@@ -94,10 +100,17 @@ public class Analyze extends DefineCommand {
} }
buff.append(" FROM ").append(table.getSQL()); buff.append(" FROM ").append(table.getSQL());
if (sample > 0) { if (sample > 0) {
buff.append(" LIMIT 1 SAMPLE_SIZE ").append(sample); buff.append(" LIMIT ? SAMPLE_SIZE ? ");
Parameter p = new Parameter(parameterIndex++);
p.setValue(ValueInt.get(1));
parameters.add(p);
p = new Parameter(parameterIndex++);
p.setValue(ValueInt.get(sample));
parameters.add(p);
} }
String sql = buff.toString(); String sql = buff.toString();
Prepared command = session.prepare(sql); Prepared command = session.prepare(sql);
command.setParameterList(parameters);
ResultInterface result = command.query(0); ResultInterface result = command.query(0);
result.next(); result.next();
for (int j = 0; j < columns.length; j++) { for (int j = 0; j < columns.length; j++) {
......
...@@ -46,9 +46,9 @@ public abstract class Query extends Prepared { ...@@ -46,9 +46,9 @@ public abstract class Query extends Prepared {
protected Expression offsetExpr; protected Expression offsetExpr;
/** /**
* The sample size * The sample size expression as specified in the SAMPLE_SIZE clause.
*/ */
protected int sampleSize; protected Expression sampleSizeExpr;
/** /**
* Whether the result must only contain distinct rows. * Whether the result must only contain distinct rows.
...@@ -509,8 +509,19 @@ public abstract class Query extends Prepared { ...@@ -509,8 +509,19 @@ public abstract class Query extends Prepared {
parameters.add(param); parameters.add(param);
} }
public void setSampleSize(int sampleSize) { public void setSampleSize(Expression sampleSize) {
this.sampleSize = sampleSize; this.sampleSizeExpr = sampleSize;
}
protected final int getSampleSizeValue(Session session) {
if (sampleSizeExpr == null) {
return 0;
}
Value v = sampleSizeExpr.getValue(session);
if (v == ValueNull.INSTANCE) {
return 0;
}
return v.getInt();
} }
public final long getMaxDataModificationId() { public final long getMaxDataModificationId() {
......
...@@ -315,6 +315,7 @@ public class Select extends Query { ...@@ -315,6 +315,7 @@ public class Select extends Query {
setCurrentRowNumber(0); setCurrentRowNumber(0);
currentGroup = null; currentGroup = null;
ValueArray defaultGroup = ValueArray.get(new Value[0]); ValueArray defaultGroup = ValueArray.get(new Value[0]);
int sampleSize = getSampleSizeValue(session);
while (topTableFilter.next()) { while (topTableFilter.next()) {
setCurrentRowNumber(rowNumber + 1); setCurrentRowNumber(rowNumber + 1);
if (condition == null || Boolean.TRUE.equals(condition.getBooleanValue(session))) { if (condition == null || Boolean.TRUE.equals(condition.getBooleanValue(session))) {
...@@ -477,6 +478,7 @@ public class Select extends Query { ...@@ -477,6 +478,7 @@ public class Select extends Query {
Index index = topTableFilter.getIndex(); Index index = topTableFilter.getIndex();
SearchRow first = null; SearchRow first = null;
int columnIndex = index.getColumns()[0].getColumnId(); int columnIndex = index.getColumns()[0].getColumnId();
int sampleSize = getSampleSizeValue(session);
while (true) { while (true) {
setCurrentRowNumber(rowNumber + 1); setCurrentRowNumber(rowNumber + 1);
Cursor cursor = index.findNext(session, first, null); Cursor cursor = index.findNext(session, first, null);
...@@ -517,6 +519,7 @@ public class Select extends Query { ...@@ -517,6 +519,7 @@ public class Select extends Query {
if (isForUpdateMvcc) { if (isForUpdateMvcc) {
forUpdateRows = New.arrayList(); forUpdateRows = New.arrayList();
} }
int sampleSize = getSampleSizeValue(session);
while (topTableFilter.next()) { while (topTableFilter.next()) {
setCurrentRowNumber(rowNumber + 1); setCurrentRowNumber(rowNumber + 1);
if (condition == null || Boolean.TRUE.equals(condition.getBooleanValue(session))) { if (condition == null || Boolean.TRUE.equals(condition.getBooleanValue(session))) {
...@@ -1066,8 +1069,8 @@ public class Select extends Query { ...@@ -1066,8 +1069,8 @@ public class Select extends Query {
buff.append(" OFFSET ").append(StringUtils.unEnclose(offsetExpr.getSQL())); buff.append(" OFFSET ").append(StringUtils.unEnclose(offsetExpr.getSQL()));
} }
} }
if (sampleSize != 0) { if (sampleSizeExpr != null) {
buff.append("\nSAMPLE_SIZE ").append(sampleSize); buff.append("\nSAMPLE_SIZE ").append(StringUtils.unEnclose(sampleSizeExpr.getSQL()));
} }
if (isForUpdate) { if (isForUpdate) {
buff.append("\nFOR UPDATE"); buff.append("\nFOR UPDATE");
......
...@@ -393,8 +393,8 @@ public class SelectUnion extends Query { ...@@ -393,8 +393,8 @@ public class SelectUnion extends Query {
buff.append("\nOFFSET ").append(StringUtils.unEnclose(offsetExpr.getSQL())); buff.append("\nOFFSET ").append(StringUtils.unEnclose(offsetExpr.getSQL()));
} }
} }
if (sampleSize != 0) { if (sampleSizeExpr != null) {
buff.append("\nSAMPLE_SIZE ").append(sampleSize); buff.append("\nSAMPLE_SIZE ").append(StringUtils.unEnclose(sampleSizeExpr.getSQL()));
} }
if (isForUpdate) { if (isForUpdate) {
buff.append("\nFOR UPDATE"); buff.append("\nFOR UPDATE");
......
...@@ -87,6 +87,7 @@ public class TestPreparedStatement extends TestBase { ...@@ -87,6 +87,7 @@ public class TestPreparedStatement extends TestBase {
testClob(conn); testClob(conn);
testParameterMetaData(conn); testParameterMetaData(conn);
conn.close(); conn.close();
testPreparedStatementWithLiteralsNone();
deleteDb("preparedStatement"); deleteDb("preparedStatement");
} }
...@@ -1168,6 +1169,21 @@ public class TestPreparedStatement extends TestBase { ...@@ -1168,6 +1169,21 @@ public class TestPreparedStatement extends TestBase {
assertTrue(conn == prep.getConnection()); assertTrue(conn == prep.getConnection());
} }
private void testPreparedStatementWithLiteralsNone() throws SQLException {
// make sure that when the analyze table kicks in, it works with ALLOW_LITERALS=NONE
deleteDb("preparedStatement");
Connection conn = getConnection("preparedStatement;ANALYZE_AUTO=100");
conn.createStatement().execute("SET ALLOW_LITERALS NONE");
conn.prepareStatement("CREATE TABLE test (id INT)").execute();
PreparedStatement ps = conn.prepareStatement("INSERT INTO test (id) VALUES (?)");
for(int i = 0; i < 200; i++) {
ps.setInt(1, i);
ps.executeUpdate();
}
conn.close();
deleteDb("preparedStatement");
}
private void checkBigDecimal(ResultSet rs, String[] value) throws SQLException { private void checkBigDecimal(ResultSet rs, String[] value) throws SQLException {
for (String v : value) { for (String v : value) {
assertTrue(rs.next()); assertTrue(rs.next());
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论