8
0
mirror of https://github.com/FirebirdSQL/firebird.git synced 2025-01-24 18:43:02 +01:00
firebird-mirror/src/jrd/cvt2.cpp

794 lines
21 KiB
C++
Raw Normal View History

2001-05-23 15:26:42 +02:00
/*
* PROGRAM: JRD Access Method
2003-10-08 10:42:48 +02:00
* MODULE: cvt2.cpp
2001-05-23 15:26:42 +02:00
* DESCRIPTION: Data mover and converter and comparator, etc.
* Routines used ONLY within engine.
*
* 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 15:03:13 +02:00
*
* 2001.6.18 Claudio Valderrama: Implement comparison on blobs and blobs against
* other datatypes by request from Ann Harrison.
2001-05-23 15:26:42 +02:00
*/
#include "firebird.h"
2001-05-23 15:26:42 +02:00
#include <string.h>
2004-03-22 12:38:23 +01:00
#include "../jrd/common.h"
#include "../jrd/ibase.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/jrd.h"
#include "../jrd/val.h"
#include "../jrd/quad.h"
#include "gen/iberror.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/intl.h"
#include "../jrd/gdsassert.h"
#include "../jrd/all_proto.h"
#include "../jrd/cvt_proto.h"
#include "../jrd/cvt2_proto.h"
#include "../jrd/err_proto.h"
#include "../jrd/intl_proto.h"
#include "../jrd/thd.h"
2002-06-04 21:56:16 +02:00
#include "../jrd/intl_classes.h"
2001-05-23 15:26:42 +02:00
#include "../jrd/gds_proto.h"
2002-06-29 15:03:13 +02:00
/* CVC: I needed them here. */
#include "../jrd/jrd.h"
#include "../jrd/blb_proto.h"
#include "../jrd/tra.h"
#include "../jrd/req.h"
2005-01-25 07:38:58 +01:00
#include "../jrd/constants.h"
#include "../common/utils_proto.h"
2001-05-23 15:26:42 +02:00
using namespace Jrd;
2001-05-23 15:26:42 +02:00
#ifdef VMS
double MTH$CVT_D_G(), MTH$CVT_G_D();
2001-05-23 15:26:42 +02:00
#endif
/* The original order of dsc_type values corresponded to the priority
of conversion (that is, always convert the lesser to the greater
type.) Introduction of dtype_int64 breaks that assumption: its
position on the scale should be between dtype_long and dtype_real, but
the types are integers, and dtype_quad occupies the only available
place. Renumbering all the higher-numbered types would be a major
ODS change and a fundamental discomfort
2005-05-28 00:45:31 +02:00
2001-05-23 15:26:42 +02:00
This table permits us to put the entries in the right order for
comparison purpose, even though isc_int64 had to get number 19, which
is otherwise too high.
This table is used in CVT2_compare, is indexed by dsc_dtype, and
returns the relative priority of types for use when different types
are compared.
*/
2003-12-22 11:00:59 +01:00
static const BYTE compare_priority[] = { dtype_unknown, /* dtype_unknown through dtype_varying */
2001-05-23 15:26:42 +02:00
dtype_text, /* have their natural values stored */
dtype_cstring, /* in the table. */
dtype_varying,
0, 0, /* dtypes and 4, 5 are unused. */
dtype_packed, /* packed through long also have */
dtype_byte, /* their natural values in the table */
dtype_short,
dtype_long,
dtype_quad + 1, /* quad through array all move up */
dtype_real + 1, /* by one to make room for int64 */
dtype_double + 1, /* at its proper place in the table. */
dtype_d_float + 1,
dtype_sql_date + 1,
dtype_sql_time + 1,
dtype_timestamp + 1,
dtype_blob + 1,
dtype_array + 1,
dtype_long + 1
}; /* int64 goes right after long */
SSHORT CVT2_compare(const dsc* arg1, const dsc* arg2, FPTR_ERROR err)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C V T 2 _ c o m p a r e
*
**************************************
*
* Functional description
* Compare two descriptors. Return (-1, 0, 1) if a<b, a=b, or a>b.
*
**************************************/
thread_db* tdbb = NULL;
2001-05-23 15:26:42 +02:00
2005-05-28 00:45:31 +02:00
// AB: Maybe we need a other error-message, but at least throw
// a message when 1 or both input paramters are empty.
if (!arg1 || !arg2) {
BUGCHECK(189); // msg 189 comparison not supported for specified data types.
}
2001-05-23 15:26:42 +02:00
/* Handle the simple (matched) ones first */
if (arg1->dsc_dtype == arg2->dsc_dtype && arg1->dsc_scale == arg2->dsc_scale)
{
const UCHAR* p1 = arg1->dsc_address;
const UCHAR* p2 = arg2->dsc_address;
2001-05-23 15:26:42 +02:00
switch (arg1->dsc_dtype) {
case dtype_short:
if (*(SSHORT *) p1 == *(SSHORT *) p2)
return 0;
if (*(SSHORT *) p1 > *(SSHORT *) p2)
return 1;
return -1;
case dtype_sql_time:
if (*(ULONG *) p1 == *(ULONG *) p2)
return 0;
if (*(ULONG *) p1 > *(ULONG *) p2)
return 1;
return -1;
case dtype_long:
case dtype_sql_date:
if (*(SLONG *) p1 == *(SLONG *) p2)
return 0;
if (*(SLONG *) p1 > *(SLONG *) p2)
return 1;
return -1;
case dtype_quad:
return QUAD_COMPARE(*(SQUAD *) p1, *(SQUAD *) p2);
case dtype_int64:
if (*(SINT64 *) p1 == *(SINT64 *) p2)
return 0;
if (*(SINT64 *) p1 > *(SINT64 *) p2)
return 1;
return -1;
case dtype_timestamp:
if (((SLONG *) p1)[0] > ((SLONG *) p2)[0])
return 1;
if (((SLONG *) p1)[0] < ((SLONG *) p2)[0])
return -1;
if (((ULONG *) p1)[1] > ((ULONG *) p2)[1])
return 1;
if (((ULONG *) p1)[1] < ((ULONG *) p2)[1])
return -1;
return 0;
case dtype_real:
if (*(float *) p1 == *(float *) p2)
return 0;
if (*(float *) p1 > *(float *) p2)
return 1;
return -1;
case DEFAULT_DOUBLE:
if (*(double *) p1 == *(double *) p2)
return 0;
if (*(double *) p1 > *(double *) p2)
return 1;
return -1;
#ifdef VMS
case SPECIAL_DOUBLE:
if (*(double *) p1 == *(double *) p2)
return 0;
if (CNVT_TO_DFLT((double *) p1) > CNVT_TO_DFLT((double *) p2))
return 1;
return -1;
#endif
case dtype_text:
{
/*
* For the sake of optimization, we call INTL_compare
* only when we cannot just do byte-by-byte compare, as is
* done in the foll. code.
* We can do a local compare here, if
* (a) one of the arguments is charset ttype_binary
* OR (b) both of the arguments are char set ttype_none
* OR (c) both of the arguments are char set ttype_ascii
* If any argument is ttype_dynamic, we must see the
* charset of the attachment.
*/
SET_TDBB(tdbb);
CHARSET_ID charset1 = INTL_TTYPE(arg1);
if (charset1 == ttype_dynamic)
charset1 = INTL_charset(tdbb, charset1);
CHARSET_ID charset2 = INTL_TTYPE(arg2);
if (charset2 == ttype_dynamic)
charset2 = INTL_charset(tdbb, charset2);
if ((IS_INTL_DATA(arg1) || IS_INTL_DATA(arg2)) &&
(charset1 != ttype_binary) &&
(charset2 != ttype_binary) &&
((charset1 != ttype_ascii) ||
(charset2 != ttype_ascii)) &&
((charset1 != ttype_none) || (charset2 != ttype_none))
)
{
return INTL_compare(tdbb, arg1, arg2, err);
}
USHORT length;
const UCHAR pad = charset1 == ttype_binary || charset2 == ttype_binary ? '\0' : ' ';
if (arg1->dsc_length >= arg2->dsc_length)
{
length = arg2->dsc_length;
if (length)
do
if (*p1++ != *p2++)
if (p1[-1] > p2[-1])
return 1;
else
return -1;
while (--length);
length = arg1->dsc_length - arg2->dsc_length;
if (length)
do
if (*p1++ != pad)
if (p1[-1] > pad)
return 1;
else
return -1;
while (--length);
return 0;
}
length = arg1->dsc_length;
2001-05-23 15:26:42 +02:00
if (length)
do
if (*p1++ != *p2++)
if (p1[-1] > p2[-1])
return 1;
else
return -1;
while (--length);
length = arg2->dsc_length - arg1->dsc_length;
2001-05-23 15:26:42 +02:00
do
if (*p2++ != pad)
if (pad > p2[-1])
2001-05-23 15:26:42 +02:00
return 1;
else
return -1;
while (--length);
return 0;
}
2001-05-23 15:26:42 +02:00
case dtype_varying:
case dtype_cstring:
case dtype_array:
case dtype_blob:
/* Special processing below */
break;
default:
/* the two arguments have identical dtype and scale, but the
dtype is not one of your defined types! */
2003-11-04 00:59:24 +01:00
fb_assert(FALSE);
2001-05-23 15:26:42 +02:00
break;
} /* switch on dtype */
} /* if dtypes and scales are equal */
/* Handle mixed string comparisons */
if (arg1->dsc_dtype <= dtype_varying && arg2->dsc_dtype <= dtype_varying)
{
2001-05-23 15:26:42 +02:00
/*
* For the sake of optimization, we call INTL_compare
* only when we cannot just do byte-by-byte compare.
* We can do a local compare here, if
* (a) one of the arguments is charset ttype_binary
* OR (b) both of the arguments are char set ttype_none
* OR (c) both of the arguments are char set ttype_ascii
* If any argument is ttype_dynamic, we must see the
* charset of the attachment.
*/
SET_TDBB(tdbb);
CHARSET_ID charset1 = INTL_TTYPE(arg1);
if (charset1 == ttype_dynamic)
charset1 = INTL_charset(tdbb, charset1);
2001-05-23 15:26:42 +02:00
CHARSET_ID charset2 = INTL_TTYPE(arg2);
if (charset2 == ttype_dynamic)
charset2 = INTL_charset(tdbb, charset2);
2001-05-23 15:26:42 +02:00
if ((IS_INTL_DATA(arg1) || IS_INTL_DATA(arg2)) &&
(charset1 != ttype_binary) &&
(charset2 != ttype_binary) &&
((charset1 != ttype_ascii) ||
(charset2 != ttype_ascii)) &&
((charset1 != ttype_none) || (charset2 != ttype_none)))
{
2001-05-23 15:26:42 +02:00
return INTL_compare(tdbb, arg1, arg2, err);
}
2001-05-23 15:26:42 +02:00
UCHAR* p1 = NULL;
UCHAR* p2 = NULL;
USHORT t1, t2; // unused later
USHORT length = CVT_get_string_ptr(arg1, &t1, &p1, NULL, 0, err);
USHORT length2 = CVT_get_string_ptr(arg2, &t2, &p2, NULL, 0, err);
2001-05-23 15:26:42 +02:00
int fill = length - length2;
const UCHAR pad = charset1 == ttype_binary || charset2 == ttype_binary ? '\0' : ' ';
2001-05-23 15:26:42 +02:00
if (length >= length2) {
if (length2)
do
if (*p1++ != *p2++)
if (p1[-1] > p2[-1])
return 1;
else
return -1;
while (--length2);
if (fill > 0)
do
if (*p1++ != pad)
if (p1[-1] > pad)
2001-05-23 15:26:42 +02:00
return 1;
else
return -1;
while (--fill);
return 0;
}
if (length)
do
if (*p1++ != *p2++)
if (p1[-1] > p2[-1])
return 1;
else
return -1;
while (--length);
do
if (*p2++ != pad)
if (pad > p2[-1])
2001-05-23 15:26:42 +02:00
return 1;
else
return -1;
while (++fill);
return 0;
}
2002-06-29 15:03:13 +02:00
/* Handle heterogeneous compares */
2001-05-23 15:26:42 +02:00
if (compare_priority[arg1->dsc_dtype] < compare_priority[arg2->dsc_dtype])
return -CVT2_compare(arg2, arg1, err);
/* At this point, the type of arg1 is guaranteed to be "greater than" arg2,
in the sense that it is the preferred type for comparing the two. */
2001-12-24 03:51:06 +01:00
switch (arg1->dsc_dtype)
{
2001-05-23 15:26:42 +02:00
SLONG date[2];
case dtype_timestamp:
{
DSC desc;
MOVE_CLEAR(&desc, sizeof(desc));
desc.dsc_dtype = dtype_timestamp;
desc.dsc_length = sizeof(date);
desc.dsc_address = (UCHAR *) date;
CVT_move(arg2, &desc, err);
return CVT2_compare(arg1, &desc, err);
}
2001-05-23 15:26:42 +02:00
case dtype_sql_time:
{
DSC desc;
MOVE_CLEAR(&desc, sizeof(desc));
desc.dsc_dtype = dtype_sql_time;
desc.dsc_length = sizeof(date[0]);
desc.dsc_address = (UCHAR *) date;
CVT_move(arg2, &desc, err);
return CVT2_compare(arg1, &desc, err);
}
2001-05-23 15:26:42 +02:00
case dtype_sql_date:
{
DSC desc;
MOVE_CLEAR(&desc, sizeof(desc));
desc.dsc_dtype = dtype_sql_date;
desc.dsc_length = sizeof(date[0]);
desc.dsc_address = (UCHAR *) date;
CVT_move(arg2, &desc, err);
return CVT2_compare(arg1, &desc, err);
}
2001-05-23 15:26:42 +02:00
case dtype_short:
{
SSHORT scale;
if (arg2->dsc_dtype > dtype_varying)
scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
else
scale = arg1->dsc_scale;
const SLONG temp1 = CVT_get_long(arg1, scale, err);
const SLONG temp2 = CVT_get_long(arg2, scale, err);
2001-05-23 15:26:42 +02:00
if (temp1 == temp2)
return 0;
if (temp1 > temp2)
return 1;
return -1;
}
case dtype_long:
/* Since longs may overflow when scaled, use int64 instead */
case dtype_int64:
{
SSHORT scale;
if (arg2->dsc_dtype > dtype_varying)
scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
else
scale = arg1->dsc_scale;
const SINT64 temp1 = CVT_get_int64(arg1, scale, err);
const SINT64 temp2 = CVT_get_int64(arg2, scale, err);
2001-05-23 15:26:42 +02:00
if (temp1 == temp2)
return 0;
if (temp1 > temp2)
return 1;
return -1;
}
case dtype_quad:
{
SSHORT scale;
if (arg2->dsc_dtype > dtype_varying)
scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
else
scale = arg1->dsc_scale;
const SQUAD temp1 = CVT_get_quad(arg1, scale, err);
const SQUAD temp2 = CVT_get_quad(arg2, scale, err);
2001-05-23 15:26:42 +02:00
return QUAD_COMPARE(temp1, temp2);
}
case dtype_real:
{
const float temp1 = (float) CVT_get_double(arg1, err);
const float temp2 = (float) CVT_get_double(arg2, err);
2001-05-23 15:26:42 +02:00
if (temp1 == temp2)
return 0;
if (temp1 > temp2)
return 1;
return -1;
}
case dtype_double:
#ifdef VMS
case dtype_d_float:
#endif
{
const double temp1 = CVT_get_double(arg1, err);
const double temp2 = CVT_get_double(arg2, err);
2001-05-23 15:26:42 +02:00
if (temp1 == temp2)
return 0;
if (temp1 > temp2)
return 1;
return -1;
}
case dtype_blob:
2002-06-29 15:03:13 +02:00
return CVT2_blob_compare(arg1, arg2, err);
2001-05-23 15:26:42 +02:00
case dtype_array:
(*err) (isc_wish_list, isc_arg_gds, isc_blobnotsup,
isc_arg_string, "compare", 0);
2001-05-23 15:26:42 +02:00
break;
default:
BUGCHECK(189); /* msg 189 comparison not supported for specified data types */
break;
}
return 0;
}
SSHORT CVT2_blob_compare(const dsc* arg1, const dsc* arg2, FPTR_ERROR err)
2002-06-29 15:03:13 +02:00
{
/**************************************
*
* C V T 2 _ b l o b _ c o m p a r e
*
**************************************
*
* Functional description
* Compare two blobs. Return (-1, 0, 1) if a<b, a=b, or a>b.
* Alternatively, it will try to compare a blob against a string;
* in this case, the string should be the second argument.
* CVC: Ann Harrison asked for this function to make comparisons more
* complete in the engine.
*
**************************************/
2005-05-28 00:45:31 +02:00
SLONG l1, l2;
USHORT ttype2;
2002-06-29 15:03:13 +02:00
SSHORT ret_val = 0;
thread_db* tdbb = NULL;
2002-06-29 15:03:13 +02:00
SET_TDBB(tdbb);
/* DEV_BLKCHK (node, type_nod); */
if (arg1->dsc_dtype != dtype_blob)
(*err) (isc_wish_list, isc_arg_gds, isc_datnotsup, 0);
2002-06-29 15:03:13 +02:00
USHORT ttype1;
2005-05-28 00:45:31 +02:00
if (arg1->dsc_sub_type == isc_blob_text)
ttype1 = arg1->dsc_blob_ttype(); /* Load blob character set and collation */
else
ttype1 = ttype_binary;
TextType* obj1 = INTL_texttype_lookup(tdbb, ttype1);
2005-05-28 00:45:31 +02:00
ttype1 = obj1->getType();
2002-06-29 15:03:13 +02:00
/* Is arg2 a blob? */
if (arg2->dsc_dtype == dtype_blob)
{
/* Same blob id address? */
if (arg1->dsc_address == arg2->dsc_address)
return 0;
else
{
/* Second test for blob id, checking relation and slot. */
bid* bid1 = (bid*) arg1->dsc_address;
bid* bid2 = (bid*) arg2->dsc_address;
if (*bid1 == *bid2)
{
2002-06-29 15:03:13 +02:00
return 0;
}
2002-06-29 15:03:13 +02:00
}
2005-05-28 00:45:31 +02:00
if (arg2->dsc_sub_type == isc_blob_text)
2005-05-28 00:45:31 +02:00
ttype2 = arg2->dsc_blob_ttype(); /* Load blob character set and collation */
2002-06-29 15:03:13 +02:00
else
2005-05-28 00:45:31 +02:00
ttype2 = ttype_binary;
2002-06-29 15:03:13 +02:00
TextType* obj2 = INTL_texttype_lookup(tdbb, ttype2);
2005-05-28 00:45:31 +02:00
ttype2 = obj2->getType();
2002-06-29 15:03:13 +02:00
2005-05-28 00:45:31 +02:00
if (ttype1 == ttype_binary || ttype2 == ttype_binary)
ttype1 = ttype2 = ttype_binary;
else if (ttype1 == ttype_none || ttype2 == ttype_none)
ttype1 = ttype2 = ttype_none;
obj1 = INTL_texttype_lookup(tdbb, ttype1);
obj2 = INTL_texttype_lookup(tdbb, ttype2);
2002-06-29 15:03:13 +02:00
2005-05-28 00:45:31 +02:00
CharSet* charSet1 = obj1->getCharSet();
CharSet* charSet2 = obj2->getCharSet();
Firebird::HalfStaticArray<UCHAR, BUFFER_LARGE> buffer1;
Firebird::HalfStaticArray<UCHAR, BUFFER_LARGE> buffer2;
fb_assert(BUFFER_LARGE % 4 == 0); // 4 is our maximum character length
UCHAR bpb[] = {isc_bpb_version1,
isc_bpb_source_type, 1, isc_blob_text, isc_bpb_source_interp, 1, 0,
isc_bpb_target_type, 1, isc_blob_text, isc_bpb_target_interp, 1, 0};
USHORT bpbLength = 0;
if (arg1->dsc_sub_type == isc_blob_text && arg2->dsc_sub_type == isc_blob_text)
2002-06-29 15:03:13 +02:00
{
2005-05-28 00:45:31 +02:00
bpb[6] = arg2->dsc_scale; // source charset
bpb[12] = arg1->dsc_scale; // destination charset
bpbLength = sizeof(bpb);
2002-06-29 15:03:13 +02:00
}
2005-05-28 00:45:31 +02:00
blb* blob1 = BLB_open(tdbb, tdbb->tdbb_request->req_transaction, (bid*) arg1->dsc_address);
blb* blob2 = BLB_open2(tdbb, tdbb->tdbb_request->req_transaction, (bid*) arg2->dsc_address, bpbLength, bpb);
if (charSet1->isMultiByte())
2002-06-29 15:03:13 +02:00
{
2005-05-28 00:45:31 +02:00
buffer1.getBuffer(blob1->blb_length);
buffer2.getBuffer(blob2->blb_length / charSet2->minBytesPerChar() * charSet1->maxBytesPerChar());
2003-11-04 00:59:24 +01:00
}
2002-06-29 15:03:13 +02:00
2005-05-28 00:45:31 +02:00
while (ret_val == 0 &&
!(blob1->blb_flags & BLB_eof) && !(blob2->blb_flags & BLB_eof))
2003-11-04 00:59:24 +01:00
{
2005-05-28 00:45:31 +02:00
l1 = BLB_get_data(tdbb, blob1, buffer1.begin(), buffer1.getCapacity(), false);
l2 = BLB_get_data(tdbb, blob2, buffer2.begin(), buffer2.getCapacity(), false);
ret_val = obj1->compare(l1, buffer1.begin(), l2, buffer2.begin());
2002-06-29 15:03:13 +02:00
}
2005-05-28 00:45:31 +02:00
if (ret_val == 0)
2002-06-29 15:03:13 +02:00
{
2005-05-28 00:45:31 +02:00
if ((blob1->blb_flags & BLB_eof) == BLB_eof)
l1 = 0;
if ((blob2->blb_flags & BLB_eof) == BLB_eof)
l2 = 0;
while (ret_val == 0 &&
!((blob1->blb_flags & BLB_eof) == BLB_eof &&
(blob2->blb_flags & BLB_eof) == BLB_eof))
2002-06-29 15:03:13 +02:00
{
2005-05-28 00:45:31 +02:00
if (!(blob1->blb_flags & BLB_eof))
l1 = BLB_get_data(tdbb, blob1, buffer1.begin(), buffer1.getCapacity(), false);
if (!(blob2->blb_flags & BLB_eof))
l2 = BLB_get_data(tdbb, blob2, buffer2.begin(), buffer2.getCapacity(), false);
ret_val = obj1->compare(l1, buffer1.begin(), l2, buffer2.begin());
2002-06-29 15:03:13 +02:00
}
}
2005-05-28 00:45:31 +02:00
2002-06-29 15:03:13 +02:00
BLB_close(tdbb, blob1);
BLB_close(tdbb, blob2);
}
/* We do not accept arrays for now. Maybe InternalArrayDesc in the future. */
2002-06-29 15:03:13 +02:00
else if (arg2->dsc_dtype == dtype_array)
(*err) (isc_wish_list, isc_arg_gds, isc_datnotsup, 0);
2002-06-29 15:03:13 +02:00
/* The second parameter should be a string. */
else
{
if (arg2->dsc_dtype <= dtype_varying)
{
if ((ttype2 = arg2->dsc_ttype()) != ttype_binary)
2005-05-28 00:45:31 +02:00
ttype2 = ttype1;
2002-06-29 15:03:13 +02:00
}
2005-05-28 00:45:31 +02:00
else
ttype2 = ttype1;
if (ttype1 == ttype_binary || ttype2 == ttype_binary)
ttype1 = ttype2 = ttype_binary;
else if (ttype1 == ttype_none || ttype2 == ttype_none)
ttype1 = ttype2 = ttype_none;
obj1 = INTL_texttype_lookup(tdbb, ttype1);
2002-06-29 15:03:13 +02:00
2005-05-28 00:45:31 +02:00
CharSet* charSet1 = obj1->getCharSet();
2002-06-29 15:03:13 +02:00
Firebird::HalfStaticArray<UCHAR, BUFFER_LARGE> buffer1;
2005-05-28 00:45:31 +02:00
UCHAR* p;
MoveBuffer temp_str;
l2 = CVT2_make_string2(arg2, ttype1, &p, temp_str, err);
2002-06-29 15:03:13 +02:00
blb* blob1 = BLB_open(tdbb, tdbb->tdbb_request->req_transaction, (bid*) arg1->dsc_address);
2005-05-28 00:45:31 +02:00
if (charSet1->isMultiByte())
buffer1.getBuffer(blob1->blb_length);
else
buffer1.getBuffer(l2);
l1 = BLB_get_data(tdbb, blob1, buffer1.begin(), buffer1.getCapacity(), false);
ret_val = obj1->compare(l1, buffer1.begin(), l2, p);
while (ret_val == 0 && (blob1->blb_flags & BLB_eof) != BLB_eof)
{
l1 = BLB_get_data(tdbb, blob1, buffer1.begin(), buffer1.getCapacity(), false);
ret_val = obj1->compare(l1, buffer1.begin(), 0, p);
}
2002-06-29 15:03:13 +02:00
BLB_close(tdbb, blob1);
}
2005-05-28 00:45:31 +02:00
2002-06-29 15:03:13 +02:00
return ret_val;
}
void CVT2_get_name(const dsc* desc, TEXT* string, FPTR_ERROR err)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C V T _ g e t _ n a m e
*
**************************************
*
* Functional description
2002-06-29 15:03:13 +02:00
* Get a name (max length 31, NULL terminated) from a descriptor.
2001-05-23 15:26:42 +02:00
*
**************************************/
2005-01-25 07:38:58 +01:00
VARY_STR(MAX_SQL_IDENTIFIER_SIZE) temp; /* 31 bytes + 1 NULL */
2002-10-29 17:27:47 +01:00
const char* p;
2001-05-23 15:26:42 +02:00
USHORT length = CVT_make_string(desc, ttype_metadata, &p,
(vary*) & temp, sizeof(temp), err);
TEXT* const orig_string = string;
for (; length; --length)
2001-05-23 15:26:42 +02:00
*string++ = *p++;
*string = 0;
fb_utils::exact_name(orig_string);
2001-05-23 15:26:42 +02:00
}
2003-10-08 10:42:48 +02:00
USHORT CVT2_make_string2(const dsc* desc,
2001-05-23 15:26:42 +02:00
USHORT to_interp,
2005-05-28 00:45:31 +02:00
UCHAR** address,
Jrd::MoveBuffer& temp,
FPTR_ERROR err)
2001-05-23 15:26:42 +02:00
{
/**************************************
*
* C V T _ m a k e _ s t r i n g 2
*
**************************************
*
* Functional description
*
* Convert the data from the desc to a string in the specified interp.
* The pointer to this string is returned in address.
*
**************************************/
UCHAR* from_buf;
2001-05-23 15:26:42 +02:00
USHORT from_len;
USHORT from_interp;
2003-11-04 00:59:24 +01:00
fb_assert(desc != NULL);
fb_assert(address != NULL);
fb_assert(err != NULL);
2001-05-23 15:26:42 +02:00
if (desc->dsc_dtype == dtype_text) {
from_buf = desc->dsc_address;
from_len = desc->dsc_length;
from_interp = INTL_TTYPE(desc);
}
else if (desc->dsc_dtype == dtype_cstring) {
from_buf = desc->dsc_address;
from_len = MIN(strlen((char *) desc->dsc_address), \
(unsigned) (desc->dsc_length - 1));
from_interp = INTL_TTYPE(desc);
}
else if (desc->dsc_dtype == dtype_varying) {
vary* varying = (vary*) desc->dsc_address;
2001-12-24 03:51:06 +01:00
from_buf = reinterpret_cast<UCHAR*>(varying->vary_string);
2001-05-23 15:26:42 +02:00
from_len =
2003-04-03 22:06:04 +02:00
MIN(varying->vary_length, (USHORT) (desc->dsc_length - sizeof(SSHORT)));
2001-05-23 15:26:42 +02:00
from_interp = INTL_TTYPE(desc);
}
if (desc->dsc_dtype <= dtype_any_text) {
if (to_interp == from_interp) {
*address = from_buf;
return from_len;
}
thread_db* tdbb = JRD_get_thread_data();
const USHORT cs1 = INTL_charset(tdbb, to_interp);
const USHORT cs2 = INTL_charset(tdbb, from_interp);
2001-05-23 15:26:42 +02:00
if (cs1 == cs2) {
*address = from_buf;
return from_len;
}
else {
USHORT length = INTL_convert_bytes(tdbb, cs1, NULL, 0,
cs2, from_buf, from_len, err);
UCHAR* tempptr = temp.getBuffer(length);
2001-05-23 15:26:42 +02:00
length = INTL_convert_bytes(tdbb, cs1, tempptr, length,
cs2, from_buf, from_len, err);
2004-03-07 08:58:55 +01:00
*address = tempptr;
2001-05-23 15:26:42 +02:00
return length;
}
}
/* Not string data, then -- convert value to varying string. */
dsc temp_desc;
2001-05-23 15:26:42 +02:00
MOVE_CLEAR(&temp_desc, sizeof(temp_desc));
temp_desc.dsc_length = temp.getCapacity();
temp_desc.dsc_address = temp.getBuffer(temp_desc.dsc_length);
vary* vtmp = reinterpret_cast<vary*>(temp_desc.dsc_address);
2001-05-23 15:26:42 +02:00
INTL_ASSIGN_TTYPE(&temp_desc, to_interp);
temp_desc.dsc_dtype = dtype_varying;
CVT_move(desc, &temp_desc, err);
*address = reinterpret_cast<UCHAR*>(vtmp->vary_string);
2001-05-23 15:26:42 +02:00
return vtmp->vary_length;
2001-05-23 15:26:42 +02:00
}