| 1 |
/*
|
| 2 |
* PROGRAM: JRD Access Method
|
| 3 |
* MODULE: cvt2.cpp
|
| 4 |
* DESCRIPTION: Data mover and converter and comparator, etc.
|
| 5 |
* Routines used ONLY within engine.
|
| 6 |
*
|
| 7 |
* The contents of this file are subject to the Interbase Public
|
| 8 |
* License Version 1.0 (the "License"); you may not use this file
|
| 9 |
* except in compliance with the License. You may obtain a copy
|
| 10 |
* of the License at http://www.Inprise.com/IPL.html
|
| 11 |
*
|
| 12 |
* Software distributed under the License is distributed on an
|
| 13 |
* "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express
|
| 14 |
* or implied. See the License for the specific language governing
|
| 15 |
* rights and limitations under the License.
|
| 16 |
*
|
| 17 |
* The Original Code was created by Inprise Corporation
|
| 18 |
* and its predecessors. Portions created by Inprise Corporation are
|
| 19 |
* Copyright (C) Inprise Corporation.
|
| 20 |
*
|
| 21 |
* All Rights Reserved.
|
| 22 |
* Contributor(s): ______________________________________.
|
| 23 |
*
|
| 24 |
* 2001.6.18 Claudio Valderrama: Implement comparison on blobs and blobs against
|
| 25 |
* other datatypes by request from Ann Harrison.
|
| 26 |
*/
|
| 27 |
|
| 28 |
#include "firebird.h"
|
| 29 |
#include <string.h>
|
| 30 |
#include "../jrd/common.h"
|
| 31 |
#include "../jrd/ibase.h"
|
| 32 |
|
| 33 |
#include "../jrd/jrd.h"
|
| 34 |
#include "../jrd/val.h"
|
| 35 |
#include "../jrd/quad.h"
|
| 36 |
#include "gen/iberror.h"
|
| 37 |
#include "../jrd/intl.h"
|
| 38 |
#include "../jrd/gdsassert.h"
|
| 39 |
#include "../jrd/cvt_proto.h"
|
| 40 |
#include "../jrd/cvt2_proto.h"
|
| 41 |
#include "../jrd/err_proto.h"
|
| 42 |
#include "../jrd/intl_proto.h"
|
| 43 |
#include "../jrd/thd.h"
|
| 44 |
#include "../jrd/intl_classes.h"
|
| 45 |
#include "../jrd/gds_proto.h"
|
| 46 |
/* CVC: I needed them here. */
|
| 47 |
#include "../jrd/jrd.h"
|
| 48 |
#include "../jrd/blb_proto.h"
|
| 49 |
#include "../jrd/tra.h"
|
| 50 |
#include "../jrd/req.h"
|
| 51 |
#include "../jrd/constants.h"
|
| 52 |
#include "../common/utils_proto.h"
|
| 53 |
|
| 54 |
using namespace Jrd;
|
| 55 |
|
| 56 |
#ifdef VMS
|
| 57 |
double MTH$CVT_D_G(), MTH$CVT_G_D();
|
| 58 |
#endif
|
| 59 |
|
| 60 |
/* The original order of dsc_type values corresponded to the priority
|
| 61 |
of conversion (that is, always convert the lesser to the greater
|
| 62 |
type.) Introduction of dtype_int64 breaks that assumption: its
|
| 63 |
position on the scale should be between dtype_long and dtype_real, but
|
| 64 |
the types are integers, and dtype_quad occupies the only available
|
| 65 |
place. Renumbering all the higher-numbered types would be a major
|
| 66 |
ODS change and a fundamental discomfort
|
| 67 |
|
| 68 |
This table permits us to put the entries in the right order for
|
| 69 |
comparison purpose, even though isc_int64 had to get number 19, which
|
| 70 |
is otherwise too high.
|
| 71 |
|
| 72 |
This table is used in CVT2_compare, is indexed by dsc_dtype, and
|
| 73 |
returns the relative priority of types for use when different types
|
| 74 |
are compared.
|
| 75 |
*/
|
| 76 |
static const BYTE compare_priority[] = { dtype_unknown, /* dtype_unknown through dtype_varying */
|
| 77 |
dtype_text, /* have their natural values stored */
|
| 78 |
dtype_cstring, /* in the table. */
|
| 79 |
dtype_varying,
|
| 80 |
0, 0, /* dtypes and 4, 5 are unused. */
|
| 81 |
dtype_packed, /* packed through long also have */
|
| 82 |
dtype_byte, /* their natural values in the table */
|
| 83 |
dtype_short,
|
| 84 |
dtype_long,
|
| 85 |
dtype_quad + 1, /* quad through array all move up */
|
| 86 |
dtype_real + 1, /* by one to make room for int64 */
|
| 87 |
dtype_double + 1, /* at its proper place in the table. */
|
| 88 |
dtype_d_float + 1,
|
| 89 |
dtype_sql_date + 1,
|
| 90 |
dtype_sql_time + 1,
|
| 91 |
dtype_timestamp + 1,
|
| 92 |
dtype_blob + 1,
|
| 93 |
dtype_array + 1,
|
| 94 |
dtype_long + 1
|
| 95 |
}; /* int64 goes right after long */
|
| 96 |
|
| 97 |
|
| 98 |
SSHORT CVT2_compare(const dsc* arg1, const dsc* arg2, FPTR_ERROR err)
|
| 99 |
{
|
| 100 |
/**************************************
|
| 101 |
*
|
| 102 |
* C V T 2 _ c o m p a r e
|
| 103 |
*
|
| 104 |
**************************************
|
| 105 |
*
|
| 106 |
* Functional description
|
| 107 |
* Compare two descriptors. Return (-1, 0, 1) if a<b, a=b, or a>b.
|
| 108 |
*
|
| 109 |
**************************************/
|
| 110 |
thread_db* tdbb = NULL;
|
| 111 |
|
| 112 |
// AB: Maybe we need a other error-message, but at least throw
|
| 113 |
// a message when 1 or both input paramters are empty.
|
| 114 |
if (!arg1 || !arg2) {
|
| 115 |
BUGCHECK(189); // msg 189 comparison not supported for specified data types.
|
| 116 |
}
|
| 117 |
|
| 118 |
/* Handle the simple (matched) ones first */
|
| 119 |
|
| 120 |
if (arg1->dsc_dtype == arg2->dsc_dtype && arg1->dsc_scale == arg2->dsc_scale)
|
| 121 |
{
|
| 122 |
const UCHAR* p1 = arg1->dsc_address;
|
| 123 |
const UCHAR* p2 = arg2->dsc_address;
|
| 124 |
|
| 125 |
switch (arg1->dsc_dtype) {
|
| 126 |
case dtype_short:
|
| 127 |
if (*(SSHORT *) p1 == *(SSHORT *) p2)
|
| 128 |
return 0;
|
| 129 |
if (*(SSHORT *) p1 > *(SSHORT *) p2)
|
| 130 |
return 1;
|
| 131 |
return -1;
|
| 132 |
|
| 133 |
case dtype_sql_time:
|
| 134 |
if (*(ULONG *) p1 == *(ULONG *) p2)
|
| 135 |
return 0;
|
| 136 |
if (*(ULONG *) p1 > *(ULONG *) p2)
|
| 137 |
return 1;
|
| 138 |
return -1;
|
| 139 |
|
| 140 |
case dtype_long:
|
| 141 |
case dtype_sql_date:
|
| 142 |
if (*(SLONG *) p1 == *(SLONG *) p2)
|
| 143 |
return 0;
|
| 144 |
if (*(SLONG *) p1 > *(SLONG *) p2)
|
| 145 |
return 1;
|
| 146 |
return -1;
|
| 147 |
|
| 148 |
case dtype_quad:
|
| 149 |
return QUAD_COMPARE(*(SQUAD *) p1, *(SQUAD *) p2);
|
| 150 |
|
| 151 |
case dtype_int64:
|
| 152 |
if (*(SINT64 *) p1 == *(SINT64 *) p2)
|
| 153 |
return 0;
|
| 154 |
if (*(SINT64 *) p1 > *(SINT64 *) p2)
|
| 155 |
return 1;
|
| 156 |
return -1;
|
| 157 |
|
| 158 |
case dtype_timestamp:
|
| 159 |
if (((SLONG *) p1)[0] > ((SLONG *) p2)[0])
|
| 160 |
return 1;
|
| 161 |
if (((SLONG *) p1)[0] < ((SLONG *) p2)[0])
|
| 162 |
return -1;
|
| 163 |
if (((ULONG *) p1)[1] > ((ULONG *) p2)[1])
|
| 164 |
return 1;
|
| 165 |
if (((ULONG *) p1)[1] < ((ULONG *) p2)[1])
|
| 166 |
return -1;
|
| 167 |
return 0;
|
| 168 |
|
| 169 |
case dtype_real:
|
| 170 |
if (*(float *) p1 == *(float *) p2)
|
| 171 |
return 0;
|
| 172 |
if (*(float *) p1 > *(float *) p2)
|
| 173 |
return 1;
|
| 174 |
return -1;
|
| 175 |
|
| 176 |
case DEFAULT_DOUBLE:
|
| 177 |
if (*(double *) p1 == *(double *) p2)
|
| 178 |
return 0;
|
| 179 |
if (*(double *) p1 > *(double *) p2)
|
| 180 |
return 1;
|
| 181 |
return -1;
|
| 182 |
|
| 183 |
#ifdef VMS
|
| 184 |
case SPECIAL_DOUBLE:
|
| 185 |
if (*(double *) p1 == *(double *) p2)
|
| 186 |
return 0;
|
| 187 |
if (CNVT_TO_DFLT((double *) p1) > CNVT_TO_DFLT((double *) p2))
|
| 188 |
return 1;
|
| 189 |
return -1;
|
| 190 |
#endif
|
| 191 |
|
| 192 |
case dtype_text:
|
| 193 |
case dtype_varying:
|
| 194 |
case dtype_cstring:
|
| 195 |
case dtype_array:
|
| 196 |
case dtype_blob:
|
| 197 |
/* Special processing below */
|
| 198 |
break;
|
| 199 |
|
| 200 |
default:
|
| 201 |
/* the two arguments have identical dtype and scale, but the
|
| 202 |
dtype is not one of your defined types! */
|
| 203 |
fb_assert(FALSE);
|
| 204 |
break;
|
| 205 |
|
| 206 |
} /* switch on dtype */
|
| 207 |
} /* if dtypes and scales are equal */
|
| 208 |
|
| 209 |
/* Handle mixed string comparisons */
|
| 210 |
|
| 211 |
if (arg1->dsc_dtype <= dtype_varying && arg2->dsc_dtype <= dtype_varying)
|
| 212 |
{
|
| 213 |
/*
|
| 214 |
* For the sake of optimization, we call INTL_compare
|
| 215 |
* only when we cannot just do byte-by-byte compare.
|
| 216 |
* We can do a local compare here, if
|
| 217 |
* (a) one of the arguments is charset ttype_binary
|
| 218 |
* OR (b) both of the arguments are char set ttype_none
|
| 219 |
* OR (c) both of the arguments are char set ttype_ascii
|
| 220 |
* If any argument is ttype_dynamic, we must see the
|
| 221 |
* charset of the attachment.
|
| 222 |
*/
|
| 223 |
|
| 224 |
SET_TDBB(tdbb);
|
| 225 |
CHARSET_ID charset1 = INTL_TTYPE(arg1);
|
| 226 |
if (charset1 == ttype_dynamic)
|
| 227 |
charset1 = INTL_charset(tdbb, charset1);
|
| 228 |
|
| 229 |
CHARSET_ID charset2 = INTL_TTYPE(arg2);
|
| 230 |
if (charset2 == ttype_dynamic)
|
| 231 |
charset2 = INTL_charset(tdbb, charset2);
|
| 232 |
|
| 233 |
if ((IS_INTL_DATA(arg1) || IS_INTL_DATA(arg2)) &&
|
| 234 |
(charset1 != ttype_binary) &&
|
| 235 |
(charset2 != ttype_binary) &&
|
| 236 |
((charset1 != ttype_ascii) ||
|
| 237 |
(charset2 != ttype_ascii)) &&
|
| 238 |
((charset1 != ttype_none) || (charset2 != ttype_none)))
|
| 239 |
{
|
| 240 |
return INTL_compare(tdbb, arg1, arg2, err);
|
| 241 |
}
|
| 242 |
|
| 243 |
UCHAR* p1 = NULL;
|
| 244 |
UCHAR* p2 = NULL;
|
| 245 |
USHORT t1, t2; // unused later
|
| 246 |
USHORT length = CVT_get_string_ptr(arg1, &t1, &p1, NULL, 0, err);
|
| 247 |
USHORT length2 = CVT_get_string_ptr(arg2, &t2, &p2, NULL, 0, err);
|
| 248 |
|
| 249 |
int fill = length - length2;
|
| 250 |
const UCHAR pad = charset1 == ttype_binary || charset2 == ttype_binary ? '\0' : ' ';
|
| 251 |
if (length >= length2) {
|
| 252 |
if (length2)
|
| 253 |
do
|
| 254 |
if (*p1++ != *p2++)
|
| 255 |
if (p1[-1] > p2[-1])
|
| 256 |
return 1;
|
| 257 |
else
|
| 258 |
return -1;
|
| 259 |
while (--length2);
|
| 260 |
if (fill > 0)
|
| 261 |
do
|
| 262 |
if (*p1++ != pad)
|
| 263 |
if (p1[-1] > pad)
|
| 264 |
return 1;
|
| 265 |
else
|
| 266 |
return -1;
|
| 267 |
while (--fill);
|
| 268 |
return 0;
|
| 269 |
}
|
| 270 |
if (length)
|
| 271 |
do
|
| 272 |
if (*p1++ != *p2++)
|
| 273 |
if (p1[-1] > p2[-1])
|
| 274 |
return 1;
|
| 275 |
else
|
| 276 |
return -1;
|
| 277 |
while (--length);
|
| 278 |
do
|
| 279 |
if (*p2++ != pad)
|
| 280 |
if (pad > p2[-1])
|
| 281 |
return 1;
|
| 282 |
else
|
| 283 |
return -1;
|
| 284 |
while (++fill);
|
| 285 |
return 0;
|
| 286 |
}
|
| 287 |
|
| 288 |
/* Handle heterogeneous compares */
|
| 289 |
|
| 290 |
if (compare_priority[arg1->dsc_dtype] < compare_priority[arg2->dsc_dtype])
|
| 291 |
return -CVT2_compare(arg2, arg1, err);
|
| 292 |
|
| 293 |
/* At this point, the type of arg1 is guaranteed to be "greater than" arg2,
|
| 294 |
in the sense that it is the preferred type for comparing the two. */
|
| 295 |
|
| 296 |
switch (arg1->dsc_dtype)
|
| 297 |
{
|
| 298 |
SLONG date[2];
|
| 299 |
|
| 300 |
case dtype_timestamp:
|
| 301 |
{
|
| 302 |
DSC desc;
|
| 303 |
MOVE_CLEAR(&desc, sizeof(desc));
|
| 304 |
desc.dsc_dtype = dtype_timestamp;
|
| 305 |
desc.dsc_length = sizeof(date);
|
| 306 |
desc.dsc_address = (UCHAR *) date;
|
| 307 |
CVT_move(arg2, &desc, err);
|
| 308 |
return CVT2_compare(arg1, &desc, err);
|
| 309 |
}
|
| 310 |
|
| 311 |
case dtype_sql_time:
|
| 312 |
{
|
| 313 |
DSC desc;
|
| 314 |
MOVE_CLEAR(&desc, sizeof(desc));
|
| 315 |
desc.dsc_dtype = dtype_sql_time;
|
| 316 |
desc.dsc_length = sizeof(date[0]);
|
| 317 |
desc.dsc_address = (UCHAR *) date;
|
| 318 |
CVT_move(arg2, &desc, err);
|
| 319 |
return CVT2_compare(arg1, &desc, err);
|
| 320 |
}
|
| 321 |
|
| 322 |
case dtype_sql_date:
|
| 323 |
{
|
| 324 |
DSC desc;
|
| 325 |
MOVE_CLEAR(&desc, sizeof(desc));
|
| 326 |
desc.dsc_dtype = dtype_sql_date;
|
| 327 |
desc.dsc_length = sizeof(date[0]);
|
| 328 |
desc.dsc_address = (UCHAR *) date;
|
| 329 |
CVT_move(arg2, &desc, err);
|
| 330 |
return CVT2_compare(arg1, &desc, err);
|
| 331 |
}
|
| 332 |
|
| 333 |
case dtype_short:
|
| 334 |
{
|
| 335 |
SSHORT scale;
|
| 336 |
if (arg2->dsc_dtype > dtype_varying)
|
| 337 |
scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
| 338 |
else
|
| 339 |
scale = arg1->dsc_scale;
|
| 340 |
const SLONG temp1 = CVT_get_long(arg1, scale, err);
|
| 341 |
const SLONG temp2 = CVT_get_long(arg2, scale, err);
|
| 342 |
if (temp1 == temp2)
|
| 343 |
return 0;
|
| 344 |
if (temp1 > temp2)
|
| 345 |
return 1;
|
| 346 |
return -1;
|
| 347 |
}
|
| 348 |
|
| 349 |
case dtype_long:
|
| 350 |
/* Since longs may overflow when scaled, use int64 instead */
|
| 351 |
case dtype_int64:
|
| 352 |
{
|
| 353 |
SSHORT scale;
|
| 354 |
if (arg2->dsc_dtype > dtype_varying)
|
| 355 |
scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
| 356 |
else
|
| 357 |
scale = arg1->dsc_scale;
|
| 358 |
const SINT64 temp1 = CVT_get_int64(arg1, scale, err);
|
| 359 |
const SINT64 temp2 = CVT_get_int64(arg2, scale, err);
|
| 360 |
if (temp1 == temp2)
|
| 361 |
return 0;
|
| 362 |
if (temp1 > temp2)
|
| 363 |
return 1;
|
| 364 |
return -1;
|
| 365 |
}
|
| 366 |
|
| 367 |
case dtype_quad:
|
| 368 |
{
|
| 369 |
SSHORT scale;
|
| 370 |
if (arg2->dsc_dtype > dtype_varying)
|
| 371 |
scale = MIN(arg1->dsc_scale, arg2->dsc_scale);
|
| 372 |
else
|
| 373 |
scale = arg1->dsc_scale;
|
| 374 |
const SQUAD temp1 = CVT_get_quad(arg1, scale, err);
|
| 375 |
const SQUAD temp2 = CVT_get_quad(arg2, scale, err);
|
| 376 |
return QUAD_COMPARE(temp1, temp2);
|
| 377 |
}
|
| 378 |
|
| 379 |
case dtype_real:
|
| 380 |
{
|
| 381 |
const float temp1 = (float) CVT_get_double(arg1, err);
|
| 382 |
const float temp2 = (float) CVT_get_double(arg2, err);
|
| 383 |
if (temp1 == temp2)
|
| 384 |
return 0;
|
| 385 |
if (temp1 > temp2)
|
| 386 |
return 1;
|
| 387 |
return -1;
|
| 388 |
}
|
| 389 |
|
| 390 |
case dtype_double:
|
| 391 |
#ifdef VMS
|
| 392 |
case dtype_d_float:
|
| 393 |
#endif
|
| 394 |
{
|
| 395 |
const double temp1 = CVT_get_double(arg1, err);
|
| 396 |
const double temp2 = CVT_get_double(arg2, err);
|
| 397 |
if (temp1 == temp2)
|
| 398 |
return 0;
|
| 399 |
if (temp1 > temp2)
|
| 400 |
return 1;
|
| 401 |
return -1;
|
| 402 |
}
|
| 403 |
|
| 404 |
case dtype_blob:
|
| 405 |
return CVT2_blob_compare(arg1, arg2, err);
|
| 406 |
|
| 407 |
case dtype_array:
|
| 408 |
(*err) (isc_wish_list, isc_arg_gds, isc_blobnotsup,
|
| 409 |
isc_arg_string, "compare", 0);
|
| 410 |
break;
|
| 411 |
|
| 412 |
default:
|
| 413 |
BUGCHECK(189); /* msg 189 comparison not supported for specified data types */
|
| 414 |
break;
|
| 415 |
}
|
| 416 |
return 0;
|
| 417 |
}
|
| 418 |
|
| 419 |
|
| 420 |
SSHORT CVT2_blob_compare(const dsc* arg1, const dsc* arg2, FPTR_ERROR err)
|
| 421 |
{
|
| 422 |
/**************************************
|
| 423 |
*
|
| 424 |
* C V T 2 _ b l o b _ c o m p a r e
|
| 425 |
*
|
| 426 |
**************************************
|
| 427 |
*
|
| 428 |
* Functional description
|
| 429 |
* Compare two blobs. Return (-1, 0, 1) if a<b, a=b, or a>b.
|
| 430 |
* Alternatively, it will try to compare a blob against a string;
|
| 431 |
* in this case, the string should be the second argument.
|
| 432 |
* CVC: Ann Harrison asked for this function to make comparisons more
|
| 433 |
* complete in the engine.
|
| 434 |
*
|
| 435 |
**************************************/
|
| 436 |
|
| 437 |
SLONG l1, l2;
|
| 438 |
USHORT ttype2;
|
| 439 |
SSHORT ret_val = 0;
|
| 440 |
|
| 441 |
thread_db* tdbb = NULL;
|
| 442 |
SET_TDBB(tdbb);
|
| 443 |
|
| 444 |
/* DEV_BLKCHK (node, type_nod); */
|
| 445 |
|
| 446 |
if (arg1->dsc_dtype != dtype_blob)
|
| 447 |
(*err) (isc_wish_list, isc_arg_gds, isc_datnotsup, 0);
|
| 448 |
|
| 449 |
USHORT ttype1;
|
| 450 |
if (arg1->dsc_sub_type == isc_blob_text)
|
| 451 |
ttype1 = arg1->dsc_blob_ttype(); /* Load blob character set and collation */
|
| 452 |
else
|
| 453 |
ttype1 = ttype_binary;
|
| 454 |
|
| 455 |
TextType* obj1 = INTL_texttype_lookup(tdbb, ttype1);
|
| 456 |
ttype1 = obj1->getType();
|
| 457 |
|
| 458 |
/* Is arg2 a blob? */
|
| 459 |
if (arg2->dsc_dtype == dtype_blob)
|
| 460 |
{
|
| 461 |
/* Same blob id address? */
|
| 462 |
if (arg1->dsc_address == arg2->dsc_address)
|
| 463 |
return 0;
|
| 464 |
else
|
| 465 |
{
|
| 466 |
/* Second test for blob id, checking relation and slot. */
|
| 467 |
bid* bid1 = (bid*) arg1->dsc_address;
|
| 468 |
bid* bid2 = (bid*) arg2->dsc_address;
|
| 469 |
if (*bid1 == *bid2)
|
| 470 |
{
|
| 471 |
return 0;
|
| 472 |
}
|
| 473 |
}
|
| 474 |
|
| 475 |
if (arg2->dsc_sub_type == isc_blob_text)
|
| 476 |
ttype2 = arg2->dsc_blob_ttype(); /* Load blob character set and collation */
|
| 477 |
else
|
| 478 |
ttype2 = ttype_binary;
|
| 479 |
|
| 480 |
TextType* obj2 = INTL_texttype_lookup(tdbb, ttype2);
|
| 481 |
ttype2 = obj2->getType();
|
| 482 |
|
| 483 |
if (ttype1 == ttype_binary || ttype2 == ttype_binary)
|
| 484 |
ttype1 = ttype2 = ttype_binary;
|
| 485 |
else if (ttype1 == ttype_none || ttype2 == ttype_none)
|
| 486 |
ttype1 = ttype2 = ttype_none;
|
| 487 |
|
| 488 |
obj1 = INTL_texttype_lookup(tdbb, ttype1);
|
| 489 |
obj2 = INTL_texttype_lookup(tdbb, ttype2);
|
| 490 |
|
| 491 |
CharSet* charSet1 = obj1->getCharSet();
|
| 492 |
CharSet* charSet2 = obj2->getCharSet();
|
| 493 |
|
| 494 |
Firebird::HalfStaticArray<UCHAR, BUFFER_LARGE> buffer1;
|
| 495 |
Firebird::HalfStaticArray<UCHAR, BUFFER_LARGE> buffer2;
|
| 496 |
fb_assert(BUFFER_LARGE % 4 == 0); // 4 is our maximum character length
|
| 497 |
|
| 498 |
UCHAR bpb[] = {isc_bpb_version1,
|
| 499 |
isc_bpb_source_type, 1, isc_blob_text, isc_bpb_source_interp, 1, 0,
|
| 500 |
isc_bpb_target_type, 1, isc_blob_text, isc_bpb_target_interp, 1, 0};
|
| 501 |
USHORT bpbLength = 0;
|
| 502 |
|
| 503 |
if (arg1->dsc_sub_type == isc_blob_text && arg2->dsc_sub_type == isc_blob_text)
|
| 504 |
{
|
| 505 |
bpb[6] = arg2->dsc_scale; // source charset
|
| 506 |
bpb[12] = arg1->dsc_scale; // destination charset
|
| 507 |
bpbLength = sizeof(bpb);
|
| 508 |
}
|
| 509 |
|
| 510 |
blb* blob1 = BLB_open(tdbb, tdbb->tdbb_request->req_transaction, (bid*) arg1->dsc_address);
|
| 511 |
blb* blob2 = BLB_open2(tdbb, tdbb->tdbb_request->req_transaction, (bid*) arg2->dsc_address, bpbLength, bpb);
|
| 512 |
|
| 513 |
if (charSet1->isMultiByte())
|
| 514 |
{
|
| 515 |
buffer1.getBuffer(blob1->blb_length);
|
| 516 |
buffer2.getBuffer(blob2->blb_length / charSet2->minBytesPerChar() * charSet1->maxBytesPerChar());
|
| 517 |
}
|
| 518 |
|
| 519 |
while (ret_val == 0 &&
|
| 520 |
!(blob1->blb_flags & BLB_eof) && !(blob2->blb_flags & BLB_eof))
|
| 521 |
{
|
| 522 |
l1 = BLB_get_data(tdbb, blob1, buffer1.begin(), buffer1.getCapacity(), false);
|
| 523 |
l2 = BLB_get_data(tdbb, blob2, buffer2.begin(), buffer2.getCapacity(), false);
|
| 524 |
|
| 525 |
ret_val = obj1->compare(l1, buffer1.begin(), l2, buffer2.begin());
|
| 526 |
}
|
| 527 |
|
| 528 |
if (ret_val == 0)
|
| 529 |
{
|
| 530 |
if ((blob1->blb_flags & BLB_eof) == BLB_eof)
|
| 531 |
l1 = 0;
|
| 532 |
|
| 533 |
if ((blob2->blb_flags & BLB_eof) == BLB_eof)
|
| 534 |
l2 = 0;
|
| 535 |
|
| 536 |
while (ret_val == 0 &&
|
| 537 |
!((blob1->blb_flags & BLB_eof) == BLB_eof &&
|
| 538 |
(blob2->blb_flags & BLB_eof) == BLB_eof))
|
| 539 |
{
|
| 540 |
if (!(blob1->blb_flags & BLB_eof))
|
| 541 |
l1 = BLB_get_data(tdbb, blob1, buffer1.begin(), buffer1.getCapacity(), false);
|
| 542 |
|
| 543 |
if (!(blob2->blb_flags & BLB_eof))
|
| 544 |
l2 = BLB_get_data(tdbb, blob2, buffer2.begin(), buffer2.getCapacity(), false);
|
| 545 |
|
| 546 |
ret_val = obj1->compare(l1, buffer1.begin(), l2, buffer2.begin());
|
| 547 |
}
|
| 548 |
}
|
| 549 |
|
| 550 |
BLB_close(tdbb, blob1);
|
| 551 |
BLB_close(tdbb, blob2);
|
| 552 |
}
|
| 553 |
/* We do not accept arrays for now. Maybe InternalArrayDesc in the future. */
|
| 554 |
else if (arg2->dsc_dtype == dtype_array)
|
| 555 |
(*err) (isc_wish_list, isc_arg_gds, isc_datnotsup, 0);
|
| 556 |
/* The second parameter should be a string. */
|
| 557 |
else
|
| 558 |
{
|
| 559 |
if (arg2->dsc_dtype <= dtype_varying)
|
| 560 |
{
|
| 561 |
if ((ttype2 = arg2->dsc_ttype()) != ttype_binary)
|
| 562 |
ttype2 = ttype1;
|
| 563 |
}
|
| 564 |
else
|
| 565 |
ttype2 = ttype1;
|
| 566 |
|
| 567 |
if (ttype1 == ttype_binary || ttype2 == ttype_binary)
|
| 568 |
ttype1 = ttype2 = ttype_binary;
|
| 569 |
else if (ttype1 == ttype_none || ttype2 == ttype_none)
|
| 570 |
ttype1 = ttype2 = ttype_none;
|
| 571 |
|
| 572 |
obj1 = INTL_texttype_lookup(tdbb, ttype1);
|
| 573 |
|
| 574 |
CharSet* charSet1 = obj1->getCharSet();
|
| 575 |
|
| 576 |
Firebird::HalfStaticArray<UCHAR, BUFFER_LARGE> buffer1;
|
| 577 |
UCHAR* p;
|
| 578 |
MoveBuffer temp_str;
|
| 579 |
|
| 580 |
l2 = CVT2_make_string2(arg2, ttype1, &p, temp_str, err);
|
| 581 |
|
| 582 |
blb* blob1 = BLB_open(tdbb, tdbb->tdbb_request->req_transaction, (bid*) arg1->dsc_address);
|
| 583 |
|
| 584 |
if (charSet1->isMultiByte())
|
| 585 |
buffer1.getBuffer(blob1->blb_length);
|
| 586 |
else
|
| 587 |
buffer1.getBuffer(l2);
|
| 588 |
|
| 589 |
l1 = BLB_get_data(tdbb, blob1, buffer1.begin(), buffer1.getCapacity(), false);
|
| 590 |
ret_val = obj1->compare(l1, buffer1.begin(), l2, p);
|
| 591 |
|
| 592 |
while (ret_val == 0 && (blob1->blb_flags & BLB_eof) != BLB_eof)
|
| 593 |
{
|
| 594 |
l1 = BLB_get_data(tdbb, blob1, buffer1.begin(), buffer1.getCapacity(), false);
|
| 595 |
ret_val = obj1->compare(l1, buffer1.begin(), 0, p);
|
| 596 |
}
|
| 597 |
|
| 598 |
BLB_close(tdbb, blob1);
|
| 599 |
}
|
| 600 |
|
| 601 |
return ret_val;
|
| 602 |
}
|
| 603 |
|
| 604 |
|
| 605 |
void CVT2_get_name(const dsc* desc, TEXT* string, FPTR_ERROR err)
|
| 606 |
{
|
| 607 |
/**************************************
|
| 608 |
*
|
| 609 |
* C V T _ g e t _ n a m e
|
| 610 |
*
|
| 611 |
**************************************
|
| 612 |
*
|
| 613 |
* Functional description
|
| 614 |
* Get a name (max length 31, NULL terminated) from a descriptor.
|
| 615 |
*
|
| 616 |
**************************************/
|
| 617 |
VARY_STR(MAX_SQL_IDENTIFIER_SIZE) temp; /* 31 bytes + 1 NULL */
|
| 618 |
const char* p;
|
| 619 |
|
| 620 |
USHORT length = CVT_make_string(desc, ttype_metadata, &p,
|
| 621 |
(vary*) & temp, sizeof(temp), err);
|
| 622 |
TEXT* const orig_string = string;
|
| 623 |
for (; length; --length)
|
| 624 |
*string++ = *p++;
|
| 625 |
|
| 626 |
*string = 0;
|
| 627 |
fb_utils::exact_name(orig_string);
|
| 628 |
}
|
| 629 |
|
| 630 |
|
| 631 |
USHORT CVT2_make_string2(const dsc* desc,
|
| 632 |
USHORT to_interp,
|
| 633 |
UCHAR** address,
|
| 634 |
Jrd::MoveBuffer& temp,
|
| 635 |
FPTR_ERROR err)
|
| 636 |
{
|
| 637 |
/**************************************
|
| 638 |
*
|
| 639 |
* C V T _ m a k e _ s t r i n g 2
|
| 640 |
*
|
| 641 |
**************************************
|
| 642 |
*
|
| 643 |
* Functional description
|
| 644 |
*
|
| 645 |
* Convert the data from the desc to a string in the specified interp.
|
| 646 |
* The pointer to this string is returned in address.
|
| 647 |
*
|
| 648 |
**************************************/
|
| 649 |
UCHAR* from_buf;
|
| 650 |
USHORT from_len;
|
| 651 |
USHORT from_interp;
|
| 652 |
|
| 653 |
fb_assert(desc != NULL);
|
| 654 |
fb_assert(address != NULL);
|
| 655 |
fb_assert(err != NULL);
|
| 656 |
|
| 657 |
if (desc->dsc_dtype == dtype_text) {
|
| 658 |
from_buf = desc->dsc_address;
|
| 659 |
from_len = desc->dsc_length;
|
| 660 |
from_interp = INTL_TTYPE(desc);
|
| 661 |
}
|
| 662 |
|
| 663 |
else if (desc->dsc_dtype == dtype_cstring) {
|
| 664 |
from_buf = desc->dsc_address;
|
| 665 |
from_len = MIN(strlen((char *) desc->dsc_address), \
|
| 666 |
(unsigned) (desc->dsc_length - 1));
|
| 667 |
from_interp = INTL_TTYPE(desc);
|
| 668 |
}
|
| 669 |
|
| 670 |
else if (desc->dsc_dtype == dtype_varying) {
|
| 671 |
vary* varying = (vary*) desc->dsc_address;
|
| 672 |
from_buf = reinterpret_cast<UCHAR*>(varying->vary_string);
|
| 673 |
from_len =
|
| 674 |
MIN(varying->vary_length, (USHORT) (desc->dsc_length - sizeof(SSHORT)));
|
| 675 |
from_interp = INTL_TTYPE(desc);
|
| 676 |
}
|
| 677 |
|
| 678 |
if (desc->dsc_dtype <= dtype_any_text) {
|
| 679 |
|
| 680 |
if (to_interp == from_interp) {
|
| 681 |
*address = from_buf;
|
| 682 |
return from_len;
|
| 683 |
}
|
| 684 |
|
| 685 |
thread_db* tdbb = JRD_get_thread_data();
|
| 686 |
const USHORT cs1 = INTL_charset(tdbb, to_interp);
|
| 687 |
const USHORT cs2 = INTL_charset(tdbb, from_interp);
|
| 688 |
if (cs1 == cs2) {
|
| 689 |
*address = from_buf;
|
| 690 |
return from_len;
|
| 691 |
}
|
| 692 |
else {
|
| 693 |
USHORT length = INTL_convert_bytes(tdbb, cs1, NULL, 0,
|
| 694 |
cs2, from_buf, from_len, err);
|
| 695 |
UCHAR* tempptr = temp.getBuffer(length);
|
| 696 |
length = INTL_convert_bytes(tdbb, cs1, tempptr, length,
|
| 697 |
cs2, from_buf, from_len, err);
|
| 698 |
*address = tempptr;
|
| 699 |
return length;
|
| 700 |
}
|
| 701 |
}
|
| 702 |
|
| 703 |
/* Not string data, then -- convert value to varying string. */
|
| 704 |
|
| 705 |
dsc temp_desc;
|
| 706 |
MOVE_CLEAR(&temp_desc, sizeof(temp_desc));
|
| 707 |
temp_desc.dsc_length = temp.getCapacity();
|
| 708 |
temp_desc.dsc_address = temp.getBuffer(temp_desc.dsc_length);
|
| 709 |
vary* vtmp = reinterpret_cast<vary*>(temp_desc.dsc_address);
|
| 710 |
INTL_ASSIGN_TTYPE(&temp_desc, to_interp);
|
| 711 |
temp_desc.dsc_dtype = dtype_varying;
|
| 712 |
CVT_move(desc, &temp_desc, err);
|
| 713 |
*address = reinterpret_cast<UCHAR*>(vtmp->vary_string);
|
| 714 |
|
| 715 |
return vtmp->vary_length;
|
| 716 |
}
|