提交 ddc90b86 authored 作者: noelgrandin@gmail.com's avatar noelgrandin@gmail.com

PostgreSQL compatibility: generate_series (as an alias for system_range). Patch by litailang.

上级 b5da88fc
...@@ -36,6 +36,7 @@ Change Log ...@@ -36,6 +36,7 @@ Change Log
</li><li>Allow declaring triggers as source code (like functions). Patch by Sylvain CUAZ. </li><li>Allow declaring triggers as source code (like functions). Patch by Sylvain CUAZ.
</li><li>Make the planner use indexes for sorting when doing a GROUP BY where </li><li>Make the planner use indexes for sorting when doing a GROUP BY where
all of the GROUP BY columns are not mentioned in the select. Patch by Frederico (zepfred). all of the GROUP BY columns are not mentioned in the select. Patch by Frederico (zepfred).
</li><li>PostgreSQL compatibility: generate_series (as an alias for system_range). Patch by litailang.
</li></ul> </li></ul>
<h2>Version 1.4.185 Beta (2015-01-16)</h2> <h2>Version 1.4.185 Beta (2015-01-16)</h2>
......
...@@ -343,7 +343,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>. ...@@ -343,7 +343,6 @@ See also <a href="build.html#providing_patches">Providing Patches</a>.
</li><li>Batch parameter for INSERT, UPDATE, and DELETE, and commit after each batch. See also MySQL DELETE. </li><li>Batch parameter for INSERT, UPDATE, and DELETE, and commit after each batch. See also MySQL DELETE.
</li><li>MySQL compatibility: support ALTER TABLE .. MODIFY COLUMN. </li><li>MySQL compatibility: support ALTER TABLE .. MODIFY COLUMN.
</li><li>Use a lazy and auto-close input stream (open resource when reading, close on eof). </li><li>Use a lazy and auto-close input stream (open resource when reading, close on eof).
</li><li>PostgreSQL compatibility: generate_series (as an alias for system_range).
</li><li>Connection pool: 'reset session' command (delete temp tables, rollback, auto-commit true). </li><li>Connection pool: 'reset session' command (delete temp tables, rollback, auto-commit true).
</li><li>Improve SQL documentation, see http://www.w3schools.com/sql/ </li><li>Improve SQL documentation, see http://www.w3schools.com/sql/
</li><li>MySQL compatibility: DatabaseMetaData.stores*() methods should return the same values. Test with SquirrelSQL. </li><li>MySQL compatibility: DatabaseMetaData.stores*() methods should return the same values. Test with SquirrelSQL.
......
...@@ -1900,8 +1900,14 @@ public class ErrorCode { ...@@ -1900,8 +1900,14 @@ public class ErrorCode {
*/ */
public static final int JAVA_OBJECT_SERIALIZER_CHANGE_WITH_DATA_TABLE = 90141; public static final int JAVA_OBJECT_SERIALIZER_CHANGE_WITH_DATA_TABLE = 90141;
/**
* The error with code <code>90142</code> is thrown when
* trying to set zero for step size.
*/
public static final int STEP_SIZE_SHOUD_NOT_BE_ZERO = 90142;
// next are 90039, 90051, 90056, 90110, 90122, 90142 // next are 90039, 90051, 90056, 90110, 90122, 90143
private ErrorCode() { private ErrorCode() {
// utility class // utility class
......
...@@ -1201,12 +1201,20 @@ public class Parser { ...@@ -1201,12 +1201,20 @@ public class Parser {
} }
if (foundLeftBracket) { if (foundLeftBracket) {
Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN); Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN);
if (equalsToken(tableName, RangeTable.NAME)) { if (equalsToken(tableName, RangeTable.NAME)
|| equalsToken(tableName, RangeTable.ALIAS)) {
Expression min = readExpression(); Expression min = readExpression();
read(","); read(",");
Expression max = readExpression(); Expression max = readExpression();
read(")"); if (readIf(",")) {
table = new RangeTable(mainSchema, min, max, false); Expression step = readExpression();
read(")");
table = new RangeTable(mainSchema, min, max, step,
false);
} else {
read(")");
table = new RangeTable(mainSchema, min, max, false);
}
} else { } else {
Expression expr = readFunction(schema, tableName); Expression expr = readFunction(schema, tableName);
if (!(expr instanceof FunctionCall)) { if (!(expr instanceof FunctionCall)) {
......
...@@ -19,11 +19,16 @@ class RangeCursor implements Cursor { ...@@ -19,11 +19,16 @@ class RangeCursor implements Cursor {
private boolean beforeFirst; private boolean beforeFirst;
private long current; private long current;
private Row currentRow; private Row currentRow;
private final long min, max; private final long start, end, step;
RangeCursor(long min, long max) { RangeCursor(long start, long end) {
this.min = min; this(start, end, 1);
this.max = max; }
RangeCursor(long start, long end, long step) {
this.start = start;
this.end = end;
this.step = step;
beforeFirst = true; beforeFirst = true;
} }
...@@ -41,12 +46,12 @@ class RangeCursor implements Cursor { ...@@ -41,12 +46,12 @@ class RangeCursor implements Cursor {
public boolean next() { public boolean next() {
if (beforeFirst) { if (beforeFirst) {
beforeFirst = false; beforeFirst = false;
current = min; current = start;
} else { } else {
current++; current += step;
} }
currentRow = new Row(new Value[]{ValueLong.get(current)}, 1); currentRow = new Row(new Value[]{ValueLong.get(current)}, 1);
return current <= max; return step > 0 ? current <= end : current >= end;
} }
@Override @Override
......
...@@ -47,6 +47,7 @@ public class RangeIndex extends BaseIndex { ...@@ -47,6 +47,7 @@ public class RangeIndex extends BaseIndex {
public Cursor find(Session session, SearchRow first, SearchRow last) { public Cursor find(Session session, SearchRow first, SearchRow last) {
long min = rangeTable.getMin(session), start = min; long min = rangeTable.getMin(session), start = min;
long max = rangeTable.getMax(session), end = max; long max = rangeTable.getMax(session), end = max;
long step = rangeTable.getStep(session);
try { try {
start = Math.max(min, first == null ? min : first.getValue(0).getLong()); start = Math.max(min, first == null ? min : first.getValue(0).getLong());
} catch (Exception e) { } catch (Exception e) {
...@@ -57,7 +58,7 @@ public class RangeIndex extends BaseIndex { ...@@ -57,7 +58,7 @@ public class RangeIndex extends BaseIndex {
} catch (Exception e) { } catch (Exception e) {
// error when converting the value - ignore // error when converting the value - ignore
} }
return new RangeCursor(start, end); return new RangeCursor(start, end, step);
} }
@Override @Override
......
...@@ -163,6 +163,7 @@ ...@@ -163,6 +163,7 @@
90139=The public static Java method was not found: {0} 90139=The public static Java method was not found: {0}
90140=The result set is readonly. You may need to use conn.createStatement(.., ResultSet.CONCUR_UPDATABLE). 90140=The result set is readonly. You may need to use conn.createStatement(.., ResultSet.CONCUR_UPDATABLE).
90141=Serializer cannot be changed because there is a data table: {0} 90141=Serializer cannot be changed because there is a data table: {0}
90142=Step size should not be zero
HY000=General error: {0} HY000=General error: {0}
HY004=Unknown data type: {0} HY004=Unknown data type: {0}
HYC00=Feature not supported: {0} HYC00=Feature not supported: {0}
......
...@@ -6,6 +6,8 @@ ...@@ -6,6 +6,8 @@
package org.h2.table; package org.h2.table;
import java.util.ArrayList; import java.util.ArrayList;
import org.h2.api.ErrorCode;
import org.h2.engine.Session; import org.h2.engine.Session;
import org.h2.expression.Expression; import org.h2.expression.Expression;
import org.h2.index.Index; import org.h2.index.Index;
...@@ -27,7 +29,12 @@ public class RangeTable extends Table { ...@@ -27,7 +29,12 @@ public class RangeTable extends Table {
*/ */
public static final String NAME = "SYSTEM_RANGE"; public static final String NAME = "SYSTEM_RANGE";
private Expression min, max; /**
* The PostgreSQL alias for the range table.
*/
public static final String ALIAS = "GENERATE_SERIES";
private Expression min, max, step;
private boolean optimized; private boolean optimized;
/** /**
...@@ -48,7 +55,13 @@ public class RangeTable extends Table { ...@@ -48,7 +55,13 @@ public class RangeTable extends Table {
setColumns(cols); setColumns(cols);
} }
@Override public RangeTable(Schema schema, Expression min, Expression max,
Expression step, boolean noColumns) {
this(schema, min, max, noColumns);
this.step = step;
}
@Override
public String getDropSQL() { public String getDropSQL() {
return null; return null;
} }
...@@ -60,7 +73,11 @@ public class RangeTable extends Table { ...@@ -60,7 +73,11 @@ public class RangeTable extends Table {
@Override @Override
public String getSQL() { public String getSQL() {
return NAME + "(" + min.getSQL() + ", " + max.getSQL() + ")"; String sql = NAME + "(" + min.getSQL() + ", " + max.getSQL();
if (step != null) {
sql += ", " + step.getSQL();
}
return sql + ")";
} }
@Override @Override
...@@ -133,6 +150,9 @@ public class RangeTable extends Table { ...@@ -133,6 +150,9 @@ public class RangeTable extends Table {
@Override @Override
public Index getScanIndex(Session session) { public Index getScanIndex(Session session) {
if (getStep(session) == 0) {
throw DbException.get(ErrorCode.STEP_SIZE_SHOUD_NOT_BE_ZERO);
}
return new RangeIndex(this, IndexColumn.wrap(columns)); return new RangeIndex(this, IndexColumn.wrap(columns));
} }
...@@ -158,10 +178,21 @@ public class RangeTable extends Table { ...@@ -158,10 +178,21 @@ public class RangeTable extends Table {
return max.getValue(session).getLong(); return max.getValue(session).getLong();
} }
public long getStep(Session session) {
optimize(session);
if (step == null) {
return 1;
}
return step.getValue(session).getLong();
}
private void optimize(Session s) { private void optimize(Session s) {
if (!optimized) { if (!optimized) {
min = min.optimize(s); min = min.optimize(s);
max = max.optimize(s); max = max.optimize(s);
if (step != null) {
step = step.optimize(s);
}
optimized = true; optimized = true;
} }
} }
......
...@@ -93,7 +93,7 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -93,7 +93,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
testToCharFromNumber(); testToCharFromNumber();
testToCharFromText(); testToCharFromText();
testTranslate(); testTranslate();
testGenerateSeries();
// TODO // TODO
// testCachingOfDeterministicFunctionAlias(); // testCachingOfDeterministicFunctionAlias();
...@@ -1628,6 +1628,57 @@ public class TestFunctions extends TestBase implements AggregateFunction { ...@@ -1628,6 +1628,57 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertResult("abc", stat, "SELECT TO_CHAR('abc') FROM DUAL"); assertResult("abc", stat, "SELECT TO_CHAR('abc') FROM DUAL");
conn.close(); conn.close();
} }
private void testGenerateSeries() throws SQLException {
Connection conn = getConnection("functions");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("select * from system_range(1,3)");
rs.next();
assertEquals(1, rs.getInt(1));
rs.next();
assertEquals(2, rs.getInt(1));
rs.next();
assertEquals(3, rs.getInt(1));
rs = stat.executeQuery("select * from system_range(2,2)");
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
rs = stat.executeQuery("select * from system_range(2,1)");
assertFalse(rs.next());
rs = stat.executeQuery("select * from system_range(1,2,-1)");
assertFalse(rs.next());
assertThrows(ErrorCode.STEP_SIZE_SHOUD_NOT_BE_ZERO, stat).executeQuery(
"select * from system_range(1,2,0)");
rs = stat.executeQuery("select * from system_range(2,1,-1)");
assertTrue(rs.next());
assertEquals(2, rs.getInt(1));
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
rs = stat.executeQuery("select * from system_range(1,5,2)");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertTrue(rs.next());
assertEquals(3, rs.getInt(1));
assertTrue(rs.next());
assertEquals(5, rs.getInt(1));
rs = stat.executeQuery("select * from system_range(1,6,2)");
assertTrue(rs.next());
assertEquals(1, rs.getInt(1));
assertTrue(rs.next());
assertEquals(3, rs.getInt(1));
assertTrue(rs.next());
assertEquals(5, rs.getInt(1));
conn.close();
}
private void assertCallResult(String expected, Statement stat, String sql) private void assertCallResult(String expected, Statement stat, String sql)
throws SQLException { throws SQLException {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论