1 ///////////////////////////////////////////////////////////////////////////////
\r 
   3 //      File    : $Id: row.cpp,v 1.2 2009/03/19 20:00:28 faust Exp $
\r 
   4 //      Subject : IBPP, Row class implementation
\r 
   6 ///////////////////////////////////////////////////////////////////////////////
\r 
   8 //      (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)
\r 
  10 //      The contents of this file are subject to the IBPP License (the "License");
\r 
  11 //      you may not use this file except in compliance with the License.  You may
\r 
  12 //      obtain a copy of the License at http://www.ibpp.org or in the 'license.txt'
\r 
  13 //      file which must have been distributed along with this file.
\r 
  15 //      This software, distributed under the License, is distributed on an "AS IS"
\r 
  16 //      basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.  See the
\r 
  17 //      License for the specific language governing rights and limitations
\r 
  18 //      under the License.
\r 
  20 ///////////////////////////////////////////////////////////////////////////////
\r 
  23 //      * Tabulations should be set every four characters when editing this file.
\r 
  25 ///////////////////////////////////////////////////////////////////////////////
\r 
  28 #pragma warning(disable: 4786 4996)
\r 
  30 #pragma warning(disable: 4702)
\r 
  44 using namespace ibpp_internals;
\r 
  46 //      (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))
\r 
  48 void RowImpl::SetNull(int param)
\r 
  50         if (mDescrArea == 0)
\r 
  51                 throw LogicExceptionImpl("Row::SetNull", _("The row is not initialized."));
\r 
  52         if (param < 1 || param > mDescrArea->sqld)
\r 
  53                 throw LogicExceptionImpl("Row::SetNull", _("Variable index out of range."));
\r 
  55         XSQLVAR* var = &(mDescrArea->sqlvar[param-1]);
\r 
  56         if (! (var->sqltype & 1))
\r 
  57                 throw LogicExceptionImpl("Row::SetNull", _("This column can't be null."));
\r 
  59         *var->sqlind = -1;      // Set the column to SQL NULL
\r 
  60         mUpdated[param-1] = true;
\r 
  63 void RowImpl::Set(int param, bool value)
\r 
  65         if (mDescrArea == 0)
\r 
  66                 throw LogicExceptionImpl("Row::Set[bool]", _("The row is not initialized."));
\r 
  68         SetValue(param, ivBool, &value);
\r 
  69         mUpdated[param-1] = true;
\r 
  72 void RowImpl::Set(int param, const char* cstring)
\r 
  74         if (mDescrArea == 0)
\r 
  75                 throw LogicExceptionImpl("Row::Set[char*]", _("The row is not initialized."));
\r 
  77                 throw LogicExceptionImpl("Row::Set[char*]", _("null char* pointer detected."));
\r 
  79         SetValue(param, ivByte, cstring, (int)strlen(cstring));
\r 
  80         mUpdated[param-1] = true;
\r 
  83 void RowImpl::Set(int param, const void* bindata, int len)
\r 
  85         if (mDescrArea == 0)
\r 
  86                 throw LogicExceptionImpl("Row::Set[void*]", _("The row is not initialized."));
\r 
  88                 throw LogicExceptionImpl("Row::Set[void*]", _("null char* pointer detected."));
\r 
  90                 throw LogicExceptionImpl("Row::Set[void*]", _("Length must be >= 0"));
\r 
  92         SetValue(param, ivByte, bindata, len);
\r 
  93         mUpdated[param-1] = true;
\r 
  96 void RowImpl::Set(int param, const std::string& s)
\r 
  98         if (mDescrArea == 0)
\r 
  99                 throw LogicExceptionImpl("Row::Set[string]", _("The row is not initialized."));
\r 
 101         SetValue(param, ivString, (void*)&s);
\r 
 102         mUpdated[param-1] = true;
\r 
 105 void RowImpl::Set(int param, int16_t value)
\r 
 107         if (mDescrArea == 0)
\r 
 108                 throw LogicExceptionImpl("Row::Set[int16_t]", _("The row is not initialized."));
\r 
 110         SetValue(param, ivInt16, &value);
\r 
 111         mUpdated[param-1] = true;
\r 
 114 void RowImpl::Set(int param, int32_t value)
\r 
 116         if (mDescrArea == 0)
\r 
 117                 throw LogicExceptionImpl("Row::Set[int32_t]", _("The row is not initialized."));
\r 
 119         SetValue(param, ivInt32, &value);
\r 
 120         mUpdated[param-1] = true;
\r 
 123 void RowImpl::Set(int param, int64_t value)
\r 
 125         if (mDescrArea == 0)
\r 
 126                 throw LogicExceptionImpl("Row::Set[int64_t]", _("The row is not initialized."));
\r 
 128         SetValue(param, ivInt64, &value);
\r 
 129         mUpdated[param-1] = true;
\r 
 132 void RowImpl::Set(int param, float value)
\r 
 134         if (mDescrArea == 0)
\r 
 135                 throw LogicExceptionImpl("Row::Set[float]", _("The row is not initialized."));
\r 
 137         SetValue(param, ivFloat, &value);
\r 
 138         mUpdated[param-1] = true;
\r 
 141 void RowImpl::Set(int param, double value)
\r 
 143         if (mDescrArea == 0)
\r 
 144                 throw LogicExceptionImpl("Row::Set[double]", _("The row is not initialized."));
\r 
 146         SetValue(param, ivDouble, &value);
\r 
 147         mUpdated[param-1] = true;
\r 
 150 void RowImpl::Set(int param, const IBPP::Timestamp& value)
\r 
 152         if (mDescrArea == 0)
\r 
 153                 throw LogicExceptionImpl("Row::Set[Timestamp]", _("The row is not initialized."));
\r 
 155         SetValue(param, ivTimestamp, &value);
\r 
 156         mUpdated[param-1] = true;
\r 
 159 void RowImpl::Set(int param, const IBPP::Date& value)
\r 
 161         if (mDescrArea == 0)
\r 
 162                 throw LogicExceptionImpl("Row::Set[Date]", _("The row is not initialized."));
\r 
 166                 // In dialect 1, IBPP::Date is supposed to work with old 'DATE'
\r 
 167                 // fields which are actually ISC_TIMESTAMP.
\r 
 168                 IBPP::Timestamp timestamp(value);
\r 
 169                 SetValue(param, ivTimestamp, ×tamp);
\r 
 174                 SetValue(param, ivDate, (void*)&value);
\r 
 177         mUpdated[param-1] = true;
\r 
 180 void RowImpl::Set(int param, const IBPP::Time& value)
\r 
 182         if (mDescrArea == 0)
\r 
 183                 throw LogicExceptionImpl("Row::Set[Time]", _("The row is not initialized."));
\r 
 185                 throw LogicExceptionImpl("Row::Set[Time]", _("Requires use of a dialect 3 database."));
\r 
 187         SetValue(param, ivTime, &value);
\r 
 188         mUpdated[param-1] = true;
\r 
 191 void RowImpl::Set(int param, const IBPP::Blob& blob)
\r 
 193         if (mDescrArea == 0)
\r 
 194                 throw LogicExceptionImpl("Row::Set[Blob]", _("The row is not initialized."));
\r 
 195         if (mDatabase != 0 && blob->DatabasePtr() != mDatabase)
\r 
 196                 throw LogicExceptionImpl("Row::Set[Blob]",
\r 
 197                         _("IBlob and Row attached to different databases"));
\r 
 198         if (mTransaction != 0 && blob->TransactionPtr() != mTransaction)
\r 
 199                 throw LogicExceptionImpl("Row::Set[Blob]",
\r 
 200                         _("IBlob and Row attached to different transactions"));
\r 
 202         SetValue(param, ivBlob, blob.intf());
\r 
 203         mUpdated[param-1] = true;
