云服务器内容精选

  • 基本数据类型映射关系 表1 PL/Java默认数据类型映射关系 GaussDB (DWS) 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(DWS)支持基础数组类型的转换,只需要在创建函数时在数据类型后追加 [] 即可,例如: 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)
  • 重载函数 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(DWS)中创建两个同名函数分别指定为上述两个方法: 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(DWS)会根据输入的参数类型去调用匹配该类型的Java方法。因此上述两个函数的调用结果如下所示: SELECT java_dummy(5); java_dummy ----------------- 10 (1 row) SELECT java_dummy('5'); java_dummy --------------- 5 (1 row) 需要注意的是,由于GaussDB(DWS)对数据类型存在隐式转换的情况,因此建议在调用重载函数时,指定输入参数的类型,例如: 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);
  • 日志 PL/Java使用标准的Java Logger。 因此,用户可以通过如下方式记录日志: Logger.getAnonymousLogger().config( "Time is " + new Date(System.currentTimeMillis())); 初始化的Java Logger类会默认设置为CONFIG级别,对应为GaussDB(DWS)的 LOG 级别。Java Logger类输出的日志消息都会重定向到GaussDB(DWS)后端,并写入到服务器日志或显示在用户界面上。MPPDB服务器日志将记录LOG、WARNING、ERROR级别的信息,而SQL用户界面将显示WARNING和ERROR级别的日志消息。Java Logger级别与GaussDB(DWS)的日志级别对应关系见下表。 表2 PL/Java日志级别 java.util.logging.Level GaussDB(DWS) 日志级别 SERVER ERROR WARNING WARNING CONFIG LOG INFO INFO FINE DEBUG1 FINER DEBUG2 FINEST DEBUG3 用户可以通过以下方式更改Java Logger的记录级别。例如通过下面的Java代码修改Java Logger级别为SEVERE,此时再记录WARNING级别的日志时,日志消息(msg)就不会再写入到GaussDB(DWS)日志中。 Logger log = Logger.getAnonymousLogger(); Log.setLevel(Level.SEVERE); log.log(Level.WARNING, msg);
  • 相关GUC参数 udf_memory_limit 系统级别的GUC参数,用于限制每个CN、DN执行UDF可以使用的物理内存量,默认为0.05 * max_process_memory。可通过修改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为0.05 * max_process_memory。查询pv_total_memory_detail视图时可以发现,process_used_memory永远不会超过max_process_memory - (udf_memory_limit - 200MB)。 UDF进程断连时会有报错提示。当出现“memory in UDF Work Process is limited by cgroup: [usage: xxx, max_usage_history: xxx, limit: xxx]”时,可以根据提示判断当前内存使用情况。报错中的usage表示UDF进程被KILL后剩余UDF进程的总物理内存使用量;max_usage_history表示UDF实例启动后历史上使用过的最大内存量,limit表示UDF进程使用内存的最大限制量。如果max_usage_history值接近limit值说明当前集群存在内存超过限制的风险,需要优化业务或按实际情况调整udf_memory_limit参数限制。 一个CN执行最简单的Java UDF函数,使用的物理内存量大约为50MB,用户可以根据自己Java函数的内存使用量和并发度设置此参数。新增此参数后,不再建议用户设置UDFWorkerMemHardLimit和FencedUDFMemoryLimit。 当UDF进程并发度过大,内存超出udf_memory_limit设置值时会导致进程退出等非预期情况,该场景下执行结果可能不可靠,强烈建议根据实际情况进行参数设置,保留足够内存余量。如果系统记录有/var/log/messages,可查看该日志文件是否存在因超过cgroup内存限制而造成内存不足。内存严重不足时,甚至可能导致UDF master进程退出,可以查看UDF日志进行分析,默认的UDF日志路径在$GAUSSLOG/cm/cm_agent/pg_log下。例如,出现以下日志时就说明内存资源严重不足,导致了UDF master进程退出,需要检查udf_memory_limit参数设置。 0 [BACKEND] FATAL: poll() failed: Bad address, please check the parameter:udf_memory_limit to make sure there is enough memory. FencedUDFMemoryLimit 会话级别的GUC参数,用户限制会话发起的单个Fenced UDF Worker进程的最大虚拟内存使用量,设置方法如下: SET FencedUDFMemoryLimit='512MB'; 该参数的取值范围为 (150MB, 1G],当设置大于1G时会立即报错,当设置小于等于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。
  • 示例 使用PL/Java函数时,需要首先将Java方法的实现打包为jar包并且部署到数据库中,然后使用数据库管理员账号创建函数,考虑兼容性问题,请使用1.8.0_322版本的JRE进行编译。 编译jar包。 Java方法的实现和出包可以借助IDE来实现,以下是一个通过命令行来进行编译和出包的简单的示例,通过这个简单示例可以创建出一个包含单个方法的jar包文件。 首先,编写一个Example.java文件,在此文件中实现子字符串大写转换的方法,本例中类名为Example,方法名为upperString,内容如下: 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 其中,Manifest-Version定义了manifest文件的版本,Main-Class定义了jar文件的入口类,Specification-Title和Specification-Version属于包的扩展属性,Specification-Title定义了扩展规范的标题,Specification-Version定义了扩展规范的版本,Created-By声明了该文件的生成者,Build-Date声明了该文件构建日期。 最后,编译java文件并打包得到javaudf-example.jar 1 2 javac Example.java jar cfm javaudf-example.jar manifest.txt Example.class jar包的命名规则应符合JDK命名要求,如果含有非法字符,在部署或者使用函数时将出错。 部署jar包。 Jar包首先需要放置到OBS服务器中,放置方法具体请参见《 对象存储服务 控制台指南》的上传文件章节。接着创建访问密钥AK/SK,获取访问密钥的具体步骤,请参见创建访问密钥(AK和SK)章节。登录数据库运行gs_extend_library函数,将文件导入到GaussDB(DWS)中: 1 SELECT gs_extend_library('addjar', 'obs://bucket/path/javaudf-example.jar accesskey=access_key_value_to_be_replaced secretkey=secret_access_key_value_to_be_replaced region=region_name libraryname=example'); gs_extend_library函数如何使用请参见 管理jar包和文件。函数中的AK/SK值,请用户根据实际获取值替换。region_name请用户根据实际所在的区 域名 称替换。 使用PL/Java函数。 首先,使用拥有sysadmin权限的数据库用户(例如:dbadmin)登录数据库并创建java_upperstring函数如下: 1 2 3 4 CREATE FUNCTION java_upperstring(VARCHAR, INTEGER, INTEGER) RETURNS VARCHAR AS 'Example.upperString' LANGUAGE JAVA; 函数java_upperstring中定义的数据类型为GaussDB(DWS)的数据类型。该数据类型需要和步骤1中java定义的方法upperString中数据类型一一对应。GaussDB(DWS)与Java数据类型的对应关系,请参见表1。 AS子句用于指定该函数所调用的Java方法的类名和static方法名,格式为“类名.方法名”。该字段需要和步骤1中java定义的类名和方法名一致。 使用PL/Java函数时,LANGUAGE字段应指定为JAVA。 CREATE FUNCTION更多说明,请参见创建函数。 然后,执行java_upperstring函数: 1 SELECT java_upperstring('test', 0, 1); 得到预期结果为: 1 2 3 4 java_upperstring --------------------- T (1 row) 授权普通用户使用PL/Java函数。 创建普通用户,名称为udf_user。 1 CREATE USER udf_user PASSWORD 'password'; 授权普通用户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 'password'; 执行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包。 使用gs_extend_library函数卸载jar包: 1 SELECT gs_extend_library('rmjar', 'libraryname=example');
  • 日志 PL/Java使用标准的Java Logger。 因此,用户可以通过如下方式记录日志: Logger.getAnonymousLogger().config( "Time is " + new Date(System.currentTimeMillis())); 初始化的Java Logger类会默认设置为CONFIG级别,对应为GaussDB(DWS)的LOG级别。Java Logger类输出的日志消息都会重定向到GaussDB(DWS)后端,并写入到服务器日志或显示在用户界面上。MPPDB服务器日志将记录LOG、WARNING、ERROR级别的信息,而SQL用户界面将显示WARNING和ERROR级别的日志消息。Java Logger级别与GaussDB(DWS)的日志级别对应关系见下表。 表2 PL/Java日志级别 java.util.logging.Level GaussDB(DWS) 日志级别 SERVER ERROR WARNING WARNING CONFIG LOG INFO INFO FINE DEBUG1 FINER DEBUG2 FINEST DEBUG3 用户可以通过以下方式更改Java Logger的记录级别。例如通过下面的Java代码修改Java Logger级别为SEVERE,此时再记录WARNING级别的日志时,日志消息(msg)就不会再写入到GaussDB(DWS)日志中。 Logger log = Logger.getAnonymousLogger(); Log.setLevel(Level.SEVERE); log.log(Level.WARNING, msg);
  • 重载函数 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(DWS)中创建两个同名函数分别指定为上述两个方法: 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(DWS)会根据输入的参数类型去调用匹配该类型的Java方法。因此上述两个函数的调用结果如下所示: SELECT java_dummy(5); java_dummy ----------------- 10 (1 row) SELECT java_dummy('5'); java_dummy --------------- 5 (1 row) 需要注意的是,由于GaussDB(DWS)对数据类型存在隐式转换的情况,因此建议在调用重载函数时,指定输入参数的类型,例如: 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);
  • 基本数据类型映射关系 表1 PL/Java默认数据类型映射关系 GaussDB(DWS) 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(DWS)支持基础数组类型的转换,只需要在创建函数时在数据类型后追加 [] 即可,例如: 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)
  • 示例 使用PL/Java函数时,需要首先将Java方法的实现打包为jar包并且部署到数据库中,然后使用数据库管理员账号创建函数,考虑兼容性问题,请使用1.8.0_322版本的JRE进行编译。 编译jar包。 Java方法的实现和出包可以借助IDE来实现,以下是一个通过命令行来进行编译和出包的简单的示例,通过这个简单示例可以创建出一个包含单个方法的jar包文件。 首先,编写一个Example.java文件,在此文件中实现子字符串大写转换的方法,本例中类名为Example,方法名为upperString,内容如下: 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 其中,Manifest-Version定义了manifest文件的版本,Main-Class定义了jar文件的入口类,Specification-Title和Specification-Version属于包的扩展属性,Specification-Title定义了扩展规范的标题,Specification-Version定义了扩展规范的版本,Created-By声明了该文件的生成者,Build-Date声明了该文件构建日期。 最后,编译java文件并打包得到javaudf-example.jar 1 2 javac Example.java jar cfm javaudf-example.jar manifest.txt Example.class jar包的命名规则应符合JDK命名要求,如果含有非法字符,在部署或者使用函数时将出错。 部署jar包。 Jar包首先需要放置到OBS服务器中,放置方法具体请参见《对象存储服务控制台指南》的上传文件章节。接着创建访问密钥AK/SK,获取访问密钥的具体步骤,请参见创建访问密钥(AK和SK)章节。登录数据库运行gs_extend_library函数,将文件导入到GaussDB(DWS)中: 1 SELECT gs_extend_library('addjar', 'obs://bucket/path/javaudf-example.jar accesskey=access_key_value_to_be_replaced secretkey=secret_access_key_value_to_be_replaced region=region_name libraryname=example'); gs_extend_library函数如何使用请参见 管理jar包和文件。函数中的AK/SK值,请用户根据实际获取值替换。region_name请用户根据实际所在的区域名称替换。 使用PL/Java函数。 首先,使用拥有sysadmin权限的数据库用户(例如:dbadmin)登录数据库并创建java_upperstring函数如下: 1 2 3 4 CREATE FUNCTION java_upperstring(VARCHAR, INTEGER, INTEGER) RETURNS VARCHAR AS 'Example.upperString' LANGUAGE JAVA; 函数java_upperstring中定义的数据类型为GaussDB(DWS)的数据类型。该数据类型需要和步骤1中java定义的方法upperString中数据类型一一对应。GaussDB(DWS)与Java数据类型的对应关系,请参见表1。 AS子句用于指定该函数所调用的Java方法的类名和static方法名,格式为“类名.方法名”。该字段需要和步骤1中java定义的类名和方法名一致。 使用PL/Java函数时,LANGUAGE字段应指定为JAVA。 CREATE FUNCTION更多说明,请参见创建函数。 然后,执行java_upperstring函数: 1 SELECT java_upperstring('test', 0, 1); 得到预期结果为: 1 2 3 4 java_upperstring --------------------- T (1 row) 授权普通用户使用PL/Java函数。 创建普通用户,名称为udf_user。 1 CREATE USER udf_user PASSWORD 'password'; 授权普通用户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 'password'; 执行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包。 使用gs_extend_library函数卸载jar包: 1 SELECT gs_extend_library('rmjar', 'libraryname=example');
  • 相关GUC参数 udf_memory_limit 系统级别的GUC参数,用于限制每个CN、DN执行UDF可以使用的物理内存量,默认为0.05 * max_process_memory。可通过修改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为0.05 * max_process_memory。查询pv_total_memory_detail视图时可以发现,process_used_memory永远不会超过max_process_memory - (udf_memory_limit - 200MB)。 UDF进程断连时会有报错提示。当出现“memory in UDF Work Process is limited by cgroup: [usage: xxx, max_usage_history: xxx, limit: xxx]”时,可以根据提示判断当前内存使用情况。报错中的usage表示UDF进程被KILL后剩余UDF进程的总物理内存使用量;max_usage_history表示UDF实例启动后历史上使用过的最大内存量,limit表示UDF进程使用内存的最大限制量。如果max_usage_history值接近limit值说明当前集群存在内存超过限制的风险,需要优化业务或按实际情况调整udf_memory_limit参数限制。 一个CN执行最简单的Java UDF函数,使用的物理内存量大约为50MB,用户可以根据自己Java函数的内存使用量和并发度设置此参数。新增此参数后,不再建议用户设置UDFWorkerMemHardLimit和FencedUDFMemoryLimit。 当UDF进程并发度过大,内存超出udf_memory_limit设置值时会导致进程退出等非预期情况,该场景下执行结果可能不可靠,强烈建议根据实际情况进行参数设置,保留足够内存余量。如果系统记录有/var/log/messages,可查看该日志文件是否存在因超过cgroup内存限制而造成内存不足。内存严重不足时,甚至可能导致UDF master进程退出,可以查看UDF日志进行分析,默认的UDF日志路径在$GAUSSLOG/cm/cm_agent/pg_log下。例如,出现以下日志时就说明内存资源严重不足,导致了UDF master进程退出,需要检查udf_memory_limit参数设置。 0 [BACKEND] FATAL: poll() failed: Bad address, please check the parameter:udf_memory_limit to make sure there is enough memory. FencedUDFMemoryLimit 会话级别的GUC参数,用户限制会话发起的单个Fenced UDF Worker进程的最大虚拟内存使用量,设置方法如下: SET FencedUDFMemoryLimit='512MB'; 该参数的取值范围为 (150MB, 1G],当设置大于1G时会立即报错,当设置小于等于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。
  • 日志 PL/Java使用标准的Java Logger。 因此,用户可以通过如下方式记录日志: Logger.getAnonymousLogger().config( "Time is " + new Date(System.currentTimeMillis())); 初始化的Java Logger类会默认设置为CONFIG级别,对应为GaussDB(DWS)的LOG级别。Java Logger类输出的日志消息都会重定向到GaussDB(DWS)后端,并写入到服务器日志或显示在用户界面上。MPPDB服务器日志将记录LOG、WARNING、ERROR级别的信息,而SQL用户界面将显示WARNING和ERROR级别的日志消息。Java Logger级别与GaussDB(DWS)的日志级别对应关系见下表。 表2 PL/Java日志级别 java.util.logging.Level GaussDB(DWS) 日志级别 SERVER ERROR WARNING WARNING CONFIG LOG INFO INFO FINE DEBUG1 FINER DEBUG2 FINEST DEBUG3 用户可以通过以下方式更改Java Logger的记录级别。例如通过下面的Java代码修改Java Logger级别为SEVERE,此时再记录WARNING级别的日志时,日志消息(msg)就不会再写入到GaussDB(DWS)日志中。 Logger log = Logger.getAnonymousLogger(); Log.setLevel(Level.SEVERE); log.log(Level.WARNING, msg);
  • 数组类型处理 GaussDB(DWS)支持基础数组类型的转换,只需要在创建函数时在数据类型后追加 [] 即可,例如: 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)
  • 重载函数 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(DWS)中创建两个同名函数分别指定为上述两个方法: 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(DWS)会根据输入的参数类型去调用匹配该类型的Java方法。因此上述两个函数的调用结果如下所示: SELECT java_dummy(5); java_dummy ----------------- 10 (1 row) SELECT java_dummy('5'); java_dummy --------------- 5 (1 row) 需要注意的是,由于GaussDB(DWS)对数据类型存在隐式转换的情况,因此建议在调用重载函数时,指定输入参数的类型,例如: 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);