对于Greenplum数据库,PL/Java扩展可作为一个包提供。从Pivotal网络下载软件包,然后使用Greenplum软件包管理器(gppkg)进行安装。
gppkg实用程序会在群集中的所有主机上安装Greenplum数据库扩展以及任何依赖项。在系统扩展和分段恢复的情况下,它也自动在新主机上安装扩展。
有关gppkg的信息,请参阅Greenplum数据库实用程序指南。
要安装和使用PL/Java:
1.安装Greenplum数据库PL/Java扩展。
2.可选。更改PL/Java使用的Java版本。
3.为每个打算使用PL/Java的数据库启用语言。
4.将包含Java方法的用户创建的JAR文件安装到所有Greenplum数据库主机的同一目录中。
5.将JAR文件的名称添加到Greenplum数据库服务器配置参数pljava_classpath。该参数列出了已安装的JAR文件。有关该参数的信息,请参阅“Greenplum数据库参考指南”。
Installing the Greenplum PL/Java Extension
Before you install the PL/Javaextension, make sure that your Greenplum database is running, you have sourced greenplum—path.sh, and that the $MASTER_DATA_DIRECTORYand $gphome variables are set.
1. Download thePL/Java extension package from PivotalNetwork then copy it to the master host.
2. Install thesoftware extension package by running the gppkg command. This example installs the PL/Java extension package on a Linux system:
$ gppkg -i pljava-ossv1.4.0_pv1.2_gpdb4.3orca-rhel5-x86_64.gppkg
3. Reload greenplum—path.sh.
$ source $GPHOME/greenplum_path.sh
4. RestartGreenplum Database.
$ gpstop -r
Changing Java version used by PL/Java (Optional)
PL/Java扩展包与Java JRE 6u32一起提供。安装软件包时,JRE将安装在Greenplum数据库集群的每个主机上。要在PL/Java中使用更新版本的Java,请执行以下步骤来指定Java版本的位置。有关支持的Java版本的信息,请参阅您的发行版的“Greenplum数据库发行说明”。
注意:较新的Java必须安装在所有Greenplum数据库主机的相同位置,并且必须可供Greenplum数据库管理员(gpadmin)的系统用户访问。
1.在$GPHOME/greenplum_path.sh文件中,修改JAVA_HOME和LD_LIBRARY_PATH环境变量。
•将JAVA_HOME变量设置为安装Java运行时的目录。例如,对于Oracle JRE,该目录将是/usr/java/latest。对于OpenJDK,目录是/usr/lib/jvm/jre。此示例将环境变量更改为使用/usr/java/iatest。
JAVA_HOME=/usr/java/latest
•将LD_LIBRARY_PATH设置为包含具有Java服务器运行时库的目录。 PL/Java依赖于libjvm.so,共享对象应该在你的LD_LIBRARY_PATH中。默认情况下,libjvm.so在$jAVA_HoME/iib/amd64/server中可用。本示例将该目录添加到环境变量。
LD_LIBRARY_PATH=$GPHOME/lib:$GPHOME/ext/python/lib:$JAVA_HOME/lib/amd64/server:$LD_LIBRARY_PATH
2.将已升级的greenplum-path.sh文件复制到所有的Greenplum数据库主机。此示例gpscp命令将文件复制到文件gphosts_file中指定的所有主机。
$ gpscp -fgphosts_file $GPHOME/greenplum_path.sh
=:$GPHOME/greenplum_path.sh
3.重新加载greenplum-path.sh。
$ source$GPHOME/greenplum_path.sh
4.重新启动Greenplum数据库。
$ gpstop -r
Enabling PL/Java and Installing JAR Files
以Greenplum数据库管理员gpadmin的身份执行以下步骤。
1.通过在将使用PL/Java的数据库中运行SQL脚本$ GPHoME/share/postgresqi/pijava/instaii.sqi来启用PL/Java。例如,这个例子在数据库上启用了PL/Java
$ psql -d mytestdb
-f $GPHOME/share/postgresql/pljava/install.sql
脚本install.sql注册可信和不可信的PL/Java语言。
2.将您的Java归档(JAR文件)复制到所有Greenplum数据库主机上的相同目录。本示例使用Greenplum数据库gpscp实用程序将文件myclasses.jar复制到目录
$GPHOME/lib/postgresql/java/:
$ gpscp -f gphosts_file myclasses.jar
=:/usr/local/greenplum-db/lib/postgresql/java/
文件gphosts_file包含Greenplum数据库主机的列表。
3.在主postgresql.conf文件中设置pijava_ciasspath服务器配置参数。对于这个例子,参数值是一个以冒号(:)分隔的JAR文件列表。例如:
$ gpconfig -c pljava_classpath
-v \'examples.jar:myclasses.jar\'
当您使用gppkg实用程序安装PL/Java扩展包时,会安装文件examples.jar:。
注:如果将JAR文件安装在$GPHOME/lib/postgresql/java/以外的目录中,则必须指定JAR文件的绝对路径。每个JAR文件必须位于所有Greenplum数据库主机上的相同位置。有关指定JAR文件位置的更多信息,请参阅
有关Greenplum数据库参考指南中的pljava_classpath服务器配置参数的信息。
4.重新加载postgresql.conf文件。
$ gpstop -u
5.(可选)Greenplum提供了一个exampies.sqi文件,其中包含可用于测试的示例PL/Java函数。运行这个文件中的命令来创建测试函数(它们使用了Java中的类)
示例的.jar)。
$ psql -f $GPHOME/share/postgresql/pljava/examples.sql
• Remove PL/Java Support for a Database
• Uninstall the Java JAR files and SoftwarePackage
Remove PL/Java Support for a Database
对于不需要PL/Java语言的数据库,删除对PL/Java的支持。 以gpadmin用户身份运行uninstall.sql文件。 例如,该命令禁用指定数据库中的PL/Java语言。
$ psql -dmydatabase
-f$GPHOME/share/postgresql/pljava/uninstall.sql
Uninstall the Java JAR files and Software Package
如果没有数据库将PL/Java作为注册语言,则删除Java JAR文件并使用gppkg实用程序卸载GreenplumPL/Java扩展。
1. 从所有Greenplum数据库主机的postgresql.conf文件中删除pljava_classpath服务器配置参数。 例如:
$ gpconfig -r pljava_classpath
2. 从所有Greenplum数据库主机上安装的目录中删除JAR文件。 有关JAR文件安装目录的信息,请参阅启用PL/Java和安装JAR文件。.
3. 使用带有-r选项的Greenplumgppkg实用程序来卸载PL/Java扩展。 本示例卸载Linux系统上的PL/Java扩展:
$ gppkg -rpljava-ossv1.4.0_pv1.3_gpdb4.3orca
您可以使用选项-q --all运行gppkg实用程序以列出已安装的扩展及其版本。
4. 重新加载greenplum_path.sh。
$ source $GPHOME/greenplum_path.sh
5. 重新启动数据库。
$ gpstop -r
About Greenplum Database PL/Java
There are a few key differencesbetween the implementation of PL/Java in standard PostgreSQL and GreenplumDatabase.
The following functions are notsupported in Greenplum Database. The classpath is handled differently in adistributed Greenplum Database environment than in the PostgreSQL environment.
sqlj.install_jar
sqlj.install_jar
sqlj.replace_jar
sqlj.remove_jar
sqlj.get_classpath
sqlj.set_classpath
GreenplumDatabase uses the pijava_ciasspath server configuration parameter inplace of the sqlj.set_classpath function.
Server Configuration parameter
在Greenplum数据库中,PL/Java使用以下服务器配置参数。 这些参数替换标准PostgreSQLPL/Java实现中使用的pijava.*参数:
• pljava_classpath
以冒号(:)分隔的包含任何PL/Java函数中使用的Java类的jar文件列表。
jar文件必须安装在所有Greenplum数据库主机的相同位置。 使用受信任的PL/Java语言处理程序,jar文件路径必须相对于$GPHOME/lib/postgresql/java/目录。 使用不受信任的语言处理程序(javaU语言标记),路径可能相对于$GPHOME/lib/postgresql/java/或绝对路径。
•pljava_statement_cache_size
为已准备好的语句设置最近使用(MRU)缓存的大小(以KB为单位)。
•pljava_release_lingering_savepoints
如果为TRUE,则将在功能退出时释放延迟的保存点。 如果FALSE,它们将被回滚。
•pljava_vmoptions
定义Greenplum数据库Java VM的启动选项。
有关Greenplum数据库参数的信息,请参阅“Greenplum数据库参考指南”。
Informationabout writing functions with PL/Java.
• Returning a SETOF <scalar type>
• Returning a SETOF〈complex type>
一个Java函数声明一个类的名称和该类的静态方法。 该类将使用已经为声明该函数的模式定义的类路径来解析。 如果没有为该模式定义类路径,则使用公共模式。 如果在其中找不到类路径,则使用系统类加载器解析该类。
可以声明以下函数来访问java.iang.system类上的静态方法getProperty:
CREATEFUNCTION getsysprop(VARCHAR)
RETURNSVARCHAR
AS'java.lang.System.getProperty'
LANGUAGE java;
运行以下命令以返回Java user.home属性:
SELECT getsysprop('user.home');
Scalar types are mapped in a straightforward way. This table lists the current mappings.
Table 142: PL/Java data type mapping
|
PostgreSQL | Java |
date | java.sql.Date |
time | java.sql.Time (stored value treated as local time) |
timetz | java.sql.Time |
timestamp | java.sql.Timestamp (stored value treated as local time) |
timestampz | java.sql.Timestamp |
complex | java.sql.ResultSet |
setof complex | java.sql.ResultSet |
|
All other types are mapped tojava.lang.String and will utilize the standard textin/textout routines registered for respectivetype.
映射到Java基元的标量类型不能作为NULL值传递。 要传递NULL值,这些类型可以有一个替代映射。 您可以通过在方法引用中明确表示它来启用此映射。
CREATE FUNCTIONtruelfEvenOrNull(integer)
RETURNS bool
AS ,foo.fee.Fum.trueIfEvenorNull(java.lang.Integer)'
LANGUAGE java;
The Java code would be similar tothis:
package foo.fee; public class Fum
{
static booleantrueIfEvenOrNull(Integer value)
{
return (value == null)
? true
:(value.intValue() % 1) == 0;
}
}
The followingtwo statements both yield true:
SELECT trueIfEvenOrNull(NULL);
SELECT trueIfEvenorNull(4);
为了从Java方法返回NULL值,可以使用对应于该基元的对象类型(例如,返回java.lang.Integer而不是int)。 PL/Java解析机制无论如何都会找到方法。 由于Java不能为同名的方法使用不同的返回类型,所以不会引入任何歧义。
一个复合类型总是作为一个只读的java.sql.ResultSet传递一行。 ResultSet位于其行,所以不应该调用next()。 使用ResultSet的标准getter方法来检索复杂类型的值。
Example:
CREATE TYPEcomplexTest
AS(baseinteger, incbase integer, ctime timestamptz); CREATE FUNCTIONuseComplexTest(complexTest)
RETURNSVARCHAR
AS 'foo.fee.Fum.useComplexTest'
IMMUTABLE LANGUAGE java;
In the Java class Fum, we add thefollowing static method:
public staticString useComplexTest(ResultSet complexTest) throws SQLException
{
int base =complexTest.getInt(1); int incbase = complexTest.getInt(2);
Timestampctime = complexTest.getTimestamp(3); return "Base =+ base +
incbase =\"" + incbase +
"\",ctime = \"" + ctime + "\"";
}
Java不规定任何方式来创建一个ResultSet。 因此,返回一个ResultSet不是一个选项。 SQL-2003草案建议复杂的返回值应作为IN/OUT参数处理。 PL/Java以这种方式实现了一个ResultSet。 如果声明一个返回复杂类型的函数,则需要使用带有布尔返回类型的Java方法,最后一个参数的类型为java.sql.ResultSet。 该参数将被初始化为一个空的可更新的ResultSet,它只包含一行。
假设上一节中的complexTest类型已经创建。
Assume that the complexTest type inprevious section has been created.
CREATEFUNCTION createComplexTest(int, int)
RETURNScomplexTest AS 'foo.fee.Fum.createComplexTest'
IMMUTABLE LANGUAGE java;
The PL/Java method resolve will nowfind the following method in the Fum class:
public staticboolean complexReturn(int base, int increment,
ResultSetreceiver) throws SQLException {
receiver.updateInt(1,base); receiver.updateInt(2, base + increment); receiver.updateTimestamp(3, new
Timestamp(System.currentTimeMillis()));return true;
}
The return value denotes if thereceiver should be considered as a valid tuple (true) or NULL (false).
返回结果集时,不要在返回结果集之前创建结果集,因为构建较大的结果集会消耗大量资源。 最好一次只产生一行。 顺便说一下,这就是Greenplum数据库后端希望用SETOF返回的功能。 您可以返回SETOF标量类型,如int,float或varchar,或者可以返回SETOF复杂类型。
Returning a SETOF <scalar type>
In order toreturn a set of a scalar type, you need create a Java method that returnssomething that implements the java.utii.iterator interface. Here is an exampleof a method that returns a SETOF
varchar:
CREATEFUNCTION javatest.getSystemProperties() RETURNS SETOF varchar AS'foo.fee.Bar.getNames'
IMMUTABLE LANGUAGE java;
This simple Java method returns aniterator:
packagefoo.fee;
import java.util.Iterator;
public classBar
{
public staticIterator getNames()
{
ArrayListnames = new ArrayList();
names.add("Lisa");
names.add("Bob");
names.add("Bill");
names.add("Sally");
returnnames.iterator();
}
}
Returning a SETOF <complex type>
返回SETOF <复杂类型>的方法必须使用接口
org.postgresql.pljava.ResultSetProvider或org.postgresql.pljava.ResultSetHandle。该有两个接口的原因是它们迎合两个不同用例的最佳处理。 前者适用于您想要动态创建要从SETOF函数返回的每一行的情况。 后者是在你想要返回执行查询的结果的情况下。
Using theResultSetProvider Interface
这个接口有两个方法。 boolean assignRowValues(java.sql.ResultSet tupleBuilder,int rowNumber)和void close()方法。 Greenplum数据库查询评估器将重复调用assignRowValues,直到它返回false或直到评估者决定不需要更多行。 然后它关闭。
你可以用下面的方法使用这个接口:
CREATEFUNCTION javatest.listComplexTests(int, int)
RETURNS SETOFcomplexTest AS 'foo.fee.Fum.listComplexTest'
IMMUTABLE LANGUAGE java;
The functionmaps to a static java method that returns an instance that implements the
ResultSetProvider interface.
public classFum implements ResultSetProvider {
private finalint m_base; private final int m_increment; public Fum(int base, int increment)
{
m base = base;
m_increment = increment;
} _
public booleanassignRowValues(ResultSet receiver, int currentRow)
throws SQLException
{
// Stop when we reach 12 rows.
//
if(currentRow >= 12) return false;
receiver.updateInt(1, m_base);
receiver.updateInt(2, m_base +m_increment * currentRow); receiver.updateTimestamp(3, newTimestamp(System.currentTimeMillis())); return true;
}
public void close()
{
// Nothing needed in this example
}
public static ResultSetProviderlistComplexTests(int base, int increment)
throws SQLException
{
return new Fum(base, increment);
}
}
listComplextTests方法被调用一次。 如果没有可用的结果或ResultSetProvider的实例,它可能会返回NULL。 这里的Java类Fum实现了这个接口,所以它返回一个它自己的实例。 assignRowValues方法将被重复调用,直到它返回false。 那时候,关闭会被调用
Using theResultSetHandle Interface
这个接口类似于ResultSetProvider接口,它有一个close()方法,最后会调用它。 但是,不是让评估者调用一次构建一行的方法,而是使用返回ResultSet的方法。 查询评估器将遍历这个集合,并一次将RestulSet内容(一次一个元组)传递给调用者,直到对next()的调用返回false或者评估者决定不再需要行为止。
以下是使用默认连接获取的语句执行查询的示例。 适合部署描述符的SQL如下所示::
publicclass Users implements ResultSetHandle
{
privatefinal String m_filter;
privateStatement m_statement;
publicUsers(String filter)
{
m_filter= filter;
}
publicResultSet getResultSet()
throwsSQLException
{
m_statement=
DriverManager.getConnection("Jdbc:default:connection").cr
eateStatement();
return m_statement.executeQuery("SELECT * FROM pg_user
WHERE" + m_filter);
}
publicvoid close()
throwsSQLException
{
m_statement.close();
}
publicstatic ResultSetHandle listSupers()
{
returnnew Users("usesuper = true");
}
public static ResultSetHandle listNonSupers()
{
return new Users("usesuper = false");
}
PL / Java包含一个映射到PostgreSQL SPI函数的JDBC驱动程序。 映射到当前事务的连接可以使用以下语句获得:
Connection conn =
DriverManager.getConnection(njdbc:default:connectionn);
获得连接后,可以准备和执行类似于其他JDBC连接的语句。 这些是对PL/Java JDBC驱动程序的限制:
•事务不能以任何方式进行管理。 因此,您不能使用连接上的方法,例如:
• commit()
• rollback()
• setAutoCommit()
• setTransactionIsolation()
•保存点有一些限制。 一个保存点不能超过它所设置的功能,并且必须通过该功能回退或释放。
•从executeQuery()返回的ResultSet始终为FETCH_FORWARD和CoNCUR_READ_ONLY。
元数据仅在PL/Java 1.1或更高版本中可用。
您可以捕获并处理Greenplum数据库后端中的异常,就像其他异常一样。 后端ErrorData结构作为一个名为属性的类被公开
org.postgresql.pljava.ServerException(派生自java.sql.SQLException),Java try/catch机制与后端机制同步。
重要说明:除非您已经使用了保存点,否则直到您的函数返回并且在后端生成异常时传播了错误,您将无法继续执行后端函数。 当保存点回滚时,异常情况将被重置,您可以继续执行。
.
Greenplum数据库保存点使用java.sql.Connection接口公开。 两个限制适用。
•保存点必须在设置的函数中回滚或释放。
•保存点不得超过设置的功能
PL/Java使用标准的Java记录器。 因此,你可以写下如下的东西:
Logger.getAnonymousLogger().info("Timeis " + new Date(System.currentTimeMillis()));
目前,记录器使用一个处理程序,将Greenplum数据库配置设置log_min_messages的当前状态映射到有效的记录器级别,并使用Greenplum数据库后端函数elog()输出所有消息。
注意:首次执行会话中的PL/Java函数时,将从数据库中读取log_min_messages设置]。 在Java方面,在特定的会话中执行第一个PL/Java函数之后,设置不会改变,直到与PL/Java一起工作的Greenplum数据库会话重新启动。
记录器级别和Greenplum数据库后端级别之间应用以下映射。
Table 143:PL/Java Logging Levels
java.util.logging.Level | Greenplum Database Level |
SEVERE ERROR | ERROR |
WARNING | WARNING |
CONFIG | LOG |
INFO | INFO |
FINE | DEBUG1 |
FINER | DEBUG2 |
FINEST | DEBUG3 |
|
Only a database super user can installPL/Java. The PL/Java utility functions are installed using SECURITY DEFINER sothat they execute with the access permissions that where granted to the creatorof the functions.
PL/Java is a trusted language. Thetrusted PL/Java language has no access to the file system as stipulated byPostgreSQL definition of a trusted language. Any database user can create andaccess functions in a trusted language.
PL/Java alsoinstalls a language handler for the language javau. This version is not trustedand only a superuser can create new functions that use it. Any user can callthe functions.
Some PL/Java Issues and Solutions
在编写PL/Java时,将JVM映射到与Greenplum数据库后端代码相同的进程空间,引发了一些关于多线程,异常处理和内存管理的担忧。 这里有简要的描述解释如何解决这些问题。
•多线程
• 异常处理
Java垃圾收集器与palloc()和堆栈分配
Java本质上是多线程的。 Greenplum数据库后端不是。 没有什么能阻止开发人员在Java代码中使用多个Threads类。 呼叫到后端的终结器可能已经从后台垃圾收集线程派生。 可能使用的几个第三方Java包使用多个线程。 在同一过程中,这个模型如何与Greenplum数据库后端共存?
解决方案很简单。 PL/Java定义了一个叫做Backend.THREADLocK的特殊对象。 当PL/Java被初始化时,后端立即抓取这个对象监视器(即它将同步这个对象)。 当后端调用Java函数时,监视器被释放,然后在调用返回时立即重新获得。 所有从Java到后端代码的调用都在同一个锁上进行同步。 这确保了一次只有一个线程可以从Java调用后端,并且只有在后端正在等待Java函数调用的返回时。
Java频繁使用try/catch/finally块。 Greenplum数据库有时会使用一个异常机制来调用longjmp来将控制转移到已知状态。 这样的跳转通常会有效地绕过JVM。
后端现在允许使用宏PG_TRY/PG_CATCH/PG_END_TRY捕获错误,并在catch块中使用ErrorData结构检查错误。 PL/Java实现了一个
java.sql.SQLException子类名为org.postgresql.pljava.ServerException。 ErrorData
可以从该例外中检索和检查。 一个catch处理程序被允许发出回退到一个保存点。 成功回滚后,执行可以继续。
Java Garbage Collector Versus palloc() and StackAllocation
原始类型总是按值传递。 这包括String类型(由于Java使用双字节字符,所以这是必须的)。 复杂类型通常包装在Java对象中,并通过引用传递。 例如,Java对象可以包含一个指向palloc或堆栈分配的内存的指针,并使用本机JNI调用来提取和操作数据。 一旦通话结束,这些数据将会变陈旧。 进一步访问这些数据的尝试最多会给出非常不可预知的结果,但更可能导致内存故障和崩溃。
PL/Java包含的代码可以确保当分配的MemoryContext或者堆栈超出范围时,陈旧的指针会被清除。 Java包装器对象可能存在,但任何尝试使用它们都将导致本机处理异常。.
The followingsimple Java example creates a JAR file that contains a single method and runsthe method.
Note: Theexample requires Java SDK to compile the Java file.
The followingmethod returns a substring.
{
public staticString substring(String text, int beginIndex, int endIndex)
{
returntext.substring(beginIndex, endIndex);
}
}
Enter the java code in a text fileexample.class.
Contents of the file manifest.txt:
Manifest-Version:1.0 Main-Class: Example Specification-Title: "Example"
Specification-Version:"1.0"
Created-By: 1.6.0_35-b10-428-11M3811Build-Date: 01/20/2013 10:09 AM
Compile the java code:
javac *.java
Create a JAR archive namedanalytics.jar that contains the class file and the manifest file MANIFEST filein the JAR.
jar cfm analytics.jar manifest.txt*.class
Upload the jar file to the Greenplummaster host.
Run the gpscp utility to copy the jarfile to the Greenplum Java directory. Use the -f option to specify the filethat contains a list of the master and segment hosts.
gpscp -f gphosts_file analytics.jar=:/usr/local/greenplum-db/lib/postgresql/java/
Use the gpconfig utility to set theGreenplum pljava_classpath server configuration parameter. The parameter liststhe installed jar files.
gpconfig -c pljava_classpath -v\'analytics.jarV
Run the gpstop utility with the -uoption to reload the configuration files.
gpstop -u
From the psql command line, run thefollowing command to show the installed jar files.
show pljava_classpath
The following SQL commands create atable and define a Java function to test the method in the jar file:
create tabletemp (a varchar) distributed randomly;
insert intotemp values ('my string');
--Examplefunction
create orreplace function java_substring(varchar, int, int) returns varchar as'Example.substring' language java;
--Exampleexecution
select java_substring(a, 1, 5) fromtemp;
You can place the contents in a file,mysample.sql and run the command from a psql command line:
> \i mysample.sql
The output is similar to this:
java_substring
y st
(1 row)
The PL/Java Github wiki page -https://github.com/tada/pljava/wiki.
PL/Java 1.4.0 release - https://github.com/tada/pljava/tree/B1_4.