?? select.c
字號(hào):
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. */ if( pOrderBy==0 ){ if( p->iOffset>=0 ){ int addr = sqliteVdbeCurrentAddr(v); sqliteVdbeAddOp(v, OP_MemIncr, p->iOffset, addr+2); sqliteVdbeAddOp(v, OP_Goto, 0, iContinue); } if( p->iLimit>=0 ){ sqliteVdbeAddOp(v, OP_MemIncr, p->iLimit, iBreak); } } /* Pull the requested columns. */ if( nColumn>0 ){ for(i=0; i<nColumn; i++){ sqliteVdbeAddOp(v, OP_Column, srcTab, i); } }else{ nColumn = pEList->nExpr; for(i=0; i<pEList->nExpr; i++){ sqliteExprCode(pParse, pEList->a[i].pExpr); } } /* 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( distinct>=0 && pEList && pEList->nExpr>0 ){#if NULL_ALWAYS_DISTINCT sqliteVdbeAddOp(v, OP_IsNull, -pEList->nExpr, sqliteVdbeCurrentAddr(v)+7);#endif sqliteVdbeAddOp(v, OP_MakeKey, pEList->nExpr, 1); if( pParse->db->file_format>=4 ) sqliteAddKeyType(v, pEList); sqliteVdbeAddOp(v, OP_Distinct, distinct, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_Pop, pEList->nExpr+1, 0); sqliteVdbeAddOp(v, OP_Goto, 0, iContinue); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, distinct, 0); } switch( eDest ){ /* In this mode, write each query result to the key of the temporary ** table iParm. */ case SRT_Union: { sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); break; } /* Store the result as data using a unique key. */ case SRT_Table: case SRT_TempTable: { sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); if( pOrderBy ){ pushOntoSorter(pParse, v, pOrderBy); }else{ sqliteVdbeAddOp(v, OP_NewRecno, iParm, 0); sqliteVdbeAddOp(v, OP_Pull, 1, 0); sqliteVdbeAddOp(v, OP_PutIntKey, 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 = sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, NULL_ALWAYS_DISTINCT); sqliteVdbeAddOp(v, OP_NotFound, iParm, addr+3); sqliteVdbeAddOp(v, OP_Delete, iParm, 0); break; } /* 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 = sqliteVdbeCurrentAddr(v); int addr2; assert( nColumn==1 ); sqliteVdbeAddOp(v, OP_NotNull, -1, addr1+3); sqliteVdbeAddOp(v, OP_Pop, 1, 0); addr2 = sqliteVdbeAddOp(v, OP_Goto, 0, 0); if( pOrderBy ){ pushOntoSorter(pParse, v, pOrderBy); }else{ sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); } sqliteVdbeChangeP2(v, addr2, sqliteVdbeCurrentAddr(v)); 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, v, pOrderBy); }else{ sqliteVdbeAddOp(v, OP_MemStore, iParm, 1); sqliteVdbeAddOp(v, OP_Goto, 0, iBreak); } break; } /* Send the data to the callback function. */ case SRT_Callback: case SRT_Sorter: { if( pOrderBy ){ sqliteVdbeAddOp(v, OP_SortMakeRec, nColumn, 0); pushOntoSorter(pParse, v, pOrderBy); }else{ assert( eDest==SRT_Callback ); sqliteVdbeAddOp(v, OP_Callback, nColumn, 0); } break; } /* Invoke a subroutine to handle the results. The subroutine itself ** is responsible for popping the results off of the stack. */ case SRT_Subroutine: { if( pOrderBy ){ sqliteVdbeAddOp(v, OP_MakeRecord, nColumn, 0); pushOntoSorter(pParse, v, pOrderBy); }else{ sqliteVdbeAddOp(v, OP_Gosub, 0, iParm); } break; } /* 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 ); sqliteVdbeAddOp(v, OP_Pop, nColumn, 0); break; } } return 0;}/*** 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( 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 end1 = sqliteVdbeMakeLabel(v); int end2 = sqliteVdbeMakeLabel(v); int addr; if( eDest==SRT_Sorter ) return; sqliteVdbeAddOp(v, OP_Sort, 0, 0); addr = sqliteVdbeAddOp(v, OP_SortNext, 0, end1); if( p->iOffset>=0 ){ sqliteVdbeAddOp(v, OP_MemIncr, p->iOffset, addr+4); sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteVdbeAddOp(v, OP_Goto, 0, addr); } if( p->iLimit>=0 ){ sqliteVdbeAddOp(v, OP_MemIncr, p->iLimit, end2); } switch( eDest ){ case SRT_Callback: { sqliteVdbeAddOp(v, OP_SortCallback, nColumn, 0); break; } case SRT_Table: case SRT_TempTable: { sqliteVdbeAddOp(v, OP_NewRecno, iParm, 0); sqliteVdbeAddOp(v, OP_Pull, 1, 0); sqliteVdbeAddOp(v, OP_PutIntKey, iParm, 0); break; } case SRT_Set: { assert( nColumn==1 ); sqliteVdbeAddOp(v, OP_NotNull, -1, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteVdbeAddOp(v, OP_Goto, 0, sqliteVdbeCurrentAddr(v)+3); sqliteVdbeAddOp(v, OP_String, 0, 0); sqliteVdbeAddOp(v, OP_PutStrKey, iParm, 0); break; } case SRT_Mem: { assert( nColumn==1 ); sqliteVdbeAddOp(v, OP_MemStore, iParm, 1); sqliteVdbeAddOp(v, OP_Goto, 0, end1); break; } case SRT_Subroutine: { int i; for(i=0; i<nColumn; i++){ sqliteVdbeAddOp(v, OP_Column, -1-i, i); } sqliteVdbeAddOp(v, OP_Gosub, 0, iParm); sqliteVdbeAddOp(v, OP_Pop, 1, 0); break; } default: { /* Do nothing */ break; } } sqliteVdbeAddOp(v, OP_Goto, 0, addr); sqliteVdbeResolveLabel(v, end2); sqliteVdbeAddOp(v, OP_Pop, 1, 0); sqliteVdbeResolveLabel(v, end1); sqliteVdbeAddOp(v, OP_SortReset, 0, 0);}/*** Generate code that will tell the VDBE the datatypes of** columns in the result set.**** This routine only generates code if the "PRAGMA show_datatypes=on"** has been executed. The datatypes are reported out in the azCol** parameter to the callback function. The first N azCol[] entries** are the names of the columns, and the second N entries are the** datatypes for the columns.**** The "datatype" for a result that is a column of a type is the** datatype definition extracted from the CREATE TABLE statement.** The datatype for an expression is either TEXT or NUMERIC. The** datatype for a ROWID field is INTEGER.*/static void generateColumnTypes( Parse *pParse, /* Parser context */ SrcList *pTabList, /* List of tables */ ExprList *pEList /* Expressions defining the result set */){ Vdbe *v = pParse->pVdbe; int i, j; for(i=0; i<pEList->nExpr; i++){ Expr *p = pEList->a[i].pExpr; char *zType = 0; if( p==0 ) continue; if( p->op==TK_COLUMN && pTabList ){ Table *pTab; int iCol = p->iColumn; for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=p->iTable; j++){} assert( j<pTabList->nSrc ); pTab = pTabList->a[j].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; } }else{ if( sqliteExprType(p)==SQLITE_SO_TEXT ){ zType = "TEXT"; }else{ zType = "NUMERIC"; } } sqliteVdbeOp3(v, OP_ColumnName, i + pEList->nExpr, 0, zType, 0); }}/*** Generate code that will tell the VDBE the names of columns** in the result set. This information is used to provide the** azCol[] values in the callback.*/static void generateColumnNames( Parse *pParse, /* Parser context */ SrcList *pTabList, /* List of tables */ ExprList *pEList /* Expressions defining the result set */){ Vdbe *v = pParse->pVdbe; int i, j; sqlite *db = pParse->db; int fullNames, shortNames; assert( v!=0 ); if( pParse->colNamesSet || v==0 || sqlite_malloc_failed ) return; pParse->colNamesSet = 1; fullNames = (db->flags & SQLITE_FullColNames)!=0; shortNames = (db->flags & SQLITE_ShortColNames)!=0; for(i=0; i<pEList->nExpr; i++){ Expr *p; int p2 = i==pEList->nExpr-1; p = pEList->a[i].pExpr; if( p==0 ) continue; if( pEList->a[i].zName ){ char *zName = pEList->a[i].zName; sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, 0); continue; } if( p->op==TK_COLUMN && pTabList ){ Table *pTab; char *zCol; int iCol = p->iColumn; for(j=0; j<pTabList->nSrc && pTabList->a[j].iCursor!=p->iTable; j++){} assert( j<pTabList->nSrc ); pTab = pTabList->a[j].pTab; if( iCol<0 ) iCol = pTab->iPKey; assert( iCol==-1 || (iCol>=0 && iCol<pTab->nCol) ); if( iCol<0 ){ zCol = "_ROWID_"; }else{ zCol = pTab->aCol[iCol].zName; } if( !shortNames && !fullNames && p->span.z && p->span.z[0] ){ int addr = sqliteVdbeOp3(v,OP_ColumnName, i, p2, p->span.z, p->span.n); sqliteVdbeCompressSpace(v, addr); }else if( fullNames || (!shortNames && pTabList->nSrc>1) ){ char *zName = 0; char *zTab; zTab = pTabList->a[j].zAlias; if( fullNames || zTab==0 ) zTab = pTab->zName; sqliteSetString(&zName, zTab, ".", zCol, 0); sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, P3_DYNAMIC); }else{ sqliteVdbeOp3(v, OP_ColumnName, i, p2, zCol, 0); } }else if( p->span.z && p->span.z[0] ){ int addr = sqliteVdbeOp3(v,OP_ColumnName, i, p2, p->span.z, p->span.n); sqliteVdbeCompressSpace(v, addr); }else{ char zName[30]; assert( p->op!=TK_COLUMN || pTabList==0 ); sprintf(zName, "column%d", i+1); sqliteVdbeOp3(v, OP_ColumnName, i, p2, zName, 0); } }}/*** Name of the connection operator, used for error messages.*/static const char *selectOpName(int id){ char *z; switch( id ){ case TK_ALL: z = "UNION ALL"; break; case TK_INTERSECT: z = "INTERSECT"; break; case TK_EXCEPT: z = "EXCEPT"; break; default: z = "UNION"; break; } return z;}/*** Forward declaration*/static int fillInColumnList(Parse*, Select*);/*** Given a SELECT statement, generate a Table structure that describes** the result set of that SELECT.*/Table *sqliteResultSetOfSelect(Parse *pParse, char *zTabName, Select *pSelect){ Table *pTab; int i, j; ExprList *pEList; Column *aCol; if( fillInColumnList(pParse, pSelect) ){ return 0; } pTab = sqliteMalloc( sizeof(Table) ); if( pTab==0 ){
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -