提交 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
</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
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>
<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>.
</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>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>Improve SQL documentation, see http://www.w3schools.com/sql/
</li><li>MySQL compatibility: DatabaseMetaData.stores*() methods should return the same values. Test with SquirrelSQL.
......
......@@ -1900,8 +1900,14 @@ public class ErrorCode {
*/
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() {
// utility class
......
......@@ -1201,12 +1201,20 @@ public class Parser {
}
if (foundLeftBracket) {
Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN);
if (equalsToken(tableName, RangeTable.NAME)) {
if (equalsToken(tableName, RangeTable.NAME)
|| equalsToken(tableName, RangeTable.ALIAS)) {
Expression min = readExpression();
read(",");
Expression max = readExpression();
read(")");
table = new RangeTable(mainSchema, min, max, false);
if (readIf(",")) {
Expression step = readExpression();
read(")");
table = new RangeTable(mainSchema, min, max, step,
false);
} else {
read(")");
table = new RangeTable(mainSchema, min, max, false);
}
} else {
Expression expr = readFunction(schema, tableName);
if (!(expr instanceof FunctionCall)) {
......
......@@ -19,11 +19,16 @@ class RangeCursor implements Cursor {
private boolean beforeFirst;
private long current;
private Row currentRow;
private final long min, max;
private final long start, end, step;
RangeCursor(long min, long max) {
this.min = min;
this.max = max;
RangeCursor(long start, long end) {
this(start, end, 1);
}
RangeCursor(long start, long end, long step) {
this.start = start;
this.end = end;
this.step = step;
beforeFirst = true;
}
......@@ -41,12 +46,12 @@ class RangeCursor implements Cursor {
public boolean next() {
if (beforeFirst) {
beforeFirst = false;
current = min;
current = start;
} else {
current++;
current += step;
}
currentRow = new Row(new Value[]{ValueLong.get(current)}, 1);
return current <= max;
return step > 0 ? current <= end : current >= end;
}
@Override
......
......@@ -47,6 +47,7 @@ public class RangeIndex extends BaseIndex {
public Cursor find(Session session, SearchRow first, SearchRow last) {
long min = rangeTable.getMin(session), start = min;
long max = rangeTable.getMax(session), end = max;
long step = rangeTable.getStep(session);
try {
start = Math.max(min, first == null ? min : first.getValue(0).getLong());
} catch (Exception e) {
......@@ -57,7 +58,7 @@ public class RangeIndex extends BaseIndex {
} catch (Exception e) {
// error when converting the value - ignore
}
return new RangeCursor(start, end);
return new RangeCursor(start, end, step);
}
@Override
......
......@@ -163,6 +163,7 @@
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).
90141=Serializer cannot be changed because there is a data table: {0}
90142=Step size should not be zero
HY000=General error: {0}
HY004=Unknown data type: {0}
HYC00=Feature not supported: {0}
......
......@@ -6,6 +6,8 @@
package org.h2.table;
import java.util.ArrayList;
import org.h2.api.ErrorCode;
import org.h2.engine.Session;
import org.h2.expression.Expression;
import org.h2.index.Index;
......@@ -27,7 +29,12 @@ public class RangeTable extends Table {
*/
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;
/**
......@@ -48,7 +55,13 @@ public class RangeTable extends Table {
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() {
return null;
}
......@@ -60,7 +73,11 @@ public class RangeTable extends Table {
@Override
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
......@@ -133,6 +150,9 @@ public class RangeTable extends Table {
@Override
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));
}
......@@ -158,10 +178,21 @@ public class RangeTable extends Table {
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) {
if (!optimized) {
min = min.optimize(s);
max = max.optimize(s);
if (step != null) {
step = step.optimize(s);
}
optimized = true;
}
}
......
......@@ -93,7 +93,7 @@ public class TestFunctions extends TestBase implements AggregateFunction {
testToCharFromNumber();
testToCharFromText();
testTranslate();
testGenerateSeries();
// TODO
// testCachingOfDeterministicFunctionAlias();
......@@ -1628,6 +1628,57 @@ public class TestFunctions extends TestBase implements AggregateFunction {
assertResult("abc", stat, "SELECT TO_CHAR('abc') FROM DUAL");
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)
throws SQLException {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论