static void pkgdb_regex(sqlite3_context *ctx, int argc, sqlite3_value **argv, int reg_type) { const unsigned char *regex = NULL; const unsigned char *str; regex_t *re; int ret; if (argc != 2 || (regex = sqlite3_value_text(argv[0])) == NULL || (str = sqlite3_value_text(argv[1])) == NULL) { sqlite3_result_error(ctx, "SQL function regex() called with invalid arguments.\n", -1); return; } re = (regex_t *)sqlite3_get_auxdata(ctx, 0); if (re == NULL) { re = malloc(sizeof(regex_t)); if (regcomp(re, regex, reg_type | REG_NOSUB) != 0) { sqlite3_result_error(ctx, "Invalid regex\n", -1); free(re); return; } sqlite3_set_auxdata(ctx, 0, re, pkgdb_regex_delete); } ret = regexec(re, str, 0, NULL, 0); sqlite3_result_int(ctx, (ret != REG_NOMATCH)); }
static void test_auxdata( sqlite3_context *pCtx, int nArg, sqlite3_value **argv ){ int i; char *zRet = sqliteMalloc(nArg*2); if( !zRet ) return; for(i=0; i<nArg; i++){ char const *z = (char*)sqlite3_value_text(argv[i]); if( z ){ char *zAux = sqlite3_get_auxdata(pCtx, i); if( zAux ){ zRet[i*2] = '1'; if( strcmp(zAux, z) ){ sqlite3_result_error(pCtx, "Auxilary data corruption", -1); return; } }else{ zRet[i*2] = '0'; zAux = sqliteStrDup(z); sqlite3_set_auxdata(pCtx, i, zAux, free_test_auxdata); } zRet[i*2+1] = ' '; } } sqlite3_result_text(pCtx, zRet, 2*nArg-1, free_test_auxdata); }
static void test_auxdata( sqlite3_context *pCtx, int nArg, sqlite3_value **argv ){ int i; char *zRet = testContextMalloc(pCtx, nArg*2); if( !zRet ) return; memset(zRet, 0, nArg*2); for(i=0; i<nArg; i++){ char const *z = (char*)sqlite3_value_text(argv[i]); if( z ){ int n; char *zAux = sqlite3_get_auxdata(pCtx, i); if( zAux ){ zRet[i*2] = '1'; assert( strcmp(zAux,z)==0 ); }else { zRet[i*2] = '0'; } n = strlen(z) + 1; zAux = testContextMalloc(pCtx, n); if( zAux ){ memcpy(zAux, z, n); sqlite3_set_auxdata(pCtx, i, zAux, free_test_auxdata); } zRet[i*2+1] = ' '; } } sqlite3_result_text(pCtx, zRet, 2*nArg-1, free_test_auxdata); }
/* ** Implementation of SQLite REGEXP operator. This scalar function takes ** two arguments. The first is a regular expression pattern to compile ** the second is a string to match against that pattern. If either ** argument is an SQL NULL, then NULL Is returned. Otherwise, the result ** is 1 if the string matches the pattern, or 0 otherwise. ** ** SQLite maps the regexp() function to the regexp() operator such ** that the following two are equivalent: ** ** zString REGEXP zPattern ** regexp(zPattern, zString) ** ** Uses the following ICU regexp APIs: ** ** uregex_open() ** uregex_matches() ** uregex_close() */ static void icuRegexpFunc(sqlite3_context *p, int nArg, sqlite3_value **apArg){ UErrorCode status = U_ZERO_ERROR; URegularExpression *pExpr; UBool res; const UChar *zString = sqlite3_value_text16(apArg[1]); (void)nArg; /* Unused parameter */ /* If the left hand side of the regexp operator is NULL, ** then the result is also NULL. */ if( !zString ){ return; } pExpr = sqlite3_get_auxdata(p, 0); if( !pExpr ){ const UChar *zPattern = sqlite3_value_text16(apArg[0]); if( !zPattern ){ return; } pExpr = uregex_open(zPattern, -1, 0, 0, &status); if( U_SUCCESS(status) ){ sqlite3_set_auxdata(p, 0, pExpr, icuRegexpDelete); }else{ assert(!pExpr); icuFunctionError(p, "uregex_open", status); return; } } /* Configure the text that the regular expression operates on. */ uregex_setText(pExpr, zString, -1, &status); if( !U_SUCCESS(status) ){ icuFunctionError(p, "uregex_setText", status); return; } /* Attempt the match */ res = uregex_matches(pExpr, 0, &status); if( !U_SUCCESS(status) ){ icuFunctionError(p, "uregex_matches", status); return; } /* Set the text that the regular expression operates on to a NULL ** pointer. This is not really necessary, but it is tidier than ** leaving the regular expression object configured with an invalid ** pointer after this function returns. */ uregex_setText(pExpr, 0, 0, &status); /* Return 1 or 0. */ sqlite3_result_int(p, res ? 1 : 0); }
ikptr ik_sqlite3_get_auxdata (ikptr s_context, ikptr s_argnum, ikpcb * pcb) { #ifdef HAVE_SQLITE3_GET_AUXDATA sqlite3_context * context = IK_SQLITE_CONTEXT(s_context); int argnum = ik_integer_to_int(s_argnum); void * aux_data; aux_data = sqlite3_get_auxdata(context, argnum); return (aux_data)? ika_pointer_alloc(pcb, (ik_ulong)aux_data) : IK_FALSE_OBJECT; #else feature_failure(__func__); #endif }
/* ** Implementation of the counter(X) function. If X is an integer ** constant, then the first invocation will return X. The second X+1. ** and so forth. Can be used (for example) to provide a sequence number ** in a result set. */ static void counterFunc( sqlite3_context *pCtx, /* Function context */ int nArg, /* Number of function arguments */ sqlite3_value **argv /* Values for all function arguments */ ){ int *pCounter = (int*)sqlite3_get_auxdata(pCtx, 0); if( pCounter==0 ){ pCounter = sqlite3_malloc( sizeof(*pCounter) ); if( pCounter==0 ){ sqlite3_result_error_nomem(pCtx); return; } *pCounter = sqlite3_value_int(argv[0]); sqlite3_set_auxdata(pCtx, 0, pCounter, sqlite3_free); }else{ ++*pCounter; } sqlite3_result_int(pCtx, *pCounter); }
static void geometry_constructor(sqlite3_context *context, const spatialdb_t *spatialdb, geometry_constructor_func constructor, void* user_data, geom_type_t requiredType, int nbArgs, sqlite3_value **args) { FUNCTION_START_STATIC(context, 256); geom_blob_auxdata *geom = (geom_blob_auxdata *)sqlite3_get_auxdata(context, 0); if (geom == NULL) { geom_blob_writer_t writer; if (sqlite3_value_type(args[nbArgs - 1]) == SQLITE_INTEGER) { spatialdb->writer_init_srid(&writer, sqlite3_value_int(args[nbArgs - 1])); nbArgs -= 1; } else { spatialdb->writer_init(&writer); } FUNCTION_RESULT = constructor(context, user_data, geom_blob_writer_geom_consumer(&writer), nbArgs, args, FUNCTION_ERROR); if (FUNCTION_RESULT == SQLITE_OK) { if (geometry_is_assignable(requiredType, writer.geom_type, FUNCTION_ERROR) == SQLITE_OK) { uint8_t *data = geom_blob_writer_getdata(&writer); int length = (int) geom_blob_writer_length(&writer); sqlite3_result_blob(context, data, length, SQLITE_TRANSIENT); spatialdb->writer_destroy(&writer, 0); geom = geom_blob_auxdata_malloc(); if (geom != NULL) { geom->data = data; geom->length = length; sqlite3_set_auxdata(context, 0, geom, geom_blob_auxdata_free); } } } else { spatialdb->writer_destroy(&writer, 1); } } else { sqlite3_result_blob(context, geom->data, geom->length, SQLITE_TRANSIENT); } FUNCTION_END(context); }
/** * This function is invoked as: * * _TOKENIZE('<token_table>', <data_row_id>, <data>, <delimiter>, * <use_token_index>, <data_tag>) * * If <use_token_index> is omitted, it is treated as 0. * If <data_tag> is omitted, it is treated as NULL. * * It will split <data> on each instance of <delimiter> and insert each token * into <token_table>. The following columns in <token_table> are used: * token TEXT, source INTEGER, token_index INTEGER, tag (any type) * The token_index column is not required if <use_token_index> is 0. * The tag column is not required if <data_tag> is NULL. * * One row is inserted for each token in <data>. * In each inserted row, 'source' is <data_row_id>. * In the first inserted row, 'token' is the hex collation key of * the entire <data> string, and 'token_index' is 0. * In each row I (where 1 <= I < N, and N is the number of tokens in <data>) * 'token' will be set to the hex collation key of the I:th token (0-based). * If <use_token_index> != 0, 'token_index' is set to I. * If <data_tag> is not NULL, 'tag' is set to <data_tag>. * * In other words, there will be one row for the entire string, * and one row for each token except the first one. * * The function returns the number of tokens generated. */ static void tokenize(sqlite3_context * context, int argc, sqlite3_value ** argv) { //ALOGD("enter tokenize"); int err; int useTokenIndex = 0; int useDataTag = 0; if (!(argc >= 4 || argc <= 6)) { ALOGE("Tokenize requires 4 to 6 arguments"); sqlite3_result_null(context); return; } if (argc > 4) { useTokenIndex = sqlite3_value_int(argv[4]); } if (argc > 5) { useDataTag = (sqlite3_value_type(argv[5]) != SQLITE_NULL); } sqlite3 * handle = sqlite3_context_db_handle(context); UCollator* collator = (UCollator*)sqlite3_user_data(context); char const * tokenTable = (char const *)sqlite3_value_text(argv[0]); if (tokenTable == NULL) { ALOGE("tokenTable null"); sqlite3_result_null(context); return; } // Get or create the prepared statement for the insertions sqlite3_stmt * statement = (sqlite3_stmt *)sqlite3_get_auxdata(context, 0); if (!statement) { char const * tokenIndexCol = useTokenIndex ? ", token_index" : ""; char const * tokenIndexParam = useTokenIndex ? ", ?" : ""; char const * dataTagCol = useDataTag ? ", tag" : ""; char const * dataTagParam = useDataTag ? ", ?" : ""; char * sql = sqlite3_mprintf("INSERT INTO %s (token, source%s%s) VALUES (?, ?%s%s);", tokenTable, tokenIndexCol, dataTagCol, tokenIndexParam, dataTagParam); err = sqlite3_prepare_v2(handle, sql, -1, &statement, NULL); sqlite3_free(sql); if (err) { ALOGE("prepare failed"); sqlite3_result_null(context); return; } // This binds the statement to the table it was compiled against, which is argv[0]. // If this function is ever called with a different table the finalizer will be called // and sqlite3_get_auxdata() will return null above, forcing a recompile for the new table. sqlite3_set_auxdata(context, 0, statement, tokenize_auxdata_delete); } else { // Reset the cached statement so that binding the row ID will work properly sqlite3_reset(statement); } // Bind the row ID of the source row int64_t rowID = sqlite3_value_int64(argv[1]); err = sqlite3_bind_int64(statement, 2, rowID); if (err != SQLITE_OK) { ALOGE("bind failed"); sqlite3_result_null(context); return; } // Bind <data_tag> to the tag column if (useDataTag) { int dataTagParamIndex = useTokenIndex ? 4 : 3; err = sqlite3_bind_value(statement, dataTagParamIndex, argv[5]); if (err != SQLITE_OK) { ALOGE("bind failed"); sqlite3_result_null(context); return; } } // Get the raw bytes for the string to tokenize // the string will be modified by following code // however, sqlite did not reuse the string, so it is safe to not dup it UChar * origData = (UChar *)sqlite3_value_text16(argv[2]); if (origData == NULL) { sqlite3_result_null(context); return; } // Get the raw bytes for the delimiter const UChar * delim = (const UChar *)sqlite3_value_text16(argv[3]); if (delim == NULL) { ALOGE("can't get delimiter"); sqlite3_result_null(context); return; } UChar * token = NULL; UChar *state; int numTokens = 0; do { if (numTokens == 0) { token = origData; } // Reset the program so we can use it to perform the insert sqlite3_reset(statement); UErrorCode status = U_ZERO_ERROR; char keybuf[1024]; uint32_t result = ucol_getSortKey(collator, token, -1, (uint8_t*)keybuf, sizeof(keybuf)-1); if (result > sizeof(keybuf)) { // TODO allocate memory for this super big string ALOGE("ucol_getSortKey needs bigger buffer %d", result); break; } uint32_t keysize = result-1; uint32_t base16Size = keysize*2; char *base16buf = (char*)malloc(base16Size); base16Encode(base16buf, keybuf, keysize); err = sqlite3_bind_text(statement, 1, base16buf, base16Size, SQLITE_STATIC); if (err != SQLITE_OK) { ALOGE(" sqlite3_bind_text16 error %d", err); free(base16buf); break; } if (useTokenIndex) { err = sqlite3_bind_int(statement, 3, numTokens); if (err != SQLITE_OK) { ALOGE(" sqlite3_bind_int error %d", err); free(base16buf); break; } } err = sqlite3_step(statement); free(base16buf); if (err != SQLITE_DONE) { ALOGE(" sqlite3_step error %d", err); break; } numTokens++; if (numTokens == 1) { // first call u_strtok_r(origData, delim, &state); } } while ((token = u_strtok_r(NULL, delim, &state)) != NULL); sqlite3_result_int(context, numTokens); }
/** Custom match function that filters to exact matches * * If no auxiliary data is stored, we decode the pattern, compile regular * expressions, etc. and store aux_pattern_data struct as auxiliary data for the * pattern. */ void matchFunction(sqlite3_context* pCtx, int argc, sqlite3_value** argv){ /* Validate the input */ if(argc != 2){ sqlite3_result_error(pCtx, "The MATCH operator on a trigram index takes 2 arguments!", -1); return; } trilite_cursor *pTrgCur; if(triliteCursorFromBlob(&pTrgCur, argv[1]) != SQLITE_OK){ sqlite3_result_error(pCtx, "The MATCH operator must have 'contents' as left hand side", -1); return; } /* Get prepared auxiliary data, if any */ aux_pattern_data *pAuxData = (aux_pattern_data*)sqlite3_get_auxdata(pCtx, 0); /* If we didn't get any auxiliary data, create it and store it! */ if(!pAuxData){ /* Check that we have correct datatype for the pattern */ if(sqlite3_value_type(argv[0]) != SQLITE_TEXT){ sqlite3_result_error(pCtx, "The pattern for the MATCH operator on a trigram index must be a string", -1); return; } /* Get the pattern */ const unsigned char *pattern = sqlite3_value_text(argv[0]); int nPattern = sqlite3_value_bytes(argv[0]); /* Create some auxiliary data :) */ matchCreate(&pAuxData, pattern, nPattern); if(!pAuxData){ /* Die on errors, there shouldn't be any here if match is called correctly */ sqlite3_result_error(pCtx, "The match operator needs a valid pattern", -1); return; } /* Save the auxiliary data for next time */ sqlite3_set_auxdata(pCtx, 0, pAuxData, (void(*)(void*))matchAuxDataFree); } /* Get the text from the cursor */ const unsigned char *text; int nText; triliteText(pTrgCur, &text, &nText); bool retval = false; if(pAuxData->eType & PATTERN_SUBSTR){ const unsigned char *start = scanstr(text, nText, pAuxData->pattern, pAuxData->nPattern); retval = start != NULL; /* If output extents is requested */ if(pAuxData->eType & PATTERN_EXTENTS){ while(start){ const unsigned char *end = start + pAuxData->nPattern; triliteAddExtents(pTrgCur, start - text, end - text); start = scanstr(end, nText - (end - text), pAuxData->pattern, pAuxData->nPattern); } } } else if(pAuxData->eType == PATTERN_REGEXP){ assert(pAuxData->pRegExp); retval = regexpMatch(pAuxData->pRegExp, text, nText); } else if(pAuxData->eType == (PATTERN_REGEXP | PATTERN_EXTENTS)){ const unsigned char *start = text; const unsigned char *end = text; while(regexpMatchExtents(pAuxData->pRegExp, &start, &end, end, nText - (end - text))){ retval = true; triliteAddExtents(pTrgCur, start - text, end - text); } } else { assert(false); sqlite3_result_error(pCtx, "The pattern must be either a regular expression or substring pattern", -1); return; } /* Return true (1) if pattern in a substring of text */ if(retval){ sqlite3_result_int(pCtx, 1); }else{ sqlite3_result_int(pCtx, 0); } }