📄 select.c
字号:
addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); sqlite3VdbeJumpHere(v, addr1); sqlite3VdbeAddOp(v, OP_Last, pOrderBy->iECursor, 0); sqlite3VdbeAddOp(v, OP_Delete, pOrderBy->iECursor, 0); sqlite3VdbeJumpHere(v, addr2); pSelect->iLimit = -1; }}/*** Add code to implement the OFFSET*/static void codeOffset( Vdbe *v, /* Generate code into this VM */ Select *p, /* The SELECT statement being coded */ int iContinue, /* Jump here to skip the current record */ int nPop /* Number of times to pop stack when jumping */){ if( p->iOffset>=0 && iContinue!=0 ){ int addr; sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iOffset); addr = sqlite3VdbeAddOp(v, OP_IfMemNeg, p->iOffset, 0); if( nPop>0 ){ sqlite3VdbeAddOp(v, OP_Pop, nPop, 0); } sqlite3VdbeAddOp(v, OP_Goto, 0, iContinue); VdbeComment((v, "# skip OFFSET records")); sqlite3VdbeJumpHere(v, addr); }}/*** Add code that will check to make sure the top N elements of the** stack are distinct. iTab is a sorting index that holds previously** seen combinations of the N values. A new entry is made in iTab** if the current N values are new.**** A jump to addrRepeat is made and the N+1 values are popped from the** stack if the top N elements are not distinct.*/static void codeDistinct( Vdbe *v, /* Generate code into this VM */ int iTab, /* A sorting index used to test for distinctness */ int addrRepeat, /* Jump to here if not distinct */ int N /* The top N elements of the stack must be distinct */){ sqlite3VdbeAddOp(v, OP_MakeRecord, -N, 0); sqlite3VdbeAddOp(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Pop, N+1, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, addrRepeat); VdbeComment((v, "# skip indistinct records")); sqlite3VdbeAddOp(v, OP_IdxInsert, iTab, 0);}/*** Generate an error message when a SELECT is used within a subexpression** (example: "a IN (SELECT * FROM table)") but it has more than 1 result** column. We do this in a subroutine because the error occurs in multiple** places.*/static int checkForMultiColumnSelectError(Parse *pParse, int eDest, int nExpr){ if( nExpr>1 && (eDest==SRT_Mem || eDest==SRT_Set) ){ sqlite3ErrorMsg(pParse, "only a single result allowed for " "a SELECT that is part of an expression"); return 1; }else{ return 0; }}/*** This routine generates the code for the inside of the inner loop** of a SELECT.**** If srcTab and nColumn are both zero, then the pEList expressions** are evaluated in order to get the data for this row. If nColumn>0** then data is pulled from srcTab and pEList is used only to get the** datatypes for each column.*/static int selectInnerLoop( Parse *pParse, /* The parser context */ Select *p, /* The complete select statement being coded */ ExprList *pEList, /* List of values being extracted */ int srcTab, /* Pull data from this table */ int nColumn, /* Number of columns in the source table */ ExprList *pOrderBy, /* If not NULL, sort results using this key */ int distinct, /* If >=0, make sure results are distinct */ int eDest, /* How to dispose of the results */ int iParm, /* An argument to the disposal method */ int iContinue, /* Jump here to continue with next row */ int iBreak, /* Jump here to break out of the inner loop */ char *aff /* affinity string if eDest is SRT_Union */){ Vdbe *v = pParse->pVdbe; int i; int hasDistinct; /* True if the DISTINCT keyword is present */ if( v==0 ) return 0; assert( pEList!=0 ); /* If there was a LIMIT clause on the SELECT statement, then do the check ** to see if this row should be output. */ hasDistinct = distinct>=0 && pEList->nExpr>0; if( pOrderBy==0 && !hasDistinct ){ codeOffset(v, p, iContinue, 0); } /* Pull the requested columns. */ if( nColumn>0 ){ for(i=0; i<nColumn; i++){ sqlite3VdbeAddOp(v, OP_Column, srcTab, i); } }else{ nColumn = pEList->nExpr; sqlite3ExprCodeExprList(pParse, pEList); } /* If the DISTINCT keyword was present on the SELECT statement ** and this row has been seen before, then do not make this row ** part of the result. */ if( hasDistinct ){ assert( pEList!=0 ); assert( pEList->nExpr==nColumn ); codeDistinct(v, distinct, iContinue, nColumn); if( pOrderBy==0 ){ codeOffset(v, p, iContinue, nColumn); } } if( checkForMultiColumnSelectError(pParse, eDest, pEList->nExpr) ){ return 0; } switch( eDest ){ /* In this mode, write each query result to the key of the temporary ** table iParm. */#ifndef SQLITE_OMIT_COMPOUND_SELECT case SRT_Union: { sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); if( aff ){ sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC); } sqlite3VdbeAddOp(v, OP_IdxInsert, iParm, 0); break; } /* Construct a record from the query result, but instead of ** saving that record, use it as a key to delete elements from ** the temporary table iParm. */ case SRT_Except: { int addr; addr = sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); sqlite3VdbeChangeP3(v, -1, aff, P3_STATIC); sqlite3VdbeAddOp(v, OP_NotFound, iParm, addr+3); sqlite3VdbeAddOp(v, OP_Delete, iParm, 0); break; }#endif /* Store the result as data using a unique key. */ case SRT_Table: case SRT_EphemTab: { sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p); }else{ sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Insert, iParm, OPFLAG_APPEND); } break; }#ifndef SQLITE_OMIT_SUBQUERY /* If we are creating a set for an "expr IN (SELECT ...)" construct, ** then there should be a single item on the stack. Write this ** item into the set table with bogus data. */ case SRT_Set: { int addr1 = sqlite3VdbeCurrentAddr(v); int addr2; assert( nColumn==1 ); sqlite3VdbeAddOp(v, OP_NotNull, -1, addr1+3); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); addr2 = sqlite3VdbeAddOp(v, OP_Goto, 0, 0); p->affinity = sqlite3CompareAffinity(pEList->a[0].pExpr,(iParm>>16)&0xff); if( pOrderBy ){ /* At first glance you would think we could optimize out the ** ORDER BY in this case since the order of entries in the set ** does not matter. But there might be a LIMIT clause, in which ** case the order does matter */ pushOntoSorter(pParse, pOrderBy, p); }else{ sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &p->affinity, 1); sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); } sqlite3VdbeJumpHere(v, addr2); break; } /* If any row exist in the result set, record that fact and abort. */ case SRT_Exists: { sqlite3VdbeAddOp(v, OP_MemInt, 1, iParm); sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); /* The LIMIT clause will terminate the loop for us */ break; } /* If this is a scalar select that is part of an expression, then ** store the results in the appropriate memory cell and break out ** of the scan loop. */ case SRT_Mem: { assert( nColumn==1 ); if( pOrderBy ){ pushOntoSorter(pParse, pOrderBy, p); }else{ sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); /* The LIMIT clause will jump out of the loop for us */ } break; }#endif /* #ifndef SQLITE_OMIT_SUBQUERY */ /* Send the data to the callback function or to a subroutine. In the ** case of a subroutine, the subroutine itself is responsible for ** popping the data from the stack. */ case SRT_Subroutine: case SRT_Callback: { if( pOrderBy ){ sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); pushOntoSorter(pParse, pOrderBy, p); }else if( eDest==SRT_Subroutine ){ sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm); }else{ sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0); } break; }#if !defined(SQLITE_OMIT_TRIGGER) /* Discard the results. This is used for SELECT statements inside ** the body of a TRIGGER. The purpose of such selects is to call ** user-defined functions that have side effects. We do not care ** about the actual results of the select. */ default: { assert( eDest==SRT_Discard ); sqlite3VdbeAddOp(v, OP_Pop, nColumn, 0); break; }#endif } /* Jump to the end of the loop if the LIMIT is reached. */ if( p->iLimit>=0 && pOrderBy==0 ){ sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit); sqlite3VdbeAddOp(v, OP_IfMemZero, p->iLimit, iBreak); } return 0;}/*** Given an expression list, generate a KeyInfo structure that records** the collating sequence for each expression in that expression list.**** If the ExprList is an ORDER BY or GROUP BY clause then the resulting** KeyInfo structure is appropriate for initializing a virtual index to** implement that clause. If the ExprList is the result set of a SELECT** then the KeyInfo structure is appropriate for initializing a virtual** index to implement a DISTINCT test.**** Space to hold the KeyInfo structure is obtain from malloc. The calling** function is responsible for seeing that this structure is eventually** freed. Add the KeyInfo structure to the P3 field of an opcode using** P3_KEYINFO_HANDOFF is the usual way of dealing with this.*/static KeyInfo *keyInfoFromExprList(Parse *pParse, ExprList *pList){ sqlite3 *db = pParse->db; int nExpr; KeyInfo *pInfo; struct ExprList_item *pItem; int i; nExpr = pList->nExpr; pInfo = sqliteMalloc( sizeof(*pInfo) + nExpr*(sizeof(CollSeq*)+1) ); if( pInfo ){ pInfo->aSortOrder = (u8*)&pInfo->aColl[nExpr]; pInfo->nField = nExpr; pInfo->enc = ENC(db); for(i=0, pItem=pList->a; i<nExpr; i++, pItem++){ CollSeq *pColl; pColl = sqlite3ExprCollSeq(pParse, pItem->pExpr); if( !pColl ){ pColl = db->pDfltColl; } pInfo->aColl[i] = pColl; pInfo->aSortOrder[i] = pItem->sortOrder; } } return pInfo;}/*** If the inner loop was generated using a non-null pOrderBy argument,** then the results were placed in a sorter. After the loop is terminated** we need to run the sorter and output the results. The following** routine generates the code needed to do that.*/static void generateSortTail( Parse *pParse, /* Parsing context */ Select *p, /* The SELECT statement */ Vdbe *v, /* Generate code into this VDBE */ int nColumn, /* Number of columns of data */ int eDest, /* Write the sorted results here */ int iParm /* Optional parameter associated with eDest */){ int brk = sqlite3VdbeMakeLabel(v); int cont = sqlite3VdbeMakeLabel(v); int addr; int iTab; int pseudoTab = 0; ExprList *pOrderBy = p->pOrderBy; iTab = pOrderBy->iECursor; if( eDest==SRT_Callback || eDest==SRT_Subroutine ){ pseudoTab = pParse->nTab++; sqlite3VdbeAddOp(v, OP_OpenPseudo, pseudoTab, 0); sqlite3VdbeAddOp(v, OP_SetNumColumns, pseudoTab, nColumn); } addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk); codeOffset(v, p, cont, 0); if( eDest==SRT_Callback || eDest==SRT_Subroutine ){ sqlite3VdbeAddOp(v, OP_Integer, 1, 0); } sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1); switch( eDest ){ case SRT_Table: case SRT_EphemTab: { sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Insert, iParm, OPFLAG_APPEND); break; }#ifndef SQLITE_OMIT_SUBQUERY case SRT_Set: { assert( nColumn==1 ); sqlite3VdbeAddOp(v, OP_NotNull, -1, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Pop, 1, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &p->affinity, 1); sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); break; } case SRT_Mem: { assert( nColumn==1 ); sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); /* The LIMIT clause will terminate the loop for us */ break; }#endif case SRT_Callback: case SRT_Subroutine: { int i; sqlite3VdbeAddOp(v, OP_Insert, pseudoTab, 0); for(i=0; i<nColumn; i++){ sqlite3VdbeAddOp(v, OP_Column, pseudoTab, i); } if( eDest==SRT_Callback ){ sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0); }else{ sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm); } break; } default: { /* Do nothing */ break; } } /* Jump to the end of the loop when the LIMIT is reached */ if( p->iLimit>=0 ){ sqlite3VdbeAddOp(v, OP_MemIncr, -1, p->iLimit);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -