gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/mptest.c (about)

     1  // 2022-09-20 Modified version of mptest.c from SQLite 3.39.3
     2  //
     3  // Make timeouts 100 times longer.
     4  
     5  /*
     6  ** 2013-04-05
     7  **
     8  ** The author disclaims copyright to this source code.  In place of
     9  ** a legal notice, here is a blessing:
    10  **
    11  **    May you do good and not evil.
    12  **    May you find forgiveness for yourself and forgive others.
    13  **    May you share freely, never taking more than you give.
    14  **
    15  *************************************************************************
    16  ** 
    17  ** This is a program used for testing SQLite, and specifically for testing
    18  ** the ability of independent processes to access the same SQLite database
    19  ** concurrently.
    20  **
    21  ** Compile this program as follows:
    22  **
    23  **    gcc -g -c -Wall sqlite3.c $(OPTS)
    24  **    gcc -g -o mptest mptest.c sqlite3.o $(LIBS)
    25  **
    26  ** Recommended options:
    27  **
    28  **    -DHAVE_USLEEP
    29  **    -DSQLITE_NO_SYNC
    30  **    -DSQLITE_THREADSAFE=0
    31  **    -DSQLITE_OMIT_LOAD_EXTENSION
    32  **
    33  ** Run like this:
    34  **
    35  **     ./mptest $database $script
    36  **
    37  ** where $database is the database to use for testing and $script is a
    38  ** test script.
    39  */
    40  #include "sqlite3.h"
    41  #include <stdio.h>
    42  #if defined(_WIN32)
    43  # define WIN32_LEAN_AND_MEAN
    44  # include <windows.h>
    45  #else
    46  # include <unistd.h>
    47  #endif
    48  #include <errno.h>
    49  #include <stdlib.h>
    50  #include <string.h>
    51  #include <assert.h>
    52  #include <ctype.h>
    53  
    54  #define ISSPACE(X) isspace((unsigned char)(X))
    55  #define ISDIGIT(X) isdigit((unsigned char)(X))
    56  
    57  /* The suffix to append to the child command lines, if any */
    58  #if defined(_WIN32)
    59  # define GETPID (int)GetCurrentProcessId
    60  #else
    61  # define GETPID getpid
    62  #endif
    63  
    64  /* The directory separator character(s) */
    65  #if defined(_WIN32)
    66  # define isDirSep(c) (((c) == '/') || ((c) == '\\'))
    67  #else
    68  # define isDirSep(c) ((c) == '/')
    69  #endif
    70  
    71  /* Mark a parameter as unused to suppress compiler warnings */
    72  #define UNUSED_PARAMETER(x)  (void)x
    73  
    74  /* Global data
    75  */
    76  static struct Global {
    77    char *argv0;           /* Name of the executable */
    78    const char *zVfs;      /* Name of VFS to use. Often NULL meaning "default" */
    79    char *zDbFile;         /* Name of the database */
    80    sqlite3 *db;           /* Open connection to database */
    81    char *zErrLog;         /* Filename for error log */
    82    FILE *pErrLog;         /* Where to write errors */
    83    char *zLog;            /* Name of output log file */
    84    FILE *pLog;            /* Where to write log messages */
    85    char zName[32];        /* Symbolic name of this process */
    86    int taskId;            /* Task ID.  0 means supervisor. */
    87    int iTrace;            /* Tracing level */
    88    int bSqlTrace;         /* True to trace SQL commands */
    89    int bIgnoreSqlErrors;  /* Ignore errors in SQL statements */
    90    int nError;            /* Number of errors */
    91    int nTest;             /* Number of --match operators */
    92    int iTimeout;          /* Milliseconds until a busy timeout */
    93    int bSync;             /* Call fsync() */
    94  } g;
    95  
    96  /* Default timeout */
    97  #define DEFAULT_TIMEOUT 1000000
    98  
    99  /*
   100  ** Print a message adding zPrefix[] to the beginning of every line.
   101  */
   102  static void printWithPrefix(FILE *pOut, const char *zPrefix, const char *zMsg){
   103    while( zMsg && zMsg[0] ){
   104      int i;
   105      for(i=0; zMsg[i] && zMsg[i]!='\n' && zMsg[i]!='\r'; i++){}
   106      fprintf(pOut, "%s%.*s\n", zPrefix, i, zMsg);
   107      zMsg += i;
   108      while( zMsg[0]=='\n' || zMsg[0]=='\r' ) zMsg++;
   109    }
   110  }
   111  
   112  /*
   113  ** Compare two pointers to strings, where the pointers might be NULL.
   114  */
   115  static int safe_strcmp(const char *a, const char *b){
   116    if( a==b ) return 0;
   117    if( a==0 ) return -1;
   118    if( b==0 ) return 1;
   119    return strcmp(a,b);
   120  }
   121  
   122  /*
   123  ** Return TRUE if string z[] matches glob pattern zGlob[].
   124  ** Return FALSE if the pattern does not match.
   125  **
   126  ** Globbing rules:
   127  **
   128  **      '*'       Matches any sequence of zero or more characters.
   129  **
   130  **      '?'       Matches exactly one character.
   131  **
   132  **     [...]      Matches one character from the enclosed list of
   133  **                characters.
   134  **
   135  **     [^...]     Matches one character not in the enclosed list.
   136  **
   137  **      '#'       Matches any sequence of one or more digits with an
   138  **                optional + or - sign in front
   139  */
   140  int strglob(const char *zGlob, const char *z){
   141    int c, c2;
   142    int invert;
   143    int seen;
   144  
   145    while( (c = (*(zGlob++)))!=0 ){
   146      if( c=='*' ){
   147        while( (c=(*(zGlob++))) == '*' || c=='?' ){
   148          if( c=='?' && (*(z++))==0 ) return 0;
   149        }
   150        if( c==0 ){
   151          return 1;
   152        }else if( c=='[' ){
   153          while( *z && strglob(zGlob-1,z) ){
   154            z++;
   155          }
   156          return (*z)!=0;
   157        }
   158        while( (c2 = (*(z++)))!=0 ){
   159          while( c2!=c ){
   160            c2 = *(z++);
   161            if( c2==0 ) return 0;
   162          }
   163          if( strglob(zGlob,z) ) return 1;
   164        }
   165        return 0;
   166      }else if( c=='?' ){
   167        if( (*(z++))==0 ) return 0;
   168      }else if( c=='[' ){
   169        int prior_c = 0;
   170        seen = 0;
   171        invert = 0;
   172        c = *(z++);
   173        if( c==0 ) return 0;
   174        c2 = *(zGlob++);
   175        if( c2=='^' ){
   176          invert = 1;
   177          c2 = *(zGlob++);
   178        }
   179        if( c2==']' ){
   180          if( c==']' ) seen = 1;
   181          c2 = *(zGlob++);
   182        }
   183        while( c2 && c2!=']' ){
   184          if( c2=='-' && zGlob[0]!=']' && zGlob[0]!=0 && prior_c>0 ){
   185            c2 = *(zGlob++);
   186            if( c>=prior_c && c<=c2 ) seen = 1;
   187            prior_c = 0;
   188          }else{
   189            if( c==c2 ){
   190              seen = 1;
   191            }
   192            prior_c = c2;
   193          }
   194          c2 = *(zGlob++);
   195        }
   196        if( c2==0 || (seen ^ invert)==0 ) return 0;
   197      }else if( c=='#' ){
   198        if( (z[0]=='-' || z[0]=='+') && ISDIGIT(z[1]) ) z++;
   199        if( !ISDIGIT(z[0]) ) return 0;
   200        z++;
   201        while( ISDIGIT(z[0]) ){ z++; }
   202      }else{
   203        if( c!=(*(z++)) ) return 0;
   204      }
   205    }
   206    return *z==0;
   207  }
   208  
   209  /*
   210  ** Close output stream pOut if it is not stdout or stderr
   211  */
   212  static void maybeClose(FILE *pOut){
   213    if( pOut!=stdout && pOut!=stderr ) fclose(pOut);
   214  }
   215  
   216  /*
   217  ** Print an error message
   218  */
   219  static void errorMessage(const char *zFormat, ...){
   220    va_list ap;
   221    char *zMsg;
   222    char zPrefix[30];
   223    va_start(ap, zFormat);
   224    zMsg = sqlite3_vmprintf(zFormat, ap);
   225    va_end(ap);
   226    sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:ERROR: ", g.zName);
   227    if( g.pLog ){
   228      printWithPrefix(g.pLog, zPrefix, zMsg);
   229      fflush(g.pLog);
   230    }
   231    if( g.pErrLog && safe_strcmp(g.zErrLog,g.zLog) ){
   232      printWithPrefix(g.pErrLog, zPrefix, zMsg);
   233      fflush(g.pErrLog);
   234    }
   235    sqlite3_free(zMsg);
   236    g.nError++;
   237  }
   238  
   239  /* Forward declaration */
   240  static int trySql(const char*, ...);
   241  
   242  /*
   243  ** Print an error message and then quit.
   244  */
   245  static void fatalError(const char *zFormat, ...){
   246    va_list ap;
   247    char *zMsg;
   248    char zPrefix[30];
   249    va_start(ap, zFormat);
   250    zMsg = sqlite3_vmprintf(zFormat, ap);
   251    va_end(ap);
   252    sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s:FATAL: ", g.zName);
   253    if( g.pLog ){
   254      printWithPrefix(g.pLog, zPrefix, zMsg);
   255      fflush(g.pLog);
   256      maybeClose(g.pLog);
   257    }
   258    if( g.pErrLog && safe_strcmp(g.zErrLog,g.zLog) ){
   259      printWithPrefix(g.pErrLog, zPrefix, zMsg);
   260      fflush(g.pErrLog);
   261      maybeClose(g.pErrLog);
   262    }
   263    sqlite3_free(zMsg);
   264    if( g.db ){
   265      int nTry = 0;
   266      g.iTimeout = 0;
   267      while( trySql("UPDATE client SET wantHalt=1;")==SQLITE_BUSY
   268             && (nTry++)<100 ){
   269        sqlite3_sleep(10);
   270      }
   271    }
   272    sqlite3_close(g.db);
   273    exit(1);  
   274  }
   275  
   276  
   277  /*
   278  ** Print a log message
   279  */
   280  static void logMessage(const char *zFormat, ...){
   281    va_list ap;
   282    char *zMsg;
   283    char zPrefix[30];
   284    va_start(ap, zFormat);
   285    zMsg = sqlite3_vmprintf(zFormat, ap);
   286    va_end(ap);
   287    sqlite3_snprintf(sizeof(zPrefix), zPrefix, "%s: ", g.zName);
   288    if( g.pLog ){
   289      printWithPrefix(g.pLog, zPrefix, zMsg);
   290      fflush(g.pLog);
   291    }
   292    sqlite3_free(zMsg);
   293  }
   294  
   295  /*
   296  ** Return the length of a string omitting trailing whitespace
   297  */
   298  static int clipLength(const char *z){
   299    int n = (int)strlen(z);
   300    while( n>0 && ISSPACE(z[n-1]) ){ n--; }
   301    return n;
   302  }
   303  
   304  /*
   305  ** Auxiliary SQL function to return the name of the VFS
   306  */
   307  static void vfsNameFunc(
   308    sqlite3_context *context,
   309    int argc,
   310    sqlite3_value **argv
   311  ){
   312    sqlite3 *db = sqlite3_context_db_handle(context);
   313    char *zVfs = 0;
   314    UNUSED_PARAMETER(argc);
   315    UNUSED_PARAMETER(argv);
   316    sqlite3_file_control(db, "main", SQLITE_FCNTL_VFSNAME, &zVfs);
   317    if( zVfs ){
   318      sqlite3_result_text(context, zVfs, -1, sqlite3_free);
   319    }
   320  }
   321  
   322  /*
   323  ** Busy handler with a g.iTimeout-millisecond timeout
   324  */
   325  static int busyHandler(void *pCD, int count){
   326    UNUSED_PARAMETER(pCD);
   327    if( count*10>g.iTimeout ){
   328      if( g.iTimeout>0 ) errorMessage("timeout after %dms", g.iTimeout);
   329      return 0;
   330    }
   331    sqlite3_sleep(10);
   332    return 1;
   333  }
   334  
   335  /*
   336  ** SQL Trace callback
   337  */
   338  static void sqlTraceCallback(void *NotUsed1, const char *zSql){
   339    UNUSED_PARAMETER(NotUsed1);
   340    logMessage("[%.*s]", clipLength(zSql), zSql);
   341  }
   342  
   343  /*
   344  ** SQL error log callback
   345  */
   346  static void sqlErrorCallback(void *pArg, int iErrCode, const char *zMsg){
   347    UNUSED_PARAMETER(pArg);
   348    if( iErrCode==SQLITE_ERROR && g.bIgnoreSqlErrors ) return;
   349    if( (iErrCode&0xff)==SQLITE_SCHEMA && g.iTrace<3 ) return;
   350    if( g.iTimeout==0 && (iErrCode&0xff)==SQLITE_BUSY && g.iTrace<3 ) return;
   351    if( (iErrCode&0xff)==SQLITE_NOTICE ){
   352      logMessage("(info) %s", zMsg);
   353    }else{
   354      errorMessage("(errcode=%d) %s", iErrCode, zMsg);
   355    }
   356  }
   357  
   358  /*
   359  ** Prepare an SQL statement.  Issue a fatal error if unable.
   360  */
   361  static sqlite3_stmt *prepareSql(const char *zFormat, ...){
   362    va_list ap;
   363    char *zSql;
   364    int rc;
   365    sqlite3_stmt *pStmt = 0;
   366    va_start(ap, zFormat);
   367    zSql = sqlite3_vmprintf(zFormat, ap);
   368    va_end(ap);
   369    rc = sqlite3_prepare_v2(g.db, zSql, -1, &pStmt, 0);
   370    if( rc!=SQLITE_OK ){
   371      sqlite3_finalize(pStmt);
   372      fatalError("%s\n%s\n", sqlite3_errmsg(g.db), zSql);
   373    }
   374    sqlite3_free(zSql);
   375    return pStmt;
   376  }
   377  
   378  /*
   379  ** Run arbitrary SQL.  Issue a fatal error on failure.
   380  */
   381  static void runSql(const char *zFormat, ...){
   382    va_list ap;
   383    char *zSql;
   384    int rc;
   385    va_start(ap, zFormat);
   386    zSql = sqlite3_vmprintf(zFormat, ap);
   387    va_end(ap);
   388    rc = sqlite3_exec(g.db, zSql, 0, 0, 0);
   389    if( rc!=SQLITE_OK ){
   390      fatalError("%s\n%s\n", sqlite3_errmsg(g.db), zSql);
   391    }
   392    sqlite3_free(zSql);
   393  }
   394  
   395  /*
   396  ** Try to run arbitrary SQL.  Return success code.
   397  */
   398  static int trySql(const char *zFormat, ...){
   399    va_list ap;
   400    char *zSql;
   401    int rc;
   402    va_start(ap, zFormat);
   403    zSql = sqlite3_vmprintf(zFormat, ap);
   404    va_end(ap);
   405    rc = sqlite3_exec(g.db, zSql, 0, 0, 0);
   406    sqlite3_free(zSql);
   407    return rc;
   408  }
   409  
   410  /* Structure for holding an arbitrary length string
   411  */
   412  typedef struct String String;
   413  struct String {
   414    char *z;         /* the string */
   415    int n;           /* Slots of z[] used */
   416    int nAlloc;      /* Slots of z[] allocated */
   417  };
   418  
   419  /* Free a string */
   420  static void stringFree(String *p){
   421    if( p->z ) sqlite3_free(p->z);
   422    memset(p, 0, sizeof(*p));
   423  }
   424  
   425  /* Append n bytes of text to a string.  If n<0 append the entire string. */
   426  static void stringAppend(String *p, const char *z, int n){
   427    if( n<0 ) n = (int)strlen(z);
   428    if( p->n+n>=p->nAlloc ){
   429      int nAlloc = p->nAlloc*2 + n + 100;
   430      char *zNew = sqlite3_realloc(p->z, nAlloc);
   431      if( zNew==0 ) fatalError("out of memory");
   432      p->z = zNew;
   433      p->nAlloc = nAlloc;
   434    }
   435    memcpy(p->z+p->n, z, n);
   436    p->n += n;
   437    p->z[p->n] = 0;
   438  }
   439  
   440  /* Reset a string to an empty string */
   441  static void stringReset(String *p){
   442    if( p->z==0 ) stringAppend(p, " ", 1);
   443    p->n = 0;
   444    p->z[0] = 0;
   445  }
   446  
   447  /* Append a new token onto the end of the string */
   448  static void stringAppendTerm(String *p, const char *z){
   449    int i;
   450    if( p->n ) stringAppend(p, " ", 1);
   451    if( z==0 ){
   452      stringAppend(p, "nil", 3);
   453      return;
   454    }
   455    for(i=0; z[i] && !ISSPACE(z[i]); i++){}
   456    if( i>0 && z[i]==0 ){
   457      stringAppend(p, z, i);
   458      return;
   459    }
   460    stringAppend(p, "'", 1);
   461    while( z[0] ){
   462      for(i=0; z[i] && z[i]!='\''; i++){}
   463      if( z[i] ){
   464        stringAppend(p, z, i+1);
   465        stringAppend(p, "'", 1);
   466        z += i+1;
   467      }else{
   468        stringAppend(p, z, i);
   469        break;
   470      }
   471    }
   472    stringAppend(p, "'", 1);
   473  }
   474  
   475  /*
   476  ** Callback function for evalSql()
   477  */
   478  static int evalCallback(void *pCData, int argc, char **argv, char **azCol){
   479    String *p = (String*)pCData;
   480    int i;
   481    UNUSED_PARAMETER(azCol);
   482    for(i=0; i<argc; i++) stringAppendTerm(p, argv[i]);
   483    return 0;
   484  }
   485  
   486  /*
   487  ** Run arbitrary SQL and record the results in an output string
   488  ** given by the first parameter.
   489  */
   490  static int evalSql(String *p, const char *zFormat, ...){
   491    va_list ap;
   492    char *zSql;
   493    int rc;
   494    char *zErrMsg = 0;
   495    va_start(ap, zFormat);
   496    zSql = sqlite3_vmprintf(zFormat, ap);
   497    va_end(ap);
   498    assert( g.iTimeout>0 );
   499    rc = sqlite3_exec(g.db, zSql, evalCallback, p, &zErrMsg);
   500    sqlite3_free(zSql);
   501    if( rc ){
   502      char zErr[30];
   503      sqlite3_snprintf(sizeof(zErr), zErr, "error(%d)", rc);
   504      stringAppendTerm(p, zErr);
   505      if( zErrMsg ){
   506        stringAppendTerm(p, zErrMsg);
   507        sqlite3_free(zErrMsg);
   508      }
   509    }
   510    return rc;
   511  }
   512  
   513  /*
   514  ** Auxiliary SQL function to recursively evaluate SQL.
   515  */
   516  static void evalFunc(
   517    sqlite3_context *context,
   518    int argc,
   519    sqlite3_value **argv
   520  ){
   521    sqlite3 *db = sqlite3_context_db_handle(context);
   522    const char *zSql = (const char*)sqlite3_value_text(argv[0]);
   523    String res;
   524    char *zErrMsg = 0;
   525    int rc;
   526    UNUSED_PARAMETER(argc);
   527    memset(&res, 0, sizeof(res));
   528    rc = sqlite3_exec(db, zSql, evalCallback, &res, &zErrMsg);
   529    if( zErrMsg ){
   530      sqlite3_result_error(context, zErrMsg, -1);
   531      sqlite3_free(zErrMsg);
   532    }else if( rc ){
   533      sqlite3_result_error_code(context, rc);
   534    }else{
   535      sqlite3_result_text(context, res.z, -1, SQLITE_TRANSIENT);
   536    }
   537    stringFree(&res);
   538  }
   539  
   540  /*
   541  ** Look up the next task for client iClient in the database.
   542  ** Return the task script and the task number and mark that
   543  ** task as being under way.
   544  */
   545  static int startScript(
   546    int iClient,              /* The client number */
   547    char **pzScript,          /* Write task script here */
   548    int *pTaskId,             /* Write task number here */
   549    char **pzTaskName         /* Name of the task */
   550  ){
   551    sqlite3_stmt *pStmt = 0;
   552    int taskId;
   553    int rc;
   554    int totalTime = 0;
   555  
   556    *pzScript = 0;
   557    g.iTimeout = 0;
   558    while(1){
   559      rc = trySql("BEGIN IMMEDIATE");
   560      if( rc==SQLITE_BUSY ){
   561        sqlite3_sleep(10);
   562        totalTime += 10;
   563        continue;
   564      }
   565      if( rc!=SQLITE_OK ){
   566        fatalError("in startScript: %s", sqlite3_errmsg(g.db));
   567      }
   568      if( g.nError || g.nTest ){
   569        runSql("UPDATE counters SET nError=nError+%d, nTest=nTest+%d",
   570               g.nError, g.nTest);
   571        g.nError = 0;
   572        g.nTest = 0;
   573      }
   574      pStmt = prepareSql("SELECT 1 FROM client WHERE id=%d AND wantHalt",iClient);
   575      rc = sqlite3_step(pStmt);
   576      sqlite3_finalize(pStmt);
   577      if( rc==SQLITE_ROW ){
   578        runSql("DELETE FROM client WHERE id=%d", iClient);
   579        g.iTimeout = DEFAULT_TIMEOUT;
   580        runSql("COMMIT TRANSACTION;");
   581        return SQLITE_DONE;
   582      }
   583      pStmt = prepareSql(
   584                "SELECT script, id, name FROM task"
   585                " WHERE client=%d AND starttime IS NULL"
   586                " ORDER BY id LIMIT 1", iClient);
   587      rc = sqlite3_step(pStmt);
   588      if( rc==SQLITE_ROW ){
   589        int n = sqlite3_column_bytes(pStmt, 0);
   590        *pzScript = sqlite3_malloc(n+1);
   591        strcpy(*pzScript, (const char*)sqlite3_column_text(pStmt, 0));
   592        *pTaskId = taskId = sqlite3_column_int(pStmt, 1);
   593        *pzTaskName = sqlite3_mprintf("%s", sqlite3_column_text(pStmt, 2));
   594        sqlite3_finalize(pStmt);
   595        runSql("UPDATE task"
   596               "   SET starttime=strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')"
   597               " WHERE id=%d;", taskId);
   598        g.iTimeout = DEFAULT_TIMEOUT;
   599        runSql("COMMIT TRANSACTION;");
   600        return SQLITE_OK;
   601      }
   602      sqlite3_finalize(pStmt);
   603      if( rc==SQLITE_DONE ){
   604        if( totalTime>3000000 ){
   605          errorMessage("Waited over 3000 seconds with no work.  Giving up.");
   606          runSql("DELETE FROM client WHERE id=%d; COMMIT;", iClient);
   607          sqlite3_close(g.db);
   608          exit(1);
   609        }
   610        while( trySql("COMMIT")==SQLITE_BUSY ){
   611          sqlite3_sleep(10);
   612          totalTime += 10;
   613        }
   614        sqlite3_sleep(100);
   615        totalTime += 100;
   616        continue;
   617      }
   618      fatalError("%s", sqlite3_errmsg(g.db));
   619    }
   620    g.iTimeout = DEFAULT_TIMEOUT;
   621  }
   622  
   623  /*
   624  ** Mark a script as having finished.   Remove the CLIENT table entry
   625  ** if bShutdown is true.
   626  */
   627  static int finishScript(int iClient, int taskId, int bShutdown){
   628    runSql("UPDATE task"
   629           "   SET endtime=strftime('%%Y-%%m-%%d %%H:%%M:%%f','now')"
   630           " WHERE id=%d;", taskId);
   631    if( bShutdown ){
   632      runSql("DELETE FROM client WHERE id=%d", iClient);
   633    }
   634    return SQLITE_OK;
   635  }
   636  
   637  /*
   638  ** Start up a client process for iClient, if it is not already
   639  ** running.  If the client is already running, then this routine
   640  ** is a no-op.
   641  */
   642  static void startClient(int iClient){
   643    runSql("INSERT OR IGNORE INTO client VALUES(%d,0)", iClient);
   644    if( sqlite3_changes(g.db) ){
   645      char *zSys;
   646      int rc;
   647      zSys = sqlite3_mprintf("%s \"%s\" --client %d --trace %d",
   648                   g.argv0, g.zDbFile, iClient, g.iTrace);
   649      if( g.bSqlTrace ){
   650        zSys = sqlite3_mprintf("%z --sqltrace", zSys);
   651      }
   652      if( g.bSync ){
   653        zSys = sqlite3_mprintf("%z --sync", zSys);
   654      }
   655      if( g.zVfs ){
   656        zSys = sqlite3_mprintf("%z --vfs \"%s\"", zSys, g.zVfs);
   657      }
   658      if( g.iTrace>=2 ) logMessage("system('%q')", zSys);
   659  #if !defined(_WIN32)
   660      zSys = sqlite3_mprintf("%z &", zSys);
   661      rc = system(zSys);
   662      if( rc ) errorMessage("system() fails with error code %d", rc);
   663  #else
   664      {
   665        STARTUPINFOA startupInfo;
   666        PROCESS_INFORMATION processInfo;
   667        memset(&startupInfo, 0, sizeof(startupInfo));
   668        startupInfo.cb = sizeof(startupInfo);
   669        memset(&processInfo, 0, sizeof(processInfo));
   670        rc = CreateProcessA(NULL, zSys, NULL, NULL, FALSE, 0, NULL, NULL,
   671                          &startupInfo, &processInfo);
   672        if( rc ){
   673          CloseHandle(processInfo.hThread);
   674          CloseHandle(processInfo.hProcess);
   675        }else{
   676          errorMessage("CreateProcessA() fails with error code %lu",
   677                       GetLastError());
   678        }
   679      }
   680  #endif
   681      sqlite3_free(zSys);
   682    }
   683  }
   684  
   685  /*
   686  ** Read the entire content of a file into memory
   687  */
   688  static char *readFile(const char *zFilename){
   689    FILE *in = fopen(zFilename, "rb");
   690    long sz;
   691    char *z;
   692    if( in==0 ){
   693      fatalError("cannot open \"%s\" for reading", zFilename);
   694    }
   695    fseek(in, 0, SEEK_END);
   696    sz = ftell(in);
   697    rewind(in);
   698    z = sqlite3_malloc( sz+1 );
   699    sz = (long)fread(z, 1, sz, in);
   700    z[sz] = 0;
   701    fclose(in);
   702    return z;
   703  }
   704  
   705  /*
   706  ** Return the length of the next token.
   707  */
   708  static int tokenLength(const char *z, int *pnLine){
   709    int n = 0;
   710    if( ISSPACE(z[0]) || (z[0]=='/' && z[1]=='*') ){
   711      int inC = 0;
   712      int c;
   713      if( z[0]=='/' ){
   714        inC = 1;
   715        n = 2;
   716      }
   717      while( (c = z[n++])!=0 ){
   718        if( c=='\n' ) (*pnLine)++;
   719        if( ISSPACE(c) ) continue;
   720        if( inC && c=='*' && z[n]=='/' ){
   721          n++;
   722          inC = 0;
   723        }else if( !inC && c=='/' && z[n]=='*' ){
   724          n++;
   725          inC = 1;
   726        }else if( !inC ){
   727          break;
   728        }
   729      }
   730      n--;
   731    }else if( z[0]=='-' && z[1]=='-' ){
   732      for(n=2; z[n] && z[n]!='\n'; n++){}
   733      if( z[n] ){ (*pnLine)++; n++; }
   734    }else if( z[0]=='"' || z[0]=='\'' ){
   735      int delim = z[0];
   736      for(n=1; z[n]; n++){
   737        if( z[n]=='\n' ) (*pnLine)++;
   738        if( z[n]==delim ){
   739          n++;
   740          if( z[n+1]!=delim ) break;
   741        }
   742      }
   743    }else{
   744      int c;
   745      for(n=1; (c = z[n])!=0 && !ISSPACE(c) && c!='"' && c!='\'' && c!=';'; n++){}
   746    }
   747    return n;
   748  }
   749  
   750  /*
   751  ** Copy a single token into a string buffer.
   752  */
   753  static int extractToken(const char *zIn, int nIn, char *zOut, int nOut){
   754    int i;
   755    if( nIn<=0 ){
   756      zOut[0] = 0;
   757      return 0;
   758    }
   759    for(i=0; i<nIn && i<nOut-1 && !ISSPACE(zIn[i]); i++){ zOut[i] = zIn[i]; }
   760    zOut[i] = 0;
   761    return i;
   762  }
   763  
   764  /*
   765  ** Find the number of characters up to the start of the next "--end" token.
   766  */
   767  static int findEnd(const char *z, int *pnLine){
   768    int n = 0;
   769    while( z[n] && (strncmp(z+n,"--end",5) || !ISSPACE(z[n+5])) ){
   770      n += tokenLength(z+n, pnLine);
   771    }
   772    return n;
   773  }
   774  
   775  /*
   776  ** Find the number of characters up to the first character past the
   777  ** of the next "--endif"  or "--else" token. Nested --if commands are
   778  ** also skipped.
   779  */
   780  static int findEndif(const char *z, int stopAtElse, int *pnLine){
   781    int n = 0;
   782    while( z[n] ){
   783      int len = tokenLength(z+n, pnLine);
   784      if( (strncmp(z+n,"--endif",7)==0 && ISSPACE(z[n+7]))
   785       || (stopAtElse && strncmp(z+n,"--else",6)==0 && ISSPACE(z[n+6]))
   786      ){
   787        return n+len;
   788      }
   789      if( strncmp(z+n,"--if",4)==0 && ISSPACE(z[n+4]) ){
   790        int skip = findEndif(z+n+len, 0, pnLine);
   791        n += skip + len;
   792      }else{
   793        n += len;
   794      }
   795    }
   796    return n;
   797  }
   798  
   799  /*
   800  ** Wait for a client process to complete all its tasks
   801  */
   802  static void waitForClient(int iClient, int iTimeout, char *zErrPrefix){
   803    sqlite3_stmt *pStmt;
   804    int rc;
   805    if( iClient>0 ){
   806      pStmt = prepareSql(
   807                 "SELECT 1 FROM task"
   808                 " WHERE client=%d"
   809                 "   AND client IN (SELECT id FROM client)"
   810                 "  AND endtime IS NULL",
   811                 iClient);
   812    }else{
   813      pStmt = prepareSql(
   814                 "SELECT 1 FROM task"
   815                 " WHERE client IN (SELECT id FROM client)"
   816                 "   AND endtime IS NULL");
   817    }
   818    g.iTimeout = 0;
   819    while( ((rc = sqlite3_step(pStmt))==SQLITE_BUSY || rc==SQLITE_ROW)
   820      && iTimeout>0
   821    ){
   822      sqlite3_reset(pStmt);
   823      sqlite3_sleep(50);
   824      iTimeout -= 50;
   825    }
   826    sqlite3_finalize(pStmt);
   827    g.iTimeout = DEFAULT_TIMEOUT;
   828    if( rc!=SQLITE_DONE ){
   829      if( zErrPrefix==0 ) zErrPrefix = "";
   830      if( iClient>0 ){
   831        errorMessage("%stimeout waiting for client %d", zErrPrefix, iClient);
   832      }else{
   833        errorMessage("%stimeout waiting for all clients", zErrPrefix);
   834      }
   835    }
   836  }
   837  
   838  /* Return a pointer to the tail of a filename
   839  */
   840  static char *filenameTail(char *z){
   841    int i, j;
   842    for(i=j=0; z[i]; i++) if( isDirSep(z[i]) ) j = i+1;
   843    return z+j;
   844  }
   845  
   846  /*
   847  ** Interpret zArg as a boolean value.  Return either 0 or 1.
   848  */
   849  static int booleanValue(char *zArg){
   850    int i;
   851    if( zArg==0 ) return 0;
   852    for(i=0; zArg[i]>='0' && zArg[i]<='9'; i++){}
   853    if( i>0 && zArg[i]==0 ) return atoi(zArg);
   854    if( sqlite3_stricmp(zArg, "on")==0 || sqlite3_stricmp(zArg,"yes")==0 ){
   855      return 1;
   856    }
   857    if( sqlite3_stricmp(zArg, "off")==0 || sqlite3_stricmp(zArg,"no")==0 ){
   858      return 0;
   859    }
   860    errorMessage("unknown boolean: [%s]", zArg);
   861    return 0;
   862  }
   863  
   864  
   865  /* This routine exists as a convenient place to set a debugger
   866  ** breakpoint.
   867  */
   868  static void test_breakpoint(void){ static volatile int cnt = 0; cnt++; }
   869  
   870  /* Maximum number of arguments to a --command */
   871  #define MX_ARG 2
   872  
   873  /*
   874  ** Run a script.
   875  */
   876  static void runScript(
   877    int iClient,       /* The client number, or 0 for the master */
   878    int taskId,        /* The task ID for clients.  0 for master */
   879    char *zScript,     /* Text of the script */
   880    char *zFilename    /* File from which script was read. */
   881  ){
   882    int lineno = 1;
   883    int prevLine = 1;
   884    int ii = 0;
   885    int iBegin = 0;
   886    int n, c, j;
   887    int len;
   888    int nArg;
   889    String sResult;
   890    char zCmd[30];
   891    char zError[1000];
   892    char azArg[MX_ARG][100];
   893  
   894    memset(&sResult, 0, sizeof(sResult));
   895    stringReset(&sResult);
   896    while( (c = zScript[ii])!=0 ){
   897      prevLine = lineno;
   898      len = tokenLength(zScript+ii, &lineno);
   899      if( ISSPACE(c) || (c=='/' && zScript[ii+1]=='*') ){
   900        ii += len;
   901        continue;
   902      }
   903      if( c!='-' || zScript[ii+1]!='-' || !isalpha(zScript[ii+2]) ){
   904        ii += len;
   905        continue;
   906      }
   907  
   908      /* Run any prior SQL before processing the new --command */
   909      if( ii>iBegin ){
   910        char *zSql = sqlite3_mprintf("%.*s", ii-iBegin, zScript+iBegin);
   911        evalSql(&sResult, zSql);
   912        sqlite3_free(zSql);
   913        iBegin = ii + len;
   914      }
   915  
   916      /* Parse the --command */
   917      if( g.iTrace>=2 ) logMessage("%.*s", len, zScript+ii);
   918      n = extractToken(zScript+ii+2, len-2, zCmd, sizeof(zCmd));
   919      for(nArg=0; n<len-2 && nArg<MX_ARG; nArg++){
   920        while( n<len-2 && ISSPACE(zScript[ii+2+n]) ){ n++; }
   921        if( n>=len-2 ) break;
   922        n += extractToken(zScript+ii+2+n, len-2-n,
   923                          azArg[nArg], sizeof(azArg[nArg]));
   924      }
   925      for(j=nArg; j<MX_ARG; j++) azArg[j++][0] = 0;
   926  
   927      /*
   928      **  --sleep N
   929      **
   930      ** Pause for N milliseconds
   931      */
   932      if( strcmp(zCmd, "sleep")==0 ){
   933        sqlite3_sleep(atoi(azArg[0]));
   934      }else 
   935  
   936      /*
   937      **   --exit N
   938      **
   939      ** Exit this process.  If N>0 then exit without shutting down
   940      ** SQLite.  (In other words, simulate a crash.)
   941      */
   942      if( strcmp(zCmd, "exit")==0 ){
   943        int rc = atoi(azArg[0]);
   944        finishScript(iClient, taskId, 1);
   945        if( rc==0 ) sqlite3_close(g.db);
   946        exit(rc);
   947      }else
   948  
   949      /*
   950      **   --testcase NAME
   951      **
   952      ** Begin a new test case.  Announce in the log that the test case
   953      ** has begun.
   954      */
   955      if( strcmp(zCmd, "testcase")==0 ){
   956        if( g.iTrace==1 ) logMessage("%.*s", len - 1, zScript+ii);
   957        stringReset(&sResult);
   958      }else
   959  
   960      /*
   961      **   --finish
   962      **
   963      ** Mark the current task as having finished, even if it is not.
   964      ** This can be used in conjunction with --exit to simulate a crash.
   965      */
   966      if( strcmp(zCmd, "finish")==0 && iClient>0 ){
   967        finishScript(iClient, taskId, 1);
   968      }else
   969  
   970      /*
   971      **  --reset
   972      **
   973      ** Reset accumulated results back to an empty string
   974      */
   975      if( strcmp(zCmd, "reset")==0 ){
   976        stringReset(&sResult);
   977      }else
   978  
   979      /*
   980      **  --match ANSWER...
   981      **
   982      ** Check to see if output matches ANSWER.  Report an error if not.
   983      */
   984      if( strcmp(zCmd, "match")==0 ){
   985        int jj;
   986        char *zAns = zScript+ii;
   987        for(jj=7; jj<len-1 && ISSPACE(zAns[jj]); jj++){}
   988        zAns += jj;
   989        if( len-jj-1!=sResult.n || strncmp(sResult.z, zAns, len-jj-1) ){
   990          errorMessage("line %d of %s:\nExpected [%.*s]\n     Got [%s]",
   991            prevLine, zFilename, len-jj-1, zAns, sResult.z);
   992        }
   993        g.nTest++;
   994        stringReset(&sResult);
   995      }else
   996  
   997      /*
   998      **  --glob ANSWER...
   999      **  --notglob ANSWER....
  1000      **
  1001      ** Check to see if output does or does not match the glob pattern
  1002      ** ANSWER.
  1003      */
  1004      if( strcmp(zCmd, "glob")==0 || strcmp(zCmd, "notglob")==0 ){
  1005        int jj;
  1006        char *zAns = zScript+ii;
  1007        char *zCopy;
  1008        int isGlob = (zCmd[0]=='g');
  1009        for(jj=9-3*isGlob; jj<len-1 && ISSPACE(zAns[jj]); jj++){}
  1010        zAns += jj;
  1011        zCopy = sqlite3_mprintf("%.*s", len-jj-1, zAns);
  1012        if( (sqlite3_strglob(zCopy, sResult.z)==0)^isGlob ){
  1013          errorMessage("line %d of %s:\nExpected [%s]\n     Got [%s]",
  1014            prevLine, zFilename, zCopy, sResult.z);
  1015        }
  1016        sqlite3_free(zCopy);
  1017        g.nTest++;
  1018        stringReset(&sResult);
  1019      }else
  1020  
  1021      /*
  1022      **  --output
  1023      **
  1024      ** Output the result of the previous SQL.
  1025      */
  1026      if( strcmp(zCmd, "output")==0 ){
  1027        logMessage("%s", sResult.z);
  1028      }else
  1029  
  1030      /*
  1031      **  --source FILENAME
  1032      **
  1033      ** Run a subscript from a separate file.
  1034      */
  1035      if( strcmp(zCmd, "source")==0 ){
  1036        char *zNewFile, *zNewScript;
  1037        char *zToDel = 0;
  1038        zNewFile = azArg[0];
  1039        if( !isDirSep(zNewFile[0]) ){
  1040          int k;
  1041          for(k=(int)strlen(zFilename)-1; k>=0 && !isDirSep(zFilename[k]); k--){}
  1042          if( k>0 ){
  1043            zNewFile = zToDel = sqlite3_mprintf("%.*s/%s", k,zFilename,zNewFile);
  1044          }
  1045        }
  1046        zNewScript = readFile(zNewFile);
  1047        if( g.iTrace ) logMessage("begin script [%s]\n", zNewFile);
  1048        runScript(0, 0, zNewScript, zNewFile);
  1049        sqlite3_free(zNewScript);
  1050        if( g.iTrace ) logMessage("end script [%s]\n", zNewFile);
  1051        sqlite3_free(zToDel);
  1052      }else
  1053  
  1054      /*
  1055      **  --print MESSAGE....
  1056      **
  1057      ** Output the remainder of the line to the log file
  1058      */
  1059      if( strcmp(zCmd, "print")==0 ){
  1060        int jj;
  1061        for(jj=7; jj<len && ISSPACE(zScript[ii+jj]); jj++){}
  1062        logMessage("%.*s", len-jj, zScript+ii+jj);
  1063      }else
  1064  
  1065      /*
  1066      **  --if EXPR
  1067      **
  1068      ** Skip forward to the next matching --endif or --else if EXPR is false.
  1069      */
  1070      if( strcmp(zCmd, "if")==0 ){
  1071        int jj, rc;
  1072        sqlite3_stmt *pStmt;
  1073        for(jj=4; jj<len && ISSPACE(zScript[ii+jj]); jj++){}
  1074        pStmt = prepareSql("SELECT %.*s", len-jj, zScript+ii+jj);
  1075        rc = sqlite3_step(pStmt);
  1076        if( rc!=SQLITE_ROW || sqlite3_column_int(pStmt, 0)==0 ){
  1077          ii += findEndif(zScript+ii+len, 1, &lineno);
  1078        }
  1079        sqlite3_finalize(pStmt);
  1080      }else
  1081  
  1082      /*
  1083      **  --else
  1084      **
  1085      ** This command can only be encountered if currently inside an --if that
  1086      ** is true.  Skip forward to the next matching --endif.
  1087      */
  1088      if( strcmp(zCmd, "else")==0 ){
  1089        ii += findEndif(zScript+ii+len, 0, &lineno);
  1090      }else
  1091  
  1092      /*
  1093      **  --endif
  1094      **
  1095      ** This command can only be encountered if currently inside an --if that
  1096      ** is true or an --else of a false if.  This is a no-op.
  1097      */
  1098      if( strcmp(zCmd, "endif")==0 ){
  1099        /* no-op */
  1100      }else
  1101  
  1102      /*
  1103      **  --start CLIENT
  1104      **
  1105      ** Start up the given client.
  1106      */
  1107      if( strcmp(zCmd, "start")==0 && iClient==0 ){
  1108        int iNewClient = atoi(azArg[0]);
  1109        if( iNewClient>0 ){
  1110          startClient(iNewClient);
  1111        }
  1112      }else
  1113  
  1114      /*
  1115      **  --wait CLIENT TIMEOUT
  1116      **
  1117      ** Wait until all tasks complete for the given client.  If CLIENT is
  1118      ** "all" then wait for all clients to complete.  Wait no longer than
  1119      ** TIMEOUT milliseconds (default 10,000)
  1120      */
  1121      if( strcmp(zCmd, "wait")==0 && iClient==0 ){
  1122        int iTimeout = nArg>=2 ? atoi(azArg[1]) : DEFAULT_TIMEOUT;
  1123        sqlite3_snprintf(sizeof(zError),zError,"line %d of %s\n",
  1124                         prevLine, zFilename);
  1125        waitForClient(atoi(azArg[0]), iTimeout, zError);
  1126      }else
  1127  
  1128      /*
  1129      **  --task CLIENT
  1130      **     <task-content-here>
  1131      **  --end
  1132      **
  1133      ** Assign work to a client.  Start the client if it is not running
  1134      ** already.
  1135      */
  1136      if( strcmp(zCmd, "task")==0 && iClient==0 ){
  1137        int iTarget = atoi(azArg[0]);
  1138        int iEnd;
  1139        char *zTask;
  1140        char *zTName;
  1141        iEnd = findEnd(zScript+ii+len, &lineno);
  1142        if( iTarget<0 ){
  1143          errorMessage("line %d of %s: bad client number: %d",
  1144                       prevLine, zFilename, iTarget);
  1145        }else{
  1146          zTask = sqlite3_mprintf("%.*s", iEnd, zScript+ii+len);
  1147          if( nArg>1 ){
  1148            zTName = sqlite3_mprintf("%s", azArg[1]);
  1149          }else{
  1150            zTName = sqlite3_mprintf("%s:%d", filenameTail(zFilename), prevLine);
  1151          }
  1152          startClient(iTarget);
  1153          runSql("INSERT INTO task(client,script,name)"
  1154                 " VALUES(%d,'%q',%Q)", iTarget, zTask, zTName);
  1155          sqlite3_free(zTask);
  1156          sqlite3_free(zTName);
  1157        }
  1158        iEnd += tokenLength(zScript+ii+len+iEnd, &lineno);
  1159        len += iEnd;
  1160        iBegin = ii+len;
  1161      }else
  1162  
  1163      /*
  1164      **  --breakpoint
  1165      **
  1166      ** This command calls "test_breakpoint()" which is a routine provided
  1167      ** as a convenient place to set a debugger breakpoint.
  1168      */
  1169      if( strcmp(zCmd, "breakpoint")==0 ){
  1170        test_breakpoint();
  1171      }else
  1172  
  1173      /*
  1174      **  --show-sql-errors BOOLEAN
  1175      **
  1176      ** Turn display of SQL errors on and off.
  1177      */
  1178      if( strcmp(zCmd, "show-sql-errors")==0 ){
  1179        g.bIgnoreSqlErrors = nArg>=1 ? !booleanValue(azArg[0]) : 1;
  1180      }else
  1181  
  1182  
  1183      /* error */{
  1184        errorMessage("line %d of %s: unknown command --%s",
  1185                     prevLine, zFilename, zCmd);
  1186      }
  1187      ii += len;
  1188    }
  1189    if( iBegin<ii ){
  1190      char *zSql = sqlite3_mprintf("%.*s", ii-iBegin, zScript+iBegin);
  1191      runSql(zSql);
  1192      sqlite3_free(zSql);
  1193    }
  1194    stringFree(&sResult);
  1195  }
  1196  
  1197  /*
  1198  ** Look for a command-line option.  If present, return a pointer.
  1199  ** Return NULL if missing.
  1200  **
  1201  ** hasArg==0 means the option is a flag.  It is either present or not.
  1202  ** hasArg==1 means the option has an argument.  Return a pointer to the
  1203  ** argument.
  1204  */
  1205  static char *findOption(
  1206    char **azArg,
  1207    int *pnArg,
  1208    const char *zOption,
  1209    int hasArg
  1210  ){
  1211    int i, j;
  1212    char *zReturn = 0;
  1213    int nArg = *pnArg;
  1214  
  1215    assert( hasArg==0 || hasArg==1 );
  1216    for(i=0; i<nArg; i++){
  1217      const char *z;
  1218      if( i+hasArg >= nArg ) break;
  1219      z = azArg[i];
  1220      if( z[0]!='-' ) continue;
  1221      z++;
  1222      if( z[0]=='-' ){
  1223        if( z[1]==0 ) break;
  1224        z++;
  1225      }
  1226      if( strcmp(z,zOption)==0 ){
  1227        if( hasArg && i==nArg-1 ){
  1228          fatalError("command-line option \"--%s\" requires an argument", z);
  1229        }
  1230        if( hasArg ){
  1231          zReturn = azArg[i+1];
  1232        }else{
  1233          zReturn = azArg[i];
  1234        }
  1235        j = i+1+(hasArg!=0);
  1236        while( j<nArg ) azArg[i++] = azArg[j++];
  1237        *pnArg = i;
  1238        return zReturn;
  1239      }
  1240    }
  1241    return zReturn;
  1242  }
  1243  
  1244  /* Print a usage message for the program and exit */
  1245  static void usage(const char *argv0){
  1246    int i;
  1247    const char *zTail = argv0;
  1248    for(i=0; argv0[i]; i++){
  1249      if( isDirSep(argv0[i]) ) zTail = argv0+i+1;
  1250    }
  1251    fprintf(stderr,"Usage: %s DATABASE ?OPTIONS? ?SCRIPT?\n", zTail);
  1252    fprintf(stderr,
  1253      "Options:\n"
  1254      "   --errlog FILENAME           Write errors to FILENAME\n"
  1255      "   --journalmode MODE          Use MODE as the journal_mode\n"
  1256      "   --log FILENAME              Log messages to FILENAME\n"
  1257      "   --quiet                     Suppress unnecessary output\n"
  1258      "   --vfs NAME                  Use NAME as the VFS\n"
  1259      "   --repeat N                  Repeat the test N times\n"
  1260      "   --sqltrace                  Enable SQL tracing\n"
  1261      "   --sync                      Enable synchronous disk writes\n"
  1262      "   --timeout MILLISEC          Busy timeout is MILLISEC\n"
  1263      "   --trace BOOLEAN             Enable or disable tracing\n"
  1264    );
  1265    exit(1);
  1266  }
  1267  
  1268  /* Report on unrecognized arguments */
  1269  static void unrecognizedArguments(
  1270    const char *argv0,
  1271    int nArg,
  1272    char **azArg
  1273  ){
  1274    int i;
  1275    fprintf(stderr,"%s: unrecognized arguments:", argv0);
  1276    for(i=0; i<nArg; i++){
  1277      fprintf(stderr," %s", azArg[i]);
  1278    }
  1279    fprintf(stderr,"\n");
  1280    exit(1);
  1281  }
  1282  
  1283  int SQLITE_CDECL main(int argc, char **argv){
  1284    const char *zClient;
  1285    int iClient;
  1286    int n, i;
  1287    int openFlags = SQLITE_OPEN_READWRITE;
  1288    int rc;
  1289    char *zScript;
  1290    int taskId;
  1291    const char *zTrace;
  1292    const char *zCOption;
  1293    const char *zJMode;
  1294    const char *zNRep;
  1295    int nRep = 1, iRep;
  1296    int iTmout = 0;              /* Default: no timeout */
  1297    const char *zTmout;
  1298  
  1299    g.argv0 = argv[0];
  1300    g.iTrace = 1;
  1301    if( argc<2 ) usage(argv[0]);
  1302    g.zDbFile = argv[1];
  1303    if( strglob("*.test", g.zDbFile) ) usage(argv[0]);
  1304    if( strcmp(sqlite3_sourceid(), SQLITE_SOURCE_ID)!=0 ){
  1305      fprintf(stderr, "SQLite library and header mismatch\n"
  1306                      "Library: %s\n"
  1307                      "Header:  %s\n",
  1308                      sqlite3_sourceid(), SQLITE_SOURCE_ID);
  1309      exit(1);
  1310    }
  1311    n = argc-2;
  1312    sqlite3_snprintf(sizeof(g.zName), g.zName, "%05d.mptest", GETPID());
  1313    zJMode = findOption(argv+2, &n, "journalmode", 1);
  1314    zNRep = findOption(argv+2, &n, "repeat", 1);
  1315    if( zNRep ) nRep = atoi(zNRep);
  1316    if( nRep<1 ) nRep = 1;
  1317    g.zVfs = findOption(argv+2, &n, "vfs", 1);
  1318    zClient = findOption(argv+2, &n, "client", 1);
  1319    g.zErrLog = findOption(argv+2, &n, "errlog", 1);
  1320    g.zLog = findOption(argv+2, &n, "log", 1);
  1321    zTrace = findOption(argv+2, &n, "trace", 1);
  1322    if( zTrace ) g.iTrace = atoi(zTrace);
  1323    if( findOption(argv+2, &n, "quiet", 0)!=0 ) g.iTrace = 0;
  1324    zTmout = findOption(argv+2, &n, "timeout", 1);
  1325    if( zTmout ) iTmout = atoi(zTmout);
  1326    g.bSqlTrace = findOption(argv+2, &n, "sqltrace", 0)!=0;
  1327    g.bSync = findOption(argv+2, &n, "sync", 0)!=0;
  1328    if( g.zErrLog ){
  1329      g.pErrLog = fopen(g.zErrLog, "a");
  1330    }else{
  1331      g.pErrLog = stderr;
  1332    }
  1333    if( g.zLog ){
  1334      g.pLog = fopen(g.zLog, "a");
  1335    }else{
  1336      g.pLog = stdout;
  1337    }
  1338    
  1339    sqlite3_config(SQLITE_CONFIG_LOG, sqlErrorCallback, 0);
  1340    if( zClient ){
  1341      iClient = atoi(zClient);
  1342      if( iClient<1 ) fatalError("illegal client number: %d\n", iClient);
  1343      sqlite3_snprintf(sizeof(g.zName), g.zName, "%05d.client%02d",
  1344                       GETPID(), iClient);
  1345    }else{
  1346      int nTry = 0;
  1347      if( g.iTrace>0 ){
  1348        printf("BEGIN: %s", argv[0]);
  1349        for(i=1; i<argc; i++) printf(" %s", argv[i]);
  1350        printf("\n");
  1351        printf("With SQLite " SQLITE_VERSION " " SQLITE_SOURCE_ID "\n" );
  1352        for(i=0; (zCOption = sqlite3_compileoption_get(i))!=0; i++){
  1353          printf("-DSQLITE_%s\n", zCOption);
  1354        }
  1355        fflush(stdout);
  1356      }
  1357      iClient =  0;
  1358      do{
  1359        if( (nTry%5)==4 ) printf("... %strying to unlink '%s'\n",
  1360                                 nTry>5 ? "still " : "", g.zDbFile);
  1361        rc = unlink(g.zDbFile);
  1362        if( rc && errno==ENOENT ) rc = 0;
  1363      }while( rc!=0 && (++nTry)<60 && sqlite3_sleep(1000)>0 );
  1364      if( rc!=0 ){
  1365        fatalError("unable to unlink '%s' after %d attempts\n",
  1366                   g.zDbFile, nTry);
  1367      }
  1368      openFlags |= SQLITE_OPEN_CREATE;
  1369    }
  1370    rc = sqlite3_open_v2(g.zDbFile, &g.db, openFlags, g.zVfs);
  1371    if( rc ) fatalError("cannot open [%s]", g.zDbFile);
  1372    if( iTmout>0 ) sqlite3_busy_timeout(g.db, iTmout);
  1373    
  1374    if( zJMode ){
  1375  #if defined(_WIN32)
  1376      if( sqlite3_stricmp(zJMode,"persist")==0
  1377       || sqlite3_stricmp(zJMode,"truncate")==0
  1378      ){
  1379        printf("Changing journal mode to DELETE from %s", zJMode);
  1380        zJMode = "DELETE";
  1381      }
  1382  #endif
  1383      runSql("PRAGMA journal_mode=%Q;", zJMode);
  1384    }
  1385    if( !g.bSync ) trySql("PRAGMA synchronous=OFF");
  1386    sqlite3_enable_load_extension(g.db, 1);
  1387    sqlite3_busy_handler(g.db, busyHandler, 0);
  1388    sqlite3_create_function(g.db, "vfsname", 0, SQLITE_UTF8, 0,
  1389                            vfsNameFunc, 0, 0);
  1390    sqlite3_create_function(g.db, "eval", 1, SQLITE_UTF8, 0,
  1391                            evalFunc, 0, 0);
  1392    g.iTimeout = DEFAULT_TIMEOUT;
  1393    if( g.bSqlTrace ) sqlite3_trace(g.db, sqlTraceCallback, 0);
  1394    if( iClient>0 ){
  1395      if( n>0 ) unrecognizedArguments(argv[0], n, argv+2);
  1396      if( g.iTrace ) logMessage("start-client");
  1397      while(1){
  1398        char *zTaskName = 0;
  1399        rc = startScript(iClient, &zScript, &taskId, &zTaskName);
  1400        if( rc==SQLITE_DONE ) break;
  1401        if( g.iTrace ) logMessage("begin %s (%d)", zTaskName, taskId);
  1402        runScript(iClient, taskId, zScript, zTaskName);
  1403        if( g.iTrace ) logMessage("end %s (%d)", zTaskName, taskId);
  1404        finishScript(iClient, taskId, 0);
  1405        sqlite3_free(zTaskName);
  1406        sqlite3_sleep(10);
  1407      }
  1408      if( g.iTrace ) logMessage("end-client");
  1409    }else{
  1410      sqlite3_stmt *pStmt;
  1411      int iTimeout;
  1412      if( n==0 ){
  1413        fatalError("missing script filename");
  1414      }
  1415      if( n>1 ) unrecognizedArguments(argv[0], n, argv+2);
  1416      runSql(
  1417        "DROP TABLE IF EXISTS task;\n"
  1418        "DROP TABLE IF EXISTS counters;\n"
  1419        "DROP TABLE IF EXISTS client;\n"
  1420        "CREATE TABLE task(\n"
  1421        "  id INTEGER PRIMARY KEY,\n"
  1422        "  name TEXT,\n"
  1423        "  client INTEGER,\n"
  1424        "  starttime DATE,\n"
  1425        "  endtime DATE,\n"
  1426        "  script TEXT\n"
  1427        ");"
  1428        "CREATE INDEX task_i1 ON task(client, starttime);\n"
  1429        "CREATE INDEX task_i2 ON task(client, endtime);\n"
  1430        "CREATE TABLE counters(nError,nTest);\n"
  1431        "INSERT INTO counters VALUES(0,0);\n"
  1432        "CREATE TABLE client(id INTEGER PRIMARY KEY, wantHalt);\n"
  1433      );
  1434      zScript = readFile(argv[2]);
  1435      for(iRep=1; iRep<=nRep; iRep++){
  1436        if( g.iTrace ) logMessage("begin script [%s] cycle %d\n", argv[2], iRep);
  1437        runScript(0, 0, zScript, argv[2]);
  1438        if( g.iTrace ) logMessage("end script [%s] cycle %d\n", argv[2], iRep);
  1439      }
  1440      sqlite3_free(zScript);
  1441      waitForClient(0, 2000, "during shutdown...\n");
  1442      trySql("UPDATE client SET wantHalt=1");
  1443      sqlite3_sleep(10);
  1444      g.iTimeout = 0;
  1445      iTimeout = 1000;
  1446      while( ((rc = trySql("SELECT 1 FROM client"))==SQLITE_BUSY
  1447          || rc==SQLITE_ROW) && iTimeout>0 ){
  1448        sqlite3_sleep(10);
  1449        iTimeout -= 10;
  1450      }
  1451      sqlite3_sleep(100);
  1452      pStmt = prepareSql("SELECT nError, nTest FROM counters");
  1453      iTimeout = 1000;
  1454      while( (rc = sqlite3_step(pStmt))==SQLITE_BUSY && iTimeout>0 ){
  1455        sqlite3_sleep(10);
  1456        iTimeout -= 10;
  1457      }
  1458      if( rc==SQLITE_ROW ){
  1459        g.nError += sqlite3_column_int(pStmt, 0);
  1460        g.nTest += sqlite3_column_int(pStmt, 1);
  1461      }
  1462      sqlite3_finalize(pStmt);
  1463    }
  1464    sqlite3_close(g.db);
  1465    maybeClose(g.pLog);
  1466    maybeClose(g.pErrLog);
  1467    if( iClient==0 ){
  1468      printf("Summary: %d errors out of %d tests\n", g.nError, g.nTest);
  1469      printf("END: %s", argv[0]);
  1470      for(i=1; i<argc; i++) printf(" %s", argv[i]);
  1471      printf("\n");
  1472    }
  1473    return g.nError>0;
  1474  }