QStringList Project::databaseFieldList( const QString &connection, const QString &table ) { DatabaseConnection *conn = databaseConnection( connection ); if ( !conn ) return QStringList(); return conn->fields( table ); }
/** * * We received a disconnect signal. Lets cleanup the connection in question * * @param args The arguments passed from the database * @return void */ void DatabaseConnectionManager::disconnected(const VariantVector &args) { DatabaseConnection *connection; std::string uuid; Variant uid = args.data()[0]; uuid = uid.toString(); // Find connection connection = disconnectingConnections[uuid]; // Stop running connection->stop(); // Wait for the connection to finish while (!connection->isFinished()) { // Process any pending events Application::getInstance()->processEvents(); // Sleep for 30ms. usleep(30 * 1000); } // Remove from collection disconnectingConnections.erase(uuid); // Free memory if (connection != mainConnection) { delete connection; } }
//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ void DatabaseService::onDestroy(wpDatabaseConnection_type _pConnection) { Threading::CriticalSection lock(m_pConnectionsGuard); connections_types::iterator iter = m_namedConnections.find(_pConnection->getName()); if (iter != m_namedConnections.end()) { // This is safe since the only place that this can transition // from expired to non-expired is in connect() where m_pConnectionsGuard // is acquired. if (iter->second.expired()) { m_namedConnections.erase(iter); DatabaseConnection* pConn = dynamic_cast<DatabaseConnection*>(_pConnection.get()); pConn->onDestroyEvent(_pConnection); delete pConn; } else { // Not expired, so we are here for no reason // We can get here during race conditions where one shared_ptr // is being deleted while connect() is being called and connect() // beat onDestroy() to the lock(m_pConnectionsGuard). return; } } else { // TODO Severe error, should never get here } }
QStringList Project::databaseConnectionList() { QStringList lst; for ( DatabaseConnection *conn = dbConnections.first(); conn; conn = dbConnections.next() ) lst << conn->name(); return lst; }
void Database::run() { m_initialized = dbInitialize(); m_condition.notify_one(); if(!m_initialized) { return; } Query* q; while (!m_shutdown) { m_queryQueue.popWait(q); if(m_shutdown && !q) { // no remaining connection, we can quit the thread return; } DatabaseConnection* dbc; m_dbConnQueue.popWait(dbc); dbc->processQuery(q); } }
QStringList Project::databaseTableList( const QString &connection ) { DatabaseConnection *conn = databaseConnection( connection ); if ( !conn ) { return QStringList(); } return conn->tables(); }
bool Database::executeSynchronousQuery(Query* q) { DatabaseConnection* dbc; m_dbConnQueue.popWait(dbc); dbc->processSynchronousQuery(q); releaseDBConnection(dbc); return true; }
DatabaseConnection *Project::databaseConnection( const QString &name ) { for ( DatabaseConnection *conn = dbConnections.first(); conn; conn = dbConnections.next() ) { if ( conn->name() == name ) return conn; } return 0; }
QPtrList<DesignerDatabase> DesignerProjectImpl::databaseConnections() const { QPtrList<DesignerDatabase> lst; #ifndef QT_NO_SQL QPtrList<DatabaseConnection> conns = project->databaseConnections(); for ( DatabaseConnection *d = conns.first(); d; d = conns.next() ) lst.append( d->iFace() ); #endif return lst; }
void Project::removeDatabaseConnection( const QString &c ) { for ( DatabaseConnection *conn = dbConnections.first(); conn; conn = dbConnections.next() ) { if ( conn->name() == c ) { conn->remove(); dbConnections.removeRef( conn ); delete conn; return; } } }
/*! Closes the database \a connection. */ void Project::closeDatabase( const QString &connection ) { #ifndef QT_NO_SQL DatabaseConnection *conn = databaseConnection( connection ); if ( connection.isEmpty() && !conn ) conn = databaseConnection( "(default)" ); if ( !conn ) return; conn->close(); #else Q_UNUSED( connection ); #endif }
void Database::addDatabase(Database * db) { if (! db) return; QString connectionName = db->connectionName(); if (mDatabaseConnections.contains(connectionName)) { DatabaseConnection* dbConnection = mDatabaseConnections.value(connectionName); dbConnection->addDatabase(db); } else { mDatabaseConnections.insert(connectionName, new DatabaseConnection(connectionName)); } }
SEXP dbConnect(SEXP dbType_sexp, SEXP connection_string_sexp, SEXP user_sexp, SEXP pass_sexp, SEXP host_sexp, SEXP port_sexp, SEXP tty_sexp, SEXP dbName_sexp, SEXP options_sexp) { SEXP dbi_conn_sexp; DatabaseConnection* conn = NULL; const char* dbType = CHAR(STRING_PTR(dbType_sexp)[0]); const char* connection_string = (connection_string_sexp == R_NilValue) ? NULL : CHAR(STRING_PTR(connection_string_sexp)[0]); const char* user = (user_sexp == R_NilValue) ? NULL : CHAR(STRING_PTR(user_sexp)[0]); const char* pass = (pass_sexp == R_NilValue) ? NULL : CHAR(STRING_PTR(pass_sexp)[0]); const char* host = (host_sexp == R_NilValue) ? NULL : CHAR(STRING_PTR(host_sexp)[0]); const char* port = (port_sexp == R_NilValue) ? NULL : CHAR(STRING_PTR(port_sexp)[0]); const char* tty = (tty_sexp == R_NilValue) ? NULL : CHAR(STRING_PTR(tty_sexp)[0]); const char* dbName = (dbName_sexp == R_NilValue) ? NULL : CHAR(STRING_PTR(dbName_sexp)[0]); const char* options = (options_sexp == R_NilValue) ? NULL : CHAR(STRING_PTR(options_sexp)[0]); // this test is to check whether the package was compiled with support // for this specific dbType try { conn = DatabaseConnection::init(dbType); } catch (DriverNotSupported& e) { REprintf("%s\n",e.what()); return R_NilValue; } // if we succeed then return a wrapped connection, otherwise return null try { // if user provides connection_string, then use it, otherwise try traditional args if(connection_string) { conn->connect(connection_string); } else { conn->connect(user,pass,host,port,tty,dbName,options); } } catch(BadDatabaseConnection& e) { REprintf("%s\n",e.what()); return R_NilValue; } PROTECT(dbi_conn_sexp = R_MakeExternalPtr(reinterpret_cast<void*>(conn),install("DBI_conn_pointer"),R_NilValue)); R_RegisterCFinalizerEx(dbi_conn_sexp, connFinalizer, TRUE); UNPROTECT(1); return dbi_conn_sexp; }
SEXP dbListTables(SEXP dbi_conn_sexp) { if(TYPEOF(dbi_conn_sexp) != EXTPTRSXP || dbi_conn_sexp == R_NilValue) { return R_NilValue; } DatabaseConnection* conn = reinterpret_cast<DatabaseConnection*>(R_ExternalPtrAddr(dbi_conn_sexp)); if(!conn) { // throw bad_connection_object REprintf("bad database connection.\n"); return R_NilValue; } return conn->listTables(); }
void Database::removeDatabase(Database * db) { if (! db) return; QString connectionName = db->connectionName(); if (mDatabaseConnections.contains(connectionName)) { DatabaseConnection* dbConnection = mDatabaseConnections.value(connectionName); dbConnection->removeDatabase(db); if (! dbConnection->isActive()) { mDatabaseConnections.remove(connectionName); dbConnection->deleteLater(); } } }
bool Project::openDatabase( const QString &connection, bool suppressDialog ) { #ifndef QT_NO_SQL DatabaseConnection *conn = databaseConnection( connection ); if ( connection.isEmpty() && !conn ) conn = databaseConnection( "(default)" ); if ( !conn ) return FALSE; bool b = conn->open( suppressDialog ); return b; #else Q_UNUSED( connection ); Q_UNUSED( suppressDialog ); return FALSE; #endif }
/** * * Destroys this connection manager * * @return void */ DatabaseConnectionManager::~DatabaseConnectionManager() { DatabaseConnection *connection; bool waiting = true; while (waiting) { // Our default state is not waiting waiting = false; Connections connections(this->connections); for (Connections::const_iterator it = connections.begin(); it != connections.end(); ++it) { connection = it->first; if (connection->isStopping()) { // Wait for the connection to finish connection->join(); // Remove from collection this->connections.erase(connection); // Free memory if (connection != mainConnection) { delete connection; } } else { // Ask the connection to stop running connection->stop(false); // This connection may not be finished yet waiting = true; } } } delete this->mainConnection; #ifdef TRACK_POINTERS rDebug << "DatabaseConnectionManager::destroy" << this; #endif }
SEXP dbSendQuery(SEXP dbi_conn_sexp, SEXP qry_sexp) { if(TYPEOF(dbi_conn_sexp) != EXTPTRSXP || dbi_conn_sexp == R_NilValue) { return R_NilValue; } SEXP dbi_query_results_sexp; DatabaseConnection* conn = reinterpret_cast<DatabaseConnection*>(R_ExternalPtrAddr(dbi_conn_sexp)); if(!conn) { // throw bad_connection_object return R_NilValue; } const char* qry = CHAR(STRING_PTR(qry_sexp)[0]); QueryResults* query_results = conn->sendQuery(qry); //query_results->getStatus(); PROTECT(dbi_query_results_sexp = R_MakeExternalPtr(reinterpret_cast<void*>(query_results),install("DBI_results_pointer"),R_NilValue)); R_RegisterCFinalizerEx(dbi_query_results_sexp, queryResultsFinalizer, TRUE); UNPROTECT(1); return dbi_query_results_sexp; }
SEXP dbExistsTable(SEXP dbi_conn_sexp, SEXP tableName_sexp) { SEXP ans; if(TYPEOF(dbi_conn_sexp) != EXTPTRSXP || dbi_conn_sexp == R_NilValue) { return R_NilValue; } DatabaseConnection* conn = reinterpret_cast<DatabaseConnection*>(R_ExternalPtrAddr(dbi_conn_sexp)); if(!conn) { // throw bad_connection_object REprintf("bad database connection.\n"); return R_NilValue; } const char* tableName = CHAR(STRING_ELT(tableName_sexp,0)); PROTECT(ans = allocVector(LGLSXP,1)); LOGICAL(ans)[0] = static_cast<int>(conn->existsTable(tableName)); UNPROTECT(1); return ans; }
bool MysqlDatabase::dbInitialize() { for (uint32 i=0; i < m_poolConnSize; i++) { DatabaseConnection* dbc = new MysqlDatabaseConnection(this,m_login,m_host,m_password,m_database,m_port); m_dbConnQueue.push(dbc); m_dbConn.push_back(dbc); if(!dbc->dbInitialize()) { Logger::log("%s\n",dbc->error().c_str()); return false; } m_group.create_thread(boost::bind(&MysqlDatabaseConnection::run, dbc)); } return true; }
// return number of rows written to database // using both overwrite and append is a bad design decision // there should just be overwrite, which will drop the table if it exists // append should be automatic if the table exists, and should fail if the row formats don't match up // having both overwrite and append just complicates the logic of this function SEXP dbWriteTable(SEXP dbi_conn_sexp, SEXP tableName_sexp, SEXP value_sexp, SEXP writeRowNames_sexp, SEXP overWrite_sexp, SEXP append_sexp) { SEXP ans; int rows; if(TYPEOF(dbi_conn_sexp) != EXTPTRSXP || dbi_conn_sexp == R_NilValue) { return R_NilValue; } DatabaseConnection* conn = reinterpret_cast<DatabaseConnection*>(R_ExternalPtrAddr(dbi_conn_sexp)); if(!conn) { // throw bad_connection_object REprintf("bad database connection.\n"); return ScalarInteger(0); } if(TYPEOF(tableName_sexp) != STRSXP) { REprintf("ERROR: tableName is not a string.\n"); return ScalarInteger(0); } const char* tableName = CHAR(STRING_ELT(tableName_sexp,0)); const bool writeRowNames = static_cast<bool>(LOGICAL(writeRowNames_sexp)[0]); const bool overWrite = static_cast<bool>(LOGICAL(overWrite_sexp)[0]); if(conn->existsTable(tableName) && overWrite) { if(!conn->removeTable(tableName)) { REprintf("could not remove existing table (aborting).\n"); return ScalarInteger(0); } } try { rows = conn->writeTable(tableName, value_sexp, writeRowNames); } catch (MapToTypeNotImplemented& e) { REprintf("%s\n",e.what()); return R_NilValue; } PROTECT(ans = allocVector(INTSXP,1)); INTEGER(ans)[0] = rows; UNPROTECT(1); return ans; }
/*! This is a helper to filter out duplicate code from the GetXXXList functions. The name_type is assumed to be the name of the table, and the column in the table is assumed to be "<name_type>_name".*/ static bool NameList(const string& name_type, const DatabaseConnection& database, vector<string>* list) { if (list == NULL) return false; Table results; if (!database.Query("SELECT * FROM get_" + name_type + "_names();", &results)) return false; const int num_rows = results.NumRows(); list->reserve(num_rows); int name_column; if (!results.GetColumnIndex(name_type + "_name", &name_column)) return false; string name; for (int row = 0; row < num_rows; ++row) { if (!results.GetField(name_column, row, &name)) return false; list->push_back(name); } return true; }
void do_speed_test() { string const filename("aaksjh237nsal"); int const loops = 50000; vector<string> statements; statements.push_back ( "insert into dummy(colA, colB) values(3, 'hi')" ); statements.push_back ( "select colA, colB from dummy where colB = " " 'asfkjasdlfkasdfasdf' and colB = '-90982097';" ); statements.push_back ( "insert into dummy(colA, colB) values(198712319, 'aasdfhasdkjhash');" ); statements.push_back ( "select colA, colB from dummy where colA = " " 'noasdsjhasdfkjhasdkfjh' and colB = '-9987293879';" ); vector<string>::size_type const num_statements = statements.size(); string const table_creation_string ( "create table dummy(colA int not null, colB text)" ); // With SQLStatement DatabaseConnection db; db.open(filename); db.execute_sql(table_creation_string); cout << "Timing with SQLStatement." << endl; db.execute_sql("begin"); Stopwatch sw1; for (int i = 0; i != loops; ++i) { SQLStatement s(db, statements[i % num_statements]); // s.step_final(); } sw1.log(); db.execute_sql("end"); windows_friendly_remove(filename); // With SQLStatementImpl SQLiteDBConn sdbc; sdbc.open(filename); sdbc.execute_sql(table_creation_string); cout << "Timing with SQLStatementImpl." << endl; sdbc.execute_sql("begin"); Stopwatch sw0; for (int i = 0; i != loops; ++i) { SQLStatementImpl s(sdbc, statements[i % num_statements]); // s.step_final(); } sw0.log(); sdbc.execute_sql("end"); windows_friendly_remove(filename); return; }
/** * * Reserves a database connection. Until this is freed, it will not be re-used. * * @param timeout The minimum amount of time to use this connection in seconds * @param receiver The object which we'll send any data to * * @return A UUID for this connection */ DatabaseConnection *DatabaseConnectionManager::reserveDatabaseConnectionObj( int timeout, SmartObject *receiver) { ConnectionRecord record, currentRecord; DatabaseConnection *connection = nullptr, *currentConnection; int count; bool running, busy; if (timeout != 0) { // Expiry = unixtime + whatever timeout started as timeout += std::time(nullptr); } while (connection == nullptr) { // Reset counter count = 0; // Iterate connections Connections connections(this->connections); for (Connections::iterator it = connections.begin(); it != connections.end(); ++it) { currentConnection = it->first; currentRecord = it->second; if (currentRecord.expiry != 0) { // This connection has an expiry. No expiry indicates that it is // a reserved connection that should not be re-assigned. if (connection == nullptr) { // Lock this connection's mutex currentConnection->mutex.lock(); // Check if this connection is in the process of shutting // down or is busy with something (or has pending queries) busy = currentConnection->busy || !currentConnection->commands.empty(); // Unlock the mutex currentConnection->mutex.unlock(); if (currentConnection->isStopping() && !busy) { // Re-use this connection connection = currentConnection; // Disconnect the execution signal so if the old // receiver is still around it won't keep getting // signals connection->disconnectQueue( DatabaseConnection::EXECUTED); // Rollback transaction if applicable connection->call(Variant(), QueryEvent::CLEAN_STATE); } } else if (currentRecord.expiry != 0 && currentRecord.expiry > std::time(nullptr)) { // This connection has expired // Lock this connection's mutex currentConnection->mutex.lock(); // Check if this connection is in the process of shutting // down or is busy with something busy = currentConnection->busy || !currentConnection->commands.empty(); // Unlock the mutex currentConnection->mutex.unlock(); if (!busy) { // Tell the connection to disconnect. We'll free memory // after that is finished if (!currentConnection->isStopping()) { // Ensure this connection's signals are disconnected currentConnection->disconnectQueue( DatabaseConnection::EXECUTED); // Connect to ourself. After the disconnect // completes, we need to free the connection currentConnection->connectQueue( DatabaseConnection::EXECUTED, this); currentConnection->call(Variant(currentRecord.uuid), QueryEvent::DISCONNECT); } // Remove from the hash this->connections.erase(currentConnection); // Add to the disconnections hash disconnectingConnections[currentRecord.uuid] = currentConnection; } } count++; } } if (connection == nullptr && count < maxConnections) { // Initialize new connection connection = mainConnection->clone(this); // Start new thread connection->start(); } if (connection != nullptr) { record.expiry = timeout; record.uuid = UUID::makeUUID(); record.receiver = receiver; this->connections[connection] = record; } if (connection == nullptr) { // Process any pending events Application::getInstance()->processEvents(); // Also sleep for 30ms. There may not be events to process above // and we don't want to pin the cpu usleep(30 * 1000); } } if (receiver != nullptr) { // Lock mutex connection->mutex.lock(); // Connect signal connection->connectQueue(DatabaseConnection::EXECUTED, receiver); // Unlock mutex connection->mutex.unlock(); } return connection; }
int main() { DatabaseConnection db; try { db.execute(const_cast<char *>("SELECT * FROM test2;")); // Example: Listing all columns from executed query cout << "Lists all columns from table" << endl; list<string> columns = db.getColumns(); for(list<string>::iterator i = columns.begin(); i != columns.end(); i++) cout << (*i) << endl; // Example: Extracting specific data types into acceptable data types cout << endl << "Extract specific data types" << endl; int intTest = db.getInt(const_cast<char *>("intTest")); double doubleTest = db.getDouble(const_cast<char *>("doubleTest")); int numericTest = db.getInt(const_cast<char *>("numericTest")); string blobTest = db.getText(const_cast<char *>("blobTest")); string textTest = db.getText(const_cast<char *>("textTest")); cout << "INT: " << intTest << endl; cout << "DOUBLE: " << doubleTest << endl; cout << "NUMERIC: " << numericTest << endl; cout << "BLOB: " << blobTest << endl; cout << "TEXT: " << textTest << endl; // Resets the pointer back to the beginning db.reset(); // Example: Extract any type of data types cout << endl << "Extract any type of data types" << endl; cout << "NUMERICTEST: " << db.getColumn(const_cast<char *>("numericTest")) << " TEXTTEST: " << db.getColumn(const_cast<char *>("textTest")) << endl; // Got new set of data. Why? Because I can. db.finalize(); db.execute(const_cast<char *>("SELECT * FROM test;")); // Example: Extract all data obtained from executing the query cout << endl << "Extract all data from query and store in a list of multimaps" << endl; list<multimap<string, string> > results = db.fetchAll(); list<multimap<string, string> >::iterator rows = results.begin(); while(rows != results.end()) { multimap<string, string>::iterator row = (*rows).begin(); while(row != (*rows).end()) { cout << (*row).first << " " << (*row).second << " "; row++; } cout << endl; rows++; } } catch (DatabaseConnectionException e) { cout << e.getMessage(); } // Deletes pointer to query db.finalize(); // Deletes pointer to database connection db.close(); return 0; }
void Project::loadConnections() { #ifndef QT_NO_SQL if ( dbFile.isEmpty() || !QFile::exists( makeAbsolute( dbFile ) ) ) return; QFile f( makeAbsolute( dbFile ) ); if ( f.open( IO_ReadOnly ) ) { QDomDocument doc; QString errMsg; int errLine; if ( doc.setContent( &f, &errMsg, &errLine ) ) { QDomElement e; e = doc.firstChild().toElement(); /* connections */ QDomNodeList connections = e.toElement().elementsByTagName( "connection" ); for ( uint i = 0; i < connections.length(); i++ ) { QDomElement connection = connections.item(i).toElement(); QDomElement connectionName = loadSingleProperty( connection, "name" ); QDomElement connectionDriver = loadSingleProperty( connection, "driver" ); QDomElement connectionDatabase = loadSingleProperty( connection, "database" ); QDomElement connectionUsername = loadSingleProperty( connection, "username" ); QDomElement connectionHostname = loadSingleProperty( connection, "hostname" ); QDomElement connectionPort = loadSingleProperty( connection, "port" ); DatabaseConnection *conn = new DatabaseConnection( this ); conn->setName( connectionName.firstChild().firstChild().toText().data() ); conn->setDriver( connectionDriver.firstChild().firstChild().toText().data() ); conn->setDatabase( connectionDatabase.firstChild().firstChild().toText().data() ); conn->setUsername( connectionUsername.firstChild().firstChild().toText().data() ); conn->setHostname( connectionHostname.firstChild().firstChild().toText().data() ); conn->setPort( QString( connectionPort.firstChild().firstChild().toText().data() ).toInt() ); /* connection tables */ QDomNodeList tables = connection.toElement().elementsByTagName( "table" ); for ( uint j = 0; j < tables.length(); j++ ) { QDomElement table = tables.item(j).toElement(); QDomElement tableName = loadSingleProperty( table, "name" ); conn->addTable( tableName.firstChild().firstChild().toText().data() ); /* table fields */ QStringList fieldList; QDomNodeList fields = table.toElement().elementsByTagName( "field" ); for ( uint k = 0; k < fields.length(); k++ ) { QDomElement field = fields.item(k).toElement(); QDomElement fieldName = loadSingleProperty( field, "name" ); fieldList.append( fieldName.firstChild().firstChild().toText().data() ); } conn->setFields( tableName.firstChild().firstChild().toText().data(), fieldList ); } dbConnections.append( conn ); } } else { qDebug( QString("Parse error: ") + errMsg + QString(" in line %d"), errLine ); } f.close(); } #endif }
void Project::saveConnections() { #ifndef QT_NO_SQL if ( dbFile.isEmpty() ) { QFileInfo fi( fileName() ); setDatabaseDescription( fi.baseName() + ".db" ); } QFile f( makeAbsolute( dbFile ) ); if ( dbConnections.isEmpty() ) { if ( f.exists() ) f.remove(); setDatabaseDescription( "" ); modified = TRUE; return; } /* .db xml */ if ( f.open( IO_WriteOnly | IO_Translate ) ) { QTextStream ts( &f ); ts.setCodec( QTextCodec::codecForName( "UTF-8" ) ); ts << "<!DOCTYPE DB><DB version=\"1.0\">" << endl; /* db connections */ int indent = 0; for ( DatabaseConnection *conn = dbConnections.first(); conn; conn = dbConnections.next() ) { ts << makeIndent( indent ) << "<connection>" << endl; ++indent; saveSingleProperty( ts, "name", conn->name(), indent ); saveSingleProperty( ts, "driver", conn->driver(), indent ); saveSingleProperty( ts, "database", conn->database(), indent ); saveSingleProperty( ts, "username", conn->username(), indent ); saveSingleProperty( ts, "hostname", conn->hostname(), indent ); saveSingleProperty( ts, "port", QString::number( conn->port() ), indent ); /* connection tables */ QStringList tables = conn->tables(); for ( QStringList::Iterator it = tables.begin(); it != tables.end(); ++it ) { ts << makeIndent( indent ) << "<table>" << endl; ++indent; saveSingleProperty( ts, "name", (*it), indent ); /* tables fields */ QStringList fields = conn->fields( *it ); for ( QStringList::Iterator it2 = fields.begin(); it2 != fields.end(); ++it2 ) { ts << makeIndent( indent ) << "<field>" << endl; ++indent; saveSingleProperty( ts, "name", (*it2), indent ); --indent; ts << makeIndent( indent ) << "</field>" << endl; } --indent; ts << makeIndent( indent ) << "</table>" << endl; } --indent; ts << makeIndent( indent ) << "</connection>" << endl; } ts << "</DB>" << endl; f.close(); } #endif }