Files

252 lines
7.9 KiB
Diff

Patch made with:
https://github.com/christian-proust/sqlite3-pcre2/blob/e3e02a4af39d5dfdbd2cc8801696ed9ae2faf569/pcre2.c
with the additional change to 'const unsigned char *pattern_str, *subject_str;'.
--- pcre.c.orig 2023-06-14 08:44:05.000000000 +0200
+++ pcre.c 2023-06-14 09:01:48.000000000 +0200
@@ -1,22 +1,24 @@
/*
- * Written by Alexey Tourbin <at@altlinux.org>.
+ * Initially written by Alexey Tourbin <at@altlinux.org>.
*
* The author has dedicated the code to the public domain. Anyone is free
* to copy, modify, publish, use, compile, sell, or distribute the original
* code, either in source code form or as a compiled binary, for any purpose,
* commercial or non-commercial, and by any means.
*/
+#define PCRE2_CODE_UNIT_WIDTH 8
#include <assert.h>
#include <stdlib.h>
#include <string.h>
-#include <pcre.h>
+#include <pcre2.h>
#include <sqlite3ext.h>
+
SQLITE_EXTENSION_INIT1
typedef struct {
- char *s;
- pcre *p;
- pcre_extra *e;
+ char *pattern_str;
+ int pattern_len;
+ pcre2_code *pattern_code;
} cache_entry;
#ifndef CACHE_SIZE
@@ -24,96 +26,136 @@
#endif
static
-void regexp(sqlite3_context *ctx, int argc, sqlite3_value **argv)
-{
- const char *re, *str;
- pcre *p;
- pcre_extra *e;
+void regexp(sqlite3_context *ctx, int argc, sqlite3_value **argv) {
+ const unsigned char *pattern_str, *subject_str;
+ int pattern_len, subject_len;
+ pcre2_code *pattern_code;
assert(argc == 2);
+ /* check null */
+ if (sqlite3_value_type(argv[0]) == SQLITE_NULL || sqlite3_value_type(argv[1]) == SQLITE_NULL) {
+ return;
+ }
- re = (const char *) sqlite3_value_text(argv[0]);
- if (!re) {
- sqlite3_result_error(ctx, "no regexp", -1);
- return;
+ pattern_str = sqlite3_value_text(argv[0]);
+ if (!pattern_str) {
+ sqlite3_result_error(ctx, "no pattern", -1);
+ return;
}
+ pattern_len = sqlite3_value_bytes(argv[0]);
- str = (const char *) sqlite3_value_text(argv[1]);
- if (!str) {
- sqlite3_result_error(ctx, "no string", -1);
- return;
+ subject_str = sqlite3_value_text(argv[1]);
+ if (!subject_str) {
+ sqlite3_result_error(ctx, "no subject", -1);
+ return;
}
+ subject_len = sqlite3_value_bytes(argv[1]);
/* simple LRU cache */
{
- int i;
- int found = 0;
- cache_entry *cache = sqlite3_user_data(ctx);
-
- 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;
+ int i;
+ int found = 0;
+ cache_entry *cache = sqlite3_user_data(ctx);
+
+ assert(cache);
+
+ for (i = 0; i < CACHE_SIZE && cache[i].pattern_str; i++)
+ if (
+ pattern_len == cache[i].pattern_len
+ && memcmp(pattern_str, cache[i].pattern_str, pattern_len) == 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 error_code;
+ PCRE2_SIZE error_position;
+ c.pattern_code = pcre2_compile(
+ pattern_str, /* the pattern */
+ pattern_len, /* the length of the pattern */
+ 0, /* default options */
+ &error_code, /* for error number */
+ &error_position, /* for error offset */
+ NULL); /* use default compile context */
+ if (!c.pattern_code) {
+ PCRE2_UCHAR error_buffer[256];
+ pcre2_get_error_message(error_code, error_buffer, sizeof(error_buffer));
+ char *e2 = sqlite3_mprintf(
+ "Cannot compile pattern \"%s\" at offset %d: %s",
+ pattern_str, (int)error_position, error_buffer);
+ sqlite3_result_error(ctx, e2, -1);
+ sqlite3_free(e2);
+ return;
+ }
+ c.pattern_str = malloc(pattern_len);
+ if (!c.pattern_str) {
+ sqlite3_result_error(ctx, "malloc: ENOMEM", -1);
+ pcre2_code_free(c.pattern_code);
+ return;
+ }
+ memcpy(c.pattern_str, pattern_str, pattern_len);
+ c.pattern_len = pattern_len;
+ i = CACHE_SIZE - 1;
+ if (cache[i].pattern_str) {
+ free(cache[i].pattern_str);
+ assert(cache[i].pattern_code);
+ pcre2_code_free(cache[i].pattern_code);
+ }
+ memmove(cache + 1, cache, i * sizeof(cache_entry));
+ cache[0] = c;
+ }
+ pattern_code = cache[0].pattern_code;
}
{
- 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;
+ pcre2_match_data *match_data;
+ assert(pattern_code);
+
+ match_data = pcre2_match_data_create_from_pattern(pattern_code, NULL);
+ rc = pcre2_match(
+ pattern_code, /* the compiled pattern */
+ subject_str, /* the subject string */
+ subject_len, /* the length of the subject */
+ 0, /* start at offset 0 in the subject */
+ 0, /* default options */
+ match_data, /* block for storing the result */
+ NULL); /* use default match context */
+
+ assert(rc != 0); // because we have not set match_data
+ if(rc >= 0) {
+ // Normal case because we have not set match_data
+ sqlite3_result_int(ctx, 1);
+ } else if(rc == PCRE2_ERROR_NOMATCH) {
+ sqlite3_result_int(ctx, 0);
+ } else { // (rc < 0 and the code is not one of the above)
+ PCRE2_UCHAR error_buffer[256];
+ pcre2_get_error_message(rc, error_buffer, sizeof(error_buffer));
+ char *e2 = sqlite3_mprintf("%s", error_buffer);
+ sqlite3_result_error(ctx, e2, -1);
+ sqlite3_free(e2);
+ return;
+ }
+ pcre2_match_data_free(match_data);
+ 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;
}