2004-03-11 05:31:04 +01:00
|
|
|
/*
|
|
|
|
* 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): ______________________________________.
|
2007-06-23 20:48:27 +02:00
|
|
|
* Adriano dos Santos Fernandes
|
2004-03-11 05:31:04 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "firebird.h"
|
|
|
|
#include "fb_types.h"
|
|
|
|
#include "gen/iberror.h"
|
|
|
|
|
|
|
|
#include "../jrd/common.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include <math.h>
|
|
|
|
#include "../jrd/jrd.h"
|
|
|
|
#include "../jrd/tra.h"
|
|
|
|
#include "../jrd/dsc.h"
|
2004-06-08 15:41:08 +02:00
|
|
|
#include "../jrd/thd.h"
|
2004-03-11 05:31:04 +01:00
|
|
|
#include "../jrd/err_proto.h"
|
|
|
|
#include "../jrd/mov_proto.h"
|
|
|
|
#include "../jrd/evl_proto.h"
|
2007-06-23 20:48:27 +02:00
|
|
|
#include "../jrd/exe_proto.h"
|
2004-03-11 05:31:04 +01:00
|
|
|
#include "../jrd/sch_proto.h"
|
2004-05-18 00:30:09 +02:00
|
|
|
#include "../jrd/thread_proto.h"
|
2004-03-11 05:31:04 +01:00
|
|
|
#define WHY_NO_API
|
|
|
|
#include "../jrd/why_proto.h"
|
2007-01-20 15:45:45 +01:00
|
|
|
#include "../jrd/y_handle.h"
|
2007-10-05 16:30:55 +02:00
|
|
|
#include "../jrd/align.h"
|
2004-03-11 05:31:04 +01:00
|
|
|
|
|
|
|
#include "../jrd/execute_statement.h"
|
2007-06-23 20:48:27 +02:00
|
|
|
#include "../common/classes/GenericMap.h"
|
|
|
|
#include "../common/classes/init.h"
|
2004-03-11 05:31:04 +01:00
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
using namespace Jrd;
|
2007-06-23 20:48:27 +02:00
|
|
|
using namespace Firebird;
|
2004-03-20 15:57:40 +01:00
|
|
|
|
2007-01-20 15:45:45 +01:00
|
|
|
YValve::Attachment* GetWhyAttachment(ISC_STATUS*, Attachment*);
|
|
|
|
|
|
|
|
namespace {
|
2004-03-11 05:31:04 +01:00
|
|
|
|
2007-06-23 20:48:27 +02:00
|
|
|
const SSHORT sqlType[] =
|
2004-03-11 05:31:04 +01:00
|
|
|
{
|
2007-06-23 20:48:27 +02:00
|
|
|
/* dtype_unknown */ -1,
|
|
|
|
/* dtype_text */ SQL_TEXT,
|
|
|
|
/* dtype_cstring */ -1,
|
|
|
|
/* dtype_varying */ SQL_VARYING,
|
|
|
|
/* dtype_none1 */ -1,
|
|
|
|
/* dtype_none2 */ -1,
|
|
|
|
/* dtype_packed */ -1,
|
|
|
|
/* dtype_byte */ -1,
|
|
|
|
/* dtype_short */ SQL_SHORT,
|
|
|
|
/* dtype_long */ SQL_LONG,
|
|
|
|
/* dtype_quad */ SQL_QUAD,
|
|
|
|
/* dtype_real */ SQL_FLOAT,
|
|
|
|
/* dtype_double */ SQL_DOUBLE,
|
|
|
|
/* dtype_d_float */ -1, // Fix to use in VMS
|
|
|
|
/* dtype_sql_date */ SQL_TYPE_DATE,
|
|
|
|
/* dtype_sql_time */ SQL_TYPE_TIME,
|
|
|
|
/* dtype_timestamp */ SQL_TIMESTAMP,
|
|
|
|
/* dtype_blob */ SQL_BLOB,
|
|
|
|
/* dtype_array */ SQL_ARRAY, // Not supported for a while
|
|
|
|
/* dtype_int64 */ SQL_INT64
|
2004-03-11 05:31:04 +01:00
|
|
|
};
|
|
|
|
|
2007-06-27 04:08:25 +02:00
|
|
|
static InitInstance<GenericMap<Pair<NonPooled<SSHORT, UCHAR> > > > sqlTypeToDscType;
|
2007-06-23 20:48:27 +02:00
|
|
|
|
2007-01-20 15:45:45 +01:00
|
|
|
void startCallback(thread_db* tdbb)
|
|
|
|
{
|
|
|
|
#if (defined DEV_BUILD && !defined MULTI_THREAD)
|
|
|
|
tdbb->tdbb_database->dbb_flags |= DBB_exec_statement;
|
|
|
|
#endif
|
|
|
|
tdbb->tdbb_transaction->tra_callback_count++;
|
|
|
|
THREAD_EXIT();
|
|
|
|
}
|
|
|
|
|
|
|
|
void finishCallback(thread_db* tdbb)
|
|
|
|
{
|
|
|
|
THREAD_ENTER();
|
|
|
|
#if (defined DEV_BUILD && !defined MULTI_THREAD)
|
|
|
|
tdbb->tdbb_database->dbb_flags &= ~DBB_exec_statement;
|
|
|
|
#endif
|
|
|
|
tdbb->tdbb_transaction->tra_callback_count--;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // anonymous namespace
|
|
|
|
|
2004-03-11 05:31:04 +01:00
|
|
|
void ExecuteStatement::Open(thread_db* tdbb, jrd_nod* sql, SSHORT nVars, bool SingleTon)
|
|
|
|
{
|
|
|
|
SET_TDBB(tdbb);
|
2007-06-23 20:48:27 +02:00
|
|
|
|
|
|
|
// initialize sqlTypeToDscType in the first call to this function
|
2007-10-05 16:30:55 +02:00
|
|
|
// non-thread safe, require mutex in Fb3
|
2007-06-23 20:48:27 +02:00
|
|
|
if (sqlTypeToDscType().count() == 0)
|
|
|
|
{
|
|
|
|
for (int i = 0; i < FB_NELEM(sqlType); ++i)
|
|
|
|
sqlTypeToDscType().put(sqlType[i], static_cast<UCHAR>(i));
|
|
|
|
}
|
|
|
|
|
2004-03-11 05:31:04 +01:00
|
|
|
if (tdbb->tdbb_transaction->tra_callback_count >= MAX_CALLBACKS) {
|
|
|
|
tdbb->tdbb_status_vector[0] = isc_arg_gds;
|
|
|
|
tdbb->tdbb_status_vector[1] = isc_exec_sql_max_call_exceeded;
|
|
|
|
tdbb->tdbb_status_vector[2] = isc_arg_end;
|
|
|
|
ERR_punt();
|
|
|
|
}
|
|
|
|
|
2004-03-20 15:57:40 +01:00
|
|
|
Sqlda = 0;
|
|
|
|
Transaction = 0;
|
|
|
|
Buffer = 0;
|
|
|
|
SingleMode = SingleTon;
|
|
|
|
|
|
|
|
fb_assert(tdbb->tdbb_transaction->tra_pool);
|
|
|
|
Firebird::string SqlText;
|
2007-02-27 03:36:20 +01:00
|
|
|
getString(tdbb, SqlText, EVL_expr(tdbb, sql), tdbb->tdbb_request);
|
2004-05-06 10:40:00 +02:00
|
|
|
memcpy(StartOfSqlOperator, SqlText.c_str(), sizeof(StartOfSqlOperator) - 1);
|
|
|
|
StartOfSqlOperator[sizeof(StartOfSqlOperator) - 1] = 0;
|
2004-03-20 15:57:40 +01:00
|
|
|
|
2007-01-20 15:45:45 +01:00
|
|
|
YValve::Attachment* temp_dbb = GetWhyAttachment(tdbb->tdbb_status_vector,
|
2004-03-11 05:31:04 +01:00
|
|
|
tdbb->tdbb_attachment);
|
2004-05-03 01:06:37 +02:00
|
|
|
if (!temp_dbb)
|
2004-03-11 05:31:04 +01:00
|
|
|
ERR_punt();
|
|
|
|
|
2004-05-03 01:06:37 +02:00
|
|
|
Attachment = temp_dbb->public_handle;
|
|
|
|
|
2007-01-20 15:45:45 +01:00
|
|
|
YValve::Transaction* temp_tra = new YValve::Transaction(tdbb->tdbb_transaction, &Transaction, temp_dbb);
|
2004-03-11 05:31:04 +01:00
|
|
|
|
|
|
|
Statement = 0;
|
|
|
|
Sqlda = MakeSqlda(tdbb, nVars ? nVars : 1);
|
2007-10-06 12:22:32 +02:00
|
|
|
Sqlda->sqln = nVars;
|
|
|
|
Sqlda->version = 1;
|
2004-03-11 05:31:04 +01:00
|
|
|
|
|
|
|
// For normal diagnostic
|
|
|
|
const int max_diag_len = 50;
|
|
|
|
|
|
|
|
// this check uses local error handler for local status vector
|
|
|
|
ISC_STATUS_ARRAY local;
|
|
|
|
ISC_STATUS *status = local;
|
|
|
|
memset(local, 0, sizeof(local));
|
2007-01-20 15:45:45 +01:00
|
|
|
|
2004-03-11 05:31:04 +01:00
|
|
|
# define Chk(x) if ((x) != 0) goto err_handler
|
2007-01-20 15:45:45 +01:00
|
|
|
startCallback(tdbb);
|
2004-03-11 05:31:04 +01:00
|
|
|
|
|
|
|
Chk(isc_dsql_allocate_statement(status, &Attachment, &Statement));
|
|
|
|
|
|
|
|
Chk(isc_dsql_prepare(status, &Transaction, &Statement,
|
2004-03-20 15:57:40 +01:00
|
|
|
SqlText.length(), SqlText.c_str(), SQL_DIALECT_CURRENT, Sqlda));
|
2007-10-06 12:22:32 +02:00
|
|
|
if (! Sqlda->sqld) { // Non-select statement - reject for a while
|
2004-03-11 05:31:04 +01:00
|
|
|
/*Chk(isc_dsql_execute(status, &Transaction,
|
2007-10-06 12:22:32 +02:00
|
|
|
&Statement, SQLDA_VERSION1, 0)); */
|
2004-03-11 05:31:04 +01:00
|
|
|
Chk(isc_dsql_free_statement(status, &Statement, DSQL_drop));
|
|
|
|
Statement = 0;
|
|
|
|
status[0] = isc_arg_gds;
|
|
|
|
status[1] = isc_exec_sql_invalid_req;
|
|
|
|
status[2] = isc_arg_string;
|
|
|
|
status[3] = (ISC_STATUS)(U_IPTR) ERR_cstring(StartOfSqlOperator);
|
|
|
|
status[4] = isc_arg_end;
|
|
|
|
Chk(status[1]);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
Chk(ReMakeSqlda(status, tdbb));
|
|
|
|
Chk(isc_dsql_describe(status, &Statement,
|
2007-10-06 12:22:32 +02:00
|
|
|
SQLDA_VERSION1, Sqlda));
|
2004-03-11 05:31:04 +01:00
|
|
|
Buffer = 0; // Buffer is used in ParseSqlda
|
|
|
|
// First dummy parse - to define buffer size
|
|
|
|
Buffer = FB_NEW(*tdbb->tdbb_transaction->tra_pool)
|
|
|
|
SCHAR[XSQLDA_LENGTH(ParseSqlda())];
|
|
|
|
ParseSqlda();
|
|
|
|
Chk(isc_dsql_execute(status, &Transaction,
|
2007-10-06 12:22:32 +02:00
|
|
|
&Statement, SQLDA_VERSION1, 0));
|
2004-03-11 05:31:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
# undef Chk
|
|
|
|
err_handler:
|
2007-01-20 15:45:45 +01:00
|
|
|
finishCallback(tdbb);
|
|
|
|
|
2004-03-11 05:31:04 +01:00
|
|
|
if (status[0] == 1 && status[1]) {
|
|
|
|
memcpy(tdbb->tdbb_status_vector, status, sizeof(local));
|
2004-05-06 10:40:00 +02:00
|
|
|
Firebird::status_exception::raise(tdbb->tdbb_status_vector);
|
2004-03-11 05:31:04 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ExecuteStatement::Fetch(thread_db* tdbb, jrd_nod** JrdVar)
|
|
|
|
{
|
|
|
|
// If already bugged - we should never get here
|
|
|
|
fb_assert(! (tdbb->tdbb_status_vector[0] == 1 &&
|
|
|
|
tdbb->tdbb_status_vector[1] != 0));
|
|
|
|
if (! Statement)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
ISC_STATUS_ARRAY local;
|
|
|
|
ISC_STATUS *status = local;
|
|
|
|
memset(local, 0, sizeof(local));
|
|
|
|
status = local;
|
2007-01-20 15:45:45 +01:00
|
|
|
|
|
|
|
startCallback(tdbb);
|
2007-10-06 12:22:32 +02:00
|
|
|
if (isc_dsql_fetch(status, &Statement,
|
|
|
|
SQLDA_VERSION1, Sqlda) == 100)
|
2004-03-11 05:31:04 +01:00
|
|
|
{
|
|
|
|
isc_dsql_free_statement(status, &Statement, DSQL_drop);
|
2007-01-20 15:45:45 +01:00
|
|
|
finishCallback(tdbb);
|
|
|
|
|
2004-03-11 05:31:04 +01:00
|
|
|
Statement = 0;
|
|
|
|
return false;
|
2007-10-06 12:22:32 +02:00
|
|
|
}
|
2007-01-20 15:45:45 +01:00
|
|
|
finishCallback(tdbb);
|
|
|
|
|
2004-03-11 05:31:04 +01:00
|
|
|
if (status[0] == 1 && status[1]) {
|
|
|
|
memcpy(tdbb->tdbb_status_vector, status, sizeof(local));
|
2004-05-06 10:40:00 +02:00
|
|
|
Firebird::status_exception::raise(tdbb->tdbb_status_vector);
|
2004-03-11 05:31:04 +01:00
|
|
|
}
|
|
|
|
|
2004-11-30 07:18:39 +01:00
|
|
|
const XSQLVAR *var = Sqlda->sqlvar;
|
2004-03-11 05:31:04 +01:00
|
|
|
for (int i = 0; i < Sqlda->sqld; i++, var++, JrdVar++) {
|
|
|
|
dsc* d = EVL_assign_to(tdbb, *JrdVar);
|
2007-06-23 20:48:27 +02:00
|
|
|
if (d->dsc_dtype >= FB_NELEM(sqlType))
|
2004-03-11 05:31:04 +01:00
|
|
|
{
|
|
|
|
rec_err:
|
|
|
|
tdbb->tdbb_status_vector[0] = isc_arg_gds;
|
|
|
|
tdbb->tdbb_status_vector[1] = isc_exec_sql_invalid_var;
|
|
|
|
tdbb->tdbb_status_vector[2] = isc_arg_number;
|
2007-02-25 09:53:38 +01:00
|
|
|
tdbb->tdbb_status_vector[3] = i + 1;
|
2004-03-11 05:31:04 +01:00
|
|
|
tdbb->tdbb_status_vector[4] = isc_arg_string;
|
|
|
|
tdbb->tdbb_status_vector[5] =
|
|
|
|
(ISC_STATUS)(U_IPTR) ERR_cstring(StartOfSqlOperator);
|
|
|
|
tdbb->tdbb_status_vector[6] = isc_arg_end;
|
2004-05-06 10:40:00 +02:00
|
|
|
Firebird::status_exception::raise(tdbb->tdbb_status_vector);
|
2004-03-11 05:31:04 +01:00
|
|
|
}
|
|
|
|
|
2007-06-23 20:48:27 +02:00
|
|
|
if (sqlType[d->dsc_dtype] < 0)
|
2004-03-11 05:31:04 +01:00
|
|
|
goto rec_err;
|
2007-06-23 20:48:27 +02:00
|
|
|
|
|
|
|
// build the src descriptor
|
|
|
|
dsc src;
|
|
|
|
src.clear();
|
|
|
|
sqlTypeToDscType().get((var->sqltype & ~1), src.dsc_dtype);
|
|
|
|
src.dsc_length = var->sqllen;
|
|
|
|
src.dsc_scale = var->sqlscale;
|
|
|
|
src.dsc_sub_type = var->sqlsubtype;
|
|
|
|
src.dsc_address = (UCHAR*) var->sqldata;
|
|
|
|
|
2007-08-31 12:43:03 +02:00
|
|
|
if ((var->sqltype & ~1) == SQL_VARYING)
|
|
|
|
src.dsc_length += sizeof(SSHORT);
|
|
|
|
|
2007-06-23 20:48:27 +02:00
|
|
|
// and assign to the target
|
|
|
|
EXE_assignment(tdbb, *JrdVar, &src, (var->sqltype & 1) && (*var->sqlind < 0), NULL, NULL);
|
|
|
|
}
|
2004-03-11 05:31:04 +01:00
|
|
|
|
|
|
|
if (SingleMode) {
|
2007-01-20 15:45:45 +01:00
|
|
|
startCallback(tdbb);
|
2004-03-11 05:31:04 +01:00
|
|
|
if (isc_dsql_fetch(status, &Statement,
|
2007-10-06 12:22:32 +02:00
|
|
|
SQLDA_VERSION1, Sqlda) == 100)
|
2004-03-11 05:31:04 +01:00
|
|
|
{
|
|
|
|
isc_dsql_free_statement(status, &Statement, DSQL_drop);
|
2007-01-20 15:45:45 +01:00
|
|
|
finishCallback(tdbb);
|
|
|
|
|
2004-03-11 05:31:04 +01:00
|
|
|
Statement = 0;
|
|
|
|
return false;
|
|
|
|
}
|
2007-01-20 15:45:45 +01:00
|
|
|
finishCallback(tdbb);
|
|
|
|
|
2004-03-11 05:31:04 +01:00
|
|
|
if (! (status[0] == 1 && status[1])) {
|
|
|
|
status[0] = isc_arg_gds;
|
|
|
|
status[1] = isc_sing_select_err;
|
|
|
|
status[2] = isc_arg_end;
|
|
|
|
}
|
|
|
|
memcpy(tdbb->tdbb_status_vector, status, sizeof(local));
|
2004-05-06 10:40:00 +02:00
|
|
|
Firebird::status_exception::raise(tdbb->tdbb_status_vector);
|
2004-03-11 05:31:04 +01:00
|
|
|
}
|
2007-10-06 12:22:32 +02:00
|
|
|
return true;
|
2004-03-11 05:31:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ExecuteStatement::Close(thread_db* tdbb)
|
|
|
|
{
|
|
|
|
if (Statement) {
|
|
|
|
// for a while don't check for errors while freeing statement
|
2007-01-20 15:45:45 +01:00
|
|
|
startCallback(tdbb);
|
2004-03-11 05:31:04 +01:00
|
|
|
isc_dsql_free_statement(0, &Statement, DSQL_drop);
|
2007-01-20 15:45:45 +01:00
|
|
|
finishCallback(tdbb);
|
|
|
|
|
2004-03-11 05:31:04 +01:00
|
|
|
Statement = 0;
|
|
|
|
}
|
|
|
|
char* p = reinterpret_cast<char*>(Sqlda);
|
|
|
|
delete[] p;
|
|
|
|
Sqlda = 0;
|
2004-05-05 06:20:39 +02:00
|
|
|
if (Transaction) {
|
2007-01-20 15:45:45 +01:00
|
|
|
delete YValve::translate<YValve::Transaction>(&Transaction);
|
|
|
|
Transaction = 0;
|
2004-05-05 06:20:39 +02:00
|
|
|
}
|
2004-03-11 05:31:04 +01:00
|
|
|
delete[] Buffer;
|
|
|
|
Buffer = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
XSQLDA* ExecuteStatement::MakeSqlda(thread_db* tdbb, short n)
|
|
|
|
{
|
|
|
|
return (XSQLDA *)
|
|
|
|
(FB_NEW(*tdbb->tdbb_transaction->tra_pool) char[XSQLDA_LENGTH(n)]);
|
|
|
|
}
|
|
|
|
|
|
|
|
ISC_STATUS ExecuteStatement::ReMakeSqlda(ISC_STATUS *vector, thread_db* tdbb)
|
|
|
|
{
|
|
|
|
if (Sqlda->sqln != Sqlda->sqld) {
|
|
|
|
vector[0] = isc_arg_gds;
|
|
|
|
vector[1] = isc_wronumarg;
|
|
|
|
vector[2] = isc_arg_end;
|
|
|
|
}
|
|
|
|
return vector[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
ULONG ExecuteStatement::ParseSqlda(void)
|
|
|
|
{
|
2007-10-06 12:22:32 +02:00
|
|
|
ULONG offset = 0;
|
|
|
|
int i = 0;
|
2007-10-06 21:08:50 +02:00
|
|
|
|
2007-10-06 12:22:32 +02:00
|
|
|
for (XSQLVAR* var = Sqlda->sqlvar; i < Sqlda->sqld; var++, i++)
|
2004-03-11 05:31:04 +01:00
|
|
|
{
|
2007-10-06 12:22:32 +02:00
|
|
|
USHORT length = var->sqllen;
|
|
|
|
const int type = var->sqltype & (~1);
|
|
|
|
UCHAR dscType;
|
2007-10-05 16:30:55 +02:00
|
|
|
sqlTypeToDscType().get(type, dscType);
|
2007-10-06 12:22:32 +02:00
|
|
|
if (type == SQL_VARYING)
|
|
|
|
length += sizeof (SSHORT);
|
2007-10-05 16:30:55 +02:00
|
|
|
|
|
|
|
const USHORT align = type_alignments[dscType];
|
|
|
|
if (align) {
|
|
|
|
offset = FB_ALIGN(offset, align);
|
|
|
|
}
|
2007-10-06 12:22:32 +02:00
|
|
|
var->sqldata = &Buffer[offset];
|
|
|
|
offset += length;
|
2007-10-05 16:30:55 +02:00
|
|
|
|
|
|
|
offset = FB_ALIGN(offset, sizeof(short));
|
2007-10-06 12:22:32 +02:00
|
|
|
var->sqlind = (short*) (&Buffer[offset]);
|
|
|
|
offset += sizeof (short);
|
|
|
|
}
|
2007-10-06 21:08:50 +02:00
|
|
|
|
2007-10-06 12:22:32 +02:00
|
|
|
return offset;
|
2004-03-11 05:31:04 +01:00
|
|
|
}
|
|
|
|
|
2007-02-27 03:36:20 +01:00
|
|
|
void ExecuteStatement::getString(thread_db* tdbb, Firebird::string& s, const dsc* d, const jrd_req* r)
|
2004-03-28 11:10:30 +02:00
|
|
|
{
|
2007-02-27 03:36:20 +01:00
|
|
|
MoveBuffer buffer;
|
2004-03-20 15:57:40 +01:00
|
|
|
|
|
|
|
UCHAR* p = 0;
|
|
|
|
const SSHORT l = (d && !(r->req_flags & req_null)) ?
|
2007-02-27 03:36:20 +01:00
|
|
|
MOV_make_string2(tdbb, d, d->getTextType(), &p, buffer) : 0; // !!! How call Msgs ?
|
2004-03-20 15:57:40 +01:00
|
|
|
if (! p) {
|
|
|
|
ERR_post(isc_exec_sql_invalid_arg, 0);
|
|
|
|
}
|
|
|
|
|
2004-03-28 11:10:30 +02:00
|
|
|
s.assign((const char*)p, l);
|
2004-03-20 15:57:40 +01:00
|
|
|
}
|
2007-10-06 12:22:32 +02:00
|
|
|
|