diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index 57b6f7aaa2ab9205e78c014284be83868844f408..de6ba6165041c3cb4f71b72113fcb11b43d2f2e7 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.525 2010/08/08 19:15:27 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.526 2010/08/10 21:51:00 tgl Exp $ -->
 
  <chapter id="functions">
   <title>Functions and Operators</title>
@@ -9736,13 +9736,14 @@ SELECT NULLIF(value, '(none)') ...
        <row>
         <entry>
          <literal>
-          <function>array_to_string</function>(<type>anyarray</type>, <type>text</type>)
+          <function>array_to_string</function>(<type>anyarray</type>, <type>text</type> <optional>, <type>text</type></optional>)
          </literal>
         </entry>
         <entry><type>text</type></entry>
-        <entry>concatenates array elements using supplied delimiter</entry>
-        <entry><literal>array_to_string(ARRAY[1, 2, 3], '~^~')</literal></entry>
-        <entry><literal>1~^~2~^~3</literal></entry>
+        <entry>concatenates array elements using supplied delimiter and
+         optional null string</entry>
+        <entry><literal>array_to_string(ARRAY[1, 2, 3, NULL, 5], ',', '*')</literal></entry>
+        <entry><literal>1,2,3,*,5</literal></entry>
        </row>
        <row>
         <entry>
@@ -9758,13 +9759,14 @@ SELECT NULLIF(value, '(none)') ...
        <row>
         <entry>
          <literal>
-          <function>string_to_array</function>(<type>text</type>, <type>text</type>)
+          <function>string_to_array</function>(<type>text</type>, <type>text</type> <optional>, <type>text</type></optional>)
          </literal>
         </entry>
         <entry><type>text[]</type></entry>
-        <entry>splits string into array elements using supplied delimiter</entry>
-        <entry><literal>string_to_array('xx~^~yy~^~zz', '~^~')</literal></entry>
-        <entry><literal>{xx,yy,zz}</literal></entry>
+        <entry>splits string into array elements using supplied delimiter and
+         optional null string</entry>
+        <entry><literal>string_to_array('xx~^~yy~^~zz', '~^~', 'yy')</literal></entry>
+        <entry><literal>{xx,NULL,zz}</literal></entry>
        </row>
        <row>
         <entry>
@@ -9781,6 +9783,34 @@ SELECT NULLIF(value, '(none)') ...
      </tgroup>
     </table>
 
+   <para>
+    In <function>string_to_array</function>, if the delimiter parameter is
+    NULL, each character in the input string will become a separate element in
+    the resulting array.  If the delimiter is an empty string, then the entire
+    input string is returned as a one-element array.  Otherwise the input
+    string is split at each occurrence of the delimiter string.
+   </para>
+
+   <para>
+    In <function>string_to_array</function>, if the null-string parameter
+    is omitted or NULL, none of the substrings of the input will be replaced
+    by NULL.
+    In <function>array_to_string</function>, if the null-string parameter
+    is omitted or NULL, any null elements in the array are simply skipped
+    and not represented in the output string.
+   </para>
+
+   <note>
+    <para>
+     There are two differences in the behavior of <function>string_to_array</>
+     from pre-9.1 versions of <productname>PostgreSQL</>.
+     First, it will return an empty (zero-element) array rather than NULL when
+     the input string is of zero length.  Second, if the delimiter string is
+     NULL, the function splits the input into individual characters, rather
+     than returning NULL as before.
+    </para>
+   </note>
+
    <para>
     See also <xref linkend="functions-aggregate"> about the aggregate
     function <function>array_agg</function> for use with arrays.
diff --git a/src/backend/utils/adt/array_userfuncs.c b/src/backend/utils/adt/array_userfuncs.c
index bca0b894422a8d731daa1df34f835a35a1edccd7..0c916149ca4e2b9cf84fdf2388ef5eb1a5c7a685 100644
--- a/src/backend/utils/adt/array_userfuncs.c
+++ b/src/backend/utils/adt/array_userfuncs.c
@@ -6,7 +6,7 @@
  * Copyright (c) 2003-2010, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.35 2010/02/26 02:01:06 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/array_userfuncs.c,v 1.36 2010/08/10 21:51:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -407,9 +407,11 @@ ArrayType *
 create_singleton_array(FunctionCallInfo fcinfo,
 					   Oid element_type,
 					   Datum element,
+					   bool isNull,
 					   int ndims)
 {
 	Datum		dvalues[1];
+	bool		nulls[1];
 	int16		typlen;
 	bool		typbyval;
 	char		typalign;
@@ -429,6 +431,7 @@ create_singleton_array(FunctionCallInfo fcinfo,
 						ndims, MAXDIM)));
 
 	dvalues[0] = element;
