Skip to content

Commit

Permalink
modified to work with MacOS (High Sierra, at least)
Browse files Browse the repository at this point in the history
  • Loading branch information
MatthewWolff committed Mar 9, 2020
1 parent c98da41 commit abe435b
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 77 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.idea/
*.so
4 changes: 2 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ prefix=/usr
.PHONY : install dist clean

pcre.so : pcre.c
${CC} -shared -o $@ ${CFLAGS} -W -Werror pcre.c ${LIBS} -Wl,-z,defs
${CC} -shared -o $@ ${CFLAGS} -W -Werror pcre.c ${LIBS}

install : pcre.so
${INSTALL} -pD -m755 pcre.so ${DESTDIR}${prefix}/lib/sqlite3/pcre.so
sudo ${INSTALL} -p pcre.so ${prefix}/lib/sqlite3/pcre.so

dist : clean
mkdir sqlite3-pcre-${VERSION}
Expand Down
29 changes: 29 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Sqlite3-pcre: Regex Extension (MacOS Version)
This is sqlite3-pcre, an extension for sqlite3 that uses libpcre to provide the REGEXP() function.

The original source code was written by Alexey Tourbin and can be found at:

[http:https://git.altlinux.org/people/at/packages/?p=sqlite3-pcre.git](http:https://git.altlinux.org/people/at/packages/?p=sqlite3-pcre.git)

## 2020 UPDATE:
Updated to work with MacOS. Modified the Makefile to compile and install on MacOS, changed C source code to get rid of "no string" error.

## Usage
```bash
git clone https://github.com/MatthewWolff/sqlite3-pcre
cd sqlite3-pcre
make
make install
```

You can then define a command line function to search whatever database you desire—I wanted to search all my iMessages.
```bash
search_messages() {
regex="$@"
database="$HOME/library/messages/chat.db"
use_extension=".load /usr/lib/sqlite3/pcre.so"
query="SELECT text FROM message WHERE text REGEXP '$regex'"
sqlite3 "$database" -cmd "$use_extension" "$query"
}
```

135 changes: 67 additions & 68 deletions pcre.c
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include <string.h>
#include <pcre.h>
#include <sqlite3ext.h>

SQLITE_EXTENSION_INIT1

typedef struct {
Expand All @@ -24,8 +25,7 @@ typedef struct {
#endif

static
void regexp(sqlite3_context *ctx, int argc, sqlite3_value **argv)
{
void regexp(sqlite3_context *ctx, int argc, sqlite3_value **argv) {
const char *re, *str;
pcre *p;
pcre_extra *e;
Expand All @@ -34,86 +34,85 @@ void regexp(sqlite3_context *ctx, int argc, sqlite3_value **argv)

re = (const char *) sqlite3_value_text(argv[0]);
if (!re) {
sqlite3_result_error(ctx, "no regexp", -1);
return;
sqlite3_result_error(ctx, "no regexp", -1);
return;
}

str = (const char *) sqlite3_value_text(argv[1]);
if (!str) {
sqlite3_result_error(ctx, "no string", -1);
return;
// sqlite3_result_error(ctx, "no string", -1);
sqlite3_result_int(ctx, 0); // if no string, just say no match found
return;
}

/* simple LRU cache */
{
int i;
int found = 0;
cache_entry *cache = sqlite3_user_data(ctx);
int i;
int found = 0;
cache_entry *cache = sqlite3_user_data(ctx);

assert(cache);
assert(cache);

for (i = 0; i < CACHE_SIZE && cache[i].s; i++)
if (strcmp(re, cache[i].s) == 0) {
found = 1;
break;
}
if (found) {
if (i > 0) {
cache_entry c = cache[i];
memmove(cache + 1, cache, i * sizeof(cache_entry));
cache[0] = c;
}
}
else {
cache_entry c;
const char *err;
int pos;
c.p = pcre_compile(re, 0, &err, &pos, NULL);
if (!c.p) {
char *e2 = sqlite3_mprintf("%s: %s (offset %d)", re, err, pos);
sqlite3_result_error(ctx, e2, -1);
sqlite3_free(e2);
return;
}
c.e = pcre_study(c.p, 0, &err);
c.s = strdup(re);
if (!c.s) {
sqlite3_result_error(ctx, "strdup: ENOMEM", -1);
pcre_free(c.p);
pcre_free(c.e);
return;
}
i = CACHE_SIZE - 1;
if (cache[i].s) {
free(cache[i].s);
assert(cache[i].p);
pcre_free(cache[i].p);
pcre_free(cache[i].e);
}
memmove(cache + 1, cache, i * sizeof(cache_entry));
cache[0] = c;
}
p = cache[0].p;
e = cache[0].e;
for (i = 0; i < CACHE_SIZE && cache[i].s; i++)
if (strcmp(re, cache[i].s) == 0) {
found = 1;
break;
}
if (found) {
if (i > 0) {
cache_entry c = cache[i];
memmove(cache + 1, cache, i * sizeof(cache_entry));
cache[0] = c;
}
} else {
cache_entry c;
const char *err;
int pos;
c.p = pcre_compile(re, 0, &err, &pos, NULL);
if (!c.p) {
char *e2 = sqlite3_mprintf("%s: %s (offset %d)", re, err, pos);
sqlite3_result_error(ctx, e2, -1);
sqlite3_free(e2);
return;
}
c.e = pcre_study(c.p, 0, &err);
c.s = strdup(re);
if (!c.s) {
sqlite3_result_error(ctx, "strdup: ENOMEM", -1);
pcre_free(c.p);
pcre_free(c.e);
return;
}
i = CACHE_SIZE - 1;
if (cache[i].s) {
free(cache[i].s);
assert(cache[i].p);
pcre_free(cache[i].p);
pcre_free(cache[i].e);
}
memmove(cache + 1, cache, i * sizeof(cache_entry));
cache[0] = c;
}
p = cache[0].p;
e = cache[0].e;
}

{
int rc;
assert(p);
rc = pcre_exec(p, e, str, strlen(str), 0, 0, NULL, 0);
sqlite3_result_int(ctx, rc >= 0);
return;
int rc;
assert(p);
rc = pcre_exec(p, e, str, strlen(str), 0, 0, NULL, 0);
sqlite3_result_int(ctx, rc >= 0);
return;
}
}

int sqlite3_extension_init(sqlite3 *db, char **err, const sqlite3_api_routines *api)
{
SQLITE_EXTENSION_INIT2(api)
cache_entry *cache = calloc(CACHE_SIZE, sizeof(cache_entry));
if (!cache) {
*err = "calloc: ENOMEM";
return 1;
}
sqlite3_create_function(db, "REGEXP", 2, SQLITE_UTF8, cache, regexp, NULL, NULL);
return 0;
int sqlite3_extension_init(sqlite3 *db, char **err, const sqlite3_api_routines *api) {
SQLITE_EXTENSION_INIT2(api)
cache_entry *cache = calloc(CACHE_SIZE, sizeof(cache_entry));
if (!cache) {
*err = "calloc: ENOMEM";
return 1;
}
sqlite3_create_function(db, "REGEXP", 2, SQLITE_UTF8, cache, regexp, NULL, NULL);
return 0;
}
7 changes: 0 additions & 7 deletions readme.txt

This file was deleted.

0 comments on commit abe435b

Please sign in to comment.