📄 select.c
字号:
pDelete = p->pPrior; p->pPrior = pPrior; p->pOrderBy = 0; sqlite3ExprDelete(db, p->pLimit); p->pLimit = pLimit; p->pOffset = pOffset; p->iLimit = 0; p->iOffset = 0; if( rc ){ goto multi_select_end; } /* Convert the data in the temporary table into whatever form ** it is that we currently need. */ if( dest.eDest!=priorOp || unionTab!=dest.iParm ){ int iCont, iBreak, iStart; assert( p->pEList ); if( dest.eDest==SRT_Output ){ Select *pFirst = p; while( pFirst->pPrior ) pFirst = pFirst->pPrior; generateColumnNames(pParse, 0, pFirst->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); iStart = sqlite3VdbeCurrentAddr(v); selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr, 0, -1, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); } break; } case TK_INTERSECT: { int tab1, tab2; int iCont, iBreak, iStart; Expr *pLimit, *pOffset; int addr; SelectDest intersectdest; int r1; /* INTERSECT is different from the others since it requires ** two temporary tables. Hence it has its own case. Begin ** by allocating the tables we will need. */ tab1 = pParse->nTab++; tab2 = pParse->nTab++; assert( p->pOrderBy==0 ); addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; p->pRightmost->selFlags |= SF_UsesEphemeral; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". */ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); rc = sqlite3Select(pParse, pPrior, &intersectdest); if( rc ){ goto multi_select_end; } /* Code the current SELECT into temporary table "tab2" */ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); assert( p->addrOpenEphm[1] == -1 ); p->addrOpenEphm[1] = addr; p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; pOffset = p->pOffset; p->pOffset = 0; intersectdest.iParm = tab2; rc = sqlite3Select(pParse, p, &intersectdest); pDelete = p->pPrior; p->pPrior = pPrior; sqlite3ExprDelete(db, p->pLimit); p->pLimit = pLimit; p->pOffset = pOffset; if( rc ){ goto multi_select_end; } /* Generate code to take the intersection of the two temporary ** tables. */ assert( p->pEList ); if( dest.eDest==SRT_Output ){ Select *pFirst = p; while( pFirst->pPrior ) pFirst = pFirst->pPrior; generateColumnNames(pParse, 0, pFirst->pEList); } iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); r1 = sqlite3GetTempReg(pParse); iStart = sqlite3VdbeAddOp2(v, OP_RowKey, tab1, r1); sqlite3VdbeAddOp3(v, OP_NotFound, tab2, iCont, r1); sqlite3ReleaseTempReg(pParse, r1); selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr, 0, -1, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); break; } } /* Compute collating sequences used by ** temporary tables needed to implement the compound select. ** Attach the KeyInfo structure to all temporary tables. ** ** This section is run by the right-most SELECT statement only. ** SELECT statements to the left always skip this part. The right-most ** SELECT might also skip this part if it has no ORDER BY clause and ** no temp tables are required. */ if( p->selFlags & SF_UsesEphemeral ){ int i; /* Loop counter */ KeyInfo *pKeyInfo; /* Collating sequence for the result set */ Select *pLoop; /* For looping through SELECT statements */ CollSeq **apColl; /* For looping through pKeyInfo->aColl[] */ int nCol; /* Number of columns in result set */ assert( p->pRightmost==p ); nCol = p->pEList->nExpr; pKeyInfo = sqlite3DbMallocZero(db, sizeof(*pKeyInfo)+nCol*(sizeof(CollSeq*) + 1)); if( !pKeyInfo ){ rc = SQLITE_NOMEM; goto multi_select_end; } pKeyInfo->enc = ENC(db); pKeyInfo->nField = nCol; for(i=0, apColl=pKeyInfo->aColl; i<nCol; i++, apColl++){ *apColl = multiSelectCollSeq(pParse, p, i); if( 0==*apColl ){ *apColl = db->pDfltColl; } } for(pLoop=p; pLoop; pLoop=pLoop->pPrior){ for(i=0; i<2; i++){ int addr = pLoop->addrOpenEphm[i]; if( addr<0 ){ /* If [0] is unused then [1] is also unused. So we can ** always safely abort as soon as the first unused slot is found */ assert( pLoop->addrOpenEphm[1]<0 ); break; } sqlite3VdbeChangeP2(v, addr, nCol); sqlite3VdbeChangeP4(v, addr, (char*)pKeyInfo, P4_KEYINFO); pLoop->addrOpenEphm[i] = -1; } } sqlite3DbFree(db, pKeyInfo); }multi_select_end: pDest->iMem = dest.iMem; pDest->nMem = dest.nMem; sqlite3SelectDelete(db, pDelete); return rc;}#endif /* SQLITE_OMIT_COMPOUND_SELECT *//*** Code an output subroutine for a coroutine implementation of a** SELECT statment.**** The data to be output is contained in pIn->iMem. There are** pIn->nMem columns to be output. pDest is where the output should** be sent.**** regReturn is the number of the register holding the subroutine** return address.**** If regPrev>0 then it is a the first register in a vector that** records the previous output. mem[regPrev] is a flag that is false** if there has been no previous output. If regPrev>0 then code is** generated to suppress duplicates. pKeyInfo is used for comparing** keys.**** If the LIMIT found in p->iLimit is reached, jump immediately to** iBreak.*/static int generateOutputSubroutine( Parse *pParse, /* Parsing context */ Select *p, /* The SELECT statement */ SelectDest *pIn, /* Coroutine supplying data */ SelectDest *pDest, /* Where to send the data */ int regReturn, /* The return address register */ int regPrev, /* Previous result register. No uniqueness if 0 */ KeyInfo *pKeyInfo, /* For comparing with previous entry */ int p4type, /* The p4 type for pKeyInfo */ int iBreak /* Jump here if we hit the LIMIT */){ Vdbe *v = pParse->pVdbe; int iContinue; int addr; addr = sqlite3VdbeCurrentAddr(v); iContinue = sqlite3VdbeMakeLabel(v); /* Suppress duplicates for UNION, EXCEPT, and INTERSECT */ if( regPrev ){ int j1, j2; j1 = sqlite3VdbeAddOp1(v, OP_IfNot, regPrev); j2 = sqlite3VdbeAddOp4(v, OP_Compare, pIn->iMem, regPrev+1, pIn->nMem, (char*)pKeyInfo, p4type); sqlite3VdbeAddOp3(v, OP_Jump, j2+2, iContinue, j2+2); sqlite3VdbeJumpHere(v, j1); sqlite3ExprCodeCopy(pParse, pIn->iMem, regPrev+1, pIn->nMem); sqlite3VdbeAddOp2(v, OP_Integer, 1, regPrev); } if( pParse->db->mallocFailed ) return 0; /* Suppress the the first OFFSET entries if there is an OFFSET clause */ codeOffset(v, p, iContinue); switch( pDest->eDest ){ /* Store the result as data using a unique key. */ case SRT_Table: case SRT_EphemTab: { int r1 = sqlite3GetTempReg(pParse); int r2 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp3(v, OP_MakeRecord, pIn->iMem, pIn->nMem, r1); sqlite3VdbeAddOp2(v, OP_NewRowid, pDest->iParm, r2); sqlite3VdbeAddOp3(v, OP_Insert, pDest->iParm, r1, r2); sqlite3VdbeChangeP5(v, OPFLAG_APPEND); sqlite3ReleaseTempReg(pParse, r2); sqlite3ReleaseTempReg(pParse, r1); 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 r1; assert( pIn->nMem==1 ); p->affinity = sqlite3CompareAffinity(p->pEList->a[0].pExpr, pDest->affinity); r1 = sqlite3GetTempReg(pParse); sqlite3VdbeAddOp4(v, OP_MakeRecord, pIn->iMem, 1, r1, &p->affinity, 1); sqlite3ExprCacheAffinityChange(pParse, pIn->iMem, 1); sqlite3VdbeAddOp2(v, OP_IdxInsert, pDest->iParm, r1); sqlite3ReleaseTempReg(pParse, r1); break; }#if 0 /* Never occurs on an ORDER BY query */ /* If any row exist in the result set, record that fact and abort. */ case SRT_Exists: { sqlite3VdbeAddOp2(v, OP_Integer, 1, pDest->iParm); /* The LIMIT clause will terminate the loop for us */ break; }#endif /* 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( pIn->nMem==1 ); sqlite3ExprCodeMove(pParse, pIn->iMem, pDest->iParm, 1); /* The LIMIT clause will jump out of the loop for us */ break; }#endif /* #ifndef SQLITE_OMIT_SUBQUERY */ /* The results are stored in a sequence of registers ** starting at pDest->iMem. Then the co-routine yields. */ case SRT_Coroutine: { if( pDest->iMem==0 ){ pDest->iMem = sqlite3GetTempRange(pParse, pIn->nMem); pDest->nMem = pIn->nMem; } sqlite3ExprCodeMove(pParse, pIn->iMem, pDest->iMem, pDest->nMem); sqlite3VdbeAddOp1(v, OP_Yield, pDest->iParm); break; } /* Results are stored in a sequence of registers. Then the ** OP_ResultRow opcode is used to cause sqlite3_step() to return ** the next row of result. */ case SRT_Output: { sqlite3VdbeAddOp2(v, OP_ResultRow, pIn->iMem, pIn->nMem); sqlite3ExprCacheAffinityChange(pParse, pIn->iMem, pIn->nMem); 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: { break; }#endif } /* Jump to the end of the loop if the LIMIT is reached. */ if( p->iLimit ){ sqlite3VdbeAddOp2(v, OP_AddImm, p->iLimit, -1); sqlite3VdbeAddOp2(v, OP_IfZero, p->iLimit, iBreak); } /* Generate the subroutine return */ sqlite3VdbeResolveLabel(v, iContinue); sqlite3VdbeAddOp1(v, OP_Return, regReturn); return addr;}/*** Alternative compound select code generator for cases when there** is an ORDER BY clause.**** We assume a query of the following form:**** <selectA> <operator> <selectB> ORDER BY <orderbylist>**** <operator> is one of UNION ALL, UNION, EXCEPT, or INTERSECT. The idea** is to code both <selectA> and <selectB> with the ORDER BY clause as** co-routines. Then run the co-routines in parallel and merge the results** into the output. In addition to the two coroutines (called selectA and** selectB) there are 7 subroutines:**** outA: Move the output of the selectA coroutine into the output** of the compound query.**** outB: Move the output of the selectB coroutine into the output** of the compound query. (Only generated for UNION and** UNION ALL. EXCEPT and INSERTSECT never output a row that** appears only in B.)**** AltB: Called when there is data from both coroutines and A<B.**** AeqB: Called when there is data from both coroutines and A==B.**** AgtB: Called when there is data from both coroutines and A>B.**** EofA: Called when data is exhausted from selectA.**** EofB: Called when data is exhausted from selectB.**** The implementation of the latter five subroutines depend on which ** <operator> is used:****** UNION ALL UNION EXCEPT INTERSECT** ------------- ----------------- -------------- -----------------** AltB: outA, nextA outA, nextA outA, nextA nextA**** AeqB: outA, nextA nextA nextA outA, nextA**** AgtB: outB, nextB outB, nextB nextB nextB**** EofA: outB, nextB outB, nextB halt halt**** EofB: outA, nextA outA, nextA outA, nextA halt**** In the AltB, AeqB, and AgtB subroutines, an EOF on A following nextA** causes an immediate jump to EofA and an EOF on B following nextB causes** an immediate jump to EofB. Within EofA and EofB, and EOF on entry or** following nextX causes a jump to the end of the select processing.**** Duplicate removal in the UNION, EXCEPT, and INTERSECT cases is handled** w
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -