8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-22 20:43:02 +01:00

1) Created classes PreparedStatement and ResultSet

2) Changed EXECUTE STATEMENT to use these classes
3) Fixed CORE-1784 - Error with EXECUTE PROCEDURE inside EXECUTE STATEMENT
This commit is contained in:
asfernandes 2008-03-13 16:37:20 +00:00
parent 49e833de50
commit c7ec88bee4
21 changed files with 723 additions and 331 deletions

View File

@ -36,8 +36,8 @@ JRD_ServerFiles= blob_filter.cpp dpm.epp dyn.epp dyn_def.epp \
idx.cpp inf.cpp intl.cpp intl_builtin.cpp IntlManager.cpp IntlUtil.cpp \
jrd.cpp Database.cpp lck.cpp \
mov.cpp nav.cpp opt.cpp Optimizer.cpp pag.cpp par.cpp \
ods.cpp plugin_manager.cpp pwd.cpp RandomGenerator.cpp Relation.cpp rlck.cpp \
rpb_chain.cpp rse.cpp \
ods.cpp plugin_manager.cpp pwd.cpp PreparedStatement.cpp RandomGenerator.cpp \
Relation.cpp ResultSet.cpp rlck.cpp rpb_chain.cpp rse.cpp \
sdw.cpp shut.cpp sort.cpp sqz.cpp \
svc.cpp SysFunction.cpp TempSpace.cpp tpc.cpp tra.cpp validation.cpp vio.cpp \
nodebug.cpp nbak.cpp sha.cpp $(Physical_IO_Module) TextType.cpp \

View File

@ -420,6 +420,10 @@ SOURCE=..\..\..\src\jrd\plugin_manager.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\PreparedStatement.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\pwd.cpp
# End Source File
# Begin Source File
@ -436,6 +440,10 @@ SOURCE=..\..\..\src\jrd\Relation.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\ResultSet.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\rlck.cpp
# End Source File
# Begin Source File
@ -1164,6 +1172,10 @@ SOURCE=..\..\..\src\jrd\pragma.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\PreparedStatement.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\prv_m_bypass.h
# End Source File
# Begin Source File
@ -1200,6 +1212,10 @@ SOURCE=..\..\..\src\jrd\relations.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\ResultSet.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\req.h
# End Source File
# Begin Source File

View File

@ -411,6 +411,10 @@ SOURCE=..\..\..\src\jrd\plugin_manager.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\PreparedStatement.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\pwd.cpp
# End Source File
# Begin Source File
@ -427,6 +431,10 @@ SOURCE=..\..\..\src\jrd\Relation.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\ResultSet.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\rlck.cpp
# End Source File
# Begin Source File
@ -1133,6 +1141,10 @@ SOURCE=..\..\..\src\jrd\pragma.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\PreparedStatement.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\prv_m_bypass.h
# End Source File
# Begin Source File
@ -1169,6 +1181,10 @@ SOURCE=..\..\..\src\jrd\relations.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\ResultSet.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\req.h
# End Source File
# Begin Source File

View File

@ -407,6 +407,10 @@ SOURCE=..\..\..\src\jrd\plugin_manager.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\PreparedStatement.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\pwd.cpp
# End Source File
# Begin Source File
@ -423,6 +427,10 @@ SOURCE=..\..\..\src\jrd\Relation.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\ResultSet.cpp
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\rlck.cpp
# End Source File
# Begin Source File
@ -1137,6 +1145,10 @@ SOURCE=..\..\..\src\jrd\pragma.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\PreparedStatement.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\prv_m_bypass.h
# End Source File
# Begin Source File
@ -1177,6 +1189,10 @@ SOURCE=..\..\..\src\jrd\relations.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\ResultSet.h
# End Source File
# Begin Source File
SOURCE=..\..\..\src\jrd\req.h
# End Source File
# Begin Source File

View File

@ -327,6 +327,9 @@
<File
RelativePath="..\..\..\src\jrd\plugin_manager.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\pwd.cpp">
</File>
@ -339,6 +342,9 @@
<File
RelativePath="..\..\..\src\jrd\Relation.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\rlck.cpp">
</File>
@ -874,6 +880,9 @@
<File
RelativePath="..\..\..\src\jrd\pragma.h">
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.h">
</File>
<File
RelativePath="..\..\..\src\jrd\prv_m_bypass.h">
</File>
@ -892,6 +901,9 @@
<File
RelativePath="..\..\..\src\jrd\RandomGenerator.h">
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.h">
</File>
<File
RelativePath="..\..\..\src\jrd\rdb.h">
</File>

View File

@ -327,6 +327,9 @@
<File
RelativePath="..\..\..\src\jrd\plugin_manager.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\pwd.cpp">
</File>
@ -339,6 +342,9 @@
<File
RelativePath="..\..\..\src\jrd\Relation.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\rlck.cpp">
</File>
@ -874,6 +880,9 @@
<File
RelativePath="..\..\..\src\jrd\pragma.h">
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.h">
</File>
<File
RelativePath="..\..\..\src\jrd\prv_m_bypass.h">
</File>
@ -892,6 +901,9 @@
<File
RelativePath="..\..\..\src\jrd\RandomGenerator.h">
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.h">
</File>
<File
RelativePath="..\..\..\src\jrd\rdb.h">
</File>

View File

@ -331,6 +331,9 @@
<File
RelativePath="..\..\..\src\jrd\plugin_manager.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\pwd.cpp">
</File>
@ -343,6 +346,9 @@
<File
RelativePath="..\..\..\src\jrd\Relation.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.cpp">
</File>
<File
RelativePath="..\..\..\src\jrd\rlck.cpp">
</File>
@ -875,6 +881,9 @@
<File
RelativePath="..\..\..\src\jrd\pragma.h">
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.h">
</File>
<File
RelativePath="..\..\..\src\jrd\prv_m_bypass.h">
</File>
@ -893,6 +902,9 @@
<File
RelativePath="..\..\..\src\jrd\RandomGenerator.h">
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.h">
</File>
<File
RelativePath="..\..\..\src\jrd\rdb.h">
</File>

View File

@ -538,6 +538,10 @@
RelativePath="..\..\..\src\jrd\plugin_manager.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\pwd.cpp"
>
@ -554,6 +558,10 @@
RelativePath="..\..\..\src\jrd\Relation.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\rlck.cpp"
>
@ -1270,6 +1278,10 @@
RelativePath="..\..\..\src\jrd\pragma.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\prv_m_bypass.h"
>
@ -1294,6 +1306,10 @@
RelativePath="..\..\..\src\jrd\RandomGenerator.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\rdb.h"
>

View File

@ -538,6 +538,10 @@
RelativePath="..\..\..\src\jrd\plugin_manager.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\pwd.cpp"
>
@ -554,6 +558,10 @@
RelativePath="..\..\..\src\jrd\Relation.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\rlck.cpp"
>
@ -1270,6 +1278,10 @@
RelativePath="..\..\..\src\jrd\pragma.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\prv_m_bypass.h"
>
@ -1294,6 +1306,10 @@
RelativePath="..\..\..\src\jrd\RandomGenerator.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\rdb.h"
>

View File

@ -542,6 +542,10 @@
RelativePath="..\..\..\src\jrd\plugin_manager.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\pwd.cpp"
>
@ -558,6 +562,10 @@
RelativePath="..\..\..\src\jrd\Relation.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.cpp"
>
</File>
<File
RelativePath="..\..\..\src\jrd\rlck.cpp"
>
@ -1270,6 +1278,10 @@
RelativePath="..\..\..\src\jrd\pragma.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\PreparedStatement.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\prv_m_bypass.h"
>
@ -1294,6 +1306,10 @@
RelativePath="..\..\..\src\jrd\RandomGenerator.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\ResultSet.h"
>
</File>
<File
RelativePath="..\..\..\src\jrd\rdb.h"
>

View File

