Files
ThirdParty-6/ParaView-5.0.1/VTK/IO/MySQL/vtkMySQLQuery.cxx

1171 lines
31 KiB
C++

/*=========================================================================
Program: Visualization Toolkit
Module: vtkMySQLQuery.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.
=========================================================================*/
#include "vtkMySQLQuery.h"
#include "vtkMySQLDatabase.h"
#include "vtkMySQLDatabasePrivate.h"
#include "vtkObjectFactory.h"
#include "vtkStringArray.h"
#include "vtkVariant.h"
#include "vtkVariantArray.h"
#include <mysql.h>
#include <errmsg.h>
#if defined(WIN32)
# include <string.h>
# include <locale.h>
# define LOWERCASE_COMPARE _stricmp
#else
# include <strings.h>
# define LOWERCASE_COMPARE strcasecmp
#endif
#include <cassert>
#include <sstream>
#include <vector>
/*
* Bound Parameters and MySQL
*
* MySQL handles prepared statements using a MYSQL_STMT struct.
* Parameters are bound to placeholders using a MYSQL_BIND struct.
* The MYSQL_BIND contains a pointer to a data buffer. That buffer
* needs to be freed somehow when it's no longer needed.
*
* I'm going to handle this by using my own class
* (vtkMySQLBoundParameter) to hold all the information the user
* passes in. At execution time, I'll take those parameters and
* assemble the array of MYSQL_BIND objects that
* mysql_stmt_bind_param() expects. The vtkMySQLBoundParameter
* instances will each own the buffers for their data.
*
* This is slightly inefficient in that it will generate
* a few tiny little new[] requests. If this ever becomes a problem,
* we can allocate a fixed-size buffer (8 or 16 bytes) inside
* vtkMySQLBoundParameter and use that for the data storage by
* default. That will still require special-case handling for blobs
* and strings.
*
* The vtkMySQLQueryInternals class will handle the bookkeeping for
* which parameters are and aren't bound at any given time.
*/
// ----------------------------------------------------------------------
class vtkMySQLBoundParameter
{
public:
vtkMySQLBoundParameter() :
IsNull(true), Data(NULL), BufferSize(0), DataLength(0), HasError(false)
{
}
~vtkMySQLBoundParameter()
{
delete [] this->Data;
}
void SetData(char *data, unsigned long size)
{
delete [] this->Data;
this->BufferSize = size;
this->Data = new char[size];
memcpy(this->Data, data, size);
}
MYSQL_BIND BuildParameterStruct()
{
MYSQL_BIND output;
output.buffer_type = this->DataType;
output.buffer = this->Data;
output.buffer_length = this->BufferSize;
output.length = &(this->DataLength);
output.is_null = &(this->IsNull);
output.is_unsigned = this->IsUnsigned;
output.error = NULL;
return output;
}
public:
my_bool IsNull; // Is this parameter NULL?
my_bool IsUnsigned; // For integer types, is it unsigned?
char *Data; // Buffer holding actual data
unsigned long BufferSize; // Buffer size
unsigned long DataLength; // Size of the data in the buffer (must
// be less than or equal to BufferSize)
my_bool HasError; // for the server to report truncation
enum enum_field_types DataType; // MySQL data type for the contained data
};
// ----------------------------------------------------------------------
MYSQL_BIND BuildNullParameterStruct()
{
MYSQL_BIND output;
output.buffer_type = MYSQL_TYPE_NULL;
return output;
}
// ----------------------------------------------------------------------
#define VTK_MYSQL_TYPENAME_MACRO(type,return_type) \
enum enum_field_types vtkMySQLTypeName(type) \
{ return return_type; }
VTK_MYSQL_TYPENAME_MACRO(signed char, MYSQL_TYPE_TINY);
VTK_MYSQL_TYPENAME_MACRO(unsigned char, MYSQL_TYPE_TINY);
VTK_MYSQL_TYPENAME_MACRO(signed short, MYSQL_TYPE_SHORT);
VTK_MYSQL_TYPENAME_MACRO(unsigned short, MYSQL_TYPE_SHORT);
VTK_MYSQL_TYPENAME_MACRO(signed int, MYSQL_TYPE_LONG);
VTK_MYSQL_TYPENAME_MACRO(unsigned int, MYSQL_TYPE_LONG);
VTK_MYSQL_TYPENAME_MACRO(signed long, MYSQL_TYPE_LONG);
VTK_MYSQL_TYPENAME_MACRO(unsigned long, MYSQL_TYPE_LONG);
VTK_MYSQL_TYPENAME_MACRO(float, MYSQL_TYPE_FLOAT);
VTK_MYSQL_TYPENAME_MACRO(double, MYSQL_TYPE_DOUBLE);
VTK_MYSQL_TYPENAME_MACRO(vtkTypeInt64, MYSQL_TYPE_LONGLONG);
VTK_MYSQL_TYPENAME_MACRO(vtkTypeUInt64, MYSQL_TYPE_LONGLONG);
VTK_MYSQL_TYPENAME_MACRO(const char *, MYSQL_TYPE_STRING);
VTK_MYSQL_TYPENAME_MACRO(char *, MYSQL_TYPE_STRING);
VTK_MYSQL_TYPENAME_MACRO(void *, MYSQL_TYPE_BLOB);
template<typename T>
bool vtkMySQLIsTypeUnsigned(T)
{
return false;
}
template<>
bool vtkMySQLIsTypeUnsigned<unsigned char>(unsigned char)
{
return true;
}
template<>
bool vtkMySQLIsTypeUnsigned<unsigned short>(unsigned short)
{
return true;
}
template<>
bool vtkMySQLIsTypeUnsigned<unsigned int>(unsigned int)
{
return true;
}
template<>
bool vtkMySQLIsTypeUnsigned<unsigned long>(unsigned long)
{
return true;
}
template<>
bool vtkMySQLIsTypeUnsigned<vtkTypeUInt64>(vtkTypeUInt64)
{
return true;
}
// ----------------------------------------------------------------------
// Description:
// This function will build and populate a vtkMySQLBoundParameter
// struct. The default implementation works for POD data types (char,
// int, long, etc). I'll need to special-case strings and blobs.
template<typename T>
vtkMySQLBoundParameter *vtkBuildBoundParameter(T data_value)
{
vtkMySQLBoundParameter *param = new vtkMySQLBoundParameter;
param->IsNull = false;
param->IsUnsigned = vtkMySQLIsTypeUnsigned(data_value);
param->DataType = vtkMySQLTypeName(data_value);
param->BufferSize = sizeof(T);
param->DataLength = sizeof(T);
param->SetData(new char[sizeof(T)], sizeof(T));
memcpy(param->Data, &data_value, sizeof(T));
return param;
}
// Description:
// Specialization of vtkBuildBoundParameter for NULL-terminated
// strings (i.e. CHAR and VARCHAR fields)
template<>
vtkMySQLBoundParameter *vtkBuildBoundParameter<const char *>(const char *data_value)
{
vtkMySQLBoundParameter *param = new vtkMySQLBoundParameter;
param->IsNull = false;
param->IsUnsigned = false;
param->DataType = MYSQL_TYPE_STRING;
param->BufferSize = strlen(data_value);
param->DataLength = strlen(data_value);
param->SetData(new char[param->BufferSize], param->BufferSize);
memcpy(param->Data, data_value, param->BufferSize);
return param;
}
// Description:
// Alternate signature for vtkBuildBoundParameter to handle blobs
vtkMySQLBoundParameter *vtkBuildBoundParameter(const char *data,
unsigned long length,
bool is_blob)
{
vtkMySQLBoundParameter *param = new vtkMySQLBoundParameter;
param->IsNull = false;
param->IsUnsigned = false;
param->BufferSize = length;
param->DataLength = length;
param->SetData(new char[length], length);
memcpy(param->Data, data, param->BufferSize);
if (is_blob)
{
param->DataType = MYSQL_TYPE_BLOB;
}
else
{
param->DataType = MYSQL_TYPE_STRING;
}
return param;
}
// ----------------------------------------------------------------------
class vtkMySQLQueryInternals
{
public:
vtkMySQLQueryInternals();
~vtkMySQLQueryInternals();
void FreeResult();
void FreeStatement();
void FreeUserParameterList();
void FreeBoundParameters();
bool SetQuery(const char *queryString, MYSQL *db, vtkStdString &error_message);
bool SetBoundParameter(int index, vtkMySQLBoundParameter *param);
bool BindParametersToStatement();
// Description:
// MySQL can only handle certain statements as prepared statements:
// CALL, CREATE TABLE, DELETE, DO, INSERT, REPLACE, SELECT, SET,
// UPDATE and some SHOW statements. This function checks for those.
// If we can't use a prepared statement then we have to do the query
// the old-fashioned way.
bool ValidPreparedStatementSQL(const char *query);
public:
MYSQL_STMT *Statement;
MYSQL_RES *Result;
MYSQL_BIND *BoundParameters;
MYSQL_ROW CurrentRow;
unsigned long *CurrentLengths;
typedef std::vector<vtkMySQLBoundParameter *> ParameterList;
ParameterList UserParameterList;
};
// ----------------------------------------------------------------------
vtkMySQLQueryInternals::vtkMySQLQueryInternals()
: Statement(NULL),
Result(NULL),
BoundParameters(NULL),
CurrentLengths(NULL)
{
}
// ----------------------------------------------------------------------
vtkMySQLQueryInternals::~vtkMySQLQueryInternals()
{
this->FreeResult();
this->FreeStatement();
this->FreeUserParameterList();
this->FreeBoundParameters();
}
// ----------------------------------------------------------------------
void vtkMySQLQueryInternals::FreeResult()
{
if (this->Result)
{
mysql_free_result(this->Result);
this->Result = NULL;
}
}
// ----------------------------------------------------------------------
void vtkMySQLQueryInternals::FreeStatement()
{
if (this->Statement)
{
mysql_stmt_close(this->Statement);
this->Statement = NULL;
}
}
// ----------------------------------------------------------------------
bool vtkMySQLQueryInternals::SetQuery(const char *queryString,
MYSQL *db,
vtkStdString &error_message)
{
this->FreeStatement();
this->FreeUserParameterList();
this->FreeBoundParameters();
if (this->ValidPreparedStatementSQL(queryString) == false)
{
return true; // we'll have to handle this query in immediate mode
}
this->Statement = mysql_stmt_init(db);
if (this->Statement == NULL)
{
error_message = vtkStdString("vtkMySQLQuery: mysql_stmt_init returned out of memory error");
return false;
}
int status = mysql_stmt_prepare(this->Statement,
queryString,
strlen(queryString));
if (status == 0)
{
this->UserParameterList.resize(mysql_stmt_param_count(this->Statement), NULL);
return true;
}
else
{
error_message = vtkStdString(mysql_stmt_error(this->Statement));
return false;
}
}
// ----------------------------------------------------------------------
void vtkMySQLQueryInternals::FreeUserParameterList()
{
for (unsigned int i = 0; i < this->UserParameterList.size(); ++i)
{
delete this->UserParameterList[i];
this->UserParameterList[i] = NULL;
}
this->UserParameterList.clear();
}
// ----------------------------------------------------------------------
void vtkMySQLQueryInternals::FreeBoundParameters()
{
delete [] this->BoundParameters;
}
// ----------------------------------------------------------------------
bool vtkMySQLQueryInternals::SetBoundParameter(int index, vtkMySQLBoundParameter *param)
{
if (index >= static_cast<int>(this->UserParameterList.size()))
{
vtkGenericWarningMacro(<<"ERROR: Illegal parameter index "
<<index << ". Did you forget to set the query?");
return false;
}
else
{
delete this->UserParameterList[index];
this->UserParameterList[index] = param;
return true;
}
}
// ----------------------------------------------------------------------
bool vtkMySQLQueryInternals::BindParametersToStatement()
{
if (this->Statement == NULL)
{
vtkGenericWarningMacro(<<"BindParametersToStatement: No prepared statement available");
return false;
}
this->FreeBoundParameters();
unsigned long numParams = mysql_stmt_param_count(this->Statement);
this->BoundParameters = new MYSQL_BIND[numParams];
for (unsigned int i = 0; i < numParams; ++i)
{
if (this->UserParameterList[i])
{
this->BoundParameters[i] = this->UserParameterList[i]->BuildParameterStruct();
}
else
{
this->BoundParameters[i] = BuildNullParameterStruct();
}
}
return mysql_stmt_bind_param(this->Statement, this->BoundParameters);
}
// ----------------------------------------------------------------------
bool vtkMySQLQueryInternals::ValidPreparedStatementSQL(const char *query)
{
if ( ! query )
return false;
if (!LOWERCASE_COMPARE("call", query))
{
return true;
}
else if (!LOWERCASE_COMPARE("create table", query))
{
return true;
}
else if (!LOWERCASE_COMPARE("delete", query))
{
return true;
}
else if (!LOWERCASE_COMPARE("do", query))
{
return true;
}
else if (!LOWERCASE_COMPARE("insert", query))
{
return true;
}
else if (!LOWERCASE_COMPARE("replace", query))
{
return true;
}
else if (!LOWERCASE_COMPARE("select", query))
{
return true;
}
else if (!LOWERCASE_COMPARE("set", query))
{
return true;
}
else if (!LOWERCASE_COMPARE("update", query))
{
return true;
}
return false;
}
// ----------------------------------------------------------------------
vtkStandardNewMacro(vtkMySQLQuery);
// ----------------------------------------------------------------------
vtkMySQLQuery::vtkMySQLQuery()
{
this->Internals = new vtkMySQLQueryInternals;
this->InitialFetch = true;
this->LastErrorText = NULL;
}
// ----------------------------------------------------------------------
vtkMySQLQuery::~vtkMySQLQuery()
{
this->SetLastErrorText(NULL);
delete this->Internals;
}
// ----------------------------------------------------------------------
void
vtkMySQLQuery::PrintSelf(ostream &os, vtkIndent indent)
{
this->Superclass::PrintSelf(os, indent);
}
// ----------------------------------------------------------------------
bool
vtkMySQLQuery::Execute()
{
this->Active = false;
if (this->Query == NULL)
{
vtkErrorMacro(<<"Cannot execute before a query has been set.");
return false;
}
this->Internals->FreeResult();
vtkMySQLDatabase *dbContainer =
static_cast<vtkMySQLDatabase *>(this->Database);
assert(dbContainer != NULL);
if (!dbContainer->IsOpen())
{
vtkErrorMacro(<<"Cannot execute query. Database is closed.");
return false;
}
vtkDebugMacro(<<"Execute(): Query ready to execute.");
if (this->Query != NULL && this->Internals->Statement == NULL)
{
MYSQL *db = dbContainer->Private->Connection;
assert(db != NULL);
int result = mysql_query(db, this->Query);
if (result == 0)
{
// The query probably succeeded.
this->Internals->Result = mysql_store_result(db);
// Statements like INSERT are supposed to return empty result sets,
// but sometimes it is an error for mysql_store_result to return null.
// If Result is null, but mysql_field_count is non-zero, it is an error.
// See: http://dev.mysql.com/doc/refman/5.0/en/null-mysql-store-result.html
if (this->Internals->Result || mysql_field_count(db) == 0)
{
// The query definitely succeeded.
this->SetLastErrorText(NULL);
// mysql_field_count will return 0 for statements like INSERT.
// set Active to false so that we don't call mysql_fetch_row on a NULL
// argument and segfault
if(mysql_field_count(db) == 0)
{
this->Active = false;
}
else
{
this->Active = true;
}
return true;
}
else
{
// There was an error in mysql_query or mysql_store_result
this->Active = false;
this->SetLastErrorText(mysql_error(db));
vtkErrorMacro(<<"Query returned an error: "
<< this->GetLastErrorText());
return false;
}
}
else
{
// result != 0; the query failed
this->Active = false;
this->SetLastErrorText(mysql_error(db));
vtkErrorMacro(<<"Query returned an error: " << this->GetLastErrorText());
return false;
}
}
else
{
vtkDebugMacro(<<"Binding parameters immediately prior to execution.");
bool bindStatus = this->Internals->BindParametersToStatement();
if (!bindStatus)
{
this->SetLastErrorText(mysql_stmt_error(this->Internals->Statement));
vtkErrorMacro(<<"Error binding parameters: "
<<this->GetLastErrorText());
return false;
}
int result = mysql_stmt_execute(this->Internals->Statement);
if (result == 0)
{
// The query succeeded.
this->SetLastErrorText(NULL);
this->Active = true;
this->Internals->Result = mysql_stmt_result_metadata(this->Internals->Statement);
return true;
}
else
{
this->Active = false;
this->SetLastErrorText(mysql_stmt_error(this->Internals->Statement));
vtkErrorMacro(<<"Query returned an error: "
<< this->GetLastErrorText());
return false;
}
}
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BeginTransaction()
{
this->SetQuery( "START TRANSACTION" );
return this->Execute();
}
bool vtkMySQLQuery::CommitTransaction()
{
this->SetQuery( "COMMIT" );
return this->Execute();
}
bool vtkMySQLQuery::RollbackTransaction()
{
this->SetQuery( "ROLLBACK" );
return this->Execute();
}
// ----------------------------------------------------------------------
int
vtkMySQLQuery::GetNumberOfFields()
{
if (! this->Active)
{
vtkErrorMacro(<<"GetNumberOfFields(): Query is not active!");
return 0;
}
else
{
return static_cast<int>(mysql_num_fields(this->Internals->Result));
}
}
// ----------------------------------------------------------------------
const char *
vtkMySQLQuery::GetFieldName(int column)
{
if (! this->Active)
{
vtkErrorMacro(<<"GetFieldName(): Query is not active!");
return NULL;
}
else if (column < 0 || column >= this->GetNumberOfFields())
{
vtkErrorMacro(<<"GetFieldName(): Illegal field index "
<< column);
return NULL;
}
else
{
MYSQL_FIELD *field = mysql_fetch_field_direct(this->Internals->Result, column);
if (field == NULL)
{
vtkErrorMacro(<<"GetFieldName(): MySQL returned null field for column "
<< column );
return NULL;
}
else
{
return field->name;
}
}
}
// ----------------------------------------------------------------------
int
vtkMySQLQuery::GetFieldType(int column)
{
if (! this->Active)
{
vtkErrorMacro(<<"GetFieldType(): Query is not active!");
return VTK_VOID;
}
else if (column < 0 || column >= this->GetNumberOfFields())
{
vtkErrorMacro(<<"GetFieldType(): Illegal field index "
<< column);
return VTK_VOID;
}
else
{
vtkMySQLDatabase *dbContainer =
static_cast<vtkMySQLDatabase *>(this->Database);
assert(dbContainer != NULL);
if (!dbContainer->IsOpen())
{
vtkErrorMacro(<<"Cannot get field type. Database is closed.");
return VTK_VOID;
}
MYSQL_FIELD *field = mysql_fetch_field_direct(this->Internals->Result,
column);
if (field == NULL)
{
vtkErrorMacro(<<"GetFieldType(): MySQL returned null field for column "
<< column );
return -1;
}
else
{
switch (field->type)
{
case MYSQL_TYPE_ENUM:
case MYSQL_TYPE_TINY:
case MYSQL_TYPE_INT24:
case MYSQL_TYPE_YEAR:
return VTK_INT;
case MYSQL_TYPE_SHORT:
return VTK_SHORT;
case MYSQL_TYPE_LONG:
case MYSQL_TYPE_LONGLONG:
return VTK_LONG;
case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_DATE:
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
case MYSQL_TYPE_NEWDATE:
return VTK_STRING; // Just return the raw string.
#if MYSQL_VERSION_ID >= 50000
case MYSQL_TYPE_BIT:
return VTK_BIT;
#endif
case MYSQL_TYPE_FLOAT:
return VTK_FLOAT;
case MYSQL_TYPE_DOUBLE:
case MYSQL_TYPE_DECIMAL:
#if MYSQL_VERSION_ID >= 50000
case MYSQL_TYPE_NEWDECIMAL:
#endif
return VTK_DOUBLE;
case MYSQL_TYPE_NULL:
return VTK_VOID;
case MYSQL_TYPE_TINY_BLOB:
case MYSQL_TYPE_MEDIUM_BLOB:
case MYSQL_TYPE_LONG_BLOB:
case MYSQL_TYPE_BLOB:
return VTK_STRING; // MySQL treats text fields as blobs
case MYSQL_TYPE_STRING:
case MYSQL_TYPE_VAR_STRING:
#if MYSQL_VERSION_ID >= 50000
case MYSQL_TYPE_VARCHAR:
#endif
return VTK_STRING;
case MYSQL_TYPE_SET:
case MYSQL_TYPE_GEOMETRY:
default:
{
vtkErrorMacro( <<"GetFieldType(): Unknown data type "
<< field->type );
return VTK_VOID;
}
}
}
}
}
// ----------------------------------------------------------------------
bool
vtkMySQLQuery::NextRow()
{
if (! this->IsActive())
{
vtkErrorMacro(<<"NextRow(): Query is not active!");
return false;
}
MYSQL_ROW row = mysql_fetch_row(this->Internals->Result);
this->Internals->CurrentRow = row;
this->Internals->CurrentLengths = mysql_fetch_lengths(this->Internals->Result);
if (!row)
{
// A null row will come back in one of two situations. The first
// is when there's an error, in which case mysql_errno will return
// some nonzero error code. The second is when there are no more
// rows to fetch. Discriminate between the two by checking the
// errno.
this->Active = false;
vtkMySQLDatabase *dbContainer =
static_cast<vtkMySQLDatabase *>(this->Database);
assert(dbContainer != NULL);
if (!dbContainer->IsOpen())
{
vtkErrorMacro(<<"Cannot get field type. Database is closed.");
this->SetLastErrorText("Database is closed.");
return VTK_VOID;
}
MYSQL *db = dbContainer->Private->Connection;
assert(db != NULL);
if (mysql_errno(db) != 0)
{
this->SetLastErrorText(mysql_error(db));
vtkErrorMacro(<<"NextRow(): MySQL returned error message "
<< this->GetLastErrorText());
}
else
{
// Nothing's wrong. We're just out of results.
this->SetLastErrorText(NULL);
}
return false;
}
else
{
this->SetLastErrorText(NULL);
return true;
}
}
// ----------------------------------------------------------------------
vtkVariant
vtkMySQLQuery::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
{
assert(this->Internals->CurrentRow);
vtkVariant result;
// Initialize base as a VTK_VOID value... only populate with
// data when a column value is non-NULL.
bool isNull = !this->Internals->CurrentRow[column];
vtkVariant base;
if ( !isNull )
{
// Make a string holding the data, including possible embedded null characters.
vtkStdString s( this->Internals->CurrentRow[column],
static_cast<size_t>(this->Internals->CurrentLengths[column]) );
base = vtkVariant( s );
}
// It would be a royal pain to try to convert the string to each
// different value in turn. Fortunately, there is already code in
// vtkVariant to do exactly that using the C++ standard library
// sstream. We'll exploit that.
switch (this->GetFieldType(column))
{
case VTK_INT:
case VTK_SHORT:
case VTK_BIT:
return isNull ? base : vtkVariant(base.ToInt());
case VTK_LONG:
case VTK_UNSIGNED_LONG:
return isNull ? base : vtkVariant(base.ToLong());
case VTK_FLOAT:
return isNull ? base : vtkVariant(base.ToFloat());
case VTK_DOUBLE:
return isNull ? base : vtkVariant(base.ToDouble());
case VTK_STRING:
return base; // it's already a string
case VTK_VOID:
return vtkVariant();
default:
{
vtkWarningMacro(<<"Unhandled type " << this->GetFieldType(column)
<<" in DataValue().");
return vtkVariant();
}
}
}
}
// ----------------------------------------------------------------------
const char *
vtkMySQLQuery::GetLastErrorText()
{
return this->LastErrorText;
}
// ----------------------------------------------------------------------
bool
vtkMySQLQuery::HasError()
{
return (this->GetLastErrorText() != NULL);
}
vtkStdString vtkMySQLQuery::EscapeString( vtkStdString src, bool addSurroundingQuotes )
{
vtkStdString dst;
vtkMySQLDatabase* dbContainer =
static_cast<vtkMySQLDatabase*>( this->Database );
assert( dbContainer != NULL );
MYSQL* db;
if ( ( ! dbContainer->IsOpen() ) || ! ( db = dbContainer->Private->Connection ) )
{ // fall back to superclass implementation
dst = this->Superclass::EscapeString( src, addSurroundingQuotes );
return dst;
}
unsigned long ssz = src.size();
char* dstarr = new char[2 * ssz + (addSurroundingQuotes ? 3 : 1)];
char* end = dstarr;
if ( addSurroundingQuotes )
{
* ( end ++ ) = '\'';
}
end += mysql_real_escape_string( db, end, src.c_str(), ssz );
if ( addSurroundingQuotes )
{
* ( end ++ ) = '\'';
* ( end ++ ) = '\0';
}
dst = dstarr;
delete [] dstarr;
return dst;
}
// ----------------------------------------------------------------------
bool
vtkMySQLQuery::SetQuery(const char *newQuery)
{
vtkDebugMacro(<< this->GetClassName()
<< " (" << this << "): setting Query to "
<< (newQuery?newQuery:"(null)") );
if (this->Query == NULL && newQuery == NULL)
{
return true;
}
if (this->Query && newQuery && (!strcmp(this->Query, newQuery)))
{
return true; // we've already got that query
}
delete [] this->Query;
if (newQuery)
{
// Keep a local copy of the query - this is from vtkSetGet.h
size_t n = strlen(newQuery) + 1;
char *cp1 = new char[n];
const char *cp2 = (newQuery);
this->Query = cp1;
do { *cp1++ = *cp2++; } while ( --n );
}
else
{
this->Query = NULL;
}
// If we get to this point the query has changed. We need to
// finalize the already-prepared statement if one exists and then
// prepare a new statement.
this->Active = false;
vtkMySQLDatabase *dbContainer =
static_cast<vtkMySQLDatabase *>(this->Database);
if (!dbContainer)
{
vtkErrorMacro(<< "SetQuery: No database connection set! This usually happens if you have instantiated vtkMySQLQuery directly. Don't do that. Call vtkSQLDatabase::GetQueryInstance instead.");
return false;
}
MYSQL *db = dbContainer->Private->Connection;
assert(db != NULL);
vtkStdString errorMessage;
bool success = this->Internals->SetQuery(this->Query, db, errorMessage);
if (!success)
{
this->SetLastErrorText(errorMessage.c_str());
vtkErrorMacro(<<"SetQuery: Error while preparing statement: "
<<errorMessage.c_str());
}
return success;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, unsigned char value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, signed char value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, unsigned short value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, signed short value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, unsigned int value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, signed int value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, unsigned long value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, signed long value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, vtkTypeUInt64 value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, vtkTypeInt64 value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, float value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, double value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, const char *value)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(value));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, const vtkStdString &value)
{
return this->BindParameter(index, value.c_str());
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, const char *data, size_t length)
{
this->Internals->SetBoundParameter(index, vtkBuildBoundParameter(data,
length,
false));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::BindParameter(int index, const void *data, size_t length)
{
this->Internals->SetBoundParameter(index,
vtkBuildBoundParameter(static_cast<const char *>(data),
length,
true));
return true;
}
// ----------------------------------------------------------------------
bool vtkMySQLQuery::ClearParameterBindings()
{
this->Internals->FreeBoundParameters();
return true;
}