本文介紹了sqlite3解析和編譯SQL語句時, 宿主語言設定的定制函數找不到的issue; 主要引用相關代碼, 描述了sqlite編譯SQL語句的大緻流程.
[GENERAL DESCRIPTION:]
Process: com.sonyericsson.album
Flags: 0x8be45
Package: com.xxxxxxxxx.album
Build: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:userdebug/release-keys
java.lang.RuntimeException: An error occured while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:299)
at java.util.concurrent.FutureTask$Sync.innerSetException(FutureTask.java:273)
at java.util.concurrent.FutureTask.setException(FutureTask.java:124)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:307)
at java.util.concurrent.FutureTask.run(FutureTask.java:137)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:230)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
at java.lang.Thread.run(Thread.java:856)
Caused by: android.database.sqlite.SQLiteException: no such function: _OBJECT_REMOVED (code 1): , while compiling: DELETE FROM files WHERE _id = 3406
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:184)
at android.database.DatabaseUtils.readExceptionFromParcel(DatabaseUtils.java:140)
at android.content.ContentProviderProxy.delete(ContentProviderNative.java:484)
at android.content.ContentResolver.delete(ContentResolver.java:956)
at com.sonyericsson.album.camera.MenuExecutor.executeOperationInBackground(MenuExecutor.java:145)
at com.sonyericsson.album.camera.MenuExecutor.access$000(MenuExecutor.java:36)
at com.sonyericsson.album.camera.MenuExecutor$OperationExecutor.doInBackground(MenuExecutor.java:122)
at com.sonyericsson.album.camera.MenuExecutor$OperationExecutor.doInBackground(MenuExecutor.java:109)
at android.os.AsyncTask$2.call(AsyncTask.java:287)
at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
... 5 more
[Analysis]
For the exception string android.database.sqlite.SQLiteException: no such function: _OBJECT_REMOVED (code 1): , while compiling: DELETE FROM files WHERE _id = 3406,
the 'while compiling: %s' part is printed out by native function nativePrepareStatement().
nativePrepareStatement() @ android_database_SQLiteConnection.cpp
282static jint nativePrepareStatement(JNIEnv* env, jclass clazz, jint connectionPtr,
283 jstring sqlString) {
284 SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
285
286 jsize sqlLength = env->GetStringLength(sqlString);
287 const jchar* sql = env->GetStringCritical(sqlString, NULL);
288 sqlite3_stmt* statement;
289 int err = sqlite3_prepare16_v2(connection->db, *******************************
290 sql, sqlLength * sizeof(jchar), &statement, NULL);
291 env->ReleaseStringCritical(sqlString, sql);
292
293 if (err != SQLITE_OK) {
294 // Error messages like 'near ")": syntax error' are not
295 // always helpful enough, so construct an error string that
296 // includes the query itself.
297 const char *query = env->GetStringUTFChars(sqlString, NULL);
298 char *message = (char*) malloc(strlen(query) + 50);
299 if (message) {
300 strcpy(message, ", while compiling: "); // less than 50 chars ********************
301 strcat(message, query);
302 }
303 env->ReleaseStringUTFChars(sqlString, query);
304 throw_sqlite3_exception(env, connection->db, message);
305 free(message);
306 return 0;
307 }
308
309 ALOGV("Prepared statement %p on connection %p", statement, connection->db);
310 return reinterpret_cast<jint>(statement);
311}
while the "no such function" string part is printed by sqlite3 sql statement parse function.
94512SQLITE_API int sqlite3_prepare16_v2(
94513 sqlite3 *db,
94514 const void *zSql,
94515 int nBytes,
94516 sqlite3_stmt **ppStmt,
94517 const void **pzTail
94518){
94519 int rc;
94520 rc = sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
94521 assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 );
94522 return rc;
94523}
calls------->>
94450static int sqlite3Prepare16(
94451 sqlite3 *db,
94452 const void *zSql,
94453 int nBytes,
94454 int saveSqlFlag,
94455 sqlite3_stmt **ppStmt,
94456 const void **pzTail
94457){
94458
94462 char *zSql8;
94463 const char *zTail8 = 0;
94464 int rc = SQLITE_OK;
94465
94466 assert( ppStmt );
94467 *ppStmt = 0;
94468 if( !sqlite3SafetyCheckOk(db) ){
94469 return SQLITE_MISUSE_BKPT;
94470 }
94471 sqlite3_mutex_enter(db->mutex);
94472 zSql8 = sqlite3Utf16to8(db, zSql, nBytes, SQLITE_UTF16NATIVE);
94473 if( zSql8 ){
94474 rc = sqlite3LockAndPrepare(db, zSql8, -1, saveSqlFlag, 0, ppStmt, &zTail8);
94475 }
94476
94477 if( zTail8 && pzTail ){
94478
94483 int chars_parsed = sqlite3Utf8CharLen(zSql8, (int)(zTail8-zSql8));
94484 *pzTail = (u8 *)zSql + sqlite3Utf16ByteLen(zSql, chars_parsed);
94485 }
94486 sqlite3DbFree(db, zSql8);
94487 rc = sqlite3ApiExit(db, rc);
94488 sqlite3_mutex_leave(db->mutex);
94489 return rc;
94490}
calls------>>
94348static int sqlite3LockAndPrepare(
94349 sqlite3 *db,
94350 const char *zSql,
94351 int nBytes,
94352 int saveSqlFlag,
94353 Vdbe *pOld,
94354 sqlite3_stmt **ppStmt,
94355 const char **pzTail
94356){
94357 int rc;
94358 assert( ppStmt!=0 );
94359 *ppStmt = 0;
94360 if( !sqlite3SafetyCheckOk(db) ){
94361 return SQLITE_MISUSE_BKPT;
94362 }
94363 sqlite3_mutex_enter(db->mutex);
94364 sqlite3BtreeEnterAll(db);
94365 rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
94366 if( rc==SQLITE_SCHEMA ){
94367 sqlite3_finalize(*ppStmt);
94368 rc = sqlite3Prepare(db, zSql, nBytes, saveSqlFlag, pOld, ppStmt, pzTail);
94369 }
94370 sqlite3BtreeLeaveAll(db);
94371 sqlite3_mutex_leave(db->mutex);
94372 return rc;
94373}
calls------>>
94185
94188static int sqlite3Prepare(
94189 sqlite3 *db,
94190 const char *zSql,
94191 int nBytes,
94192 int saveSqlFlag,
94193 Vdbe *pReprepare,
94194 sqlite3_stmt **ppStmt,
94195 const char **pzTail
94196){
94197 Parse *pParse;
94198 char *zErrMsg = 0;
94199 int rc = SQLITE_OK;
94200 int i;
94201
94202
94203 pParse = sqlite3StackAllocZero(db, sizeof(*pParse));
94204 if( pParse==0 ){
94205 rc = SQLITE_NOMEM;
94206 goto end_prepare;
94207 }
94208 pParse->pReprepare = pReprepare;
94209 assert( ppStmt && *ppStmt==0 );
94210 assert( !db->mallocFailed );
94211 assert( sqlite3_mutex_held(db->mutex) );
94212
94213
94236 for(i=0; i<db->nDb; i++) {
94237 Btree *pBt = db->aDb[i].pBt;
94238 if( pBt ){
94239 assert( sqlite3BtreeHoldsMutex(pBt) );
94240 rc = sqlite3BtreeSchemaLocked(pBt);
94241 if( rc ){
94242 const char *zDb = db->aDb[i].zName;
94243 sqlite3Error(db, rc, "database schema is locked: %s", zDb);
94244 testcase( db->flags & SQLITE_ReadUncommitted );
94245 goto end_prepare;
94246 }
94247 }
94248 }
94249
94250 sqlite3VtabUnlockList(db);
94251
94252 pParse->db = db;
94253 pParse->nQueryLoop = (double)1;
94254 if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){
94255 char *zSqlCopy;
94256 int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH];
94257 testcase( nBytes==mxLen );
94258 testcase( nBytes==mxLen+1 );
94259 if( nBytes>mxLen ){
94260 sqlite3Error(db, SQLITE_TOOBIG, "statement too long");
94261 rc = sqlite3ApiExit(db, SQLITE_TOOBIG);
94262 goto end_prepare;
94263 }
94264 zSqlCopy = sqlite3DbStrNDup(db, zSql, nBytes);
94265 if( zSqlCopy ){
94266 sqlite3RunParser(pParse, zSqlCopy, &zErrMsg); ******************************
94267 sqlite3DbFree(db, zSqlCopy);
94268 pParse->zTail = &zSql[pParse->zTail-zSqlCopy];
94269 }else{
94270 pParse->zTail = &zSql[nBytes];
94271 }
94272 }else{
94273 sqlite3RunParser(pParse, zSql, &zErrMsg); ********************************
94274 }
94275 assert( 1==(int)pParse->nQueryLoop );
94276
94277 if( db->mallocFailed ){
94278 pParse->rc = SQLITE_NOMEM;
94279 }
94280 if( pParse->rc==SQLITE_DONE ) pParse->rc = SQLITE_OK;
94281 if( pParse->checkSchema ){
94282 schemaIsValid(pParse);
94283 }
94284 if( db->mallocFailed ){
94285 pParse->rc = SQLITE_NOMEM;
94286 }
94287 if( pzTail ){
94288 *pzTail = pParse->zTail;
94289 }
94290 rc = pParse->rc;
94291
94292#ifndef SQLITE_OMIT_EXPLAIN
94293 if( rc==SQLITE_OK && pParse->pVdbe && pParse->explain ){
94294 static const char * const azColName[] = {
94295 "addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
94296 "selectid", "order", "from", "detail"
94297 };
94298 int iFirst, mx;
94299 if( pParse->explain==2 ){
94300 sqlite3VdbeSetNumCols(pParse->pVdbe, 4);
94301 iFirst = 8;
94302 mx = 12;
94303 }else{
94304 sqlite3VdbeSetNumCols(pParse->pVdbe, 8);
94305 iFirst = 0;
94306 mx = 8;
94307 }
94308 for(i=iFirst; i<mx; i++){
94309 sqlite3VdbeSetColName(pParse->pVdbe, i-iFirst, COLNAME_NAME,
94310 azColName[i], SQLITE_STATIC);
94311 }
94312 }
94313#endif
94314
94315 assert( db->init.busy==0 || saveSqlFlag==0 );
94316 if( db->init.busy==0 ){
94317 Vdbe *pVdbe = pParse->pVdbe;
94318 sqlite3VdbeSetSql(pVdbe, zSql, (int)(pParse->zTail-zSql), saveSqlFlag);
94319 }
94320 if( pParse->pVdbe && (rc!=SQLITE_OK || db->mallocFailed) ){
94321 sqlite3VdbeFinalize(pParse->pVdbe);
94322 assert(!(*ppStmt));
94323 }else{
94324 *ppStmt = (sqlite3_stmt*)pParse->pVdbe;
94325 }
94326
94327 if( zErrMsg ){
94328 sqlite3Error(db, rc, "%s", zErrMsg);
94329 sqlite3DbFree(db, zErrMsg);
94330 }else{
94331 sqlite3Error(db, rc, 0);
94332 }
94333
94334
94335 while( pParse->pTriggerPrg ){
94336 TriggerPrg *pT = pParse->pTriggerPrg;
94337 pParse->pTriggerPrg = pT->pNext;
94338 sqlite3DbFree(db, pT);
94339 }
94340
94341end_prepare:
94342
94343 sqlite3StackFree(db, pParse);
94344 rc = sqlite3ApiExit(db, rc);
94345 assert( (rc&db->errMask)==rc );
94346 return rc;
94347}
sqlite3RunParser() calls sqlite3Parser() to parse the sql statement, and compile it using the following
yy_reduce, lexical analysis.
resolveOrderByTermToExprList \
resolveOrderGroupBy |
resolveSelectStep |
resolveAttachExpr |
sqlite3EndTable \
sqlite3DeleteFrom ** / sqlite3ResolveExprNames
fkScanChildren |
sqlite3Insert |
codeRowTrigger |
sqlite3Update /
The sql statement is consist of severial sub-clause, such as CRUD, ORDER BY, GROUP BY, LIKE, HAVING.
Every sub-clause is compiled by a yy_reduce entry.
These sub-clause compiling functions call sqlite3ResolveExprNames or sqlite3ResolveSelectNames.
sqlite3ResolveExprNames is one most important routine to compile sql statement.
In this issue, the DELETE is compiled by sqlite3DeleteFrom(...) which calls sqlite3ResolveExprNames.
The source of sqlite3ResolveExprNames & sqlite3ResolveSelectNames list as follows.
============================================================================================
74340SQLITE_PRIVATE int sqlite3ResolveExprNames(
74341 NameContext *pNC,
74342 Expr *pExpr
74343){
74344 int savedHasAgg;
74345 Walker w;
74346
74347 if( pExpr==0 ) return 0;
74348#if SQLITE_MAX_EXPR_DEPTH>0
74349 {
74350 Parse *pParse = pNC->pParse;
74351 if( sqlite3ExprCheckHeight(pParse, pExpr->nHeight+pNC->pParse->nHeight) ){
74352 return 1;
74353 }
74354 pParse->nHeight += pExpr->nHeight;
74355 }
74356#endif
74357 savedHasAgg = pNC->hasAgg;
74358 pNC->hasAgg = 0;
74359 w.xExprCallback = resolveExprStep; *****************
74360 w.xSelectCallback = resolveSelectStep;
74361 w.pParse = pNC->pParse;
74362 w.u.pNC = pNC;
74363 sqlite3WalkExpr(&w, pExpr); ****************
74364#if SQLITE_MAX_EXPR_DEPTH>0
74365 pNC->pParse->nHeight -= pExpr->nHeight;
74366#endif
74367 if( pNC->nErr>0 || w.pParse->nErr>0 ){
74368 ExprSetProperty(pExpr, EP_Error);
74369 }
74370 if( pNC->hasAgg ){
74371 ExprSetProperty(pExpr, EP_Agg);
74372 }else if( savedHasAgg ){
74373 pNC->hasAgg = 1;
74374 }
74375 return ExprHasProperty(pExpr, EP_Error);
74376}
-------------------------------------------------------------------
74391SQLITE_PRIVATE void sqlite3ResolveSelectNames(
74392 Parse *pParse,
74393 Select *p,
74394 NameContext *pOuterNC
74395){
74396 Walker w;
74397
74398 assert( p!=0 );
74399 w.xExprCallback = resolveExprStep; ***************
74400 w.xSelectCallback = resolveSelectStep;
74401 w.pParse = pParse;
74402 w.u.pNC = pOuterNC;
74403 sqlite3WalkSelect(&w, p); *************************
74404}
===========================================================================================
sqlite3ResolveExprNames(...) uses sqlite3WalkExpr(...) with worker callbacks to resolve expression names.
The ExprCallback field is resolveExprStep(...).
The source of resolveExprStep(...) is following.
Notice the first line comment of the function, it is callback for sqlite3WalkExpr().
73615** This routine is callback for sqlite3WalkExpr().
73616**
73617** Resolve symbolic names into TK_COLUMN operators for the current
73618** node in the expression tree. Return 0 to continue the search down
73619** the tree or 2 to abort the tree walk.
73620**
73621** This routine also does error checking and name resolution for
73622** function names. The operator for aggregate functions is changed
73623** to TK_AGG_FUNCTION.
73624*/
73625static int resolveExprStep(Walker *pWalker, Expr *pExpr){
73626 NameContext *pNC;
73627 Parse *pParse;
73628
73629 pNC = pWalker->u.pNC;
73630 assert( pNC!=0 );
73631 pParse = pNC->pParse;
73632 assert( pParse==pWalker->pParse );
73633
73634 if( ExprHasAnyProperty(pExpr, EP_Resolved) ) return WRC_Prune;
73635 ExprSetProperty(pExpr, EP_Resolved);
73636#ifndef NDEBUG
73637 if( pNC->pSrcList && pNC->pSrcList->nAlloc>0 ){
73638 SrcList *pSrcList = pNC->pSrcList;
73639 int i;
73640 for(i=0; i<pNC->pSrcList->nSrc; i++){
73641 assert( pSrcList->a[i].iCursor>=0 && pSrcList->a[i].iCursor<pParse->nTab);
73642 }
73643 }
73644#endif
73645 switch( pExpr->op ){
73646
73647#if defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY)
73648
73652 case TK_ROW: {
73653 SrcList *pSrcList = pNC->pSrcList;
73654 struct SrcList_item *pItem;
73655 assert( pSrcList && pSrcList->nSrc==1 );
73656 pItem = pSrcList->a;
73657 pExpr->op = TK_COLUMN;
73658 pExpr->pTab = pItem->pTab;
73659 pExpr->iTable = pItem->iCursor;
73660 pExpr->iColumn = -1;
73661 pExpr->affinity = SQLITE_AFF_INTEGER;
73662 break;
73663 }
73664#endif
73665
73666
73668 case TK_ID: {
73669 return lookupName(pParse, 0, 0, pExpr->u.zToken, pNC, pExpr);
73670 }
73671
73672
73675 case TK_DOT: {
73676 const char *zColumn;
73677 const char *zTable;
73678 const char *zDb;
73679 Expr *pRight;
73680
73681
73682 pRight = pExpr->pRight;
73683 if( pRight->op==TK_ID ){
73684 zDb = 0;
73685 zTable = pExpr->pLeft->u.zToken;
73686 zColumn = pRight->u.zToken;
73687 }else{
73688 assert( pRight->op==TK_DOT );
73689 zDb = pExpr->pLeft->u.zToken;
73690 zTable = pRight->pLeft->u.zToken;
73691 zColumn = pRight->pRight->u.zToken;
73692 }
73693 return lookupName(pParse, zDb, zTable, zColumn, pNC, pExpr);
73694 }
73695
73696
73698 case TK_CONST_FUNC:
73699 case TK_FUNCTION: {
73700 ExprList *pList = pExpr->x.pList;
73701 int n = pList ? pList->nExpr : 0;
73702 int no_such_func = 0;
73703 int wrong_num_args = 0;
73704 int is_agg = 0;
73705 int auth;
73706 int nId;
73707 const char *zId;
73708 FuncDef *pDef;
73709 u8 enc = ENC(pParse->db);
73710
73711 testcase( pExpr->op==TK_CONST_FUNC );
73712 assert( !ExprHasProperty(pExpr, EP_xIsSelect) );
73713 zId = pExpr->u.zToken;
73714 nId = sqlite3Strlen30(zId);
73715 pDef = sqlite3FindFunction(pParse->db, zId, nId, n, enc, 0); *****************
73716 if( pDef==0 ){
73717 pDef = sqlite3FindFunction(pParse->db, zId, nId, -1, enc, 0); *****************
73718 if( pDef==0 ){
73719 no_such_func = 1;
73720 }else{
73721 wrong_num_args = 1;
73722 }
73723 }else{
73724 is_agg = pDef->xFunc==0;
73725 }
73726#ifndef SQLITE_OMIT_AUTHORIZATION
73727 if( pDef ){
73728 auth = sqlite3AuthCheck(pParse, SQLITE_FUNCTION, 0, pDef->zName, 0);
73729 if( auth!=SQLITE_OK ){
73730 if( auth==SQLITE_DENY ){
73731 sqlite3ErrorMsg(pParse, "not authorized to use function: %s",
73732 pDef->zName);
73733 pNC->nErr++;
73734 }
73735 pExpr->op = TK_NULL;
73736 return WRC_Prune;
73737 }
73738 }
73739#endif
73740 if( is_agg && !pNC->allowAgg ){
73741 sqlite3ErrorMsg(pParse, "misuse of aggregate function %.*s()", nId,zId);
73742 pNC->nErr++;
73743 is_agg = 0;
73744 }else if( no_such_func ){
73745 sqlite3ErrorMsg(pParse, "no such function: %.*s", nId, zId); **************
73746 pNC->nErr++;
73747 }else if( wrong_num_args ){
73748 sqlite3ErrorMsg(pParse,"wrong number of arguments to function %.*s()",
73749 nId, zId);
73750 pNC->nErr++;
73751 }
73752 if( is_agg ){
73753 pExpr->op = TK_AGG_FUNCTION;
73754 pNC->hasAgg = 1;
73755 }
73756 if( is_agg ) pNC->allowAgg = 0;
73757 sqlite3WalkExprList(pWalker, pList);
73758 if( is_agg ) pNC->allowAgg = 1;
73759
73762 return WRC_Prune;
73763 }
73764#ifndef SQLITE_OMIT_SUBQUERY
73765 case TK_SELECT:
73766 case TK_EXISTS: testcase( pExpr->op==TK_EXISTS );
73767#endif
73768 case TK_IN: {
73769 testcase( pExpr->op==TK_IN );
73770 if( ExprHasProperty(pExpr, EP_xIsSelect) ){
73771 int nRef = pNC->nRef;
73772#ifndef SQLITE_OMIT_CHECK
73773 if( pNC->isCheck ){
73774 sqlite3ErrorMsg(pParse,"subqueries prohibited in CHECK constraints");
73775 }
73776#endif
73777 sqlite3WalkSelect(pWalker, pExpr->x.pSelect);
73778 assert( pNC->nRef>=nRef );
73779 if( nRef!=pNC->nRef ){
73780 ExprSetProperty(pExpr, EP_VarSelect);
73781 }
73782 }
73783 break;
73784 }
73785#ifndef SQLITE_OMIT_CHECK
73786 case TK_VARIABLE: {
73787 if( pNC->isCheck ){
73788 sqlite3ErrorMsg(pParse,"parameters prohibited in CHECK constraints");
73789 }
73790 break;
73791 }
73792#endif
73793 }
73794 return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue;
73795}
For the opcodes of TK_CONST_FUNC and TK_FUNCTION, the sqlite3FindFunction is used to find the registerred custom function of host language.
85332
85352SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
85353 sqlite3 *db,
85354 const char *zName,
85355 int nName,
85356 int nArg,
85357 u8 enc,
85358 int createFlag
85359){
85360 FuncDef *p;
85361 FuncDef *pBest = 0;
85362 int bestScore = 0;
85363 int h;
85364
85365
85366 assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE );
85367 h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % ArraySize(db->aFunc.a);
85368
85369
85371 p = functionSearch(&db->aFunc, h, zName, nName);
85372 while( p ){
85373 int score = matchQuality(p, nArg, enc);
85374 if( score>bestScore ){
85375 pBest = p;
85376 bestScore = score;
85377 }
85378 p = p->pNext;
85379 }
85380
85381
85393 if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
85394 FuncDefHash *pHash = &GLOBAL(FuncDefHash, sqlite3GlobalFunctions);
85395 bestScore = 0;
85396 p = functionSearch(pHash, h, zName, nName);
85397 while( p ){
85398 int score = matchQuality(p, nArg, enc);
85399 if( score>bestScore ){
85400 pBest = p;
85401 bestScore = score;
85402 }
85403 p = p->pNext;
85404 }
85405 }
85406
85407
85411 if( createFlag && (bestScore<6 || pBest->nArg!=nArg) &&
85412 (pBest = sqlite3DbMallocZero(db, sizeof(*pBest)+nName+1))!=0 ){
85413 pBest->zName = (char *)&pBest[1];
85414 pBest->nArg = (u16)nArg;
85415 pBest->iPrefEnc = enc;
85416 memcpy(pBest->zName, zName, nName);
85417 pBest->zName[nName] = 0;
85418 sqlite3FuncDefInsert(&db->aFunc, pBest);
85419 }
85420
85421 if( pBest && (pBest->xStep || pBest->xFunc || createFlag) ){
85422 return pBest;
85423 }
85424 return 0;
85425}
If the custom function is not found, the sql statement compiling engine claims that there is no such function.
U see, there are more other thing it may claim, such as wrong number of arguments to function, no such colomn, etc.
By now, look at where to set and trigger the user custom sql function.
In updateDatabase(...) @ MediaProvider.java, sql function triggered on deleting from table files is announced.
757 private static void MediaProvider::updateDatabase(Context context, SQLiteDatabase db, boolean internal,
758 int fromVersion, int toVersion) {
1602 if (fromVersion < 304 && !internal) {
1603 // notifies host when files are deleted
1604 db.execSQL("CREATE TRIGGER IF NOT EXISTS files_cleanup DELETE ON files" + ****************
1605 "BEGIN " +
1606 "SELECT _OBJECT_REMOVED(old._id);" +
1607 "END");
1608
1609 }
1610
1733 if (fromVersion < 506) {
1734 // sd card storage got moved to /storage/sdcard0
1735 // first delete everything that already got scanned in /storage before this
1736 // update step was added
1737 db.execSQL("DROP TRIGGER IF EXISTS files_cleanup");
1738 db.execSQL("DELETE FROM files WHERE _data LIKE '/storage/%';");
1739 db.execSQL("DELETE FROM album_art WHERE _data LIKE '/storage/%';");
1740 db.execSQL("DELETE FROM thumbnails WHERE _data LIKE '/storage/%';");
1741 db.execSQL("DELETE FROM videothumbnails WHERE _data LIKE '/storage/%';");
1742 // then rename everything from /mnt/sdcard/ to /storage/sdcard0,
1743 // and from /mnt/external1 to /storage/sdcard1
1744 db.execSQL("UPDATE files SET " +
1745 "_data='/storage/sdcard0'||SUBSTR(_data,12) WHERE _data LIKE '/mnt/sdcard/%';");
1746 db.execSQL("UPDATE files SET " +
1747 "_data='/storage/sdcard1'||SUBSTR(_data,15) WHERE _data LIKE '/mnt/external1/%';");
1748 db.execSQL("UPDATE album_art SET " +
1749 "_data='/storage/sdcard0'||SUBSTR(_data,12) WHERE _data LIKE '/mnt/sdcard/%';");
1750 db.execSQL("UPDATE album_art SET " +
1751 "_data='/storage/sdcard1'||SUBSTR(_data,15) WHERE _data LIKE '/mnt/external1/%';");
1752 db.execSQL("UPDATE thumbnails SET " +
1753 "_data='/storage/sdcard0'||SUBSTR(_data,12) WHERE _data LIKE '/mnt/sdcard/%';");
1754 db.execSQL("UPDATE thumbnails SET " +
1755 "_data='/storage/sdcard1'||SUBSTR(_data,15) WHERE _data LIKE '/mnt/external1/%';");
1756 db.execSQL("UPDATE videothumbnails SET " +
1757 "_data='/storage/sdcard0'||SUBSTR(_data,12) WHERE _data LIKE '/mnt/sdcard/%';");
1758 db.execSQL("UPDATE videothumbnails SET " +
1759 "_data='/storage/sdcard1'||SUBSTR(_data,15) WHERE _data LIKE '/mnt/external1/%';");
1760
1761 if (!internal) {
1762 db.execSQL("CREATE TRIGGER IF NOT EXISTS files_cleanup DELETE ON files" + ***************8
1763 "BEGIN " +
1764 "SELECT _OBJECT_REMOVED(old._id);" +
1765 "END");
1766 }
1767 }
In onOpen(...) @ MediaProvider.java, the callback function is actually set in host language scope.
436 @Override
437 public void DatabaseHelper::onOpen(SQLiteDatabase db) {
438
439 if (mInternal) return; // The internal database is kept separately.
440
441 if (mEarlyUpgrade) return; // Doing early upgrade.
442
443 if (mObjectRemovedCallback != null) {
444 db.addCustomFunction("_OBJECT_REMOVED", 1, mObjectRemovedCallback); *************
445 }
.....
507 }
So, if here is the cause, _OBJECT_REMOVED customed function is not set for the reason mObjectRemovedCallback is null except the reason that the sqlite customed function hash table is corrupted.
In another database open function, open() @ SQLiteConnection.java, costum functions are not registerred. This is the root cause with more possibility.
208 private void open() {
209 mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags,
210 mConfiguration.label,
211 SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);
212
213 setPageSize();
214 setForeignKeyModeFromConfiguration();
215 setWalModeFromConfiguration();
216 setJournalSizeLimit();
217 setAutoCheckpointInterval();
218 setLocaleFromConfiguration();
219 }
It should be patched with lines #219--#225 to register custom functions.
208 private void open() {
209 mConnectionPtr = nativeOpen(mConfiguration.path, mConfiguration.openFlags,
210 mConfiguration.label,
211 SQLiteDebug.DEBUG_SQL_STATEMENTS, SQLiteDebug.DEBUG_SQL_TIME);
212
213 setPageSize();
214 setForeignKeyModeFromConfiguration();
215 setWalModeFromConfiguration();
216 setJournalSizeLimit();
217 setAutoCheckpointInterval();
218 setLocaleFromConfiguration();
219
220 // Register custom functions.
221 final int functionCount = mConfiguration.customFunctions.size();
222 for (int i = 0; i < functionCount; i++) {
223 SQLiteCustomFunction function = mConfiguration.customFunctions.get(i);
224 nativeRegisterCustomFunction(mConnectionPtr, function);
225 }
226 }