+	nulls[0] = isNull;
 
 	for (i = 0; i < ndims; i++)
 	{
@@ -462,7 +465,7 @@ create_singleton_array(FunctionCallInfo fcinfo,
 	typbyval = my_extra->typbyval;
 	typalign = my_extra->typalign;
 
-	return construct_md_array(dvalues, NULL, ndims, dims, lbs, element_type,
+	return construct_md_array(dvalues, nulls, ndims, dims, lbs, element_type,
 							  typlen, typbyval, typalign);
 }
 
diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c
index e9f9f597ec79a583a30ebd685d638528064d1cb0..1ad4667d63356a77b1b49241c982bda5e67028cc 100644
--- a/src/backend/utils/adt/varlena.c
+++ b/src/backend/utils/adt/varlena.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.178 2010/08/05 18:21:17 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.179 2010/08/10 21:51:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -75,6 +75,10 @@ static bytea *bytea_substring(Datum str,
 static bytea *bytea_overlay(bytea *t1, bytea *t2, int sp, int sl);
 static StringInfo makeStringAggState(FunctionCallInfo fcinfo);
 
+static Datum text_to_array_internal(PG_FUNCTION_ARGS);
+static text *array_to_text_internal(FunctionCallInfo fcinfo, ArrayType *v,
+									char *fldsep, char *null_string);
+
 
 /*****************************************************************************
  *	 CONVERSION ROUTINES EXPORTED FOR USE BY C CODE							 *
@@ -2964,98 +2968,204 @@ split_text(PG_FUNCTION_ARGS)
 	PG_RETURN_TEXT_P(result_text);
 }
 
+/*
+ * Convenience function to return true when two text params are equal.
+ */
+static bool
+text_isequal(text *txt1, text *txt2)
+{
+	return DatumGetBool(DirectFunctionCall2(texteq,
+											PointerGetDatum(txt1),
+											PointerGetDatum(txt2)));
+}
+
 /*
  * text_to_array
- * parse input string
- * return text array of elements
+ * parse input string and return text array of elements,
  * based on provided field separator
  */
 Datum
 text_to_array(PG_FUNCTION_ARGS)
 {
-	text	   *inputstring = PG_GETARG_TEXT_PP(0);
-	text	   *fldsep = PG_GETARG_TEXT_PP(1);
+	return text_to_array_internal(fcinfo);
+}
+
+/*
+ * text_to_array_null
+ * parse input string and return text array of elements,
+ * based on provided field separator and null string
+ *
+ * This is a separate entry point only to prevent the regression tests from
+ * complaining about different argument sets for the same internal function.
+ */
+Datum
+text_to_array_null(PG_FUNCTION_ARGS)
+{
+	return text_to_array_internal(fcinfo);
+}
+
+/*
+ * common code for text_to_array and text_to_array_null functions
+ *
+ * These are not strict so we have to test for null inputs explicitly.
+ */
+static Datum
+text_to_array_internal(PG_FUNCTION_ARGS)
+{
+	text	   *inputstring;
+	text	   *fldsep;
+	text	   *null_string;
 	int			inputstring_len;
 	int			fldsep_len;
-	TextPositionState state;
-	int			fldnum;
-	int			start_posn;
-	int			end_posn;
-	int			chunk_len;
 	char	   *start_ptr;
 	text	   *result_text;
+	bool		is_null;
 	ArrayBuildState *astate = NULL;
 
-	text_position_setup(inputstring, fldsep, &state);
-
-	/*
-	 * Note: we check the converted string length, not the original, because
-	 * they could be different if the input contained invalid encoding.
-	 */
-	inputstring_len = state.len1;
-	fldsep_len = state.len2;
-
-	/* return NULL for empty input string */
-	if (inputstring_len < 1)
-	{
-		text_position_cleanup(&state);
+	/* when input string is NULL, then result is NULL too */
+	if (PG_ARGISNULL(0))
 		PG_RETURN_NULL();
-	}
 
-	/*
-	 * empty field separator return one element, 1D, array using the input
-	 * string
-	 */
-	if (fldsep_len < 1)
-	{
-		text_position_cleanup(&state);
-		PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, TEXTOID,
-										   PointerGetDatum(inputstring), 1));
-	}
+	inputstring = PG_GETARG_TEXT_PP(0);
 
-	start_posn = 1;
-	/* start_ptr points to the start_posn'th character of inputstring */
-	start_ptr = VARDATA_ANY(inputstring);
+	/* fldsep can be NULL */
+	if (!PG_ARGISNULL(1))
+		fldsep = PG_GETARG_TEXT_PP(1);
+	else
+		fldsep = NULL;
+
+	/* null_string can be NULL or omitted */
+	if (PG_NARGS() > 2 && !PG_ARGISNULL(2))
+		null_string = PG_GETARG_TEXT_PP(2);
+	else
+		null_string = NULL;
 
-	for (fldnum = 1;; fldnum++) /* field number is 1 based */
+	if (fldsep != NULL)
 	{
-		CHECK_FOR_INTERRUPTS();
+		/*
+		 * Normal case with non-null fldsep.  Use the text_position machinery
+		 * to search for occurrences of fldsep.
+		 */
+		TextPositionState state;
+		int			fldnum;
+		int			start_posn;
+		int			end_posn;
+		int			chunk_len;
+		
+		text_position_setup(inputstring, fldsep, &state);
 
-		end_posn = text_position_next(start_posn, &state);
+		/*
+		 * Note: we check the converted string length, not the original,
+		 * because they could be different if the input contained invalid
+		 * encoding.
+		 */
+		inputstring_len = state.len1;
+		fldsep_len = state.len2;
 
-		if (end_posn == 0)
+		/* return empty array for empty input string */
+		if (inputstring_len < 1)
 		{
-			/* fetch last field */
-			chunk_len = ((char *) inputstring + VARSIZE_ANY(inputstring)) - start_ptr;
+			text_position_cleanup(&state);
+			PG_RETURN_ARRAYTYPE_P(construct_empty_array(TEXTOID));
 		}
-		else
+
+		/*
+		 * empty field separator: return the input string as a one-element
+		 * array
+		 */
+		if (fldsep_len < 1)
 		{
-			/* fetch non-last field */
-			chunk_len = charlen_to_bytelen(start_ptr, end_posn - start_posn);
+			text_position_cleanup(&state);
+			/* single element can be a NULL too */
+			is_null = null_string ? text_isequal(inputstring, null_string) : false;
+			PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, TEXTOID,
+														 PointerGetDatum(inputstring),
+														 is_null, 1));
 		}
+		
+		start_posn = 1;
+		/* start_ptr points to the start_posn'th character of inputstring */
+		start_ptr = VARDATA_ANY(inputstring);
+
+		for (fldnum = 1;; fldnum++) /* field number is 1 based */
+		{
+			CHECK_FOR_INTERRUPTS();
 
-		/* must build a temp text datum to pass to accumArrayResult */
-		result_text = cstring_to_text_with_len(start_ptr, chunk_len);
+			end_posn = text_position_next(start_posn, &state);
 
-		/* stash away this field */
-		astate = accumArrayResult(astate,
-								  PointerGetDatum(result_text),
-								  false,
-								  TEXTOID,
-								  CurrentMemoryContext);
+			if (end_posn == 0)
+			{
+				/* fetch last field */
+				chunk_len = ((char *) inputstring + VARSIZE_ANY(inputstring)) - start_ptr;
+			}
+			else
+			{
+				/* fetch non-last field */
+				chunk_len = charlen_to_bytelen(start_ptr, end_posn - start_posn);
+			}
 
-		pfree(result_text);
+			/* must build a temp text datum to pass to accumArrayResult */
+			result_text = cstring_to_text_with_len(start_ptr, chunk_len);
+			is_null = null_string ? text_isequal(result_text, null_string) : false;
+		
+			/* stash away this field */
+			astate = accumArrayResult(astate,
+									  PointerGetDatum(result_text),
+									  is_null,
+									  TEXTOID,
+									  CurrentMemoryContext);
 
-		if (end_posn == 0)
-			break;
+			pfree(result_text);
 
-		start_posn = end_posn;
-		start_ptr += chunk_len;
-		start_posn += fldsep_len;
-		start_ptr += charlen_to_bytelen(start_ptr, fldsep_len);
+			if (end_posn == 0)
+				break;
+
+			start_posn = end_posn;
+			start_ptr += chunk_len;
+			start_posn += fldsep_len;
+			start_ptr += charlen_to_bytelen(start_ptr, fldsep_len);
+		}
+
+		text_position_cleanup(&state);
 	}
