8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-25 00:03:03 +01:00
firebird-mirror/src/jrd/execute_statement.cpp
2008-12-05 01:20:14 +00:00

219 lines
5.0 KiB
C++

/*
* PROGRAM: JRD Access Method
* MODULE: execute_statement.cpp
* DESCRIPTION: Dynamic SQL statements execution
*
* The contents of this file are subject to the Initial
* Developer's Public License Version 1.0 (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.ibphoenix.com/main.nfs?a=ibphoenix&page=ibp_idpl.
*
* Software distributed under the License is distributed AS IS,
* WITHOUT WARRANTY OF ANY KIND, either express or implied.
* See the License for the specific language governing rights
* and limitations under the License.
*
* The Original Code was created by Alexander Peshkoff
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2003 Alexander Peshkoff <peshkoff@mail.ru>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
* Adriano dos Santos Fernandes
*/
#include "firebird.h"
#include "gen/iberror.h"
#include "../jrd/common.h"
#include "../jrd/jrd.h"
#include "../jrd/tra.h"
#include "../jrd/dsc.h"
#include "../jrd/err_proto.h"
#include "../jrd/mov_proto.h"
#include "../jrd/evl_proto.h"
#include "../jrd/exe_proto.h"
#include "../jrd/execute_statement.h"
#include "../dsql/dsql.h"
#include "../common/classes/auto.h"
#include <string.h>
#include <math.h>
using namespace Jrd;
using namespace Firebird;
using Firebird::AutoPtr;
void ExecuteStatement::execute(Jrd::thread_db* tdbb, jrd_req* request, DSC* desc)
{
SET_TDBB(tdbb);
Attachment* attachment = tdbb->getAttachment();
jrd_tra* const transaction = tdbb->getTransaction();
if (transaction->tra_callback_count >= MAX_CALLBACKS)
{
ERR_post(Arg::Gds(isc_exec_sql_max_call_exceeded));
}
Firebird::string sqlStatementText;
getString(tdbb, sqlStatementText, desc, request);
transaction->tra_callback_count++;
try
{
AutoPtr<PreparedStatement> stmt(attachment->prepareStatement(
tdbb, *tdbb->getDefaultPool(), transaction, sqlStatementText));
// Other requests appear to be incorrect in this context
const long requests =
(1 << REQ_INSERT) | (1 << REQ_DELETE) | (1 << REQ_UPDATE) |
(1 << REQ_DDL) | (1 << REQ_SET_GENERATOR) | (1 << REQ_EXEC_PROCEDURE) |
(1 << REQ_EXEC_BLOCK);
if (!((1 << stmt->getRequest()->req_type) & requests))
{
ERR_post(Arg::Gds(isc_sqlerr) << Arg::Num(-902) <<
Arg::Gds(isc_exec_sql_invalid_req) << Arg::Str(sqlStatementText));
}
stmt->execute(tdbb, transaction);
fb_assert(transaction == tdbb->getTransaction());
}
catch (const Firebird::Exception&)
{
transaction->tra_callback_count--;
throw;
}
transaction->tra_callback_count--;
}
void ExecuteStatement::open(thread_db* tdbb, jrd_nod* sql, SSHORT nVars, bool singleton)
{
SET_TDBB(tdbb);
Attachment* const attachment = tdbb->getAttachment();
jrd_tra* transaction = tdbb->getTransaction();
if (transaction->tra_callback_count >= MAX_CALLBACKS)
{
ERR_post(Arg::Gds(isc_exec_sql_max_call_exceeded));
}
varCount = nVars;
singleMode = singleton;
Firebird::string sqlText;
getString(tdbb, sqlText, EVL_expr(tdbb, sql), tdbb->getRequest());
memcpy(startOfSqlOperator, sqlText.c_str(), sizeof(startOfSqlOperator) - 1);
startOfSqlOperator[sizeof(startOfSqlOperator) - 1] = 0;
transaction->tra_callback_count++;
try
{
stmt = attachment->prepareStatement(tdbb, *tdbb->getDefaultPool(), transaction, sqlText);
if (stmt->getResultCount() == 0)
{
delete stmt;
stmt = NULL;
ERR_post(Arg::Gds(isc_exec_sql_invalid_req) << Arg::Str(startOfSqlOperator));
}
if (stmt->getResultCount() != varCount)
{
delete stmt;
stmt = NULL;
ERR_post(Arg::Gds(isc_wronumarg));
}
resultSet = stmt->executeQuery(tdbb, transaction);
fb_assert(transaction == tdbb->getTransaction());
}
catch (const Firebird::Exception&)
{
transaction->tra_callback_count--;
throw;
}
transaction->tra_callback_count--;
}
bool ExecuteStatement::fetch(thread_db* tdbb, jrd_nod** jrdVar)
{
if (!resultSet->fetch(tdbb))
{
delete resultSet;
resultSet = NULL;
delete stmt;
stmt = NULL;
return false;
}
for (int i = 0; i < varCount; i++)
{
dsc& desc = resultSet->getDesc(i + 1);
bool nullFlag = resultSet->isNull(i + 1);
EXE_assignment(tdbb, jrdVar[i], &desc, nullFlag, NULL, NULL);
}
if (singleMode)
{
if (!resultSet->fetch(tdbb))
{
delete resultSet;
resultSet = NULL;
delete stmt;
stmt = NULL;
return false;
}
ERR_post(Arg::Gds(isc_sing_select_err));
}
return true;
}
void ExecuteStatement::close(thread_db* tdbb)
{
delete resultSet;
resultSet = NULL;
delete stmt;
stmt = NULL;
}
void ExecuteStatement::getString(thread_db* tdbb,
Firebird::string& sql,
const dsc* desc,
const jrd_req* request)
{
MoveBuffer buffer;
UCHAR* ptr = NULL;
const SSHORT len = (desc && !(request->req_flags & req_null)) ?
MOV_make_string2(tdbb, desc, desc->getTextType(), &ptr, buffer) : 0; // !!! How call Msgs ?
if (!ptr)
{
ERR_post(Arg::Gds(isc_exec_sql_invalid_arg));
}
sql.assign((const char*) ptr, len);
}