--- /dev/null
+///////////////////////////////////////////////////////////////////////////////\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, ×tamp);\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*)×tamp);\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*)×tamp);\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