#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 */
int regcomp_result;
cached_re_str re_temp;
char errMsg[100];
+ MemoryContext oldcontext;
/*
* Look for a match among previously compiled REs. Since the data
}
}
+ /* 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.
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,
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;
{
--num_res;
Assert(num_res < MAX_CACHED_RES);
- pg_regfree(&re_array[num_res].cre_re);
- free(re_array[num_res].cre_pat);
+ /* Delete the memory context holding the regexp and pattern. */
+ MemoryContextDelete(re_array[num_res].cre_context);
}
+ /* 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;
}
slen = pg_wchar2mb_with_len(str, result, slen);
Assert(slen < maxlen);
- free(str);
+ pfree(str);
return result;
}