转载自:https://www.modb.pro/db/9824

PL/Java语言函数

使用GaussDB 200数据库的PL/Java函数,用户可以使用自己喜欢的Java IDE编写Java方法,并将包含这些方法的jar文件安装到GaussDB 200数据库中,然后使用该方法。GaussDB 200 PL/Java基于开源Greenplum PL/Java 1.4.0开发,PL/Java所使用的JDK版本为1.8.0_201。

使用限制

Java UDF可以实现一些java逻辑计算,强烈建议不要在Java UDF中封装业务

  • 强烈建议不要在Java函数中使用任何方式连接数据库,包括但不限于JDBC。
  • 暂不支持的数据类型:除表1内容之外的数据类型,包括自定义类型,复杂数据类型(Java Array类及派生类)。
  • 暂不支持UDAF,UDTF。

示例

使用PL/Java函数时,需要首先将Java方法的实现打包为jar包并且部署到数据库中,然后使用数据库管理员账号创建函数,考虑兼容性问题,请使用1.8.0_201版本的JDK进行编译。

  • 编译jar包

     

    Java方法的实现和出包可以借助IDE来实现,以下是一个通过命令行来进行编译和出包的简单的示例,通过这个简单示例可以创建出一个包含单个方法的jar包文件。

    首先,编写一个Example.java文件,在此文件中实现子字符串大写转换的方法,内容如下:

    1
    2
    3
    4
    5
    6
    7
    public class Example 
    {
        public static String upperString (String text, int beginIndex, int endIndex) 
        {
            return text.substring(beginIndex, endIndex).toUpperCase();
        }
    }
    

    然后,创建manifest.txt清单文件,文件内容如下:

    1
    2
    3
    4
    5
    6
    Manifest-Version: 1.0
    Main-Class: Example
    Specification-Title: "Example"
    Specification-Version: "1.0"
    Created-By: 1.6.0_35-b10-428-11M3811
    Build-Date: 08/14/2018 10:09 AM
    

    最后,编译java文件并打包得到javaudf-example.jar

    1
    2
    javac Example.java
    jar cfm javaudf-example.jar manifest.txt Example.class
    

    jar包的命名规则应符合JDK命名要求,如果含有非法字符,在部署或者使用函数时将出错。

     

  • 部署jar

     

    Jar包的部署需要omm用户在命令行中调用gs_om工具完成。以操作系统用户omm登录CN所在主机,执行source ${BIGDATA_HOME}/mppdb/.mppdbgs_profile命令启动环境变量。

    首先,修改jar包权限:

    1
    chmod 644 javaudf-example.jar
    

    然后,将jar包部署到数据库中:

    1
    gs_om –t JavaUDF –m addjar –s javaudf-example.jar
    

    gs_extend_library函数如何使用请参见 管理jar包和文件。函数中的AK/SK值,请用户根据实际获取值替换。region_name请用户根据实际所在的区域名称替换。

     

  • 使用PL/Java函数

     

    首先,使用拥有sysadmin权限的数据库用户(例如:omm)登录数据库并创建java_upperstring函数如下:

    1
    2
    3
    4
    CREATE FUNCTION java_upperstring(VARCHAR, INTEGER, INTEGER)
        RETURNS VARCHAR
        AS 'Example.upperString'
    LANGUAGE JAVA;
    
    说明:
    • 函数java_upperstring中定义的数据类型为GaussDB 200的数据类型。该数据类型需要和1中java定义的方法upperString中数据类型一一对应。GaussDB 200与Java数据类型的对应关系,请参见表1。
    • AS子句用于指定该函数所调用的Java方法的类名和static方法名,格式为“类名.方法名”。
    • CREATE FUNCTION更多说明,请参见•创建函数。

    然后,执行java_upperstring函数:

    1
    SELECT java_upperstring('test', 0, 1);
    

    得到预期结果为:

    1
    2
    3
    4
     java_upperstring
    ---------------------
     T
    (1 row)
    

     

  • 授权普通用户使用PL/Java函数

     

    创建普通用户,名称为udf_user,密码为'GAUSS@123'。

    1
    CREATE USER udf_user PASSWORD 'GAUSS@123';
    

    授权普通用户udf_user对java_upperstring函数的使用权限。注意,此处需要把函数所在模式和函数的使用权限同时赋予给用户,用户才可以使用此函数。

    1
    2
    GRANT ALL PRIVILEGES ON SCHEMA public TO udf_user;
    GRANT ALL PRIVILEGES ON FUNCTION java_upperstring(VARCHAR, INTEGER, INTEGER) TO udf_user;
    

    以普通用户udf_user登录数据库。

    1
    SET SESSION SESSION AUTHORIZATION udf_user PASSWORD 'GAUSS@123';
    

    执行java_upperstring函数:

    1
    SELECT public.java_upperstring('test', 0, 1);
    

    得到预期结果为:

    1
    2
    3
    4
     java_upperstring
    ---------------------
     T
    (1 row)
    

     

  • 删除函数。

     

    如果不再使用该函数可以进行删除:
    1
    DROP FUNCTION java_upperstring;
    

     

  • 卸载jar

     

    Jar包的卸载同样需要omm用户通过命令行调用gs_om工具完成:

    1
    gs_om –t JavaUDF –m rmjar –d javaudf-example.jar
    

     

gs_om -t javaUDF工具

目前可以通过两种方式进行部署,一种是使用gs_om命令行工具,该工具可以部署任意格式文件,另一种是使用SQL函数gs_extend_library进行部署,该方式功能比较有限,建议线下用户使用gs_om命令行工具完成jar包或文件的部署。

  • 部署jar包或文件

    用户通过gs_om –t javaUDF –m addjar [-s LocalPath] [-d RemoteRelativePath] 命令实现jar包和其他配置文件的安装部署。

    说明:

    -t javaUDF:操作名称。

    -m addjar:表明操作类型为新增文件。

    -s LocalPath:命令执行节点的绝对路径,可以是文件也可以是路径,不能为空。

    -d RemoteRelativePath:相对路径,可缺省,若LocalPath为目录,该操作可以把LocalPath目录下的所有文件以及子目录及文件拷贝到集群中所有服务器的$GUASSHOME/lib/java/[RemoteRelativePath]目录下;若LocalPath为文件,该操作可以把LocalPath文件拷贝到集群中所有服务器的$GUASSHOME/lib/java/[RemoteRelativePath]目录下。拷贝过程中如果存在冲突,提供是否覆盖选项y/n/a,分别表示是、否、全部替换,由用户根据实际需要自行选择策略。

  • 卸载jar包或文件

    用户通过gs_om –t javaUDF –m rmjar [-d RemoteRelativePath] 命令实现jar和其他配置文件的卸载。

    说明:

    -t javaUDF:操作名称。

    -m rmjar:表明操作类型为删除文件。

    -d RemoteRelativePath:相对路径,可缺省,该操作可以删除集群中所有节点的指定目录$GUASSHOME/lib/java/[RemoteRelativePath] 及其下层目录下的目录、jar包和文件。

  • 查看jar包或文件

    线下用户通过gs_om -t javaUDF –m ls [-d RemoteRelativePath]命令查看已部署的jar和配置文件。并对文件一致性做校验。

    说明:

    -t javaUDF:操作名称。

    -m ls:表明操作类型为查看文件。

    -d RemoteRelativePath:相对路径,可缺省,该操作可以查看集群中所有节点的指定目录$GUASSHOME/lib /java/[RemoteRelativePath] 及其下层目录下的目录、jar包和文件(包括每个jar包或配置文件的相对路径),以执行节点为标准,对各节点中jar包及配置文件进行一致性检查。一致性检查会检查名称和MD5码,若有不一致给以警告。

