1 ///////////////////////////////////////////////////////////////////////////////
\r
3 // File : $Id: array.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $
\r
4 // Subject : IBPP, Array class implementation
\r
6 ///////////////////////////////////////////////////////////////////////////////
\r
8 // (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)
\r
10 // The contents of this file are subject to the IBPP License (the "License");
\r
11 // you may not use this file except in compliance with the License. You may
\r
12 // obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'
\r
13 // file which must have been distributed along with this file.
\r
15 // This software, distributed under the License, is distributed on an "AS IS"
\r
16 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
\r
17 // License for the specific language governing rights and limitations
\r
18 // under the License.
\r
20 ///////////////////////////////////////////////////////////////////////////////
\r
23 // * Tabulations should be set every four characters when editing this file.
\r
25 ///////////////////////////////////////////////////////////////////////////////
\r
28 #pragma warning(disable: 4786 4996)
\r
30 #pragma warning(disable: 4702)
\r
43 using namespace ibpp_internals;
\r
45 // (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))
\r
47 void ArrayImpl::Describe(const std::string& table, const std::string& column)
\r
50 // throw LogicExceptionImpl("Array::Lookup", _("Array already in use."));
\r
52 throw LogicExceptionImpl("Array::Lookup", _("No Database is attached."));
\r
53 if (mTransaction == 0)
\r
54 throw LogicExceptionImpl("Array::Lookup", _("No Transaction is attached."));
\r
56 ResetId(); // Re-use this array object if was previously assigned
\r
59 (*gds.Call()->m_array_lookup_bounds)(status.Self(), mDatabase->GetHandlePtr(),
\r
60 mTransaction->GetHandlePtr(), const_cast<char*>(table.c_str()),
\r
61 const_cast<char*>(column.c_str()), &mDesc);
\r
62 if (status.Errors())
\r
63 throw SQLExceptionImpl(status, "Array::Lookup",
\r
64 _("isc_array_lookup_bounds failed."));
\r
71 void ArrayImpl::SetBounds(int dim, int low, int high)
\r
74 throw LogicExceptionImpl("Array::SetBounds", _("Array description not set."));
\r
76 throw LogicExceptionImpl("Array::SetBounds", _("No Database is attached."));
\r
77 if (mTransaction == 0)
\r
78 throw LogicExceptionImpl("Array::SetBounds", _("No Transaction is attached."));
\r
79 if (dim < 0 || dim > mDesc.array_desc_dimensions-1)
\r
80 throw LogicExceptionImpl("Array::SetBounds", _("Invalid dimension."));
\r
82 low < mDesc.array_desc_bounds[dim].array_bound_lower ||
\r
83 low > mDesc.array_desc_bounds[dim].array_bound_upper ||
\r
84 high > mDesc.array_desc_bounds[dim].array_bound_upper ||
\r
85 high < mDesc.array_desc_bounds[dim].array_bound_lower)
\r
86 throw LogicExceptionImpl("Array::SetBounds",
\r
87 _("Invalid bounds. You can only narrow the bounds."));
\r
89 mDesc.array_desc_bounds[dim].array_bound_lower = short(low);
\r
90 mDesc.array_desc_bounds[dim].array_bound_upper = short(high);
\r
95 IBPP::SDT ArrayImpl::ElementType()
\r
98 throw LogicExceptionImpl("Array::ElementType",
\r
99 _("Array description not set."));
\r
102 switch (mDesc.array_desc_dtype)
\r
104 case blr_text : value = IBPP::sdString; break;
\r
105 case blr_varying : value = IBPP::sdString; break;
\r
106 case blr_cstring : value = IBPP::sdString; break;
\r
107 case blr_short : value = IBPP::sdSmallint; break;
\r
108 case blr_long : value = IBPP::sdInteger; break;
\r
109 case blr_int64 : value = IBPP::sdLargeint; break;
\r
110 case blr_float : value = IBPP::sdFloat; break;
\r
111 case blr_double : value = IBPP::sdDouble; break;
\r
112 case blr_timestamp : value = IBPP::sdTimestamp; break;
\r
113 case blr_sql_date : value = IBPP::sdDate; break;
\r
114 case blr_sql_time : value = IBPP::sdTime; break;
\r
115 default : throw LogicExceptionImpl("Array::ElementType",
\r
116 _("Found an unknown sqltype !"));
\r
122 int ArrayImpl::ElementSize()
\r
125 throw LogicExceptionImpl("Array::ElementSize",
\r
126 _("Array description not set."));
\r
128 return mDesc.array_desc_length;
\r
131 int ArrayImpl::ElementScale()
\r
134 throw LogicExceptionImpl("Array::ElementScale",
\r
135 _("Array description not set."));
\r
137 return mDesc.array_desc_scale;
\r
140 int ArrayImpl::Dimensions()
\r
143 throw LogicExceptionImpl("Array::Dimensions",
\r
144 _("Array description not set."));
\r
146 return mDesc.array_desc_dimensions;
\r
149 void ArrayImpl::Bounds(int dim, int* low, int* high)
\r
152 throw LogicExceptionImpl("Array::Bounds", _("Array description not set."));
\r
153 if (dim < 0 || dim > mDesc.array_desc_dimensions-1)
\r
154 throw LogicExceptionImpl("Array::Bounds", _("Invalid dimension."));
\r
155 if (low == 0 || high == 0)
\r
156 throw LogicExceptionImpl("Array::Bounds", _("Null reference detected."));
\r
158 *low = mDesc.array_desc_bounds[dim].array_bound_lower;
\r
159 *high = mDesc.array_desc_bounds[dim].array_bound_upper;
\r
167 For an array column of type CHAR(X), the internal type returned or expected is blr_text.
\r
168 In such case, the byte array received or submitted to get/put_slice is formatted in
\r
169 elements of X bytes, which correspond to what is reported in array_desc_length.
\r
170 The elements are not '\0' terminated but are right-padded with spaces ' '.
\r
173 For an array column of type VARCHAR(X), the internal type is blr_varying.
\r
174 The underlying format is rather curious and different than what is used in XSQLDA.
\r
175 The element size is reported in array_desc_length as X.
\r
176 Yet each element of the byte array is expected to be of size X+2 (just as if we were
\r
177 to stuff a short in the first 2 bytes to store the length (as is done with XSQLDA).
\r
178 No. The string of X characters maximum has to be stored in the chunks of X+2 bytes as
\r
179 a zero-terminated c-string. Note that the buffer is indeed one byte too large.
\r
180 Internally, the API probably convert in-place in these chunks the zero-terminated string
\r
181 to a variable-size string with a short in front and the string data non zero-terminated
\r
185 With Interbase 6.0 and Firebird 1.0 (initial april 2002 release), the int64 support is
\r
186 broken regarding the arrays. It is not possible to work on arrays using a datatype stored
\r
187 in an int64, as for instance any NUMERIC(x,0) where x is equal or greater than 10. That's
\r
188 a bug in the engine, not in IBPP, which has been fixed in june 2002. Engines compiled from
\r
189 the current Firebird CVS code as of july 2002 are okay. As will be the 1.01 Firebird version.
\r
190 We have no idea if this is fixed or not in Interbase 6.5 though.
\r
194 void ArrayImpl::ReadTo(IBPP::ADT adtype, void* data, int datacount)
\r
197 throw LogicExceptionImpl("Array::ReadTo", _("Array Id not read from column."));
\r
199 throw LogicExceptionImpl("Array::ReadTo", _("Array description not set."));
\r
200 if (mDatabase == 0)
\r
201 throw LogicExceptionImpl("Array::ReadTo", _("No Database is attached."));
\r
202 if (mTransaction == 0)
\r
203 throw LogicExceptionImpl("Array::ReadTo", _("No Transaction is attached."));
\r
204 if (datacount != mElemCount)
\r
205 throw LogicExceptionImpl("Array::ReadTo", _("Wrong count of array elements"));
\r
208 ISC_LONG lenbuf = mBufferSize;
\r
209 (*gds.Call()->m_array_get_slice)(status.Self(), mDatabase->GetHandlePtr(),
\r
210 mTransaction->GetHandlePtr(), &mId, &mDesc, mBuffer, &lenbuf);
\r
211 if (status.Errors())
\r
212 throw SQLExceptionImpl(status, "Array::ReadTo", _("isc_array_get_slice failed."));
\r
213 if (lenbuf != mBufferSize)
\r
214 throw SQLExceptionImpl(status, "Array::ReadTo", _("Internal buffer size discrepancy."));
\r
216 // Now, convert the types and copy values to the user array...
\r
218 char* src = (char*)mBuffer;
\r
219 char* dst = (char*)data;
\r
221 switch (mDesc.array_desc_dtype)
\r
224 if (adtype == IBPP::adString)
\r
226 for (int i = 0; i < mElemCount; i++)
\r
228 strncpy(dst, src, mElemSize);
\r
229 dst[mElemSize] = '\0';
\r
231 dst += (mElemSize + 1);
\r
234 else if (adtype == IBPP::adBool)
\r
236 for (int i = 0; i < mElemCount; i++)
\r
238 if (*src == 't' || *src == 'T' || *src == 'y' || *src == 'Y' || *src == '1')
\r
239 *(bool*)dst = true;
\r
240 else *(bool*)dst = false;
\r
242 dst += sizeof(bool);
\r
245 else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));
\r
249 if (adtype == IBPP::adString)
\r
251 for (int i = 0; i < mElemCount; i++)
\r
253 len = (int)strlen(src);
\r
254 if (len > mElemSize-2) len = mElemSize-2;
\r
255 strncpy(dst, src, len);
\r
258 dst += (mElemSize - 2 + 1);
\r
261 else if (adtype == IBPP::adBool)
\r
263 for (int i = 0; i < mElemCount; i++)
\r
265 if (*src == 't' || *src == 'T' || *src == 'y' || *src == 'Y' || *src == '1')
\r
266 *(bool*)dst = true;
\r
267 else *(bool*)dst = false;
\r
269 dst += sizeof(bool);
\r
272 else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));
\r
276 if (adtype == IBPP::adBool)
\r
278 for (int i = 0; i < mElemCount; i++)
\r
280 *(bool*)dst = (*(short*)src != 0) ? true : false;
\r
282 dst += sizeof(bool);
\r
285 else if (adtype == IBPP::adInt16)
\r
287 for (int i = 0; i < mElemCount; i++)
\r
289 *(short*)dst = *(short*)src;
\r
291 dst += sizeof(short);
\r
294 else if (adtype == IBPP::adInt32)
\r
296 for (int i = 0; i < mElemCount; i++)
\r
298 *(int*)dst = (int)*(short*)src;
\r
300 dst += sizeof(int);
\r
303 else if (adtype == IBPP::adInt64)
\r
305 for (int i = 0; i < mElemCount; i++)
\r
307 *(int64_t*)dst = (int64_t)*(short*)src;
\r
309 dst += sizeof(int64_t);
\r
312 else if (adtype == IBPP::adFloat)
\r
314 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r
315 double divisor = consts::dscales[-mDesc.array_desc_scale];
\r
316 for (int i = 0; i < mElemCount; i++)
\r
318 *(float*)dst = (float)(*(short*)src / divisor);
\r
320 dst += sizeof(float);
\r
323 else if (adtype == IBPP::adDouble)
\r
325 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r
326 double divisor = consts::dscales[-mDesc.array_desc_scale];
\r
327 for (int i = 0; i < mElemCount; i++)
\r
329 *(double*)dst = (double)(*(short*)src / divisor);
\r
331 dst += sizeof(double);
\r
334 else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));
\r
338 if (adtype == IBPP::adBool)
\r
340 for (int i = 0; i < mElemCount; i++)
\r
342 *(bool*)dst = (*(long*)src != 0) ? true : false;
\r
344 dst += sizeof(bool);
\r
347 else if (adtype == IBPP::adInt16)
\r
349 for (int i = 0; i < mElemCount; i++)
\r
351 if (*(long*)src < consts::min16 || *(long*)src > consts::max16)
\r
352 throw LogicExceptionImpl("Array::ReadTo",
\r
353 _("Out of range numeric conversion !"));
\r
354 *(short*)dst = short(*(long*)src);
\r
356 dst += sizeof(short);
\r
359 else if (adtype == IBPP::adInt32)
\r
361 for (int i = 0; i < mElemCount; i++)
\r
363 *(long*)dst = *(long*)src;
\r
365 dst += sizeof(long);
\r
368 else if (adtype == IBPP::adInt64)
\r
370 for (int i = 0; i < mElemCount; i++)
\r
372 *(int64_t*)dst = (int64_t)*(long*)src;
\r
374 dst += sizeof(int64_t);
\r
377 else if (adtype == IBPP::adFloat)
\r
379 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r
380 double divisor = consts::dscales[-mDesc.array_desc_scale];
\r
381 for (int i = 0; i < mElemCount; i++)
\r
383 *(float*)dst = (float)(*(long*)src / divisor);
\r
385 dst += sizeof(float);
\r
388 else if (adtype == IBPP::adDouble)
\r
390 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r
391 double divisor = consts::dscales[-mDesc.array_desc_scale];
\r
392 for (int i = 0; i < mElemCount; i++)
\r
394 *(double*)dst = (double)(*(long*)src / divisor);
\r
396 dst += sizeof(double);
\r
399 else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));
\r
403 if (adtype == IBPP::adBool)
\r
405 for (int i = 0; i < mElemCount; i++)
\r
407 *(bool*)dst = (*(int64_t*)src != 0) ? true : false;
\r
409 dst += sizeof(bool);
\r
412 else if (adtype == IBPP::adInt16)
\r
414 for (int i = 0; i < mElemCount; i++)
\r
416 if (*(int64_t*)src < consts::min16 || *(int64_t*)src > consts::max16)
\r
417 throw LogicExceptionImpl("Array::ReadTo",
\r
418 _("Out of range numeric conversion !"));
\r
419 *(short*)dst = short(*(int64_t*)src);
\r
421 dst += sizeof(short);
\r
424 else if (adtype == IBPP::adInt32)
\r
426 for (int i = 0; i < mElemCount; i++)
\r
428 if (*(int64_t*)src < consts::min32 || *(int64_t*)src > consts::max32)
\r
429 throw LogicExceptionImpl("Array::ReadTo",
\r
430 _("Out of range numeric conversion !"));
\r
431 *(long*)dst = (long)*(int64_t*)src;
\r
433 dst += sizeof(long);
\r
436 else if (adtype == IBPP::adInt64)
\r
438 for (int i = 0; i < mElemCount; i++)
\r
440 *(int64_t*)dst = *(int64_t*)src;
\r
442 dst += sizeof(int64_t);
\r
445 else if (adtype == IBPP::adFloat)
\r
447 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r
448 double divisor = consts::dscales[-mDesc.array_desc_scale];
\r
449 for (int i = 0; i < mElemCount; i++)
\r
451 *(float*)dst = (float)(*(int64_t*)src / divisor);
\r
453 dst += sizeof(float);
\r
456 else if (adtype == IBPP::adDouble)
\r
458 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r
459 double divisor = consts::dscales[-mDesc.array_desc_scale];
\r
460 for (int i = 0; i < mElemCount; i++)
\r
462 *(double*)dst = (double)(*(int64_t*)src / divisor);
\r
464 dst += sizeof(double);
\r
467 else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));
\r
471 if (adtype != IBPP::adFloat || mDesc.array_desc_scale != 0)
\r
472 throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));
\r
473 for (int i = 0; i < mElemCount; i++)
\r
475 *(float*)dst = *(float*)src;
\r
477 dst += sizeof(float);
\r
482 if (adtype != IBPP::adDouble) throw LogicExceptionImpl("Array::ReadTo",
\r
483 _("Incompatible types."));
\r
484 if (mDesc.array_desc_scale != 0)
\r
486 // Round to scale of NUMERIC(x,y)
\r
487 double divisor = consts::dscales[-mDesc.array_desc_scale];
\r
488 for (int i = 0; i < mElemCount; i++)
\r
490 *(double*)dst = (double)(*(double*)src / divisor);
\r
492 dst += sizeof(double);
\r
497 for (int i = 0; i < mElemCount; i++)
\r
499 *(double*)dst = *(double*)src;
\r
501 dst += sizeof(double);
\r
506 case blr_timestamp :
\r
507 if (adtype != IBPP::adTimestamp) throw LogicExceptionImpl("Array::ReadTo",
\r
508 _("Incompatible types."));
\r
509 for (int i = 0; i < mElemCount; i++)
\r
511 decodeTimestamp(*(IBPP::Timestamp*)dst, *(ISC_TIMESTAMP*)src);
\r
513 dst += sizeof(IBPP::Timestamp);
\r
517 case blr_sql_date :
\r
518 if (adtype != IBPP::adDate) throw LogicExceptionImpl("Array::ReadTo",
\r
519 _("Incompatible types."));
\r
520 for (int i = 0; i < mElemCount; i++)
\r
522 decodeDate(*(IBPP::Date*)dst, *(ISC_DATE*)src);
\r
524 dst += sizeof(IBPP::Date);
\r
528 case blr_sql_time :
\r
529 if (adtype != IBPP::adTime) throw LogicExceptionImpl("Array::ReadTo",
\r
530 _("Incompatible types."));
\r
531 for (int i = 0; i < mElemCount; i++)
\r
533 decodeTime(*(IBPP::Time*)dst, *(ISC_TIME*)src);
\r
535 dst += sizeof(IBPP::Time);
\r
540 throw LogicExceptionImpl("Array::ReadTo", _("Unknown sql type."));
\r
544 void ArrayImpl::WriteFrom(IBPP::ADT adtype, const void* data, int datacount)
\r
547 throw LogicExceptionImpl("Array::WriteFrom", _("Array description not set."));
\r
548 if (mDatabase == 0)
\r
549 throw LogicExceptionImpl("Array::WriteFrom", _("No Database is attached."));
\r
550 if (mTransaction == 0)
\r
551 throw LogicExceptionImpl("Array::WriteFrom", _("No Transaction is attached."));
\r
552 if (datacount != mElemCount)
\r
553 throw LogicExceptionImpl("Array::ReadTo", _("Wrong count of array elements"));
\r
555 // Read user data and convert types to the mBuffer
\r
557 char* src = (char*)data;
\r
558 char* dst = (char*)mBuffer;
\r
560 switch (mDesc.array_desc_dtype)
\r
563 if (adtype == IBPP::adString)
\r
565 for (int i = 0; i < mElemCount; i++)
\r
567 len = (int)strlen(src);
\r
568 if (len > mElemSize) len = mElemSize;
\r
569 strncpy(dst, src, len);
\r
570 while (len < mElemSize) dst[len++] = ' ';
\r
571 src += (mElemSize + 1);
\r
575 else if (adtype == IBPP::adBool)
\r
577 for (int i = 0; i < mElemCount; i++)
\r
579 *dst = *(bool*)src ? 'T' : 'F';
\r
581 while (len < mElemSize) dst[len++] = ' ';
\r
582 src += sizeof(bool);
\r
586 else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));
\r
590 if (adtype == IBPP::adString)
\r
592 for (int i = 0; i < mElemCount; i++)
\r
594 len = (int)strlen(src);
\r
595 if (len > mElemSize-2) len = mElemSize-2;
\r
596 strncpy(dst, src, len);
\r
598 src += (mElemSize - 2 + 1);
\r
602 else if (adtype == IBPP::adBool)
\r
604 for (int i = 0; i < mElemCount; i++)
\r
606 *(short*)dst = (short)1;
\r
607 dst[2] = *(bool*)src ? 'T' : 'F';
\r
608 src += sizeof(bool);
\r
612 else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));
\r
616 if (adtype == IBPP::adBool)
\r
618 for (int i = 0; i < mElemCount; i++)
\r
620 *(short*)dst = short(*(bool*)src ? 1 : 0);
\r
621 src += sizeof(bool);
\r
625 else if (adtype == IBPP::adInt16)
\r
627 for (int i = 0; i < mElemCount; i++)
\r
629 *(short*)dst = *(short*)src;
\r
630 src += sizeof(short);
\r
634 else if (adtype == IBPP::adInt32)
\r
636 for (int i = 0; i < mElemCount; i++)
\r
638 if (*(long*)src < consts::min16 || *(long*)src > consts::max16)
\r
639 throw LogicExceptionImpl("Array::WriteFrom",
\r
640 _("Out of range numeric conversion !"));
\r
641 *(short*)dst = (short)*(int*)src;
\r
642 src += sizeof(int);
\r
646 else if (adtype == IBPP::adInt64)
\r
648 for (int i = 0; i < mElemCount; i++)
\r
650 if (*(int64_t*)src < consts::min16 || *(int64_t*)src > consts::max16)
\r
651 throw LogicExceptionImpl("Array::WriteFrom",
\r
652 _("Out of range numeric conversion !"));
\r
653 *(short*)dst = (short)*(int64_t*)src;
\r
654 src += sizeof(int64_t);
\r
658 else if (adtype == IBPP::adFloat)
\r
660 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r
661 double multiplier = consts::dscales[-mDesc.array_desc_scale];
\r
662 for (int i = 0; i < mElemCount; i++)
\r
665 (short)floor(*(float*)src * multiplier + 0.5);
\r
666 src += sizeof(float);
\r
670 else if (adtype == IBPP::adDouble)
\r
672 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r
673 double multiplier = consts::dscales[-mDesc.array_desc_scale];
\r
674 for (int i = 0; i < mElemCount; i++)
\r
677 (short)floor(*(double*)src * multiplier + 0.5);
\r
678 src += sizeof(double);
\r
682 else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));
\r
686 if (adtype == IBPP::adBool)
\r
688 for (int i = 0; i < mElemCount; i++)
\r
690 *(long*)dst = *(bool*)src ? 1 : 0;
\r
691 src += sizeof(bool);
\r
695 else if (adtype == IBPP::adInt16)
\r
697 for (int i = 0; i < mElemCount; i++)
\r
699 *(long*)dst = *(short*)src;
\r
700 src += sizeof(short);
\r
704 else if (adtype == IBPP::adInt32)
\r
706 for (int i = 0; i < mElemCount; i++)
\r
708 *(long*)dst = *(long*)src;
\r
709 src += sizeof(long);
\r
713 else if (adtype == IBPP::adInt64)
\r
715 for (int i = 0; i < mElemCount; i++)
\r
717 if (*(int64_t*)src < consts::min32 || *(int64_t*)src > consts::max32)
\r
718 throw LogicExceptionImpl("Array::WriteFrom",
\r
719 _("Out of range numeric conversion !"));
\r
720 *(long*)dst = (long)*(int64_t*)src;
\r
721 src += sizeof(int64_t);
\r
725 else if (adtype == IBPP::adFloat)
\r
727 // This SQL_INT is a NUMERIC(x,y), scale it !
\r
728 double multiplier = consts::dscales[-mDesc.array_desc_scale];
\r
729 for (int i = 0; i < mElemCount; i++)
\r
732 (long)floor(*(float*)src * multiplier + 0.5);
\r
733 src += sizeof(float);
\r
737 else if (adtype == IBPP::adDouble)
\r
739 // This SQL_INT is a NUMERIC(x,y), scale it !
\r
740 double multiplier = consts::dscales[-mDesc.array_desc_scale];
\r
741 for (int i = 0; i < mElemCount; i++)
\r
744 (long)floor(*(double*)src * multiplier + 0.5);
\r
745 src += sizeof(double);
\r
749 else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));
\r
753 if (adtype == IBPP::adBool)
\r
755 for (int i = 0; i < mElemCount; i++)
\r
757 *(int64_t*)dst = *(bool*)src ? 1 : 0;
\r
758 src += sizeof(bool);
\r
762 else if (adtype == IBPP::adInt16)
\r
764 for (int i = 0; i < mElemCount; i++)
\r
766 *(int64_t*)dst = *(short*)src;
\r
767 src += sizeof(short);
\r
771 else if (adtype == IBPP::adInt32)
\r
773 for (int i = 0; i < mElemCount; i++)
\r
775 *(int64_t*)dst = *(long*)src;
\r
776 src += sizeof(long);
\r
780 else if (adtype == IBPP::adInt64)
\r
782 for (int i = 0; i < mElemCount; i++)
\r
784 *(int64_t*)dst = *(int64_t*)src;
\r
785 src += sizeof(int64_t);
\r
789 else if (adtype == IBPP::adFloat)
\r
791 // This SQL_INT is a NUMERIC(x,y), scale it !
\r
792 double multiplier = consts::dscales[-mDesc.array_desc_scale];
\r
793 for (int i = 0; i < mElemCount; i++)
\r
796 (int64_t)floor(*(float*)src * multiplier + 0.5);
\r
797 src += sizeof(float);
\r
801 else if (adtype == IBPP::adDouble)
\r
803 // This SQL_INT is a NUMERIC(x,y), scale it !
\r
804 double multiplier = consts::dscales[-mDesc.array_desc_scale];
\r
805 for (int i = 0; i < mElemCount; i++)
\r
808 (int64_t)floor(*(double*)src * multiplier + 0.5);
\r
809 src += sizeof(double);
\r
814 throw LogicExceptionImpl("Array::WriteFrom",
\r
815 _("Incompatible types (blr_int64 and ADT %d)."), (int)adtype);
\r
819 if (adtype != IBPP::adFloat || mDesc.array_desc_scale != 0)
\r
820 throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));
\r
821 for (int i = 0; i < mElemCount; i++)
\r
823 *(float*)dst = *(float*)src;
\r
824 src += sizeof(float);
\r
830 if (adtype != IBPP::adDouble) throw LogicExceptionImpl("Array::WriteFrom",
\r
831 _("Incompatible types."));
\r
832 if (mDesc.array_desc_scale != 0)
\r
834 // Round to scale of NUMERIC(x,y)
\r
835 double multiplier = consts::dscales[-mDesc.array_desc_scale];
\r
836 for (int i = 0; i < mElemCount; i++)
\r
839 floor(*(double*)src * multiplier + 0.5) / multiplier;
\r
840 src += sizeof(double);
\r
846 for (int i = 0; i < mElemCount; i++)
\r
848 *(double*)dst = *(double*)src;
\r
849 src += sizeof(double);
\r
855 case blr_timestamp :
\r
856 if (adtype != IBPP::adTimestamp) throw LogicExceptionImpl("Array::ReadTo",
\r
857 _("Incompatible types."));
\r
858 for (int i = 0; i < mElemCount; i++)
\r
860 encodeTimestamp(*(ISC_TIMESTAMP*)dst, *(IBPP::Timestamp*)src);
\r
861 src += sizeof(IBPP::Timestamp);
\r
866 case blr_sql_date :
\r
867 if (adtype != IBPP::adDate) throw LogicExceptionImpl("Array::ReadTo",
\r
868 _("Incompatible types."));
\r
869 for (int i = 0; i < mElemCount; i++)
\r
871 encodeDate(*(ISC_DATE*)dst, *(IBPP::Date*)src);
\r
872 src += sizeof(IBPP::Date);
\r
877 case blr_sql_time :
\r
878 if (adtype != IBPP::adTime) throw LogicExceptionImpl("Array::ReadTo",
\r
879 _("Incompatible types."));
\r
880 for (int i = 0; i < mElemCount; i++)
\r
882 encodeTime(*(ISC_TIME*)dst, *(IBPP::Time*)src);
\r
883 src += sizeof(IBPP::Time);
\r
889 throw LogicExceptionImpl("Array::WriteFrom", _("Unknown sql type."));
\r
893 ISC_LONG lenbuf = mBufferSize;
\r
894 (*gds.Call()->m_array_put_slice)(status.Self(), mDatabase->GetHandlePtr(),
\r
895 mTransaction->GetHandlePtr(), &mId, &mDesc, mBuffer, &lenbuf);
\r
896 if (status.Errors())
\r
897 throw SQLExceptionImpl(status, "Array::WriteFrom", _("isc_array_put_slice failed."));
\r
898 if (lenbuf != mBufferSize)
\r
899 throw SQLExceptionImpl(status, "Array::WriteFrom", _("Internal buffer size discrepancy."));
\r
902 IBPP::Database ArrayImpl::DatabasePtr() const
\r
904 if (mDatabase == 0) throw LogicExceptionImpl("Array::DatabasePtr",
\r
905 _("No Database is attached."));
\r
909 IBPP::Transaction ArrayImpl::TransactionPtr() const
\r
911 if (mTransaction == 0) throw LogicExceptionImpl("Array::TransactionPtr",
\r
912 _("No Transaction is attached."));
\r
913 return mTransaction;
\r
916 IBPP::IArray* ArrayImpl::AddRef()
\r
918 ASSERTION(mRefCount >= 0);
\r
923 void ArrayImpl::Release()
\r
925 // Release cannot throw, except in DEBUG builds on assertion
\r
926 ASSERTION(mRefCount >= 0);
\r
928 try { if (mRefCount <= 0) delete this; }
\r
932 // (((((((( OBJECT INTERNAL METHODS ))))))))
\r
934 void ArrayImpl::Init()
\r
937 mDescribed = false;
\r
944 void ArrayImpl::SetId(ISC_QUAD* quad)
\r
947 throw LogicExceptionImpl("ArrayImpl::SetId", _("Null Id reference detected."));
\r
949 memcpy(&mId, quad, sizeof(mId));
\r
950 mIdAssigned = true;
\r
953 void ArrayImpl::GetId(ISC_QUAD* quad)
\r
956 throw LogicExceptionImpl("ArrayImpl::GetId", _("Null Id reference detected."));
\r
958 memcpy(quad, &mId, sizeof(mId));
\r
961 void ArrayImpl::ResetId()
\r
963 memset(&mId, 0, sizeof(mId));
\r
964 mIdAssigned = false;
\r
967 void ArrayImpl::AllocArrayBuffer()
\r
969 // Clean previous buffer if any
\r
970 if (mBuffer != 0) delete [] (char*)mBuffer;
\r
973 // Computes total number of elements in the array or slice
\r
975 for (int i = 0; i < mDesc.array_desc_dimensions; i++)
\r
977 mElemCount = mElemCount *
\r
978 (mDesc.array_desc_bounds[i].array_bound_upper -
\r
979 mDesc.array_desc_bounds[i].array_bound_lower + 1);
\r
982 // Allocates a buffer for this count of elements
\r
983 mElemSize = mDesc.array_desc_length;
\r
984 if (mDesc.array_desc_dtype == blr_varying) mElemSize += 2;
\r
985 else if (mDesc.array_desc_dtype == blr_cstring) mElemSize += 1;
\r
986 mBufferSize = mElemSize * mElemCount;
\r
987 mBuffer = (void*) new char[mBufferSize];
\r
990 void ArrayImpl::AttachDatabaseImpl(DatabaseImpl* database)
\r
992 if (database == 0) throw LogicExceptionImpl("Array::AttachDatabase",
\r
993 _("Can't attach a 0 Database object."));
\r
995 if (mDatabase != 0) mDatabase->DetachArrayImpl(this);
\r
996 mDatabase = database;
\r
997 mDatabase->AttachArrayImpl(this);
\r
1000 void ArrayImpl::AttachTransactionImpl(TransactionImpl* transaction)
\r
1002 if (transaction == 0) throw LogicExceptionImpl("Array::AttachTransaction",
\r
1003 _("Can't attach a 0 Transaction object."));
\r
1005 if (mTransaction != 0) mTransaction->DetachArrayImpl(this);
\r
1006 mTransaction = transaction;
\r
1007 mTransaction->AttachArrayImpl(this);
\r
1010 void ArrayImpl::DetachDatabaseImpl()
\r
1012 if (mDatabase == 0) return;
\r
1014 mDatabase->DetachArrayImpl(this);
\r
1018 void ArrayImpl::DetachTransactionImpl()
\r
1020 if (mTransaction == 0) return;
\r
1022 mTransaction->DetachArrayImpl(this);
\r
1026 ArrayImpl::ArrayImpl(DatabaseImpl* database, TransactionImpl* transaction)
\r
1030 AttachDatabaseImpl(database);
\r
1031 if (transaction != 0) AttachTransactionImpl(transaction);
\r
1034 ArrayImpl::~ArrayImpl()
\r
1036 try { if (mTransaction != 0) mTransaction->DetachArrayImpl(this); }
\r
1038 try { if (mDatabase != 0) mDatabase->DetachArrayImpl(this); }
\r
1040 try { if (mBuffer != 0) delete [] (char*)mBuffer; }
\r