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

📄 vdbeaux.c

📁 sqlite 嵌入式数据库的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
** This routine will automatically close any cursors, lists, and/or** sorters that were left open.  It also deletes the values of** variables in the aVar[] array.*/static void Cleanup(Vdbe *p){  int i;  if( p->aStack ){    releaseMemArray(p->aStack, 1 + (p->pTos - p->aStack));    p->pTos = &p->aStack[-1];  }  closeAllCursors(p);  releaseMemArray(p->aMem, p->nMem);  if( p->pList ){    sqlite3VdbeKeylistFree(p->pList);    p->pList = 0;  }  if( p->contextStack ){    for(i=0; i<p->contextStackTop; i++){      sqlite3VdbeKeylistFree(p->contextStack[i].pList);    }    sqliteFree(p->contextStack);  }  sqlite3VdbeSorterReset(p);  for(i=0; i<p->nAgg; i++){    sqlite3VdbeAggReset(0, &p->apAgg[i], 0);  }  p->contextStack = 0;  p->contextStackDepth = 0;  p->contextStackTop = 0;  sqliteFree(p->zErrMsg);  p->zErrMsg = 0;}/*** Set the number of result columns that will be returned by this SQL** statement. This is now set at compile time, rather than during** execution of the vdbe program so that sqlite3_column_count() can** be called on an SQL statement before sqlite3_step().*/void sqlite3VdbeSetNumCols(Vdbe *p, int nResColumn){  Mem *pColName;  int n;  assert( 0==p->nResColumn );  p->nResColumn = nResColumn;  n = nResColumn*2;  p->aColName = pColName = (Mem*)sqliteMalloc( sizeof(Mem)*n );  if( p->aColName==0 ) return;  while( n-- > 0 ){    (pColName++)->flags = MEM_Null;  }}/*** Set the name of the idx'th column to be returned by the SQL statement.** zName must be a pointer to a nul terminated string.**** This call must be made after a call to sqlite3VdbeSetNumCols().**** If N==P3_STATIC  it means that zName is a pointer to a constant static** string and we can just copy the pointer. If it is P3_DYNAMIC, then ** the string is freed using sqliteFree() when the vdbe is finished with** it. Otherwise, N bytes of zName are copied.*/int sqlite3VdbeSetColName(Vdbe *p, int idx, const char *zName, int N){  int rc;  Mem *pColName;  assert( idx<(2*p->nResColumn) );  if( sqlite3_malloc_failed ) return SQLITE_NOMEM;  assert( p->aColName!=0 );  pColName = &(p->aColName[idx]);  if( N==P3_DYNAMIC || N==P3_STATIC ){    rc = sqlite3VdbeMemSetStr(pColName, zName, -1, SQLITE_UTF8, SQLITE_STATIC);  }else{    rc = sqlite3VdbeMemSetStr(pColName, zName, N, SQLITE_UTF8,SQLITE_TRANSIENT);  }  if( rc==SQLITE_OK && N==P3_DYNAMIC ){    pColName->flags = (pColName->flags&(~MEM_Static))|MEM_Dyn;    pColName->xDel = 0;  }  return rc;}/*** A read or write transaction may or may not be active on database handle** db. If a transaction is active, commit it. If there is a** write-transaction spanning more than one database file, this routine** takes care of the master journal trickery.*/static int vdbeCommit(sqlite3 *db){  int i;  int nTrans = 0;  /* Number of databases with an active write-transaction */  int rc = SQLITE_OK;  int needXcommit = 0;  for(i=0; i<db->nDb; i++){     Btree *pBt = db->aDb[i].pBt;    if( pBt && sqlite3BtreeIsInTrans(pBt) ){      needXcommit = 1;      if( i!=1 ) nTrans++;    }  }  /* If there are any write-transactions at all, invoke the commit hook */  if( needXcommit && db->xCommitCallback ){    int rc;    sqlite3SafetyOff(db);    rc = db->xCommitCallback(db->pCommitArg);    sqlite3SafetyOn(db);    if( rc ){      return SQLITE_CONSTRAINT;    }  }  /* The simple case - no more than one database file (not counting the  ** TEMP database) has a transaction active.   There is no need for the  ** master-journal.  **  ** If the return value of sqlite3BtreeGetFilename() is a zero length  ** string, it means the main database is :memory:.  In that case we do  ** not support atomic multi-file commits, so use the simple case then  ** too.  */  if( 0==strlen(sqlite3BtreeGetFilename(db->aDb[0].pBt)) || nTrans<=1 ){    for(i=0; rc==SQLITE_OK && i<db->nDb; i++){       Btree *pBt = db->aDb[i].pBt;      if( pBt ){        rc = sqlite3BtreeSync(pBt, 0);      }    }    /* Do the commit only if all databases successfully synced */    if( rc==SQLITE_OK ){      for(i=0; i<db->nDb; i++){        Btree *pBt = db->aDb[i].pBt;        if( pBt ){          sqlite3BtreeCommit(pBt);        }      }    }  }  /* The complex case - There is a multi-file write-transaction active.  ** This requires a master journal file to ensure the transaction is  ** committed atomicly.  */#ifndef SQLITE_OMIT_DISKIO  else{    char *zMaster = 0;   /* File-name for the master journal */    char const *zMainFile = sqlite3BtreeGetFilename(db->aDb[0].pBt);    OsFile master;    /* Select a master journal file name */    do {      u32 random;      sqliteFree(zMaster);      sqlite3Randomness(sizeof(random), &random);      zMaster = sqlite3MPrintf("%s-mj%08X", zMainFile, random&0x7fffffff);      if( !zMaster ){        return SQLITE_NOMEM;      }    }while( sqlite3OsFileExists(zMaster) );    /* Open the master journal. */    memset(&master, 0, sizeof(master));    rc = sqlite3OsOpenExclusive(zMaster, &master, 0);    if( rc!=SQLITE_OK ){      sqliteFree(zMaster);      return rc;    }     /* Write the name of each database file in the transaction into the new    ** master journal file. If an error occurs at this point close    ** and delete the master journal file. All the individual journal files    ** still have 'null' as the master journal pointer, so they will roll    ** back independently if a failure occurs.    */    for(i=0; i<db->nDb; i++){       Btree *pBt = db->aDb[i].pBt;      if( i==1 ) continue;   /* Ignore the TEMP database */      if( pBt && sqlite3BtreeIsInTrans(pBt) ){        char const *zFile = sqlite3BtreeGetJournalname(pBt);        if( zFile[0]==0 ) continue;  /* Ignore :memory: databases */        rc = sqlite3OsWrite(&master, zFile, strlen(zFile)+1);        if( rc!=SQLITE_OK ){          sqlite3OsClose(&master);          sqlite3OsDelete(zMaster);          sqliteFree(zMaster);          return rc;        }      }    }    /* Sync the master journal file. Before doing this, open the directory    ** the master journal file is store in so that it gets synced too.    */    zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt);    rc = sqlite3OsOpenDirectory(zMainFile, &master);    if( rc!=SQLITE_OK || (rc = sqlite3OsSync(&master))!=SQLITE_OK ){      sqlite3OsClose(&master);      sqlite3OsDelete(zMaster);      sqliteFree(zMaster);      return rc;    }    /* Sync all the db files involved in the transaction. The same call    ** sets the master journal pointer in each individual journal. If    ** an error occurs here, do not delete the master journal file.    **    ** If the error occurs during the first call to sqlite3BtreeSync(),    ** then there is a chance that the master journal file will be    ** orphaned. But we cannot delete it, in case the master journal    ** file name was written into the journal file before the failure    ** occured.    */    for(i=0; i<db->nDb; i++){       Btree *pBt = db->aDb[i].pBt;      if( pBt && sqlite3BtreeIsInTrans(pBt) ){        rc = sqlite3BtreeSync(pBt, zMaster);        if( rc!=SQLITE_OK ){          sqlite3OsClose(&master);          sqliteFree(zMaster);          return rc;        }      }    }    sqlite3OsClose(&master);    /* Delete the master journal file. This commits the transaction. After    ** doing this the directory is synced again before any individual    ** transaction files are deleted.    */    rc = sqlite3OsDelete(zMaster);    assert( rc==SQLITE_OK );    sqliteFree(zMaster);    zMaster = 0;    rc = sqlite3OsSyncDirectory(zMainFile);    if( rc!=SQLITE_OK ){      /* This is not good. The master journal file has been deleted, but      ** the directory sync failed. There is no completely safe course of      ** action from here. The individual journals contain the name of the      ** master journal file, but there is no way of knowing if that      ** master journal exists now or if it will exist after the operating      ** system crash that may follow the fsync() failure.      */      return rc;    }    /* All files and directories have already been synced, so the following    ** calls to sqlite3BtreeCommit() are only closing files and deleting    ** journals. If something goes wrong while this is happening we don't    ** really care. The integrity of the transaction is already guaranteed,    ** but some stray 'cold' journals may be lying around. Returning an    ** error code won't help matters.    */    for(i=0; i<db->nDb; i++){       Btree *pBt = db->aDb[i].pBt;      if( pBt ){        sqlite3BtreeCommit(pBt);      }    }  }#endif  return rc;}/*** Find every active VM other than pVdbe and change its status to** aborted.  This happens when one VM causes a rollback due to an** ON CONFLICT ROLLBACK clause (for example).  The other VMs must be** aborted so that they do not have data rolled out from underneath** them leading to a segfault.*/static void abortOtherActiveVdbes(Vdbe *pVdbe){  Vdbe *pOther;  for(pOther=pVdbe->db->pVdbe; pOther; pOther=pOther->pNext){    if( pOther==pVdbe ) continue;    if( pOther->magic!=VDBE_MAGIC_RUN || pOther->pc<0 ) continue;    closeAllCursors(pOther);    pOther->aborted = 1;  }}/* ** This routine checks that the sqlite3.activeVdbeCnt count variable** matches the number of vdbe's in the list sqlite3.pVdbe that are** currently active. An assertion fails if the two counts do not match.** This is an internal self-check only - it is not an essential processing** step.**** This is a no-op if NDEBUG is defined.*/#ifndef NDEBUGstatic void checkActiveVdbeCnt(sqlite3 *db){  Vdbe *p;  int cnt = 0;  p = db->pVdbe;  while( p ){    if( p->magic==VDBE_MAGIC_RUN && p->pc>=0 ){      cnt++;    }    p = p->pNext;  }  assert( cnt==db->activeVdbeCnt );}#else#define checkActiveVdbeCnt(x)#endif/*** This routine is called the when a VDBE tries to halt.  If the VDBE** has made changes and is in autocommit mode, then commit those** changes.  If a rollback is needed, then do the rollback.**** This routine is the only way to move the state of a VM from** SQLITE_MAGIC_RUN to SQLITE_MAGIC_HALT.**** Return an error code.  If the commit could not complete because of** lock contention, return SQLITE_BUSY.  If SQLITE_BUSY is returned, it** means the close did not happen and needs to be repeated.*/int sqlite3VdbeHalt(Vdbe *p){  sqlite3 *db = p->db;  int i;  int (*xFunc)(Btree *pBt) = 0;  /* Function to call on each btree backend */  if( p->magic!=VDBE_MAGIC_RUN ){    /* Already halted.  Nothing to do. */    assert( p->magic==VDBE_MAGIC_HALT );    return SQLITE_OK;  }  closeAllCursors(p);  checkActiveVdbeCnt(db);  if( p->pc<0 ){    /* No commit or rollback needed if the program never started */  }else if( db->autoCommit && db->activeVdbeCnt==1 ){    if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){      /* The auto-commit flag is true, there are no other active queries      ** using this handle and the vdbe program was successful or hit an      ** 'OR FAIL' constraint. This means a commit is required.      */      int rc = vdbeCommit(db);      if( rc==SQLITE_BUSY ){        return SQLITE_BUSY;      }else if( rc!=SQLITE_OK ){        p->rc = rc;        xFunc = sqlite3BtreeRollback;      }    }else{      xFunc = sqlite3BtreeRollback;    }  }else{    if( p->rc==SQLITE_OK || p->errorAction==OE_Fail ){      xFunc = sqlite3BtreeCommitStmt;    }else if( p->errorAction==OE_Abort ){      xFunc = sqlite3BtreeRollbackStmt;    }else{      xFunc = sqlite3BtreeRollback;      db->autoCommit = 1;      abortOtherActiveVdbes(p);    }  }  /* If xFunc is not NULL, then it is one of sqlite3BtreeRollback,  ** sqlite3BtreeRollbackStmt or sqlite3BtreeCommitStmt. Call it once on  ** each backend. If an error occurs and the return code is still  ** SQLITE_OK, set the return code to the new error value.  */  for(i=0; xFunc && i<db->nDb; i++){     int rc;    Btree *pBt = db->aDb[i].pBt;    if( pBt ){      rc = xFunc(pBt);      if( p->rc==SQLITE_OK ) p->rc = rc;    }  }  /* If this was an INSERT, UPDATE or DELETE, set the change counter. */  if( p->changeCntOn && p->pc>=0 ){    if( !xFunc || xFunc==sqlite3BtreeCommitStmt ){      sqlite3VdbeSetChanges(db, p->nChange);    }else{      sqlite3VdbeSetChanges(db, 0);    }    p->nChange = 0;  }  /* Rollback or commit any schema changes that occurred. */  if( p->rc!=SQLITE_OK ){    sqlite3RollbackInternalChanges(db);  }else if( db->flags & SQLITE_InternChanges ){    sqlite3CommitInternalChanges(db);  }  /* We have successfully halted and closed the VM.  Record this fact. */  if( p->pc>=0 ){    db->activeVdbeCnt--;  }  p->magic = VDBE_MAGIC_HALT;  checkActiveVdbeCnt(db);  return SQLITE_OK;}/*** Clean up a VDBE after execution but do not delete the VDBE just yet.** Write any error messages into *pzErrMsg.  Return the result code.**** After this routine is run, the VDBE should be ready to be executed** again.**** To look at it another way, this routine resets the state of the** virtual machine from VDBE_MAGIC_RUN or VDBE_MAGIC_HALT back to** VDBE_MAGIC_INIT.*/int sqlite3VdbeReset(Vdbe *p){  if( p->magic!=VDBE_MAGIC_RUN && p->magic!=VDBE_MAGIC_HALT ){    sqlite3Error(p->db, SQLITE_MISUSE, 0);    return SQLITE_MISUSE;  }  /* If the VM did not run to completion or if it encountered an  ** error, then it might not have been halted properly.  So halt  ** it now.  */  sqlite3VdbeHalt(p);  /* If the VDBE has be run even partially, then transfer the error code  ** and error message from the VDBE into the main database structure.  But  ** if the VDBE has just been set to run but has not actually executed any  ** instructions yet, leave the main database error information unchanged.  */  if( p->pc>=0 ){    if( p->zErrMsg ){      sqlite3Error(p->db, p->rc, "%s", p->zErrMsg);      sqliteFree(p->zErrMsg);      p->zErrMsg = 0;    }else if( p->rc ){      sqlite3Error(p->db, p->rc, 0);    }else{      sqlite3Error(p->db, SQLITE_OK, 0);    }  }else if( p->rc && p->expired ){    /* The expired flag was set on the VDBE before the first call    ** to sqlite3_step(). For consistency (since sqlite3_step() was    ** called), set the database error in this case as well.    */    sqlite3Error(p->db, p->rc, 0);  }  /* Reclaim all memory used by the VDBE  */  Cleanup(p);  /* Save profiling information from this VDBE run.  */  assert( p->pTos<&p->aStack[p->pc<0?0:p->pc] || sqlite3_malloc_failed==1 );#ifdef VDBE_PROFILE  {    FILE *out = fopen("vdbe_profile.out", "a");    if( out ){      int i;      fprintf(out, "---- ");      for(i=0; i<p->nOp; i++){        fprintf(out, "%02x", p->aOp[i].opcode);      }      fprintf(out, "\n");      for(i=0; i<p->nOp; i++){        fprintf(out, "%6d %10lld %8lld ",           p->aOp[i].cnt,           p->aOp[i].cycles,           p->aOp[i].cnt>0 ? p->aOp[i].cycles/p->aOp[i].cnt : 0        );        sqlite3VdbePrintOp(out, i, &p->aOp[i]);      }      fclose(out);    }  }#endif  p->magic = VDBE_MAGIC_INIT;  p->aborted = 0;  if( p->rc==SQLITE_SCHEMA ){    sqlite3ResetInternalSchema(p->db, 0);  }  return p->rc;} /*** Clean up and delete a VDBE after execution.  Return an integer which is** the result code.  Write any error message text into *pzErrMsg.*/int sqlite3VdbeFinalize(Vdbe *p){  int rc = SQLITE_OK;  if( p->magic==VDBE_MAGIC_RUN || p->magic==VDBE_MAGIC_HALT ){    rc = sqlite3VdbeReset(p);  }else if( p->magic!=VDBE_MAGIC_INIT ){    return SQLITE_MISUSE;  }

⌨️ 快捷键说明

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