/*=========================================================================Program: Visualization ToolkitModule: vtkSQLDatabase.cxxCopyright (c) Ken Martin, Will Schroeder, Bill LorensenAll rights reserved.See Copyright.txt or http://www.kitware.com/Copyright.htm for details.This software is distributed WITHOUT ANY WARRANTY; without eventhe implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULARPURPOSE. 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 "vtkToolkits.h"#include "vtkInformationObjectBaseKey.h"#include "vtkSQLDatabase.h"#include "vtkSQLQuery.h"#include "vtkSQLDatabaseSchema.h"#include "vtkSQLiteDatabase.h"#include "vtkCriticalSection.h"#include "vtkObjectFactory.h"#include "vtkStdString.h"#include <vtksys/SystemTools.hxx>#include <sstream>class vtkSQLDatabase::vtkCallbackVector :public std::vector<vtkSQLDatabase::CreateFunction>{public:vtkSQLDatabase* CreateFromURL(const char* URL){iterator iter;for (iter = this->begin(); iter != this->end(); ++iter){vtkSQLDatabase* db =(*(*iter))(URL);if (db){return db;}}return nullptr;}};vtkSQLDatabase::vtkCallbackVector* vtkSQLDatabase::Callbacks = nullptr;// Ensures that there are no leaks when the application exits.class vtkSQLDatabaseCleanup{public:inline void Use(){};~vtkSQLDatabaseCleanup(){vtkSQLDatabase::UnRegisterAllCreateFromURLCallbacks();}};// Used to clean up the Callbacksstatic vtkSQLDatabaseCleanup vtkCleanupSQLDatabaseGlobal;vtkInformationKeyMacro(vtkSQLDatabase, DATABASE, ObjectBase);// ----------------------------------------------------------------------vtkSQLDatabase::vtkSQLDatabase(){}// ----------------------------------------------------------------------vtkSQLDatabase::~vtkSQLDatabase(){}// ----------------------------------------------------------------------void vtkSQLDatabase::RegisterCreateFromURLCallback(vtkSQLDatabase::CreateFunction func){if (!vtkSQLDatabase::Callbacks){vtkCleanupSQLDatabaseGlobal.Use();vtkSQLDatabase::Callbacks = new vtkCallbackVector();}vtkSQLDatabase::Callbacks->push_back(func);}// ----------------------------------------------------------------------void vtkSQLDatabase::UnRegisterCreateFromURLCallback(vtkSQLDatabase::CreateFunction func){if (vtkSQLDatabase::Callbacks){vtkSQLDatabase::vtkCallbackVector::iterator iter;for (iter = vtkSQLDatabase::Callbacks->begin();iter != vtkSQLDatabase::Callbacks->end(); ++iter){if ((*iter) == func){vtkSQLDatabase::Callbacks->erase(iter);break;}}}}// ----------------------------------------------------------------------void vtkSQLDatabase::UnRegisterAllCreateFromURLCallbacks(){delete vtkSQLDatabase::Callbacks;vtkSQLDatabase::Callbacks = nullptr;}// ----------------------------------------------------------------------void vtkSQLDatabase::PrintSelf(ostream &os, vtkIndent indent){this->Superclass::PrintSelf(os, indent);}// ----------------------------------------------------------------------vtkStdString vtkSQLDatabase::GetColumnSpecification( vtkSQLDatabaseSchema* schema,int tblHandle,int colHandle ){std::ostringstream queryStr;queryStr << schema->GetColumnNameFromHandle( tblHandle, colHandle );// Figure out column typeint colType = schema->GetColumnTypeFromHandle( tblHandle, colHandle );vtkStdString colTypeStr;switch ( static_cast<vtkSQLDatabaseSchema::DatabaseColumnType>( colType ) ){case vtkSQLDatabaseSchema::SERIAL:colTypeStr = "INTEGER";break;case vtkSQLDatabaseSchema::SMALLINT:colTypeStr = "INTEGER";break;case vtkSQLDatabaseSchema::INTEGER:colTypeStr = "INTEGER";break;case vtkSQLDatabaseSchema::BIGINT:colTypeStr = "INTEGER";break;case vtkSQLDatabaseSchema::VARCHAR:colTypeStr = "VARCHAR";break;case vtkSQLDatabaseSchema::TEXT:colTypeStr = "VARCHAR";break;case vtkSQLDatabaseSchema::REAL:colTypeStr = "FLOAT";break;case vtkSQLDatabaseSchema::DOUBLE:colTypeStr = "DOUBLE";break;case vtkSQLDatabaseSchema::BLOB:colTypeStr = "";break;case vtkSQLDatabaseSchema::TIME:colTypeStr = "TIME";break;case vtkSQLDatabaseSchema::DATE:colTypeStr = "DATE";break;case vtkSQLDatabaseSchema::TIMESTAMP:colTypeStr = "TIMESTAMP";break;}if ( !colTypeStr.empty() ){queryStr << " " << colTypeStr;}else // if ( colTypeStr.size() ){vtkGenericWarningMacro( "Unable to get column specification: unsupported data type " << colType );return vtkStdString();}// Decide whether size is allowed, required, or unusedint colSizeType = 0;switch ( static_cast<vtkSQLDatabaseSchema::DatabaseColumnType>( colType ) ){case vtkSQLDatabaseSchema::SERIAL:colSizeType = 0;break;case vtkSQLDatabaseSchema::SMALLINT:colSizeType = 1;break;case vtkSQLDatabaseSchema::INTEGER:colSizeType = 1;break;case vtkSQLDatabaseSchema::BIGINT:colSizeType = 1;break;case vtkSQLDatabaseSchema::VARCHAR:colSizeType = -1;break;case vtkSQLDatabaseSchema::TEXT:colSizeType = -1;break;case vtkSQLDatabaseSchema::REAL:colSizeType = 0;break;case vtkSQLDatabaseSchema::DOUBLE:colSizeType = 0;break;case vtkSQLDatabaseSchema::BLOB:colSizeType = 0;break;case vtkSQLDatabaseSchema::TIME:colSizeType = 0;break;case vtkSQLDatabaseSchema::DATE:colSizeType = 0;break;case vtkSQLDatabaseSchema::TIMESTAMP:colSizeType = 0;break;}// Specify size if allowed or requiredif ( colSizeType ){int colSize = schema->GetColumnSizeFromHandle( tblHandle, colHandle );// IF size is provided but absurd,// OR, if size is required but not provided OR absurd,// THEN assign the default size.if ( ( colSize < 0 ) || ( colSizeType == -1 && colSize < 1 ) ){colSize = VTK_SQL_DEFAULT_COLUMN_SIZE;}// At this point, we have either a valid size if required, or a possibly null valid size// if not required. Thus, skip sizing in the latter case.if ( colSize > 0 ){queryStr << "(" << colSize << ")";}}vtkStdString attStr = schema->GetColumnAttributesFromHandle( tblHandle, colHandle );if ( !attStr.empty() ){queryStr << " " << attStr;}return queryStr.str();}// ----------------------------------------------------------------------vtkStdString vtkSQLDatabase::GetIndexSpecification( vtkSQLDatabaseSchema* schema,int tblHandle,int idxHandle,bool& skipped ){vtkStdString queryStr;int idxType = schema->GetIndexTypeFromHandle( tblHandle, idxHandle );switch ( idxType ){case vtkSQLDatabaseSchema::PRIMARY_KEY:queryStr = ", PRIMARY KEY ";skipped = false;break;case vtkSQLDatabaseSchema::UNIQUE:queryStr = ", UNIQUE ";skipped = false;break;case vtkSQLDatabaseSchema::INDEX:// Not supported within a CREATE TABLE statement by all SQL backends:// must be created later with a CREATE INDEX statementqueryStr = "CREATE INDEX ";skipped = true;break;default:return vtkStdString();}// No index_name for PRIMARY KEYs nor UNIQUEsif ( skipped ){queryStr += schema->GetIndexNameFromHandle( tblHandle, idxHandle );}// CREATE INDEX <index name> ON <table name> syntaxif ( skipped ){queryStr += " ON ";queryStr += schema->GetTableNameFromHandle( tblHandle );}queryStr += " (";// Loop over all column names of the indexint numCnm = schema->GetNumberOfColumnNamesInIndex( tblHandle, idxHandle );if ( numCnm < 0 ){vtkGenericWarningMacro( "Unable to get index specification: index has incorrect number of columns " << numCnm );return vtkStdString();}bool firstCnm = true;for ( int cnmHandle = 0; cnmHandle < numCnm; ++ cnmHandle ){if ( firstCnm ){firstCnm = false;}else{queryStr += ",";}queryStr += schema->GetIndexColumnNameFromHandle( tblHandle, idxHandle, cnmHandle );}queryStr += ")";return queryStr;}// ----------------------------------------------------------------------vtkStdString vtkSQLDatabase::GetTriggerSpecification( vtkSQLDatabaseSchema* schema,int tblHandle,int trgHandle ){vtkStdString queryStr = "CREATE TRIGGER ";queryStr += schema->GetTriggerNameFromHandle( tblHandle, trgHandle );int trgType = schema->GetTriggerTypeFromHandle( tblHandle, trgHandle );// odd types: AFTER, even types: BEFOREif ( trgType % 2 ){queryStr += " AFTER ";}else{queryStr += " BEFORE ";}// 0/1: INSERT, 2/3: UPDATE, 4/5: DELETEif ( trgType > 1 ){if ( trgType > 3 ){queryStr += "DELETE ON ";}else // if ( trgType > 3 ){queryStr += "UPDATE ON ";}}else // if ( trgType > 1 ){queryStr += "INSERT ON ";}queryStr += schema->GetTableNameFromHandle( tblHandle );queryStr += " ";queryStr += schema->GetTriggerActionFromHandle( tblHandle, trgHandle );return queryStr;}// ----------------------------------------------------------------------vtkSQLDatabase* vtkSQLDatabase::CreateFromURL( const char* URL ){std::string urlstr( URL ? URL : "" );std::string protocol;std::string username;std::string unused;std::string hostname;std::string dataport;std::string database;std::string dataglom;vtkSQLDatabase* db = nullptr;static vtkSimpleCriticalSection dbURLCritSec;dbURLCritSec.Lock();// SQLite is a bit special so lets get that out of the way :)if ( ! vtksys::SystemTools::ParseURLProtocol( urlstr, protocol, dataglom )){vtkGenericWarningMacro( "Invalid URL (no protocol found): \"" << urlstr.c_str() << "\"" );dbURLCritSec.Unlock();return nullptr;}if ( protocol == "sqlite" ){db = vtkSQLiteDatabase::New();db->ParseURL( URL );dbURLCritSec.Unlock();return db;}// Okay now for all the other database types get more detailed infoif ( ! vtksys::SystemTools::ParseURL( urlstr, protocol, username,unused, hostname, dataport, database) ){vtkGenericWarningMacro( "Invalid URL (other components missing): \"" << urlstr.c_str() << "\"" );dbURLCritSec.Unlock();return nullptr;}// Now try to look at registered callback to try and find someone who can// provide us with the required implementation.if (!db && vtkSQLDatabase::Callbacks){db = vtkSQLDatabase::Callbacks->CreateFromURL( URL );}if ( ! db ){vtkGenericWarningMacro( "Unsupported protocol: " << protocol.c_str() );}dbURLCritSec.Unlock();return db;}// ----------------------------------------------------------------------bool vtkSQLDatabase::EffectSchema( vtkSQLDatabaseSchema* schema, bool dropIfExists ){if ( ! this->IsOpen() ){vtkGenericWarningMacro( "Unable to effect the schema: no database is open" );return false;}// Instantiate an empty query and begin the transaction.vtkSQLQuery* query = this->GetQueryInstance();if ( ! query->BeginTransaction() ){vtkGenericWarningMacro( "Unable to effect the schema: unable to begin transaction" );return false;}// Loop over preamble statements of the schema and execute them only if they are relevantint numPre = schema->GetNumberOfPreambles();for ( int preHandle = 0; preHandle < numPre; ++ preHandle ){// Don't execute if the statement is not for this backendconst char* preBackend = schema->GetPreambleBackendFromHandle( preHandle );if ( strcmp( preBackend, VTK_SQL_ALLBACKENDS ) && strcmp( preBackend, this->GetClassName() ) ){continue;}vtkStdString preStr = schema->GetPreambleActionFromHandle( preHandle );query->SetQuery( preStr );if ( ! query->Execute() ){vtkGenericWarningMacro( "Unable to effect the schema: unable to execute query.\nDetails: "<< query->GetLastErrorText() );query->RollbackTransaction();query->Delete();return false;}}// Loop over all tables of the schema and create themint numTbl = schema->GetNumberOfTables();for ( int tblHandle = 0; tblHandle < numTbl; ++ tblHandle ){// Construct the CREATE TABLE query for this tablevtkStdString queryStr( "CREATE TABLE " );queryStr += this->GetTablePreamble( dropIfExists );queryStr += schema->GetTableNameFromHandle( tblHandle );queryStr += " (";// Loop over all columns of the current tableint numCol = schema->GetNumberOfColumnsInTable( tblHandle );if ( numCol < 0 ){query->RollbackTransaction();query->Delete();return false;}bool firstCol = true;for ( int colHandle = 0; colHandle < numCol; ++ colHandle ){if ( ! firstCol ){queryStr += ", ";}else // ( ! firstCol ){firstCol = false;}// Get column creation syntax (backend-dependent)vtkStdString colStr = this->GetColumnSpecification( schema, tblHandle, colHandle );if ( !colStr.empty() ){queryStr += colStr;}else // if ( colStr.size() ){query->RollbackTransaction();query->Delete();return false;}}// Check out number of indicesint numIdx = schema->GetNumberOfIndicesInTable( tblHandle );if ( numIdx < 0 ){query->RollbackTransaction();query->Delete();return false;}// In case separate INDEX statements are needed (backend-specific)std::vector<vtkStdString> idxStatements;bool skipped = false;// Loop over all indices of the current tablefor ( int idxHandle = 0; idxHandle < numIdx; ++ idxHandle ){// Get index creation syntax (backend-dependent)vtkStdString idxStr = this->GetIndexSpecification( schema, tblHandle, idxHandle, skipped );if ( !idxStr.empty() ){if ( skipped ){// Must create this index lateridxStatements.push_back( idxStr );continue;}else // if ( skipped ){queryStr += idxStr;}}else // if ( idxStr.size() ){query->RollbackTransaction();query->Delete();return false;}}queryStr += ")";// Add options to the end of the CREATE TABLE statementint numOpt = schema->GetNumberOfOptionsInTable( tblHandle );if ( numOpt < 0 ){query->RollbackTransaction();query->Delete();return false;}for ( int optHandle = 0; optHandle < numOpt; ++ optHandle ){vtkStdString optBackend = schema->GetOptionBackendFromHandle( tblHandle, optHandle );if ( strcmp( optBackend, VTK_SQL_ALLBACKENDS ) && strcmp( optBackend, this->GetClassName() ) ){continue;}queryStr += " ";queryStr += schema->GetOptionTextFromHandle( tblHandle, optHandle );}// Execute the CREATE TABLE queryquery->SetQuery( queryStr );if ( ! query->Execute() ){vtkGenericWarningMacro( "Unable to effect the schema: unable to execute query.\nDetails: "<< query->GetLastErrorText() );query->RollbackTransaction();query->Delete();return false;}// Execute separate CREATE INDEX statements if neededfor ( std::vector<vtkStdString>::iterator it = idxStatements.begin();it != idxStatements.end(); ++ it ){query->SetQuery( *it );if ( ! query->Execute() ){vtkGenericWarningMacro( "Unable to effect the schema: unable to execute query.\nDetails: "<< query->GetLastErrorText() );query->RollbackTransaction();query->Delete();return false;}}// Check out number of triggersint numTrg = schema->GetNumberOfTriggersInTable( tblHandle );if ( numTrg < 0 ){query->RollbackTransaction();query->Delete();return false;}// Construct CREATE TRIGGER statements only if they are supported by the backend at handif ( numTrg && IsSupported( VTK_SQL_FEATURE_TRIGGERS ) ){// Loop over all triggers of the current tablefor ( int trgHandle = 0; trgHandle < numTrg; ++ trgHandle ){// Don't execute if the trigger is not for this backendconst char* trgBackend = schema->GetTriggerBackendFromHandle( tblHandle, trgHandle );if ( strcmp( trgBackend, VTK_SQL_ALLBACKENDS ) && strcmp( trgBackend, this->GetClassName() ) ){continue;}// Get trigger creation syntax (backend-dependent)vtkStdString trgStr = this->GetTriggerSpecification( schema, tblHandle, trgHandle );// If not empty, execute queryif ( !trgStr.empty() ){query->SetQuery( vtkStdString( trgStr ) );if ( ! query->Execute() ){vtkGenericWarningMacro( "Unable to effect the schema: unable to execute query.\nDetails: "<< query->GetLastErrorText() );query->RollbackTransaction();query->Delete();return false;}}else // if ( trgStr.size() ){query->RollbackTransaction();query->Delete();return false;}}}// If triggers are specified but not supported, don't quit, but let the user know itelse if ( numTrg ){vtkGenericWarningMacro( "Triggers are not supported by this SQL backend; ignoring them." );}} // for ( int tblHandle = 0; tblHandle < numTbl; ++ tblHandle )// Commit the transaction.if ( ! query->CommitTransaction() ){vtkGenericWarningMacro( "Unable to effect the schema: unable to commit transaction.\nDetails: "<< query->GetLastErrorText() );query->Delete();return false;}query->Delete();return true;}
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。