+	else
+	{
+		/* 
+		 * When fldsep is NULL, each character in the inputstring becomes an
+		 * element in the result array.  The separator is effectively the space
+		 * between characters.
+		 */
+		inputstring_len = VARSIZE_ANY_EXHDR(inputstring);
+		
+		/* return empty array for empty input string */
+		if (inputstring_len < 1)
+			PG_RETURN_ARRAYTYPE_P(construct_empty_array(TEXTOID));
+		
+		start_ptr = VARDATA_ANY(inputstring);
+		
+		while (inputstring_len > 0)
+		{
+			int		chunk_len = pg_mblen(start_ptr);
 
-	text_position_cleanup(&state);
+			CHECK_FOR_INTERRUPTS();
+
+			/* must build a temp text datum to pass to accumArrayResult */
+			result_text = cstring_to_text_with_len(start_ptr, chunk_len);
+			is_null = null_string ? text_isequal(result_text, null_string) : false;
+		
+			/* stash away this field */
+			astate = accumArrayResult(astate,
+									  PointerGetDatum(result_text),
+									  is_null,
+									  TEXTOID,
+									  CurrentMemoryContext);
+
+			pfree(result_text);
+
+			start_ptr += chunk_len;
+			inputstring_len -= chunk_len;
+		}
+	}
 
 	PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate,
 										  CurrentMemoryContext));
