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