Attached is a small patch to $SUBJECT. In master, only single-byte characters are allowed as an escape. Of course, with the patch it must still be a single character, but it may be multi-byte.
Regards, Jeff Davis
*** a/src/backend/utils/adt/regexp.c --- b/src/backend/utils/adt/regexp.c *************** *** 688,698 **** similar_escape(PG_FUNCTION_ARGS) 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."))); } /*---------- --- 688,704 ---- elen = VARSIZE_ANY_EXHDR(esc_text); if (elen == 0) e = NULL; /* no escape character */ ! else ! { ! int escape_mblen = pg_verify_mbstr_len(GetDatabaseEncoding(), e, ! elen, false); ! ! if (escape_mblen > 1) ! ereport(ERROR, ! (errcode(ERRCODE_INVALID_ESCAPE_SEQUENCE), ! errmsg("invalid escape string"), ! errhint("Escape string must be empty or one character."))); ! } } /*---------- *************** *** 722,781 **** similar_escape(PG_FUNCTION_ARGS) 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++ = ')'; --- 728,816 ---- while (plen > 0) { ! char pchar = *p; ! int mblen = pg_encoding_verifymb(GetDatabaseEncoding(), p, plen); ! ! Assert(mblen > 0); ! if (mblen == 1) { ! 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--; } ! else { ! if (afterescape) ! { *r++ = '\\'; ! memcpy(r, p, mblen); ! r += mblen; ! afterescape = false; ! } ! else if (e && elen == mblen && memcmp(e, p, mblen) == 0) ! { ! /* SQL99 escape character; do not send to output */ ! afterescape = true; ! } ! else ! { ! memcpy(r, p, mblen); ! r += mblen; ! } ! ! p += mblen; ! plen -= mblen; } } *r++ = ')';
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers