]> git.stg.codes - stg.git/blob - stglibs/ibpp.lib/row.cpp
Merge branch 'stg-2.409-radius'
[stg.git] / stglibs / ibpp.lib / row.cpp
1 ///////////////////////////////////////////////////////////////////////////////\r
2 //\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
5 //\r
6 ///////////////////////////////////////////////////////////////////////////////\r
7 //\r
8 //      (C) Copyright 2000-2006 T.I.P. Group S.A. and the IBPP Team (www.ibpp.org)\r
9 //\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
14 //\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
19 //\r
20 ///////////////////////////////////////////////////////////////////////////////\r
21 //\r
22 //      COMMENTS\r
23 //      * Tabulations should be set every four characters when editing this file.\r
24 //\r
25 ///////////////////////////////////////////////////////////////////////////////\r
26 \r
27 #ifdef _MSC_VER\r
28 #pragma warning(disable: 4786 4996)\r
29 #ifndef _DEBUG\r
30 #pragma warning(disable: 4702)\r
31 #endif\r
32 #endif\r
33 \r
34 #include "_ibpp.h"\r
35 \r
36 #ifdef HAS_HDRSTOP\r
37 #pragma hdrstop\r
38 #endif\r
39 \r
40 #include <math.h>\r
41 #include <time.h>\r
42 #include <cstring>\r
43 \r
44 using namespace ibpp_internals;\r
45 \r
46 //      (((((((( OBJECT INTERFACE IMPLEMENTATION ))))))))\r
47 \r
48 void RowImpl::SetNull(int param)\r
49 {\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
54 \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
58 \r
59         *var->sqlind = -1;      // Set the column to SQL NULL\r
60         mUpdated[param-1] = true;\r
61 }\r
62 \r
63 void RowImpl::Set(int param, bool value)\r
64 {\r
65         if (mDescrArea == 0)\r
66                 throw LogicExceptionImpl("Row::Set[bool]", _("The row is not initialized."));\r
67 \r
68         SetValue(param, ivBool, &value);\r
69         mUpdated[param-1] = true;\r
70 }\r
71 \r
72 void RowImpl::Set(int param, const char* cstring)\r
73 {\r
74         if (mDescrArea == 0)\r
75                 throw LogicExceptionImpl("Row::Set[char*]", _("The row is not initialized."));\r
76         if (cstring == 0)\r
77                 throw LogicExceptionImpl("Row::Set[char*]", _("null char* pointer detected."));\r
78 \r
79         SetValue(param, ivByte, cstring, (int)strlen(cstring));\r
80         mUpdated[param-1] = true;\r
81 }\r
82 \r
83 void RowImpl::Set(int param, const void* bindata, int len)\r
84 {\r
85         if (mDescrArea == 0)\r
86                 throw LogicExceptionImpl("Row::Set[void*]", _("The row is not initialized."));\r
87         if (bindata == 0)\r
88                 throw LogicExceptionImpl("Row::Set[void*]", _("null char* pointer detected."));\r
89         if (len < 0)\r
90                 throw LogicExceptionImpl("Row::Set[void*]", _("Length must be >= 0"));\r
91                 \r
92         SetValue(param, ivByte, bindata, len);\r
93         mUpdated[param-1] = true;\r
94 }\r
95 \r
96 void RowImpl::Set(int param, const std::string& s)\r
97 {\r
98         if (mDescrArea == 0)\r
99                 throw LogicExceptionImpl("Row::Set[string]", _("The row is not initialized."));\r
100 \r
101         SetValue(param, ivString, (void*)&s);\r
102         mUpdated[param-1] = true;\r
103 }\r
104 \r
105 void RowImpl::Set(int param, int16_t value)\r
106 {\r
107         if (mDescrArea == 0)\r
108                 throw LogicExceptionImpl("Row::Set[int16_t]", _("The row is not initialized."));\r
109                                                                                         \r
110         SetValue(param, ivInt16, &value);\r
111         mUpdated[param-1] = true;\r
112 }\r
113 \r
114 void RowImpl::Set(int param, int32_t value)\r
115 {\r
116         if (mDescrArea == 0)\r
117                 throw LogicExceptionImpl("Row::Set[int32_t]", _("The row is not initialized."));\r
118 \r
119         SetValue(param, ivInt32, &value);\r
120         mUpdated[param-1] = true;\r
121 }\r
122 \r
123 void RowImpl::Set(int param, int64_t value)\r
124 {\r
125         if (mDescrArea == 0)\r
126                 throw LogicExceptionImpl("Row::Set[int64_t]", _("The row is not initialized."));\r
127 \r
128         SetValue(param, ivInt64, &value);\r
129         mUpdated[param-1] = true;\r
130 }\r
131 \r
132 void RowImpl::Set(int param, float value)\r
133 {\r
134         if (mDescrArea == 0)\r
135                 throw LogicExceptionImpl("Row::Set[float]", _("The row is not initialized."));\r
136 \r
137         SetValue(param, ivFloat, &value);\r
138         mUpdated[param-1] = true;\r
139 }\r
140 \r
141 void RowImpl::Set(int param, double value)\r
142 {\r
143         if (mDescrArea == 0)\r
144                 throw LogicExceptionImpl("Row::Set[double]", _("The row is not initialized."));\r
145 \r
146         SetValue(param, ivDouble, &value);\r
147         mUpdated[param-1] = true;\r
148 }\r
149 \r
150 void RowImpl::Set(int param, const IBPP::Timestamp& value)\r
151 {\r
152         if (mDescrArea == 0)\r
153                 throw LogicExceptionImpl("Row::Set[Timestamp]", _("The row is not initialized."));\r
154 \r
155         SetValue(param, ivTimestamp, &value);\r
156         mUpdated[param-1] = true;\r
157 }\r
158 \r
159 void RowImpl::Set(int param, const IBPP::Date& value)\r
160 {\r
161         if (mDescrArea == 0)\r
162                 throw LogicExceptionImpl("Row::Set[Date]", _("The row is not initialized."));\r
163 \r
164         if (mDialect == 1)\r
165         {\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, &timestamp);\r
170         }\r
171         else\r
172         {\r
173                 // Dialect 3\r
174                 SetValue(param, ivDate, (void*)&value);\r
175         }\r
176 \r
177         mUpdated[param-1] = true;\r
178 }\r
179 \r
180 void RowImpl::Set(int param, const IBPP::Time& value)\r
181 {\r
182         if (mDescrArea == 0)\r
183                 throw LogicExceptionImpl("Row::Set[Time]", _("The row is not initialized."));\r
184         if (mDialect == 1)\r
185                 throw LogicExceptionImpl("Row::Set[Time]", _("Requires use of a dialect 3 database."));\r
186 \r
187         SetValue(param, ivTime, &value);\r
188         mUpdated[param-1] = true;\r
189 }\r
190 \r
191 void RowImpl::Set(int param, const IBPP::Blob& blob)\r
192 {\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
201 \r
202         SetValue(param, ivBlob, blob.intf());\r
203         mUpdated[param-1] = true;\r
204 }\r
205 \r
206 void RowImpl::Set(int param, const IBPP::Array& array)\r
207 {\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
216 \r
217         SetValue(param, ivArray, (void*)array.intf());\r
218         mUpdated[param-1] = true;\r
219 }\r
220 \r
221 void RowImpl::Set(int param, const IBPP::DBKey& key)\r
222 {\r
223         if (mDescrArea == 0)\r
224                 throw LogicExceptionImpl("Row::Set[DBKey]", _("The row is not initialized."));\r
225 \r
226         SetValue(param, ivDBKey, (void*)&key);\r
227         mUpdated[param-1] = true;\r
228 }\r
229 \r
230 /*\r
231 void RowImpl::Set(int param, const IBPP::Value& value)\r
232 {\r
233         if (mDescrArea == 0)\r
234                 throw LogicExceptionImpl("Row::Set[Value]", _("The row is not initialized."));\r
235 \r
236         //SetValue(param, ivDBKey, (void*)&key);\r
237         //mUpdated[param-1] = true;\r
238 }\r
239 */\r
240 \r
241 bool RowImpl::IsNull(int column)\r
242 {\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
247 \r
248         XSQLVAR* var = &(mDescrArea->sqlvar[column-1]);\r
249         return ((var->sqltype & 1) && *(var->sqlind) != 0) ? true : false;\r
250 }\r
251 \r
252 bool RowImpl::Get(int column, bool& retvalue)\r
253 {\r
254         if (mDescrArea == 0)\r
255                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
256 \r
257         void* pvalue = GetValue(column, ivBool);\r
258         if (pvalue != 0)\r
259                 retvalue = (*(char*)pvalue == 0 ? false : true);\r
260         return pvalue == 0 ? true : false;\r
261 }\r
262 \r
263 bool RowImpl::Get(int column, char* retvalue)\r
264 {\r
265         if (mDescrArea == 0)\r
266                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
267         if (retvalue == 0)\r
268                 throw LogicExceptionImpl("Row::Get", _("Null pointer detected"));\r
269 \r
270         int sqllen;\r
271         void* pvalue = GetValue(column, ivByte, &sqllen);\r
272         if (pvalue != 0)\r
273         {\r
274                 memcpy(retvalue, pvalue, sqllen);\r
275                 retvalue[sqllen] = '\0';\r
276         }\r
277         return pvalue == 0 ? true : false;\r
278 }\r
279 \r
280 bool RowImpl::Get(int column, void* bindata, int& userlen)\r
281 {\r
282         if (mDescrArea == 0)\r
283                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
284         if (bindata == 0)\r
285                 throw LogicExceptionImpl("Row::Get", _("Null pointer detected"));\r
286         if (userlen < 0)\r
287                 throw LogicExceptionImpl("Row::Get", _("Length must be >= 0"));\r
288 \r
289         int sqllen;\r
290         void* pvalue = GetValue(column, ivByte, &sqllen);\r
291         if (pvalue != 0)\r
292         {\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
297         }\r
298         return pvalue == 0 ? true : false;\r
299 }\r
300 \r
301 bool RowImpl::Get(int column, std::string& retvalue)\r
302 {\r
303         if (mDescrArea == 0)\r
304                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
305 \r
306         void* pvalue = GetValue(column, ivString, &retvalue);\r
307         return pvalue == 0 ? true : false;\r
308 }\r
309 \r
310 bool RowImpl::Get(int column, int16_t& retvalue)\r
311 {\r
312         if (mDescrArea == 0)\r
313                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
314 \r
315         void* pvalue = GetValue(column, ivInt16);\r
316         if (pvalue != 0)\r
317                 retvalue = *(int16_t*)pvalue;\r
318         return pvalue == 0 ? true : false;\r
319 }\r
320 \r
321 bool RowImpl::Get(int column, int32_t& retvalue)\r
322 {\r
323         if (mDescrArea == 0)\r
324                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
325 \r
326         void* pvalue = GetValue(column, ivInt32);\r
327         if (pvalue != 0)\r
328                 retvalue = *(int32_t*)pvalue;\r
329         return pvalue == 0 ? true : false;\r
330 }\r
331 \r
332 bool RowImpl::Get(int column, int64_t& retvalue)\r
333 {\r
334         if (mDescrArea == 0)\r
335                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
336 \r
337         void* pvalue = GetValue(column, ivInt64);\r
338         if (pvalue != 0)\r
339                 retvalue = *(int64_t*)pvalue;\r
340         return pvalue == 0 ? true : false;\r
341 }\r
342 \r
343 bool RowImpl::Get(int column, float& retvalue)\r
344 {\r
345         if (mDescrArea == 0)\r
346                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
347 \r
348         void* pvalue = GetValue(column, ivFloat);\r
349         if (pvalue != 0)\r
350                 retvalue = *(float*)pvalue;\r
351         return pvalue == 0 ? true : false;\r
352 }\r
353 \r
354 bool RowImpl::Get(int column, double& retvalue)\r
355 {\r
356         if (mDescrArea == 0)\r
357                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
358 \r
359         void* pvalue = GetValue(column, ivDouble);\r
360         if (pvalue != 0)\r
361                 retvalue = *(double*)pvalue;\r
362         return pvalue == 0 ? true : false;\r
363 }\r
364 \r
365 bool RowImpl::Get(int column, IBPP::Timestamp& timestamp)\r
366 {\r
367         if (mDescrArea == 0)\r
368                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
369 \r
370         void* pvalue = GetValue(column, ivTimestamp, (void*)&timestamp);\r
371         return pvalue == 0 ? true : false;\r
372 }\r
373 \r
374 bool RowImpl::Get(int column, IBPP::Date& date)\r
375 {\r
376         if (mDescrArea == 0)\r
377                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
378 \r
379         if (mDialect == 1)\r
380         {\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*)&timestamp);\r
385                 if (pvalue != 0) date = timestamp;\r
386                 return pvalue == 0 ? true : false;\r
387         }\r
388         else\r
389         {\r
390                 void* pvalue = GetValue(column, ivDate, (void*)&date);\r
391                 return pvalue == 0 ? true : false;\r
392         }\r
393 }\r
394 \r
395 bool RowImpl::Get(int column, IBPP::Time& time)\r
396 {\r
397         if (mDescrArea == 0)\r
398                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
399 \r
400         void* pvalue = GetValue(column, ivTime, (void*)&time);\r
401         return pvalue == 0 ? true : false;\r
402 }\r
403 \r
404 bool RowImpl::Get(int column, IBPP::Blob& retblob)\r
405 {\r
406         if (mDescrArea == 0)\r
407                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
408 \r
409         void* pvalue = GetValue(column, ivBlob, (void*)retblob.intf());\r
410         return pvalue == 0 ? true : false;\r
411 }\r
412 \r
413 bool RowImpl::Get(int column, IBPP::DBKey& retkey)\r
414 {\r
415         if (mDescrArea == 0)\r
416                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
417 \r
418         void* pvalue = GetValue(column, ivDBKey, (void*)&retkey);\r
419         return pvalue == 0 ? true : false;\r
420 }\r
421 \r
422 bool RowImpl::Get(int column, IBPP::Array& retarray)\r
423 {\r
424         if (mDescrArea == 0)\r
425                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
426 \r
427         void* pvalue = GetValue(column, ivArray, (void*)retarray.intf());\r
428         return pvalue == 0 ? true : false;\r
429 }\r
430 \r
431 /*\r
432 const IBPP::Value RowImpl::Get(int column)\r
433 {\r
434         if (mDescrArea == 0)\r
435                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
436 \r
437         //void* value = GetValue(column, ivArray, (void*)retarray.intf());\r
438         //return value == 0 ? true : false;\r
439         return IBPP::Value();\r
440 }\r
441 */\r
442 \r
443 bool RowImpl::IsNull(const std::string& name)\r
444 {\r
445         if (mDescrArea == 0)\r
446                 throw LogicExceptionImpl("Row::IsNull", _("The row is not initialized."));\r
447 \r
448         return IsNull(ColumnNum(name));\r
449 }\r
450 \r
451 bool RowImpl::Get(const std::string& name, bool& retvalue)\r
452 {\r
453         if (mDescrArea == 0)\r
454                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
455 \r
456         return Get(ColumnNum(name), retvalue);\r
457 }\r
458 \r
459 bool RowImpl::Get(const std::string& name, char* retvalue)\r
460 {\r
461         if (mDescrArea == 0)\r
462                 throw LogicExceptionImpl("Row::Get[char*]", _("The row is not initialized."));\r
463 \r
464         return Get(ColumnNum(name), retvalue);\r
465 }\r
466 \r
467 bool RowImpl::Get(const std::string& name, void* retvalue, int& count)\r
468 {\r
469         if (mDescrArea == 0)\r
470                 throw LogicExceptionImpl("Row::Get[void*,int]", _("The row is not initialized."));\r
471 \r
472         return Get(ColumnNum(name), retvalue, count);\r
473 }\r
474 \r
475 bool RowImpl::Get(const std::string& name, std::string& retvalue)\r
476 {\r
477         if (mDescrArea == 0)\r
478                 throw LogicExceptionImpl("Row::GetString", _("The row is not initialized."));\r
479 \r
480         return Get(ColumnNum(name), retvalue);\r
481 }\r
482 \r
483 bool RowImpl::Get(const std::string& name, int16_t& retvalue)\r
484 {\r
485         if (mDescrArea == 0)\r
486                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
487 \r
488         return Get(ColumnNum(name), retvalue);\r
489 }\r
490 \r
491 bool RowImpl::Get(const std::string& name, int32_t& retvalue)\r
492 {\r
493         if (mDescrArea == 0)\r
494                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
495 \r
496         return Get(ColumnNum(name), retvalue);\r
497 }\r
498 \r
499 bool RowImpl::Get(const std::string& name, int64_t& retvalue)\r
500 {\r
501         if (mDescrArea == 0)\r
502                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
503 \r
504         return Get(ColumnNum(name), retvalue);\r
505 }\r
506 \r
507 bool RowImpl::Get(const std::string& name, float& retvalue)\r
508 {\r
509         if (mDescrArea == 0)\r
510                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
511 \r
512         return Get(ColumnNum(name), retvalue);\r
513 }\r
514 \r
515 bool RowImpl::Get(const std::string& name, double& retvalue)\r
516 {\r
517         if (mDescrArea == 0)\r
518                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
519 \r
520         return Get(ColumnNum(name), retvalue);\r
521 }\r
522 \r
523 bool RowImpl::Get(const std::string& name, IBPP::Timestamp& retvalue)\r
524 {\r
525         if (mDescrArea == 0)\r
526                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
527 \r
528         return Get(ColumnNum(name), retvalue);\r
529 }\r
530 \r
531 bool RowImpl::Get(const std::string& name, IBPP::Date& retvalue)\r
532 {\r
533         if (mDescrArea == 0)\r
534                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
535 \r
536         return Get(ColumnNum(name), retvalue);\r
537 }\r
538 \r
539 bool RowImpl::Get(const std::string& name, IBPP::Time& retvalue)\r
540 {\r
541         if (mDescrArea == 0)\r
542                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
543 \r
544         return Get(ColumnNum(name), retvalue);\r
545 }\r
546 \r
547 bool RowImpl::Get(const std::string&name, IBPP::Blob& retblob)\r
548 {\r
549         if (mDescrArea == 0)\r
550                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
551 \r
552         return Get(ColumnNum(name), retblob);\r
553 }\r
554 \r
555 bool RowImpl::Get(const std::string& name, IBPP::DBKey& retvalue)\r
556 {\r
557         if (mDescrArea == 0)\r
558                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
559 \r
560         return Get(ColumnNum(name), retvalue);\r
561 }\r
562 \r
563 bool RowImpl::Get(const std::string& name, IBPP::Array& retarray)\r
564 {\r
565         if (mDescrArea == 0)\r
566                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
567 \r
568         return Get(ColumnNum(name), retarray);\r
569 }\r
570 \r
571 /*\r
572 const IBPP::Value RowImpl::Get(const std::string& name)\r
573 {\r
574         if (mDescrArea == 0)\r
575                 throw LogicExceptionImpl("Row::Get", _("The row is not initialized."));\r
576 \r
577         return Get(ColumnNum(name));\r
578 }\r
579 */\r
580 \r
581 int RowImpl::Columns()\r
582 {\r
583         if (mDescrArea == 0)\r
584                 throw LogicExceptionImpl("Row::Columns", _("The row is not initialized."));\r
585 \r
586         return mDescrArea->sqld;\r
587 }\r
588 \r
589 int RowImpl::ColumnNum(const std::string& name)\r
590 {\r
591         if (mDescrArea == 0)\r
592                 throw LogicExceptionImpl("Row::ColumnNum", _("The row is not initialized."));\r
593         if (name.empty())\r
594                 throw LogicExceptionImpl("Row::ColumnNum", _("Column name <empty> not found."));\r
595 \r
596         XSQLVAR* var;\r
597         char Uname[sizeof(var->sqlname)+1];             // Max size of sqlname + '\0'\r
598 \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
603         Uname[len] = '\0';\r
604         char* p = Uname;\r
605         while (*p != '\0') { *p = char(toupper(*p)); ++p; }\r
606 \r
607         // Loop through the columns of the descriptor\r
608         for (int i = 0; i < mDescrArea->sqld; i++)\r
609         {\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
613         }\r
614 \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
617 \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
623         p = Ualias;\r
624         while (*p != '\0') { *p = char(toupper(*p)); ++p; }\r
625 \r
626         // Loop through the columns of the descriptor\r
627         for (int i = 0; i < mDescrArea->sqld; i++)\r
628         {\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
632         }\r
633 \r
634         throw LogicExceptionImpl("Row::ColumnNum", _("Could not find matching column."));\r
635 #ifdef __DMC__\r
636         return 0;       // DMC errronously warns here about a missing return\r
637 #endif\r
638 }\r
639 \r
640 /*\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
646 */\r
647 \r
648 const char* RowImpl::ColumnName(int varnum)\r
649 {\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
654 \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
659 }\r
660 \r
661 const char* RowImpl::ColumnAlias(int varnum)\r
662 {\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
667 \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
672 }\r
673 \r
674 const char* RowImpl::ColumnTable(int varnum)\r
675 {\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
680 \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
685 }\r
686 \r
687 IBPP::SDT RowImpl::ColumnType(int varnum)\r
688 {\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
693 \r
694         IBPP::SDT value;\r
695         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
696 \r
697         switch (var->sqltype & ~1)\r
698         {\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
713         }\r
714 \r
715         return value;\r
716 }\r
717 \r
718 int RowImpl::ColumnSubtype(int varnum)\r
719 {\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
724 \r
725         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
726         return (int)var->sqlsubtype;\r
727 }\r
728 \r
729 int RowImpl::ColumnSize(int varnum)\r
730 {\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
735 \r
736         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
737     return var->sqllen;\r
738 }\r
739 \r
740 int RowImpl::ColumnScale(int varnum)\r
741 {\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
746 \r
747         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
748     return -var->sqlscale;\r
749 }\r
750 \r
751 bool RowImpl::ColumnUpdated(int varnum)\r
752 {\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
757 \r
758         return mUpdated[varnum-1];\r
759 }\r
760 \r
761 bool RowImpl::Updated()\r
762 {\r
763         if (mDescrArea == 0)\r
764                 throw LogicExceptionImpl("Row::ColumnUpdated", _("The row is not initialized."));\r
765 \r
766         for (int i = 0; i < mDescrArea->sqld; i++)\r
767                 if (mUpdated[i]) return true;\r
768         return false;\r
769 }\r
770 \r
771 IBPP::Database RowImpl::DatabasePtr() const\r
772 {\r
773         return mDatabase;\r
774 }\r
775 \r
776 IBPP::Transaction RowImpl::TransactionPtr() const\r
777 {\r
778         return mTransaction;\r
779 }\r
780 \r
781 IBPP::IRow* RowImpl::Clone()\r
782 {\r
783         // By definition the clone of an IBPP Row is a new row (so refcount=0).\r
784 \r
785         RowImpl* clone = new RowImpl(*this);\r
786         return clone;\r
787 }\r
788 \r
789 IBPP::IRow* RowImpl::AddRef()\r
790 {\r
791         ASSERTION(mRefCount >= 0);\r
792         ++mRefCount;\r
793         return this;\r
794 }\r
795 \r
796 void RowImpl::Release()\r
797 {\r
798         // Release cannot throw, except in DEBUG builds on assertion\r
799         ASSERTION(mRefCount >= 0);\r
800         --mRefCount;\r
801         try { if (mRefCount <= 0) delete this; }\r
802                 catch (...) { }\r
803 }\r
804 \r
805 //      (((((((( OBJECT INTERNAL METHODS ))))))))\r
806 \r
807 void RowImpl::SetValue(int varnum, IITYPE ivType, const void* value, int userlen)\r
808 {\r
809         if (varnum < 1 || varnum > mDescrArea->sqld)\r
810                 throw LogicExceptionImpl("RowImpl::SetValue", _("Variable index out of range."));\r
811         if (value == 0)\r
812                 throw LogicExceptionImpl("RowImpl::SetValue", _("Unexpected null pointer detected."));\r
813 \r
814         int16_t len;\r
815         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
816         switch (var->sqltype & ~1)\r
817         {\r
818                 case SQL_TEXT :\r
819                         if (ivType == ivString)\r
820                         {\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
826                         }\r
827                         else if (ivType == ivByte)\r
828                         {\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
832                         }\r
833                         else if (ivType == ivDBKey)\r
834                         {\r
835                                 IBPP::DBKey* key = (IBPP::DBKey*)value;\r
836                                 key->GetKey(var->sqldata, var->sqllen);\r
837                         }\r
838                         else if (ivType == ivBool)\r
839                         {\r
840                                 var->sqldata[0] = *(bool*)value ? 'T' : 'F';\r
841                                 len = 1;\r
842                                 while (len < var->sqllen) var->sqldata[len++] = ' ';\r
843                         }\r
844                         else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
845                                                                                 _("Incompatible types."));\r
846                         break;\r
847 \r
848                 case SQL_VARYING :\r
849                         if (ivType == ivString)\r
850                         {\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
856                         }\r
857                         else if (ivType == ivByte)\r
858                         {\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
862                         }\r
863                         else if (ivType == ivBool)\r
864                         {\r
865                                 *(int16_t*)var->sqldata = (int16_t)1;\r
866                                 var->sqldata[2] = *(bool*)value ? 'T' : 'F';\r
867                         }\r
868                         else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
869                                                                                 _("Incompatible types."));\r
870                         break;\r
871 \r
872                 case SQL_SHORT :\r
873                         if (ivType == ivBool)\r
874                         {\r
875                                 *(int16_t*)var->sqldata = int16_t(*(bool*)value ? 1 : 0);\r
876                         }\r
877                         else if (ivType == ivInt16)\r
878                         {\r
879                                 *(int16_t*)var->sqldata = *(int16_t*)value;\r
880                         }\r
881                         else if (ivType == ivInt32)\r
882                         {\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
887                         }\r
888                         else if (ivType == ivInt64)\r
889                         {\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
894                         }\r
895                         else if (ivType == ivFloat)\r
896                         {\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
901                         }\r
902                         else if (ivType == ivDouble)\r
903                         {\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
908                         }\r
909                         else throw WrongTypeImpl("RowImpl::SetValue",  var->sqltype, ivType,\r
910                                                                                 _("Incompatible types."));\r
911                         break;\r
912 \r
913                 case SQL_LONG :\r
914                         if (ivType == ivBool)\r
915                         {\r
916                                 *(ISC_LONG*)var->sqldata = *(bool*)value ? 1 : 0;\r
917                         }\r
918                         else if (ivType == ivInt16)\r
919                         {\r
920                                 *(ISC_LONG*)var->sqldata = *(int16_t*)value;\r
921                         }\r
922                         else if (ivType == ivInt32)\r
923                         {\r
924                                 *(ISC_LONG*)var->sqldata = *(ISC_LONG*)value;\r
925                         }\r
926                         else if (ivType == ivInt64)\r
927                         {\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
932                         }\r
933                         else if (ivType == ivFloat)\r
934                         {\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
939                         }\r
940                         else if (ivType == ivDouble)\r
941                         {\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
946                         }\r
947                         else throw WrongTypeImpl("RowImpl::SetValue",  var->sqltype, ivType,\r
948                                                                                 _("Incompatible types."));\r
949                         break;\r
950 \r
951                 case SQL_INT64 :\r
952                         if (ivType == ivBool)\r
953                         {\r
954                                 *(int64_t*)var->sqldata = *(bool*)value ? 1 : 0;\r
955                         }\r
956                         else if (ivType == ivInt16)\r
957                         {\r
958                                 *(int64_t*)var->sqldata = *(int16_t*)value;\r
959                         }\r
960                         else if (ivType == ivInt32)\r
961                         {\r
962                                 *(int64_t*)var->sqldata = *(int32_t*)value;\r
963                         }\r
964                         else if (ivType == ivInt64)\r
965                         {\r
966                                 *(int64_t*)var->sqldata = *(int64_t*)value;\r
967                         }\r
968                         else if (ivType == ivFloat)\r
969                         {\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
974                         }\r
975                         else if (ivType == ivDouble)\r
976                         {\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
981                         }\r
982                         else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
983                                                                                 _("Incompatible types."));\r
984                         break;\r
985 \r
986                 case SQL_FLOAT :\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
991                         break;\r
992 \r
993                 case SQL_DOUBLE :\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
998                         {\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
1003                         }\r
1004                         else *(double*)var->sqldata = *(double*)value;\r
1005                         break;\r
1006 \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
1012                         break;\r
1013 \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
1019                         break;\r
1020 \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
1026                         break;\r
1027 \r
1028                 case SQL_BLOB :\r
1029                         if (ivType == ivBlob)\r
1030                         {\r
1031                                 BlobImpl* blob = (BlobImpl*)value;\r
1032                                 blob->GetId((ISC_QUAD*)var->sqldata);\r
1033                         }\r
1034                         else if (ivType == ivString)\r
1035                         {\r
1036                                 BlobImpl blob(mDatabase, mTransaction);\r
1037                                 blob.Save(*(std::string*)value);\r
1038                                 blob.GetId((ISC_QUAD*)var->sqldata);\r
1039                         }\r
1040                         else throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
1041                                                                                 _("Incompatible types."));\r
1042                         break;\r
1043 \r
1044                 case SQL_ARRAY :\r
1045                         if (ivType != ivArray)\r
1046                                 throw WrongTypeImpl("RowImpl::SetValue", var->sqltype, ivType,\r
1047                                                                                 _("Incompatible types."));\r
1048                         {\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
1055                                 array->ResetId();\r
1056                         }\r
1057                         break;\r
1058 \r
1059                 default : throw LogicExceptionImpl("RowImpl::SetValue",\r
1060                                                 _("The field uses an unsupported SQL type !"));\r
1061         }\r
1062 \r
1063         if (var->sqltype & 1) *var->sqlind = 0;         // Remove the 0 flag\r
1064 }\r
1065 \r
1066 void* RowImpl::GetValue(int varnum, IITYPE ivType, void* retvalue)\r
1067 {\r
1068         if (varnum < 1 || varnum > mDescrArea->sqld)\r
1069                 throw LogicExceptionImpl("RowImpl::GetValue", _("Variable index out of range."));\r
1070 \r
1071         void* value;\r
1072         int len;\r
1073         XSQLVAR* var = &(mDescrArea->sqlvar[varnum-1]);\r
1074 \r
1075         // When there is no value (SQL NULL)\r
1076         if ((var->sqltype & 1) && *(var->sqlind) != 0) return 0;\r
1077 \r
1078         switch (var->sqltype & ~1)\r
1079         {\r
1080                 case SQL_TEXT :\r
1081                         if (ivType == ivString)\r
1082                         {\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
1086                                 str->erase();\r
1087                                 str->append(var->sqldata, var->sqllen);\r
1088                                 value = retvalue;       // value != 0 means 'not null'\r
1089                         }\r
1090                         else if (ivType == ivByte)\r
1091                         {\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
1096                         }\r
1097                         else if (ivType == ivDBKey)\r
1098                         {\r
1099                                 IBPP::DBKey* key = (IBPP::DBKey*)retvalue;\r
1100                                 key->SetKey(var->sqldata, var->sqllen);\r
1101                                 value = retvalue;\r
1102                         }\r
1103                         else if (ivType == ivBool)\r
1104                         {\r
1105                                 mBools[varnum-1] = 0;\r
1106                                 if (var->sqllen >= 1)\r
1107                                 {\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
1111                                 }\r
1112                                 value = &mBools[varnum-1];\r
1113                         }\r
1114                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
1115                                                                                 _("Incompatible types."));\r
1116                         break;\r
1117 \r
1118                 case SQL_VARYING :\r
1119                         if (ivType == ivString)\r
1120                         {\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
1124                                 str->erase();\r
1125                                 str->append(var->sqldata+2, (int32_t)*(int16_t*)var->sqldata);\r
1126                                 value = retvalue;\r
1127                         }\r
1128                         else if (ivType == ivByte)\r
1129                         {\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
1134                         }\r
1135                         else if (ivType == ivBool)\r
1136                         {\r
1137                                 mBools[varnum-1] = 0;\r
1138                                 len = *(int16_t*)var->sqldata;\r
1139                                 if (len >= 1)\r
1140                                 {\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
1144                                 }\r
1145                                 value = &mBools[varnum-1];\r
1146                         }\r
1147                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
1148                                                                                 _("Incompatible types."));\r
1149                         break;\r
1150 \r
1151                 case SQL_SHORT :\r
1152                         if (ivType == ivInt16)\r
1153                         {\r
1154                                 value = var->sqldata;\r
1155                         }\r
1156                         else if (ivType == ivBool)\r
1157                         {\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
1161                         }\r
1162                         else if (ivType == ivInt32)\r
1163                         {\r
1164                                 mInt32s[varnum-1] = *(int16_t*)var->sqldata;\r
1165                                 value = &mInt32s[varnum-1];\r
1166                         }\r
1167                         else if (ivType == ivInt64)\r
1168                         {\r
1169                                 mInt64s[varnum-1] = *(int16_t*)var->sqldata;\r
1170                                 value = &mInt64s[varnum-1];\r
1171                         }\r
1172                         else if (ivType == ivFloat)\r
1173                         {\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
1177 \r
1178                                 value = &mFloats[varnum-1];\r
1179                         }\r
1180                         else if (ivType == ivDouble)\r
1181                         {\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
1186                         }\r
1187                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
1188                                                                                 _("Incompatible types."));\r
1189                         break;\r
1190 \r
1191                 case SQL_LONG :\r
1192                         if (ivType == ivInt32)\r
1193                         {\r
1194                                 value = var->sqldata;\r
1195                         }\r
1196                         else if (ivType == ivBool)\r
1197                         {\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
1201                         }\r
1202                         else if (ivType == ivInt16)\r
1203                         {\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
1210                         }\r
1211                         else if (ivType == ivInt64)\r
1212                         {\r
1213                                 mInt64s[varnum-1] = *(int32_t*)var->sqldata;\r
1214                                 value = &mInt64s[varnum-1];\r
1215                         }\r
1216                         else if (ivType == ivFloat)\r
1217                         {\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
1222                         }\r
1223                         else if (ivType == ivDouble)\r
1224                         {\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
1229                         }\r
1230                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
1231                                                                                 _("Incompatible types."));\r
1232                         break;\r
1233 \r
1234                 case SQL_INT64 :\r
1235                         if (ivType == ivInt64)\r
1236                         {\r
1237                                 value = var->sqldata;\r
1238                         }\r
1239                         else if (ivType == ivBool)\r
1240                         {\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
1244                         }\r
1245                         else if (ivType == ivInt16)\r
1246                         {\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
1253                         }\r
1254                         else if (ivType == ivInt32)\r
1255                         {\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
1262                         }\r
1263                         else if (ivType == ivFloat)\r
1264                         {\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
1269                         }\r
1270                         else if (ivType == ivDouble)\r
1271                         {\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
1276                         }\r
1277                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
1278                                                                                 _("Incompatible types."));\r
1279                         break;\r
1280 \r
1281                 case SQL_FLOAT :\r
1282                         if (ivType != ivFloat)\r
1283                                 throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
1284                                                                                 _("Incompatible types."));\r
1285                         value = var->sqldata;\r
1286                         break;\r
1287 \r
1288                 case SQL_DOUBLE :\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
1293                         {\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
1299                         }\r
1300                         else value = var->sqldata;\r
1301                         break;\r
1302 \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
1308                         value = retvalue;\r
1309                         break;\r
1310 \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
1316                         value = retvalue;\r
1317                         break;\r
1318 \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
1324                         value = retvalue;\r
1325                         break;\r
1326 \r
1327                 case SQL_BLOB :\r
1328                         if (ivType == ivBlob)\r
1329                         {\r
1330                                 BlobImpl* blob = (BlobImpl*)retvalue;\r
1331                                 blob->SetId((ISC_QUAD*)var->sqldata);\r
1332                                 value = retvalue;\r
1333                         }\r
1334                         else if (ivType == ivString)\r
1335                         {\r
1336                                 BlobImpl blob(mDatabase, mTransaction);\r
1337                                 blob.SetId((ISC_QUAD*)var->sqldata);\r
1338                                 std::string* str = (std::string*)retvalue;\r
1339                                 blob.Load(*str);\r
1340                                 value = retvalue;\r
1341                         }\r
1342                         else throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
1343                                                                                 _("Incompatible types."));\r
1344                         break;\r
1345                         \r
1346                 case SQL_ARRAY :\r
1347                         if (ivType != ivArray)\r
1348                                 throw WrongTypeImpl("RowImpl::GetValue", var->sqltype, ivType,\r
1349                                                                                         _("Incompatible types."));\r
1350                         {\r
1351                                 ArrayImpl* array = (ArrayImpl*)retvalue;\r
1352                                 array->SetId((ISC_QUAD*)var->sqldata);\r
1353                                 value = retvalue;\r
1354                         }\r
1355                         break;\r
1356 \r
1357                 default : throw LogicExceptionImpl("RowImpl::GetValue",\r
1358                                                 _("Found an unknown sqltype !"));\r
1359         }\r
1360 \r
1361         return value;\r
1362 }\r
1363 \r
1364 void RowImpl::Free()\r
1365 {\r
1366         if (mDescrArea != 0)\r
1367         {\r
1368                 for (int i = 0; i < mDescrArea->sqln; i++)\r
1369                 {\r
1370                         XSQLVAR* var = &(mDescrArea->sqlvar[i]);\r
1371                         if (var->sqldata != 0)\r
1372                         {\r
1373                                 switch (var->sqltype & ~1)\r
1374                                 {\r
1375                                         case SQL_ARRAY :\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
1380                                         case SQL_TEXT :\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
1389                                 }\r
1390                         }\r
1391                         if (var->sqlind != 0) delete var->sqlind;\r
1392                 }\r
1393                 delete [] (char*)mDescrArea;\r
1394                 mDescrArea = 0;\r
1395         }\r
1396 \r
1397         mNumerics.clear();\r
1398         mFloats.clear();\r
1399         mInt64s.clear();\r
1400         mInt32s.clear();\r
1401         mInt16s.clear();\r
1402         mBools.clear();\r
1403         mStrings.clear();\r
1404         mUpdated.clear();\r
1405 \r
1406         mDialect = 0;\r
1407         mDatabase = 0;\r
1408         mTransaction = 0;\r
1409 }\r
1410 \r
1411 void RowImpl::Resize(int n)\r
1412 {\r
1413         const int size = XSQLDA_LENGTH(n);\r
1414 \r
1415         Free();\r
1416     mDescrArea = (XSQLDA*) new char[size];\r
1417 \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
1424         mBools.resize(n);\r
1425         mStrings.resize(n);\r
1426         mUpdated.resize(n);\r
1427         for (int i = 0; i < n; i++)\r
1428         {\r
1429                 mNumerics[i] = 0.0;\r
1430                 mFloats[i] = 0.0;\r
1431                 mInt64s[i] = 0;\r
1432                 mInt32s[i] = 0;\r
1433                 mInt16s[i] = 0;\r
1434                 mBools[i] = 0;\r
1435                 mStrings[i].erase();\r
1436                 mUpdated[i] = false;\r
1437         }\r
1438 \r
1439         mDescrArea->version = SQLDA_VERSION1;\r
1440         mDescrArea->sqln = (int16_t)n;\r
1441 }\r
1442 \r
1443 void RowImpl::AllocVariables()\r
1444 {\r
1445         int i;\r
1446         for (i = 0; i < mDescrArea->sqld; i++)\r
1447         {\r
1448                 XSQLVAR* var = &(mDescrArea->sqlvar[i]);\r
1449                 switch (var->sqltype & ~1)\r
1450                 {\r
1451                         case SQL_ARRAY :\r
1452                         case SQL_BLOB :         var->sqldata = (char*) new ISC_QUAD;\r
1453                                                                 memset(var->sqldata, 0, sizeof(ISC_QUAD));\r
1454                                                                 break;\r
1455                         case SQL_TIMESTAMP :var->sqldata = (char*) new ISC_TIMESTAMP;\r
1456                                                                 memset(var->sqldata, 0, sizeof(ISC_TIMESTAMP));\r
1457                                                                 break;\r
1458                         case SQL_TYPE_TIME :var->sqldata = (char*) new ISC_TIME;\r
1459                                                                 memset(var->sqldata, 0, sizeof(ISC_TIME));\r
1460                                                                 break;\r
1461                         case SQL_TYPE_DATE :var->sqldata = (char*) new ISC_DATE;\r
1462                                                                 memset(var->sqldata, 0, sizeof(ISC_DATE));\r
1463                                                                 break;\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
1467                                                                 break;\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
1472                                                                 break;\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
1480                 }\r
1481                 if (var->sqltype & 1) var->sqlind = new short(-1);      // 0 indicator\r
1482         }\r
1483 }\r
1484 \r
1485 bool RowImpl::MissingValues()\r
1486 {\r
1487         for (int i = 0; i < mDescrArea->sqld; i++)\r
1488                 if (! mUpdated[i]) return true;\r
1489         return false;\r
1490 }\r
1491 \r
1492 RowImpl& RowImpl::operator=(const RowImpl& copied)\r
1493 {\r
1494         Free();\r
1495 \r
1496         const int n = copied.mDescrArea->sqln;\r
1497         const int size = XSQLDA_LENGTH(n);\r
1498 \r
1499         // Initial brute copy\r
1500     mDescrArea = (XSQLDA*) new char[size];\r
1501         memcpy(mDescrArea, copied.mDescrArea, size);\r
1502 \r
1503         // Copy of the columns data\r
1504         for (int i = 0; i < mDescrArea->sqld; i++)\r
1505         {\r
1506                 XSQLVAR* var = &(mDescrArea->sqlvar[i]);\r
1507                 XSQLVAR* org = &(copied.mDescrArea->sqlvar[i]);\r
1508                 switch (var->sqltype & ~1)\r
1509                 {\r
1510                         case SQL_ARRAY :\r
1511                         case SQL_BLOB :         var->sqldata = (char*) new ISC_QUAD;\r
1512                                                                 memcpy(var->sqldata, org->sqldata, sizeof(ISC_QUAD));\r
1513                                                                 break;\r
1514                         case SQL_TIMESTAMP :var->sqldata = (char*) new ISC_TIMESTAMP;\r
1515                                                                 memcpy(var->sqldata, org->sqldata, sizeof(ISC_TIMESTAMP));\r
1516                                                                 break;\r
1517                         case SQL_TYPE_TIME :var->sqldata = (char*) new ISC_TIME;\r
1518                                                                 memcpy(var->sqldata, org->sqldata, sizeof(ISC_TIME));\r
1519                                                                 break;\r
1520                         case SQL_TYPE_DATE :var->sqldata = (char*) new ISC_DATE;\r
1521                                                                 memcpy(var->sqldata, org->sqldata, sizeof(ISC_DATE));\r
1522                                                                 break;\r
1523                         case SQL_TEXT :         var->sqldata = new char[var->sqllen+1];\r
1524                                                                 memcpy(var->sqldata, org->sqldata, var->sqllen+1);\r
1525                                                                 break;\r
1526                         case SQL_VARYING :      var->sqldata = new char[var->sqllen+3];\r
1527                                                                 memcpy(var->sqldata, org->sqldata, var->sqllen+3);\r
1528                                                                 break;\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
1536                 }\r
1537                 if (var->sqltype & 1) var->sqlind = new short(*org->sqlind);    // 0 indicator\r
1538         }\r
1539 \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
1548 \r
1549         mDialect = copied.mDialect;\r
1550         mDatabase = copied.mDatabase;\r
1551         mTransaction = copied.mTransaction;\r
1552         \r
1553         return *this;\r
1554 }\r
1555 \r
1556 RowImpl::RowImpl(const RowImpl& copied)\r
1557         : IBPP::IRow(), mRefCount(0), mDescrArea(0)\r
1558 {\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
1561 }\r
1562 \r
1563 RowImpl::RowImpl(int dialect, int n, DatabaseImpl* db, TransactionImpl* tr)\r
1564         : mRefCount(0), mDescrArea(0)\r
1565 {\r
1566         Resize(n);\r
1567         mDialect = dialect;\r
1568         mDatabase = db;\r
1569         mTransaction = tr;\r
1570 }\r
1571 \r
1572 RowImpl::~RowImpl()\r
1573 {\r
1574         try { Free(); }\r
1575                 catch (...) { }\r
1576 }\r
1577 \r
1578 //\r
1579 //      EOF\r
1580 //\r