X-Git-Url: https://git.stg.codes/stg.git/blobdiff_plain/8c6fa3fbaccc22127280bf77a48fab5a3ee0716e..46b0747592074017ff0ea4b33d4a7194235886e5:/libs/ibpp/statement.cpp diff --git a/libs/ibpp/statement.cpp b/libs/ibpp/statement.cpp new file mode 100644 index 00000000..e2271cf4 --- /dev/null +++ b/libs/ibpp/statement.cpp @@ -0,0 +1,1307 @@ +/////////////////////////////////////////////////////////////////////////////// +// +// File : $Id: statement.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $ +// Subject : IBPP, Service class implementation +// +/////////////////////////////////////////////////////////////////////////////// +// +// (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org) +// +// The contents of this file are subject to the IBPP License (the "License"); +// you may not use this file except in compliance with the License. You may +// obtain a copy of the License at http://www.ibpp.org or in the 'license.txt' +// file which must have been distributed along with this file. +// +// This software, distributed under the License, is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations +// under the License. +// +/////////////////////////////////////////////////////////////////////////////// +// +// COMMENTS +// * Tabulations should be set every four characters when editing this file. +// +/////////////////////////////////////////////////////////////////////////////// + +#ifdef _MSC_VER +#pragma warning(disable: 4786 4996) +#ifndef _DEBUG +#pragma warning(disable: 4702) +#endif +#endif + +#include "_ibpp.h" + +#ifdef HAS_HDRSTOP +#pragma hdrstop +#endif + +#include + +using namespace ibpp_internals; + +// (((((((( OBJECT INTERFACE IMPLEMENTATION )))))))) + +void StatementImpl::Prepare(const std::string& sql) +{ + if (mDatabase == 0) + throw LogicExceptionImpl("Statement::Prepare", _("An IDatabase must be attached.")); + if (mDatabase->GetHandle() == 0) + throw LogicExceptionImpl("Statement::Prepare", _("IDatabase must be connected.")); + if (mTransaction == 0) + throw LogicExceptionImpl("Statement::Prepare", _("An ITransaction must be attached.")); + if (mTransaction->GetHandle() == 0) + throw LogicExceptionImpl("Statement::Prepare", _("ITransaction must be started.")); + if (sql.empty()) + throw LogicExceptionImpl("Statement::Prepare", _("SQL statement can't be 0.")); + + // Saves the SQL sentence, only for reporting reasons in case of errors + mSql = sql; + + IBS status; + + // Free all resources currently attached to this Statement, then allocate + // a new statement descriptor. + Close(); + (*gds.Call()->m_dsql_allocate_statement)(status.Self(), mDatabase->GetHandlePtr(), &mHandle); + if (status.Errors()) + throw SQLExceptionImpl(status, "Statement::Prepare", + _("isc_dsql_allocate_statement failed")); + + // Empirical estimate of parameters count and output columns count. + // This is by far not an exact estimation, which would require parsing the + // SQL statement. If the SQL statement contains '?' and ',' in string + // constants, this count will obviously be wrong, but it will be exagerated. + // It won't hurt. We just try to not have to re-allocate those descriptors later. + // So we prefer to get them a little bit larger than needed than the other way. + int16_t inEstimate = 0; + int16_t outEstimate = 1; + for (size_t i = 0; i < strlen(sql.c_str()); i++) + { + if (sql[i] == '?') ++inEstimate; + if (sql[i] == ',') ++outEstimate; + } + + /* + DebugStream()<< "Prepare(\""<< sql<< "\")"<< fds; + DebugStream()<< _("Estimation: ")<< inEstimate<< _(" IN parameters and ") + << outEstimate<< _(" OUT columns")<< fds; + */ + + // Allocates output descriptor and prepares the statement + mOutRow = new RowImpl(mDatabase->Dialect(), outEstimate, mDatabase, mTransaction); + mOutRow->AddRef(); + + status.Reset(); + (*gds.Call()->m_dsql_prepare)(status.Self(), mTransaction->GetHandlePtr(), + &mHandle, (short)sql.length(), const_cast(sql.c_str()), + short(mDatabase->Dialect()), mOutRow->Self()); + if (status.Errors()) + { + Close(); + std::string context = "Statement::Prepare( "; + context.append(mSql).append(" )"); + throw SQLExceptionImpl(status, context.c_str(), + _("isc_dsql_prepare failed")); + } + + // Read what kind of statement was prepared + status.Reset(); + char itemsReq[] = {isc_info_sql_stmt_type}; + char itemsRes[8]; + (*gds.Call()->m_dsql_sql_info)(status.Self(), &mHandle, 1, itemsReq, + sizeof(itemsRes), itemsRes); + if (status.Errors()) + { + Close(); + throw SQLExceptionImpl(status, "Statement::Prepare", + _("isc_dsql_sql_info failed")); + } + if (itemsRes[0] == isc_info_sql_stmt_type) + { + switch (itemsRes[3]) + { + case isc_info_sql_stmt_select : mType = IBPP::stSelect; break; + case isc_info_sql_stmt_insert : mType = IBPP::stInsert; break; + case isc_info_sql_stmt_update : mType = IBPP::stUpdate; break; + case isc_info_sql_stmt_delete : mType = IBPP::stDelete; break; + case isc_info_sql_stmt_ddl : mType = IBPP::stDDL; break; + case isc_info_sql_stmt_exec_procedure : mType = IBPP::stExecProcedure; break; + case isc_info_sql_stmt_select_for_upd : mType = IBPP::stSelectUpdate; break; + case isc_info_sql_stmt_set_generator : mType = IBPP::stSetGenerator; break; + case isc_info_sql_stmt_savepoint : mType = IBPP::stSavePoint; break; + default : mType = IBPP::stUnsupported; + } + } + if (mType == IBPP::stUnknown || mType == IBPP::stUnsupported) + { + Close(); + throw LogicExceptionImpl("Statement::Prepare", + _("Unknown or unsupported statement type")); + } + + if (mOutRow->Columns() == 0) + { + // Get rid of the output descriptor, if it wasn't required (no output) + mOutRow->Release(); + mOutRow = 0; + /* + DebugStream()<< _("Dropped output descriptor which was not required")<< fds; + */ + } + else if (mOutRow->Columns() > mOutRow->AllocatedSize()) + { + // Resize the output descriptor (which is too small). + // The statement does not need to be prepared again, though the + // output columns must be described again. + + /* + DebugStream()<< _("Resize output descriptor from ") + << mOutRow->AllocatedSize()<< _(" to ")<< mOutRow->Columns()<< fds; + */ + + mOutRow->Resize(mOutRow->Columns()); + status.Reset(); + (*gds.Call()->m_dsql_describe)(status.Self(), &mHandle, 1, mOutRow->Self()); + if (status.Errors()) + { + Close(); + throw SQLExceptionImpl(status, "Statement::Prepare", + _("isc_dsql_describe failed")); + } + } + + if (inEstimate > 0) + { + // Ready an input descriptor + mInRow = new RowImpl(mDatabase->Dialect(), inEstimate, mDatabase, mTransaction); + mInRow->AddRef(); + + status.Reset(); + (*gds.Call()->m_dsql_describe_bind)(status.Self(), &mHandle, 1, mInRow->Self()); + if (status.Errors()) + { + Close(); + throw SQLExceptionImpl(status, "Statement::Prepare", + _("isc_dsql_describe_bind failed")); + } + + if (mInRow->Columns() == 0) + { + // Get rid of the input descriptor, if it wasn't required (no parameters) + mInRow->Release(); + mInRow = 0; + /* + DebugStream()<< _("Dropped input descriptor which was not required")<< fds; + */ + } + else if (mInRow->Columns() > mInRow->AllocatedSize()) + { + // Resize the input descriptor (which is too small). + // The statement does not need to be prepared again, though the + // parameters must be described again. + + /* + DebugStream()<< _("Resize input descriptor from ") + << mInRow->AllocatedSize()<< _(" to ") + << mInRow->Columns()<< fds; + */ + + mInRow->Resize(mInRow->Columns()); + status.Reset(); + (*gds.Call()->m_dsql_describe_bind)(status.Self(), &mHandle, 1, mInRow->Self()); + if (status.Errors()) + { + Close(); + throw SQLExceptionImpl(status, "Statement::Prepare", + _("isc_dsql_describe_bind failed")); + } + } + } + + // Allocates variables of the input descriptor + if (mInRow != 0) + { + // Turn on 'can be NULL' on each input parameter + for (int i = 0; i < mInRow->Columns(); i++) + { + XSQLVAR* var = &(mInRow->Self()->sqlvar[i]); + if (! (var->sqltype & 1)) var->sqltype += short(1); + } + mInRow->AllocVariables(); + } + + // Allocates variables of the output descriptor + if (mOutRow != 0) mOutRow->AllocVariables(); +} + +void StatementImpl::Plan(std::string& plan) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Plan", _("No statement has been prepared.")); + if (mDatabase == 0) + throw LogicExceptionImpl("Statement::Plan", _("A Database must be attached.")); + if (mDatabase->GetHandle() == 0) + throw LogicExceptionImpl("Statement::Plan", _("Database must be connected.")); + + IBS status; + RB result(4096); + char itemsReq[] = {isc_info_sql_get_plan}; + + (*gds.Call()->m_dsql_sql_info)(status.Self(), &mHandle, 1, itemsReq, + result.Size(), result.Self()); + if (status.Errors()) throw SQLExceptionImpl(status, + "Statement::Plan", _("isc_dsql_sql_info failed.")); + + result.GetString(isc_info_sql_get_plan, plan); + if (plan[0] == '\n') plan.erase(0, 1); +} + +void StatementImpl::Execute(const std::string& sql) +{ + if (! sql.empty()) Prepare(sql); + + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Execute", + _("No statement has been prepared.")); + + // Check that a value has been set for each input parameter + if (mInRow != 0 && mInRow->MissingValues()) + throw LogicExceptionImpl("Statement::Execute", + _("All parameters must be specified.")); + + CursorFree(); // Free a previous 'cursor' if any + + IBS status; + if (mType == IBPP::stSelect) + { + // Could return a result set (none, single or multi rows) + (*gds.Call()->m_dsql_execute)(status.Self(), mTransaction->GetHandlePtr(), + &mHandle, 1, mInRow == 0 ? 0 : mInRow->Self()); + if (status.Errors()) + { + //Close(); Commented because Execute error should not free the statement + std::string context = "Statement::Execute( "; + context.append(mSql).append(" )"); + throw SQLExceptionImpl(status, context.c_str(), + _("isc_dsql_execute failed")); + } + if (mOutRow != 0) + { + mResultSetAvailable = true; + mCursorOpened = true; + } + } + else + { + // Should return at most a single row + (*gds.Call()->m_dsql_execute2)(status.Self(), mTransaction->GetHandlePtr(), + &mHandle, 1, mInRow == 0 ? 0 : mInRow->Self(), + mOutRow == 0 ? 0 : mOutRow->Self()); + if (status.Errors()) + { + //Close(); Commented because Execute error should not free the statement + std::string context = "Statement::Execute( "; + context.append(mSql).append(" )"); + throw SQLExceptionImpl(status, context.c_str(), + _("isc_dsql_execute2 failed")); + } + } +} + +void StatementImpl::CursorExecute(const std::string& cursor, const std::string& sql) +{ + if (cursor.empty()) + throw LogicExceptionImpl("Statement::CursorExecute", _("Cursor name can't be 0.")); + + if (! sql.empty()) Prepare(sql); + + if (mHandle == 0) + throw LogicExceptionImpl("Statement::CursorExecute", _("No statement has been prepared.")); + if (mType != IBPP::stSelectUpdate) + throw LogicExceptionImpl("Statement::CursorExecute", _("Statement must be a SELECT FOR UPDATE.")); + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::CursorExecute", _("Statement would return no rows.")); + + // Check that a value has been set for each input parameter + if (mInRow != 0 && mInRow->MissingValues()) + throw LogicExceptionImpl("Statement::CursorExecute", + _("All parameters must be specified.")); + + CursorFree(); // Free a previous 'cursor' if any + + IBS status; + (*gds.Call()->m_dsql_execute)(status.Self(), mTransaction->GetHandlePtr(), + &mHandle, 1, mInRow == 0 ? 0 : mInRow->Self()); + if (status.Errors()) + { + //Close(); Commented because Execute error should not free the statement + std::string context = "Statement::CursorExecute( "; + context.append(mSql).append(" )"); + throw SQLExceptionImpl(status, context.c_str(), + _("isc_dsql_execute failed")); + } + + status.Reset(); + (*gds.Call()->m_dsql_set_cursor_name)(status.Self(), &mHandle, const_cast(cursor.c_str()), 0); + if (status.Errors()) + { + //Close(); Commented because Execute error should not free the statement + throw SQLExceptionImpl(status, "Statement::CursorExecute", + _("isc_dsql_set_cursor_name failed")); + } + + mResultSetAvailable = true; + mCursorOpened = true; +} + +void StatementImpl::ExecuteImmediate(const std::string& sql) +{ + if (mDatabase == 0) + throw LogicExceptionImpl("Statement::ExecuteImmediate", _("An IDatabase must be attached.")); + if (mDatabase->GetHandle() == 0) + throw LogicExceptionImpl("Statement::ExecuteImmediate", _("IDatabase must be connected.")); + if (mTransaction == 0) + throw LogicExceptionImpl("Statement::ExecuteImmediate", _("An ITransaction must be attached.")); + if (mTransaction->GetHandle() == 0) + throw LogicExceptionImpl("Statement::ExecuteImmediate", _("ITransaction must be started.")); + if (sql.empty()) + throw LogicExceptionImpl("Statement::ExecuteImmediate", _("SQL statement can't be 0.")); + + IBS status; + Close(); + (*gds.Call()->m_dsql_execute_immediate)(status.Self(), mDatabase->GetHandlePtr(), + mTransaction->GetHandlePtr(), 0, const_cast(sql.c_str()), + short(mDatabase->Dialect()), 0); + if (status.Errors()) + { + std::string context = "Statement::ExecuteImmediate( "; + context.append(sql).append(" )"); + throw SQLExceptionImpl(status, context.c_str(), + _("isc_dsql_execute_immediate failed")); + } +} + +int StatementImpl::AffectedRows() +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::AffectedRows", _("No statement has been prepared.")); + if (mDatabase == 0) + throw LogicExceptionImpl("Statement::AffectedRows", _("A Database must be attached.")); + if (mDatabase->GetHandle() == 0) + throw LogicExceptionImpl("Statement::AffectedRows", _("Database must be connected.")); + + int count; + IBS status; + RB result; + char itemsReq[] = {isc_info_sql_records}; + + (*gds.Call()->m_dsql_sql_info)(status.Self(), &mHandle, 1, itemsReq, + result.Size(), result.Self()); + if (status.Errors()) throw SQLExceptionImpl(status, + "Statement::AffectedRows", _("isc_dsql_sql_info failed.")); + + if (mType == IBPP::stInsert) + count = result.GetValue(isc_info_sql_records, isc_info_req_insert_count); + else if (mType == IBPP::stUpdate) + count = result.GetValue(isc_info_sql_records, isc_info_req_update_count); + else if (mType == IBPP::stDelete) + count = result.GetValue(isc_info_sql_records, isc_info_req_delete_count); + else if (mType == IBPP::stSelect) + count = result.GetValue(isc_info_sql_records, isc_info_req_select_count); + else count = 0; // Returns zero count for unknown cases + + return count; +} + +bool StatementImpl::Fetch() +{ + if (! mResultSetAvailable) + throw LogicExceptionImpl("Statement::Fetch", + _("No statement has been executed or no result set available.")); + + IBS status; + ISC_STATUS code = (*gds.Call()->m_dsql_fetch)(status.Self(), &mHandle, 1, mOutRow->Self()); + if (code == 100) // This special code means "no more rows" + { + mResultSetAvailable = false; + // Oddly enough, fetching rows up to the last one seems to open + // an 'implicit' cursor that needs to be closed. + mCursorOpened = true; + CursorFree(); // Free the explicit or implicit cursor/result-set + return false; + } + if (status.Errors()) + { + Close(); + throw SQLExceptionImpl(status, "Statement::Fetch", + _("isc_dsql_fetch failed.")); + } + + return true; +} + +bool StatementImpl::Fetch(IBPP::Row& row) +{ + if (! mResultSetAvailable) + throw LogicExceptionImpl("Statement::Fetch(row)", + _("No statement has been executed or no result set available.")); + + RowImpl* rowimpl = new RowImpl(*mOutRow); + row = rowimpl; + + IBS status; + ISC_STATUS code = (*gds.Call()->m_dsql_fetch)(status.Self(), &mHandle, 1, + rowimpl->Self()); + if (code == 100) // This special code means "no more rows" + { + mResultSetAvailable = false; + // Oddly enough, fetching rows up to the last one seems to open + // an 'implicit' cursor that needs to be closed. + mCursorOpened = true; + CursorFree(); // Free the explicit or implicit cursor/result-set + row.clear(); + return false; + } + if (status.Errors()) + { + Close(); + row.clear(); + throw SQLExceptionImpl(status, "Statement::Fetch(row)", + _("isc_dsql_fetch failed.")); + } + + return true; +} + +void StatementImpl::Close() +{ + // Free all statement resources. + // Used before preparing a new statement or from destructor. + + if (mInRow != 0) { mInRow->Release(); mInRow = 0; } + if (mOutRow != 0) { mOutRow->Release(); mOutRow = 0; } + + mResultSetAvailable = false; + mCursorOpened = false; + mType = IBPP::stUnknown; + + if (mHandle != 0) + { + IBS status; + (*gds.Call()->m_dsql_free_statement)(status.Self(), &mHandle, DSQL_drop); + mHandle = 0; + if (status.Errors()) + throw SQLExceptionImpl(status, "Statement::Close(DSQL_drop)", + _("isc_dsql_free_statement failed.")); + } +} + +void StatementImpl::SetNull(int param) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::SetNull", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::SetNull", _("The statement does not take parameters.")); + + mInRow->SetNull(param); +} + +void StatementImpl::Set(int param, bool value) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[bool]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[bool]", _("The statement does not take parameters.")); + + mInRow->Set(param, value); +} + +void StatementImpl::Set(int param, const char* cstring) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[char*]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[char*]", _("The statement does not take parameters.")); + + mInRow->Set(param, cstring); +} + +void StatementImpl::Set(int param, const void* bindata, int len) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[void*]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[void*]", _("The statement does not take parameters.")); + + mInRow->Set(param, bindata, len); +} + +void StatementImpl::Set(int param, const std::string& s) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[string]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[string]", _("The statement does not take parameters.")); + + mInRow->Set(param, s); +} + +void StatementImpl::Set(int param, int16_t value) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[int16_t]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[int16_t]", _("The statement does not take parameters.")); + + mInRow->Set(param, value); +} + +void StatementImpl::Set(int param, int32_t value) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[int32_t]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[int32_t]", _("The statement does not take parameters.")); + + mInRow->Set(param, value); +} + +void StatementImpl::Set(int param, int64_t value) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[int64_t]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[int64_t]", _("The statement does not take parameters.")); + + mInRow->Set(param, value); +} + +void StatementImpl::Set(int param, float value) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[float]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[float]", _("The statement does not take parameters.")); + + mInRow->Set(param, value); +} + +void StatementImpl::Set(int param, double value) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[double]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[double]", _("The statement does not take parameters.")); + + mInRow->Set(param, value); +} + +void StatementImpl::Set(int param, const IBPP::Timestamp& value) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[Timestamp]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[Timestamp]", _("The statement does not take parameters.")); + + mInRow->Set(param, value); +} + +void StatementImpl::Set(int param, const IBPP::Date& value) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[Date]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[Date]", _("The statement does not take parameters.")); + + mInRow->Set(param, value); +} + +void StatementImpl::Set(int param, const IBPP::Time& value) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[Time]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[Time]", _("The statement does not take parameters.")); + + mInRow->Set(param, value); +} + +void StatementImpl::Set(int param, const IBPP::Blob& blob) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[Blob]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[Blob]", _("The statement does not take parameters.")); + + mInRow->Set(param, blob); +} + +void StatementImpl::Set(int param, const IBPP::Array& array) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[Array]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[Array]", _("The statement does not take parameters.")); + + mInRow->Set(param, array); +} + +void StatementImpl::Set(int param, const IBPP::DBKey& key) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[DBKey]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[DBKey]", _("The statement does not take parameters.")); + + mInRow->Set(param, key); +} + +/* +void StatementImpl::Set(int param, const IBPP::Value& value) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Set[Value]", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Set[Value]", _("The statement does not take parameters.")); + + mInRow->Set(param, value); +} +*/ + +bool StatementImpl::IsNull(int column) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::IsNull", _("The row is not initialized.")); + + return mOutRow->IsNull(column); +} + +bool StatementImpl::Get(int column, bool* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(column, *retvalue); +} + +bool StatementImpl::Get(int column, bool& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, retvalue); +} + +bool StatementImpl::Get(int column, char* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, retvalue); +} + +bool StatementImpl::Get(int column, void* bindata, int& userlen) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, bindata, userlen); +} + +bool StatementImpl::Get(int column, std::string& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, retvalue); +} + +bool StatementImpl::Get(int column, int16_t* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(column, *retvalue); +} + +bool StatementImpl::Get(int column, int16_t& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, retvalue); +} + +bool StatementImpl::Get(int column, int32_t* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(column, *retvalue); +} + +bool StatementImpl::Get(int column, int32_t& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, retvalue); +} + +bool StatementImpl::Get(int column, int64_t* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(column, *retvalue); +} + +bool StatementImpl::Get(int column, int64_t& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, retvalue); +} + +bool StatementImpl::Get(int column, float* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(column, *retvalue); +} + +bool StatementImpl::Get(int column, float& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, retvalue); +} + +bool StatementImpl::Get(int column, double* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(column, *retvalue); +} + +bool StatementImpl::Get(int column, double& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, retvalue); +} + +bool StatementImpl::Get(int column, IBPP::Timestamp& timestamp) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, timestamp); +} + +bool StatementImpl::Get(int column, IBPP::Date& date) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, date); +} + +bool StatementImpl::Get(int column, IBPP::Time& time) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, time); +} + +bool StatementImpl::Get(int column, IBPP::Blob& blob) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, blob); +} + +bool StatementImpl::Get(int column, IBPP::DBKey& key) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, key); +} + +bool StatementImpl::Get(int column, IBPP::Array& array) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column, array); +} + +/* +const IBPP::Value StatementImpl::Get(int column) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(column); +} +*/ + +bool StatementImpl::IsNull(const std::string& name) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::IsNull", _("The row is not initialized.")); + + return mOutRow->IsNull(name); +} + +bool StatementImpl::Get(const std::string& name, bool* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(name, *retvalue); +} + +bool StatementImpl::Get(const std::string& name, bool& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string& name, char* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get[char*]", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string& name, void* retvalue, int& count) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get[void*,int]", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue, count); +} + +bool StatementImpl::Get(const std::string& name, std::string& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::GetString", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string& name, int16_t* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(name, *retvalue); +} + +bool StatementImpl::Get(const std::string& name, int16_t& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string& name, int32_t* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(name, *retvalue); +} + +bool StatementImpl::Get(const std::string& name, int32_t& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string& name, int64_t* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(name, *retvalue); +} + +bool StatementImpl::Get(const std::string& name, int64_t& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string& name, float* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(name, *retvalue); +} + +bool StatementImpl::Get(const std::string& name, float& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string& name, double* retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + if (retvalue == 0) + throw LogicExceptionImpl("Statement::Get", _("Null pointer detected")); + + return mOutRow->Get(name, *retvalue); +} + +bool StatementImpl::Get(const std::string& name, double& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string& name, IBPP::Timestamp& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string& name, IBPP::Date& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string& name, IBPP::Time& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string&name, IBPP::Blob& retblob) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retblob); +} + +bool StatementImpl::Get(const std::string& name, IBPP::DBKey& retvalue) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retvalue); +} + +bool StatementImpl::Get(const std::string& name, IBPP::Array& retarray) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name, retarray); +} + +/* +const IBPP::Value StatementImpl::Get(const std::string& name) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Get", _("The row is not initialized.")); + + return mOutRow->Get(name); +} +*/ + +int StatementImpl::Columns() +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Columns", _("The row is not initialized.")); + + return mOutRow->Columns(); +} + +int StatementImpl::ColumnNum(const std::string& name) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::ColumnNum", _("The row is not initialized.")); + + return mOutRow->ColumnNum(name); +} + +const char* StatementImpl::ColumnName(int varnum) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Columns", _("The row is not initialized.")); + + return mOutRow->ColumnName(varnum); +} + +const char* StatementImpl::ColumnAlias(int varnum) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Columns", _("The row is not initialized.")); + + return mOutRow->ColumnAlias(varnum); +} + +const char* StatementImpl::ColumnTable(int varnum) +{ + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::Columns", _("The row is not initialized.")); + + return mOutRow->ColumnTable(varnum); +} + +IBPP::SDT StatementImpl::ColumnType(int varnum) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::ColumnType", _("No statement has been prepared.")); + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::ColumnType", _("The statement does not return results.")); + + return mOutRow->ColumnType(varnum); +} + +int StatementImpl::ColumnSubtype(int varnum) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::ColumnSubtype", _("No statement has been prepared.")); + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::ColumnSubtype", _("The statement does not return results.")); + + return mOutRow->ColumnSubtype(varnum); +} + +int StatementImpl::ColumnSize(int varnum) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::ColumnSize", _("No statement has been prepared.")); + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::ColumnSize", _("The row is not initialized.")); + + return mOutRow->ColumnSize(varnum); +} + +int StatementImpl::ColumnScale(int varnum) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::ColumnScale", _("No statement has been prepared.")); + if (mOutRow == 0) + throw LogicExceptionImpl("Statement::ColumnScale", _("The row is not initialized.")); + + return mOutRow->ColumnScale(varnum); +} + +int StatementImpl::Parameters() +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::Parameters", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::Parameters", _("The statement uses no parameters.")); + + return mInRow->Columns(); +} + +IBPP::SDT StatementImpl::ParameterType(int varnum) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::ParameterType", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::ParameterType", _("The statement uses no parameters.")); + + return mInRow->ColumnType(varnum); +} + +int StatementImpl::ParameterSubtype(int varnum) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::ParameterSubtype", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::ParameterSubtype", _("The statement uses no parameters.")); + + return mInRow->ColumnSubtype(varnum); +} + +int StatementImpl::ParameterSize(int varnum) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::ParameterSize", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::ParameterSize", _("The statement uses no parameters.")); + + return mInRow->ColumnSize(varnum); +} + +int StatementImpl::ParameterScale(int varnum) +{ + if (mHandle == 0) + throw LogicExceptionImpl("Statement::ParameterScale", _("No statement has been prepared.")); + if (mInRow == 0) + throw LogicExceptionImpl("Statement::ParameterScale", _("The statement uses no parameters.")); + + return mInRow->ColumnScale(varnum); +} + +IBPP::Database StatementImpl::DatabasePtr() const +{ + return mDatabase; +} + +IBPP::Transaction StatementImpl::TransactionPtr() const +{ + return mTransaction; +} + +IBPP::IStatement* StatementImpl::AddRef() +{ + ASSERTION(mRefCount >= 0); + ++mRefCount; + + return this; +} + +void StatementImpl::Release() +{ + // Release cannot throw, except in DEBUG builds on assertion + ASSERTION(mRefCount >= 0); + --mRefCount; + try { if (mRefCount <= 0) delete this; } + catch (...) { } +} + +// (((((((( OBJECT INTERNAL METHODS )))))))) + +void StatementImpl::AttachDatabaseImpl(DatabaseImpl* database) +{ + if (database == 0) + throw LogicExceptionImpl("Statement::AttachDatabase", + _("Can't attach a 0 IDatabase object.")); + + if (mDatabase != 0) mDatabase->DetachStatementImpl(this); + mDatabase = database; + mDatabase->AttachStatementImpl(this); +} + +void StatementImpl::DetachDatabaseImpl() +{ + if (mDatabase == 0) return; + + Close(); + mDatabase->DetachStatementImpl(this); + mDatabase = 0; +} + +void StatementImpl::AttachTransactionImpl(TransactionImpl* transaction) +{ + if (transaction == 0) + throw LogicExceptionImpl("Statement::AttachTransaction", + _("Can't attach a 0 ITransaction object.")); + + if (mTransaction != 0) mTransaction->DetachStatementImpl(this); + mTransaction = transaction; + mTransaction->AttachStatementImpl(this); +} + +void StatementImpl::DetachTransactionImpl() +{ + if (mTransaction == 0) return; + + Close(); + mTransaction->DetachStatementImpl(this); + mTransaction = 0; +} + +void StatementImpl::CursorFree() +{ + if (mCursorOpened) + { + mCursorOpened = false; + if (mHandle != 0) + { + IBS status; + (*gds.Call()->m_dsql_free_statement)(status.Self(), &mHandle, DSQL_close); + if (status.Errors()) + throw SQLExceptionImpl(status, "StatementImpl::CursorFree(DSQL_close)", + _("isc_dsql_free_statement failed.")); + } + } +} + +StatementImpl::StatementImpl(DatabaseImpl* database, TransactionImpl* transaction, + const std::string& sql) + : mRefCount(0), mHandle(0), mDatabase(0), mTransaction(0), + mInRow(0), mOutRow(0), + mResultSetAvailable(false), mCursorOpened(false), mType(IBPP::stUnknown) +{ + AttachDatabaseImpl(database); + if (transaction != 0) AttachTransactionImpl(transaction); + if (! sql.empty()) Prepare(sql); +} + +StatementImpl::~StatementImpl() +{ + try { Close(); } + catch (...) { } + try { if (mTransaction != 0) mTransaction->DetachStatementImpl(this); } + catch (...) { } + try { if (mDatabase != 0) mDatabase->DetachStatementImpl(this); } + catch (...) { } +} + +// +// EOF +//