#include "postgres.h" #include "fmgr.h" #include "utils/array.h" #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/regexp.h" PG_MODULE_MAGIC; Datum regexp_matches(PG_FUNCTION_ARGS); PG_FUNCTION_INFO_V1(regexp_matches); Datum regexp_matches(PG_FUNCTION_ARGS) { text *s = PG_GETARG_TEXT_P(0); text *p = PG_GETARG_TEXT_P(1); regex_t *cpat; cpat = RE_compile_and_cache(p, regex_flavor); if (cpat->re_nsub) { regmatch_t *pmatch = palloc0(sizeof(regmatch_t) * (cpat->re_nsub + 1)); if (RE_execute(cpat, VARDATA(s), VARSIZE(s) - VARHDRSZ, cpat->re_nsub + 1, pmatch)) { ArrayType *result; Datum elems[cpat->re_nsub]; bool nulls[cpat->re_nsub]; /* get text type oid, too lazy to do it some other way */ Oid param_type = get_fn_expr_argtype(fcinfo->flinfo, 0); size_t i; int ndims = 1; int dims[1] = {cpat->re_nsub}; int lbs[1] = {1}; int16 typlen; bool typbyval; char typalign; get_typlenbyvalalign(param_type, &typlen, &typbyval, &typalign); for (i = 0; i < cpat->re_nsub; ++i) { int so = pmatch[i+1].rm_so, eo = pmatch[i+1].rm_eo; if (so < 0 || eo < 0) { elems[i] = 0; nulls[i] = true; } else { elems[i] = DirectFunctionCall3(text_substr, PointerGetDatum(s), Int32GetDatum(so + 1), Int32GetDatum(eo - so)); nulls[i] = false; } } pfree(pmatch); result = construct_md_array(elems, nulls, ndims, dims, lbs, param_type, typlen, typbyval, typalign); PG_RETURN_ARRAYTYPE_P(result); } /* if no match, fall through and return null */ } else { ereport(ERROR, (errcode(ERRCODE_INVALID_REGULAR_EXPRESSION), errmsg("regular expression has no match groups"))); } PG_RETURN_NULL(); }