SQL定义与使用

  • 创建函数

    PL/Java函数通过CREATE FUNCTION语法创建,并且定义为LANGUAGE JAVA,且包含RETURNS和AS子句。

    • CREATE FUNCTION时指定所创建函数的名称,以及参数类型;
    • RETURNS子句用于指定该函数的返回类型;
    • AS子句与用于指定该函数所调用的Java方法的类名和static方法名,如果需要向Java方法传递NULL值作为入参,还需要指定该参数类型所对应的Java封装类名 (详见NULL值处理)。
    • 更多语法说明,请参见CREATE FUNCTION。
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      CREATE [ OR REPLACE ] FUNCTION function_name
      ( [ { argname [ argmode ] argtype [ { DEFAULT | := | = } expression ]} [, …] ])
      [ RETURNS rettype [ DETERMINISTIC ] ]
      LANGAUGE JAVA
      [
          { IMMUTABLE | STATBLE | VOLATILE }
          | [ NOT ] LEAKPROOF
          | WINDOW
          | { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT |STRICT }
          | {[ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | AUTHID DEFINER | AUTHID CURRENT_USER}
          | { FENCED }
          | COST execution_cost
          | ROWS result_rows
          | SET configuration_parameter { {TO |=} value | FROM CURRENT}
      ] […]
      {
          AS 'class_name.method_name' ( { argtype } [, …] )
      }
      
  • 使用函数

    执行时,PL/Java会根据jar包名的字母序列,在所有部署的jar包中寻找函数指定的Java类,并调用首次找到的类中函数所指定的Java方法,并返回调用结果。

  • 删除函数

    PL/Java函数通过DROP FUNCTION语法删除函数。更多语法说明,请参见DROP FUNCTION。

    DROP FUNCTION [ IF EXISTS ] function_name [ ( [ {[ argmode ] [ argname ] argtype} [, ...] ] ) [ CASCADE | RESTRICT ] ];

    需要注意的是,如果所删除的函数为重载函数(详见重载函数),则删除时需要指明该函数的参数类型,如为非重载函数,则可直接指定函数名进行删除。

  • 函数授权

    非sysadmin户无法创建PL/Java函数,sysadmin用户可以赋予其他类型用户使用函数的权限。更多语法说明,请参见GRANT。

    GRANT { EXECUTE | ALL [ PRIVILEGES ] } ON { FUNCTION {function_name ( [ {[ argmode ] [ arg_name ] arg_type} [, ...] ] )} [, ...] | ALL FUNCTIONS IN SCHEMA schema_name [, ...] } TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ];

基本数据类型映射关系

表1 PL/Java默认数据类型映射关系

GaussDB 200

Java

BOOLEAN

boolean

"char"

byte

bytea

byte[]

SMALLINT

short

INTEGER

int

BIGINT

long

FLOAT4

float

FLOAT8

double

CHAR

java.lang.String

VARCHAR

java.lang.String

TEXT

java.lang.String

name

java.lang.String

DATE

java.sql.Timestamp

TIME

java.sql.Time (stored value treated as local time)

TIMETZ

java.sql.Time

TIMESTAMP

java.sql.Timestamp

TIMESTAMPTZ

java.sql.Timestamp

数组类型处理

GaussDB 200支持基础数组类型的转换,只需要在创建函数时在数据类型后追加 [] 即可,例如:

CREATE FUNCTION java_arrayLength(INTEGER[]) RETURNS INTEGER AS 'Example.getArrayLength' LANGUAGE JAVA;

Java代码类似于:

public class Example { public static int getArrayLength(Integer[] intArray) { return intArray.length; } }

那么下面的调用的语句后:

SELECT java_arrayLength(ARRAY[1, 2, 3]);

得到预期结果应该如下所示:

java_arrayLength --------------------- 3 (1 row)

NULL值处理

对于默认与Java的简单类型进行映射转换的那些GaussDB 200数据类型,是无法处理NULL值的,如果希望在Java方法里能够获得并处理从GaussDB 200中传入的NULL值,可以使用Java的封装类,并通过以下方式在AS子句中指定该Java封装类:

