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

Commita9eb492

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 parent3e2db4c commita9eb492

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
staticstructfnsfunctions= {
278281
rfree,/* regfree insides */
282+
rcancelrequested/* check for cancel request */
279283
};
280284

281285

@@ -1876,6 +1880,22 @@ rfree(regex_t *re)
18761880
}
18771881
}
18781882

1883+
/*
1884+
* rcancelrequested - check for external request to cancel regex operation
1885+
*
1886+
* Return nonzero to fail the operation with error code REG_CANCEL,
1887+
* zero to keep going
1888+
*
1889+
* The current implementation is Postgres-specific. If we ever get around
1890+
* to splitting the regex code out as a standalone library, there will need
1891+
* to be some API to let applications define a callback function for this.
1892+
*/
1893+
staticint
1894+
rcancelrequested(void)
1895+
{
1896+
returnInterruptPending&& (QueryCancelPending||ProcDiePending);
1897+
}
1898+
18791899
#ifdefREG_DEBUG
18801900

18811901
/*

‎src/backend/regex/regexec.c‎

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

716+
/* handy place to check for operation cancel */
717+
if (CANCEL_REQUESTED(v->re))
718+
returnREG_CANCEL;
719+
716720
switch (t->op)
717721
{
718722
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/builtins.h"
3637
#include"utils/guc.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
@@ -2854,6 +2854,7 @@ replace_text_regexp(text *src_text, void *regexp,
28542854
{
28552855
charerrMsg[100];
28562856

2857+
CHECK_FOR_INTERRUPTS();
28572858
pg_regerror(regexec_result,re,errMsg,sizeof(errMsg));
28582859
ereport(ERROR,
28592860
(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
@@ -403,8 +403,11 @@ struct subre
403403
structfns
404404
{
405405
voidFUNCPTR(free, (regex_t*));
406+
intFUNCPTR(cancel_requested, (void));
406407
};
407408

409+
#defineCANCEL_REQUESTED(re) \
410+
((*((struct fns *) (re)->re_fns)->cancel_requested) ())
408411

409412

410413
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp