提交 37a81b39 authored 作者: andrei's avatar andrei

Merge remote-tracking branch 'h2database/master' into non_blocking

# Conflicts:
#	h2/src/main/org/h2/mvstore/MVMap.java
#	h2/src/main/org/h2/mvstore/MVStore.java
#	h2/src/test/org/h2/test/store/SequenceMap.java
......@@ -5,18 +5,19 @@
1. Very fast, open source, JDBC API
2. Embedded and server modes; in-memory databases
3. Browser based Console application
4. Small footprint: around 1.5 MB jar file size
4. Small footprint: around 2 MB jar file size
More information: http://h2database.com
## Features
| | [H2](http://www.h2database.com/) | [Derby](http://db.apache.org/derby) | [HSQLDB](http://hsqldb.org) | [MySQL](http://mysql.com) | [PostgreSQL](http://www.postgresql.org) |
|---------------------------|-------|-------|-------|-------|-------|
| Pure Java | Yes | Yes | Yes | No | No |
| Memory Mode | Yes | Yes | Yes | No | No |
| Encrypted Database | Yes | Yes | Yes | No | No |
| ODBC Driver | Yes | No | No | Yes | Yes |
| Fulltext Search | Yes | No | No | Yes | Yes |
| Multi Version Concurrency | Yes | No | Yes | Yes | Yes |
| Footprint (jar/dll size) | ~1 MB | ~2 MB | ~1 MB | ~4 MB | ~6 MB |
| | [H2](http://www.h2database.com/) | [Derby](http://db.apache.org/derby) | [HSQLDB](http://hsqldb.org) | [MySQL](https://www.mysql.com/) | [PostgreSQL](https://www.postgresql.org) |
|--------------------------------|---------|---------|---------|-------|---------|
| Pure Java | Yes | Yes | Yes | No | No |
| Memory Mode | Yes | Yes | Yes | No | No |
| Encrypted Database | Yes | Yes | Yes | No | No |
| ODBC Driver | Yes | No | No | Yes | Yes |
| Fulltext Search | Yes | No | No | Yes | Yes |
| Multi Version Concurrency | Yes | No | Yes | Yes | Yes |
| Footprint (embedded database) | ~2 MB | ~3 MB | ~1.5 MB | — | — |
| Footprint (JDBC client driver) | ~500 KB | ~600 KB | ~1.5 MB | ~1 MB | ~700 KB |
......@@ -329,9 +329,11 @@ ALTER TABLE [ IF EXISTS ] tableName ALTER COLUMN columnName
| { RESTART WITH long }
| { SELECTIVITY int }
| { SET DEFAULT expression }
| { SET ON UPDATE expression }
| { SET NULL }
| { SET NOT NULL }
| { SET { VISIBLE | INVISIBLE } } }
| { SET { VISIBLE | INVISIBLE } }
| { DROP { DEFAULT | ON UPDATE } } }
","
Changes the data type of a column, rename a column,
change the identity value, or change the selectivity.
......@@ -349,6 +351,8 @@ Selectivity 100 means values are unique, 10 means every distinct value appears 1
SET DEFAULT changes the default value of a column.
SET ON UPDATE changes the value that is set on update if value for this column is not specified in update statement.
SET NULL sets a column to allow NULL. The row may not be part of a primary key.
Single column indexes on this column are dropped.
......@@ -357,6 +361,10 @@ SET NOT NULL sets a column to not allow NULL. Rows may not contains NULL in this
SET INVISIBLE makes the column hidden, i.e. it will not appear in SELECT * results.
SET VISIBLE has the reverse effect.
DROP DEFAULT removes the default value of a column.
DROP ON UPDATE removes the value that is set on update of a column.
This command commits an open transaction in this connection.
","
ALTER TABLE TEST ALTER COLUMN NAME CLOB;
......@@ -2050,13 +2058,17 @@ AES
"Other Grammar","Column Definition","
dataType [ VISIBLE | INVISIBLE ]
[ { DEFAULT expression | AS computedColumnExpression } ] [ [ NOT ] NULL ]
[ { DEFAULT expression | AS computedColumnExpression } ]
[ ON UPDATE expression ] [ [ NOT ] NULL ]
[ { AUTO_INCREMENT | IDENTITY } [ ( startInt [, incrementInt ] ) ] ]
[ SELECTIVITY selectivity ] [ COMMENT expression ]
[ PRIMARY KEY [ HASH ] | UNIQUE ] [ CHECK condition ]
","
Default expressions are used if no explicit value was used when adding a row.
The computed column expression is evaluated and assigned whenever the row changes.
On update column expression is used if row is updated,
at least one column have a new value that is different from its previous value
and value for this column is not set explicitly in update statement.
Identity and auto-increment columns are columns with a sequence as the
default. The column declared as the identity columns is implicitly the
......
......@@ -482,7 +482,7 @@ This is achieved using different database URLs. Settings in the URLs are not cas
<tr>
<td><a href="advanced.html#tls_connections">Server mode (remote connections)<br /> using TLS</a></td>
<td class="notranslate">
jdbc:h2:ssl://&lt;server&gt;[:&lt;port&gt;]/&lt;databaseName&gt;<br />
jdbc:h2:ssl://&lt;server&gt;[:&lt;port&gt;]/[&lt;path&gt;]&lt;databaseName&gt;<br />
jdbc:h2:ssl://localhost:8085/~/sample;
</td>
</tr>
......@@ -1047,6 +1047,7 @@ or the SQL statement <code>SET MODE DB2</code>.
</li><li>Concatenating <code>NULL</code> with another value
results in the other value.
</li><li>Support the pseudo-table SYSIBM.SYSDUMMY1.
</li><li>Timestamps with dash between date and time are supported.
</li></ul>
<h3>Derby Compatibility Mode</h3>
......@@ -1098,7 +1099,7 @@ or the SQL statement <code>SET MODE MSSQLServer</code>.
<h3>MySQL Compatibility Mode</h3>
<p>
To use the MySQL mode, use the database URL <code>jdbc:h2:~/test;MODE=MySQL</code>
or the SQL statement <code>SET MODE MySQL</code>.
or the SQL statement <code>SET MODE MySQL</code>. Use this mode for compatibility with MariaDB too.
</p>
<ul><li>When inserting data, if a column is defined to be <code>NOT NULL</code>
and <code>NULL</code> is inserted,
......@@ -1112,6 +1113,9 @@ or the SQL statement <code>SET MODE MySQL</code>.
digits are not truncated, but the value is rounded.
</li><li>Concatenating <code>NULL</code> with another value
results in the other value.
</li><li>ON DUPLICATE KEY UPDATE is supported in INSERT statements.
</li><li>INSERT IGNORE is partially supported and may be used to skip rows with duplicate keys if ON DUPLICATE KEY UPDATE is not specified.
</li><li>REGEXP_REPLACE() uses \ for back-references for compatibility with MariaDB.
</li></ul>
<p>
Text comparison in MySQL is case insensitive by default, while in H2 it is case sensitive (as in most other databases).
......@@ -1134,6 +1138,8 @@ or the SQL statement <code>SET MODE Oracle</code>.
</li><li>Concatenating <code>NULL</code> with another value
results in the other value.
</li><li>Empty strings are treated like <code>NULL</code> values.
</li><li>REGEXP_REPLACE() uses \ for back-references.
</li><li>DATE data type is treated like TIMESTAMP data type.
</li></ul>
<h3>PostgreSQL Compatibility Mode</h3>
......@@ -1149,6 +1155,19 @@ or the SQL statement <code>SET MODE PostgreSQL</code>.
</li><li>The system columns <code>CTID</code> and
<code>OID</code> are supported.
</li><li>LOG(x) is base 10 in this mode.
</li><li>REGEXP_REPLACE() uses \ for back-references.
</li><li>Fixed-width strings are padded with spaces.
</li></ul>
<h3>Ignite Compatibility Mode</h3>
<p>
To use the Ignite mode, use the database URL <code>jdbc:h2:~/test;MODE=Ignite</code>
or the SQL statement <code>SET MODE Ignite</code>.
</p>
<ul><li>Creating indexes in the <code>CREATE TABLE</code> statement is allowed using
<code>INDEX(..)</code> or <code>KEY(..)</code>.
Example: <code>create table test(id int primary key, name varchar(255), key idx_name(name));</code>
</li><li>AFFINITY KEY and SHARD KEY keywords may be used in index definition.
</li></ul>
<h2 id="auto_reconnect">Auto-Reconnect</h2>
......
......@@ -478,6 +478,11 @@ public interface CommandInterface {
*/
int DROP_SYNONYM = 89;
/**
* The type of a ALTER TABLE ALTER COLUMN SET ON UPDATE statement.
*/
int ALTER_TABLE_ALTER_COLUMN_ON_UPDATE = 90;
/**
* Get command type.
*
......
......@@ -992,7 +992,7 @@ public class Parser {
buff.append("'ISO' AS DATESTYLE FROM DUAL");
} else if (readIf("SERVER_VERSION")) {
// for PostgreSQL compatibility
buff.append("'8.1.4' AS SERVER_VERSION FROM DUAL");
buff.append("'" + Constants.PG_VERSION + "' AS SERVER_VERSION FROM DUAL");
} else if (readIf("SERVER_ENCODING")) {
// for PostgreSQL compatibility
buff.append("'UTF8' AS SERVER_ENCODING FROM DUAL");
......@@ -4291,6 +4291,11 @@ public class Parser {
column.setPrimaryKey(true);
column.setAutoIncrement(true, start, increment);
}
if (readIf("ON")) {
read("UPDATE");
Expression onUpdateExpression = readExpression();
column.setOnUpdateExpression(session, onUpdateExpression);
}
if (NullConstraintType.NULL_IS_NOT_ALLOWED == parseNotNullConstraint()) {
column.setNullable(false);
}
......@@ -6205,6 +6210,16 @@ public class Parser {
command.setDefaultExpression(null);
return command;
}
if (readIf("ON")) {
read("UPDATE");
AlterTableAlterColumn command = new AlterTableAlterColumn(session, schema);
command.setTableName(tableName);
command.setIfTableExists(ifTableExists);
command.setOldColumn(column);
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_ON_UPDATE);
command.setDefaultExpression(null);
return command;
}
read("NOT");
read("NULL");
AlterTableAlterColumn command = new AlterTableAlterColumn(
......@@ -6243,11 +6258,14 @@ public class Parser {
Expression defaultExpression = readExpression();
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT);
command.setDefaultExpression(defaultExpression);
} else if (readIf("ON")) {
read("UPDATE");
Expression onUpdateExpression = readExpression();
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_ON_UPDATE);
command.setDefaultExpression(onUpdateExpression);
} else if (readIf("INVISIBLE")) {
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_VISIBILITY);
command.setVisible(false);
} else if (readIf("VISIBLE")) {
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_VISIBILITY);
command.setVisible(true);
......
......@@ -54,6 +54,9 @@ public class AlterTableAlterColumn extends CommandWithColumns {
private Column oldColumn;
private Column newColumn;
private int type;
/**
* Default or on update expression.
*/
private Expression defaultExpression;
private Expression newSelectivity;
private boolean addFirst;
......@@ -147,6 +150,12 @@ public class AlterTableAlterColumn extends CommandWithColumns {
db.updateMeta(session, table);
break;
}
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_ON_UPDATE: {
checkDefaultReferencesTable(table, defaultExpression);
oldColumn.setOnUpdateExpression(session, defaultExpression);
db.updateMeta(session, table);
break;
}
case CommandInterface.ALTER_TABLE_ALTER_COLUMN_CHANGE_TYPE: {
// if the change is only increasing the precision, then we don't
// need to copy the table because the length is only a constraint,
......@@ -551,6 +560,11 @@ public class AlterTableAlterColumn extends CommandWithColumns {
newSelectivity = selectivity;
}
/**
* Set default or on update expression.
*
* @param defaultExpression default or on update expression
*/
public void setDefaultExpression(Expression defaultExpression) {
this.defaultExpression = defaultExpression;
}
......
......@@ -125,8 +125,7 @@ public class CreateTable extends CommandWithColumns {
try {
session.setUndoLogEnabled(false);
session.startStatementWithinTransaction();
Insert insert = null;
insert = new Insert(session);
Insert insert = new Insert(session);
insert.setSortedInsertMode(sortedInsertMode);
insert.setQuery(asQuery);
insert.setTable(table);
......
......@@ -118,6 +118,7 @@ public class Merge extends Prepared {
}
} else {
// process select data for list
query.setNeverLazy(true);
ResultInterface rows = query.query(0);
count = 0;
targetTable.fire(session, Trigger.UPDATE | Trigger.INSERT, true);
......
......@@ -7,6 +7,8 @@ package org.h2.command.dml;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Objects;
import org.h2.api.ErrorCode;
import org.h2.api.Trigger;
import org.h2.command.CommandInterface;
......@@ -115,20 +117,43 @@ public class Update extends Prepared {
if (condition == null || condition.getBooleanValue(session)) {
Row oldRow = targetTableFilter.get();
Row newRow = table.getTemplateRow();
boolean setOnUpdate = false;
for (int i = 0; i < columnCount; i++) {
Expression newExpr = expressionMap.get(columns[i]);
Column column = table.getColumn(i);
Value newValue;
if (newExpr == null) {
if (column.getOnUpdateExpression() != null) {
setOnUpdate = true;
}
newValue = oldRow.getValue(i);
} else if (newExpr == ValueExpression.getDefault()) {
Column column = table.getColumn(i);
newValue = table.getDefaultValue(session, column);
} else {
Column column = table.getColumn(i);
newValue = column.convert(newExpr.getValue(session));
}
newRow.setValue(i, newValue);
}
if (setOnUpdate) {
setOnUpdate = false;
for (int i = 0; i < columnCount; i++) {
// Use equals here to detect changes from numeric 0 to 0.0 and similar
if (!Objects.equals(oldRow.getValue(i), newRow.getValue(i))) {
setOnUpdate = true;
break;
}
}
if (setOnUpdate) {
for (int i = 0; i < columnCount; i++) {
if (expressionMap.get(columns[i]) == null) {
Column column = table.getColumn(i);
if (column.getOnUpdateExpression() != null) {
newRow.setValue(i, table.getOnUpdateValue(session, column));
}
}
}
}
}
table.validateConvertUpdateSequence(session, newRow);
boolean done = false;
if (table.fireRow()) {
......
......@@ -530,6 +530,11 @@ public class Constants {
*/
public static final int QUERY_STATISTICS_MAX_ENTRIES = 100;
/**
* Announced version for PgServer.
*/
public static final String PG_VERSION = "8.2.23";
private Constants() {
// utility class
}
......
......@@ -107,7 +107,7 @@ public class Function extends Expression implements FunctionCall {
SECOND = 114, WEEK = 115, YEAR = 116, CURRENT_DATE = 117,
CURRENT_TIME = 118, CURRENT_TIMESTAMP = 119, EXTRACT = 120,
FORMATDATETIME = 121, PARSEDATETIME = 122, ISO_YEAR = 123,
ISO_WEEK = 124, ISO_DAY_OF_WEEK = 125;
ISO_WEEK = 124, ISO_DAY_OF_WEEK = 125, DATE_TRUNC = 132;
/**
* Pseudo functions for DATEADD, DATEDIFF, and EXTRACT.
......@@ -419,6 +419,7 @@ public class Function extends Expression implements FunctionCall {
1, Value.INT);
addFunction("ISO_DAY_OF_WEEK", ISO_DAY_OF_WEEK,
1, Value.INT);
addFunction("DATE_TRUNC", DATE_TRUNC, 2, Value.NULL);
// system
addFunctionNotDeterministic("DATABASE", DATABASE,
0, Value.STRING);
......@@ -1493,6 +1494,13 @@ public class Function extends Expression implements FunctionCall {
break;
case DATE_DIFF:
result = ValueLong.get(datediff(v0.getString(), v1, v2));
break;
case DATE_TRUNC:
// Retrieve the time unit (e.g. 'day', 'microseconds', etc.)
String timeUnit = StringUtils.toUpperEnglish(v0.getString());
result = DateTimeUtils.truncateDate(timeUnit, v1);
break;
case EXTRACT: {
int field = getDatePart(v0.getString());
......@@ -2371,6 +2379,10 @@ public class Function extends Expression implements FunctionCall {
min = 1;
max = 2;
break;
case DATE_TRUNC:
min = 2;
max = 2;
break;
case TO_CHAR:
case TO_DATE:
min = 1;
......
......@@ -646,9 +646,7 @@ public final class DataUtils {
c = s.charAt(i++);
if (c == '\\') {
if (i == size) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_CORRUPT,
"Not a map: {0}", s);
throw newIllegalStateException(ERROR_FILE_CORRUPT, "Not a map: {0}", s);
}
c = s.charAt(i++);
} else if (c == '\"') {
......@@ -677,8 +675,7 @@ public final class DataUtils {
int startKey = i;
i = s.indexOf(':', i);
if (i < 0) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_CORRUPT, "Not a map: {0}", s);
throw newIllegalStateException(ERROR_FILE_CORRUPT, "Not a map: {0}", s);
}
String key = s.substring(startKey, i++);
i = parseMapValue(buff, s, i, size);
......@@ -710,20 +707,19 @@ public final class DataUtils {
int startKey = i;
i = s.indexOf(':', i);
if (i < 0) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_CORRUPT, "Not a map: {0}", s);
throw newIllegalStateException(ERROR_FILE_CORRUPT, "Not a map: {0}", s);
}
if (i - startKey == 8 && s.regionMatches(startKey, "fletcher", 0, 8)) {
DataUtils.parseMapValue(buff, s, i + 1, size);
parseMapValue(buff, s, i + 1, size);
int check = (int) Long.parseLong(buff.toString(), 16);
if (check == DataUtils.getFletcher32(bytes, start, startKey - 1)) {
if (check == getFletcher32(bytes, start, startKey - 1)) {
return map;
}
// Corrupted map
return null;
}
String key = s.substring(startKey, i++);
i = DataUtils.parseMapValue(buff, s, i, size);
i = parseMapValue(buff, s, i, size);
map.put(key, buff.toString());
buff.setLength(0);
}
......@@ -739,16 +735,28 @@ public final class DataUtils {
* @throws IllegalStateException if parsing failed
*/
public static String getMapName(String s) {
return getFromMap(s, "name");
}
/**
* Parse a specified pair from key-value pair list.
*
* @param s the list
* @param key the name of the key
* @return value of the specified item, or {@code null}
* @throws IllegalStateException if parsing failed
*/
public static String getFromMap(String s, String key) {
int keyLength = key.length();
for (int i = 0, size = s.length(); i < size;) {
int startKey = i;
i = s.indexOf(':', i);
if (i < 0) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_CORRUPT, "Not a map: {0}", s);
throw newIllegalStateException(ERROR_FILE_CORRUPT, "Not a map: {0}", s);
}
if (i++ - startKey == 4 && s.regionMatches(startKey, "name", 0, 4)) {
if (i++ - startKey == keyLength && s.regionMatches(startKey, key, 0, keyLength)) {
StringBuilder buff = new StringBuilder();
i = parseMapValue(buff, s, i, size);
parseMapValue(buff, s, i, size);
return buff.toString();
} else {
while (i < size) {
......@@ -759,12 +767,9 @@ public final class DataUtils {
while (i < size) {
c = s.charAt(i++);
if (c == '\\') {
if (i == size) {
throw DataUtils.newIllegalStateException(
DataUtils.ERROR_FILE_CORRUPT,
"Not a map: {0}", s);
if (i++ == size) {
throw newIllegalStateException(ERROR_FILE_CORRUPT, "Not a map: {0}", s);
}
c = s.charAt(i++);
} else if (c == '\"') {
break;
}
......@@ -1094,8 +1099,7 @@ public final class DataUtils {
@Override
public V setValue(V value) {
throw DataUtils.newUnsupportedOperationException(
"Updating the value is not supported");
throw newUnsupportedOperationException("Updating the value is not supported");
}
}
......
......@@ -344,7 +344,7 @@ public class TransactionStore {
}
// TODO could synchronize on blocks (100 at a time or so)
rwLock.writeLock().lock();
int oldStatus = t.status;
int oldStatus = t.getStatus();
try {
t.setStatus(Transaction.STATUS_COMMITTING);
for (long logId = 0; logId < maxLogId; logId++) {
......@@ -372,9 +372,7 @@ public class TransactionStore {
if (value.value == null) {
map.remove(key);
} else {
VersionedValue v2 = new VersionedValue();
v2.value = value.value;
map.put(key, v2);
map.put(key, new VersionedValue(0L, value.value));
}
}
}
......@@ -983,9 +981,10 @@ public class TransactionStore {
long size = 0;
Cursor<K, VersionedValue> cursor = map.cursor(null);
while (cursor.hasNext()) {
VersionedValue data;
K key = cursor.next();
data = getValue(key, readLogId, cursor.getValue());
// cursor.getValue() returns outdated value
VersionedValue data = map.get(key);
data = getValue(key, readLogId, data);
if (data != null && data.value != null) {
size++;
}
......@@ -1068,8 +1067,7 @@ public class TransactionStore {
@SuppressWarnings("unchecked")
public V putCommitted(K key, V value) {
DataUtils.checkArgument(value != null, "The value may not be null");
VersionedValue newValue = new VersionedValue();
newValue.value = value;
VersionedValue newValue = new VersionedValue(0L, value);
VersionedValue oldValue = map.put(key, newValue);
return (V) (oldValue == null ? null : oldValue.value);
}
......@@ -1148,10 +1146,9 @@ public class TransactionStore {
}
}
}
VersionedValue newValue = new VersionedValue();
newValue.operationId = getOperationId(
transaction.transactionId, transaction.logId);
newValue.value = value;
VersionedValue newValue = new VersionedValue(
getOperationId(transaction.transactionId, transaction.logId),
value);
if (current == null) {
// a new value
transaction.log(mapId, key, current);
......@@ -1548,7 +1545,8 @@ public class TransactionStore {
if (to != null && map.getKeyType().compare(k, to) > 0) {
break;
}
VersionedValue data = cursor.getValue();
// cursor.getValue() returns outdated value
VersionedValue data = map.get(key);
data = getValue(key, readLogId, data);
if (data != null && data.value != null) {
@SuppressWarnings("unchecked")
......@@ -1656,12 +1654,17 @@ public class TransactionStore {
/**
* The operation id.
*/
public long operationId;
final long operationId;
/**
* The value.
*/
public Object value;
final Object value;
VersionedValue(long operationId, Object value) {
this.operationId = operationId;
this.value = value;
}
@Override
public String toString() {
......@@ -1709,9 +1712,7 @@ public class TransactionStore {
if (buff.get() == 0) {
// fast path (no op ids or null entries)
for (int i = 0; i < len; i++) {
VersionedValue v = new VersionedValue();
v.value = valueType.read(buff);
obj[i] = v;
obj[i] = new VersionedValue(0L, valueType.read(buff));
}
} else {
// slow path (some entries may be null)
......@@ -1723,12 +1724,14 @@ public class TransactionStore {
@Override
public Object read(ByteBuffer buff) {
VersionedValue v = new VersionedValue();
v.operationId = DataUtils.readVarLong(buff);
long operationId = DataUtils.readVarLong(buff);
Object value;
if (buff.get() == 1) {
v.value = valueType.read(buff);
value = valueType.read(buff);
} else {
value = null;
}
return v;
return new VersionedValue(operationId, value);
}
@Override
......
......@@ -392,7 +392,7 @@ public class PgServer implements Service {
* @return the server name and version
*/
public static String getVersion() {
return "PostgreSQL 8.1.4 server protocol using H2 " +
return "PostgreSQL " + Constants.PG_VERSION + " server protocol using H2 " +
Constants.getFullVersion();
}
......
......@@ -33,6 +33,7 @@ import java.util.Properties;
import org.h2.command.CommandInterface;
import org.h2.engine.ConnectionInfo;
import org.h2.engine.Constants;
import org.h2.engine.SysProperties;
import org.h2.jdbc.JdbcConnection;
import org.h2.jdbc.JdbcPreparedStatement;
......@@ -949,7 +950,7 @@ public class PgServerThread implements Runnable {
sendParameterStatus("integer_datetimes", "off");
sendParameterStatus("is_superuser", "off");
sendParameterStatus("server_encoding", "SQL_ASCII");
sendParameterStatus("server_version", "8.1.4");
sendParameterStatus("server_version", Constants.PG_VERSION);
sendParameterStatus("session_authorization", userName);
sendParameterStatus("standard_conforming_strings", "off");
// TODO PostgreSQL TimeZone
......
......@@ -4,7 +4,7 @@
* Initial Developer: H2 Group
*/
;
drop schema if exists pg_catalog;
drop schema if exists pg_catalog cascade;
create schema pg_catalog;
drop alias if exists pg_convertType;
......
......@@ -75,6 +75,7 @@ public class Column {
private int columnId;
private boolean nullable = true;
private Expression defaultExpression;
private Expression onUpdateExpression;
private Expression checkConstraint;
private String checkConstraintSQL;
private String originalSQL;
......@@ -248,6 +249,23 @@ public class Column {
this.defaultExpression = defaultExpression;
}
/**
* Set the on update expression.
*
* @param session the session
* @param onUpdateExpression the on update expression
*/
public void setOnUpdateExpression(Session session, Expression onUpdateExpression) {
// also to test that no column names are used
if (onUpdateExpression != null) {
onUpdateExpression = onUpdateExpression.optimize(session);
if (onUpdateExpression.isConstant()) {
onUpdateExpression = ValueExpression.get(onUpdateExpression.getValue(session));
}
}
this.onUpdateExpression = onUpdateExpression;
}
public int getColumnId() {
return columnId;
}
......@@ -461,11 +479,16 @@ public class Column {
* @param session the session
*/
public void prepareExpression(Session session) {
if (defaultExpression != null) {
computeTableFilter = new TableFilter(session, table, null, false, null, 0,
null);
defaultExpression.mapColumns(computeTableFilter, 0);
defaultExpression = defaultExpression.optimize(session);
if (defaultExpression != null || onUpdateExpression != null) {
computeTableFilter = new TableFilter(session, table, null, false, null, 0, null);
if (defaultExpression != null) {
defaultExpression.mapColumns(computeTableFilter, 0);
defaultExpression = defaultExpression.optimize(session);
}
if (onUpdateExpression != null) {
onUpdateExpression.mapColumns(computeTableFilter, 0);
onUpdateExpression = onUpdateExpression.optimize(session);
}
}
}
......@@ -526,6 +549,12 @@ public class Column {
}
}
}
if (onUpdateExpression != null) {
String sql = onUpdateExpression.getSQL();
if (sql != null) {
buff.append(" ON UPDATE ").append(sql);
}
}
if (!nullable) {
buff.append(" NOT NULL");
}
......@@ -563,6 +592,10 @@ public class Column {
return defaultExpression;
}
public Expression getOnUpdateExpression() {
return onUpdateExpression;
}
public boolean isAutoIncrement() {
return autoIncrement;
}
......@@ -695,6 +728,10 @@ public class Column {
return defaultExpression == null ? null : defaultExpression.getSQL();
}
String getOnUpdateSQL() {
return onUpdateExpression == null ? null : onUpdateExpression.getSQL();
}
int getPrecisionAsInt() {
return MathUtils.convertLongToInt(precision);
}
......@@ -800,6 +837,9 @@ public class Column {
if (isComputed || newColumn.isComputed) {
return false;
}
if (onUpdateExpression != null || newColumn.onUpdateExpression != null) {
return false;
}
return true;
}
......@@ -821,6 +861,7 @@ public class Column {
// columnId is not set
nullable = source.nullable;
defaultExpression = source.defaultExpression;
onUpdateExpression = source.onUpdateExpression;
originalSQL = source.originalSQL;
// autoIncrement, start, increment is not set
convertNullToDefault = source.convertNullToDefault;
......
......@@ -179,7 +179,8 @@ public class MetaTable extends Table {
"SEQUENCE_NAME",
"REMARKS",
"SOURCE_DATA_TYPE SMALLINT",
"COLUMN_TYPE"
"COLUMN_TYPE",
"COLUMN_ON_UPDATE"
);
indexColumnName = "TABLE_NAME";
break;
......@@ -882,7 +883,9 @@ public class MetaTable extends Table {
// SOURCE_DATA_TYPE
null,
// COLUMN_TYPE
c.getCreateSQLWithoutName()
c.getCreateSQLWithoutName(),
// COLUMN_ON_UPDATE
c.getOnUpdateSQL()
);
}
}
......
......@@ -1209,6 +1209,16 @@ public abstract class Table extends SchemaObjectBase {
database.checkWritingAllowed();
}
private static Value getGeneratedValue(Session session, Column column, Expression expression) {
Value v;
if (expression == null) {
v = column.validateConvertUpdateSequence(session, null);
} else {
v = expression.getValue(session);
}
return column.convert(v);
}
/**
* Get or generate a default value for the given column.
*
......@@ -1217,14 +1227,18 @@ public abstract class Table extends SchemaObjectBase {
* @return the value
*/
public Value getDefaultValue(Session session, Column column) {
Expression defaultExpr = column.getDefaultExpression();
Value v;
if (defaultExpr == null) {
v = column.validateConvertUpdateSequence(session, null);
} else {
v = defaultExpr.getValue(session);
}
return column.convert(v);
return getGeneratedValue(session, column, column.getDefaultExpression());
}
/**
* Generates on update value for the given column.
*
* @param session the session
* @param column the column
* @return the value
*/
public Value getOnUpdateValue(Session session, Column column) {
return getGeneratedValue(session, column, column.getOnUpdateExpression());
}
@Override
......
......@@ -843,25 +843,69 @@ public class SimpleResultSet implements ResultSet, ResultSetMetaData,
}
/**
* INTERNAL
* Returns the value as an Object of the specified type.
*
* @param columnIndex the column index (1, 2, ...)
* @param type the class of the returned value
* @return the value
*/
@Override
public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
throw getUnsupportedException();
if (wasNull()) {
return null;
}
if (type == BigDecimal.class) {
return type.cast(getBigDecimal(columnIndex));
} else if (type == BigInteger.class) {
return type.cast(getBigDecimal(columnIndex).toBigInteger());
} else if (type == String.class) {
return type.cast(getString(columnIndex));
} else if (type == Boolean.class) {
return type.cast(getBoolean(columnIndex));
} else if (type == Byte.class) {
return type.cast(getByte(columnIndex));
} else if (type == Short.class) {
return type.cast(getShort(columnIndex));
} else if (type == Integer.class) {
return type.cast(getInt(columnIndex));
} else if (type == Long.class) {
return type.cast(getLong(columnIndex));
} else if (type == Float.class) {
return type.cast(getFloat(columnIndex));
} else if (type == Double.class) {
return type.cast(getDouble(columnIndex));
} else if (type == Date.class) {
return type.cast(getDate(columnIndex));
} else if (type == Time.class) {
return type.cast(getTime(columnIndex));
} else if (type == Timestamp.class) {
return type.cast(getTimestamp(columnIndex));
} else if (type == UUID.class) {
return type.cast(getObject(columnIndex));
} else if (type == byte[].class) {
return type.cast(getBytes(columnIndex));
} else if (type == java.sql.Array.class) {
return type.cast(getArray(columnIndex));
} else if (type == Blob.class) {
return type.cast(getBlob(columnIndex));
} else if (type == Clob.class) {
return type.cast(getClob(columnIndex));
} else {
throw getUnsupportedException();
}
}
/**
* INTERNAL
* Returns the value as an Object of the specified type.
*
* @param columnName the column name
* @param type the class of the returned value
* @return the value
*/
@Override
public <T> T getObject(String columnName, Class<T> type) throws SQLException {
throw getUnsupportedException();
return getObject(findColumn(columnName), type);
}
/**
......
......@@ -1471,4 +1471,48 @@ public class DateTimeUtils {
return nanosOfDay - mod;
}
/**
* Truncate the given date to 'day'
*
* @param timeUnit the time unit (e.g. 'DAY', 'HOUR', etc.)
* @param value the date
* @return date truncated to 'day'
*/
public static Value truncateDate(String timeUnit, Value value) {
Value result = null;
// Retrieve the dateValue.
long[] fieldDateAndTime = DateTimeUtils.dateAndTimeFromValue(value);
long dateValue = fieldDateAndTime[0];
// Case where the date has to be truncated to the day.
if (timeUnit.equals("DAY")) {
if (value instanceof ValueTimestampTimeZone) {
// Create a new ValueTimestampTimeZone by only setting the
// date. The time in nanoseconds since midnight will be set
// to 0.
ValueTimestampTimeZone vTmp = (ValueTimestampTimeZone) value;
result = ValueTimestampTimeZone.fromDateValueAndNanos(vTmp.getDateValue(), 0,
vTmp.getTimeZoneOffsetMins());
} else {
// By default, we create a timestamp by setting the
// date value to the date value retrieved and the time in
// nanoseconds since midnight to 0.
result = ValueTimestamp.fromDateValueAndNanos(dateValue, 0);
}
} else {
// Return an exception for the other possible value (not yet
// supported).
throw DbException.getUnsupportedException(timeUnit);
}
return result;
}
}
......@@ -40,7 +40,7 @@ public class TestShow extends TestBase {
assertResult("read committed", stat, "SHOW DEFAULT_TRANSACTION_ISOLATION");
assertResult("read committed", stat, "SHOW TRANSACTION ISOLATION LEVEL");
assertResult("ISO", stat, "SHOW DATESTYLE");
assertResult("8.1.4", stat, "SHOW SERVER_VERSION");
assertResult("8.2.23", stat, "SHOW SERVER_VERSION");
assertResult("UTF8", stat, "SHOW SERVER_ENCODING");
}
}
......
......@@ -598,10 +598,16 @@ public class TestGetGeneratedKeys extends TestBase {
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertEquals(3L, rs.getLong("ID"));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertEquals(UUID.class, rs.getObject("UID").getClass());
assertEquals(UUID.class, rs.getObject("UID", UUID.class).getClass());
assertTrue(rs.next());
assertEquals(4L, rs.getLong(1));
assertEquals(4L, rs.getLong("ID"));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertEquals(UUID.class, rs.getObject("UID").getClass());
assertEquals(UUID.class, rs.getObject("UID", UUID.class).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
......@@ -639,10 +645,16 @@ public class TestGetGeneratedKeys extends TestBase {
assertEquals("UID", rs.getMetaData().getColumnName(2));
assertTrue(rs.next());
assertEquals(3L, rs.getLong(1));
assertEquals(3L, rs.getLong("ID"));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertEquals(UUID.class, rs.getObject("UID").getClass());
assertEquals(UUID.class, rs.getObject("UID", UUID.class).getClass());
assertTrue(rs.next());
assertEquals(4L, rs.getLong(1));
assertEquals(4L, rs.getLong("ID"));
assertEquals(UUID.class, rs.getObject(2).getClass());
assertEquals(UUID.class, rs.getObject("UID").getClass());
assertEquals(UUID.class, rs.getObject("UID", UUID.class).getClass());
assertFalse(rs.next());
rs.close();
stat.execute("DROP TABLE TEST");
......
......@@ -12,6 +12,7 @@ import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import org.h2.jdbc.JdbcSQLException;
import org.h2.message.DbException;
import org.h2.test.TestBase;
import org.h2.util.IOUtils;
......@@ -63,6 +64,9 @@ public class TestMvccMultiThreaded2 extends TestBase {
ps.setInt(1, 1);
ps.setInt(2, 100);
ps.executeUpdate();
ps.setInt(1, 2);
ps.setInt(2, 200);
ps.executeUpdate();
conn.commit();
ArrayList<SelectForUpdate> threads = new ArrayList<>();
......@@ -80,9 +84,11 @@ public class TestMvccMultiThreaded2 extends TestBase {
@SuppressWarnings("unused")
int minProcessed = Integer.MAX_VALUE, maxProcessed = 0, totalProcessed = 0;
boolean allOk = true;
for (SelectForUpdate sfu : threads) {
// make sure all threads have stopped by joining with them
sfu.join();
allOk &= sfu.ok;
totalProcessed += sfu.iterationsProcessed;
if (sfu.iterationsProcessed > maxProcessed) {
maxProcessed = sfu.iterationsProcessed;
......@@ -102,6 +108,8 @@ public class TestMvccMultiThreaded2 extends TestBase {
IOUtils.closeSilently(conn);
deleteDb(getTestName());
assertTrue(allOk);
}
/**
......@@ -111,6 +119,8 @@ public class TestMvccMultiThreaded2 extends TestBase {
public int iterationsProcessed;
public boolean ok;
SelectForUpdate() {
}
......@@ -130,11 +140,20 @@ public class TestMvccMultiThreaded2 extends TestBase {
try {
PreparedStatement ps = conn.prepareStatement(
"SELECT * FROM test WHERE entity_id = ? FOR UPDATE");
ps.setString(1, "1");
String id;
int value;
if ((iterationsProcessed & 1) == 0) {
id = "1";
value = 100;
} else {
id = "2";
value = 200;
}
ps.setString(1, id);
ResultSet rs = ps.executeQuery();
assertTrue(rs.next());
assertTrue(rs.getInt(2) == 100);
assertTrue(rs.getInt(2) == value);
conn.commit();
iterationsProcessed++;
......@@ -149,11 +168,13 @@ public class TestMvccMultiThreaded2 extends TestBase {
}
} catch (SQLException e) {
TestBase.logError("SQL error from thread "+getName(), e);
throw DbException.convert(e);
} catch (Exception e) {
TestBase.logError("General error from thread "+getName(), e);
throw e;
}
IOUtils.closeSilently(conn);
ok = true;
}
}
}
......@@ -86,6 +86,7 @@ public class TestScript extends TestBase {
testScript("information_schema.sql");
testScript("joins.sql");
testScript("altertable-index-reuse.sql");
testScript("default-and-on_update.sql");
testScript("query-optimisations.sql");
String decimal2;
if (SysProperties.BIG_DECIMAL_IS_DECIMAL) {
......@@ -147,9 +148,10 @@ public class TestScript extends TestBase {
"current-time", "dateadd", "datediff", "dayname",
"day-of-month", "day-of-week", "day-of-year", "extract",
"formatdatetime", "hour", "minute", "month", "monthname",
"parsedatetime", "quarter", "second", "truncate", "week", "year" }) {
"parsedatetime", "quarter", "second", "truncate", "week", "year", "date_trunc" }) {
testScript("functions/timeanddate/" + s + ".sql");
}
deleteDb("script");
System.out.flush();
}
......
......@@ -9,13 +9,13 @@ create memory table orders ( orderid varchar(10), name varchar(20), customer_id
> ok
select * from information_schema.columns where table_name = 'ORDERS';
> TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_PRECISION_RADIX NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME TYPE_NAME NULLABLE IS_COMPUTED SELECTIVITY CHECK_CONSTRAINT SEQUENCE_NAME REMARKS SOURCE_DATA_TYPE COLUMN_TYPE
> ------------- ------------ ---------- ----------- ---------------- -------------- ----------- --------- ------------------------ ---------------------- ----------------- ----------------------- ------------- ------------------ -------------- --------- -------- ----------- ----------- ---------------- ------------- ------- ---------------- -------------------
> SCRIPT PUBLIC ORDERS COMPLETED 4 null NO 3 1 1 1 10 0 Unicode OFF DECIMAL 0 FALSE 50 null null NUMERIC(1) NOT NULL
> SCRIPT PUBLIC ORDERS CUSTOMER_ID 3 null YES 12 10 10 10 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(10)
> SCRIPT PUBLIC ORDERS NAME 2 null YES 12 20 20 20 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(20)
> SCRIPT PUBLIC ORDERS ORDERID 1 null YES 12 10 10 10 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(10)
> SCRIPT PUBLIC ORDERS VERIFIED 5 null YES 3 1 1 1 10 0 Unicode OFF DECIMAL 1 FALSE 50 null null NUMERIC(1)
> TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_PRECISION_RADIX NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME TYPE_NAME NULLABLE IS_COMPUTED SELECTIVITY CHECK_CONSTRAINT SEQUENCE_NAME REMARKS SOURCE_DATA_TYPE COLUMN_TYPE COLUMN_ON_UPDATE
> ------------- ------------ ---------- ----------- ---------------- -------------- ----------- --------- ------------------------ ---------------------- ----------------- ----------------------- ------------- ------------------ -------------- --------- -------- ----------- ----------- ---------------- ------------- ------- ---------------- ------------------- ----------------
> SCRIPT PUBLIC ORDERS COMPLETED 4 null NO 3 1 1 1 10 0 Unicode OFF DECIMAL 0 FALSE 50 null null NUMERIC(1) NOT NULL null
> SCRIPT PUBLIC ORDERS CUSTOMER_ID 3 null YES 12 10 10 10 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(10) null
> SCRIPT PUBLIC ORDERS NAME 2 null YES 12 20 20 20 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(20) null
> SCRIPT PUBLIC ORDERS ORDERID 1 null YES 12 10 10 10 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(10) null
> SCRIPT PUBLIC ORDERS VERIFIED 5 null YES 3 1 1 1 10 0 Unicode OFF DECIMAL 1 FALSE 50 null null NUMERIC(1) null
> rows: 5
drop table orders;
......
......@@ -9,13 +9,13 @@ create memory table orders ( orderid varchar(10), name varchar(20), customer_id
> ok
select * from information_schema.columns where table_name = 'ORDERS';
> TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_PRECISION_RADIX NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME TYPE_NAME NULLABLE IS_COMPUTED SELECTIVITY CHECK_CONSTRAINT SEQUENCE_NAME REMARKS SOURCE_DATA_TYPE COLUMN_TYPE
> ------------- ------------ ---------- ----------- ---------------- -------------- ----------- --------- ------------------------ ---------------------- ----------------- ----------------------- ------------- ------------------ -------------- --------- -------- ----------- ----------- ---------------- ------------- ------- ---------------- -------------------
> SCRIPT PUBLIC ORDERS COMPLETED 4 null NO 2 1 1 1 10 0 Unicode OFF NUMERIC 0 FALSE 50 null null NUMERIC(1) NOT NULL
> SCRIPT PUBLIC ORDERS CUSTOMER_ID 3 null YES 12 10 10 10 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(10)
> SCRIPT PUBLIC ORDERS NAME 2 null YES 12 20 20 20 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(20)
> SCRIPT PUBLIC ORDERS ORDERID 1 null YES 12 10 10 10 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(10)
> SCRIPT PUBLIC ORDERS VERIFIED 5 null YES 2 1 1 1 10 0 Unicode OFF NUMERIC 1 FALSE 50 null null NUMERIC(1)
> TABLE_CATALOG TABLE_SCHEMA TABLE_NAME COLUMN_NAME ORDINAL_POSITION COLUMN_DEFAULT IS_NULLABLE DATA_TYPE CHARACTER_MAXIMUM_LENGTH CHARACTER_OCTET_LENGTH NUMERIC_PRECISION NUMERIC_PRECISION_RADIX NUMERIC_SCALE CHARACTER_SET_NAME COLLATION_NAME TYPE_NAME NULLABLE IS_COMPUTED SELECTIVITY CHECK_CONSTRAINT SEQUENCE_NAME REMARKS SOURCE_DATA_TYPE COLUMN_TYPE COLUMN_ON_UPDATE
> ------------- ------------ ---------- ----------- ---------------- -------------- ----------- --------- ------------------------ ---------------------- ----------------- ----------------------- ------------- ------------------ -------------- --------- -------- ----------- ----------- ---------------- ------------- ------- ---------------- ------------------- ----------------
> SCRIPT PUBLIC ORDERS COMPLETED 4 null NO 2 1 1 1 10 0 Unicode OFF NUMERIC 0 FALSE 50 null null NUMERIC(1) NOT NULL null
> SCRIPT PUBLIC ORDERS CUSTOMER_ID 3 null YES 12 10 10 10 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(10) null
> SCRIPT PUBLIC ORDERS NAME 2 null YES 12 20 20 20 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(20) null
> SCRIPT PUBLIC ORDERS ORDERID 1 null YES 12 10 10 10 10 0 Unicode OFF VARCHAR 1 FALSE 50 null null VARCHAR(10) null
> SCRIPT PUBLIC ORDERS VERIFIED 5 null YES 2 1 1 1 10 0 Unicode OFF NUMERIC 1 FALSE 50 null null NUMERIC(1) null
> rows: 5
drop table orders;
......
-- Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
CREATE SEQUENCE SEQ;
> ok
CREATE TABLE TEST(ID INT PRIMARY KEY, V INT DEFAULT NEXT VALUE FOR SEQ ON UPDATE 1000 * NEXT VALUE FOR SEQ);
> ok
INSERT INTO TEST(ID) VALUES (1), (2);
> update count: 2
SELECT * FROM TEST ORDER BY ID;
> ID V
> -- -
> 1 1
> 2 2
> rows (ordered): 2
UPDATE TEST SET ID = 3 WHERE ID = 2;
> update count: 1
SELECT * FROM TEST ORDER BY ID;
> ID V
> -- ----
> 1 1
> 3 3000
> rows (ordered): 2
UPDATE TEST SET V = 3 WHERE ID = 3;
> update count: 1
SELECT * FROM TEST ORDER BY ID;
> ID V
> -- -
> 1 1
> 3 3
> rows (ordered): 2
ALTER TABLE TEST ADD V2 TIMESTAMP ON UPDATE CURRENT_TIMESTAMP;
> ok
UPDATE TEST SET V = 4 WHERE ID = 3;
> update count: 1
SELECT ID, V, LENGTH(V2) > 18 AS L FROM TEST ORDER BY ID;
> ID V L
> -- - ----
> 1 1 null
> 3 4 TRUE
> rows (ordered): 2
UPDATE TEST SET V = 1 WHERE V = 1;
> update count: 1
SELECT ID, V, LENGTH(V2) > 18 AS L FROM TEST ORDER BY ID;
> ID V L
> -- - ----
> 1 1 null
> 3 4 TRUE
> rows (ordered): 2
MERGE INTO TEST(ID, V) KEY(ID) VALUES (1, 1);
> update count: 1
SELECT ID, V, LENGTH(V2) > 18 AS L FROM TEST ORDER BY ID;
> ID V L
> -- - ----
> 1 1 null
> 3 4 TRUE
> rows (ordered): 2
MERGE INTO TEST(ID, V) KEY(ID) VALUES (1, 2);
> update count: 1
SELECT ID, V, LENGTH(V2) > 18 AS L FROM TEST ORDER BY ID;
> ID V L
> -- - ----
> 1 2 TRUE
> 3 4 TRUE
> rows (ordered): 2
ALTER TABLE TEST ALTER COLUMN V SET ON UPDATE NULL;
> ok
SELECT COLUMN_NAME, COLUMN_DEFAULT, COLUMN_ON_UPDATE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TEST' ORDER BY COLUMN_NAME;
> COLUMN_NAME COLUMN_DEFAULT COLUMN_ON_UPDATE
> ----------- --------------------------- -------------------
> ID null null
> V (NEXT VALUE FOR PUBLIC.SEQ) NULL
> V2 null CURRENT_TIMESTAMP()
> rows (ordered): 3
ALTER TABLE TEST ALTER COLUMN V DROP ON UPDATE;
> ok
SELECT COLUMN_NAME, COLUMN_DEFAULT, COLUMN_ON_UPDATE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'TEST' ORDER BY COLUMN_NAME;
> COLUMN_NAME COLUMN_DEFAULT COLUMN_ON_UPDATE
> ----------- --------------------------- -------------------
> ID null null
> V (NEXT VALUE FOR PUBLIC.SEQ) null
> V2 null CURRENT_TIMESTAMP()
> rows (ordered): 3
DROP TABLE TEST;
> ok
DROP SEQUENCE SEQ;
> ok
-- Copyright 2004-2018 H2 Group. Multiple-Licensed under the MPL 2.0,
-- and the EPL 1.0 (http://h2database.com/html/license.html).
-- Initial Developer: H2 Group
--
select DATE_TRUNC('day', time '00:00:00');
>> 1970-01-01 00:00:00
select DATE_TRUNC('DAY', time '00:00:00');
>> 1970-01-01 00:00:00
select DATE_TRUNC('day', time '15:14:13');
>> 1970-01-01 00:00:00
select DATE_TRUNC('DAY', time '15:14:13');
>> 1970-01-01 00:00:00
select DATE_TRUNC('day', date '2015-05-29');
>> 2015-05-29 00:00:00
select DATE_TRUNC('DAY', date '2015-05-29');
>> 2015-05-29 00:00:00
select DATE_TRUNC('day', timestamp '2015-05-29 15:14:13');
>> 2015-05-29 00:00:00
select DATE_TRUNC('DAY', timestamp '2015-05-29 15:14:13');
>> 2015-05-29 00:00:00
select DATE_TRUNC('day', timestamp with time zone '2015-05-29 15:14:13');
>> 2015-05-29 00:00:00+00
select DATE_TRUNC('DAY', timestamp with time zone '2015-05-29 15:14:13');
>> 2015-05-29 00:00:00+00
select DATE_TRUNC('day', timestamp with time zone '2015-05-29 05:14:13-06');
>> 2015-05-29 00:00:00-06
select DATE_TRUNC('DAY', timestamp with time zone '2015-05-29 05:14:13-06');
>> 2015-05-29 00:00:00-06
select DATE_TRUNC('day', timestamp with time zone '2015-05-29 15:14:13+10');
>> 2015-05-29 00:00:00+10
select DATE_TRUNC('DAY', timestamp with time zone '2015-05-29 15:14:13+10');
>> 2015-05-29 00:00:00+10
select DATE_TRUNC('day', '2015-05-29 15:14:13');
>> 2015-05-29 00:00:00
select DATE_TRUNC('DAY', '2015-05-29 15:14:13');
>> 2015-05-29 00:00:00
SELECT DATE_TRUNC('---', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('microseconds', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('MICROSECONDS', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('milliseconds', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('MILLISECONDS', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('second', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('SECOND', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('minute', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('MINUTE', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('hour', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('HOUR', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('week', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('WEEK', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('month', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('MONTH', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('quarter', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('QUARTER', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('year', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('YEAR', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('decade', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('DECADE', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('century', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('CENTURY', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('millennium', '2015-05-29 15:14:13');
> exception
SELECT DATE_TRUNC('MILLENNIUM', '2015-05-29 15:14:13');
> exception
......@@ -747,7 +747,7 @@ public class TestTransactionStore extends TestBase {
Class.forName("org.postgresql.Driver");
for (int i = 0; i < connectionCount; i++) {
Connection conn = DriverManager.getConnection(
"jdbc:postgresql:test", "sa", "sa");
"jdbc:postgresql:test?loggerLevel=OFF", "sa", "sa");
statements.add(conn.createStatement());
}
} catch (Exception e) {
......
......@@ -54,7 +54,7 @@ public class TestNestedJoins extends TestBase {
try {
Class.forName("org.postgresql.Driver");
Connection c2 = DriverManager.getConnection("jdbc:postgresql:test", "sa", "sa");
Connection c2 = DriverManager.getConnection("jdbc:postgresql:test?loggerLevel=OFF", "sa", "sa");
dbs.add(c2.createStatement());
} catch (Exception e) {
// database not installed - ok
......
......@@ -53,7 +53,7 @@ public class TestOuterJoins extends TestBase {
try {
Class.forName("org.postgresql.Driver");
Connection c2 = DriverManager.getConnection(
"jdbc:postgresql:test", "sa", "sa");
"jdbc:postgresql:test?loggerLevel=OFF", "sa", "sa");
dbs.add(c2.createStatement());
} catch (Exception e) {
// database not installed - ok
......
......@@ -50,7 +50,7 @@ public class TestRandomCompare extends TestBase {
try {
Class.forName("org.postgresql.Driver");
Connection c2 = DriverManager.getConnection(
"jdbc:postgresql:test", "sa", "sa");
"jdbc:postgresql:test?loggerLevel=OFF", "sa", "sa");
dbs.add(c2.createStatement());
} catch (Exception e) {
// database not installed - ok
......
......@@ -59,9 +59,9 @@ public class Build extends BuildBase {
downloadUsingMaven("ext/derbynet-10.10.1.1.jar",
"org/apache/derby", "derbynet", "10.10.1.1",
"912b08dca73663d4665e09cd317be1218412d93e");
downloadUsingMaven("ext/postgresql-9.4.1209.jre6.jar",
"org.postgresql", "postgresql", "9.4.1209.jre6",
"2ed7a5a8c952d9ea18af92efea7e56ef854abfea");
downloadUsingMaven("ext/postgresql-42.2.1.jre7",
"org.postgresql", "postgresql", "42.2.1.jre7",
"d06eb133d573240718fe4c24577ef086f7daad6c");
downloadUsingMaven("ext/mysql-connector-java-5.1.6.jar",
"mysql", "mysql-connector-java", "5.1.6",
"380ef5226de2c85ff3b38cbfefeea881c5fce09d");
......@@ -74,7 +74,7 @@ public class Build extends BuildBase {
File.pathSeparator + "ext/derby-10.10.1.1.jar" +
File.pathSeparator + "ext/derbyclient-10.10.1.1.jar" +
File.pathSeparator + "ext/derbynet-10.10.1.1.jar" +
File.pathSeparator + "ext/postgresql-9.4.1209.jre6.jar" +
File.pathSeparator + "ext/postgresql-42.2.1.jre7" +
File.pathSeparator + "ext/mysql-connector-java-5.1.6.jar";
StringList args = args("-Xmx128m",
"-cp", cp, "org.h2.test.bench.TestPerformance");
......@@ -182,7 +182,7 @@ public class Build extends BuildBase {
// JaCoCo does not support multiple versions of the same classes
delete(files("coverage/bin/META-INF/versions"));
String cp = "coverage/bin" +
File.pathSeparator + "ext/postgresql-9.4.1209.jre6.jar" +
File.pathSeparator + "ext/postgresql-42.2.1.jre7" +
File.pathSeparator + "ext/servlet-api-3.1.0.jar" +
File.pathSeparator + "ext/lucene-core-3.6.2.jar" +
File.pathSeparator + "ext/h2mig_pagestore_addon.jar" +
......@@ -427,9 +427,9 @@ public class Build extends BuildBase {
"com/h2database", "h2", "1.2.127",
"056e784c7cf009483366ab9cd8d21d02fe47031a");
// for TestPgServer
downloadUsingMaven("ext/postgresql-9.4.1209.jre6.jar",
"org.postgresql", "postgresql", "9.4.1209.jre6",
"2ed7a5a8c952d9ea18af92efea7e56ef854abfea");
downloadUsingMaven("ext/postgresql-42.2.1.jre7.jar",
"org.postgresql", "postgresql", "42.2.1.jre7",
"d06eb133d573240718fe4c24577ef086f7daad6c");
// for TestTraceSystem
downloadUsingMaven("ext/slf4j-nop-1.6.0.jar",
"org/slf4j", "slf4j-nop", "1.6.0",
......@@ -1012,7 +1012,7 @@ public class Build extends BuildBase {
private void test(boolean travis) {
downloadTest();
String cp = "temp" + File.pathSeparator + "bin" +
File.pathSeparator + "ext/postgresql-9.4.1209.jre6.jar" +
File.pathSeparator + "ext/postgresql-42.2.1.jre7.jar" +
File.pathSeparator + "ext/servlet-api-3.1.0.jar" +
File.pathSeparator + "ext/lucene-core-3.6.2.jar" +
File.pathSeparator + "ext/h2mig_pagestore_addon.jar" +
......
......@@ -766,4 +766,4 @@ interpolated thead
die weekdiff osx subprocess dow proleptic microsecond microseconds divisible cmp denormalized suppressed saturated mcs
london dfs weekdays intermittent looked msec tstz africa monrovia asia tokyo weekday joi callers multipliers ucn
openoffice organize libre systemtables gmane sea borders
openoffice organize libre systemtables gmane sea borders announced millennium
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论