/* ** 2017 January 31 ** ** The author disclaims copyright to this source code. In place of ** a legal notice, here is a blessing: ** ** May you do good and not evil. ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains the source code for a standalone program used to ** test the performance of the sessions module. Compile and run: ** ** ./session_speed_test -help ** ** for details. */ #include "sqlite3.h" #include #include #include #include #include /************************************************************************* ** Start of generic command line parser. */ #define CMDLINE_BARE 0 #define CMDLINE_INTEGER 1 #define CMDLINE_STRING 2 #define CMDLINE_BOOLEAN 3 typedef struct CmdLineOption CmdLineOption; struct CmdLineOption { const char *zText; /* Name of command line option */ const char *zHelp; /* Help text for option */ int eType; /* One of the CMDLINE_* values */ int iOff; /* Offset of output variable */ }; #define CMDLINE_INT32(x,y,z) {x, y, CMDLINE_INTEGER, z} #define CMDLINE_BOOL(x,y,z) {x, y, CMDLINE_BOOLEAN, z} #define CMDLINE_TEXT(x,y,z) {x, y, CMDLINE_STRING, z} #define CMDLINE_NONE(x,y,z) {x, y, CMDLINE_BARE, z} static void option_requires_argument_error(CmdLineOption *pOpt){ fprintf(stderr, "Option requires a%s argument: %s\n", pOpt->eType==CMDLINE_INTEGER ? "n integer" : pOpt->eType==CMDLINE_STRING ? " string" : " boolean", pOpt->zText ); exit(1); } static void ambiguous_option_error(const char *zArg){ fprintf(stderr, "Option is ambiguous: %s\n", zArg); exit(1); } static void unknown_option_error( const char *zArg, CmdLineOption *aOpt, const char *zHelp ){ int i; fprintf(stderr, "Unknown option: %s\n", zArg); fprintf(stderr, "\nOptions are:\n"); fprintf(stderr, " % -30sEcho command line options\n", "-cmdline:verbose"); for(i=0; aOpt[i].zText; i++){ int eType = aOpt[i].eType; char *zOpt = sqlite3_mprintf("%s %s", aOpt[i].zText, eType==CMDLINE_BARE ? "" : eType==CMDLINE_INTEGER ? "N" : eType==CMDLINE_BOOLEAN ? "BOOLEAN" : "TEXT" ); fprintf(stderr, " % -30s%s\n", zOpt, aOpt[i].zHelp); sqlite3_free(zOpt); } if( zHelp ){ fprintf(stderr, "\n%s\n", zHelp); } exit(1); } static int get_integer_option(CmdLineOption *pOpt, const char *zArg){ int i = 0; int iRet = 0; int bSign = 1; if( zArg[0]=='-' ){ bSign = -1; i = 1; } while( zArg[i] ){ if( zArg[i]<'0' || zArg[i]>'9' ) option_requires_argument_error(pOpt); iRet = iRet*10 + (zArg[i] - '0'); i++; } return (iRet*bSign); } static int get_boolean_option(CmdLineOption *pOpt, const char *zArg){ if( 0==sqlite3_stricmp(zArg, "true") ) return 1; if( 0==sqlite3_stricmp(zArg, "1") ) return 1; if( 0==sqlite3_stricmp(zArg, "0") ) return 0; if( 0==sqlite3_stricmp(zArg, "false") ) return 0; option_requires_argument_error(pOpt); return 0; } static void parse_command_line( int argc, char **argv, int iStart, CmdLineOption *aOpt, void *pStruct, const char *zHelp ){ char *pOut = (char*)pStruct; int bVerbose = 0; int iArg; for(iArg=iStart; iArgzText, zArg, nArg) ){ if( nMatch ){ ambiguous_option_error(zArg); } nMatch++; if( pOpt->eType==CMDLINE_BARE ){ *(int*)(&pOut[pOpt->iOff]) = 1; }else{ iArg++; if( iArg==argc ){ option_requires_argument_error(pOpt); } switch( pOpt->eType ){ case CMDLINE_INTEGER: *(int*)(&pOut[pOpt->iOff]) = get_integer_option(pOpt, argv[iArg]); break; case CMDLINE_STRING: *(const char**)(&pOut[pOpt->iOff]) = argv[iArg]; break; case CMDLINE_BOOLEAN: *(int*)(&pOut[pOpt->iOff]) = get_boolean_option(pOpt, argv[iArg]); break; } } } } if( nMatch==0 && 0==sqlite3_strnicmp("-cmdline:verbose", zArg, nArg) ){ bVerbose = 1; nMatch = 1; } if( nMatch==0 ){ unknown_option_error(zArg, aOpt, zHelp); } } if( bVerbose ){ int iOpt; fprintf(stdout, "Options are: "); for(iOpt=0; aOpt[iOpt].zText; iOpt++){ CmdLineOption *pOpt = &aOpt[iOpt]; if( pOpt->eType!=CMDLINE_BARE || *(int*)(&pOut[pOpt->iOff]) ){ fprintf(stdout, "%s ", pOpt->zText); } switch( pOpt->eType ){ case CMDLINE_INTEGER: fprintf(stdout, "%d ", *(int*)(&pOut[pOpt->iOff])); break; case CMDLINE_BOOLEAN: fprintf(stdout, "%d ", *(int*)(&pOut[pOpt->iOff])); break; case CMDLINE_STRING: fprintf(stdout, "%s ", *(const char**)(&pOut[pOpt->iOff])); break; } } fprintf(stdout, "\n"); } } /* ** End of generic command line parser. *************************************************************************/ static void abort_due_to_error(int rc){ fprintf(stderr, "Error: %d\n"); exit(-1); } static void execsql(sqlite3 *db, const char *zSql){ int rc = sqlite3_exec(db, zSql, 0, 0, 0); if( rc!=SQLITE_OK ) abort_due_to_error(rc); } static int xConflict(void *pCtx, int eConflict, sqlite3_changeset_iter *p){ return SQLITE_CHANGESET_ABORT; } static void run_test( sqlite3 *db, sqlite3 *db2, int nRow, const char *zSql ){ sqlite3_session *pSession = 0; sqlite3_stmt *pStmt = 0; int rc; int i; int nChangeset; void *pChangeset; /* Attach a session object to database db */ rc = sqlite3session_create(db, "main", &pSession); if( rc!=SQLITE_OK ) abort_due_to_error(rc); /* Configure the session to capture changes on all tables */ rc = sqlite3session_attach(pSession, 0); if( rc!=SQLITE_OK ) abort_due_to_error(rc); /* Prepare the SQL statement */ rc = sqlite3_prepare(db, zSql, -1, &pStmt, 0); if( rc!=SQLITE_OK ) abort_due_to_error(rc); /* Open a transaction */ execsql(db, "BEGIN"); /* Execute the SQL statement nRow times */ for(i=0; i