mirror of https://gitee.com/openkylin/vtk9.git
1033 lines
26 KiB
C++
1033 lines
26 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkPostgreSQLQuery.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 "vtkPostgreSQLQuery.h"
|
|
|
|
#include "vtkObjectFactory.h"
|
|
#include "vtkPostgreSQLDatabase.h"
|
|
#include "vtkPostgreSQLDatabasePrivate.h"
|
|
#include "vtkStringArray.h"
|
|
#include "vtkVariant.h"
|
|
#include "vtkVariantArray.h"
|
|
|
|
#include <cassert>
|
|
#include <limits> // man, I hope all platforms have this nowadays
|
|
|
|
#include <sstream>
|
|
|
|
#define BEGIN_TRANSACTION "BEGIN"
|
|
#define COMMIT_TRANSACTION "COMMIT"
|
|
#define ROLLBACK_TRANSACTION "ROLLBACK"
|
|
|
|
#define DECLARE_CONVERTER(TargetType) vtkVariant ConvertStringTo##TargetType(bool, const char*);
|
|
|
|
DECLARE_CONVERTER(Boolean);
|
|
DECLARE_CONVERTER(SignedChar);
|
|
DECLARE_CONVERTER(UnsignedChar);
|
|
DECLARE_CONVERTER(SignedShort);
|
|
DECLARE_CONVERTER(UnsignedShort);
|
|
DECLARE_CONVERTER(SignedInt);
|
|
DECLARE_CONVERTER(UnsignedInt);
|
|
DECLARE_CONVERTER(SignedLong);
|
|
DECLARE_CONVERTER(UnsignedLong);
|
|
DECLARE_CONVERTER(Float);
|
|
DECLARE_CONVERTER(Double);
|
|
DECLARE_CONVERTER(VtkIdType);
|
|
DECLARE_CONVERTER(String);
|
|
DECLARE_CONVERTER(SignedLongLong);
|
|
DECLARE_CONVERTER(UnsignedLongLong);
|
|
|
|
template <typename T>
|
|
void ConvertFromNetworkOrder(T& target, const char* rawBytes)
|
|
{
|
|
for (unsigned int i = 0; i < sizeof(T); ++i)
|
|
{
|
|
int targetByte = sizeof(T) - (i + 1);
|
|
target |= (rawBytes[i] << (8 * targetByte));
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkStandardNewMacro(vtkPostgreSQLQuery);
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
class vtkPostgreSQLQueryPrivate
|
|
{
|
|
public:
|
|
vtkPostgreSQLQueryPrivate()
|
|
{
|
|
this->QueryResults = nullptr;
|
|
this->CurrentRow = -1;
|
|
}
|
|
~vtkPostgreSQLQueryPrivate()
|
|
{
|
|
if (this->QueryResults)
|
|
{
|
|
PQclear(this->QueryResults);
|
|
}
|
|
}
|
|
|
|
PGresult* QueryResults;
|
|
int CurrentRow;
|
|
};
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant vtkPostgreSQLQuery::DataValue(vtkIdType column)
|
|
{
|
|
if (this->IsActive() == false)
|
|
{
|
|
vtkWarningMacro("DataValue() called on inactive query");
|
|
return vtkVariant();
|
|
}
|
|
else if (column < 0 || column >= this->GetNumberOfFields())
|
|
{
|
|
vtkWarningMacro("DataValue() called with out-of-range column index " << column);
|
|
return vtkVariant();
|
|
}
|
|
else if (this->QueryInternals->CurrentRow < 0)
|
|
{
|
|
vtkWarningMacro(
|
|
"DataValue() cannot be called before advancing to the first row with NextRow().");
|
|
return vtkVariant();
|
|
}
|
|
|
|
// Since null is independent of data type, check that next
|
|
if (PQgetisnull(this->QueryInternals->QueryResults, this->QueryInternals->CurrentRow, column))
|
|
{
|
|
return vtkVariant();
|
|
}
|
|
|
|
int colType = this->GetFieldType(column);
|
|
bool isBinary = this->IsColumnBinary(column);
|
|
const char* rawData = this->GetColumnRawData(column);
|
|
switch (colType)
|
|
{
|
|
case VTK_VOID:
|
|
return vtkVariant();
|
|
case VTK_BIT:
|
|
{
|
|
return ConvertStringToBoolean(isBinary, rawData);
|
|
}
|
|
case VTK_CHAR:
|
|
case VTK_SIGNED_CHAR:
|
|
{
|
|
return ConvertStringToSignedChar(isBinary, rawData);
|
|
}
|
|
case VTK_UNSIGNED_CHAR:
|
|
{
|
|
return ConvertStringToUnsignedChar(isBinary, rawData);
|
|
}
|
|
case VTK_SHORT:
|
|
{
|
|
return ConvertStringToSignedShort(isBinary, rawData);
|
|
}
|
|
case VTK_UNSIGNED_SHORT:
|
|
{
|
|
return ConvertStringToUnsignedShort(isBinary, rawData);
|
|
}
|
|
case VTK_INT:
|
|
{
|
|
return ConvertStringToSignedInt(isBinary, rawData);
|
|
}
|
|
case VTK_UNSIGNED_INT:
|
|
{
|
|
return ConvertStringToUnsignedInt(isBinary, rawData);
|
|
}
|
|
case VTK_LONG:
|
|
{
|
|
return ConvertStringToSignedLong(isBinary, rawData);
|
|
}
|
|
case VTK_UNSIGNED_LONG:
|
|
{
|
|
return ConvertStringToUnsignedLong(isBinary, rawData);
|
|
}
|
|
case VTK_LONG_LONG:
|
|
{
|
|
return ConvertStringToSignedLongLong(isBinary, rawData);
|
|
}
|
|
case VTK_UNSIGNED_LONG_LONG:
|
|
{
|
|
return ConvertStringToUnsignedLongLong(isBinary, rawData);
|
|
}
|
|
case VTK_FLOAT:
|
|
{
|
|
return ConvertStringToFloat(isBinary, rawData);
|
|
}
|
|
case VTK_DOUBLE:
|
|
{
|
|
return ConvertStringToDouble(isBinary, rawData);
|
|
}
|
|
case VTK_ID_TYPE:
|
|
{
|
|
return ConvertStringToVtkIdType(isBinary, rawData);
|
|
}
|
|
case VTK_STRING:
|
|
{
|
|
return vtkVariant(rawData);
|
|
}
|
|
default:
|
|
{
|
|
return vtkVariant();
|
|
}
|
|
} // end of switch on column type
|
|
} // end of DataValue(int column)
|
|
|
|
//------------------------------------------------------------------------------
|
|
vtkPostgreSQLQuery::vtkPostgreSQLQuery()
|
|
{
|
|
this->TransactionInProgress = false;
|
|
this->LastErrorText = nullptr;
|
|
this->QueryInternals = nullptr;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
vtkPostgreSQLQuery::~vtkPostgreSQLQuery()
|
|
{
|
|
this->SetDatabase(nullptr);
|
|
this->SetLastErrorText(nullptr);
|
|
delete this->QueryInternals;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
void vtkPostgreSQLQuery::PrintSelf(ostream& os, vtkIndent indent)
|
|
{
|
|
this->Superclass::PrintSelf(os, indent);
|
|
os << indent << "Transaction in progress: " << (this->TransactionInProgress ? "YES" : "NO")
|
|
<< "\n";
|
|
os << indent << "Last error message: " << (this->LastErrorText ? this->LastErrorText : "(null)")
|
|
<< "\n";
|
|
os << indent << "Internals: ";
|
|
if (this->QueryInternals)
|
|
{
|
|
os << this->QueryInternals;
|
|
}
|
|
else
|
|
{
|
|
os << "(null)";
|
|
}
|
|
os << "\n";
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLQuery::Execute()
|
|
{
|
|
if (this->Query == nullptr)
|
|
{
|
|
vtkErrorMacro("Cannot execute before a query has been set.");
|
|
return false;
|
|
}
|
|
|
|
vtkPostgreSQLDatabase* db = vtkPostgreSQLDatabase::SafeDownCast(this->Database);
|
|
assert(db);
|
|
|
|
// If a query is already in progress clear out its results so we can
|
|
// begin anew.
|
|
if (this->QueryInternals)
|
|
{
|
|
this->DeleteQueryResults();
|
|
}
|
|
|
|
if (!db->IsOpen())
|
|
{
|
|
this->SetLastErrorText("Cannot execute query. Database connection is closed.");
|
|
vtkErrorMacro(<< "Cannot execute query. Database connection is closed.");
|
|
this->Active = false;
|
|
return false;
|
|
}
|
|
|
|
this->QueryInternals = new vtkPostgreSQLQueryPrivate;
|
|
this->QueryInternals->QueryResults = PQexec(db->Connection->Connection, this->Query);
|
|
|
|
bool returnStatus;
|
|
switch (PQresultStatus(this->QueryInternals->QueryResults))
|
|
{
|
|
case PGRES_EMPTY_QUERY:
|
|
{
|
|
returnStatus = true;
|
|
this->Active = false;
|
|
this->DeleteQueryResults();
|
|
vtkWarningMacro(<< "Query string was set but empty.");
|
|
this->SetLastErrorText(nullptr);
|
|
};
|
|
break;
|
|
|
|
case PGRES_COMMAND_OK: // success on a command returning no data
|
|
{
|
|
returnStatus = true;
|
|
this->Active = true;
|
|
this->DeleteQueryResults();
|
|
this->SetLastErrorText(nullptr);
|
|
};
|
|
break;
|
|
|
|
case PGRES_TUPLES_OK:
|
|
{
|
|
returnStatus = true;
|
|
this->Active = true;
|
|
this->SetLastErrorText(nullptr);
|
|
};
|
|
break;
|
|
|
|
case PGRES_BAD_RESPONSE:
|
|
{
|
|
returnStatus = false;
|
|
this->Active = false;
|
|
this->DeleteQueryResults();
|
|
this->SetLastErrorText("Incomprehensible server response");
|
|
};
|
|
break;
|
|
|
|
case PGRES_FATAL_ERROR:
|
|
{
|
|
returnStatus = false;
|
|
this->Active = false;
|
|
this->SetLastErrorText(PQerrorMessage(db->Connection->Connection));
|
|
vtkErrorMacro(<< "Fatal error during query: " << this->GetLastErrorText());
|
|
this->DeleteQueryResults();
|
|
};
|
|
break;
|
|
|
|
default:
|
|
{
|
|
returnStatus = false;
|
|
this->Active = false;
|
|
std::ostringstream sbuf;
|
|
sbuf << "Unhandled server response: ";
|
|
sbuf << PQresStatus(PQresultStatus(this->QueryInternals->QueryResults));
|
|
this->SetLastErrorText(sbuf.str().c_str());
|
|
vtkErrorMacro(<< "Unhandled server response: " << this->GetLastErrorText());
|
|
this->DeleteQueryResults();
|
|
};
|
|
break;
|
|
}
|
|
|
|
return returnStatus;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int vtkPostgreSQLQuery::GetNumberOfFields()
|
|
{
|
|
if (!this->Active || !this->QueryInternals)
|
|
{
|
|
vtkErrorMacro("Query is not active!");
|
|
return 0;
|
|
}
|
|
|
|
return PQnfields(this->QueryInternals->QueryResults);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
const char* vtkPostgreSQLQuery::GetFieldName(int column)
|
|
{
|
|
if (!this->Active || !this->QueryInternals->QueryResults)
|
|
{
|
|
vtkErrorMacro("Query is not active!");
|
|
return nullptr;
|
|
}
|
|
else if (column < 0 || column >= this->GetNumberOfFields())
|
|
{
|
|
vtkErrorMacro("Illegal field index " << column);
|
|
return nullptr;
|
|
}
|
|
return PQfname(this->QueryInternals->QueryResults, column);
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
int vtkPostgreSQLQuery::GetFieldType(int column)
|
|
{
|
|
if (!this->Active || !this->QueryInternals)
|
|
{
|
|
vtkErrorMacro("Query is not active!");
|
|
return -1;
|
|
}
|
|
else if (column < 0 || column >= this->GetNumberOfFields())
|
|
{
|
|
vtkErrorMacro("Illegal field index " << column);
|
|
return -1;
|
|
}
|
|
|
|
vtkPostgreSQLDatabase* db = vtkPostgreSQLDatabase::SafeDownCast(this->Database);
|
|
if (!db)
|
|
{
|
|
vtkErrorMacro(<< "No database! How did this happen?");
|
|
return -1;
|
|
}
|
|
return db->Connection->GetVTKTypeFromOID(PQftype(this->QueryInternals->QueryResults, column));
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLQuery::NextRow()
|
|
{
|
|
if (!this->IsActive() || !this->QueryInternals)
|
|
{
|
|
vtkErrorMacro("Query is not active!");
|
|
return false;
|
|
}
|
|
|
|
if (this->QueryInternals->CurrentRow < (this->GetNumberOfRows() - 1))
|
|
{
|
|
++this->QueryInternals->CurrentRow;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
const char* vtkPostgreSQLQuery::GetLastErrorText()
|
|
{
|
|
if (!this->Database)
|
|
{
|
|
return "No database";
|
|
}
|
|
return this->LastErrorText;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkStdString vtkPostgreSQLQuery::EscapeString(vtkStdString s, bool addSurroundingQuotes)
|
|
{
|
|
vtkStdString retval;
|
|
if (addSurroundingQuotes)
|
|
{
|
|
retval = "'";
|
|
}
|
|
|
|
vtkPostgreSQLDatabase* db = static_cast<vtkPostgreSQLDatabase*>(this->Database);
|
|
|
|
if (db && db->Connection)
|
|
{
|
|
char* escaped = new char[2 * s.size() + 1];
|
|
int error;
|
|
PQescapeStringConn(db->Connection->Connection, escaped, s.c_str(), s.size(), &error);
|
|
retval.append(escaped);
|
|
delete[] escaped;
|
|
if (error)
|
|
{
|
|
vtkErrorMacro(<< "Error while escaping string. Expect the result to be unusable.");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
retval.append(this->Superclass::EscapeString(s, false));
|
|
}
|
|
|
|
if (addSurroundingQuotes)
|
|
{
|
|
retval += "'";
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLQuery::HasError()
|
|
{
|
|
if (!this->Database)
|
|
{
|
|
return false;
|
|
}
|
|
return this->LastErrorText != nullptr;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLQuery::BeginTransaction()
|
|
{
|
|
if (this->TransactionInProgress)
|
|
{
|
|
vtkErrorMacro(<< "Cannot start a transaction. One is already in progress.");
|
|
return false;
|
|
}
|
|
|
|
vtkPostgreSQLDatabase* db = vtkPostgreSQLDatabase::SafeDownCast(this->Database);
|
|
assert(db);
|
|
bool status;
|
|
PGresult* result = PQexec(db->Connection->Connection, BEGIN_TRANSACTION);
|
|
switch (PQresultStatus(result))
|
|
{
|
|
case PGRES_COMMAND_OK:
|
|
{
|
|
this->SetLastErrorText(nullptr);
|
|
this->TransactionInProgress = true;
|
|
status = true;
|
|
};
|
|
break;
|
|
case PGRES_FATAL_ERROR:
|
|
{
|
|
this->SetLastErrorText(PQresultErrorMessage(result));
|
|
vtkErrorMacro(<< "Error in BeginTransaction: " << this->GetLastErrorText());
|
|
status = false;
|
|
};
|
|
break;
|
|
default:
|
|
{
|
|
this->SetLastErrorText(PQresultErrorMessage(result));
|
|
vtkWarningMacro(<< "Unexpected return code " << PQresultStatus(result) << " ("
|
|
<< PQresStatus(PQresultStatus(result)) << ") with error message "
|
|
<< (this->LastErrorText ? this->LastErrorText : "(null)"));
|
|
status = false;
|
|
};
|
|
break;
|
|
}
|
|
PQclear(result);
|
|
return status;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLQuery::CommitTransaction()
|
|
{
|
|
if (!this->TransactionInProgress)
|
|
{
|
|
vtkErrorMacro(<< "Cannot commit: no transaction is in progress.");
|
|
return false;
|
|
}
|
|
|
|
vtkPostgreSQLDatabase* db = vtkPostgreSQLDatabase::SafeDownCast(this->Database);
|
|
assert(db);
|
|
|
|
PGresult* result = PQexec(db->Connection->Connection, COMMIT_TRANSACTION);
|
|
bool status;
|
|
switch (PQresultStatus(result))
|
|
{
|
|
case PGRES_COMMAND_OK:
|
|
{
|
|
this->SetLastErrorText(nullptr);
|
|
this->TransactionInProgress = false;
|
|
status = true;
|
|
};
|
|
break;
|
|
case PGRES_FATAL_ERROR:
|
|
{
|
|
this->SetLastErrorText(PQresultErrorMessage(result));
|
|
vtkErrorMacro(<< "Error in CommitTransaction: " << this->GetLastErrorText());
|
|
this->TransactionInProgress = false;
|
|
status = false;
|
|
};
|
|
break;
|
|
default:
|
|
{
|
|
this->SetLastErrorText(PQresultErrorMessage(result));
|
|
vtkWarningMacro(<< "Unexpected return code " << PQresultStatus(result) << " ("
|
|
<< PQresStatus(PQresultStatus(result)) << ") with error message "
|
|
<< (this->LastErrorText ? this->LastErrorText : "(null)"));
|
|
this->TransactionInProgress = false;
|
|
status = false;
|
|
};
|
|
break;
|
|
}
|
|
PQclear(result);
|
|
return status;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
bool vtkPostgreSQLQuery::RollbackTransaction()
|
|
{
|
|
if (!this->TransactionInProgress)
|
|
{
|
|
vtkErrorMacro(<< "Cannot rollback: no transaction is in progress.");
|
|
return false;
|
|
}
|
|
|
|
vtkPostgreSQLDatabase* db = vtkPostgreSQLDatabase::SafeDownCast(this->Database);
|
|
assert(db);
|
|
|
|
PGresult* result = PQexec(db->Connection->Connection, ROLLBACK_TRANSACTION);
|
|
bool status;
|
|
switch (PQresultStatus(result))
|
|
{
|
|
case PGRES_COMMAND_OK:
|
|
{
|
|
this->SetLastErrorText(nullptr);
|
|
this->TransactionInProgress = false;
|
|
status = true;
|
|
};
|
|
break;
|
|
case PGRES_FATAL_ERROR:
|
|
{
|
|
this->SetLastErrorText(PQresultErrorMessage(result));
|
|
vtkErrorMacro(<< "Error in RollbackTransaction: " << this->GetLastErrorText());
|
|
this->TransactionInProgress = false;
|
|
status = false;
|
|
};
|
|
break;
|
|
default:
|
|
{
|
|
this->SetLastErrorText(PQresultErrorMessage(result));
|
|
vtkWarningMacro(<< "Unexpected return code " << PQresultStatus(result) << " ("
|
|
<< PQresStatus(PQresultStatus(result)) << ") with error message "
|
|
<< (this->LastErrorText ? this->LastErrorText : "(null)"));
|
|
this->TransactionInProgress = false;
|
|
status = false;
|
|
};
|
|
break;
|
|
}
|
|
PQclear(result);
|
|
return status;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
void vtkPostgreSQLQuery::DeleteQueryResults()
|
|
{
|
|
this->Active = false;
|
|
delete this->QueryInternals;
|
|
this->QueryInternals = nullptr;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToBoolean(bool, const char* rawData)
|
|
{
|
|
// Since there are only a few possibilities I'm going to check
|
|
// them all by hand.
|
|
switch (rawData[0])
|
|
{
|
|
case 'T':
|
|
case 't':
|
|
case 'Y':
|
|
case 'y':
|
|
case '1':
|
|
case 1:
|
|
{
|
|
return vtkVariant(true);
|
|
}
|
|
|
|
case 'F':
|
|
case 'f':
|
|
case 'N':
|
|
case 'n':
|
|
case '0':
|
|
case 0:
|
|
{
|
|
return vtkVariant(false);
|
|
}
|
|
|
|
default:
|
|
{
|
|
vtkGenericWarningMacro(<< "Unable to convert raw data to boolean. Data length is "
|
|
<< strlen(rawData) << " and string is '" << rawData << "'");
|
|
return vtkVariant();
|
|
}
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToSignedChar(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
return vtkVariant(rawData[0]);
|
|
}
|
|
else
|
|
{
|
|
vtkVariant converter(rawData);
|
|
return vtkVariant(converter.ToChar());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToUnsignedChar(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
return vtkVariant(static_cast<unsigned char>(rawData[0]));
|
|
}
|
|
else
|
|
{
|
|
vtkVariant converter(rawData);
|
|
return vtkVariant(converter.ToUnsignedChar());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToSignedShort(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
short result = 0;
|
|
ConvertFromNetworkOrder(result, rawData);
|
|
return vtkVariant(result);
|
|
}
|
|
else
|
|
{
|
|
vtkVariant converter(rawData);
|
|
return vtkVariant(converter.ToShort());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToUnsignedShort(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
unsigned short result = 0;
|
|
ConvertFromNetworkOrder(result, rawData);
|
|
return vtkVariant(result);
|
|
}
|
|
else
|
|
{
|
|
vtkVariant converter(rawData);
|
|
return vtkVariant(converter.ToUnsignedShort());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToSignedInt(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
int result = 0;
|
|
ConvertFromNetworkOrder(result, rawData);
|
|
return vtkVariant(result);
|
|
}
|
|
else
|
|
{
|
|
vtkVariant converter(rawData);
|
|
return vtkVariant(converter.ToInt());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToUnsignedInt(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
unsigned int result = 0;
|
|
ConvertFromNetworkOrder(result, rawData);
|
|
return vtkVariant(result);
|
|
}
|
|
else
|
|
{
|
|
vtkVariant converter(rawData);
|
|
return vtkVariant(converter.ToUnsignedInt());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToSignedLong(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
signed long result = 0;
|
|
ConvertFromNetworkOrder(result, rawData);
|
|
return vtkVariant(result);
|
|
}
|
|
else
|
|
{
|
|
vtkVariant converter(rawData);
|
|
return vtkVariant(converter.ToLong());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToUnsignedLong(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
unsigned long result = 0;
|
|
ConvertFromNetworkOrder(result, rawData);
|
|
return vtkVariant(result);
|
|
}
|
|
else
|
|
{
|
|
vtkVariant converter(rawData);
|
|
return vtkVariant(converter.ToLong());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToSignedLongLong(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
long long result = 0;
|
|
ConvertFromNetworkOrder(result, rawData);
|
|
return vtkVariant(result);
|
|
}
|
|
else
|
|
{
|
|
vtkVariant converter(rawData);
|
|
return vtkVariant(converter.ToLongLong());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToUnsignedLongLong(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
unsigned long long result = 0;
|
|
ConvertFromNetworkOrder(result, rawData);
|
|
return vtkVariant(result);
|
|
}
|
|
else
|
|
{
|
|
vtkVariant converter(rawData);
|
|
return vtkVariant(converter.ToUnsignedLongLong());
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToFloat(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
// As of PostgreSQL version 8.3.0, libpq transmits a float in network
|
|
// byte order -- that is, it reinterprets the bits as an unsigned int
|
|
// and then transmits them that way. This... frightens me. It assumes
|
|
// that both sender and recipient use IEEE floats. Still, I'm not sure
|
|
// there's any other good way to do it.
|
|
unsigned int intResult = 0;
|
|
ConvertFromNetworkOrder(intResult, rawData);
|
|
|
|
// This is the idiom that libpq uses internally to convert between the
|
|
// two types.
|
|
union {
|
|
unsigned int i;
|
|
float f;
|
|
} swap;
|
|
swap.i = intResult;
|
|
float floatResult = swap.f;
|
|
|
|
return vtkVariant(floatResult);
|
|
}
|
|
else
|
|
{
|
|
vtkStdString rawString(rawData);
|
|
float finalResult;
|
|
|
|
// Catch NaN
|
|
if (rawData[0] == 'N' || rawData[0] == 'n')
|
|
{
|
|
if (std::numeric_limits<float>::has_quiet_NaN)
|
|
{
|
|
finalResult = std::numeric_limits<float>::quiet_NaN();
|
|
}
|
|
else
|
|
{
|
|
// C99 defines a NAN macro. If it's there, that solves our problem.
|
|
#if defined(NAN)
|
|
finalResult = NAN;
|
|
#else
|
|
float zero = 0.0;
|
|
finalResult = zero / zero;
|
|
#endif
|
|
}
|
|
}
|
|
else if (rawString == "Infinity")
|
|
{
|
|
if (std::numeric_limits<float>::has_infinity)
|
|
{
|
|
finalResult = std::numeric_limits<float>::infinity();
|
|
}
|
|
else
|
|
{
|
|
finalResult = VTK_FLOAT_MAX;
|
|
}
|
|
}
|
|
else if (rawString == "-Infinity")
|
|
{
|
|
if (std::numeric_limits<float>::has_infinity)
|
|
{
|
|
finalResult = -std::numeric_limits<float>::infinity();
|
|
}
|
|
else
|
|
{
|
|
finalResult = -VTK_FLOAT_MAX;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// hurray, it's an ordinary float
|
|
vtkVariant converter(rawData);
|
|
finalResult = converter.ToFloat();
|
|
}
|
|
return vtkVariant(finalResult);
|
|
} // end of handling string representation
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToVtkIdType(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
vtkIdType result = 0;
|
|
ConvertFromNetworkOrder(result, rawData);
|
|
return vtkVariant(result);
|
|
}
|
|
else
|
|
{
|
|
std::stringstream convertStream;
|
|
convertStream.str(rawData);
|
|
vtkIdType result;
|
|
convertStream >> result;
|
|
return vtkVariant(result);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
vtkVariant ConvertStringToDouble(bool isBinary, const char* rawData)
|
|
{
|
|
if (isBinary)
|
|
{
|
|
// As of PostgreSQL version 8.3.0, libpq transmits a float in network
|
|
// byte order -- that is, it reinterprets the bits as an unsigned int
|
|
// and then transmits them that way. This... frightens me. It assumes
|
|
// that both sender and recipient use IEEE floats. Still, I'm not sure
|
|
// there's any other good way to do it.
|
|
|
|
// Let's hope that we always have a 64-bit type.
|
|
vtkTypeUInt64 intResult = 0;
|
|
ConvertFromNetworkOrder(intResult, rawData);
|
|
union {
|
|
vtkTypeUInt64 i;
|
|
double d;
|
|
} swap;
|
|
swap.i = intResult;
|
|
return vtkVariant(swap.d);
|
|
}
|
|
else
|
|
{
|
|
double finalResult;
|
|
vtkStdString rawString(rawData);
|
|
|
|
// Catch NaN
|
|
if (rawData[0] == 'N' || rawData[0] == 'n')
|
|
{
|
|
if (std::numeric_limits<double>::has_quiet_NaN)
|
|
{
|
|
finalResult = std::numeric_limits<double>::quiet_NaN();
|
|
}
|
|
else
|
|
{
|
|
// C99 defines a NAN macro. If it's there, that solves our problem.
|
|
#if defined(NAN)
|
|
finalResult = NAN;
|
|
#else
|
|
double zero = 0.0;
|
|
finalResult = zero / zero;
|
|
#endif
|
|
}
|
|
}
|
|
else if (rawString == "Infinity")
|
|
{
|
|
if (std::numeric_limits<double>::has_infinity)
|
|
{
|
|
finalResult = std::numeric_limits<double>::infinity();
|
|
}
|
|
else
|
|
{
|
|
finalResult = VTK_DOUBLE_MAX;
|
|
}
|
|
}
|
|
else if (rawString == "-Infinity")
|
|
{
|
|
if (std::numeric_limits<double>::has_infinity)
|
|
{
|
|
finalResult = -std::numeric_limits<double>::infinity();
|
|
}
|
|
else
|
|
{
|
|
finalResult = -VTK_DOUBLE_MAX;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// hurray, it's an ordinary double
|
|
vtkVariant converter(rawData);
|
|
finalResult = converter.ToDouble();
|
|
}
|
|
return vtkVariant(finalResult);
|
|
} // end of handling string representation
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
bool vtkPostgreSQLQuery::IsColumnBinary(int whichColumn)
|
|
{
|
|
if ((!this->Active) || (!this->Database) || (!this->QueryInternals->QueryResults))
|
|
{
|
|
vtkWarningMacro(<< "No active query!");
|
|
return false;
|
|
}
|
|
else if (whichColumn < 0 || whichColumn >= this->GetNumberOfFields())
|
|
{
|
|
vtkWarningMacro(<< "Illegal column index " << whichColumn);
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
return (PQfformat(this->QueryInternals->QueryResults, whichColumn) == 1);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
const char* vtkPostgreSQLQuery::GetColumnRawData(int whichColumn)
|
|
{
|
|
if ((!this->Active) || (!this->Database) || (!this->QueryInternals->QueryResults))
|
|
{
|
|
vtkWarningMacro(<< "No active query!");
|
|
return nullptr;
|
|
}
|
|
else if (whichColumn < 0 || whichColumn >= this->GetNumberOfFields())
|
|
{
|
|
vtkWarningMacro(<< "Illegal column index " << whichColumn);
|
|
return nullptr;
|
|
}
|
|
else
|
|
{
|
|
return PQgetvalue(
|
|
this->QueryInternals->QueryResults, this->QueryInternals->CurrentRow, whichColumn);
|
|
}
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
int vtkPostgreSQLQuery::GetNumberOfRows()
|
|
{
|
|
if (!this->Database || !this->Database->IsOpen() || !this->QueryInternals || !this->Active)
|
|
{
|
|
vtkWarningMacro(<< "No active query. Cannot retrieve number of rows.");
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
return PQntuples(this->QueryInternals->QueryResults);
|
|
}
|
|
}
|