Bladeren bron

"add built-in REGEXP function to SQLite"

Ralf S. Engelschall 16 jaren geleden
bovenliggende
commit
1693ab9773
2 gewijzigde bestanden met toevoegingen van 201 en 11 verwijderingen
  1. 196 10
      sqlite/sqlite.patch
  2. 5 1
      sqlite/sqlite.spec

+ 196 - 10
sqlite/sqlite.patch

@@ -1,7 +1,7 @@
 Index: Makefile.in
---- Makefile.in.orig	2009-07-06 16:29:57 +0200
-+++ Makefile.in	2009-08-12 20:12:13 +0200
-@@ -187,6 +187,17 @@
+--- Makefile.in.orig	2010-01-05 01:02:40 +0100
++++ Makefile.in	2010-01-30 20:42:09 +0100
+@@ -187,6 +187,23 @@
  USE_AMALGAMATION = @USE_AMALGAMATION@
  LIBOBJ = $(OBJS$(USE_AMALGAMATION))
  
@@ -15,16 +15,31 @@ Index: Makefile.in
 +ifdef RTREE
 +TCC    += -DSQLITE_ENABLE_RTREE -I$(TOP)/ext/rtree
 +LIBOBJ += rtree.lo
++endif
++
++# REGEXP support
++ifdef REGEXP
++TCC    += -DSQLITE_ENABLE_REGEXP
++LIBOBJ += regexp.lo
 +endif
  
  # All of the source code files.
  #
-@@ -477,6 +488,24 @@
+@@ -329,6 +346,8 @@
+ SRC += \
+   $(TOP)/ext/rtree/rtree.h \
+   $(TOP)/ext/rtree/rtree.c
++SRC += \
++  $(TOP)/ext/regexp/regexp.c
+ 
+ # Source code to the library files needed by the test fixture
+ #
+@@ -477,6 +496,27 @@
  		-o $@ $(TOP)/src/shell.c libsqlite3.la \
  		$(LIBREADLINE) $(TLIBS) -rpath "$(libdir)"
  
 +fts3.lo:	$(TOP)/ext/fts3/fts3.c $(HDR)
-+	$(LTCOMPILE) -c $(TOP)/ext/fts3/fts3.c
++	$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/fts3/fts3.c
 +fts3_hash.lo:	$(TOP)/ext/fts3/fts3_hash.c $(HDR)
 +	$(LTCOMPILE) -c $(TOP)/ext/fts3/fts3_hash.c
 +fts3_expr.lo:	$(TOP)/ext/fts3/fts3_expr.c $(HDR)
@@ -39,14 +54,17 @@ Index: Makefile.in
 +	$(LTCOMPILE) -c $(TOP)/ext/fts3/fts3_tokenizer1.c
 +
 +rtree.lo:	$(TOP)/ext/rtree/rtree.c $(HDR)
-+	$(LTCOMPILE) -c $(TOP)/ext/rtree/rtree.c
++	$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/rtree/rtree.c
++
++regexp.lo:	$(TOP)/ext/regexp/regexp.c $(HDR)
++	$(LTCOMPILE) -DSQLITE_CORE -c $(TOP)/ext/regexp/regexp.c
 +
  # This target creates a directory named "tsrc" and fills it with
  # copies of all of the C source code and header files needed to
  # build on the target system.  Some of the C source code and header
 Index: configure
---- configure.orig	2009-08-01 17:04:20 +0200
-+++ configure	2009-08-12 20:12:13 +0200
+--- configure.orig	2010-01-05 01:02:40 +0100
++++ configure	2010-01-30 20:00:15 +0100
 @@ -6012,11 +6012,7 @@
  if $ac_preproc_ok; then
    :
@@ -60,9 +78,160 @@ Index: configure
  fi
  
  ac_ext=c