\r 
 206 void RowImpl::Set(int param, const IBPP::Array& array)
\r 
 208         if (mDescrArea == 0)
\r 
 209                 throw LogicExceptionImpl("Row::Set[Array]", _("The row is not initialized."));
\r 
 210         if (mDatabase != 0 && array->DatabasePtr() != mDatabase)
\r 
 211                 throw LogicExceptionImpl("Row::Set[Array]",
\r 
 212                         _("IArray and Row attached to different databases"));
\r 
 213         if (mTransaction != 0 && array->TransactionPtr() != mTransaction)
\r 
 214                 throw LogicExceptionImpl("Row::Set[Array]",
\r 
 215                         _("IArray and Row attached to different transactions"));
\r 
 217         SetValue(param, ivArray, (void*)array.intf());
\r 
 218         mUpdated[param-1] = true;
\r 
 221 void RowImpl::Set(int param, const IBPP::DBKey& key)
\r 
 223         if (mDescrArea == 0)
\r 
 224                 throw LogicExceptionImpl("Row::Set[DBKey]", _("The row is not initialized."));
\r 
 226         SetValue(param, ivDBKey, (void*)&key);
\r 
 227         mUpdated[param-1] = true;
\r 
 231 void RowImpl::Set(int param, const IBPP::Value& value)
\r 
 233         if (mDescrArea == 0)
\r 
 234                 throw LogicExceptionImpl("Row::Set[Value]", _("The row is not initialized."));
\r 
 236         //SetValue(param, ivDBKey, (void*)&key);
\r 
 237         //mUpdated[param-1] = true;
\r 
 241 bool RowImpl::IsNull(int column)
\r 
 243         if (mDescrArea == 0)
\r 
 244                 throw LogicExceptionImpl("Row::IsNull", _("The row is not initialized."));
\r 
 245         if (column < 1 || column > mDescrArea->sqld)
\r 
 246                 throw LogicExceptionImpl("Row::IsNull", _("Variable index out of range."));
\r 
 248         XSQLVAR* var = &(mDescrArea->sqlvar[column-1]);
\r 
 249         return ((var->sqltype & 1) && *(var->sqlind) != 0) ? true : false;
\r 
 252 bool RowImpl::Get(int column, bool& retvalue)
\r 
 254         if (mDescrArea == 0)
\r 
 255                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 257         void* pvalue = GetValue(column, ivBool);
\r 
 259                 retvalue = (*(char*)pvalue == 0 ? false : true);
\r 
 260         return pvalue == 0 ? true : false;
\r 
 263 bool RowImpl::Get(int column, char* retvalue)
\r 
 265         if (mDescrArea == 0)
\r 
 266                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 268                 throw LogicExceptionImpl("Row::Get", _("Null pointer detected"));
\r 
 271         void* pvalue = GetValue(column, ivByte, &sqllen);
\r 
 274                 memcpy(retvalue, pvalue, sqllen);
\r 
 275                 retvalue[sqllen] = '\0';
\r 
 277         return pvalue == 0 ? true : false;
\r 
 280 bool RowImpl::Get(int column, void* bindata, int& userlen)
\r 
 282         if (mDescrArea == 0)
\r 
 283                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 285                 throw LogicExceptionImpl("Row::Get", _("Null pointer detected"));
\r 
 287                 throw LogicExceptionImpl("Row::Get", _("Length must be >= 0"));
\r 
 290         void* pvalue = GetValue(column, ivByte, &sqllen);
\r 
 293                 // userlen says how much bytes the user can accept
\r 
 294                 // let's shorten it, if there is less bytes available
\r 
 295                 if (sqllen < userlen) userlen = sqllen;
\r 
 296                 memcpy(bindata, pvalue, userlen);
\r 
 298         return pvalue == 0 ? true : false;
\r 
 301 bool RowImpl::Get(int column, std::string& retvalue)
\r 
 303         if (mDescrArea == 0)
\r 
 304                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 306         void* pvalue = GetValue(column, ivString, &retvalue);
\r 
 307         return pvalue == 0 ? true : false;
\r 
 310 bool RowImpl::Get(int column, int16_t& retvalue)
\r 
 312         if (mDescrArea == 0)
\r 
 313                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 315         void* pvalue = GetValue(column, ivInt16);
\r 
 317                 retvalue = *(int16_t*)pvalue;
\r 
 318         return pvalue == 0 ? true : false;
\r 
 321 bool RowImpl::Get(int column, int32_t& retvalue)
\r 
 323         if (mDescrArea == 0)
\r 
 324                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 326         void* pvalue = GetValue(column, ivInt32);
\r 
 328                 retvalue = *(int32_t*)pvalue;
\r 
 329         return pvalue == 0 ? true : false;
\r 
 332 bool RowImpl::Get(int column, int64_t& retvalue)
\r 
 334         if (mDescrArea == 0)
\r 
 335                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 337         void* pvalue = GetValue(column, ivInt64);
\r 
 339                 retvalue = *(int64_t*)pvalue;
\r 
 340         return pvalue == 0 ? true : false;
\r 
 343 bool RowImpl::Get(int column, float& retvalue)
\r 
 345         if (mDescrArea == 0)
\r 
 346                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 348         void* pvalue = GetValue(column, ivFloat);
\r 
 350                 retvalue = *(float*)pvalue;
\r 
 351         return pvalue == 0 ? true : false;
\r 
 354 bool RowImpl::Get(int column, double& retvalue)
\r 
 356         if (mDescrArea == 0)
\r 
 357                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 359         void* pvalue = GetValue(column, ivDouble);
\r 
 361                 retvalue = *(double*)pvalue;
\r 
 362         return pvalue == 0 ? true : false;
\r 
 365 bool RowImpl::Get(int column, IBPP::Timestamp& timestamp)
\r 
 367         if (mDescrArea == 0)
\r 
 368                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 370         void* pvalue = GetValue(column, ivTimestamp, (void*)×tamp);
\r 
 371         return pvalue == 0 ? true : false;
\r 
 374 bool RowImpl::Get(int column, IBPP::Date& date)
\r 
 376         if (mDescrArea == 0)
\r 
 377                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 381                 // Dialect 1. IBPP::Date is supposed to work with old 'DATE'
\r 
 382                 // fields which are actually ISC_TIMESTAMP.
\r 
 383                 IBPP::Timestamp timestamp;
\r 
 384                 void* pvalue = GetValue(column, ivTimestamp, (void*)×tamp);
\r 
 385                 if (pvalue != 0) date = timestamp;
\r 
 386                 return pvalue == 0 ? true : false;
\r 
 390                 void* pvalue = GetValue(column, ivDate, (void*)&date);
\r 
 391                 return pvalue == 0 ? true : false;
\r 
 395 bool RowImpl::Get(int column, IBPP::Time& time)
\r 
 397         if (mDescrArea == 0)
\r 
 398                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 400         void* pvalue = GetValue(column, ivTime, (void*)&time);
\r 
 401         return pvalue == 0 ? true : false;
\r 
 404 bool RowImpl::Get(int column, IBPP::Blob& retblob)
\r 
 406         if (mDescrArea == 0)
\r 
 407                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 409         void* pvalue = GetValue(column, ivBlob, (void*)retblob.intf());
\r 
 410         return pvalue == 0 ? true : false;
\r 
 413 bool RowImpl::Get(int column, IBPP::DBKey& retkey)
\r 
 415         if (mDescrArea == 0)
\r 
 416                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 418         void* pvalue = GetValue(column, ivDBKey, (void*)&retkey);
\r 
 419         return pvalue == 0 ? true : false;
\r 
 422 bool RowImpl::Get(int column, IBPP::Array& retarray)
\r 
 424         if (mDescrArea == 0)
\r 
 425                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 427         void* pvalue = GetValue(column, ivArray, (void*)retarray.intf());
