#include #include #include #include #include #include #include #include #include #include #include #include "sqlite3ext.h" SQLITE_EXTENSION_INIT1 static const char * error_str( int erc ) { switch(erc) { case REG_NOMATCH: return "regexec() failed to match"; case REG_BADPAT: return "invalid regular expression"; case REG_ECOLLATE: return "invalid collating element"; case REG_ECTYPE: return "invalid character class"; case REG_EESCAPE: return "applied to unescapable character"; case REG_ESUBREG: return "invalid backreference number"; case REG_EBRACK: return "brackets [ ] not balanced"; case REG_EPAREN: return "parentheses ( ) not balanced"; case REG_EBRACE: return "braces { } not balanced"; case REG_BADBR: return "invalid repetition count(s) in { }"; case REG_ERANGE: return "invalid character range in [ ]"; case REG_ESPACE: return "ran out of memory"; case REG_BADRPT: return "or + operand invalid"; case REG_EMPTY: return "empty (sub)expression"; case REG_ASSERT: return "can't happen''--you found a bug"; case REG_INVARG: return "invalid argument, e.g. negative-length string"; } assert(0); return "invalid return code from regex(3)"; } static void local_free(void *preg) { regfree( (regex_t *)preg); } static void regex( sqlite3_context* context, int argc, sqlite3_value** argv ) { enum { flags = REG_EXTENDED | REG_NOSUB, nmatch = 1 }; static const char TF[2] = { 'F', 'T' }; const char *tf = TF; const char * pattern = (const char *)sqlite3_value_text(argv[0]); const char * data = (const char *)sqlite3_value_text(argv[1]); int erc; regmatch_t pmatch[nmatch]; if( pattern == NULL || data == NULL ) { sqlite3_result_text(context, tf, 1, SQLITE_STATIC); return; } regex_t *preg = sqlite3_get_auxdata(context, 0); if( preg == NULL ) { if( (preg = sqlite3_malloc(sizeof(*preg))) == NULL ) { sqlite3_result_error_nomem(context); return; } if( (erc = regcomp(preg, pattern, flags)) != 0) { char *msg = sqlite3_mprintf("regcomp: %s", error_str(erc)); sqlite3_result_error(context, msg, SQLITE_ERROR); sqlite3_free(msg); sqlite3_free(preg); return; } sqlite3_set_auxdata(context, 0, preg, local_free); } if( (erc = regexec(preg, data, nmatch, pmatch, 0)) != 0 ) { if( erc != REG_NOMATCH ) { char *msg = sqlite3_mprintf("regcomp: %s", error_str(erc)); sqlite3_result_error(context, msg, SQLITE_ERROR); sqlite3_free(msg); sqlite3_free(preg); return; } } else { /* found a match */ tf++; } sqlite3_result_text(context, tf, 1, SQLITE_STATIC); } struct func_desc_t { const char *name; int narg; void *papp; void (*xfunc)(sqlite3_context*,int,sqlite3_value**); void (*xstep)(sqlite3_context*,int,sqlite3_value**); void (*xfinal)(sqlite3_context*); }; /* * functions implemented */ static struct func_desc_t functions[] = { { "regex", 2, NULL, regex, NULL, NULL } }; static size_t nfunctions = sizeof(functions)/sizeof(functions[0]); enum { eTextRep=SQLITE_UTF8 }; /* * Register functions and the virtual table. */ static int register_functions(sqlite3 *db) { int erc = SQLITE_OK; struct func_desc_t *pf; for( pf=functions; pf < functions + nfunctions; pf++ ) { erc = sqlite3_create_function( db, pf->name, pf->narg, eTextRep, pf->papp, pf->xfunc, pf->xstep, pf->xfinal ); if( erc != SQLITE_OK ) { sqlite3_log(erc, "error loading UDF '%s'", pf->name); return erc; } } return SQLITE_OK; } /* * Extension load function. */ int sqlite3_extension_init( sqlite3 *db, char **pzErrMsg, const sqlite3_api_routines *pApi ) { SQLITE_EXTENSION_INIT2(pApi); return register_functions(db); }