+///////////////////////////////////////////////////////////////////////////////\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