@@ -3071,6 +3181,48 @@ array_to_text(PG_FUNCTION_ARGS)
 {
 	ArrayType  *v = PG_GETARG_ARRAYTYPE_P(0);
 	char	   *fldsep = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+	PG_RETURN_TEXT_P(array_to_text_internal(fcinfo, v, fldsep, NULL));
+}
+
+/*
+ * array_to_text_null
+ * concatenate Cstring representation of input array elements
+ * using provided field separator and null string
+ *
+ * This version is not strict so we have to test for null inputs explicitly.
+ */
+Datum
+array_to_text_null(PG_FUNCTION_ARGS)
+{
+	ArrayType  *v;
+	char	   *fldsep;
+	char	   *null_string;
+
+	/* returns NULL when first or second parameter is NULL */
+	if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
+		PG_RETURN_NULL();
+	
+	v = PG_GETARG_ARRAYTYPE_P(0);
+	fldsep = text_to_cstring(PG_GETARG_TEXT_PP(1));
+
+	/* NULL null string is passed through as a null pointer */
+	if (!PG_ARGISNULL(2))
+		null_string = text_to_cstring(PG_GETARG_TEXT_PP(2));
+	else
+		null_string = NULL;
+
+	PG_RETURN_TEXT_P(array_to_text_internal(fcinfo, v, fldsep, null_string));
+}
+
+/*
+ * common code for array_to_text and array_to_text_null functions
+ */
+static text *
+array_to_text_internal(FunctionCallInfo fcinfo, ArrayType *v,
+					   char *fldsep, char *null_string)
+{
+	text	   *result;
 	int			nitems,
 			   *dims,
 				ndims;
@@ -3092,7 +3244,7 @@ array_to_text(PG_FUNCTION_ARGS)
 
 	/* if there are no elements, return an empty string */
 	if (nitems == 0)
-		PG_RETURN_TEXT_P(cstring_to_text(""));
+		return cstring_to_text_with_len("", 0);
 
 	element_type = ARR_ELEMTYPE(v);
 	initStringInfo(&buf);
@@ -3140,7 +3292,15 @@ array_to_text(PG_FUNCTION_ARGS)
 		/* Get source element, checking for NULL */
 		if (bitmap && (*bitmap & bitmask) == 0)
 		{
-			/* we ignore nulls */
+			/* if null_string is NULL, we just ignore null elements */
+			if (null_string != NULL)
+			{
+				if (printed)
+					appendStringInfo(&buf, "%s%s", fldsep, null_string);
+				else
+					appendStringInfoString(&buf, null_string);
+				printed = true;
+			}
 		}
 		else
 		{
@@ -3169,8 +3329,11 @@ array_to_text(PG_FUNCTION_ARGS)
 			}
 		}
 	}
+	
+	result = cstring_to_text_with_len(buf.data, buf.len);
+	pfree(buf.data);
 
