| | @@ -1171,11 +1171,11 @@ |
| 1171 | 1171 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 1172 | 1172 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 1173 | 1173 | */ |
| 1174 | 1174 | #define SQLITE_VERSION "3.34.0" |
| 1175 | 1175 | #define SQLITE_VERSION_NUMBER 3034000 |
| 1176 | | -#define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692392d" |
| 1176 | +#define SQLITE_SOURCE_ID "2020-11-23 21:05:29 4f1573b146193e5d552981a9d1d11e50da4da4a843f790e4af1cf0cc19a0b020" |
| 1177 | 1177 | |
| 1178 | 1178 | /* |
| 1179 | 1179 | ** CAPI3REF: Run-Time Library Version Numbers |
| 1180 | 1180 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 1181 | 1181 | ** |
| | @@ -1550,10 +1550,11 @@ |
| 1550 | 1550 | #define SQLITE_IOERR_AUTH (SQLITE_IOERR | (28<<8)) |
| 1551 | 1551 | #define SQLITE_IOERR_BEGIN_ATOMIC (SQLITE_IOERR | (29<<8)) |
| 1552 | 1552 | #define SQLITE_IOERR_COMMIT_ATOMIC (SQLITE_IOERR | (30<<8)) |
| 1553 | 1553 | #define SQLITE_IOERR_ROLLBACK_ATOMIC (SQLITE_IOERR | (31<<8)) |
| 1554 | 1554 | #define SQLITE_IOERR_DATA (SQLITE_IOERR | (32<<8)) |
| 1555 | +#define SQLITE_IOERR_CORRUPTFS (SQLITE_IOERR | (33<<8)) |
| 1555 | 1556 | #define SQLITE_LOCKED_SHAREDCACHE (SQLITE_LOCKED | (1<<8)) |
| 1556 | 1557 | #define SQLITE_LOCKED_VTAB (SQLITE_LOCKED | (2<<8)) |
| 1557 | 1558 | #define SQLITE_BUSY_RECOVERY (SQLITE_BUSY | (1<<8)) |
| 1558 | 1559 | #define SQLITE_BUSY_SNAPSHOT (SQLITE_BUSY | (2<<8)) |
| 1559 | 1560 | #define SQLITE_BUSY_TIMEOUT (SQLITE_BUSY | (3<<8)) |
| | @@ -28182,16 +28183,19 @@ |
| 28182 | 28183 | EnableLookaside; |
| 28183 | 28184 | } |
| 28184 | 28185 | } |
| 28185 | 28186 | |
| 28186 | 28187 | /* |
| 28187 | | -** Take actions at the end of an API call to indicate an OOM error |
| 28188 | +** Take actions at the end of an API call to deal with error codes. |
| 28188 | 28189 | */ |
| 28189 | | -static SQLITE_NOINLINE int apiOomError(sqlite3 *db){ |
| 28190 | | - sqlite3OomClear(db); |
| 28191 | | - sqlite3Error(db, SQLITE_NOMEM); |
| 28192 | | - return SQLITE_NOMEM_BKPT; |
| 28190 | +static SQLITE_NOINLINE int apiHandleError(sqlite3 *db, int rc){ |
| 28191 | + if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ |
| 28192 | + sqlite3OomClear(db); |
| 28193 | + sqlite3Error(db, SQLITE_NOMEM); |
| 28194 | + return SQLITE_NOMEM_BKPT; |
| 28195 | + } |
| 28196 | + return rc & db->errMask; |
| 28193 | 28197 | } |
| 28194 | 28198 | |
| 28195 | 28199 | /* |
| 28196 | 28200 | ** This function must be called before exiting any API function (i.e. |
| 28197 | 28201 | ** returning control to the user) that has called sqlite3_malloc or |
| | @@ -28209,12 +28213,12 @@ |
| 28209 | 28213 | ** Otherwise the read (and possible write) of db->mallocFailed |
| 28210 | 28214 | ** is unsafe, as is the call to sqlite3Error(). |
| 28211 | 28215 | */ |
| 28212 | 28216 | assert( db!=0 ); |
| 28213 | 28217 | assert( sqlite3_mutex_held(db->mutex) ); |
| 28214 | | - if( db->mallocFailed || rc==SQLITE_IOERR_NOMEM ){ |
| 28215 | | - return apiOomError(db); |
| 28218 | + if( db->mallocFailed || rc ){ |
| 28219 | + return apiHandleError(db, rc); |
| 28216 | 28220 | } |
| 28217 | 28221 | return rc & db->errMask; |
| 28218 | 28222 | } |
| 28219 | 28223 | |
| 28220 | 28224 | /************** End of malloc.c **********************************************/ |
| | @@ -37003,11 +37007,28 @@ |
| 37003 | 37007 | |
| 37004 | 37008 | got = seekAndRead(pFile, offset, pBuf, amt); |
| 37005 | 37009 | if( got==amt ){ |
| 37006 | 37010 | return SQLITE_OK; |
| 37007 | 37011 | }else if( got<0 ){ |
| 37008 | | - /* lastErrno set by seekAndRead */ |
| 37012 | + /* pFile->lastErrno has been set by seekAndRead(). |
| 37013 | + ** Usually we return SQLITE_IOERR_READ here, though for some |
| 37014 | + ** kinds of errors we return SQLITE_IOERR_CORRUPTFS. The |
| 37015 | + ** SQLITE_IOERR_CORRUPTFS will be converted into SQLITE_CORRUPT |
| 37016 | + ** prior to returning to the application by the sqlite3ApiExit() |
| 37017 | + ** routine. |
| 37018 | + */ |
| 37019 | + switch( pFile->lastErrno ){ |
| 37020 | + case ERANGE: |
| 37021 | + case EIO: |
| 37022 | +#ifdef ENXIO |
| 37023 | + case ENXIO: |
| 37024 | +#endif |
| 37025 | +#ifdef EDEVERR |
| 37026 | + case EDEVERR: |
| 37027 | +#endif |
| 37028 | + return SQLITE_IOERR_CORRUPTFS; |
| 37029 | + } |
| 37009 | 37030 | return SQLITE_IOERR_READ; |
| 37010 | 37031 | }else{ |
| 37011 | 37032 | storeLastErrno(pFile, 0); /* not a system error */ |
| 37012 | 37033 | /* Unread parts of the buffer must be zero-filled */ |
| 37013 | 37034 | memset(&((char*)pBuf)[got], 0, amt-got); |
| | @@ -38535,11 +38556,11 @@ |
| 38535 | 38556 | if( bUnlock ){ |
| 38536 | 38557 | rc = unixShmSystemLock(pDbFd, F_UNLCK, ofst+UNIX_SHM_BASE, n); |
| 38537 | 38558 | if( rc==SQLITE_OK ){ |
| 38538 | 38559 | memset(&aLock[ofst], 0, sizeof(int)*n); |
| 38539 | 38560 | } |
| 38540 | | - }else if( p->sharedMask & (1<<ofst) ){ |
| 38561 | + }else if( ALWAYS(p->sharedMask & (1<<ofst)) ){ |
| 38541 | 38562 | assert( n==1 && aLock[ofst]>1 ); |
| 38542 | 38563 | aLock[ofst]--; |
| 38543 | 38564 | } |
| 38544 | 38565 | |
| 38545 | 38566 | /* Undo the local locks */ |
| | @@ -38568,11 +38589,11 @@ |
| 38568 | 38589 | /* Make sure no sibling connections hold locks that will block this |
| 38569 | 38590 | ** lock. If any do, return SQLITE_BUSY right away. */ |
| 38570 | 38591 | int ii; |
| 38571 | 38592 | for(ii=ofst; ii<ofst+n; ii++){ |
| 38572 | 38593 | assert( (p->sharedMask & mask)==0 ); |
| 38573 | | - if( (p->exclMask & (1<<ii))==0 && aLock[ii] ){ |
| 38594 | + if( ALWAYS((p->exclMask & (1<<ii))==0) && aLock[ii] ){ |
| 38574 | 38595 | rc = SQLITE_BUSY; |
| 38575 | 38596 | break; |
| 38576 | 38597 | } |
| 38577 | 38598 | } |
| 38578 | 38599 | |
| | @@ -39964,19 +39985,39 @@ |
| 39964 | 39985 | } |
| 39965 | 39986 | return SQLITE_OK; |
| 39966 | 39987 | } |
| 39967 | 39988 | |
| 39968 | 39989 | /* |
| 39990 | +** If the last component of the pathname in z[0]..z[j-1] is something |
| 39991 | +** other than ".." then back it out and return true. If the last |
| 39992 | +** component is empty or if it is ".." then return false. |
| 39993 | +*/ |
| 39994 | +static int unixBackupDir(const char *z, int *pJ){ |
| 39995 | + int j = *pJ; |
| 39996 | + int i; |
| 39997 | + if( j<=0 ) return 0; |
| 39998 | + for(i=j-1; ALWAYS(i>0) && z[i-1]!='/'; i--){} |
| 39999 | + if( z[i]=='.' && i==j-2 && z[i+1]=='.' ) return 0; |
| 40000 | + *pJ = i-1; |
| 40001 | + return 1; |
| 40002 | +} |
| 40003 | + |
| 40004 | +/* |
| 40005 | +** Convert a relative pathname into a full pathname. Also |
| 40006 | +** simplify the pathname as follows: |
| 39969 | 40007 | ** |
| 40008 | +** Remove all instances of /./ |
| 40009 | +** Remove all isntances of /X/../ for any X |
| 39970 | 40010 | */ |
| 39971 | 40011 | static int mkFullPathname( |
| 39972 | 40012 | const char *zPath, /* Input path */ |
| 39973 | 40013 | char *zOut, /* Output buffer */ |
| 39974 | 40014 | int nOut /* Allocated size of buffer zOut */ |
| 39975 | 40015 | ){ |
| 39976 | 40016 | int nPath = sqlite3Strlen30(zPath); |
| 39977 | 40017 | int iOff = 0; |
| 40018 | + int i, j; |
| 39978 | 40019 | if( zPath[0]!='/' ){ |
| 39979 | 40020 | if( osGetcwd(zOut, nOut-2)==0 ){ |
| 39980 | 40021 | return unixLogError(SQLITE_CANTOPEN_BKPT, "getcwd", zPath); |
| 39981 | 40022 | } |
| 39982 | 40023 | iOff = sqlite3Strlen30(zOut); |
| | @@ -39987,10 +40028,45 @@ |
| 39987 | 40028 | ** even if it returns an error. */ |
| 39988 | 40029 | zOut[iOff] = '\0'; |
| 39989 | 40030 | return SQLITE_CANTOPEN_BKPT; |
| 39990 | 40031 | } |
| 39991 | 40032 | sqlite3_snprintf(nOut-iOff, &zOut[iOff], "%s", zPath); |
| 40033 | + |
| 40034 | + /* Remove duplicate '/' characters. Except, two // at the beginning |
| 40035 | + ** of a pathname is allowed since this is important on windows. */ |
| 40036 | + for(i=j=1; zOut[i]; i++){ |
| 40037 | + zOut[j++] = zOut[i]; |
| 40038 | + while( zOut[i]=='/' && zOut[i+1]=='/' ) i++; |
| 40039 | + } |
| 40040 | + zOut[j] = 0; |
| 40041 | + |
| 40042 | + assert( zOut[0]=='/' ); |
| 40043 | + for(i=j=0; zOut[i]; i++){ |
| 40044 | + if( zOut[i]=='/' ){ |
| 40045 | + /* Skip over internal "/." directory components */ |
| 40046 | + if( zOut[i+1]=='.' && zOut[i+2]=='/' ){ |
| 40047 | + i += 1; |
| 40048 | + continue; |
| 40049 | + } |
| 40050 | + |
| 40051 | + /* If this is a "/.." directory component then back out the |
| 40052 | + ** previous term of the directory if it is something other than "..". |
| 40053 | + */ |
| 40054 | + if( zOut[i+1]=='.' |
| 40055 | + && zOut[i+2]=='.' |
| 40056 | + && zOut[i+3]=='/' |
| 40057 | + && unixBackupDir(zOut, &j) |
| 40058 | + ){ |
| 40059 | + i += 2; |
| 40060 | + continue; |
| 40061 | + } |
| 40062 | + } |
| 40063 | + if( ALWAYS(j>=0) ) zOut[j] = zOut[i]; |
| 40064 | + j++; |
| 40065 | + } |
| 40066 | + if( NEVER(j==0) ) zOut[j++] = '/'; |
| 40067 | + zOut[j] = 0; |
| 39992 | 40068 | return SQLITE_OK; |
| 39993 | 40069 | } |
| 39994 | 40070 | |
| 39995 | 40071 | /* |
| 39996 | 40072 | ** Turn a relative pathname into a full pathname. The relative path |
| | @@ -82192,13 +82268,16 @@ |
| 82192 | 82268 | ** equal to, or greater than the second (double). |
| 82193 | 82269 | */ |
| 82194 | 82270 | static int sqlite3IntFloatCompare(i64 i, double r){ |
| 82195 | 82271 | if( sizeof(LONGDOUBLE_TYPE)>8 ){ |
| 82196 | 82272 | LONGDOUBLE_TYPE x = (LONGDOUBLE_TYPE)i; |
| 82273 | + testcase( x<r ); |
| 82274 | + testcase( x>r ); |
| 82275 | + testcase( x==r ); |
| 82197 | 82276 | if( x<r ) return -1; |
| 82198 | | - if( x>r ) return +1; |
| 82199 | | - return 0; |
| 82277 | + if( x>r ) return +1; /*NO_TEST*/ /* work around bugs in gcov */ |
| 82278 | + return 0; /*NO_TEST*/ /* work around bugs in gcov */ |
| 82200 | 82279 | }else{ |
| 82201 | 82280 | i64 y; |
| 82202 | 82281 | double s; |
| 82203 | 82282 | if( r<-9223372036854775808.0 ) return +1; |
| 82204 | 82283 | if( r>=9223372036854775808.0 ) return -1; |
| | @@ -89388,11 +89467,11 @@ |
| 89388 | 89467 | assert( rc==SQLITE_OK ); |
| 89389 | 89468 | break; |
| 89390 | 89469 | } |
| 89391 | 89470 | |
| 89392 | 89471 | |
| 89393 | | -/* Opcode: OpenEphemeral P1 P2 * P4 P5 |
| 89472 | +/* Opcode: OpenEphemeral P1 P2 P3 P4 P5 |
| 89394 | 89473 | ** Synopsis: nColumn=P2 |
| 89395 | 89474 | ** |
| 89396 | 89475 | ** Open a new cursor P1 to a transient table. |
| 89397 | 89476 | ** The cursor is always opened read/write even if |
| 89398 | 89477 | ** the main database is read-only. The ephemeral |
| | @@ -89408,10 +89487,14 @@ |
| 89408 | 89487 | ** |
| 89409 | 89488 | ** The P5 parameter can be a mask of the BTREE_* flags defined |
| 89410 | 89489 | ** in btree.h. These flags control aspects of the operation of |
| 89411 | 89490 | ** the btree. The BTREE_OMIT_JOURNAL and BTREE_SINGLE flags are |
| 89412 | 89491 | ** added automatically. |
| 89492 | +** |
| 89493 | +** If P3 is positive, then reg[P3] is modified slightly so that it |
| 89494 | +** can be used as zero-length data for OP_Insert. This is an optimization |
| 89495 | +** that avoids an extra OP_Blob opcode to initialize that register. |
| 89413 | 89496 | */ |
| 89414 | 89497 | /* Opcode: OpenAutoindex P1 P2 * P4 * |
| 89415 | 89498 | ** Synopsis: nColumn=P2 |
| 89416 | 89499 | ** |
| 89417 | 89500 | ** This opcode works the same as OP_OpenEphemeral. It has a |
| | @@ -89430,10 +89513,19 @@ |
| 89430 | 89513 | SQLITE_OPEN_EXCLUSIVE | |
| 89431 | 89514 | SQLITE_OPEN_DELETEONCLOSE | |
| 89432 | 89515 | SQLITE_OPEN_TRANSIENT_DB; |
| 89433 | 89516 | assert( pOp->p1>=0 ); |
| 89434 | 89517 | assert( pOp->p2>=0 ); |
| 89518 | + if( pOp->p3>0 ){ |
| 89519 | + /* Make register reg[P3] into a value that can be used as the data |
| 89520 | + ** form sqlite3BtreeInsert() where the length of the data is zero. */ |
| 89521 | + assert( pOp->p2==0 ); /* Only used when number of columns is zero */ |
| 89522 | + assert( pOp->opcode==OP_OpenEphemeral ); |
| 89523 | + assert( aMem[pOp->p3].flags & MEM_Null ); |
| 89524 | + aMem[pOp->p3].n = 0; |
| 89525 | + aMem[pOp->p3].z = ""; |
| 89526 | + } |
| 89435 | 89527 | pCx = p->apCsr[pOp->p1]; |
| 89436 | 89528 | if( pCx && pCx->pBtx ){ |
| 89437 | 89529 | /* If the ephermeral table is already open, erase all existing content |
| 89438 | 89530 | ** so that the table is empty again, rather than creating a new table. */ |
| 89439 | 89531 | assert( pCx->isEphemeral ); |
| | @@ -90589,11 +90681,11 @@ |
| 90589 | 90681 | if( pOp->p5 & OPFLAG_ISNOOP ) break; |
| 90590 | 90682 | #endif |
| 90591 | 90683 | |
| 90592 | 90684 | if( pOp->p5 & OPFLAG_NCHANGE ) p->nChange++; |
| 90593 | 90685 | if( pOp->p5 & OPFLAG_LASTROWID ) db->lastRowid = x.nKey; |
| 90594 | | - assert( pData->flags & (MEM_Blob|MEM_Str) ); |
| 90686 | + assert( (pData->flags & (MEM_Blob|MEM_Str))!=0 || pData->n==0 ); |
| 90595 | 90687 | x.pData = pData->z; |
| 90596 | 90688 | x.nData = pData->n; |
| 90597 | 90689 | seekResult = ((pOp->p5 & OPFLAG_USESEEKRESULT) ? pC->seekResult : 0); |
| 90598 | 90690 | if( pData->flags & MEM_Zero ){ |
| 90599 | 90691 | x.nZero = pData->u.nZero; |
| | @@ -93644,11 +93736,15 @@ |
| 93644 | 93736 | |
| 93645 | 93737 | /* If we reach this point, it means that execution is finished with |
| 93646 | 93738 | ** an error of some kind. |
| 93647 | 93739 | */ |
| 93648 | 93740 | abort_due_to_error: |
| 93649 | | - if( db->mallocFailed ) rc = SQLITE_NOMEM_BKPT; |
| 93741 | + if( db->mallocFailed ){ |
| 93742 | + rc = SQLITE_NOMEM_BKPT; |
| 93743 | + }else if( rc==SQLITE_IOERR_CORRUPTFS ){ |
| 93744 | + rc = SQLITE_CORRUPT_BKPT; |
| 93745 | + } |
| 93650 | 93746 | assert( rc ); |
| 93651 | 93747 | if( p->zErrMsg==0 && rc!=SQLITE_IOERR_NOMEM ){ |
| 93652 | 93748 | sqlite3VdbeError(p, "%s", sqlite3ErrStr(rc)); |
| 93653 | 93749 | } |
| 93654 | 93750 | p->rc = rc; |
| | @@ -99381,10 +99477,11 @@ |
| 99381 | 99477 | for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){ |
| 99382 | 99478 | int iCol = -1; |
| 99383 | 99479 | Expr *pE, *pDup; |
| 99384 | 99480 | if( pItem->done ) continue; |
| 99385 | 99481 | pE = sqlite3ExprSkipCollateAndLikely(pItem->pExpr); |
| 99482 | + if( NEVER(pE==0) ) continue; |
| 99386 | 99483 | if( sqlite3ExprIsInteger(pE, &iCol) ){ |
| 99387 | 99484 | if( iCol<=0 || iCol>pEList->nExpr ){ |
| 99388 | 99485 | resolveOutOfRangeError(pParse, "ORDER", i+1, pEList->nExpr); |
| 99389 | 99486 | return 1; |
| 99390 | 99487 | } |
| | @@ -99560,10 +99657,11 @@ |
| 99560 | 99657 | nResult = pSelect->pEList->nExpr; |
| 99561 | 99658 | pParse = pNC->pParse; |
| 99562 | 99659 | for(i=0, pItem=pOrderBy->a; i<pOrderBy->nExpr; i++, pItem++){ |
| 99563 | 99660 | Expr *pE = pItem->pExpr; |
| 99564 | 99661 | Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pE); |
| 99662 | + if( NEVER(pE2==0) ) continue; |
| 99565 | 99663 | if( zType[0]!='G' ){ |
| 99566 | 99664 | iCol = resolveAsName(pParse, pSelect->pEList, pE2); |
| 99567 | 99665 | if( iCol>0 ){ |
| 99568 | 99666 | /* If an AS-name match is found, mark this ORDER BY column as being |
| 99569 | 99667 | ** a copy of the iCol-th result-set column. The subsequent call to |
| | @@ -103679,10 +103777,11 @@ |
| 103679 | 103777 | ** register iReg. The caller must ensure that iReg already contains |
| 103680 | 103778 | ** the correct value for the expression. |
| 103681 | 103779 | */ |
| 103682 | 103780 | static void exprToRegister(Expr *pExpr, int iReg){ |
| 103683 | 103781 | Expr *p = sqlite3ExprSkipCollateAndLikely(pExpr); |
| 103782 | + if( NEVER(p==0) ) return; |
| 103684 | 103783 | p->op2 = p->op; |
| 103685 | 103784 | p->op = TK_REGISTER; |
| 103686 | 103785 | p->iTable = iReg; |
| 103687 | 103786 | ExprClearProperty(p, EP_Skip); |
| 103688 | 103787 | } |
| | @@ -104666,10 +104765,11 @@ |
| 104666 | 104765 | */ |
| 104667 | 104766 | SQLITE_PRIVATE int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ |
| 104668 | 104767 | int r2; |
| 104669 | 104768 | pExpr = sqlite3ExprSkipCollateAndLikely(pExpr); |
| 104670 | 104769 | if( ConstFactorOk(pParse) |
| 104770 | + && ALWAYS(pExpr!=0) |
| 104671 | 104771 | && pExpr->op!=TK_REGISTER |
| 104672 | 104772 | && sqlite3ExprIsConstantNotJoin(pExpr) |
| 104673 | 104773 | ){ |
| 104674 | 104774 | *pReg = 0; |
| 104675 | 104775 | r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); |
| | @@ -119424,10 +119524,12 @@ |
| 119424 | 119524 | VFUNCTION(total_changes, 0, 0, 0, total_changes ), |
| 119425 | 119525 | FUNCTION(replace, 3, 0, 0, replaceFunc ), |
| 119426 | 119526 | FUNCTION(zeroblob, 1, 0, 0, zeroblobFunc ), |
| 119427 | 119527 | FUNCTION(substr, 2, 0, 0, substrFunc ), |
| 119428 | 119528 | FUNCTION(substr, 3, 0, 0, substrFunc ), |
| 119529 | + FUNCTION(substring, 2, 0, 0, substrFunc ), |
| 119530 | + FUNCTION(substring, 3, 0, 0, substrFunc ), |
| 119429 | 119531 | WAGGREGATE(sum, 1,0,0, sumStep, sumFinalize, sumFinalize, sumInverse, 0), |
| 119430 | 119532 | WAGGREGATE(total, 1,0,0, sumStep,totalFinalize,totalFinalize,sumInverse, 0), |
| 119431 | 119533 | WAGGREGATE(avg, 1,0,0, sumStep, avgFinalize, avgFinalize, sumInverse, 0), |
| 119432 | 119534 | WAGGREGATE(count, 0,0,0, countStep, |
| 119433 | 119535 | countFinalize, countFinalize, countInverse, SQLITE_FUNC_COUNT ), |
| | @@ -131654,10 +131756,11 @@ |
| 131654 | 131756 | Column *aCol, *pCol; /* For looping over result columns */ |
| 131655 | 131757 | int nCol; /* Number of columns in the result set */ |
| 131656 | 131758 | char *zName; /* Column name */ |
| 131657 | 131759 | int nName; /* Size of name in zName[] */ |
| 131658 | 131760 | Hash ht; /* Hash table of column names */ |
| 131761 | + Table *pTab; |
| 131659 | 131762 | |
| 131660 | 131763 | sqlite3HashInit(&ht); |
| 131661 | 131764 | if( pEList ){ |
| 131662 | 131765 | nCol = pEList->nExpr; |
| 131663 | 131766 | aCol = sqlite3DbMallocZero(db, sizeof(aCol[0])*nCol); |
| | @@ -131676,19 +131779,17 @@ |
| 131676 | 131779 | */ |
| 131677 | 131780 | if( (zName = pEList->a[i].zEName)!=0 && pEList->a[i].eEName==ENAME_NAME ){ |
| 131678 | 131781 | /* If the column contains an "AS <name>" phrase, use <name> as the name */ |
| 131679 | 131782 | }else{ |
| 131680 | 131783 | Expr *pColExpr = sqlite3ExprSkipCollateAndLikely(pEList->a[i].pExpr); |
| 131681 | | - while( pColExpr->op==TK_DOT ){ |
| 131784 | + while( ALWAYS(pColExpr!=0) && pColExpr->op==TK_DOT ){ |
| 131682 | 131785 | pColExpr = pColExpr->pRight; |
| 131683 | 131786 | assert( pColExpr!=0 ); |
| 131684 | 131787 | } |
| 131685 | | - if( pColExpr->op==TK_COLUMN ){ |
| 131788 | + if( pColExpr->op==TK_COLUMN && (pTab = pColExpr->y.pTab)!=0 ){ |
| 131686 | 131789 | /* For columns use the column name name */ |
| 131687 | 131790 | int iCol = pColExpr->iColumn; |
| 131688 | | - Table *pTab = pColExpr->y.pTab; |
| 131689 | | - assert( pTab!=0 ); |
| 131690 | 131791 | if( iCol<0 ) iCol = pTab->iPKey; |
| 131691 | 131792 | zName = iCol>=0 ? pTab->aCol[iCol].zName : "rowid"; |
| 131692 | 131793 | }else if( pColExpr->op==TK_ID ){ |
| 131693 | 131794 | assert( !ExprHasProperty(pColExpr, EP_IntValue) ); |
| 131694 | 131795 | zName = pColExpr->u.zToken; |
| | @@ -136959,26 +137060,15 @@ |
| 136959 | 137060 | goto trigger_cleanup; |
| 136960 | 137061 | } |
| 136961 | 137062 | pTab = sqlite3SrcListLookup(pParse, pTableName); |
| 136962 | 137063 | if( !pTab ){ |
| 136963 | 137064 | /* The table does not exist. */ |
| 136964 | | - if( db->init.iDb==1 ){ |
| 136965 | | - /* Ticket #3810. |
| 136966 | | - ** Normally, whenever a table is dropped, all associated triggers are |
| 136967 | | - ** dropped too. But if a TEMP trigger is created on a non-TEMP table |
| 136968 | | - ** and the table is dropped by a different database connection, the |
| 136969 | | - ** trigger is not visible to the database connection that does the |
| 136970 | | - ** drop so the trigger cannot be dropped. This results in an |
| 136971 | | - ** "orphaned trigger" - a trigger whose associated table is missing. |
| 136972 | | - */ |
| 136973 | | - db->init.orphanTrigger = 1; |
| 136974 | | - } |
| 136975 | | - goto trigger_cleanup; |
| 137065 | + goto trigger_orphan_error; |
| 136976 | 137066 | } |
| 136977 | 137067 | if( IsVirtual(pTab) ){ |
| 136978 | 137068 | sqlite3ErrorMsg(pParse, "cannot create triggers on virtual tables"); |
| 136979 | | - goto trigger_cleanup; |
| 137069 | + goto trigger_orphan_error; |
| 136980 | 137070 | } |
| 136981 | 137071 | |
| 136982 | 137072 | /* Check that the trigger name is not reserved and that no trigger of the |
| 136983 | 137073 | ** specified name exists */ |
| 136984 | 137074 | zName = sqlite3NameFromToken(db, pName); |
| | @@ -137012,16 +137102,16 @@ |
| 137012 | 137102 | ** of triggers. |
| 137013 | 137103 | */ |
| 137014 | 137104 | if( pTab->pSelect && tr_tm!=TK_INSTEAD ){ |
| 137015 | 137105 | sqlite3ErrorMsg(pParse, "cannot create %s trigger on view: %S", |
| 137016 | 137106 | (tr_tm == TK_BEFORE)?"BEFORE":"AFTER", pTableName, 0); |
| 137017 | | - goto trigger_cleanup; |
| 137107 | + goto trigger_orphan_error; |
| 137018 | 137108 | } |
| 137019 | 137109 | if( !pTab->pSelect && tr_tm==TK_INSTEAD ){ |
| 137020 | 137110 | sqlite3ErrorMsg(pParse, "cannot create INSTEAD OF" |
| 137021 | 137111 | " trigger on table: %S", pTableName, 0); |
| 137022 | | - goto trigger_cleanup; |
| 137112 | + goto trigger_orphan_error; |
| 137023 | 137113 | } |
| 137024 | 137114 | |
| 137025 | 137115 | #ifndef SQLITE_OMIT_AUTHORIZATION |
| 137026 | 137116 | if( !IN_RENAME_OBJECT ){ |
| 137027 | 137117 | int iTabDb = sqlite3SchemaToIndex(db, pTab->pSchema); |
| | @@ -137077,10 +137167,27 @@ |
| 137077 | 137167 | if( !pParse->pNewTrigger ){ |
| 137078 | 137168 | sqlite3DeleteTrigger(db, pTrigger); |
| 137079 | 137169 | }else{ |
| 137080 | 137170 | assert( pParse->pNewTrigger==pTrigger ); |
| 137081 | 137171 | } |
| 137172 | + return; |
| 137173 | + |
| 137174 | +trigger_orphan_error: |
| 137175 | + if( db->init.iDb==1 ){ |
| 137176 | + /* Ticket #3810. |
| 137177 | + ** Normally, whenever a table is dropped, all associated triggers are |
| 137178 | + ** dropped too. But if a TEMP trigger is created on a non-TEMP table |
| 137179 | + ** and the table is dropped by a different database connection, the |
| 137180 | + ** trigger is not visible to the database connection that does the |
| 137181 | + ** drop so the trigger cannot be dropped. This results in an |
| 137182 | + ** "orphaned trigger" - a trigger whose associated table is missing. |
| 137183 | + ** |
| 137184 | + ** 2020-11-05 see also https://sqlite.org/forum/forumpost/157dc791df |
| 137185 | + */ |
| 137186 | + db->init.orphanTrigger = 1; |
| 137187 | + } |
| 137188 | + goto trigger_cleanup; |
| 137082 | 137189 | } |
| 137083 | 137190 | |
| 137084 | 137191 | /* |
| 137085 | 137192 | ** This routine is called after all of the trigger actions have been parsed |
| 137086 | 137193 | ** in order to complete the process of building the trigger. |
| | @@ -138664,10 +138771,12 @@ |
| 138664 | 138771 | sqlite3VdbeAddOp2(v, OP_Integer, 0, regRowCount); |
| 138665 | 138772 | } |
| 138666 | 138773 | |
| 138667 | 138774 | if( nChangeFrom==0 && HasRowid(pTab) ){ |
| 138668 | 138775 | sqlite3VdbeAddOp3(v, OP_Null, 0, regRowSet, regOldRowid); |
| 138776 | + iEph = pParse->nTab++; |
| 138777 | + addrOpen = sqlite3VdbeAddOp3(v, OP_OpenEphemeral, iEph, 0, regRowSet); |
| 138669 | 138778 | }else{ |
| 138670 | 138779 | assert( pPk!=0 || HasRowid(pTab) ); |
| 138671 | 138780 | nPk = pPk ? pPk->nKeyCol : 0; |
| 138672 | 138781 | iPk = pParse->nMem+1; |
| 138673 | 138782 | pParse->nMem += nPk; |
| | @@ -138755,13 +138864,14 @@ |
| 138755 | 138864 | /* Read the rowid of the current row of the WHERE scan. In ONEPASS_OFF |
| 138756 | 138865 | ** mode, write the rowid into the FIFO. In either of the one-pass modes, |
| 138757 | 138866 | ** leave it in register regOldRowid. */ |
| 138758 | 138867 | sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regOldRowid); |
| 138759 | 138868 | if( eOnePass==ONEPASS_OFF ){ |
| 138760 | | - /* We need to use regRowSet, so reallocate aRegIdx[nAllIdx] */ |
| 138761 | 138869 | aRegIdx[nAllIdx] = ++pParse->nMem; |
| 138762 | | - sqlite3VdbeAddOp2(v, OP_RowSetAdd, regRowSet, regOldRowid); |
| 138870 | + sqlite3VdbeAddOp3(v, OP_Insert, iEph, regRowSet, regOldRowid); |
| 138871 | + }else{ |
| 138872 | + if( ALWAYS(addrOpen) ) sqlite3VdbeChangeToNoop(v, addrOpen); |
| 138763 | 138873 | } |
| 138764 | 138874 | }else{ |
| 138765 | 138875 | /* Read the PK of the current row into an array of registers. In |
| 138766 | 138876 | ** ONEPASS_OFF mode, serialize the array into a record and store it in |
| 138767 | 138877 | ** the ephemeral table. Or, in ONEPASS_SINGLE or MULTI mode, change |
| | @@ -138845,12 +138955,13 @@ |
| 138845 | 138955 | sqlite3VdbeAddOp2(v, OP_RowData, iEph, regKey); |
| 138846 | 138956 | sqlite3VdbeAddOp4Int(v, OP_NotFound, iDataCur, labelContinue, regKey,0); |
| 138847 | 138957 | VdbeCoverage(v); |
| 138848 | 138958 | } |
| 138849 | 138959 | }else{ |
| 138850 | | - labelContinue = sqlite3VdbeAddOp3(v, OP_RowSetRead, regRowSet,labelBreak, |
| 138851 | | - regOldRowid); |
| 138960 | + sqlite3VdbeAddOp2(v, OP_Rewind, iEph, labelBreak); VdbeCoverage(v); |
| 138961 | + labelContinue = sqlite3VdbeMakeLabel(pParse); |
| 138962 | + addrTop = sqlite3VdbeAddOp2(v, OP_Rowid, iEph, regOldRowid); |
| 138852 | 138963 | VdbeCoverage(v); |
| 138853 | 138964 | sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, labelContinue, regOldRowid); |
| 138854 | 138965 | VdbeCoverage(v); |
| 138855 | 138966 | } |
| 138856 | 138967 | } |
| | @@ -139096,15 +139207,13 @@ |
| 139096 | 139207 | if( eOnePass==ONEPASS_SINGLE ){ |
| 139097 | 139208 | /* Nothing to do at end-of-loop for a single-pass */ |
| 139098 | 139209 | }else if( eOnePass==ONEPASS_MULTI ){ |
| 139099 | 139210 | sqlite3VdbeResolveLabel(v, labelContinue); |
| 139100 | 139211 | sqlite3WhereEnd(pWInfo); |
| 139101 | | - }else if( pPk || nChangeFrom ){ |
| 139212 | + }else{ |
| 139102 | 139213 | sqlite3VdbeResolveLabel(v, labelContinue); |
| 139103 | 139214 | sqlite3VdbeAddOp2(v, OP_Next, iEph, addrTop); VdbeCoverage(v); |
| 139104 | | - }else{ |
| 139105 | | - sqlite3VdbeGoto(v, labelContinue); |
| 139106 | 139215 | } |
| 139107 | 139216 | sqlite3VdbeResolveLabel(v, labelBreak); |
| 139108 | 139217 | |
| 139109 | 139218 | /* Update the sqlite_sequence table by storing the content of the |
| 139110 | 139219 | ** maximum rowid counter values recorded while inserting into |
| | @@ -145894,10 +146003,11 @@ |
| 145894 | 146003 | ** all terms of the WHERE clause. |
| 145895 | 146004 | */ |
| 145896 | 146005 | SQLITE_PRIVATE void sqlite3WhereSplit(WhereClause *pWC, Expr *pExpr, u8 op){ |
| 145897 | 146006 | Expr *pE2 = sqlite3ExprSkipCollateAndLikely(pExpr); |
| 145898 | 146007 | pWC->op = op; |
| 146008 | + assert( pE2!=0 || pExpr==0 ); |
| 145899 | 146009 | if( pE2==0 ) return; |
| 145900 | 146010 | if( pE2->op!=op ){ |
| 145901 | 146011 | whereClauseInsert(pWC, pExpr, 0); |
| 145902 | 146012 | }else{ |
| 145903 | 146013 | sqlite3WhereSplit(pWC, pE2->pLeft, op); |
| | @@ -146292,10 +146402,20 @@ |
| 146292 | 146402 | */ |
| 146293 | 146403 | static void createMask(WhereMaskSet *pMaskSet, int iCursor){ |
| 146294 | 146404 | assert( pMaskSet->n < ArraySize(pMaskSet->ix) ); |
| 146295 | 146405 | pMaskSet->ix[pMaskSet->n++] = iCursor; |
| 146296 | 146406 | } |
| 146407 | + |
| 146408 | +/* |
| 146409 | +** If the right-hand branch of the expression is a TK_COLUMN, then return |
| 146410 | +** a pointer to the right-hand branch. Otherwise, return NULL. |
| 146411 | +*/ |
| 146412 | +static Expr *whereRightSubexprIsColumn(Expr *p){ |
| 146413 | + p = sqlite3ExprSkipCollateAndLikely(p->pRight); |
| 146414 | + if( ALWAYS(p!=0) && p->op==TK_COLUMN ) return p; |
| 146415 | + return 0; |
| 146416 | +} |
| 146297 | 146417 | |
| 146298 | 146418 | /* |
| 146299 | 146419 | ** Advance to the next WhereTerm that matches according to the criteria |
| 146300 | 146420 | ** established when the pScan object was initialized by whereScanInit(). |
| 146301 | 146421 | ** Return NULL if there are no more matching WhereTerms. |
| | @@ -146323,12 +146443,11 @@ |
| 146323 | 146443 | pScan->pIdxExpr,iCur)==0) |
| 146324 | 146444 | && (pScan->iEquiv<=1 || !ExprHasProperty(pTerm->pExpr, EP_FromJoin)) |
| 146325 | 146445 | ){ |
| 146326 | 146446 | if( (pTerm->eOperator & WO_EQUIV)!=0 |
| 146327 | 146447 | && pScan->nEquiv<ArraySize(pScan->aiCur) |
| 146328 | | - && (pX = sqlite3ExprSkipCollateAndLikely(pTerm->pExpr->pRight))->op |
| 146329 | | - ==TK_COLUMN |
| 146448 | + && (pX = whereRightSubexprIsColumn(pTerm->pExpr))!=0 |
| 146330 | 146449 | ){ |
| 146331 | 146450 | int j; |
| 146332 | 146451 | for(j=0; j<pScan->nEquiv; j++){ |
| 146333 | 146452 | if( pScan->aiCur[j]==pX->iTable |
| 146334 | 146453 | && pScan->aiColumn[j]==pX->iColumn ){ |
| | @@ -146520,11 +146639,12 @@ |
| 146520 | 146639 | int i; |
| 146521 | 146640 | const char *zColl = pIdx->azColl[iCol]; |
| 146522 | 146641 | |
| 146523 | 146642 | for(i=0; i<pList->nExpr; i++){ |
| 146524 | 146643 | Expr *p = sqlite3ExprSkipCollateAndLikely(pList->a[i].pExpr); |
| 146525 | | - if( p->op==TK_COLUMN |
| 146644 | + if( ALWAYS(p!=0) |
| 146645 | + && p->op==TK_COLUMN |
| 146526 | 146646 | && p->iColumn==pIdx->aiColumn[iCol] |
| 146527 | 146647 | && p->iTable==iBase |
| 146528 | 146648 | ){ |
| 146529 | 146649 | CollSeq *pColl = sqlite3ExprNNCollSeq(pParse, pList->a[i].pExpr); |
| 146530 | 146650 | if( 0==sqlite3StrICmp(pColl->zName, zColl) ){ |
| | @@ -146584,10 +146704,11 @@ |
| 146584 | 146704 | ** true. Note: The (p->iTable==iBase) part of this test may be false if the |
| 146585 | 146705 | ** current SELECT is a correlated sub-query. |
| 146586 | 146706 | */ |
| 146587 | 146707 | for(i=0; i<pDistinct->nExpr; i++){ |
| 146588 | 146708 | Expr *p = sqlite3ExprSkipCollateAndLikely(pDistinct->a[i].pExpr); |
| 146709 | + if( NEVER(p==0) ) continue; |
| 146589 | 146710 | if( p->op==TK_COLUMN && p->iTable==iBase && p->iColumn<0 ) return 1; |
| 146590 | 146711 | } |
| 146591 | 146712 | |
| 146592 | 146713 | /* Loop through all indices on the table, checking each to see if it makes |
| 146593 | 146714 | ** the DISTINCT qualifier redundant. It does so if: |
| | @@ -148498,13 +148619,13 @@ |
| 148498 | 148619 | LogEst rLogSize; /* Logarithm of table size */ |
| 148499 | 148620 | WhereTerm *pTop = 0, *pBtm = 0; /* Top and bottom range constraints */ |
| 148500 | 148621 | |
| 148501 | 148622 | pNew = pBuilder->pNew; |
| 148502 | 148623 | if( db->mallocFailed ) return SQLITE_NOMEM_BKPT; |
| 148503 | | - WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d\n", |
| 148624 | + WHERETRACE(0x800, ("BEGIN %s.addBtreeIdx(%s), nEq=%d, nSkip=%d, rRun=%d\n", |
| 148504 | 148625 | pProbe->pTable->zName,pProbe->zName, |
| 148505 | | - pNew->u.btree.nEq, pNew->nSkip)); |
| 148626 | + pNew->u.btree.nEq, pNew->nSkip, pNew->rRun)); |
| 148506 | 148627 | |
| 148507 | 148628 | assert( (pNew->wsFlags & WHERE_VIRTUALTABLE)==0 ); |
| 148508 | 148629 | assert( (pNew->wsFlags & WHERE_TOP_LIMIT)==0 ); |
| 148509 | 148630 | if( pNew->wsFlags & WHERE_BTM_LIMIT ){ |
| 148510 | 148631 | opMask = WO_LT|WO_LE; |
| | @@ -148869,10 +148990,11 @@ |
| 148869 | 148990 | |
| 148870 | 148991 | if( pIndex->bUnordered ) return 0; |
| 148871 | 148992 | if( (pOB = pBuilder->pWInfo->pOrderBy)==0 ) return 0; |
| 148872 | 148993 | for(ii=0; ii<pOB->nExpr; ii++){ |
| 148873 | 148994 | Expr *pExpr = sqlite3ExprSkipCollateAndLikely(pOB->a[ii].pExpr); |
| 148995 | + if( NEVER(pExpr==0) ) continue; |
| 148874 | 148996 | if( pExpr->op==TK_COLUMN && pExpr->iTable==iCursor ){ |
| 148875 | 148997 | if( pExpr->iColumn<0 ) return 1; |
| 148876 | 148998 | for(jj=0; jj<pIndex->nKeyCol; jj++){ |
| 148877 | 148999 | if( pExpr->iColumn==pIndex->aiColumn[jj] ) return 1; |
| 148878 | 149000 | } |
| | @@ -149847,10 +149969,11 @@ |
| 149847 | 149969 | ** loops. |
| 149848 | 149970 | */ |
| 149849 | 149971 | for(i=0; i<nOrderBy; i++){ |
| 149850 | 149972 | if( MASKBIT(i) & obSat ) continue; |
| 149851 | 149973 | pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr); |
| 149974 | + if( NEVER(pOBExpr==0) ) continue; |
| 149852 | 149975 | if( pOBExpr->op!=TK_COLUMN ) continue; |
| 149853 | 149976 | if( pOBExpr->iTable!=iCur ) continue; |
| 149854 | 149977 | pTerm = sqlite3WhereFindTerm(&pWInfo->sWC, iCur, pOBExpr->iColumn, |
| 149855 | 149978 | ~ready, eqOpMask, 0); |
| 149856 | 149979 | if( pTerm==0 ) continue; |
| | @@ -149973,10 +150096,11 @@ |
| 149973 | 150096 | for(i=0; bOnce && i<nOrderBy; i++){ |
| 149974 | 150097 | if( MASKBIT(i) & obSat ) continue; |
| 149975 | 150098 | pOBExpr = sqlite3ExprSkipCollateAndLikely(pOrderBy->a[i].pExpr); |
| 149976 | 150099 | testcase( wctrlFlags & WHERE_GROUPBY ); |
| 149977 | 150100 | testcase( wctrlFlags & WHERE_DISTINCTBY ); |
| 150101 | + if( NEVER(pOBExpr==0) ) continue; |
| 149978 | 150102 | if( (wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY))==0 ) bOnce = 0; |
| 149979 | 150103 | if( iColumn>=XN_ROWID ){ |
| 149980 | 150104 | if( pOBExpr->op!=TK_COLUMN ) continue; |
| 149981 | 150105 | if( pOBExpr->iTable!=iCur ) continue; |
| 149982 | 150106 | if( pOBExpr->iColumn!=iColumn ) continue; |
| | @@ -150136,11 +150260,11 @@ |
| 150136 | 150260 | rScale = sqlite3LogEst((nOrderBy-nSorted)*100/nOrderBy) - 66; |
| 150137 | 150261 | rSortCost = nRow + rScale + 16; |
| 150138 | 150262 | |
| 150139 | 150263 | /* Multiple by log(M) where M is the number of output rows. |
| 150140 | 150264 | ** Use the LIMIT for M if it is smaller. Or if this sort is for |
| 150141 | | - ** a DISTINT operator, M will be the number of distinct output |
| 150265 | + ** a DISTINCT operator, M will be the number of distinct output |
| 150142 | 150266 | ** rows, so fudge it downwards a bit. |
| 150143 | 150267 | */ |
| 150144 | 150268 | if( (pWInfo->wctrlFlags & WHERE_USE_LIMIT)!=0 && pWInfo->iLimit<nRow ){ |
| 150145 | 150269 | nRow = pWInfo->iLimit; |
| 150146 | 150270 | }else if( (pWInfo->wctrlFlags & WHERE_WANT_DISTINCT) ){ |
| | @@ -226679,11 +226803,11 @@ |
| 226679 | 226803 | int nArg, /* Number of args */ |
| 226680 | 226804 | sqlite3_value **apUnused /* Function arguments */ |
| 226681 | 226805 | ){ |
| 226682 | 226806 | assert( nArg==0 ); |
| 226683 | 226807 | UNUSED_PARAM2(nArg, apUnused); |
| 226684 | | - sqlite3_result_text(pCtx, "fts5: 2020-10-26 16:22:31 80eba105d6d1b49ba8ca2ad4e14ddec2de0bdc2f6686c2f8a1c1d24fc1fe846f", -1, SQLITE_TRANSIENT); |
| 226808 | + sqlite3_result_text(pCtx, "fts5: 2020-11-19 21:12:08 c38dec6f52c01614c1bee8356daf0fcd9f708d029116e9bff51e06719a730dde", -1, SQLITE_TRANSIENT); |
| 226685 | 226809 | } |
| 226686 | 226810 | |
| 226687 | 226811 | /* |
| 226688 | 226812 | ** Return true if zName is the extension on one of the shadow tables used |
| 226689 | 226813 | ** by this module. |
| | @@ -231602,12 +231726,12 @@ |
| 231602 | 231726 | } |
| 231603 | 231727 | #endif /* SQLITE_CORE */ |
| 231604 | 231728 | #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ |
| 231605 | 231729 | |
| 231606 | 231730 | /************** End of stmt.c ************************************************/ |
| 231607 | | -#if __LINE__!=231607 |
| 231731 | +#if __LINE__!=231731 |
| 231608 | 231732 | #undef SQLITE_SOURCE_ID |
| 231609 | | -#define SQLITE_SOURCE_ID "2020-10-31 18:58:37 7d01e84dc49074e6364267eea9fd20d46a457d2498121a0f218fbf482692alt2" |
| 231733 | +#define SQLITE_SOURCE_ID "2020-11-23 21:05:29 4f1573b146193e5d552981a9d1d11e50da4da4a843f790e4af1cf0cc19a0alt2" |
| 231610 | 231734 | #endif |
| 231611 | 231735 | /* Return the source-id for this library */ |
| 231612 | 231736 | SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } |
| 231613 | 231737 | /************************** End of sqlite3.c ******************************/ |
| 231614 | 231738 | |