2001-05-23 15:26:42 +02:00
|
|
|
/*
|
|
|
|
* PROGRAM: Dynamic SQL runtime support
|
|
|
|
* MODULE: utld.c
|
|
|
|
* 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
|
|
|
*
|
|
|
|
* 21 Nov 01 - Ann Harrison - Turn off the code in parse_sqlda that
|
|
|
|
* 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
|
|
|
/*
|
2003-09-21 01:28:38 +02:00
|
|
|
$Id: utld.cpp,v 1.15 2003-09-20 23:28:10 brodsom Exp $
|
2001-05-23 15:26:42 +02:00
|
|
|
*/
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "firebird.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/ib_stdio.h"
|
|
|
|
#include <string.h>
|
|
|
|
#include "../dsql/dsql.h"
|
|
|
|
#include "../dsql/sqlda.h"
|
|
|
|
#include "../jrd/blr.h"
|
2001-07-30 01:43:24 +02:00
|
|
|
#include "../jrd/gdsold.h"
|
2001-05-23 15:26:42 +02:00
|
|
|
#include "../jrd/inf.h"
|
|
|
|
#include "../jrd/align.h"
|
|
|
|
#include "../dsql/utld_proto.h"
|
|
|
|
#include "../jrd/gds_proto.h"
|
|
|
|
|
|
|
|
|
|
|
|
static void cleanup(void *);
|
2003-04-10 08:32:58 +02:00
|
|
|
static ISC_STATUS error_dsql_804(ISC_STATUS *, ISC_STATUS);
|
2001-05-23 15:26:42 +02:00
|
|
|
static SLONG get_numeric_info(SCHAR **);
|
|
|
|
static SLONG get_string_info(SCHAR **, SCHAR *, int);
|
2003-03-03 09:29:18 +01:00
|
|
|
#ifdef NOT_USED_OR_REPLACED
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef DEV_BUILD
|
|
|
|
static void print_xsqlda(XSQLDA *);
|
|
|
|
#endif
|
2003-03-03 09:29:18 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
static void sqlvar_to_xsqlvar(SQLVAR *, XSQLVAR *);
|
|
|
|
static void xsqlvar_to_sqlvar(XSQLVAR *, SQLVAR *);
|
|
|
|
|
|
|
|
#ifndef PRINTF
|
|
|
|
#define PRINTF ib_printf
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#define CH_STUFF(p,value) {if ((SCHAR) *(p) == (SCHAR) (value)) (p)++; else\
|
2003-08-19 12:25:21 +02:00
|
|
|
{*(p)++ = (value); same_flag = false;}}
|
2001-05-23 15:26:42 +02:00
|
|
|
#define CH_STUFF_WORD(p,value) {CH_STUFF (p, (value) & 255);\
|
|
|
|
CH_STUFF (p, (value) >> 8);}
|
|
|
|
|
|
|
|
/* these statics define a round-robin data area for storing
|
|
|
|
textual error messages returned to the user */
|
|
|
|
|
|
|
|
static TEXT *DSQL_failures, *DSQL_failures_ptr;
|
|
|
|
|
|
|
|
#define DSQL_FAILURE_SPACE 2048
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
UTLD_parse_sql_info
|
|
|
|
|
|
|
|
@brief Fill in an SQLDA using data returned
|
|
|
|
by a call to isc_dsql_sql_info.
|
|
|
|
|
|
|
|
|
|
|
|
@param status
|
|
|
|
@param dialect
|
|
|
|
@param info
|
|
|
|
@param xsqlda
|
|
|
|
@param return_index
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS DLL_EXPORT UTLD_parse_sql_info(
|
2003-08-13 13:08:50 +02:00
|
|
|
ISC_STATUS * status,
|
|
|
|
USHORT dialect,
|
|
|
|
SCHAR * info,
|
|
|
|
XSQLDA * xsqlda,
|
|
|
|
USHORT * return_index)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
XSQLVAR *xvar, xsqlvar;
|
|
|
|
SQLDA *sqlda;
|
|
|
|
SQLVAR *var;
|
2003-08-13 13:08:50 +02:00
|
|
|
USHORT last_index = 0;
|
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;
|
|
|
|
|
|
|
|
/* The first byte of the returned buffer is assumed to be either a
|
|
|
|
gds__info_sql_select or gds__info_sql_bind item. The second byte
|
|
|
|
is assumed to be gds__info_sql_describe_vars. */
|
|
|
|
|
|
|
|
info += 2;
|
|
|
|
|
2003-08-13 13:08:50 +02:00
|
|
|
SSHORT n = static_cast<SSHORT> (get_numeric_info(&info));
|
2001-05-23 15:26:42 +02:00
|
|
|
if (dialect >= DIALECT_xsqlda)
|
|
|
|
{
|
|
|
|
if (xsqlda->version != SQLDA_VERSION1)
|
2001-07-30 01:43:24 +02:00
|
|
|
return error_dsql_804(status, gds_dsql_sqlda_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
xsqlda->sqld = n;
|
|
|
|
|
|
|
|
/* If necessary, inform the application that more sqlda items are needed */
|
|
|
|
if (xsqlda->sqld > xsqlda->sqln)
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sqlda = (SQLDA *) xsqlda;
|
|
|
|
sqlda->sqld = n;
|
|
|
|
|
|
|
|
/* If necessary, inform the application that more sqlda items are needed */
|
|
|
|
if (sqlda->sqld > sqlda->sqln)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
xsqlda = NULL;
|
|
|
|
xvar = &xsqlvar;
|
|
|
|
}
|
|
|
|
|
2003-08-13 13:08:50 +02:00
|
|
|
// Loop over the variables being described.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-08-13 13:08:50 +02:00
|
|
|
USHORT index = 0;
|
2001-07-30 01:43:24 +02:00
|
|
|
while (*info != gds_info_end)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
2003-08-19 12:25:21 +02:00
|
|
|
SCHAR item;
|
|
|
|
while ((item = *info++) != gds_info_sql_describe_end)
|
2001-05-23 15:26:42 +02:00
|
|
|
switch (item)
|
|
|
|
{
|
2001-07-30 01:43:24 +02:00
|
|
|
case gds_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
|
|
|
|
{
|
|
|
|
var = sqlda->sqlvar + index - 1;
|
|
|
|
memset(xvar, 0, sizeof(XSQLVAR));
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
case gds_info_sql_type:
|
2001-05-23 15:26:42 +02:00
|
|
|
xvar->sqltype =
|
|
|
|
static_cast<SSHORT>(get_numeric_info(&info));
|
|
|
|
break;
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
case gds_info_sql_sub_type:
|
2001-05-23 15:26:42 +02:00
|
|
|
xvar->sqlsubtype =
|
|
|
|
static_cast<SSHORT>(get_numeric_info(&info));
|
|
|
|
break;
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
case gds_info_sql_scale:
|
2001-05-23 15:26:42 +02:00
|
|
|
xvar->sqlscale =
|
|
|
|
static_cast<SSHORT>(get_numeric_info(&info));
|
|
|
|
break;
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
case gds_info_sql_length:
|
2001-05-23 15:26:42 +02:00
|
|
|
xvar->sqllen =
|
|
|
|
static_cast<SSHORT>(get_numeric_info(&info));
|
|
|
|
break;
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
case gds_info_sql_field:
|
2001-05-23 15:26:42 +02:00
|
|
|
xvar->sqlname_length =
|
|
|
|
static_cast<SSHORT>(get_string_info(&info, xvar->sqlname, sizeof(xvar->sqlname)));
|
|
|
|
break;
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
case gds_info_sql_relation:
|
2001-05-23 15:26:42 +02:00
|
|
|
xvar->relname_length =
|
|
|
|
static_cast<SSHORT>(get_string_info(&info, xvar->relname, sizeof(xvar->relname)));
|
|
|
|
break;
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
case gds_info_sql_owner:
|
2001-05-23 15:26:42 +02:00
|
|
|
xvar->ownname_length =
|
|
|
|
static_cast<SSHORT>(get_string_info(&info, xvar->ownname, sizeof(xvar->ownname)));
|
|
|
|
break;
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
case gds_info_sql_alias:
|
2001-05-23 15:26:42 +02:00
|
|
|
xvar->aliasname_length =
|
|
|
|
static_cast<SSHORT>
|
|
|
|
(get_string_info
|
|
|
|
(&info, xvar->aliasname, sizeof(xvar->aliasname)));
|
|
|
|
break;
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
case gds_info_truncated:
|
2001-05-23 15:26:42 +02:00
|
|
|
if (return_index)
|
|
|
|
*return_index = last_index;
|
|
|
|
|
|
|
|
default:
|
2001-07-30 01:43:24 +02:00
|
|
|
return error_dsql_804(status, gds_dsql_sqlda_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!xsqlda)
|
|
|
|
xsqlvar_to_sqlvar(xvar, var);
|
|
|
|
|
|
|
|
if (index > last_index)
|
|
|
|
last_index = index;
|
|
|
|
}
|
|
|
|
|
2001-07-30 01:43:24 +02:00
|
|
|
if (*info != gds_info_end)
|
|
|
|
return error_dsql_804(status, gds_dsql_sqlda_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2002-11-14 09:33:08 +01:00
|
|
|
return FB_SUCCESS;
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
UTLD_parse_sqlda
|
|
|
|
|
|
|
|
@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.
|
|
|
|
|
|
|
|
|
|
|
|
@param status
|
|
|
|
@param dasup
|
|
|
|
@param blr_length
|
|
|
|
@param msg_type
|
|
|
|
@param msg_length
|
|
|
|
@param dialect
|
|
|
|
@param xsqlda
|
|
|
|
@param clause
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
ISC_STATUS DLL_EXPORT UTLD_parse_sqlda(ISC_STATUS * status,
|
2001-05-23 15:26:42 +02:00
|
|
|
DASUP dasup,
|
|
|
|
USHORT * blr_length,
|
|
|
|
USHORT * msg_type,
|
|
|
|
USHORT * msg_length,
|
|
|
|
USHORT dialect,
|
|
|
|
XSQLDA * xsqlda,
|
|
|
|
USHORT clause)
|
|
|
|
{
|
2003-08-13 13:08:50 +02:00
|
|
|
USHORT i, n, blr_len, par_count, dtype, msg_len, len, align,
|
2001-05-23 15:26:42 +02:00
|
|
|
null_offset;
|
|
|
|
XSQLVAR *xvar, xsqlvar;
|
|
|
|
SQLDA *sqlda;
|
|
|
|
SQLVAR *var;
|
2003-08-13 13:08:50 +02:00
|
|
|
//BLOB_PTR *p; /* one huge pointer per line for LIBS */
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
if (!xsqlda)
|
|
|
|
n = 0;
|
|
|
|
else
|
|
|
|
if (dialect >= DIALECT_xsqlda)
|
|
|
|
{
|
|
|
|
if (xsqlda->version != SQLDA_VERSION1)
|
2001-07-30 01:43:24 +02:00
|
|
|
return error_dsql_804(status, gds_dsql_sqlda_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
n = xsqlda->sqld;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sqlda = (SQLDA *) xsqlda;
|
|
|
|
n = sqlda->sqld;
|
|
|
|
xsqlda = NULL;
|
|
|
|
xvar = &xsqlvar;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!n)
|
|
|
|
{
|
|
|
|
/* If there isn't an SQLDA, don't bother with anything else. */
|
|
|
|
|
|
|
|
if (blr_length)
|
|
|
|
*blr_length = dasup->dasup_clauses[clause].dasup_blr_length = 0;
|
|
|
|
if (msg_length)
|
|
|
|
*msg_length = 0;
|
|
|
|
if (msg_type)
|
|
|
|
*msg_type = 0;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (msg_length)
|
|
|
|
{
|
|
|
|
/* 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. */
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
|
|
|
/* Make a quick pass through the SQLDA to determine the amount of
|
|
|
|
blr that will be generated. */
|
|
|
|
|
|
|
|
blr_len = 8;
|
|
|
|
par_count = 0;
|
|
|
|
if (xsqlda)
|
|
|
|
xvar = xsqlda->sqlvar - 1;
|
|
|
|
else
|
|
|
|
var = sqlda->sqlvar - 1;
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
if (xsqlda)
|
|
|
|
xvar++;
|
|
|
|
else {
|
|
|
|
var++;
|
|
|
|
sqlvar_to_xsqlvar(var, xvar);
|
|
|
|
}
|
|
|
|
dtype = xvar->sqltype & ~1;
|
|
|
|
if (dtype == SQL_VARYING || dtype == SQL_TEXT)
|
|
|
|
blr_len += 3;
|
|
|
|
else
|
|
|
|
if (dtype == SQL_SHORT ||
|
|
|
|
dtype == SQL_LONG ||
|
|
|
|
dtype == SQL_INT64 ||
|
|
|
|
dtype == SQL_QUAD ||
|
|
|
|
dtype == SQL_BLOB
|
|
|
|
|| dtype == SQL_ARRAY)
|
|
|
|
{
|
|
|
|
blr_len += 2;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
blr_len++;
|
|
|
|
blr_len += 2;
|
|
|
|
par_count += 2;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Make sure the blr buffer is large enough. If it isn't, allocate
|
|
|
|
a new one. */
|
|
|
|
|
|
|
|
if (blr_len > dasup->dasup_clauses[clause].dasup_blr_buf_len)
|
|
|
|
{
|
|
|
|
if (dasup->dasup_clauses[clause].dasup_blr) {
|
|
|
|
gds__free(dasup->dasup_clauses[clause].dasup_blr);
|
|
|
|
}
|
|
|
|
dasup->dasup_clauses[clause].dasup_blr =
|
|
|
|
reinterpret_cast<char*>(gds__alloc((SLONG) blr_len));
|
2003-08-13 13:08:50 +02:00
|
|
|
// FREE: unknown
|
|
|
|
if (!dasup->dasup_clauses[clause].dasup_blr) // NOMEM:
|
2001-07-30 01:43:24 +02:00
|
|
|
return error_dsql_804(status, gds_virmemexh);
|
2001-05-23 15:26:42 +02:00
|
|
|
memset(dasup->dasup_clauses[clause].dasup_blr, 0, blr_len);
|
|
|
|
dasup->dasup_clauses[clause].dasup_blr_buf_len = blr_len;
|
|
|
|
dasup->dasup_clauses[clause].dasup_blr_length = 0;
|
|
|
|
}
|
|
|
|
|
2003-08-13 13:08:50 +02:00
|
|
|
bool same_flag = (blr_len == dasup->dasup_clauses[clause].dasup_blr_length);
|
2002-06-29 08:56:51 +02:00
|
|
|
|
|
|
|
/* turn off same_flag because it breaks execute & execute2 when
|
|
|
|
more than one statement is prepared */
|
|
|
|
|
2003-08-13 13:08:50 +02:00
|
|
|
same_flag = false;
|
2002-06-29 08:56:51 +02:00
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
dasup->dasup_clauses[clause].dasup_blr_length = blr_len;
|
|
|
|
|
|
|
|
/* 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. */
|
|
|
|
|
2003-08-13 13:08:50 +02:00
|
|
|
// one huge pointer per line for LIBS
|
|
|
|
BLOB_PTR *p = reinterpret_cast <UCHAR*>(dasup->dasup_clauses[clause].dasup_blr);
|
|
|
|
|
2001-05-23 15:26:42 +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) {
|
2001-05-23 15:26:42 +02:00
|
|
|
CH_STUFF(p, blr_version5)
|
2002-06-29 08:56:51 +02:00
|
|
|
}
|
|
|
|
else if ((SCHAR) *(p) == (SCHAR) (blr_version4)) {
|
|
|
|
(p)++;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
*(p)++ = (blr_version4);
|
2003-08-19 12:25:21 +02:00
|
|
|
same_flag = false;
|
2002-06-29 08:56:51 +02:00
|
|
|
}
|
|
|
|
|
2001-05-23 15:26:42 +02:00
|
|
|
CH_STUFF(p, blr_begin);
|
|
|
|
CH_STUFF(p, blr_message);
|
|
|
|
CH_STUFF(p, 0);
|
|
|
|
CH_STUFF_WORD(p, par_count);
|
|
|
|
msg_len = 0;
|
|
|
|
if (xsqlda)
|
|
|
|
xvar = xsqlda->sqlvar - 1;
|
|
|
|
else
|
|
|
|
var = sqlda->sqlvar - 1;
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
if (xsqlda)
|
|
|
|
xvar++;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var++;
|
|
|
|
sqlvar_to_xsqlvar(var, xvar);
|
|
|
|
}
|
|
|
|
dtype = xvar->sqltype & ~1;
|
|
|
|
len = xvar->sqllen;
|
|
|
|
switch (dtype)
|
|
|
|
{
|
|
|
|
case SQL_VARYING:
|
|
|
|
CH_STUFF(p, blr_varying);
|
|
|
|
CH_STUFF_WORD(p, len);
|
|
|
|
dtype = dtype_varying;
|
|
|
|
len += sizeof(USHORT);
|
|
|
|
break;
|
|
|
|
case SQL_TEXT:
|
|
|
|
CH_STUFF(p, blr_text);
|
|
|
|
CH_STUFF_WORD(p, len);
|
|
|
|
dtype = dtype_text;
|
|
|
|
break;
|
|
|
|
case SQL_DOUBLE:
|
|
|
|
CH_STUFF(p, blr_double);
|
|
|
|
dtype = dtype_double;
|
|
|
|
break;
|
|
|
|
case SQL_FLOAT:
|
|
|
|
CH_STUFF(p, blr_float);
|
|
|
|
dtype = dtype_real;
|
|
|
|
break;
|
|
|
|
case SQL_D_FLOAT:
|
|
|
|
CH_STUFF(p, blr_d_float);
|
|
|
|
dtype = dtype_d_float;
|
|
|
|
break;
|
|
|
|
case SQL_TYPE_DATE:
|
|
|
|
CH_STUFF(p, blr_sql_date);
|
|
|
|
dtype = dtype_sql_date;
|
|
|
|
break;
|
|
|
|
case SQL_TYPE_TIME:
|
|
|
|
CH_STUFF(p, blr_sql_time);
|
|
|
|
dtype = dtype_sql_time;
|
|
|
|
break;
|
|
|
|
case SQL_TIMESTAMP:
|
|
|
|
CH_STUFF(p, blr_timestamp);
|
|
|
|
dtype = dtype_timestamp;
|
|
|
|
break;
|
|
|
|
case SQL_BLOB:
|
|
|
|
CH_STUFF(p, blr_quad);
|
|
|
|
CH_STUFF(p, 0);
|
|
|
|
dtype = dtype_blob;
|
|
|
|
break;
|
|
|
|
case SQL_ARRAY:
|
|
|
|
CH_STUFF(p, blr_quad);
|
|
|
|
CH_STUFF(p, 0);
|
|
|
|
dtype = dtype_array;
|
|
|
|
break;
|
|
|
|
case SQL_LONG:
|
|
|
|
CH_STUFF(p, blr_long);
|
|
|
|
CH_STUFF(p, xvar->sqlscale);
|
|
|
|
dtype = dtype_long;
|
|
|
|
break;
|
|
|
|
case SQL_SHORT:
|
|
|
|
CH_STUFF(p, blr_short);
|
|
|
|
CH_STUFF(p, xvar->sqlscale);
|
|
|
|
dtype = dtype_short;
|
|
|
|
break;
|
|
|
|
case SQL_INT64:
|
|
|
|
CH_STUFF(p, blr_int64);
|
|
|
|
CH_STUFF(p, xvar->sqlscale);
|
|
|
|
dtype = dtype_int64;
|
|
|
|
break;
|
|
|
|
case SQL_QUAD:
|
|
|
|
CH_STUFF(p, blr_quad);
|
|
|
|
CH_STUFF(p, xvar->sqlscale);
|
|
|
|
dtype = dtype_quad;
|
|
|
|
break;
|
|
|
|
default:
|
2001-07-30 01:43:24 +02:00
|
|
|
return error_dsql_804(status, gds_dsql_sqlda_value_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
CH_STUFF(p, blr_short);
|
|
|
|
CH_STUFF(p, 0);
|
|
|
|
|
|
|
|
align = type_alignments[dtype];
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
CH_STUFF(p, blr_end);
|
|
|
|
CH_STUFF(p, blr_eoc);
|
|
|
|
|
|
|
|
/* Make sure the message buffer is large enough. If it isn't, allocate
|
|
|
|
a new one. */
|
|
|
|
|
|
|
|
if (msg_len > dasup->dasup_clauses[clause].dasup_msg_buf_len)
|
|
|
|
{
|
|
|
|
if (dasup->dasup_clauses[clause].dasup_msg)
|
|
|
|
gds__free(dasup->dasup_clauses[clause].dasup_msg);
|
|
|
|
dasup->dasup_clauses[clause].dasup_msg =
|
|
|
|
reinterpret_cast<char*>(gds__alloc((SLONG) msg_len));
|
2003-08-13 13:08:50 +02:00
|
|
|
// FREE: unknown
|
|
|
|
if (!dasup->dasup_clauses[clause].dasup_msg) // NOMEM:
|
2001-07-30 01:43:24 +02:00
|
|
|
return error_dsql_804(status, gds_virmemexh);
|
2001-05-23 15:26:42 +02:00
|
|
|
memset(dasup->dasup_clauses[clause].dasup_msg, 0, msg_len);
|
|
|
|
dasup->dasup_clauses[clause].dasup_msg_buf_len = msg_len;
|
|
|
|
}
|
|
|
|
|
2003-08-13 13:08:50 +02:00
|
|
|
// Fill in the return values to the caller.
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
*blr_length = (same_flag) ? 0 : blr_len;
|
|
|
|
*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;
|
|
|
|
}
|
|
|
|
|
2003-08-13 13:08:50 +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
|
|
|
|
BLOB_PTR *msg_buf =
|
2001-05-23 15:26:42 +02:00
|
|
|
reinterpret_cast<UCHAR*>(dasup->dasup_clauses[clause].dasup_msg);
|
|
|
|
if (xsqlda)
|
|
|
|
xvar = xsqlda->sqlvar - 1;
|
|
|
|
else
|
|
|
|
var = sqlda->sqlvar - 1;
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
if (xsqlda)
|
|
|
|
xvar++;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
var++;
|
|
|
|
sqlvar_to_xsqlvar(var, xvar);
|
|
|
|
}
|
|
|
|
dtype = xvar->sqltype & ~1;
|
|
|
|
len = xvar->sqllen;
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
align = type_alignments[dtype];
|
|
|
|
if (align)
|
|
|
|
offset = FB_ALIGN(offset, align);
|
|
|
|
null_offset = offset + len;
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
/* Move data from the message into the SQLDA. */
|
|
|
|
|
|
|
|
/* Make sure user has specified a data location */
|
|
|
|
if (!xvar->sqldata)
|
2001-07-30 01:43:24 +02:00
|
|
|
return error_dsql_804(status, gds_dsql_sqlda_value_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
memcpy(xvar->sqldata, msg_buf + offset, len);
|
|
|
|
if (xvar->sqltype & 1)
|
|
|
|
{
|
|
|
|
/* Make sure user has specified a location for null indicator */
|
|
|
|
if (!xvar->sqlind)
|
2001-07-30 01:43:24 +02:00
|
|
|
return error_dsql_804(status, gds_dsql_sqlda_value_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
*xvar->sqlind = *null_ind;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Move data from the SQLDA into the message. If the
|
|
|
|
indicator variable identifies a null value, permit
|
|
|
|
the data value to be missing. */
|
|
|
|
|
|
|
|
if (xvar->sqltype & 1)
|
|
|
|
{
|
|
|
|
/* Make sure user has specified a location for null indicator */
|
|
|
|
if (!xvar->sqlind)
|
2001-07-30 01:43:24 +02:00
|
|
|
return error_dsql_804(status, gds_dsql_sqlda_value_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
*null_ind = *xvar->sqlind;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
*null_ind = 0;
|
|
|
|
|
|
|
|
/* Make sure user has specified a data location (unless NULL) */
|
|
|
|
if (!xvar->sqldata && !*null_ind)
|
2001-07-30 01:43:24 +02:00
|
|
|
return error_dsql_804(status, gds_dsql_sqlda_value_err);
|
2001-05-23 15:26:42 +02:00
|
|
|
|
|
|
|
/* Copy data - unless known to be NULL */
|
2002-04-04 18:22:14 +02:00
|
|
|
if ((offset + len) > dasup->dasup_clauses[clause].dasup_msg_buf_len)
|
|
|
|
return error_dsql_804(status, gds_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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
UTLD_save_status_strings
|
|
|
|
|
|
|
|
@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.
|
|
|
|
|
|
|
|
|
|
|
|
@param vector
|
|
|
|
|
|
|
|
**/
|
2003-04-10 08:32:58 +02:00
|
|
|
void DLL_EXPORT UTLD_save_status_strings( ISC_STATUS * vector)
|
2001-05-23 15:26:42 +02:00
|
|
|
{
|
|
|
|
TEXT *p;
|
|
|
|
USHORT l;
|
|
|
|
|
|
|
|
/* allocate space for failure strings if it hasn't already been allocated */
|
|
|
|
|
|
|
|
if (!DSQL_failures)
|
|
|
|
{
|
|
|
|
DSQL_failures = (TEXT *) ALLOC_LIB_MEMORY((SLONG) DSQL_FAILURE_SPACE);
|
|
|
|
/* FREE: by exit handler cleanup() */
|
|
|
|
if (!DSQL_failures) /* NOMEM: don't try to copy the strings */
|
|
|
|
return;
|
|
|
|
DSQL_failures_ptr = DSQL_failures;
|
|
|
|
gds__register_cleanup(cleanup, 0);
|
|
|
|
|
|
|
|
#ifdef DEBUG_GDS_ALLOC
|
|
|
|
gds_alloc_flag_unfreed((void *) DSQL_failures);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
while (*vector)
|
|
|
|
{
|
2003-08-13 13:08:50 +02:00
|
|
|
ISC_STATUS status = *vector;
|
2001-05-23 15:26:42 +02:00
|
|
|
vector++;
|
|
|
|
switch (status)
|
|
|
|
{
|
|
|
|
case gds_arg_cstring:
|
|
|
|
l = static_cast<USHORT>(*vector++);
|
|
|
|
|
|
|
|
case gds_arg_interpreted:
|
|
|
|
case gds_arg_string:
|
|
|
|
p = (TEXT *) * vector;
|
|
|
|
if (status != gds_arg_cstring)
|
|
|
|
l = strlen(p) + 1;
|
|
|
|
|
|
|
|
/* If there isn't any more room in the buffer,
|
|
|
|
start at the beginning again */
|
|
|
|
|
|
|
|
if (DSQL_failures_ptr + l > DSQL_failures + DSQL_FAILURE_SPACE)
|
|
|
|
DSQL_failures_ptr = DSQL_failures;
|
2003-04-10 08:32:58 +02:00
|
|
|
*vector++ = (ISC_STATUS) DSQL_failures_ptr;
|
2001-05-23 15:26:42 +02:00
|
|
|
if (l)
|
|
|
|
do
|
|
|
|
*DSQL_failures_ptr++ = *p++;
|
|
|
|
while (--l && (DSQL_failures_ptr < DSQL_failures + DSQL_FAILURE_SPACE));
|
|
|
|
if (l)
|
|
|
|
*(DSQL_failures_ptr - 1) = '\0';
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
++vector;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
cleanup
|
|
|
|
|
|
|
|
@brief Exit handler to cleanup dynamically allocated memory.
|
|
|
|
|
|
|
|
|
|
|
|
@param arg
|
|
|
|
|
|
|
|
**/
|
2001-05-23 15:26:42 +02:00
|
|
|
static void cleanup( void *arg)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (DSQL_failures)
|
|
|
|
FREE_LIB_MEMORY(DSQL_failures);
|
|
|
|
|
|
|
|
gds__unregister_cleanup(cleanup, 0);
|
|
|
|
DSQL_failures = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
error_dsql_804
|
|
|
|
|
|
|
|
@brief Move a DSQL -804 error message into a status vector.
|
|
|
|
|
|
|
|
|
|
|
|
@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
|
|
|
|
|
|
|
*p++ = gds_arg_gds;
|
2001-07-30 01:43:24 +02:00
|
|
|
*p++ = gds_dsql_error;
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = gds_arg_gds;
|
2001-07-30 01:43:24 +02:00
|
|
|
*p++ = gds_sqlerr;
|
2001-05-23 15:26:42 +02:00
|
|
|
*p++ = gds_arg_number;
|
|
|
|
*p++ = -804;
|
|
|
|
*p++ = gds_arg_gds;
|
|
|
|
*p++ = (err);
|
|
|
|
*p = gds_arg_end;
|
|
|
|
|
|
|
|
return status[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
get_numeric_info
|
|
|
|
|
|
|
|
@brief Pick up a VAX format numeric info item
|
|
|
|
with a 2 byte length.
|
|
|
|
|
|
|
|
|
|
|
|
@param ptr
|
|
|
|
|
|
|
|
**/
|
2001-05-23 15:26:42 +02:00
|
|
|
static SLONG get_numeric_info( SCHAR ** ptr)
|
|
|
|
{
|
2003-08-13 13:08:50 +02:00
|
|
|
SSHORT l = static_cast<SSHORT>(gds__vax_integer(reinterpret_cast<UCHAR*>(*ptr), 2));
|
2001-05-23 15:26:42 +02:00
|
|
|
*ptr += 2;
|
2003-08-13 13:08:50 +02:00
|
|
|
int item = gds__vax_integer(reinterpret_cast<UCHAR*>(*ptr), l);
|
2001-05-23 15:26:42 +02:00
|
|
|
*ptr += l;
|
|
|
|
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
get_string_info
|
|
|
|
|
|
|
|
@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.
|
|
|
|
|
|
|
|
|
|
|
|
@param ptr
|
|
|
|
@param buffer
|
|
|
|
@param buffer_len
|
|
|
|
|
|
|
|
**/
|
2001-05-23 15:26:42 +02:00
|
|
|
static SLONG get_string_info( SCHAR ** ptr, SCHAR * buffer, int buffer_len)
|
|
|
|
{
|
2003-08-13 13:08:50 +02:00
|
|
|
SCHAR *p = *ptr;
|
|
|
|
SSHORT l = static_cast<SSHORT>(gds__vax_integer(reinterpret_cast<UCHAR*>(p), 2));
|
2001-05-23 15:26:42 +02:00
|
|
|
*ptr += l + 2;
|
|
|
|
p += 2;
|
|
|
|
|
|
|
|
if (l >= buffer_len)
|
|
|
|
l = buffer_len - 1;
|
|
|
|
|
2003-08-13 13:08:50 +02:00
|
|
|
SSHORT len = l;
|
|
|
|
if (len)
|
2001-05-23 15:26:42 +02:00
|
|
|
do
|
|
|
|
*buffer++ = *p++;
|
|
|
|
while (--l);
|
|
|
|
*buffer = 0;
|
|
|
|
|
|
|
|
return len;
|
|
|
|
}
|
|
|
|
|
2003-03-03 09:29:18 +01:00
|
|
|
#ifdef NOT_USED_OR_REPLACED
|
2001-05-23 15:26:42 +02:00
|
|
|
#ifdef DEV_BUILD
|
|
|
|
static void print_xsqlda( XSQLDA * xsqlda)
|
|
|
|
{
|
|
|
|
/*****************************************
|
|
|
|
*
|
|
|
|
* p r i n t _ x s q l d a
|
|
|
|
*
|
|
|
|
*****************************************
|
|
|
|
*
|
|
|
|
* print an sqlda
|
|
|
|
*
|
|
|
|
*****************************************/
|
|
|
|
XSQLVAR *xvar, *end_var;
|
|
|
|
|
|
|
|
if (!xsqlda)
|
|
|
|
return;
|
|
|
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
xvar = xsqlda->sqlvar;
|
|
|
|
for (end_var = xvar + xsqlda->sqld; xvar < end_var; xvar++)
|
|
|
|
PRINTF(" %.31s %.31s type: %d, scale %d, len %d subtype %d\n",
|
|
|
|
xvar->sqlname, xvar->relname, xvar->sqltype,
|
|
|
|
xvar->sqlscale, xvar->sqllen, xvar->sqlsubtype);
|
|
|
|
}
|
|
|
|
#endif
|
2003-03-03 09:29:18 +01:00
|
|
|
#endif
|
2001-05-23 15:26:42 +02:00
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
sqlvar_to_xsqlvar
|
|
|
|
|
|
|
|
|
|
|
|
@param sqlvar
|
|
|
|
@param xsqlvar
|
|
|
|
|
|
|
|
|
|
|
|
@param sqlvar
|
|
|
|
@param xsqlvar
|
|
|
|
|
|
|
|
**/
|
2001-05-23 15:26:42 +02:00
|
|
|
static void sqlvar_to_xsqlvar( SQLVAR * sqlvar, XSQLVAR * xsqlvar)
|
|
|
|
{
|
|
|
|
|
|
|
|
xsqlvar->sqltype = sqlvar->sqltype;
|
|
|
|
xsqlvar->sqldata = sqlvar->sqldata;
|
|
|
|
xsqlvar->sqlind = sqlvar->sqlind;
|
|
|
|
|
|
|
|
xsqlvar->sqlsubtype = 0;
|
|
|
|
xsqlvar->sqlscale = 0;
|
|
|
|
xsqlvar->sqllen = sqlvar->sqllen;
|
|
|
|
if ((xsqlvar->sqltype & ~1) == SQL_LONG) {
|
|
|
|
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
|
|
|
|
xsqlvar->sqllen = sizeof(SLONG);
|
|
|
|
}
|
|
|
|
else if ((xsqlvar->sqltype & ~1) == SQL_SHORT) {
|
|
|
|
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
|
|
|
|
xsqlvar->sqllen = sizeof(SSHORT);
|
|
|
|
}
|
|
|
|
else if ((xsqlvar->sqltype & ~1) == SQL_INT64) {
|
|
|
|
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
|
|
|
|
xsqlvar->sqllen = sizeof(SINT64);
|
|
|
|
}
|
|
|
|
else if ((xsqlvar->sqltype & ~1) == SQL_QUAD) {
|
|
|
|
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
|
|
|
|
xsqlvar->sqllen = sizeof(GDS_QUAD);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-02-15 04:01:51 +01:00
|
|
|
/**
|
|
|
|
|
|
|
|
xsqlvar_to_sqlvar
|
|
|
|
|
|
|
|
@brief Move an XSQLVAR to an SQLVAR.
|
|
|
|
|
|
|
|
|
|
|
|
@param xsqlvar
|
|
|
|
@param sqlvar
|
|
|
|
|
|
|
|
**/
|
2001-05-23 15:26:42 +02:00
|
|
|
static void xsqlvar_to_sqlvar( XSQLVAR * xsqlvar, SQLVAR * sqlvar)
|
|
|
|
{
|
|
|
|
|
|
|
|
sqlvar->sqltype = xsqlvar->sqltype;
|
|
|
|
sqlvar->sqlname_length = xsqlvar->aliasname_length;
|
|
|
|
|
|
|
|
/* N.B., this may not NULL-terminate the name... */
|
|
|
|
|
|
|
|
memcpy(sqlvar->sqlname, xsqlvar->aliasname, sizeof(sqlvar->sqlname));
|
|
|
|
|
|
|
|
sqlvar->sqllen = xsqlvar->sqllen;
|
|
|
|
if ((sqlvar->sqltype & ~1) == SQL_LONG)
|
|
|
|
sqlvar->sqllen = sizeof(SLONG) | (xsqlvar->sqlscale << 8);
|
|
|
|
else if ((sqlvar->sqltype & ~1) == SQL_SHORT)
|
|
|
|
sqlvar->sqllen = sizeof(SSHORT) | (xsqlvar->sqlscale << 8);
|
|
|
|
else if ((sqlvar->sqltype & ~1) == SQL_INT64)
|
|
|
|
sqlvar->sqllen = sizeof(SINT64) | (xsqlvar->sqlscale << 8);
|
|
|
|
else if ((sqlvar->sqltype & ~1) == SQL_QUAD)
|
|
|
|
sqlvar->sqllen = sizeof(GDS_QUAD) | (xsqlvar->sqlscale << 8);
|
|
|
|
}
|
|
|
|
|