加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

sqlite3 engine claims no such function when compiling sql st

发布时间:2020-12-12 20:22:42 所属栏目:百科 来源:网络整理
导读:本文介绍了sqlite3解析和编译SQL语句时,宿主语言设置的定制函数找不到的issue; 主要引用相关代码,描述了sqlite编译SQL语句的大致流程. [GENERAL DESCRIPTION:] Process: com.sonyericsson.album Flags: 0x8be45 Package: com.xxxxxxxxx.album Build: xxxxxxx

本文介绍了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,/* Database handle. */
94514 const void *zSql,/* UTF-16 encoded SQL statement. */
94515 int nBytes,/* Length of zSql in bytes. */
94516 sqlite3_stmt **ppStmt,/* OUT: A pointer to the prepared statement */
94517 const void **pzTail /* OUT: End of parsed string */
94518){
94519 int rc;
94520 rc = sqlite3Prepare16(db,zSql,nBytes,1,ppStmt,pzTail);
94521 assert( rc==SQLITE_OK || ppStmt==0 || *ppStmt==0 ); /* VERIFY: F13021 */
94522 return rc;
94523}

calls------->>

94450static int sqlite3Prepare16(
94451 sqlite3 *db,/* Database handle. */
94452 const void *zSql,/* UTF-16 encoded SQL statement. */
94453 int nBytes,/* Length of zSql in bytes. */
94454 int saveSqlFlag,/* True to save SQL text into the sqlite3_stmt */
94455 sqlite3_stmt **ppStmt,/* OUT: A pointer to the prepared statement */
94456 const void **pzTail /* OUT: End of parsed string */
94457){
94458 /* This function currently works by first transforming the UTF-16
94459 ** encoded string to UTF-8,then invoking sqlite3_prepare(). The
94460 ** tricky bit is figuring out the pointer to return in *pzTail.
94461 */
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,SQLITE_UTF16NATIVE);
94473 if( zSql8 ){
94474 rc = sqlite3LockAndPrepare(db,zSql8,-1,saveSqlFlag,&zTail8);
94475 }
94476
94477 if( zTail8 && pzTail ){
94478 /* If sqlite3_prepare returns a tail pointer,we calculate the
94479 ** equivalent pointer into the UTF-16 string by counting the unicode
94480 ** characters between zSql8 and zTail8,and then returning a pointer
94481 ** the same number of characters into the UTF-16 string.
94482 */
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,/* Database handle. */
94350 const char *zSql,/* UTF-8 encoded SQL statement. */
94351 int nBytes,/* Length of zSql in bytes. */
94352 int saveSqlFlag,/* True to copy SQL text into the sqlite3_stmt */
94353 Vdbe *pOld,/* VM being reprepared */
94354 sqlite3_stmt **ppStmt,/* OUT: A pointer to the prepared statement */
94355 const char **pzTail /* OUT: End of parsed string */
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,pOld,pzTail);
94366 if( rc==SQLITE_SCHEMA ){
94367 sqlite3_finalize(*ppStmt);
94368 rc = sqlite3Prepare(db,pzTail);
94369 }
94370 sqlite3BtreeLeaveAll(db);
94371 sqlite3_mutex_leave(db->mutex);
94372 return rc;
94373}
calls------>>
94185/*
94186** Compile the UTF-8 encoded SQL statement zSql into a statement handle.
94187*/
94188static int sqlite3Prepare(
94189 sqlite3 *db,/* Database handle. */
94190 const char *zSql,/* UTF-8 encoded SQL statement. */
94191 int nBytes,/* Length of zSql in bytes. */
94192 int saveSqlFlag,/* True to copy SQL text into the sqlite3_stmt */
94193 Vdbe *pReprepare,/* VM being reprepared */
94194 sqlite3_stmt **ppStmt,/* OUT: A pointer to the prepared statement */
94195 const char **pzTail /* OUT: End of parsed string */
94196){
94197 Parse *pParse; /* Parsing context */
94198 char *zErrMsg = 0; /* Error message */
94199 int rc = SQLITE_OK; /* Result code */
94200 int i; /* Loop counter */
94201
94202 /* Allocate the parsing context */
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 /* Check to verify that it is possible to get a read lock on all
94214 ** database schemas. The inability to get a read lock indicates that
94215 ** some other database connection is holding a write-lock,which in
94216 ** turn means that the other connection has made uncommitted changes
94217 ** to the schema.
94218 **
94219 ** Were we to proceed and prepare the statement against the uncommitted
94220 ** schema changes and if those schema changes are subsequently rolled
94221 ** back and different changes are made in their place,then when this
94222 ** prepared statement goes to run the schema cookie would fail to detect
94223 ** the schema change. Disaster would follow.
94224 **
94225 ** This thread is currently holding mutexes on all Btrees (because
94226 ** of the sqlite3BtreeEnterAll() in sqlite3LockAndPrepare()) so it
94227 ** is not possible for another thread to start a new schema change
94228 ** while this routine is running. Hence,we do not need to hold
94229 ** locks on the schema,we just need to make sure nobody else is
94230 ** holding them.
94231 **
94232 ** Note that setting READ_UNCOMMITTED overrides most lock detection,
94233 ** but it does *not* override schema lock detection,so this all still
94234 ** works even if READ_UNCOMMITTED is set.
94235 */
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,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,&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,(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,"%s",zErrMsg);
94329 sqlite3DbFree(db,zErrMsg);
94330 }else{
94331 sqlite3Error(db,0);
94332 }
94333
94334 /* Delete any TriggerPrg structures allocated while parsing this statement. */
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,/* Namespace to resolve expressions in. */
74342 Expr *pExpr /* The expression to be analyzed. */
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,/* The parser context */
74393 Select *p,/* The SELECT statement being coded. */
74394 NameContext *pOuterNC /* Name context for parent SELECT statement */
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 /* The special operator TK_ROW means use the rowid for the first
73649 ** column in the FROM clause. This is used by the LIMIT and ORDER BY
73650 ** clause processing on UPDATE and DELETE statements.
73651 */
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 /* defined(SQLITE_ENABLE_UPDATE_DELETE_LIMIT) && !defined(SQLITE_OMIT_SUBQUERY) */
73665
73666 /* A lone identifier is the name of a column.
73667 */
73668 case TK_ID: {
73669 return lookupName(pParse,pExpr->u.zToken,pNC,pExpr);
73670 }
73671
73672 /* A table name and column name: ID.ID
73673 ** Or a database,table and column: ID.ID.ID
73674 */
73675 case TK_DOT: {
73676 const char *zColumn;
73677 const char *zTable;
73678 const char *zDb;
73679 Expr *pRight;
73680
73681 /* if( pSrcList==0 ) break; */
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,pExpr);
73694 }
73695
73696 /* Resolve function names
73697 */
73698 case TK_CONST_FUNC:
73699 case TK_FUNCTION: {
73700 ExprList *pList = pExpr->x.pList; /* The argument list */
73701 int n = pList ? pList->nExpr : 0; /* Number of arguments */
73702 int no_such_func = 0; /* True if no such function exists */
73703 int wrong_num_args = 0; /* True if wrong number of arguments */
73704 int is_agg = 0; /* True if is an aggregate function */
73705 int auth; /* Authorization to use the function */
73706 int nId; /* Number of characters in function name */
73707 const char *zId; /* The function name. */
73708 FuncDef *pDef; /* Information about the function */
73709 u8 enc = ENC(pParse->db); /* The database encoding */
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,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,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()",zId);
73742 pNC->nErr++;
73743 is_agg = 0;
73744 }else if( no_such_func ){
73745 sqlite3ErrorMsg(pParse,"no such function: %.*s",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 /* FIX ME: Compute pExpr->affinity based on the expected return
73760 ** type of the function
73761 */
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/*
85333** Locate a user function given a name,a number of arguments and a flag
85334** indicating whether the function prefers UTF-16 over UTF-8. Return a
85335** pointer to the FuncDef structure that defines that function,or return
85336** NULL if the function does not exist.
85337**
85338** If the createFlag argument is true,then a new (blank) FuncDef
85339** structure is created and liked into the "db" structure if a
85340** no matching function previously existed. When createFlag is true
85341** and the nArg parameter is -1,then only a function that accepts
85342** any number of arguments will be returned.
85343**
85344** If createFlag is false and nArg is -1,then the first valid
85345** function found is returned. A function is valid if either xFunc
85346** or xStep is non-zero.
85347**
85348** If createFlag is false,then a function with the required name and
85349** number of arguments may be returned even if the eTextRep flag does not
85350** match that requested.
85351*/
85352SQLITE_PRIVATE FuncDef *sqlite3FindFunction(
85353 sqlite3 *db,/* An open database */
85354 const char *zName,/* Name of the function. Not null-terminated */
85355 int nName,/* Number of characters in the name */
85356 int nArg,/* Number of arguments. -1 means any number */
85357 u8 enc,/* Preferred text encoding */
85358 int createFlag /* Create new entry if true and does not otherwise exist */
85359){
85360 FuncDef *p; /* Iterator variable */
85361 FuncDef *pBest = 0; /* Best match found so far */
85362 int bestScore = 0; /* Score of best match */
85363 int h; /* Hash value */
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 /* First search for a match amongst the application-defined functions.
85370 */
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 /* If no match is found,search the built-in functions.
85382 **
85383 ** If the SQLITE_PreferBuiltin flag is set,then search the built-in
85384 ** functions even if a prior app-defined function was found. And give
85385 ** priority to built-in functions.
85386 **
85387 ** Except,if createFlag is true,that means that we are trying to
85388 ** install a new function. Whatever FuncDef structure is returned it will
85389 ** have fields overwritten with new information appropriate for the
85390 ** new function. But the FuncDefs for built-in functions are read-only.
85391 ** So we must not search for built-ins when creating a new function.
85392 */
85393 if( !createFlag && (pBest==0 || (db->flags & SQLITE_PreferBuiltin)!=0) ){
85394 FuncDefHash *pHash = &GLOBAL(FuncDefHash,sqlite3GlobalFunctions);
85395 bestScore = 0;
85396 p = functionSearch(pHash,nName);
85397 while( p ){
85398 int score = matchQuality(p,enc);
85399 if( score>bestScore ){
85400 pBest = p;
85401 bestScore = score;
85402 }
85403 p = p->pNext;
85404 }
85405 }
85406
85407 /* If the createFlag parameter is true and the search did not reveal an
85408 ** exact match for the name,number of arguments and encoding,then add a
85409 ** new entry to the hash table and return it.
85410 */
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,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}

Ifthe 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",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,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 }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读