-	PG_RETURN_TEXT_P(cstring_to_text_with_len(buf.data, buf.len));
+	return result;
 }
 
 #define HEXBASE 16
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index b4aeacb217e1c19a1a76945dcae358ab62c993b9..a7739db82d72c6b54d67727001ff629640605757 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.593 2010/08/08 19:15:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.594 2010/08/10 21:51:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	201008081
+#define CATALOG_VERSION_NO	201008101
 
 #endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 812c65cb0455a80488f887f53d6d70092001d81c..0ba9435b0afb2a3e70f3926b2f63be1ae4305049 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.577 2010/08/08 19:15:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.578 2010/08/10 21:51:00 tgl Exp $
  *
  * NOTES
  *	  The script catalog/genbki.pl reads this file and generates .bki
@@ -1018,10 +1018,14 @@ DATA(insert OID = 379 (  array_prepend	   PGNSP PGUID 12 1 0 0 f f f f f i 2 0 2
 DESCR("prepend element onto front of array");
 DATA(insert OID = 383 (  array_cat		   PGNSP PGUID 12 1 0 0 f f f f f i 2 0 2277 "2277 2277" _null_ _null_ _null_ _null_ array_cat _null_ _null_ _null_ ));
 DESCR("concatenate two arrays");
-DATA(insert OID = 394 (  string_to_array   PGNSP PGUID 12 1 0 0 f f f t f i 2 0 1009 "25 25" _null_ _null_ _null_ _null_ text_to_array _null_ _null_ _null_ ));
+DATA(insert OID = 394 (  string_to_array   PGNSP PGUID 12 1 0 0 f f f f f i 2 0 1009 "25 25" _null_ _null_ _null_ _null_ text_to_array _null_ _null_ _null_ ));
 DESCR("split delimited text into text[]");
 DATA(insert OID = 395 (  array_to_string   PGNSP PGUID 12 1 0 0 f f f t f s 2 0 25 "2277 25" _null_ _null_ _null_ _null_ array_to_text _null_ _null_ _null_ ));
 DESCR("concatenate array elements, using delimiter, into text");
+DATA(insert OID = 376 (  string_to_array   PGNSP PGUID 12 1 0 0 f f f f f i 3 0 1009 "25 25 25" _null_ _null_ _null_ _null_ text_to_array_null _null_ _null_ _null_ ));
+DESCR("split delimited text into text[], with null string");
+DATA(insert OID = 384 (  array_to_string   PGNSP PGUID 12 1 0 0 f f f f f s 3 0 25 "2277 25 25" _null_ _null_ _null_ _null_ array_to_text_null _null_ _null_ _null_ ));
+DESCR("concatenate array elements, using delimiter and null string, into text");
 DATA(insert OID = 515 (  array_larger	   PGNSP PGUID 12 1 0 0 f f f t f i 2 0 2277 "2277 2277" _null_ _null_ _null_ _null_ array_larger _null_ _null_ _null_ ));
 DESCR("larger of two");
 DATA(insert OID = 516 (  array_smaller	   PGNSP PGUID 12 1 0 0 f f f t f i 2 0 2277 "2277 2277" _null_ _null_ _null_ _null_ array_smaller _null_ _null_ _null_ ));
diff --git a/src/include/utils/array.h b/src/include/utils/array.h
index 02e882761aa99bb05cc7660a5cc6b5155a8dc056..ca9f16c4d9c9c604e4e094fd586f801111250dd2 100644
--- a/src/include/utils/array.h
+++ b/src/include/utils/array.h
@@ -49,7 +49,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/array.h,v 1.77 2010/01/02 16:58:09 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/array.h,v 1.78 2010/08/10 21:51:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -274,6 +274,7 @@ extern Datum array_cat(PG_FUNCTION_ARGS);
 extern ArrayType *create_singleton_array(FunctionCallInfo fcinfo,
 					   Oid element_type,
 					   Datum element,
+					   bool isNull,
 					   int ndims);
 
 extern Datum array_agg_transfn(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 4ba866453c5073758ab7ddae0872389cef0bf549..258a37494303214b7e5a984fa50ac6cbf0d92f77 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.353 2010/08/05 18:21:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.354 2010/08/10 21:51:00 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -716,6 +716,8 @@ extern text *replace_text_regexp(text *src_text, void *regexp,
 extern Datum split_text(PG_FUNCTION_ARGS);
 extern Datum text_to_array(PG_FUNCTION_ARGS);
 extern Datum array_to_text(PG_FUNCTION_ARGS);
+extern Datum text_to_array_null(PG_FUNCTION_ARGS);
+extern Datum array_to_text_null(PG_FUNCTION_ARGS);
 extern Datum to_hex32(PG_FUNCTION_ARGS);
 extern Datum to_hex64(PG_FUNCTION_ARGS);
 extern Datum md5_text(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/arrays.out b/src/test/regress/expected/arrays.out
index 3ab18be9a79c634287d08dee9c2394476fbb1e88..eff5f88c24c355574649d99f9e8b24f2fd9a5f22 100644
--- a/src/test/regress/expected/arrays.out
+++ b/src/test/regress/expected/arrays.out
@@ -1055,21 +1055,99 @@ select string_to_array('1|2|3', '');
 select string_to_array('', '|');
  string_to_array 
 -----------------
- 
+ {}
 (1 row)
 
 select string_to_array('1|2|3', NULL);
  string_to_array 
 -----------------
- 
+ {1,|,2,|,3}
+(1 row)
+
+select string_to_array(NULL, '|') IS NULL;
+ ?column? 
+----------
+ t
 (1 row)
 
-select string_to_array(NULL, '|');
+select string_to_array('abc', '');
  string_to_array 
 -----------------
+ {abc}
+(1 row)
+
+select string_to_array('abc', '', 'abc');
+ string_to_array 
+-----------------
+ {NULL}
+(1 row)
+
+select string_to_array('abc', ',');
+ string_to_array 
+-----------------
+ {abc}
+(1 row)
+
+select string_to_array('abc', ',', 'abc');
+ string_to_array 
+-----------------
+ {NULL}
+(1 row)
+
+select string_to_array('1,2,3,4,,6', ',');
+ string_to_array 
+-----------------
+ {1,2,3,4,"",6}
+(1 row)
+
+select string_to_array('1,2,3,4,,6', ',', '');
+ string_to_array  
+------------------
+ {1,2,3,4,NULL,6}
+(1 row)
+
+select string_to_array('1,2,3,4,*,6', ',', '*');
+ string_to_array  
+------------------
+ {1,2,3,4,NULL,6}
+(1 row)
+
+select array_to_string(NULL::int4[], ',') IS NULL;
+ ?column? 
+----------
+ t
+(1 row)
+
+select array_to_string('{}'::int4[], ',');
+ array_to_string 
+-----------------
  
 (1 row)
 
+select array_to_string(array[1,2,3,4,NULL,6], ',');
+ array_to_string 
+-----------------
+ 1,2,3,4,6
+(1 row)
+
+select array_to_string(array[1,2,3,4,NULL,6], ',', '*');
+ array_to_string 
+-----------------
+ 1,2,3,4,*,6
+(1 row)
+
+select array_to_string(array[1,2,3,4,NULL,6], NULL);
+ array_to_string 
+-----------------
+ 
+(1 row)
+
+select array_to_string(array[1,2,3,4,NULL,6], ',', NULL);
+ array_to_string 
+-----------------
+ 1,2,3,4,6
+(1 row)
+
 select array_to_string(string_to_array('1|2|3', '|'), '|');
  array_to_string 
 -----------------
diff --git a/src/test/regress/sql/arrays.sql b/src/test/regress/sql/arrays.sql
index f65bc452e2e734e515f7664f4f4c0af4ff8fa829..a75b8c4d2dd2253f739da050aa035678003dae8b 100644
--- a/src/test/regress/sql/arrays.sql
+++ b/src/test/regress/sql/arrays.sql
@@ -383,7 +383,21 @@ select string_to_array('1||2|3||', '||');
 select string_to_array('1|2|3', '');
 select string_to_array('', '|');
 select string_to_array('1|2|3', NULL);
-select string_to_array(NULL, '|');
+select string_to_array(NULL, '|') IS NULL;
+select string_to_array('abc', '');
+select string_to_array('abc', '', 'abc');
+select string_to_array('abc', ',');
+select string_to_array('abc', ',', 'abc');
+select string_to_array('1,2,3,4,,6', ',');
+select string_to_array('1,2,3,4,,6', ',', '');
+select string_to_array('1,2,3,4,*,6', ',', '*');
+
+select array_to_string(NULL::int4[], ',') IS NULL;
+select array_to_string('{}'::int4[], ',');
+select array_to_string(array[1,2,3,4,NULL,6], ',');
+select array_to_string(array[1,2,3,4,NULL,6], ',', '*');
+select array_to_string(array[1,2,3,4,NULL,6], NULL);
+select array_to_string(array[1,2,3,4,NULL,6], ',', NULL);
 
 select array_to_string(string_to_array('1|2|3', '|'), '|');