2
* PROGRAM: Dynamic SQL runtime support
4
* DESCRIPTION: Utility routines for DSQL
6
* The contents of this file are subject to the Interbase Public
7
* License Version 1.0 (the "License"); you may not use this file
8
* except in compliance with the License. You may obtain a copy
9
* of the License at http://www.Inprise.com/IPL.html
11
* Software distributed under the License is distributed on an
12
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
13
* or implied. See the License for the specific language governing
14
* rights and limitations under the License.
16
* The Original Code was created by Inprise Corporation
17
* and its predecessors. Portions created by Inprise Corporation are
18
* Copyright (C) Inprise Corporation.
20
* All Rights Reserved.
21
* Contributor(s): ______________________________________.
23
* 21 Nov 01 - Ann Harrison - Turn off the code in parse_sqlda that
24
* decides that two statements are the same based on their message
25
* descriptions because it misleads some code in remote/interface.c
26
* and causes problems when two statements are prepared.
28
* 2002.10.29 Sean Leyne - Removed obsolete "Netware" port
36
#include "../dsql/dsql.h"
37
#include "../dsql/sqlda.h"
38
#include "../jrd/ibase.h"
39
#include "../jrd/align.h"
40
#include "../jrd/constants.h"
41
#include "../dsql/utld_proto.h"
42
#include "../jrd/gds_proto.h"
44
#if !defined(REQUESTER) && !defined(SUPERCLIENT)
45
#include "../dsql/metd_proto.h"
49
static void cleanup(void *);
50
static ISC_STATUS error_dsql_804(ISC_STATUS *, ISC_STATUS);
51
static SLONG get_numeric_info(const SCHAR**);
52
static SLONG get_string_info(const SCHAR**, SCHAR*, int);
53
#ifdef NOT_USED_OR_REPLACED
55
static void print_xsqlda(XSQLDA *);
58
static void sqlvar_to_xsqlvar(const SQLVAR*, XSQLVAR*);
59
static void xsqlvar_to_sqlvar(const XSQLVAR*, SQLVAR*);
61
static inline void ch_stuff(BLOB_PTR*& p, const SCHAR value, bool& same_flag)
71
static inline void ch_stuff_word(BLOB_PTR*& p, const SSHORT value, bool& same_flag)
73
ch_stuff(p, value & 255, same_flag);
74
ch_stuff(p, value >> 8, same_flag);
77
/* these statics define a round-robin data area for storing
78
textual error messages returned to the user */
80
static TEXT *DSQL_failures, *DSQL_failures_ptr;
82
const int DSQL_FAILURE_SPACE = 2048;
85
Parse response on isc_info_sql_select or isc_info_sql_bind
86
request. Return pointer to the next byte after successfully
87
parsed info or NULL if error is encountered or info is truncated
89
SCHAR* UTLD_skip_sql_info(SCHAR* info)
91
if (*info != isc_info_sql_select &&
92
*info != isc_info_sql_bind)
99
if (*info++ != isc_info_sql_describe_vars)
102
get_numeric_info((const SCHAR**) &info);
104
// Loop over the variables being described
107
SCHAR str[256]; // must be big enough to hold metadata name
108
SCHAR item = *info++;
115
case isc_info_truncated:
118
case isc_info_sql_select:
119
case isc_info_sql_bind:
122
case isc_info_sql_describe_end:
125
case isc_info_sql_sqlda_seq:
126
case isc_info_sql_type:
127
case isc_info_sql_sub_type:
128
case isc_info_sql_scale:
129
case isc_info_sql_length:
130
get_numeric_info((const SCHAR**) &info);
133
case isc_info_sql_field:
134
case isc_info_sql_relation:
135
case isc_info_sql_owner:
136
case isc_info_sql_alias:
137
get_string_info((const SCHAR**) &info, str, sizeof(str));
151
UTLD_char_length_to_byte_length
153
@brief Return max byte length necessary for a specified character length string
156
@param maxBytesPerChar
159
USHORT UTLD_char_length_to_byte_length(USHORT lengthInChars, USHORT maxBytesPerChar)
161
return MIN((MAX_COLUMN_SIZE - sizeof(USHORT)) / maxBytesPerChar * maxBytesPerChar,
162
lengthInChars * maxBytesPerChar);
166
ISC_STATUS UTLD_copy_status(const ISC_STATUS* from, ISC_STATUS* to)
168
/**************************************
170
* c o p y _ s t a t u s
172
**************************************
174
* Functional description
175
* Copy a status vector.
177
**************************************/
178
const ISC_STATUS status = from[1];
180
const ISC_STATUS* const end = from + ISC_STATUS_LENGTH;
192
@brief Fill in an SQLDA using data returned
193
by a call to isc_dsql_sql_info.
203
ISC_STATUS UTLD_parse_sql_info(
208
USHORT* return_index)
210
XSQLVAR *xvar, xsqlvar;
213
USHORT last_index = 0;
221
/* The first byte of the returned buffer is assumed to be either a
222
isc_info_sql_select or isc_info_sql_bind item. The second byte
223
is assumed to be isc_info_sql_describe_vars. */
227
const SSHORT n = static_cast<SSHORT>(get_numeric_info(&info));
228
if (dialect >= DIALECT_xsqlda)
230
if (xsqlda->version != SQLDA_VERSION1)
231
return error_dsql_804(status, isc_dsql_sqlda_err);
234
// If necessary, inform the application that more sqlda items are needed
235
if (xsqlda->sqld > xsqlda->sqln)
240
sqlda = (SQLDA *) xsqlda;
243
// If necessary, inform the application that more sqlda items are needed
244
if (sqlda->sqld > sqlda->sqln)
251
// Loop over the variables being described.
254
while (*info != isc_info_end)
257
while ((item = *info++) != isc_info_sql_describe_end)
260
case isc_info_sql_sqlda_seq:
261
index = static_cast<USHORT>(get_numeric_info(&info));
263
xvar = xsqlda->sqlvar + index - 1;
266
qvar = sqlda->sqlvar + index - 1;
267
memset(xvar, 0, sizeof(XSQLVAR));
271
case isc_info_sql_type:
273
static_cast<SSHORT>(get_numeric_info(&info));
276
case isc_info_sql_sub_type:
278
static_cast<SSHORT>(get_numeric_info(&info));
281
case isc_info_sql_scale:
283
static_cast<SSHORT>(get_numeric_info(&info));
286
case isc_info_sql_length:
288
static_cast<SSHORT>(get_numeric_info(&info));
291
case isc_info_sql_field:
292
xvar->sqlname_length =
293
static_cast<SSHORT>(get_string_info(&info, xvar->sqlname, sizeof(xvar->sqlname)));
296
case isc_info_sql_relation:
297
xvar->relname_length =
298
static_cast<SSHORT>(get_string_info(&info, xvar->relname, sizeof(xvar->relname)));
301
case isc_info_sql_owner:
302
xvar->ownname_length =
303
static_cast<SSHORT>(get_string_info(&info, xvar->ownname, sizeof(xvar->ownname)));
306
case isc_info_sql_alias:
307
xvar->aliasname_length =
310
(&info, xvar->aliasname, sizeof(xvar->aliasname)));
313
case isc_info_truncated:
315
*return_index = last_index;
318
return error_dsql_804(status, isc_dsql_sqlda_err);
322
xsqlvar_to_sqlvar(xvar, qvar);
324
if (index > last_index)
328
if (*info != isc_info_end)
329
return error_dsql_804(status, isc_dsql_sqlda_err);
339
@brief This routine creates a blr message that describes
340
a SQLDA as well as moving data from the SQLDA
341
into a message buffer or from the message buffer
355
ISC_STATUS UTLD_parse_sqlda(
357
sqlda_sup* const dasup,
366
XSQLVAR *xvar, xsqlvar;
373
if (dialect >= DIALECT_xsqlda)
375
if (xsqlda->version != SQLDA_VERSION1)
376
return error_dsql_804(status, isc_dsql_sqlda_err);
381
sqlda = (SQLDA *) xsqlda;
388
sqlda_sup::dasup_clause* const pClause = &dasup->dasup_clauses[clause];
392
// If there isn't an SQLDA, don't bother with anything else.
395
*blr_length = pClause->dasup_blr_length = 0;
407
/* This is a call from execute or open, or the first call from fetch.
408
Determine the size of the blr, allocate a blr buffer, create the
409
blr, and finally allocate a message buffer. */
411
/* The message buffer we are describing could be for a message to
412
either IB 4.0 or IB 3.3 - thus we need to describe the buffer
413
with the right set of blr.
414
As the BLR is only used to describe space allocation and alignment,
415
we can safely use blr_text for both 4.0 and 3.3. */
417
/* Make a quick pass through the SQLDA to determine the amount of
418
blr that will be generated. */
421
USHORT par_count = 0;
423
xvar = xsqlda->sqlvar - 1;
425
qvar = sqlda->sqlvar - 1;
426
for (i = 0; i < n; i++)
432
sqlvar_to_xsqlvar(qvar, xvar);
434
const USHORT dtype = xvar->sqltype & ~1;
435
if (dtype == SQL_VARYING || dtype == SQL_TEXT)
438
if (dtype == SQL_SHORT ||
440
dtype == SQL_INT64 ||
443
|| dtype == SQL_ARRAY)
453
/* Make sure the blr buffer is large enough. If it isn't, allocate
456
if (blr_len > pClause->dasup_blr_buf_len)
458
if (pClause->dasup_blr) {
459
gds__free(pClause->dasup_blr);
462
reinterpret_cast<char*>(gds__alloc((SLONG) blr_len));
464
if (!pClause->dasup_blr) // NOMEM:
465
return error_dsql_804(status, isc_virmemexh);
466
pClause->dasup_blr_buf_len = blr_len;
467
pClause->dasup_blr_length = 0;
469
memset(pClause->dasup_blr, 0, blr_len);
471
bool same_flag = (blr_len == pClause->dasup_blr_length);
473
/* turn off same_flag because it breaks execute & execute2 when
474
more than one statement is prepared */
478
pClause->dasup_blr_length = blr_len;
480
/* Generate the blr for the message and at the same time, determine
481
the size of the message buffer. Allow for a null indicator with
482
each variable in the SQLDA. */
484
// one huge pointer per line for LIBS
485
BLOB_PTR* p = reinterpret_cast<UCHAR*>(pClause->dasup_blr);
487
/** The define SQL_DIALECT_V5 is not available here, Hence using
491
ch_stuff(p, blr_version5, same_flag);
494
ch_stuff(p, blr_version4, same_flag);
496
//else if ((SCHAR) *(p) == (SCHAR) (blr_version4)) {
500
// *(p)++ = (blr_version4);
501
// same_flag = false;
504
ch_stuff(p, blr_begin, same_flag);
505
ch_stuff(p, blr_message, same_flag);
506
ch_stuff(p, 0, same_flag);
507
ch_stuff_word(p, par_count, same_flag);
510
xvar = xsqlda->sqlvar - 1;
512
qvar = sqlda->sqlvar - 1;
513
for (i = 0; i < n; i++)
520
sqlvar_to_xsqlvar(qvar, xvar);
522
USHORT dtype = xvar->sqltype & ~1;
523
USHORT len = xvar->sqllen;
527
ch_stuff(p, blr_varying, same_flag);
528
ch_stuff_word(p, len, same_flag);
529
dtype = dtype_varying;
530
len += sizeof(USHORT);
533
ch_stuff(p, blr_text, same_flag);
534
ch_stuff_word(p, len, same_flag);
538
ch_stuff(p, blr_double, same_flag);
539
dtype = dtype_double;
542
ch_stuff(p, blr_float, same_flag);
546
ch_stuff(p, blr_d_float, same_flag);
547
dtype = dtype_d_float;
550
ch_stuff(p, blr_sql_date, same_flag);
551
dtype = dtype_sql_date;
554
ch_stuff(p, blr_sql_time, same_flag);
555
dtype = dtype_sql_time;
558
ch_stuff(p, blr_timestamp, same_flag);
559
dtype = dtype_timestamp;
562
ch_stuff(p, blr_quad, same_flag);
563
ch_stuff(p, 0, same_flag);
567
ch_stuff(p, blr_quad, same_flag);
568
ch_stuff(p, 0, same_flag);
572
ch_stuff(p, blr_long, same_flag);
573
ch_stuff(p, xvar->sqlscale, same_flag);
577
ch_stuff(p, blr_short, same_flag);
578
ch_stuff(p, xvar->sqlscale, same_flag);
582
ch_stuff(p, blr_int64, same_flag);
583
ch_stuff(p, xvar->sqlscale, same_flag);
587
ch_stuff(p, blr_quad, same_flag);
588
ch_stuff(p, xvar->sqlscale, same_flag);
592
return error_dsql_804(status, isc_dsql_sqlda_value_err);
595
ch_stuff(p, blr_short, same_flag);
596
ch_stuff(p, 0, same_flag);
598
USHORT align = type_alignments[dtype];
600
msg_len = FB_ALIGN(msg_len, align);
602
align = type_alignments[dtype_short];
604
msg_len = FB_ALIGN(msg_len, align);
605
msg_len += sizeof(SSHORT);
608
ch_stuff(p, blr_end, same_flag);
609
ch_stuff(p, blr_eoc, same_flag);
611
/* Make sure the message buffer is large enough. If it isn't, allocate
614
if (msg_len > pClause->dasup_msg_buf_len)
616
if (pClause->dasup_msg)
617
gds__free(pClause->dasup_msg);
619
reinterpret_cast<char*>(gds__alloc((SLONG) msg_len));
621
if (!pClause->dasup_msg) // NOMEM:
622
return error_dsql_804(status, isc_virmemexh);
623
pClause->dasup_msg_buf_len = msg_len;
625
memset(pClause->dasup_msg, 0, msg_len);
627
// Fill in the return values to the caller.
629
*blr_length = (same_flag) ? 0 : blr_len;
630
*msg_length = msg_len;
633
// If this is the first call from fetch, we're done.
635
if (clause == DASUP_CLAUSE_select)
639
// Move the data between the SQLDA and the message buffer.
642
// one huge pointer per line for LIBS
644
reinterpret_cast<UCHAR*>(pClause->dasup_msg);
646
xvar = xsqlda->sqlvar - 1;
648
qvar = sqlda->sqlvar - 1;
649
for (i = 0; i < n; i++)
656
sqlvar_to_xsqlvar(qvar, xvar);
658
USHORT dtype = xvar->sqltype & ~1;
659
USHORT len = xvar->sqllen;
663
dtype = dtype_varying;
664
len += sizeof(USHORT);
670
dtype = dtype_double;
676
dtype = dtype_d_float;
679
dtype = dtype_sql_date;
682
dtype = dtype_sql_time;
685
dtype = dtype_timestamp;
706
USHORT align = type_alignments[dtype];
708
offset = FB_ALIGN(offset, align);
709
USHORT null_offset = offset + len;
711
align = type_alignments[dtype_short];
713
null_offset = FB_ALIGN(null_offset, align);
715
SSHORT *null_ind = (SSHORT *) (msg_buf + null_offset);
716
if (clause == DASUP_CLAUSE_select)
718
// Move data from the message into the SQLDA.
720
// Make sure user has specified a data location
722
return error_dsql_804(status, isc_dsql_sqlda_value_err);
724
memcpy(xvar->sqldata, msg_buf + offset, len);
725
if (xvar->sqltype & 1)
727
// Make sure user has specified a location for null indicator
729
return error_dsql_804(status, isc_dsql_sqlda_value_err);
730
*xvar->sqlind = *null_ind;
735
/* Move data from the SQLDA into the message. If the
736
indicator variable identifies a null value, permit
737
the data value to be missing. */
739
if (xvar->sqltype & 1)
741
// Make sure user has specified a location for null indicator
743
return error_dsql_804(status, isc_dsql_sqlda_value_err);
744
*null_ind = *xvar->sqlind;
749
// Make sure user has specified a data location (unless NULL)
750
if (!xvar->sqldata && !*null_ind)
751
return error_dsql_804(status, isc_dsql_sqlda_value_err);
753
// Copy data - unless known to be NULL
754
if ((offset + len) > pClause->dasup_msg_buf_len)
755
return error_dsql_804(status, isc_dsql_sqlda_value_err);
758
memcpy(msg_buf + offset, xvar->sqldata, len);
761
offset = null_offset + sizeof(SSHORT);
770
UTLD_save_status_strings
772
@brief Strings in status vectors may be stored in stack variables
773
or memory pools that are transient. To perserve the information,
774
copy any included strings to a special buffer.
780
void UTLD_save_status_strings(ISC_STATUS* vector)
782
// allocate space for failure strings if it hasn't already been allocated
786
DSQL_failures = (TEXT *) ALLOC_LIB_MEMORY((SLONG) DSQL_FAILURE_SPACE);
787
// FREE: by exit handler cleanup()
788
if (!DSQL_failures) // NOMEM: don't try to copy the strings
790
DSQL_failures_ptr = DSQL_failures;
791
gds__register_cleanup(cleanup, 0);
793
#ifdef DEBUG_GDS_ALLOC
794
gds_alloc_flag_unfreed((void *) DSQL_failures);
802
const ISC_STATUS status = *vector++;
805
case isc_arg_cstring:
806
l = static_cast<USHORT>(*vector++);
808
case isc_arg_interpreted:
810
p = (TEXT *) * vector;
811
if (status != isc_arg_cstring)
814
/* If there isn't any more room in the buffer,
815
start at the beginning again */
817
if (DSQL_failures_ptr + l > DSQL_failures + DSQL_FAILURE_SPACE)
818
DSQL_failures_ptr = DSQL_failures;
819
*vector++ = (ISC_STATUS) DSQL_failures_ptr;
822
*DSQL_failures_ptr++ = *p++;
823
while (--l && (DSQL_failures_ptr < DSQL_failures + DSQL_FAILURE_SPACE));
825
*(DSQL_failures_ptr - 1) = '\0';
840
@brief Exit handler to cleanup dynamically allocated memory.
846
static void cleanup( void *arg)
850
FREE_LIB_MEMORY(DSQL_failures);
852
gds__unregister_cleanup(cleanup, 0);
853
DSQL_failures = NULL;
861
@brief Move a DSQL -804 error message into a status vector.
868
static ISC_STATUS error_dsql_804( ISC_STATUS * status, ISC_STATUS err)
870
ISC_STATUS *p = status;
873
*p++ = isc_dsql_error;
876
*p++ = isc_arg_number;
890
@brief Pick up a VAX format numeric info item
891
with a 2 byte length.
897
static SLONG get_numeric_info( const SCHAR** ptr)
900
static_cast<SSHORT>(gds__vax_integer(reinterpret_cast<const UCHAR*>(*ptr), 2));
902
int item = gds__vax_integer(reinterpret_cast<const UCHAR*>(*ptr), l);
913
@brief Pick up a string valued info item and return
914
its length. The buffer_len argument is assumed
915
to include space for the terminating null.
923
static SLONG get_string_info( const SCHAR** ptr, SCHAR * buffer, int buffer_len)
925
const SCHAR* p = *ptr;
927
static_cast<SSHORT>(gds__vax_integer(reinterpret_cast<const UCHAR*>(p), 2));
944
#ifdef NOT_USED_OR_REPLACED
946
static void print_xsqlda( XSQLDA * xsqlda)
948
/*****************************************
950
* p r i n t _ x s q l d a
952
*****************************************
956
*****************************************/
957
XSQLVAR *xvar, *end_var;
962
printf("SQLDA Version %d\n", xsqlda->version);
963
printf(" sqldaid %.8s\n", xsqlda->sqldaid);
964
printf(" sqldabc %d\n", xsqlda->sqldabc);
965
printf(" sqln %d\n", xsqlda->sqln);
966
printf(" sqld %d\n", xsqlda->sqld);
968
xvar = xsqlda->sqlvar;
969
for (end_var = xvar + xsqlda->sqld; xvar < end_var; xvar++)
970
printf(" %.31s %.31s type: %d, scale %d, len %d subtype %d\n",
971
xvar->sqlname, xvar->relname, xvar->sqltype,
972
xvar->sqlscale, xvar->sqllen, xvar->sqlsubtype);
990
static void sqlvar_to_xsqlvar(const SQLVAR* sqlvar, XSQLVAR* xsqlvar)
993
xsqlvar->sqltype = sqlvar->sqltype;
994
xsqlvar->sqldata = sqlvar->sqldata;
995
xsqlvar->sqlind = sqlvar->sqlind;
997
xsqlvar->sqlsubtype = 0;
998
xsqlvar->sqlscale = 0;
999
xsqlvar->sqllen = sqlvar->sqllen;
1000
switch (xsqlvar->sqltype & ~1)
1003
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
1004
xsqlvar->sqllen = sizeof(SLONG);
1007
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
1008
xsqlvar->sqllen = sizeof(SSHORT);
1011
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
1012
xsqlvar->sqllen = sizeof(SINT64);
1015
xsqlvar->sqlscale = xsqlvar->sqllen >> 8;
1016
xsqlvar->sqllen = sizeof(ISC_QUAD);
1026
@brief Move an XSQLVAR to an SQLVAR.
1033
static void xsqlvar_to_sqlvar(const XSQLVAR* xsqlvar, SQLVAR* sqlvar)
1036
sqlvar->sqltype = xsqlvar->sqltype;
1037
sqlvar->sqlname_length = xsqlvar->aliasname_length;
1039
// N.B., this may not NULL-terminate the name...
1041
memcpy(sqlvar->sqlname, xsqlvar->aliasname, sizeof(sqlvar->sqlname));
1043
sqlvar->sqllen = xsqlvar->sqllen;
1044
const USHORT scale = xsqlvar->sqlscale << 8;
1045
switch (sqlvar->sqltype & ~1)
1048
sqlvar->sqllen = sizeof(SLONG) | scale;
1051
sqlvar->sqllen = sizeof(SSHORT) | scale;
1054
sqlvar->sqllen = sizeof(SINT64) | scale;
1057
sqlvar->sqllen = sizeof(ISC_QUAD) | scale;
1063
#if !defined(REQUESTER) && !defined(SUPERCLIENT)
1065
UCHAR DSqlDataTypeUtil::maxBytesPerChar(UCHAR charSet)
1067
return METD_get_charset_bpc(request, charSet);
1070
USHORT DSqlDataTypeUtil::getDialect() const
1072
return request->req_client_dialect;