]> git.stg.codes - stg.git/blobdiff - libs/ibpp/array.cpp
Port to CMake, get rid of os_int.h.
[stg.git] / libs / ibpp / array.cpp
diff --git a/libs/ibpp/array.cpp b/libs/ibpp/array.cpp
new file mode 100644 (file)
index 0000000..2dc7ab2
--- /dev/null
@@ -0,0 +1,1046 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: array.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $\r
+//     Subject : IBPP, Array class implementation\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
+//\r
+//     The contents of this file are subject to the IBPP License (the "License");\r
+//     you may not use this file except in compliance with the License.  You may\r
+//     obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'\r
+//     file which must have been distributed along with this file.\r
+//\r
+//     This software, distributed under the License, is distributed on an "AS IS"\r
+//     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the\r
+//     License for the specific language governing rights and limitations\r
+//     under the License.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     COMMENTS\r
+//     * Tabulations should be set every four characters when editing this file.\r
+//\r
+///////////////////////////////////////////////////////////////////////////////\r
+\r
+#ifdef _MSC_VER\r
+#pragma warning(disable: 4786 4996)\r
+#ifndef _DEBUG\r
+#pragma warning(disable: 4702)\r
+#endif\r
+#endif\r
+\r
+#include "_ibpp.h"\r
+\r
+#ifdef HAS_HDRSTOP\r
+#pragma hdrstop\r
+#endif\r
+\r
+#include <math.h>\r
+#include <cstring>\r
+\r
+using namespace ibpp_internals;\r
+\r
+//     (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
+\r
+void ArrayImpl::Describe(const std::string& table, const std::string& column)\r
+{\r
+       //if (mIdAssigned)\r
+       //      throw LogicExceptionImpl("Array::Lookup", _("Array already in use."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Array::Lookup", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Array::Lookup", _("No Transaction is attached."));\r
+\r
+       ResetId();      // Re-use this array object if was previously assigned\r
+\r
+       IBS status;\r
+       (*gds.Call()->m_array_lookup_bounds)(status.Self(), mDatabase->GetHandlePtr(),\r
+               mTransaction->GetHandlePtr(), const_cast<char*>(table.c_str()),\r
+                       const_cast<char*>(column.c_str()), &mDesc);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Array::Lookup",\r
+                       _("isc_array_lookup_bounds failed."));\r
+\r
+       AllocArrayBuffer();\r
+\r
+       mDescribed = true;\r
+}\r
+\r
+void ArrayImpl::SetBounds(int dim, int low, int high)\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::SetBounds", _("Array description not set."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Array::SetBounds", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Array::SetBounds", _("No Transaction is attached."));\r
+       if (dim < 0 || dim > mDesc.array_desc_dimensions-1)\r
+               throw LogicExceptionImpl("Array::SetBounds", _("Invalid dimension."));\r
+       if (low > high ||\r
+               low < mDesc.array_desc_bounds[dim].array_bound_lower ||\r
+               low > mDesc.array_desc_bounds[dim].array_bound_upper ||\r
+               high > mDesc.array_desc_bounds[dim].array_bound_upper ||\r
+               high < mDesc.array_desc_bounds[dim].array_bound_lower)\r
+               throw LogicExceptionImpl("Array::SetBounds",\r
+                       _("Invalid bounds. You can only narrow the bounds."));\r
+\r
+       mDesc.array_desc_bounds[dim].array_bound_lower = short(low);\r
+       mDesc.array_desc_bounds[dim].array_bound_upper = short(high);\r
+\r
+       AllocArrayBuffer();\r
+}\r
+\r
+IBPP::SDT ArrayImpl::ElementType()\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::ElementType",\r
+                       _("Array description not set."));\r
+\r
+       IBPP::SDT value;\r
+       switch (mDesc.array_desc_dtype)\r
+       {\r
+               case blr_text :                 value = IBPP::sdString;         break;\r
+               case blr_varying :              value = IBPP::sdString;         break;\r
+               case blr_cstring :              value = IBPP::sdString;         break;\r
+               case blr_short :                value = IBPP::sdSmallint;       break;\r
+               case blr_long :                 value = IBPP::sdInteger;        break;\r
+               case blr_int64 :                value = IBPP::sdLargeint;       break;\r
+               case blr_float :                value = IBPP::sdFloat;          break;\r
+               case blr_double :               value = IBPP::sdDouble;         break;\r
+               case blr_timestamp :    value = IBPP::sdTimestamp;      break;\r
+               case blr_sql_date :             value = IBPP::sdDate;           break;\r
+               case blr_sql_time :             value = IBPP::sdTime;           break;\r
+               default : throw LogicExceptionImpl("Array::ElementType",\r
+                                               _("Found an unknown sqltype !"));\r
+       }\r
+\r
+       return value;\r
+}\r
+\r
+int ArrayImpl::ElementSize()\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::ElementSize",\r
+                       _("Array description not set."));\r
+\r
+       return mDesc.array_desc_length;\r
+}\r
+\r
+int ArrayImpl::ElementScale()\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::ElementScale",\r
+                       _("Array description not set."));\r
+\r
+       return mDesc.array_desc_scale;\r
+}\r
+\r
+int ArrayImpl::Dimensions()\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::Dimensions",\r
+                       _("Array description not set."));\r
+\r
+       return mDesc.array_desc_dimensions;\r
+}\r
+\r
+void ArrayImpl::Bounds(int dim, int* low, int* high)\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::Bounds", _("Array description not set."));\r
+       if (dim < 0 || dim > mDesc.array_desc_dimensions-1)\r
+               throw LogicExceptionImpl("Array::Bounds", _("Invalid dimension."));\r
+       if (low == 0 || high == 0)\r
+               throw LogicExceptionImpl("Array::Bounds", _("Null reference detected."));\r
+\r
+       *low =  mDesc.array_desc_bounds[dim].array_bound_lower;\r
+       *high = mDesc.array_desc_bounds[dim].array_bound_upper;\r
+}\r
+\r
+/*\r
+\r
+COMMENTS\r
+\r
+1)\r
+For an array column of type CHAR(X), the internal type returned or expected is blr_text.\r
+In such case, the byte array received or submitted to get/put_slice is formatted in\r
+elements of X bytes, which correspond to what is reported in array_desc_length.\r
+The elements are not '\0' terminated but are right-padded with spaces ' '.\r
+\r
+2)\r
+For an array column of type VARCHAR(X), the internal type is blr_varying.\r
+The underlying format is rather curious and different than what is used in XSQLDA.\r
+The element size is reported in array_desc_length as X.\r
+Yet each element of the byte array is expected to be of size X+2 (just as if we were\r
+to stuff a short in the first 2 bytes to store the length (as is done with XSQLDA).\r
+No. The string of X characters maximum has to be stored in the chunks of X+2 bytes as\r
+a zero-terminated c-string. Note that the buffer is indeed one byte too large.\r
+Internally, the API probably convert in-place in these chunks the zero-terminated string\r
+to a variable-size string with a short in front and the string data non zero-terminated\r
+behind.\r
+\r
+3)\r
+With Interbase 6.0 and Firebird 1.0 (initial april 2002 release), the int64 support is\r
+broken regarding the arrays. It is not possible to work on arrays using a datatype stored\r
+in an int64, as for instance any NUMERIC(x,0) where x is equal or greater than 10. That's\r
+a bug in the engine, not in IBPP, which has been fixed in june 2002. Engines compiled from\r
+the current Firebird CVS code as of july 2002 are okay. As will be the 1.01 Firebird version.\r
+We have no idea if this is fixed or not in Interbase 6.5 though.\r
+\r
+*/\r
+\r
+void ArrayImpl::ReadTo(IBPP::ADT adtype, void* data, int datacount)\r
+{\r
+       if (! mIdAssigned)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("Array Id not read from column."));\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("Array description not set."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("No Transaction is attached."));\r
+       if (datacount != mElemCount)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("Wrong count of array elements"));\r
+\r
+       IBS status;\r
+       ISC_LONG lenbuf = mBufferSize;\r
+       (*gds.Call()->m_array_get_slice)(status.Self(), mDatabase->GetHandlePtr(),\r
+               mTransaction->GetHandlePtr(), &mId, &mDesc, mBuffer, &lenbuf);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Array::ReadTo", _("isc_array_get_slice failed."));\r
+       if (lenbuf != mBufferSize)\r
+               throw SQLExceptionImpl(status, "Array::ReadTo", _("Internal buffer size discrepancy."));\r
+\r
+       // Now, convert the types and copy values to the user array...\r
+       int len;\r
+       char* src = (char*)mBuffer;\r
+       char* dst = (char*)data;\r
+\r
+       switch (mDesc.array_desc_dtype)\r
+       {\r
+               case blr_text :\r
+                       if (adtype == IBPP::adString)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       strncpy(dst, src, mElemSize);\r
+                                       dst[mElemSize] = '\0';\r
+                                       src += mElemSize;\r
+                                       dst += (mElemSize + 1);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*src == 't' || *src == 'T' || *src == 'y' || *src == 'Y' || *src == '1')\r
+                                               *(bool*)dst = true;\r
+                                       else *(bool*)dst = false;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(bool);\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_varying :\r
+                       if (adtype == IBPP::adString)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       len = (int)strlen(src);\r
+                                       if (len > mElemSize-2) len = mElemSize-2;\r
+                                       strncpy(dst, src, len);\r
+                                       dst[len] = '\0';\r
+                                       src += mElemSize;\r
+                                       dst += (mElemSize - 2 + 1);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*src == 't' || *src == 'T' || *src == 'y' || *src == 'Y' || *src == '1')\r
+                                               *(bool*)dst = true;\r
+                                       else *(bool*)dst = false;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(bool);\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_short :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(bool*)dst = (*(short*)src != 0) ? true : false;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(bool);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst = *(short*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(short);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int*)dst = (int)*(short*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(int);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = (int64_t)*(short*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(int64_t);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(float*)dst = (float)(*(short*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(float);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = (double)(*(short*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(double);\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_long :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(bool*)dst = (*(long*)src != 0) ? true : false;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(bool);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(long*)src < consts::min16 || *(long*)src > consts::max16)\r
+                                               throw LogicExceptionImpl("Array::ReadTo",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(short*)dst = short(*(long*)src);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(short);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst = *(long*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(long);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = (int64_t)*(long*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(int64_t);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(float*)dst = (float)(*(long*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(float);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = (double)(*(long*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(double);\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_int64 :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(bool*)dst = (*(int64_t*)src != 0) ? true : false;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(bool);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(int64_t*)src < consts::min16 || *(int64_t*)src > consts::max16)\r
+                                               throw LogicExceptionImpl("Array::ReadTo",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(short*)dst = short(*(int64_t*)src);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(short);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(int64_t*)src < consts::min32 || *(int64_t*)src > consts::max32)\r
+                                               throw LogicExceptionImpl("Array::ReadTo",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(long*)dst = (long)*(int64_t*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(long);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = *(int64_t*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(int64_t);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(float*)dst = (float)(*(int64_t*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(float);\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = (double)(*(int64_t*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(double);\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_float :\r
+                       if (adtype != IBPP::adFloat || mDesc.array_desc_scale != 0)\r
+                               throw LogicExceptionImpl("Array::ReadTo", _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               *(float*)dst = *(float*)src;\r
+                               src += mElemSize;\r
+                               dst += sizeof(float);\r
+                       }\r
+                       break;\r
+\r
+               case blr_double :\r
+                       if (adtype != IBPP::adDouble) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                               _("Incompatible types."));\r
+                       if (mDesc.array_desc_scale != 0)\r
+                       {\r
+                               // Round to scale of NUMERIC(x,y)\r
+                               double divisor = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = (double)(*(double*)src / divisor);\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(double);\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = *(double*)src;\r
+                                       src += mElemSize;\r
+                                       dst += sizeof(double);\r
+                               }\r
+                       }\r
+                       break;\r
+\r
+               case blr_timestamp :\r
+                       if (adtype != IBPP::adTimestamp) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               decodeTimestamp(*(IBPP::Timestamp*)dst, *(ISC_TIMESTAMP*)src);\r
+                               src += mElemSize;\r
+                               dst += sizeof(IBPP::Timestamp);\r
+                       }\r
+                       break;\r
+\r
+               case blr_sql_date :\r
+                       if (adtype != IBPP::adDate) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               decodeDate(*(IBPP::Date*)dst, *(ISC_DATE*)src);\r
+                               src += mElemSize;\r
+                               dst += sizeof(IBPP::Date);\r
+                       }\r
+                       break;\r
+\r
+               case blr_sql_time :\r
+                       if (adtype != IBPP::adTime) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               decodeTime(*(IBPP::Time*)dst, *(ISC_TIME*)src);\r
+                               src += mElemSize;\r
+                               dst += sizeof(IBPP::Time);\r
+                       }\r
+                       break;\r
+\r
+               default :\r
+                       throw LogicExceptionImpl("Array::ReadTo", _("Unknown sql type."));\r
+       }\r
+}\r
+\r
+void ArrayImpl::WriteFrom(IBPP::ADT adtype, const void* data, int datacount)\r
+{\r
+       if (! mDescribed)\r
+               throw LogicExceptionImpl("Array::WriteFrom", _("Array description not set."));\r
+       if (mDatabase == 0)\r
+               throw LogicExceptionImpl("Array::WriteFrom", _("No Database is attached."));\r
+       if (mTransaction == 0)\r
+               throw LogicExceptionImpl("Array::WriteFrom", _("No Transaction is attached."));\r
+       if (datacount != mElemCount)\r
+               throw LogicExceptionImpl("Array::ReadTo", _("Wrong count of array elements"));\r
+\r
+       // Read user data and convert types to the mBuffer\r
+       int len;\r
+       char* src = (char*)data;\r
+       char* dst = (char*)mBuffer;\r
+\r
+       switch (mDesc.array_desc_dtype)\r
+       {\r
+               case blr_text :\r
+                       if (adtype == IBPP::adString)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       len = (int)strlen(src);\r
+                                       if (len > mElemSize) len = mElemSize;\r
+                                       strncpy(dst, src, len);\r
+                                       while (len < mElemSize) dst[len++] = ' ';\r
+                                       src += (mElemSize + 1);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *dst = *(bool*)src ? 'T' : 'F';\r
+                                       len = 1;\r
+                                       while (len < mElemSize) dst[len++] = ' ';\r
+                                       src += sizeof(bool);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_varying :\r
+                       if (adtype == IBPP::adString)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       len = (int)strlen(src);\r
+                                       if (len > mElemSize-2) len = mElemSize-2;\r
+                                       strncpy(dst, src, len);\r
+                                       dst[len] = '\0';\r
+                                       src += (mElemSize - 2 + 1);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst = (short)1;\r
+                                       dst[2] = *(bool*)src ? 'T' : 'F';\r
+                                       src += sizeof(bool);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_short :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst = short(*(bool*)src ? 1 : 0);\r
+                                       src += sizeof(bool);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst = *(short*)src;\r
+                                       src += sizeof(short);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(long*)src < consts::min16 || *(long*)src > consts::max16)\r
+                                               throw LogicExceptionImpl("Array::WriteFrom",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(short*)dst = (short)*(int*)src;\r
+                                       src += sizeof(int);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(int64_t*)src < consts::min16 || *(int64_t*)src > consts::max16)\r
+                                               throw LogicExceptionImpl("Array::WriteFrom",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(short*)dst = (short)*(int64_t*)src;\r
+                                       src += sizeof(int64_t);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst =\r
+                                               (short)floor(*(float*)src * multiplier + 0.5);\r
+                                       src += sizeof(float);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(short*)dst =\r
+                                               (short)floor(*(double*)src * multiplier + 0.5);\r
+                                       src += sizeof(double);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_long :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst = *(bool*)src ? 1 : 0;\r
+                                       src += sizeof(bool);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst = *(short*)src;\r
+                                       src += sizeof(short);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst = *(long*)src;\r
+                                       src += sizeof(long);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       if (*(int64_t*)src < consts::min32 || *(int64_t*)src > consts::max32)\r
+                                               throw LogicExceptionImpl("Array::WriteFrom",\r
+                                                       _("Out of range numeric conversion !"));\r
+                                       *(long*)dst = (long)*(int64_t*)src;\r
+                                       src += sizeof(int64_t);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_INT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst =\r
+                                               (long)floor(*(float*)src * multiplier + 0.5);\r
+                                       src += sizeof(float);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_INT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(long*)dst =\r
+                                               (long)floor(*(double*)src * multiplier + 0.5);\r
+                                       src += sizeof(double);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));\r
+                       break;\r
+\r
+               case blr_int64 :\r
+                       if (adtype == IBPP::adBool)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = *(bool*)src ? 1 : 0;\r
+                                       src += sizeof(bool);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt16)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = *(short*)src;\r
+                                       src += sizeof(short);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt32)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = *(long*)src;\r
+                                       src += sizeof(long);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adInt64)\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst = *(int64_t*)src;\r
+                                       src += sizeof(int64_t);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adFloat)\r
+                       {\r
+                               // This SQL_INT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst =\r
+                                               (int64_t)floor(*(float*)src * multiplier + 0.5);\r
+                                       src += sizeof(float);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else if (adtype == IBPP::adDouble)\r
+                       {\r
+                               // This SQL_INT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(int64_t*)dst =\r
+                                               (int64_t)floor(*(double*)src * multiplier + 0.5);\r
+                                       src += sizeof(double);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else\r
+                               throw LogicExceptionImpl("Array::WriteFrom",\r
+                                       _("Incompatible types (blr_int64 and ADT %d)."), (int)adtype);\r
+                       break;\r
+\r
+               case blr_float :\r
+                       if (adtype != IBPP::adFloat || mDesc.array_desc_scale != 0)\r
+                               throw LogicExceptionImpl("Array::WriteFrom", _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               *(float*)dst = *(float*)src;\r
+                               src += sizeof(float);\r
+                               dst += mElemSize;\r
+                       }\r
+                       break;\r
+\r
+               case blr_double :\r
+                       if (adtype != IBPP::adDouble) throw LogicExceptionImpl("Array::WriteFrom",\r
+                                                                               _("Incompatible types."));\r
+                       if (mDesc.array_desc_scale != 0)\r
+                       {\r
+                               // Round to scale of NUMERIC(x,y)\r
+                               double multiplier = consts::dscales[-mDesc.array_desc_scale];\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst =\r
+                                               floor(*(double*)src * multiplier + 0.5) / multiplier;\r
+                                       src += sizeof(double);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               for (int i = 0; i < mElemCount; i++)\r
+                               {\r
+                                       *(double*)dst = *(double*)src;\r
+                                       src += sizeof(double);\r
+                                       dst += mElemSize;\r
+                               }\r
+                       }\r
+                       break;\r
+\r
+               case blr_timestamp :\r
+                       if (adtype != IBPP::adTimestamp) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               encodeTimestamp(*(ISC_TIMESTAMP*)dst, *(IBPP::Timestamp*)src);\r
+                               src += sizeof(IBPP::Timestamp);\r
+                               dst += mElemSize;\r
+                       }\r
+                       break;\r
+\r
+               case blr_sql_date :\r
+                       if (adtype != IBPP::adDate) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               encodeDate(*(ISC_DATE*)dst, *(IBPP::Date*)src); \r
+                               src += sizeof(IBPP::Date);\r
+                               dst += mElemSize;\r
+                       }\r
+                       break;\r
+\r
+               case blr_sql_time :\r
+                       if (adtype != IBPP::adTime) throw LogicExceptionImpl("Array::ReadTo",\r
+                                                                                               _("Incompatible types."));\r
+                       for (int i = 0; i < mElemCount; i++)\r
+                       {\r
+                               encodeTime(*(ISC_TIME*)dst, *(IBPP::Time*)src);\r
+                               src += sizeof(IBPP::Time);\r
+                               dst += mElemSize;\r
+                       }\r
+                       break;\r
+\r
+               default :\r
+                       throw LogicExceptionImpl("Array::WriteFrom", _("Unknown sql type."));\r
+       }\r
+\r
+       IBS status;\r
+       ISC_LONG lenbuf = mBufferSize;\r
+       (*gds.Call()->m_array_put_slice)(status.Self(), mDatabase->GetHandlePtr(),\r
+               mTransaction->GetHandlePtr(), &mId, &mDesc, mBuffer, &lenbuf);\r
+       if (status.Errors())\r
+               throw SQLExceptionImpl(status, "Array::WriteFrom", _("isc_array_put_slice failed."));\r
+       if (lenbuf != mBufferSize)\r
+               throw SQLExceptionImpl(status, "Array::WriteFrom", _("Internal buffer size discrepancy."));\r
+}\r
+\r
+IBPP::Database ArrayImpl::DatabasePtr() const\r
+{\r
+       if (mDatabase == 0) throw LogicExceptionImpl("Array::DatabasePtr",\r
+                       _("No Database is attached."));\r
+       return mDatabase;\r
+}\r
+\r
+IBPP::Transaction ArrayImpl::TransactionPtr() const\r
+{\r
+       if (mTransaction == 0) throw LogicExceptionImpl("Array::TransactionPtr",\r
+                       _("No Transaction is attached."));\r
+       return mTransaction;\r
+}\r
+\r
+IBPP::IArray* ArrayImpl::AddRef()\r
+{\r
+       ASSERTION(mRefCount >= 0);\r
+       ++mRefCount;\r
+       return this;\r
+}\r
+\r
+void ArrayImpl::Release()\r
+{\r
+       // Release cannot throw, except in DEBUG builds on assertion\r
+       ASSERTION(mRefCount >= 0);\r
+       --mRefCount;\r
+       try { if (mRefCount <= 0) delete this; }\r
+               catch (...) { }\r
+}\r
+\r
+//     (((((((( OBJECT INTERNAL METHODS ))))))))\r
+\r
+void ArrayImpl::Init()\r
+{\r
+       ResetId();\r
+       mDescribed = false;\r
+       mDatabase = 0;\r
+       mTransaction = 0;\r
+       mBuffer = 0;\r
+       mBufferSize = 0;\r
+}\r
+\r
+void ArrayImpl::SetId(ISC_QUAD* quad)\r
+{\r
+       if (quad == 0)\r
+               throw LogicExceptionImpl("ArrayImpl::SetId", _("Null Id reference detected."));\r
+\r
+       memcpy(&mId, quad, sizeof(mId));\r
+       mIdAssigned = true;\r
+}\r
+\r
+void ArrayImpl::GetId(ISC_QUAD* quad)\r
+{\r
+       if (quad == 0)\r
+               throw LogicExceptionImpl("ArrayImpl::GetId", _("Null Id reference detected."));\r
+\r
+       memcpy(quad, &mId, sizeof(mId));\r
+}\r
+\r
+void ArrayImpl::ResetId()\r
+{\r
+       memset(&mId, 0, sizeof(mId));\r
+       mIdAssigned = false;\r
+}\r
+\r
+void ArrayImpl::AllocArrayBuffer()\r
+{\r
+       // Clean previous buffer if any\r
+       if (mBuffer != 0) delete [] (char*)mBuffer;\r
+       mBuffer = 0;\r
+\r
+       // Computes total number of elements in the array or slice\r
+       mElemCount = 1;\r
+       for (int i = 0; i < mDesc.array_desc_dimensions; i++)\r
+       {\r
+               mElemCount = mElemCount *\r
+                       (mDesc.array_desc_bounds[i].array_bound_upper -\r
+                               mDesc.array_desc_bounds[i].array_bound_lower + 1);\r
+       }\r
+\r
+       // Allocates a buffer for this count of elements\r
+       mElemSize = mDesc.array_desc_length;\r
+       if (mDesc.array_desc_dtype == blr_varying) mElemSize += 2;\r
+       else if (mDesc.array_desc_dtype == blr_cstring) mElemSize += 1;\r
+       mBufferSize = mElemSize * mElemCount;\r
+       mBuffer = (void*) new char[mBufferSize];\r
+}\r
+\r
+void ArrayImpl::AttachDatabaseImpl(DatabaseImpl* database)\r
+{\r
+       if (database == 0) throw LogicExceptionImpl("Array::AttachDatabase",\r
+                       _("Can't attach a 0 Database object."));\r
+\r
+       if (mDatabase != 0) mDatabase->DetachArrayImpl(this);\r
+       mDatabase = database;\r
+       mDatabase->AttachArrayImpl(this);\r
+}\r
+\r
+void ArrayImpl::AttachTransactionImpl(TransactionImpl* transaction)\r
+{\r
+       if (transaction == 0) throw LogicExceptionImpl("Array::AttachTransaction",\r
+                       _("Can't attach a 0 Transaction object."));\r
+\r
+       if (mTransaction != 0) mTransaction->DetachArrayImpl(this);\r
+       mTransaction = transaction;\r
+       mTransaction->AttachArrayImpl(this);\r
+}\r
+\r
+void ArrayImpl::DetachDatabaseImpl()\r
+{\r
+       if (mDatabase == 0) return;\r
+\r
+       mDatabase->DetachArrayImpl(this);\r
+       mDatabase = 0;\r
+}\r
+\r
+void ArrayImpl::DetachTransactionImpl()\r
+{\r
+       if (mTransaction == 0) return;\r
+\r
+       mTransaction->DetachArrayImpl(this);\r
+       mTransaction = 0;\r
+}\r
+\r
+ArrayImpl::ArrayImpl(DatabaseImpl* database, TransactionImpl* transaction)\r
+       : mRefCount(0)\r
+{\r
+       Init();\r
+       AttachDatabaseImpl(database);\r
+       if (transaction != 0) AttachTransactionImpl(transaction);\r
+}\r
+\r
+ArrayImpl::~ArrayImpl()\r
+{\r
+       try { if (mTransaction != 0) mTransaction->DetachArrayImpl(this); }\r
+               catch (...) {}\r
+       try { if (mDatabase != 0) mDatabase->DetachArrayImpl(this); }\r
+               catch (...) {}\r
+       try { if (mBuffer != 0) delete [] (char*)mBuffer; }\r
+               catch (...) {}\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r