Example #1
0
/*
** Wait for a client process to complete all its tasks
*/
static void waitForClient(int iClient, int iTimeout, char *zErrPrefix){
  sqlite3_stmt *pStmt;
  int rc;
  if( iClient>0 ){
    pStmt = prepareSql(
               "SELECT 1 FROM task"
               " WHERE client=%d"
               "   AND client IN (SELECT id FROM client)"
               "  AND endtime IS NULL",
               iClient);
  }else{
    pStmt = prepareSql(
               "SELECT 1 FROM task"
               " WHERE client IN (SELECT id FROM client)"
               "   AND endtime IS NULL");
  }
  g.iTimeout = 0;
  while( ((rc = sqlite3_step(pStmt))==SQLITE_BUSY || rc==SQLITE_ROW)
    && iTimeout>0
  ){
    sqlite3_reset(pStmt);
    sqlite3_sleep(50);
    iTimeout -= 50;
  }
  sqlite3_finalize(pStmt);
  g.iTimeout = DEFAULT_TIMEOUT;
  if( rc!=SQLITE_DONE ){
    if( zErrPrefix==0 ) zErrPrefix = "";
    if( iClient>0 ){
      errorMessage("%stimeout waiting for client %d", zErrPrefix, iClient);
    }else{
      errorMessage("%stimeout waiting for all clients", zErrPrefix);
    }
  }
}
Example #2
0
/*
** Print an error message and then quit.
*/
static void fatalError(const char *zFormat, ...){
  va_list ap;
  char *zMsg;
  char zPrefix[30];
  va_start(ap, zFormat);
  zMsg = sqlite3_vmprintf(zFormat, ap);
  va_end(ap);
  sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:FATAL: ", g.zName);
  if( g.pLog ){
    printWithPrefix(g.pLog, zPrefix, zMsg);
    fflush(g.pLog);
    maybeClose(g.pLog);
  }
  if( g.pErrLog && safe_strcmp(g.zErrLog,g.zLog) ){
    printWithPrefix(g.pErrLog, zPrefix, zMsg);
    fflush(g.pErrLog);
    maybeClose(g.pErrLog);
  }
  sqlite3_free(zMsg);
  if( g.db ){
    int nTry = 0;
    g.iTimeout = 0;
    while( trySql("UPDATE client SET wantHalt=1;")==SQLITE_BUSY
           && (nTry++)<100 ){
      sqlite3_sleep(10);
    }
  }
  sqlite3_close(g.db);
  exit(1);  
}
Example #3
0
static int
sql_step(sqlite3 *db, sqlite3_stmt *sql_stmt)
{
	int rc;

	PTHREAD_DISABLE_CANCEL();

	/* Using the newer sqlite_prepare_v2() interface means that
	 * sqlite3_step() will return more detailed error codes. See
	 * sqlite3_step() API reference.
	 */
	while ((rc = sqlite3_step(sql_stmt)) == SQLITE_BUSY) {
		(void) sqlite3_sleep(1000);
	}

	if (rc != SQLITE_DONE && rc != SQLITE_ROW)
		syslog(LOG_ERR, "sql error %s", sqlite3_errmsg(db));

	if (rc != SQLITE_ROW) {
		/* http://www.sqlite.org/cvstrac/wiki?p=DatabaseIsLocked
		 *
		 * "Sometimes people think they have finished with a SELECT statement
		 *  because sqlite3_step() has returned SQLITE_DONE. But the SELECT is
		 *  not really complete until sqlite3_reset() or sqlite3_finalize()
		 *  have been called.
		 */
		(void) sqlite3_reset(sql_stmt);
	}
	PTHREAD_RESTORE_CANCEL();

	return rc;
}
int bwl_backup_database(const char *szBackupDBFilePath)
{
#if SQLITE_VERSION_NUMBER >= 3006011
    if (NULL == db)
    {
        LOG("Blacklist Whitelist Database File Has Been Closed!");
        return BWLIST_ERROR;
    }

    sqlite3* pDBBake;
    sqlite3_backup* pBackup;
    int rc;
    rc = sqlite3_open(szBackupDBFilePath, &pDBBake);
    if (rc != SQLITE_OK)
    {
        LOG("Open Backup DB error:%s.", sqlite3_errmsg(pDBBake));
        sqlite3_close(pDBBake);
        return BWLIST_ERROR;
    }

    pBackup = sqlite3_backup_init(pDBBake, "main", db, "main");
    if (pBackup == 0)
    {
        LOG("Backup Init Error:%s.", sqlite3_errmsg(pDBBake));
        sqlite3_close(pDBBake);
        return BWLIST_ERROR;
    }

    do
    {
        rc = sqlite3_backup_step(pBackup, BACKUP_PAGECOUNT);
        if (rc == SQLITE_BUSY || rc == SQLITE_LOCKED)
        {
          sqlite3_sleep(250);
        }
    }
    while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED);

    sqlite3_backup_finish(pBackup);
    if (rc == SQLITE_DONE)
    {
        sqlite3_close(pDBBake);
        return BWLIST_OK;
    }
    else
    {
        LOG("Backup Step Error:%s.", sqlite3_errmsg(pDBBake));
        sqlite3_close(pDBBake);
        return BWLIST_ERROR;
    }

#else

    LOG("Backup not supported in this SQLite Version!");
    return BWLIST_ERROR;

#endif
}
Example #5
0
/*
** Busy handler with a g.iTimeout-millisecond timeout
*/
static int busyHandler(void *pCD, int count){
  UNUSED_PARAMETER(pCD);
  if( count*10>g.iTimeout ){
    if( g.iTimeout>0 ) errorMessage("timeout after %dms", g.iTimeout);
    return 0;
  }
  sqlite3_sleep(10);
  return 1;
}
ikptr
ik_sqlite3_sleep (ikptr s_milliseconds, ikpcb * pcb)
{
#ifdef HAVE_SQLITE3_SLEEP
  int	milliseconds = ik_integer_to_int(s_milliseconds);
  int	rv;
  rv = sqlite3_sleep(milliseconds);
  return ika_integer_from_int(pcb, rv);
#else
  feature_failure(__func__);
#endif
}
Example #7
0
int32_t sqlite3_step_sleep(sqlite3_stmt *stmt, int32_t ms)
{
    while (true)
    {
        int32_t r = sqlite3_step(stmt);
        if ((r != SQLITE_LOCKED && r != SQLITE_BUSY) || ms <= 0)
            return r;

        sqlite3_sleep(1);
        ms --;
    }
}
Example #8
0
int sqlite3_step_sleep(sqlite3_stmt *stmt, int ms)
{
    while (true)
    {
        int r = sqlite3_step(stmt);
        if (r != SQLITE_LOCKED || ms <= 0)
            return r;

        sqlite3_sleep(1);
        ms --;
    }
}
Example #9
0
svn_error_t *
svn_sqlite__hotcopy(const char *src_path,
                    const char *dst_path,
                    apr_pool_t *scratch_pool)
{
  svn_sqlite__db_t *src_db;

  SVN_ERR(svn_sqlite__open(&src_db, src_path, svn_sqlite__mode_readonly,
                           NULL, 0, NULL, 0,
                           scratch_pool, scratch_pool));

  {
    svn_sqlite__db_t *dst_db;
    sqlite3_backup *backup;
    int rc1, rc2;

    SVN_ERR(svn_sqlite__open(&dst_db, dst_path, svn_sqlite__mode_rwcreate,
                             NULL, 0, NULL, 0, scratch_pool, scratch_pool));
    backup = sqlite3_backup_init(dst_db->db3, "main", src_db->db3, "main");
    if (!backup)
      return svn_error_createf(SVN_ERR_SQLITE_ERROR, NULL,
                               _("SQLite hotcopy failed for %s"), src_path);
    do
      {
        /* Pages are usually 1024 byte (SQLite docs). On my laptop
           copying gets faster as the number of pages is increased up
           to about 64, beyond that speed levels off.  Lets put the
           number of pages an order of magnitude higher, this is still
           likely to be a fraction of large databases. */
        rc1 = sqlite3_backup_step(backup, 1024);

        /* Should we sleep on SQLITE_OK?  That would make copying a
           large database take much longer.  When we do sleep how,
           long should we sleep?  Should the sleep get longer if we
           keep getting BUSY/LOCKED?  I have no real reason for
           choosing 25. */
        if (rc1 == SQLITE_BUSY || rc1 == SQLITE_LOCKED)
          sqlite3_sleep(25);
      }
    while (rc1 == SQLITE_OK || rc1 == SQLITE_BUSY || rc1 == SQLITE_LOCKED);
    rc2 = sqlite3_backup_finish(backup);
    if (rc1 != SQLITE_DONE)
      SQLITE_ERR(rc1, dst_db);
    SQLITE_ERR(rc2, dst_db);
    SVN_ERR(svn_sqlite__close(dst_db));
  }

  SVN_ERR(svn_sqlite__close(src_db));

  SVN_ERR(svn_io_copy_perms(src_path, dst_path, scratch_pool));

  return SVN_NO_ERROR;
}
Example #10
0
int32_t sqlite3_prepare_sleep(sqlite3 *db, const char *zSql, int nByte,
                              sqlite3_stmt **ppStmt, const char **pzTail, int32_t ms)
{
    while (true)
    {
        int32_t r = sqlite3_prepare_v2(db, zSql, nByte, ppStmt, pzTail);
        if ((r != SQLITE_LOCKED && r != SQLITE_BUSY) || ms <= 0)
            return r;

        sqlite3_sleep(1);
        ms --;
    }
}
Example #11
0
int SQLiteQuery::busyCallback(void *pArg, int busy)
{
	sqlite3_sleep(50);
	if (busy == 50)
	{
		printf("SQLiteQuery::busyCallback...\n");
	}
	else if (busy > 100)
	{
		return 0;
	}

	return 1;
}
Example #12
0
result_t SQLite::backup(exlib::string fileName, AsyncEvent *ac)
{
    if (!m_db)
        return CHECK_ERROR(CALL_E_INVALID_CALL);

    if (!ac)
        return CHECK_ERROR(CALL_E_NOSYNC);

    int32_t rc;
    struct sqlite3 *db2 = NULL;
    sqlite3_backup *pBackup;

    const char* c_str = fileName.c_str();

    if (!qstrcmp(c_str, "sqlite:", 7))
        c_str += 7;

    if (sqlite3_open_v2(c_str, &db2, SQLITE_OPEN_FLAGS, 0))
    {
        result_t hr = CHECK_ERROR(Runtime::setError(sqlite3_errmsg(db2)));
        return hr;
    }

    pBackup = sqlite3_backup_init(db2, "main", m_db, "main");
    if (pBackup)
    {
        do
        {
            rc = sqlite3_backup_step(pBackup, 5);
            if (rc == SQLITE_LOCKED)
                sqlite3_sleep(1);
        }
        while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED);

        sqlite3_backup_finish(pBackup);
    }
    else
    {
        result_t hr = CHECK_ERROR(Runtime::setError(sqlite3_errmsg(m_db)));
        sqlite3_close(db2);
        return hr;
    }

    sqlite3_close(db2);

    return 0;
}
Example #13
0
/**
 * @brief Perform an online backup of our database db to the database file named
 * by zFilename. Used to store our memory table in between map changes to disk
 *
 * This function copies 5 database pages from pDb to
 * zFilename, then unlocks pDb and sleeps for 250 ms, then repeats the
 * process until the entire database is backed up.
 *
 * The third argument passed to this function must be a pointer to a progress
 * function. After each set of 5 pages is backed up, the progress function
 * is invoked with two integer parameters: the number of pages left to
 * copy, and the total number of pages in the source file. This information
 * may be used, for example, to update a GUI progress bar.
 *
 * While this function is running, another thread may use the database pDb, or
 * another process may access the underlying database file via a separate
 * connection.
 *
 * If the backup process is successfully completed, SQLITE_OK is returned.
 * Otherwise, if an error occurs, an SQLite error code is returned.
 *
 * @param zFilename
 *
 * @return
 *
 */
