2008-03-13 17:37:20 +01:00
|
|
|
/*
|
|
|
|
* 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 {
|
|
|
|
|
|
|
|
|
2008-03-31 03:51:18 +02:00
|
|
|
PreparedStatement::PreparedStatement(thread_db* tdbb, Firebird::MemoryPool& aPool,
|
2008-03-13 17:37:20 +01:00
|
|
|
Attachment* attachment, jrd_tra* transaction, const Firebird::string& text)
|
2008-03-31 03:51:18 +02:00
|
|
|
: pool(aPool),
|
|
|
|
values(pool),
|
2008-03-13 17:37:20 +01:00
|
|
|
blr(pool),
|
|
|
|
message(pool),
|
|
|
|
resultSet(NULL)
|
|
|
|
{
|
|
|
|
request = DSQL_allocate_statement(tdbb, attachment);
|
2008-03-14 16:59:12 +01:00
|
|
|
try
|
2008-03-13 17:37:20 +01:00
|
|
|
{
|
2008-03-14 16:59:12 +01:00
|
|
|
const Database* const dbb = tdbb->getDatabase();
|
|
|
|
const int dialect = dbb->dbb_flags & DBB_DB_SQL_dialect_3 ? SQL_DIALECT_V6 : SQL_DIALECT_V5;
|
2008-03-13 17:37:20 +01:00
|
|
|
|
2008-03-14 16:59:12 +01:00
|
|
|
DSQL_prepare(tdbb, transaction, &request, text.length(), text.c_str(), dialect,
|
|
|
|
0, NULL, 0, NULL);
|
2008-03-13 17:37:20 +01:00
|
|
|
|
2008-03-14 16:59:12 +01:00
|
|
|
int paramCount = 0;
|
|
|
|
size_t msgLength = 0;
|
2008-03-13 17:37:20 +01:00
|
|
|
|
2008-03-14 16:59:12 +01:00
|
|
|
if (request->req_receive)
|
2008-03-13 17:37:20 +01:00
|
|
|
{
|
2008-03-15 11:25:30 +01:00
|
|
|
for (const dsql_par* par = request->req_receive->msg_parameters; par; par = par->par_next)
|
2008-03-13 17:37:20 +01:00
|
|
|
{
|
2008-03-14 16:59:12 +01:00
|
|
|
if (!par->par_index)
|
2008-03-13 17:37:20 +01:00
|
|
|
continue;
|
|
|
|
|
|
|
|
if (type_alignments[par->par_desc.dsc_dtype])
|
|
|
|
msgLength = FB_ALIGN(msgLength, type_alignments[par->par_desc.dsc_dtype]);
|
|
|
|
msgLength += par->par_desc.dsc_length;
|
2008-03-14 16:59:12 +01:00
|
|
|
msgLength = FB_ALIGN(msgLength, type_alignments[dtype_short]);
|
|
|
|
msgLength += sizeof(SSHORT);
|
2008-03-13 17:37:20 +01:00
|
|
|
|
2008-03-14 16:59:12 +01:00
|
|
|
++paramCount;
|
|
|
|
}
|
2008-03-13 17:37:20 +01:00
|
|
|
|
2008-03-14 16:59:12 +01:00
|
|
|
paramCount *= 2;
|
2008-03-13 17:37:20 +01:00
|
|
|
|
2008-03-14 16:59:12 +01:00
|
|
|
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;
|
2008-03-13 17:37:20 +01:00
|
|
|
|
2008-03-14 16:59:12 +01:00
|
|
|
int i = 0;
|
2008-03-13 17:37:20 +01:00
|
|
|
|
2008-03-14 16:59:12 +01:00
|
|
|
for (int j = 1; j <= paramCount / 2; ++j)
|
|
|
|
{
|
2008-03-15 11:25:30 +01:00
|
|
|
for (const dsql_par* par = request->req_receive->msg_parameters; par; par = par->par_next)
|
2008-03-14 16:59:12 +01:00
|
|
|
{
|
|
|
|
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;
|
|
|
|
}
|
2008-03-13 17:37:20 +01:00
|
|
|
}
|
|
|
|
|
2008-03-14 16:59:12 +01:00
|
|
|
blr.add(blr_end);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (const Firebird::Exception&)
|
|
|
|
{
|
|
|
|
DSQL_free_statement(tdbb, request, DSQL_drop);
|
|
|
|
throw;
|
2008-03-13 17:37:20 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
2008-03-15 18:55:27 +01:00
|
|
|
fb_assert(resultSet == NULL);
|
2008-03-13 17:37:20 +01:00
|
|
|
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);
|
2008-03-31 03:51:18 +02:00
|
|
|
return FB_NEW(pool) ResultSet(tdbb, this, transaction);
|
2008-03-13 17:37:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-03-15 11:25:30 +01:00
|
|
|
int PreparedStatement::getResultCount() const
|
2008-03-13 17:37:20 +01:00
|
|
|
{
|
|
|
|
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
|