mirror of https://gitee.com/openkylin/vtk9.git
764 lines
22 KiB
C++
764 lines
22 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkPostgreSQLDatabase.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 "vtkPostgreSQLDatabase.h"
|
|
#include "vtkPostgreSQLDatabasePrivate.h"
|
|
#include "vtkPostgreSQLQuery.h"
|
|
|
|
#include "vtkSQLDatabaseSchema.h"
|
|
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkStringArray.h"
|
|
|
|
#include <sstream>
|
|
#include <vtksys/SystemTools.hxx>
|
|
|
|
#include "vtkSmartPointer.h"
|
|
#define VTK_CREATE(classname, varname) \
|
|
vtkSmartPointer<classname> varname = vtkSmartPointer<classname>::New()
|
|
|
|
#include <libpq-fe.h>
|
|
|
|
#include <cassert>
|
|
|
|
vtkStandardNewMacro(vtkPostgreSQLDatabase);
|
|
|
|
//------------------------------------------------------------------------------
|
|
vtkPostgreSQLDatabase::vtkPostgreSQLDatabase()
|
|
{
|
|
this->Connection = nullptr;
|
|
this->ConnectionMTime = this->MTime;
|
|
|
|
this->DatabaseType = nullptr;
|
|
this->SetDatabaseType("psql");
|
|
this->HostName = nullptr;
|
|
this->User = nullptr;
|
|
this->Password = nullptr;
|
|
this->DatabaseName = nullptr;
|
|
this->ServerPort = -1;
|
|
this->ConnectOptions = nullptr;
|
|
this->LastErrorText = nullptr;
|
|
this->Tables = vtkStringArray::New();
|
|
this->Tables->Register(this);
|
|
this->Tables->Delete();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
vtkPostgreSQLDatabase::~vtkPostgreSQLDatabase()
|
|
{
|
|
if (this->IsOpen())
|
|
{
|
|
this->Close();
|
|
}
|
|
|
|
this->SetHostName(nullptr);
|
|
this->SetUser(nullptr);
|
|
this->SetDatabaseName(nullptr);
|
|
this->SetConnectOptions(nullptr);
|
|
this->SetDatabaseType(nullptr);
|
|
this->SetLastErrorText(nullptr);
|
|
this->Tables->UnRegister(this);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void vtkPostgreSQLDatabase::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
os << indent << "Connection: ";
|
|
if (this->Connection)
|
|
{
|
|
os << this->Connection << endl;
|
|
}
|
|
else
|
|
{
|
|
os << "(null)" << endl;
|
|
}
|
|
os << indent << "DatabaseType: " << (this->DatabaseType ? this->DatabaseType : "nullptr") << endl;
|
|
os << indent << "HostName: " << (this->HostName ? this->HostName : "nullptr") << endl;
|
|
os << indent << "User: " << (this->User ? this->User : "nullptr") << endl;
|
|
os << indent << "Password: " << (this->Password ? "(hidden)" : "(none)") << endl;
|
|
os << indent << "DatabaseName: " << (this->DatabaseName ? this->DatabaseName : "nullptr") << endl;
|
|
os << indent << "ServerPort: " << this->ServerPort << endl;
|
|
os << indent << "ConnectOptions: " << (this->ConnectOptions ? this->ConnectOptions : "nullptr")
|
|
<< endl;
|
|
os << indent << "LastErrorText: " << this->LastErrorText << endl;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
vtkStdString vtkPostgreSQLDatabase::GetColumnSpecification(
|
|
vtkSQLDatabaseSchema* schema, int tblHandle, int colHandle)
|
|
{
|
|
std::ostringstream queryStr;
|
|
queryStr << schema->GetColumnNameFromHandle(tblHandle, colHandle);
|
|
|
|
// Figure out column type
|
|
int colType = schema->GetColumnTypeFromHandle(tblHandle, colHandle);
|
|
vtkStdString colTypeStr;
|
|
switch (static_cast<vtkSQLDatabaseSchema::DatabaseColumnType>(colType))
|
|
{
|
|
case vtkSQLDatabaseSchema::SERIAL:
|
|
colTypeStr = "SERIAL";
|
|
break;
|
|
case vtkSQLDatabaseSchema::SMALLINT:
|
|
colTypeStr = "SMALLINT";
|
|
break;
|
|
case vtkSQLDatabaseSchema::INTEGER:
|
|
colTypeStr = "INTEGER";
|
|
break;
|
|
case vtkSQLDatabaseSchema::BIGINT:
|
|
colTypeStr = "BIGINT";
|
|
break;
|
|
case vtkSQLDatabaseSchema::VARCHAR:
|
|
colTypeStr = "VARCHAR";
|
|
break;
|
|
case vtkSQLDatabaseSchema::TEXT:
|
|
colTypeStr = "TEXT";
|
|
break;
|
|
case vtkSQLDatabaseSchema::REAL:
|
|
colTypeStr = "REAL";
|
|
break;
|
|
case vtkSQLDatabaseSchema::DOUBLE:
|
|
colTypeStr = "DOUBLE PRECISION";
|
|
break;
|
|
case vtkSQLDatabaseSchema::BLOB:
|
|
colTypeStr = "BYTEA";
|
|
break;
|
|
case vtkSQLDatabaseSchema::TIME:
|
|
colTypeStr = "TIME";
|
|
break;
|
|
case vtkSQLDatabaseSchema::DATE:
|
|
colTypeStr = "DATE";
|
|
break;
|
|
case vtkSQLDatabaseSchema::TIMESTAMP:
|
|
colTypeStr = "TIMESTAMP WITH TIME ZONE";
|
|
break;
|
|
}
|
|
|
|
if (!colTypeStr.empty())
|
|
{
|
|
queryStr << " " << colTypeStr;
|
|
}
|
|
else // if ( !colTypeStr.empty() )
|
|
{
|
|
vtkGenericWarningMacro("Unable to get column specification: unsupported data type " << colType);
|
|
return vtkStdString();
|
|
}
|
|
|
|
// Decide whether size is allowed, required, or unused
|
|
int colSizeType = 0;
|
|
switch (static_cast<vtkSQLDatabaseSchema::DatabaseColumnType>(colType))
|
|
{
|
|
case vtkSQLDatabaseSchema::SERIAL:
|
|
colSizeType = 0;
|
|
break;
|
|
case vtkSQLDatabaseSchema::SMALLINT:
|
|
colSizeType = 0;
|
|
break;
|
|
case vtkSQLDatabaseSchema::INTEGER:
|
|
colSizeType = 0;
|
|
break;
|
|
case vtkSQLDatabaseSchema::BIGINT:
|
|
colSizeType = 0;
|
|
break;
|
|
case vtkSQLDatabaseSchema::VARCHAR:
|
|
colSizeType = -1;
|
|
break;
|
|
case vtkSQLDatabaseSchema::TEXT:
|
|
colSizeType = 0;
|
|
break;
|
|
case vtkSQLDatabaseSchema::REAL:
|
|
colSizeType = 0;
|
|
break;
|
|
case vtkSQLDatabaseSchema::DOUBLE:
|
|
colSizeType = 0;
|
|
break;
|
|
case vtkSQLDatabaseSchema::BLOB:
|
|
colSizeType = 0;
|
|
break;
|
|
case vtkSQLDatabaseSchema::TIME:
|
|
colSizeType = 1;
|
|
break;
|
|
case vtkSQLDatabaseSchema::DATE:
|
|
colSizeType = 0;
|
|
break;
|
|
case vtkSQLDatabaseSchema::TIMESTAMP:
|
|
colSizeType = 0;
|
|
break;
|
|
}
|
|
|
|
// Specify size if allowed or required
|
|
if (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();
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLDatabase::Open(const char* password)
|
|
{
|
|
if (!this->HostName || !this->DatabaseName)
|
|
{
|
|
this->SetLastErrorText("Cannot open database because HostName and/or DatabaseName are null.");
|
|
vtkErrorMacro(<< this->GetLastErrorText());
|
|
return false;
|
|
}
|
|
|
|
if (this->Connection)
|
|
{
|
|
if (this->ConnectionMTime > this->URLMTime)
|
|
{
|
|
return true; // we already had that database open.
|
|
}
|
|
this->Close(); // close the old connection before opening a new one
|
|
}
|
|
|
|
std::string options;
|
|
options = "dbname=";
|
|
options += this->DatabaseName;
|
|
|
|
if (this->ServerPort > 0)
|
|
{
|
|
options += " port=";
|
|
std::ostringstream stream;
|
|
stream << this->ServerPort;
|
|
options += stream.str();
|
|
}
|
|
if (this->User && strlen(this->User) > 0)
|
|
{
|
|
options += " user=";
|
|
options += this->User;
|
|
}
|
|
if (password && this->Password != password)
|
|
{
|
|
delete[] this->Password;
|
|
this->Password = password ? vtksys::SystemTools::DuplicateString(password) : nullptr;
|
|
}
|
|
if (this->Password && strlen(this->Password) > 0)
|
|
{
|
|
options += " password=";
|
|
options += this->Password;
|
|
}
|
|
if (this->ConnectOptions && strlen(this->ConnectOptions) > 0)
|
|
{
|
|
options += this->ConnectOptions;
|
|
}
|
|
|
|
// If localhost is specified, try the local socket connection
|
|
// first. Only if that doesn't work will we try the loopback
|
|
// device.
|
|
if (!strcmp(this->HostName, "localhost"))
|
|
{
|
|
if (this->OpenInternal(options.c_str()))
|
|
{
|
|
this->SetLastErrorText(nullptr);
|
|
return true;
|
|
}
|
|
}
|
|
std::string hspec("host=");
|
|
hspec += this->HostName;
|
|
options = hspec + " " + options;
|
|
if (this->OpenInternal(options.c_str()))
|
|
{
|
|
this->SetLastErrorText(nullptr);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void vtkPostgreSQLDatabase::Close()
|
|
{
|
|
if (this->Connection)
|
|
{
|
|
delete this->Connection;
|
|
this->Connection = nullptr;
|
|
this->SetLastErrorText(nullptr);
|
|
this->URLMTime.Modified(); // Force a re-open to occur when Open() is called.
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLDatabase::IsOpen()
|
|
{
|
|
return (this->Connection != nullptr && this->Connection->Connection != nullptr &&
|
|
PQstatus(this->Connection->Connection) == CONNECTION_OK);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
vtkSQLQuery* vtkPostgreSQLDatabase::GetQueryInstance()
|
|
{
|
|
vtkPostgreSQLQuery* query = vtkPostgreSQLQuery::New();
|
|
query->SetDatabase(this);
|
|
return query;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLDatabase::HasError()
|
|
{
|
|
// Assume that an unopened connection is not a symptom of failure.
|
|
if (this->Connection)
|
|
{
|
|
return this->LastErrorText ? true : false;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
const char* vtkPostgreSQLDatabase::GetLastErrorText()
|
|
{
|
|
return this->LastErrorText;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
vtkStdString vtkPostgreSQLDatabase::GetURL()
|
|
{
|
|
vtkStdString url = this->GetDatabaseType();
|
|
url += "://";
|
|
if (this->HostName && this->DatabaseName)
|
|
{
|
|
if (this->User && strlen(this->User) > 0)
|
|
{
|
|
url += this->User;
|
|
url += "@";
|
|
}
|
|
url += this->HostName;
|
|
url += "/";
|
|
url += this->DatabaseName;
|
|
}
|
|
return url;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLDatabase::ParseURL(const char* URL)
|
|
{
|
|
std::string urlstr(URL ? URL : "");
|
|
std::string protocol;
|
|
std::string username;
|
|
std::string password;
|
|
std::string hostname;
|
|
std::string dataport;
|
|
std::string database;
|
|
|
|
// Okay now for all the other database types get more detailed info
|
|
if (!vtksys::SystemTools::ParseURL(
|
|
urlstr, protocol, username, password, hostname, dataport, database))
|
|
{
|
|
vtkErrorMacro("Invalid URL: \"" << urlstr.c_str() << "\"");
|
|
return false;
|
|
}
|
|
|
|
if (protocol == "psql")
|
|
{
|
|
this->SetUser(username.empty() ? nullptr : username.c_str());
|
|
this->SetPassword(password.empty() ? nullptr : password.c_str());
|
|
this->SetHostName(hostname.empty() ? nullptr : hostname.c_str());
|
|
this->SetServerPort(atoi(dataport.c_str()));
|
|
this->SetDatabaseName(database.empty() ? nullptr : database.c_str());
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
vtkStringArray* vtkPostgreSQLDatabase::GetTables()
|
|
{
|
|
this->Tables->Resize(0);
|
|
if (!this->Connection)
|
|
{
|
|
vtkErrorMacro(<< this->GetLastErrorText());
|
|
return this->Tables;
|
|
}
|
|
|
|
// NB: Other columns of interest include table_catalog, table_schema, table_type,
|
|
// self_referencing_column_name, reference_generation, user_defined_type_catalog,
|
|
// user_defined_type_schema, user_defined_type_name, is_insertable_into, is_typed,
|
|
// commit_action
|
|
vtkSQLQuery* query = this->GetQueryInstance();
|
|
query->SetQuery("SELECT table_name FROM information_schema.tables"
|
|
" WHERE table_schema='public' and table_type='BASE TABLE'");
|
|
bool status = query->Execute();
|
|
|
|
if (!status)
|
|
{
|
|
vtkErrorMacro(<< "Database returned error: " << query->GetLastErrorText());
|
|
this->SetLastErrorText(query->GetLastErrorText());
|
|
query->Delete();
|
|
return this->Tables;
|
|
}
|
|
vtkDebugMacro(<< "GetTables(): SQL query succeeded.");
|
|
while (query->NextRow())
|
|
{
|
|
this->Tables->InsertNextValue(query->DataValue(0).ToString());
|
|
}
|
|
query->Delete();
|
|
this->SetLastErrorText(nullptr);
|
|
return this->Tables;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
vtkStringArray* vtkPostgreSQLDatabase::GetRecord(const char* table)
|
|
{
|
|
// NB: There are *too many* other column names to list. Even the ones
|
|
// currently in the query below are probably over the top. But there's
|
|
// just so much peanut-buttery goodness in the table, I couldn't resist.
|
|
vtkSQLQuery* query = this->GetQueryInstance();
|
|
vtkStdString text("SELECT "
|
|
"column_name,column_default,data_type,is_nullable,character_maximum_length,"
|
|
"numeric_precision,datetime_precision"
|
|
" FROM information_schema.columns"
|
|
" WHERE table_name='");
|
|
text += table;
|
|
text += "' ORDER BY ordinal_position";
|
|
|
|
query->SetQuery(text.c_str());
|
|
bool status = query->Execute();
|
|
if (!status)
|
|
{
|
|
vtkErrorMacro(<< "GetRecord(" << table
|
|
<< "): Database returned error: " << query->GetLastErrorText());
|
|
this->SetLastErrorText(query->GetLastErrorText());
|
|
query->Delete();
|
|
return nullptr;
|
|
}
|
|
|
|
// Each row in the results that come back from this query
|
|
// describes a single column in the table.
|
|
vtkStringArray* results = vtkStringArray::New();
|
|
|
|
while (query->NextRow())
|
|
{
|
|
results->InsertNextValue(query->DataValue(0).ToString());
|
|
}
|
|
|
|
query->Delete();
|
|
this->SetLastErrorText(nullptr);
|
|
return results;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLDatabase::IsSupported(int feature)
|
|
{
|
|
switch (feature)
|
|
{
|
|
case VTK_SQL_FEATURE_BLOB:
|
|
case VTK_SQL_FEATURE_LAST_INSERT_ID:
|
|
case VTK_SQL_FEATURE_NAMED_PLACEHOLDERS:
|
|
case VTK_SQL_FEATURE_POSITIONAL_PLACEHOLDERS:
|
|
case VTK_SQL_FEATURE_PREPARED_QUERIES:
|
|
case VTK_SQL_FEATURE_TRANSACTIONS:
|
|
case VTK_SQL_FEATURE_UNICODE:
|
|
case VTK_SQL_FEATURE_BATCH_OPERATIONS:
|
|
case VTK_SQL_FEATURE_QUERY_SIZE:
|
|
case VTK_SQL_FEATURE_TRIGGERS:
|
|
return true;
|
|
default:
|
|
{
|
|
vtkErrorMacro(<< "Unknown SQL feature code " << feature << "! See "
|
|
<< "vtkSQLDatabase.h for a list of possible features.");
|
|
return false;
|
|
};
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
vtkStringArray* vtkPostgreSQLDatabase::GetDatabases()
|
|
{
|
|
if (!this->Connection)
|
|
{
|
|
vtkErrorMacro("Must be connected to a server to get a list of databases.");
|
|
return nullptr;
|
|
}
|
|
|
|
vtkSQLQuery* query = this->GetQueryInstance();
|
|
if (!query)
|
|
{
|
|
vtkErrorMacro("Could not create a query.");
|
|
return nullptr;
|
|
}
|
|
|
|
query->SetQuery("SELECT datname FROM pg_database");
|
|
if (!query->Execute())
|
|
{
|
|
query->Delete();
|
|
return nullptr;
|
|
}
|
|
vtkStringArray* dbNames = vtkStringArray::New();
|
|
while (query->NextRow())
|
|
{
|
|
dbNames->InsertNextValue(query->DataValue(0).ToString());
|
|
}
|
|
query->Delete();
|
|
return dbNames;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLDatabase::CreateDatabase(const char* dbName, bool dropExisting)
|
|
{
|
|
if (!dbName)
|
|
{
|
|
vtkErrorMacro("Databases must have a non-nullptr name");
|
|
return false;
|
|
}
|
|
|
|
bool dropCurrentlyConnected = false;
|
|
if (this->DatabaseName && !strcmp(this->DatabaseName, dbName))
|
|
{
|
|
dropCurrentlyConnected = true;
|
|
if (dropExisting)
|
|
{
|
|
// we can't drop a database we're connected to...
|
|
this->SetDatabaseName("template1");
|
|
this->Open();
|
|
}
|
|
else
|
|
{
|
|
// this will fail... let it. then report the error via LastErrorText
|
|
}
|
|
}
|
|
|
|
if (!this->Connection)
|
|
{
|
|
if (this->DatabaseName && !strcmp(this->DatabaseName, dbName))
|
|
{
|
|
// we can't connect to a database we haven't created yet and aren't connected to...
|
|
this->SetDatabaseName("template1");
|
|
dropCurrentlyConnected = true;
|
|
}
|
|
bool err = true;
|
|
if (this->DatabaseName && this->HostName)
|
|
{
|
|
err = this->Open() ? false : true;
|
|
}
|
|
if (err)
|
|
{
|
|
vtkErrorMacro("Must be connected to a server to create a database.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (dropExisting)
|
|
{
|
|
this->DropDatabase(dbName);
|
|
}
|
|
|
|
std::string qstr("CREATE DATABASE \"");
|
|
qstr += dbName;
|
|
qstr += "\"";
|
|
vtkSQLQuery* query = this->GetQueryInstance();
|
|
query->SetQuery(qstr.c_str());
|
|
if (query->Execute() == false)
|
|
{
|
|
this->SetLastErrorText(query->GetLastErrorText());
|
|
vtkErrorMacro(
|
|
"Could not create database \"" << dbName << "\". " << this->GetLastErrorText() << "\n");
|
|
query->Delete();
|
|
return false;
|
|
}
|
|
|
|
query->Delete();
|
|
this->SetLastErrorText(nullptr);
|
|
if (dropCurrentlyConnected)
|
|
{
|
|
this->SetDatabaseName(dbName);
|
|
this->Open();
|
|
}
|
|
return true;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLDatabase::DropDatabase(const char* dbName)
|
|
{
|
|
if (!dbName || strlen(dbName) == 0)
|
|
{
|
|
vtkErrorMacro("DropDatabase called with an empty database name");
|
|
return false;
|
|
}
|
|
|
|
if (!strcmp(dbName, this->DatabaseName))
|
|
{
|
|
// Can't drop database we're connected to... connect to the default db.
|
|
this->SetDatabaseName("template1");
|
|
}
|
|
|
|
if (!this->Connection)
|
|
{
|
|
bool err = true;
|
|
if (this->DatabaseName && this->HostName)
|
|
{
|
|
err = this->Open() ? false : true;
|
|
}
|
|
if (err)
|
|
{
|
|
vtkErrorMacro("Must be connected to a server to create a database.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
std::string qstr("DROP DATABASE IF EXISTS \"");
|
|
qstr += dbName;
|
|
qstr += "\"";
|
|
vtkSQLQuery* query = this->GetQueryInstance();
|
|
query->SetQuery(qstr.c_str());
|
|
if (query->Execute() == false)
|
|
{
|
|
this->SetLastErrorText(query->GetLastErrorText());
|
|
vtkErrorMacro(<< "Could not drop database \"" << dbName << "\". "
|
|
<< query->GetLastErrorText());
|
|
query->Delete();
|
|
return false;
|
|
}
|
|
this->SetLastErrorText(nullptr);
|
|
query->Delete();
|
|
return true;
|
|
}
|
|
|
|
void vtkPostgreSQLDatabase::NullTrailingWhitespace(char* msg)
|
|
{
|
|
// overwrite any blank space at the end of a message with nullptr.
|
|
// PostgreSQL error messages are terminated with a newline, which
|
|
// does not work well with VTK's already lengthy error output.
|
|
int msglen = strlen(msg);
|
|
char* tail = msg + msglen - 1;
|
|
while (tail > msg && isspace(*tail))
|
|
*(tail--) = 0;
|
|
}
|
|
|
|
bool vtkPostgreSQLDatabase::OpenInternal(const char* connectionOptions)
|
|
{
|
|
assert(this->Connection == nullptr);
|
|
this->Connection = new vtkPostgreSQLDatabasePrivate;
|
|
this->Connection->Connection = PQconnectdb(connectionOptions);
|
|
if (PQstatus(this->Connection->Connection) == CONNECTION_OK)
|
|
{
|
|
this->SetLastErrorText(nullptr);
|
|
this->UpdateDataTypeMap();
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
this->SetLastErrorText(PQerrorMessage(this->Connection->Connection));
|
|
vtkErrorMacro(<< "Unable to open database connection. " << this->GetLastErrorText());
|
|
delete this->Connection;
|
|
this->Connection = nullptr;
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void vtkPostgreSQLDatabase::UpdateDataTypeMap()
|
|
{
|
|
if (!this->IsOpen())
|
|
{
|
|
return;
|
|
}
|
|
|
|
this->Connection->DataTypeMap.clear();
|
|
|
|
vtkSQLQuery* typeQuery = this->GetQueryInstance();
|
|
typeQuery->SetQuery("SELECT oid, typname, typlen FROM pg_type");
|
|
bool status = typeQuery->Execute();
|
|
if (!status)
|
|
{
|
|
vtkErrorMacro(<< "I was totally surprised to see the data type query fail. Error message: "
|
|
<< typeQuery->GetLastErrorText());
|
|
typeQuery->Delete();
|
|
}
|
|
else
|
|
{
|
|
while (typeQuery->NextRow())
|
|
{
|
|
Oid oid;
|
|
vtkStdString name;
|
|
int len;
|
|
|
|
// Caution: this assumes that the Postgres OID type is a 32-bit
|
|
// unsigned int.
|
|
oid = typeQuery->DataValue(0).ToUnsignedInt();
|
|
name = typeQuery->DataValue(1).ToString();
|
|
len = typeQuery->DataValue(2).ToInt();
|
|
|
|
if (name == "int8" || (name == "oid" && len == 8))
|
|
{
|
|
this->Connection->DataTypeMap[oid] = VTK_TYPE_INT64;
|
|
}
|
|
else if (name == "int4" || (name == "oid" && len == 4))
|
|
{
|
|
this->Connection->DataTypeMap[oid] = VTK_TYPE_INT32;
|
|
}
|
|
else if (name == "int2")
|
|
{
|
|
this->Connection->DataTypeMap[oid] = VTK_TYPE_INT16;
|
|
}
|
|
else if (name == "char")
|
|
{
|
|
this->Connection->DataTypeMap[oid] = VTK_TYPE_INT8;
|
|
}
|
|
else if (name == "time_stamp")
|
|
{
|
|
this->Connection->DataTypeMap[oid] = VTK_TYPE_INT64;
|
|
}
|
|
else if (name == "float4")
|
|
{
|
|
this->Connection->DataTypeMap[oid] = VTK_FLOAT;
|
|
}
|
|
else if (name == "float8")
|
|
{
|
|
this->Connection->DataTypeMap[oid] = VTK_DOUBLE;
|
|
}
|
|
else if (name == "abstime" || name == "reltime")
|
|
{
|
|
this->Connection->DataTypeMap[oid] = (len == 4 ? VTK_TYPE_INT32 : VTK_TYPE_INT64);
|
|
}
|
|
else if (name == "text")
|
|
{
|
|
this->Connection->DataTypeMap[oid] = VTK_STRING;
|
|
}
|
|
} // done looping over rows
|
|
} // done with "query is successful"
|
|
typeQuery->Delete();
|
|
}
|