1 5 package org.h2.engine; 6 7 import java.lang.reflect.Method ; 8 import java.lang.reflect.Modifier ; 9 import java.sql.Connection ; 10 import java.sql.SQLException ; 11 12 import org.h2.command.Parser; 13 import org.h2.expression.Expression; 14 import org.h2.message.Message; 15 import org.h2.message.Trace; 16 import org.h2.table.Table; 17 import org.h2.value.DataType; 18 import org.h2.value.Value; 19 import org.h2.value.ValueNull; 20 21 public class FunctionAlias extends DbObject { 22 23 private String className; 24 private String methodName; 25 private Method javaMethod; 26 private int paramCount; 27 private boolean hasConnectionParam; 28 private int dataType; 29 30 public FunctionAlias(Database db, int id, String name, String javaClassMethod) throws SQLException { 31 super(db, id, name, Trace.FUNCTION); 32 int paren = javaClassMethod.indexOf('('); 33 int lastDot = javaClassMethod.lastIndexOf('.', paren < 0 ? javaClassMethod.length() : paren); 34 if(lastDot < 0) { 35 throw Message.getSQLException(Message.SYNTAX_ERROR_1, javaClassMethod); 36 } 37 className = javaClassMethod.substring(0, lastDot); 38 methodName = javaClassMethod.substring(lastDot + 1); 39 Class javaClass; 40 try { 41 javaClass = database.loadClass(className); 42 } catch (ClassNotFoundException e) { 43 throw Message.getSQLException(Message.CLASS_NOT_FOUND_1, new String []{className + " (" + methodName + ")"}, e); 44 } 45 Method [] methods = javaClass.getMethods(); 46 for(int i=0; i<methods.length; i++) { 47 Method m = methods[i]; 48 if(!Modifier.isStatic(m.getModifiers())) { 49 continue; 50 } 51 if(m.getName().equals(methodName)) { 52 javaMethod = m; 53 break; 54 } else if(getMethodSignature(m).equals(methodName)) { 55 javaMethod = m; 56 break; 57 } 58 } 59 if(javaMethod == null) { 60 throw Message.getSQLException(Message.METHOD_NOT_FOUND_1, methodName + " (" + className + ")"); 61 } 62 Class [] paramClasses = javaMethod.getParameterTypes(); 63 paramCount = paramClasses.length; 64 if(paramCount > 0) { 65 Class paramClass = paramClasses[0]; 66 if(Connection .class.isAssignableFrom(paramClass)) { 67 hasConnectionParam = true; 68 paramCount--; 69 } 70 } 71 Class returnClass = javaMethod.getReturnType(); 72 dataType = DataType.getTypeFromClass(returnClass); 73 } 74 75 private String getMethodSignature(Method m) { 76 StringBuffer buff = new StringBuffer (); 77 buff.append(m.getName()); 78 buff.append('('); 79 Class [] params = m.getParameterTypes(); 80 for(int i=0; i<params.length; i++) { 81 if(i>0) { 82 buff.append(", "); 83 } 84 Class p = params[i]; 85 if(p.isArray()) { 86 buff.append(p.getComponentType().getName()); 87 buff.append("[]"); 88 } else { 89 buff.append(p.getName()); 90 } 91 } 92 buff.append(')'); 93 return buff.toString(); 94 } 95 96 public Class [] getColumnClasses() { 97 return javaMethod.getParameterTypes(); 98 } 99 100 public int getDataType() { 101 return dataType; 102 } 103 104 public String getCreateSQLForCopy(Table table, String quotedName) { 105 throw Message.getInternalError(); 106 } 107 108 public String getCreateSQL() { 109 StringBuffer buff = new StringBuffer (); 110 buff.append("CREATE ALIAS "); 111 buff.append(getSQL()); 112 buff.append(" FOR "); 113 buff.append(Parser.quoteIdentifier(className + "." + methodName)); 114 return buff.toString(); 115 } 116 117 public int getType() { 118 return DbObject.FUNCTION_ALIAS; 119 } 120 121 public void removeChildrenAndResources(Session session) throws SQLException { 122 className = methodName = null; 123 javaMethod = null; 124 invalidate(); 125 } 126 127 public void checkRename() throws SQLException { 128 throw Message.getUnsupportedException(); 129 } 130 131 public Value getValue(Session session, Expression[] args) throws SQLException { 132 return getValue(session, args, false); 133 } 134 135 public Value getValue(Session session, Expression[] args, boolean columnList) throws SQLException { 136 synchronized(this) { 137 Class [] paramClasses = javaMethod.getParameterTypes(); 138 Object [] params = new Object [paramClasses.length]; 139 int p = 0; 140 if(hasConnectionParam && params.length > 0) { 141 params[p++] = session.createConnection(columnList); 142 } 143 for(int a=0; a<args.length && p<params.length; a++, p++) { 144 Class paramClass = paramClasses[p]; 145 int type = DataType.getTypeFromClass(paramClass); 146 Value v = args[a].getValue(session); 147 v = v.convertTo(type); 148 Object o = v.getObject(); 149 if(o == null) { 150 if(paramClass.isPrimitive()) { 151 if(columnList) { 152 o = DataType.getDefaultForPrimitiveType(paramClass); 155 } else { 156 return ValueNull.INSTANCE; 158 } 159 } 160 } else { 161 if(!paramClass.isAssignableFrom(o.getClass()) && !paramClass.isPrimitive()) { 162 o = DataType.convertTo(session, session.createConnection(false), v, paramClass); 163 } 164 } 165 params[p] = o; 166 } 167 boolean old = session.getAutoCommit(); 168 try { 169 session.setAutoCommit(false); 170 try { 171 Object returnValue; 172 returnValue = javaMethod.invoke(null, params); 173 if(returnValue == null) { 174 return ValueNull.INSTANCE; 175 } 176 Value ret = DataType.convertToValue(session, returnValue, dataType); 177 return ret.convertTo(dataType); 178 } catch (Exception e) { 179 throw Message.convert(e); 180 } 181 } finally { 182 session.setAutoCommit(old); 183 } 184 } 185 } 186 187 public int getParameterCount() { 188 return paramCount; 189 } 190 191 public String getJavaClassName() { 192 return this.className; 193 } 194 195 public String getJavaMethodName() { 196 return this.methodName; 197 } 198 199 public boolean hasConnectionParam() { 200 return this.hasConnectionParam; 201 } 202 203 } 204 | Popular Tags |