\r 
 428         return pvalue == 0 ? true : false;
\r 
 432 const IBPP::Value RowImpl::Get(int column)
\r 
 434         if (mDescrArea == 0)
\r 
 435                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 437         //void* value = GetValue(column, ivArray, (void*)retarray.intf());
\r 
 438         //return value == 0 ? true : false;
\r 
 439         return IBPP::Value();
\r 
 443 bool RowImpl::IsNull(const std::string& name)
\r 
 445         if (mDescrArea == 0)
\r 
 446                 throw LogicExceptionImpl("Row::IsNull", _("The row is not initialized."));
\r 
 448         return IsNull(ColumnNum(name));
\r 
 451 bool RowImpl::Get(const std::string& name, bool& retvalue)
\r 
 453         if (mDescrArea == 0)
\r 
 454                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 456         return Get(ColumnNum(name), retvalue);
\r 
 459 bool RowImpl::Get(const std::string& name, char* retvalue)
\r 
 461         if (mDescrArea == 0)
\r 
 462                 throw LogicExceptionImpl("Row::Get[char*]", _("The row is not initialized."));
\r 
 464         return Get(ColumnNum(name), retvalue);
\r 
 467 bool RowImpl::Get(const std::string& name, void* retvalue, int& count)
\r 
 469         if (mDescrArea == 0)
\r 
 470                 throw LogicExceptionImpl("Row::Get[void*,int]", _("The row is not initialized."));
\r 
 472         return Get(ColumnNum(name), retvalue, count);
\r 
 475 bool RowImpl::Get(const std::string& name, std::string& retvalue)
\r 
 477         if (mDescrArea == 0)
\r 
 478                 throw LogicExceptionImpl("Row::GetString", _("The row is not initialized."));
\r 
 480         return Get(ColumnNum(name), retvalue);
\r 
 483 bool RowImpl::Get(const std::string& name, int16_t& retvalue)
\r 
 485         if (mDescrArea == 0)
\r 
 486                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 488         return Get(ColumnNum(name), retvalue);
\r 
 491 bool RowImpl::Get(const std::string& name, int32_t& retvalue)
\r 
 493         if (mDescrArea == 0)
\r 
 494                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 496         return Get(ColumnNum(name), retvalue);
\r 
 499 bool RowImpl::Get(const std::string& name, int64_t& retvalue)
\r 
 501         if (mDescrArea == 0)
\r 
 502                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 504         return Get(ColumnNum(name), retvalue);
\r 
 507 bool RowImpl::Get(const std::string& name, float& retvalue)
\r 
 509         if (mDescrArea == 0)
\r 
 510                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 512         return Get(ColumnNum(name), retvalue);
\r 
 515 bool RowImpl::Get(const std::string& name, double& retvalue)
\r 
 517         if (mDescrArea == 0)
\r 
 518                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 520         return Get(ColumnNum(name), retvalue);
\r 
 523 bool RowImpl::Get(const std::string& name, IBPP::Timestamp& retvalue)
\r 
 525         if (mDescrArea == 0)
\r 
 526                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 528         return Get(ColumnNum(name), retvalue);
\r 
 531 bool RowImpl::Get(const std::string& name, IBPP::Date& retvalue)
\r 
 533         if (mDescrArea == 0)
\r 
 534                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 536         return Get(ColumnNum(name), retvalue);
\r 
 539 bool RowImpl::Get(const std::string& name, IBPP::Time& retvalue)
\r 
 541         if (mDescrArea == 0)
\r 
 542                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 544         return Get(ColumnNum(name), retvalue);
\r 
 547 bool RowImpl::Get(const std::string&name, IBPP::Blob& retblob)
\r 
 549         if (mDescrArea == 0)
\r 
 550                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 552         return Get(ColumnNum(name), retblob);
\r 
 555 bool RowImpl::Get(const std::string& name, IBPP::DBKey& retvalue)
\r 
 557         if (mDescrArea == 0)
\r 
 558                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 560         return Get(ColumnNum(name), retvalue);
\r 
 563 bool RowImpl::Get(const std::string& name, IBPP::Array& retarray)
\r 
 565         if (mDescrArea == 0)
\r 
 566                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 568         return Get(ColumnNum(name), retarray);
\r 
 572 const IBPP::Value RowImpl::Get(const std::string& name)
\r 
 574         if (mDescrArea == 0)
\r 
 575                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));
\r 
 577         return Get(ColumnNum(name));
\r 
 581 int RowImpl::Columns()
\r 
 583         if (mDescrArea == 0)
\r 
 584                 throw LogicExceptionImpl("Row::Columns", _("The row is not initialized."));
\r 
 586         return mDescrArea->sqld;
\r 
 589 int RowImpl::ColumnNum(const std::string& name)
\r 
 591         if (mDescrArea == 0)
\r 
 592                 throw LogicExceptionImpl("Row::ColumnNum", _("The row is not initialized."));
\r 
 594                 throw LogicExceptionImpl("Row::ColumnNum", _("Column name <empty> not found."));
\r 
 597         char Uname[sizeof(var->sqlname)+1];             // Max size of sqlname + '\0'
\r 
 599         // Local upper case copy of the column name
\r 
 600         size_t len = name.length();
\r 
 601         if (len > sizeof(var->sqlname)) len = sizeof(var->sqlname);
\r 
 602         strncpy(Uname, name.c_str(), len);
\r 
 605         while (*p != '\0') { *p = char(toupper(*p)); ++p; }
\r 
 607         // Loop through the columns of the descriptor
\r 
 608         for (int i = 0; i < mDescrArea->sqld; i++)
\r 
 610                 var = &(mDescrArea->sqlvar[i]);
\r 
 611                 if (var->sqlname_length != (int16_t)len) continue;
\r 
 612                 if (strncmp(Uname, var->sqlname, len) == 0) return i+1;
\r 
 615         // Failed finding the column name, let's retry using the aliases
\r 
 616         char Ualias[sizeof(var->aliasname)+1];          // Max size of aliasname + '\0'
\r 
 618         // Local upper case copy of the column name
\r 
 619         len = name.length();
\r 
 620         if (len > sizeof(var->aliasname)) len = sizeof(var->aliasname);
\r 
 621         strncpy(Ualias, name.c_str(), len);
\r 
 622         Ualias[len] = '\0';
\r 
 624         while (*p != '\0') { *p = char(toupper(*p)); ++p; }
\r 
 626         // Loop through the columns of the descriptor
\r 
 627         for (int i = 0; i < mDescrArea->sqld; i++)
\r 
 629                 var = &(mDescrArea->sqlvar[i]);
\r 
 630                 if (var->aliasname_length != (int16_t)len) continue;
\r 
 631                 if (strncmp(Ualias, var->aliasname, len) == 0) return i+1;
\r 
 634         throw LogicExceptionImpl("Row::ColumnNum", _("Could not find matching column."));
\r 
 636         return 0;       // DMC errronously warns here about a missing return
\r 
 641 ColumnName, ColumnAlias, ColumnTable : all these 3 have a mistake.
\r 
 642 Ideally, the strings should be stored elsewhere (like _Numerics and so on) to
\r 
 643 take into account the final '\0' which needs to be added. For now, we insert
\r 
 644 the '\0' in the original data, which will cut the 32th character. Not terribly
\r 
 645 bad, but should be cleanly rewritten.
\r 
 648 const char* RowImpl::ColumnName(int varnum)
\r 
 650         if (mDescrArea == 0)
\r 
 651                 throw LogicExceptionImpl("Row::ColumnName", _("The row is not initialized."));
\r 
 652         if (varnum < 1 || varnum > mDescrArea->sqld)
\r 
 653                 throw LogicExceptionImpl("Row::ColumName", _("Variable index out of range."));
\r 
 655         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);
