aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/regexp.c
diff options
context:
space:
mode:
authorMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
committerMarc G. Fournier <scrappy@hub.org>1996-07-09 06:22:35 +0000
commitd31084e9d1118b25fd16580d9d8c2924b5740dff (patch)
tree3179e66307d54df9c7b966543550e601eb55e668 /src/backend/utils/adt/regexp.c
downloadpostgresql-d31084e9d1118b25fd16580d9d8c2924b5740dff.tar.gz
postgresql-d31084e9d1118b25fd16580d9d8c2924b5740dff.zip
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/utils/adt/regexp.c')
-rw-r--r--src/backend/utils/adt/regexp.c343
1 files changed, 343 insertions, 0 deletions
diff --git a/src/backend/utils/adt/regexp.c b/src/backend/utils/adt/regexp.c
new file mode 100644
index 00000000000..4b5a0089039
--- /dev/null
+++ b/src/backend/utils/adt/regexp.c
@@ -0,0 +1,343 @@
+/*-------------------------------------------------------------------------
+ *
+ * regexp.c--
+ * regular expression handling code.
+ *
+ * Copyright (c) 1994, Regents of the University of California
+ *
+ *
+ * IDENTIFICATION
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/regexp.c,v 1.1.1.1 1996/07/09 06:22:05 scrappy Exp $
+ *
+ * Alistair Crooks added the code for the regex caching
+ * agc - cached the regular expressions used - there's a good chance
+ * that we'll get a hit, so this saves a compile step for every
+ * attempted match. I haven't actually measured the speed improvement,
+ * but it `looks' a lot quicker visually when watching regression
+ * test output.
+ *
+ * agc - incorporated Keith Bostic's Berkeley regex code into
+ * the tree for all ports. To distinguish this regex code from any that
+ * is existent on a platform, I've prepended the string "pg95_" to
+ * the functions regcomp, regerror, regexec and regfree.
+ * Fixed a bug that was originally a typo by me, where `i' was used
+ * instead of `oldest' when compiling regular expressions - benign
+ * results mostly, although occasionally it bit you...
+ *
+ *
+ *-------------------------------------------------------------------------
+ */
+#include <string.h>
+#include "postgres.h" /* postgres system include file */
+#include "utils/elog.h" /* for logging postgres errors */
+#include "utils/palloc.h"
+#include "utils/builtins.h" /* where the function declarations go */
+
+#if defined(DISABLE_XOPEN_NLS)
+#undef _XOPEN_SOURCE
+#endif /* DISABLE_XOPEN_NLS */
+
+#ifndef WIN32
+
+#include <sys/types.h>
+#include <regex.h>
+
+#endif /* WIN32 why is this necessary? */
+
+/* this is the number of cached regular expressions held. */
+#ifndef MAX_CACHED_RES
+#define MAX_CACHED_RES 32
+#endif
+
+/* this structure describes a cached regular expression */
+struct cached_re_str {
+ struct varlena *cre_text; /* pattern as a text* */
+ char *cre_s; /* pattern as null-terminated string */
+ int cre_type; /* compiled-type: extended,icase etc */
+ regex_t cre_re; /* the compiled regular expression */
+ unsigned long cre_lru; /* lru tag */
+};
+
+static int rec = 0; /* # of cached re's */
+static struct cached_re_str rev[MAX_CACHED_RES]; /* cached re's */
+static unsigned long lru; /* system lru tag */
+
+/* attempt to compile `re' as an re, then match it against text */
+/* cflags - flag to regcomp indicates case sensitivity */
+static int
+RE_compile_and_execute(struct varlena *text_re, char *text, int cflags)
+{
+ int oldest;
+ int n;
+ int i;
+ char *re;
+ int regcomp_result;
+
+ re = textout(text_re);
+ /* find a previously compiled regular expression */
+ for (i = 0 ; i < rec ; i++) {
+ if (rev[i].cre_s) {
+ if (strcmp(rev[i].cre_s, re) == 0) {
+ if (rev[i].cre_type == cflags) {
+ rev[i].cre_lru = ++lru;
+ pfree(re);
+ return(pg95_regexec(&rev[i].cre_re,
+ text, 0,
+ (regmatch_t *) NULL, 0) == 0);
+ }
+ }
+ }
+ }
+
+
+
+ /* we didn't find it - make room in the cache for it */
+ if (rec == MAX_CACHED_RES) {
+ /* cache is full - find the oldest entry */
+ for (oldest = 0, i = 1 ; i < rec ; i++) {
+ if (rev[i].cre_lru < rev[oldest].cre_lru) {
+ oldest = i;
+ }
+ }
+ } else {
+ oldest = rec++;
+ }
+
+ /* if there was an old re, then de-allocate the space it used */
+ if (rev[oldest].cre_s != (char *) NULL) {
+ for (lru = i = 0 ; i < rec ; i++) {
+ rev[i].cre_lru =
+ (rev[i].cre_lru - rev[oldest].cre_lru) / 2;
+ if (rev[i].cre_lru > lru) {
+ lru = rev[i].cre_lru;
+ }
+ }
+ pg95_regfree(&rev[oldest].cre_re);
+ /* use malloc/free for the cre_s field because the storage
+ has to persist across transactions */
+ free(rev[oldest].cre_s);
+ }
+
+ /* compile the re */
+ regcomp_result = pg95_regcomp(&rev[oldest].cre_re, re, cflags);
+ if ( regcomp_result == 0) {
+ n = strlen(re);
+ /* use malloc/free for the cre_s field because the storage
+ has to persist across transactions */
+ rev[oldest].cre_s = (char *) malloc(n + 1);
+ (void) memmove(rev[oldest].cre_s, re, n);
+ rev[oldest].cre_s[n] = 0;
+ rev[oldest].cre_text = text_re;
+ rev[oldest].cre_lru = ++lru;
+ rev[oldest].cre_type = cflags;
+ pfree(re);
+ /* agc - fixed an old typo here */
+ return(pg95_regexec(&rev[oldest].cre_re, text, 0,
+ (regmatch_t *) NULL, 0) == 0);
+ } else {
+ char errMsg[1000];
+ /* re didn't compile */
+ rev[oldest].cre_s = (char *) NULL;
+ pg95_regerror(regcomp_result, &rev[oldest].cre_re, errMsg,
+ sizeof(errMsg));
+ elog(WARN,"regcomp failed with error %s",errMsg);
+ }
+
+ /* not reached */
+ return(0);
+}
+
+
+
+/*
+ * interface routines called by the function manager
+ */
+
+/*
+ fixedlen_regexeq:
+
+ a generic fixed length regexp routine
+ s - the string to match against (not necessarily null-terminated)
+ p - the pattern
+ charlen - the length of the string
+*/
+static bool
+fixedlen_regexeq(char *s, struct varlena* p, int charlen, int cflags)
+{
+ char *sterm;
+ int result;
+
+ if (!s || !p)
+ return FALSE;
+
+ /* be sure sterm is null-terminated */
+ sterm = (char *) palloc(charlen + 1);
+ memset(sterm, 0, charlen + 1);
+ strncpy(sterm, s, charlen);
+
+ result = RE_compile_and_execute(p, sterm, cflags);
+
+ pfree(sterm);
+
+ return ((bool) result);
+
+}
+
+
+/*
+ * routines that use the regexp stuff
+ */
+bool
+char2regexeq(uint16 arg1, struct varlena *p)
+{
+ char *s = (char *) &arg1;
+ return (fixedlen_regexeq(s, p, 2, REG_EXTENDED));
+}
+
+bool
+char2regexne(uint16 arg1, struct varlena *p)
+{
+ return (!char2regexeq(arg1, p));
+}
+
+bool
+char4regexeq(uint32 arg1, struct varlena *p)
+{
+ char *s = (char *) &arg1;
+ return (fixedlen_regexeq(s, p, 4, REG_EXTENDED));
+}
+
+bool
+char4regexne(uint32 arg1, struct varlena *p)
+{
+ return (!char4regexeq(arg1, p));
+}
+
+bool
+char8regexeq(char *s, struct varlena *p)
+{
+ return (fixedlen_regexeq(s, p, 8, REG_EXTENDED));
+}
+
+bool
+char8regexne(char *s, struct varlena *p)
+{
+ return (!char8regexeq(s, p));
+}
+
+bool
+char16regexeq(char *s, struct varlena *p)
+{
+ return (fixedlen_regexeq(s, p, 16, REG_EXTENDED));
+}
+
+bool
+char16regexne(char *s, struct varlena *p)
+{
+ return (!char16regexeq(s, p));
+}
+
+bool
+nameregexeq(NameData *n, struct varlena *p)
+{
+ return (fixedlen_regexeq(n->data, p, NAMEDATALEN, REG_EXTENDED));
+}
+bool
+nameregexne(NameData *s, struct varlena *p)
+{
+ return (!nameregexeq(s, p));
+}
+
+bool
+textregexeq(struct varlena *s, struct varlena *p)
+{
+ return (fixedlen_regexeq(VARDATA(s), p, VARSIZE(s) - VARHDRSZ, REG_EXTENDED));
+}
+
+bool
+textregexne(struct varlena *s, struct varlena *p)
+{
+ return (!textregexeq(s, p));
+}
+
+
+/*
+* routines that use the regexp stuff, but ignore the case.
+ * for this, we use the REG_ICASE flag to pg95_regcomp
+ */
+bool
+char2icregexeq(uint16 arg1, struct varlena *p)
+{
+ char *s = (char *) &arg1;
+ return (fixedlen_regexeq(s, p, 2, REG_ICASE | REG_EXTENDED));
+}
+
+
+bool
+char2icregexne(uint16 arg1, struct varlena *p)
+{
+ return (!char2icregexeq(arg1, p));
+}
+
+bool
+char4icregexeq(uint32 arg1, struct varlena *p)
+{
+ char *s = (char *) &arg1;
+ return (fixedlen_regexeq(s, p, 4, REG_ICASE | REG_EXTENDED ));
+}
+
+bool
+char4icregexne(uint32 arg1, struct varlena *p)
+{
+ return (!char4icregexeq(arg1, p));
+}
+
+bool
+char8icregexeq(char *s, struct varlena *p)
+{
+ return (fixedlen_regexeq(s, p, 8, REG_ICASE | REG_EXTENDED));
+}
+
+bool
+char8icregexne(char *s, struct varlena *p)
+{
+ return (!char8icregexeq(s, p));
+}
+
+bool
+char16icregexeq(char *s, struct varlena *p)
+{
+ return (fixedlen_regexeq(s, p, 16, REG_ICASE | REG_EXTENDED));
+}
+
+bool
+char16icregexne(char *s, struct varlena *p)
+{
+ return (!char16icregexeq(s, p));
+}
+
+bool
+texticregexeq(struct varlena *s, struct varlena *p)
+{
+ return (fixedlen_regexeq(VARDATA(s), p, VARSIZE(s) - VARHDRSZ,
+ REG_ICASE | REG_EXTENDED));
+}
+
+bool
+texticregexne(struct varlena *s, struct varlena *p)
+{
+ return (!texticregexeq(s, p));
+}
+
+bool
+nameicregexeq(NameData *n, struct varlena *p)
+{
+ return (fixedlen_regexeq(n->data, p, NAMEDATALEN,
+ REG_ICASE | REG_EXTENDED));
+}
+bool
+nameicregexne(NameData *s, struct varlena *p)
+{
+ return (!nameicregexeq(s, p));
+}
+