Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit9662143

Browse files
committed
Allow regex operations to be terminated early by query cancel requests.
The regex code didn't have any provision for query cancel; which isunsurprising given its non-Postgres origin, but still problematic sincesome operations can take a long time. Introduce a callback function tocheck for a pending query cancel or session termination request, andcall it in a couple of strategic spots where we can make the regex codeexit with an error indicator.If we ever actually split out the regex code as a standalone library,some additional work will be needed to let the cancel callback functionbe specified externally to the library. But that's straightforward(certainly so by comparison to putting the locale-dependent characterclassification logic on a similar arms-length basis), and there seemsno need to do it right now.A bigger issue is that there may be more places than these two wherewe need to check for cancels. We can always add more checks later,now that the infrastructure is in place.Since there are known examples of not-terribly-long regexes that canlock up a backend for a long time, back-patch to all supported branches.I have hopes of fixing the known performance problems later, but addingquery cancel ability seems like a good idea even if they were all fixed.
1 parentd8a42b1 commit9662143

File tree

8 files changed

+57
-0
lines changed

8 files changed

+57
-0
lines changed

‎src/backend/regex/regc_nfa.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,11 +174,23 @@ newstate(struct nfa * nfa)
174174
{
175175
structstate*s;
176176

177+
/*
178+
* This is a handy place to check for operation cancel during regex
179+
* compilation, since no code path will go very long without making a new
180+
* state.
181+
*/
182+
if (CANCEL_REQUESTED(nfa->v->re))
183+
{
184+
NERR(REG_CANCEL);
185+
returnNULL;
186+
}
187+
177188
if (TooManyStates(nfa))
178189
{
179190
NERR(REG_ETOOBIG);
180191
returnNULL;
181192
}
193+
182194
if (nfa->free!=NULL)
183195
{
184196
s=nfa->free;

‎src/backend/regex/regcomp.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@
3434

3535
#include"regex/regguts.h"
3636

37+
#include"miscadmin.h"/* needed by rcancelrequested() */
38+
3739
/*
3840
* forward declarations, up here so forward datatypes etc. are defined early
3941
*/
@@ -67,6 +69,7 @@ static long nfanode(struct vars *, struct subre *, FILE *);
6769
staticintnewlacon(structvars*,structstate*,structstate*,int);
6870
staticvoidfreelacons(structsubre*,int);
6971
staticvoidrfree(regex_t*);
72+
staticintrcancelrequested(void);
7073

7174
#ifdefREG_DEBUG
7275
staticvoiddump(regex_t*,FILE*);
@@ -276,6 +279,7 @@ struct vars
276279
/* static function list */
277280
staticconststructfnsfunctions= {
278281
rfree,/* regfree insides */
282+
rcancelrequested/* check for cancel request */
279283
};
280284

281285

@@ -1893,6 +1897,22 @@ rfree(regex_t *re)
18931897
}
18941898
}
18951899

1900+
/*
1901+
* rcancelrequested - check for external request to cancel regex operation
1902+
*
1903+
* Return nonzero to fail the operation with error code REG_CANCEL,
1904+
* zero to keep going
1905+
*
1906+
* The current implementation is Postgres-specific. If we ever get around
1907+
* to splitting the regex code out as a standalone library, there will need
1908+
* to be some API to let applications define a callback function for this.
1909+
*/
1910+
staticint
1911+
rcancelrequested(void)
1912+
{
1913+
returnInterruptPending&& (QueryCancelPending||ProcDiePending);
1914+
}
1915+
18961916
#ifdefREG_DEBUG
18971917

18981918
/*

‎src/backend/regex/regexec.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -595,6 +595,10 @@ cdissect(struct vars * v,
595595
assert(t!=NULL);
596596
MDEBUG(("cdissect %ld-%ld %c\n",LOFF(begin),LOFF(end),t->op));
597597

598+
/* handy place to check for operation cancel */
599+
if (CANCEL_REQUESTED(v->re))
600+
returnREG_CANCEL;
601+
598602
switch (t->op)
599603
{
600604
case'=':/* terminal node */

‎src/backend/utils/adt/regexp.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131

3232
#include"catalog/pg_type.h"
3333
#include"funcapi.h"
34+
#include"miscadmin.h"
3435
#include"regex/regex.h"
3536
#include"utils/array.h"
3637
#include"utils/builtins.h"
@@ -188,6 +189,15 @@ RE_compile_and_cache(text *text_re, int cflags, Oid collation)
188189
if (regcomp_result!=REG_OKAY)
189190
{
190191
/* re didn't compile (no need for pg_regfree, if so) */
192+
193+
/*
194+
* Here and in other places in this file, do CHECK_FOR_INTERRUPTS
195+
* before reporting a regex error.This is so that if the regex
196+
* library aborts and returns REG_CANCEL, we don't print an error
197+
* message that implies the regex was invalid.
198+
*/
199+
CHECK_FOR_INTERRUPTS();
200+
191201
pg_regerror(regcomp_result,&re_temp.cre_re,errMsg,sizeof(errMsg));
192202
ereport(ERROR,
193203
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
@@ -268,6 +278,7 @@ RE_wchar_execute(regex_t *re, pg_wchar *data, int data_len,
268278
if (regexec_result!=REG_OKAY&&regexec_result!=REG_NOMATCH)
269279
{
270280
/* re failed??? */
281+
CHECK_FOR_INTERRUPTS();
271282
pg_regerror(regexec_result,re,errMsg,sizeof(errMsg));
272283
ereport(ERROR,
273284
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),
@@ -1216,6 +1227,7 @@ regexp_fixed_prefix(text *text_re, bool case_insensitive, Oid collation,
12161227

12171228
default:
12181229
/* re failed??? */
1230+
CHECK_FOR_INTERRUPTS();
12191231
pg_regerror(re_result,re,errMsg,sizeof(errMsg));
12201232
ereport(ERROR,
12211233
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),

‎src/backend/utils/adt/varlena.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3035,6 +3035,7 @@ replace_text_regexp(text *src_text, void *regexp,
30353035
{
30363036
charerrMsg[100];
30373037

3038+
CHECK_FOR_INTERRUPTS();
30383039
pg_regerror(regexec_result,re,errMsg,sizeof(errMsg));
30393040
ereport(ERROR,
30403041
(errcode(ERRCODE_INVALID_REGULAR_EXPRESSION),

‎src/include/regex/regerrs.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,3 +81,7 @@
8181
{
8282
REG_ECOLORS,"REG_ECOLORS","too many colors"
8383
},
84+
85+
{
86+
REG_CANCEL,"REG_CANCEL","operation cancelled"
87+
},

‎src/include/regex/regex.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,7 @@ typedef struct
154154
#defineREG_BADOPT18/* invalid embedded option */
155155
#defineREG_ETOOBIG 19/* nfa has too many states */
156156
#defineREG_ECOLORS 20/* too many colors */
157+
#defineREG_CANCEL21/* operation cancelled */
157158
/* two specials for debugging and testing */
158159
#defineREG_ATOI101/* convert error-code name to number */
159160
#defineREG_ITOA102/* convert error-code number to name */

‎src/include/regex/regguts.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,8 +446,11 @@ struct subre
446446
structfns
447447
{
448448
voidFUNCPTR(free, (regex_t*));
449+
intFUNCPTR(cancel_requested, (void));
449450
};
450451

452+
#defineCANCEL_REQUESTED(re) \
453+
((*((struct fns *) (re)->re_fns)->cancel_requested) ())
451454

452455

453456
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp