static void UdfInsertFunc(sqlite3_context* aCtx, int aCnt, sqlite3_value** aValues) { int err; const char* tail = 0; sqlite3* db = 0; TEST2(aCnt, 1); db = sqlite3_context_db_handle(aCtx);/* to test that sqlite3_context_db_handle() can be called */ TEST(db != 0); TEST(!TheStmt); err = sqlite3_prepare(TheDb, "INSERT INTO t1(x) VALUES(:Val)", -1, &TheStmt, &tail); if(err == SQLITE_OK) { err = sqlite3_bind_value(TheStmt, 1, aValues[0]); if(err == SQLITE_OK) { err = sqlite3_step(TheStmt); } } (void)sqlite3_finalize(TheStmt); TheStmt = 0; sqlite3_result_int(aCtx, err); }
/* ** group_concat(EXPR, ?SEPARATOR?) */ static void groupConcatStep( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zVal; StrAccum *pAccum; const char *zSep; int nVal, nSep; assert( argc==1 || argc==2 ); if( sqlite3_value_type(argv[0])==SQLITE_NULL ) return; pAccum = (StrAccum*)sqlite3_aggregate_context(context, sizeof(*pAccum)); if( pAccum ){ sqlite3 *db = sqlite3_context_db_handle(context); int firstTerm = pAccum->useMalloc==0; pAccum->useMalloc = 2; pAccum->mxAlloc = db->aLimit[SQLITE_LIMIT_LENGTH]; if( !firstTerm ){ if( argc==2 ){ zSep = (char*)sqlite3_value_text(argv[1]); nSep = sqlite3_value_bytes(argv[1]); }else{ zSep = ","; nSep = 1; } sqlite3StrAccumAppend(pAccum, zSep, nSep); } zVal = (char*)sqlite3_value_text(argv[0]); nVal = sqlite3_value_bytes(argv[0]); sqlite3StrAccumAppend(pAccum, zVal, nVal); } }
static void file_exists(sqlite3_context *ctx, int argc, sqlite3_value **argv) { char fpath[MAXPATHLEN]; sqlite3 *db = sqlite3_context_db_handle(ctx); char *path = dirname(sqlite3_db_filename(db, "main")); char cksum[SHA256_DIGEST_LENGTH * 2 +1]; if (argc != 2) { sqlite3_result_error(ctx, "file_exists needs two argument", -1); return; } snprintf(fpath, sizeof(fpath), "%s/%s", path, sqlite3_value_text(argv[0])); if (access(fpath, R_OK) == 0) { sha256_file(fpath, cksum); if (strcmp(cksum, sqlite3_value_text(argv[1])) == 0) sqlite3_result_int(ctx, 1); else sqlite3_result_int(ctx, 0); } else { sqlite3_result_int(ctx, 0); } }
static int dbpageColumn( sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i ){ DbpageCursor *pCsr = (DbpageCursor *)pCursor; DbpageTable *pTab = (DbpageTable *)pCursor->pVtab; int rc = SQLITE_OK; switch( i ){ case 0: { /* pgno */ sqlite3_result_int(ctx, pCsr->pgno); break; } case 1: { /* data */ DbPage *pDbPage = 0; rc = sqlite3PagerGet(pTab->pPager, pCsr->pgno, (DbPage**)&pDbPage, 0); if( rc==SQLITE_OK ){ sqlite3_result_blob(ctx, sqlite3PagerGetData(pDbPage), pTab->szPage, SQLITE_TRANSIENT); } sqlite3PagerUnref(pDbPage); break; } default: { /* schema */ sqlite3 *db = sqlite3_context_db_handle(ctx); sqlite3_result_text(ctx, db->aDb[pTab->iDb].zDbSName, -1, SQLITE_STATIC); break; } } return SQLITE_OK; }
/* * SQLite manages explicit transactions by setting a flag when a BEGIN; is * issued, then starting an actual transaction in the btree layer when the * first operation happens (a read txn if it's a read op, a write txn if write) * Then each statement will be contained in a sub-transaction. Since sequences * are implemented using a custom function, we need to emulate that * functionality. So there are three cases here: * - Not in an explicit transaction - start a statement, since we might do * write operations, and thus we need a valid statement_txn. * - In an explicit transaction, and the first statement. Start a txn and a statement txn. * - In an explicit transaction and not the first statemetn. Start a statement * transaction. * * The SQLite vdbe will take care of closing the statement transaction for us, * so we don't need to worry about that. * * Caching sequences can't be transactionally protected, so it's a no-op in * that case (and this function should not be called). * * It's safe to call this method multiple times since both * sqlite3BtreeBeginTrans and sqlite3BtreeBeginStmt are no-ops on subsequent * calls. */ static int btreeSeqStartTransaction( sqlite3_context *context, Btree *p, int is_write) { sqlite3 *db; Vdbe *vdbe; int rc; db = sqlite3_context_db_handle(context); /* * TODO: This is actually a linked list of VDBEs, not necessarily * the vdbe we want. I can't see a way to get the correct * vdbe handle. * It's possible that there is only one VDBE handle in DB, since * we use a shared cache. */ vdbe = db->pVdbe; if (!sqlite3BtreeIsInTrans(p) && (rc = btreeBeginTransInternal(p, 1)) != SQLITE_OK) { btreeSeqError(context, SQLITE_ERROR, "Could not begin transaction."); return (rc); } /* * TODO: Do we need logic bumping the VDBE statement count here? * vdbe.c:OP_Transaction does, but adding it here causes an * assert failure. It should be OK, because this code is only * really relevant in the case where there is a single statement. */ rc = sqlite3BtreeBeginStmt(p, vdbe->iStatement); return (rc); }
/* ** The implementation of the sqlite_record() function. This function accepts ** a single argument of any type. The return value is a formatted database ** record (a blob) containing the argument value. ** ** This is used to convert the value stored in the 'sample' column of the ** sqlite_stat3 table to the record format SQLite uses internally. */ static void recordFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const int file_format = 1; int iSerial; /* Serial type */ int nSerial; /* Bytes of space for iSerial as varint */ int nVal; /* Bytes of space required for argv[0] */ int nRet; sqlite3 *db; u8 *aRet; UNUSED_PARAMETER( argc ); iSerial = sqlite3VdbeSerialType(argv[0], file_format); nSerial = sqlite3VarintLen(iSerial); nVal = sqlite3VdbeSerialTypeLen(iSerial); db = sqlite3_context_db_handle(context); nRet = 1 + nSerial + nVal; aRet = sqlite3DbMallocRaw(db, nRet); if( aRet==0 ){ sqlite3_result_error_nomem(context); }else{ aRet[0] = nSerial+1; sqlite3PutVarint(&aRet[1], iSerial); sqlite3VdbeSerialPut(&aRet[1+nSerial], nVal, argv[0], file_format); sqlite3_result_blob(context, aRet, nRet, SQLITE_TRANSIENT); sqlite3DbFree(db, aRet); } }
/* Create or update the cookie entry in the metadata db. */ static int btreeSeqPutCookie( sqlite3_context *context, Btree *p, SEQ_COOKIE *cookie, u_int32_t flags) { BtShared *pBt; DBT cookie_key, cookie_data; int rc, ret; sqlite3 *db; pBt = p->pBt; db = sqlite3_context_db_handle(context); /* Ensure a transaction has been started. */ if (cookie->cache == 0 && (rc = btreeSeqStartTransaction(context, p, 1)) != SQLITE_OK) { btreeSeqError(context, SQLITE_ERROR, "Could not begin transaction for create."); return rc; } /* Create the matching cookie entry in the metadata db. */ memset(&cookie_key, 0, sizeof(cookie_key)); memset(&cookie_data, 0, sizeof(cookie_data)); cookie_key.data = cookie->name; cookie_key.size = cookie_key.ulen = cookie->name_len; cookie_key.flags = cookie_data.flags = DB_DBT_USERMEM; cookie_data.data = cookie; cookie_data.size = cookie_data.ulen = sizeof(SEQ_COOKIE); if ((ret = pBt->metadb->put(pBt->metadb, p->savepoint_txn, &cookie_key, &cookie_data, flags)) != 0) return ret; return (0); }
/* ** Implementation of the eval(X) and eval(X,Y) SQL functions. ** ** Evaluate the SQL text in X. Return the results, using string ** Y as the separator. If Y is omitted, use a single space character. */ static void sqlEvalFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const char *zSql; sqlite3 *db; char *zErr = 0; int rc; struct EvalResult x; memset(&x, 0, sizeof(x)); x.zSep = " "; zSql = (const char*)sqlite3_value_text(argv[0]); if( zSql==0 ) return; if( argc>1 ){ x.zSep = (const char*)sqlite3_value_text(argv[1]); if( x.zSep==0 ) return; } x.szSep = (int)strlen(x.zSep); db = sqlite3_context_db_handle(context); rc = sqlite3_exec(db, zSql, callback, &x, &zErr); if( rc!=SQLITE_OK ){ sqlite3_result_error(context, zErr, -1); sqlite3_free(zErr); }else if( x.zSep==0 ){ sqlite3_result_error_nomem(context); sqlite3_free(x.z); }else{ sqlite3_result_text(context, x.z, (int)x.nUsed, sqlite3_free); } }
/* ** 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 the substr() function. ** ** substr(x,p1,p2) returns p2 characters of x[] beginning with p1. ** p1 is 1-indexed. So substr(x,1,1) returns the first character ** of x. If x is text, then we actually count UTF-8 characters. ** If x is a blob, then we count bytes. ** ** If p1 is negative, then we begin abs(p1) from the end of x[]. */ static void substrFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *z; const unsigned char *z2; int len; int p0type; i64 p1, p2; assert( argc==3 || argc==2 ); p0type = sqlite3_value_type(argv[0]); if( p0type==SQLITE_BLOB ){ len = sqlite3_value_bytes(argv[0]); z = sqlite3_value_blob(argv[0]); if( z==0 ) return; assert( len==sqlite3_value_bytes(argv[0]) ); }else{ z = sqlite3_value_text(argv[0]); if( z==0 ) return; len = 0; for(z2=z; *z2; len++){ SQLITE_SKIP_UTF8(z2); } } p1 = sqlite3_value_int(argv[1]); if( argc==3 ){ p2 = sqlite3_value_int(argv[2]); }else{ p2 = sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH]; } if( p1<0 ){ p1 += len; if( p1<0 ){ p2 += p1; p1 = 0; } }else if( p1>0 ){ p1--; } if( p1+p2>len ){ p2 = len-p1; } if( p0type!=SQLITE_BLOB ){ while( *z && p1 ){ SQLITE_SKIP_UTF8(z); p1--; } for(z2=z; *z2 && p2; p2--){ SQLITE_SKIP_UTF8(z2); } sqlite3_result_text(context, (char*)z, z2-z, SQLITE_TRANSIENT); }else{ if( p2<0 ) p2 = 0; sqlite3_result_blob(context, (char*)&z[p1], p2, SQLITE_TRANSIENT); } }
/* ** Implementation of the last_insert_rowid() SQL function. The return ** value is the same as the sqlite3_last_insert_rowid() API function. */ static void last_insert_rowid( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER2(NotUsed, NotUsed2); sqlite3_result_int64(context, sqlite3_last_insert_rowid(db)); }
/* ** Implementation of the total_changes() SQL function. The return value is ** the same as the sqlite3_total_changes() API function. */ static void total_changes( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER2(NotUsed, NotUsed2); sqlite3_result_int(context, sqlite3_total_changes(db)); }
/* ** Implementation of the total_changes() SQL function. The return value is ** the same as the sqlite3_total_changes() API function. */ static void total_changes( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER2(NotUsed, NotUsed2); /* IMP: R-52756-41993 This function is a wrapper around the ** sqlite3_total_changes() C/C++ interface. */ sqlite3_result_int(context, sqlite3_total_changes(db)); }
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); }
static void test_agg_errmsg16_final(sqlite3_context *ctx){ #ifndef SQLITE_OMIT_UTF16 const void *z; sqlite3 * db = sqlite3_context_db_handle(ctx); sqlite3_aggregate_context(ctx, 2048); sqlite3BeginBenignMalloc(); z = sqlite3_errmsg16(db); sqlite3EndBenignMalloc(); sqlite3_result_text16(ctx, z, -1, SQLITE_TRANSIENT); #endif }
extern void my_row_count(sqlite3_context *context, int argc, sqlite3_value **argv){ sqlite3 *thisdb; thisdb = sqlite3_context_db_handle(context); if (thisdb) { sqlite3_result_int(context, sqlite3_changes(thisdb)); } else { sqlite3_result_null(context); } }
ikptr ik_sqlite3_context_db_handle (ikptr s_context, ikpcb * pcb) { #ifdef HAVE_SQLITE3_CONTEXT_DB_HANDLE sqlite3_context * context = IK_SQLITE_CONTEXT(s_context); sqlite3 * conn; conn = sqlite3_context_db_handle(context); return (conn)? ika_pointer_alloc(pcb, (ik_ulong)conn) : IK_FALSE; #else feature_failure(__func__); #endif }
/* ** Implementation of the last_insert_rowid() SQL function. The return ** value is the same as the sqlite3_last_insert_rowid() API function. */ static void last_insert_rowid( sqlite3_context *context, int NotUsed, sqlite3_value **NotUsed2 ){ sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER2(NotUsed, NotUsed2); /* IMP: R-51513-12026 The last_insert_rowid() SQL function is a ** wrapper around the sqlite3_last_insert_rowid() C/C++ interface ** function. */ sqlite3_result_int64(context, sqlite3_last_insert_rowid(db)); }
/* ** This function is used by SQL generated to implement the ** ALTER TABLE command. The first argument is the text of a CREATE TABLE or ** CREATE INDEX command. The second is a table name. The table name in ** the CREATE TABLE or CREATE INDEX statement is replaced with the third ** argument and the result returned. Examples: ** ** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def') ** -> 'CREATE TABLE def(a, b, c)' ** ** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def') ** -> 'CREATE INDEX i ON def(a, b, c)' 这个函数使用SQL执行ALTER TABLE命令生成。 第一个参数是创建表或文本 创建索引的命令。第二个是表名。 创建表的表名或创建INDEX语句被替换为第三个参数,返回的结果。 例子: ** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def') ** -> 'CREATE TABLE def(a, b, c)' ** ** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def') ** -> 'CREATE INDEX i ON def(a, b, c)' */ static void renameTableFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ unsigned char const *zSql = sqlite3_value_text(argv[0]); unsigned char const *zTableName = sqlite3_value_text(argv[1]); int token; Token tname; unsigned char const *zCsr = zSql; int len = 0; char *zRet; sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER(NotUsed); /* The principle used to locate the table name in the CREATE TABLE ** statement is that the table name is the first non-space token that ** is immediately followed by a TK_LP or TK_USING token. 原理用于定位在CREATE table语句表名, 该语句是表名是立即紧随其后TK_LP或进行技术改造TK_USING令牌的第一个非空间令牌。 */ if( zSql ){ do { if( !*zCsr ){ /* Ran out of input before finding an opening bracket. Return NULL. 找到一个开括号之前放弃输入。返回null。*/ return; } /* Store the token that zCsr points to in tname. 存储tname zCsr指向表名的令牌 */ tname.z = (char*)zCsr; tname.n = len; /* Advance zCsr to the next token. Store that token type in 'token', ** and its length in 'len' (to be used next iteration of this loop). 推进zCsr到下一个令牌。令牌类型存储用“token”, 和它的长度的用‘len’(下一个迭代的循环使用)。 */ do { zCsr += len; len = sqlite3GetToken(zCsr, &token); } while( token==TK_SPACE ); assert( len>0 ); } while( token!=TK_LP && token!=TK_USING ); zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", ((u8*)tname.z) - zSql, zSql, zTableName, tname.z+tname.n); sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); } }
/* ** Allocate nByte bytes of space using sqlite3_malloc(). If the ** allocation fails, call sqlite3_result_error_nomem() to notify ** the database handle that malloc() has failed. */ static void *contextMalloc(sqlite3_context *context, i64 nByte){ char *z; if( nByte>sqlite3_context_db_handle(context)->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(context); z = 0; }else{ z = sqlite3Malloc(nByte); if( !z && nByte>0 ){ sqlite3_result_error_nomem(context); } } return z; }
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); }
/* ** Auxiliary SQL function to return the name of the VFS */ static void vfsNameFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); char *zVfs = 0; UNUSED_PARAMETER(argc); UNUSED_PARAMETER(argv); sqlite3_file_control(db, "main", SQLITE_FCNTL_VFSNAME, &zVfs); if( zVfs ){ sqlite3_result_text(context, zVfs, -1, sqlite3_free); } }
/* ** This function is used by SQL generated to implement the ** ALTER TABLE command. The first argument is the text of a CREATE TABLE or ** CREATE INDEX command. The second is a table name. The table name in ** the CREATE TABLE or CREATE INDEX statement is replaced with the third ** argument and the result returned. Examples: ** ** sqlite_rename_table('CREATE TABLE abc(a, b, c)', 'def') ** -> 'CREATE TABLE def(a, b, c)' ** ** sqlite_rename_table('CREATE INDEX i ON abc(a)', 'def') ** -> 'CREATE INDEX i ON def(a, b, c)' */ static void renameTableFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ unsigned char const *zSql = sqlite3_value_text(argv[0]); unsigned char const *zTableName = sqlite3_value_text(argv[1]); int token; Token tname; unsigned char const *zCsr = zSql; int len = 0; char *zRet; sqlite3 *db = sqlite3_context_db_handle(context); UNUSED_PARAMETER(NotUsed); /* The principle used to locate the table name in the CREATE TABLE ** statement is that the table name is the first non-space token that ** is immediately followed by a TK_LP or TK_USING token. */ if( zSql ){ do { if( !*zCsr ){ /* Ran out of input before finding an opening bracket. Return NULL. */ return; } /* Store the token that zCsr points to in tname. */ tname.z = zCsr; tname.n = len; /* Advance zCsr to the next token. Store that token type in 'token', ** and its length in 'len' (to be used next iteration of this loop). */ do { zCsr += len; len = sqlite3GetToken(zCsr, &token); } while( token==TK_SPACE ); assert( len>0 ); } while( token!=TK_LP && token!=TK_USING ); zRet = sqlite3MPrintf(db, "%.*s\"%w\"%s", tname.z - zSql, zSql, zTableName, tname.z+tname.n); sqlite3_result_text(context, zRet, -1, SQLITE_DYNAMIC); } }
/* ** A function that loads a shared-library extension then returns NULL. */ static void loadExt(sqlite3_context *context, int argc, sqlite3_value **argv){ const char *zFile = (const char *)sqlite3_value_text(argv[0]); const char *zProc; sqlite3 *db = sqlite3_context_db_handle(context); char *zErrMsg = 0; if( argc==2 ){ zProc = (const char *)sqlite3_value_text(argv[1]); }else{ zProc = 0; } if( zFile && sqlite3_load_extension(db, zFile, zProc, &zErrMsg) ){ sqlite3_result_error(context, zErrMsg, -1); sqlite3_free(zErrMsg); } }
/* ** Implementation of the like() SQL function. This function implements ** the build-in LIKE operator. The first argument to the function is the ** pattern and the second argument is the string. So, the SQL statements: ** ** A LIKE B ** ** is implemented as like(B,A). ** ** This same function (with a different compareInfo structure) computes ** the GLOB operator. */ static void likeFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ const unsigned char *zA, *zB; int escape = 0; int nPat; sqlite3 *db = sqlite3_context_db_handle(context); zB = sqlite3_value_text(argv[0]); zA = sqlite3_value_text(argv[1]); /* Limit the length of the LIKE or GLOB pattern to avoid problems ** of deep recursion and N*N behavior in patternCompare(). */ nPat = sqlite3_value_bytes(argv[0]); testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ); testcase( nPat==db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH]+1 ); if( nPat > db->aLimit[SQLITE_LIMIT_LIKE_PATTERN_LENGTH] ){ sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1); return; } assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */ if( argc==3 ){ /* The escape character string must consist of a single UTF-8 character. ** Otherwise, return an error. */ const unsigned char *zEsc = sqlite3_value_text(argv[2]); if( zEsc==0 ) return; if( sqlite3Utf8CharLen((char*)zEsc, -1)!=1 ){ sqlite3_result_error(context, "ESCAPE expression must be a single character", -1); return; } escape = sqlite3Utf8Read(zEsc, &zEsc); } if( zA && zB ){ struct compareInfo *pInfo = sqlite3_user_data(context); #ifdef SQLITE_TEST sqlite3_like_count++; #endif sqlite3_result_int(context, patternCompare(zB, zA, pInfo, escape)); } }
/* ** An SQL user-function registered to do the work of an DETACH statement. The ** three arguments to the function come directly from a detach statement: ** ** DETACH DATABASE x ** ** SELECT sqlite_detach(x) */ static void detachFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ const char *zName = (const char *)sqlite3_value_text(argv[0]); sqlite3 *db = sqlite3_context_db_handle(context); int i; Db *pDb = 0; char zErr[128]; UNUSED_PARAMETER(NotUsed); if( zName==0 ) zName = ""; for(i=0; i<db->nDb; i++){ pDb = &db->aDb[i]; if( pDb->pBt==0 ) continue; if( sqlite3StrICmp(pDb->zName, zName)==0 ) break; } if( i>=db->nDb ){ sqlite3_snprintf(sizeof(zErr),zErr, "no such database: %s", zName); goto detach_error; } if( i<2 ){ sqlite3_snprintf(sizeof(zErr),zErr, "cannot detach database %s", zName); goto detach_error; } if( !db->autoCommit ){ sqlite3_snprintf(sizeof(zErr), zErr, "cannot DETACH database within transaction"); goto detach_error; } if( sqlite3BtreeIsInReadTrans(pDb->pBt) || sqlite3BtreeIsInBackup(pDb->pBt) ){ sqlite3_snprintf(sizeof(zErr),zErr, "database %s is locked", zName); goto detach_error; } sqlite3BtreeClose(pDb->pBt); pDb->pBt = 0; pDb->pSchema = 0; sqlite3ResetInternalSchema(db, 0); return; detach_error: sqlite3_result_error(context, zErr, -1); }
static void renameParentFunc( sqlite3_context *context, int NotUsed, sqlite3_value **argv ){ sqlite3 *db = sqlite3_context_db_handle(context); char *zOutput = 0; char *zResult; unsigned char const *zInput = sqlite3_value_text(argv[0]); unsigned char const *zOld = sqlite3_value_text(argv[1]); unsigned char const *zNew = sqlite3_value_text(argv[2]); unsigned const char *z; /* Pointer to token */ int n; /* Length of token z */ int token; /* Type of token */ UNUSED_PARAMETER(NotUsed); if( zInput==0 || zOld==0 ) return; for(z=zInput; *z; z=z+n){ n = sqlite3GetToken(z, &token); if( token==TK_REFERENCES ){ char *zParent; do { z += n; n = sqlite3GetToken(z, &token); }while( token==TK_SPACE ); if( token==TK_ILLEGAL ) break; zParent = sqlite3DbStrNDup(db, (const char *)z, n); if( zParent==0 ) break; sqlite3Dequote(zParent); if( 0==sqlite3StrICmp((const char *)zOld, zParent) ){ char *zOut = sqlite3MPrintf(db, "%s%.*s\"%w\"", (zOutput?zOutput:""), (int)(z-zInput), zInput, (const char *)zNew ); sqlite3DbFree(db, zOutput); zOutput = zOut; zInput = &z[n]; } sqlite3DbFree(db, zParent); } } zResult = sqlite3MPrintf(db, "%s%s", (zOutput?zOutput:""), zInput), sqlite3_result_text(context, zResult, -1, SQLITE_DYNAMIC); sqlite3DbFree(db, zOutput); }
static int statColumn( sqlite3_vtab_cursor *pCursor, sqlite3_context *ctx, int i ){ StatCursor *pCsr = (StatCursor *)pCursor; switch( i ){ case 0: /* name */ sqlite3_result_text(ctx, pCsr->zName, -1, SQLITE_TRANSIENT); break; case 1: /* path */ sqlite3_result_text(ctx, pCsr->zPath, -1, SQLITE_TRANSIENT); break; case 2: /* pageno */ sqlite3_result_int64(ctx, pCsr->iPageno); break; case 3: /* pagetype */ sqlite3_result_text(ctx, pCsr->zPagetype, -1, SQLITE_STATIC); break; case 4: /* ncell */ sqlite3_result_int(ctx, pCsr->nCell); break; case 5: /* payload */ sqlite3_result_int(ctx, pCsr->nPayload); break; case 6: /* unused */ sqlite3_result_int(ctx, pCsr->nUnused); break; case 7: /* mx_payload */ sqlite3_result_int(ctx, pCsr->nMxPayload); break; case 8: /* pgoffset */ sqlite3_result_int64(ctx, pCsr->iOffset); break; case 9: /* pgsize */ sqlite3_result_int(ctx, pCsr->szPage); break; default: { /* schema */ sqlite3 *db = sqlite3_context_db_handle(ctx); int iDb = pCsr->iDb; sqlite3_result_text(ctx, db->aDb[iDb].zName, -1, SQLITE_STATIC); break; } } return SQLITE_OK; }
/* ** Allocate nByte bytes of space using sqlite3_malloc(). If the ** allocation fails, call sqlite3_result_error_nomem() to notify ** the database handle that malloc() has failed and return NULL. ** If nByte is larger than the maximum string or blob length, then ** raise an SQLITE_TOOBIG exception and return NULL. */ static void *contextMalloc(sqlite3_context *context, i64 nByte){ char *z; sqlite3 *db = sqlite3_context_db_handle(context); assert( nByte>0 ); testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH] ); testcase( nByte==db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); if( nByte>db->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(context); z = 0; }else{ z = sqlite3Malloc((int)nByte); if( !z ){ sqlite3_result_error_nomem(context); } } return z; }
/* ** The zeroblob(N) function returns a zero-filled blob of size N bytes. */ static void zeroblobFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ i64 n; sqlite3 *db = sqlite3_context_db_handle(context); assert( argc==1 ); UNUSED_PARAMETER(argc); n = sqlite3_value_int64(argv[0]); testcase( n==db->aLimit[SQLITE_LIMIT_LENGTH] ); testcase( n==db->aLimit[SQLITE_LIMIT_LENGTH]+1 ); if( n>db->aLimit[SQLITE_LIMIT_LENGTH] ){ sqlite3_result_error_toobig(context); }else{ sqlite3_result_zeroblob(context, (int)n); } }