]> git.stg.codes - stg.git/blobdiff - libs/ibpp/row.cpp
Port to CMake, get rid of os_int.h.
[stg.git] / libs / ibpp / row.cpp
diff --git a/libs/ibpp/row.cpp b/libs/ibpp/row.cpp
new file mode 100644 (file)
index 0000000..fa6939a
--- /dev/null
@@ -0,0 +1,1580 @@
+///////////////////////////////////////////////////////////////////////////////\r
+//\r
+//     File    : $Id: row.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $\r
+//     Subject : IBPP, Row 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 <time.h>\r
+#include <cstring>\r
+\r
+using namespace ibpp_internals;\r
+\r
+//     (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
+\r
+void RowImpl::SetNull(int param)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::SetNull", _("The row is not initialized."));\r
+       if (param < 1 || param > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::SetNull", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[param-1]);\r
+       if (! (var->sqltype & 1))\r
+               throw LogicExceptionImpl("Row::SetNull", _("This column can't be null."));\r
+\r
+       *var->sqlind = -1;      // Set the column to SQL NULL\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, bool value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[bool]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivBool, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const char* cstring)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[char*]", _("The row is not initialized."));\r
+       if (cstring == 0)\r
+               throw LogicExceptionImpl("Row::Set[char*]", _("null char* pointer detected."));\r
+\r
+       SetValue(param, ivByte, cstring, (int)strlen(cstring));\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const void* bindata, int len)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[void*]", _("The row is not initialized."));\r
+       if (bindata == 0)\r
+               throw LogicExceptionImpl("Row::Set[void*]", _("null char* pointer detected."));\r
+       if (len < 0)\r
+               throw LogicExceptionImpl("Row::Set[void*]", _("Length must be >= 0"));\r
+               \r
+       SetValue(param, ivByte, bindata, len);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const std::string& s)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[string]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivString, (void*)&s);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, int16_t value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[int16_t]", _("The row is not initialized."));\r
+                                                                                       \r
+       SetValue(param, ivInt16, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, int32_t value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[int32_t]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivInt32, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, int64_t value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[int64_t]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivInt64, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, float value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[float]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivFloat, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, double value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[double]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivDouble, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::Timestamp& value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Timestamp]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivTimestamp, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::Date& value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Date]", _("The row is not initialized."));\r
+\r
+       if (mDialect == 1)\r
+       {\r
+               // In dialect 1, IBPP::Date is supposed to work with old 'DATE'\r
+               // fields which are actually ISC_TIMESTAMP.\r
+               IBPP::Timestamp timestamp(value);\r
+               SetValue(param, ivTimestamp, &timestamp);\r
+       }\r
+       else\r
+       {\r
+               // Dialect 3\r
+               SetValue(param, ivDate, (void*)&value);\r
+       }\r
+\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::Time& value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Time]", _("The row is not initialized."));\r
+       if (mDialect == 1)\r
+               throw LogicExceptionImpl("Row::Set[Time]", _("Requires use of a dialect 3 database."));\r
+\r
+       SetValue(param, ivTime, &value);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::Blob& blob)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Blob]", _("The row is not initialized."));\r
+       if (mDatabase != 0 && blob->DatabasePtr() != mDatabase)\r
+               throw LogicExceptionImpl("Row::Set[Blob]",\r
+                       _("IBlob and Row attached to different databases"));\r
+       if (mTransaction != 0 && blob->TransactionPtr() != mTransaction)\r
+               throw LogicExceptionImpl("Row::Set[Blob]",\r
+                       _("IBlob and Row attached to different transactions"));\r
+\r
+       SetValue(param, ivBlob, blob.intf());\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::Array& array)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Array]", _("The row is not initialized."));\r
+       if (mDatabase != 0 && array->DatabasePtr() != mDatabase)\r
+               throw LogicExceptionImpl("Row::Set[Array]",\r
+                       _("IArray and Row attached to different databases"));\r
+       if (mTransaction != 0 && array->TransactionPtr() != mTransaction)\r
+               throw LogicExceptionImpl("Row::Set[Array]",\r
+                       _("IArray and Row attached to different transactions"));\r
+\r
+       SetValue(param, ivArray, (void*)array.intf());\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+void RowImpl::Set(int param, const IBPP::DBKey& key)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[DBKey]", _("The row is not initialized."));\r
+\r
+       SetValue(param, ivDBKey, (void*)&key);\r
+       mUpdated[param-1] = true;\r
+}\r
+\r
+/*\r
+void RowImpl::Set(int param, const IBPP::Value& value)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Set[Value]", _("The row is not initialized."));\r
+\r
+       //SetValue(param, ivDBKey, (void*)&key);\r
+       //mUpdated[param-1] = true;\r
+}\r
+*/\r
+\r
+bool RowImpl::IsNull(int column)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::IsNull", _("The row is not initialized."));\r
+       if (column < 1 || column > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::IsNull", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[column-1]);\r
+       return ((var->sqltype & 1) && *(var->sqlind) != 0) ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, bool& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivBool);\r
+       if (pvalue != 0)\r
+               retvalue = (*(char*)pvalue == 0 ? false : true);\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, char* retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+       if (retvalue == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("Null pointer detected"));\r
+\r
+       int sqllen;\r
+       void* pvalue = GetValue(column, ivByte, &sqllen);\r
+       if (pvalue != 0)\r
+       {\r
+               memcpy(retvalue, pvalue, sqllen);\r
+               retvalue[sqllen] = '\0';\r
+       }\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, void* bindata, int& userlen)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+       if (bindata == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("Null pointer detected"));\r
+       if (userlen < 0)\r
+               throw LogicExceptionImpl("Row::Get", _("Length must be >= 0"));\r
+\r
+       int sqllen;\r
+       void* pvalue = GetValue(column, ivByte, &sqllen);\r
+       if (pvalue != 0)\r
+       {\r
+               // userlen says how much bytes the user can accept\r
+               // let's shorten it, if there is less bytes available\r
+               if (sqllen < userlen) userlen = sqllen;\r
+               memcpy(bindata, pvalue, userlen);\r
+       }\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, std::string& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivString, &retvalue);\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, int16_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivInt16);\r
+       if (pvalue != 0)\r
+               retvalue = *(int16_t*)pvalue;\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, int32_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivInt32);\r
+       if (pvalue != 0)\r
+               retvalue = *(int32_t*)pvalue;\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, int64_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivInt64);\r
+       if (pvalue != 0)\r
+               retvalue = *(int64_t*)pvalue;\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, float& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivFloat);\r
+       if (pvalue != 0)\r
+               retvalue = *(float*)pvalue;\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, double& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivDouble);\r
+       if (pvalue != 0)\r
+               retvalue = *(double*)pvalue;\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::Timestamp& timestamp)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivTimestamp, (void*)&timestamp);\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::Date& date)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       if (mDialect == 1)\r
+       {\r
+               // Dialect 1. IBPP::Date is supposed to work with old 'DATE'\r
+               // fields which are actually ISC_TIMESTAMP.\r
+               IBPP::Timestamp timestamp;\r
+               void* pvalue = GetValue(column, ivTimestamp, (void*)&timestamp);\r
+               if (pvalue != 0) date = timestamp;\r
+               return pvalue == 0 ? true : false;\r
+       }\r
+       else\r
+       {\r
+               void* pvalue = GetValue(column, ivDate, (void*)&date);\r
+               return pvalue == 0 ? true : false;\r
+       }\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::Time& time)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivTime, (void*)&time);\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::Blob& retblob)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivBlob, (void*)retblob.intf());\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::DBKey& retkey)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivDBKey, (void*)&retkey);\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+bool RowImpl::Get(int column, IBPP::Array& retarray)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       void* pvalue = GetValue(column, ivArray, (void*)retarray.intf());\r
+       return pvalue == 0 ? true : false;\r
+}\r
+\r
+/*\r
+const IBPP::Value RowImpl::Get(int column)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       //void* value = GetValue(column, ivArray, (void*)retarray.intf());\r
+       //return value == 0 ? true : false;\r
+       return IBPP::Value();\r
+}\r
+*/\r
+\r
+bool RowImpl::IsNull(const std::string& name)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::IsNull", _("The row is not initialized."));\r
+\r
+       return IsNull(ColumnNum(name));\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, bool& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, char* retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get[char*]", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, void* retvalue, int& count)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get[void*,int]", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue, count);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, std::string& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::GetString", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, int16_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, int32_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, int64_t& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, float& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, double& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, IBPP::Timestamp& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, IBPP::Date& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, IBPP::Time& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string&name, IBPP::Blob& retblob)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retblob);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, IBPP::DBKey& retvalue)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retvalue);\r
+}\r
+\r
+bool RowImpl::Get(const std::string& name, IBPP::Array& retarray)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name), retarray);\r
+}\r
+\r
+/*\r
+const IBPP::Value RowImpl::Get(const std::string& name)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
+\r
+       return Get(ColumnNum(name));\r
+}\r
+*/\r
+\r
+int RowImpl::Columns()\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::Columns", _("The row is not initialized."));\r
+\r
+       return mDescrArea->sqld;\r
+}\r
+\r
+int RowImpl::ColumnNum(const std::string& name)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnNum", _("The row is not initialized."));\r
+       if (name.empty())\r
+               throw LogicExceptionImpl("Row::ColumnNum", _("Column name <empty> not found."));\r
+\r
+       XSQLVAR* var;\r
+       char Uname[sizeof(var->sqlname)+1];             // Max size of sqlname + '\0'\r
+\r
+       // Local upper case copy of the column name\r
+       size_t len = name.length();\r
+       if (len > sizeof(var->sqlname)) len = sizeof(var->sqlname);\r
+       strncpy(Uname, name.c_str(), len);\r
+       Uname[len] = '\0';\r
+       char* p = Uname;\r
+       while (*p != '\0') { *p = char(toupper(*p)); ++p; }\r
+\r
+       // Loop through the columns of the descriptor\r
+       for (int i = 0; i < mDescrArea->sqld; i++)\r
+       {\r
+               var = &(mDescrArea->sqlvar[i]);\r
+               if (var->sqlname_length != (int16_t)len) continue;\r
+               if (strncmp(Uname, var->sqlname, len) == 0) return i+1;\r
+       }\r
+\r
+       // Failed finding the column name, let's retry using the aliases\r
+       char Ualias[sizeof(var->aliasname)+1];          // Max size of aliasname + '\0'\r
+\r
+       // Local upper case copy of the column name\r
+       len = name.length();\r
+       if (len > sizeof(var->aliasname)) len = sizeof(var->aliasname);\r
+       strncpy(Ualias, name.c_str(), len);\r
+       Ualias[len] = '\0';\r
+       p = Ualias;\r
+       while (*p != '\0') { *p = char(toupper(*p)); ++p; }\r
+\r
+       // Loop through the columns of the descriptor\r
+       for (int i = 0; i < mDescrArea->sqld; i++)\r
+       {\r
+               var = &(mDescrArea->sqlvar[i]);\r
+               if (var->aliasname_length != (int16_t)len) continue;\r
+               if (strncmp(Ualias, var->aliasname, len) == 0) return i+1;\r
+       }\r
+\r
+       throw LogicExceptionImpl("Row::ColumnNum", _("Could not find matching column."));\r
+#ifdef __DMC__\r
+       return 0;       // DMC errronously warns here about a missing return\r
+#endif\r
+}\r
+\r
+/*\r
+ColumnName, ColumnAlias, ColumnTable : all these 3 have a mistake.\r
+Ideally, the strings should be stored elsewhere (like _Numerics and so on) to\r
+take into account the final '\0' which needs to be added. For now, we insert\r
+the '\0' in the original data, which will cut the 32th character. Not terribly\r
+bad, but should be cleanly rewritten.\r
+*/\r
+\r
+const char* RowImpl::ColumnName(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnName", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumName", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+       if (var->sqlname_length >= 31) var->sqlname_length = 31;\r
+       var->sqlname[var->sqlname_length] = '\0';\r
+       return var->sqlname;\r
+}\r
+\r
+const char* RowImpl::ColumnAlias(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnAlias", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnAlias", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+       if (var->aliasname_length >= 31) var->aliasname_length = 31;\r
+       var->aliasname[var->aliasname_length] = '\0';\r
+       return var->aliasname;\r
+}\r
+\r
+const char* RowImpl::ColumnTable(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnTable", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnTable", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+       if (var->relname_length >= 31) var->relname_length = 31;\r
+       var->relname[var->relname_length] = '\0';\r
+       return var->relname;\r
+}\r
+\r
+IBPP::SDT RowImpl::ColumnType(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnType", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnType", _("Variable index out of range."));\r
+\r
+       IBPP::SDT value;\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+\r
+       switch (var->sqltype & ~1)\r
+       {\r
+               case SQL_TEXT :      value = IBPP::sdString;    break;\r
+               case SQL_VARYING :   value = IBPP::sdString;    break;\r
+               case SQL_SHORT :     value = IBPP::sdSmallint;  break;\r
+               case SQL_LONG :      value = IBPP::sdInteger;   break;\r
+               case SQL_INT64 :     value = IBPP::sdLargeint;  break;\r
+               case SQL_FLOAT :     value = IBPP::sdFloat;     break;\r
+               case SQL_DOUBLE :    value = IBPP::sdDouble;    break;\r
+               case SQL_TIMESTAMP : value = IBPP::sdTimestamp; break;\r
+               case SQL_TYPE_DATE : value = IBPP::sdDate;      break;\r
+               case SQL_TYPE_TIME : value = IBPP::sdTime;      break;\r
+               case SQL_BLOB :      value = IBPP::sdBlob;      break;\r
+               case SQL_ARRAY :     value = IBPP::sdArray;     break;\r
+               default : throw LogicExceptionImpl("Row::ColumnType",\r
+                                               _("Found an unknown sqltype !"));\r
+       }\r
+\r
+       return value;\r
+}\r
+\r
+int RowImpl::ColumnSubtype(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnSubtype", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnSubtype", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+       return (int)var->sqlsubtype;\r
+}\r
+\r
+int RowImpl::ColumnSize(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnSize", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnSize", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+    return var->sqllen;\r
+}\r
+\r
+int RowImpl::ColumnScale(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnScale", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnScale", _("Variable index out of range."));\r
+\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+    return -var->sqlscale;\r
+}\r
+\r
+bool RowImpl::ColumnUpdated(int varnum)\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnUpdated", _("The row is not initialized."));\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("Row::ColumnUpdated", _("Variable index out of range."));\r
+\r
+       return mUpdated[varnum-1];\r
+}\r
+\r
+bool RowImpl::Updated()\r
+{\r
+       if (mDescrArea == 0)\r
+               throw LogicExceptionImpl("Row::ColumnUpdated", _("The row is not initialized."));\r
+\r
+       for (int i = 0; i < mDescrArea->sqld; i++)\r
+               if (mUpdated[i]) return true;\r
+       return false;\r
+}\r
+\r
+IBPP::Database RowImpl::DatabasePtr() const\r
+{\r
+       return mDatabase;\r
+}\r
+\r
+IBPP::Transaction RowImpl::TransactionPtr() const\r
+{\r
+       return mTransaction;\r
+}\r
+\r
+IBPP::IRow* RowImpl::Clone()\r
+{\r
+       // By definition the clone of an IBPP Row is a new row (so refcount=0).\r
+\r
+       RowImpl* clone = new RowImpl(*this);\r
+       return clone;\r
+}\r
+\r
+IBPP::IRow* RowImpl::AddRef()\r
+{\r
+       ASSERTION(mRefCount >= 0);\r
+       ++mRefCount;\r
+       return this;\r
+}\r
+\r
+void RowImpl::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 RowImpl::SetValue(int varnum, IITYPE ivType, const void* value, int userlen)\r
+{\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("RowImpl::SetValue", _("Variable index out of range."));\r
+       if (value == 0)\r
+               throw LogicExceptionImpl("RowImpl::SetValue", _("Unexpected null pointer detected."));\r
+\r
+       int16_t len;\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+       switch (var->sqltype & ~1)\r
+       {\r
+               case SQL_TEXT :\r
+                       if (ivType == ivString)\r
+                       {\r
+                               std::string* svalue = (std::string*)value;\r
+                               len = (int16_t)svalue->length();\r
+                               if (len > var->sqllen) len = var->sqllen;\r
+                               strncpy(var->sqldata, svalue->c_str(), len);\r
+                               while (len < var->sqllen) var->sqldata[len++] = ' ';\r
+                       }\r
+                       else if (ivType == ivByte)\r
+                       {\r
+                               if (userlen > var->sqllen) userlen = var->sqllen;\r
+                               memcpy(var->sqldata, value, userlen);\r
+                               while (userlen < var->sqllen) var->sqldata[userlen++] = ' ';\r
+                       }\r
+                       else if (ivType == ivDBKey)\r
+                       {\r
+                               IBPP::DBKey* key = (IBPP::DBKey*)value;\r
+                               key->GetKey(var->sqldata, var->sqllen);\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               var->sqldata[0] = *(bool*)value ? 'T' : 'F';\r
+                               len = 1;\r
+                               while (len < var->sqllen) var->sqldata[len++] = ' ';\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_VARYING :\r
+                       if (ivType == ivString)\r
+                       {\r
+                               std::string* svalue = (std::string*)value;\r
+                               len = (int16_t)svalue->length();\r
+                               if (len > var->sqllen) len = var->sqllen;\r
+                               *(int16_t*)var->sqldata = (int16_t)len;\r
+                               strncpy(var->sqldata+2, svalue->c_str(), len);\r
+                       }\r
+                       else if (ivType == ivByte)\r
+                       {\r
+                               if (userlen > var->sqllen) userlen = var->sqllen;\r
+                               *(int16_t*)var->sqldata = (int16_t)userlen;\r
+                               memcpy(var->sqldata+2, value, userlen);\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               *(int16_t*)var->sqldata = (int16_t)1;\r
+                               var->sqldata[2] = *(bool*)value ? 'T' : 'F';\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_SHORT :\r
+                       if (ivType == ivBool)\r
+                       {\r
+                               *(int16_t*)var->sqldata = int16_t(*(bool*)value ? 1 : 0);\r
+                       }\r
+                       else if (ivType == ivInt16)\r
+                       {\r
+                               *(int16_t*)var->sqldata = *(int16_t*)value;\r
+                       }\r
+                       else if (ivType == ivInt32)\r
+                       {\r
+                               if (*(int32_t*)value < consts::min16 || *(int32_t*)value > consts::max16)\r
+                                       throw LogicExceptionImpl("RowImpl::SetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               *(int16_t*)var->sqldata = (int16_t)*(int32_t*)value;\r
+                       }\r
+                       else if (ivType == ivInt64)\r
+                       {\r
+                               if (*(int64_t*)value < consts::min16 || *(int64_t*)value > consts::max16)\r
+                                       throw LogicExceptionImpl("RowImpl::SetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               *(int16_t*)var->sqldata = (int16_t)*(int64_t*)value;\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(int16_t*)var->sqldata =\r
+                                       (int16_t)floor(*(float*)value * multiplier + 0.5);\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(int16_t*)var->sqldata =\r
+                                       (int16_t)floor(*(double*)value * multiplier + 0.5);\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue",  var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_LONG :\r
+                       if (ivType == ivBool)\r
+                       {\r
+                               *(ISC_LONG*)var->sqldata = *(bool*)value ? 1 : 0;\r
+                       }\r
+                       else if (ivType == ivInt16)\r
+                       {\r
+                               *(ISC_LONG*)var->sqldata = *(int16_t*)value;\r
+                       }\r
+                       else if (ivType == ivInt32)\r
+                       {\r
+                               *(ISC_LONG*)var->sqldata = *(ISC_LONG*)value;\r
+                       }\r
+                       else if (ivType == ivInt64)\r
+                       {\r
+                               if (*(int64_t*)value < consts::min32 || *(int64_t*)value > consts::max32)\r
+                                       throw LogicExceptionImpl("RowImpl::SetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               *(ISC_LONG*)var->sqldata = (ISC_LONG)*(int64_t*)value;\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_LONG is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(ISC_LONG*)var->sqldata =\r
+                                       (ISC_LONG)floor(*(float*)value * multiplier + 0.5);\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_LONG is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(ISC_LONG*)var->sqldata =\r
+                                       (ISC_LONG)floor(*(double*)value * multiplier + 0.5);\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue",  var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_INT64 :\r
+                       if (ivType == ivBool)\r
+                       {\r
+                               *(int64_t*)var->sqldata = *(bool*)value ? 1 : 0;\r
+                       }\r
+                       else if (ivType == ivInt16)\r
+                       {\r
+                               *(int64_t*)var->sqldata = *(int16_t*)value;\r
+                       }\r
+                       else if (ivType == ivInt32)\r
+                       {\r
+                               *(int64_t*)var->sqldata = *(int32_t*)value;\r
+                       }\r
+                       else if (ivType == ivInt64)\r
+                       {\r
+                               *(int64_t*)var->sqldata = *(int64_t*)value;\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_INT64 is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(int64_t*)var->sqldata =\r
+                                       (int64_t)floor(*(float*)value * multiplier + 0.5);\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_INT64 is a NUMERIC(x,y), scale it !\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(int64_t*)var->sqldata =\r
+                                       (int64_t)floor(*(double*)value * multiplier + 0.5);\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_FLOAT :\r
+                       if (ivType != ivFloat || var->sqlscale != 0)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                       _("Incompatible types."));\r
+                       *(float*)var->sqldata = *(float*)value;\r
+                       break;\r
+\r
+               case SQL_DOUBLE :\r
+                       if (ivType != ivDouble)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       if (var->sqlscale != 0)\r
+                       {\r
+                               // Round to scale of NUMERIC(x,y)\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               *(double*)var->sqldata =\r
+                                       floor(*(double*)value * multiplier + 0.5) / multiplier;\r
+                       }\r
+                       else *(double*)var->sqldata = *(double*)value;\r
+                       break;\r
+\r
+               case SQL_TIMESTAMP :\r
+                       if (ivType != ivTimestamp)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       encodeTimestamp(*(ISC_TIMESTAMP*)var->sqldata, *(IBPP::Timestamp*)value);\r
+                       break;\r
+\r
+               case SQL_TYPE_DATE :\r
+                       if (ivType != ivDate)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       encodeDate(*(ISC_DATE*)var->sqldata, *(IBPP::Date*)value);\r
+                       break;\r
+\r
+               case SQL_TYPE_TIME :\r
+                       if (ivType != ivTime)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                                       _("Incompatible types."));\r
+                       encodeTime(*(ISC_TIME*)var->sqldata, *(IBPP::Time*)value);\r
+                       break;\r
+\r
+               case SQL_BLOB :\r
+                       if (ivType == ivBlob)\r
+                       {\r
+                               BlobImpl* blob = (BlobImpl*)value;\r
+                               blob->GetId((ISC_QUAD*)var->sqldata);\r
+                       }\r
+                       else if (ivType == ivString)\r
+                       {\r
+                               BlobImpl blob(mDatabase, mTransaction);\r
+                               blob.Save(*(std::string*)value);\r
+                               blob.GetId((ISC_QUAD*)var->sqldata);\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_ARRAY :\r
+                       if (ivType != ivArray)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       {\r
+                               ArrayImpl* array = (ArrayImpl*)value;\r
+                               array->GetId((ISC_QUAD*)var->sqldata);\r
+                               // When an array has been affected to a column, we want to reset\r
+                               // its ID. This way, the next WriteFrom() on the same Array object\r
+                               // will allocate a new ID. This protects against storing the same\r
+                               // array ID in multiple columns or rows.\r
+                               array->ResetId();\r
+                       }\r
+                       break;\r
+\r
+               default : throw LogicExceptionImpl("RowImpl::SetValue",\r
+                                               _("The field uses an unsupported SQL type !"));\r
+       }\r
+\r
+       if (var->sqltype & 1) *var->sqlind = 0;         // Remove the 0 flag\r
+}\r
+\r
+void* RowImpl::GetValue(int varnum, IITYPE ivType, void* retvalue)\r
+{\r
+       if (varnum < 1 || varnum > mDescrArea->sqld)\r
+               throw LogicExceptionImpl("RowImpl::GetValue", _("Variable index out of range."));\r
+\r
+       void* value;\r
+       int len;\r
+       XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
+\r
+       // When there is no value (SQL NULL)\r
+       if ((var->sqltype & 1) && *(var->sqlind) != 0) return 0;\r
+\r
+       switch (var->sqltype & ~1)\r
+       {\r
+               case SQL_TEXT :\r
+                       if (ivType == ivString)\r
+                       {\r
+                               // In case of ivString, 'void* retvalue' points to a std::string where we\r
+                               // will directly store the data.\r
+                               std::string* str = (std::string*)retvalue;\r
+                               str->erase();\r
+                               str->append(var->sqldata, var->sqllen);\r
+                               value = retvalue;       // value != 0 means 'not null'\r
+                       }\r
+                       else if (ivType == ivByte)\r
+                       {\r
+                               // In case of ivByte, void* retvalue points to an int where we\r
+                               // will store the len of the available data\r
+                               if (retvalue != 0) *(int*)retvalue = var->sqllen;\r
+                               value = var->sqldata;\r
+                       }\r
+                       else if (ivType == ivDBKey)\r
+                       {\r
+                               IBPP::DBKey* key = (IBPP::DBKey*)retvalue;\r
+                               key->SetKey(var->sqldata, var->sqllen);\r
+                               value = retvalue;\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               mBools[varnum-1] = 0;\r
+                               if (var->sqllen >= 1)\r
+                               {\r
+                                       char c = var->sqldata[0];\r
+                                       if (c == 't' || c == 'T' || c == 'y' || c == 'Y' ||     c == '1')\r
+                                               mBools[varnum-1] = 1;\r
+                               }\r
+                               value = &mBools[varnum-1];\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_VARYING :\r
+                       if (ivType == ivString)\r
+                       {\r
+                               // In case of ivString, 'void* retvalue' points to a std::string where we\r
+                               // will directly store the data.\r
+                               std::string* str = (std::string*)retvalue;\r
+                               str->erase();\r
+                               str->append(var->sqldata+2, (int32_t)*(int16_t*)var->sqldata);\r
+                               value = retvalue;\r
+                       }\r
+                       else if (ivType == ivByte)\r
+                       {\r
+                               // In case of ivByte, void* retvalue points to an int where we\r
+                               // will store the len of the available data\r
+                               if (retvalue != 0) *(int*)retvalue = (int)*(int16_t*)var->sqldata;\r
+                               value = var->sqldata+2;\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               mBools[varnum-1] = 0;\r
+                               len = *(int16_t*)var->sqldata;\r
+                               if (len >= 1)\r
+                               {\r
+                                       char c = var->sqldata[2];\r
+                                       if (c == 't' || c == 'T' || c == 'y' || c == 'Y' ||     c == '1')\r
+                                               mBools[varnum-1] = 1;\r
+                               }\r
+                               value = &mBools[varnum-1];\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_SHORT :\r
+                       if (ivType == ivInt16)\r
+                       {\r
+                               value = var->sqldata;\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               if (*(int16_t*)var->sqldata == 0) mBools[varnum-1] = 0;\r
+                               else mBools[varnum-1] = 1;\r
+                               value = &mBools[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt32)\r
+                       {\r
+                               mInt32s[varnum-1] = *(int16_t*)var->sqldata;\r
+                               value = &mInt32s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt64)\r
+                       {\r
+                               mInt64s[varnum-1] = *(int16_t*)var->sqldata;\r
+                               value = &mInt64s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mFloats[varnum-1] = (float)(*(int16_t*)var->sqldata / divisor);\r
+\r
+                               value = &mFloats[varnum-1];\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_SHORT is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mNumerics[varnum-1] = *(int16_t*)var->sqldata / divisor;\r
+                               value = &mNumerics[varnum-1];\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_LONG :\r
+                       if (ivType == ivInt32)\r
+                       {\r
+                               value = var->sqldata;\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               if (*(int32_t*)var->sqldata == 0) mBools[varnum-1] = 0;\r
+                               else mBools[varnum-1] = 1;\r
+                               value = &mBools[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt16)\r
+                       {\r
+                               int32_t tmp = *(int32_t*)var->sqldata;\r
+                               if (tmp < consts::min16 || tmp > consts::max16)\r
+                                       throw LogicExceptionImpl("RowImpl::GetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               mInt16s[varnum-1] = (int16_t)tmp;\r
+                               value = &mInt16s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt64)\r
+                       {\r
+                               mInt64s[varnum-1] = *(int32_t*)var->sqldata;\r
+                               value = &mInt64s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_LONG is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mFloats[varnum-1] = (float)(*(int32_t*)var->sqldata / divisor);\r
+                               value = &mFloats[varnum-1];\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_LONG is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mNumerics[varnum-1] = *(int32_t*)var->sqldata / divisor;\r
+                               value = &mNumerics[varnum-1];\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_INT64 :\r
+                       if (ivType == ivInt64)\r
+                       {\r
+                               value = var->sqldata;\r
+                       }\r
+                       else if (ivType == ivBool)\r
+                       {\r
+                               if (*(int64_t*)var->sqldata == 0) mBools[varnum-1] = 0;\r
+                               else mBools[varnum-1] = 1;\r
+                               value = &mBools[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt16)\r
+                       {\r
+                               int64_t tmp = *(int64_t*)var->sqldata;\r
+                               if (tmp < consts::min16 || tmp > consts::max16)\r
+                                       throw LogicExceptionImpl("RowImpl::GetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               mInt16s[varnum-1] = (int16_t)tmp;\r
+                               value = &mInt16s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivInt32)\r
+                       {\r
+                               int64_t tmp = *(int64_t*)var->sqldata;\r
+                               if (tmp < consts::min32 || tmp > consts::max32)\r
+                                       throw LogicExceptionImpl("RowImpl::GetValue",\r
+                                               _("Out of range numeric conversion !"));\r
+                               mInt32s[varnum-1] = (int32_t)tmp;\r
+                               value = &mInt32s[varnum-1];\r
+                       }\r
+                       else if (ivType == ivFloat)\r
+                       {\r
+                               // This SQL_INT64 is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mFloats[varnum-1] = (float)(*(int64_t*)var->sqldata / divisor);\r
+                               value = &mFloats[varnum-1];\r
+                       }\r
+                       else if (ivType == ivDouble)\r
+                       {\r
+                               // This SQL_INT64 is a NUMERIC(x,y), scale it !\r
+                               double divisor = consts::dscales[-var->sqlscale];\r
+                               mNumerics[varnum-1] = *(int64_t*)var->sqldata / divisor;\r
+                               value = &mNumerics[varnum-1];\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+\r
+               case SQL_FLOAT :\r
+                       if (ivType != ivFloat)\r
+                               throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       value = var->sqldata;\r
+                       break;\r
+\r
+               case SQL_DOUBLE :\r
+                       if (ivType != ivDouble)\r
+                               throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       if (var->sqlscale != 0)\r
+                       {\r
+                               // Round to scale y of NUMERIC(x,y)\r
+                               double multiplier = consts::dscales[-var->sqlscale];\r
+                               mNumerics[varnum-1] =\r
+                                       floor(*(double*)var->sqldata * multiplier + 0.5) / multiplier;\r
+                               value = &mNumerics[varnum-1];\r
+                       }\r
+                       else value = var->sqldata;\r
+                       break;\r
+\r
+               case SQL_TIMESTAMP :\r
+                       if (ivType != ivTimestamp)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       decodeTimestamp(*(IBPP::Timestamp*)retvalue, *(ISC_TIMESTAMP*)var->sqldata);\r
+                       value = retvalue;\r
+                       break;\r
+\r
+               case SQL_TYPE_DATE :\r
+                       if (ivType != ivDate)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       decodeDate(*(IBPP::Date*)retvalue, *(ISC_DATE*)var->sqldata);\r
+                       value = retvalue;\r
+                       break;\r
+\r
+               case SQL_TYPE_TIME :\r
+                       if (ivType != ivTime)\r
+                               throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       decodeTime(*(IBPP::Time*)retvalue, *(ISC_TIME*)var->sqldata);\r
+                       value = retvalue;\r
+                       break;\r
+\r
+               case SQL_BLOB :\r
+                       if (ivType == ivBlob)\r
+                       {\r
+                               BlobImpl* blob = (BlobImpl*)retvalue;\r
+                               blob->SetId((ISC_QUAD*)var->sqldata);\r
+                               value = retvalue;\r
+                       }\r
+                       else if (ivType == ivString)\r
+                       {\r
+                               BlobImpl blob(mDatabase, mTransaction);\r
+                               blob.SetId((ISC_QUAD*)var->sqldata);\r
+                               std::string* str = (std::string*)retvalue;\r
+                               blob.Load(*str);\r
+                               value = retvalue;\r
+                       }\r
+                       else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                               _("Incompatible types."));\r
+                       break;\r
+                       \r
+               case SQL_ARRAY :\r
+                       if (ivType != ivArray)\r
+                               throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
+                                                                                       _("Incompatible types."));\r
+                       {\r
+                               ArrayImpl* array = (ArrayImpl*)retvalue;\r
+                               array->SetId((ISC_QUAD*)var->sqldata);\r
+                               value = retvalue;\r
+                       }\r
+                       break;\r
+\r
+               default : throw LogicExceptionImpl("RowImpl::GetValue",\r
+                                               _("Found an unknown sqltype !"));\r
+       }\r
+\r
+       return value;\r
+}\r
+\r
+void RowImpl::Free()\r
+{\r
+       if (mDescrArea != 0)\r
+       {\r
+               for (int i = 0; i < mDescrArea->sqln; i++)\r
+               {\r
+                       XSQLVAR* var = &(mDescrArea->sqlvar[i]);\r
+                       if (var->sqldata != 0)\r
+                       {\r
+                               switch (var->sqltype & ~1)\r
+                               {\r
+                                       case SQL_ARRAY :\r
+                                       case SQL_BLOB :         delete (ISC_QUAD*) var->sqldata; break;\r
+                                       case SQL_TIMESTAMP :delete (ISC_TIMESTAMP*) var->sqldata; break;\r
+                                       case SQL_TYPE_TIME :delete (ISC_TIME*) var->sqldata; break;\r
+                                       case SQL_TYPE_DATE :delete (ISC_DATE*) var->sqldata; break;\r
+                                       case SQL_TEXT :\r
+                                       case SQL_VARYING :      delete [] var->sqldata; break;\r
+                                       case SQL_SHORT :        delete (int16_t*) var->sqldata; break;\r
+                                       case SQL_LONG :         delete (int32_t*) var->sqldata; break;\r
+                                       case SQL_INT64 :        delete (int64_t*) var->sqldata; break;\r
+                                       case SQL_FLOAT :        delete (float*) var->sqldata; break;\r
+                                       case SQL_DOUBLE :       delete (double*) var->sqldata; break;\r
+                                       default : throw LogicExceptionImpl("RowImpl::Free",\r
+                                                               _("Found an unknown sqltype !"));\r
+                               }\r
+                       }\r
+                       if (var->sqlind != 0) delete var->sqlind;\r
+               }\r
+               delete [] (char*)mDescrArea;\r
+               mDescrArea = 0;\r
+       }\r
+\r
+       mNumerics.clear();\r
+       mFloats.clear();\r
+       mInt64s.clear();\r
+       mInt32s.clear();\r
+       mInt16s.clear();\r
+       mBools.clear();\r
+       mStrings.clear();\r
+       mUpdated.clear();\r
+\r
+       mDialect = 0;\r
+       mDatabase = 0;\r
+       mTransaction = 0;\r
+}\r
+\r
+void RowImpl::Resize(int n)\r
+{\r
+       const int size = XSQLDA_LENGTH(n);\r
+\r
+       Free();\r
+    mDescrArea = (XSQLDA*) new char[size];\r
+\r
+       memset(mDescrArea, 0, size);\r
+       mNumerics.resize(n);\r
+       mFloats.resize(n);\r
+       mInt64s.resize(n);\r
+       mInt32s.resize(n);\r
+       mInt16s.resize(n);\r
+       mBools.resize(n);\r
+       mStrings.resize(n);\r
+       mUpdated.resize(n);\r
+       for (int i = 0; i < n; i++)\r
+       {\r
+               mNumerics[i] = 0.0;\r
+               mFloats[i] = 0.0;\r
+               mInt64s[i] = 0;\r
+               mInt32s[i] = 0;\r
+               mInt16s[i] = 0;\r
+               mBools[i] = 0;\r
+               mStrings[i].erase();\r
+               mUpdated[i] = false;\r
+       }\r
+\r
+       mDescrArea->version = SQLDA_VERSION1;\r
+       mDescrArea->sqln = (int16_t)n;\r
+}\r
+\r
+void RowImpl::AllocVariables()\r
+{\r
+       int i;\r
+       for (i = 0; i < mDescrArea->sqld; i++)\r
+       {\r
+               XSQLVAR* var = &(mDescrArea->sqlvar[i]);\r
+               switch (var->sqltype & ~1)\r
+               {\r
+                       case SQL_ARRAY :\r
+                       case SQL_BLOB :         var->sqldata = (char*) new ISC_QUAD;\r
+                                                               memset(var->sqldata, 0, sizeof(ISC_QUAD));\r
+                                                               break;\r
+                       case SQL_TIMESTAMP :var->sqldata = (char*) new ISC_TIMESTAMP;\r
+                                                               memset(var->sqldata, 0, sizeof(ISC_TIMESTAMP));\r
+                                                               break;\r
+                       case SQL_TYPE_TIME :var->sqldata = (char*) new ISC_TIME;\r
+                                                               memset(var->sqldata, 0, sizeof(ISC_TIME));\r
+                                                               break;\r
+                       case SQL_TYPE_DATE :var->sqldata = (char*) new ISC_DATE;\r
+                                                               memset(var->sqldata, 0, sizeof(ISC_DATE));\r
+                                                               break;\r
+                       case SQL_TEXT :         var->sqldata = new char[var->sqllen+1];\r
+                                                               memset(var->sqldata, ' ', var->sqllen);\r
+                                                               var->sqldata[var->sqllen] = '\0';\r
+                                                               break;\r
+                       case SQL_VARYING :      var->sqldata = new char[var->sqllen+3];\r
+                                                               memset(var->sqldata, 0, 2);\r
+                                                               memset(var->sqldata+2, ' ', var->sqllen);\r
+                                                               var->sqldata[var->sqllen+2] = '\0';\r
+                                                               break;\r
+                       case SQL_SHORT :        var->sqldata = (char*) new int16_t(0); break;\r
+                       case SQL_LONG :         var->sqldata = (char*) new int32_t(0); break;\r
+                       case SQL_INT64 :        var->sqldata = (char*) new int64_t(0); break;\r
+                       case SQL_FLOAT :        var->sqldata = (char*) new float(0.0); break;\r
+                       case SQL_DOUBLE :       var->sqldata = (char*) new double(0.0); break;\r
+                       default : throw LogicExceptionImpl("RowImpl::AllocVariables",\r
+                                               _("Found an unknown sqltype !"));\r
+               }\r
+               if (var->sqltype & 1) var->sqlind = new short(-1);      // 0 indicator\r
+       }\r
+}\r
+\r
+bool RowImpl::MissingValues()\r
+{\r
+       for (int i = 0; i < mDescrArea->sqld; i++)\r
+               if (! mUpdated[i]) return true;\r
+       return false;\r
+}\r
+\r
+RowImpl& RowImpl::operator=(const RowImpl& copied)\r
+{\r
+       Free();\r
+\r
+       const int n = copied.mDescrArea->sqln;\r
+       const int size = XSQLDA_LENGTH(n);\r
+\r
+       // Initial brute copy\r
+    mDescrArea = (XSQLDA*) new char[size];\r
+       memcpy(mDescrArea, copied.mDescrArea, size);\r
+\r
+       // Copy of the columns data\r
+       for (int i = 0; i < mDescrArea->sqld; i++)\r
+       {\r
+               XSQLVAR* var = &(mDescrArea->sqlvar[i]);\r
+               XSQLVAR* org = &(copied.mDescrArea->sqlvar[i]);\r
+               switch (var->sqltype & ~1)\r
+               {\r
+                       case SQL_ARRAY :\r
+                       case SQL_BLOB :         var->sqldata = (char*) new ISC_QUAD;\r
+                                                               memcpy(var->sqldata, org->sqldata, sizeof(ISC_QUAD));\r
+                                                               break;\r
+                       case SQL_TIMESTAMP :var->sqldata = (char*) new ISC_TIMESTAMP;\r
+                                                               memcpy(var->sqldata, org->sqldata, sizeof(ISC_TIMESTAMP));\r
+                                                               break;\r
+                       case SQL_TYPE_TIME :var->sqldata = (char*) new ISC_TIME;\r
+                                                               memcpy(var->sqldata, org->sqldata, sizeof(ISC_TIME));\r
+                                                               break;\r
+                       case SQL_TYPE_DATE :var->sqldata = (char*) new ISC_DATE;\r
+                                                               memcpy(var->sqldata, org->sqldata, sizeof(ISC_DATE));\r
+                                                               break;\r
+                       case SQL_TEXT :         var->sqldata = new char[var->sqllen+1];\r
+                                                               memcpy(var->sqldata, org->sqldata, var->sqllen+1);\r
+                                                               break;\r
+                       case SQL_VARYING :      var->sqldata = new char[var->sqllen+3];\r
+                                                               memcpy(var->sqldata, org->sqldata, var->sqllen+3);\r
+                                                               break;\r
+                       case SQL_SHORT :        var->sqldata = (char*) new int16_t(*(int16_t*)org->sqldata); break;\r
+                       case SQL_LONG :         var->sqldata = (char*) new int32_t(*(int32_t*)org->sqldata); break;\r
+                       case SQL_INT64 :        var->sqldata = (char*) new int64_t(*(int64_t*)org->sqldata); break;\r
+                       case SQL_FLOAT :        var->sqldata = (char*) new float(*(float*)org->sqldata); break;\r
+                       case SQL_DOUBLE :       var->sqldata = (char*) new double(*(double*)org->sqldata); break;\r
+                       default : throw LogicExceptionImpl("RowImpl::Ctor",\r
+                                               _("Found an unknown sqltype !"));\r
+               }\r
+               if (var->sqltype & 1) var->sqlind = new short(*org->sqlind);    // 0 indicator\r
+       }\r
+\r
+       // Pointers init, real data copy\r
+       mNumerics = copied.mNumerics;\r
+       mFloats = copied.mFloats;\r
+       mInt64s = copied.mInt64s;\r
+       mInt32s = copied.mInt32s;\r
+       mInt16s = copied.mInt16s;\r
+       mBools = copied.mBools;\r
+       mStrings = copied.mStrings;\r
+\r
+       mDialect = copied.mDialect;\r
+       mDatabase = copied.mDatabase;\r
+       mTransaction = copied.mTransaction;\r
+       \r
+       return *this;\r
+}\r
+\r
+RowImpl::RowImpl(const RowImpl& copied)\r
+       : IBPP::IRow(), mRefCount(0), mDescrArea(0)\r
+{\r
+       // mRefCount and mDescrArea are set to 0 before using the assignment operator\r
+       *this = copied;         // The assignment operator does the real copy\r
+}\r
+\r
+RowImpl::RowImpl(int dialect, int n, DatabaseImpl* db, TransactionImpl* tr)\r
+       : mRefCount(0), mDescrArea(0)\r
+{\r
+       Resize(n);\r
+       mDialect = dialect;\r
+       mDatabase = db;\r
+       mTransaction = tr;\r
+}\r
+\r
+RowImpl::~RowImpl()\r
+{\r
+       try { Free(); }\r
+               catch (...) { }\r
+}\r
+\r
+//\r
+//     EOF\r
+//\r