+Index: ext/regexp/regexp.c
+--- ext/regexp/regexp.c.orig	2010-01-30 20:00:15 +0100
++++ ext/regexp/regexp.c	2010-01-30 20:43:01 +0100
+@@ -0,0 +1,147 @@
++/*
++ * SQLite REGEXP(regex, string) function
++ * Copyright (c) 2010 by Ralf S. Engelschall <rse@engelschall.com>
++ *
++ * Based on Public Domain code from 2007 by Alexey Tourbin
++ * <at@altlinux.org> which added plain PCRE based REGEXP function to
++ * SQLite. In order to not require the SQLite _library_ to require the
++ * external PCRE library, the code was adapted to the regex(3) API as
++ * standardized by IEEE Std 1003.2 ("POSIX.2"), sections 2.8 (Regular
++ * Expression Notation) and B.5 (C Binding for Regular Expression
++ * Matching) and which is usually provided already by any modern Unix
++ * system in libc.
++ */
++
++#if !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_REGEXP)
++
++/*  standard includes  */
++#include <assert.h>
++#include <stdlib.h>
++#include <string.h>
++#include <regex.h>
++
++/*  SQLite includes  */
++#ifndef SQLITE_CORE
++#include "sqlite3ext.h"
++SQLITE_EXTENSION_INIT1
++#else
++#include "sqlite3.h"
++#endif
++
++/*  regex cache configuration  */ 
++#ifndef CACHE_SIZE
++#define CACHE_SIZE 32
++#endif
++typedef struct {
++    char    *str;
++    regex_t  re;
++} cache_entry;
++
++/*  the SQL REGEXP(regex, string) function C implementation  */
++static void regexp(sqlite3_context *ctx, int argc, sqlite3_value **argv)
++{
++    const char *re_str, *str;
++    regex_t *re;
++    int i;
++    int rc;
++    int found;
++    cache_entry *cache;
++    cache_entry c;
++    char err[1024];
++
++    /*  sanity check arguments  */
++    if (argc != 2) {
++        sqlite3_result_error(ctx, "invalid number of arguments to REGEXP function", -1);
++        return;
++    }
++    if ((re_str = (const char *)sqlite3_value_text(argv[0])) == NULL) {
++        sqlite3_result_error(ctx, "no regexp argument given to REGEXP function", -1);
++        return;
++    }
++    if ((str = (const char *)sqlite3_value_text(argv[1])) == NULL) {
++        sqlite3_result_error(ctx, "no string argument given to REGEXP function", -1);
++        return;
++    }
++
++    /*  simple regex LRU caching  */
++    if ((cache = sqlite3_user_data(ctx)) == NULL) {
++        sqlite3_result_error(ctx, "no regex cache available", -1);
++        return;
++    }
++    found = 0;
++    for (i = 0; i < CACHE_SIZE && cache[i].str != NULL; i++) {
++        if (strcmp(re_str, cache[i].str) == 0) {
++            found = 1;
++            break;
++        }
++    }
++    if (found) {
++        if (i > 0) {
++            /*  move cache[i] element to front for faster searching next time  */
++            c = cache[i];
++            memmove(cache + 1, cache, i * sizeof(cache_entry));
++            cache[0] = c;
++        }
++    }
++    else {
++        /*  compile and store regular expression  */
++        int rc = regcomp(&(c.re), re_str, REG_EXTENDED|REG_NOSUB);
++        if (rc != 0) {
++            regerror(rc, &(c.re), err, sizeof(err));
++            char *e2 = sqlite3_mprintf("regex \"%s\" failed to compile: %s", re_str, err);
++            sqlite3_result_error(ctx, e2, -1);
++            sqlite3_free(e2);
++            return;
++        }
++        if ((c.str = strdup(re_str)) == NULL) {
++            sqlite3_result_error(ctx, "strdup: ENOMEM", -1);
++            regfree(&(c.re));
++            return;
++        }
++
++        /*  insert regex into cache (at first position)  */
++        i = CACHE_SIZE - 1;
++        if (cache[i].str != NULL) {
++            /*  expire oldest cache entry  */
++            free(cache[i].str);
++            regfree(&(cache[i].re));
++        }
++        memmove(cache + 1, cache, i * sizeof(cache_entry));
++        cache[0] = c;
++    }
++
++    /*  take compiled regular expression (either found old one or created new one)  */
++    re = &(cache[0].re);
++
++    /*  apply regular expression onto given string and report matching result  */
++    rc = regexec(re, str, 0, NULL, 0);
++    sqlite3_result_int(ctx, rc == 0);
++
++    return;
++}
++
++/*  SQLITE_CORE (built-in) entry point  */
++int sqlite3RegexpInit(sqlite3 *);
++int sqlite3RegexpInit(sqlite3 *db)
++{
++    cache_entry *cache = NULL;
++    int rc = SQLITE_OK;
++
++    if ((cache = calloc(CACHE_SIZE, sizeof(cache_entry))) == NULL)
++        return SQLITE_NOMEM;
++    rc = sqlite3_create_function(db, "REGEXP", 2, SQLITE_UTF8, cache, regexp, NULL, NULL);
++    return rc;
++}
++
++#ifndef SQLITE_CORE
++/*  DSO entry point  */
++int sqlite3_extension_init(sqlite3 *, char **, const sqlite3_api_routines *);
++int sqlite3_extension_init(sqlite3 *db, char **err, const sqlite3_api_routines *api)
++{
++    SQLITE_EXTENSION_INIT2(api)
++    return sqlite3RegexpInit(db);
++}
++#endif
++
++#endif
++
 Index: sqlite3.pc.in
