@ -96,9 +96,13 @@ typedef struct regexp_matches_ctx
# define MAX_CACHED_RES 32
# endif
/* A parent memory context for regular expressions. */
static MemoryContext RegexpCacheMemoryContext ;
/* this structure describes one cached regular expression */
typedef struct cached_re_str
{
MemoryContext cre_context ; /* memory context for this regexp */
char * cre_pat ; /* original RE (not null terminated!) */
int cre_pat_len ; /* length of original RE, in bytes */
int cre_flags ; /* compile flags: extended,icase etc */
@ -145,6 +149,7 @@ RE_compile_and_cache(text *text_re, int cflags, Oid collation)
int regcomp_result ;
cached_re_str re_temp ;
char errMsg [ 100 ] ;
MemoryContext oldcontext ;
/*
* Look for a match among previously compiled REs . Since the data
@ -172,6 +177,13 @@ RE_compile_and_cache(text *text_re, int cflags, Oid collation)
}
}
/* Set up the cache memory on first go through. */
if ( unlikely ( RegexpCacheMemoryContext = = NULL ) )
RegexpCacheMemoryContext =
AllocSetContextCreate ( TopMemoryContext ,
" RegexpCacheMemoryContext " ,
ALLOCSET_SMALL_SIZES ) ;
/*
* Couldn ' t find it , so try to compile the new RE . To avoid leaking
* resources on failure , we build into the re_temp local .
@ -183,6 +195,18 @@ RE_compile_and_cache(text *text_re, int cflags, Oid collation)
pattern ,
text_re_len ) ;
/*
* Make a memory context for this compiled regexp . This is initially a
* child of the current memory context , so it will be cleaned up
* automatically if compilation is interrupted and throws an ERROR . We ' ll
* re - parent it under the longer lived cache context if we make it to the
* bottom of this function .
*/
re_temp . cre_context = AllocSetContextCreate ( CurrentMemoryContext ,
" RegexpMemoryContext " ,
ALLOCSET_SMALL_SIZES ) ;
oldcontext = MemoryContextSwitchTo ( re_temp . cre_context ) ;
regcomp_result = pg_regcomp ( & re_temp . cre_re ,
pattern ,
pattern_len ,
@ -209,21 +233,17 @@ RE_compile_and_cache(text *text_re, int cflags, Oid collation)
errmsg ( " invalid regular expression: %s " , errMsg ) ) ) ;
}
/* Copy the pattern into the per-regexp memory context. */
re_temp . cre_pat = palloc ( text_re_len + 1 ) ;
memcpy ( re_temp . cre_pat , text_re_val , text_re_len ) ;
/*
* We use malloc / free for the cre_pat field because the storage has to
* persist across transactions , and because we want to get control back on
* out - of - memory . The Max ( ) is because some malloc implementations return
* NULL for malloc ( 0 ) .
* NUL - terminate it only for the benefit of the identifier used for the
* memory context , visible in the pg_backend_memory_contexts view .
*/
re_temp . cre_pat = malloc ( Max ( text_re_len , 1 ) ) ;
if ( re_temp . cre_pat = = NULL )
{
pg_regfree ( & re_temp . cre_re ) ;
ereport ( ERROR ,
( errcode ( ERRCODE_OUT_OF_MEMORY ) ,
errmsg ( " out of memory " ) ) ) ;
}
memcpy ( re_temp . cre_pat , text_re_val , text_re_len ) ;
re_temp . cre_pat [ text_re_len ] = 0 ;
MemoryContextSetIdentifier ( re_temp . cre_context , re_temp . cre_pat ) ;
re_temp . cre_pat_len = text_re_len ;
re_temp . cre_flags = cflags ;
re_temp . cre_collation = collation ;
@ -236,16 +256,21 @@ RE_compile_and_cache(text *text_re, int cflags, Oid collation)
{
- - num_res ;
Assert ( num_res < MAX_CACHED_RES ) ;
pg_regfree ( & re_array [ num_res ] . cre_re ) ;
fre e( re_array [ num_res ] . cre_pa t ) ;
/* Delete the memory context holding the regexp and pattern. */
MemoryContextDelet e( re_array [ num_res ] . cre_contex t ) ;
}
/* Re-parent the memory context to our long-lived cache context. */
MemoryContextSetParent ( re_temp . cre_context , RegexpCacheMemoryContext ) ;
if ( num_res > 0 )
memmove ( & re_array [ 1 ] , & re_array [ 0 ] , num_res * sizeof ( cached_re_str ) ) ;
re_array [ 0 ] = re_temp ;
num_res + + ;
MemoryContextSwitchTo ( oldcontext ) ;
return & re_array [ 0 ] . cre_re ;
}
@ -1990,7 +2015,7 @@ regexp_fixed_prefix(text *text_re, bool case_insensitive, Oid collation,
slen = pg_wchar2mb_with_len ( str , result , slen ) ;
Assert ( slen < maxlen ) ;
free ( str ) ;
p free( str ) ;
return result ;
}