int DB_BackupDB(const char *zFilename, void (*xProgress)(int, int)) // Progress function to invoke
{
	int            rc;        // Function return code
	sqlite3        *pFile;    // Database connection opened on zFilename
	sqlite3_backup *pBackup;  // Backup handle used to copy data

	// Open the database file identified by zFilename.
	rc = sqlite3_open(zFilename, &pFile);
	if (rc == SQLITE_OK)
	{
		// Open the sqlite3_backup object used to accomplish the transfer
		pBackup = sqlite3_backup_init(pFile, "main", db, "main");
		if (pBackup)
		{
			// Each iteration of this loop copies 5 database pages from database
			// pDb to the backup database. If the return value of backup_step()
			// indicates that there are still further pages to copy, sleep for
			// 250 ms before repeating.
			do
			{
				rc = sqlite3_backup_step(pBackup, 5);
				xProgress(sqlite3_backup_remaining(pBackup), sqlite3_backup_pagecount(pBackup));
				if (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED)
				{
					sqlite3_sleep(250);
				}
			}
			while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED);

			// Release resources allocated by backup_init().
			(void) sqlite3_backup_finish(pBackup);
		}
		rc = sqlite3_errcode(pFile);
	}

	// Close the database connection opened on database file zFilename and return the result of this function.
	(void) sqlite3_close(pFile);
	return rc;
}
Example #14
0
void SQLiteQuery::sleep(long ms)
{
	sqlite3_sleep(ms);
}
Example #15
0
/*
** Run a script.
*/
static void runScript(
  int iClient,       /* The client number, or 0 for the master */
  int taskId,        /* The task ID for clients.  0 for master */
  char *zScript,     /* Text of the script */
  char *zFilename    /* File from which script was read. */
){
  int lineno = 1;
  int prevLine = 1;
  int ii = 0;
  int iBegin = 0;
  int n, c, j;
  int len;
  int nArg;
  String sResult;
  char zCmd[30];
  char zError[1000];
  char azArg[MX_ARG][100];

  memset(&sResult, 0, sizeof(sResult));
  stringReset(&sResult);
  while( (c = zScript[ii])!=0 ){
    prevLine = lineno;
    len = tokenLength(zScript+ii, &lineno);
    if( isspace(c) || (c=='/' && zScript[ii+1]=='*') ){
      ii += len;
      continue;
    }
    if( c!='-' || zScript[ii+1]!='-' || !isalpha(zScript[ii+2]) ){
      ii += len;
      continue;
    }

    /* Run any prior SQL before processing the new --command */
    if( ii>iBegin ){
      char *zSql = sqlite3_mprintf("%.*s", ii-iBegin, zScript+iBegin);
      evalSql(&sResult, zSql);
      sqlite3_free(zSql);
      iBegin = ii + len;
    }

    /* Parse the --command */
    if( g.iTrace>=2 ) logMessage("%.*s", len, zScript+ii);
    n = extractToken(zScript+ii+2, len-2, zCmd, sizeof(zCmd));
    for(nArg=0; n<len-2 && nArg<MX_ARG; nArg++){
      while( n<len-2 && isspace(zScript[ii+2+n]) ){ n++; }
      if( n>=len-2 ) break;
      n += extractToken(zScript+ii+2+n, len-2-n,
                        azArg[nArg], sizeof(azArg[nArg]));
    }
    for(j=nArg; j<MX_ARG; j++) azArg[j++][0] = 0;

    /*
    **  --sleep N
    **
    ** Pause for N milliseconds
    */
    if( strcmp(zCmd, "sleep")==0 ){
      sqlite3_sleep(atoi(azArg[0]));
    }else 

    /*
    **   --exit N
    **
    ** Exit this process.  If N>0 then exit without shutting down
    ** SQLite.  (In other words, simulate a crash.)
    */
    if( strcmp(zCmd, "exit")==0 ){
      int rc = atoi(azArg[0]);
      finishScript(iClient, taskId, 1);
      if( rc==0 ) sqlite3_close(g.db);
      exit(rc);
    }else

    /*
    **   --testcase NAME
    **
    ** Begin a new test case.  Announce in the log that the test case
    ** has begun.
    */
    if( strcmp(zCmd, "testcase")==0 ){
      if( g.iTrace==1 ) logMessage("%.*s", len - 1, zScript+ii);
      stringReset(&sResult);
    }else

    /*
    **   --finish
    **
    ** Mark the current task as having finished, even if it is not.
    ** This can be used in conjunction with --exit to simulate a crash.
    */
    if( strcmp(zCmd, "finish")==0 && iClient>0 ){
      finishScript(iClient, taskId, 1);
    }else

    /*
    **  --reset
    **
    ** Reset accumulated results back to an empty string
    */
    if( strcmp(zCmd, "reset")==0 ){
      stringReset(&sResult);
    }else

    /*
    **  --match ANSWER...
    **
    ** Check to see if output matches ANSWER.  Report an error if not.
    */
    if( strcmp(zCmd, "match")==0 ){
      int jj;
      char *zAns = zScript+ii;
      for(jj=7; jj<len-1 && isspace(zAns[jj]); jj++){}
      zAns += jj;
      if( len-jj-1!=sResult.n || strncmp(sResult.z, zAns, len-jj-1) ){
        errorMessage("line %d of %s:\nExpected [%.*s]\n     Got [%s]",
          prevLine, zFilename, len-jj-1, zAns, sResult.z);
      }
      g.nTest++;
      stringReset(&sResult);
    }else

    /*
    **  --glob ANSWER...
    **  --notglob ANSWER....
    **
    ** Check to see if output does or does not match the glob pattern
    ** ANSWER.
    */
    if( strcmp(zCmd, "glob")==0 || strcmp(zCmd, "notglob")==0 ){
      int jj;
      char *zAns = zScript+ii;
      char *zCopy;
      int isGlob = (zCmd[0]=='g');
      for(jj=9-3*isGlob; jj<len-1 && isspace(zAns[jj]); jj++){}
      zAns += jj;
      zCopy = sqlite3_mprintf("%.*s", len-jj-1, zAns);
      if( (sqlite3_strglob(zCopy, sResult.z)==0)^isGlob ){
        errorMessage("line %d of %s:\nExpected [%s]\n     Got [%s]",
          prevLine, zFilename, zCopy, sResult.z);
      }
      sqlite3_free(zCopy);
      g.nTest++;
      stringReset(&sResult);
    }else

    /*
    **  --output
    **
    ** Output the result of the previous SQL.
    */
    if( strcmp(zCmd, "output")==0 ){
      logMessage("%s", sResult.z);
    }else

    /*
    **  --source FILENAME
    **
    ** Run a subscript from a separate file.
    */
    if( strcmp(zCmd, "source")==0 ){
      char *zNewFile, *zNewScript;
      char *zToDel = 0;
      zNewFile = azArg[0];
      if( zNewFile[0]!='/' ){
        int k;
        for(k=(int)strlen(zFilename)-1; k>=0 && zFilename[k]!='/'; k--){}
        if( k>0 ){
          zNewFile = zToDel = sqlite3_mprintf("%.*s/%s", k,zFilename,zNewFile);
        }
      }
      zNewScript = readFile(zNewFile);
      if( g.iTrace ) logMessage("begin script [%s]\n", zNewFile);
      runScript(0, 0, zNewScript, zNewFile);
      sqlite3_free(zNewScript);
      if( g.iTrace ) logMessage("end script [%s]\n", zNewFile);
      sqlite3_free(zToDel);
    }else

    /*
    **  --print MESSAGE....
    **
    ** Output the remainder of the line to the log file
    */
    if( strcmp(zCmd, "print")==0 ){
      int jj;
      for(jj=7; jj<len && isspace(zScript[ii+jj]); jj++){}
      logMessage("%.*s", len-jj, zScript+ii+jj);
    }else

    /*
    **  --if EXPR
    **
    ** Skip forward to the next matching --endif or --else if EXPR is false.
    */
    if( strcmp(zCmd, "if")==0 ){
      int jj, rc;
      sqlite3_stmt *pStmt;
      for(jj=4; jj<len && isspace(zScript[ii+jj]); jj++){}
      pStmt = prepareSql("SELECT %.*s", len-jj, zScript+ii+jj);
      rc = sqlite3_step(pStmt);
      if( rc!=SQLITE_ROW || sqlite3_column_int(pStmt, 0)==0 ){
        ii += findEndif(zScript+ii+len, 1, &lineno);
      }
      sqlite3_finalize(pStmt);
    }else

    /*
    **  --else
    **
    ** This command can only be encountered if currently inside an --if that
    ** is true.  Skip forward to the next matching --endif.
    */
    if( strcmp(zCmd, "else")==0 ){
      ii += findEndif(zScript+ii+len, 0, &lineno);
    }else

    /*
    **  --endif
    **
    ** This command can only be encountered if currently inside an --if that
    ** is true or an --else of a false if.  This is a no-op.
    */
    if( strcmp(zCmd, "endif")==0 ){
      /* no-op */
    }else

    /*
    **  --start CLIENT
    **
    ** Start up the given client.
    */
    if( strcmp(zCmd, "start")==0 && iClient==0 ){
      int iNewClient = atoi(azArg[0]);
      if( iNewClient>0 ){
        startClient(iNewClient);
      }
    }else

    /*
    **  --wait CLIENT TIMEOUT
    **
    ** Wait until all tasks complete for the given client.  If CLIENT is
    ** "all" then wait for all clients to complete.  Wait no longer than
    ** TIMEOUT milliseconds (default 10,000)
    */
    if( strcmp(zCmd, "wait")==0 && iClient==0 ){
      int iTimeout = nArg>=2 ? atoi(azArg[1]) : 10000;
      sqlite3_snprintf(sizeof(zError),zError,"line %d of %s\n",
                       prevLine, zFilename);
      waitForClient(atoi(azArg[0]), iTimeout, zError);
    }else

    /*
    **  --task CLIENT
    **     <task-content-here>
    **  --end
    **
    ** Assign work to a client.  Start the client if it is not running
    ** already.
    */
    if( strcmp(zCmd, "task")==0 && iClient==0 ){
      int iTarget = atoi(azArg[0]);
      int iEnd;
      char *zTask;
      char *zTName;
      iEnd = findEnd(zScript+ii+len, &lineno);
      if( iTarget<0 ){
        errorMessage("line %d of %s: bad client number: %d",
                     prevLine, zFilename, iTarget);
      }else{
        zTask = sqlite3_mprintf("%.*s", iEnd, zScript+ii+len);
        if( nArg>1 ){
          zTName = sqlite3_mprintf("%s", azArg[1]);
        }else{
          zTName = sqlite3_mprintf("%s:%d", filenameTail(zFilename), prevLine);
        }
        startClient(iTarget);
        runSql("INSERT INTO task(client,script,name)"
               " VALUES(%d,'%q',%Q)", iTarget, zTask, zTName);
        sqlite3_free(zTask);
        sqlite3_free(zTName);
      }
      iEnd += tokenLength(zScript+ii+len+iEnd, &lineno);
      len += iEnd;
      iBegin = ii+len;
    }else

    /*
    **  --breakpoint
    **
    ** This command calls "test_breakpoint()" which is a routine provided
    ** as a convenient place to set a debugger breakpoint.
    */
    if( strcmp(zCmd, "breakpoint")==0 ){
      test_breakpoint();
    }else

    /*
    **  --show-sql-errors BOOLEAN
    **
    ** Turn display of SQL errors on and off.
    */
    if( strcmp(zCmd, "show-sql-errors")==0 ){
      g.bIgnoreSqlErrors = nArg>=1 ? !booleanValue(azArg[0]) : 1;
    }else


    /* error */{
      errorMessage("line %d of %s: unknown command --%s",
                   prevLine, zFilename, zCmd);
    }
    ii += len;
  }
  if( iBegin<ii ){
    char *zSql = sqlite3_mprintf("%.*s", ii-iBegin, zScript+iBegin);
    runSql(zSql);
    sqlite3_free(zSql);
  }
  stringFree(&sResult);
}
Example #16
0
static int
copy_database(sqlite3 *src, sqlite3 *dst, const char *name)
{
    sqlite3_backup	*b;
    char		*errmsg;
    off_t		 total;
    off_t		 done;
    off_t		 page_size;
    int		 ret;

    assert(src != NULL);
    assert(dst != NULL);

    ret = sqlite3_exec(dst, "PRAGMA main.locking_mode=EXCLUSIVE;"
                       "BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);
    if (ret != SQLITE_OK) {
        pkg_emit_error("sqlite error -- %s", errmsg);
        sqlite3_free(errmsg);
        return (EPKG_FATAL);
    }

    ret = sqlite3_exec(dst, "PRAGMA page_size", ps_cb, &page_size, &errmsg);
    if (ret != SQLITE_OK) {
        pkg_emit_error("sqlite error -- %s", errmsg);
        sqlite3_free(errmsg);
        return (EPKG_FATAL);
    }

    b = sqlite3_backup_init(dst, "main", src, "main");

    done = total = 0;

    pkg_emit_progress_start(NULL);
    do {
        ret = sqlite3_backup_step(b, NPAGES);
        total = sqlite3_backup_pagecount(b);
        done = total - sqlite3_backup_remaining(b);
        pkg_emit_progress_tick(done, total);

        if (ret != SQLITE_OK && ret != SQLITE_DONE ) {
            if (ret == SQLITE_BUSY) {
                sqlite3_sleep(250);
            } else {
                ERROR_SQLITE(dst, "backup step");
                break;
            }
        }
    } while(done < total);

    ret = sqlite3_backup_finish(b);
    pkg_emit_progress_tick(total, total);

    sqlite3_exec(dst, "PRAGMA main.locking_mode=NORMAL;"
                 "BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);

    if (ret != SQLITE_OK) {
        pkg_emit_error("sqlite error -- %s", errmsg);
        sqlite3_free(errmsg);
        return (EPKG_FATAL);
    }

    return ret;
}
Example #17
0
void Database::sqliteDBMemFile(bool save)
{
  if (save) qWarning() << "sqliteDBMemFile(): from memory to file...";
  else qWarning() << "sqliteDBMemFile(): from file to memory...";

  int rc = -1;                   /* Function return code */
  QVariant v = QSqlDatabase::database().driver()->handle();
  if (v.isValid() && qstrcmp(v.typeName(),"sqlite3*") == 0) {
    // v.data() returns a pointer to the handle
    sqlite3 *handle = *static_cast<sqlite3 **>(v.data());
    if (handle != 0) {  // check that it is not NULL
      sqlite3 *pInMemory = handle;
      sqlite3 *pFile;           /* Database connection opened on zFilename */
      sqlite3_backup *pBackup;  /* Backup object used to copy data */
      sqlite3 *pTo;             /* Database to copy to (pFile or pInMemory) */
      sqlite3 *pFrom;           /* Database to copy from (pFile or pInMemory) */

      /* Open the database file identified by zFilename. Exit early if this fails
      ** for any reason. */
      rc = sqlite3_open(mainApp->dbFileName().toUtf8().data(), &pFile);
      if (rc == SQLITE_OK) {
        /* If this is a 'load' operation (isSave==0), then data is copied
        ** from the database file just opened to database pInMemory.
        ** Otherwise, if this is a 'save' operation (isSave==1), then data
        ** is copied from pInMemory to pFile.  Set the variables pFrom and
        ** pTo accordingly. */
        pFrom = (save ? pInMemory : pFile);
        pTo   = (save ? pFile     : pInMemory);

        /* Set up the backup procedure to copy from the "main" database of
        ** connection pFile to the main database of connection pInMemory.
        ** If something goes wrong, pBackup will be set to NULL and an error
        ** code and  message left in connection pTo.
        **
        ** If the backup object is successfully created, call backup_step()
        ** to copy data from pFile to pInMemory. Then call backup_finish()
        ** to release resources associated with the pBackup object.  If an
        ** error occurred, then  an error code and message will be left in
        ** connection pTo. If no error occurred, then the error code belonging
        ** to pTo is set to SQLITE_OK.
        */

        pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");

        /* Each iteration of this loop copies 5 database pages from database
        ** pDb to the backup database. If the return value of backup_step()
        ** indicates that there are still further pages to copy, sleep for
        ** 250 ms before repeating. */
        do {
          rc = sqlite3_backup_step(pBackup, 10000);

          if (!mainApp->isNoDebugOutput()) {
            int remaining = sqlite3_backup_remaining(pBackup);
            int pagecount = sqlite3_backup_pagecount(pBackup);
            qDebug() << rc << "backup" << pagecount << "remain" << remaining;
          }

          if((rc == SQLITE_OK) || (rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED))
            sqlite3_sleep(100);
        } while((rc == SQLITE_OK) || (rc == SQLITE_BUSY) || (rc == SQLITE_LOCKED));

        /* Release resources allocated by backup_init(). */
        (void)sqlite3_backup_finish(pBackup);

        if (rc != SQLITE_DONE)
          qCritical() << "sqliteDBMemFile(): return code =" << rc;
      } else {
        qCritical() << "sqliteDBMemFile(): error open =" << rc;
      }

      /* Close the database connection opened on database file zFilename
      ** and return the result of this function. */
      (void)sqlite3_close(pFile);
    }
  }
  qWarning() << "sqliteDBMemFile(): finished!";
}
Example #18
0
int sqlite_generate_prebuild_db()
{
    sqlite3* db = NULL;
    int      rc;
    char*    errmsg = NULL;
    int      node_type;
    int      start_id, end_id;
    sqlite3_stmt* stat = NULL;
    char     sql_sentence[512] = {0};
    uint8_t* ptr_buf = NULL;
    uint32_t bufflen;
    uint8_t* ptr_precalc_node_buff = NULL;
    int      layer;

    bufflen = (INIT_MAX_HASH_TREE_LAYER-2)*sizeof(hash_tree_internal_node_t) + 
              sizeof(hash_tree_leaf_node_t);

    ptr_precalc_node_buff = (uint8_t*)malloc(bufflen);
    if(NULL == ptr_precalc_node_buff)
    {
        return -1;
    }

    memset(ptr_precalc_node_buff, 0, bufflen);

    hash_tree_internal_node_t* internal_node = (hash_tree_internal_node_t*)ptr_precalc_node_buff;
    for(int index=INIT_MAX_HASH_TREE_LAYER-3; index>=0; index--)
    {
        if(memcpy_s(internal_node->hash, 
                    sizeof(internal_node->hash), 
                    &(internal_node_hash_value_table[index][0]), 
                    HASH_VALUE_SIZE))
        {
            free(ptr_precalc_node_buff);
            return -1;
        }
        internal_node++;
    }

    if(gDb)
    {
        db = gDb;
    }
    else
    {
        rc = sqlite3_open(SQLITE_DB_FILE_NAME, &gDb);
        if( SQLITE_OK != rc )
        {
            free(ptr_precalc_node_buff);
            return rc;
        }
		db = gDb;
    }

    rc = sqlite3_exec( db, 
                       "create table VMC_QUOTA_TABLE( ID integer primary key AUTOINCREMENT, MRSIGNER char(64), COUNTER integer)", 
                       NULL,
                       NULL,
                       &errmsg );
    EXIT_IFNOT_SQLITE_OK(rc)

    rc = sqlite3_exec( db, 
                       "create table HASH_TREE_NODE_TABLE( ID integer primary key, node_content blob, USED integer, REFID integer NULL REFERENCES VMC_QUOTA_TABLE(ID))", 
                       NULL,
                       NULL,
                       &errmsg );
    EXIT_IFNOT_SQLITE_OK(rc)

    rc = sqlite3_exec( db, 
                       "create table BACKUP_TABLE( ID integer primary key, node_content blob, USED integer, REFID integer)", 
                       NULL,
                       NULL,
                       &errmsg );
    EXIT_IFNOT_SQLITE_OK(rc)

    // all nodes in the same layer have the same precalculated value
    // the merkel hash tree has 12 layers including root layer

    rc = sqlite3_exec(db, "BEGIN TRANSACTION;", NULL, NULL, NULL);
    EXIT_IFNOT_SQLITE_OK(rc)

    sprintf(sql_sentence, "insert into HASH_TREE_NODE_TABLE( ID, node_content, USED, REFID) values( ?, ?, 0, NULL)");

    rc = sqlite3_prepare_v2(db, 
                         sql_sentence, 
                         -1, 
                         &stat, 
                         0);
    EXIT_IFNOT_SQLITE_OK(rc)

    layer = INIT_MAX_HASH_TREE_LAYER - 1;
    do{
        if(INIT_MAX_HASH_TREE_LAYER - 1 == layer)
        {
            node_type = HASH_TREE_NODE_TYPE_LEAF;
        }
        else
        {
            node_type = HASH_TREE_NODE_TYPE_INTERNAL;
        }

        start_id = (int)pow((double)2,layer);
        end_id = (int)pow((double)2,layer+1) - 1;

        for(int id = start_id; id <= end_id; id++)
        {
            rc =sqlite3_bind_int(stat, 1, id);
            EXIT_IFNOT_SQLITE_OK(rc)

            switch(node_type)
            {
                case HASH_TREE_NODE_TYPE_INTERNAL:
                    ptr_buf = ptr_precalc_node_buff;
                    rc = sqlite3_bind_blob(stat,
                                           2,
                                           (hash_tree_internal_node_t*)ptr_buf + layer - 1,
                                           sizeof(hash_tree_internal_node_t),
                                           NULL
                                           );
                    break;
                case HASH_TREE_NODE_TYPE_LEAF:
                    rc = sqlite3_bind_blob(stat,
                                           2,
                                           ptr_precalc_node_buff + (INIT_MAX_HASH_TREE_LAYER-2)*sizeof(hash_tree_internal_node_t),
                                           sizeof(hash_tree_leaf_node_t),
                                           NULL
                                           );

                    break;
                default:
                    goto error;
            }
            EXIT_IFNOT_SQLITE_OK(rc)

            rc = sqlite3_step(stat);
            if(rc != SQLITE_DONE)
            {
                goto error;
            }

            rc = sqlite3_clear_bindings(stat);
            EXIT_IFNOT_SQLITE_OK(rc)

            rc = sqlite3_reset(stat);
            EXIT_IFNOT_SQLITE_OK(rc)
        }
        layer--;
        if(layer&0x1)
            sqlite3_sleep(1);
    }while(layer>0);

    rc = sqlite3_exec(db, "END TRANSACTION;", NULL, NULL, NULL);
    EXIT_IFNOT_SQLITE_OK(rc)

    rc = sqlite3_finalize(stat);
    EXIT_IFNOT_SQLITE_OK(rc)

    stat = NULL;

    sqlite3_close_v2(db);
    gDb = NULL;

    free(ptr_precalc_node_buff);
    
    return 0;
error:
    free(ptr_precalc_node_buff);
    if(db)
    {
        sqlite3_finalize(stat);
        sqlite3_exec(db, "ROLLBACK TRANSACTION;", NULL, NULL, NULL);
        sqlite3_close_v2(db);
        gDb = NULL;
    }
    return -1;
}
Example #19
0
DLL_FUNCTION(int32_t) BU_SQLite_Sleep(int32_t ms) {
#pragma comment(linker, "/EXPORT:BU_SQLite_Sleep=_BU_SQLite_Sleep@4")
	return sqlite3_sleep(ms);
}
Example #20
0
int sqlite_test()
{
  const char *zClient;
  int iClient;
  int n, i;
  int openFlags = SQLITE_OPEN_READWRITE;
  int rc;
  char *zScript;
  int taskId;
  const char *zTrace;
  const char *zCOption;

  g.argv0 = argv[0];
  g.iTrace = 1;
  if( argc<2 ) usage(argv[0]);
  g.zDbFile = argv[1];
  if( strglob("*.test", g.zDbFile) ) usage(argv[0]);
  if( strcmp(sqlite3_sourceid(), SQLITE_SOURCE_ID)!=0 ){
    fprintf(stderr, "SQLite library and header mismatch\n"
                    "Library: %s\n"
                    "Header:  %s\n",
                    sqlite3_sourceid(), SQLITE_SOURCE_ID);
    exit(1);
  }
  n = argc-2;
  sqlite3_snprintf(sizeof(g.zName), g.zName, "%05d.mptest", GETPID());
  g.zVfs = findOption(argv+2, &n, "vfs", 1);
  zClient = findOption(argv+2, &n, "client", 1);
  g.zErrLog = findOption(argv+2, &n, "errlog", 1);
  g.zLog = findOption(argv+2, &n, "log", 1);
  zTrace = findOption(argv+2, &n, "trace", 1);
  if( zTrace ) g.iTrace = atoi(zTrace);
  if( findOption(argv+2, &n, "quiet", 0)!=0 ) g.iTrace = 0;
  g.bSqlTrace = findOption(argv+2, &n, "sqltrace", 0)!=0;
  g.bSync = findOption(argv+2, &n, "sync", 0)!=0;
  if( g.zErrLog ){
    g.pErrLog = fopen(g.zErrLog, "a");
  }else{
    g.pErrLog = stderr;
  }
  if( g.zLog ){
    g.pLog = fopen(g.zLog, "a");
  }else{
    g.pLog = stdout;
  }
  
  sqlite3_config(SQLITE_CONFIG_LOG, sqlErrorCallback, 0);
  if( zClient ){
    iClient = atoi(zClient);
    if( iClient<1 ) fatalError("illegal client number: %d\n", iClient);
    sqlite3_snprintf(sizeof(g.zName), g.zName, "%05d.client%02d",
                     GETPID(), iClient);
  }else{
    if( g.iTrace>0 ){
      printf("With SQLite " SQLITE_VERSION " " SQLITE_SOURCE_ID "\n" );
      for(i=0; (zCOption = sqlite3_compileoption_get(i))!=0; i++){
        printf("-DSQLITE_%s\n", zCOption);
      }
      fflush(stdout);
    }
    iClient =  0;
    unlink(g.zDbFile);
    openFlags |= SQLITE_OPEN_CREATE;
  }
  rc = sqlite3_open_v2(g.zDbFile, &g.db, openFlags, g.zVfs);
  if( rc ) fatalError("cannot open [%s]", g.zDbFile);
  sqlite3_enable_load_extension(g.db, 1);
  sqlite3_busy_handler(g.db, busyHandler, 0);
  sqlite3_create_function(g.db, "vfsname", 0, SQLITE_UTF8, 0,
                          vfsNameFunc, 0, 0);
  sqlite3_create_function(g.db, "eval", 1, SQLITE_UTF8, 0,
                          evalFunc, 0, 0);
  g.iTimeout = DEFAULT_TIMEOUT;
  if( g.bSqlTrace ) sqlite3_trace(g.db, sqlTraceCallback, 0);
  if( !g.bSync ) trySql("PRAGMA synchronous=OFF");
  if( iClient>0 ){
    if( n>0 ) unrecognizedArguments(argv[0], n, argv+2);
    if( g.iTrace ) logMessage("start-client");
    while(1){
      char *zTaskName = 0;
      rc = startScript(iClient, &zScript, &taskId, &zTaskName);
      if( rc==SQLITE_DONE ) break;
      if( g.iTrace ) logMessage("begin %s (%d)", zTaskName, taskId);
      runScript(iClient, taskId, zScript, zTaskName);
      if( g.iTrace ) logMessage("end %s (%d)", zTaskName, taskId);
      finishScript(iClient, taskId, 0);
      sqlite3_free(zTaskName);
      sqlite3_sleep(10);
    }
    if( g.iTrace ) logMessage("end-client");
  }else{
    sqlite3_stmt *pStmt;
    int iTimeout;
    if( n==0 ){
      fatalError("missing script filename");
    }
    if( n>1 ) unrecognizedArguments(argv[0], n, argv+2);
    runSql(
      "CREATE TABLE task(\n"
      "  id INTEGER PRIMARY KEY,\n"
      "  name TEXT,\n"
      "  client INTEGER,\n"
      "  starttime DATE,\n"
      "  endtime DATE,\n"
      "  script TEXT\n"
      ");"
      "CREATE INDEX task_i1 ON task(client, starttime);\n"
      "CREATE INDEX task_i2 ON task(client, endtime);\n"
      "CREATE TABLE counters(nError,nTest);\n"
      "INSERT INTO counters VALUES(0,0);\n"
      "CREATE TABLE client(id INTEGER PRIMARY KEY, wantHalt);\n"
    );
    zScript = readFile(argv[2]);
    if( g.iTrace ) logMessage("begin script [%s]\n", argv[2]);
    runScript(0, 0, zScript, argv[2]);
    sqlite3_free(zScript);
    if( g.iTrace ) logMessage("end script [%s]\n", argv[2]);
    waitForClient(0, 2000, "during shutdown...\n");
    trySql("UPDATE client SET wantHalt=1");
    sqlite3_sleep(10);
    g.iTimeout = 0;
    iTimeout = 1000;
    while( ((rc = trySql("SELECT 1 FROM client"))==SQLITE_BUSY
        || rc==SQLITE_ROW) && iTimeout>0 ){
      sqlite3_sleep(10);
      iTimeout -= 10;
    }
    sqlite3_sleep(100);
    pStmt = prepareSql("SELECT nError, nTest FROM counters");
    iTimeout = 1000;
    while( (rc = sqlite3_step(pStmt))==SQLITE_BUSY && iTimeout>0 ){
      sqlite3_sleep(10);
      iTimeout -= 10;
    }
    if( rc==SQLITE_ROW ){
      g.nError += sqlite3_column_int(pStmt, 0);
      g.nTest += sqlite3_column_int(pStmt, 1);
    }
    sqlite3_finalize(pStmt);
  }
  sqlite3_close(g.db);  
  maybeClose(g.pLog);
  maybeClose(g.pErrLog);
  if( iClient==0 ){
    printf("Summary: %d errors in %d tests\n", g.nError, g.nTest);
  }
  return g.nError>0;
}
Example #21
0
static int
copy_database(sqlite3 *src, sqlite3 *dst, const char *name)
{
	sqlite3_backup	*b;
	char		*errmsg;
	off_t		 total;
	off_t		 done;
	off_t		 page_size;
	time_t		 start;
	time_t		 elapsed;
	int		 ret;

	assert(src != NULL);
	assert(dst != NULL);

	/* Do not remove until gcc has gone from FreeBSD base */
	done = total = 0;

	ret = sqlite3_exec(dst, "PRAGMA main.locking_mode=EXCLUSIVE;"
			   "BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);
	if (ret != SQLITE_OK) {
		pkg_emit_error("sqlite error -- %s", errmsg);
		sqlite3_free(errmsg);
		return (EPKG_FATAL);
	}

	ret = sqlite3_exec(dst, "PRAGMA page_size", ps_cb, &page_size, &errmsg);
	if (ret != SQLITE_OK) {
		pkg_emit_error("sqlite error -- %s", errmsg);
		sqlite3_free(errmsg);
		return (EPKG_FATAL);
	}

	b = sqlite3_backup_init(dst, "main", src, "main");

	elapsed = -1;
	done = total = 0;
	start = time(NULL);

	do {
		ret = sqlite3_backup_step(b, NPAGES);

		if (ret != SQLITE_OK && ret != SQLITE_DONE ) {
			if (ret == SQLITE_BUSY) {
				sqlite3_sleep(250);
			} else {
				ERROR_SQLITE(dst);
				break;
			}
		}

		total = sqlite3_backup_pagecount(b) * page_size;
		done = total - sqlite3_backup_remaining(b) * page_size; 

		/* Callout no more than once a second */
		if (elapsed < time(NULL) - start) {
			elapsed = time(NULL) - start;
			pkg_emit_fetching(name, total, done, elapsed);
		}
	} while(done < total);

	ret = sqlite3_backup_finish(b);
	pkg_emit_fetching(name, total, done, time(NULL) - start); 

	sqlite3_exec(dst, "PRAGMA main.locking_mode=NORMAL;"
			   "BEGIN IMMEDIATE;COMMIT;", NULL, NULL, &errmsg);

	if (ret != SQLITE_OK) {
		pkg_emit_error("sqlite error -- %s", errmsg);
		sqlite3_free(errmsg);
		return (EPKG_FATAL);
	}

	return ret;
}
Example #22
0
int
main(int argc, char **argv)
{
	sqlite3        *db;
	int		res;
	int		i;
	char           *query;
	char           *tmp;
	char           *err = NULL;
	int		maxretry = 10;
	int		retry = 0;
	sqlite3_stmt   *stmt;
	int		ret;

	if (argc < 3) {
		usage();
		return 0;
	}
	res = 0;
	for (i = 2; i < argc; i++)
		res += strlen(argv[i]) + 1;

	if (!res)
		return 1;

	if (SQLITE_OK != (res = sqlite3_open(argv[1], &db))) {
		printf("%s: Can't open database file: %s\n", nm(), argv[1]);
		return 1;
	}
	res = 0;
	for (i = 2; i < argc; i++)
		res += strlen(argv[i]) + 1;
	if (res) {
		query = (char *)sqlite3_malloc(res);
		tmp = query;
		for (i = 2; i < argc; i++) {
			strcpy(tmp, argv[i]);
			tmp += strlen(tmp);
			*tmp = ' ';
			tmp++;
		}
		tmp[-1] = 0;
	}
	ret = sqlite3_prepare_v2(db, query, strlen(query) + 1, &stmt, NULL);

	retry = 0;

	if (ret == SQLITE_OK) {
		while ((ret != SQLITE_DONE) && (retry < maxretry)) {
			ret = sqlite3_step(stmt);
			if (ret == SQLITE_ROW) {
				sqlCB(stmt);
				continue;
			}
			//
			else if (ret == SQLITE_BUSY) {
				sqlite3_sleep(5);
				retry++;
				//
			}
		}
	}
	sqlite3_finalize(stmt);

	sqlite3_free(query);
	sqlite3_close(db);

	//printf("ERR: %d(Q: %s)\n", ret, query);

	return 0;
}
Example #23
0
/*
** Look up the next task for client iClient in the database.
** Return the task script and the task number and mark that
** task as being under way.
*/
static int startScript(
  int iClient,              /* The client number */
  char **pzScript,          /* Write task script here */
  int *pTaskId,             /* Write task number here */
  char **pzTaskName         /* Name of the task */
){
  sqlite3_stmt *pStmt = 0;
  int taskId;
  int rc;
  int totalTime = 0;

  *pzScript = 0;
  g.iTimeout = 0;
  while(1){
    rc = trySql("BEGIN IMMEDIATE");
    if( rc==SQLITE_BUSY ){
      sqlite3_sleep(10);
      totalTime += 10;
      continue;
    }
    if( rc!=SQLITE_OK ){
      fatalError("in startScript: %s", sqlite3_errmsg(g.db));
    }
    if( g.nError || g.nTest ){
      runSql("UPDATE counters SET nError=nError+%d, nTest=nTest+%d",
             g.nError, g.nTest);
      g.nError = 0;
      g.nTest = 0;
    }
    pStmt = prepareSql("SELECT 1 FROM client WHERE id=%d AND wantHalt",iClient);
    rc = sqlite3_step(pStmt);
    sqlite3_finalize(pStmt);
    if( rc==SQLITE_ROW ){
      runSql("DELETE FROM client WHERE id=%d", iClient);
      g.iTimeout = DEFAULT_TIMEOUT;
      runSql("COMMIT TRANSACTION;");
      return SQLITE_DONE;
    }
    pStmt = prepareSql(
              "SELECT script, id, name FROM task"
              " WHERE client=%d AND starttime IS NULL"
              " ORDER BY id LIMIT 1", iClient);
    rc = sqlite3_step(pStmt);
    if( rc==SQLITE_ROW ){
      int n = sqlite3_column_bytes(pStmt, 0);
      *pzScript = sqlite3_malloc(n+1);
      strcpy(*pzScript, (const char*)sqlite3_column_text(pStmt, 0));
      *pTaskId = taskId = sqlite3_column_int(pStmt, 1);
      *pzTaskName = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 2));
      sqlite3_finalize(pStmt);
      runSql("UPDATE task"
             "   SET starttime=strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')"
             " WHERE id=%d;", taskId);
      g.iTimeout = DEFAULT_TIMEOUT;
      runSql("COMMIT TRANSACTION;");
      return SQLITE_OK;
    }
    sqlite3_finalize(pStmt);
    if( rc==SQLITE_DONE ){
      if( totalTime>30000 ){
        errorMessage("Waited over 30 seconds with no work.  Giving up.");
        runSql("DELETE FROM client WHERE id=%d; COMMIT;", iClient);
        sqlite3_close(g.db);
        exit(1);
      }
      while( trySql("COMMIT")==SQLITE_BUSY ){
        sqlite3_sleep(10);
        totalTime += 10;
      }
      sqlite3_sleep(100);
      totalTime += 100;
      continue;
    }
    fatalError("%s", sqlite3_errmsg(g.db));
  }
  g.iTimeout = DEFAULT_TIMEOUT;
}
Example #24
0
int SQLITE_CDECL main(int argc, char **argv){
  const char *zClient;
  int iClient;
  int n, i;
  int openFlags = SQLITE_OPEN_READWRITE;
  int rc;
  char *zScript;
  int taskId;
  const char *zTrace;
  const char *zCOption;
  const char *zJMode;
  const char *zNRep;
  int nRep = 1, iRep;
  int iTmout = 0;              /* Default: no timeout */
  const char *zTmout;

  g.argv0 = argv[0];
  g.iTrace = 1;
  if( argc<2 ) usage(argv[0]);
  g.zDbFile = argv[1];
  if( strglob("*.test", g.zDbFile) ) usage(argv[0]);
  if( strcmp(sqlite3_sourceid(), SQLITE_SOURCE_ID)!=0 ){
    fprintf(stderr, "SQLite library and header mismatch\n"
                    "Library: %s\n"
                    "Header:  %s\n",
                    sqlite3_sourceid(), SQLITE_SOURCE_ID);
    exit(1);
  }
  n = argc-2;
  sqlite3_snprintf(sizeof(g.zName), g.zName, "%05d.mptest", GETPID());
  zJMode = findOption(argv+2, &n, "journalmode", 1);
  zNRep = findOption(argv+2, &n, "repeat", 1);
  if( zNRep ) nRep = atoi(zNRep);
  if( nRep<1 ) nRep = 1;
  g.zVfs = findOption(argv+2, &n, "vfs", 1);
  zClient = findOption(argv+2, &n, "client", 1);
  g.zErrLog = findOption(argv+2, &n, "errlog", 1);
  g.zLog = findOption(argv+2, &n, "log", 1);
  zTrace = findOption(argv+2, &n, "trace", 1);
  if( zTrace ) g.iTrace = atoi(zTrace);
  if( findOption(argv+2, &n, "quiet", 0)!=0 ) g.iTrace = 0;
  zTmout = findOption(argv+2, &n, "timeout", 1);
  if( zTmout ) iTmout = atoi(zTmout);
  g.bSqlTrace = findOption(argv+2, &n, "sqltrace", 0)!=0;
  g.bSync = findOption(argv+2, &n, "sync", 0)!=0;
  if( g.zErrLog ){
    g.pErrLog = fopen(g.zErrLog, "a");
  }else{
    g.pErrLog = stderr;
  }
  if( g.zLog ){
    g.pLog = fopen(g.zLog, "a");
  }else{
    g.pLog = stdout;
  }
  
  sqlite3_config(SQLITE_CONFIG_LOG, sqlErrorCallback, 0);
  if( zClient ){
    iClient = atoi(zClient);
    if( iClient<1 ) fatalError("illegal client number: %d\n", iClient);
    sqlite3_snprintf(sizeof(g.zName), g.zName, "%05d.client%02d",
                     GETPID(), iClient);
  }else{
    int nTry = 0;
    if( g.iTrace>0 ){
      printf("BEGIN: %s", argv[0]);
      for(i=1; i<argc; i++) printf(" %s", argv[i]);
      printf("\n");
      printf("With SQLite " SQLITE_VERSION " " SQLITE_SOURCE_ID "\n" );
      for(i=0; (zCOption = sqlite3_compileoption_get(i))!=0; i++){
        printf("-DSQLITE_%s\n", zCOption);
      }
      fflush(stdout);
    }
    iClient =  0;
    do{
      if( (nTry%5)==4 ) printf("... %strying to unlink '%s'\n",
                               nTry>5 ? "still " : "", g.zDbFile);
      rc = unlink(g.zDbFile);
      if( rc && errno==ENOENT ) rc = 0;
    }while( rc!=0 && (++nTry)<60 && sqlite3_sleep(1000)>0 );
    if( rc!=0 ){
      fatalError("unable to unlink '%s' after %d attempts\n",
                 g.zDbFile, nTry);
    }
    openFlags |= SQLITE_OPEN_CREATE;
  }
  rc = sqlite3_open_v2(g.zDbFile, &g.db, openFlags, g.zVfs);
  if( rc ) fatalError("cannot open [%s]", g.zDbFile);
  if( iTmout>0 ) sqlite3_busy_timeout(g.db, iTmout);
  
  if( zJMode ){
#if defined(_WIN32)
    if( sqlite3_stricmp(zJMode,"persist")==0
     || sqlite3_stricmp(zJMode,"truncate")==0
    ){
      printf("Changing journal mode to DELETE from %s", zJMode);
      zJMode = "DELETE";
    }
#endif
    runSql("PRAGMA journal_mode=%Q;", zJMode);
  }
  if( !g.bSync ) trySql("PRAGMA synchronous=OFF");
  sqlite3_enable_load_extension(g.db, 1);
  sqlite3_busy_handler(g.db, busyHandler, 0);
  sqlite3_create_function(g.db, "vfsname", 0, SQLITE_UTF8, 0,
                          vfsNameFunc, 0, 0);
  sqlite3_create_function(g.db, "eval", 1, SQLITE_UTF8, 0,
                          evalFunc, 0, 0);
  g.iTimeout = DEFAULT_TIMEOUT;
  if( g.bSqlTrace ) sqlite3_trace(g.db, sqlTraceCallback, 0);
  if( iClient>0 ){
    if( n>0 ) unrecognizedArguments(argv[0], n, argv+2);
    if( g.iTrace ) logMessage("start-client");
    while(1){
      char *zTaskName = 0;
      rc = startScript(iClient, &zScript, &taskId, &zTaskName);
      if( rc==SQLITE_DONE ) break;
      if( g.iTrace ) logMessage("begin %s (%d)", zTaskName, taskId);
      runScript(iClient, taskId, zScript, zTaskName);
      if( g.iTrace ) logMessage("end %s (%d)", zTaskName, taskId);
      finishScript(iClient, taskId, 0);
      sqlite3_free(zTaskName);
      sqlite3_sleep(10);
    }
    if( g.iTrace ) logMessage("end-client");
  }else{
    sqlite3_stmt *pStmt;
    int iTimeout;
    if( n==0 ){
      fatalError("missing script filename");
    }
    if( n>1 ) unrecognizedArguments(argv[0], n, argv+2);
    runSql(
      "DROP TABLE IF EXISTS task;\n"
      "DROP TABLE IF EXISTS counters;\n"
      "DROP TABLE IF EXISTS client;\n"
      "CREATE TABLE task(\n"
      "  id INTEGER PRIMARY KEY,\n"
      "  name TEXT,\n"
      "  client INTEGER,\n"
      "  starttime DATE,\n"
      "  endtime DATE,\n"
      "  script TEXT\n"
      ");"
      "CREATE INDEX task_i1 ON task(client, starttime);\n"
      "CREATE INDEX task_i2 ON task(client, endtime);\n"
      "CREATE TABLE counters(nError,nTest);\n"
      "INSERT INTO counters VALUES(0,0);\n"
      "CREATE TABLE client(id INTEGER PRIMARY KEY, wantHalt);\n"
    );
    zScript = readFile(argv[2]);
    for(iRep=1; iRep<=nRep; iRep++){
      if( g.iTrace ) logMessage("begin script [%s] cycle %d\n", argv[2], iRep);
      runScript(0, 0, zScript, argv[2]);
      if( g.iTrace ) logMessage("end script [%s] cycle %d\n", argv[2], iRep);
    }
    sqlite3_free(zScript);
    waitForClient(0, 2000, "during shutdown...\n");
    trySql("UPDATE client SET wantHalt=1");
    sqlite3_sleep(10);
    g.iTimeout = 0;
    iTimeout = 1000;
    while( ((rc = trySql("SELECT 1 FROM client"))==SQLITE_BUSY
        || rc==SQLITE_ROW) && iTimeout>0 ){
      sqlite3_sleep(10);
      iTimeout -= 10;
    }
    sqlite3_sleep(100);
    pStmt = prepareSql("SELECT nError, nTest FROM counters");
    iTimeout = 1000;
    while( (rc = sqlite3_step(pStmt))==SQLITE_BUSY && iTimeout>0 ){
      sqlite3_sleep(10);
      iTimeout -= 10;
    }
    if( rc==SQLITE_ROW ){
      g.nError += sqlite3_column_int(pStmt, 0);
      g.nTest += sqlite3_column_int(pStmt, 1);
    }
    sqlite3_finalize(pStmt);
  }
  sqlite3_close(g.db);
  maybeClose(g.pLog);
  maybeClose(g.pErrLog);
  if( iClient==0 ){
    printf("Summary: %d errors out of %d tests\n", g.nError, g.nTest);
    printf("END: %s", argv[0]);
    for(i=1; i<argc; i++) printf(" %s", argv[i]);
    printf("\n");
  }
  return g.nError>0;
}