#include "postgres.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "regex/regex.h"
#include "utils/array.h"
#include "utils/builtins.h"
Go to the source code of this file.
Data Structures | |
struct | pg_re_flags |
struct | regexp_matches_ctx |
struct | cached_re_str |
Defines | |
#define | PG_GETARG_TEXT_PP_IF_EXISTS(_n) (PG_NARGS() > (_n) ? PG_GETARG_TEXT_PP(_n) : NULL) |
#define | MAX_CACHED_RES 32 |
Typedefs | |
typedef struct pg_re_flags | pg_re_flags |
typedef struct regexp_matches_ctx | regexp_matches_ctx |
typedef struct cached_re_str | cached_re_str |
Functions | |
static regexp_matches_ctx * | setup_regexp_matches (text *orig_str, text *pattern, text *flags, Oid collation, bool force_glob, bool use_subpatterns, bool ignore_degenerate) |
static void | cleanup_regexp_matches (regexp_matches_ctx *matchctx) |
static ArrayType * | build_regexp_matches_result (regexp_matches_ctx *matchctx) |
static Datum | build_regexp_split_result (regexp_matches_ctx *splitctx) |
static regex_t * | RE_compile_and_cache (text *text_re, int cflags, Oid collation) |
static bool | RE_wchar_execute (regex_t *re, pg_wchar *data, int data_len, int start_search, int nmatch, regmatch_t *pmatch) |
static bool | RE_execute (regex_t *re, char *dat, int dat_len, int nmatch, regmatch_t *pmatch) |
static bool | RE_compile_and_execute (text *text_re, char *dat, int dat_len, int cflags, Oid collation, int nmatch, regmatch_t *pmatch) |
static void | parse_re_flags (pg_re_flags *flags, text *opts) |
Datum | nameregexeq (PG_FUNCTION_ARGS) |
Datum | nameregexne (PG_FUNCTION_ARGS) |
Datum | textregexeq (PG_FUNCTION_ARGS) |
Datum | textregexne (PG_FUNCTION_ARGS) |
Datum | nameicregexeq (PG_FUNCTION_ARGS) |
Datum | nameicregexne (PG_FUNCTION_ARGS) |
Datum | texticregexeq (PG_FUNCTION_ARGS) |
Datum | texticregexne (PG_FUNCTION_ARGS) |
Datum | textregexsubstr (PG_FUNCTION_ARGS) |
Datum | textregexreplace_noopt (PG_FUNCTION_ARGS) |
Datum | textregexreplace (PG_FUNCTION_ARGS) |
Datum | similar_escape (PG_FUNCTION_ARGS) |
Datum | regexp_matches (PG_FUNCTION_ARGS) |
Datum | regexp_matches_no_flags (PG_FUNCTION_ARGS) |
Datum | regexp_split_to_table (PG_FUNCTION_ARGS) |
Datum | regexp_split_to_table_no_flags (PG_FUNCTION_ARGS) |
Datum | regexp_split_to_array (PG_FUNCTION_ARGS) |
Datum | regexp_split_to_array_no_flags (PG_FUNCTION_ARGS) |
char * | regexp_fixed_prefix (text *text_re, bool case_insensitive, Oid collation, bool *exact) |
Variables | |
static int | num_res = 0 |
static cached_re_str | re_array [MAX_CACHED_RES] |
#define MAX_CACHED_RES 32 |
Definition at line 90 of file regexp.c.
Referenced by RE_compile_and_cache().
#define PG_GETARG_TEXT_PP_IF_EXISTS | ( | _n | ) | (PG_NARGS() > (_n) ? PG_GETARG_TEXT_PP(_n) : NULL) |
Definition at line 38 of file regexp.c.
Referenced by regexp_matches(), regexp_split_to_array(), and regexp_split_to_table().
typedef struct cached_re_str cached_re_str |
typedef struct pg_re_flags pg_re_flags |
typedef struct regexp_matches_ctx regexp_matches_ctx |
static ArrayType * build_regexp_matches_result | ( | regexp_matches_ctx * | matchctx | ) | [static] |
Definition at line 999 of file regexp.c.
References construct_md_array(), DirectFunctionCall3, regexp_matches_ctx::elems, i, Int32GetDatum, regexp_matches_ctx::match_locs, regexp_matches_ctx::next_match, regexp_matches_ctx::npatterns, regexp_matches_ctx::nulls, regexp_matches_ctx::orig_str, PointerGetDatum, text_substr(), and TEXTOID.
Referenced by regexp_matches().
{ Datum *elems = matchctx->elems; bool *nulls = matchctx->nulls; int dims[1]; int lbs[1]; int loc; int i; /* Extract matching substrings from the original string */ loc = matchctx->next_match * matchctx->npatterns * 2; for (i = 0; i < matchctx->npatterns; i++) { int so = matchctx->match_locs[loc++]; int eo = matchctx->match_locs[loc++]; if (so < 0 || eo < 0) { elems[i] = (Datum) 0; nulls[i] = true; } else { elems[i] = DirectFunctionCall3(text_substr, PointerGetDatum(matchctx->orig_str), Int32GetDatum(so + 1), Int32GetDatum(eo - so)); nulls[i] = false; } } /* And form an array */ dims[0] = matchctx->npatterns; lbs[0] = 1; /* XXX: this hardcodes assumptions about the text type */ return construct_md_array(elems, nulls, 1, dims, lbs, TEXTOID, -1, false, 'i'); }
static Datum build_regexp_split_result | ( | regexp_matches_ctx * | splitctx | ) | [static] |
Definition at line 1142 of file regexp.c.
References DirectFunctionCall2, DirectFunctionCall3, elog, ERROR, Int32GetDatum, regexp_matches_ctx::match_locs, regexp_matches_ctx::next_match, regexp_matches_ctx::nmatches, regexp_matches_ctx::orig_str, PointerGetDatum, text_substr(), and text_substr_no_len().
Referenced by regexp_split_to_array(), and regexp_split_to_table().
{ int startpos; int endpos; if (splitctx->next_match > 0) startpos = splitctx->match_locs[splitctx->next_match * 2 - 1]; else startpos = 0; if (startpos < 0) elog(ERROR, "invalid match ending position"); if (splitctx->next_match < splitctx->nmatches) { endpos = splitctx->match_locs[splitctx->next_match * 2]; if (endpos < startpos) elog(ERROR, "invalid match starting position"); return DirectFunctionCall3(text_substr, PointerGetDatum(splitctx->orig_str), Int32GetDatum(startpos + 1), Int32GetDatum(endpos - startpos)); } else { /* no more matches, return rest of string */ return DirectFunctionCall2(text_substr_no_len, PointerGetDatum(splitctx->orig_str), Int32GetDatum(startpos + 1)); } }
static void cleanup_regexp_matches | ( | regexp_matches_ctx * | matchctx | ) | [static] |
Definition at line 984 of file regexp.c.
References regexp_matches_ctx::elems, regexp_matches_ctx::match_locs, regexp_matches_ctx::nulls, regexp_matches_ctx::orig_str, and pfree().
Referenced by regexp_matches(), and regexp_split_to_table().
Datum nameicregexeq | ( | PG_FUNCTION_ARGS | ) |
Definition at line 488 of file regexp.c.
References NameStr, NULL, PG_GET_COLLATION, PG_GETARG_NAME, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, RE_compile_and_execute(), REG_ADVANCED, and REG_ICASE.
{ Name n = PG_GETARG_NAME(0); text *p = PG_GETARG_TEXT_PP(1); PG_RETURN_BOOL(RE_compile_and_execute(p, NameStr(*n), strlen(NameStr(*n)), REG_ADVANCED | REG_ICASE, PG_GET_COLLATION(), 0, NULL)); }
Datum nameicregexne | ( | PG_FUNCTION_ARGS | ) |
Definition at line 502 of file regexp.c.
References NameStr, NULL, PG_GET_COLLATION, PG_GETARG_NAME, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, RE_compile_and_execute(), REG_ADVANCED, and REG_ICASE.
{ Name n = PG_GETARG_NAME(0); text *p = PG_GETARG_TEXT_PP(1); PG_RETURN_BOOL(!RE_compile_and_execute(p, NameStr(*n), strlen(NameStr(*n)), REG_ADVANCED | REG_ICASE, PG_GET_COLLATION(), 0, NULL)); }
Datum nameregexeq | ( | PG_FUNCTION_ARGS | ) |
Definition at line 425 of file regexp.c.
References NameStr, NULL, PG_GET_COLLATION, PG_GETARG_NAME, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, RE_compile_and_execute(), and REG_ADVANCED.
{ Name n = PG_GETARG_NAME(0); text *p = PG_GETARG_TEXT_PP(1); PG_RETURN_BOOL(RE_compile_and_execute(p, NameStr(*n), strlen(NameStr(*n)), REG_ADVANCED, PG_GET_COLLATION(), 0, NULL)); }
Datum nameregexne | ( | PG_FUNCTION_ARGS | ) |
Definition at line 439 of file regexp.c.
References NameStr, NULL, PG_GET_COLLATION, PG_GETARG_NAME, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, RE_compile_and_execute(), and REG_ADVANCED.
{ Name n = PG_GETARG_NAME(0); text *p = PG_GETARG_TEXT_PP(1); PG_RETURN_BOOL(!RE_compile_and_execute(p, NameStr(*n), strlen(NameStr(*n)), REG_ADVANCED, PG_GET_COLLATION(), 0, NULL)); }
static void parse_re_flags | ( | pg_re_flags * | flags, | |
text * | opts | |||
) | [static] |
Definition at line 351 of file regexp.c.
References pg_re_flags::cflags, ereport, errcode(), errmsg(), ERROR, pg_re_flags::glob, i, REG_ADVANCED, REG_EXTENDED, VARDATA_ANY, and VARSIZE_ANY_EXHDR.
Referenced by setup_regexp_matches(), and textregexreplace().
{ /* regex flavor is always folded into the compile flags */ flags->cflags = REG_ADVANCED; flags->glob = false; if (opts) { char *opt_p = VARDATA_ANY(opts); int opt_len = VARSIZE_ANY_EXHDR(opts); int i; for (i = 0; i < opt_len; i++) { switch (opt_p[i]) { case 'g': flags->glob = true; break; case 'b': /* BREs (but why???) */ flags->cflags &= ~(REG_ADVANCED | REG_EXTENDED | REG_QUOTE); break; case 'c': /* case sensitive */ flags->cflags &= ~REG_ICASE; break; case 'e': /* plain EREs */ flags->cflags |= REG_EXTENDED; flags->cflags &= ~(REG_ADVANCED | REG_QUOTE); break; case 'i': /* case insensitive */ flags->cflags |= REG_ICASE; break; case 'm': /* Perloid synonym for n */ case 'n': /* \n affects ^ $ . [^ */ flags->cflags |= REG_NEWLINE; break; case 'p': /* ~Perl, \n affects . [^ */ flags->cflags |= REG_NLSTOP; flags->cflags &= ~REG_NLANCH; break; case 'q': /* literal string */ flags->cflags |= REG_QUOTE; flags->cflags &= ~(REG_ADVANCED | REG_EXTENDED); break; case 's': /* single line, \n ordinary */ flags->cflags &= ~REG_NEWLINE; break; case 't': /* tight syntax */ flags->cflags &= ~REG_EXPANDED; break; case 'w': /* weird, \n affects ^ $ only */ flags->cflags &= ~REG_NLSTOP; flags->cflags |= REG_NLANCH; break; case 'x': /* expanded syntax */ flags->cflags |= REG_EXPANDED; break; default: ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid regexp option: \"%c\"", opt_p[i]))); break; } } } }
Definition at line 132 of file regexp.c.
References Assert, cached_re_str::cre_collation, cached_re_str::cre_flags, cached_re_str::cre_pat, cached_re_str::cre_pat_len, cached_re_str::cre_re, ereport, errcode(), errmsg(), ERROR, free, i, malloc, Max, MAX_CACHED_RES, memcmp(), memmove, NULL, num_res, palloc(), pfree(), pg_mb2wchar_with_len(), pg_regcomp(), pg_regerror(), pg_regfree(), REG_OKAY, VARDATA_ANY, and VARSIZE_ANY_EXHDR.
Referenced by RE_compile_and_execute(), regexp_fixed_prefix(), setup_regexp_matches(), textregexreplace(), textregexreplace_noopt(), and textregexsubstr().
{ int text_re_len = VARSIZE_ANY_EXHDR(text_re); char *text_re_val = VARDATA_ANY(text_re); pg_wchar *pattern; int pattern_len; int i; int regcomp_result; cached_re_str re_temp; char errMsg[100]; /* * Look for a match among previously compiled REs. Since the data * structure is self-organizing with most-used entries at the front, our * search strategy can just be to scan from the front. */ for (i = 0; i < num_res; i++) { if (re_array[i].cre_pat_len == text_re_len && re_array[i].cre_flags == cflags && re_array[i].cre_collation == collation && memcmp(re_array[i].cre_pat, text_re_val, text_re_len) == 0) { /* * Found a match; move it to front if not there already. */ if (i > 0) { re_temp = re_array[i]; memmove(&re_array[1], &re_array[0], i * sizeof(cached_re_str)); re_array[0] = re_temp; } return &re_array[0].cre_re; } } /* * Couldn't find it, so try to compile the new RE. To avoid leaking * resources on failure, we build into the re_temp local. */ /* Convert pattern string to wide characters */ pattern = (pg_wchar *) palloc((text_re_len + 1) * sizeof(pg_wchar)); pattern_len = pg_mb2wchar_with_len(text_re_val, pattern, text_re_len); regcomp_result = pg_regcomp(&re_temp.cre_re, pattern, pattern_len, cflags, collation); pfree(pattern); if (regcomp_result != REG_OKAY) { /* re didn't compile (no need for pg_regfree, if so) */ pg_regerror(regcomp_result, &re_temp.cre_re, errMsg, sizeof(errMsg)); ereport(ERROR, (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), errmsg("invalid regular expression: %s", errMsg))); } /* * We use malloc/free for the cre_pat field because the storage has to * persist across transactions, and because we want to get control back on * out-of-memory. The Max() is because some malloc implementations return * NULL for malloc(0). */ re_temp.cre_pat = malloc(Max(text_re_len, 1)); if (re_temp.cre_pat == NULL) { pg_regfree(&re_temp.cre_re); ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); } memcpy(re_temp.cre_pat, text_re_val, text_re_len); re_temp.cre_pat_len = text_re_len; re_temp.cre_flags = cflags; re_temp.cre_collation = collation; /* * Okay, we have a valid new item in re_temp; insert it into the storage * array. Discard last entry if needed. */ if (num_res >= MAX_CACHED_RES) { --num_res; Assert(num_res < MAX_CACHED_RES); pg_regfree(&re_array[num_res].cre_re); free(re_array[num_res].cre_pat); } if (num_res > 0) memmove(&re_array[1], &re_array[0], num_res * sizeof(cached_re_str)); re_array[0] = re_temp; num_res++; return &re_array[0].cre_re; }
static bool RE_compile_and_execute | ( | text * | text_re, | |
char * | dat, | |||
int | dat_len, | |||
int | cflags, | |||
Oid | collation, | |||
int | nmatch, | |||
regmatch_t * | pmatch | |||
) | [static] |
Definition at line 328 of file regexp.c.
References RE_compile_and_cache(), and RE_execute().
Referenced by nameicregexeq(), nameicregexne(), nameregexeq(), nameregexne(), texticregexeq(), texticregexne(), textregexeq(), and textregexne().
{ regex_t *re; /* Compile RE */ re = RE_compile_and_cache(text_re, cflags, collation); return RE_execute(re, dat, dat_len, nmatch, pmatch); }
static bool RE_execute | ( | regex_t * | re, | |
char * | dat, | |||
int | dat_len, | |||
int | nmatch, | |||
regmatch_t * | pmatch | |||
) | [static] |
Definition at line 294 of file regexp.c.
References palloc(), pfree(), pg_mb2wchar_with_len(), and RE_wchar_execute().
Referenced by RE_compile_and_execute(), and textregexsubstr().
{ pg_wchar *data; int data_len; bool match; /* Convert data string to wide characters */ data = (pg_wchar *) palloc((dat_len + 1) * sizeof(pg_wchar)); data_len = pg_mb2wchar_with_len(dat, data, dat_len); /* Perform RE match and return result */ match = RE_wchar_execute(re, data, data_len, 0, nmatch, pmatch); pfree(data); return match; }
static bool RE_wchar_execute | ( | regex_t * | re, | |
pg_wchar * | data, | |||
int | data_len, | |||
int | start_search, | |||
int | nmatch, | |||
regmatch_t * | pmatch | |||
) | [static] |
Definition at line 252 of file regexp.c.
References ereport, errcode(), errmsg(), ERROR, NULL, pg_regerror(), pg_regexec(), REG_NOMATCH, and REG_OKAY.
Referenced by RE_execute(), and setup_regexp_matches().
{ int regexec_result; char errMsg[100]; /* Perform RE match and return result */ regexec_result = pg_regexec(re, data, data_len, start_search, NULL, /* no details */ nmatch, pmatch, 0); if (regexec_result != REG_OKAY && regexec_result != REG_NOMATCH) { /* re failed??? */ pg_regerror(regexec_result, re, errMsg, sizeof(errMsg)); ereport(ERROR, (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), errmsg("regular expression failed: %s", errMsg))); } return (regexec_result == REG_OKAY); }
Definition at line 1180 of file regexp.c.
References Assert, ereport, errcode(), errmsg(), ERROR, free, palloc(), pg_database_encoding_max_length(), pg_regerror(), pg_regprefix(), pg_wchar2mb_with_len(), RE_compile_and_cache(), REG_EXACT, REG_NOMATCH, and REG_PREFIX.
Referenced by regex_fixed_prefix().
{ char *result; regex_t *re; int cflags; int re_result; pg_wchar *str; size_t slen; size_t maxlen; char errMsg[100]; *exact = false; /* default result */ /* Compile RE */ cflags = REG_ADVANCED; if (case_insensitive) cflags |= REG_ICASE; re = RE_compile_and_cache(text_re, cflags, collation); /* Examine it to see if there's a fixed prefix */ re_result = pg_regprefix(re, &str, &slen); switch (re_result) { case REG_NOMATCH: return NULL; case REG_PREFIX: /* continue with wchar conversion */ break; case REG_EXACT: *exact = true; /* continue with wchar conversion */ break; default: /* re failed??? */ pg_regerror(re_result, re, errMsg, sizeof(errMsg)); ereport(ERROR, (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), errmsg("regular expression failed: %s", errMsg))); break; } /* Convert pg_wchar result back to database encoding */ maxlen = pg_database_encoding_max_length() * slen + 1; result = (char *) palloc(maxlen); slen = pg_wchar2mb_with_len(str, result, slen); Assert(slen < maxlen); free(str); return result; }
Datum regexp_matches | ( | PG_FUNCTION_ARGS | ) |
Definition at line 783 of file regexp.c.
References build_regexp_matches_result(), cleanup_regexp_matches(), regexp_matches_ctx::elems, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, regexp_matches_ctx::next_match, regexp_matches_ctx::nmatches, regexp_matches_ctx::npatterns, regexp_matches_ctx::nulls, palloc(), PG_GET_COLLATION, PG_GETARG_TEXT_P_COPY, PG_GETARG_TEXT_PP, PG_GETARG_TEXT_PP_IF_EXISTS, PointerGetDatum, setup_regexp_matches(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, and FuncCallContext::user_fctx.
Referenced by regexp_matches_no_flags().
{ FuncCallContext *funcctx; regexp_matches_ctx *matchctx; if (SRF_IS_FIRSTCALL()) { text *pattern = PG_GETARG_TEXT_PP(1); text *flags = PG_GETARG_TEXT_PP_IF_EXISTS(2); MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* be sure to copy the input string into the multi-call ctx */ matchctx = setup_regexp_matches(PG_GETARG_TEXT_P_COPY(0), pattern, flags, PG_GET_COLLATION(), false, true, false); /* Pre-create workspace that build_regexp_matches_result needs */ matchctx->elems = (Datum *) palloc(sizeof(Datum) * matchctx->npatterns); matchctx->nulls = (bool *) palloc(sizeof(bool) * matchctx->npatterns); MemoryContextSwitchTo(oldcontext); funcctx->user_fctx = (void *) matchctx; } funcctx = SRF_PERCALL_SETUP(); matchctx = (regexp_matches_ctx *) funcctx->user_fctx; if (matchctx->next_match < matchctx->nmatches) { ArrayType *result_ary; result_ary = build_regexp_matches_result(matchctx); matchctx->next_match++; SRF_RETURN_NEXT(funcctx, PointerGetDatum(result_ary)); } /* release space in multi-call ctx to avoid intraquery memory leak */ cleanup_regexp_matches(matchctx); SRF_RETURN_DONE(funcctx); }
Datum regexp_matches_no_flags | ( | PG_FUNCTION_ARGS | ) |
Definition at line 831 of file regexp.c.
References regexp_matches().
{ return regexp_matches(fcinfo); }
Datum regexp_split_to_array | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1098 of file regexp.c.
References accumArrayResult(), build_regexp_split_result(), CurrentMemoryContext, makeArrayResult(), regexp_matches_ctx::next_match, regexp_matches_ctx::nmatches, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_GETARG_TEXT_PP_IF_EXISTS, PG_RETURN_ARRAYTYPE_P, setup_regexp_matches(), and TEXTOID.
Referenced by regexp_split_to_array_no_flags().
{ ArrayBuildState *astate = NULL; regexp_matches_ctx *splitctx; splitctx = setup_regexp_matches(PG_GETARG_TEXT_PP(0), PG_GETARG_TEXT_PP(1), PG_GETARG_TEXT_PP_IF_EXISTS(2), PG_GET_COLLATION(), true, false, true); while (splitctx->next_match <= splitctx->nmatches) { astate = accumArrayResult(astate, build_regexp_split_result(splitctx), false, TEXTOID, CurrentMemoryContext); splitctx->next_match++; } /* * We don't call cleanup_regexp_matches here; it would try to pfree the * input string, which we didn't copy. The space is not in a long-lived * memory context anyway. */ PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, CurrentMemoryContext)); }
Datum regexp_split_to_array_no_flags | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1130 of file regexp.c.
References regexp_split_to_array().
{ return regexp_split_to_array(fcinfo); }
Datum regexp_split_to_table | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1044 of file regexp.c.
References build_regexp_split_result(), cleanup_regexp_matches(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, regexp_matches_ctx::next_match, regexp_matches_ctx::nmatches, PG_GET_COLLATION, PG_GETARG_TEXT_P_COPY, PG_GETARG_TEXT_PP, PG_GETARG_TEXT_PP_IF_EXISTS, setup_regexp_matches(), SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, and FuncCallContext::user_fctx.
Referenced by regexp_split_to_table_no_flags().
{ FuncCallContext *funcctx; regexp_matches_ctx *splitctx; if (SRF_IS_FIRSTCALL()) { text *pattern = PG_GETARG_TEXT_PP(1); text *flags = PG_GETARG_TEXT_PP_IF_EXISTS(2); MemoryContext oldcontext; funcctx = SRF_FIRSTCALL_INIT(); oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx); /* be sure to copy the input string into the multi-call ctx */ splitctx = setup_regexp_matches(PG_GETARG_TEXT_P_COPY(0), pattern, flags, PG_GET_COLLATION(), true, false, true); MemoryContextSwitchTo(oldcontext); funcctx->user_fctx = (void *) splitctx; } funcctx = SRF_PERCALL_SETUP(); splitctx = (regexp_matches_ctx *) funcctx->user_fctx; if (splitctx->next_match <= splitctx->nmatches) { Datum result = build_regexp_split_result(splitctx); splitctx->next_match++; SRF_RETURN_NEXT(funcctx, result); } /* release space in multi-call ctx to avoid intraquery memory leak */ cleanup_regexp_matches(splitctx); SRF_RETURN_DONE(funcctx); }
Datum regexp_split_to_table_no_flags | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1087 of file regexp.c.
References regexp_split_to_table().
{ return regexp_split_to_table(fcinfo); }
static regexp_matches_ctx * setup_regexp_matches | ( | text * | orig_str, | |
text * | pattern, | |||
text * | flags, | |||
Oid | collation, | |||
bool | force_glob, | |||
bool | use_subpatterns, | |||
bool | ignore_degenerate | |||
) | [static] |
Definition at line 849 of file regexp.c.
References pg_re_flags::cflags, ereport, errcode(), errmsg(), ERROR, pg_re_flags::glob, i, regexp_matches_ctx::match_locs, regexp_matches_ctx::nmatches, regexp_matches_ctx::npatterns, regexp_matches_ctx::orig_str, palloc(), palloc0(), parse_re_flags(), pfree(), pg_mb2wchar_with_len(), RE_compile_and_cache(), regex_t::re_nsub, RE_wchar_execute(), repalloc(), regmatch_t::rm_eo, regmatch_t::rm_so, VARDATA_ANY, and VARSIZE_ANY_EXHDR.
Referenced by regexp_matches(), regexp_split_to_array(), and regexp_split_to_table().
{ regexp_matches_ctx *matchctx = palloc0(sizeof(regexp_matches_ctx)); int orig_len; pg_wchar *wide_str; int wide_len; pg_re_flags re_flags; regex_t *cpattern; regmatch_t *pmatch; int pmatch_len; int array_len; int array_idx; int prev_match_end; int start_search; /* save original string --- we'll extract result substrings from it */ matchctx->orig_str = orig_str; /* convert string to pg_wchar form for matching */ orig_len = VARSIZE_ANY_EXHDR(orig_str); wide_str = (pg_wchar *) palloc(sizeof(pg_wchar) * (orig_len + 1)); wide_len = pg_mb2wchar_with_len(VARDATA_ANY(orig_str), wide_str, orig_len); /* determine options */ parse_re_flags(&re_flags, flags); if (force_glob) { /* user mustn't specify 'g' for regexp_split */ if (re_flags.glob) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("regexp_split does not support the global option"))); /* but we find all the matches anyway */ re_flags.glob = true; } /* set up the compiled pattern */ cpattern = RE_compile_and_cache(pattern, re_flags.cflags, collation); /* do we want to remember subpatterns? */ if (use_subpatterns && cpattern->re_nsub > 0) { matchctx->npatterns = cpattern->re_nsub; pmatch_len = cpattern->re_nsub + 1; } else { use_subpatterns = false; matchctx->npatterns = 1; pmatch_len = 1; } /* temporary output space for RE package */ pmatch = palloc(sizeof(regmatch_t) * pmatch_len); /* the real output space (grown dynamically if needed) */ array_len = re_flags.glob ? 256 : 32; matchctx->match_locs = (int *) palloc(sizeof(int) * array_len); array_idx = 0; /* search for the pattern, perhaps repeatedly */ prev_match_end = 0; start_search = 0; while (RE_wchar_execute(cpattern, wide_str, wide_len, start_search, pmatch_len, pmatch)) { /* * If requested, ignore degenerate matches, which are zero-length * matches occurring at the start or end of a string or just after a * previous match. */ if (!ignore_degenerate || (pmatch[0].rm_so < wide_len && pmatch[0].rm_eo > prev_match_end)) { /* enlarge output space if needed */ while (array_idx + matchctx->npatterns * 2 > array_len) { array_len *= 2; matchctx->match_locs = (int *) repalloc(matchctx->match_locs, sizeof(int) * array_len); } /* save this match's locations */ if (use_subpatterns) { int i; for (i = 1; i <= matchctx->npatterns; i++) { matchctx->match_locs[array_idx++] = pmatch[i].rm_so; matchctx->match_locs[array_idx++] = pmatch[i].rm_eo; } } else { matchctx->match_locs[array_idx++] = pmatch[0].rm_so; matchctx->match_locs[array_idx++] = pmatch[0].rm_eo; } matchctx->nmatches++; } prev_match_end = pmatch[0].rm_eo; /* if not glob, stop after one match */ if (!re_flags.glob) break; /* * Advance search position. Normally we start just after the end of * the previous match, but always advance at least one character (the * special case can occur if the pattern matches zero characters just * after the prior match or at the end of the string). */ if (start_search < pmatch[0].rm_eo) start_search = pmatch[0].rm_eo; else start_search++; if (start_search > wide_len) break; } /* Clean up temp storage */ pfree(wide_str); pfree(pmatch); return matchctx; }
Datum similar_escape | ( | PG_FUNCTION_ARGS | ) |
Definition at line 647 of file regexp.c.
References ereport, errcode(), errhint(), errmsg(), ERROR, palloc(), PG_ARGISNULL, PG_GETARG_TEXT_PP, PG_RETURN_NULL, PG_RETURN_TEXT_P, SET_VARSIZE, VARDATA, VARDATA_ANY, VARHDRSZ, and VARSIZE_ANY_EXHDR.
{ text *pat_text; text *esc_text; text *result; char *p, *e, *r; int plen, elen; bool afterescape = false; bool incharclass = false; int nquotes = 0; /* This function is not strict, so must test explicitly */ if (PG_ARGISNULL(0)) PG_RETURN_NULL(); pat_text = PG_GETARG_TEXT_PP(0); p = VARDATA_ANY(pat_text); plen = VARSIZE_ANY_EXHDR(pat_text); if (PG_ARGISNULL(1)) { /* No ESCAPE clause provided; default to backslash as escape */ e = "\\"; elen = 1; } else { esc_text = PG_GETARG_TEXT_PP(1); e = VARDATA_ANY(esc_text); elen = VARSIZE_ANY_EXHDR(esc_text); if (elen == 0) e = NULL; /* no escape character */ else if (elen != 1) ereport(ERROR, (errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE), errmsg("invalid escape string"), errhint("Escape string must be empty or one character."))); } /*---------- * We surround the transformed input string with * ^(?: ... )$ * which requires some explanation. We need "^" and "$" to force * the pattern to match the entire input string as per SQL99 spec. * The "(?:" and ")" are a non-capturing set of parens; we have to have * parens in case the string contains "|", else the "^" and "$" will * be bound into the first and last alternatives which is not what we * want, and the parens must be non capturing because we don't want them * to count when selecting output for SUBSTRING. *---------- */ /* * We need room for the prefix/postfix plus as many as 3 output bytes per * input byte; since the input is at most 1GB this can't overflow */ result = (text *) palloc(VARHDRSZ + 6 + 3 * plen); r = VARDATA(result); *r++ = '^'; *r++ = '('; *r++ = '?'; *r++ = ':'; while (plen > 0) { char pchar = *p; if (afterescape) { if (pchar == '"' && !incharclass) /* for SUBSTRING patterns */ *r++ = ((nquotes++ % 2) == 0) ? '(' : ')'; else { *r++ = '\\'; *r++ = pchar; } afterescape = false; } else if (e && pchar == *e) { /* SQL99 escape character; do not send to output */ afterescape = true; } else if (incharclass) { if (pchar == '\\') *r++ = '\\'; *r++ = pchar; if (pchar == ']') incharclass = false; } else if (pchar == '[') { *r++ = pchar; incharclass = true; } else if (pchar == '%') { *r++ = '.'; *r++ = '*'; } else if (pchar == '_') *r++ = '.'; else if (pchar == '(') { /* convert to non-capturing parenthesis */ *r++ = '('; *r++ = '?'; *r++ = ':'; } else if (pchar == '\\' || pchar == '.' || pchar == '^' || pchar == '$') { *r++ = '\\'; *r++ = pchar; } else *r++ = pchar; p++, plen--; } *r++ = ')'; *r++ = '$'; SET_VARSIZE(result, r - ((char *) result)); PG_RETURN_TEXT_P(result); }
Datum texticregexeq | ( | PG_FUNCTION_ARGS | ) |
Definition at line 516 of file regexp.c.
References NULL, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, RE_compile_and_execute(), REG_ADVANCED, REG_ICASE, VARDATA_ANY, and VARSIZE_ANY_EXHDR.
{ text *s = PG_GETARG_TEXT_PP(0); text *p = PG_GETARG_TEXT_PP(1); PG_RETURN_BOOL(RE_compile_and_execute(p, VARDATA_ANY(s), VARSIZE_ANY_EXHDR(s), REG_ADVANCED | REG_ICASE, PG_GET_COLLATION(), 0, NULL)); }
Datum texticregexne | ( | PG_FUNCTION_ARGS | ) |
Definition at line 530 of file regexp.c.
References NULL, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, RE_compile_and_execute(), REG_ADVANCED, REG_ICASE, VARDATA_ANY, and VARSIZE_ANY_EXHDR.
{ text *s = PG_GETARG_TEXT_PP(0); text *p = PG_GETARG_TEXT_PP(1); PG_RETURN_BOOL(!RE_compile_and_execute(p, VARDATA_ANY(s), VARSIZE_ANY_EXHDR(s), REG_ADVANCED | REG_ICASE, PG_GET_COLLATION(), 0, NULL)); }
Datum textregexeq | ( | PG_FUNCTION_ARGS | ) |
Definition at line 453 of file regexp.c.
References NULL, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, RE_compile_and_execute(), REG_ADVANCED, VARDATA_ANY, and VARSIZE_ANY_EXHDR.
{ text *s = PG_GETARG_TEXT_PP(0); text *p = PG_GETARG_TEXT_PP(1); PG_RETURN_BOOL(RE_compile_and_execute(p, VARDATA_ANY(s), VARSIZE_ANY_EXHDR(s), REG_ADVANCED, PG_GET_COLLATION(), 0, NULL)); }
Datum textregexne | ( | PG_FUNCTION_ARGS | ) |
Definition at line 467 of file regexp.c.
References NULL, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_BOOL, RE_compile_and_execute(), REG_ADVANCED, VARDATA_ANY, and VARSIZE_ANY_EXHDR.
{ text *s = PG_GETARG_TEXT_PP(0); text *p = PG_GETARG_TEXT_PP(1); PG_RETURN_BOOL(!RE_compile_and_execute(p, VARDATA_ANY(s), VARSIZE_ANY_EXHDR(s), REG_ADVANCED, PG_GET_COLLATION(), 0, NULL)); }
Datum textregexreplace | ( | PG_FUNCTION_ARGS | ) |
Definition at line 625 of file regexp.c.
References pg_re_flags::cflags, pg_re_flags::glob, parse_re_flags(), PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_TEXT_P, RE_compile_and_cache(), and replace_text_regexp().
Referenced by execute_extension_script().
{ text *s = PG_GETARG_TEXT_PP(0); text *p = PG_GETARG_TEXT_PP(1); text *r = PG_GETARG_TEXT_PP(2); text *opt = PG_GETARG_TEXT_PP(3); regex_t *re; pg_re_flags flags; parse_re_flags(&flags, opt); re = RE_compile_and_cache(p, flags.cflags, PG_GET_COLLATION()); PG_RETURN_TEXT_P(replace_text_regexp(s, (void *) re, r, flags.glob)); }
Datum textregexreplace_noopt | ( | PG_FUNCTION_ARGS | ) |
Definition at line 608 of file regexp.c.
References PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_TEXT_P, RE_compile_and_cache(), REG_ADVANCED, and replace_text_regexp().
{ text *s = PG_GETARG_TEXT_PP(0); text *p = PG_GETARG_TEXT_PP(1); text *r = PG_GETARG_TEXT_PP(2); regex_t *re; re = RE_compile_and_cache(p, REG_ADVANCED, PG_GET_COLLATION()); PG_RETURN_TEXT_P(replace_text_regexp(s, (void *) re, r, false)); }
Datum textregexsubstr | ( | PG_FUNCTION_ARGS | ) |
Definition at line 549 of file regexp.c.
References DirectFunctionCall3, Int32GetDatum, PG_GET_COLLATION, PG_GETARG_TEXT_PP, PG_RETURN_NULL, PointerGetDatum, RE_compile_and_cache(), RE_execute(), regex_t::re_nsub, REG_ADVANCED, regmatch_t::rm_eo, regmatch_t::rm_so, text_substr(), VARDATA_ANY, and VARSIZE_ANY_EXHDR.
{ text *s = PG_GETARG_TEXT_PP(0); text *p = PG_GETARG_TEXT_PP(1); regex_t *re; regmatch_t pmatch[2]; int so, eo; /* Compile RE */ re = RE_compile_and_cache(p, REG_ADVANCED, PG_GET_COLLATION()); /* * We pass two regmatch_t structs to get info about the overall match and * the match for the first parenthesized subexpression (if any). If there * is a parenthesized subexpression, we return what it matched; else * return what the whole regexp matched. */ if (!RE_execute(re, VARDATA_ANY(s), VARSIZE_ANY_EXHDR(s), 2, pmatch)) PG_RETURN_NULL(); /* definitely no match */ if (re->re_nsub > 0) { /* has parenthesized subexpressions, use the first one */ so = pmatch[1].rm_so; eo = pmatch[1].rm_eo; } else { /* no parenthesized subexpression, use whole match */ so = pmatch[0].rm_so; eo = pmatch[0].rm_eo; } /* * It is possible to have a match to the whole pattern but no match for a * subexpression; for example 'foo(bar)?' is considered to match 'foo' but * there is no subexpression match. So this extra test for match failure * is not redundant. */ if (so < 0 || eo < 0) PG_RETURN_NULL(); return DirectFunctionCall3(text_substr, PointerGetDatum(s), Int32GetDatum(so + 1), Int32GetDatum(eo - so)); }
int num_res = 0 [static] |
Definition at line 103 of file regexp.c.
Referenced by RE_compile_and_cache().
cached_re_str re_array[MAX_CACHED_RES] [static] |