/* all the options of interest for regex functions */ typedefstruct test_re_flags
{ int cflags; /* compile flags for Spencer's regex code */ int eflags; /* execute flags for Spencer's regex code */ long info; /* expected re_info bits */ bool glob; /* do it globally (for each occurrence) */ bool indices; /* report indices not actual strings */ bool partial; /* expect partial match */
} test_re_flags;
/* cross-call state for test_regex() */ typedefstruct test_regex_ctx
{
test_re_flags re_flags; /* flags */
rm_detail_t details; /* "details" from execution */
text *orig_str; /* data string in original TEXT form */ int nmatches; /* number of places where pattern matched */ int npatterns; /* number of capturing subpatterns */ /* We store start char index and end+1 char index for each match */ /* so the number of entries in match_locs is nmatches * npatterns * 2 */ int *match_locs; /* 0-based character indexes */ int next_match; /* 0-based index of next match to process */ /* workspace for build_test_match_result() */
Datum *elems; /* has npatterns+1 elements */ bool *nulls; /* has npatterns+1 elements */
pg_wchar *wide_str; /* wide-char version of original string */ char *conv_buf; /* conversion buffer, if needed */ int conv_bufsiz; /* size thereof */
} test_regex_ctx;
/* Local functions */ staticvoid test_re_compile(text *text_re, int cflags, Oid collation,
regex_t *result_re); staticvoid parse_test_flags(test_re_flags *flags, text *opts); static test_regex_ctx *setup_test_matches(text *orig_str,
regex_t *cpattern,
test_re_flags *re_flags,
Oid collation, bool use_subpatterns); static ArrayType *build_test_info_result(regex_t *cpattern,
test_re_flags *flags); static ArrayType *build_test_match_result(test_regex_ctx *matchctx);
/* set up the compiled pattern */
test_re_compile(pattern, re_flags.cflags, collation, &cpattern);
/* be sure to copy the input string into the multi-call ctx */
matchctx = setup_test_matches(PG_GETARG_TEXT_P_COPY(1), &cpattern,
&re_flags,
collation, true);
if (regcomp_result != REG_OKAY)
{ /* re didn't compile (no need for pg_regfree, if so) */
pg_regerror(regcomp_result, result_re, errMsg, sizeof(errMsg));
ereport(ERROR,
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
errmsg("invalid regular expression: %s", errMsg)));
}
}
/* *test_re_execute-executeaREonpg_wchardata * *Returnstrueonmatch,falseonnomatch *Argumentsareasforpg_regexec
*/ staticbool
test_re_execute(regex_t *re, pg_wchar *data, int data_len, int start_search,
rm_detail_t *details, int nmatch, regmatch_t *pmatch, int eflags)
{ int regexec_result; char errMsg[100];
/* Initialize match locations in case engine doesn't */
details->rm_extend.rm_so = -1;
details->rm_extend.rm_eo = -1; for (int i = 0; i < nmatch; i++)
{
pmatch[i].rm_so = -1;
pmatch[i].rm_eo = -1;
}
/* Perform RE match and return result */
regexec_result = pg_regexec(re,
data,
data_len,
start_search,
details,
nmatch,
pmatch,
eflags);
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);
}
/* *parse_test_flags-parsetheflagsargument * *flags---outputargument,filledwithdesiredoptions *opts---TEXTobject,orNULLfordefaults
*/ staticvoid
parse_test_flags(test_re_flags *flags, text *opts)
{ /* these defaults must match Tcl's */ int cflags = REG_ADVANCED; int eflags = 0; long info = 0;
/* These flags define expected info bits: */ case'A':
info |= REG_UBSALNUM; break; case'B':
info |= REG_UBRACES; break; case'E':
info |= REG_UBBS; break; case'H':
info |= REG_ULOOKAROUND; break; case'I':
info |= REG_UIMPOSSIBLE; break; case'L':
info |= REG_ULOCALE; break; case'M':
info |= REG_UUNPORT; break; case'N':
info |= REG_UEMPTYMATCH; break; case'P':
info |= REG_UNONPOSIX; break; case'Q':
info |= REG_UBOUNDS; break; case'R':
info |= REG_UBACKREF; break; case'S':
info |= REG_UUNSPEC; break; case'T':
info |= REG_USHORTEST; break; case'U':
info |= REG_UPBOTCH; break;
/* *setup_test_matches---dotheinitialmatching * *Tosimplifymemorymanagement,wedoallthematchinginoneswoop. *Thereturnedtest_regex_ctxcontainsthelocationsofallthesubstrings *matchingthepattern.
*/ static test_regex_ctx *
setup_test_matches(text *orig_str,
regex_t *cpattern, test_re_flags *re_flags,
Oid collation, bool use_subpatterns)
{
test_regex_ctx *matchctx = palloc0(sizeof(test_regex_ctx)); int eml = pg_database_encoding_max_length(); int orig_len;
pg_wchar *wide_str; int wide_len;
regmatch_t *pmatch; int pmatch_len; int array_len; int array_idx; int prev_match_end; int start_search; int maxlen = 0; /* largest fetch length in characters */
/* save flags */
matchctx->re_flags = *re_flags;
/* 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);
/* do we want to remember subpatterns? */ if (use_subpatterns && cpattern->re_nsub > 0)
{
matchctx->npatterns = cpattern->re_nsub + 1;
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);
matchctx->conv_buf = palloc(conv_bufsiz);
matchctx->conv_bufsiz = conv_bufsiz;
matchctx->wide_str = wide_str;
} else
{ /* No need to keep the wide string if we're in a single-byte charset. */
pfree(wide_str);
matchctx->wide_str = NULL;
matchctx->conv_buf = NULL;
matchctx->conv_bufsiz = 0;
}
/* Clean up temp storage */
pfree(pmatch);
return matchctx;
}
/* *build_test_info_result-buildoutputarraydescribingcompiledregexp * *ThisborrowssomecodefromTcl'sTclRegAbout().
*/ static ArrayType *
build_test_info_result(regex_t *cpattern, test_re_flags *flags)
{ /* Translation data for flag bits in regex_t.re_info */ struct infoname
{ int bit; constchar *text;
}; staticconststruct infoname infonames[] = {
{REG_UBACKREF, "REG_UBACKREF"},
{REG_ULOOKAROUND, "REG_ULOOKAROUND"},
{REG_UBOUNDS, "REG_UBOUNDS"},
{REG_UBRACES, "REG_UBRACES"},
{REG_UBSALNUM, "REG_UBSALNUM"},
{REG_UPBOTCH, "REG_UPBOTCH"},
{REG_UBBS, "REG_UBBS"},
{REG_UNONPOSIX, "REG_UNONPOSIX"},
{REG_UUNSPEC, "REG_UUNSPEC"},
{REG_UUNPORT, "REG_UUNPORT"},
{REG_ULOCALE, "REG_ULOCALE"},
{REG_UEMPTYMATCH, "REG_UEMPTYMATCH"},
{REG_UIMPOSSIBLE, "REG_UIMPOSSIBLE"},
{REG_USHORTEST, "REG_USHORTEST"},
{0, NULL}
}; conststruct infoname *inf;
Datum elems[lengthof(infonames) + 1]; int nresults = 0; char buf[80]; int dims[1]; int lbs[1];
/* Set up results: first, the number of subexpressions */
snprintf(buf, sizeof(buf), "%d", (int) cpattern->re_nsub);
elems[nresults++] = PointerGetDatum(cstring_to_text(buf));
/* Report individual info bit states */ for (inf = infonames; inf->bit != 0; inf++)
{ if (cpattern->re_info & inf->bit)
{ if (flags->info & inf->bit)
elems[nresults++] = PointerGetDatum(cstring_to_text(inf->text)); else
{
snprintf(buf, sizeof(buf), "unexpected %s!", inf->text);
elems[nresults++] = PointerGetDatum(cstring_to_text(buf));
}
} else
{ if (flags->info & inf->bit)
{
snprintf(buf, sizeof(buf), "missing %s!", inf->text);
elems[nresults++] = PointerGetDatum(cstring_to_text(buf));
}
}
}
/* And form an array */
dims[0] = nresults;
lbs[0] = 1; /* XXX: this hardcodes assumptions about the text type */ return construct_md_array(elems, NULL, 1, dims, lbs,
TEXTOID, -1, false, TYPALIGN_INT);
}
/* *build_test_match_result-buildoutputarrayforcurrentmatch * *Notethatiftheindicesflagisset,wedon'tneedanystrings, *justthelocationdata.
*/ static ArrayType *
build_test_match_result(test_regex_ctx *matchctx)
{ char *buf = matchctx->conv_buf;
Datum *elems = matchctx->elems; bool *nulls = matchctx->nulls; bool indices = matchctx->re_flags.indices; char bufstr[80]; 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 (indices)
{ /* Report eo this way for consistency with Tcl */
snprintf(bufstr, sizeof(bufstr), "%d %d",
so, so < 0 ? eo : eo - 1);
elems[i] = PointerGetDatum(cstring_to_text(bufstr));
nulls[i] = false;
} elseif (so < 0 || eo < 0)
{
elems[i] = (Datum) 0;
nulls[i] = true;
} elseif (buf)
{ int len = pg_wchar2mb_with_len(matchctx->wide_str + so,
buf,
eo - so);
/* In EXPECT indices mode, also report the "details" */ if (indices && (matchctx->re_flags.cflags & REG_EXPECT))
{ int so = matchctx->details.rm_extend.rm_so; int eo = matchctx->details.rm_extend.rm_eo;
snprintf(bufstr, sizeof(bufstr), "%d %d",
so, so < 0 ? eo : eo - 1);
elems[i] = PointerGetDatum(cstring_to_text(bufstr));
nulls[i] = false;
i++;
}
/* And form an array */
dims[0] = i;
lbs[0] = 1; /* XXX: this hardcodes assumptions about the text type */ return construct_md_array(elems, nulls, 1, dims, lbs,
TEXTOID, -1, false, TYPALIGN_INT);
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.17 Sekunden
(vorverarbeitet am 2026-08-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.