⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 select.c

📁 sqlite数据库管理系统开放源码
💻 C
📖 第 1 页 / 共 5 页
字号:
**** 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 */){  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++){      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( hasDistinct ){#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);    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.    */    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);  codeLimiter(v, p, addr, end2, 1);  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.*/

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -