/* ** This is the implementation of the multiplex_control() SQL function. */ static void multiplexControlFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ int rc = SQLITE_OK; sqlite3 *db = sqlite3_context_db_handle(context); int op = 0; int iVal; if( !db || argc!=2 ){ rc = SQLITE_ERROR; }else{ /* extract params */ op = sqlite3_value_int(argv[0]); iVal = sqlite3_value_int(argv[1]); /* map function op to file_control op */ switch( op ){ case 1: op = MULTIPLEX_CTRL_ENABLE; break; case 2: op = MULTIPLEX_CTRL_SET_CHUNK_SIZE; break; case 3: op = MULTIPLEX_CTRL_SET_MAX_CHUNKS; break; default: rc = SQLITE_NOTFOUND; break; } } if( rc==SQLITE_OK ){ rc = sqlite3_file_control(db, 0, op, &iVal); } sqlite3_result_error_code(context, rc); }
static void sqlite_callback_final(sqlite3_context *ctx) { RefNode *klass = (RefNode*)sqlite3_user_data(ctx); Value *v = sqlite3_aggregate_context(ctx, sizeof(Value)); if (*v == VALUE_NULL) { if (!sqlite_aggrigate_new(v, klass)) { goto ERROR_END; } } fs->Value_push("v", v); if (!fs->call_member_func(fs->intern("final", -1), 0, TRUE)) { goto ERROR_END; } // 戻り値の設定 if (!sqlite_callback_return(fg->stk_top[-1], ctx)) { goto ERROR_END; } fs->Value_pop(); fs->unref(*v); *v = VALUE_NULL; return; ERROR_END: if (fg->error == VALUE_NULL) { sqlite3_result_error_code(ctx, SQLITE_ERROR_USER); } return; }
static void fts5MatchinfoFunc( const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ Fts5Context *pFts, /* First arg to pass to pApi functions */ sqlite3_context *pCtx, /* Context for returning result/error */ int nVal, /* Number of values in apVal[] array */ sqlite3_value **apVal /* Array of trailing arguments */ ){ const char *zArg; Fts5MatchinfoCtx *p; int rc; if( nVal>0 ){ zArg = (const char*)sqlite3_value_text(apVal[0]); }else{ zArg = "pcx"; } p = (Fts5MatchinfoCtx*)pApi->xGetAuxdata(pFts, 0); if( p==0 || sqlite3_stricmp(zArg, p->zArg) ){ p = fts5MatchinfoNew(pApi, pFts, pCtx, zArg); pApi->xSetAuxdata(pFts, p, sqlite3_free); if( p==0 ) return; } rc = fts5MatchinfoIter(pApi, pFts, p, fts5MatchinfoLocalCb); if( rc!=SQLITE_OK ){ sqlite3_result_error_code(pCtx, rc); }else{ /* No errors has occured, so return a copy of the array of integers. */ int nByte = p->nRet * sizeof(u32); sqlite3_result_blob(pCtx, (void*)p->aRet, nByte, SQLITE_TRANSIENT); } }
/* ** Invoke an SQL statement recursively. The function result is the ** first column of the first row of the result set. */ static void test_eval( sqlite3_context *pCtx, int nArg, sqlite3_value **argv ){ sqlite3_stmt *pStmt; int rc; sqlite3 *db = sqlite3_context_db_handle(pCtx); const char *zSql; zSql = (char*)sqlite3_value_text(argv[0]); rc = sqlite3_prepare_v2(db, zSql, -1, &pStmt, 0); if( rc==SQLITE_OK ){ rc = sqlite3_step(pStmt); if( rc==SQLITE_ROW ){ sqlite3_result_value(pCtx, sqlite3_column_value(pStmt, 0)); } rc = sqlite3_finalize(pStmt); } if( rc ){ char *zErr; assert( pStmt==0 ); zErr = sqlite3_mprintf("sqlite3_prepare_v2() error: %s",sqlite3_errmsg(db)); sqlite3_result_text(pCtx, zErr, -1, sqlite3_free); sqlite3_result_error_code(pCtx, rc); } }
/* ** Implementation of bm25() function. */ static void fts5Bm25Function( const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ Fts5Context *pFts, /* First arg to pass to pApi functions */ sqlite3_context *pCtx, /* Context for returning result/error */ int nVal, /* Number of values in apVal[] array */ sqlite3_value **apVal /* Array of trailing arguments */ ){ const double k1 = 1.2; /* Constant "k1" from BM25 formula */ const double b = 0.75; /* Constant "b" from BM25 formula */ int rc = SQLITE_OK; /* Error code */ double score = 0.0; /* SQL function return value */ Fts5Bm25Data *pData; /* Values allocated/calculated once only */ int i; /* Iterator variable */ int nInst = 0; /* Value returned by xInstCount() */ double D = 0.0; /* Total number of tokens in row */ double *aFreq = 0; /* Array of phrase freq. for current row */ /* Calculate the phrase frequency (symbol "f(qi,D)" in the documentation) ** for each phrase in the query for the current row. */ rc = fts5Bm25GetData(pApi, pFts, &pData); if( rc==SQLITE_OK ){ aFreq = pData->aFreq; memset(aFreq, 0, sizeof(double) * pData->nPhrase); rc = pApi->xInstCount(pFts, &nInst); } for(i=0; rc==SQLITE_OK && i<nInst; i++){ int ip; int ic; int io; rc = pApi->xInst(pFts, i, &ip, &ic, &io); if( rc==SQLITE_OK ){ double w = (nVal > ic) ? sqlite3_value_double(apVal[ic]) : 1.0; aFreq[ip] += w; } } /* Figure out the total size of the current row in tokens. */ if( rc==SQLITE_OK ){ int nTok; rc = pApi->xColumnSize(pFts, -1, &nTok); D = (double)nTok; } /* Determine the BM25 score for the current row. */ for(i=0; rc==SQLITE_OK && i<pData->nPhrase; i++){ score += pData->aIDF[i] * ( ( aFreq[i] * (k1 + 1.0) ) / ( aFreq[i] + k1 * (1 - b + b * D / pData->avgdl) ) ); } /* If no error has occurred, return the calculated score. Otherwise, ** throw an SQL exception. */ if( rc==SQLITE_OK ){ sqlite3_result_double(pCtx, -1.0 * score); }else{ sqlite3_result_error_code(pCtx, rc); } }
/* ** A function to test error reporting from user functions. This function ** returns a copy of its first argument as the error message. If the ** second argument exists, it becomes the error code. */ static void test_error( sqlite3_context *pCtx, int nArg, sqlite3_value **argv ){ sqlite3_result_error(pCtx, (char*)sqlite3_value_text(argv[0]), -1); if( nArg==2 ){ sqlite3_result_error_code(pCtx, sqlite3_value_int(argv[1])); } }
static Fts5MatchinfoCtx *fts5MatchinfoNew( const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ Fts5Context *pFts, /* First arg to pass to pApi functions */ sqlite3_context *pCtx, /* Context for returning error message */ const char *zArg /* Matchinfo flag string */ ){ Fts5MatchinfoCtx *p; int nCol; int nPhrase; int i; int nInt; int nByte; int rc; nCol = pApi->xColumnCount(pFts); nPhrase = pApi->xPhraseCount(pFts); nInt = 0; for(i=0; zArg[i]; i++){ int n = fts5MatchinfoFlagsize(nCol, nPhrase, zArg[i]); if( n<0 ){ char *zErr = sqlite3_mprintf("unrecognized matchinfo flag: %c", zArg[i]); sqlite3_result_error(pCtx, zErr, -1); sqlite3_free(zErr); return 0; } nInt += n; } nByte = sizeof(Fts5MatchinfoCtx) /* The struct itself */ + sizeof(u32) * nInt /* The p->aRet[] array */ + (i+1); /* The p->zArg string */ p = (Fts5MatchinfoCtx*)sqlite3_malloc(nByte); if( p==0 ){ sqlite3_result_error_nomem(pCtx); return 0; } memset(p, 0, nByte); p->nCol = nCol; p->nPhrase = nPhrase; p->aRet = (u32*)&p[1]; p->nRet = nInt; p->zArg = (char*)&p->aRet[nInt]; memcpy(p->zArg, zArg, i); rc = fts5MatchinfoIter(pApi, pFts, p, fts5MatchinfoGlobalCb); if( rc!=SQLITE_OK ){ sqlite3_result_error_code(pCtx, rc); sqlite3_free(p); p = 0; } return p; }
static void function_property_names (sqlite3_context *context, int argc, sqlite3_value *argv[]) { static gchar **names = NULL; static GMutex mutex; int rc = SQLITE_DONE; g_mutex_lock (&mutex); if (G_UNLIKELY (names == NULL)) { GPtrArray *names_array; sqlite3_stmt *stmt; sqlite3 *db; names_array = g_ptr_array_new (); db = sqlite3_context_db_handle (context); rc = sqlite3_prepare_v2 (db, "SELECT Uri " "FROM Resource " "JOIN \"rdf:Property\" " "ON Resource.ID = \"rdf:Property\".ID " "WHERE \"rdf:Property\".\"tracker:fulltextIndexed\" = 1 " "ORDER BY \"rdf:Property\".ID ", -1, &stmt, NULL); while ((rc = sqlite3_step (stmt)) != SQLITE_DONE) { if (rc == SQLITE_ROW) { const gchar *name; name = sqlite3_column_text (stmt, 0); g_ptr_array_add (names_array, g_strdup (name)); } else if (rc != SQLITE_BUSY) { break; } } sqlite3_finalize (stmt); if (rc == SQLITE_DONE) { names = (gchar **) g_ptr_array_free (names_array, FALSE); } else { g_ptr_array_free (names_array, TRUE); } } g_mutex_unlock (&mutex); if (rc == SQLITE_DONE) sqlite3_result_blob (context, names, sizeof (names), NULL); else sqlite3_result_error_code (context, rc); }
ikptr ik_sqlite3_result_error_code (ikptr s_context, ikptr s_errcode, ikpcb * pcb) { #ifdef HAVE_SQLITE3_RESULT_ERROR_CODE sqlite3_context * context = IK_SQLITE_CONTEXT(s_context); int errcode = ik_integer_to_int(s_errcode); sqlite3_result_error_code(context, errcode); return IK_VOID_OBJECT; #else feature_failure(__func__); #endif }
static void btreeSeqError( sqlite3_context *context, int code, const char *fmt, ...) { char buf[BT_MAX_PATH]; va_list ap; va_start(ap, fmt); vsnprintf(buf, BT_MAX_PATH, fmt, ap); va_end(ap); sqlite3_result_error(context, buf, -1); if (code != SQLITE_ERROR) sqlite3_result_error_code(context, code); }
static void sqlite_callback_func(sqlite3_context *ctx, int argc, sqlite3_value **argv) { Value *fn = (Value*)sqlite3_user_data(ctx); fs->Value_push("v", *fn); // 引数の設定 sqlite_callback_args(argc, argv); if (!fs->call_function_obj(argc)) { sqlite3_result_error_code(ctx, SQLITE_ERROR_USER); return; } // 戻り値の設定 if (!sqlite_callback_return(fg->stk_top[-1], ctx)) { sqlite3_result_error_code(ctx, SQLITE_ERROR_USER); return; } fs->Value_pop(); return; }
static void function_weights (sqlite3_context *context, int argc, sqlite3_value *argv[]) { static guint *weights = NULL; static GMutex mutex; int rc = SQLITE_DONE; g_mutex_lock (&mutex); if (G_UNLIKELY (weights == NULL)) { GArray *weight_array; sqlite3_stmt *stmt; sqlite3 *db; weight_array = g_array_new (FALSE, FALSE, sizeof (guint)); db = sqlite3_context_db_handle (context); rc = sqlite3_prepare_v2 (db, "SELECT \"rdf:Property\".\"tracker:weight\" " "FROM \"rdf:Property\" " "WHERE \"rdf:Property\".\"tracker:fulltextIndexed\" = 1 " "ORDER BY \"rdf:Property\".ID ", -1, &stmt, NULL); while ((rc = sqlite3_step (stmt)) != SQLITE_DONE) { if (rc == SQLITE_ROW) { guint weight; weight = sqlite3_column_int (stmt, 0); g_array_append_val (weight_array, weight); } else if (rc != SQLITE_BUSY) { break; } } sqlite3_finalize (stmt); if (rc == SQLITE_DONE) { weights = (guint *) g_array_free (weight_array, FALSE); } else { g_array_free (weight_array, TRUE); } } g_mutex_unlock (&mutex); if (rc == SQLITE_DONE) sqlite3_result_blob (context, weights, sizeof (weights), NULL); else sqlite3_result_error_code (context, rc); }
/* ** build a simple bitstring (mostly for testing) */ static void bfp_dummy_f(sqlite3_context* ctx, int argc, sqlite3_value** argv) { assert(argc == 2); int rc = SQLITE_OK; int len, value; u8 * pBlob = 0; /* Check that value is a blob */ if (sqlite3_value_type(argv[0]) != SQLITE_INTEGER) { rc = SQLITE_MISMATCH; } else if (sqlite3_value_type(argv[1]) != SQLITE_INTEGER) { rc = SQLITE_MISMATCH; } else { len = sqlite3_value_int(argv[0]); if (len <= 0) { len = 1; } if (len > MAX_BITSTRING_SIZE) { len = MAX_BITSTRING_SIZE; } value = sqlite3_value_int(argv[1]); if (value < 0) { value = 0; } if (value > 255) { value = 255; } pBlob = (u8 *)sqlite3_malloc(len); if (!pBlob) { rc = SQLITE_NOMEM; } else { u8 *p = pBlob; int ii; for (ii = 0; ii < len; ++ii) { *p++ = value; } } } if (rc == SQLITE_OK) { sqlite3_result_blob(ctx, pBlob, len, sqlite3_free); } else { sqlite3_result_error_code(ctx, rc); } }
static void bfp_weight_f(sqlite3_context* ctx, int argc, sqlite3_value** argv) { assert(argc == 1); int rc = SQLITE_OK; Bfp *pBfp = 0; rc = fetch_bfp_arg(argv[0], &pBfp); if (rc == SQLITE_OK) { int weight = bfp_weight(pBfp); free_bfp(pBfp); sqlite3_result_int(ctx, weight); } else { sqlite3_result_error_code(ctx, rc); } }
/* ** Implementation of highlight() function. */ static void fts5HighlightFunction( const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ Fts5Context *pFts, /* First arg to pass to pApi functions */ sqlite3_context *pCtx, /* Context for returning result/error */ int nVal, /* Number of values in apVal[] array */ sqlite3_value **apVal /* Array of trailing arguments */ ){ HighlightContext ctx; int rc; int iCol; if( nVal!=3 ){ const char *zErr = "wrong number of arguments to function highlight()"; sqlite3_result_error(pCtx, zErr, -1); return; } iCol = sqlite3_value_int(apVal[0]); memset(&ctx, 0, sizeof(HighlightContext)); ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); rc = pApi->xColumnText(pFts, iCol, &ctx.zIn, &ctx.nIn); if( ctx.zIn ){ if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iCol, &ctx.iter); } if( rc==SQLITE_OK ){ rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); } fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); if( rc==SQLITE_OK ){ sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT); } sqlite3_free(ctx.zOut); } if( rc!=SQLITE_OK ){ sqlite3_result_error_code(pCtx, rc); } }
static void checkfreelist_function( sqlite3_context *pCtx, int nArg, sqlite3_value **apArg ){ const char *zDb; int rc; char *zOut = 0; sqlite3 *db = sqlite3_context_db_handle(pCtx); assert( nArg==1 ); zDb = (const char*)sqlite3_value_text(apArg[0]); rc = checkFreelist(db, zDb, &zOut); if( rc==SQLITE_OK ){ sqlite3_result_text(pCtx, zOut?zOut:"ok", -1, SQLITE_TRANSIENT); }else{ sqlite3_result_error_code(pCtx, rc); } sqlite3_free(zOut); }
/* ** Auxiliary SQL function to recursively evaluate SQL. */ static void evalFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); const char *zSql = (const char*)sqlite3_value_text(argv[0]); String res; char *zErrMsg = 0; int rc; UNUSED_PARAMETER(argc); memset(&res, 0, sizeof(res)); rc = sqlite3_exec(db, zSql, evalCallback, &res, &zErrMsg); if( zErrMsg ){ sqlite3_result_error(context, zErrMsg, -1); sqlite3_free(zErrMsg); }else if( rc ){ sqlite3_result_error_code(context, rc); }else{ sqlite3_result_text(context, res.z, -1, SQLITE_TRANSIENT); } stringFree(&res); }
static void sqlite_callback_step(sqlite3_context *ctx, int argc, sqlite3_value **argv) { RefNode *klass = (RefNode*)sqlite3_user_data(ctx); Value *v = sqlite3_aggregate_context(ctx, sizeof(Value)); if (*v == VALUE_NULL) { if (!sqlite_aggrigate_new(v, klass)) { goto ERROR_END; } } fs->Value_push("v", v); sqlite_callback_args(argc, argv); if (!fs->call_member_func(fs->intern("step", -1), argc, TRUE)) { goto ERROR_END; } fs->Value_pop(); return; ERROR_END: sqlite3_result_error_code(ctx, SQLITE_ERROR_USER); return; }
static void mm_cipher_key_func(sqlite3_context *db, int argc, sqlite3_value **argv) { mm_cipher_context_t *ctx; // only accept 1 BLOB argument. if (argc != 1) goto error_misuse; if (sqlite3_value_type(argv[0]) != SQLITE_BLOB) goto error_misuse; if (sqlite3_value_bytes(argv[0]) != 16) goto error_misuse; ctx = (mm_cipher_context_t *) sqlite3_user_data(db); memcpy(ctx->key, sqlite3_value_blob(argv[0]), 16); sqlite3_result_null(db); return; error_misuse: sqlite3_result_error_code(db, SQLITE_MISUSE); return; }
/* ** An SQL user-function registered to do the work of an ATTACH statement. The ** three arguments to the function come directly from an attach statement: ** ** ATTACH DATABASE x AS y KEY z ** ** SELECT sqlite_attach(x, y, z) ** ** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the ** third argument. */ static void attachFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ int i; int rc = 0; sqlite3 *db = sqlite3_context_db_handle(context); const char *zName; const char *zFile; Db *aNew; char *zErrDyn = 0; UNUSED_PARAMETER(NotUsed); zFile = (const char *)sqlite3_value_text(argv[0]); zName = (const char *)sqlite3_value_text(argv[1]); if( zFile==0 ) zFile = ""; if( zName==0 ) zName = ""; /* Check for the following errors: ** ** * Too many attached databases, ** * Transaction currently open ** * Specified database name already being used. */ if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){ zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", db->aLimit[SQLITE_LIMIT_ATTACHED] ); goto attach_error; } if( !db->autoCommit ){ zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction"); goto attach_error; } for(i=0; i<db->nDb; i++){ char *z = db->aDb[i].zName; assert( z && zName ); if( sqlite3StrICmp(z, zName)==0 ){ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); goto attach_error; } } /* Allocate the new entry in the db->aDb[] array and initialise the schema ** hash tables. */ if( db->aDb==db->aDbStatic ){ aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 ); if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); if( aNew==0 ) return; } db->aDb = aNew; aNew = &db->aDb[db->nDb]; memset(aNew, 0, sizeof(*aNew)); /* Open the database file. If the btree is successfully opened, use ** it to obtain the database schema. At this point the schema may ** or may not be initialised. */ rc = sqlite3BtreeFactory(db, zFile, 0, SQLITE_DEFAULT_CACHE_SIZE, db->openFlags | SQLITE_OPEN_MAIN_DB, &aNew->pBt); db->nDb++; if( rc==SQLITE_CONSTRAINT ){ rc = SQLITE_ERROR; zErrDyn = sqlite3MPrintf(db, "database is already attached"); }else if( rc==SQLITE_OK ){ Pager *pPager; aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt); if( !aNew->pSchema ){ rc = SQLITE_NOMEM; }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ zErrDyn = sqlite3MPrintf(db, "attached databases must use the same text encoding as main database"); rc = SQLITE_ERROR; } pPager = sqlite3BtreePager(aNew->pBt); sqlite3PagerLockingMode(pPager, db->dfltLockMode); sqlite3PagerJournalMode(pPager, db->dfltJournalMode); } aNew->zName = sqlite3DbStrDup(db, zName); aNew->safety_level = 3; #if SQLITE_HAS_CODEC { extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); int nKey; char *zKey; int t = sqlite3_value_type(argv[2]); switch( t ){ case SQLITE_INTEGER: case SQLITE_FLOAT: zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); rc = SQLITE_ERROR; break; case SQLITE_TEXT: case SQLITE_BLOB: nKey = sqlite3_value_bytes(argv[2]); zKey = (char *)sqlite3_value_blob(argv[2]); sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); break; case SQLITE_NULL: /* No key specified. Use the key from the main database */ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); break; } } #endif /* If the file was opened successfully, read the schema for the new database. ** If this fails, or if opening the file failed, then close the file and ** remove the entry from the db->aDb[] array. i.e. put everything back the way ** we found it. */ if( rc==SQLITE_OK ){ (void)sqlite3SafetyOn(db); sqlite3BtreeEnterAll(db); rc = sqlite3Init(db, &zErrDyn); sqlite3BtreeLeaveAll(db); (void)sqlite3SafetyOff(db); } if( rc ){ int iDb = db->nDb - 1; assert( iDb>=2 ); if( db->aDb[iDb].pBt ){ sqlite3BtreeClose(db->aDb[iDb].pBt); db->aDb[iDb].pBt = 0; db->aDb[iDb].pSchema = 0; } sqlite3ResetInternalSchema(db, 0); db->nDb = iDb; if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ db->mallocFailed = 1; sqlite3DbFree(db, zErrDyn); zErrDyn = sqlite3MPrintf(db, "out of memory"); }else if( zErrDyn==0 ){ zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile); } goto attach_error; } return; attach_error: /* Return an error if we get here */ if( zErrDyn ){ sqlite3_result_error(context, zErrDyn, -1); sqlite3DbFree(db, zErrDyn); } if( rc ) sqlite3_result_error_code(context, rc); }
static void mmenc_func(sqlite3_context *db, int argc, sqlite3_value **argv) { mm_cipher_context_t *ctx; const UChar *src; int32_t src_len; char buf[1024]; char *dst = buf; int32_t dst_len; UErrorCode status = U_ZERO_ERROR; int arg_type; // only accept 1 argument. if (argc != 1) goto error_misuse; // encoding BLOB data type is not supported. arg_type = sqlite3_value_type(argv[0]); if (arg_type == SQLITE_BLOB) goto error_misuse; // for data types other than TEXT, just return them. if (arg_type != SQLITE_TEXT) { sqlite3_result_value(db, argv[0]); return; } ctx = (mm_cipher_context_t *) sqlite3_user_data(db); src_len = sqlite3_value_bytes16(argv[0]) / 2; src = (const UChar *) sqlite3_value_text16(argv[0]); // transform input string to BOCU-1 encoding. // try stack buffer first, if it doesn't fit, malloc a new buffer. dst_len = ucnv_fromUChars(ctx->cnv, dst, sizeof(buf), src, src_len, &status); if (status == U_BUFFER_OVERFLOW_ERROR) { status = U_ZERO_ERROR; dst = (char *) sqlite3_malloc(dst_len); dst_len = ucnv_fromUChars(ctx->cnv, dst, dst_len, src, src_len, &status); } if (U_FAILURE(status) && status != U_STRING_NOT_TERMINATED_WARNING) { sqlite3_mm_set_last_error( "Failed transforming text to internal encoding."); goto error_error; } // encrypt transformed BOCU-1 string. do_rc4(ctx, dst, dst_len); // return sqlite3_result_blob(db, dst, dst_len, SQLITE_TRANSIENT); if (dst != buf) sqlite3_free(dst); return; error_error: if (dst != buf) sqlite3_free(dst); sqlite3_result_error_code(db, SQLITE_ERROR); return; error_misuse: if (dst != buf) sqlite3_free(dst); sqlite3_result_error_code(db, SQLITE_MISUSE); return; }
void context::result_error_code(int code) { sqlite3_result_error_code(handle, code); }
/* ** An SQL user-function registered to do the work of an ATTACH statement. The ** three arguments to the function come directly from an attach statement: ** ** ATTACH DATABASE x AS y KEY z ** ** SELECT sqlite_attach(x, y, z) ** ** If the optional "KEY z" syntax is omitted, an SQL NULL is passed as the ** third argument. */ static void attachFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ int i; int rc = 0; sqlite3 *db = sqlite3_context_db_handle(context); const char *zName; const char *zFile; char *zPath = 0; char *zErr = 0; unsigned int flags; Db *aNew; char *zErrDyn = 0; sqlite3_vfs *pVfs; UNUSED_PARAMETER(NotUsed); zFile = (const char *)sqlite3_value_text(argv[0]); zName = (const char *)sqlite3_value_text(argv[1]); if( zFile==0 ) zFile = ""; if( zName==0 ) zName = ""; /* Check for the following errors: ** ** * Too many attached databases, ** * Transaction currently open ** * Specified database name already being used. */ if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){ zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", db->aLimit[SQLITE_LIMIT_ATTACHED] ); goto attach_error; } if( !db->autoCommit ){ zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction"); goto attach_error; } for(i=0; i<db->nDb; i++){ char *z = db->aDb[i].zName; assert( z && zName ); if( sqlite3StrICmp(z, zName)==0 ){ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); goto attach_error; } } /* Allocate the new entry in the db->aDb[] array and initialize the schema ** hash tables. */ if( db->aDb==db->aDbStatic ){ aNew = sqlite3DbMallocRawNN(db, sizeof(db->aDb[0])*3 ); if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); if( aNew==0 ) return; } db->aDb = aNew; aNew = &db->aDb[db->nDb]; memset(aNew, 0, sizeof(*aNew)); /* Open the database file. If the btree is successfully opened, use ** it to obtain the database schema. At this point the schema may ** or may not be initialized. */ flags = db->openFlags; rc = sqlite3ParseUri(db->pVfs->zName, zFile, &flags, &pVfs, &zPath, &zErr); if( rc!=SQLITE_OK ){ if( rc==SQLITE_NOMEM ) sqlite3OomFault(db); sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); return; } assert( pVfs ); flags |= SQLITE_OPEN_MAIN_DB; rc = sqlite3BtreeOpen(pVfs, zPath, db, &aNew->pBt, 0, flags); sqlite3_free( zPath ); db->nDb++; if( rc==SQLITE_CONSTRAINT ){ rc = SQLITE_ERROR; zErrDyn = sqlite3MPrintf(db, "database is already attached"); }else if( rc==SQLITE_OK ){ Pager *pPager; aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt); if( !aNew->pSchema ){ rc = SQLITE_NOMEM; }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ zErrDyn = sqlite3MPrintf(db, "attached databases must use the same text encoding as main database"); rc = SQLITE_ERROR; } sqlite3BtreeEnter(aNew->pBt); pPager = sqlite3BtreePager(aNew->pBt); sqlite3PagerLockingMode(pPager, db->dfltLockMode); sqlite3BtreeSecureDelete(aNew->pBt, sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) ); #ifndef SQLITE_OMIT_PAGER_PRAGMAS sqlite3BtreeSetPagerFlags(aNew->pBt, PAGER_SYNCHRONOUS_FULL | (db->flags & PAGER_FLAGS_MASK)); #endif sqlite3BtreeLeave(aNew->pBt); } aNew->safety_level = 3; aNew->zName = sqlite3DbStrDup(db, zName); if( rc==SQLITE_OK && aNew->zName==0 ){ rc = SQLITE_NOMEM; } #ifdef SQLITE_HAS_CODEC if( rc==SQLITE_OK ){ extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); int nKey; char *zKey; int t = sqlite3_value_type(argv[2]); switch( t ){ case SQLITE_INTEGER: case SQLITE_FLOAT: zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); rc = SQLITE_ERROR; break; case SQLITE_TEXT: case SQLITE_BLOB: nKey = sqlite3_value_bytes(argv[2]); zKey = (char *)sqlite3_value_blob(argv[2]); rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); break; case SQLITE_NULL: /* No key specified. Use the key from the main database */ sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); if( nKey>0 || sqlite3BtreeGetOptimalReserve(db->aDb[0].pBt)>0 ){ rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); } break; } } #endif /* If the file was opened successfully, read the schema for the new database. ** If this fails, or if opening the file failed, then close the file and ** remove the entry from the db->aDb[] array. i.e. put everything back the way ** we found it. */ if( rc==SQLITE_OK ){ sqlite3BtreeEnterAll(db); rc = sqlite3Init(db, &zErrDyn); sqlite3BtreeLeaveAll(db); } #ifdef SQLITE_USER_AUTHENTICATION if( rc==SQLITE_OK ){ u8 newAuth = 0; rc = sqlite3UserAuthCheckLogin(db, zName, &newAuth); if( newAuth<db->auth.authLevel ){ rc = SQLITE_AUTH_USER; } } #endif if( rc ){ int iDb = db->nDb - 1; assert( iDb>=2 ); if( db->aDb[iDb].pBt ){ sqlite3BtreeClose(db->aDb[iDb].pBt); db->aDb[iDb].pBt = 0; db->aDb[iDb].pSchema = 0; } sqlite3ResetAllSchemasOfConnection(db); db->nDb = iDb; if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ sqlite3OomFault(db); sqlite3DbFree(db, zErrDyn); zErrDyn = sqlite3MPrintf(db, "out of memory"); }else if( zErrDyn==0 ){ zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile); } goto attach_error; } return; attach_error: /* Return an error if we get here */ if( zErrDyn ){ sqlite3_result_error(context, zErrDyn, -1); sqlite3DbFree(db, zErrDyn); } if( rc ) sqlite3_result_error_code(context, rc); }
static void attachFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ int i; int rc = 0; sqlite3 *db = sqlite3_context_db_handle(context); const char *zName; const char *zFile; Db *aNew; char *zErrDyn = 0; UNUSED_PARAMETER(NotUsed); zFile = (const char *)sqlite3_value_text(argv[0]); zName = (const char *)sqlite3_value_text(argv[1]); if( zFile==0 ) zFile = ""; if( zName==0 ) zName = ""; if( db->nDb>=db->aLimit[SQLITE_LIMIT_ATTACHED]+2 ){ zErrDyn = sqlite3MPrintf(db, "too many attached databases - max %d", db->aLimit[SQLITE_LIMIT_ATTACHED] ); goto attach_error; } if( !db->autoCommit ){ zErrDyn = sqlite3MPrintf(db, "cannot ATTACH database within transaction"); goto attach_error; } for(i=0; i<db->nDb; i++){ char *z = db->aDb[i].zName; assert( z && zName ); if( sqlite3StrICmp(z, zName)==0 ){ zErrDyn = sqlite3MPrintf(db, "database %s is already in use", zName); goto attach_error; } } if( db->aDb==db->aDbStatic ){ aNew = sqlite3DbMallocRaw(db, sizeof(db->aDb[0])*3 ); if( aNew==0 ) return; memcpy(aNew, db->aDb, sizeof(db->aDb[0])*2); }else{ aNew = sqlite3DbRealloc(db, db->aDb, sizeof(db->aDb[0])*(db->nDb+1) ); if( aNew==0 ) return; } db->aDb = aNew; aNew = &db->aDb[db->nDb]; memset(aNew, 0, sizeof(*aNew)); rc = sqlite3BtreeOpen(zFile, db, &aNew->pBt, 0, db->openFlags | SQLITE_OPEN_MAIN_DB); db->nDb++; if( rc==SQLITE_CONSTRAINT ){ rc = SQLITE_ERROR; zErrDyn = sqlite3MPrintf(db, "database is already attached"); }else if( rc==SQLITE_OK ){ Pager *pPager; aNew->pSchema = sqlite3SchemaGet(db, aNew->pBt); if( !aNew->pSchema ){ rc = SQLITE_NOMEM; }else if( aNew->pSchema->file_format && aNew->pSchema->enc!=ENC(db) ){ zErrDyn = sqlite3MPrintf(db, "attached databases must use the same text encoding as main database"); rc = SQLITE_ERROR; } pPager = sqlite3BtreePager(aNew->pBt); sqlite3PagerLockingMode(pPager, db->dfltLockMode); sqlite3BtreeSecureDelete(aNew->pBt, sqlite3BtreeSecureDelete(db->aDb[0].pBt,-1) ); } aNew->safety_level = 3; aNew->zName = sqlite3DbStrDup(db, zName); if( rc==SQLITE_OK && aNew->zName==0 ){ rc = SQLITE_NOMEM; } #ifdef SQLITE_HAS_CODEC if( rc==SQLITE_OK ){ extern int sqlite3CodecAttach(sqlite3*, int, const void*, int); extern void sqlite3CodecGetKey(sqlite3*, int, void**, int*); int nKey; char *zKey; int t = sqlite3_value_type(argv[2]); switch( t ){ case SQLITE_INTEGER: case SQLITE_FLOAT: zErrDyn = sqlite3DbStrDup(db, "Invalid key value"); rc = SQLITE_ERROR; break; case SQLITE_TEXT: case SQLITE_BLOB: nKey = sqlite3_value_bytes(argv[2]); zKey = (char *)sqlite3_value_blob(argv[2]); rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); break; case SQLITE_NULL: sqlite3CodecGetKey(db, 0, (void**)&zKey, &nKey); if( nKey>0 || sqlite3BtreeGetReserve(db->aDb[0].pBt)>0 ){ rc = sqlite3CodecAttach(db, db->nDb-1, zKey, nKey); } break; } } #endif if( rc==SQLITE_OK ){ sqlite3BtreeEnterAll(db); rc = sqlite3Init(db, &zErrDyn); sqlite3BtreeLeaveAll(db); } if( rc ){ int iDb = db->nDb - 1; assert( iDb>=2 ); if( db->aDb[iDb].pBt ){ sqlite3BtreeClose(db->aDb[iDb].pBt); db->aDb[iDb].pBt = 0; db->aDb[iDb].pSchema = 0; } sqlite3ResetInternalSchema(db, -1); db->nDb = iDb; if( rc==SQLITE_NOMEM || rc==SQLITE_IOERR_NOMEM ){ db->mallocFailed = 1; sqlite3DbFree(db, zErrDyn); zErrDyn = sqlite3MPrintf(db, "out of memory"); }else if( zErrDyn==0 ){ zErrDyn = sqlite3MPrintf(db, "unable to open database: %s", zFile); } goto attach_error; } return; attach_error: if( zErrDyn ){ sqlite3_result_error(context, zErrDyn, -1); sqlite3DbFree(db, zErrDyn); } if( rc ) sqlite3_result_error_code(context, rc); }
/* ** Implementation of snippet() function. */ static void fts5SnippetFunction( const Fts5ExtensionApi *pApi, /* API offered by current FTS version */ Fts5Context *pFts, /* First arg to pass to pApi functions */ sqlite3_context *pCtx, /* Context for returning result/error */ int nVal, /* Number of values in apVal[] array */ sqlite3_value **apVal /* Array of trailing arguments */ ){ HighlightContext ctx; int rc = SQLITE_OK; /* Return code */ int iCol; /* 1st argument to snippet() */ const char *zEllips; /* 4th argument to snippet() */ int nToken; /* 5th argument to snippet() */ int nInst = 0; /* Number of instance matches this row */ int i; /* Used to iterate through instances */ int nPhrase; /* Number of phrases in query */ unsigned char *aSeen; /* Array of "seen instance" flags */ int iBestCol; /* Column containing best snippet */ int iBestStart = 0; /* First token of best snippet */ int iBestLast; /* Last token of best snippet */ int nBestScore = 0; /* Score of best snippet */ int nColSize = 0; /* Total size of iBestCol in tokens */ if( nVal!=5 ){ const char *zErr = "wrong number of arguments to function snippet()"; sqlite3_result_error(pCtx, zErr, -1); return; } memset(&ctx, 0, sizeof(HighlightContext)); iCol = sqlite3_value_int(apVal[0]); ctx.zOpen = (const char*)sqlite3_value_text(apVal[1]); ctx.zClose = (const char*)sqlite3_value_text(apVal[2]); zEllips = (const char*)sqlite3_value_text(apVal[3]); nToken = sqlite3_value_int(apVal[4]); iBestLast = nToken-1; iBestCol = (iCol>=0 ? iCol : 0); nPhrase = pApi->xPhraseCount(pFts); aSeen = sqlite3_malloc(nPhrase); if( aSeen==0 ){ rc = SQLITE_NOMEM; } if( rc==SQLITE_OK ){ rc = pApi->xInstCount(pFts, &nInst); } for(i=0; rc==SQLITE_OK && i<nInst; i++){ int ip, iSnippetCol, iStart; memset(aSeen, 0, nPhrase); rc = pApi->xInst(pFts, i, &ip, &iSnippetCol, &iStart); if( rc==SQLITE_OK && (iCol<0 || iSnippetCol==iCol) ){ int nScore = 1000; int iLast = iStart - 1 + pApi->xPhraseSize(pFts, ip); int j; aSeen[ip] = 1; for(j=i+1; rc==SQLITE_OK && j<nInst; j++){ int ic; int io; int iFinal; rc = pApi->xInst(pFts, j, &ip, &ic, &io); iFinal = io + pApi->xPhraseSize(pFts, ip) - 1; if( rc==SQLITE_OK && ic==iSnippetCol && iLast<iStart+nToken ){ nScore += aSeen[ip] ? 1000 : 1; aSeen[ip] = 1; if( iFinal>iLast ) iLast = iFinal; } } if( rc==SQLITE_OK && nScore>nBestScore ){ iBestCol = iSnippetCol; iBestStart = iStart; iBestLast = iLast; nBestScore = nScore; } } } if( rc==SQLITE_OK ){ rc = pApi->xColumnSize(pFts, iBestCol, &nColSize); } if( rc==SQLITE_OK ){ rc = pApi->xColumnText(pFts, iBestCol, &ctx.zIn, &ctx.nIn); } if( ctx.zIn ){ if( rc==SQLITE_OK ){ rc = fts5CInstIterInit(pApi, pFts, iBestCol, &ctx.iter); } if( (iBestStart+nToken-1)>iBestLast ){ iBestStart -= (iBestStart+nToken-1-iBestLast) / 2; } if( iBestStart+nToken>nColSize ){ iBestStart = nColSize - nToken; } if( iBestStart<0 ) iBestStart = 0; ctx.iRangeStart = iBestStart; ctx.iRangeEnd = iBestStart + nToken - 1; if( iBestStart>0 ){ fts5HighlightAppend(&rc, &ctx, zEllips, -1); } if( rc==SQLITE_OK ){ rc = pApi->xTokenize(pFts, ctx.zIn, ctx.nIn, (void*)&ctx,fts5HighlightCb); } if( ctx.iRangeEnd>=(nColSize-1) ){ fts5HighlightAppend(&rc, &ctx, &ctx.zIn[ctx.iOff], ctx.nIn - ctx.iOff); }else{ fts5HighlightAppend(&rc, &ctx, zEllips, -1); } if( rc==SQLITE_OK ){ sqlite3_result_text(pCtx, (const char*)ctx.zOut, -1, SQLITE_TRANSIENT); }else{ sqlite3_result_error_code(pCtx, rc); } sqlite3_free(ctx.zOut); } sqlite3_free(aSeen); }