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

--no commit message

--no commit message
上级 e9bd9c7d
......@@ -11,6 +11,7 @@ import org.h2.message.Message;
import org.h2.table.ColumnResolver;
import org.h2.table.TableFilter;
import org.h2.value.Value;
import org.h2.value.ValueNull;
/**
* @author Thomas
......@@ -33,7 +34,12 @@ public class Parameter extends Expression implements ParameterInterface {
}
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 {
......
......@@ -44,6 +44,10 @@ public abstract class Index extends SchemaObject {
}
}
}
public String getDropSQL() {
return null;
}
public SQLException getDuplicateKeyException() {
StringBuffer buff = new StringBuffer();
......
......@@ -39,6 +39,10 @@ public class LinkedIndex extends Index {
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 {
StringBuffer buff = new StringBuffer("INSERT INTO ");
......@@ -50,10 +54,10 @@ public class LinkedIndex extends Index {
buff.append(',');
}
j++;
if(v != null && v != ValueNull.INSTANCE) {
buff.append('?');
} else {
if(isNull(v)) {
buff.append("NULL");
} else {
buff.append('?');
}
}
buff.append(')');
......@@ -83,20 +87,25 @@ public class LinkedIndex extends Index {
buff.append("AND ");
}
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();
try {
PreparedStatement prep = link.getPreparedStatement(sql);
for(int i=0, j=0; i<row.getColumnCount(); i++) {
Value v = row.getValue(i);
if(v != null) {
if(!isNull(v)) {
v.set(prep, j+1);
j++;
}
}
prep.executeUpdate();
rowCount--;
int count = prep.executeUpdate();
rowCount -= count;
} catch(SQLException e) {
throw Message.getSQLException(Message.ERROR_ACCESSING_LINKED_TABLE_1, new String[]{sql}, e);
}
......@@ -185,7 +194,7 @@ public class LinkedIndex extends Index {
}
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();
}
......
/*
* 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;
import java.sql.Savepoint;
//#endif
import java.sql.Statement;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
......@@ -34,6 +33,7 @@ import org.h2.message.Message;
import org.h2.message.Trace;
import org.h2.message.TraceObject;
import org.h2.result.ResultInterface;
import org.h2.util.ClassUtils;
import org.h2.util.TempFileDeleter;
import org.h2.value.Value;
import org.h2.value.ValueInt;
......@@ -655,39 +655,12 @@ public class JdbcConnection extends TraceObject implements Connection {
public void setTypeMap(Map map) throws SQLException {
try {
debugCode("setTypeMap("+quoteMap(map)+");");
if(map != null && map.size()>0) {
throw Message.getUnsupportedException();
}
checkMap(map);
} catch(Throwable 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.
*
......@@ -946,7 +919,7 @@ public class JdbcConnection extends TraceObject implements Connection {
if (ci.isRemote()) {
session = new SessionRemote().createSession(ci);
} 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);
}
trace = session.getTrace();
......@@ -1456,4 +1429,10 @@ public class JdbcConnection extends TraceObject implements Connection {
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 {
}
/**
* [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 {
try {
int id = getNextId(TraceObject.ARRAY);
debugCodeAssign("Clob", TraceObject.ARRAY, id);
debugCodeCall("getArray", columnIndex);
throw Message.getUnsupportedException();
Value v = get(columnIndex);
return v == ValueNull.INSTANCE ? null : new JdbcArray(session, conn, v, id);
} catch(Throwable 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 {
try {
int id = getNextId(TraceObject.ARRAY);
debugCodeAssign("Clob", TraceObject.ARRAY, id);
debugCodeCall("getArray", columnName);
throw Message.getUnsupportedException();
Value v = get(columnName);
return v == ValueNull.INSTANCE ? null : new JdbcArray(session, conn, v, id);
} catch(Throwable e) {
throw logAndConvert(e);
}
......
......@@ -89,7 +89,7 @@ public class JdbcSQLException extends SQLException {
if(s!=null) {
super.printStackTrace(s);
//#ifdef JDK13
/*
/*
if (cause != null) {
cause.printStackTrace(s);
}
......
......@@ -9,6 +9,8 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.Map;
import org.h2.engine.Constants;
import org.h2.util.StringUtils;
......@@ -18,14 +20,14 @@ public class TraceObject {
PREPARED_STATEMENT = 3, RESULT_SET = 4, RESULT_SET_META_DATA = 5,
SAVEPOINT = 6, SQL_EXCEPTION = 7, STATEMENT = 8, BLOB = 9, CLOB = 10,
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 static final int[] ID = new int[LAST];
private static final String[] PREFIX = {
"call", "conn", "dbMeta", "prep", "rs", "rsMeta", "sp", "ex", "stat", "blob", "clob", "pMeta",
"ds", "xads", "xid"
"ds", "xads", "xid", "ar"
};
private int type, id;
......@@ -151,6 +153,31 @@ public class TraceObject {
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) {
if(Constants.LOG_ALL_ERRORS) {
synchronized(this.getClass()) {
......
......@@ -45,6 +45,7 @@ public class TraceSystem {
private static final int CHECK_SIZE_EACH_WRITES = 128;
private int checkSize;
private boolean closed;
private boolean manualEnabling = true;
public static void traceThrowable(Throwable e) {
PrintWriter writer = DriverManager.getLogWriter();
......@@ -52,6 +53,10 @@ public class TraceSystem {
e.printStackTrace(writer);
}
}
public void setManualEnabling(boolean value) {
this.manualEnabling = value;
}
public TraceSystem(String fileName) {
this.fileName = fileName;
......@@ -121,25 +126,32 @@ public class TraceSystem {
}
if (fileName != null) {
if (l > levelFile) {
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
}
}
}
enableIfRequired();
}
if (l <= levelFile) {
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) {
try {
......
......@@ -44,6 +44,17 @@ Deletes rows form a table.
","
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","
CALL expression
","
......@@ -353,6 +364,7 @@ name(driverString, urlString,
userString, passwordString, originalTableString)
","
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.
","
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.
"
"Other Grammar","Value","
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
","
......@@ -1202,7 +1214,7 @@ ID AS VALUE
intType | booleanType | tinyintType | smallintType | bigintType | identityType |
decimalType | doubleType | realType | dateType | timeType | timestampType |
binaryType | otherType | varcharType | varcharIgnorecaseType |
blobType | clobType | uuidType
blobType | clobType | uuidType | arrayType
","
A data type definition.
","
......@@ -1303,6 +1315,7 @@ A boolean value.
","
TRUE
"
"Other Grammar","Bytes","
X'hex'
","
......@@ -1310,6 +1323,15 @@ A binary value. The hex value is not case sensitive.
","
X'01FF'
"
"Other Grammar","Array","
( expression [,..] )
","
An array of values.
","
(1, 2)
"
"Other Grammar","Null","
NULL
","
......@@ -1507,6 +1529,15 @@ Use PreparedStatement.setBytes or setString to store values.
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","
AVG([DISTINCT] {int | long | decimal | double}): value
","
......@@ -2077,7 +2108,7 @@ REPLACE(NAME, ' ')
SOUNDEX(string): 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)
"
......@@ -2323,6 +2354,22 @@ Returns the year from a timestamp.
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","
AUTOCOMMIT(): boolean
","
......@@ -2445,6 +2492,20 @@ Returns the lock timeout of the current session (in milliseconds).
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","
MEMORY_FREE(): int
","
......@@ -2519,6 +2580,14 @@ The database engine may re-use a session id after the connection is closed.
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","
{USER | CURRENT_USER}(): string
","
......
......@@ -32,6 +32,7 @@ class ResultDiskBuffer {
rowBuff = DataPage.create(db, Constants.DEFAULT_DATA_PAGE_SIZE);
String fileName = session.getDatabase().createTempFile();
file = session.getDatabase().openFile(fileName, false);
file.setCheckedWriting(false);
file.autoDelete();
file.seek(FileStore.HEADER_LENGTH);
if (sort != null) {
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论