提交 e3d1039b authored 作者: Thomas Mueller's avatar Thomas Mueller

--no commit message

--no commit message
上级 e9bd9c7d
...@@ -16,6 +16,7 @@ import java.util.HashMap; ...@@ -16,6 +16,7 @@ import java.util.HashMap;
import java.util.Locale; import java.util.Locale;
import java.util.TimeZone; import java.util.TimeZone;
import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.Mode; import org.h2.engine.Mode;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -26,14 +27,17 @@ import org.h2.security.CipherFactory; ...@@ -26,14 +27,17 @@ import org.h2.security.CipherFactory;
import org.h2.security.SHA256; import org.h2.security.SHA256;
import org.h2.table.Column; import org.h2.table.Column;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.LinkSchema;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.tools.CompressTool; import org.h2.tools.CompressTool;
import org.h2.tools.Csv; import org.h2.tools.Csv;
import org.h2.tools.SimpleResultSet;
import org.h2.util.MathUtils; import org.h2.util.MathUtils;
import org.h2.util.MemoryUtils; import org.h2.util.MemoryUtils;
import org.h2.util.ObjectArray; import org.h2.util.ObjectArray;
import org.h2.util.RandomUtils; import org.h2.util.RandomUtils;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
import org.h2.value.DataType;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueArray; import org.h2.value.ValueArray;
import org.h2.value.ValueBoolean; import org.h2.value.ValueBoolean;
...@@ -89,7 +93,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -89,7 +93,8 @@ public class Function extends Expression implements FunctionCall {
public static final int IFNULL = 200, CASEWHEN = 201, CONVERT = 202, CAST = 203, public static final int IFNULL = 200, CASEWHEN = 201, CONVERT = 202, CAST = 203,
COALESCE = 204, NULLIF = 205, CASE = 206, NEXTVAL = 207, CURRVAL = 208, COALESCE = 204, NULLIF = 205, CASE = 206, NEXTVAL = 207, CURRVAL = 208,
ARRAY_GET = 209, CSVREAD = 210, CSVWRITE = 211, MEMORY_FREE = 212, ARRAY_GET = 209, CSVREAD = 210, CSVWRITE = 211, MEMORY_FREE = 212,
MEMORY_USED = 213, LOCK_MODE = 214, SCHEMA = 215, SESSION_ID = 216, ARRAY_LENGTH = 217; MEMORY_USED = 213, LOCK_MODE = 214, SCHEMA = 215, SESSION_ID = 216, ARRAY_LENGTH = 217,
LINK_SCHEMA = 218, TABLE = 219;
private static final int VAR_ARGS = -1; private static final int VAR_ARGS = -1;
...@@ -100,6 +105,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -100,6 +105,7 @@ public class Function extends Expression implements FunctionCall {
private ObjectArray varArgs; private ObjectArray varArgs;
private int dataType, scale; private int dataType, scale;
private long precision; private long precision;
private Column[] columnList;
private Database database; private Database database;
private static HashMap datePart; private static HashMap datePart;
...@@ -126,7 +132,7 @@ public class Function extends Expression implements FunctionCall { ...@@ -126,7 +132,7 @@ public class Function extends Expression implements FunctionCall {
datePart.put("MS", new Integer(Calendar.MILLISECOND)); datePart.put("MS", new Integer(Calendar.MILLISECOND));
datePart.put("MILLISECOND", new Integer(Calendar.MILLISECOND)); datePart.put("MILLISECOND", new Integer(Calendar.MILLISECOND));
} }
static { static {
String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R"; String index = "7AEIOUY8HW1BFPV2CGJKQSXZ3DT4L5MN6R";
char number = 0; char number = 0;
...@@ -271,13 +277,15 @@ public class Function extends Expression implements FunctionCall { ...@@ -271,13 +277,15 @@ public class Function extends Expression implements FunctionCall {
addFunctionNotConst("CURRVAL", CURRVAL, VAR_ARGS, Value.LONG); addFunctionNotConst("CURRVAL", CURRVAL, VAR_ARGS, Value.LONG);
addFunction("ARRAY_GET", ARRAY_GET, 2, Value.NULL); addFunction("ARRAY_GET", ARRAY_GET, 2, Value.NULL);
addFunction("CSVREAD", CSVREAD, VAR_ARGS, Value.RESULT_SET, false, false); addFunction("CSVREAD", CSVREAD, VAR_ARGS, Value.RESULT_SET, false, false);
addFunction("CSVWRITE", CSVWRITE, VAR_ARGS, Value.NULL, false, false); addFunction("CSVWRITE", CSVWRITE, VAR_ARGS, Value.INT, false, false);
addFunctionNotConst("MEMORY_FREE", MEMORY_FREE, 0, Value.INT); addFunctionNotConst("MEMORY_FREE", MEMORY_FREE, 0, Value.INT);
addFunctionNotConst("MEMORY_USED", MEMORY_USED, 0, Value.INT); addFunctionNotConst("MEMORY_USED", MEMORY_USED, 0, Value.INT);
addFunctionNotConst("LOCK_MODE", LOCK_MODE, 0, Value.INT); addFunctionNotConst("LOCK_MODE", LOCK_MODE, 0, Value.INT);
addFunctionNotConst("SCHEMA", SCHEMA, 0, Value.STRING); addFunctionNotConst("SCHEMA", SCHEMA, 0, Value.STRING);
addFunctionNotConst("SESSION_ID", SESSION_ID, 0, Value.INT); addFunctionNotConst("SESSION_ID", SESSION_ID, 0, Value.INT);
addFunction("ARRAY_LENGTH", ARRAY_LENGTH, 1, Value.INT); addFunction("ARRAY_LENGTH", ARRAY_LENGTH, 1, Value.INT);
addFunction("LINK_SCHEMA", LINK_SCHEMA, 6, Value.RESULT_SET);
addFunctionWithNull("TABLE", TABLE, VAR_ARGS, Value.RESULT_SET);
} }
private static void addFunction(String name, int type, int parameterCount, private static void addFunction(String name, int type, int parameterCount,
...@@ -343,25 +351,36 @@ public class Function extends Expression implements FunctionCall { ...@@ -343,25 +351,36 @@ public class Function extends Expression implements FunctionCall {
public Value getValue(Session session) throws SQLException { public Value getValue(Session session) throws SQLException {
return getValueWithArgs(session, args); return getValueWithArgs(session, args);
} }
private Value getNullOrValue(Session session, Expression[] x, int i) throws SQLException {
if (i < x.length) {
Expression e = x[i];
if(e != null) {
return e.getValue(session);
}
}
return null;
}
public Value getValueWithArgs(Session session, Expression[] args) throws SQLException { public Value getValueWithArgs(Session session, Expression[] args) throws SQLException {
if (info.nullIfParameterIsNull) { if (info.nullIfParameterIsNull) {
for (int i = 0; i < args.length; i++) { for (int i = 0; i < args.length; i++) {
Expression e = args[i]; if (getNullOrValue(session, args, i) == ValueNull.INSTANCE) {
if (e != null && e.getValue(session) == ValueNull.INSTANCE) {
return ValueNull.INSTANCE; return ValueNull.INSTANCE;
} }
} }
} }
Value v0 = args.length < 1 || args[0] == null ? null : args[0].getValue(session); Value v0 = getNullOrValue(session, args, 0);
switch (info.type) { switch (info.type) {
case IFNULL: case IFNULL:
return v0 == ValueNull.INSTANCE ? args[1].getValue(session) : v0; return v0 == ValueNull.INSTANCE ? args[1].getValue(session) : v0;
case CASEWHEN: { case CASEWHEN: {
if(v0 == ValueNull.INSTANCE) { Expression result;
return v0; if(v0 == ValueNull.INSTANCE || !v0.getBoolean().booleanValue()) {
result = args[2];
} else {
result = args[1];
} }
Expression result = v0.getBoolean().booleanValue() ? args[1] : args[2];
Value v = result.getValue(session); Value v = result.getValue(session);
v = v.convertTo(dataType); v = v.convertTo(dataType);
return v; return v;
...@@ -408,9 +427,11 @@ public class Function extends Expression implements FunctionCall { ...@@ -408,9 +427,11 @@ public class Function extends Expression implements FunctionCall {
default: default:
// ok // ok
} }
Value v1 = args.length < 2 || args[1] == null ? null : args[1].getValue(session); Value v1 = getNullOrValue(session, args, 1);
Value v2 = args.length < 3 || args[2] == null ? null : args[2].getValue(session); Value v2 = getNullOrValue(session, args, 2);
Value v3 = args.length < 4 || args[3] == null ? null : args[3].getValue(session); Value v3 = getNullOrValue(session, args, 3);
Value v4 = getNullOrValue(session, args, 4);
Value v5 = getNullOrValue(session, args, 5);
switch (info.type) { switch (info.type) {
case ABS: case ABS:
return v0.getSignum() > 0 ? v0 : v0.negate(); return v0.getSignum() > 0 ? v0 : v0.negate();
...@@ -752,7 +773,16 @@ public class Function extends Expression implements FunctionCall { ...@@ -752,7 +773,16 @@ public class Function extends Expression implements FunctionCall {
ValueResultSet vr = ValueResultSet.get(csv.read(fileName, columns, charset)); ValueResultSet vr = ValueResultSet.get(csv.read(fileName, columns, charset));
return vr; return vr;
} }
case LINK_SCHEMA: {
session.getUser().checkAdmin();
Connection conn = session.createConnection(false);
ResultSet rs = LinkSchema.linkSchema(conn, v0.getString(), v1.getString(), v2.getString(), v3.getString(), v4.getString(), v5.getString());
return ValueResultSet.get(rs);
}
case TABLE:
return getTable(session, args, false);
case CSVWRITE: { case CSVWRITE: {
session.getUser().checkAdmin();
Connection conn = session.createConnection(false); Connection conn = session.createConnection(false);
String charset = v2 == null ? null : v2.getString(); String charset = v2 == null ? null : v2.getString();
String fieldSeparatorWrite = v3 == null ? null : v3.getString(); String fieldSeparatorWrite = v3 == null ? null : v3.getString();
...@@ -760,8 +790,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -760,8 +790,8 @@ public class Function extends Expression implements FunctionCall {
if(fieldSeparatorWrite != null) { if(fieldSeparatorWrite != null) {
csv.setFieldSeparatorWrite(fieldSeparatorWrite); csv.setFieldSeparatorWrite(fieldSeparatorWrite);
} }
csv.write(conn, v0.getString(), v1.getString(), charset); int rows = csv.write(conn, v0.getString(), v1.getString(), charset);
return ValueNull.INSTANCE; return ValueInt.get(rows);
} }
case MEMORY_FREE: case MEMORY_FREE:
session.getUser().checkAdmin(); session.getUser().checkAdmin();
...@@ -1188,6 +1218,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -1188,6 +1218,8 @@ public class Function extends Expression implements FunctionCall {
int min=0, max=Integer.MAX_VALUE; int min=0, max=Integer.MAX_VALUE;
switch (info.type) { switch (info.type) {
case COALESCE: case COALESCE:
case CSVREAD:
case TABLE:
min = 1; min = 1;
break; break;
case NOW: case NOW:
...@@ -1211,11 +1243,6 @@ public class Function extends Expression implements FunctionCall { ...@@ -1211,11 +1243,6 @@ public class Function extends Expression implements FunctionCall {
break; break;
case CASE: case CASE:
case CONCAT: case CONCAT:
min = 2;
break;
case CSVREAD:
min = 1;
break;
case CSVWRITE: case CSVWRITE:
min = 2; min = 2;
break; break;
...@@ -1274,6 +1301,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -1274,6 +1301,8 @@ public class Function extends Expression implements FunctionCall {
} }
Expression p0 = args.length < 1 ? null : args[0]; Expression p0 = args.length < 1 ? null : args[0];
switch (info.type) { switch (info.type) {
case IFNULL:
case NULLIF:
case COALESCE: { case COALESCE: {
dataType = Value.STRING; dataType = Value.STRING;
scale = 0; scale = 0;
...@@ -1304,14 +1333,23 @@ public class Function extends Expression implements FunctionCall { ...@@ -1304,14 +1333,23 @@ public class Function extends Expression implements FunctionCall {
case ROUND: case ROUND:
case TRUNCATE: case TRUNCATE:
case POWER: case POWER:
case ARRAY_GET:
dataType = p0.getType(); dataType = p0.getType();
scale = p0.getScale(); scale = p0.getScale();
precision = p0.getPrecision(); precision = p0.getPrecision();
if(dataType == Value.NULL) {
dataType = Value.INT;
precision = ValueInt.PRECISION;
scale = 0;
}
break; break;
default: default:
dataType = info.dataType; dataType = info.dataType;
scale = 0;
precision = 0; precision = 0;
scale = 0;
}
if(Constants.CHECK && dataType == Value.NULL) {
throw Message.getInternalError("type NULL: " + getSQL());
} }
if(allConst) { if(allConst) {
return ValueExpression.get(getValue(session)); return ValueExpression.get(getValue(session));
...@@ -1392,7 +1430,8 @@ public class Function extends Expression implements FunctionCall { ...@@ -1392,7 +1430,8 @@ public class Function extends Expression implements FunctionCall {
} }
public ValueResultSet getValueForColumnList(Session session, Expression[] args) throws SQLException { public ValueResultSet getValueForColumnList(Session session, Expression[] args) throws SQLException {
if(info.type == CSVREAD) { switch(info.type) {
case CSVREAD: {
String fileName = args[0].getValue(session).getString(); String fileName = args[0].getValue(session).getString();
if(fileName == null) { if(fileName == null) {
throw Message.getSQLException(Message.PARAMETER_NOT_SET_1, "fileName"); throw Message.getSQLException(Message.PARAMETER_NOT_SET_1, "fileName");
...@@ -1411,6 +1450,10 @@ public class Function extends Expression implements FunctionCall { ...@@ -1411,6 +1450,10 @@ public class Function extends Expression implements FunctionCall {
ValueResultSet vr = ValueResultSet.getCopy(rs, 0); ValueResultSet vr = ValueResultSet.getCopy(rs, 0);
return vr; return vr;
} }
case TABLE: {
return getTable(session, args, true);
}
}
return (ValueResultSet)getValueWithArgs(session, args); return (ValueResultSet)getValueWithArgs(session, args);
} }
...@@ -1438,5 +1481,58 @@ public class Function extends Expression implements FunctionCall { ...@@ -1438,5 +1481,58 @@ public class Function extends Expression implements FunctionCall {
} }
return cost; return cost;
} }
public ValueResultSet getTable(Session session, Expression[] args, boolean onlyColumnList) throws SQLException {
SimpleResultSet rs = new SimpleResultSet();
int len = columnList.length;
for(int i=0; i<len; i++) {
Column c = columnList[i];
String columnName = c.getName();
int dataType = DataType.convertTypeToSQLType(c.getType());
int precision = MathUtils.convertLongToInt(c.getPrecision());
int scale = c.getScale();
rs.addColumn(columnName, dataType, precision, scale);
}
if(!onlyColumnList) {
Value[][] list = new Value[args.length][];
int rowCount = 0;
for(int i=0; i<len; i++) {
Value v = args[i].getValue(session);
if(v == ValueNull.INSTANCE) {
list[i] = new Value[0];
} else {
ValueArray array = (ValueArray) v.convertTo(Value.ARRAY);
Value[] l = array.getList();
list[i] = l;
rowCount = Math.max(rowCount, l.length);
}
}
for(int row = 0; row < rowCount; row++) {
Object[] r = new Object[len];
for(int j=0; j<len; j++) {
Value[] l = list[j];
Value v;
if(l.length <= row) {
v = ValueNull.INSTANCE;
} else {
Column c = columnList[j];
v = l[row];
v = v.convertTo(c.getType());
v = v.convertPrecision(c.getPrecision());
v = v.convertScale(true, c.getScale());
}
r[j] = v.getObject();
}
rs.addRow(r);
}
}
ValueResultSet vr = ValueResultSet.get(rs);
return vr;
}
public void setColumns(ObjectArray columns) {
this.columnList = new Column[columns.size()];
columns.toArray(columnList);
}
} }
...@@ -11,6 +11,7 @@ import org.h2.message.Message; ...@@ -11,6 +11,7 @@ import org.h2.message.Message;
import org.h2.table.ColumnResolver; import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter; import org.h2.table.TableFilter;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueNull;
/** /**
* @author Thomas * @author Thomas
...@@ -33,7 +34,12 @@ public class Parameter extends Expression implements ParameterInterface { ...@@ -33,7 +34,12 @@ public class Parameter extends Expression implements ParameterInterface {
} }
public Value getParamValue() throws SQLException { public Value getParamValue() throws SQLException {
return value == null ? null : value; if(value == null) {
// to allow parameters in function tables
return ValueNull.INSTANCE;
} else {
return value;
}
} }
public Value getValue(Session session) throws SQLException { public Value getValue(Session session) throws SQLException {
......
...@@ -44,6 +44,10 @@ public abstract class Index extends SchemaObject { ...@@ -44,6 +44,10 @@ public abstract class Index extends SchemaObject {
} }
} }
} }
public String getDropSQL() {
return null;
}
public SQLException getDuplicateKeyException() { public SQLException getDuplicateKeyException() {
StringBuffer buff = new StringBuffer(); StringBuffer buff = new StringBuffer();
......
...@@ -39,6 +39,10 @@ public class LinkedIndex extends Index { ...@@ -39,6 +39,10 @@ public class LinkedIndex extends Index {
public void close(Session session) throws SQLException { public void close(Session session) throws SQLException {
} }
private boolean isNull(Value v) {
return v == null || v == ValueNull.INSTANCE;
}
public void add(Session session, Row row) throws SQLException { public void add(Session session, Row row) throws SQLException {
StringBuffer buff = new StringBuffer("INSERT INTO "); StringBuffer buff = new StringBuffer("INSERT INTO ");
...@@ -50,10 +54,10 @@ public class LinkedIndex extends Index { ...@@ -50,10 +54,10 @@ public class LinkedIndex extends Index {
buff.append(','); buff.append(',');
} }
j++; j++;
if(v != null && v != ValueNull.INSTANCE) { if(isNull(v)) {
buff.append('?');
} else {
buff.append("NULL"); buff.append("NULL");
} else {
buff.append('?');
} }
} }
buff.append(')'); buff.append(')');
...@@ -83,20 +87,25 @@ public class LinkedIndex extends Index { ...@@ -83,20 +87,25 @@ public class LinkedIndex extends Index {
buff.append("AND "); buff.append("AND ");
} }
buff.append(table.getColumn(i).getSQL()); buff.append(table.getColumn(i).getSQL());
buff.append("=? "); Value v = row.getValue(i);
if(isNull(v)) {
buff.append(" IS NULL ");
} else {
buff.append("=? ");
}
} }
String sql = buff.toString(); String sql = buff.toString();
try { try {
PreparedStatement prep = link.getPreparedStatement(sql); PreparedStatement prep = link.getPreparedStatement(sql);
for(int i=0, j=0; i<row.getColumnCount(); i++) { for(int i=0, j=0; i<row.getColumnCount(); i++) {
Value v = row.getValue(i); Value v = row.getValue(i);
if(v != null) { if(!isNull(v)) {
v.set(prep, j+1); v.set(prep, j+1);
j++; j++;
} }
} }
prep.executeUpdate(); int count = prep.executeUpdate();
rowCount--; rowCount -= count;
} catch(SQLException e) { } catch(SQLException e) {
throw Message.getSQLException(Message.ERROR_ACCESSING_LINKED_TABLE_1, new String[]{sql}, e); throw Message.getSQLException(Message.ERROR_ACCESSING_LINKED_TABLE_1, new String[]{sql}, e);
} }
...@@ -185,7 +194,7 @@ public class LinkedIndex extends Index { ...@@ -185,7 +194,7 @@ public class LinkedIndex extends Index {
} }
public Value findFirstOrLast(Session session, boolean first) throws SQLException { public Value findFirstOrLast(Session session, boolean first) throws SQLException {
// TODO optimization: could get the first or last value (in any cases; maybe not optimized) // TODO optimization: could get the first or last value (in any case; maybe not optimized)
throw Message.getUnsupportedException(); throw Message.getUnsupportedException();
} }
......
/*
* Copyright 2004-2006 H2 Group. Licensed under the H2 License, Version 1.0 (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.jdbc;
import java.sql.Array;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Map;
import org.h2.engine.SessionInterface;
import org.h2.message.Message;
import org.h2.message.TraceObject;
import org.h2.tools.SimpleResultSet;
import org.h2.value.Value;
/**
* Represents an ARRAY value.
*/
public class JdbcArray extends TraceObject implements Array {
private Value value;
private JdbcConnection conn;
/**
* INTERNAL
*/
public JdbcArray(SessionInterface session, JdbcConnection conn, Value value, int id) {
setTrace(session.getTrace(), TraceObject.ARRAY, id);
this.conn = conn;
this.value = value;
}
/**
* Returns the value as a Java array.
* This method always returns an Object[].
*
* @return the Object array
*/
public Object getArray() throws SQLException {
try {
debugCodeCall("getArray");
checkClosed();
return get();
} catch(Throwable e) {
throw logAndConvert(e);
}
}
/**
* Returns the value as a Java array.
* This method always returns an Object[].
*
* @param map is ignored. Only empty or null maps are supported
* @return the Object array
*/
public Object getArray(Map map) throws SQLException {
try {
debugCode("getArray("+quoteMap(map)+");");
checkMap(map);
checkClosed();
return get();
} catch(Throwable e) {
throw logAndConvert(e);
}
}
/**
* Returns the value as a Java array.
* A subset of the array is returned, starting from the index (1 meaning the first element)
* and up to the given object count.
* This method always returns an Object[].
*
* @param index the start index of the subset (starting with 1)
* @param count the maximum number of values
* @return the Object array
*/
public Object getArray(long index, int count) throws SQLException {
try {
debugCode("getArray(" + index + ", " + count + ");");
checkClosed();
return get(index, count);
} catch(Throwable e) {
throw logAndConvert(e);
}
}
/**
* Returns the value as a Java array.
* A subset of the array is returned, starting from the index (1 meaning the first element)
* and up to the given object count.
* This method always returns an Object[].
*
* @param index the start index of the subset (starting with 1)
* @param count the maximum number of values
* @param map is ignored. Only empty or null maps are supported
* @return the Object array
*/
public Object getArray(long index, int count, Map map) throws SQLException {
try {
debugCode("getArray(" + index + ", " + count + ", " + quoteMap(map)+");");
checkClosed();
checkMap(map);
return get(index, count);
} catch(Throwable e) {
throw logAndConvert(e);
}
}
/**
* Returns the base type of the array.
* This database does support mixed type arrays and therefore there is no base type.
*
* @return Types.NULL
*/
public int getBaseType() throws SQLException {
try {
debugCodeCall("getBaseType");
checkClosed();
return Types.NULL;
} catch(Throwable e) {
throw logAndConvert(e);
}
}
/**
* Returns the base type name of the array.
* This database does support mixed type arrays and therefore there is no base type.
*
* @return "NULL"
*/
public String getBaseTypeName() throws SQLException {
try {
debugCodeCall("getBaseTypeName");
checkClosed();
return "NULL";
} catch(Throwable e) {
throw logAndConvert(e);
}
}
/**
* Returns the value as a result set.
* The first column contains the index (starting with 1) and the second column the value.
*
* @return the result set
*/
public ResultSet getResultSet() throws SQLException {
try {
debugCodeCall("getResultSet");
checkClosed();
return getResultSet(get(), 0);
} catch(Throwable e) {
throw logAndConvert(e);
}
}
/**
* Returns the value as a result set.
* The first column contains the index (starting with 1) and the second column the value.
*
* @param map is ignored. Only empty or null maps are supported
* @return the result set
*/
public ResultSet getResultSet(Map map) throws SQLException {
try {
debugCode("getResultSet("+quoteMap(map)+");");
checkClosed();
checkMap(map);
return getResultSet(get(), 0);
} catch(Throwable e) {
throw logAndConvert(e);
}
}
/**
* Returns the value as a result set.
* The first column contains the index (starting with 1) and the second column the value.
* A subset of the array is returned, starting from the index (1 meaning the first element)
* and up to the given object count.
*
* @param index the start index of the subset (starting with 1)
* @param count the maximum number of values
* @return the result set
*/
public ResultSet getResultSet(long index, int count) throws SQLException {
try {
debugCode("getResultSet("+index+", " + count+");");
checkClosed();
return getResultSet(get(index, count), index);
} catch(Throwable e) {
throw logAndConvert(e);
}
}
/**
* Returns the value as a result set.
* The first column contains the index (starting with 1) and the second column the value.
* A subset of the array is returned, starting from the index (1 meaning the first element)
* and up to the given object count.
*
* @param index the start index of the subset (starting with 1)
* @param count the maximum number of values
* @param map is ignored. Only empty or null maps are supported
* @return the result set
*/
public ResultSet getResultSet(long index, int count, Map map) throws SQLException {
try {
debugCode("getResultSet("+index+", " + count+", " + quoteMap(map)+");");
checkClosed();
checkMap(map);
return getResultSet(get(index, count), index);
} catch(Throwable e) {
throw logAndConvert(e);
}
}
/**
* Release all resources of this object.
*/
public void free() throws SQLException {
debugCodeCall("free");
value = null;
}
private ResultSet getResultSet(Object[] array, long offset) throws SQLException {
SimpleResultSet rs = new SimpleResultSet();
rs.addColumn("INDEX", Types.BIGINT, 0, 0);
// TODO array result set: there are multiple data types possible
rs.addColumn("VALUE", Types.NULL, 0, 0);
for(int i=0; i<array.length; i++) {
Object[] row = new Object[2];
row[0] = new Long(offset + i + 1);
row[1] = array[i];
rs.addRow(row);
}
return rs;
}
private void checkClosed() throws SQLException {
conn.checkClosed();
if (value == null) {
throw Message.getSQLException(Message.OBJECT_CLOSED);
}
}
private Object[] get() throws SQLException {
return (Object[]) value.convertTo(Value.ARRAY).getObject();
}
private Object[] get(long index, int count) throws SQLException {
Object[] array = get();
if(count < 0 || count > array.length) {
throw Message.getInvalidValueException(""+count, "count (1.."+array.length+")");
}
if(index < 1 || index > array.length) {
throw Message.getInvalidValueException(""+index, "index (1.."+array.length+")");
}
Object[] subset = new Object[count];
System.arraycopy(array, (int)(index - 1), subset, 0, count);
return subset;
}
private void checkMap(Map map) throws SQLException {
if(map != null && map.size()>0) {
throw Message.getUnsupportedException();
}
}
}
...@@ -19,7 +19,6 @@ import java.sql.SQLWarning; ...@@ -19,7 +19,6 @@ import java.sql.SQLWarning;
import java.sql.Savepoint; import java.sql.Savepoint;
//#endif //#endif
import java.sql.Statement; import java.sql.Statement;
import java.util.Iterator;
import java.util.Map; import java.util.Map;
import java.util.Properties; import java.util.Properties;
...@@ -34,6 +33,7 @@ import org.h2.message.Message; ...@@ -34,6 +33,7 @@ import org.h2.message.Message;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.message.TraceObject; import org.h2.message.TraceObject;
import org.h2.result.ResultInterface; import org.h2.result.ResultInterface;
import org.h2.util.ClassUtils;
import org.h2.util.TempFileDeleter; import org.h2.util.TempFileDeleter;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueInt; import org.h2.value.ValueInt;
...@@ -655,39 +655,12 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -655,39 +655,12 @@ public class JdbcConnection extends TraceObject implements Connection {
public void setTypeMap(Map map) throws SQLException { public void setTypeMap(Map map) throws SQLException {
try { try {
debugCode("setTypeMap("+quoteMap(map)+");"); debugCode("setTypeMap("+quoteMap(map)+");");
if(map != null && map.size()>0) { checkMap(map);
throw Message.getUnsupportedException();
}
} catch(Throwable e) { } catch(Throwable e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
} }
private String quoteMap(Map map) {
if(map == null) {
return "null";
}
if(map.size() == 0) {
return "new Map()";
}
StringBuffer buff = new StringBuffer("new Map() /* ");
try {
// Map<String, Class>
for(Iterator it = map.entrySet().iterator(); it.hasNext(); ) {
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
buff.append(key);
buff.append(':');
Class clazz = (Class) entry.getValue();
buff.append(clazz.getName());
}
} catch(Exception e) {
buff.append(e.toString()+": "+map.toString());
}
buff.append("*/");
return buff.toString();
}
/** /**
* Creates a new callable statement. * Creates a new callable statement.
* *
...@@ -946,7 +919,7 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -946,7 +919,7 @@ public class JdbcConnection extends TraceObject implements Connection {
if (ci.isRemote()) { if (ci.isRemote()) {
session = new SessionRemote().createSession(ci); session = new SessionRemote().createSession(ci);
} else { } else {
SessionInterface si = (SessionInterface) Class.forName("org.h2.engine.Session").newInstance(); SessionInterface si = (SessionInterface) ClassUtils.loadClass("org.h2.engine.Session").newInstance();
session = si.createSession(ci); session = si.createSession(ci);
} }
trace = session.getTrace(); trace = session.getTrace();
...@@ -1456,4 +1429,10 @@ public class JdbcConnection extends TraceObject implements Connection { ...@@ -1456,4 +1429,10 @@ public class JdbcConnection extends TraceObject implements Connection {
return v; return v;
} }
private void checkMap(Map map) throws SQLException {
if(map != null && map.size()>0) {
throw Message.getUnsupportedException();
}
}
} }
...@@ -1016,24 +1016,38 @@ public class JdbcResultSet extends TraceObject implements ResultSet { ...@@ -1016,24 +1016,38 @@ public class JdbcResultSet extends TraceObject implements ResultSet {
} }
/** /**
* [Not supported] Returns the value of the specified column as a Array. * Returns the value of the specified column as an Array.
*
* @param columnIndex (1,2,...)
* @return the value
* @throws SQLException if the column is not found or if the result set is closed
*/ */
public Array getArray(int columnIndex) throws SQLException { public Array getArray(int columnIndex) throws SQLException {
try { try {
int id = getNextId(TraceObject.ARRAY);
debugCodeAssign("Clob", TraceObject.ARRAY, id);
debugCodeCall("getArray", columnIndex); debugCodeCall("getArray", columnIndex);
throw Message.getUnsupportedException(); Value v = get(columnIndex);
return v == ValueNull.INSTANCE ? null : new JdbcArray(session, conn, v, id);
} catch(Throwable e) { } catch(Throwable e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
} }
/** /**
* [Not supported] Returns the value of the specified column as a Array. * Returns the value of the specified column as an Array.
*
* @param columnName the name of the column label
* @return the value
* @throws SQLException if the column is not found or if the result set is closed
*/ */
public Array getArray(String columnName) throws SQLException { public Array getArray(String columnName) throws SQLException {
try { try {
int id = getNextId(TraceObject.ARRAY);
debugCodeAssign("Clob", TraceObject.ARRAY, id);
debugCodeCall("getArray", columnName); debugCodeCall("getArray", columnName);
throw Message.getUnsupportedException(); Value v = get(columnName);
return v == ValueNull.INSTANCE ? null : new JdbcArray(session, conn, v, id);
} catch(Throwable e) { } catch(Throwable e) {
throw logAndConvert(e); throw logAndConvert(e);
} }
......
...@@ -89,7 +89,7 @@ public class JdbcSQLException extends SQLException { ...@@ -89,7 +89,7 @@ public class JdbcSQLException extends SQLException {
if(s!=null) { if(s!=null) {
super.printStackTrace(s); super.printStackTrace(s);
//#ifdef JDK13 //#ifdef JDK13
/* /*
if (cause != null) { if (cause != null) {
cause.printStackTrace(s); cause.printStackTrace(s);
} }
......
...@@ -9,6 +9,8 @@ import java.io.IOException; ...@@ -9,6 +9,8 @@ import java.io.IOException;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.math.BigDecimal; import java.math.BigDecimal;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Iterator;
import java.util.Map;
import org.h2.engine.Constants; import org.h2.engine.Constants;
import org.h2.util.StringUtils; import org.h2.util.StringUtils;
...@@ -18,14 +20,14 @@ public class TraceObject { ...@@ -18,14 +20,14 @@ public class TraceObject {
PREPARED_STATEMENT = 3, RESULT_SET = 4, RESULT_SET_META_DATA = 5, PREPARED_STATEMENT = 3, RESULT_SET = 4, RESULT_SET_META_DATA = 5,
SAVEPOINT = 6, SQL_EXCEPTION = 7, STATEMENT = 8, BLOB = 9, CLOB = 10, SAVEPOINT = 6, SQL_EXCEPTION = 7, STATEMENT = 8, BLOB = 9, CLOB = 10,
PARAMETER_META_DATA = 11; PARAMETER_META_DATA = 11;
public static final int DATA_SOURCE = 12, XA_DATA_SOURCE = 13, XID = 14; public static final int DATA_SOURCE = 12, XA_DATA_SOURCE = 13, XID = 14, ARRAY = 15;
private static int LAST = XID + 1; private static int LAST = ARRAY + 1;
private Trace trace; private Trace trace;
private static final int[] ID = new int[LAST]; private static final int[] ID = new int[LAST];
private static final String[] PREFIX = { private static final String[] PREFIX = {
"call", "conn", "dbMeta", "prep", "rs", "rsMeta", "sp", "ex", "stat", "blob", "clob", "pMeta", "call", "conn", "dbMeta", "prep", "rs", "rsMeta", "sp", "ex", "stat", "blob", "clob", "pMeta",
"ds", "xads", "xid" "ds", "xads", "xid", "ar"
}; };
private int type, id; private int type, id;
...@@ -151,6 +153,31 @@ public class TraceObject { ...@@ -151,6 +153,31 @@ public class TraceObject {
return StringUtils.quoteJavaIntArray(s); return StringUtils.quoteJavaIntArray(s);
} }
protected String quoteMap(Map map) {
if(map == null) {
return "null";
}
if(map.size() == 0) {
return "new Map()";
}
StringBuffer buff = new StringBuffer("new Map() /* ");
try {
// Map<String, Class>
for(Iterator it = map.entrySet().iterator(); it.hasNext(); ) {
Map.Entry entry = (Map.Entry) it.next();
String key = (String) entry.getKey();
buff.append(key);
buff.append(':');
Class clazz = (Class) entry.getValue();
buff.append(clazz.getName());
}
} catch(Exception e) {
buff.append(e.toString()+": "+map.toString());
}
buff.append("*/");
return buff.toString();
}
protected SQLException logAndConvert(Throwable e) { protected SQLException logAndConvert(Throwable e) {
if(Constants.LOG_ALL_ERRORS) { if(Constants.LOG_ALL_ERRORS) {
synchronized(this.getClass()) { synchronized(this.getClass()) {
......
...@@ -45,6 +45,7 @@ public class TraceSystem { ...@@ -45,6 +45,7 @@ public class TraceSystem {
private static final int CHECK_SIZE_EACH_WRITES = 128; private static final int CHECK_SIZE_EACH_WRITES = 128;
private int checkSize; private int checkSize;
private boolean closed; private boolean closed;
private boolean manualEnabling = true;
public static void traceThrowable(Throwable e) { public static void traceThrowable(Throwable e) {
PrintWriter writer = DriverManager.getLogWriter(); PrintWriter writer = DriverManager.getLogWriter();
...@@ -52,6 +53,10 @@ public class TraceSystem { ...@@ -52,6 +53,10 @@ public class TraceSystem {
e.printStackTrace(writer); e.printStackTrace(writer);
} }
} }
public void setManualEnabling(boolean value) {
this.manualEnabling = value;
}
public TraceSystem(String fileName) { public TraceSystem(String fileName) {
this.fileName = fileName; this.fileName = fileName;
...@@ -121,25 +126,32 @@ public class TraceSystem { ...@@ -121,25 +126,32 @@ public class TraceSystem {
} }
if (fileName != null) { if (fileName != null) {
if (l > levelFile) { if (l > levelFile) {
long time = System.currentTimeMillis(); enableIfRequired();
if (time > lastCheck + CHECK_FILE_TIME) {
String checkFile = fileName + Constants.SUFFIX_TRACE_START_FILE;
lastCheck = time;
if (FileUtils.exists(checkFile)) {
levelFile = DEBUG;
try {
FileUtils.delete(checkFile);
} catch (Exception e) {
// the file may be read only
}
}
}
} }
if (l <= levelFile) { if (l <= levelFile) {
writeFile(format(module, s), t); writeFile(format(module, s), t);
} }
} }
} }
private void enableIfRequired() {
if(!manualEnabling) {
return;
}
long time = System.currentTimeMillis();
if (time > lastCheck + CHECK_FILE_TIME) {
String checkFile = fileName + Constants.SUFFIX_TRACE_START_FILE;
lastCheck = time;
if (FileUtils.exists(checkFile)) {
levelFile = DEBUG;
try {
FileUtils.delete(checkFile);
} catch (Exception e) {
// the file may be read only
}
}
}
}
private synchronized void writeFile(String s, Throwable t) { private synchronized void writeFile(String s, Throwable t) {
try { try {
......
...@@ -44,6 +44,17 @@ Deletes rows form a table. ...@@ -44,6 +44,17 @@ Deletes rows form a table.
"," ","
DELETE FROM TEST WHERE ID=2 DELETE FROM TEST WHERE ID=2
" "
"Commands (DML)","BACKUP","
BACKUP TO fileNameString
","
Backs up the database files to a .zip file.
Objects are not locked.
Admin rights are required to execute this command.
","
BACKUP TO 'backup.zip'
"
"Commands (DML)","CALL"," "Commands (DML)","CALL","
CALL expression CALL expression
"," ","
...@@ -353,6 +364,7 @@ name(driverString, urlString, ...@@ -353,6 +364,7 @@ name(driverString, urlString,
userString, passwordString, originalTableString) userString, passwordString, originalTableString)
"," ","
Creates a table link to an external table. Creates a table link to an external table.
The driver name may be empty if the driver is already loaded.
The current user owner must have admin rights. The current user owner must have admin rights.
"," ","
CREATE LINKED TABLE LINK('org.h2.Driver', 'jdbc:h2:test', 'sa', '', 'TEST') CREATE LINKED TABLE LINK('org.h2.Driver', 'jdbc:h2:test', 'sa', '', 'TEST')
...@@ -1159,7 +1171,7 @@ A value. Parameters can be indexed, for example ?1 meaning the first parameter. ...@@ -1159,7 +1171,7 @@ A value. Parameters can be indexed, for example ?1 meaning the first parameter.
" "
"Other Grammar","Value"," "Other Grammar","Value","
string | hexNumber | int | long | decimal | double | string | hexNumber | int | long | decimal | double |
date | time | timestamp | boolean | bytes | null date | time | timestamp | boolean | bytes | array | null
"," ","
A value of any data type, or null A value of any data type, or null
"," ","
...@@ -1202,7 +1214,7 @@ ID AS VALUE ...@@ -1202,7 +1214,7 @@ ID AS VALUE
intType | booleanType | tinyintType | smallintType | bigintType | identityType | intType | booleanType | tinyintType | smallintType | bigintType | identityType |
decimalType | doubleType | realType | dateType | timeType | timestampType | decimalType | doubleType | realType | dateType | timeType | timestampType |
binaryType | otherType | varcharType | varcharIgnorecaseType | binaryType | otherType | varcharType | varcharIgnorecaseType |
blobType | clobType | uuidType blobType | clobType | uuidType | arrayType
"," ","
A data type definition. A data type definition.
"," ","
...@@ -1303,6 +1315,7 @@ A boolean value. ...@@ -1303,6 +1315,7 @@ A boolean value.
"," ","
TRUE TRUE
" "
"Other Grammar","Bytes"," "Other Grammar","Bytes","
X'hex' X'hex'
"," ","
...@@ -1310,6 +1323,15 @@ A binary value. The hex value is not case sensitive. ...@@ -1310,6 +1323,15 @@ A binary value. The hex value is not case sensitive.
"," ","
X'01FF' X'01FF'
" "
"Other Grammar","Array","
( expression [,..] )
","
An array of values.
","
(1, 2)
"
"Other Grammar","Null"," "Other Grammar","Null","
NULL NULL
"," ","
...@@ -1507,6 +1529,15 @@ Use PreparedStatement.setBytes or setString to store values. ...@@ -1507,6 +1529,15 @@ Use PreparedStatement.setBytes or setString to store values.
UUID UUID
" "
"Data Types","ARRAY Type","
ARRAY
","
An array of values.
Use a value list (1, 2) or PreparedStatement.setObject(.., new Object[]{..}) to store values.
","
ARRAY
"
"Functions (Aggregate)","AVG"," "Functions (Aggregate)","AVG","
AVG([DISTINCT] {int | long | decimal | double}): value AVG([DISTINCT] {int | long | decimal | double}): value
"," ","
...@@ -2077,7 +2108,7 @@ REPLACE(NAME, ' ') ...@@ -2077,7 +2108,7 @@ REPLACE(NAME, ' ')
SOUNDEX(string): string SOUNDEX(string): string
"," ","
Returns a four character code representing the sound of a string. Returns a four character code representing the sound of a string.
See also http://www.nara.gov/genealogy/coding.html. See also http://www.archives.gov/genealogy/soundex.html.
"," ","
SOUNDEX(NAME) SOUNDEX(NAME)
" "
...@@ -2323,6 +2354,22 @@ Returns the year from a timestamp. ...@@ -2323,6 +2354,22 @@ Returns the year from a timestamp.
YEAR(CREATED) YEAR(CREATED)
" "
"Functions (System)","ARRAY_GET","
ARRAY_GET(arrayExpression, indexExpression): value
","
Returns one element of an array.
","
CALL ARRAY_GET(('Hello', 'World'), 2)
"
"Functions (System)","ARRAY_LENGTH","
ARRAY_GET(arrayExpression): int
","
Returns the length of an array.
","
CALL ARRAY_LENGTH(('Hello', 'World'))
"
"Functions (System)","AUTOCOMMIT"," "Functions (System)","AUTOCOMMIT","
AUTOCOMMIT(): boolean AUTOCOMMIT(): boolean
"," ","
...@@ -2445,6 +2492,20 @@ Returns the lock timeout of the current session (in milliseconds). ...@@ -2445,6 +2492,20 @@ Returns the lock timeout of the current session (in milliseconds).
LOCK_TIMEOUT() LOCK_TIMEOUT()
" "
"Functions (System)","LINK_SCHEMA","
LINK_SCHEMA(targetSchemaString, driverString, urlString,
userString, passwordString, sourceSchemaString): resultSet
","
Creates table links for all tables in a schema.
If tables with the same name already exist, they are dropped first.
The target schema is created automatically if it does not yet exist.
The driver name may be empty if the driver is already loaded.
The list of tables linked is returned.
Admin rights are required to execute this command.
","
CALL LINK_SCHEMA('TEST2', '', 'jdbc:h2:test2', 'sa', 'sa', 'PUBLIC');
"
"Functions (System)","MEMORY_FREE"," "Functions (System)","MEMORY_FREE","
MEMORY_FREE(): int MEMORY_FREE(): int
"," ","
...@@ -2519,6 +2580,14 @@ The database engine may re-use a session id after the connection is closed. ...@@ -2519,6 +2580,14 @@ The database engine may re-use a session id after the connection is closed.
CALL SESSION_ID() CALL SESSION_ID()
" "
"Functions (System)","TABLE","
TABLE( { name dataType = expression } [,..]): result set
","
Returns the result set.
","
SELECT * FROM TABLE(ID INT=(1, 2), NAME VARCHAR=('Hello', 'World'))
"
"Functions (System)","USER"," "Functions (System)","USER","
{USER | CURRENT_USER}(): string {USER | CURRENT_USER}(): string
"," ","
......
...@@ -32,6 +32,7 @@ class ResultDiskBuffer { ...@@ -32,6 +32,7 @@ class ResultDiskBuffer {
rowBuff = DataPage.create(db, Constants.DEFAULT_DATA_PAGE_SIZE); rowBuff = DataPage.create(db, Constants.DEFAULT_DATA_PAGE_SIZE);
String fileName = session.getDatabase().createTempFile(); String fileName = session.getDatabase().createTempFile();
file = session.getDatabase().openFile(fileName, false); file = session.getDatabase().openFile(fileName, false);
file.setCheckedWriting(false);
file.autoDelete(); file.autoDelete();
file.seek(FileStore.HEADER_LENGTH); file.seek(FileStore.HEADER_LENGTH);
if (sort != null) { if (sort != null) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论