/////////////////////////////////////////////////////////////// // // CDatabaseManagerImpl::Disconnect // // // /////////////////////////////////////////////////////////////// bool CDatabaseManagerImpl::Disconnect ( uint hConnection ) { ClearLastErrorMessage (); // Check connection if ( !MapContains ( m_ConnectionTypeMap, hConnection ) ) { SetLastErrorMessage ( "Invalid connection" ); return false; } // Start disconnect CDbJobData* pJobData = m_JobQueue->AddCommand ( EJobCommand::DISCONNECT, hConnection, "" ); // Complete disconnect m_JobQueue->PollCommand ( pJobData, -1 ); // Check for problems if ( pJobData->result.status == EJobResult::FAIL ) { SetLastErrorMessage ( pJobData->result.strReason ); return false; } // Remove connection refs MapRemove ( m_ConnectionTypeMap, hConnection ); m_JobQueue->IgnoreConnectionResults ( hConnection ); return true; }
/////////////////////////////////////////////////////////////// // // CDatabaseManagerImpl::QueryWithCallbackf // // Start a query and direct the result through a callback // /////////////////////////////////////////////////////////////// bool CDatabaseManagerImpl::QueryWithCallbackf ( SConnectionHandle hConnection, PFN_DBRESULT pfnDbResult, void* pCallbackContext, const char* szQuery, ... ) { va_list vl; va_start ( vl, szQuery ); ClearLastErrorMessage (); // Check connection if ( !MapContains ( m_ConnectionTypeMap, hConnection ) ) { SetLastErrorMessage ( "Invalid connection" ); return NULL; } // Insert arguments with correct escapement SString strEscapedQuery = InsertQueryArguments ( hConnection, szQuery, vl ); // Start query CDbJobData* pJobData = m_JobQueue->AddCommand ( EJobCommand::QUERY, hConnection, strEscapedQuery ); // Set callback vars pJobData->SetCallback ( pfnDbResult, pCallbackContext ); return true; }
bool CRegistry::Exec ( const std::string& strQuery ) { if ( m_bOpened == false ) { SetLastErrorMessage ( "SQLite3 was not opened, cannot perform query!", strQuery ); return false; } BeginAutomaticTransaction (); return ExecInternal ( strQuery.c_str () ); }
/////////////////////////////////////////////////////////////// // // CDatabaseManagerImpl::QueryPoll // // ulTimeout = 0 - No wait if not ready // ulTimeout > 0 - Wait(ms) if not ready // ulTimeout = -1 - Wait infinity+1 if not ready // /////////////////////////////////////////////////////////////// bool CDatabaseManagerImpl::QueryPoll ( CDbJobData* pJobData, uint ulTimeout ) { ClearLastErrorMessage (); if ( m_JobQueue->PollCommand ( pJobData, ulTimeout ) ) { if ( pJobData->result.status == EJobResult::FAIL ) SetLastErrorMessage ( pJobData->result.strReason ); return true; } return false; }
bool CRegistry::ExecInternal ( const char* szQuery ) { TIMEUS startTime = GetTimeUs(); char *szErrorMsg = NULL; if ( sqlite3_exec ( m_db, szQuery, NULL, NULL, &szErrorMsg ) != SQLITE_OK ) { SetLastErrorMessage ( szErrorMsg, szQuery ); sqlite3_free ( szErrorMsg ); return false; } CPerfStatSqliteTiming::GetSingleton ()->UpdateSqliteTiming ( this, szQuery, GetTimeUs() - startTime ); return true; }
/////////////////////////////////////////////////////////////// // // CDatabaseManagerImpl::QueryStart // // Start a query // /////////////////////////////////////////////////////////////// CDbJobData* CDatabaseManagerImpl::QueryStart ( SConnectionHandle hConnection, const SString& strQuery, CLuaArguments* pArgs ) { ClearLastErrorMessage (); // Check connection if ( !MapContains ( m_ConnectionTypeMap, hConnection ) ) { SetLastErrorMessage ( "Invalid connection" ); return NULL; } // Insert arguments with correct escapement SString strEscapedQuery = InsertQueryArguments ( hConnection, strQuery, pArgs ); // Start query return m_JobQueue->AddCommand ( EJobCommand::QUERY, hConnection, strEscapedQuery ); }
bool CRegistry::Select ( const std::string& strColumns, const std::string& strTable, const std::string& strWhere, unsigned int uiLimit, CRegistryResult* pResult ) { char szBuffer[32] = {0}; std::string strQuery = "SELECT " + strColumns + " FROM " + strTable; if ( !strWhere.empty () ) strQuery += " WHERE " + strWhere; if ( uiLimit > 0 ) strQuery += " LIMIT " + std::string ( itoa ( uiLimit, szBuffer, 10 ) ); if ( m_bOpened == false ) { SetLastErrorMessage ( "SQLite3 was not opened, cannot get value!", strQuery ); return false; } // Execute the query return QueryInternal ( strQuery.c_str (), pResult ); }
/////////////////////////////////////////////////////////////// // // CDatabaseManagerImpl::QueryStartf // // // /////////////////////////////////////////////////////////////// CDbJobData* CDatabaseManagerImpl::QueryStartf ( SConnectionHandle hConnection, const char* szQuery, ... ) { va_list vl; va_start ( vl, szQuery ); ClearLastErrorMessage (); // Check connection if ( !MapContains ( m_ConnectionTypeMap, hConnection ) ) { SetLastErrorMessage ( "Invalid connection" ); return NULL; } // Insert arguments with correct escapement SString strEscapedQuery = InsertQueryArguments ( hConnection, szQuery, vl ); // Start query return m_JobQueue->AddCommand ( EJobCommand::QUERY, hConnection, strEscapedQuery ); }
/////////////////////////////////////////////////////////////// // // CDatabaseManagerImpl::DatabaseConnect // // strType is one of the supported database types i.e. "sqlite" // /////////////////////////////////////////////////////////////// uint CDatabaseManagerImpl::Connect ( const SString& strType, const SString& strHost, const SString& strUsername, const SString& strPassword, const SString& strOptions ) { ClearLastErrorMessage (); SString strCombo = strType + "\1" + strHost + "\1" + strUsername + "\1" + strPassword + "\1" + strOptions; // Start connect CDbJobData* pJobData = m_JobQueue->AddCommand ( EJobCommand::CONNECT, 0, strCombo ); // Complete connect m_JobQueue->PollCommand ( pJobData, -1 ); // Check for problems if ( pJobData->result.status == EJobResult::FAIL ) { SetLastErrorMessage ( pJobData->result.strReason ); return INVALID_DB_HANDLE; } // Process result MapSet ( m_ConnectionTypeMap, pJobData->result.connectionHandle, strType ); return pJobData->result.connectionHandle; }
/////////////////////////////////////////////////////////////// // // CDatabaseManagerImpl::QueryWithResultf // // Start a query and wait for the result // /////////////////////////////////////////////////////////////// bool CDatabaseManagerImpl::QueryWithResultf ( SConnectionHandle hConnection, CRegistryResult* pResult, const char* szQuery, ... ) { va_list vl; va_start ( vl, szQuery ); ClearLastErrorMessage (); // Check connection if ( !MapContains ( m_ConnectionTypeMap, hConnection ) ) { SetLastErrorMessage ( "Invalid connection" ); return false; } // Insert arguments with correct escapement SString strEscapedQuery = InsertQueryArguments ( hConnection, szQuery, vl ); // Start query CDbJobData* pJobData = m_JobQueue->AddCommand ( EJobCommand::QUERY, hConnection, strEscapedQuery ); // Wait for result QueryPoll ( pJobData, -1 ); // Process result if ( pJobData->result.status == EJobResult::FAIL ) { if ( pResult ) *pResult = CRegistryResult (); return false; } else { if ( pResult ) *pResult = pJobData->result.registryResult; return true; } }
bool CRegistry::Query ( CRegistryResult* pResult, const char* szQuery, va_list vl ) { // Clear result if ( pResult ) *pResult = CRegistryResult (); if ( m_bOpened == false ) { SetLastErrorMessage ( "SQLite3 was not opened, cannot perform query!", szQuery ); return false; } SString strParsedQuery; for ( unsigned int i = 0; szQuery[i] != '\0'; i++ ) { if ( szQuery[i] != SQL_VARIABLE_PLACEHOLDER ) { strParsedQuery += szQuery[i]; } else { switch ( va_arg( vl, int ) ) { case SQLITE_INTEGER: { int iValue = va_arg( vl, int ); strParsedQuery += SString ( "%d", iValue ); } break; case SQLITE_FLOAT: { double fValue = va_arg( vl, double ); strParsedQuery += SString ( "%f", fValue ); } break; case SQLITE_TEXT: { const char* szValue = va_arg( vl, const char* ); assert ( szValue ); strParsedQuery += SString ( "'%s'", SQLEscape ( szValue, true, false ).c_str () ); } break; case SQLITE_BLOB: { strParsedQuery += "CANT_DO_BLOBS_M8"; } break; case SQLITE_NULL: { strParsedQuery += "NULL"; } break; default: // someone passed a value without specifying its type assert ( 0 ); break; } } } va_end ( vl ); // VACUUM query does not work with transactions if ( strParsedQuery.BeginsWithI( "VACUUM" ) ) EndAutomaticTransaction (); else BeginAutomaticTransaction (); return QueryInternal ( strParsedQuery.c_str (), pResult ); }
bool CRegistry::Query ( const std::string& strQuery, CLuaArguments *pArgs, CRegistryResult* pResult ) { std::string strParsedQuery = ""; if ( m_bOpened == false ) { SetLastErrorMessage ( "SQLite3 was not opened, cannot perform query!", strQuery ); return false; } // Walk through the query and replace the variable placeholders with the actual variables unsigned int uiLen = strQuery.length (); unsigned int a = 0, type = 0; const char *szContent = NULL; char szBuffer[32] = {0}; for ( unsigned int i = 0; i < uiLen; i++ ) { if ( strQuery.at(i) == SQL_VARIABLE_PLACEHOLDER ) { // If the placeholder is found, replace it with the variable CLuaArgument *pArgument = (*pArgs)[a++]; // Check the type of the argument and convert it to a string we can process if ( pArgument ) { type = pArgument->GetType (); if ( type == LUA_TBOOLEAN ) { szContent = ( pArgument->GetBoolean() ) ? "true" : "false"; } else if ( type == LUA_TNUMBER ) { snprintf ( szBuffer, 31, "%f", pArgument->GetNumber () ); szContent = szBuffer; } else if ( type == LUA_TSTRING ) { szContent = pArgument->GetString ().c_str (); // If we have a string, add a quote at the beginning too strParsedQuery += '\''; } } // Copy the string into the query, and escape the single quotes as well if ( szContent ) { for ( unsigned int k = 0; szContent[k] != '\0'; k++ ) { if ( szContent[k] == '\'' ) strParsedQuery += '\''; strParsedQuery += szContent[k]; } // If we have a string, add a quote at the end too if ( type == LUA_TSTRING ) strParsedQuery += '\''; } else { // If we don't have any content, put just output 2 quotes to indicate an empty variable strParsedQuery += "\'\'"; } } else { // If we found a normal character, copy it into the destination buffer strParsedQuery += strQuery[i]; } } // Catch BEGIN/END/COMMIT TRANSACTION and ignore SString strTest = SString ( strParsedQuery ).ToUpper (); if ( strTest.find ( "TRANSACTION" ) != std::string::npos ) { strTest = strTest.Replace ( "\t", " " ).Replace ( " ", " ", true ).TrimStart ( " " ).TrimEnd ( " " ); if ( strTest.find ( "BEGIN" ) == 0 || strTest.find ( "END" ) == 0 || strTest.find ( "COMMIT" ) == 0 ) { return true; } } BeginAutomaticTransaction (); return QueryInternal ( strParsedQuery.c_str (), pResult ); }
bool CRegistry::QueryInternal ( const char* szQuery, CRegistryResult* ppResult ) { TIMEUS startTime = GetTimeUs(); // Prepare the query sqlite3_stmt* pStmt; if ( sqlite3_prepare ( m_db, szQuery, strlen ( szQuery ) + 1, &pStmt, NULL ) != SQLITE_OK ) { SetLastErrorMessage ( sqlite3_errmsg ( m_db ), szQuery ); return false; } CRegistryResult& pResult = *ppResult; // Get column names pResult->nColumns = sqlite3_column_count ( pStmt ); pResult->ColNames.clear (); for ( int i = 0; i < pResult->nColumns; i++ ) { pResult->ColNames.push_back ( sqlite3_column_name ( pStmt, i ) ); } // Fetch the rows pResult->nRows = 0; pResult->Data.clear (); int status; while ( (status = sqlite3_step(pStmt)) == SQLITE_ROW ) { pResult->Data.push_back ( vector < CRegistryResultCell > ( pResult->nColumns ) ); vector < CRegistryResultCell > & row = pResult->Data.back(); for ( int i = 0; i < pResult->nColumns; i++ ) { CRegistryResultCell& cell = row[i]; cell.nType = sqlite3_column_type ( pStmt, i ); switch ( cell.nType ) { case SQLITE_NULL: break; case SQLITE_INTEGER: cell.nVal = sqlite3_column_int ( pStmt, i ); break; case SQLITE_FLOAT: cell.fVal = (float)sqlite3_column_double ( pStmt, i ); break; case SQLITE_BLOB: cell.nLength = sqlite3_column_bytes ( pStmt, i ); if ( cell.nLength == 0 ) { cell.pVal = NULL; } else { cell.pVal = new unsigned char [ cell.nLength ]; memcpy ( cell.pVal, sqlite3_column_blob ( pStmt, i ), cell.nLength ); } break; default: cell.nLength = sqlite3_column_bytes ( pStmt, i ) + 1; cell.pVal = new unsigned char [ cell.nLength ]; memcpy ( cell.pVal, sqlite3_column_text ( pStmt, i ), cell.nLength ); break; } } pResult->nRows++; } // Did we leave the fetching loop because of an error? if ( status != SQLITE_DONE ) { SetLastErrorMessage ( sqlite3_errmsg ( m_db ), szQuery ); sqlite3_finalize ( pStmt ); return false; } // All done sqlite3_finalize ( pStmt ); CPerfStatSqliteTiming::GetSingleton ()->UpdateSqliteTiming ( this, szQuery, GetTimeUs() - startTime ); return true; }