#include struct scratchPadMapping {
pcre *re;
pcre_extra *extra;
const char *error;
int errOffset;
int numSubstr;
int *substr;
int currentSubstr;
};
void regexpSubstr(
// input parameters
SQLUDF_VARCHAR *pattern, SQLUDF_CLOB *str,
// output
SQLUDF_INTEGER *pos, SQLUDF_VARCHAR *substr,
// null indicators
SQLUDF_NULLIND *pattern_ind, SQLUDF_NULLIND *str_ind,
SQLUDF_NULLIND *pos_ind, SQLUDF_NULLIND *substr_ind,
SQLUDF_TRAIL_ARGS_ALL) // SQLUDF_SCRAT & SQLUDF_CALLT
{
int rc = 0;
size_t length = 0;
struct scratchPadMapping *scratch = NULL;
// map the buffer of the scratchpad and assume NULL return
scratch = (struct scratchPadMapping *)SQLUDF_SCRAT->data;
*pos_ind = 0;
*substr_ind = 0;
switch (SQLUDF_CALLT) {
case SQLUDF_TF_OPEN:
// initialize data on the scratchpad
scratch->re = NULL;
scratch->extra = NULL;
scratch->error = NULL;
scratch->errOffset = 0;
scratch->numSubstr = 0;
scratch->substr = NULL;
scratch->currentSubstr = 1; // skip the complete match
// compile the pattern (only in the FIRST call
scratch->re = pcre_compile(pattern, 0 /* default options */,
&scratch->error, &scratch->errOffset, NULL);
if (scratch->re == NULL) {
snprintf(SQLUDF_MSGTX, 70, "Regexp compilation failed at "
"offset %d: %s\\n", scratch->errOffset, scratch->error);
strcpy(SQLUDF_STATE, "38900");
rc = -1;
break;
}
// further analyze the pattern (might return NULL)
scratch->extra = pcre_study(scratch->re,
0 /* default options */, &scratch->error);
// determine the number of capturing subpatterns
rc = pcre_fullinfo(scratch->re, scratch->extra,
PCRE_INFO_CAPTURECOUNT, &scratch->numSubstr);
if (rc) {
snprintf(SQLUDF_MSGTX, 70, "Could not retrieve info "
"on pattern. (rc = %d)", rc);
strcpy(SQLUDF_STATE, "38901");
rc = -1;
break;
}
// allocate memory for the substring indices
{
int size = (scratch->numSubstr+1)*3;
scratch->substr = (int *)malloc(size * sizeof(int));
if (!scratch->substr) {
snprintf(SQLUDF_MSGTX, 70, "Could allocate memory for "
"substring indices.");
strcpy(SQLUDF_STATE, "38902");
rc = -1;
break;
}
memset(scratch->substr, 0, size * sizeof(int));
// match the current string
rc = pcre_exec(scratch->re, scratch->extra, str->data,
str->length, 0, 0 /* default options */,
scratch->substr, size);
}
switch (rc) {
case PCRE_ERROR_BADOPTION:
snprintf(SQLUDF_MSGTX, 70, "An unrecognized bit was set "
"in the options argument");
strcpy(SQLUDF_STATE, "38903");
rc = -1;
break;
case PCRE_ERROR_NOMEMORY:
snprintf(SQLUDF_MSGTX, 70, "Not enough memory available.");
strcpy(SQLUDF_STATE, "38904");
rc = -1;
break;
case PCRE_ERROR_NOMATCH:
scratch->currentSubstr = scratch->numSubstr + 1;
rc = 0;
break;
default:
if (rc < 0) {
snprintf(SQLUDF_MSGTX, 70, "A regexp match error "
"occured: %d", rc);
strcpy(SQLUDF_STATE, "38905");
rc = -1;
break;
}
}
break;
case SQLUDF_TF_FETCH:
// skip capturing substrings without a match
while (scratch->currentSubstr <= scratch->numSubstr &&
(scratch->substr[2*scratch->currentSubstr] < 0 ||
scratch->substr[2*scratch->currentSubstr+1] < 0)) {
scratch->currentSubstr++;
}
// no more data to be returned
if (scratch->currentSubstr > scratch->numSubstr) {
strcpy(SQLUDF_STATE, SQL_NODATA_EXCEPTION);
rc = 0;
break;
}
// get the current substring
*pos = scratch->currentSubstr;
length = scratch->substr[2*scratch->currentSubstr+1] -
scratch->substr[2*scratch->currentSubstr];
strncpy(substr, str->data + scratch->substr[2*scratch->currentSubstr],
length);
substr[length] = '\\0';
scratch->currentSubstr++;
}
// cleanup in CLOSE call, or if we encountered an error in
// the OPEN call (DB2 will make a CLOSE call if we encounter
// an error in any FETCH call)
if (SQLUDF_CALLT == SQLUDF_TF_CLOSE ||
(SQLUDF_CALLT == SQLUDF_TF_OPEN && rc < 0)) {
(*pcre_free)(scratch->re);
(*pcre_free)(scratch->extra);
free(scratch->substr);
}
return;
}