*** ./doc/src/sgml/func.sgml.orig 2010-04-07 08:12:52.000000000 +0200 --- ./doc/src/sgml/func.sgml 2010-05-05 20:36:31.692244426 +0200 *************** *** 4639,4645 **** ! If case-independent matching is specified, the effect is much as if all case distinctions had vanished from the alphabet. When an alphabetic that exists in multiple cases appears as an --- 4639,4645 ---- ! If case-independent matching is specified, the effect is much as if all case distinctions had vanished from the alphabet. When an alphabetic that exists in multiple cases appears as an *************** *** 9501,9506 **** --- 9501,9512 ---- string_to_array + to_array + + + to_string + + unnest *************** *** 9643,9648 **** --- 9649,9676 ---- + to_array(text, text , text) + + + text[] + splits string into array elements using supplied delimiter and null string + to_array('1,2,3,,5', ',') + {1,2,3,4,NULL,5} + + + + + to_string(anyarray, text , text) + + + text + concatenates array elements using supplied delimiter and null string + to_string(ARRAY[1, 2, 3, NULL, 5], ',', '*') + 1,2,3,*,5 + + + + unnest(anyarray) *** ./src/backend/catalog/system_views.sql.orig 2010-04-26 16:22:37.000000000 +0200 --- ./src/backend/catalog/system_views.sql 2010-05-05 19:59:05.256243744 +0200 *************** *** 487,489 **** --- 487,497 ---- CREATE OR REPLACE FUNCTION pg_start_backup(label text, fast boolean DEFAULT false) RETURNS text STRICT VOLATILE LANGUAGE internal AS 'pg_start_backup'; + + CREATE OR REPLACE FUNCTION + to_string(v anyarray, fldsep text, null_string text DEFAULT '') + RETURNS text STRICT IMMUTABLE LANGUAGE internal AS 'to_string'; + + CREATE OR REPLACE FUNCTION + to_array(inputstr text, fldsep text, null_string text DEFAULT '') + RETURNS text[] STRICT IMMUTABLE LANGUAGE internal AS 'to_array'; *** ./src/backend/utils/adt/array_userfuncs.c.orig 2010-02-26 03:01:06.000000000 +0100 --- ./src/backend/utils/adt/array_userfuncs.c 2010-05-05 19:15:45.898243688 +0200 *************** *** 407,415 **** --- 407,417 ---- 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,434 **** --- 431,437 ---- ndims, MAXDIM))); dvalues[0] = element; + nulls[0] = isNull; for (i = 0; i < ndims; i++) { *************** *** 462,468 **** typbyval = my_extra->typbyval; typalign = my_extra->typalign; ! return construct_md_array(dvalues, NULL, ndims, dims, lbs, element_type, typlen, typbyval, typalign); } --- 465,471 ---- typbyval = my_extra->typbyval; typalign = my_extra->typalign; ! return construct_md_array(dvalues, nulls, ndims, dims, lbs, element_type, typlen, typbyval, typalign); } *** ./src/backend/utils/adt/varlena.c.orig 2010-02-26 03:01:10.000000000 +0100 --- ./src/backend/utils/adt/varlena.c 2010-05-05 20:17:53.657243603 +0200 *************** *** 2965,2980 **** } /* ! * text_to_array ! * parse input string ! * 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); int inputstring_len; int fldsep_len; TextPositionState state; --- 2965,2986 ---- } /* ! * Returns true when two text params are same. */ ! static ! bool text_isequal(text *txt1, text *txt2) ! { ! return DatumGetBool(DirectFunctionCall2(texteq, ! PointerGetDatum(txt1), ! PointerGetDatum(txt2))); ! } ! ! /* ! * common code for text_to_array and to_array functions ! */ ! static Datum ! _text_to_array(FunctionCallInfo fcinfo, text *inputstring, text *fldsep, text *null_string, bool *isNull) { int inputstring_len; int fldsep_len; TextPositionState state; *************** *** 2985,2993 **** char *start_ptr; text *result_text; 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. --- 2991,3000 ---- char *start_ptr; text *result_text; ArrayBuildState *astate = NULL; + bool is_null_string; 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. *************** *** 2999,3005 **** if (inputstring_len < 1) { text_position_cleanup(&state); ! PG_RETURN_NULL(); } /* --- 3006,3013 ---- if (inputstring_len < 1) { text_position_cleanup(&state); ! *isNull = true; ! return (Datum) 0; } /* *************** *** 3009,3016 **** if (fldsep_len < 1) { text_position_cleanup(&state); ! PG_RETURN_ARRAYTYPE_P(create_singleton_array(fcinfo, TEXTOID, ! PointerGetDatum(inputstring), 1)); } start_posn = 1; --- 3017,3026 ---- if (fldsep_len < 1) { text_position_cleanup(&state); ! is_null_string = null_string != NULL ? text_isequal(null_string, inputstring) : false; ! *isNull = false; ! return (Datum) create_singleton_array(fcinfo, TEXTOID, ! PointerGetDatum(inputstring), is_null_string, 1); } start_posn = 1; *************** *** 3036,3046 **** /* must build a temp text datum to pass to accumArrayResult */ result_text = cstring_to_text_with_len(start_ptr, chunk_len); ! /* stash away this field */ astate = accumArrayResult(astate, PointerGetDatum(result_text), ! false, TEXTOID, CurrentMemoryContext); --- 3046,3057 ---- /* must build a temp text datum to pass to accumArrayResult */ result_text = cstring_to_text_with_len(start_ptr, chunk_len); ! is_null_string = null_string != NULL ? text_isequal(null_string, result_text) : false; ! /* stash away this field */ astate = accumArrayResult(astate, PointerGetDatum(result_text), ! is_null_string, TEXTOID, CurrentMemoryContext); *************** *** 3057,3076 **** text_position_cleanup(&state); ! PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, ! CurrentMemoryContext)); } /* ! * array_to_text ! * concatenate Cstring representation of input array elements ! * using provided field separator */ Datum ! array_to_text(PG_FUNCTION_ARGS) { - ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); - char *fldsep = text_to_cstring(PG_GETARG_TEXT_PP(1)); int nitems, *dims, ndims; --- 3068,3129 ---- text_position_cleanup(&state); ! *isNull = false; ! return makeArrayResult(astate, CurrentMemoryContext); } + /* ! * text_to_array ! * parse input string ! * 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); ! bool isNull; ! Datum result; ! ! result = _text_to_array(fcinfo, inputstring, fldsep, NULL, &isNull); ! ! if (isNull) ! PG_RETURN_NULL(); ! else ! PG_RETURN_ARRAYTYPE_P(result); ! } ! ! /* ! * to_array ! * Parse string, returns array. string defined as nullsym is replaced by NULL. ! * Default value for nullsym is empty string. ! */ ! Datum ! to_array(PG_FUNCTION_ARGS) ! { ! text *inputstring = PG_GETARG_TEXT_PP(0); ! text *fldsep = PG_GETARG_TEXT_PP(1); ! text *null_string = PG_GETARG_TEXT_PP(2); ! bool isNull; ! Datum result; ! ! result = _text_to_array(fcinfo, inputstring, fldsep, null_string, &isNull); ! ! if (isNull) ! PG_RETURN_NULL(); ! else ! PG_RETURN_ARRAYTYPE_P(result); ! } ! ! /* ! * common code for array_to_text and to_string function. null_string can be ! * NULL (only for array_to_text function). ! */ ! static text * ! _array_to_text(FunctionCallInfo fcinfo, ArrayType *v, char *fldsep, char *null_string) { int nitems, *dims, ndims; *************** *** 3092,3098 **** /* if there are no elements, return an empty string */ if (nitems == 0) ! PG_RETURN_TEXT_P(cstring_to_text("")); element_type = ARR_ELEMTYPE(v); initStringInfo(&buf); --- 3145,3151 ---- /* if there are no elements, return an empty string */ if (nitems == 0) ! return cstring_to_text(""); element_type = ARR_ELEMTYPE(v); initStringInfo(&buf); *************** *** 3140,3146 **** /* Get source element, checking for NULL */ if (bitmap && (*bitmap & bitmask) == 0) { ! /* we ignore nulls */ } else { --- 3193,3207 ---- /* Get source element, checking for NULL */ if (bitmap && (*bitmap & bitmask) == 0) { ! /* we ignore nulls, when null_string isn't defined (is NULL) */ ! if (null_string != NULL) ! { ! if (printed) ! appendStringInfo(&buf, "%s%s", fldsep, null_string); ! else ! appendStringInfoString(&buf, null_string); ! printed = true; ! } } else { *************** *** 3170,3178 **** } } ! PG_RETURN_TEXT_P(cstring_to_text_with_len(buf.data, buf.len)); } #define HEXBASE 16 /* * Convert a int32 to a string containing a base 16 (hex) representation of --- 3231,3269 ---- } } ! return cstring_to_text_with_len(buf.data, buf.len); } + /* + * array_to_text + * concatenate Cstring representation of input array elements + * using provided field separator + */ + Datum + 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(fcinfo, v, fldsep, NULL)); + } + + /* + * to_string + * concatenate Cstring representation of input array elements + * using provided field separator and null string + */ + Datum + to_string(PG_FUNCTION_ARGS) + { + ArrayType *v = PG_GETARG_ARRAYTYPE_P(0); + char *fldsep = text_to_cstring(PG_GETARG_TEXT_PP(1)); + char *null_string = text_to_cstring(PG_GETARG_TEXT_PP(2)); + + PG_RETURN_TEXT_P(_array_to_text(fcinfo, v, fldsep, null_string)); + } + + #define HEXBASE 16 /* * Convert a int32 to a string containing a base 16 (hex) representation of *** ./src/include/catalog/pg_proc.h.orig 2010-02-26 03:01:21.000000000 +0100 --- ./src/include/catalog/pg_proc.h 2010-05-05 19:41:37.518244240 +0200 *************** *** 1022,1027 **** --- 1022,1031 ---- DESCR("split delimited text into text[]"); DATA(insert OID = 395 ( array_to_string PGNSP PGUID 12 1 0 0 f f f t f i 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 = 950 ( to_array PGNSP PGUID 12 1 0 0 f f f t f i 3 0 1009 "25 25 25" _null_ _null_ _null_ _null_ to_array _null_ _null_ _null_ )); + DESCR("split delimited text into text[], possible to set null string"); + DATA(insert OID = 951 ( to_string PGNSP PGUID 12 1 0 0 f f f t f i 3 0 25 "2277 25 25" _null_ _null_ _null_ _null_ to_string _null_ _null_ _null_ )); + DESCR("concatenate array elements, using delimiter, into text, possible to set null string"); 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_ )); *** ./src/include/utils/array.h.orig 2010-01-02 17:58:09.000000000 +0100 --- ./src/include/utils/array.h 2010-05-05 18:02:44.191119209 +0200 *************** *** 274,279 **** --- 274,280 ---- extern ArrayType *create_singleton_array(FunctionCallInfo fcinfo, Oid element_type, Datum element, + bool isNull, int ndims); extern Datum array_agg_transfn(PG_FUNCTION_ARGS); *** ./src/include/utils/builtins.h.orig 2010-02-26 03:01:28.000000000 +0100 --- ./src/include/utils/builtins.h 2010-05-05 18:36:03.468243638 +0200 *************** *** 714,719 **** --- 714,721 ---- 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 to_array(PG_FUNCTION_ARGS); + extern Datum to_string(PG_FUNCTION_ARGS); extern Datum to_hex32(PG_FUNCTION_ARGS); extern Datum to_hex64(PG_FUNCTION_ARGS); extern Datum md5_text(PG_FUNCTION_ARGS); *** ./src/test/regress/expected/arrays.out.orig 2010-02-18 19:41:47.000000000 +0100 --- ./src/test/regress/expected/arrays.out 2010-05-05 20:19:26.000000000 +0200 *************** *** 1208,1210 **** --- 1208,1265 ---- [5:5]={"(42,43)"} (1 row) + -- check to_string and to_array functions + select to_array('abc',''); + to_array + ---------- + {abc} + (1 row) + + select to_array('abc','','abc'); + to_array + ---------- + {NULL} + (1 row) + + select to_array('abc',','); + to_array + ---------- + {abc} + (1 row) + + select to_array('abc',',','abc'); + to_array + ---------- + {NULL} + (1 row) + + select to_array('1,2,3,4,,6',','); + to_array + ------------------ + {1,2,3,4,NULL,6} + (1 row) + + select to_array('1,2,3,4,,6',',',''); + to_array + ------------------ + {1,2,3,4,NULL,6} + (1 row) + + select to_array('1,2,3,4,*,6',',','*'); + to_array + ------------------ + {1,2,3,4,NULL,6} + (1 row) + + select to_string(array[1,2,3,4,NULL,6],','); + to_string + ------------ + 1,2,3,4,,6 + (1 row) + + select to_string(array[1,2,3,4,NULL,6],',','*'); + to_string + ------------- + 1,2,3,4,*,6 + (1 row) + *** ./src/test/regress/sql/arrays.sql.orig 2010-02-18 19:41:47.000000000 +0100 --- ./src/test/regress/sql/arrays.sql 2010-05-05 20:13:12.194118475 +0200 *************** *** 412,414 **** --- 412,426 ---- select * from t1; update t1 set f1[5].q2 = 43; select * from t1; + + -- check to_string and to_array functions + + select to_array('abc',''); + select to_array('abc','','abc'); + select to_array('abc',','); + select to_array('abc',',','abc'); + select to_array('1,2,3,4,,6',','); + select to_array('1,2,3,4,,6',',',''); + select to_array('1,2,3,4,*,6',',','*'); + select to_string(array[1,2,3,4,NULL,6],','); + select to_string(array[1,2,3,4,NULL,6],',','*');