Index: src/docsrc/help/help.csv
===================================================================
--- src/docsrc/help/help.csv	(revision 4381)
+++ src/docsrc/help/help.csv	(working copy)
@@ -2883,6 +2883,15 @@
 CONCAT(NAME, '!')
 "
 
+"Functions (String)","CONCAT_WS","
+CONCAT_WS(string, string, string [,...])
+","
+Combines strings with separator.
+This method returns a string.
+","
+CONCAT_WS(',', NAME, '!')
+"
+
 "Functions (String)","DIFFERENCE","
 DIFFERENCE(string, string)
 ","
Index: src/main/org/h2/expression/Function.java
===================================================================
--- src/main/org/h2/expression/Function.java	(revision 4381)
+++ src/main/org/h2/expression/Function.java	(working copy)
@@ -81,7 +81,8 @@
             OCTET_LENGTH = 64, RAWTOHEX = 65, REPEAT = 66, REPLACE = 67, RIGHT = 68, RTRIM = 69, SOUNDEX = 70,
             SPACE = 71, SUBSTR = 72, SUBSTRING = 73, UCASE = 74, LOWER = 75, UPPER = 76, POSITION = 77, TRIM = 78,
             STRINGENCODE = 79, STRINGDECODE = 80, STRINGTOUTF8 = 81, UTF8TOSTRING = 82, XMLATTR = 83, XMLNODE = 84,
-            XMLCOMMENT = 85, XMLCDATA = 86, XMLSTARTDOC = 87, XMLTEXT = 88, REGEXP_REPLACE = 89, RPAD = 90, LPAD = 91;
+            XMLCOMMENT = 85, XMLCDATA = 86, XMLSTARTDOC = 87, XMLTEXT = 88, REGEXP_REPLACE = 89, RPAD = 90, LPAD = 91,
+            CONCAT_WS = 92;
 
     public static final int CURDATE = 100, CURTIME = 101, DATE_ADD = 102, DATE_DIFF = 103, DAY_NAME = 104,
             DAY_OF_MONTH = 105, DAY_OF_WEEK = 106, DAY_OF_YEAR = 107, HOUR = 108, MINUTE = 109, MONTH = 110, MONTH_NAME = 111,
@@ -221,6 +222,7 @@
         // same as CHAR_LENGTH
         addFunction("CHARACTER_LENGTH", CHAR_LENGTH, 1, Value.INT);
         addFunctionWithNull("CONCAT", CONCAT, VAR_ARGS, Value.STRING);
+        addFunctionWithNull("CONCAT_WS", CONCAT_WS, VAR_ARGS, Value.STRING);
         addFunction("DIFFERENCE", DIFFERENCE, 2, Value.INT);
         addFunction("HEXTORAW", HEXTORAW, 1, Value.STRING);
         addFunctionWithNull("INSERT", INSERT, 4, Value.STRING);
@@ -570,9 +572,16 @@
         case OCTET_LENGTH:
             result = ValueLong.get(2 * length(v0));
             break;
+        case CONCAT_WS:
         case CONCAT: {
             result = ValueNull.INSTANCE;
-            for (int i = 0; i < args.length; i++) {
+            int start = 0;
+            String separator = "";
+            if(info.type == CONCAT_WS){
+                start = 1;
+                separator = getNullOrValue(session, args, values, 0).getString();
+            }
+            for (int i = start; i < args.length; i++) {
                 Value v = getNullOrValue(session, args, values, i);
                 if (v == ValueNull.INSTANCE) {
                     continue;
@@ -580,7 +589,16 @@
                 if (result == ValueNull.INSTANCE) {
                     result = v;
                 } else {
-                    result = ValueString.get(result.getString().concat(v.getString()));
+                    String tmp = v.getString();
+                    if(!StringUtils.isNullOrEmpty(separator) && !StringUtils.isNullOrEmpty(tmp)){
+                        tmp = separator.concat(tmp);
+                    }
+                    result = ValueString.get(result.getString().concat(tmp));
+                }
+            }
+            if(info.type == CONCAT_WS){
+                if(separator != null && result == ValueNull.INSTANCE){
+                    result = ValueString.get("");
                 }
             }
             break;
@@ -1682,6 +1700,7 @@
             break;
         case CASE:
         case CONCAT:
+        case CONCAT_WS:
         case CSVWRITE:
             min = 2;
             break;
Index: src/main/org/h2/res/help.csv
===================================================================
--- src/main/org/h2/res/help.csv	(revision 4381)
+++ src/main/org/h2/res/help.csv	(working copy)
@@ -1015,6 +1015,10 @@
 CONCAT(string, string [,...])
 ","
 Combines strings."
+"Functions (String)","CONCAT_WS","
+CONCAT_WS(string, string, string [,...])
+","
+Combines strings with separator."
 "Functions (String)","DIFFERENCE","
 DIFFERENCE(string, string)
 ","
Index: src/test/org/h2/test/db/TestFunctions.java
===================================================================
--- src/test/org/h2/test/db/TestFunctions.java	(revision 4381)
+++ src/test/org/h2/test/db/TestFunctions.java	(working copy)
@@ -74,6 +74,7 @@
         testFileRead();
         testValue();
         testNvl2();
+        testConcatWs();
         deleteDb("functions");
         FileUtils.deleteRecursive(TEMP_DIR, true);
     }
@@ -148,6 +149,45 @@
         conn.close();
     }
 
+    private void testConcatWs() throws SQLException {
+        Connection conn = getConnection("functions");
+        Statement stat = conn.createStatement();
+
+        String createSQL = "CREATE TABLE testConcat(id BIGINT, txt1 varchar, txt2 varchar, txt3 varchar);";
+        stat.execute(createSQL);
+        stat.execute("insert into testConcat(id, txt1, txt2, txt3) values(1, 'test1', 'test2', 'test3')");
+        stat.execute("insert into testConcat(id, txt1, txt2, txt3) values(2, 'test1', 'test2', null)");
+        stat.execute("insert into testConcat(id, txt1, txt2, txt3) values(3, 'test1', null, null)");
+        stat.execute("insert into testConcat(id, txt1, txt2, txt3) values(4, null, 'test2', null)");
+        stat.execute("insert into testConcat(id, txt1, txt2, txt3) values(5, null, null, null)");
+
+        String query = "SELECT concat_ws('_',txt1, txt2, txt3), txt1 FROM testConcat order by id asc";
+        ResultSet rs = stat.executeQuery(query);
+        rs.next();
+        String actual = rs.getString(1);
+        assertEquals("test1_test2_test3", actual);
+        rs.next();
+        actual = rs.getString(1);
+        assertEquals("test1_test2", actual);
+        rs.next();
+        actual = rs.getString(1);
+        assertEquals("test1", actual);
+        rs.next();
+        actual = rs.getString(1);
+        assertEquals("test2", actual);
+        rs.next();
+        actual = rs.getString(1);
+        assertEquals("", actual);
+        rs.close();
+
+        rs = stat.executeQuery("select concat_ws(null,null,null)");
+        rs.next();
+        assertNull(rs.getObject(1));
+
+        stat.execute("drop table testConcat");
+        conn.close();
+    }
+
     private void testValue() throws SQLException {
         Connection conn = getConnection("functions");
         Statement stat = conn.createStatement();
