📄 select.c
字号:
**** A jump to addrRepeat is made and the K 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 */ int K /* Pop K elements from the stack if indistinct */){#if NULL_ALWAYS_DISTINCT sqlite3VdbeAddOp(v, OP_IsNull, -N, sqlite3VdbeCurrentAddr(v)+6);#endif sqlite3VdbeAddOp(v, OP_MakeRecord, -N, 0); sqlite3VdbeAddOp(v, OP_Distinct, iTab, sqlite3VdbeCurrentAddr(v)+3); sqlite3VdbeAddOp(v, OP_Pop, K, 0); sqlite3VdbeAddOp(v, OP_Goto, 0, addrRepeat); VdbeComment((v, "# skip indistinct records")); sqlite3VdbeAddOp(v, OP_IdxInsert, iTab, 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 && pEList->nExpr>0; if( pOrderBy==0 && !hasDistinct ){ codeLimiter(v, p, iContinue, iBreak, 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 ){ int n = pEList->nExpr; codeDistinct(v, distinct, iContinue, n, n+1); if( pOrderBy==0 ){ codeLimiter(v, p, iContinue, iBreak, nColumn); } } 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, NULL_ALWAYS_DISTINCT); 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, NULL_ALWAYS_DISTINCT); 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_VirtualTab: { sqlite3VdbeAddOp(v, OP_MakeRecord, nColumn, 0); if( pOrderBy ){ pushOntoSorter(pParse, v, pOrderBy); }else{ sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Insert, iParm, 0); } 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); 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, v, pOrderBy); }else{ char aff = (iParm>>16)&0xFF; aff = sqlite3CompareAffinity(pEList->a[0].pExpr, aff); sqlite3VdbeOp3(v, OP_MakeRecord, 1, 0, &aff, 1); sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); } sqlite3VdbeJumpHere(v, addr2); 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_Exists: case SRT_Mem: { assert( nColumn==1 ); if( pOrderBy ){ pushOntoSorter(pParse, v, pOrderBy); }else{ sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); sqlite3VdbeAddOp(v, OP_Goto, 0, iBreak); } 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, v, pOrderBy); }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 } 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 = (char*)&pInfo->aColl[nExpr]; pInfo->nField = nExpr; pInfo->enc = db->enc; 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, /* The 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; ExprList *pOrderBy = p->pOrderBy; iTab = pOrderBy->iECursor; addr = 1 + sqlite3VdbeAddOp(v, OP_Sort, iTab, brk); codeLimiter(v, p, cont, brk, 0); sqlite3VdbeAddOp(v, OP_Column, iTab, pOrderBy->nExpr + 1); switch( eDest ){ case SRT_Table: case SRT_VirtualTab: { sqlite3VdbeAddOp(v, OP_NewRowid, iParm, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); sqlite3VdbeAddOp(v, OP_Insert, iParm, 0); 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, "n", P3_STATIC); sqlite3VdbeAddOp(v, OP_IdxInsert, (iParm&0x0000FFFF), 0); break; } case SRT_Exists: case SRT_Mem: { assert( nColumn==1 ); sqlite3VdbeAddOp(v, OP_MemStore, iParm, 1); sqlite3VdbeAddOp(v, OP_Goto, 0, brk); break; }#endif case SRT_Callback: case SRT_Subroutine: { int i; sqlite3VdbeAddOp(v, OP_Integer, p->pEList->nExpr, 0); sqlite3VdbeAddOp(v, OP_Pull, 1, 0); for(i=0; i<nColumn; i++){ sqlite3VdbeAddOp(v, OP_Column, -1-i, i); } if( eDest==SRT_Callback ){ sqlite3VdbeAddOp(v, OP_Callback, nColumn, 0); }else{ sqlite3VdbeAddOp(v, OP_Gosub, 0, iParm); } sqlite3VdbeAddOp(v, OP_Pop, 2, 0); break; } default: { /* Do nothing */ break; } } sqlite3VdbeResolveLabel(v, cont); sqlite3VdbeAddOp(v, OP_Next, iTab, addr); sqlite3VdbeResolveLabel(v, brk);}/*** Return a pointer to a string containing the 'declaration type' of the** expression pExpr. The string may be treated as static by the caller.**** If the declaration type is the exact datatype definition extracted from** the original CREATE TABLE statement if the expression is a column.** ** The declaration type for an expression is either TEXT, NUMERIC or ANY.** The declaration type for a ROWID field is INTEGER.*/static const char *columnType(NameContext *pNC, Expr *pExpr){ char const *zType; int j; if( pExpr==0 || pNC->pSrcList==0 ) return 0; /* The TK_AS operator can only occur in ORDER BY, GROUP BY, HAVING, ** and LIMIT clauses. But pExpr originates in the result set of a ** SELECT. So pExpr can never contain an AS operator. */ assert( pExpr->op!=TK_AS ); switch( pExpr->op ){ case TK_COLUMN: { Table *pTab = 0; int iCol = pExpr->iColumn; while( pNC && !pTab ){ SrcList *pTabList = pNC->pSrcList; for(j=0;j<pTabList->nSrc && pTabList->a[j].iCursor!=pExpr->iTable;j++); if( j<pTabList->nSrc ){ pTab = pTabList->a[j].pTab; }else{ pNC = pNC->pNext; } } if( pTab==0 ){ /* FIX ME: ** This can occurs if you have something like "SELECT new.x;" inside ** a trigger. In other words, if you reference the special "new" ** table in the result set of a select. We do not have a good way ** to find the actual table type, so call it "TEXT". This is really ** something of a bug, but I do not know how to fix it. ** ** This code does not produce the correct answer - it just prevents ** a segfault. See ticket #1229. */ zType = "TEXT"; break; } assert( pTab ); if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); if( iCol<0 ){ zType = "INTEGER"; }else{ zType = pTab->aCol[iCol].zType; } break; }#ifndef SQLITE_OMIT_SUBQUERY case TK_SELECT: { NameContext sNC; Select *pS = pExpr->pSelect; sNC.pSrcList = pExpr->pSelect->pSrc; sNC.pNext = pNC; zType = columnType(&sNC, pS->pEList->a[0].pExpr); break; }#endif default:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -