You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hawq.apache.org by hu...@apache.org on 2016/07/28 03:18:44 UTC

incubator-hawq git commit: HAWQ-922. Add basic verification for various pl and udf in HAWQ

Repository: incubator-hawq
Updated Branches:
  refs/heads/master 4de3d107c -> 7ecf59aa9


HAWQ-922. Add basic verification for various pl and udf in HAWQ


Project: http://git-wip-us.apache.org/repos/asf/incubator-hawq/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-hawq/commit/7ecf59aa
Tree: http://git-wip-us.apache.org/repos/asf/incubator-hawq/tree/7ecf59aa
Diff: http://git-wip-us.apache.org/repos/asf/incubator-hawq/diff/7ecf59aa

Branch: refs/heads/master
Commit: 7ecf59aa95b287949c9ae4a97d81eca55ecde21f
Parents: 4de3d10
Author: Ruilong Huo <rh...@pivotal.io>
Authored: Mon Jul 25 15:20:00 2016 +0800
Committer: Ruilong Huo <rh...@pivotal.io>
Committed: Thu Jul 28 11:18:12 2016 +0800

----------------------------------------------------------------------
 src/test/feature/UDF/TestUDF.cpp                | 218 ++++++++++++++++++-
 src/test/feature/UDF/ans/function_c.ans.source  |  15 ++
 src/test/feature/UDF/ans/function_internal.ans  |  16 ++
 src/test/feature/UDF/ans/function_pgcrypto.ans  |  12 +
 src/test/feature/UDF/ans/function_pljava.ans    |  21 ++
 src/test/feature/UDF/ans/function_pljavau.ans   |  21 ++
 src/test/feature/UDF/ans/function_plperl.ans    |  35 +++
 src/test/feature/UDF/ans/function_plperlu.ans   |  35 +++
 src/test/feature/UDF/ans/function_plpgsql.ans   |  18 ++
 src/test/feature/UDF/ans/function_plpythonu.ans |  18 ++
 src/test/feature/UDF/ans/function_plr.ans       |  20 ++
 src/test/feature/UDF/ans/function_sql.ans       |  24 ++
 src/test/feature/UDF/lib/function.c             |  12 +-
 src/test/feature/UDF/sql/PLJavaAdd.jar          | Bin 0 -> 654 bytes
 src/test/feature/UDF/sql/PLJavaAdd.java         |   7 +
 src/test/feature/UDF/sql/PLJavauAdd.jar         | Bin 0 -> 657 bytes
 src/test/feature/UDF/sql/PLJavauAdd.java        |   7 +
 src/test/feature/UDF/sql/function_c.sql.source  |   6 +
 src/test/feature/UDF/sql/function_internal.sql  |   7 +
 src/test/feature/UDF/sql/function_pgcrypto.sql  |   2 +
 src/test/feature/UDF/sql/function_pljava.sql    |   8 +
 src/test/feature/UDF/sql/function_pljavau.sql   |   8 +
 src/test/feature/UDF/sql/function_plperl.sql    |  22 ++
 src/test/feature/UDF/sql/function_plperlu.sql   |  22 ++
 src/test/feature/UDF/sql/function_plpgsql.sql   |   9 +
 src/test/feature/UDF/sql/function_plpythonu.sql |   9 +
 src/test/feature/UDF/sql/function_plr.sql       |  11 +
 src/test/feature/UDF/sql/function_sql.sql       |  13 ++
 src/test/feature/lib/hawq_scp.cpp               |  24 ++
 src/test/feature/lib/hawq_scp.h                 |  23 ++
 src/test/feature/lib/sql_util.cpp               |  33 +++
 src/test/feature/lib/sql_util.h                 |  10 +
 32 files changed, 683 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/TestUDF.cpp
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/TestUDF.cpp b/src/test/feature/UDF/TestUDF.cpp
index ce7f158..7107b63 100755
--- a/src/test/feature/UDF/TestUDF.cpp
+++ b/src/test/feature/UDF/TestUDF.cpp
@@ -1,7 +1,9 @@
 #include "gtest/gtest.h"
 
+#include "lib/command.h"
 #include "lib/sql_util.h"
 #include "lib/file_replace.h"
+#include "lib/hawq_scp.h"
 
 
 class TestUDF: public ::testing::Test
@@ -51,8 +53,18 @@ TEST_F(TestUDF, TestUDFCreation)
 TEST_F(TestUDF, TestUDFSetReturning)
 {
 	hawq::test::SQLUtility util;
-	util.execSQLFile("UDF/sql/function_set_returning.sql",
-	                 "UDF/ans/function_set_returning.ans");
+	// enable plpythonu language if it is absent
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plpythonu'") != "plpythonu")
+	{
+		util.execute("CREATE LANGUAGE plpythonu", false);
+	}
+
+	// run test if plpythonu language is enabled
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plpythonu'") == "plpythonu")
+	{
+		util.execSQLFile("UDF/sql/function_set_returning.sql",
+		                 "UDF/ans/function_set_returning.ans");
+	}
 }
 
 TEST_F(TestUDF, TestUDFExtension)
