| | @@ -211,11 +211,11 @@ |
| 211 | 211 | #endif |
| 212 | 212 | #if SQLITE_ENABLE_BATCH_ATOMIC_WRITE |
| 213 | 213 | "ENABLE_BATCH_ATOMIC_WRITE", |
| 214 | 214 | #endif |
| 215 | 215 | #if SQLITE_ENABLE_CEROD |
| 216 | | - "ENABLE_CEROD", |
| 216 | + "ENABLE_CEROD=" CTIMEOPT_VAL(SQLITE_ENABLE_CEROD), |
| 217 | 217 | #endif |
| 218 | 218 | #if SQLITE_ENABLE_COLUMN_METADATA |
| 219 | 219 | "ENABLE_COLUMN_METADATA", |
| 220 | 220 | #endif |
| 221 | 221 | #if SQLITE_ENABLE_COLUMN_USED_MASK |
| | @@ -1147,11 +1147,11 @@ |
| 1147 | 1147 | ** [sqlite3_libversion_number()], [sqlite3_sourceid()], |
| 1148 | 1148 | ** [sqlite_version()] and [sqlite_source_id()]. |
| 1149 | 1149 | */ |
| 1150 | 1150 | #define SQLITE_VERSION "3.23.0" |
| 1151 | 1151 | #define SQLITE_VERSION_NUMBER 3023000 |
| 1152 | | -#define SQLITE_SOURCE_ID "2018-03-17 16:26:36 442e816b5fed80ebeb58c7c0ab9c2ef999bf488519bf5da670e9cec477034540" |
| 1152 | +#define SQLITE_SOURCE_ID "2018-03-22 17:13:44 eb4f452e354065d610ff57a6a9312ad119b6b0cc467f9dff105f0718bc27ef01" |
| 1153 | 1153 | |
| 1154 | 1154 | /* |
| 1155 | 1155 | ** CAPI3REF: Run-Time Library Version Numbers |
| 1156 | 1156 | ** KEYWORDS: sqlite3_version sqlite3_sourceid |
| 1157 | 1157 | ** |
| | @@ -3076,31 +3076,40 @@ |
| 3076 | 3076 | ** <dd> Usually, when a database in wal mode is closed or detached from a |
| 3077 | 3077 | ** database handle, SQLite checks if this will mean that there are now no |
| 3078 | 3078 | ** connections at all to the database. If so, it performs a checkpoint |
| 3079 | 3079 | ** operation before closing the connection. This option may be used to |
| 3080 | 3080 | ** override this behaviour. The first parameter passed to this operation |
| 3081 | | -** is an integer - non-zero to disable checkpoints-on-close, or zero (the |
| 3082 | | -** default) to enable them. The second parameter is a pointer to an integer |
| 3081 | +** is an integer - positive to disable checkpoints-on-close, or zero (the |
| 3082 | +** default) to enable them, and negative to leave the setting unchanged. |
| 3083 | +** The second parameter is a pointer to an integer |
| 3083 | 3084 | ** into which is written 0 or 1 to indicate whether checkpoints-on-close |
| 3084 | 3085 | ** have been disabled - 0 if they are not disabled, 1 if they are. |
| 3085 | 3086 | ** </dd> |
| 3087 | +** |
| 3086 | 3088 | ** <dt>SQLITE_DBCONFIG_ENABLE_QPSG</dt> |
| 3087 | 3089 | ** <dd>^(The SQLITE_DBCONFIG_ENABLE_QPSG option activates or deactivates |
| 3088 | 3090 | ** the [query planner stability guarantee] (QPSG). When the QPSG is active, |
| 3089 | 3091 | ** a single SQL query statement will always use the same algorithm regardless |
| 3090 | 3092 | ** of values of [bound parameters].)^ The QPSG disables some query optimizations |
| 3091 | 3093 | ** that look at the values of bound parameters, which can make some queries |
| 3092 | 3094 | ** slower. But the QPSG has the advantage of more predictable behavior. With |
| 3093 | 3095 | ** the QPSG active, SQLite will always use the same query plan in the field as |
| 3094 | 3096 | ** was used during testing in the lab. |
| 3097 | +** The first argument to this setting is an integer which is 0 to disable |
| 3098 | +** the QPSG, positive to enable QPSG, or negative to leave the setting |
| 3099 | +** unchanged. The second parameter is a pointer to an integer into which |
| 3100 | +** is written 0 or 1 to indicate whether the QPSG is disabled or enabled |
| 3101 | +** following this call. |
| 3095 | 3102 | ** </dd> |
| 3103 | +** |
| 3096 | 3104 | ** <dt>SQLITE_DBCONFIG_TRIGGER_EQP</dt> |
| 3097 | 3105 | ** <dd> By default, the output of EXPLAIN QUERY PLAN commands does not |
| 3098 | 3106 | ** include output for any operations performed by trigger programs. This |
| 3099 | 3107 | ** option is used to set or clear (the default) a flag that governs this |
| 3100 | 3108 | ** behavior. The first parameter passed to this operation is an integer - |
| 3101 | | -** non-zero to enable output for trigger programs, or zero to disable it. |
| 3109 | +** positive to enable output for trigger programs, or zero to disable it, |
| 3110 | +** or negative to leave the setting unchanged. |
| 3102 | 3111 | ** The second parameter is a pointer to an integer into which is written |
| 3103 | 3112 | ** 0 or 1 to indicate whether output-for-triggers has been disabled - 0 if |
| 3104 | 3113 | ** it is not disabled, 1 if it is. |
| 3105 | 3114 | ** </dd> |
| 3106 | 3115 | ** </dl> |
| | @@ -15519,10 +15528,12 @@ |
| 15519 | 15528 | #define SQLITE_OmitNoopJoin 0x0100 /* Omit unused tables in joins */ |
| 15520 | 15529 | #define SQLITE_CountOfView 0x0200 /* The count-of-view optimization */ |
| 15521 | 15530 | #define SQLITE_CursorHints 0x0400 /* Add OP_CursorHint opcodes */ |
| 15522 | 15531 | #define SQLITE_Stat34 0x0800 /* Use STAT3 or STAT4 data */ |
| 15523 | 15532 | /* TH3 expects the Stat34 ^^^^^^ value to be 0x0800. Don't change it */ |
| 15533 | +#define SQLITE_PushDown 0x1000 /* The push-down optimization */ |
| 15534 | +#define SQLITE_SimplifyJoin 0x2000 /* Convert LEFT JOIN to JOIN */ |
| 15524 | 15535 | #define SQLITE_AllOpts 0xffff /* All optimizations */ |
| 15525 | 15536 | |
| 15526 | 15537 | /* |
| 15527 | 15538 | ** Macros for testing whether or not optimizations are enabled or disabled. |
| 15528 | 15539 | */ |
| | @@ -16980,11 +16991,10 @@ |
| 16980 | 16991 | int regRowid; /* Register holding rowid of CREATE TABLE entry */ |
| 16981 | 16992 | int regRoot; /* Register holding root page number for new objects */ |
| 16982 | 16993 | int nMaxArg; /* Max args passed to user function by sub-program */ |
| 16983 | 16994 | #if SELECTTRACE_ENABLED |
| 16984 | 16995 | int nSelect; /* Number of SELECT statements seen */ |
| 16985 | | - int nSelectIndent; /* How far to indent SELECTTRACE() output */ |
| 16986 | 16996 | #endif |
| 16987 | 16997 | #ifndef SQLITE_OMIT_SHARED_CACHE |
| 16988 | 16998 | int nTableLock; /* Number of locks in aTableLock */ |
| 16989 | 16999 | TableLock *aTableLock; /* Required table locks for shared-cache mode */ |
| 16990 | 17000 | #endif |
| | @@ -17344,13 +17354,13 @@ |
| 17344 | 17354 | SrcList *pSrcList; /* FROM clause */ |
| 17345 | 17355 | struct SrcCount *pSrcCount; /* Counting column references */ |
| 17346 | 17356 | struct CCurHint *pCCurHint; /* Used by codeCursorHint() */ |
| 17347 | 17357 | int *aiCol; /* array of column indexes */ |
| 17348 | 17358 | struct IdxCover *pIdxCover; /* Check for index coverage */ |
| 17349 | | - struct IdxExprTrans *pIdxTrans; /* Convert indexed expr to column */ |
| 17359 | + struct IdxExprTrans *pIdxTrans; /* Convert idxed expr to column */ |
| 17350 | 17360 | ExprList *pGroupBy; /* GROUP BY clause */ |
| 17351 | | - struct HavingToWhereCtx *pHavingCtx; /* HAVING to WHERE clause ctx */ |
| 17361 | + Select *pSelect; /* HAVING to WHERE clause ctx */ |
| 17352 | 17362 | } u; |
| 17353 | 17363 | }; |
| 17354 | 17364 | |
| 17355 | 17365 | /* Forward declarations */ |
| 17356 | 17366 | SQLITE_PRIVATE int sqlite3WalkExpr(Walker*, Expr*); |
| | @@ -17810,10 +17820,11 @@ |
| 17810 | 17820 | SQLITE_PRIVATE char *sqlite3NameFromToken(sqlite3*, Token*); |
| 17811 | 17821 | SQLITE_PRIVATE int sqlite3ExprCompare(Parse*,Expr*, Expr*, int); |
| 17812 | 17822 | SQLITE_PRIVATE int sqlite3ExprCompareSkip(Expr*, Expr*, int); |
| 17813 | 17823 | SQLITE_PRIVATE int sqlite3ExprListCompare(ExprList*, ExprList*, int); |
| 17814 | 17824 | SQLITE_PRIVATE int sqlite3ExprImpliesExpr(Parse*,Expr*, Expr*, int); |
| 17825 | +SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr*,int); |
| 17815 | 17826 | SQLITE_PRIVATE void sqlite3ExprAnalyzeAggregates(NameContext*, Expr*); |
| 17816 | 17827 | SQLITE_PRIVATE void sqlite3ExprAnalyzeAggList(NameContext*,ExprList*); |
| 17817 | 17828 | SQLITE_PRIVATE int sqlite3ExprCoveredByIndex(Expr*, int iCur, Index *pIdx); |
| 17818 | 17829 | SQLITE_PRIVATE int sqlite3FunctionUsesThisSrc(Expr*, SrcList*); |
| 17819 | 17830 | SQLITE_PRIVATE Vdbe *sqlite3GetVdbe(Parse*); |
| | @@ -27316,15 +27327,25 @@ |
| 27316 | 27327 | sqlite3TreeViewWith(pView, p->pWith, 1); |
| 27317 | 27328 | cnt = 1; |
| 27318 | 27329 | sqlite3TreeViewPush(pView, 1); |
| 27319 | 27330 | } |
| 27320 | 27331 | do{ |
| 27332 | +#if SELECTTRACE_ENABLED |
| 27333 | + sqlite3TreeViewLine(pView, |
| 27334 | + "SELECT%s%s (%s/%p) selFlags=0x%x nSelectRow=%d", |
| 27335 | + ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), |
| 27336 | + ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), |
| 27337 | + p->zSelName, p, p->selFlags, |
| 27338 | + (int)p->nSelectRow |
| 27339 | + ); |
| 27340 | +#else |
| 27321 | 27341 | sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d", |
| 27322 | 27342 | ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), |
| 27323 | 27343 | ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags, |
| 27324 | 27344 | (int)p->nSelectRow |
| 27325 | 27345 | ); |
| 27346 | +#endif |
| 27326 | 27347 | if( cnt++ ) sqlite3TreeViewPop(pView); |
| 27327 | 27348 | if( p->pPrior ){ |
| 27328 | 27349 | n = 1000; |
| 27329 | 27350 | }else{ |
| 27330 | 27351 | n = 0; |
| | @@ -98687,10 +98708,62 @@ |
| 98687 | 98708 | testcase( pX!=pE1->pLeft ); |
| 98688 | 98709 | if( sqlite3ExprCompare(pParse, pX, pE2->pLeft, iTab)==0 ) return 1; |
| 98689 | 98710 | } |
| 98690 | 98711 | return 0; |
| 98691 | 98712 | } |
| 98713 | + |
| 98714 | +/* |
| 98715 | +** This is the Expr node callback for sqlite3ExprImpliesNotNullRow(). |
| 98716 | +** If the expression node requires that the table at pWalker->iCur |
| 98717 | +** have a non-NULL column, then set pWalker->eCode to 1 and abort. |
| 98718 | +*/ |
| 98719 | +static int impliesNotNullRow(Walker *pWalker, Expr *pExpr){ |
| 98720 | + if( ExprHasProperty(pExpr, EP_FromJoin) ) return WRC_Prune; |
| 98721 | + switch( pExpr->op ){ |
| 98722 | + case TK_ISNULL: |
| 98723 | + case TK_IS: |
| 98724 | + case TK_OR: |
| 98725 | + case TK_FUNCTION: |
| 98726 | + case TK_AGG_FUNCTION: |
| 98727 | + return WRC_Prune; |
| 98728 | + case TK_COLUMN: |
| 98729 | + case TK_AGG_COLUMN: |
| 98730 | + if( pWalker->u.iCur==pExpr->iTable ){ |
| 98731 | + pWalker->eCode = 1; |
| 98732 | + return WRC_Abort; |
| 98733 | + } |
| 98734 | + return WRC_Prune; |
| 98735 | + default: |
| 98736 | + return WRC_Continue; |
| 98737 | + } |
| 98738 | +} |
| 98739 | + |
| 98740 | +/* |
| 98741 | +** Return true (non-zero) if expression p can only be true if at least |
| 98742 | +** one column of table iTab is non-null. In other words, return true |
| 98743 | +** if expression p will always be NULL or false if every column of iTab |
| 98744 | +** is NULL. |
| 98745 | +** |
| 98746 | +** Terms of p that are marked with EP_FromJoin (and hence that come from |
| 98747 | +** the ON or USING clauses of LEFT JOINS) are excluded from the analysis. |
| 98748 | +** |
| 98749 | +** This routine is used to check if a LEFT JOIN can be converted into |
| 98750 | +** an ordinary JOIN. The p argument is the WHERE clause. If the WHERE |
| 98751 | +** clause requires that some column of the right table of the LEFT JOIN |
| 98752 | +** be non-NULL, then the LEFT JOIN can be safely converted into an |
| 98753 | +** ordinary join. |
| 98754 | +*/ |
| 98755 | +SQLITE_PRIVATE int sqlite3ExprImpliesNonNullRow(Expr *p, int iTab){ |
| 98756 | + Walker w; |
| 98757 | + w.xExprCallback = impliesNotNullRow; |
| 98758 | + w.xSelectCallback = 0; |
| 98759 | + w.xSelectCallback2 = 0; |
| 98760 | + w.eCode = 0; |
| 98761 | + w.u.iCur = iTab; |
| 98762 | + sqlite3WalkExpr(&w, p); |
| 98763 | + return w.eCode; |
| 98764 | +} |
| 98692 | 98765 | |
| 98693 | 98766 | /* |
| 98694 | 98767 | ** An instance of the following structure is used by the tree walker |
| 98695 | 98768 | ** to determine if an expression can be evaluated by reference to the |
| 98696 | 98769 | ** index only, without having to do a search for the corresponding |
| | @@ -112201,15 +112274,16 @@ |
| 112201 | 112274 | ** same table is autoincremented multiple times due to inserts within |
| 112202 | 112275 | ** triggers. A new AutoincInfo structure is created if this is the |
| 112203 | 112276 | ** first use of table pTab. On 2nd and subsequent uses, the original |
| 112204 | 112277 | ** AutoincInfo structure is used. |
| 112205 | 112278 | ** |
| 112206 | | -** Three memory locations are allocated: |
| 112279 | +** Four consecutive registers are allocated: |
| 112207 | 112280 | ** |
| 112208 | | -** (1) Register to hold the name of the pTab table. |
| 112209 | | -** (2) Register to hold the maximum ROWID of pTab. |
| 112210 | | -** (3) Register to hold the rowid in sqlite_sequence of pTab |
| 112281 | +** (1) The name of the pTab table. |
| 112282 | +** (2) The maximum ROWID of pTab. |
| 112283 | +** (3) The rowid in sqlite_sequence of pTab |
| 112284 | +** (4) The original value of the max ROWID in pTab, or NULL if none |
| 112211 | 112285 | ** |
| 112212 | 112286 | ** The 2nd register is the one that is returned. That is all the |
| 112213 | 112287 | ** insert routine needs to know about. |
| 112214 | 112288 | */ |
| 112215 | 112289 | static int autoIncBegin( |
| | @@ -112233,11 +112307,11 @@ |
| 112233 | 112307 | pToplevel->pAinc = pInfo; |
| 112234 | 112308 | pInfo->pTab = pTab; |
| 112235 | 112309 | pInfo->iDb = iDb; |
| 112236 | 112310 | pToplevel->nMem++; /* Register to hold name of table */ |
| 112237 | 112311 | pInfo->regCtr = ++pToplevel->nMem; /* Max rowid register */ |
| 112238 | | - pToplevel->nMem++; /* Rowid in sqlite_sequence */ |
| 112312 | + pToplevel->nMem +=2; /* Rowid in sqlite_sequence + orig max val */ |
| 112239 | 112313 | } |
| 112240 | 112314 | memId = pInfo->regCtr; |
| 112241 | 112315 | } |
| 112242 | 112316 | return memId; |
| 112243 | 112317 | } |
| | @@ -112261,19 +112335,21 @@ |
| 112261 | 112335 | assert( v ); /* We failed long ago if this is not so */ |
| 112262 | 112336 | for(p = pParse->pAinc; p; p = p->pNext){ |
| 112263 | 112337 | static const int iLn = VDBE_OFFSET_LINENO(2); |
| 112264 | 112338 | static const VdbeOpList autoInc[] = { |
| 112265 | 112339 | /* 0 */ {OP_Null, 0, 0, 0}, |
| 112266 | | - /* 1 */ {OP_Rewind, 0, 9, 0}, |
| 112340 | + /* 1 */ {OP_Rewind, 0, 10, 0}, |
| 112267 | 112341 | /* 2 */ {OP_Column, 0, 0, 0}, |
| 112268 | | - /* 3 */ {OP_Ne, 0, 7, 0}, |
| 112342 | + /* 3 */ {OP_Ne, 0, 9, 0}, |
| 112269 | 112343 | /* 4 */ {OP_Rowid, 0, 0, 0}, |
| 112270 | 112344 | /* 5 */ {OP_Column, 0, 1, 0}, |
| 112271 | | - /* 6 */ {OP_Goto, 0, 9, 0}, |
| 112272 | | - /* 7 */ {OP_Next, 0, 2, 0}, |
| 112273 | | - /* 8 */ {OP_Integer, 0, 0, 0}, |
| 112274 | | - /* 9 */ {OP_Close, 0, 0, 0} |
| 112345 | + /* 6 */ {OP_AddImm, 0, 0, 0}, |
| 112346 | + /* 7 */ {OP_Copy, 0, 0, 0}, |
| 112347 | + /* 8 */ {OP_Goto, 0, 11, 0}, |
| 112348 | + /* 9 */ {OP_Next, 0, 2, 0}, |
| 112349 | + /* 10 */ {OP_Integer, 0, 0, 0}, |
| 112350 | + /* 11 */ {OP_Close, 0, 0, 0} |
| 112275 | 112351 | }; |
| 112276 | 112352 | VdbeOp *aOp; |
| 112277 | 112353 | pDb = &db->aDb[p->iDb]; |
| 112278 | 112354 | memId = p->regCtr; |
| 112279 | 112355 | assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); |
| | @@ -112280,18 +112356,21 @@ |
| 112280 | 112356 | sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenRead); |
| 112281 | 112357 | sqlite3VdbeLoadString(v, memId-1, p->pTab->zName); |
| 112282 | 112358 | aOp = sqlite3VdbeAddOpList(v, ArraySize(autoInc), autoInc, iLn); |
| 112283 | 112359 | if( aOp==0 ) break; |
| 112284 | 112360 | aOp[0].p2 = memId; |
| 112285 | | - aOp[0].p3 = memId+1; |
| 112361 | + aOp[0].p3 = memId+2; |
| 112286 | 112362 | aOp[2].p3 = memId; |
| 112287 | 112363 | aOp[3].p1 = memId-1; |
| 112288 | 112364 | aOp[3].p3 = memId; |
| 112289 | 112365 | aOp[3].p5 = SQLITE_JUMPIFNULL; |
| 112290 | 112366 | aOp[4].p2 = memId+1; |
| 112291 | 112367 | aOp[5].p3 = memId; |
| 112292 | | - aOp[8].p2 = memId; |
| 112368 | + aOp[6].p1 = memId; |
| 112369 | + aOp[7].p2 = memId+2; |
| 112370 | + aOp[7].p1 = memId; |
| 112371 | + aOp[10].p2 = memId; |
| 112293 | 112372 | } |
| 112294 | 112373 | } |
| 112295 | 112374 | |
| 112296 | 112375 | /* |
| 112297 | 112376 | ** Update the maximum rowid for an autoincrement calculation. |
| | @@ -112334,10 +112413,12 @@ |
| 112334 | 112413 | int iRec; |
| 112335 | 112414 | int memId = p->regCtr; |
| 112336 | 112415 | |
| 112337 | 112416 | iRec = sqlite3GetTempReg(pParse); |
| 112338 | 112417 | assert( sqlite3SchemaMutexHeld(db, 0, pDb->pSchema) ); |
| 112418 | + sqlite3VdbeAddOp3(v, OP_Le, memId+2, sqlite3VdbeCurrentAddr(v)+7, memId); |
| 112419 | + VdbeCoverage(v); |
| 112339 | 112420 | sqlite3OpenTable(pParse, 0, p->iDb, pDb->pSchema->pSeqTab, OP_OpenWrite); |
| 112340 | 112421 | aOp = sqlite3VdbeAddOpList(v, ArraySize(autoIncEnd), autoIncEnd, iLn); |
| 112341 | 112422 | if( aOp==0 ) break; |
| 112342 | 112423 | aOp[0].p1 = memId+1; |
| 112343 | 112424 | aOp[1].p2 = memId+1; |
| | @@ -119861,12 +119942,11 @@ |
| 119861 | 119942 | */ |
| 119862 | 119943 | #if SELECTTRACE_ENABLED |
| 119863 | 119944 | /***/ int sqlite3SelectTrace = 0; |
| 119864 | 119945 | # define SELECTTRACE(K,P,S,X) \ |
| 119865 | 119946 | if(sqlite3SelectTrace&(K)) \ |
| 119866 | | - sqlite3DebugPrintf("%*s%s.%p: ",(P)->nSelectIndent*2-2,"",\ |
| 119867 | | - (S)->zSelName,(S)),\ |
| 119947 | + sqlite3DebugPrintf("%s/%p: ",(S)->zSelName,(S)),\ |
| 119868 | 119948 | sqlite3DebugPrintf X |
| 119869 | 119949 | #else |
| 119870 | 119950 | # define SELECTTRACE(K,P,S,X) |
| 119871 | 119951 | #endif |
| 119872 | 119952 | |
| | @@ -120222,10 +120302,33 @@ |
| 120222 | 120302 | } |
| 120223 | 120303 | setJoinExpr(p->pLeft, iTable); |
| 120224 | 120304 | p = p->pRight; |
| 120225 | 120305 | } |
| 120226 | 120306 | } |
| 120307 | + |
| 120308 | +/* Undo the work of setJoinExpr(). In the expression tree p, convert every |
| 120309 | +** term that is marked with EP_FromJoin and iRightJoinTable==iTable into |
| 120310 | +** an ordinary term that omits the EP_FromJoin mark. |
| 120311 | +** |
| 120312 | +** This happens when a LEFT JOIN is simplified into an ordinary JOIN. |
| 120313 | +*/ |
| 120314 | +static void unsetJoinExpr(Expr *p, int iTable){ |
| 120315 | + while( p ){ |
| 120316 | + if( ExprHasProperty(p, EP_FromJoin) |
| 120317 | + && (iTable<0 || p->iRightJoinTable==iTable) ){ |
| 120318 | + ExprClearProperty(p, EP_FromJoin); |
| 120319 | + } |
| 120320 | + if( p->op==TK_FUNCTION && p->x.pList ){ |
| 120321 | + int i; |
| 120322 | + for(i=0; i<p->x.pList->nExpr; i++){ |
| 120323 | + unsetJoinExpr(p->x.pList->a[i].pExpr, iTable); |
| 120324 | + } |
| 120325 | + } |
| 120326 | + unsetJoinExpr(p->pLeft, iTable); |
| 120327 | + p = p->pRight; |
| 120328 | + } |
| 120329 | +} |
| 120227 | 120330 | |
| 120228 | 120331 | /* |
| 120229 | 120332 | ** This routine processes the join information for a SELECT statement. |
| 120230 | 120333 | ** ON and USING clauses are converted into extra terms of the WHERE clause. |
| 120231 | 120334 | ** NATURAL joins also create extra WHERE clause terms. |
| | @@ -123675,16 +123778,25 @@ |
| 123675 | 123778 | ** (2) The inner query is the recursive part of a common table expression. |
| 123676 | 123779 | ** |
| 123677 | 123780 | ** (3) The inner query has a LIMIT clause (since the changes to the WHERE |
| 123678 | 123781 | ** close would change the meaning of the LIMIT). |
| 123679 | 123782 | ** |
| 123680 | | -** (4) The inner query is the right operand of a LEFT JOIN. (The caller |
| 123681 | | -** enforces this restriction since this routine does not have enough |
| 123682 | | -** information to know.) |
| 123783 | +** (4) (** This restriction was removed on 2018-03-21. It used to read: |
| 123784 | +** The inner query is the right operand of a LEFT JOIN. **) |
| 123683 | 123785 | ** |
| 123684 | 123786 | ** (5) The WHERE clause expression originates in the ON or USING clause |
| 123685 | | -** of a LEFT JOIN. |
| 123787 | +** of a LEFT JOIN where iCursor is not the right-hand table of that |
| 123788 | +** left join. An example: |
| 123789 | +** |
| 123790 | +** SELECT * |
| 123791 | +** FROM (SELECT 1 AS a1 UNION ALL SELECT 2) AS aa |
| 123792 | +** JOIN (SELECT 1 AS b2 UNION ALL SELECT 2) AS bb ON (a1=b2) |
| 123793 | +** LEFT JOIN (SELECT 8 AS c3 UNION ALL SELECT 9) AS cc ON (b2=2); |
| 123794 | +** |
| 123795 | +** The correct answer is three rows: (1,1,NULL),(2,2,8),(2,2,9). |
| 123796 | +** But if the (b2=2) term were to be pushed down into the bb subquery, |
| 123797 | +** then the (1,1,NULL) row would be suppressed. |
| 123686 | 123798 | ** |
| 123687 | 123799 | ** Return 0 if no changes are made and non-zero if one or more WHERE clause |
| 123688 | 123800 | ** terms are duplicated into the subquery. |
| 123689 | 123801 | */ |
| 123690 | 123802 | static int pushDownWhereTerms( |
| | @@ -123716,16 +123828,19 @@ |
| 123716 | 123828 | } |
| 123717 | 123829 | while( pWhere->op==TK_AND ){ |
| 123718 | 123830 | nChng += pushDownWhereTerms(pParse, pSubq, pWhere->pRight, iCursor); |
| 123719 | 123831 | pWhere = pWhere->pLeft; |
| 123720 | 123832 | } |
| 123721 | | - if( ExprHasProperty(pWhere,EP_FromJoin) ) return 0; /* restriction (5) */ |
| 123833 | + if( ExprHasProperty(pWhere,EP_FromJoin) && pWhere->iRightJoinTable!=iCursor ){ |
| 123834 | + return 0; /* restriction (5) */ |
| 123835 | + } |
| 123722 | 123836 | if( sqlite3ExprIsTableConstant(pWhere, iCursor) ){ |
| 123723 | 123837 | nChng++; |
| 123724 | 123838 | while( pSubq ){ |
| 123725 | 123839 | SubstContext x; |
| 123726 | 123840 | pNew = sqlite3ExprDup(pParse->db, pWhere, 0); |
| 123841 | + unsetJoinExpr(pNew, -1); |
| 123727 | 123842 | x.pParse = pParse; |
| 123728 | 123843 | x.iTable = iCursor; |
| 123729 | 123844 | x.iNewTable = iCursor; |
| 123730 | 123845 | x.isLeftJoin = 0; |
| 123731 | 123846 | x.pEList = pSubq->pEList; |
| | @@ -124753,18 +124868,10 @@ |
| 124753 | 124868 | } |
| 124754 | 124869 | #else |
| 124755 | 124870 | # define explainSimpleCount(a,b,c) |
| 124756 | 124871 | #endif |
| 124757 | 124872 | |
| 124758 | | -/* |
| 124759 | | -** Context object for havingToWhereExprCb(). |
| 124760 | | -*/ |
| 124761 | | -struct HavingToWhereCtx { |
| 124762 | | - Expr **ppWhere; |
| 124763 | | - ExprList *pGroupBy; |
| 124764 | | -}; |
| 124765 | | - |
| 124766 | 124873 | /* |
| 124767 | 124874 | ** sqlite3WalkExpr() callback used by havingToWhere(). |
| 124768 | 124875 | ** |
| 124769 | 124876 | ** If the node passed to the callback is a TK_AND node, return |
| 124770 | 124877 | ** WRC_Continue to tell sqlite3WalkExpr() to iterate through child nodes. |
| | @@ -124774,19 +124881,20 @@ |
| 124774 | 124881 | ** clause. If so, add it to the WHERE clause and replace the sub-expression |
| 124775 | 124882 | ** within the HAVING expression with a constant "1". |
| 124776 | 124883 | */ |
| 124777 | 124884 | static int havingToWhereExprCb(Walker *pWalker, Expr *pExpr){ |
| 124778 | 124885 | if( pExpr->op!=TK_AND ){ |
| 124779 | | - struct HavingToWhereCtx *p = pWalker->u.pHavingCtx; |
| 124780 | | - if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, p->pGroupBy) ){ |
| 124886 | + Select *pS = pWalker->u.pSelect; |
| 124887 | + if( sqlite3ExprIsConstantOrGroupBy(pWalker->pParse, pExpr, pS->pGroupBy) ){ |
| 124781 | 124888 | sqlite3 *db = pWalker->pParse->db; |
| 124782 | 124889 | Expr *pNew = sqlite3ExprAlloc(db, TK_INTEGER, &sqlite3IntTokens[1], 0); |
| 124783 | 124890 | if( pNew ){ |
| 124784 | | - Expr *pWhere = *(p->ppWhere); |
| 124891 | + Expr *pWhere = pS->pWhere; |
| 124785 | 124892 | SWAP(Expr, *pNew, *pExpr); |
| 124786 | 124893 | pNew = sqlite3ExprAnd(db, pWhere, pNew); |
| 124787 | | - *(p->ppWhere) = pNew; |
| 124894 | + pS->pWhere = pNew; |
| 124895 | + pWalker->eCode = 1; |
| 124788 | 124896 | } |
| 124789 | 124897 | } |
| 124790 | 124898 | return WRC_Prune; |
| 124791 | 124899 | } |
| 124792 | 124900 | return WRC_Continue; |
| | @@ -124805,27 +124913,23 @@ |
| 124805 | 124913 | ** |
| 124806 | 124914 | ** A term of the HAVING expression is eligible for transfer if it consists |
| 124807 | 124915 | ** entirely of constants and expressions that are also GROUP BY terms that |
| 124808 | 124916 | ** use the "BINARY" collation sequence. |
| 124809 | 124917 | */ |
| 124810 | | -static void havingToWhere( |
| 124811 | | - Parse *pParse, |
| 124812 | | - ExprList *pGroupBy, |
| 124813 | | - Expr *pHaving, |
| 124814 | | - Expr **ppWhere |
| 124815 | | -){ |
| 124816 | | - struct HavingToWhereCtx sCtx; |
| 124918 | +static void havingToWhere(Parse *pParse, Select *p){ |
| 124817 | 124919 | Walker sWalker; |
| 124818 | | - |
| 124819 | | - sCtx.ppWhere = ppWhere; |
| 124820 | | - sCtx.pGroupBy = pGroupBy; |
| 124821 | | - |
| 124822 | 124920 | memset(&sWalker, 0, sizeof(sWalker)); |
| 124823 | 124921 | sWalker.pParse = pParse; |
| 124824 | 124922 | sWalker.xExprCallback = havingToWhereExprCb; |
| 124825 | | - sWalker.u.pHavingCtx = &sCtx; |
| 124826 | | - sqlite3WalkExpr(&sWalker, pHaving); |
| 124923 | + sWalker.u.pSelect = p; |
| 124924 | + sqlite3WalkExpr(&sWalker, p->pHaving); |
| 124925 | +#if SELECTTRACE_ENABLED |
| 124926 | + if( sWalker.eCode && (sqlite3SelectTrace & 0x100)!=0 ){ |
| 124927 | + SELECTTRACE(0x100,pParse,p,("Move HAVING terms into WHERE:\n")); |
| 124928 | + sqlite3TreeViewSelect(0, p, 0); |
| 124929 | + } |
| 124930 | +#endif |
| 124827 | 124931 | } |
| 124828 | 124932 | |
| 124829 | 124933 | /* |
| 124830 | 124934 | ** Check to see if the pThis entry of pTabList is a self-join of a prior view. |
| 124831 | 124935 | ** If it is, then return the SrcList_item for the prior view. If it is not, |
| | @@ -124982,11 +125086,10 @@ |
| 124982 | 125086 | return 1; |
| 124983 | 125087 | } |
| 124984 | 125088 | if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; |
| 124985 | 125089 | memset(&sAggInfo, 0, sizeof(sAggInfo)); |
| 124986 | 125090 | #if SELECTTRACE_ENABLED |
| 124987 | | - pParse->nSelectIndent++; |
| 124988 | 125091 | SELECTTRACE(1,pParse,p, ("begin processing:\n")); |
| 124989 | 125092 | if( sqlite3SelectTrace & 0x100 ){ |
| 124990 | 125093 | sqlite3TreeViewSelect(0, p, 0); |
| 124991 | 125094 | } |
| 124992 | 125095 | #endif |
| | @@ -125028,17 +125131,33 @@ |
| 125028 | 125131 | if( v==0 ) goto select_end; |
| 125029 | 125132 | if( pDest->eDest==SRT_Output ){ |
| 125030 | 125133 | generateColumnNames(pParse, p); |
| 125031 | 125134 | } |
| 125032 | 125135 | |
| 125033 | | - /* Try to flatten subqueries in the FROM clause up into the main query |
| 125136 | + /* Try to various optimizations (flattening subqueries, and strength |
| 125137 | + ** reduction of join operators) in the FROM clause up into the main query |
| 125034 | 125138 | */ |
| 125035 | 125139 | #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) |
| 125036 | 125140 | for(i=0; !p->pPrior && i<pTabList->nSrc; i++){ |
| 125037 | 125141 | struct SrcList_item *pItem = &pTabList->a[i]; |
| 125038 | 125142 | Select *pSub = pItem->pSelect; |
| 125039 | 125143 | Table *pTab = pItem->pTab; |
| 125144 | + |
| 125145 | + /* Convert LEFT JOIN into JOIN if there are terms of the right table |
| 125146 | + ** of the LEFT JOIN used in the WHERE clause. |
| 125147 | + */ |
| 125148 | + if( (pItem->fg.jointype & JT_LEFT)!=0 |
| 125149 | + && sqlite3ExprImpliesNonNullRow(p->pWhere, pItem->iCursor) |
| 125150 | + && OptimizationEnabled(db, SQLITE_SimplifyJoin) |
| 125151 | + ){ |
| 125152 | + SELECTTRACE(0x100,pParse,p, |
| 125153 | + ("LEFT-JOIN simplifies to JOIN on term %d\n",i)); |
| 125154 | + pItem->fg.jointype &= ~(JT_LEFT|JT_OUTER); |
| 125155 | + unsetJoinExpr(p->pWhere, pItem->iCursor); |
| 125156 | + } |
| 125157 | + |
| 125158 | + /* No futher action if this term of the FROM clause is no a subquery */ |
| 125040 | 125159 | if( pSub==0 ) continue; |
| 125041 | 125160 | |
| 125042 | 125161 | /* Catch mismatch in the declared columns of a view and the number of |
| 125043 | 125162 | ** columns in the SELECT on the RHS */ |
| 125044 | 125163 | if( pTab->nCol!=pSub->pEList->nExpr ){ |
| | @@ -125103,11 +125222,10 @@ |
| 125103 | 125222 | if( p->pPrior ){ |
| 125104 | 125223 | rc = multiSelect(pParse, p, pDest); |
| 125105 | 125224 | explainSetInteger(pParse->iSelectId, iRestoreSelectId); |
| 125106 | 125225 | #if SELECTTRACE_ENABLED |
| 125107 | 125226 | SELECTTRACE(1,pParse,p,("end compound-select processing\n")); |
| 125108 | | - pParse->nSelectIndent--; |
| 125109 | 125227 | #endif |
| 125110 | 125228 | return rc; |
| 125111 | 125229 | } |
| 125112 | 125230 | #endif |
| 125113 | 125231 | |
| | @@ -125176,19 +125294,21 @@ |
| 125176 | 125294 | pParse->nHeight += sqlite3SelectExprHeight(p); |
| 125177 | 125295 | |
| 125178 | 125296 | /* Make copies of constant WHERE-clause terms in the outer query down |
| 125179 | 125297 | ** inside the subquery. This can help the subquery to run more efficiently. |
| 125180 | 125298 | */ |
| 125181 | | - if( (pItem->fg.jointype & JT_OUTER)==0 |
| 125299 | + if( OptimizationEnabled(db, SQLITE_PushDown) |
| 125182 | 125300 | && pushDownWhereTerms(pParse, pSub, p->pWhere, pItem->iCursor) |
| 125183 | 125301 | ){ |
| 125184 | 125302 | #if SELECTTRACE_ENABLED |
| 125185 | 125303 | if( sqlite3SelectTrace & 0x100 ){ |
| 125186 | 125304 | SELECTTRACE(0x100,pParse,p,("After WHERE-clause push-down:\n")); |
| 125187 | 125305 | sqlite3TreeViewSelect(0, p, 0); |
| 125188 | 125306 | } |
| 125189 | 125307 | #endif |
| 125308 | + }else{ |
| 125309 | + SELECTTRACE(0x100,pParse,p,("Push-down not possible\n")); |
| 125190 | 125310 | } |
| 125191 | 125311 | |
| 125192 | 125312 | zSavedAuthContext = pParse->zAuthContext; |
| 125193 | 125313 | pParse->zAuthContext = pItem->zName; |
| 125194 | 125314 | |
| | @@ -125387,10 +125507,11 @@ |
| 125387 | 125507 | u16 wctrlFlags = (sDistinct.isTnct ? WHERE_WANT_DISTINCT : 0); |
| 125388 | 125508 | assert( WHERE_USE_LIMIT==SF_FixedLimit ); |
| 125389 | 125509 | wctrlFlags |= p->selFlags & SF_FixedLimit; |
| 125390 | 125510 | |
| 125391 | 125511 | /* Begin the database scan. */ |
| 125512 | + SELECTTRACE(1,pParse,p,("WhereBegin\n")); |
| 125392 | 125513 | pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, sSort.pOrderBy, |
| 125393 | 125514 | p->pEList, wctrlFlags, p->nSelectRow); |
| 125394 | 125515 | if( pWInfo==0 ) goto select_end; |
| 125395 | 125516 | if( sqlite3WhereOutputRowCount(pWInfo) < p->nSelectRow ){ |
| 125396 | 125517 | p->nSelectRow = sqlite3WhereOutputRowCount(pWInfo); |
| | @@ -125488,11 +125609,13 @@ |
| 125488 | 125609 | sqlite3ExprAnalyzeAggList(&sNC, pEList); |
| 125489 | 125610 | sqlite3ExprAnalyzeAggList(&sNC, sSort.pOrderBy); |
| 125490 | 125611 | if( pHaving ){ |
| 125491 | 125612 | if( pGroupBy ){ |
| 125492 | 125613 | assert( pWhere==p->pWhere ); |
| 125493 | | - havingToWhere(pParse, pGroupBy, pHaving, &p->pWhere); |
| 125614 | + assert( pHaving==p->pHaving ); |
| 125615 | + assert( pGroupBy==p->pGroupBy ); |
| 125616 | + havingToWhere(pParse, p); |
| 125494 | 125617 | pWhere = p->pWhere; |
| 125495 | 125618 | } |
| 125496 | 125619 | sqlite3ExprAnalyzeAggregates(&sNC, pHaving); |
| 125497 | 125620 | } |
| 125498 | 125621 | sAggInfo.nAccumulator = sAggInfo.nColumn; |
| | @@ -125575,10 +125698,11 @@ |
| 125575 | 125698 | ** This might involve two separate loops with an OP_Sort in between, or |
| 125576 | 125699 | ** it might be a single loop that uses an index to extract information |
| 125577 | 125700 | ** in the right order to begin with. |
| 125578 | 125701 | */ |
| 125579 | 125702 | sqlite3VdbeAddOp2(v, OP_Gosub, regReset, addrReset); |
| 125703 | + SELECTTRACE(1,pParse,p,("WhereBegin\n")); |
| 125580 | 125704 | pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pGroupBy, 0, |
| 125581 | 125705 | WHERE_GROUPBY | (orderByGrp ? WHERE_SORTBYGROUP : 0), 0 |
| 125582 | 125706 | ); |
| 125583 | 125707 | if( pWInfo==0 ) goto select_end; |
| 125584 | 125708 | if( sqlite3WhereIsOrdered(pWInfo)==pGroupBy->nExpr ){ |
| | @@ -125830,10 +125954,11 @@ |
| 125830 | 125954 | ** be an appropriate ORDER BY expression for the optimization. |
| 125831 | 125955 | */ |
| 125832 | 125956 | assert( minMaxFlag==WHERE_ORDERBY_NORMAL || pMinMaxOrderBy!=0 ); |
| 125833 | 125957 | assert( pMinMaxOrderBy==0 || pMinMaxOrderBy->nExpr==1 ); |
| 125834 | 125958 | |
| 125959 | + SELECTTRACE(1,pParse,p,("WhereBegin\n")); |
| 125835 | 125960 | pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, pMinMaxOrderBy, |
| 125836 | 125961 | 0, minMaxFlag, 0); |
| 125837 | 125962 | if( pWInfo==0 ){ |
| 125838 | 125963 | goto select_end; |
| 125839 | 125964 | } |
| | @@ -125885,11 +126010,10 @@ |
| 125885 | 126010 | sqlite3ExprListDelete(db, pMinMaxOrderBy); |
| 125886 | 126011 | sqlite3DbFree(db, sAggInfo.aCol); |
| 125887 | 126012 | sqlite3DbFree(db, sAggInfo.aFunc); |
| 125888 | 126013 | #if SELECTTRACE_ENABLED |
| 125889 | 126014 | SELECTTRACE(1,pParse,p,("end processing\n")); |
| 125890 | | - pParse->nSelectIndent--; |
| 125891 | 126015 | #endif |
| 125892 | 126016 | return rc; |
| 125893 | 126017 | } |
| 125894 | 126018 | |
| 125895 | 126019 | /************** End of select.c **********************************************/ |
| | @@ -142086,12 +142210,11 @@ |
| 142086 | 142210 | ** is an integer that is incremented with each SELECT statement seen. |
| 142087 | 142211 | */ |
| 142088 | 142212 | if( yymsp[-8].minor.yy387!=0 ){ |
| 142089 | 142213 | const char *z = s.z+6; |
| 142090 | 142214 | int i; |
| 142091 | | - sqlite3_snprintf(sizeof(yymsp[-8].minor.yy387->zSelName), yymsp[-8].minor.yy387->zSelName, "#%d", |
| 142092 | | - ++pParse->nSelect); |
| 142215 | + sqlite3_snprintf(sizeof(yymsp[-8].minor.yy387->zSelName), yymsp[-8].minor.yy387->zSelName,"#%d",++pParse->nSelect); |
| 142093 | 142216 | while( z[0]==' ' ) z++; |
| 142094 | 142217 | if( z[0]=='/' && z[1]=='*' ){ |
| 142095 | 142218 | z += 2; |
| 142096 | 142219 | while( z[0]==' ' ) z++; |
| 142097 | 142220 | for(i=0; sqlite3Isalnum(z[i]); i++){} |
| | @@ -175718,11 +175841,11 @@ |
| 175718 | 175841 | int bKey = sqlite3_column_int(pXInfo, 5); |
| 175719 | 175842 | if( bKey ){ |
| 175720 | 175843 | int iCid = sqlite3_column_int(pXInfo, 1); |
| 175721 | 175844 | int bDesc = sqlite3_column_int(pXInfo, 3); |
| 175722 | 175845 | const char *zCollate = (const char*)sqlite3_column_text(pXInfo, 4); |
| 175723 | | - zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %s", zCols, zComma, |
| 175846 | + zCols = rbuMPrintf(p, "%z%sc%d %s COLLATE %Q", zCols, zComma, |
| 175724 | 175847 | iCid, pIter->azTblType[iCid], zCollate |
| 175725 | 175848 | ); |
| 175726 | 175849 | zPk = rbuMPrintf(p, "%z%sc%d%s", zPk, zComma, iCid, bDesc?" DESC":""); |
| 175727 | 175850 | zComma = ", "; |
| 175728 | 175851 | } |
| | @@ -175779,11 +175902,11 @@ |
| 175779 | 175902 | if( pIter->eType==RBU_PK_IPK && pIter->abTblPk[iCol] ){ |
| 175780 | 175903 | /* If the target table column is an "INTEGER PRIMARY KEY", add |
| 175781 | 175904 | ** "PRIMARY KEY" to the imposter table column declaration. */ |
| 175782 | 175905 | zPk = "PRIMARY KEY "; |
| 175783 | 175906 | } |
| 175784 | | - zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %s%s", |
| 175907 | + zSql = rbuMPrintf(p, "%z%s\"%w\" %s %sCOLLATE %Q%s", |
| 175785 | 175908 | zSql, zComma, zCol, pIter->azTblType[iCol], zPk, zColl, |
| 175786 | 175909 | (pIter->abNotNull[iCol] ? " NOT NULL" : "") |
| 175787 | 175910 | ); |
| 175788 | 175911 | zComma = ", "; |
| 175789 | 175912 | } |
| | @@ -204574,11 +204697,11 @@ |
| 204574 | 204697 | int nArg, /* Number of args */ |
| 204575 | 204698 | sqlite3_value **apUnused /* Function arguments */ |
| 204576 | 204699 | ){ |
| 204577 | 204700 | assert( nArg==0 ); |
| 204578 | 204701 | UNUSED_PARAM2(nArg, apUnused); |
| 204579 | | - sqlite3_result_text(pCtx, "fts5: 2018-03-16 20:23:01 d75e67654aa9620b9617786553a002f54e8c6dcbbcc58948a06bd98a0916d75a", -1, SQLITE_TRANSIENT); |
| 204702 | + sqlite3_result_text(pCtx, "fts5: 2018-03-22 17:13:44 eb4f452e354065d610ff57a6a9312ad119b6b0cc467f9dff105f0718bc27ef01", -1, SQLITE_TRANSIENT); |
| 204580 | 204703 | } |
| 204581 | 204704 | |
| 204582 | 204705 | static int fts5Init(sqlite3 *db){ |
| 204583 | 204706 | static const sqlite3_module fts5Mod = { |
| 204584 | 204707 | /* iVersion */ 2, |
| | @@ -208844,12 +208967,12 @@ |
| 208844 | 208967 | } |
| 208845 | 208968 | #endif /* SQLITE_CORE */ |
| 208846 | 208969 | #endif /* !defined(SQLITE_CORE) || defined(SQLITE_ENABLE_STMTVTAB) */ |
| 208847 | 208970 | |
| 208848 | 208971 | /************** End of stmt.c ************************************************/ |
| 208849 | | -#if __LINE__!=208849 |
| 208972 | +#if __LINE__!=208972 |
| 208850 | 208973 | #undef SQLITE_SOURCE_ID |
| 208851 | | -#define SQLITE_SOURCE_ID "2018-03-17 16:26:36 442e816b5fed80ebeb58c7c0ab9c2ef999bf488519bf5da670e9cec47703alt2" |
| 208974 | +#define SQLITE_SOURCE_ID "2018-03-22 17:13:44 eb4f452e354065d610ff57a6a9312ad119b6b0cc467f9dff105f0718bc27alt2" |
| 208852 | 208975 | #endif |
| 208853 | 208976 | /* Return the source-id for this library */ |
| 208854 | 208977 | SQLITE_API const char *sqlite3_sourceid(void){ return SQLITE_SOURCE_ID; } |
| 208855 | 208978 | /************************** End of sqlite3.c ******************************/ |
| 208856 | 208979 | |