CREATE FUNCTION java_countnulls(INTEGER[]) RETURNS INTEGER AS 'Example.countNulls(java.lang.Integer[])' LANGUAGE JAVA;

Java代码类似于:

public class Example { public static int countNulls(Integer[] intArray) { int nullCount = 0; for (int idx = 0; idx < intArray.length; ++idx) { if (intArray[idx] == null) nullCount++; } return nullCount; } }

那么下面的调用的语句后:

SELECT java_countNulls(ARRAY[null, 1, null, 2, null]);

得到的预期结果应该如下所示:

java_countNulls -------------------- 3 (1 row)

重载函数

PL/Java支持重载函数,因此可以创建同名函数,或者调用Java代码中的重载方法。步骤如下:

  • 创建重载函数

     

    例如,在Java中可以实现两个方法名相同,输入参数类型不同的方法dummy(int) 和dummy(String)

    public class Example { public static int dummy(int value) { return value*2; } public static String dummy(String value) { return value; } }

    并在GaussDB 200中创建两个同名函数分别指定为上述两个方法:

    CREATE FUNCTION java_dummy(INTEGER) RETURNS INTEGER AS 'Example.dummy' LANGUAGE JAVA; CREATE FUNCTION java_dummy(VARCHAR) RETURNS VARCHAR AS 'Example.dummy' LANGUAGE JAVA;
  • 调用重载函数

     

    在调用重载函数时,GaussDB 200会根据输入的参数类型去调用匹配该类型的Java方法。因此上述两个函数的调用结果如下所示:

    SELECT java_dummy(5); java_dummy ----------------- 10 (1 row) SELECT java_dummy('5'); java_dummy --------------- 5 (1 row)

    需要注意的是,由于GaussDB 200对数据类型存在隐式转换的情况,因此建议在调用重载函数时,指定输入参数的类型,例如:

    SELECT java_dummy(5::varchar); java_dummy ---------------- 5 (1 row)

    此时会优先匹配所指定的参数类型,如果不存在指定参数类型的Java方法,则会对参数进行隐式转换匹配转换后的参数类型对应的Java方法。

    SELECT java_dummy(5::INTEGER); java_dummy ----------------- 10 (1 row) DROP FUNCTION java_dummy(INTEGER); SELECT java_dummy(5::INTEGER); java_dummy ---------------- 5 (1 row)

    隐式转换的数据类型包括:

    • 可以默认转换为INTEGER类型的包括:SMALLINT
    • 可以默认转换为BIGINT类型的包括:SMALLINT, INTEGER
    • 可以默认转换为BOOL类型的包括:TINYINT, SMALLINT, INTEGER, BIGINT
    • 可以默认转换为TEXT类型的包括:CHAR, NAME, BIGINT, INTEGER, SMALLINT, TINYINT, RAW, FLOAT4, FLOAT8, BPCHAR, VARCHAR, NVARCHAR2, DATE, TIMESTAMP, TIMESTAMPTZ, NUMERIC, SMALLDATETIME
    • 可以默认转换为VARCHAR类型的包括:TEXT, CHAR, BIGINT, INTEGER, SMALLINT, TINYINT, RAW, FLOAT4, FLOAT8, BPCHAR, DATE, NVARCHAR2, TIMESTAMP, NUMERIC, SMALLDATETIME
  • 删除重载函数

     

    对于重载函数,删除时需要指定函数的参数类型,否则无法删除。

    DROP FUNCTION java_dummy(INTEGER);

相关GUC参数

  • pljava_vmoptions

    会话级别的GUC参数,该参数用于设置JVM的启动参数,例如:

    SET pljava_vmoptions='-Xmx64m –Xms2m –XX:MaxMetaspaceSize=8m';

    pljava_vmoptions可接受的参数包括:

    • JDK8 JVM启动参数
    • JDK8 JVM系统属性参数(以–D开头,如:–Djava.ext.dirs)。
      • 由于Fenced UDF Master/Worker被沙箱控制,Fenced UDF Master/Worker的文件系统被隔离,这些进程不能看到整台机器上的所有文件。如果采用-Djava.ext.dirs、-Dhadoop.home.dir等设置的目录没有被配置到沙箱的配置文件中,则Fenced UDF Master/Worker无法读取这些目录。沙箱的进程名字为secbox,该进程以root权限运行,以便对UDF Master/Worker进程进行安全控制,比如,对文件系统进行隔离。
      • 把相应目录配置到沙箱配置文件的方法是:在$GAUSSHOME/secbox/secbox.conf中增加相应的[mount_path]条目。例如,如果希望Fenced UDF Master/Worker可以读取/path/to/java.ext.dirs,则在此文件中增加一行:
        [mount_path] read /path/to/java.ext.dirs
      • $GAUSSHOME/secbox/secbox.conf在每台节点的内容均相同,在一个节点设置完毕后,拷贝到所有其它节点。
    • -Dhadoop.home.dir (用于指定Hadoop环境,详见使用HDFS)
    • 用户自定义参数(以–D开头,如:–Duser.defined.option)

      如果所设置的参数不在上述范围内,视为非法参数,会在调用函数时报错。

      SET pljava_vmoptions=' illegal.option'; SET SELECT java_dummy(5::int); ERROR: UDF Error:cannot use PL/Java before successfully completing its setup.Please check if your pljava_vmoption is set correctly,since we do not ignore illegal parameters.Or check the log for more messages.
  • udf_memory_limit

    系统级别的GUC参数,用于限制每个CN、DN执行UDF可以使用的物理内存量,默认为200MB。可通过修改postgresql.conf文件进行配置,配置后需要重启数据库服务后才可生效。

    • udf_memory_limit是max_process_memory的一部分。每个CN、DN启动时,会预留(udf_memory_limit - 200MB)内存供UDF Worker进程使用。CN、DN和UDF Worker是不同的进程,但CN、DN自动少用一部分内存,把这部分内存节省下来供UDF Worker进程使用。

      例如:在某DN上把max_process_memory设置为10GB,udf_memory_limit设置为4GB,则此DN最多使用10GB - (4GB - 200MB)=6.2GB内存。即使用户没有执行任何UDF,则此DN也最多只能使用6.2GB内存。默认情况下,udf_memory_limit为200MB。查询pv_total_memory_detail视图时可以发现,process_used_memory永远不会超过max_process_memory - (udf_memory_limit - 200MB)。

    • 一个CN执行最简单的Java UDF函数,使用的物理内存量大约为50MB,用户可以根据自己Java函数的内存使用量和并发度设置此参数。新增此参数后,不再建议用户设置UDFWorkerMemHardLimit和FencedUDFMemoryLimit。
  • UDFWorkerMemHardLimit

    系统级别的GUC参数,用于限制系统允许的单个Fenced UDF Worker进程的最大虚拟内存使用量,默认为1GB。可以通过修改postgresql.conf文件进行配置,配置后需要重启数据库服务后才可生效。

    • 不建议设置此参数,可通过设置udf_memory_limit代替。
    • UDFWorkerMemHardLimit只控制FencedUDFMemoryLimit的上限。
    • 如果未设置FencedUDFMemoryLimit,则UDFWorkerMemHardLimit并不影响Fenced UDF Worker进程使用的虚拟内存量。
  • FencedUDFMemoryLimit

    会话级别的GUC参数,用户限制会话发起的单个Fenced UDF Worker进程的最大虚拟内存使用量,设置方法如下:

    SET FencedUDFMemoryLimit='512MB';

    该参数的取值范围为 (150MB, UDFWorkerMemHardLimit],当设置大于UDFWorkerMemHardLimit时会立即报错,当设置小于等于150MB时,则会在调用函数时报错。

    • FencedUDFMemoryLimit设置为0,表示不控制Fenced UDF Worker的虚拟内存使用量。
    • 建议通过设置udf_memory_limit控制Fenced UDF Worker使用的物理内存量。不建议用户使用FencedUDFMemoryLimit,尤其在使用Java UDF时不建议用户设置此参数。但是如果用户非常清楚设置该参数带来的影响,可以参考下列信息进行设置:
      • C UDF worker启动之后,占用的虚拟内存约为200MB,占用的物理内存约为16MB。
      • Java UDF worker启动之后,占用的虚拟内存约为2.5GB,占用的物理内存约为50MB。

