code: /*
  ** 2018-04-12
  **
  ** The author disclaims copyright to this source code.  In place of
  ** a legal notice, here is a blessing:
  **
  **    May you do good and not evil.
  **    May you find forgiveness for yourself and forgive others.
  **    May you share freely, never taking more than you give.
  **
  *************************************************************************
  ** This file contains code to implement various aspects of UPSERT
  ** processing and handling of the Upsert object.
  */
  #include "sqliteInt.h"
  
  #ifndef SQLITE_OMIT_UPSERT
  /*
  ** Free a list of Upsert objects
  */
  static void SQLITE_NOINLINE upsertDelete(sqlite3 *db, Upsert *p){
    do{
      Upsert *pNext = p->pNextUpsert;
      sqlite3ExprListDelete(db, p->pUpsertTarget);
      sqlite3ExprDelete(db, p->pUpsertTargetWhere);
      sqlite3ExprListDelete(db, p->pUpsertSet);
      sqlite3ExprDelete(db, p->pUpsertWhere);
      sqlite3DbFree(db, p->pToFree);
      sqlite3DbFree(db, p);
      p = pNext;
    }while( p );
  }
  void sqlite3UpsertDelete(sqlite3 *db, Upsert *p){
    if( p ) upsertDelete(db, p);
  }
  
  
  /*
  ** Duplicate an Upsert object.
  */
  Upsert *sqlite3UpsertDup(sqlite3 *db, Upsert *p){
    if( p==0 ) return 0;
    return sqlite3UpsertNew(db,
             sqlite3ExprListDup(db, p->pUpsertTarget, 0),
             sqlite3ExprDup(db, p->pUpsertTargetWhere, 0),
             sqlite3ExprListDup(db, p->pUpsertSet, 0),
             sqlite3ExprDup(db, p->pUpsertWhere, 0),
             sqlite3UpsertDup(db, p->pNextUpsert)
           );
  }
  
  /*
  ** Create a new Upsert object.
  */
  Upsert *sqlite3UpsertNew(
    sqlite3 *db,           /* Determines which memory allocator to use */
    ExprList *pTarget,     /* Target argument to ON CONFLICT, or NULL */
    Expr *pTargetWhere,    /* Optional WHERE clause on the target */
    ExprList *pSet,        /* UPDATE columns, or NULL for a DO NOTHING */
    Expr *pWhere,          /* WHERE clause for the ON CONFLICT UPDATE */
    Upsert *pNext          /* Next ON CONFLICT clause in the list */
  ){
    Upsert *pNew;
    pNew = sqlite3DbMallocZero(db, sizeof(Upsert));
    if( pNew==0 ){
      sqlite3ExprListDelete(db, pTarget);
      sqlite3ExprDelete(db, pTargetWhere);
      sqlite3ExprListDelete(db, pSet);
      sqlite3ExprDelete(db, pWhere);
      sqlite3UpsertDelete(db, pNext);
      return 0;
    }else{
      pNew->pUpsertTarget = pTarget;
      pNew->pUpsertTargetWhere = pTargetWhere;
      pNew->pUpsertSet = pSet;
      pNew->pUpsertWhere = pWhere;
      pNew->isDoUpdate = pSet!=0;
      pNew->pNextUpsert = pNext;
    }
    return pNew;
  }
  
  /*
  ** Analyze the ON CONFLICT clause described by pUpsert.  Resolve all
  ** symbols in the conflict-target.
  **
  ** Return SQLITE_OK if everything works, or an error code is something
  ** is wrong.
  */
  int sqlite3UpsertAnalyzeTarget(
    Parse *pParse,     /* The parsing context */
    SrcList *pTabList, /* Table into which we are inserting */
    Upsert *pUpsert    /* The ON CONFLICT clauses */
  ){
    Table *pTab;            /* That table into which we are inserting */
    int rc;                 /* Result code */
    int iCursor;            /* Cursor used by pTab */
    Index *pIdx;            /* One of the indexes of pTab */
    ExprList *pTarget;      /* The conflict-target clause */
    Expr *pTerm;            /* One term of the conflict-target clause */
    NameContext sNC;        /* Context for resolving symbolic names */
    Expr sCol[2];           /* Index column converted into an Expr */
    int nClause = 0;        /* Counter of ON CONFLICT clauses */
  
    assert( pTabList->nSrc==1 );
    assert( pTabList->a[0].pTab!=0 );
    assert( pUpsert!=0 );
    assert( pUpsert->pUpsertTarget!=0 );
  
    /* Resolve all symbolic names in the conflict-target clause, which
    ** includes both the list of columns and the optional partial-index
    ** WHERE clause.
    */
    memset(&sNC, 0, sizeof(sNC));
    sNC.pParse = pParse;
    sNC.pSrcList = pTabList;
    for(; pUpsert && pUpsert->pUpsertTarget;
          pUpsert=pUpsert->pNextUpsert, nClause++){
      rc = sqlite3ResolveExprListNames(&sNC, pUpsert->pUpsertTarget);
      if( rc ) return rc;
      rc = sqlite3ResolveExprNames(&sNC, pUpsert->pUpsertTargetWhere);
      if( rc ) return rc;
    
      /* Check to see if the conflict target matches the rowid. */  
      pTab = pTabList->a[0].pTab;
      pTarget = pUpsert->pUpsertTarget;
      iCursor = pTabList->a[0].iCursor;
      if( HasRowid(pTab) 
       && pTarget->nExpr==1
       && (pTerm = pTarget->a[0].pExpr)->op==TK_COLUMN
       && pTerm->iColumn==XN_ROWID
      ){
        /* The conflict-target is the rowid of the primary table */
        assert( pUpsert->pUpsertIdx==0 );
        continue;
      }
    
      /* Initialize sCol[0..1] to be an expression parse tree for a
      ** single column of an index.  The sCol[0] node will be the TK_COLLATE
      ** operator and sCol[1] will be the TK_COLUMN operator.  Code below
      ** will populate the specific collation and column number values
      ** prior to comparing against the conflict-target expression.
      */
      memset(sCol, 0, sizeof(sCol));
      sCol[0].op = TK_COLLATE;
      sCol[0].pLeft = &sCol[1];
      sCol[1].op = TK_COLUMN;
      sCol[1].iTable = pTabList->a[0].iCursor;
    
      /* Check for matches against other indexes */
      for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
        int ii, jj, nn;
        if( !IsUniqueIndex(pIdx) ) continue;
        if( pTarget->nExpr!=pIdx->nKeyCol ) continue;
        if( pIdx->pPartIdxWhere ){
          if( pUpsert->pUpsertTargetWhere==0 ) continue;
          if( sqlite3ExprCompare(pParse, pUpsert->pUpsertTargetWhere,
                                 pIdx->pPartIdxWhere, iCursor)!=0 ){
            continue;
          }
        }
        nn = pIdx->nKeyCol;
        for(ii=0; ii<nn; ii++){
          Expr *pExpr;
          sCol[0].u.zToken = (char*)pIdx->azColl[ii];
          if( pIdx->aiColumn[ii]==XN_EXPR ){
            assert( pIdx->aColExpr!=0 );
            assert( pIdx->aColExpr->nExpr>ii );
            pExpr = pIdx->aColExpr->a[ii].pExpr;
            if( pExpr->op!=TK_COLLATE ){
              sCol[0].pLeft = pExpr;
              pExpr = &sCol[0];
            }
          }else{
            sCol[0].pLeft = &sCol[1];
            sCol[1].iColumn = pIdx->aiColumn[ii];
            pExpr = &sCol[0];
          }
          for(jj=0; jj<nn; jj++){
            if( sqlite3ExprCompare(pParse,pTarget->a[jj].pExpr,pExpr,iCursor)<2 ){
              break;  /* Column ii of the index matches column jj of target */
            }
          }
          if( jj>=nn ){
            /* The target contains no match for column jj of the index */
            break;
          }
        }
        if( ii<nn ){
          /* Column ii of the index did not match any term of the conflict target.
          ** Continue the search with the next index. */
          continue;
        }
        pUpsert->pUpsertIdx = pIdx;
        break;
      }
      if( pUpsert->pUpsertIdx==0 ){
        char zWhich[16];
        if( nClause==0 && pUpsert->pNextUpsert==0 ){
          zWhich[0] = 0;
        }else{
          sqlite3_snprintf(sizeof(zWhich),zWhich,"%r ", nClause+1);
        }
        sqlite3ErrorMsg(pParse, "%sON CONFLICT clause does not match any "
                                "PRIMARY KEY or UNIQUE constraint", zWhich);
        return SQLITE_ERROR;
      }
    }
    return SQLITE_OK;
  }
  
  /*
  ** Return true if pUpsert is the last ON CONFLICT clause with a
  ** conflict target, or if pUpsert is followed by another ON CONFLICT
  ** clause that targets the INTEGER PRIMARY KEY.
  */
  int sqlite3UpsertNextIsIPK(Upsert *pUpsert){
    Upsert *pNext;
    if( NEVER(pUpsert==0) ) return 0;
    pNext = pUpsert->pNextUpsert;
    if( pNext==0 ) return 1;
    if( pNext->pUpsertTarget==0 ) return 1;
    if( pNext->pUpsertIdx==0 ) return 1;
    return 0;
  }
  
  /*
  ** Given the list of ON CONFLICT clauses described by pUpsert, and
  ** a particular index pIdx, return a pointer to the particular ON CONFLICT
  ** clause that applies to the index.  Or, if the index is not subject to
  ** any ON CONFLICT clause, return NULL.
  */
  Upsert *sqlite3UpsertOfIndex(Upsert *pUpsert, Index *pIdx){
    while(
        pUpsert
     && pUpsert->pUpsertTarget!=0
     && pUpsert->pUpsertIdx!=pIdx
    ){
       pUpsert = pUpsert->pNextUpsert;
    }
    return pUpsert;
  }
  
  /*
  ** Generate bytecode that does an UPDATE as part of an upsert.
  **
  ** If pIdx is NULL, then the UNIQUE constraint that failed was the IPK.
  ** In this case parameter iCur is a cursor open on the table b-tree that
  ** currently points to the conflicting table row. Otherwise, if pIdx
  ** is not NULL, then pIdx is the constraint that failed and iCur is a
  ** cursor points to the conflicting row.
  */
  void sqlite3UpsertDoUpdate(
    Parse *pParse,        /* The parsing and code-generating context */
    Upsert *pUpsert,      /* The ON CONFLICT clause for the upsert */
    Table *pTab,          /* The table being updated */
    Index *pIdx,          /* The UNIQUE constraint that failed */
    int iCur              /* Cursor for pIdx (or pTab if pIdx==NULL) */
  ){
    Vdbe *v = pParse->pVdbe;
    sqlite3 *db = pParse->db;
    SrcList *pSrc;            /* FROM clause for the UPDATE */
    int iDataCur;
    int i;
    Upsert *pTop = pUpsert;
  
    assert( v!=0 );
    assert( pUpsert!=0 );
    iDataCur = pUpsert->iDataCur;
    pUpsert = sqlite3UpsertOfIndex(pTop, pIdx);
    VdbeNoopComment((v, "Begin DO UPDATE of UPSERT"));
    if( pIdx && iCur!=iDataCur ){
      if( HasRowid(pTab) ){
        int regRowid = sqlite3GetTempReg(pParse);
        sqlite3VdbeAddOp2(v, OP_IdxRowid, iCur, regRowid);
        sqlite3VdbeAddOp3(v, OP_SeekRowid, iDataCur, 0, regRowid);
        VdbeCoverage(v);
        sqlite3ReleaseTempReg(pParse, regRowid);
      }else{
        Index *pPk = sqlite3PrimaryKeyIndex(pTab);
        int nPk = pPk->nKeyCol;
        int iPk = pParse->nMem+1;
        pParse->nMem += nPk;
        for(i=0; i<nPk; i++){
          int k;
          assert( pPk->aiColumn[i]>=0 );
          k = sqlite3TableColumnToIndex(pIdx, pPk->aiColumn[i]);
          sqlite3VdbeAddOp3(v, OP_Column, iCur, k, iPk+i);
          VdbeComment((v, "%s.%s", pIdx->zName,
                      pTab->aCol[pPk->aiColumn[i]].zName));
        }
        sqlite3VdbeVerifyAbortable(v, OE_Abort);
        i = sqlite3VdbeAddOp4Int(v, OP_Found, iDataCur, 0, iPk, nPk);
        VdbeCoverage(v);
        sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CORRUPT, OE_Abort, 0, 
              "corrupt database", P4_STATIC);
        sqlite3MayAbort(pParse);
        sqlite3VdbeJumpHere(v, i);
      }
    }
    /* pUpsert does not own pTop->pUpsertSrc - the outer INSERT statement does.
    ** So we have to make a copy before passing it down into sqlite3Update() */
    pSrc = sqlite3SrcListDup(db, pTop->pUpsertSrc, 0);
    /* excluded.* columns of type REAL need to be converted to a hard real */
    for(i=0; i<pTab->nCol; i++){
      if( pTab->aCol[i].affinity==SQLITE_AFF_REAL ){
        sqlite3VdbeAddOp1(v, OP_RealAffinity, pTop->regData+i);
      }
    }
    sqlite3Update(pParse, pSrc, sqlite3ExprListDup(db,pUpsert->pUpsertSet,0),
        sqlite3ExprDup(db,pUpsert->pUpsertWhere,0), OE_Abort, 0, 0, pUpsert);
    VdbeNoopComment((v, "End DO UPDATE of UPSERT"));
  }
  
  #endif /* SQLITE_OMIT_UPSERT */
  