---- sqlite3.pc.in.orig	2009-05-05 05:39:51 +0200
-+++ sqlite3.pc.in	2009-08-12 20:12:13 +0200
+--- sqlite3.pc.in.orig	2009-09-03 22:32:06 +0200
++++ sqlite3.pc.in	2010-01-30 20:00:15 +0100
 @@ -8,6 +8,5 @@
  Name: SQLite
  Description: SQL database engine
@@ -71,3 +240,20 @@ Index: sqlite3.pc.in
 -Libs.private: @LIBS@
 +Libs: -L${libdir} -lsqlite3 @LIBS@
  Cflags: -I${includedir}
+Index: src/main.c
+--- src/main.c.orig	2010-01-05 01:02:40 +0100
++++ src/main.c	2010-01-30 20:43:26 +0100
+@@ -1715,6 +1715,13 @@
+   }
+ #endif
+ 
++#ifdef SQLITE_ENABLE_REGEXP
++  if( !db->mallocFailed && rc==SQLITE_OK){
++    extern int sqlite3RegexpInit(sqlite3*);
++    rc = sqlite3RegexpInit(db);
++  }
++#endif
++
+   sqlite3Error(db, rc, 0);
+ 
+   /* -DSQLITE_DEFAULT_LOCKING_MODE=1 makes EXCLUSIVE the default locking

+ 5 - 1
sqlite/sqlite.spec

@@ -37,7 +37,7 @@ Class:        BASE
 Group:        Database
 License:      PD
 Version:      %{V_sqlite}
-Release:      20100113
+Release:      20100130
 
 #   package options
 %option       with_debug           no
@@ -47,6 +47,7 @@ Release:      20100113
 %option       with_rtree           no
 %option       with_odbc            no
 %option       with_jdbc            no
+%option       with_regexp          yes
 
 #   list of sources
 Source0:      http://www.sqlite.org/sqlite-%{V_sqlite}.tar.gz
@@ -150,6 +151,9 @@ AutoReqProv:  no
         --disable-amalgamation \
         --disable-shared
     MFLAGS=""
+%if "%{with_regexp}" == "yes"
+    MFLAGS="$MFLAGS REGEXP=1"
+%endif
 %if "%{with_fts3}" == "yes"
     MFLAGS="$MFLAGS FTS3=1"
 %endif