@ -80,8 +80,7 @@ static void execute_blob(thread_db*, dsql_req*, USHORT, const UCHAR*, USHORT, c
static void execute_immediate(thread_db*, Attachment*, jrd_tra**,
USHORT, const TEXT*, USHORT,
USHORT, const UCHAR*, USHORT, USHORT, const UCHAR*,
USHORT, UCHAR*, USHORT, USHORT, UCHAR*,
long);
USHORT, UCHAR*, USHORT, USHORT, UCHAR*);
static void execute_request(thread_db*, dsql_req*, jrd_tra**, USHORT, const UCHAR*,
USHORT, const UCHAR*, USHORT, UCHAR*, USHORT, UCHAR*, bool);
static SSHORT filter_sub_type(dsql_req*, const dsql_nod*);
@ -325,42 +324,7 @@ void DSQL_execute_immediate(thread_db* tdbb,
out_blr_length,
out_blr,
out_msg_type, out_msg_length,
out_msg,
~0);
}
/**
DSQL_callback_execute_immediate
@brief Execute sql_operator in context of jrd_transaction_handle
@param tdbb
@param sql_operator
@param dialect
**/
void DSQL_callback_execute_immediate(thread_db* tdbb,
const Firebird::string& sql_operator)
{
// Other requests appear to be incorrect in this context
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);
Attachment* const attachment = tdbb->getAttachment();
const Database* const dbb = attachment->att_database;
const int dialect = dbb->dbb_flags & DBB_DB_SQL_dialect_3 ? SQL_DIALECT_V6 : SQL_DIALECT_V5;
jrd_tra* transaction = tdbb->getTransaction();
execute_immediate(tdbb, attachment, &transaction,
sql_operator.length(), sql_operator.c_str(), dialect,
0, NULL, 0, 0, NULL, 0, NULL, 0, 0, NULL, requests);
fb_assert(transaction == tdbb->getTransaction());
out_msg);
}
@ -1130,8 +1094,7 @@ static void execute_immediate(thread_db* tdbb,
USHORT in_blr_length, const UCHAR* in_blr,
USHORT in_msg_type, USHORT in_msg_length, const UCHAR* in_msg,
USHORT out_blr_length, UCHAR* out_blr,
USHORT out_msg_type, USHORT out_msg_length, UCHAR* out_msg,
long possible_requests)
USHORT out_msg_type, USHORT out_msg_length, UCHAR* out_msg)
{
SET_TDBB(tdbb);
@ -1187,17 +1150,6 @@ static void execute_immediate(thread_db* tdbb,
request = prepare(tdbb, request, length, string, dialect, parser_version);
if (!((1 << request->req_type) & possible_requests))
{
const int max_diag_len = 50;
char err_str[max_diag_len + 1];
strncpy(err_str, string, max_diag_len);
err_str[max_diag_len] = 0;
ERRD_post(isc_sqlerr, isc_arg_number, (SLONG) -902,
isc_arg_gds, isc_exec_sql_invalid_req,
isc_arg_string, err_str, isc_arg_end);
}
execute_request(tdbb, request, tra_handle, in_blr_length, in_blr,
in_msg_length, in_msg, out_blr_length, out_blr,
out_msg_length, out_msg, false);

View File

@ -19,6 +19,7 @@
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
* Adriano dos Santos Fernandes
*/
#ifndef DSQL_DSQL_PROTO_H
@ -82,7 +83,4 @@ void DSQL_sql_info(Jrd::thread_db*,
USHORT, const UCHAR*,
USHORT, UCHAR*);
void DSQL_callback_execute_immediate(Jrd::thread_db* tdbb,
const Firebird::string& sql_operator);
#endif // DSQL_DSQL_PROTO_H

View File

@ -0,0 +1,235 @@
/*
* 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 Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2008 Adriano dos Santos Fernandes <adrianosf@uol.com.br>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "../jrd/PreparedStatement.h"
#include "../jrd/ResultSet.h"
#include "../jrd/align.h"
#include "../jrd/jrd.h"
#include "../jrd/dsc.h"
#include "../dsql/dsql.h"
#include "../dsql/sqlda_pub.h"
#include "../dsql/dsql_proto.h"
namespace Jrd {
PreparedStatement::PreparedStatement(thread_db* tdbb, Firebird::MemoryPool& pool,
Attachment* attachment, jrd_tra* transaction, const Firebird::string& text)
: values(pool),
blr(pool),
message(pool),
resultSet(NULL)
{
request = DSQL_allocate_statement(tdbb, attachment);
const Database* const dbb = tdbb->getDatabase();
const int dialect = dbb->dbb_flags & DBB_DB_SQL_dialect_3 ? SQL_DIALECT_V6 : SQL_DIALECT_V5;
DSQL_prepare(tdbb, transaction, &request, text.length(), text.c_str(), dialect,
0, NULL, 0, NULL);
int paramCount = 0;
size_t msgLength = 0;
if (request->req_receive)
{
for (dsql_par* par = request->req_receive->msg_parameters; par; par = par->par_next)
{
if (!par->par_index)
continue;
msgLength = FB_ALIGN(msgLength, type_alignments[par->par_desc.dsc_dtype]);
msgLength += par->par_desc.dsc_length;
msgLength = FB_ALIGN(msgLength, type_alignments[dtype_short]);
msgLength += sizeof(SSHORT);
++paramCount;
}
paramCount *= 2;
blr.add(blr_version5);
blr.add(blr_begin);
blr.add(blr_message);
blr.add(0);
blr.add(paramCount);
blr.add(paramCount >> 8);
values.resize(paramCount);
message.resize(msgLength);
msgLength = 0;
int i = 0;
for (int j = 1; j <= paramCount / 2; ++j)
{
for (dsql_par* par = request->req_receive->msg_parameters; par; par = par->par_next)
{
if (par->par_index != j)
continue;
if (type_alignments[par->par_desc.dsc_dtype])
msgLength = FB_ALIGN(msgLength, type_alignments[par->par_desc.dsc_dtype]);
values[i] = par->par_desc;
values[i].dsc_address = message.begin() + msgLength;
msgLength += par->par_desc.dsc_length;
generateBlr(&values[i]);
++i;
// Calculate the NULL indicator offset
if (type_alignments[dtype_short])
msgLength = FB_ALIGN(msgLength, type_alignments[dtype_short]);
values[i].makeShort(0);
values[i].dsc_address = message.begin() + msgLength;
msgLength += sizeof(SSHORT);
// Generate BLR for the NULL indicator
blr.add(blr_short);
blr.add(0);
++i;
}
}
blr.add(blr_end);
}
}
PreparedStatement::~PreparedStatement()
{
thread_db* tdbb = JRD_get_thread_data();
DSQL_free_statement(tdbb, request, DSQL_drop);
if (resultSet)
resultSet->stmt = NULL;
}
void PreparedStatement::execute(thread_db* tdbb, jrd_tra* transaction)
{
DSQL_execute(tdbb, &transaction, request, 0, NULL, 0, 0, NULL, 0, NULL, 0, 0, NULL);
}
ResultSet* PreparedStatement::executeQuery(thread_db* tdbb, jrd_tra* transaction)
{
fb_assert(resultSet == NULL && request->req_receive);
return new ResultSet(tdbb, this, transaction);
}
int PreparedStatement::getResultCount()
{
return values.getCount() / 2;
}
void PreparedStatement::generateBlr(const dsc* desc)
{
USHORT length = 0;
switch (desc->dsc_dtype)
{
case dtype_text:
blr.add(blr_text2);
blr.add(desc->dsc_ttype());
blr.add(desc->dsc_ttype() >> 8);
length = desc->dsc_length;
blr.add(length);
blr.add(length >> 8);
break;
case dtype_varying:
blr.add(blr_varying2);
blr.add(desc->dsc_ttype());
blr.add(desc->dsc_ttype() >> 8);
fb_assert(desc->dsc_length >= sizeof(USHORT));
length = desc->dsc_length - sizeof(USHORT);
blr.add(length);
blr.add(length >> 8);
break;
case dtype_short:
blr.add(blr_short);
blr.add(desc->dsc_scale);
break;
case dtype_long:
blr.add(blr_long);
blr.add(desc->dsc_scale);
break;
case dtype_quad:
blr.add(blr_quad);
blr.add(desc->dsc_scale);
break;
case dtype_int64:
blr.add(blr_int64);
blr.add(desc->dsc_scale);
break;
case dtype_real:
blr.add(blr_float);
break;
case dtype_double:
blr.add(blr_double);
break;
case dtype_sql_date:
blr.add(blr_sql_date);
break;
case dtype_sql_time:
blr.add(blr_sql_time);
break;
case dtype_timestamp:
blr.add(blr_timestamp);
break;
case dtype_array:
blr.add(blr_quad);
blr.add(0);
break;
case dtype_blob:
blr.add(blr_blob2);
blr.add(desc->dsc_sub_type);
blr.add(desc->dsc_sub_type >> 8);
blr.add(desc->getTextType());
blr.add(desc->getTextType() >> 8);
break;
default:
fb_assert(false);
}
}
} // namespace

View File

@ -0,0 +1,74 @@
/*
* 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 Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2008 Adriano dos Santos Fernandes <adrianosf@uol.com.br>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef JRD_PREPARED_STATEMENT_H
#define JRD_PREPARED_STATEMENT_H
#include "../common/classes/fb_string.h"
#include "../common/classes/array.h"
struct dsc;
namespace Jrd {
class thread_db;
class jrd_tra;
class Attachment;
class dsql_req;
class ResultSet;
class PreparedStatement
{
friend class ResultSet;
public:
PreparedStatement(thread_db* tdbb, Firebird::MemoryPool& pool, Attachment* attachment,
jrd_tra* transaction, const Firebird::string& text);
~PreparedStatement();
public:
void execute(thread_db* tdbb, jrd_tra* transaction);
ResultSet* executeQuery(thread_db* tdbb, jrd_tra* transaction);
int getResultCount();
dsql_req* getRequest()
{
return request;
}
private:
void generateBlr(const dsc* desc);
private:
dsql_req* request;
Firebird::Array<dsc> values;
Firebird::UCharBuffer blr;
Firebird::UCharBuffer message;
ResultSet* resultSet;
};
} // namespace
#endif // JRD_PREPARED_STATEMENT_H

94
src/jrd/ResultSet.cpp Normal file
View File

@ -0,0 +1,94 @@
/*
* 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 Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2008 Adriano dos Santos Fernandes <adrianosf@uol.com.br>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#include "../jrd/ResultSet.h"
#include "../jrd/PreparedStatement.h"
#include "../jrd/align.h"
#include "../jrd/jrd.h"
#include "../jrd/dsc.h"
#include "../dsql/dsql.h"
#include "../dsql/sqlda_pub.h"
#include "../dsql/dsql_proto.h"
namespace Jrd {
ResultSet::ResultSet(thread_db* tdbb, PreparedStatement* aStmt, jrd_tra* aTransaction)
: stmt(aStmt),
transaction(aTransaction),
firstFetch(false)
{
DSQL_execute(tdbb, &transaction, stmt->request, 0, NULL, 0, 0, NULL, 0, NULL, 0, 0, NULL);
stmt->resultSet = this;
}
ResultSet::~ResultSet()
{
if (!stmt)
return;
thread_db* tdbb = JRD_get_thread_data();
stmt->resultSet = NULL;
if (stmt->request->req_type != REQ_EXEC_PROCEDURE)
DSQL_free_statement(tdbb, stmt->request, DSQL_close);
}
bool ResultSet::fetch(thread_db* tdbb)
{
if (stmt->request->req_type == REQ_EXEC_PROCEDURE && firstFetch)
return false;
memset(stmt->message.begin(), 0, stmt->message.getCount());
ISC_STATUS status = DSQL_fetch(tdbb, stmt->request, stmt->blr.getCount(), stmt->blr.begin(),
0, stmt->message.getCount(), stmt->message.begin());
if (status == 100)
return false;
firstFetch = true;
return true;
}
bool ResultSet::isNull(int param)
{
dsc* desc = &stmt->values[(param - 1) * 2 + 1];
fb_assert(desc->dsc_dtype == dtype_short);
return *(SSHORT*) desc->dsc_address != 0;
}
dsc ResultSet::getDesc(int param)
{
return stmt->values[(param - 1) * 2];
}
} // namespace

58
src/jrd/ResultSet.h Normal file
View File

@ -0,0 +1,58 @@
/*
* 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 Adriano dos Santos Fernandes
* for the Firebird Open Source RDBMS project.
*
* Copyright (c) 2008 Adriano dos Santos Fernandes <adrianosf@uol.com.br>
* and all contributors signed below.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
*/
#ifndef JRD_RESULT_SET_H
#define JRD_RESULT_SET_H
struct dsc;
namespace Jrd {
class thread_db;
class jrd_tra;
class Attachment;
class PreparedStatement;
class ResultSet
{
friend class PreparedStatement;
public:
ResultSet(thread_db* tdbb, PreparedStatement* aStmt, jrd_tra* aTransaction);
~ResultSet();
public:
bool fetch(thread_db* tdbb);
bool isNull(int param);
dsc getDesc(int param);
private:
PreparedStatement* stmt;
jrd_tra* transaction;
bool firstFetch;
};
} // namespace
#endif // JRD_RESULT_SET_H

View File

@ -1159,7 +1159,7 @@ void EXE_unwind(thread_db* tdbb, jrd_req* request)
jrd_nod* node = request->req_exec_sta[i];
ExecuteStatement* impure =
(ExecuteStatement*) ((char*) request + node->nod_impure);
impure->Close(tdbb);
impure->close(tdbb);
}
}
catch (const Firebird::Exception&)
@ -1477,30 +1477,7 @@ static void exec_sql(thread_db* tdbb, jrd_req* request, DSC* dsc)
*
**************************************/
SET_TDBB(tdbb);
jrd_tra* const transaction = tdbb->getTransaction();
if (transaction->tra_callback_count >= MAX_CALLBACKS)
{
ERR_post(isc_exec_sql_max_call_exceeded, 0);
}
Firebird::string sqlStatementText;
ExecuteStatement::getString(tdbb, sqlStatementText, dsc, request);
transaction->tra_callback_count++;
try
{
DSQL_callback_execute_immediate(tdbb, sqlStatementText);
}
catch (const Firebird::Exception&)
{
transaction->tra_callback_count--;
throw;
}
transaction->tra_callback_count--;
ExecuteStatement::execute(tdbb, request, dsc);
}
@ -2533,15 +2510,15 @@ static jrd_nod* looper(thread_db* tdbb, jrd_req* request, jrd_nod* in_node)
case nod_exec_into:
{
ExecuteStatement* impure =
(ExecuteStatement*)
((SCHAR *) request + node->nod_impure);
ExecuteStatement* impure = (ExecuteStatement*)
((SCHAR *) request + node->nod_impure);
switch (request->req_operation) {
case jrd_req::req_evaluate:
impure->Open(tdbb, node->nod_arg[0], node->nod_count - 2, !node->nod_arg[1]);
impure->open(tdbb, node->nod_arg[0], node->nod_count - 2, !node->nod_arg[1]);
case jrd_req::req_return:
case jrd_req::req_sync:
if (impure->Fetch(tdbb, &node->nod_arg[2])) {
if (impure->fetch(tdbb, &node->nod_arg[2])) {
request->req_operation = jrd_req::req_evaluate;
node = node->nod_arg[1];
break;
@ -2549,7 +2526,7 @@ static jrd_nod* looper(thread_db* tdbb, jrd_req* request, jrd_nod* in_node)
request->req_operation = jrd_req::req_return;
default:
// if have active opened request - close it
impure->Close(tdbb);
impure->close(tdbb);
node = node->nod_parent;
}
}

View File

@ -36,22 +36,69 @@
#include "../jrd/mov_proto.h"
#include "../jrd/evl_proto.h"
#include "../jrd/exe_proto.h"
#include "../jrd/align.h"
#include "../jrd/execute_statement.h"
#include "../dsql/dsql_proto.h"
#include "../dsql/dsql.h"
#include "../common/classes/auto.h"
#include <string.h>
#include <math.h>
using namespace Jrd;
using Firebird::AutoPtr;
namespace {
const UCHAR sql_output_info[] = {isc_info_sql_select, isc_info_sql_num_variables};
void ExecuteStatement::execute(Jrd::thread_db* tdbb, jrd_req* request, DSC* dsc)
{
SET_TDBB(tdbb);
} // anonymous namespace
Attachment* attachment = tdbb->getAttachment();
jrd_tra* const transaction = tdbb->getTransaction();
void ExecuteStatement::Open(thread_db* tdbb, jrd_nod* sql, SSHORT nVars, bool singleton)
if (transaction->tra_callback_count >= MAX_CALLBACKS)
{
ERR_post(isc_exec_sql_max_call_exceeded, 0);
}
Firebird::string sqlStatementText;
getString(tdbb, sqlStatementText, dsc, 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(
isc_sqlerr, isc_arg_number, (SLONG) -902,
isc_arg_gds, isc_exec_sql_invalid_req,
isc_arg_string, ERR_string(sqlStatementText),
0);
}
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);
@ -63,10 +110,6 @@ void ExecuteStatement::Open(thread_db* tdbb, jrd_nod* sql, SSHORT nVars, bool si
ERR_post(isc_exec_sql_max_call_exceeded, 0);
}
blr = NULL;
message = NULL;
values = NULL;
varCount = nVars;
singleMode = singleton;
@ -79,51 +122,28 @@ void ExecuteStatement::Open(thread_db* tdbb, jrd_nod* sql, SSHORT nVars, bool si
try
{
statement = DSQL_allocate_statement(tdbb, attachment);
stmt = attachment->prepareStatement(tdbb, *tdbb->getDefaultPool(), transaction, sqlText);
const Database* const dbb = tdbb->getDatabase();
const int dialect = dbb->dbb_flags & DBB_DB_SQL_dialect_3 ? SQL_DIALECT_V6 : SQL_DIALECT_V5;
UCHAR info_buffer[BUFFER_TINY];
DSQL_prepare(tdbb, transaction, &statement,
sqlText.length(), sqlText.c_str(), dialect,
sizeof(sql_output_info), sql_output_info,
sizeof(info_buffer), info_buffer);
const UCHAR* info(info_buffer);
UCHAR tag = *info++;
fb_assert(tag == isc_info_sql_select);
tag = *info++;
fb_assert(tag == isc_info_sql_num_variables);
const int length = gds__vax_integer(info, sizeof(SSHORT));
info += sizeof(SSHORT);
const int number = gds__vax_integer(info, length);
info += length;
tag = *info++;
fb_assert(tag == isc_info_end);
if (!number)
if (stmt->getResultCount() == 0)
{
DSQL_free_statement(tdbb, statement, DSQL_drop);
statement = NULL;
delete stmt;
stmt = NULL;
ERR_post(isc_exec_sql_invalid_req,
isc_arg_string, ERR_cstring(startOfSqlOperator),
0);
ERR_post(
isc_exec_sql_invalid_req,
isc_arg_string, ERR_cstring(startOfSqlOperator),
0);
}
if (number != varCount)
if (stmt->getResultCount() != varCount)
{
DSQL_free_statement(tdbb, statement, DSQL_drop);
statement = NULL;
delete stmt;
stmt = NULL;
ERR_post(isc_wronumarg, 0);
}
DSQL_execute(tdbb, &transaction, statement,
0, NULL, 0, 0, NULL,
0, NULL, 0, 0, NULL);
resultSet = stmt->executeQuery(tdbb, transaction);
fb_assert(transaction == tdbb->getTransaction());
}
@ -136,103 +156,33 @@ void ExecuteStatement::Open(thread_db* tdbb, jrd_nod* sql, SSHORT nVars, bool si
transaction->tra_callback_count--;
}
bool ExecuteStatement::Fetch(thread_db* tdbb, jrd_nod** jrdVar)
bool ExecuteStatement::fetch(thread_db* tdbb, jrd_nod** jrdVar)
{
fb_assert(statement);
size_t blr_length = 0;
if (!message && !blr && !values)
if (!resultSet->fetch(tdbb))
{
const size_t param_count = varCount * 2;
MemoryPool& pool = *tdbb->getDefaultPool();
values = FB_NEW(pool) Firebird::Array<dsc>(pool);
values->grow(param_count);
blr = FB_NEW(pool) Firebird::UCharBuffer(pool);
blr->add(blr_version5);
blr->add(blr_begin);
blr->add(blr_message);
blr->add(0);
blr->add(param_count);
blr->add(param_count >> 8);
size_t msg_length = 0;
for (int i = 0; i < varCount; i++)
{
jrd_nod* const target = jrdVar[i];
fb_assert(target);
dsc* const desc = EVL_assign_to(tdbb, target);
(*values)[i * 2] = *desc;
(*values)[i * 2 + 1].dsc_dtype = dtype_short;
(*values)[i * 2 + 1].dsc_length = sizeof(SSHORT);
// Generate BLR for the value
generateBlr(desc);
// Generate BLR for the NULL indicator
blr->add(blr_short);
blr->add(desc->dsc_scale);
// Calculate the value offset
msg_length = FB_ALIGN(msg_length, type_alignments[desc->dsc_dtype]);
(*values)[i * 2].dsc_address = (UCHAR*)(IPTR) msg_length;
msg_length += desc->dsc_length;
// Calculate the NULL indicator offset
msg_length = FB_ALIGN(msg_length, type_alignments[dtype_short]);
(*values)[i * 2 + 1].dsc_address = (UCHAR*)(IPTR) msg_length;
msg_length += sizeof(SSHORT);
}
blr->add(blr_end);
blr_length = blr->getCount();
message = FB_NEW(pool) Firebird::UCharBuffer(pool);
message->grow(msg_length);
}
else
{
memset(message->begin(), 0, message->getCount());
}
ISC_STATUS status = DSQL_fetch(tdbb, statement,
blr->getCount(), blr->begin(),
0, message->getCount(), message->begin());
if (status == 100)
{
DSQL_free_statement(tdbb, statement, DSQL_drop);
statement = NULL;
delete resultSet;
resultSet = NULL;
delete stmt;
stmt = NULL;
return false;
}
for (int i = 0; i < varCount; i++)
{
dsc desc = (*values)[i * 2];
desc.dsc_address = message->begin() + (IPTR) desc.dsc_address;
dsc null_desc = (*values)[i * 2 + 1];
null_desc.dsc_address = message->begin() + (IPTR) null_desc.dsc_address;
const bool null_flag = ((*(SSHORT*) null_desc.dsc_address) == 0) ? false : true;
EXE_assignment(tdbb, jrdVar[i], &desc, null_flag, NULL, NULL);
dsc desc = resultSet->getDesc(i + 1);
bool nullFlag = resultSet->isNull(i + 1);
EXE_assignment(tdbb, jrdVar[i], &desc, nullFlag, NULL, NULL);
}
if (singleMode)
{
status = DSQL_fetch(tdbb, statement,
blr->getCount(), blr->begin(),
0, message->getCount(), message->begin());
if (status == 100)
if (!resultSet->fetch(tdbb))
{
DSQL_free_statement(tdbb, statement, DSQL_drop);
statement = NULL;
delete resultSet;
resultSet = NULL;
delete stmt;
stmt = NULL;
return false;
}
@ -242,22 +192,14 @@ bool ExecuteStatement::Fetch(thread_db* tdbb, jrd_nod** jrdVar)
return true;
}
void ExecuteStatement::Close(thread_db* tdbb)
{
if (statement)
{
DSQL_free_statement(tdbb, statement, DSQL_drop);
statement = NULL;
}
delete blr;
blr = NULL;
delete message;
message = NULL;
delete values;
values = NULL;
void ExecuteStatement::close(thread_db* tdbb)
{
delete resultSet;
delete stmt;
}
void ExecuteStatement::getString(thread_db* tdbb,
Firebird::string& sql,
const dsc* desc,
@ -277,88 +219,3 @@ void ExecuteStatement::getString(thread_db* tdbb,
sql.assign((const char*) ptr, len);
}
void ExecuteStatement::generateBlr(const dsc* desc)
{
fb_assert(blr);
USHORT length = 0;
switch (desc->dsc_dtype)
{
case dtype_text:
blr->add(blr_text2);
blr->add(desc->dsc_ttype());
blr->add(desc->dsc_ttype() >> 8);
length = desc->dsc_length;
blr->add(length);
blr->add(length >> 8);
break;
case dtype_varying:
blr->add(blr_varying2);
blr->add(desc->dsc_ttype());
blr->add(desc->dsc_ttype() >> 8);
fb_assert(desc->dsc_length >= sizeof(USHORT));
length = desc->dsc_length - sizeof(USHORT);
blr->add(length);
blr->add(length >> 8);
break;
case dtype_short:
blr->add(blr_short);
blr->add(desc->dsc_scale);
break;
case dtype_long:
blr->add(blr_long);
blr->add(desc->dsc_scale);
break;
case dtype_quad:
blr->add(blr_quad);
blr->add(desc->dsc_scale);
break;
case dtype_int64:
blr->add(blr_int64);
blr->add(desc->dsc_scale);
break;
case dtype_real:
blr->add(blr_float);
break;
case dtype_double:
blr->add(blr_double);
break;
case dtype_sql_date:
blr->add(blr_sql_date);
break;
case dtype_sql_time:
blr->add(blr_sql_time);
break;
case dtype_timestamp:
blr->add(blr_timestamp);
break;
case dtype_array:
blr->add(blr_quad);
blr->add(0);
break;
case dtype_blob:
blr->add(blr_blob2);
blr->add(desc->dsc_sub_type);
blr->add(desc->dsc_sub_type >> 8);
blr->add(desc->getTextType());
blr->add(desc->getTextType() >> 8);
break;
default:
fb_assert(false);
}
}

View File

@ -22,6 +22,7 @@
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
* Adriano dos Santos Fernandes
*/
#ifndef JRD_EXECUTE_STATEMENT_H
@ -29,35 +30,35 @@
#include "../jrd/jrd_blks.h"
#include "../include/fb_blk.h"
#include "../jrd/PreparedStatement.h"
#include "../jrd/ResultSet.h"
#include "../jrd/exe.h"
#include "../jrd/ibase.h"
#include "../dsql/dsql.h"
const int MAX_CALLBACKS = 50;
namespace Jrd {
class ExecuteStatement {
class ExecuteStatement
{
public:
static void execute(Jrd::thread_db* tdbb, Jrd::jrd_req* request, DSC* dsc);
void open(Jrd::thread_db* tdbb, Jrd::jrd_nod* sql, SSHORT nVars, bool SingleTon);
bool fetch(Jrd::thread_db* tdbb, Jrd::jrd_nod** FirstVar);
void close(Jrd::thread_db* tdbb);
static void getString(Jrd::thread_db*, Firebird::string&, const dsc* d, const Jrd::jrd_req* r);
private:
dsql_req* statement;
Firebird::UCharBuffer* blr;
Firebird::UCharBuffer* message;
Firebird::Array<dsc>* values;
PreparedStatement* stmt;
ResultSet* resultSet;
int varCount;
bool singleMode;
TEXT startOfSqlOperator[32];
void generateBlr(const dsc* desc);
public:
void Open(Jrd::thread_db* tdbb, Jrd::jrd_nod* sql, SSHORT nVars, bool SingleTon);
bool Fetch(Jrd::thread_db* tdbb, Jrd::jrd_nod** FirstVar);
void Close(Jrd::thread_db* tdbb);
static void getString(Jrd::thread_db*, Firebird::string&, const dsc* d, const Jrd::jrd_req* r);
};
} // namespace
#endif // JRD_EXECUTE_STATEMENT_H

View File

@ -30,6 +30,7 @@
*
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
* Claudio Valderrama C.
* Adriano dos Santos Fernandes
*
*/
@ -77,6 +78,7 @@
#include "../jrd/iberr.h"
#include "../intl/charsets.h"
#include "../jrd/sort.h"
#include "../jrd/PreparedStatement.h"
#include "../jrd/blb_proto.h"
#include "../jrd/cch_proto.h"
@ -5614,6 +5616,13 @@ static vdnResult verify_database_name(const Firebird::PathName& name, ISC_STATUS
}
PreparedStatement* Attachment::prepareStatement(thread_db* tdbb, Firebird::MemoryPool& pool,
jrd_tra* transaction, const Firebird::string& text)
{
return new PreparedStatement(tdbb, pool, this, transaction, text);
}
/**
getUserInfo

View File

@ -24,6 +24,7 @@
*
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
* Claudio Valderrama C.
* Adriano dos Santos Fernandes
*
*/
@ -152,6 +153,7 @@ class TextType;
class Parameter;
class jrd_fld;
class dsql_dbb;
class PreparedStatement;
// The database block, the topmost block in the metadata
// cache for a database
@ -316,6 +318,9 @@ public:
dsql_dbb* att_dsql_instance;
bool locksmith() const;
PreparedStatement* prepareStatement(thread_db* tdbb, Firebird::MemoryPool& pool,
jrd_tra* transaction, const Firebird::string& text);
};