提交 23571cda authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Merge branch 'master' into datetime

...@@ -35,55 +35,55 @@ Change Log ...@@ -35,55 +35,55 @@ Change Log
</li> </li>
<li>PR #798: Add partial support of DATE, TIME, and TIMESTAMP data types to PgServer <li>PR #798: Add partial support of DATE, TIME, and TIMESTAMP data types to PgServer
</li> </li>
<li>PR #799: Use result of ArrayList.remove() <li>PR #799: Use result of ArrayList.remove()
</li> </li>
<li>PR #797: Add ceilingKey() and floorKey() to TransactionMap (version 2) <li>PR #797: Add ceilingKey() and floorKey() to TransactionMap (version 2)
</li> </li>
<li>PR #796: Add MDY to DateStyle in PgServerThread <li>PR #796: Add MDY to DateStyle in PgServerThread
</li> </li>
<li>PR #794: Sort files in generated jars <li>PR #794: Sort files in generated jars
</li> </li>
<li>PR #793: Change return type of Value.getBoolean() to boolean (unwrapped) <li>PR #793: Change return type of Value.getBoolean() to boolean (unwrapped)
</li> </li>
<li>PR #792: Inherit classpath from parent process <li>PR #792: Inherit classpath from parent process
</li> </li>
<li>PR #791: Switch to JaCoCo code coverage <li>PR #791: Switch to JaCoCo code coverage
</li> </li>
<li>PR #788: Update lists of keywords <li>PR #788: Update lists of keywords
</li> </li>
<li>PR #789: Map DATE in Oracle mode to ValueTimestamp <li>PR #789: Map DATE in Oracle mode to ValueTimestamp
</li> </li>
<li>PR #787: Assorted changes <li>PR #787: Assorted changes
</li> </li>
<li>PR #785: Optimize NULL handling in MVSecondaryIndex.add() <li>PR #785: Optimize NULL handling in MVSecondaryIndex.add()
</li> </li>
<li>PR #783: Add Bits implementation for Java 9 and later versions <li>PR #783: Add Bits implementation for Java 9 and later versions
</li> </li>
<li>PR #784: Hardcoded port numbers should not be used in unit tests <li>PR #784: Hardcoded port numbers should not be used in unit tests
</li> </li>
<li>PR #780: Close JavaFileManager after use. <li>PR #780: Close JavaFileManager after use.
</li> </li>
<li>PR #782: Leftover shared lock after release <li>PR #782: Leftover shared lock after release
</li> </li>
<li>PR #781: Locks left behind after commit <li>PR #781: Locks left behind after commit
</li> </li>
<li>PR #778: Reduce code duplication <li>PR #778: Reduce code duplication
</li> </li>
<li>PR #775: Fix building of documentation and zip <li>PR #775: Fix building of documentation and zip
</li> </li>
<li>PR #774: Assorted changes <li>PR #774: Assorted changes
</li> </li>
<li>PR #773: Better checks for arguments of partial LOB reading methods <li>PR #773: Better checks for arguments of partial LOB reading methods
</li> </li>
<li>PR #772: getBinaryStream() and getCharacterStream() with pos and length <li>PR #772: getBinaryStream() and getCharacterStream() with pos and length
</li> </li>
<li>Issue #754: Make NUMERIC type read as NUMERIC <li>Issue #754: Make NUMERIC type read as NUMERIC
</li> </li>
<li>PR #768: Add DataUtils.parseChecksummedMap() <li>PR #768: Add DataUtils.parseChecksummedMap()
</li> </li>
<li>PR #769: Do not copy result of DataUtils.parseMap() to a new maps <li>PR #769: Do not copy result of DataUtils.parseMap() to a new maps
</li> </li>
<li>PR #766: Minor clean up of DateTimeUtils <li>PR #766: Minor clean up of DateTimeUtils
</li> </li>
<li>PR #764: Make use of try-with-resources statement <li>PR #764: Make use of try-with-resources statement
</li> </li>
...@@ -109,7 +109,7 @@ Change Log ...@@ -109,7 +109,7 @@ Change Log
</li> </li>
<li>PR #750: Use AtomicIntegerArray and StandardCharsets <li>PR #750: Use AtomicIntegerArray and StandardCharsets
</li> </li>
<li>PR #749: Fix some build checks in sources <li>PR #749: Fix some build checks in sources
</li> </li>
<li>Issue #740: TestWeb hangups if webSSL=true specified in configuration <li>Issue #740: TestWeb hangups if webSSL=true specified in configuration
</li> </li>
...@@ -125,7 +125,7 @@ Change Log ...@@ -125,7 +125,7 @@ Change Log
</li> </li>
<li>PR #738: Copy javadoc to *BackwardsCompat to fix building of documentation <li>PR #738: Copy javadoc to *BackwardsCompat to fix building of documentation
</li> </li>
<li>PR #735: Add support of java.time.Instant V2 <li>PR #735: Add support of java.time.Instant V2
</li> </li>
<li>PR #733: Remove JPA/ORM configuration txt files as they're already integrated <li>PR #733: Remove JPA/ORM configuration txt files as they're already integrated
</li> </li>
...@@ -139,15 +139,15 @@ Change Log ...@@ -139,15 +139,15 @@ Change Log
</li> </li>
<li>PR #726: Fixes in tests <li>PR #726: Fixes in tests
</li> </li>
<li>Issue #725: FilePathMem.tryLock() fails since Java 9 <li>Issue #725: FilePathMem.tryLock() fails since Java 9
</li> </li>
<li>PR #723: Clean up LocalDateTimeUtils <li>PR #723: Clean up LocalDateTimeUtils
</li> </li>
<li>PR #724: Use StringBuilder instead of StringBuffer <li>PR #724: Use StringBuilder instead of StringBuffer
</li> </li>
<li>PR #720: DROP TABLE RESTRICT shouldn't drop foreign keys in other tables <li>PR #720: DROP TABLE RESTRICT shouldn't drop foreign keys in other tables
</li> </li>
<li>PR #722: Assorted minor changes <li>PR #722: Assorted minor changes
</li> </li>
<li>Issue #638: Oracle mode: incompatible regexp back-reference syntax <li>Issue #638: Oracle mode: incompatible regexp back-reference syntax
</li> </li>
......
...@@ -490,7 +490,7 @@ Instead, use a prepared statement with arrays as in the following example: ...@@ -490,7 +490,7 @@ Instead, use a prepared statement with arrays as in the following example:
</p> </p>
<pre> <pre>
PreparedStatement prep = conn.prepareStatement( PreparedStatement prep = conn.prepareStatement(
"SELECT * TEST.ID = ANY(?)"); "SELECT * FROM TEST WHERE ID = ANY(?)");
prep.setObject(1, new Object[] { "1", "2" }); prep.setObject(1, new Object[] { "1", "2" });
ResultSet rs = prep.executeQuery(); ResultSet rs = prep.executeQuery();
</pre> </pre>
......
...@@ -311,7 +311,7 @@ public class Aggregate extends Expression { ...@@ -311,7 +311,7 @@ public class Aggregate extends Expression {
return v; return v;
} }
case MEDIAN: { case MEDIAN: {
return AggregateDataMedian.getFromIndex(session, on, dataType); return AggregateDataMedian.getResultFromIndex(session, on, dataType);
} }
default: default:
DbException.throwInternalError("type=" + type); DbException.throwInternalError("type=" + type);
......
...@@ -49,6 +49,12 @@ class AggregateDataMedian extends AggregateData { ...@@ -49,6 +49,12 @@ class AggregateDataMedian extends AggregateData {
|| (sortType & SortOrder.DESCENDING) != 0 && (sortType & SortOrder.NULLS_FIRST) == 0; || (sortType & SortOrder.DESCENDING) != 0 && (sortType & SortOrder.NULLS_FIRST) == 0;
} }
/**
* Get the index (if any) for the column specified in the median aggregate.
*
* @param on the expression (usually a column expression)
* @return the index, or null
*/
static Index getMedianColumnIndex(Expression on) { static Index getMedianColumnIndex(Expression on) {
if (on instanceof ExpressionColumn) { if (on instanceof ExpressionColumn) {
ExpressionColumn col = (ExpressionColumn) on; ExpressionColumn col = (ExpressionColumn) on;
...@@ -68,8 +74,8 @@ class AggregateDataMedian extends AggregateData { ...@@ -68,8 +74,8 @@ class AggregateDataMedian extends AggregateData {
if (!index.isFirstColumn(column)) { if (!index.isFirstColumn(column)) {
continue; continue;
} }
if (result == null || result.getColumns().length > index.getColumns().length
// Prefer index without nulls last for nullable columns // Prefer index without nulls last for nullable columns
if (result == null || result.getColumns().length > index.getColumns().length
|| nullable && isNullsLast(result) && !isNullsLast(index)) { || nullable && isNullsLast(result) && !isNullsLast(index)) {
result = index; result = index;
} }
...@@ -81,7 +87,15 @@ class AggregateDataMedian extends AggregateData { ...@@ -81,7 +87,15 @@ class AggregateDataMedian extends AggregateData {
return null; return null;
} }
static Value getFromIndex(Session session, Expression on, int dataType) { /**
* Get the result from the index.
*
* @param session the session
* @param on the expression
* @param dataType the data type
* @return the result
*/
static Value getResultFromIndex(Session session, Expression on, int dataType) {
Index index = getMedianColumnIndex(on); Index index = getMedianColumnIndex(on);
long count = index.getRowCount(session); long count = index.getRowCount(session);
if (count == 0) { if (count == 0) {
...@@ -94,10 +108,8 @@ class AggregateDataMedian extends AggregateData { ...@@ -94,10 +108,8 @@ class AggregateDataMedian extends AggregateData {
if (expr.getColumn().isNullable()) { if (expr.getColumn().isNullable()) {
boolean hasNulls = false; boolean hasNulls = false;
SearchRow row; SearchRow row;
/* // Try to skip nulls from the start first with the same cursor that
* Try to skip nulls from the start first with the same cursor that will be used // will be used to read values.
* to read values.
*/
while (count > 0) { while (count > 0) {
row = cursor.getSearchRow(); row = cursor.getSearchRow();
if (row == null) { if (row == null) {
...@@ -113,10 +125,8 @@ class AggregateDataMedian extends AggregateData { ...@@ -113,10 +125,8 @@ class AggregateDataMedian extends AggregateData {
if (count == 0) { if (count == 0) {
return ValueNull.INSTANCE; return ValueNull.INSTANCE;
} }
/* // If no nulls found and if index orders nulls last create a second
* If no nulls found and if index orders nulls last create a second cursor to // cursor to count nulls at the end.
* count nulls at the end.
*/
if (!hasNulls && isNullsLast(index)) { if (!hasNulls && isNullsLast(index)) {
TableFilter tableFilter = expr.getTableFilter(); TableFilter tableFilter = expr.getTableFilter();
SearchRow check = tableFilter.getTable().getTemplateSimpleRow(true); SearchRow check = tableFilter.getTable().getTemplateSimpleRow(true);
...@@ -196,7 +206,7 @@ class AggregateDataMedian extends AggregateData { ...@@ -196,7 +206,7 @@ class AggregateDataMedian extends AggregateData {
return getMedian(a[idx - 1], v1, dataType, mode); return getMedian(a[idx - 1], v1, dataType, mode);
} }
static Value getMedian(Value v0, Value v1, int dataType, CompareMode mode) { private static Value getMedian(Value v0, Value v1, int dataType, CompareMode mode) {
if (v0.compareTo(v1, mode) == 0) { if (v0.compareTo(v1, mode) == 0) {
return v0.convertTo(dataType); return v0.convertTo(dataType);
} }
......
...@@ -57,7 +57,7 @@ public class ConditionInParameter extends Condition { ...@@ -57,7 +57,7 @@ public class ConditionInParameter extends Condition {
private Expression left; private Expression left;
final Parameter parameter; private final Parameter parameter;
/** /**
* Create a new {@code = ANY(?)} condition. * Create a new {@code = ANY(?)} condition.
......
...@@ -464,6 +464,17 @@ public abstract class TestBase { ...@@ -464,6 +464,17 @@ public abstract class TestBase {
throw new AssertionError(string); throw new AssertionError(string);
} }
/**
* Log an error message.
*
* @param s the message
*/
public static void logErrorMessage(String s) {
System.out.flush();
System.err.println("ERROR: " + s + "------------------------------");
logThrowable(s, null);
}
/** /**
* Log an error message. * Log an error message.
* *
...@@ -478,6 +489,10 @@ public abstract class TestBase { ...@@ -478,6 +489,10 @@ public abstract class TestBase {
System.err.println("ERROR: " + s + " " + e.toString() System.err.println("ERROR: " + s + " " + e.toString()
+ " ------------------------------"); + " ------------------------------");
e.printStackTrace(); e.printStackTrace();
logThrowable(null, e);
}
private static void logThrowable(String s, Throwable e) {
// synchronize on this class, because file locks are only visible to // synchronize on this class, because file locks are only visible to
// other JVMs // other JVMs
synchronized (TestBase.class) { synchronized (TestBase.class) {
...@@ -494,9 +509,14 @@ public abstract class TestBase { ...@@ -494,9 +509,14 @@ public abstract class TestBase {
} }
// append // append
FileWriter fw = new FileWriter("error.txt", true); FileWriter fw = new FileWriter("error.txt", true);
PrintWriter pw = new PrintWriter(fw); if (s != null) {
e.printStackTrace(pw); fw.write(s);
pw.close(); }
if (e != null) {
PrintWriter pw = new PrintWriter(fw);
e.printStackTrace(pw);
pw.close();
}
fw.close(); fw.close();
// unlock // unlock
lock.release(); lock.release();
......
...@@ -17,7 +17,20 @@ import org.h2.test.TestBase; ...@@ -17,7 +17,20 @@ import org.h2.test.TestBase;
*/ */
public abstract class AbstractBaseForCommonTableExpressions extends TestBase { public abstract class AbstractBaseForCommonTableExpressions extends TestBase {
protected void testRepeatedQueryWithSetup(int maxRetries, String[] expectedRowData, String[] expectedColumnNames, /**
* Test a query.
*
* @param maxRetries the number of times the query is run
* @param expectedRowData the expected result data
* @param expectedColumnNames the expected columns of the result
* @param expectedNumberOfRows the expected number of rows
* @param setupSQL the SQL statement used for setup
* @param withQuery the query
* @param closeAndReopenDatabaseConnectionOnIteration whether the connection
* should be re-opened each time
* @param expectedColumnTypes the expected datatypes of the result
*/
void testRepeatedQueryWithSetup(int maxRetries, String[] expectedRowData, String[] expectedColumnNames,
int expectedNumberOfRows, String setupSQL, String withQuery, int expectedNumberOfRows, String setupSQL, String withQuery,
int closeAndReopenDatabaseConnectionOnIteration, String[] expectedColumnTypes) throws SQLException { int closeAndReopenDatabaseConnectionOnIteration, String[] expectedColumnTypes) throws SQLException {
......
...@@ -68,7 +68,9 @@ public class TestOptimizations extends TestBase { ...@@ -68,7 +68,9 @@ public class TestOptimizations extends TestBase {
testMultiColumnRangeQuery(); testMultiColumnRangeQuery();
testDistinctOptimization(); testDistinctOptimization();
testQueryCacheTimestamp(); testQueryCacheTimestamp();
testQueryCacheSpeed(); if (!config.lazy) {
testQueryCacheSpeed();
}
testQueryCache(true); testQueryCache(true);
testQueryCache(false); testQueryCache(false);
testIn(); testIn();
...@@ -800,21 +802,26 @@ public class TestOptimizations extends TestBase { ...@@ -800,21 +802,26 @@ public class TestOptimizations extends TestBase {
} }
private void testQuerySpeed(Statement stat, String sql) throws SQLException { private void testQuerySpeed(Statement stat, String sql) throws SQLException {
stat.execute("set OPTIMIZE_REUSE_RESULTS 0"); long totalTime = 0;
long totalTimeOptimized = 0;
for (int i = 0; i < 3; i++) {
totalTime += measureQuerySpeed(stat, sql, false);
totalTimeOptimized += measureQuerySpeed(stat, sql, true);
}
System.out.println(TimeUnit.NANOSECONDS.toMillis(totalTime)+" "+TimeUnit.NANOSECONDS.toMillis(totalTimeOptimized));
if (totalTimeOptimized > totalTime) {
fail("not optimized: " + TimeUnit.NANOSECONDS.toMillis(totalTime) +
" optimized: " + TimeUnit.NANOSECONDS.toMillis(totalTimeOptimized) +
" sql:" + sql);
}
}
private long measureQuerySpeed(Statement stat, String sql, boolean optimized) throws SQLException {
stat.execute("set OPTIMIZE_REUSE_RESULTS " + (optimized ? "1" : "0"));
stat.execute(sql); stat.execute(sql);
long time = System.nanoTime(); long time = System.nanoTime();
stat.execute(sql); stat.execute(sql);
time = System.nanoTime() - time; return System.nanoTime() - time;
stat.execute("set OPTIMIZE_REUSE_RESULTS 1");
stat.execute(sql);
long time2 = System.nanoTime();
stat.execute(sql);
time2 = System.nanoTime() - time2;
if (time2 > time * 2) {
fail("not optimized: " + TimeUnit.NANOSECONDS.toMillis(time) +
" optimized: " + TimeUnit.NANOSECONDS.toMillis(time2) +
" sql:" + sql);
}
} }
private void testQueryCache(boolean optimize) throws SQLException { private void testQueryCache(boolean optimize) throws SQLException {
......
...@@ -41,6 +41,7 @@ public class TestScript extends TestBase { ...@@ -41,6 +41,7 @@ public class TestScript extends TestBase {
private boolean reconnectOften; private boolean reconnectOften;
private Connection conn; private Connection conn;
private Statement stat; private Statement stat;
private String fileName;
private LineNumberReader in; private LineNumberReader in;
private int outputLineNo; private int outputLineNo;
private PrintStream out; private PrintStream out;
...@@ -155,6 +156,7 @@ public class TestScript extends TestBase { ...@@ -155,6 +156,7 @@ public class TestScript extends TestBase {
// we processed. // we processed.
conn = null; conn = null;
stat = null; stat = null;
fileName = null;
in = null; in = null;
outputLineNo = 0; outputLineNo = 0;
out = null; out = null;
...@@ -172,7 +174,7 @@ public class TestScript extends TestBase { ...@@ -172,7 +174,7 @@ public class TestScript extends TestBase {
conn.close(); conn.close();
out.close(); out.close();
if (errors.length() > 0) { if (errors.length() > 0) {
throw new Exception("errors:\n" + errors.toString()); throw new Exception("errors in " + scriptFileName + " found");
} }
// new File(outFile).delete(); // new File(outFile).delete();
} }
...@@ -200,6 +202,7 @@ public class TestScript extends TestBase { ...@@ -200,6 +202,7 @@ public class TestScript extends TestBase {
if (is == null) { if (is == null) {
throw new IOException("could not find " + inFile); throw new IOException("could not find " + inFile);
} }
fileName = inFile;
in = new LineNumberReader(new InputStreamReader(is, "Cp1252")); in = new LineNumberReader(new InputStreamReader(is, "Cp1252"));
StringBuilder buff = new StringBuilder(); StringBuilder buff = new StringBuilder();
while (true) { while (true) {
...@@ -435,17 +438,14 @@ public class TestScript extends TestBase { ...@@ -435,17 +438,14 @@ public class TestScript extends TestBase {
if (reconnectOften && sql.toUpperCase().startsWith("EXPLAIN")) { if (reconnectOften && sql.toUpperCase().startsWith("EXPLAIN")) {
return; return;
} }
errors.append("line: "); errors.append(fileName).append('\n');
errors.append(outputLineNo); errors.append("line: ").append(outputLineNo).append('\n');
errors.append("\n" + "exp: "); errors.append("exp: ").append(compare).append('\n');
errors.append(compare); errors.append("got: ").append(s).append('\n');
errors.append("\n" + "got: ");
errors.append(s);
errors.append("\n");
if (e != null) { if (e != null) {
TestBase.logError("script", e); TestBase.logError("script", e);
} }
TestBase.logError(errors.toString(), null); TestBase.logErrorMessage(errors.toString());
if (failFast) { if (failFast) {
conn.close(); conn.close();
System.exit(1); System.exit(1);
......
...@@ -48,7 +48,7 @@ public class TestDateTimeUtils extends TestBase { ...@@ -48,7 +48,7 @@ public class TestDateTimeUtils extends TestBase {
* {@link DateTimeUtils#getIsoDayOfWeek(long)}. * {@link DateTimeUtils#getIsoDayOfWeek(long)}.
*/ */
private void testDayOfWeek() { private void testDayOfWeek() {
GregorianCalendar gc = DateTimeUtils.createGregorianCalendar(); GregorianCalendar gc = DateTimeUtils.createGregorianCalendar(DateTimeUtils.UTC);
for (int i = -1_000_000; i <= 1_000_000; i++) { for (int i = -1_000_000; i <= 1_000_000; i++) {
gc.clear(); gc.clear();
gc.setTimeInMillis(i * 86400000L); gc.setTimeInMillis(i * 86400000L);
...@@ -66,7 +66,8 @@ public class TestDateTimeUtils extends TestBase { ...@@ -66,7 +66,8 @@ public class TestDateTimeUtils extends TestBase {
int isoDow = (dow + 5) % 7 + 1; int isoDow = (dow + 5) % 7 + 1;
assertEquals(isoDow, DateTimeUtils.getIsoDayOfWeek(dateValue)); assertEquals(isoDow, DateTimeUtils.getIsoDayOfWeek(dateValue));
assertEquals(gc.get(Calendar.WEEK_OF_YEAR), assertEquals(gc.get(Calendar.WEEK_OF_YEAR),
DateTimeUtils.getWeekOfYear(dateValue, gc.getFirstDayOfWeek() - 1, gc.getMinimalDaysInFirstWeek())); DateTimeUtils.getWeekOfYear(dateValue, gc.getFirstDayOfWeek() - 1,
gc.getMinimalDaysInFirstWeek()));
} }
} }
...@@ -86,7 +87,8 @@ public class TestDateTimeUtils extends TestBase { ...@@ -86,7 +87,8 @@ public class TestDateTimeUtils extends TestBase {
gc.clear(); gc.clear();
gc.setTimeInMillis(i * 86400000L); gc.setTimeInMillis(i * 86400000L);
assertEquals(gc.get(Calendar.DAY_OF_YEAR), DateTimeUtils.getDayOfYear(dateValue)); assertEquals(gc.get(Calendar.DAY_OF_YEAR), DateTimeUtils.getDayOfYear(dateValue));
assertEquals(gc.get(Calendar.WEEK_OF_YEAR), DateTimeUtils.getWeekOfYear(dateValue, firstDay - 1, minimalDays)); assertEquals(gc.get(Calendar.WEEK_OF_YEAR),
DateTimeUtils.getWeekOfYear(dateValue, firstDay - 1, minimalDays));
assertEquals(gc.getWeekYear(), DateTimeUtils.getWeekYear(dateValue, firstDay - 1, minimalDays)); assertEquals(gc.getWeekYear(), DateTimeUtils.getWeekYear(dateValue, firstDay - 1, minimalDays));
} }
} }
......
...@@ -763,3 +763,6 @@ assorted reimplemented hangups confirmation predefined ...@@ -763,3 +763,6 @@ assorted reimplemented hangups confirmation predefined
mdy destfile hclf forbids spellchecking selfdestruct expects accident jacocoagent cli historic mitigate mdy destfile hclf forbids spellchecking selfdestruct expects accident jacocoagent cli historic mitigate
jacoco xdata invokes sourcefiles classfiles duplication crypto stacktraces prt directions handled overly asm hardcoded jacoco xdata invokes sourcefiles classfiles duplication crypto stacktraces prt directions handled overly asm hardcoded
interpolated thead interpolated thead
die weekdiff osx subprocess dow proleptic
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论