@ -51,7 +51,7 @@ typedef struct varlena VarString;
typedef struct
{
bool is_multibyte ; /* T if multibyte encoding */
bool is_multibyte_char_in_char ;
bool is_multibyte_char_in_char ; /* need to check char boundaries? */
char * str1 ; /* haystack string */
char * str2 ; /* needle string */
@ -1439,8 +1439,7 @@ text_position_next_internal(char *start_ptr, TextPositionState *state)
/*
* Return a pointer to the current match .
*
* The returned pointer points into correct position in the original
* the haystack string .
* The returned pointer points into the original haystack string .
*/
static char *
text_position_get_match_ptr ( TextPositionState * state )
@ -1471,12 +1470,27 @@ text_position_get_match_pos(TextPositionState *state)
}
}
/*
* Reset search state to the initial state installed by text_position_setup .
*
* The next call to text_position_next will search from the beginning
* of the string .
*/
static void
text_position_reset ( TextPositionState * state )
{
state - > last_match = NULL ;
state - > refpoint = state - > str1 ;
state - > refpos = 0 ;
}
static void
text_position_cleanup ( TextPositionState * state )
{
/* no cleanup needed */
}
static void
check_collation_set ( Oid collid )
{
@ -4581,9 +4595,8 @@ replace_text_regexp(text *src_text, void *regexp,
/*
* split_part
* parse input string
* return ord item ( 1 based )
* based on provided field separator
* parse input string based on provided field separator
* return N ' th item ( 1 based , negative counts from end )
*/
Datum
split_part ( PG_FUNCTION_ARGS )
@ -4600,10 +4613,10 @@ split_part(PG_FUNCTION_ARGS)
bool found ;
/* field number is 1 based */
if ( fldnum < 1 )
if ( fldnum = = 0 )
ereport ( ERROR ,
( errcode ( ERRCODE_INVALID_PARAMETER_VALUE ) ,
errmsg ( " field position must be greater than zero " ) ) ) ;
errmsg ( " field position must not be zero " ) ) ) ;
inputstring_len = VARSIZE_ANY_EXHDR ( inputstring ) ;
fldsep_len = VARSIZE_ANY_EXHDR ( fldsep ) ;
@ -4612,32 +4625,72 @@ split_part(PG_FUNCTION_ARGS)
if ( inputstring_len < 1 )
PG_RETURN_TEXT_P ( cstring_to_text ( " " ) ) ;
/* empty field separator */
/* handle empty field separator */
if ( fldsep_len < 1 )
{
/* if first field, return input string, else empty string */
if ( fldnum = = 1 )
/* if first or last field, return input string, else empty string */
if ( fldnum = = 1 | | fldnum = = - 1 )
PG_RETURN_TEXT_P ( inputstring ) ;
else
PG_RETURN_TEXT_P ( cstring_to_text ( " " ) ) ;
}
/* find the first field separator */
text_position_setup ( inputstring , fldsep , PG_GET_COLLATION ( ) , & state ) ;
/* identify bounds of first field */
start_ptr = VARDATA_ANY ( inputstring ) ;
found = text_position_next ( & state ) ;
/* special case if fldsep not found at all */
if ( ! found )
{
text_position_cleanup ( & state ) ;
/* if field 1 requeste d, return input string, else empty string */
if ( fldnum = = 1 )
/* if first or last fiel d, return input string, else empty string */
if ( fldnum = = 1 | | fldnum = = - 1 )
PG_RETURN_TEXT_P ( inputstring ) ;
else
PG_RETURN_TEXT_P ( cstring_to_text ( " " ) ) ;
}
/*
* take care of a negative field number ( i . e . count from the right ) by
* converting to a positive field number ; we need total number of fields
*/
if ( fldnum < 0 )
{
/* we found a fldsep, so there are at least two fields */
int numfields = 2 ;
while ( text_position_next ( & state ) )
numfields + + ;
/* special case of last field does not require an extra pass */
if ( fldnum = = - 1 )
{
start_ptr = text_position_get_match_ptr ( & state ) + fldsep_len ;
end_ptr = VARDATA_ANY ( inputstring ) + inputstring_len ;
text_position_cleanup ( & state ) ;
PG_RETURN_TEXT_P ( cstring_to_text_with_len ( start_ptr ,
end_ptr - start_ptr ) ) ;
}
/* else, convert fldnum to positive notation */
fldnum + = numfields + 1 ;
/* if nonexistent field, return empty string */
if ( fldnum < = 0 )
{
text_position_cleanup ( & state ) ;
PG_RETURN_TEXT_P ( cstring_to_text ( " " ) ) ;
}
/* reset to pointing at first match, but now with positive fldnum */
text_position_reset ( & state ) ;
found = text_position_next ( & state ) ;
Assert ( found ) ;
}
/* identify bounds of first field */
start_ptr = VARDATA_ANY ( inputstring ) ;
end_ptr = text_position_get_match_ptr ( & state ) ;
while ( found & & - - fldnum > 0 )