/*========================================================================= Program: Visualization Toolkit Module: vtkQtSQLDatabase.cxx Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen All rights reserved. See Copyright.txt or http://www.kitware.com/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notice for more information. =========================================================================*/ /*------------------------------------------------------------------------- Copyright 2008 Sandia Corporation. Under the terms of Contract DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains certain rights in this software. -------------------------------------------------------------------------*/ #include "vtkQtSQLDatabase.h" #include "vtkObjectFactory.h" #include "vtkQtSQLQuery.h" #include "vtkStringArray.h" #include "vtkVariant.h" #include #include #include #include vtkStandardNewMacro(vtkQtSQLDatabase); int vtkQtSQLDatabase::id = 0; vtkSQLDatabase* vtkQtSQLDatabaseCreateFromURLCallback(const char* URL) { return vtkQtSQLDatabase::CreateFromURL(URL); } class vtkQtSQLDatabaseInitializer { public: inline void Use() {} vtkQtSQLDatabaseInitializer() { vtkSQLDatabase::RegisterCreateFromURLCallback(vtkQtSQLDatabaseCreateFromURLCallback); } }; static vtkQtSQLDatabaseInitializer vtkQtSQLDatabaseInitializerGlobal; vtkQtSQLDatabase::vtkQtSQLDatabase() { vtkQtSQLDatabaseInitializerGlobal.Use(); this->DatabaseType = nullptr; this->HostName = nullptr; this->UserName = nullptr; this->DatabaseName = nullptr; this->DbPort = -1; this->ConnectOptions = nullptr; this->myTables = vtkStringArray::New(); this->currentRecord = vtkStringArray::New(); } vtkQtSQLDatabase::~vtkQtSQLDatabase() { this->SetDatabaseType(nullptr); this->SetHostName(nullptr); this->SetUserName(nullptr); this->SetDatabaseName(nullptr); this->SetConnectOptions(nullptr); this->myTables->Delete(); this->currentRecord->Delete(); } bool vtkQtSQLDatabase::Open(const char* password) { if (!QCoreApplication::instance()) { vtkErrorMacro("Qt isn't initialized, you must create an instance of QCoreApplication before " "using this class."); return false; } if (this->DatabaseType == nullptr) { vtkErrorMacro("Qt database type must be non-null."); return false; } // We have to assign a unique ID to each database connection, so // Qt doesn't blow-away existing connections const QString connection_name = QString::number(vtkQtSQLDatabase::id++); this->QtDatabase = QSqlDatabase::addDatabase(this->DatabaseType, connection_name); if (this->HostName != nullptr) { this->QtDatabase.setHostName(this->HostName); } if (this->DatabaseName != nullptr) { this->QtDatabase.setDatabaseName(this->DatabaseName); } if (this->ConnectOptions != nullptr) { this->QtDatabase.setConnectOptions(this->ConnectOptions); } if (this->DbPort >= 0) { this->QtDatabase.setPort(this->DbPort); } return this->QtDatabase.open(this->UserName, password); } void vtkQtSQLDatabase::Close() { this->QtDatabase.close(); } bool vtkQtSQLDatabase::IsOpen() { return this->QtDatabase.isOpen(); } vtkSQLQuery* vtkQtSQLDatabase::GetQueryInstance() { vtkQtSQLQuery* query = vtkQtSQLQuery::New(); query->SetDatabase(this); return query; } bool vtkQtSQLDatabase::HasError() { return this->QtDatabase.lastError().isValid(); } const char* vtkQtSQLDatabase::GetLastErrorText() { return this->QtDatabase.lastError().text().toUtf8().data(); } vtkStringArray* vtkQtSQLDatabase::GetTables() { // Clear out any exiting stuff this->myTables->Initialize(); // Yea... do different things depending on database type // Get tables on oracle is different if (this->QtDatabase.driverName() == "QOCI") { vtkSQLQuery* query = this->GetQueryInstance(); query->SetQuery("select table_name from user_tables"); query->Execute(); while (query->NextRow()) this->myTables->InsertNextValue(query->DataValue(0).ToString()); // Okay done with query so delete query->Delete(); } else { // Copy the table list from Qt database QStringList tables = this->QtDatabase.tables(QSql::Tables); for (int i = 0; i < tables.size(); ++i) { this->myTables->InsertNextValue(tables.at(i).toUtf8().data()); } } return this->myTables; } vtkStringArray* vtkQtSQLDatabase::GetRecord(const char* table) { // Clear any existing records currentRecord->Resize(0); QSqlRecord columns = this->QtDatabase.record(table); for (int i = 0; i < columns.count(); i++) { this->currentRecord->InsertNextValue(columns.fieldName(i).toUtf8().data()); } return currentRecord; } vtkStringArray* vtkQtSQLDatabase::GetColumns() { return this->currentRecord; } void vtkQtSQLDatabase::SetColumnsTable(const char* table) { this->GetRecord(table); } bool vtkQtSQLDatabase::IsSupported(int feature) { switch (feature) { case VTK_SQL_FEATURE_TRANSACTIONS: return this->QtDatabase.driver()->hasFeature(QSqlDriver::Transactions); case VTK_SQL_FEATURE_QUERY_SIZE: return this->QtDatabase.driver()->hasFeature(QSqlDriver::QuerySize); case VTK_SQL_FEATURE_BLOB: return this->QtDatabase.driver()->hasFeature(QSqlDriver::BLOB); case VTK_SQL_FEATURE_UNICODE: return this->QtDatabase.driver()->hasFeature(QSqlDriver::Unicode); case VTK_SQL_FEATURE_PREPARED_QUERIES: return this->QtDatabase.driver()->hasFeature(QSqlDriver::PreparedQueries); case VTK_SQL_FEATURE_NAMED_PLACEHOLDERS: return this->QtDatabase.driver()->hasFeature(QSqlDriver::NamedPlaceholders); case VTK_SQL_FEATURE_POSITIONAL_PLACEHOLDERS: return this->QtDatabase.driver()->hasFeature(QSqlDriver::PositionalPlaceholders); case VTK_SQL_FEATURE_LAST_INSERT_ID: return this->QtDatabase.driver()->hasFeature(QSqlDriver::LastInsertId); case VTK_SQL_FEATURE_BATCH_OPERATIONS: return this->QtDatabase.driver()->hasFeature(QSqlDriver::BatchOperations); default: { vtkErrorMacro(<< "Unknown SQL feature code " << feature << "! See " << "vtkSQLDatabase.h for a list of possible features."); return false; } } } void vtkQtSQLDatabase::PrintSelf(ostream& os, vtkIndent indent) { this->Superclass::PrintSelf(os, indent); os << indent << "DatabaseType: " << (this->DatabaseType ? this->DatabaseType : "nullptr") << endl; os << indent << "HostName: " << (this->HostName ? this->HostName : "nullptr") << endl; os << indent << "UserName: " << (this->UserName ? this->UserName : "nullptr") << endl; os << indent << "DatabaseName: " << (this->DatabaseName ? this->DatabaseName : "nullptr") << endl; os << indent << "DbPort: " << this->DbPort << endl; os << indent << "ConnectOptions: " << (this->ConnectOptions ? this->ConnectOptions : "nullptr") << endl; } //------------------------------------------------------------------------------ bool vtkQtSQLDatabase::ParseURL(const char* URL) { std::string protocol; std::string username; std::string unused; std::string hostname; std::string dataport; std::string database; std::string dataglom; // SQLite is a bit special so lets get that out of the way :) if (!vtksys::SystemTools::ParseURLProtocol(URL, protocol, dataglom)) { vtkGenericWarningMacro("Invalid URL: " << URL); return false; } if (protocol == "sqlite") { this->SetDatabaseType("QSQLITE"); this->SetDatabaseName(dataglom.c_str()); return true; } // Okay now for all the other database types get more detailed info if (!vtksys::SystemTools::ParseURL(URL, protocol, username, unused, hostname, dataport, database)) { vtkGenericWarningMacro("Invalid URL: " << URL); return false; } // Create Qt 'version' of database prototcol type QString qtType = "Q" + QString::fromUtf8(protocol.c_str()).toUpper(); this->SetDatabaseType(qtType.toUtf8().data()); this->SetUserName(username.c_str()); this->SetHostName(hostname.c_str()); this->SetDbPort(atoi(dataport.c_str())); this->SetDatabaseName(database.c_str()); return true; } //------------------------------------------------------------------------------ vtkSQLDatabase* vtkQtSQLDatabase::CreateFromURL(const char* URL) { vtkQtSQLDatabase* qt_db = vtkQtSQLDatabase::New(); if (qt_db->ParseURL(URL)) { return qt_db; } qt_db->Delete(); return nullptr; } //------------------------------------------------------------------------------ vtkStdString vtkQtSQLDatabase::GetURL() { vtkStdString url; url = this->GetDatabaseType(); url += "://"; url += this->GetUserName(); url += "@"; url += this->GetHostName(); url += ":"; url += std::to_string(this->GetDbPort()); url += "/"; url += this->GetDatabaseName(); return url; }