\r 
 656         if (var->sqlname_length >= 31) var->sqlname_length = 31;
\r 
 657         var->sqlname[var->sqlname_length] = '\0';
\r 
 658         return var->sqlname;
\r 
 661 const char* RowImpl::ColumnAlias(int varnum)
\r 
 663         if (mDescrArea == 0)
\r 
 664                 throw LogicExceptionImpl("Row::ColumnAlias", _("The row is not initialized."));
\r 
 665         if (varnum < 1 || varnum > mDescrArea->sqld)
\r 
 666                 throw LogicExceptionImpl("Row::ColumnAlias", _("Variable index out of range."));
\r 
 668         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);
\r 
 669         if (var->aliasname_length >= 31) var->aliasname_length = 31;
\r 
 670         var->aliasname[var->aliasname_length] = '\0';
\r 
 671         return var->aliasname;
\r 
 674 const char* RowImpl::ColumnTable(int varnum)
\r 
 676         if (mDescrArea == 0)
\r 
 677                 throw LogicExceptionImpl("Row::ColumnTable", _("The row is not initialized."));
\r 
 678         if (varnum < 1 || varnum > mDescrArea->sqld)
\r 
 679                 throw LogicExceptionImpl("Row::ColumnTable", _("Variable index out of range."));
\r 
 681         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);
\r 
 682         if (var->relname_length >= 31) var->relname_length = 31;
\r 
 683         var->relname[var->relname_length] = '\0';
\r 
 684         return var->relname;
\r 
 687 IBPP::SDT RowImpl::ColumnType(int varnum)
\r 
 689         if (mDescrArea == 0)
\r 
 690                 throw LogicExceptionImpl("Row::ColumnType", _("The row is not initialized."));
\r 
 691         if (varnum < 1 || varnum > mDescrArea->sqld)
\r 
 692                 throw LogicExceptionImpl("Row::ColumnType", _("Variable index out of range."));
\r 
 695         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);
\r 
 697         switch (var->sqltype & ~1)
\r 
 699                 case SQL_TEXT :      value = IBPP::sdString;    break;
\r 
 700                 case SQL_VARYING :   value = IBPP::sdString;    break;
\r 
 701                 case SQL_SHORT :     value = IBPP::sdSmallint;  break;
\r 
 702                 case SQL_LONG :      value = IBPP::sdInteger;   break;
\r 
 703                 case SQL_INT64 :     value = IBPP::sdLargeint;  break;
\r 
 704                 case SQL_FLOAT :     value = IBPP::sdFloat;     break;
\r 
 705                 case SQL_DOUBLE :    value = IBPP::sdDouble;    break;
\r 
 706                 case SQL_TIMESTAMP : value = IBPP::sdTimestamp; break;
\r 
 707                 case SQL_TYPE_DATE : value = IBPP::sdDate;      break;
\r 
 708                 case SQL_TYPE_TIME : value = IBPP::sdTime;      break;
\r 
 709                 case SQL_BLOB :      value = IBPP::sdBlob;      break;
\r 
 710                 case SQL_ARRAY :     value = IBPP::sdArray;     break;
\r 
 711                 default : throw LogicExceptionImpl("Row::ColumnType",
\r 
 712                                                 _("Found an unknown sqltype !"));
\r 
 718 int RowImpl::ColumnSubtype(int varnum)
\r 
 720         if (mDescrArea == 0)
\r 
 721                 throw LogicExceptionImpl("Row::ColumnSubtype", _("The row is not initialized."));
\r 
 722         if (varnum < 1 || varnum > mDescrArea->sqld)
\r 
 723                 throw LogicExceptionImpl("Row::ColumnSubtype", _("Variable index out of range."));
\r 
 725         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);
\r 
 726         return (int)var->sqlsubtype;
\r 
 729 int RowImpl::ColumnSize(int varnum)
\r 
 731         if (mDescrArea == 0)
\r 
 732                 throw LogicExceptionImpl("Row::ColumnSize", _("The row is not initialized."));
\r 
 733         if (varnum < 1 || varnum > mDescrArea->sqld)
\r 
 734                 throw LogicExceptionImpl("Row::ColumnSize", _("Variable index out of range."));
\r 
 736         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);
\r 
 737     return var->sqllen;
\r 
 740 int RowImpl::ColumnScale(int varnum)
\r 
 742         if (mDescrArea == 0)
\r 
 743                 throw LogicExceptionImpl("Row::ColumnScale", _("The row is not initialized."));
\r 
 744         if (varnum < 1 || varnum > mDescrArea->sqld)
\r 
 745                 throw LogicExceptionImpl("Row::ColumnScale", _("Variable index out of range."));
\r 
 747         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);
\r 
 748     return -var->sqlscale;
\r 
 751 bool RowImpl::ColumnUpdated(int varnum)
\r 
 753         if (mDescrArea == 0)
\r 
 754                 throw LogicExceptionImpl("Row::ColumnUpdated", _("The row is not initialized."));
\r 
 755         if (varnum < 1 || varnum > mDescrArea->sqld)
\r 
 756                 throw LogicExceptionImpl("Row::ColumnUpdated", _("Variable index out of range."));
\r 
 758         return mUpdated[varnum-1];
\r 
 761 bool RowImpl::Updated()
\r 
 763         if (mDescrArea == 0)
\r 
 764                 throw LogicExceptionImpl("Row::ColumnUpdated", _("The row is not initialized."));
\r 
 766         for (int i = 0; i < mDescrArea->sqld; i++)
\r 
 767                 if (mUpdated[i]) return true;
\r 
 771 IBPP::Database RowImpl::DatabasePtr() const
\r 
 776 IBPP::Transaction RowImpl::TransactionPtr() const
\r 
 778         return mTransaction;
\r 
 781 IBPP::IRow* RowImpl::Clone()
\r 
 783         // By definition the clone of an IBPP Row is a new row (so refcount=0).
\r 
 785         RowImpl* clone = new RowImpl(*this);
\r 
 789 IBPP::IRow* RowImpl::AddRef()
\r 
 791         ASSERTION(mRefCount >= 0);
\r 
 796 void RowImpl::Release()
\r 
 798         // Release cannot throw, except in DEBUG builds on assertion
\r 
 799         ASSERTION(mRefCount >= 0);
\r 
 801         try { if (mRefCount <= 0) delete this; }
\r 
 805 //      (((((((( OBJECT INTERNAL METHODS ))))))))
\r 
 807 void RowImpl::SetValue(int varnum, IITYPE ivType, const void* value, int userlen)
\r 
 809         if (varnum < 1 || varnum > mDescrArea->sqld)
\r 
 810                 throw LogicExceptionImpl("RowImpl::SetValue", _("Variable index out of range."));
\r 
 812                 throw LogicExceptionImpl("RowImpl::SetValue", _("Unexpected null pointer detected."));
\r 
 815         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);
\r 
 816         switch (var->sqltype & ~1)
\r 
 819                         if (ivType == ivString)
\r 
 821                                 std::string* svalue = (std::string*)value;
\r 
 822                                 len = (int16_t)svalue->length();
\r 
 823                                 if (len > var->sqllen) len = var->sqllen;
\r 
 824                                 strncpy(var->sqldata, svalue->c_str(), len);
\r 
 825                                 while (len < var->sqllen) var->sqldata[len++] = ' ';
\r 
 827                         else if (ivType == ivByte)
\r 
 829                                 if (userlen > var->sqllen) userlen = var->sqllen;
\r 
 830                                 memcpy(var->sqldata, value, userlen);
\r 
 831                                 while (userlen < var->sqllen) var->sqldata[userlen++] = ' ';
\r 
 833                         else if (ivType == ivDBKey)
\r 
 835                                 IBPP::DBKey* key = (IBPP::DBKey*)value;
\r 
 836                                 key->GetKey(var->sqldata, var->sqllen);