部署使用配置文件

支持全局配置文件的部署,以更好的支持多个jar包中的类依赖同一个配置文件的场景。

用户可使用如下步骤完成配置:

  • 部署配置文件

     

    将配置文件config.properties部署到conf目录下:

    chmod 644 config.properties gs_om –t javaUDF –m addjar –s config.properties –d conf/

     

  • 编写Java函数

     

    可通过系统属性javaudf.file.path获得配置文件在GaussDB 200中的根路径:

    public class Example { public static String readConfigFile() { String path = System.getProperty("javaudf.file.path") + "/conf/config.properties"; File file = new File(path); BufferedReader reader = new BufferedReader(new FileReader(file)); String content = reader.readLine(); reader.close(); return content; } }

 

使用HDFS

在使用HDFS时,需要指定Hadoop的位置,同时使用kerberos方式获取访问Hadoop文件系统的权限。

如果物理节点上配置有HADOOP_HOME环境变量,PL/Java则会自动加载HADOOP_HOME/share/Hadoop/common,HADOOP_HOME/share/Hadoop/common/lib,HADOOP_HOME/share/Hadoop/hdfs,HADOOP_HOME/share/Hadoop/hdfs/lib,HADOOP_HOME/share/Hadoop/mapreduce,HADOOP_HOME/share/Hadoop/mapreduce/lib中的jar包。

用户也可以通过JVM启动参数-Dhadoop.home.dir=$HADOOP_HOME来指明Hadoop的位置。如果设置该启动参数,PL/Java则会以此参数为准加载该参数下上述路径中的jar包。

用户也可以通过设置-Djava.ext.dirs来加载所需要的Hadoop的依赖jar包,不过需要注意是,设置该参数时,需要同时追加JDK的依赖jar包路径,否则可能导致部分JDK功能缺失。

SET pljava_vmoptions='-Dhadoop.home.dir=$HADOOP_HOME'; SET pljava_vmoptions= '-Djava.ext.dirs=$GAUSSHOME/jdk/jre/lib/ext:HADOOP_HOME_PATH/share/Hadoop/common: HADOOP_HOME_PATH/share/Hadoop/common/lib';

同时,用户需要将HDFS相关的配置文件通过gs_om工具部署到conf目录下(详见部署使用配置文件),那么,用户在Java方法中则可以使用如下方式访问Hadoop中的文件。

public static String readHDFSFile(String filePath) throws Exception { FSDataInputStream in = null; FileSystem fs = null; String line = null; try { String confpath = System.getProperty("javaudf.file.path") + "/conf/"; Configuration conf = new Configuration(); conf.addResource(new Path(confpath+"core-site.xml")); conf.addResource(new Path(confpath+"hdfs-site.xml")); System.setProperty("java.security.krb5.conf", confpath+"krb5.conf"); org.apache.hadoop.security.UserGroupInformation.setConfiguration(conf); UserGroupInformation.loginUserFromKeytab("user@HADOOP.COM", confpath+"user.keytab"); fs = FileSystem.get(conf); in = fs.open(new Path(filePath)); BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(in, "UTF-8")); line = bufferedReader.readLine(); in.close(); fs.close(); return line; } catch (Exception e) { return e.getMessage(); } }

使用第三方库

对于只需要通过Java classpath加载的第三方库,可以简单的通过jar包部署到数据库中即可使用,而对于需要通过Java extension加载的第三方库(例如bcprov-ext-jdk15on-153.jar),可以尝试如下两种方式进行加载:

  • 将第三方jar包放置到各物理节点上$GAUSSHOME/jdk/jre/lib/ext目录下。
  • 通过设置GUC参数pljava_vmoptions进行加载,例如:
    SET pljava_vmoptions='-Djava.ext.dirs=$GAUSSHOME/jdk/jre/lib/ext:$PATH_TO_THIRD_LIB';

    其中,$GAUSSHOME需要替换成绝对路径;$PATH_TO_THIRD_LIB需要替换为第三方库所在的绝对路径。可能需要在沙箱的配置文件中指定$PATH_TO_THIRD_LIB对UDF Worker可见,详细见pljava_vmoptions中的注意,如果第三方库所在目录的某层上级目录已经对UDF Worker可见,则不需要指定

异常处理

如果在JVM中发生异常,PL/Java的异常处理机制会将异常时JVM的堆栈信息输出到客户端和pg_log文件中。为了便于用户调试,用户可以通过pg_log文件来查看异常发生前后数据库的运行情况,同时也可以通过hs_err_pidxxx.log文件查看JVM runtime的异常信息。

日志

PL/Java使用标准的Java Logger。 因此,用户可以通过如下方式记录日志:

Logger.getAnonymousLogger().config( "Time is " + new Date(System.currentTimeMillis()));

初始化的Java Logger类会默认设置为CONIFG级别,对应为GaussDB 200的LOG级别。Java Logger类输出的日志消息都会重定向到GaussDB 200后端,并写入到服务器日志或显示在用户界面上。MPPDB服务器日志将记录LOG、WARNING、ERROR级别的信息,而SQL用户界面将显示WARNING和ERROR级别的日志消息。Java Logger级别与GaussDB 200的日志级别对应关系见下表。

表2 PL/Java日志级别

java.util.logging.Level

GaussDB 200 日志级别

SERVER

ERROR

WARINING

WARNING

CONFIG

LOG

INFO

INFO

FINE

DEBUG1

FINER

DEBUG2

FINEST

DEBUG3

用户可以通过以下方式更改Java Logger的记录级别。例如通过下面的Java代码修改Java Logger级别为SEVERE,此时再记录WARNING级别的日志时,日志消息(msg)就不会再写入到GaussDB 200日志中。

Logger log = Logger.getAnonymousLogger(); Log.setLevel(Level.SEVERE); log.log(Level.WARNING, msg);

安全问题

在GaussDB 200中,PL/Java是一种untrusted语言,PL/Java函数只能由数据库sysdamin用户进行创建,通过GRANT方式赋予其他用户使用权限(详见函数授权)。

同时PL/Java控制用户对文件系统的访问权限,不允许用户在Java方法中对大部分的系统文件进行读操作,不允许所有的写、删除和执行操作。

允许的操作包括:

  • 允许读$GAUSSHOME/lib/postgresql/java目录及下属文件,但具体操作权限仍受操作系统权限限制;
  • 允许读$GAUSSHOME/jdk/jre中目录及下属文件,但具体操作权限仍受操作系统权限限制;
  • 允许读java.library.path中目录及下属文件的读权限,但具体操作权限仍受操作系统权限限制。
  • 如果环境中配置有HADOOP_HOME,或者用户在pljava_vmoptions中添加JVM启动参数-Dhadoop.home.dir=$HADOOP_HOME时,允许读$HADOOP_HOME下目录及下属文件的读权限,但具体操作权限仍受操作系统权限限制;
  • 允许对Hadoop文件系统的操作,但具体操作权限仍然受到kerberos权限限制;
  • 允许由名为org.apache.hadoop.security.UserGroupInfomation类发起的对整个文件系统中所有文件的执行权限(发生在进行kerberos认证调用Hadoop所提供的官方Java类方法UserGroupInfomation.setConfiguration()来初始化UserGroupInfomation类时),但实际的操作权限仍然受到操作系统权限限制。