8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-25 01:23:03 +01:00
firebird-mirror/src/dsql/utld.cpp

1088 lines
24 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: Dynamic SQL runtime support
2003-10-05 08:37:26 +02:00
* MODULE: utld.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Utility routines for DSQL
*
* The contents of this file are subject to the Interbase 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.Inprise.com/IPL.html
*
* 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.
*
* The Original Code was created by Inprise Corporation
* and its predecessors. Portions created by Inprise Corporation are
* Copyright (C) Inprise Corporation.
*
* All Rights Reserved.
* Contributor(s): ______________________________________.
2002-06-29 08:56:51 +02:00
*
2008-09-11 08:49:27 +02:00
* 21 Nov 01 - Ann Harrison - Turn off the code in parse_sqlda that
2002-06-29 08:56:51 +02:00
* decides that two statements are the same based on their message
* descriptions because it misleads some code in remote/interface.c
* and causes problems when two statements are prepared.
2002-10-30 07:40:58 +01:00
*
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
*
2001-05-23 15:26:42 +02:00
*/
2002-06-29 08:56:51 +02:00
2001-05-23 15:26:42 +02:00
#include "firebird.h"
2004-04-29 00:00:03 +02:00
#include <stdio.h>
2001-05-23 15:26:42 +02:00
#include <string.h>
#include "../dsql/dsql.h"
#include "../dsql/sqlda.h"
2003-11-08 00:27:24 +01:00
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/align.h"
#include "../jrd/constants.h"
2001-05-23 15:26:42 +02:00
#include "../dsql/utld_proto.h"
#include "../jrd/gds_proto.h"
2008-01-16 07:52:43 +01:00
#if !defined(SUPERCLIENT)
#include "../dsql/metd_proto.h"
#endif
2008-02-03 15:27:13 +01:00
#include "../common/classes/init.h"
2008-02-28 14:48:16 +01:00
using namespace Jrd;
2001-05-23 15:26:42 +02:00
static void cleanup(void *);
2003-04-10 08:32:58 +02:00
static ISC_STATUS error_dsql_804(ISC_STATUS *, ISC_STATUS);
static SLONG get_numeric_info(const SCHAR**);
2008-03-10 10:23:27 +01:00
static SSHORT get_string_info(const SCHAR**, SCHAR*, int);
#ifdef NOT_USED_OR_REPLACED
2001-05-23 15:26:42 +02:00
#ifdef DEV_BUILD
static void print_xsqlda(XSQLDA *);
#endif
#endif
2007-10-27 09:03:25 +02:00
static void sqlvar_to_xsqlvar(const SQLVAR*, XSQLVAR*);
static void xsqlvar_to_sqlvar(const XSQLVAR*, SQLVAR*);
2001-05-23 15:26:42 +02:00
static inline void ch_stuff(BLOB_PTR*& p, const UCHAR value, bool& same_flag)
2003-10-05 08:37:26 +02:00
{
2008-09-11 08:49:27 +02:00
if (*p == value)
p++;
2003-10-01 20:11:23 +02:00
else {
*p++ = value;
same_flag = false;
}
}
static inline void ch_stuff_word(BLOB_PTR*& p, const USHORT value, bool& same_flag)
2003-10-05 08:37:26 +02:00
{
ch_stuff(p, value & 255, same_flag);
ch_stuff(p, value >> 8, same_flag);
2003-10-01 20:11:23 +02:00
}
2001-05-23 15:26:42 +02:00
2009-04-19 12:05:22 +02:00
// these statics define a round-robin data area for storing
// textual error messages returned to the user
2001-05-23 15:26:42 +02:00
2008-02-03 15:27:13 +01:00
static Firebird::GlobalPtr<Firebird::Mutex> failuresMutex;
2001-05-23 15:26:42 +02:00
static TEXT *DSQL_failures, *DSQL_failures_ptr;
2003-09-28 02:36:28 +02:00
const int DSQL_FAILURE_SPACE = 2048;
2001-05-23 15:26:42 +02:00
/**
2008-09-11 08:49:27 +02:00
Parse response on isc_info_sql_select or isc_info_sql_bind
request. Return pointer to the next byte after successfully
parsed info or NULL if error is encountered or info is truncated
**/
SCHAR* UTLD_skip_sql_info(SCHAR* info)
{
if (*info != isc_info_sql_select &&
*info != isc_info_sql_bind)
{
return 0;
}
info++;
if (*info++ != isc_info_sql_describe_vars)
return 0;
2008-03-10 10:23:27 +01:00
get_numeric_info((const SCHAR**) &info); // skip message->msg_index
// Loop over the variables being described
while (true)
{
SCHAR str[256]; // must be big enough to hold metadata name
2008-03-10 10:23:27 +01:00
const UCHAR item = *info++;
switch (item)
{
case isc_info_end:
return info;
case isc_info_truncated:
return 0;
case isc_info_sql_select:
case isc_info_sql_bind:
return --info;
case isc_info_sql_describe_end:
break;
case isc_info_sql_sqlda_seq:
case isc_info_sql_type:
case isc_info_sql_sub_type:
case isc_info_sql_scale:
case isc_info_sql_length:
get_numeric_info((const SCHAR**) &info);
break;
case isc_info_sql_field:
case isc_info_sql_relation:
case isc_info_sql_owner:
case isc_info_sql_alias:
get_string_info((const SCHAR**) &info, str, sizeof(str));
break;
default:
return 0;
}
}
return 0;
}
2001-05-23 15:26:42 +02:00
/**
UTLD_char_length_to_byte_length
2008-09-11 08:49:27 +02:00
@brief Return max byte length necessary for a specified character length string
2008-09-11 08:49:27 +02:00
@param lengthInChars
@param maxBytesPerChar
2008-09-11 08:49:27 +02:00
**/
USHORT UTLD_char_length_to_byte_length(USHORT lengthInChars, USHORT maxBytesPerChar)
{
return MIN(((MAX_COLUMN_SIZE - sizeof(USHORT)) / maxBytesPerChar) * maxBytesPerChar,
2009-04-19 12:05:22 +02:00
(ULONG) lengthInChars * maxBytesPerChar);
}
ISC_STATUS UTLD_copy_status(const ISC_STATUS* from, ISC_STATUS* to)
{
/**************************************
*
* c o p y _ s t a t u s
*
**************************************
*
* Functional description
* Copy a status vector.
*
**************************************/
const ISC_STATUS status = from[1];
const ISC_STATUS* const end = from + ISC_STATUS_LENGTH;
while (from < end)
*to++ = *from++;
return status;
}
/**
2008-09-11 08:49:27 +02:00
UTLD_parse_sql_info
2008-09-11 08:49:27 +02:00
@brief Fill in an SQLDA using data returned
by a call to isc_dsql_sql_info.
2008-09-11 08:49:27 +02:00
@param status
@param dialect
@param info
@param xsqlda
@param return_index
**/
2009-01-08 10:26:06 +01:00
ISC_STATUS UTLD_parse_sql_info(ISC_STATUS* status,
USHORT dialect,
const SCHAR* info,
XSQLDA* xsqlda,
USHORT* return_index)
2001-05-23 15:26:42 +02:00
{
XSQLVAR *xvar, xsqlvar;
2004-02-02 12:02:12 +01:00
SQLDA* sqlda;
2001-05-23 15:26:42 +02:00
if (return_index)
2003-08-13 13:08:50 +02:00
*return_index = 0;
2001-05-23 15:26:42 +02:00
if (!xsqlda)
return 0;
2009-04-19 12:05:22 +02:00
// The first byte of the returned buffer is assumed to be either a
// isc_info_sql_select or isc_info_sql_bind item. The second byte
// is assumed to be isc_info_sql_describe_vars.
2001-05-23 15:26:42 +02:00
info += 2;
const SSHORT n = static_cast<SSHORT>(get_numeric_info(&info));
2001-05-23 15:26:42 +02:00
if (dialect >= DIALECT_xsqlda)
{
2009-01-29 21:36:29 +01:00
if (xsqlda->version != SQLDA_VERSION1)
2003-11-08 00:27:24 +01:00
return error_dsql_804(status, isc_dsql_sqlda_err);
2001-05-23 15:26:42 +02:00
xsqlda->sqld = n;
2008-09-11 08:49:27 +02:00
// If necessary, inform the application that more sqlda items are needed
2001-05-23 15:26:42 +02:00
if (xsqlda->sqld > xsqlda->sqln)
return 0;
}
else
{
sqlda = (SQLDA *) xsqlda;
sqlda->sqld = n;
2008-09-11 08:49:27 +02:00
// If necessary, inform the application that more sqlda items are needed
2001-05-23 15:26:42 +02:00
if (sqlda->sqld > sqlda->sqln)
return 0;
xsqlda = NULL;
xvar = &xsqlvar;
}
2009-04-19 12:05:22 +02:00
// Loop over the variables being described.
2001-05-23 15:26:42 +02:00
2008-09-15 01:17:58 +02:00
SQLVAR* qvar = NULL;
2008-09-11 08:49:27 +02:00
USHORT last_index = 0;
2003-08-13 13:08:50 +02:00
USHORT index = 0;
2008-09-11 08:49:27 +02:00
2003-11-08 00:27:24 +01:00
while (*info != isc_info_end)
2001-05-23 15:26:42 +02:00
{
2003-08-19 12:25:21 +02:00
SCHAR item;
2003-11-08 00:27:24 +01:00
while ((item = *info++) != isc_info_sql_describe_end)
2001-05-23 15:26:42 +02:00
switch (item)
{
2003-11-08 00:27:24 +01:00
case isc_info_sql_sqlda_seq:
2001-05-23 15:26:42 +02:00
index = static_cast<USHORT>(get_numeric_info(&info));
if (xsqlda)
xvar = xsqlda->sqlvar + index - 1;
else
{
2004-02-02 12:02:12 +01:00
qvar = sqlda->sqlvar + index - 1;
2001-05-23 15:26:42 +02:00
memset(xvar, 0, sizeof(XSQLVAR));
}
break;
2003-11-08 00:27:24 +01:00
case isc_info_sql_type:
2009-01-05 09:48:32 +01:00
xvar->sqltype = static_cast<SSHORT>(get_numeric_info(&info));
2001-05-23 15:26:42 +02:00
break;
2003-11-08 00:27:24 +01:00
case isc_info_sql_sub_type:
2009-01-05 09:48:32 +01:00
xvar->sqlsubtype = static_cast<SSHORT>(get_numeric_info(&info));
2001-05-23 15:26:42 +02:00
break;
2003-11-08 00:27:24 +01:00
case isc_info_sql_scale:
2009-01-05 09:48:32 +01:00
xvar->sqlscale = static_cast<SSHORT>(get_numeric_info(&info));
2001-05-23 15:26:42 +02:00
break;
2003-11-08 00:27:24 +01:00
case isc_info_sql_length:
2009-01-05 09:48:32 +01:00
xvar->sqllen = static_cast<SSHORT>(get_numeric_info(&info));
2001-05-23 15:26:42 +02:00
break;
2003-11-08 00:27:24 +01:00
case isc_info_sql_field:
2009-01-05 09:48:32 +01:00
xvar->sqlname_length = get_string_info(&info, xvar->sqlname, sizeof(xvar->sqlname));
2001-05-23 15:26:42 +02:00
break;
2003-11-08 00:27:24 +01:00
case isc_info_sql_relation:
2009-01-05 09:48:32 +01:00
xvar->relname_length = get_string_info(&info, xvar->relname, sizeof(xvar->relname));
2001-05-23 15:26:42 +02:00
break;
2003-11-08 00:27:24 +01:00
case isc_info_sql_owner:
2009-01-05 09:48:32 +01:00
xvar->ownname_length = get_string_info(&info, xvar->ownname, sizeof(xvar->ownname));
2001-05-23 15:26:42 +02:00
break;
2003-11-08 00:27:24 +01:00
case isc_info_sql_alias:
2001-05-23 15:26:42 +02:00
xvar->aliasname_length =
2008-03-10 10:23:27 +01:00
get_string_info(&info, xvar->aliasname, sizeof(xvar->aliasname));
2001-05-23 15:26:42 +02:00
break;
2003-11-08 00:27:24 +01:00
case isc_info_truncated:
2001-05-23 15:26:42 +02:00
if (return_index)
*return_index = last_index;
default:
2003-11-08 00:27:24 +01:00
return error_dsql_804(status, isc_dsql_sqlda_err);
2001-05-23 15:26:42 +02:00
}
if (!xsqlda)
2004-02-02 12:02:12 +01:00
xsqlvar_to_sqlvar(xvar, qvar);
2001-05-23 15:26:42 +02:00
if (index > last_index)
last_index = index;
}
2003-11-08 00:27:24 +01:00
if (*info != isc_info_end)
return error_dsql_804(status, isc_dsql_sqlda_err);
2001-05-23 15:26:42 +02:00
return FB_SUCCESS;
2001-05-23 15:26:42 +02:00
}
/**
2008-09-11 08:49:27 +02:00
UTLD_parse_sqlda
2008-09-11 08:49:27 +02:00
@brief This routine creates a blr message that describes
a SQLDA as well as moving data from the SQLDA
into a message buffer or from the message buffer
into the SQLDA.
2008-09-11 08:49:27 +02:00
@param status
@param dasup
@param blr_length
@param msg_type
@param msg_length
@param dialect
@param xsqlda
@param clause
**/
2009-01-08 10:26:06 +01:00
ISC_STATUS UTLD_parse_sqlda(ISC_STATUS* status,
sqlda_sup* const dasup,
USHORT* blr_length,
USHORT* msg_type,
USHORT* msg_length,
USHORT dialect,
const XSQLDA* xsqlda,
const USHORT clause)
2001-05-23 15:26:42 +02:00
{
2004-12-12 02:58:43 +01:00
USHORT n;
XSQLVAR xsqlvar;
const XSQLVAR* xvar = &xsqlvar;
const SQLVAR* qvar;
const SQLDA* sqlda = NULL;
2001-05-23 15:26:42 +02:00
if (!xsqlda)
n = 0;
else
if (dialect >= DIALECT_xsqlda)
{
2009-01-29 21:36:29 +01:00
if (xsqlda->version != SQLDA_VERSION1)
2003-11-08 00:27:24 +01:00
return error_dsql_804(status, isc_dsql_sqlda_err);
2001-05-23 15:26:42 +02:00
n = xsqlda->sqld;
}
else
{
2008-09-15 01:17:58 +02:00
sqlda = reinterpret_cast<const SQLDA*>(xsqlda);
2001-05-23 15:26:42 +02:00
n = sqlda->sqld;
xsqlda = NULL;
}
2004-02-02 12:02:12 +01:00
sqlda_sup::dasup_clause* const pClause = &dasup->dasup_clauses[clause];
2001-05-23 15:26:42 +02:00
if (!n)
{
2008-09-11 08:49:27 +02:00
// If there isn't an SQLDA, don't bother with anything else.
2001-05-23 15:26:42 +02:00
if (blr_length)
2004-02-02 12:02:12 +01:00
*blr_length = pClause->dasup_blr_length = 0;
2001-05-23 15:26:42 +02:00
if (msg_length)
*msg_length = 0;
if (msg_type)
*msg_type = 0;
return 0;
}
if (msg_length)
{
2009-04-19 12:05:22 +02:00
// This is a call from execute or open, or the first call from fetch.
// Determine the size of the blr, allocate a blr buffer, create the
// blr, and finally allocate a message buffer.
2001-05-23 15:26:42 +02:00
2009-04-19 12:05:22 +02:00
// The message buffer we are describing could be for a message to
// either IB 4.0 or IB 3.3 - thus we need to describe the buffer
// with the right set of blr.
// As the BLR is only used to describe space allocation and alignment,
// we can safely use blr_text for both 4.0 and 3.3.
2001-05-23 15:26:42 +02:00
2009-04-19 12:05:22 +02:00
// Make a quick pass through the SQLDA to determine the amount of
// blr that will be generated.
2001-05-23 15:26:42 +02:00
2004-12-12 02:58:43 +01:00
USHORT blr_len = 8;
USHORT par_count = 0;
2001-05-23 15:26:42 +02:00
if (xsqlda)
xvar = xsqlda->sqlvar - 1;
else
2004-02-02 12:02:12 +01:00
qvar = sqlda->sqlvar - 1;
2008-03-10 10:23:27 +01:00
2009-06-27 08:23:36 +02:00
for (USHORT i = 0; i < n; i++)
2001-05-23 15:26:42 +02:00
{
if (xsqlda)
++xvar;
else
sqlvar_to_xsqlvar(++qvar, &xsqlvar);
2008-03-10 10:23:27 +01:00
2004-12-12 02:58:43 +01:00
const USHORT dtype = xvar->sqltype & ~1;
2008-03-10 10:23:27 +01:00
switch (dtype)
{
case SQL_VARYING:
case SQL_TEXT:
case SQL_NULL:
2001-05-23 15:26:42 +02:00
blr_len += 3;
2008-03-10 10:23:27 +01:00
break;
case SQL_SHORT:
case SQL_LONG:
case SQL_INT64:
case SQL_QUAD:
case SQL_BLOB:
case SQL_ARRAY:
blr_len += 2;
break;
default:
++blr_len;
}
2008-09-11 08:49:27 +02:00
2001-05-23 15:26:42 +02:00
blr_len += 2;
par_count += 2;
}
2009-04-19 12:05:22 +02:00
// Make sure the blr buffer is large enough. If it isn't, allocate
// a new one.
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
if (blr_len > pClause->dasup_blr_buf_len)
2001-05-23 15:26:42 +02:00
{
2004-02-02 12:02:12 +01:00
if (pClause->dasup_blr) {
gds__free(pClause->dasup_blr);
2001-05-23 15:26:42 +02:00
}
2009-01-07 10:30:57 +01:00
pClause->dasup_blr = static_cast<char*>(gds__alloc((SLONG) blr_len));
2003-08-13 13:08:50 +02:00
// FREE: unknown
2004-02-02 12:02:12 +01:00
if (!pClause->dasup_blr) // NOMEM:
2003-11-08 00:27:24 +01:00
return error_dsql_804(status, isc_virmemexh);
2004-02-02 12:02:12 +01:00
pClause->dasup_blr_buf_len = blr_len;
pClause->dasup_blr_length = 0;
2001-05-23 15:26:42 +02:00
}
memset(pClause->dasup_blr, 0, blr_len);
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
bool same_flag = (blr_len == pClause->dasup_blr_length);
2002-06-29 08:56:51 +02:00
2009-04-19 12:05:22 +02:00
// turn off same_flag because it breaks execute & execute2 when
// more than one statement is prepared
2002-06-29 08:56:51 +02:00
2003-10-01 20:11:23 +02:00
same_flag = false;
2002-06-29 08:56:51 +02:00
2004-02-02 12:02:12 +01:00
pClause->dasup_blr_length = blr_len;
2001-05-23 15:26:42 +02:00
2009-04-19 12:05:22 +02:00
// Generate the blr for the message and at the same time, determine
// the size of the message buffer. Allow for a null indicator with
// each variable in the SQLDA.
2001-05-23 15:26:42 +02:00
2003-08-13 13:08:50 +02:00
// one huge pointer per line for LIBS
2004-02-02 12:02:12 +01:00
BLOB_PTR* p = reinterpret_cast<UCHAR*>(pClause->dasup_blr);
2003-08-13 13:08:50 +02:00
2009-04-19 12:05:22 +02:00
// The define SQL_DIALECT_V5 is not available here, Hence using
// constant 1.
2002-06-29 08:56:51 +02:00
if (dialect > 1) {
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_version5, same_flag);
}
else {
2003-10-05 08:37:26 +02:00
ch_stuff(p, blr_version4, same_flag);
2003-10-01 20:11:23 +02:00
}
2003-10-05 08:37:26 +02:00
//else if ((SCHAR) *(p) == (SCHAR) (blr_version4)) {
2008-09-11 08:49:27 +02:00
// (p)++;
2003-10-05 08:37:26 +02:00
//}
//else {
2008-09-11 08:49:27 +02:00
// *(p)++ = (blr_version4);
2003-10-05 08:37:26 +02:00
// same_flag = false;
//}
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_begin, same_flag);
ch_stuff(p, blr_message, same_flag);
ch_stuff(p, 0, same_flag);
ch_stuff_word(p, par_count, same_flag);
2004-12-12 02:58:43 +01:00
USHORT msg_len = 0;
2001-05-23 15:26:42 +02:00
if (xsqlda)
xvar = xsqlda->sqlvar - 1;
else
2004-02-02 12:02:12 +01:00
qvar = sqlda->sqlvar - 1;
2009-06-27 08:23:36 +02:00
for (USHORT i = 0; i < n; i++)
2001-05-23 15:26:42 +02:00
{
if (xsqlda)
++xvar;
2001-05-23 15:26:42 +02:00
else
sqlvar_to_xsqlvar(++qvar, &xsqlvar);
2004-12-12 02:58:43 +01:00
USHORT dtype = xvar->sqltype & ~1;
USHORT len = xvar->sqllen;
2001-05-23 15:26:42 +02:00
switch (dtype)
{
case SQL_VARYING:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_varying, same_flag);
ch_stuff_word(p, len, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_varying;
len += sizeof(USHORT);
break;
case SQL_TEXT:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_text, same_flag);
ch_stuff_word(p, len, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_text;
break;
case SQL_DOUBLE:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_double, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_double;
break;
case SQL_FLOAT:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_float, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_real;
break;
case SQL_D_FLOAT:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_d_float, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_d_float;
break;
case SQL_TYPE_DATE:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_sql_date, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_sql_date;
break;
case SQL_TYPE_TIME:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_sql_time, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_sql_time;
break;
case SQL_TIMESTAMP:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_timestamp, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_timestamp;
break;
case SQL_BLOB:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_quad, same_flag);
ch_stuff(p, 0, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_blob;
break;
case SQL_ARRAY:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_quad, same_flag);
ch_stuff(p, 0, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_array;
break;
case SQL_LONG:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_long, same_flag);
ch_stuff(p, xvar->sqlscale, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_long;
break;
case SQL_SHORT:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_short, same_flag);
ch_stuff(p, xvar->sqlscale, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_short;
break;
case SQL_INT64:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_int64, same_flag);
ch_stuff(p, xvar->sqlscale, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_int64;
break;
case SQL_QUAD:
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_quad, same_flag);
ch_stuff(p, xvar->sqlscale, same_flag);
2001-05-23 15:26:42 +02:00
dtype = dtype_quad;
break;
case SQL_NULL:
ch_stuff(p, blr_text, same_flag);
ch_stuff_word(p, len, same_flag);
dtype = dtype_text;
break;
2001-05-23 15:26:42 +02:00
default:
2003-11-08 00:27:24 +01:00
return error_dsql_804(status, isc_dsql_sqlda_value_err);
2001-05-23 15:26:42 +02:00
}
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_short, same_flag);
ch_stuff(p, 0, same_flag);
2001-05-23 15:26:42 +02:00
2004-12-12 02:58:43 +01:00
USHORT align = type_alignments[dtype];
2001-05-23 15:26:42 +02:00
if (align)
msg_len = FB_ALIGN(msg_len, align);
msg_len += len;
align = type_alignments[dtype_short];
if (align)
msg_len = FB_ALIGN(msg_len, align);
msg_len += sizeof(SSHORT);
}
2003-10-01 20:11:23 +02:00
ch_stuff(p, blr_end, same_flag);
ch_stuff(p, blr_eoc, same_flag);
2001-05-23 15:26:42 +02:00
2009-04-19 12:05:22 +02:00
// Make sure the message buffer is large enough. If it isn't, allocate
// a new one.
2001-05-23 15:26:42 +02:00
2004-02-02 12:02:12 +01:00
if (msg_len > pClause->dasup_msg_buf_len)
2001-05-23 15:26:42 +02:00
{
2004-02-02 12:02:12 +01:00
if (pClause->dasup_msg)
gds__free(pClause->dasup_msg);
2009-01-07 10:30:57 +01:00
pClause->dasup_msg = static_cast<char*>(gds__alloc((SLONG) msg_len));
2003-08-13 13:08:50 +02:00
// FREE: unknown
2004-02-02 12:02:12 +01:00
if (!pClause->dasup_msg) // NOMEM:
2003-11-08 00:27:24 +01:00
return error_dsql_804(status, isc_virmemexh);
2004-02-02 12:02:12 +01:00
pClause->dasup_msg_buf_len = msg_len;
2001-05-23 15:26:42 +02:00
}
memset(pClause->dasup_msg, 0, msg_len);
2001-05-23 15:26:42 +02:00
2003-08-13 13:08:50 +02:00
// Fill in the return values to the caller.
2001-05-23 15:26:42 +02:00
2009-02-28 12:57:40 +01:00
*blr_length = same_flag ? 0 : blr_len;
2001-05-23 15:26:42 +02:00
*msg_length = msg_len;
*msg_type = 0;
2003-08-13 13:08:50 +02:00
// If this is the first call from fetch, we're done.
2001-05-23 15:26:42 +02:00
if (clause == DASUP_CLAUSE_select)
return 0;
}
2009-04-19 12:05:22 +02:00
// Move the data between the SQLDA and the message buffer.
2001-05-23 15:26:42 +02:00
2003-08-13 13:08:50 +02:00
USHORT offset = 0;
// one huge pointer per line for LIBS
2009-01-05 09:48:32 +01:00
BLOB_PTR* msg_buf = reinterpret_cast<UCHAR*>(pClause->dasup_msg);
2001-05-23 15:26:42 +02:00
if (xsqlda)
xvar = xsqlda->sqlvar - 1;
else
2004-02-02 12:02:12 +01:00
qvar = sqlda->sqlvar - 1;
2009-06-27 08:23:36 +02:00
for (USHORT i = 0; i < n; i++)
2001-05-23 15:26:42 +02:00
{
if (xsqlda)
++xvar;
2001-05-23 15:26:42 +02:00
else
sqlvar_to_xsqlvar(++qvar, &xsqlvar);
2004-12-12 02:58:43 +01:00
USHORT dtype = xvar->sqltype & ~1;
USHORT len = xvar->sqllen;
2001-05-23 15:26:42 +02:00
switch (dtype)
{
case SQL_VARYING:
dtype = dtype_varying;
len += sizeof(USHORT);
break;
case SQL_TEXT:
dtype = dtype_text;
break;
case SQL_DOUBLE:
dtype = dtype_double;
break;
case SQL_FLOAT:
dtype = dtype_real;
break;
case SQL_D_FLOAT:
dtype = dtype_d_float;
break;
case SQL_TYPE_DATE:
dtype = dtype_sql_date;
break;
case SQL_TYPE_TIME:
dtype = dtype_sql_time;
break;
case SQL_TIMESTAMP:
dtype = dtype_timestamp;
break;
case SQL_BLOB:
dtype = dtype_blob;
break;
case SQL_ARRAY:
dtype = dtype_array;
break;
case SQL_LONG:
dtype = dtype_long;
break;
case SQL_SHORT:
dtype = dtype_short;
break;
case SQL_INT64:
dtype = dtype_int64;
break;
case SQL_QUAD:
dtype = dtype_quad;
break;
case SQL_NULL:
dtype = dtype_text;
break;
2001-05-23 15:26:42 +02:00
}
2004-12-12 02:58:43 +01:00
USHORT align = type_alignments[dtype];
2001-05-23 15:26:42 +02:00
if (align)
offset = FB_ALIGN(offset, align);
2004-12-12 02:58:43 +01:00
USHORT null_offset = offset + len;
2001-05-23 15:26:42 +02:00
align = type_alignments[dtype_short];
if (align)
null_offset = FB_ALIGN(null_offset, align);
2003-08-13 13:08:50 +02:00
SSHORT *null_ind = (SSHORT *) (msg_buf + null_offset);
2001-05-23 15:26:42 +02:00
if (clause == DASUP_CLAUSE_select)
{
2008-09-11 08:49:27 +02:00
// Move data from the message into the SQLDA.
2001-05-23 15:26:42 +02:00
if ((xvar->sqltype & ~1) != SQL_NULL)
{
// Make sure user has specified a data location
if (!xvar->sqldata)
return error_dsql_804(status, isc_dsql_sqlda_value_err);
memcpy(xvar->sqldata, msg_buf + offset, len);
}
2001-05-23 15:26:42 +02:00
if (xvar->sqltype & 1)
{
2008-09-11 08:49:27 +02:00
// Make sure user has specified a location for null indicator
2001-05-23 15:26:42 +02:00
if (!xvar->sqlind)
2003-11-08 00:27:24 +01:00
return error_dsql_804(status, isc_dsql_sqlda_value_err);
2001-05-23 15:26:42 +02:00
*xvar->sqlind = *null_ind;
}
}
else
{
2009-04-19 12:05:22 +02:00
// Move data from the SQLDA into the message. If the
// indicator variable identifies a null value, permit
// the data value to be missing.
2001-05-23 15:26:42 +02:00
if (xvar->sqltype & 1)
{
2008-09-11 08:49:27 +02:00
// Make sure user has specified a location for null indicator
2001-05-23 15:26:42 +02:00
if (!xvar->sqlind)
2003-11-08 00:27:24 +01:00
return error_dsql_804(status, isc_dsql_sqlda_value_err);
2001-05-23 15:26:42 +02:00
*null_ind = *xvar->sqlind;
}
else
*null_ind = 0;
2008-09-11 08:49:27 +02:00
// Make sure user has specified a data location (unless NULL)
if (!xvar->sqldata && !*null_ind && (xvar->sqltype & ~1) != SQL_NULL)
2003-11-08 00:27:24 +01:00
return error_dsql_804(status, isc_dsql_sqlda_value_err);
2001-05-23 15:26:42 +02:00
2008-09-11 08:49:27 +02:00
// Copy data - unless known to be NULL
2004-02-02 12:02:12 +01:00
if ((offset + len) > pClause->dasup_msg_buf_len)
2003-11-08 00:27:24 +01:00
return error_dsql_804(status, isc_dsql_sqlda_value_err);
2001-05-23 15:26:42 +02:00
if (!*null_ind)
memcpy(msg_buf + offset, xvar->sqldata, len);
}
offset = null_offset + sizeof(SSHORT);
}
return 0;
}
/**
2008-09-11 08:49:27 +02:00
UTLD_save_status_strings
2008-09-11 08:49:27 +02:00
@brief Strings in status vectors may be stored in stack variables
or memory pools that are transient. To perserve the information,
copy any included strings to a special buffer.
2008-09-11 08:49:27 +02:00
@param vector
**/
2004-09-24 08:48:24 +02:00
void UTLD_save_status_strings(ISC_STATUS* vector)
2001-05-23 15:26:42 +02:00
{
2008-02-03 15:27:13 +01:00
Firebird::MutexLockGuard guard(failuresMutex);
// allocate space for failure strings if it hasn't already been allocated
2001-05-23 15:26:42 +02:00
if (!DSQL_failures)
{
2009-01-07 10:30:57 +01:00
DSQL_failures = (TEXT*) gds__alloc((SLONG) DSQL_FAILURE_SPACE);
2008-09-11 08:49:27 +02:00
// FREE: by exit handler cleanup()
if (!DSQL_failures) // NOMEM: don't try to copy the strings
2001-05-23 15:26:42 +02:00
return;
DSQL_failures_ptr = DSQL_failures;
gds__register_cleanup(cleanup, 0);
#ifdef DEBUG_GDS_ALLOC
2009-01-07 10:30:57 +01:00
gds_alloc_flag_unfreed((void*) DSQL_failures);
2001-05-23 15:26:42 +02:00
#endif
}
while (*vector)
{
2004-09-24 08:48:24 +02:00
const TEXT* p;
USHORT l;
const ISC_STATUS status = *vector++;
2001-05-23 15:26:42 +02:00
switch (status)
{
2003-11-08 00:27:24 +01:00
case isc_arg_cstring:
2001-05-23 15:26:42 +02:00
l = static_cast<USHORT>(*vector++);
2003-11-08 00:27:24 +01:00
case isc_arg_string:
case isc_arg_interpreted:
case isc_arg_sql_state:
2008-02-26 03:23:28 +01:00
p = (TEXT*) *vector;
2008-02-03 15:27:13 +01:00
2003-11-08 00:27:24 +01:00
if (status != isc_arg_cstring)
2001-05-23 15:26:42 +02:00
l = strlen(p) + 1;
2009-04-19 12:05:22 +02:00
// If there isn't any more room in the buffer,
// start at the beginning again
2001-05-23 15:26:42 +02:00
if (DSQL_failures_ptr + l > DSQL_failures + DSQL_FAILURE_SPACE)
DSQL_failures_ptr = DSQL_failures;
2008-02-03 15:27:13 +01:00
2003-04-10 08:32:58 +02:00
*vector++ = (ISC_STATUS) DSQL_failures_ptr;
2008-02-03 15:27:13 +01:00
2001-05-23 15:26:42 +02:00
if (l)
2008-02-03 15:27:13 +01:00
{
2001-05-23 15:26:42 +02:00
do
2008-02-03 15:27:13 +01:00
{
2001-05-23 15:26:42 +02:00
*DSQL_failures_ptr++ = *p++;
2008-02-03 15:27:13 +01:00
} while (--l && (DSQL_failures_ptr < DSQL_failures + DSQL_FAILURE_SPACE));
}
2001-05-23 15:26:42 +02:00
if (l)
*(DSQL_failures_ptr - 1) = '\0';
2008-02-03 15:27:13 +01:00
2001-05-23 15:26:42 +02:00
break;
default:
++vector;
break;
}
}
}
/**
2008-09-11 08:49:27 +02:00
cleanup
2008-09-11 08:49:27 +02:00
@brief Exit handler to cleanup dynamically allocated memory.
2008-09-11 08:49:27 +02:00
@param arg
**/
2009-04-26 12:24:44 +02:00
static void cleanup(void*)
2001-05-23 15:26:42 +02:00
{
2008-02-03 15:27:13 +01:00
Firebird::MutexLockGuard guard(failuresMutex);
2001-05-23 15:26:42 +02:00
if (DSQL_failures)
gds__free(DSQL_failures);
2001-05-23 15:26:42 +02:00
gds__unregister_cleanup(cleanup, 0);
DSQL_failures = NULL;
}
/**
2008-09-11 08:49:27 +02:00
error_dsql_804
2008-09-11 08:49:27 +02:00
@brief Move a DSQL -804 error message into a status vector.
2008-09-11 08:49:27 +02:00
@param status
@param err
**/
2003-04-10 08:32:58 +02:00
static ISC_STATUS error_dsql_804( ISC_STATUS * status, ISC_STATUS err)
2001-05-23 15:26:42 +02:00
{
2003-08-13 13:08:50 +02:00
ISC_STATUS *p = status;
2001-05-23 15:26:42 +02:00
2003-11-08 00:27:24 +01:00
*p++ = isc_arg_gds;
*p++ = isc_dsql_error;
*p++ = isc_arg_gds;
*p++ = isc_sqlerr;
*p++ = isc_arg_number;
2001-05-23 15:26:42 +02:00
*p++ = -804;
2003-11-08 00:27:24 +01:00
*p++ = isc_arg_gds;
2008-09-11 08:49:27 +02:00
*p++ = err;
2003-11-08 00:27:24 +01:00
*p = isc_arg_end;
2001-05-23 15:26:42 +02:00
return status[1];
}
/**
2008-09-11 08:49:27 +02:00
get_numeric_info
2008-09-11 08:49:27 +02:00
@brief Pick up a VAX format numeric info item
with a 2 byte length.
2008-09-11 08:49:27 +02:00
@param ptr
**/
2008-03-10 10:23:27 +01:00
static SLONG get_numeric_info(const SCHAR** ptr)
2001-05-23 15:26:42 +02:00
{
2009-01-05 09:48:32 +01:00
const SSHORT l = static_cast<SSHORT>(gds__vax_integer(reinterpret_cast<const UCHAR*>(*ptr), 2));
2001-05-23 15:26:42 +02:00
*ptr += 2;
int item = gds__vax_integer(reinterpret_cast<const UCHAR*>(*ptr), l);
2001-05-23 15:26:42 +02:00
*ptr += l;
return item;
}
/**
2008-09-11 08:49:27 +02:00
get_string_info
2008-09-11 08:49:27 +02:00
@brief Pick up a string valued info item and return
its length. The buffer_len argument is assumed
to include space for the terminating null.
2008-09-11 08:49:27 +02:00
@param ptr
@param buffer
@param buffer_len
**/
2008-03-10 10:23:27 +01:00
static SSHORT get_string_info(const SCHAR** ptr, SCHAR* buffer, int buffer_len)
2001-05-23 15:26:42 +02:00
{
const SCHAR* p = *ptr;
2008-03-10 10:23:27 +01:00
SSHORT len = static_cast<SSHORT>(gds__vax_integer(reinterpret_cast<const UCHAR*>(p), 2));
// CVC: What else can we do here?
if (len < 0)
len = 0;
2008-09-11 08:49:27 +02:00
2008-03-10 10:23:27 +01:00
*ptr += len + 2;
2001-05-23 15:26:42 +02:00
p += 2;
2008-03-10 10:23:27 +01:00
if (len >= buffer_len)
len = buffer_len - 1;
2001-05-23 15:26:42 +02:00
2003-08-13 13:08:50 +02:00
if (len)
2008-03-10 10:23:27 +01:00
memcpy(buffer, p, len);
buffer[len] = 0;
2001-05-23 15:26:42 +02:00
return len;
}
#ifdef NOT_USED_OR_REPLACED
2001-05-23 15:26:42 +02:00
#ifdef DEV_BUILD
static void print_xsqlda( XSQLDA * xsqlda)
{
/*****************************************
*
2008-09-11 08:49:27 +02:00
* p r i n t _ x s q l d a
2001-05-23 15:26:42 +02:00
*
*****************************************
*
* print an sqlda
*
*****************************************/
XSQLVAR *xvar, *end_var;
if (!xsqlda)
return;
2004-04-29 00:00:03 +02:00
printf("SQLDA Version %d\n", xsqlda->version);
printf(" sqldaid %.8s\n", xsqlda->sqldaid);
printf(" sqldabc %d\n", xsqlda->sqldabc);
printf(" sqln %d\n", xsqlda->sqln);
printf(" sqld %d\n", xsqlda->sqld);
2001-05-23 15:26:42 +02:00
xvar = xsqlda->sqlvar;
for (end_var = xvar + xsqlda->sqld; xvar < end_var; xvar++)
2004-04-29 00:00:03 +02:00
printf(" %.31s %.31s type: %d, scale %d, len %d subtype %d\n",
2001-05-23 15:26:42 +02:00
xvar->sqlname, xvar->relname, xvar->sqltype,
xvar->sqlscale, xvar->sqllen, xvar->sqlsubtype);
}
#endif
#endif
2001-05-23 15:26:42 +02:00
/**
2008-09-11 08:49:27 +02:00
sqlvar_to_xsqlvar
2008-09-11 08:49:27 +02:00
@param sqlvar
@param xsqlvar
@param sqlvar
@param xsqlvar
**/
2007-10-27 09:03:25 +02:00
static void sqlvar_to_xsqlvar(const SQLVAR* sqlvar, XSQLVAR* xsqlvar)
2001-05-23 15:26:42 +02:00
{
xsqlvar->sqltype = sqlvar->sqltype;
xsqlvar->sqldata = sqlvar->sqldata;
xsqlvar->sqlind = sqlvar->sqlind;
xsqlvar->sqlsubtype = 0;
xsqlvar->sqlscale = 0;
xsqlvar->sqllen = sqlvar->sqllen;
2007-10-27 09:03:25 +02:00
switch (xsqlvar->sqltype & ~1)
{
case SQL_LONG:
2001-05-23 15:26:42 +02:00
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
xsqlvar->sqllen = sizeof(SLONG);
2007-10-27 09:03:25 +02:00
break;
case SQL_SHORT:
2001-05-23 15:26:42 +02:00
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
xsqlvar->sqllen = sizeof(SSHORT);
2007-10-27 09:03:25 +02:00
break;
case SQL_INT64:
2001-05-23 15:26:42 +02:00
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
xsqlvar->sqllen = sizeof(SINT64);
2007-10-27 09:03:25 +02:00
break;
case SQL_QUAD:
2001-05-23 15:26:42 +02:00
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
xsqlvar->sqllen = sizeof(ISC_QUAD);
2007-10-27 09:03:25 +02:00
break;
2001-05-23 15:26:42 +02:00
}
}
/**
2008-09-11 08:49:27 +02:00
xsqlvar_to_sqlvar
2008-09-11 08:49:27 +02:00
@brief Move an XSQLVAR to an SQLVAR.
2008-09-11 08:49:27 +02:00
@param xsqlvar
@param sqlvar
**/
2007-10-27 09:03:25 +02:00
static void xsqlvar_to_sqlvar(const XSQLVAR* xsqlvar, SQLVAR* sqlvar)
2001-05-23 15:26:42 +02:00
{
sqlvar->sqltype = xsqlvar->sqltype;
sqlvar->sqlname_length = xsqlvar->aliasname_length;
2009-04-19 12:05:22 +02:00
// N.B., this may not NULL-terminate the name...
2001-05-23 15:26:42 +02:00
memcpy(sqlvar->sqlname, xsqlvar->aliasname, sizeof(sqlvar->sqlname));
sqlvar->sqllen = xsqlvar->sqllen;
2007-10-27 09:03:25 +02:00
const USHORT scale = xsqlvar->sqlscale << 8;
switch (sqlvar->sqltype & ~1)
{
case SQL_LONG:
sqlvar->sqllen = sizeof(SLONG) | scale;
break;
case SQL_SHORT:
sqlvar->sqllen = sizeof(SSHORT) | scale;
break;
case SQL_INT64:
sqlvar->sqllen = sizeof(SINT64) | scale;
break;
case SQL_QUAD:
sqlvar->sqllen = sizeof(ISC_QUAD) | scale;
break;
}
2001-05-23 15:26:42 +02:00
}
2008-01-16 07:52:43 +01:00
#if !defined(SUPERCLIENT)
UCHAR DSqlDataTypeUtil::maxBytesPerChar(UCHAR charSet)
{
return METD_get_charset_bpc(statement, charSet);
}
2007-10-28 17:00:53 +01:00
USHORT DSqlDataTypeUtil::getDialect() const
{
return statement->req_client_dialect;
}
#endif