提交 2a83a1ba authored 作者: Thomas Mueller's avatar Thomas Mueller

the lucene index was always recreated and never closed

上级 4ba52d30
/*
* Copyright 2004-2008 H2 Group. Multiple-Licensed under the H2 License,
* Version 1.0, and under the Eclipse Public License, Version 1.0
* (http://h2database.com/html/license.html).
* Initial Developer: H2 Group
*/
package org.h2.api;
import java.sql.SQLException;
/**
* A trigger that implements this interface will be notified when the database
* is closed.
*/
public interface CloseListener {
/**
* This method is called when the database is closed.
* If the method throws an exception, it will be logged, but
* closing the database will continue.
*
* @throws SQLException
*/
void close() throws SQLException;
}
...@@ -63,5 +63,5 @@ public interface Trigger { ...@@ -63,5 +63,5 @@ public interface Trigger {
* if the operation must be undone * if the operation must be undone
*/ */
void fire(Connection conn, Object[] oldRow, Object[] newRow) throws SQLException; void fire(Connection conn, Object[] oldRow, Object[] newRow) throws SQLException;
} }
...@@ -34,6 +34,7 @@ import org.h2.result.SearchRow; ...@@ -34,6 +34,7 @@ import org.h2.result.SearchRow;
import org.h2.schema.Schema; import org.h2.schema.Schema;
import org.h2.schema.SchemaObject; import org.h2.schema.SchemaObject;
import org.h2.schema.Sequence; import org.h2.schema.Sequence;
import org.h2.schema.TriggerObject;
import org.h2.store.DataHandler; import org.h2.store.DataHandler;
import org.h2.store.DataPage; import org.h2.store.DataPage;
import org.h2.store.DiskFile; import org.h2.store.DiskFile;
...@@ -1043,6 +1044,11 @@ public class Database implements DataHandler { ...@@ -1043,6 +1044,11 @@ public class Database implements DataHandler {
Sequence sequence = (Sequence) sequences.get(i); Sequence sequence = (Sequence) sequences.get(i);
sequence.close(); sequence.close();
} }
ObjectArray triggers = getAllSchemaObjects(DbObject.TRIGGER);
for (int i = 0; i < triggers.size(); i++) {
TriggerObject trigger = (TriggerObject) triggers.get(i);
trigger.close();
}
meta.close(systemSession); meta.close(systemSession);
systemSession.commit(true); systemSession.commit(true);
indexSummaryValid = true; indexSummaryValid = true;
......
...@@ -18,21 +18,22 @@ import org.h2.message.Message; ...@@ -18,21 +18,22 @@ import org.h2.message.Message;
import org.h2.message.Trace; import org.h2.message.Trace;
import org.h2.table.Table; import org.h2.table.Table;
import org.h2.util.ClassUtils; import org.h2.util.ClassUtils;
import org.h2.util.ObjectArray;
import org.h2.value.DataType; import org.h2.value.DataType;
import org.h2.value.Value; import org.h2.value.Value;
import org.h2.value.ValueNull; import org.h2.value.ValueNull;
/** /**
* Represents a user-defined function, or alias. * Represents a user-defined function, or alias.
*
* @author Thomas Mueller
* @author Gary Tong
*/ */
public class FunctionAlias extends DbObjectBase { public class FunctionAlias extends DbObjectBase {
private boolean hasConnectionParam;
private String className; private String className;
private String methodName; private String methodName;
private Method javaMethod; private JavaMethod[] javaMethods;
private int paramCount;
private int dataType;
public FunctionAlias(Database db, int id, String name, String javaClassMethod, boolean force) throws SQLException { public FunctionAlias(Database db, int id, String name, String javaClassMethod, boolean force) throws SQLException {
initDbObjectBase(db, id, name, Trace.FUNCTION); initDbObjectBase(db, id, name, Trace.FUNCTION);
...@@ -55,38 +56,38 @@ public class FunctionAlias extends DbObjectBase { ...@@ -55,38 +56,38 @@ public class FunctionAlias extends DbObjectBase {
} }
private synchronized void load() throws SQLException { private synchronized void load() throws SQLException {
if (javaMethod != null) { if (javaMethods != null) {
return; return;
} }
Class javaClass = ClassUtils.loadUserClass(className); Class javaClass = ClassUtils.loadUserClass(className);
Method[] methods = javaClass.getMethods(); Method[] methods = javaClass.getMethods();
ObjectArray list = new ObjectArray();
for (int i = 0; i < methods.length; i++) { for (int i = 0; i < methods.length; i++) {
Method m = methods[i]; Method m = methods[i];
if (!Modifier.isStatic(m.getModifiers())) { if (!Modifier.isStatic(m.getModifiers())) {
continue; continue;
} }
if (m.getName().equals(methodName)) { if (m.getName().equals(methodName) || getMethodSignature(m).equals(methodName)) {
javaMethod = m; JavaMethod javaMethod = new JavaMethod(m);
break; for (int j = 0; j < list.size(); j++) {
} else if (getMethodSignature(m).equals(methodName)) { JavaMethod old = (JavaMethod) list.get(j);
javaMethod = m; if (old.paramCount == javaMethod.paramCount) {
break; throw Message.getSQLException(ErrorCode.METHODS_MUST_HAVE_DIFFERENT_PARAMETER_COUNTS_2,
new String[] {
old.method.toString(),
javaMethod.method.toString()
}
);
}
}
list.add(javaMethod);
} }
} }
if (javaMethod == null) { if (list.size() == 0) {
throw Message.getSQLException(ErrorCode.METHOD_NOT_FOUND_1, methodName + " (" + className + ")"); throw Message.getSQLException(ErrorCode.METHOD_NOT_FOUND_1, methodName + " (" + className + ")");
} }
Class[] paramClasses = javaMethod.getParameterTypes(); javaMethods = new JavaMethod[list.size()];
paramCount = paramClasses.length; list.toArray(javaMethods);
if (paramCount > 0) {
Class paramClass = paramClasses[0];
if (Connection.class.isAssignableFrom(paramClass)) {
hasConnectionParam = true;
paramCount--;
}
}
Class returnClass = javaMethod.getReturnType();
dataType = DataType.getTypeFromClass(returnClass);
} }
private String getMethodSignature(Method m) { private String getMethodSignature(Method m) {
...@@ -110,15 +111,6 @@ public class FunctionAlias extends DbObjectBase { ...@@ -110,15 +111,6 @@ public class FunctionAlias extends DbObjectBase {
return buff.toString(); return buff.toString();
} }
public Class[] getColumnClasses() throws SQLException {
load();
return javaMethod.getParameterTypes();
}
public int getDataType() {
return dataType;
}
public String getCreateSQLForCopy(Table table, String quotedName) { public String getCreateSQLForCopy(Table table, String quotedName) {
throw Message.getInternalError(); throw Message.getInternalError();
} }
...@@ -144,7 +136,7 @@ public class FunctionAlias extends DbObjectBase { ...@@ -144,7 +136,7 @@ public class FunctionAlias extends DbObjectBase {
database.removeMeta(session, getId()); database.removeMeta(session, getId());
className = null; className = null;
methodName = null; methodName = null;
javaMethod = null; javaMethods = null;
invalidate(); invalidate();
} }
...@@ -153,69 +145,20 @@ public class FunctionAlias extends DbObjectBase { ...@@ -153,69 +145,20 @@ public class FunctionAlias extends DbObjectBase {
} }
/** /**
* Call the user-defined function and return the value. * Find the Java method that matches the arguments.
* *
* @param session the session
* @param args the argument list * @param args the argument list
* @param columnList true if the function should only return the column list * @return the Java method
* @return the value * @throws SQLException if no matching method could be found
*/ */
public synchronized Value getValue(Session session, Expression[] args, boolean columnList) throws SQLException { public JavaMethod findJavaMethod(Expression[] args) throws SQLException {
load(); load();
Class[] paramClasses = javaMethod.getParameterTypes(); for (int i = 0; i < javaMethods.length; i++) {
Object[] params = new Object[paramClasses.length]; if (javaMethods[i].paramCount == args.length) {
int p = 0; return javaMethods[i];
if (hasConnectionParam && params.length > 0) {
params[p++] = session.createConnection(columnList);
}
for (int a = 0; a < args.length && p < params.length; a++, p++) {
Class paramClass = paramClasses[p];
int type = DataType.getTypeFromClass(paramClass);
Value v = args[a].getValue(session);
v = v.convertTo(type);
Object o = v.getObject();
if (o == null) {
if (paramClass.isPrimitive()) {
if (columnList) {
// if the column list is requested, the parameters may
// be null
// need to set to default value otherwise the function
// can't be called at all
o = DataType.getDefaultForPrimitiveType(paramClass);
} else {
// NULL for a java primitive: return NULL
return ValueNull.INSTANCE;
}
}
} else {
if (!paramClass.isAssignableFrom(o.getClass()) && !paramClass.isPrimitive()) {
o = DataType.convertTo(session, session.createConnection(false), v, paramClass);
}
}
params[p] = o;
}
boolean old = session.getAutoCommit();
try {
session.setAutoCommit(false);
try {
Object returnValue;
returnValue = javaMethod.invoke(null, params);
if (returnValue == null) {
return ValueNull.INSTANCE;
}
Value ret = DataType.convertToValue(session, returnValue, dataType);
return ret.convertTo(dataType);
} catch (Exception e) {
throw Message.convert(e);
} }
} finally {
session.setAutoCommit(old);
} }
} throw Message.getSQLException(ErrorCode.METHOD_NOT_FOUND_1, methodName + " (" + className + ")");
public int getParameterCount() throws SQLException {
load();
return paramCount;
} }
public String getJavaClassName() { public String getJavaClassName() {
...@@ -225,14 +168,124 @@ public class FunctionAlias extends DbObjectBase { ...@@ -225,14 +168,124 @@ public class FunctionAlias extends DbObjectBase {
public String getJavaMethodName() { public String getJavaMethodName() {
return this.methodName; return this.methodName;
} }
/** /**
* Check if this function requires a database connection. * Get the Java methods mapped by this function.
* *
* @return if the function requires a connection * @return the Java methods.
*/ */
public boolean hasConnectionParam() { public JavaMethod[] getJavaMethods() throws SQLException {
return this.hasConnectionParam; load();
return javaMethods;
}
/**
* There may be multiple Java methods that match a function name.
* Each method must have a different number of parameters however.
* This helper class represents one such method.
*/
public static class JavaMethod {
Method method;
boolean hasConnectionParam;
int paramCount;
int dataType;
JavaMethod(Method method) throws SQLException {
this.method = method;
Class[] paramClasses = method.getParameterTypes();
paramCount = paramClasses.length;
if (paramCount > 0) {
Class paramClass = paramClasses[0];
if (Connection.class.isAssignableFrom(paramClass)) {
hasConnectionParam = true;
paramCount--;
}
}
Class returnClass = method.getReturnType();
dataType = DataType.getTypeFromClass(returnClass);
}
/**
* Check if this function requires a database connection.
*
* @return if the function requires a connection
*/
public boolean hasConnectionParam() {
return this.hasConnectionParam;
}
/**
* Call the user-defined function and return the value.
*
* @param session the session
* @param args the argument list
* @param columnList true if the function should only return the column list
* @return the value
*/
public Value getValue(Session session, Expression[] args, boolean columnList) throws SQLException {
Class[] paramClasses = method.getParameterTypes();
Object[] params = new Object[paramClasses.length];
int p = 0;
if (hasConnectionParam && params.length > 0) {
params[p++] = session.createConnection(columnList);
}
for (int a = 0; a < args.length && p < params.length; a++, p++) {
Class paramClass = paramClasses[p];
int type = DataType.getTypeFromClass(paramClass);
Value v = args[a].getValue(session);
v = v.convertTo(type);
Object o = v.getObject();
if (o == null) {
if (paramClass.isPrimitive()) {
if (columnList) {
// if the column list is requested, the parameters may
// be null
// need to set to default value otherwise the function
// can't be called at all
o = DataType.getDefaultForPrimitiveType(paramClass);
} else {
// NULL for a java primitive: return NULL
return ValueNull.INSTANCE;
}
}
} else {
if (!paramClass.isAssignableFrom(o.getClass()) && !paramClass.isPrimitive()) {
o = DataType.convertTo(session, session.createConnection(false), v, paramClass);
}
}
params[p] = o;
}
boolean old = session.getAutoCommit();
try {
session.setAutoCommit(false);
try {
Object returnValue;
returnValue = method.invoke(null, params);
if (returnValue == null) {
return ValueNull.INSTANCE;
}
Value ret = DataType.convertToValue(session, returnValue, dataType);
return ret.convertTo(dataType);
} catch (Exception e) {
throw Message.convert(e);
}
} finally {
session.setAutoCommit(old);
}
}
public Class[] getColumnClasses() throws SQLException {
return method.getParameterTypes();
}
public int getDataType() {
return dataType;
}
public int getParameterCount() throws SQLException {
return paramCount;
}
} }
} }
...@@ -32,6 +32,7 @@ import org.apache.lucene.search.Hits; ...@@ -32,6 +32,7 @@ import org.apache.lucene.search.Hits;
import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.IndexSearcher;
import org.apache.lucene.search.Query; import org.apache.lucene.search.Query;
import org.apache.lucene.search.Searcher; import org.apache.lucene.search.Searcher;
import org.h2.api.CloseListener;
import org.h2.api.Trigger; import org.h2.api.Trigger;
import org.h2.command.Parser; import org.h2.command.Parser;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -50,7 +51,7 @@ import org.h2.util.StringUtils; ...@@ -50,7 +51,7 @@ import org.h2.util.StringUtils;
*/ */
public class FullTextLucene extends FullText public class FullTextLucene extends FullText
//## Java 1.4 begin ## //## Java 1.4 begin ##
implements Trigger implements Trigger, CloseListener
//## Java 1.4 end ## //## Java 1.4 end ##
{ {
...@@ -574,8 +575,9 @@ implements Trigger ...@@ -574,8 +575,9 @@ implements Trigger
synchronized (indexers) { synchronized (indexers) {
indexer = (IndexModifier) indexers.get(path); indexer = (IndexModifier) indexers.get(path);
if (indexer == null) { if (indexer == null) {
// TODO: create flag = true means re-create Analyzer analyzer = new StandardAnalyzer();
indexer = new IndexModifier(path, new StandardAnalyzer(), true); boolean create = !IndexReader.indexExists(path);
indexer = new IndexModifier(path, analyzer, create);
indexers.put(path, indexer); indexers.put(path, indexer);
} }
} }
...@@ -613,6 +615,18 @@ implements Trigger ...@@ -613,6 +615,18 @@ implements Trigger
index[i] = found; index[i] = found;
} }
} }
public void close() throws SQLException {
try {
if (indexer != null) {
indexer.flush();
indexer.close();
indexer = null;
}
} catch (Exception e) {
throw convertException(e);
}
}
//## Java 1.4 end ## //## Java 1.4 end ##
} }
...@@ -9,6 +9,7 @@ package org.h2.schema; ...@@ -9,6 +9,7 @@ package org.h2.schema;
import java.sql.Connection; import java.sql.Connection;
import java.sql.SQLException; import java.sql.SQLException;
import org.h2.api.CloseListener;
import org.h2.api.Trigger; import org.h2.api.Trigger;
import org.h2.command.Parser; import org.h2.command.Parser;
import org.h2.constant.ErrorCode; import org.h2.constant.ErrorCode;
...@@ -313,7 +314,7 @@ public class TriggerObject extends SchemaObjectBase { ...@@ -313,7 +314,7 @@ public class TriggerObject extends SchemaObjectBase {
} }
/** /**
* Get the trigger class name * Get the trigger class name.
* *
* @return the class name * @return the class name
*/ */
...@@ -321,4 +322,15 @@ public class TriggerObject extends SchemaObjectBase { ...@@ -321,4 +322,15 @@ public class TriggerObject extends SchemaObjectBase {
return triggerClassName; return triggerClassName;
} }
/**
* Close the trigger.
*/
public void close() throws SQLException {
if (triggerCallback != null) {
if (triggerCallback instanceof CloseListener) {
((CloseListener) triggerCallback).close();
}
}
}
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论