\r 
 838                         else if (ivType == ivBool)
\r 
 840                                 var->sqldata[0] = *(bool*)value ? 'T' : 'F';
\r 
 842                                 while (len < var->sqllen) var->sqldata[len++] = ' ';
\r 
 844                         else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
 845                                                                                 _("Incompatible types."));
\r 
 849                         if (ivType == ivString)
\r 
 851                                 std::string* svalue = (std::string*)value;
\r 
 852                                 len = (int16_t)svalue->length();
\r 
 853                                 if (len > var->sqllen) len = var->sqllen;
\r 
 854                                 *(int16_t*)var->sqldata = (int16_t)len;
\r 
 855                                 strncpy(var->sqldata+2, svalue->c_str(), len);
\r 
 857                         else if (ivType == ivByte)
\r 
 859                                 if (userlen > var->sqllen) userlen = var->sqllen;
\r 
 860                                 *(int16_t*)var->sqldata = (int16_t)userlen;
\r 
 861                                 memcpy(var->sqldata+2, value, userlen);
\r 
 863                         else if (ivType == ivBool)
\r 
 865                                 *(int16_t*)var->sqldata = (int16_t)1;
\r 
 866                                 var->sqldata[2] = *(bool*)value ? 'T' : 'F';
\r 
 868                         else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
 869                                                                                 _("Incompatible types."));
\r 
 873                         if (ivType == ivBool)
\r 
 875                                 *(int16_t*)var->sqldata = int16_t(*(bool*)value ? 1 : 0);
\r 
 877                         else if (ivType == ivInt16)
\r 
 879                                 *(int16_t*)var->sqldata = *(int16_t*)value;
\r 
 881                         else if (ivType == ivInt32)
\r 
 883                                 if (*(int32_t*)value < consts::min16 || *(int32_t*)value > consts::max16)
\r 
 884                                         throw LogicExceptionImpl("RowImpl::SetValue",
\r 
 885                                                 _("Out of range numeric conversion !"));
\r 
 886                                 *(int16_t*)var->sqldata = (int16_t)*(int32_t*)value;
\r 
 888                         else if (ivType == ivInt64)
\r 
 890                                 if (*(int64_t*)value < consts::min16 || *(int64_t*)value > consts::max16)
\r 
 891                                         throw LogicExceptionImpl("RowImpl::SetValue",
\r 
 892                                                 _("Out of range numeric conversion !"));
\r 
 893                                 *(int16_t*)var->sqldata = (int16_t)*(int64_t*)value;
\r 
 895                         else if (ivType == ivFloat)
\r 
 897                                 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r 
 898                                 double multiplier = consts::dscales[-var->sqlscale];
\r 
 899                                 *(int16_t*)var->sqldata =
\r 
 900                                         (int16_t)floor(*(float*)value * multiplier + 0.5);
\r 
 902                         else if (ivType == ivDouble)
\r 
 904                                 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r 
 905                                 double multiplier = consts::dscales[-var->sqlscale];
\r 
 906                                 *(int16_t*)var->sqldata =
\r 
 907                                         (int16_t)floor(*(double*)value * multiplier + 0.5);
\r 
 909                         else throw WrongTypeImpl("RowImpl::SetValue",  var->sqltype, ivType,
\r 
 910                                                                                 _("Incompatible types."));
\r 
 914                         if (ivType == ivBool)
\r 
 916                                 *(ISC_LONG*)var->sqldata = *(bool*)value ? 1 : 0;
\r 
 918                         else if (ivType == ivInt16)
\r 
 920                                 *(ISC_LONG*)var->sqldata = *(int16_t*)value;
\r 
 922                         else if (ivType == ivInt32)
\r 
 924                                 *(ISC_LONG*)var->sqldata = *(ISC_LONG*)value;
\r 
 926                         else if (ivType == ivInt64)
\r 
 928                                 if (*(int64_t*)value < consts::min32 || *(int64_t*)value > consts::max32)
\r 
 929                                         throw LogicExceptionImpl("RowImpl::SetValue",
\r 
 930                                                 _("Out of range numeric conversion !"));
\r 
 931                                 *(ISC_LONG*)var->sqldata = (ISC_LONG)*(int64_t*)value;
\r 
 933                         else if (ivType == ivFloat)
\r 
 935                                 // This SQL_LONG is a NUMERIC(x,y), scale it !
\r 
 936                                 double multiplier = consts::dscales[-var->sqlscale];
\r 
 937                                 *(ISC_LONG*)var->sqldata =
\r 
 938                                         (ISC_LONG)floor(*(float*)value * multiplier + 0.5);
\r 
 940                         else if (ivType == ivDouble)
\r 
 942                                 // This SQL_LONG is a NUMERIC(x,y), scale it !
\r 
 943                                 double multiplier = consts::dscales[-var->sqlscale];
\r 
 944                                 *(ISC_LONG*)var->sqldata =
\r 
 945                                         (ISC_LONG)floor(*(double*)value * multiplier + 0.5);
\r 
 947                         else throw WrongTypeImpl("RowImpl::SetValue",  var->sqltype, ivType,
\r 
 948                                                                                 _("Incompatible types."));
\r 
 952                         if (ivType == ivBool)
\r 
 954                                 *(int64_t*)var->sqldata = *(bool*)value ? 1 : 0;
\r 
 956                         else if (ivType == ivInt16)
\r 
 958                                 *(int64_t*)var->sqldata = *(int16_t*)value;
\r 
 960                         else if (ivType == ivInt32)
\r 
 962                                 *(int64_t*)var->sqldata = *(int32_t*)value;
\r 
 964                         else if (ivType == ivInt64)
\r 
 966                                 *(int64_t*)var->sqldata = *(int64_t*)value;
\r 
 968                         else if (ivType == ivFloat)
\r 
 970                                 // This SQL_INT64 is a NUMERIC(x,y), scale it !
\r 
 971                                 double multiplier = consts::dscales[-var->sqlscale];
\r 
 972                                 *(int64_t*)var->sqldata =
\r 
 973                                         (int64_t)floor(*(float*)value * multiplier + 0.5);
\r 
 975                         else if (ivType == ivDouble)
\r 
 977                                 // This SQL_INT64 is a NUMERIC(x,y), scale it !
\r 
 978                                 double multiplier = consts::dscales[-var->sqlscale];
\r 
 979                                 *(int64_t*)var->sqldata =
\r 
 980                                         (int64_t)floor(*(double*)value * multiplier + 0.5);
\r 
 982                         else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
 983                                                                                 _("Incompatible types."));
\r 
 987                         if (ivType != ivFloat || var->sqlscale != 0)
\r 
 988                                 throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
 989                                                                         _("Incompatible types."));
\r 
 990                         *(float*)var->sqldata = *(float*)value;
\r 
 994                         if (ivType != ivDouble)
\r 
 995                                 throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
 996                                                                                 _("Incompatible types."));
\r 
 997                         if (var->sqlscale != 0)
\r 
 999                                 // Round to scale of NUMERIC(x,y)
