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

📄 select.c

📁 sqlite 嵌入式数据库的源码
💻 C
📖 第 1 页 / 共 5 页
字号:
      if( rc ){        goto multi_select_end;      }      /* Convert the data in the temporary table into whatever form      ** it is that we currently need.      */            if( eDest!=priorOp || unionTab!=iParm ){        int iCont, iBreak, iStart;        assert( p->pEList );        if( eDest==SRT_Callback ){          generateColumnNames(pParse, 0, p->pEList);        }        iBreak = sqlite3VdbeMakeLabel(v);        iCont = sqlite3VdbeMakeLabel(v);        sqlite3VdbeAddOp(v, OP_Rewind, unionTab, iBreak);        computeLimitRegisters(pParse, p);        iStart = sqlite3VdbeCurrentAddr(v);        rc = selectInnerLoop(pParse, p, p->pEList, unionTab, p->pEList->nExpr,                             p->pOrderBy, -1, eDest, iParm,                              iCont, iBreak, 0);        if( rc ){          rc = 1;          goto multi_select_end;        }        sqlite3VdbeResolveLabel(v, iCont);        sqlite3VdbeAddOp(v, OP_Next, unionTab, iStart);        sqlite3VdbeResolveLabel(v, iBreak);        sqlite3VdbeAddOp(v, OP_Close, unionTab, 0);      }      break;    }    case TK_INTERSECT: {      int tab1, tab2;      int iCont, iBreak, iStart;      Expr *pLimit, *pOffset;      int addr;      /* 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++;      if( p->pOrderBy && matchOrderbyToColumn(pParse,p,p->pOrderBy,tab1,1) ){        rc = 1;        goto multi_select_end;      }      addr = sqlite3VdbeAddOp(v, OP_OpenTemp, tab1, 0);      rc = multiSelectOpenTempAddr(p, addr);      if( rc!=SQLITE_OK ){        goto multi_select_end;      }      assert( nAddr<sizeof(aAddr)/sizeof(aAddr[0]) );      aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, tab1, 0);      assert( p->pEList );      /* Code the SELECTs to our left into temporary table "tab1".      */      rc = sqlite3Select(pParse, pPrior, SRT_Union, tab1, 0, 0, 0, aff);      if( rc ){        goto multi_select_end;      }      /* Code the current SELECT into temporary table "tab2"      */      addr = sqlite3VdbeAddOp(v, OP_OpenTemp, tab2, 0);      rc = multiSelectOpenTempAddr(p, addr);      if( rc!=SQLITE_OK ){        goto multi_select_end;      }      assert( nAddr<sizeof(aAddr)/sizeof(aAddr[0]) );      aAddr[nAddr++] = sqlite3VdbeAddOp(v, OP_SetNumColumns, tab2, 0);      p->pPrior = 0;      pLimit = p->pLimit;      p->pLimit = 0;      pOffset = p->pOffset;      p->pOffset = 0;      rc = sqlite3Select(pParse, p, SRT_Union, tab2, 0, 0, 0, aff);      p->pPrior = pPrior;      sqlite3ExprDelete(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( eDest==SRT_Callback ){        generateColumnNames(pParse, 0, p->pEList);      }      iBreak = sqlite3VdbeMakeLabel(v);      iCont = sqlite3VdbeMakeLabel(v);      sqlite3VdbeAddOp(v, OP_Rewind, tab1, iBreak);      computeLimitRegisters(pParse, p);      iStart = sqlite3VdbeAddOp(v, OP_RowKey, tab1, 0);      sqlite3VdbeAddOp(v, OP_NotFound, tab2, iCont);      rc = selectInnerLoop(pParse, p, p->pEList, tab1, p->pEList->nExpr,                             p->pOrderBy, -1, eDest, iParm,                              iCont, iBreak, 0);      if( rc ){        rc = 1;        goto multi_select_end;      }      sqlite3VdbeResolveLabel(v, iCont);      sqlite3VdbeAddOp(v, OP_Next, tab1, iStart);      sqlite3VdbeResolveLabel(v, iBreak);      sqlite3VdbeAddOp(v, OP_Close, tab2, 0);      sqlite3VdbeAddOp(v, OP_Close, tab1, 0);      break;    }  }  /* Make sure all SELECTs in the statement have the same number of elements  ** in their result sets.  */  assert( p->pEList && pPrior->pEList );  if( p->pEList->nExpr!=pPrior->pEList->nExpr ){    sqlite3ErrorMsg(pParse, "SELECTs to the left and right of %s"      " do not have the same number of result columns", selectOpName(p->op));    rc = 1;    goto multi_select_end;  }  /* Set the number of columns in temporary tables  */  nCol = p->pEList->nExpr;  while( nAddr>0 ){    nAddr--;    sqlite3VdbeChangeP2(v, aAddr[nAddr], nCol);  }  /* Compute collating sequences used by either the ORDER BY clause or  ** by any temporary tables needed to implement the compound select.  ** Attach the KeyInfo structure to all temporary tables.  Invoke the  ** ORDER BY processing if there is an ORDER BY clause.  **  ** 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->pOrderBy || (pOpenTemp && pOpenTemp->nId>0) ){    int i;                        /* Loop counter */    KeyInfo *pKeyInfo;            /* Collating sequence for the result set */    assert( p->ppOpenTemp == &pOpenTemp );    pKeyInfo = sqliteMalloc(sizeof(*pKeyInfo)+nCol*sizeof(CollSeq*));    if( !pKeyInfo ){      rc = SQLITE_NOMEM;      goto multi_select_end;    }    pKeyInfo->enc = pParse->db->enc;    pKeyInfo->nField = nCol;    for(i=0; i<nCol; i++){      pKeyInfo->aColl[i] = multiSelectCollSeq(pParse, p, i);      if( !pKeyInfo->aColl[i] ){        pKeyInfo->aColl[i] = pParse->db->pDfltColl;      }    }    for(i=0; pOpenTemp && i<pOpenTemp->nId; i++){      int p3type = (i==0?P3_KEYINFO_HANDOFF:P3_KEYINFO);      int addr = pOpenTemp->a[i].idx;      sqlite3VdbeChangeP3(v, addr, (char *)pKeyInfo, p3type);    }    if( p->pOrderBy ){      struct ExprList_item *pOrderByTerm = p->pOrderBy->a;      for(i=0; i<p->pOrderBy->nExpr; i++, pOrderByTerm++){        Expr *pExpr = pOrderByTerm->pExpr;        char *zName = pOrderByTerm->zName;        assert( pExpr->op==TK_COLUMN && pExpr->iColumn<nCol );        /* assert( !pExpr->pColl ); */        if( zName ){          pExpr->pColl = sqlite3LocateCollSeq(pParse, zName, -1);        }else{          pExpr->pColl = pKeyInfo->aColl[pExpr->iColumn];        }      }      generateSortTail(pParse, p, v, p->pEList->nExpr, eDest, iParm);    }    if( !pOpenTemp ){      /* This happens for UNION ALL ... ORDER BY */      sqliteFree(pKeyInfo);    }  }multi_select_end:  if( pOpenTemp ){    sqlite3IdListDelete(pOpenTemp);  }  p->ppOpenTemp = 0;  return rc;}#endif /* SQLITE_OMIT_COMPOUND_SELECT */#ifndef SQLITE_OMIT_VIEW/*** Scan through the expression pExpr.  Replace every reference to** a column in table number iTable with a copy of the iColumn-th** entry in pEList.  (But leave references to the ROWID column ** unchanged.)**** This routine is part of the flattening procedure.  A subquery** whose result set is defined by pEList appears as entry in the** FROM clause of a SELECT such that the VDBE cursor assigned to that** FORM clause entry is iTable.  This routine make the necessary ** changes to pExpr so that it refers directly to the source table** of the subquery rather the result set of the subquery.*/static void substExprList(ExprList*,int,ExprList*);  /* Forward Decl */static void substSelect(Select *, int, ExprList *);  /* Forward Decl */static void substExpr(Expr *pExpr, int iTable, ExprList *pEList){  if( pExpr==0 ) return;  if( pExpr->op==TK_COLUMN && pExpr->iTable==iTable ){    if( pExpr->iColumn<0 ){      pExpr->op = TK_NULL;    }else{      Expr *pNew;      assert( pEList!=0 && pExpr->iColumn<pEList->nExpr );      assert( pExpr->pLeft==0 && pExpr->pRight==0 && pExpr->pList==0 );      pNew = pEList->a[pExpr->iColumn].pExpr;      assert( pNew!=0 );      pExpr->op = pNew->op;      assert( pExpr->pLeft==0 );      pExpr->pLeft = sqlite3ExprDup(pNew->pLeft);      assert( pExpr->pRight==0 );      pExpr->pRight = sqlite3ExprDup(pNew->pRight);      assert( pExpr->pList==0 );      pExpr->pList = sqlite3ExprListDup(pNew->pList);      pExpr->iTable = pNew->iTable;      pExpr->iColumn = pNew->iColumn;      pExpr->iAgg = pNew->iAgg;      sqlite3TokenCopy(&pExpr->token, &pNew->token);      sqlite3TokenCopy(&pExpr->span, &pNew->span);      pExpr->pSelect = sqlite3SelectDup(pNew->pSelect);      pExpr->flags = pNew->flags;    }  }else{    substExpr(pExpr->pLeft, iTable, pEList);    substExpr(pExpr->pRight, iTable, pEList);    substSelect(pExpr->pSelect, iTable, pEList);    substExprList(pExpr->pList, iTable, pEList);  }}static void substExprList(ExprList *pList, int iTable, ExprList *pEList){  int i;  if( pList==0 ) return;  for(i=0; i<pList->nExpr; i++){    substExpr(pList->a[i].pExpr, iTable, pEList);  }}static void substSelect(Select *p, int iTable, ExprList *pEList){  if( !p ) return;  substExprList(p->pEList, iTable, pEList);  substExprList(p->pGroupBy, iTable, pEList);  substExprList(p->pOrderBy, iTable, pEList);  substExpr(p->pHaving, iTable, pEList);  substExpr(p->pWhere, iTable, pEList);}#endif /* !defined(SQLITE_OMIT_VIEW) */#ifndef SQLITE_OMIT_VIEW/*** This routine attempts to flatten subqueries in order to speed** execution.  It returns 1 if it makes changes and 0 if no flattening** occurs.**** To understand the concept of flattening, consider the following** query:****     SELECT a FROM (SELECT x+y AS a FROM t1 WHERE z<100) WHERE a>5**** The default way of implementing this query is to execute the** subquery first and store the results in a temporary table, then** run the outer query on that temporary table.  This requires two** passes over the data.  Furthermore, because the temporary table** has no indices, the WHERE clause on the outer query cannot be** optimized.**** This routine attempts to rewrite queries such as the above into** a single flat select, like this:****     SELECT x+y AS a FROM t1 WHERE z<100 AND a>5**** The code generated for this simpification gives the same result** but only has to scan the data once.  And because indices might ** exist on the table t1, a complete scan of the data might be** avoided.**** Flattening is only attempted if all of the following are true:****   (1)  The subquery and the outer query do not both use aggregates.****   (2)  The subquery is not an aggregate or the outer query is not a join.****   (3)  The subquery is not the right operand of a left outer join, or**        the subquery is not itself a join.  (Ticket #306)****   (4)  The subquery is not DISTINCT or the outer query is not a join.****   (5)  The subquery is not DISTINCT or the outer query does not use**        aggregates.****   (6)  The subquery does not use aggregates or the outer query is not**        DISTINCT.****   (7)  The subquery has a FROM clause.****   (8)  The subquery does not use LIMIT or the outer query is not a join.****   (9)  The subquery does not use LIMIT or the outer query does not use**        aggregates.****  (10)  The subquery does not use aggregates or the outer query does not**        use LIMIT.****  (11)  The subquery and the outer query do not both have ORDER BY clauses.****  (12)  The subquery is not the right term of a LEFT OUTER JOIN or the**        subquery has no WHERE clause.  (added by ticket #350)**** In this routine, the "p" parameter is a pointer to the outer query.** The subquery is p->pSrc->a[iFrom].  isAgg is true if the outer query** uses aggregates and subqueryIsAgg is true if the subquery uses aggregates.**** If flattening is not attempted, this routine is a no-op and returns 0.** If flattening is attempted this routine returns 1.**** All of the expression analysis must occur on both the outer query and** the subquery before this routine runs.*/static int flattenSubquery(  Parse *pParse,       /* The parsing context */  Select *p,           /* The parent or outer SELECT statement */  int iFrom,           /* Index in p->pSrc->a[] of the inner subquery */  int isAgg,           /* True if outer SELECT uses aggregate functions */  int subqueryIsAgg    /* True if the subquery uses aggregate functions */){  Select *pSub;       /* The inner query or "subquery" */  SrcList *pSrc;      /* The FROM clause of the outer query */  SrcList *pSubSrc;   /* The FROM clause of the subquery */  ExprList *pList;    /* The result set of the outer query */  int iParent;        /* VDBE cursor number of the pSub result set temp table */  int i;              /* Loop counter */  Expr *pWhere;                    /* The WHERE clause */  struct SrcList_item *pSubitem;   /* The subquery */  /* Check to see if flattening is permitted.  Return 0 if not.  */  if( p==0 ) return 0;  pSrc = p->pSrc;  assert( pSrc && iFrom>=0 && iFrom<pSrc->nSrc );  pSubitem = &pSrc->a[iFrom];  pSub = pSubitem->pSelect;  assert( pSub!=0 );  if( isAgg && subqueryIsAgg ) return 0;  if( subqueryIsAgg && pSrc->nSrc>1 ) return 0;  pSubSrc = pSub->pSrc;  assert( pSubSrc );  if( (pSub->pLimit && p->pLimit) || pSub->pOffset ||       (pSub->pLimit && isAgg) ) return 0;  if( pSubSrc->nSrc==0 ) return 0;  if( pSub->isDistinct && (pSrc->nSrc>1 || isAgg) ){     return 0;  }  if( p->isDistinct && subqueryIsAgg ) return 0;  if( p->pOrderBy && pSub->pOrderBy ) return 0;  /* Restriction 3:  If the subquery is a join, make sure the subquery is   ** not used as the right operand of an outer join.  Examples of why this  ** is not allowed:  **  **         t1 LEFT OUTER JOIN (t2 JOIN t3)  **  ** If we flatten the above, we would get  **  **         (t1 LEFT OUTER JOIN t2) JOIN t3  **  ** which is not at all the same thing.  */  if( pSubSrc->nSrc>1 && iFrom>0 && (pSrc->a[iFrom-1].jointype & JT_OUTER)!=0 ){    return 0;  }  /* Restriction 1

⌨️ 快捷键说明

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