@@ -61,3 +73,205 @@ TEST_F(TestUDF, TestUDFExtension)
 	util.execSQLFile("UDF/sql/function_extension.sql",
 	                 "UDF/ans/function_extension.ans");
 }
+
+TEST_F(TestUDF, TestUDFInternal)
+{
+	hawq::test::SQLUtility util;
+	util.execSQLFile("UDF/sql/function_internal.sql",
+	                 "UDF/ans/function_internal.ans");
+}
+
+TEST_F(TestUDF, TestUDFC)
+{
+	// preprocess source files to get sql/ans files
+	hawq::test::SQLUtility util;
+	std::string d_feature_test_root(util.getTestRootPath());
+	std::string f_sql_tpl(d_feature_test_root + "/UDF/sql/function_c.sql.source");
+	std::string f_ans_tpl(d_feature_test_root + "/UDF/ans/function_c.ans.source");
+	std::string f_sql(d_feature_test_root + "/UDF/sql/function_c.sql");
+	std::string f_ans(d_feature_test_root + "/UDF/ans/function_c.ans");
+
+	hawq::test::FileReplace frep;
+	std::unordered_map<std::string, std::string> strs_src_dst;
+	strs_src_dst["@SHARE_LIBRARY_PATH@"] = d_feature_test_root + "/UDF/lib/function.so";
+
+	frep.replace(f_sql_tpl, f_sql, strs_src_dst);
+	frep.replace(f_ans_tpl, f_ans, strs_src_dst);
+
+	// run sql file to get ans file and then diff it with out file
+	util.execSQLFile("UDF/sql/function_c.sql",
+	                 "UDF/ans/function_c.ans");
+}
+
+TEST_F(TestUDF, TestUDFSql)
+{
+	hawq::test::SQLUtility util;
+	util.execSQLFile("UDF/sql/function_sql.sql",
+	                 "UDF/ans/function_sql.ans");
+}
+
+TEST_F(TestUDF, TestUDFPlpgsql)
+{
+	hawq::test::SQLUtility util;
+	// enable plpgsql language if it is absent
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plpgsql'") != "plpgsql")
+	{
+		util.execute("CREATE LANGUAGE plpgsql", false);
+	}
+
+	// run test if plpgsql language is enabled
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plpgsql'") == "plpgsql")
+	{
+		util.execSQLFile("UDF/sql/function_plpgsql.sql",
+		                 "UDF/ans/function_plpgsql.ans");
+	}
+}
+
+TEST_F(TestUDF, TestUDFPgcrypto)
+{
+	hawq::test::SQLUtility util;
+	// enable pgcrypto package if it is absent
+	if (util.getQueryResult("SELECT proname FROM pg_proc WHERE proname = 'crypt'") != "crypt")
+	{
+		const char *gph = getenv("GPHOME");
+		std::string gphome = gph ? gph : "";
+		EXPECT_NE(gphome, "");
+
+		util.execSQLFile(gphome + "/share/postgresql/contrib/pgcrypto.sql");
+	}
+
+	// run test if pgcrypto package is enabled
+	if (util.getQueryResult("SELECT proname FROM pg_proc WHERE proname = 'crypt'") == "crypt")
+	{
+		util.execSQLFile("UDF/sql/function_pgcrypto.sql",
+		                 "UDF/ans/function_pgcrypto.ans");
+	}
+}
+
+TEST_F(TestUDF, TestUDFPlr)
+{
+	hawq::test::SQLUtility util;
+	// enable plr language if it is absent
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plr'") != "plr")
+	{
+		util.execute("CREATE LANGUAGE plr", false);
+	}
+
+	// run test if plr language is enabled
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plr'") == "plr")
+	{
+		util.execSQLFile("UDF/sql/function_plr.sql",
+		                 "UDF/ans/function_plr.ans");
+	}
+}
+
+TEST_F(TestUDF, TestUDFPljava)
+{
+	hawq::test::SQLUtility util;
+	std::string d_feature_test_root(util.getTestRootPath());
+
+	const char *gph = getenv("GPHOME");
+	std::string gphome = gph ? gph : "";
+	EXPECT_NE(gphome, "");
+
+	// enable pljava language if it is absent
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'java'") != "java")
+	{
+		hawq::test::Command cmd("psql -f " + gphome + "/share/postgresql/pljava/install.sql");
+		cmd.run();
+	}
+
+	// run test if pljava language is enabled
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'java'") == "java")
+	{
+		// copy jar files over hawq cluster
+		std::string query = "SELECT string_agg('-h ' || hostname, ' ' ORDER BY hostname) FROM gp_segment_configuration;";
+		std::string hosts = util.getQueryResult(query);
+		hawq::test::HAWQScp hscp;
+		EXPECT_EQ(hscp.copy(hosts, d_feature_test_root + "/UDF/sql/PLJavaAdd.jar", gphome + "/lib/postgresql/java/"), true);
+
+		util.execSQLFile("UDF/sql/function_pljava.sql",
+		                 "UDF/ans/function_pljava.ans");
+	}
+}
+
+TEST_F(TestUDF, TestUDFPljavau)
+{
+	hawq::test::SQLUtility util;
+	std::string d_feature_test_root(util.getTestRootPath());
+
+	const char *gph = getenv("GPHOME");
+	std::string gphome = gph ? gph : "";
+	EXPECT_NE(gphome, "");
+
+	// enable pljavau language if it is absent
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'javau'") != "javau")
+	{
+		hawq::test::Command cmd("psql -f " + gphome + "/share/postgresql/pljava/install.sql");
+		cmd.run();
+	}
+
+	// run test if pljavau language is enabled
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'javau'") == "javau")
+	{
+		// copy jar files over hawq cluster
+		std::string query = "SELECT string_agg('-h ' || hostname, ' ' ORDER BY hostname) FROM gp_segment_configuration;";
+		std::string hosts = util.getQueryResult(query);
+		hawq::test::HAWQScp hscp;
+		EXPECT_EQ(hscp.copy(hosts, d_feature_test_root + "/UDF/sql/PLJavauAdd.jar", gphome + "/lib/postgresql/java/"), true);
+
+		util.execSQLFile("UDF/sql/function_pljavau.sql",
+		                 "UDF/ans/function_pljavau.ans");
+	}
+}
+
+TEST_F(TestUDF, TestUDFPlpythonu)
+{
+	hawq::test::SQLUtility util;
+	// enable plpythonu language if it is absent
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plpythonu'") != "plpythonu")
+	{
+		util.execute("CREATE LANGUAGE plpythonu", false);
+	}
+
+	// run test if plpythonu language is enabled
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plpythonu'") == "plpythonu")
+	{
+		util.execSQLFile("UDF/sql/function_plpythonu.sql",
+		                 "UDF/ans/function_plpythonu.ans");
+	}
+}
+
+TEST_F(TestUDF, TestUDFPlperl)
+{
+	hawq::test::SQLUtility util;
+	// enable plperl language if it is absent
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plperl'") != "plperl")
+	{
+		util.execute("CREATE LANGUAGE plperl", false);
+	}
+
+	// run test if plperl language is enabled
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plperl'") == "plperl")
+	{
+		util.execSQLFile("UDF/sql/function_plperl.sql",
+		                 "UDF/ans/function_plperl.ans");
+	}
+}
+
+TEST_F(TestUDF, TestUDFPlperlu)
+{
+	hawq::test::SQLUtility util;
+	// enable plperlu language if it is absent
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plperlu'") != "plperlu")
+	{
+		util.execute("CREATE LANGUAGE plperlu", false);
+	}
+
+	// run test if plperlu language is enabled
+	if (util.getQueryResult("SELECT lanname FROM pg_language WHERE lanname = 'plperlu'") == "plperlu")
+	{
+		util.execSQLFile("UDF/sql/function_plperlu.sql",
+		                 "UDF/ans/function_plperlu.ans");
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/ans/function_c.ans.source
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/ans/function_c.ans.source b/src/test/feature/UDF/ans/function_c.ans.source
new file mode 100644
index 0000000..c99f33c
--- /dev/null
+++ b/src/test/feature/UDF/ans/function_c.ans.source
@@ -0,0 +1,15 @@
+-- start_ignore
+SET SEARCH_PATH=TestUDF_TestUDFC;
+SET
+-- end_ignore
+CREATE OR REPLACE FUNCTION c_add(x INT, y INT)
+RETURNS INT
+AS '@SHARE_LIBRARY_PATH@', 'c_add'
+LANGUAGE C IMMUTABLE STRICT;
+CREATE FUNCTION
+SELECT c_add(20, 30);
+ c_add 
+-------
+    50
+(1 row)
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/ans/function_internal.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/ans/function_internal.ans b/src/test/feature/UDF/ans/function_internal.ans
new file mode 100644
index 0000000..4740703
--- /dev/null
+++ b/src/test/feature/UDF/ans/function_internal.ans
@@ -0,0 +1,16 @@
+-- start_ignore
+SET SEARCH_PATH=TestUDF_TestUDFInternal;
+SET
+-- end_ignore
+CREATE OR REPLACE FUNCTION internal_sqrt(DOUBLE PRECISION)
+RETURNS DOUBLE PRECISION
+AS 'dsqrt'
+LANGUAGE internal
+STRICT;
+CREATE FUNCTION
+SELECT internal_sqrt(25.0);
+ internal_sqrt 
+---------------
+             5
+(1 row)
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/ans/function_pgcrypto.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/ans/function_pgcrypto.ans b/src/test/feature/UDF/ans/function_pgcrypto.ans
new file mode 100644
index 0000000..f5eba2d
--- /dev/null
+++ b/src/test/feature/UDF/ans/function_pgcrypto.ans
@@ -0,0 +1,12 @@
+-- start_ignore
+SET SEARCH_PATH=TestUDF_TestUDFPgcrypto;
+SET
+-- end_ignore
+SET search_path = public;
+SET
+SELECT crypt('abc', '123');
+     crypt     
+---------------
+ 12BWKETBcM70Q
+(1 row)
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/ans/function_pljava.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/ans/function_pljava.ans b/src/test/feature/UDF/ans/function_pljava.ans
new file mode 100644
index 0000000..e3f54d0
--- /dev/null
+++ b/src/test/feature/UDF/ans/function_pljava.ans
@@ -0,0 +1,21 @@
+-- start_ignore
+SET SEARCH_PATH=TestUDF_TestUDFPljava;
+SET
+-- end_ignore
+SELECT set_config('pljava_classpath', 'PLJavaAdd.jar', false);
+  set_config   
+---------------
+ PLJavaAdd.jar
+(1 row)
+
+CREATE OR REPLACE FUNCTION pljava_add(x INT, y INT)
+RETURNS INT
+AS 'PLJavaAdd.add'
+LANGUAGE java;
+CREATE FUNCTION
+SELECT pljava_add(10, 20);
+ pljava_add 
+------------
+         30
+(1 row)
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/ans/function_pljavau.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/ans/function_pljavau.ans b/src/test/feature/UDF/ans/function_pljavau.ans
new file mode 100644
index 0000000..7e1f556
--- /dev/null
+++ b/src/test/feature/UDF/ans/function_pljavau.ans
@@ -0,0 +1,21 @@
+-- start_ignore
+SET SEARCH_PATH=TestUDF_TestUDFPljavau;
+SET
+-- end_ignore
+SELECT set_config('pljava_classpath', 'PLJavauAdd.jar', false);
+   set_config   
+----------------
+ PLJavauAdd.jar
+(1 row)
+
+CREATE OR REPLACE FUNCTION pljavau_add(x INT, y INT)
+RETURNS INT
+AS 'PLJavauAdd.add'
+LANGUAGE javau;
+CREATE FUNCTION
+SELECT pljavau_add(10, 20);
+ pljavau_add 
+-------------
+          30
+(1 row)
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/ans/function_plperl.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/ans/function_plperl.ans b/src/test/feature/UDF/ans/function_plperl.ans
new file mode 100644
index 0000000..d39a9d1
--- /dev/null
+++ b/src/test/feature/UDF/ans/function_plperl.ans
@@ -0,0 +1,35 @@
+-- start_ignore
+SET SEARCH_PATH=TestUDF_TestUDFPlperl;
+SET
+-- end_ignore
+CREATE OR REPLACE FUNCTION plperl_max (INTEGER, INTEGER)
+RETURNS INTEGER
+AS $$
+    my ($x, $y) = @_;
+    if (not defined $x) {
+        return undef if not defined $y;
+        return $y;
+    }
+    return $x if not defined $y;
+    return $x if $x > $y;
+    return $y;
+$$ LANGUAGE plperl;
+CREATE FUNCTION
+SELECT plperl_max(1, 10);
+ plperl_max 
+------------
+         10
+(1 row)
+
+CREATE OR REPLACE FUNCTION plperl_returns_array()
+RETURNS TEXT[][]
+AS $$
+    return [['a"b','c,d'],['e\\f','g']];
+$$ LANGUAGE plperl;
+CREATE FUNCTION
+SELECT plperl_returns_array();
+    plperl_returns_array     
+-----------------------------
+ {{"a\"b","c,d"},{"e\\f",g}}
+(1 row)
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/ans/function_plperlu.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/ans/function_plperlu.ans b/src/test/feature/UDF/ans/function_plperlu.ans
new file mode 100644
index 0000000..5319f95
--- /dev/null
+++ b/src/test/feature/UDF/ans/function_plperlu.ans
@@ -0,0 +1,35 @@
+-- start_ignore
+SET SEARCH_PATH=TestUDF_TestUDFPlperlu;
+SET
+-- end_ignore
+CREATE OR REPLACE FUNCTION plperlu_max (INTEGER, INTEGER)
+RETURNS INTEGER
+AS $$
+    my ($x, $y) = @_;
+    if (not defined $x) {
+        return undef if not defined $y;
+        return $y;
+    }
+    return $x if not defined $y;
+    return $x if $x > $y;
+    return $y;
+$$ LANGUAGE plperlu;
+CREATE FUNCTION
+SELECT plperlu_max(1, 10);
+ plperlu_max 
+-------------
+          10
+(1 row)
+
+CREATE OR REPLACE FUNCTION plperlu_returns_array()
+RETURNS TEXT[][]
+AS $$
+    return [['a"b','c,d'],['e\\f','g']];
+$$ LANGUAGE plperlu;
+CREATE FUNCTION
+SELECT plperlu_returns_array();
+    plperlu_returns_array    
+-----------------------------
+ {{"a\"b","c,d"},{"e\\f",g}}
+(1 row)
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/ans/function_plpgsql.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/ans/function_plpgsql.ans b/src/test/feature/UDF/ans/function_plpgsql.ans
new file mode 100644
index 0000000..23396b6
--- /dev/null
+++ b/src/test/feature/UDF/ans/function_plpgsql.ans
@@ -0,0 +1,18 @@
+-- start_ignore
+SET SEARCH_PATH=TestUDF_TestUDFPlpgsql;
+SET
+-- end_ignore
+CREATE OR REPLACE FUNCTION plpgsql_increment(i INTEGER)
+RETURNS INTEGER
+AS $$
+    BEGIN
+        RETURN i + 1;
+    END;
+$$ LANGUAGE plpgsql;
+CREATE FUNCTION
+SELECT plpgsql_increment(6);
+ plpgsql_increment 
+-------------------
+                 7
+(1 row)
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/ans/function_plpythonu.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/ans/function_plpythonu.ans b/src/test/feature/UDF/ans/function_plpythonu.ans
new file mode 100644
index 0000000..f1e9846
--- /dev/null
+++ b/src/test/feature/UDF/ans/function_plpythonu.ans
@@ -0,0 +1,18 @@
+-- start_ignore
+SET SEARCH_PATH=TestUDF_TestUDFPlpythonu;
+SET
+-- end_ignore
+CREATE OR REPLACE FUNCTION plpythonu_max (a INTEGER, b INTEGER)
+RETURNS INTEGER
+AS $$
+  if a > b:
+    return a
+  return b
+$$ LANGUAGE plpythonu;
+CREATE FUNCTION
+SELECT plpythonu_max(1, 10);
+ plpythonu_max 
+---------------
+            10
+(1 row)
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/ans/function_plr.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/ans/function_plr.ans b/src/test/feature/UDF/ans/function_plr.ans
new file mode 100644
index 0000000..424bd39
--- /dev/null
+++ b/src/test/feature/UDF/ans/function_plr.ans
@@ -0,0 +1,20 @@
+-- start_ignore
+SET SEARCH_PATH=TestUDF_TestUDFPlr;
+SET
+-- end_ignore
+CREATE OR REPLACE FUNCTION r_max (INTEGER, INTEGER)
+RETURNS INTEGER
+AS $$
+	if (arg1 > arg2)
+		return(arg1)
+	else
+		return(arg2)
+$$
+LANGUAGE plr STRICT;
+CREATE FUNCTION
+SELECT r_max(1, 10);
+ r_max 
+-------
+    10
+(1 row)
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/ans/function_sql.ans
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/ans/function_sql.ans b/src/test/feature/UDF/ans/function_sql.ans
new file mode 100644
index 0000000..c521db0
--- /dev/null
+++ b/src/test/feature/UDF/ans/function_sql.ans
@@ -0,0 +1,24 @@
+-- start_ignore
+SET SEARCH_PATH=TestUDF_TestUDFSql;
+SET
+-- end_ignore
+CREATE OR REPLACE FUNCTION sql_add(INTEGER, INTEGER)
+RETURNS INTEGER
+AS $$
+    SELECT $1 + $2;
+$$ LANGUAGE SQL;
+CREATE FUNCTION
+SELECT sql_add(1, 2);
+ sql_add 
+---------
+       3
+(1 row)
+
+CREATE OR REPLACE FUNCTION sql_add_invalid(x INTEGER, y INTEGER)
+RETURNS INTEGER
+AS $$
+    SELECT x + y;
+$$ LANGUAGE SQL;
+psql:/tmp/TestUDF_TestUDFSql.sql:16: ERROR:  column "x" does not exist
+LINE 4:     SELECT x + y;
+                   ^

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/lib/function.c
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/lib/function.c b/src/test/feature/UDF/lib/function.c
index f346855..d9a842b 100755
--- a/src/test/feature/UDF/lib/function.c
+++ b/src/test/feature/UDF/lib/function.c
@@ -36,7 +36,7 @@ extern Datum autoinc(PG_FUNCTION_ARGS);
 extern Datum funny_dup17(PG_FUNCTION_ARGS);
 extern Datum ttdummy(PG_FUNCTION_ARGS);
 extern Datum set_ttdummy(PG_FUNCTION_ARGS);
-
+extern Datum c_add(PG_FUNCTION_ARGS);
 
 #ifdef PG_MODULE_MAGIC
 PG_MODULE_MAGIC;
@@ -1243,3 +1243,13 @@ Datum set_ttdummy(PG_FUNCTION_ARGS)
 
 	PG_RETURN_INT32(1);
 }
+
+PG_FUNCTION_INFO_V1(c_add);
+Datum c_add(PG_FUNCTION_ARGS)
+{
+	int32 x = PG_GETARG_INT32(0);
+	int32 y = PG_GETARG_INT32(1);
+
+	PG_RETURN_INT32(x+y);
+}
+

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/PLJavaAdd.jar
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/PLJavaAdd.jar b/src/test/feature/UDF/sql/PLJavaAdd.jar
new file mode 100644
index 0000000..1041373
Binary files /dev/null and b/src/test/feature/UDF/sql/PLJavaAdd.jar differ

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/PLJavaAdd.java
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/PLJavaAdd.java b/src/test/feature/UDF/sql/PLJavaAdd.java
new file mode 100644
index 0000000..2267821
--- /dev/null
+++ b/src/test/feature/UDF/sql/PLJavaAdd.java
@@ -0,0 +1,7 @@
+public class PLJavaAdd
+{
+	static int add(int x, int y)
+	{
+		return (x+y);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/PLJavauAdd.jar
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/PLJavauAdd.jar b/src/test/feature/UDF/sql/PLJavauAdd.jar
new file mode 100644
index 0000000..fafff6b
Binary files /dev/null and b/src/test/feature/UDF/sql/PLJavauAdd.jar differ

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/PLJavauAdd.java
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/PLJavauAdd.java b/src/test/feature/UDF/sql/PLJavauAdd.java
new file mode 100644
index 0000000..eceffe8
--- /dev/null
+++ b/src/test/feature/UDF/sql/PLJavauAdd.java
@@ -0,0 +1,7 @@
+public class PLJavauAdd
+{
+	static int add(int x, int y)
+	{
+		return (x+y);
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/function_c.sql.source
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/function_c.sql.source b/src/test/feature/UDF/sql/function_c.sql.source
new file mode 100644
index 0000000..f9c6433
--- /dev/null
+++ b/src/test/feature/UDF/sql/function_c.sql.source
@@ -0,0 +1,6 @@
+CREATE OR REPLACE FUNCTION c_add(x INT, y INT)
+RETURNS INT
+AS '@SHARE_LIBRARY_PATH@', 'c_add'
+LANGUAGE C IMMUTABLE STRICT;
+
+SELECT c_add(20, 30);

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/function_internal.sql
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/function_internal.sql b/src/test/feature/UDF/sql/function_internal.sql
new file mode 100644
index 0000000..b0299be
--- /dev/null
+++ b/src/test/feature/UDF/sql/function_internal.sql
@@ -0,0 +1,7 @@
+CREATE OR REPLACE FUNCTION internal_sqrt(DOUBLE PRECISION)
+RETURNS DOUBLE PRECISION
+AS 'dsqrt'
+LANGUAGE internal
+STRICT;
+
+SELECT internal_sqrt(25.0);

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/function_pgcrypto.sql
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/function_pgcrypto.sql b/src/test/feature/UDF/sql/function_pgcrypto.sql
new file mode 100644
index 0000000..4cdf188
--- /dev/null
+++ b/src/test/feature/UDF/sql/function_pgcrypto.sql
@@ -0,0 +1,2 @@
+SET search_path = public;
+SELECT crypt('abc', '123');

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/function_pljava.sql
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/function_pljava.sql b/src/test/feature/UDF/sql/function_pljava.sql
new file mode 100644
index 0000000..5730228
--- /dev/null
+++ b/src/test/feature/UDF/sql/function_pljava.sql
@@ -0,0 +1,8 @@
+SELECT set_config('pljava_classpath', 'PLJavaAdd.jar', false);
+
+CREATE OR REPLACE FUNCTION pljava_add(x INT, y INT)
+RETURNS INT
+AS 'PLJavaAdd.add'
+LANGUAGE java;
+
+SELECT pljava_add(10, 20);

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/function_pljavau.sql
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/function_pljavau.sql b/src/test/feature/UDF/sql/function_pljavau.sql
new file mode 100644
index 0000000..0e594c4
--- /dev/null
+++ b/src/test/feature/UDF/sql/function_pljavau.sql
@@ -0,0 +1,8 @@
+SELECT set_config('pljava_classpath', 'PLJavauAdd.jar', false);
+
+CREATE OR REPLACE FUNCTION pljavau_add(x INT, y INT)
+RETURNS INT
+AS 'PLJavauAdd.add'
+LANGUAGE javau;
+
+SELECT pljavau_add(10, 20);

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/function_plperl.sql
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/function_plperl.sql b/src/test/feature/UDF/sql/function_plperl.sql
new file mode 100644
index 0000000..35c8ba3
--- /dev/null
+++ b/src/test/feature/UDF/sql/function_plperl.sql
@@ -0,0 +1,22 @@
+CREATE OR REPLACE FUNCTION plperl_max (INTEGER, INTEGER)
+RETURNS INTEGER
+AS $$
+    my ($x, $y) = @_;
+    if (not defined $x) {
+        return undef if not defined $y;
+        return $y;
+    }
+    return $x if not defined $y;
+    return $x if $x > $y;
+    return $y;
+$$ LANGUAGE plperl;
+
+SELECT plperl_max(1, 10);
+
+CREATE OR REPLACE FUNCTION plperl_returns_array()
+RETURNS TEXT[][]
+AS $$
+    return [['a"b','c,d'],['e\\f','g']];
+$$ LANGUAGE plperl;
+
+SELECT plperl_returns_array();

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/function_plperlu.sql
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/function_plperlu.sql b/src/test/feature/UDF/sql/function_plperlu.sql
new file mode 100644
index 0000000..a710843
--- /dev/null
+++ b/src/test/feature/UDF/sql/function_plperlu.sql
@@ -0,0 +1,22 @@
+CREATE OR REPLACE FUNCTION plperlu_max (INTEGER, INTEGER)
+RETURNS INTEGER
+AS $$
+    my ($x, $y) = @_;
+    if (not defined $x) {
+        return undef if not defined $y;
+        return $y;
+    }
+    return $x if not defined $y;
+    return $x if $x > $y;
+    return $y;
+$$ LANGUAGE plperlu;
+
+SELECT plperlu_max(1, 10);
+
+CREATE OR REPLACE FUNCTION plperlu_returns_array()
+RETURNS TEXT[][]
+AS $$
+    return [['a"b','c,d'],['e\\f','g']];
+$$ LANGUAGE plperlu;
+
+SELECT plperlu_returns_array();

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/function_plpgsql.sql
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/function_plpgsql.sql b/src/test/feature/UDF/sql/function_plpgsql.sql
new file mode 100644
index 0000000..80f8d75
--- /dev/null
+++ b/src/test/feature/UDF/sql/function_plpgsql.sql
@@ -0,0 +1,9 @@
+CREATE OR REPLACE FUNCTION plpgsql_increment(i INTEGER)
+RETURNS INTEGER
+AS $$
+    BEGIN
+        RETURN i + 1;
+    END;
+$$ LANGUAGE plpgsql;
+
+SELECT plpgsql_increment(6);

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/function_plpythonu.sql
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/function_plpythonu.sql b/src/test/feature/UDF/sql/function_plpythonu.sql
new file mode 100644
index 0000000..8c883ab
--- /dev/null
+++ b/src/test/feature/UDF/sql/function_plpythonu.sql
@@ -0,0 +1,9 @@
+CREATE OR REPLACE FUNCTION plpythonu_max (a INTEGER, b INTEGER)
+RETURNS INTEGER
+AS $$
+  if a > b:
+    return a
+  return b
+$$ LANGUAGE plpythonu;
+
+SELECT plpythonu_max(1, 10);

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/function_plr.sql
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/function_plr.sql b/src/test/feature/UDF/sql/function_plr.sql
new file mode 100644
index 0000000..cb6bbce
--- /dev/null
+++ b/src/test/feature/UDF/sql/function_plr.sql
@@ -0,0 +1,11 @@
+CREATE OR REPLACE FUNCTION r_max (INTEGER, INTEGER)
+RETURNS INTEGER
+AS $$
+	if (arg1 > arg2)
+		return(arg1)
+	else
+		return(arg2)
+$$
+LANGUAGE plr STRICT;
+
+SELECT r_max(1, 10);

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/UDF/sql/function_sql.sql
----------------------------------------------------------------------
diff --git a/src/test/feature/UDF/sql/function_sql.sql b/src/test/feature/UDF/sql/function_sql.sql
new file mode 100644
index 0000000..f2c885f
--- /dev/null
+++ b/src/test/feature/UDF/sql/function_sql.sql
@@ -0,0 +1,13 @@
+CREATE OR REPLACE FUNCTION sql_add(INTEGER, INTEGER)
+RETURNS INTEGER
+AS $$
+    SELECT $1 + $2;
+$$ LANGUAGE SQL;
+
+SELECT sql_add(1, 2);
+
+CREATE OR REPLACE FUNCTION sql_add_invalid(x INTEGER, y INTEGER)
+RETURNS INTEGER
+AS $$
+    SELECT x + y;
+$$ LANGUAGE SQL;

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/lib/hawq_scp.cpp
----------------------------------------------------------------------
diff --git a/src/test/feature/lib/hawq_scp.cpp b/src/test/feature/lib/hawq_scp.cpp
new file mode 100644
index 0000000..8af4c60
--- /dev/null
+++ b/src/test/feature/lib/hawq_scp.cpp
@@ -0,0 +1,24 @@
+#include "command.h"
+#include "sql_util.h"
+#include "hawq_scp.h"
+
+using std::string;
+
+namespace hawq {
+namespace test {
+
+bool HAWQScp::copy(const string& host_list, const string& src_file, const string& dst_dir)
+{
+	Command cmd("hawq scp " + host_list + " " + src_file + " =:" + dst_dir);
+	if (cmd.run().getResultStatus() == 0)
+	{
+		return true;
+	}
+	else
+	{
+		return false;
+	}
+}
+
+} // namespace test
+} // namespace hawq

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/lib/hawq_scp.h
----------------------------------------------------------------------
diff --git a/src/test/feature/lib/hawq_scp.h b/src/test/feature/lib/hawq_scp.h
new file mode 100644
index 0000000..5f3eed5
--- /dev/null
+++ b/src/test/feature/lib/hawq_scp.h
@@ -0,0 +1,23 @@
+#ifndef SRC_TEST_FEATURE_LIB_HAWQ_SCP_H_
+#define SRC_TEST_FEATURE_LIB_HAWQ_SCP_H_
+
+#include <string>
+
+namespace hawq {
+namespace test {
+
+class HAWQScp
+{
+public:
+	HAWQScp() = default;
+	~HAWQScp() = default;
+	HAWQScp(const HAWQScp&) = delete;
+	HAWQScp& operator=(const HAWQScp&) = delete;
+
+	bool copy(const std::string& host_list, const std::string& src_file, const std::string& dst_dir);
+};
+
+} // namespace test
+} // namespace hawq
+
+#endif   // SRC_TEST_FEATURE_LIB_HAWQ_SCP_H_

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/lib/sql_util.cpp
----------------------------------------------------------------------
diff --git a/src/test/feature/lib/sql_util.cpp b/src/test/feature/lib/sql_util.cpp
index c11e519..36f33a7 100644
--- a/src/test/feature/lib/sql_util.cpp
+++ b/src/test/feature/lib/sql_util.cpp
@@ -158,6 +158,27 @@ void SQLUtility::execSQLFile(const string &sqlFile,
   }
 }
 
+bool SQLUtility::execSQLFile(const string &sqlFile) {
+  // do precheck for sqlFile
+  if (hawq::test::startsWith(sqlFile, "/"))
+    return false;
+
+  // double check to avoid empty fileBaseName
+  FilePath fp = splitFilePath(sqlFile);
+  if (fp.fileBaseName.empty())
+    return false;
+
+  // outFile is located in the same folder with ansFile
+  string outFileAbsPath = "/tmp/" + fp.fileBaseName + ".out";
+
+  // generate new sql file with set search_path added at the begining
+  const string newSqlFile = generateSQLFile(sqlFile);
+
+  // run sql file and store its result in output file
+  conn->setOutputFile(outFileAbsPath);
+  return conn->runSQLFile(newSqlFile).getLastStatus() == 0 ? true : false;
+}
+
 const string SQLUtility::generateSQLFile(const string &sqlFile) {
   const string originSqlFile = testRootPath + "/" + sqlFile;
   const string newSqlFile = "/tmp/" + string(test_info->test_case_name()) + "_" + test_info->name() + ".sql";
@@ -230,6 +251,18 @@ std::string SQLUtility::getGUCValue(const std::string &guc) {
   return row[0];
 }
 
+std::string SQLUtility::getQueryResult(const std::string &query) {
+  const hawq::test::PSQLQueryResult &result = executeQuery(query);
+  EXPECT_LE(result.rowCount(), 1);
+  std::string value;
+  if (result.rowCount() == 1)
+  {
+    value = result.getRows()[0][0];
+  }
+
+  return value;
+}
+
 FilePath SQLUtility::splitFilePath(const string &filePath) const {
   FilePath fp;
   size_t found1 = filePath.find_last_of("/");

http://git-wip-us.apache.org/repos/asf/incubator-hawq/blob/7ecf59aa/src/test/feature/lib/sql_util.h
----------------------------------------------------------------------
diff --git a/src/test/feature/lib/sql_util.h b/src/test/feature/lib/sql_util.h
index 6e8439a..8f8a6df 100644
--- a/src/test/feature/lib/sql_util.h
+++ b/src/test/feature/lib/sql_util.h
@@ -64,6 +64,11 @@ class SQLUtility {
   // @return void
   void execSQLFile(const std::string &sqlFile, const std::string &ansFile, const std::string &initFile = "");
 
+  // Execute sql file and check its return status
+  // @param sqlFile The given sqlFile which is relative path to test root dir
+  // @return true if the sql file is executed successfully, false otherwise
+  bool execSQLFile(const std::string &sqlFile);
+
   // Get PSQL connection: do not suggest to use
   // @return PSQL raw pointer
   const hawq::test::PSQL *getPSQL() const;
@@ -77,6 +82,11 @@ class SQLUtility {
   // Get GUC value
   std::string getGUCValue(const std::string &guc);
 
+  // execute given query and return query result
+  // @param query the given query
+  // @return the query result
+  std::string getQueryResult(const std::string &query);
+
   // execute expect error message
   // @param sql the given sql command
   // @param errmsg the expected sql error message