\r 
1000                                 double multiplier = consts::dscales[-var->sqlscale];
\r 
1001                                 *(double*)var->sqldata =
\r 
1002                                         floor(*(double*)value * multiplier + 0.5) / multiplier;
\r 
1004                         else *(double*)var->sqldata = *(double*)value;
\r 
1007                 case SQL_TIMESTAMP :
\r 
1008                         if (ivType != ivTimestamp)
\r 
1009                                 throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
1010                                                                                 _("Incompatible types."));
\r 
1011                         encodeTimestamp(*(ISC_TIMESTAMP*)var->sqldata, *(IBPP::Timestamp*)value);
\r 
1014                 case SQL_TYPE_DATE :
\r 
1015                         if (ivType != ivDate)
\r 
1016                                 throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
1017                                                                                 _("Incompatible types."));
\r 
1018                         encodeDate(*(ISC_DATE*)var->sqldata, *(IBPP::Date*)value);
\r 
1021                 case SQL_TYPE_TIME :
\r 
1022                         if (ivType != ivTime)
\r 
1023                                 throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
1024                                                                                         _("Incompatible types."));
\r 
1025                         encodeTime(*(ISC_TIME*)var->sqldata, *(IBPP::Time*)value);
\r 
1029                         if (ivType == ivBlob)
\r 
1031                                 BlobImpl* blob = (BlobImpl*)value;
\r 
1032                                 blob->GetId((ISC_QUAD*)var->sqldata);
\r 
1034                         else if (ivType == ivString)
\r 
1036                                 BlobImpl blob(mDatabase, mTransaction);
\r 
1037                                 blob.Save(*(std::string*)value);
\r 
1038                                 blob.GetId((ISC_QUAD*)var->sqldata);
\r 
1040                         else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
1041                                                                                 _("Incompatible types."));
\r 
1045                         if (ivType != ivArray)
\r 
1046                                 throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
1047                                                                                 _("Incompatible types."));
\r 
1049                                 ArrayImpl* array = (ArrayImpl*)value;
\r 
1050                                 array->GetId((ISC_QUAD*)var->sqldata);
\r 
1051                                 // When an array has been affected to a column, we want to reset
\r 
1052                                 // its ID. This way, the next WriteFrom() on the same Array object
\r 
1053                                 // will allocate a new ID. This protects against storing the same
\r 
1054                                 // array ID in multiple columns or rows.
\r 
1059                 default : throw LogicExceptionImpl("RowImpl::SetValue",
\r 
1060                                                 _("The field uses an unsupported SQL type !"));
\r 
1063         if (var->sqltype & 1) *var->sqlind = 0;         // Remove the 0 flag
\r 
1066 void* RowImpl::GetValue(int varnum, IITYPE ivType, void* retvalue)
\r 
1068         if (varnum < 1 || varnum > mDescrArea->sqld)
\r 
1069                 throw LogicExceptionImpl("RowImpl::GetValue", _("Variable index out of range."));
\r 
1073         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);
\r 
1075         // When there is no value (SQL NULL)
\r 
1076         if ((var->sqltype & 1) && *(var->sqlind) != 0) return 0;
\r 
1078         switch (var->sqltype & ~1)
\r 
1081                         if (ivType == ivString)
\r 
1083                                 // In case of ivString, 'void* retvalue' points to a std::string where we
\r 
1084                                 // will directly store the data.
\r 
1085                                 std::string* str = (std::string*)retvalue;
\r 
1087                                 str->append(var->sqldata, var->sqllen);
\r 
1088                                 value = retvalue;       // value != 0 means 'not null'
\r 
1090                         else if (ivType == ivByte)
\r 
1092                                 // In case of ivByte, void* retvalue points to an int where we
\r 
1093                                 // will store the len of the available data
\r 
1094                                 if (retvalue != 0) *(int*)retvalue = var->sqllen;
\r 
1095                                 value = var->sqldata;
\r 
1097                         else if (ivType == ivDBKey)
\r 
1099                                 IBPP::DBKey* key = (IBPP::DBKey*)retvalue;
\r 
1100                                 key->SetKey(var->sqldata, var->sqllen);
\r 
1103                         else if (ivType == ivBool)
\r 
1105                                 mBools[varnum-1] = 0;
\r 
1106                                 if (var->sqllen >= 1)
\r 
1108                                         char c = var->sqldata[0];
\r 
1109                                         if (c == 't' || c == 'T' || c == 'y' || c == 'Y' ||     c == '1')
\r 
1110                                                 mBools[varnum-1] = 1;
\r 
1112                                 value = &mBools[varnum-1];
\r 
1114                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,
\r 
1115                                                                                 _("Incompatible types."));
\r 
1118                 case SQL_VARYING :
\r 
1119                         if (ivType == ivString)
\r 
1121                                 // In case of ivString, 'void* retvalue' points to a std::string where we
\r 
1122                                 // will directly store the data.
\r 
1123                                 std::string* str = (std::string*)retvalue;
\r 
1125                                 str->append(var->sqldata+2, (int32_t)*(int16_t*)var->sqldata);
\r 
1128                         else if (ivType == ivByte)
\r 
1130                                 // In case of ivByte, void* retvalue points to an int where we
\r 
1131                                 // will store the len of the available data
\r 
1132                                 if (retvalue != 0) *(int*)retvalue = (int)*(int16_t*)var->sqldata;
\r 
1133                                 value = var->sqldata+2;
\r 
1135                         else if (ivType == ivBool)
\r 
1137                                 mBools[varnum-1] = 0;
\r 
1138                                 len = *(int16_t*)var->sqldata;
\r 
1141                                         char c = var->sqldata[2];
\r 
1142                                         if (c == 't' || c == 'T' || c == 'y' || c == 'Y' ||     c == '1')
\r 
1143                                                 mBools[varnum-1] = 1;
\r 
1145                                 value = &mBools[varnum-1];
\r 
1147                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,
\r 
1148                                                                                 _("Incompatible types."));
\r 
1152                         if (ivType == ivInt16)
\r 
1154                                 value = var->sqldata;
\r 
1156                         else if (ivType == ivBool)
\r 
1158                                 if (*(int16_t*)var->sqldata == 0) mBools[varnum-1] = 0;
\r 
1159                                 else mBools[varnum-1] = 1;
\r 
1160                                 value = &mBools[varnum-1];
\r 
1162                         else if (ivType == ivInt32)
\r 
1164                                 mInt32s[varnum-1] = *(int16_t*)var->sqldata;
\r 
1165                                 value = &mInt32s[varnum-1];
\r 
1167                         else if (ivType == ivInt64)
\r 
1169                                 mInt64s[varnum-1] = *(int16_t*)var->sqldata;
\r 
1170                                 value = &mInt64s[varnum-1];
\r 
1172                         else if (ivType == ivFloat)
\r 
1174                                 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r 
1175                                 double divisor = consts::dscales[-var->sqlscale];
\r 
1176                                 mFloats[varnum-1] = (float)(*(int16_t*)var->sqldata / divisor);
\r 
1178                                 value = &mFloats[varnum-1];
\r 
1180                         else if (ivType == ivDouble)
\r 
1182                                 // This SQL_SHORT is a NUMERIC(x,y), scale it !
\r 
1183                                 double divisor = consts::dscales[-var->sqlscale];
\r 
1184                                 mNumerics[varnum-1] = *(int16_t*)var->sqldata / divisor;
\r 
1185                                 value = &mNumerics[varnum-1];
\r 
1187                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,
\r 
1188                                                                                 _("Incompatible types."));
\r 
1192                         if (ivType == ivInt32)
\r 
1194                                 value = var->sqldata;
\r 
1196                         else if (ivType == ivBool)
\r 
1198                                 if (*(int32_t*)var->sqldata == 0) mBools[varnum-1] = 0;
\r 
1199                                 else mBools[varnum-1] = 1;
\r 
1200                                 value = &mBools[varnum-1];
\r 
1202                         else if (ivType == ivInt16)
\r 
1204                                 int32_t tmp = *(int32_t*)var->sqldata;
\r 
1205                                 if (tmp < consts::min16 || tmp > consts::max16)
\r 
1206                                         throw LogicExceptionImpl("RowImpl::GetValue",
\r 
1207                                                 _("Out of range numeric conversion !"));
\r 
1208                                 mInt16s[varnum-1] = (int16_t)tmp;
\r 
1209                                 value = &mInt16s[varnum-1];
\r 
1211                         else if (ivType == ivInt64)
\r 
1213                                 mInt64s[varnum-1] = *(int32_t*)var->sqldata;
\r 
1214                                 value = &mInt64s[varnum-1];
\r 
1216                         else if (ivType == ivFloat)
\r 
1218                                 // This SQL_LONG is a NUMERIC(x,y), scale it !
\r 
1219                                 double divisor = consts::dscales[-var->sqlscale];
\r 
1220                                 mFloats[varnum-1] = (float)(*(int32_t*)var->sqldata / divisor);
\r 
1221                                 value = &mFloats[varnum-1];
\r 
1223                         else if (ivType == ivDouble)
\r 
1225                                 // This SQL_LONG is a NUMERIC(x,y), scale it !
\r 
1226                                 double divisor = consts::dscales[-var->sqlscale];
\r 
1227                                 mNumerics[varnum-1] = *(int32_t*)var->sqldata / divisor;
\r 
1228                                 value = &mNumerics[varnum-1];
\r 
1230                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,
\r 
1231                                                                                 _("Incompatible types."));
\r 
1235                         if (ivType == ivInt64)
\r 
1237                                 value = var->sqldata;
\r 
1239                         else if (ivType == ivBool)
\r 
1241                                 if (*(int64_t*)var->sqldata == 0) mBools[varnum-1] = 0;
\r 
1242                                 else mBools[varnum-1] = 1;
\r 
1243                                 value = &mBools[varnum-1];
\r 
1245                         else if (ivType == ivInt16)
\r 
1247                                 int64_t tmp = *(int64_t*)var->sqldata;
\r 
1248                                 if (tmp < consts::min16 || tmp > consts::max16)
\r 
1249                                         throw LogicExceptionImpl("RowImpl::GetValue",
\r 
1250                                                 _("Out of range numeric conversion !"));
\r 
1251                                 mInt16s[varnum-1] = (int16_t)tmp;
\r 
1252                                 value = &mInt16s[varnum-1];
\r 
1254                         else if (ivType == ivInt32)
\r 
1256                                 int64_t tmp = *(int64_t*)var->sqldata;
\r 
1257                                 if (tmp < consts::min32 || tmp > consts::max32)
\r 
1258                                         throw LogicExceptionImpl("RowImpl::GetValue",
\r 
1259                                                 _("Out of range numeric conversion !"));
\r 
1260                                 mInt32s[varnum-1] = (int32_t)tmp;
\r 
1261                                 value = &mInt32s[varnum-1];
\r 
1263                         else if (ivType == ivFloat)
\r 
1265                                 // This SQL_INT64 is a NUMERIC(x,y), scale it !
\r 
1266                                 double divisor = consts::dscales[-var->sqlscale];
\r 
1267                                 mFloats[varnum-1] = (float)(*(int64_t*)var->sqldata / divisor);
\r 
1268                                 value = &mFloats[varnum-1];
\r 
1270                         else if (ivType == ivDouble)
\r 
1272                                 // This SQL_INT64 is a NUMERIC(x,y), scale it !
\r 
1273                                 double divisor = consts::dscales[-var->sqlscale];
\r 
1274                                 mNumerics[varnum-1] = *(int64_t*)var->sqldata / divisor;
\r 
1275                                 value = &mNumerics[varnum-1];
\r 
1277                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,
\r 
1278                                                                                 _("Incompatible types."));
\r 
1282                         if (ivType != ivFloat)
\r 
1283                                 throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,
\r 
1284                                                                                 _("Incompatible types."));
\r 
1285                         value = var->sqldata;
\r 
1289                         if (ivType != ivDouble)
\r 
1290                                 throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,
\r 
1291                                                                                 _("Incompatible types."));
\r 
1292                         if (var->sqlscale != 0)
\r 
1294                                 // Round to scale y of NUMERIC(x,y)
\r 
1295                                 double multiplier = consts::dscales[-var->sqlscale];
\r 
1296                                 mNumerics[varnum-1] =
\r 
1297                                         floor(*(double*)var->sqldata * multiplier + 0.5) / multiplier;
\r 
1298                                 value = &mNumerics[varnum-1];
\r 
1300                         else value = var->sqldata;
\r 
1303                 case SQL_TIMESTAMP :
\r 
1304                         if (ivType != ivTimestamp)
\r 
1305                                 throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
1306                                                                                 _("Incompatible types."));
\r 
1307                         decodeTimestamp(*(IBPP::Timestamp*)retvalue, *(ISC_TIMESTAMP*)var->sqldata);
\r 
1311                 case SQL_TYPE_DATE :
\r 
1312                         if (ivType != ivDate)
\r 
1313                                 throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
1314                                                                                 _("Incompatible types."));
\r 
1315                         decodeDate(*(IBPP::Date*)retvalue, *(ISC_DATE*)var->sqldata);
\r 
1319                 case SQL_TYPE_TIME :
\r 
1320                         if (ivType != ivTime)
\r 
1321                                 throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,
\r 
1322                                                                                 _("Incompatible types."));
\r 
1323                         decodeTime(*(IBPP::Time*)retvalue, *(ISC_TIME*)var->sqldata);
\r 
1328                         if (ivType == ivBlob)
\r 
1330                                 BlobImpl* blob = (BlobImpl*)retvalue;
\r 
1331                                 blob->SetId((ISC_QUAD*)var->sqldata);
\r 
1334                         else if (ivType == ivString)
\r 
1336                                 BlobImpl blob(mDatabase, mTransaction);
\r 
1337                                 blob.SetId((ISC_QUAD*)var->sqldata);
\r 
1338                                 std::string* str = (std::string*)retvalue;
\r 
1342                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,
\r 
1343                                                                                 _("Incompatible types."));
\r 
1347                         if (ivType != ivArray)
\r 
1348                                 throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,
\r 
1349                                                                                         _("Incompatible types."));
\r 
1351                                 ArrayImpl* array = (ArrayImpl*)retvalue;
\r 
1352                                 array->SetId((ISC_QUAD*)var->sqldata);
\r 
1357                 default : throw LogicExceptionImpl("RowImpl::GetValue",
\r 
1358                                                 _("Found an unknown sqltype !"));
\r 
1364 void RowImpl::Free()
\r 
1366         if (mDescrArea != 0)
\r 
1368                 for (int i = 0; i < mDescrArea->sqln; i++)
\r 
1370                         XSQLVAR* var = &(mDescrArea->sqlvar[i]);
\r 
1371                         if (var->sqldata != 0)
\r 
1373                                 switch (var->sqltype & ~1)
\r 
1376                                         case SQL_BLOB :         delete (ISC_QUAD*) var->sqldata; break;
\r 
1377                                         case SQL_TIMESTAMP :delete (ISC_TIMESTAMP*) var->sqldata; break;
\r 
1378                                         case SQL_TYPE_TIME :delete (ISC_TIME*) var->sqldata; break;
\r 
1379                                         case SQL_TYPE_DATE :delete (ISC_DATE*) var->sqldata; break;
\r 
1381                                         case SQL_VARYING :      delete [] var->sqldata; break;
\r 
1382                                         case SQL_SHORT :        delete (int16_t*) var->sqldata; break;
\r 
1383                                         case SQL_LONG :         delete (int32_t*) var->sqldata; break;
\r 
1384                                         case SQL_INT64 :        delete (int64_t*) var->sqldata; break;
\r 
1385                                         case SQL_FLOAT :        delete (float*) var->sqldata; break;
\r 
1386                                         case SQL_DOUBLE :       delete (double*) var->sqldata; break;
\r 
1387                                         default : throw LogicExceptionImpl("RowImpl::Free",
\r 
1388                                                                 _("Found an unknown sqltype !"));
\r 
1391                         if (var->sqlind != 0) delete var->sqlind;
\r 
1393                 delete [] (char*)mDescrArea;
\r 
1397         mNumerics.clear();
\r 
1411 void RowImpl::Resize(int n)
\r 
1413         const int size = XSQLDA_LENGTH(n);
\r 
1416     mDescrArea = (XSQLDA*) new char[size];
\r 
1418         memset(mDescrArea, 0, size);
\r 
1419         mNumerics.resize(n);
\r 
1420         mFloats.resize(n);
\r 
1421         mInt64s.resize(n);
\r 
1422         mInt32s.resize(n);
\r 
1423         mInt16s.resize(n);
\r 
1425         mStrings.resize(n);
\r 
1426         mUpdated.resize(n);
\r 
1427         for (int i = 0; i < n; i++)
\r 
1429                 mNumerics[i] = 0.0;
\r 
1435                 mStrings[i].erase();
\r 
1436                 mUpdated[i] = false;
\r 
1439         mDescrArea->version = SQLDA_VERSION1;
\r 
1440         mDescrArea->sqln = (int16_t)n;
\r 
1443 void RowImpl::AllocVariables()
\r 
1446         for (i = 0; i < mDescrArea->sqld; i++)
\r 
1448                 XSQLVAR* var = &(mDescrArea->sqlvar[i]);
\r 
1449                 switch (var->sqltype & ~1)
\r 
1452                         case SQL_BLOB :         var->sqldata = (char*) new ISC_QUAD;
\r 
1453                                                                 memset(var->sqldata, 0, sizeof(ISC_QUAD));
\r 
1455                         case SQL_TIMESTAMP :var->sqldata = (char*) new ISC_TIMESTAMP;
\r 
1456                                                                 memset(var->sqldata, 0, sizeof(ISC_TIMESTAMP));
\r 
1458                         case SQL_TYPE_TIME :var->sqldata = (char*) new ISC_TIME;
\r 
1459                                                                 memset(var->sqldata, 0, sizeof(ISC_TIME));
\r 
1461                         case SQL_TYPE_DATE :var->sqldata = (char*) new ISC_DATE;
\r 
1462                                                                 memset(var->sqldata, 0, sizeof(ISC_DATE));
\r 
1464                         case SQL_TEXT :         var->sqldata = new char[var->sqllen+1];
\r 
1465                                                                 memset(var->sqldata, ' ', var->sqllen);
\r 
1466                                                                 var->sqldata[var->sqllen] = '\0';
\r 
1468                         case SQL_VARYING :      var->sqldata = new char[var->sqllen+3];
\r 
1469                                                                 memset(var->sqldata, 0, 2);
\r 
1470                                                                 memset(var->sqldata+2, ' ', var->sqllen);
\r 
1471                                                                 var->sqldata[var->sqllen+2] = '\0';
\r 
1473                         case SQL_SHORT :        var->sqldata = (char*) new int16_t(0); break;
\r 
1474                         case SQL_LONG :         var->sqldata = (char*) new int32_t(0); break;
\r 
1475                         case SQL_INT64 :        var->sqldata = (char*) new int64_t(0); break;
\r 
1476                         case SQL_FLOAT :        var->sqldata = (char*) new float(0.0); break;
\r 
1477                         case SQL_DOUBLE :       var->sqldata = (char*) new double(0.0); break;
\r 
1478                         default : throw LogicExceptionImpl("RowImpl::AllocVariables",
\r 
1479                                                 _("Found an unknown sqltype !"));
\r 
1481                 if (var->sqltype & 1) var->sqlind = new short(-1);      // 0 indicator
\r 
1485 bool RowImpl::MissingValues()
\r 
1487         for (int i = 0; i < mDescrArea->sqld; i++)
\r 
1488                 if (! mUpdated[i]) return true;
\r 
1492 RowImpl& RowImpl::operator=(const RowImpl& copied)
\r 
1496         const int n = copied.mDescrArea->sqln;
\r 
1497         const int size = XSQLDA_LENGTH(n);
\r 
1499         // Initial brute copy
\r 
1500     mDescrArea = (XSQLDA*) new char[size];
\r 
1501         memcpy(mDescrArea, copied.mDescrArea, size);
\r 
1503         // Copy of the columns data
\r 
1504         for (int i = 0; i < mDescrArea->sqld; i++)
\r 
1506                 XSQLVAR* var = &(mDescrArea->sqlvar[i]);
\r 
1507                 XSQLVAR* org = &(copied.mDescrArea->sqlvar[i]);
\r 
1508                 switch (var->sqltype & ~1)
\r 
1511                         case SQL_BLOB :         var->sqldata = (char*) new ISC_QUAD;
\r 
1512                                                                 memcpy(var->sqldata, org->sqldata, sizeof(ISC_QUAD));
\r 
1514                         case SQL_TIMESTAMP :var->sqldata = (char*) new ISC_TIMESTAMP;
\r 
1515                                                                 memcpy(var->sqldata, org->sqldata, sizeof(ISC_TIMESTAMP));
\r 
1517                         case SQL_TYPE_TIME :var->sqldata = (char*) new ISC_TIME;
\r 
1518                                                                 memcpy(var->sqldata, org->sqldata, sizeof(ISC_TIME));
\r 
1520                         case SQL_TYPE_DATE :var->sqldata = (char*) new ISC_DATE;
\r 
1521                                                                 memcpy(var->sqldata, org->sqldata, sizeof(ISC_DATE));
\r 
1523                         case SQL_TEXT :         var->sqldata = new char[var->sqllen+1];
\r 
1524                                                                 memcpy(var->sqldata, org->sqldata, var->sqllen+1);
\r 
1526                         case SQL_VARYING :      var->sqldata = new char[var->sqllen+3];
\r 
1527                                                                 memcpy(var->sqldata, org->sqldata, var->sqllen+3);
\r 
1529                         case SQL_SHORT :        var->sqldata = (char*) new int16_t(*(int16_t*)org->sqldata); break;
\r 
1530                         case SQL_LONG :         var->sqldata = (char*) new int32_t(*(int32_t*)org->sqldata); break;
\r 
1531                         case SQL_INT64 :        var->sqldata = (char*) new int64_t(*(int64_t*)org->sqldata); break;
\r 
1532                         case SQL_FLOAT :        var->sqldata = (char*) new float(*(float*)org->sqldata); break;
\r 
1533                         case SQL_DOUBLE :       var->sqldata = (char*) new double(*(double*)org->sqldata); break;
\r 
1534                         default : throw LogicExceptionImpl("RowImpl::Ctor",
\r 
1535                                                 _("Found an unknown sqltype !"));
\r 
1537                 if (var->sqltype & 1) var->sqlind = new short(*org->sqlind);    // 0 indicator
\r 
1540         // Pointers init, real data copy
\r 
1541         mNumerics = copied.mNumerics;
\r 
1542         mFloats = copied.mFloats;
\r 
1543         mInt64s = copied.mInt64s;
\r 
1544         mInt32s = copied.mInt32s;
\r 
1545         mInt16s = copied.mInt16s;
\r 
1546         mBools = copied.mBools;
\r 
1547         mStrings = copied.mStrings;
\r 
1549         mDialect = copied.mDialect;
\r 
1550         mDatabase = copied.mDatabase;
\r 
1551         mTransaction = copied.mTransaction;
\r 
1556 RowImpl::RowImpl(const RowImpl& copied)
\r 
1557         : IBPP::IRow(), mRefCount(0), mDescrArea(0)
\r 
1559         // mRefCount and mDescrArea are set to 0 before using the assignment operator
\r 
1560         *this = copied;         // The assignment operator does the real copy
\r 
1563 RowImpl::RowImpl(int dialect, int n, DatabaseImpl* db, TransactionImpl* tr)
\r 
1564         : mRefCount(0), mDescrArea(0)
\r 
1567         mDialect = dialect;
\r 
1569         mTransaction = tr;
\r 
1572 RowImpl::~RowImpl()
\r