OK heres the contribution:

I wrote the code, it's mine, and I'm contributing it to H2 for distribution 
multiple-licensed under the H2 License, version 1.0, and under the Eclipse 
Public License, version 1.0 (http://h2database.com/html/license.html).

Copyright 2012 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: Alfred Reibenschuh contributed to the H2 Group

C

-- 
You received this message because you are subscribed to the Google Groups "H2 
Database" group.
To view this discussion on the web visit 
https://groups.google.com/d/msg/h2-database/-/M_Uhuvhn9x8J.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/h2-database?hl=en.

Index: src/main/org/h2/engine/Database.java
===================================================================
--- src/main/org/h2/engine/Database.java	(revision 4285)
+++ src/main/org/h2/engine/Database.java	(working copy)
@@ -23,6 +23,7 @@
 import org.h2.constant.ErrorCode;
 import org.h2.constant.SysProperties;
 import org.h2.constraint.Constraint;
+import org.h2.ext.FnRegUtil;
 import org.h2.index.Cursor;
 import org.h2.index.Index;
 import org.h2.index.IndexType;
@@ -174,6 +175,8 @@
     private final DbSettings dbSettings;
     private final int reconnectCheckDelay;
     private int logMode;
+    private boolean doFnAutoReg = false;
+    private String fnAutoRegModules = "";
 
     public Database(ConnectionInfo ci, String cipher) {
         String name = ci.getName();
@@ -209,6 +212,8 @@
         }
         this.multiVersion = ci.getProperty("MVCC", false);
         this.logMode = ci.getProperty("LOG", PageStore.LOG_MODE_SYNC);
+        this.doFnAutoReg = ci.getProperty("EXT_FN_AUTOREG", false);
+        this.fnAutoRegModules = ci.getProperty("EXT_FN_AUTOREG_MODULE", "common");
         boolean closeAtVmShutdown = dbSettings.dbCloseOnExit;
         int traceLevelFile = ci.getIntProperty(SetTypes.TRACE_LEVEL_FILE, TraceSystem.DEFAULT_TRACE_LEVEL_FILE);
         int traceLevelSystemOut = ci.getIntProperty(SetTypes.TRACE_LEVEL_SYSTEM_OUT,
@@ -655,6 +660,43 @@
         }
         getLobStorage().init();
         systemSession.commit(true);
+        
+        // load extension functions/aggregates into default schema
+        try {
+	        if(this.doFnAutoReg)
+	        {
+	            FnRegUtil.registerFromClasspath(
+	            		trace, 
+	            		this.getClass().getClassLoader(), 
+	            		systemSession, 
+	            		mainSchema, 
+	            		"");
+	            
+	            for(String fnMod : this.fnAutoRegModules.split(","))
+	            {
+	                FnRegUtil.registerFromClasspath(
+	                		trace, 
+	                		this.getClass().getClassLoader(), 
+	                		systemSession, 
+	                		mainSchema, 
+	                		fnMod.trim());
+	            }
+	        }
+	        else
+	        {
+	            FnRegUtil.registerFromClasspath(
+	            		trace, 
+	            		this.getClass().getClassLoader(), 
+	            		systemSession, 
+	            		mainSchema, 
+	            		null);
+	        }
+        }
+        catch (Exception xe)
+        {
+            trace.info("problem with function auto-register -- {0}", xe.toString());
+        }
+        
         trace.info("opened {0}", databaseName);
         if (checkpointAllowed > 0) {
             afterWriting();
Index: src/main/org/h2/ext/FnRegUtil.java
===================================================================
--- src/main/org/h2/ext/FnRegUtil.java	(revision 0)
+++ src/main/org/h2/ext/FnRegUtil.java	(revision 0)
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2012 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.ext;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.net.URL;
+import java.util.Collections;
+
+import org.h2.command.ddl.CreateAggregate;
+import org.h2.command.ddl.CreateFunctionAlias;
+import org.h2.engine.Session;
+import org.h2.message.Trace;
+import org.h2.schema.Schema;
+
+public abstract class FnRegUtil 
+{
+	public static final String META_INF_NAME = "/META-INF/org.h2.ext.FunctionRegistry";
+	public static final String SYS_PROP_AUTOREG = "h2.ext.fnAutoreg";
+	public static final String JDBC_PROP_AUTOREG = "extFnAutoreg";
+	
+	public static final boolean registerFunction(Trace trace, ClassLoader cl, Session session, Schema schema, String clazz, String method, String alias) throws ClassNotFoundException
+	{
+		CreateFunctionAlias cfn = new CreateFunctionAlias(session, schema);
+		cfn.setIfNotExists(true);
+		cfn.setJavaClassMethod(clazz+"."+method);
+		cfn.setAliasName(alias.toUpperCase());
+		cfn.setDeterministic(true);
+		try { 
+			cfn.update();
+			trace.info("registered function {0} of {1}/{2}", alias.toUpperCase(), clazz, method);
+		} catch(Exception xe) { 
+			trace.info("registration error: function {0} of {1}/{2} -- {3}", alias.toUpperCase(), clazz, method, xe.toString());
+			return false;
+		}
+		return true;
+	}
+
+	public static final boolean registerAggregate(Trace trace, ClassLoader cl, Session session, Schema schema, String clazz, String alias) throws ClassNotFoundException
+	{
+		CreateAggregate ca = new CreateAggregate(session);
+		ca.setIfNotExists(true);
+		ca.setJavaClassMethod(clazz);
+		ca.setName(alias.toUpperCase());
+		ca.setSchema(schema);
+		try { 
+			ca.update(); 
+			trace.info("registered aggregate {0} of {1}", alias.toUpperCase(), clazz);
+		} 
+		catch(Exception xe) 
+		{ 
+			trace.info("registration error: aggregate {0} of {1} -- {2}", alias.toUpperCase(), clazz, xe.toString());
+			return false;
+		}
+		return true;
+	}
+	
+	public static final boolean register(Trace trace, ClassLoader cl, Session session, Schema schema, String clazz) throws ClassNotFoundException
+	{
+		String alias = null;
+		clazz = clazz.trim();
+		
+		if(clazz.lastIndexOf(' ')>0)
+		{
+			alias = clazz.substring(clazz.lastIndexOf(' ')+1).toUpperCase();
+			clazz = clazz.substring(0, clazz.lastIndexOf(' ')).trim();
+		}
+		else
+		{
+			alias = clazz.substring(clazz.lastIndexOf('.')+1).toUpperCase();
+		}
+		
+		Class cla = cl.loadClass(clazz);
+		
+		for(Class x : cla.getInterfaces())
+		{
+			if("org.h2.api.AggregateFunction".equalsIgnoreCase(x.getCanonicalName()))
+			{
+				return registerAggregate(trace, cl, session, schema, clazz, alias);
+			}
+		}
+		
+		// not an aggreagate impl
+		for(Method m : cla.getDeclaredMethods())
+		{
+			if(m.getName().toUpperCase().startsWith("FN_") 
+					&& m.isAccessible() 
+					&& (m.getModifiers() & Modifier.STATIC)==Modifier.STATIC)
+			{
+				registerFunction(trace, cl, session, schema, clazz, m.getName(), m.getName().substring(3));
+			}
+		}
+				
+		return true;
+	}
+
+	public static final boolean registerFromClasspath(Trace trace, ClassLoader cl, Session session, Schema schema, String tag) throws ClassNotFoundException, IOException
+	{
+		boolean procEnabled = Boolean.parseBoolean(System.getProperty(SYS_PROP_AUTOREG, "false").trim());
+
+		if(procEnabled || tag!=null)
+		{
+			String metaName = META_INF_NAME;
+	
+			if(tag!=null && !"".equals(tag))
+			{
+				metaName += "."+(tag.toUpperCase());
+			}
+			
+			for(URL url : Collections.list(cl.getResources(metaName)))
+			{
+				trace.info("found function registration at {0}", url.toString());
+				BufferedReader in = new BufferedReader(new InputStreamReader(url.openStream()));
+				try
+				{
+					String line = null;
+					while((line = in.readLine()) != null)
+					{
+						line=line.trim();
+						if(!"".equals(line))
+						{
+							trace.info("registration of {0}", line);
+							register(trace, cl, session, schema, line);
+						}
+					}
+				}
+				catch(Exception xe)
+				{
+					
+				}
+				finally
+				{
+					in.close();
+				}
+			}
+		}
+		
+		return procEnabled;
+	}
+}
Index: src/docsrc/html/features.html
===================================================================
--- src/docsrc/html/features.html	(revision 4285)
+++ src/docsrc/html/features.html	(working copy)
@@ -1622,6 +1622,37 @@
 SELECT * FROM MATRIX(4) ORDER BY X, Y;
 </pre>
 
+<h3>Auto-Referencing Compiled Methods / Aggregates from prepared JARs</h3>
+<p>
+You can enable auto-registration of methods by adding special prepared JARs
+and setting the system-property "h2.ext.fnAutoreg" to "true".
+The Classpath will be scanned for files named "/META-INF/org.h2.ext.FunctionRegistry", 
+which should look like: 
+</p>
+<pre>
+my.aggregate.Method   my_AGGR
+my.aggregate.my_AGGR2
+my.function.MySQL_FN_Library
+</pre>
+<p>
+If "my.function.MySQL_FN_Library" implements any static methods prefixed with "FN_", they will be registered in the database by calling <code>CREATE ALIAS ... FOR</code>:
+</p>
+<pre>
+CREATE ALIAS UNIX_TIMESTAMP FOR "my.function.MySQL_FN_Library.FN_unix_TIMEstamp";
+</pre>
+<p>
+If "my.aggregate.my_AGGR2" implements the "org.h2.api.AggregateFunction" interface it will be registered in the database by calling <code>CREATE AGGREGATE ... FOR</code>:
+</p>
+<pre>
+CREATE AGGREGATE MY_AGGR2 FOR "my.aggregate.my_AGGR2";
+</pre>
+<p>
+If "my.aggregate.Method" implements the "org.h2.api.AggregateFunction" interface it will be registered in the database by calling <code>CREATE AGGREGATE ... FOR</code>:
+</p>
+<pre>
+CREATE AGGREGATE MY_AGGR FOR "my.aggregate.Method";
+</pre>
+
 <h2 id="triggers">Triggers</h2>
 <p>
 This database supports Java triggers that are called before or after a row is updated, inserted or deleted.
Index: src/docsrc/html/changelog.html
===================================================================
--- src/docsrc/html/changelog.html	(revision 4285)
+++ src/docsrc/html/changelog.html	(working copy)
@@ -18,7 +18,9 @@
 <h1>Change Log</h1>
 
 <h2>Next Version (unreleased)</h2>
-<ul><li>New system property "h2.serializeJavaObject" (default: true) that allows to disable
+<ul><li>New system property "h2.ext.fnAutoreg" (default: false) and jdbc-property "EXT_FN_AUTOREG" 
+	that allows to autoregister aggregates and functions from special provided jars.
+</li><li>New system property "h2.serializeJavaObject" (default: true) that allows to disable
     serializing Java objects, so that the objects compareTo and toString methods can be used.
 </li><li>Dylan has translated the H2 Console tool to Korean. Thanks a lot!
 </li><li>Executing the statement CREATE INDEX IF ALREADY EXISTS if the index already exists

Reply via email to