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

📄 expr.c

📁 sqlite的最新源码 This ZIP archive contains preprocessed C code for the SQLite library as individual sour
💻 C
📖 第 1 页 / 共 5 页
字号:
      }    }  }  if( eType==0 ){    int rMayHaveNull = 0;    eType = IN_INDEX_EPH;    if( prNotFound ){      *prNotFound = rMayHaveNull = ++pParse->nMem;    }else if( pX->pLeft->iColumn<0 && pX->pSelect==0 ){      eType = IN_INDEX_ROWID;    }    sqlite3CodeSubselect(pParse, pX, rMayHaveNull, eType==IN_INDEX_ROWID);  }else{    pX->iTable = iTab;  }  return eType;}#endif/*** Generate code for scalar subqueries used as an expression** and IN operators.  Examples:****     (SELECT a FROM b)          -- subquery**     EXISTS (SELECT a FROM b)   -- EXISTS subquery**     x IN (4,5,11)              -- IN operator with list on right-hand side**     x IN (SELECT a FROM b)     -- IN operator with subquery on the right**** The pExpr parameter describes the expression that contains the IN** operator or subquery.**** If parameter isRowid is non-zero, then expression pExpr is guaranteed** to be of the form "<rowid> IN (?, ?, ?)", where <rowid> is a reference** to some integer key column of a table B-Tree. In this case, use an** intkey B-Tree to store the set of IN(...) values instead of the usual** (slower) variable length keys B-Tree.*/#ifndef SQLITE_OMIT_SUBQUERYvoid sqlite3CodeSubselect(  Parse *pParse,   Expr *pExpr,   int rMayHaveNull,  int isRowid){  int testAddr = 0;                       /* One-time test address */  Vdbe *v = sqlite3GetVdbe(pParse);  if( v==0 ) return;  /* This code must be run in its entirety every time it is encountered  ** if any of the following is true:  **  **    *  The right-hand side is a correlated subquery  **    *  The right-hand side is an expression list containing variables  **    *  We are inside a trigger  **  ** If all of the above are false, then we can run this code just once  ** save the results, and reuse the same result on subsequent invocations.  */  if( !ExprHasAnyProperty(pExpr, EP_VarSelect) && !pParse->trigStack ){    int mem = ++pParse->nMem;    sqlite3VdbeAddOp1(v, OP_If, mem);    testAddr = sqlite3VdbeAddOp2(v, OP_Integer, 1, mem);    assert( testAddr>0 || pParse->db->mallocFailed );  }  switch( pExpr->op ){    case TK_IN: {      char affinity;      KeyInfo keyInfo;      int addr;        /* Address of OP_OpenEphemeral instruction */      Expr *pLeft = pExpr->pLeft;      if( rMayHaveNull ){        sqlite3VdbeAddOp2(v, OP_Null, 0, rMayHaveNull);      }      affinity = sqlite3ExprAffinity(pLeft);      /* Whether this is an 'x IN(SELECT...)' or an 'x IN(<exprlist>)'      ** expression it is handled the same way. A virtual table is       ** filled with single-field index keys representing the results      ** from the SELECT or the <exprlist>.      **      ** If the 'x' expression is a column value, or the SELECT...      ** statement returns a column value, then the affinity of that      ** column is used to build the index keys. If both 'x' and the      ** SELECT... statement are columns, then numeric affinity is used      ** if either column has NUMERIC or INTEGER affinity. If neither      ** 'x' nor the SELECT... statement are columns, then numeric affinity      ** is used.      */      pExpr->iTable = pParse->nTab++;      addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, pExpr->iTable, !isRowid);      memset(&keyInfo, 0, sizeof(keyInfo));      keyInfo.nField = 1;      if( pExpr->pSelect ){        /* Case 1:     expr IN (SELECT ...)        **        ** Generate code to write the results of the select into the temporary        ** table allocated and opened above.        */        SelectDest dest;        ExprList *pEList;        assert( !isRowid );        sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable);        dest.affinity = (int)affinity;        assert( (pExpr->iTable&0x0000FFFF)==pExpr->iTable );        if( sqlite3Select(pParse, pExpr->pSelect, &dest) ){          return;        }        pEList = pExpr->pSelect->pEList;        if( pEList && pEList->nExpr>0 ){           keyInfo.aColl[0] = sqlite3BinaryCompareCollSeq(pParse, pExpr->pLeft,              pEList->a[0].pExpr);        }      }else if( pExpr->pList ){        /* Case 2:     expr IN (exprlist)        **        ** For each expression, build an index key from the evaluation and        ** store it in the temporary table. If <expr> is a column, then use        ** that columns affinity when building index keys. If <expr> is not        ** a column, use numeric affinity.        */        int i;        ExprList *pList = pExpr->pList;        struct ExprList_item *pItem;        int r1, r2, r3;        if( !affinity ){          affinity = SQLITE_AFF_NONE;        }        keyInfo.aColl[0] = sqlite3ExprCollSeq(pParse, pExpr->pLeft);        /* Loop through each expression in <exprlist>. */        r1 = sqlite3GetTempReg(pParse);        r2 = sqlite3GetTempReg(pParse);        sqlite3VdbeAddOp2(v, OP_Null, 0, r2);        for(i=pList->nExpr, pItem=pList->a; i>0; i--, pItem++){          Expr *pE2 = pItem->pExpr;          /* If the expression is not constant then we will need to          ** disable the test that was generated above that makes sure          ** this code only executes once.  Because for a non-constant          ** expression we need to rerun this code each time.          */          if( testAddr && !sqlite3ExprIsConstant(pE2) ){            sqlite3VdbeChangeToNoop(v, testAddr-1, 2);            testAddr = 0;          }          /* Evaluate the expression and insert it into the temp table */          pParse->disableColCache++;          r3 = sqlite3ExprCodeTarget(pParse, pE2, r1);          assert( pParse->disableColCache>0 );          pParse->disableColCache--;          if( isRowid ){            sqlite3VdbeAddOp2(v, OP_MustBeInt, r3, sqlite3VdbeCurrentAddr(v)+2);            sqlite3VdbeAddOp3(v, OP_Insert, pExpr->iTable, r2, r3);          }else{            sqlite3VdbeAddOp4(v, OP_MakeRecord, r3, 1, r2, &affinity, 1);            sqlite3ExprCacheAffinityChange(pParse, r3, 1);            sqlite3VdbeAddOp2(v, OP_IdxInsert, pExpr->iTable, r2);          }        }        sqlite3ReleaseTempReg(pParse, r1);        sqlite3ReleaseTempReg(pParse, r2);      }      if( !isRowid ){        sqlite3VdbeChangeP4(v, addr, (void *)&keyInfo, P4_KEYINFO);      }      break;    }    case TK_EXISTS:    case TK_SELECT: {      /* This has to be a scalar SELECT.  Generate code to put the      ** value of this select in a memory cell and record the number      ** of the memory cell in iColumn.      */      static const Token one = { (u8*)"1", 0, 1 };      Select *pSel;      SelectDest dest;      pSel = pExpr->pSelect;      sqlite3SelectDestInit(&dest, 0, ++pParse->nMem);      if( pExpr->op==TK_SELECT ){        dest.eDest = SRT_Mem;        sqlite3VdbeAddOp2(v, OP_Null, 0, dest.iParm);        VdbeComment((v, "Init subquery result"));      }else{        dest.eDest = SRT_Exists;        sqlite3VdbeAddOp2(v, OP_Integer, 0, dest.iParm);        VdbeComment((v, "Init EXISTS result"));      }      sqlite3ExprDelete(pParse->db, pSel->pLimit);      pSel->pLimit = sqlite3PExpr(pParse, TK_INTEGER, 0, 0, &one);      if( sqlite3Select(pParse, pSel, &dest) ){        return;      }      pExpr->iColumn = dest.iParm;      break;    }  }  if( testAddr ){    sqlite3VdbeJumpHere(v, testAddr-1);  }  return;}#endif /* SQLITE_OMIT_SUBQUERY *//*** Duplicate an 8-byte value*/static char *dup8bytes(Vdbe *v, const char *in){  char *out = sqlite3DbMallocRaw(sqlite3VdbeDb(v), 8);  if( out ){    memcpy(out, in, 8);  }  return out;}/*** Generate an instruction that will put the floating point** value described by z[0..n-1] into register iMem.**** The z[] string will probably not be zero-terminated.  But the ** z[n] character is guaranteed to be something that does not look** like the continuation of the number.*/static void codeReal(Vdbe *v, const char *z, int n, int negateFlag, int iMem){  assert( z || v==0 || sqlite3VdbeDb(v)->mallocFailed );  assert( !z || !isdigit(z[n]) );  UNUSED_PARAMETER(n);  if( z ){    double value;    char *zV;    sqlite3AtoF(z, &value);    if( sqlite3IsNaN(value) ){      sqlite3VdbeAddOp2(v, OP_Null, 0, iMem);    }else{      if( negateFlag ) value = -value;      zV = dup8bytes(v, (char*)&value);      sqlite3VdbeAddOp4(v, OP_Real, 0, iMem, 0, zV, P4_REAL);    }  }}/*** Generate an instruction that will put the integer describe by** text z[0..n-1] into register iMem.**** The z[] string will probably not be zero-terminated.  But the ** z[n] character is guaranteed to be something that does not look** like the continuation of the number.*/static void codeInteger(Vdbe *v, Expr *pExpr, int negFlag, int iMem){  const char *z;  if( pExpr->flags & EP_IntValue ){    int i = pExpr->iTable;    if( negFlag ) i = -i;    sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);  }else if( (z = (char*)pExpr->token.z)!=0 ){    int i;    int n = pExpr->token.n;    assert( !isdigit(z[n]) );    if( sqlite3GetInt32(z, &i) ){      if( negFlag ) i = -i;      sqlite3VdbeAddOp2(v, OP_Integer, i, iMem);    }else if( sqlite3FitsIn64Bits(z, negFlag) ){      i64 value;      char *zV;      sqlite3Atoi64(z, &value);      if( negFlag ) value = -value;      zV = dup8bytes(v, (char*)&value);      sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);    }else{      codeReal(v, z, n, negFlag, iMem);    }  }}/*** Generate code that will extract the iColumn-th column from** table pTab and store the column value in a register.  An effort** is made to store the column value in register iReg, but this is** not guaranteed.  The location of the column value is returned.**** There must be an open cursor to pTab in iTable when this routine** is called.  If iColumn<0 then code is generated that extracts the rowid.**** This routine might attempt to reuse the value of the column that** has already been loaded into a register.  The value will always** be used if it has not undergone any affinity changes.  But if** an affinity change has occurred, then the cached value will only be** used if allowAffChng is true.*/int sqlite3ExprCodeGetColumn(  Parse *pParse,   /* Parsing and code generating context */  Table *pTab,     /* Description of the table we are reading from */  int iColumn,     /* Index of the table column */  int iTable,      /* The cursor pointing to the table */  int iReg,        /* Store results here */  int allowAffChng /* True if prior affinity changes are OK */){  Vdbe *v = pParse->pVdbe;  int i;  struct yColCache *p;  for(i=0, p=pParse->aColCache; i<pParse->nColCache; i++, p++){    if( p->iTable==iTable && p->iColumn==iColumn           && (!p->affChange || allowAffChng) ){#if 0      sqlite3VdbeAddOp0(v, OP_Noop);      VdbeComment((v, "OPT: tab%d.col%d -> r%d", iTable, iColumn, p->iReg));#endif      return p->iReg;    }  }    assert( v!=0 );  if( iColumn<0 ){    int op = (pTab && IsVirtual(pTab)) ? OP_VRowid : OP_Rowid;    sqlite3VdbeAddOp2(v, op, iTable, iReg);  }else if( pTab==0 ){    sqlite3VdbeAddOp3(v, OP_Column, iTable, iColumn, iReg);  }else{    int op = IsVirtual(pTab) ? OP_VColumn : OP_Column;    sqlite3VdbeAddOp3(v, op, iTable, iColumn, iReg);    sqlite3ColumnDefault(v, pTab, iColumn);#ifndef SQLITE_OMIT_FLOATING_POINT    if( pTab->aCol[iColumn].affinity==SQLITE_AFF_REAL ){      sqlite3VdbeAddOp1(v, OP_RealAffinity, iReg);    }#endif  }  if( pParse->disableColCache==0 ){    i = pParse->iColCache;    p = &pParse->aColCache[i];    p->iTable = iTable;    p->iColumn = iColumn;    p->iReg = iReg;    p->affChange = 0;    i++;    if( i>=ArraySize(pParse->aColCache) ) i = 0;    if( i>pParse->nColCache ) pParse->nColCache = i;    pParse->iColCache = i;  }  return iReg;}/*** Clear all column cache entries associated with the vdbe** cursor with cursor number iTable.*/void sqlite3ExprClearColumnCache(Parse *pParse, int iTable){  if( iTable<0 ){    pParse->nColCache = 0;    pParse->iColCache = 0;  }else{    int i;    for(i=0; i<pParse->nColCache; i++){      if( pParse->aColCache[i].iTable==iTable ){        testcase( i==pParse->nColCache-1 );        pParse->aColCache[i] = pParse->aColCache[--pParse->nColCache];        pParse->iColCache = pParse->nColCache;      }    }  }}/*** Record the fact that an affinity change has occurred on iCount** registers starting with iStart.*/void sqlite3ExprCacheAffinityChange(Parse *pParse, int iStart, int iCount){  int iEnd = iStart + iCount - 1;  int i;  for(i=0; i<pParse->nColCache; i++){    int r = pParse->aColCache[i].iReg;    if( r>=iStart && r<=iEnd ){      pParse->aColCache[i].affChange = 1;    }  }}/*** Generate code to move content from registers iFrom...iFrom+nReg-1** over to iTo..iTo+nReg-1. Keep the column cache up-to-date.*/void sqlite3ExprCodeMove(Parse *pParse, int iFrom, int iTo, int nReg){  int i;  if( iFrom==iTo ) return;  sqlite3VdbeAddOp3(pParse->pVdbe, OP_Move, iFrom, iTo, nReg);  for(i=0; i<pParse->nColCache; i++){    int x = pParse->aColCache[i].iReg;    if( x>=iFrom && x<iFrom+nReg ){      pParse->aColCache[i].iReg += iTo-iFrom;    }  }}

⌨️ 快捷键说明

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